blob: 42c5c2480f1f07fabdfcd93a712ae7604dbfd342 [file] [log] [blame]
<!doctype html>
<html>
<head>
<style type='text/css'>
table, tr, td
{
border-spacing: 1px;
padding: 0px;
}
td.textColumn
{
white-space: nowrap;
font-family: Courier, monospace;
}
#directories, #codeviewer
{
overflow: scroll;
background-color: white;
position: absolute;
width: 50%;
height: 100%;
}
#directories
{
left: 0%;
}
#codeviewer
{
left: 50%;
}
ul
{
padding: 1px 0px 1px 8px;
margin: 0px;
list-style-type: none;
}
li.file
{
/* 8px is to match the width of downArrow and rightArrow because files don't have an image before them. */
padding: 0px 0px 0px 8px;
}
div.graphsContainer
{
right: 0px;
width: 300px;
position: absolute;
display: inline-block;
}
div.codeCoverage
{
right: 0px;
width: 150px;
position: absolute;
display: inline-block;
}
div.branchCoverage
{
right: 150px;
width: 150px;
position: absolute;
display: inline-block;
}
</style>
<script type='text/javascript'>
// This is the contents of the images left of directories.
var downArrow = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QYHFioBcCRLNAAAAJhJREFUGNOFzrEKwjAURuHTJHUspekDZGmhdlawCEqoUDK19O1cnX0dFxcnQXyIOAhKSsUzXr4Lf3Q8nf3leuNXy8IgBmeRYh5IAYOziDxLsdv1LNo3K/IsRQAcdhu0TgKgdUJnG4A3ipVk7NoAjV2LkvKLAKrSUBcGgLowVKX5PASTe2eJF4re2XCcn3R/PKcnH3nvPX96AbbuOGLOrLT1AAAAAElFTkSuQmCC';
var rightArrow = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QYHFiojpUQK0AAAAKZJREFUGNNjmL1k/f+379//xweYlXXMGo6dvcDw/x8jg7y0OAMzMzMDOmBiYGBg+PP7P8OO/ccYOqctZLh2+x52RTDw9t0nhtlLNjDMWbqB4d2HD9gVwcDVW/cYumcsZXj56i0DAwMDAws2RdqqCgwBHo4MIiKCmIqEBPgYgrycGbTVFVE0sTAwMDCwMjMyONqYMbjYWjCwsmL6jmH24rX/37zBH04AHAxpneY+98AAAAAASUVORK5CYII=';
function getHeatBackgroundColor(hits, maxHits)
{
if (hits === -1)
return 'white'; // Non-code lines are white.
else if (hits === 0)
return 'orange'; // Unexecuted lines are orange.
else {
// Executed lines are between red and green.
var relativeHeat = Math.floor(hits / maxHits * 255);
return 'rgb(' + relativeHeat + ',' + (255 - relativeHeat) + ', 0)';
}
}
function getCoverageBackgroundColor(coverage)
{
var value = Math.floor(coverage * 255);
return 'rgb(' + (255 - value) + ',' + value + ', 0)';
}
function expandClicked(event)
{
var children = this.parentNode.lastChild;
if (children.style.display === '') {
children.style.display = 'none';
this.src = rightArrow;
} else {
children.style.display = '';
this.src = downArrow;
}
}
function processFile(fileData, contents)
{
var lines = contents.split('\n');
var hits = new Array();
var branchesNumerator = new Array();
var branchesDenominator = new Array();
for (var i = 0; i < lines.length; i++) {
hits[i] = -1;
branchesNumerator[i] = -1;
branchesDenominator[i] = -1;
}
for (var i = 0; i < fileData.hitLines.length; i++)
hits[fileData.hitLines[i] - 1] = fileData.hits[i];
for (var i = 0; i < fileData.branchLines.length; i++) {
branchesNumerator[fileData.branchLines[i] - 1] = fileData.branchesTaken[i];
branchesDenominator[fileData.branchLines[i] - 1] = fileData.branchesPossible[i];
}
var table = document.createElement('table');
for (var i = 0; i < lines.length; i++) {
var row = document.createElement('tr');
var branchesColumn = document.createElement('td');
if (branchesNumerator[i] != -1)
branchesColumn.appendChild(document.createTextNode('(' + branchesNumerator[i] + '/' + branchesDenominator[i] + ')'));
var hitsColumn = document.createElement('td');
if (hits[i] != -1)
hitsColumn.appendChild(document.createTextNode(hits[i]));
var textColumn = document.createElement('td');
textColumn.style.background = getHeatBackgroundColor(hits[i], fileData.maxHeat);
textColumn.style.className = 'textColumn';
textColumn.appendChild(document.createTextNode(lines[i]));
row.appendChild(branchesColumn);
row.appendChild(hitsColumn);
row.appendChild(textColumn);
table.appendChild(row);
}
return table;
}
function fileClicked(event)
{
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function()
{
if (xhr.readyState === XMLHttpRequest.DONE) {
var codeviewer = document.getElementById('codeviewer');
codeviewer.replaceChild(processFile(xhr.fileData, xhr.responseText), codeviewer.firstChild);
}
}
xhr.fileData = event.target.fileData;
xhr.open('GET', '../../' + event.target.fileData.filename.substring(1), true);
xhr.send();
event.stopPropagation();
}
function makeGraphs(dirOrFile)
{
var codeCoverage = document.createElement('div');
codeCoverage.className = 'codeCoverage';
var codeCoveragePercent = dirOrFile.totalLines ? Math.floor(dirOrFile.totalHitLines / dirOrFile.totalLines * 100) + '%' : '-';
var codeCoverageText = codeCoveragePercent + ' (' + dirOrFile.totalHitLines + '/' + dirOrFile.totalLines + ')';
codeCoverage.appendChild(document.createTextNode(codeCoverageText));
codeCoverage.style.backgroundColor = getCoverageBackgroundColor(dirOrFile.coverage);
var branchCoverage = document.createElement('div');
branchCoverage.className = 'branchCoverage';
var branchCoveragePercent = dirOrFile.totalBranchesPossible ? Math.floor(dirOrFile.totalBranchesTaken / dirOrFile.totalBranchesPossible * 100) + '%' : '-';
branchCoverage.appendChild(document.createTextNode(branchCoveragePercent + ' (' + dirOrFile.totalBranchesTaken + '/' + dirOrFile.totalBranchesPossible + ')'));
branchCoverage.style.backgroundColor = getCoverageBackgroundColor(dirOrFile.branchCoverage);
var graphsContainer = document.createElement('div');
graphsContainer.className = 'graphsContainer';
graphsContainer.appendChild(codeCoverage);
graphsContainer.appendChild(branchCoverage);
return graphsContainer;
}
function makeFileListItem(fileData, filename)
{
var li = document.createElement('li');
li.className = 'file';
var a = document.createElement('a');
a.appendChild(document.createTextNode(filename));
a.href = '#';
a.addEventListener('click', fileClicked.bind(a));
a.fileData = fileData;
li.appendChild(a);
li.appendChild(makeGraphs(fileData));
return li;
}
function makeDirectoryListItem(dir, dirName)
{
var li = document.createElement('li');
var children = document.createElement('ul');
// Recursively add all sorted subdirectories and files.
var fileNames = dir.files ? Object.keys(dir.files).sort() : [];
var subdirNames = dir.subdirs ? Object.keys(dir.subdirs).sort() : [];
for (var i = 0; i < subdirNames.length; i++) {
var subdir = subdirNames[i];
children.appendChild(makeDirectoryListItem(dir.subdirs[subdir], subdir));
}
for (var i = 0; i < fileNames.length; i++) {
var file = fileNames[i];
children.appendChild(makeFileListItem(dir.files[file], file, dir.maxHeat, dir.totalHeat));
}
var img = document.createElement('img');
img.addEventListener('click', expandClicked.bind(img));
// These four directories are expanded by default.
if (dirName === '' || dirName === 'Source' || dirName === 'Tools' || dirName === 'WebKitBuild') {
img.src = downArrow;
children.style.display = '';
} else {
img.src = rightArrow;
children.style.display = 'none';
}
li.appendChild(img);
li.appendChild(document.createTextNode(dirName));
li.appendChild(makeGraphs(dir));
li.appendChild(children);
return li;
}
// Collect total coverage for a directory and its subdirectories.
function collectDirectoryTotals(directory)
{
directory.totalBranchesPossible = 0;
directory.totalBranchesTaken = 0;
directory.totalHitLines = 0;
directory.totalLines = 0;
directory.totalHeat = 0;
directory.maxHeat = 0;
if (directory.subdirs) {
for (var subdirName in directory.subdirs) {
var subdir = directory.subdirs[subdirName];
collectDirectoryTotals(subdir);
directory.totalBranchesPossible += subdir.totalBranchesPossible;
directory.totalBranchesTaken += subdir.totalBranchesTaken;
directory.totalHitLines += subdir.totalHitLines;
directory.totalLines += subdir.totalLines;
directory.totalHeat += subdir.totalHeat;
directory.maxHeat = Math.max(directory.maxHeat, subdir.maxHeat);
}
}
if (directory.files) {
for (var fileName in directory.files) {
var file = directory.files[fileName];
file.totalBranchesPossible = 0;
file.totalBranchesTaken = 0;
file.totalHitLines = 0;
file.totalLines = file.hitLines.length;
file.totalHeat = 0;
for (var i = 0; i < file.branchesPossible.length; i++) {
file.totalBranchesPossible += file.branchesPossible[i];
file.totalBranchesTaken += file.branchesTaken[i];
}
for (var i = 0; i < file.hits.length; i++) {
file.totalHeat += file.hits[i];
if (file.hits[i])
file.totalHitLines++;
}
directory.totalBranchesPossible += file.totalBranchesPossible;
directory.totalBranchesTaken += file.totalBranchesTaken;
directory.totalHitLines += file.totalHitLines;
directory.totalLines += file.totalLines;
directory.totalHeat += file.totalHeat;
directory.maxHeat = Math.max(directory.maxHeat, file.maxHeat);
}
}
directory.coverage = directory.totalHitLines / directory.totalLines;
directory.branchCoverage = directory.totalBranchesPossible ? directory.totalBranchesTaken / directory.totalBranchesPossible : 1;
}
function addFileToDirectory(filename, filedata, directory)
{
var slashIndex = filename.indexOf('/', 1);
if (slashIndex === -1) {
if (!directory.files)
directory.files = {};
directory.files[filename.substring(1)] = filedata;
} else {
if (!directory.subdirs)
directory.subdirs = {};
var subdirName = filename.substring(1, slashIndex);
if (!directory.subdirs[subdirName])
directory.subdirs[subdirName] = {};
addFileToDirectory(filename.substring(slashIndex), filedata, directory.subdirs[subdirName]);
}
}
function updateReport(data)
{
var rootDirectory = {};
for (var i = 0; i < data.length; i++)
addFileToDirectory(data[i].filename, data[i], rootDirectory);
collectDirectoryTotals(rootDirectory);
var report = document.createElement('div');
var codeCoverageHeader = document.createElement('div');
codeCoverageHeader.className = 'codeCoverage';
codeCoverageHeader.appendChild(document.createTextNode('Code Coverage'));
var branchCoverageHeader = document.createElement('div');
branchCoverageHeader.className = 'branchCoverage';
branchCoverageHeader.appendChild(document.createTextNode('Branch Coverage'));
var ul = document.createElement('ul');
ul.appendChild(makeDirectoryListItem(rootDirectory, ''));
report.appendChild(codeCoverageHeader);
report.appendChild(branchCoverageHeader);
report.appendChild(document.createTextNode('Directories'));
report.appendChild(ul);
var directories = document.getElementById('directories');
directories.replaceChild(report, directories.firstChild);
}
function bodyLoaded()
{
updateReport(JSON.parse(document.getElementById('json').textContent));
}
</script>
</head>
<body onload='bodyLoaded();'>
<div id='directories'>
loading data...
</div>
<div id='codeviewer'>
</div>
<script id='json' type='application/json'>%CoverageDataJSON%</script>
</body>
</html>