1 <!DocType html> 2 <style> 3 body { 4 margin: 4px; 5 } 6 7 body > p:first-of-type { 8 margin-top: 0; 9 } 10 11 tr:first-of-type:hover { 12 opacity: 0.7 13 } 14 15 thead, tbody { 16 background-color: #E3E9FF; 17 } 18 19 td { 20 padding: 0 4px; 21 } 22 23 th:empty, td:empty { 24 padding: 0; 25 } 26 27 th { 28 -webkit-user-select: none; 29 -moz-user-select: none; 30 } 31 32 label { 33 margin-left: 10px; 34 } 35 36 .results-row { 37 background-color: white; 38 } 39 40 .results-row iframe { 41 width: 800px; 42 height: 600px; 43 } 44 45 #options { 46 position: absolute; 47 top: 4px; 48 right: 4px; 49 } 50 51 .expand-button { 52 background-color: white; 53 color: blue; 54 width: 11px; 55 height: 11px; 56 border: 1px solid blue; 57 display: inline-block; 58 margin: 0 3px 0 0; 59 position: relative; 60 } 61 62 .expand-button-text { 63 position: absolute; 64 top: -0.3em; 65 left: 1px; 66 } 67 68 .result-container { 69 display: inline-block; 70 border: 1px solid gray; 71 } 72 73 .result-container iframe, .result-container img { 74 border: 0; 75 border-top: 1px solid lightgray; 76 vertical-align: top; 77 } 78 79 .label { 80 padding-left: 3px; 81 font-weight: bold; 82 font-size: small; 83 } 84 85 .pixel-zoom-container { 86 position: fixed; 87 top: 0; 88 left: 0; 89 width: 100%; 90 display: -webkit-box; 91 } 92 93 .pixel-zoom-container > * { 94 display: -webkit-box; 95 -webkit-box-flex: 1; 96 border: 1px inset lightgray; 97 height: 100px; 98 overflow: hidden; 99 zoom: 300%; 100 background-color: white; 101 } 102 103 .pixel-zoom-container img { 104 width: 800px; 105 height: 600px; 106 vertical-align: top; 107 } 108 </style> 109 110 <script> 111 var g_results; 112 function ADD_RESULTS(input) 113 { 114 g_results = input; 115 } 116 </script> 117 118 <script src="full_results.json"></script> 119 120 <script> 121 function stripExtension(test) 122 { 123 var index = test.lastIndexOf('.'); 124 return test.substring(0, index); 125 } 126 127 function parentOfType(node, selector) 128 { 129 while (node = node.parentElement) { 130 if (node.webkitMatchesSelector(selector)) 131 return node; 132 } 133 return null; 134 } 135 136 function appendResultIframe(src, parent) 137 { 138 // FIXME: use audio tags for AUDIO tests? 139 var layoutTestsIndex = src.indexOf('LayoutTests'); 140 var name; 141 if (layoutTestsIndex != -1) { 142 var hasTrac = src.indexOf('trac.webkit.org') != -1; 143 var prefix = hasTrac ? 'trac.webkit.org/.../' : ''; 144 name = prefix + src.substring(layoutTestsIndex + 'LayoutTests/'.length); 145 } else { 146 var lastDashIndex = src.lastIndexOf('-pretty'); 147 if (lastDashIndex == -1) 148 lastDashIndex = src.lastIndexOf('-'); 149 name = src.substring(lastDashIndex + 1); 150 } 151 152 var tagName = (src.lastIndexOf('.png') == -1) ? 'iframe' : 'img'; 153 154 var container = document.createElement('div'); 155 container.className = 'result-container'; 156 container.innerHTML = '<div class=label>' + name + '</div><' + tagName + ' src="' + src + '?format=txt"></' + tagName + '>'; 157 parent.appendChild(container); 158 } 159 160 function expandExpectations(e) 161 { 162 var expandLink = e.target; 163 if (expandLink.className != 'expand-button-text') 164 expandLink = expandLink.querySelector('.expand-button-text'); 165 166 var isExpand = expandLink.textContent == '+'; 167 var row = parentOfType(expandLink, 'tr'); 168 var parentTbody = row.parentNode; 169 var existingResultsRow = parentTbody.querySelector('.results-row'); 170 171 if (!isExpand) { 172 expandLink.textContent = '+'; 173 existingResultsRow.style.display = 'none'; 174 return; 175 } 176 177 var enDash = '\u2013'; 178 expandLink.textContent = enDash; 179 if (existingResultsRow) { 180 existingResultsRow.style.display = ''; 181 return; 182 } 183 184 var newRow = document.createElement('tr'); 185 newRow.className = 'results-row'; 186 var newCell = document.createElement('td'); 187 newCell.colSpan = row.querySelectorAll('td').length; 188 189 appendResultIframe(row.querySelector('.test-link').href, newCell); 190 191 var resultLinks = row.querySelectorAll('.result-link'); 192 for (var i = 0; i < resultLinks.length; i++) 193 appendResultIframe(resultLinks[i].href, newCell); 194 195 newRow.appendChild(newCell); 196 parentTbody.appendChild(newRow); 197 } 198 199 function testLink(test) 200 { 201 var basePath; 202 if (g_results.layout_tests_dir && location.toString().indexOf('file://') == 0) 203 basePath = g_results.layout_tests_dir + '/'; 204 else 205 basePath = 'http://trac.webkit.org/browser/trunk/LayoutTests/'; 206 return ' + ' 207 'basePath + test + '">' + test + ''; 208 } 209 210 function resultLink(testPrefix, suffix, contents) 211 { 212 return 'testPrefix + suffix + '">' + contents + ' '; 213 } 214 215 var g_hasTextFailures = false; 216 var g_hasImageFailures = false; 217 218 var g_testsWithStderr = []; 219 var g_newTests = []; 220 var g_hasHttpTests = false; 221 222 function tableRows() 223 { 224 var html = ''; 225 for (var test in g_results.tests) { 226 if (g_results.tests[test].has_stderr) 227 g_testsWithStderr.push(test); 228 229 g_hasHttpTests = g_hasHttpTests || test.indexOf('http/') == 0; 230 231 var actual = g_results.tests[test].actual; 232 if (actual == 'MISSING') { 233 // FIXME: make sure that new-run-webkit-tests spits out an -actual.txt file for 234 // tests with MISSING results. 235 g_newTests.push(test); 236 continue; 237 } 238 239 var expected = g_results.tests[test].expected || 'PASS'; 240 if (actual == 'PASS' && (!g_results.uses_expectations_file || expected == 'PASS')) 241 continue; 242 243 // FIXME: put unexpected passes in a separate table. 244 245 var row = '' + testLink(test) + ' '; 246 var test_prefix = stripExtension(test); 247 248 row += ''; 249 if (actual == 'CRASH') 250 row += resultLink(test_prefix, '-stack.txt', 'stack'); 251 else if (actual == 'AUDIO') { 252 row += resultLink(test_prefix, '-expected.wav', 'expected'); 253 row += resultLink(test_prefix, '-actual.wav', 'actual'); 254 } else if (actual.indexOf('TEXT') != -1 || actual == 'TIMEOUT') { 255 // FIXME: only include timeout actual/expected results here if we actually spit out results for timeout tests. 256 g_hasTextFailures = true; 257 row += resultLink(test_prefix, '-expected.txt', 'expected') + 258 resultLink(test_prefix, '-actual.txt', 'actual') + 259 resultLink(test_prefix, '-diff.txt', 'diff'); 260 261 if (g_results.has_pretty_patch) 262 row += resultLink(test_prefix, '-pretty-diff.html', 'pretty diff'); 263 264 if (g_results.has_wdiff) 265 row += resultLink(test_prefix, '-wdiff.html', 'wdiff'); 266 } 267 268 row += ' '; 269 270 if (actual.indexOf('IMAGE') != -1) { 271 g_hasImageFailures = true; 272 273 if (g_results.tests[test].is_mismatch_reftest) { 274 row += resultLink(test_prefix, '-expected-mismatch.html', 'ref mismatch html') + 275 resultLink(test_prefix, '-actual.png', 'actual'); 276 } else { 277 if (g_results.tests[test].is_reftest) 278 row += resultLink(test_prefix, '-expected.html', 'ref html'); 279 280 row += resultLink(test_prefix, '-expected.png', 'expected') + 281 resultLink(test_prefix, '-actual.png', 'actual') + 282 resultLink(test_prefix, '-diff.png', 'diff'); 283 } 284 } 285 286 row += ' '; 287 row += '' + actual + ' '; 288 289 if (g_results.uses_expectations_file) 290 row += '' + expected + ' '; 291 292 var isExpected = actual == 'SKIP'; 293 if (!isExpected && g_results.uses_expectations_file) { 294 var expectedArray = expected.split(' '); 295 if (expectedArray.indexOf(actual) != -1) 296 isExpected = true; 297 else if (expectedArray.indexOf('FAIL') != -1) 298 isExpected = actual == 'IMAGE' || actual == 'TEXT' || actual == 'IMAGE+TEXT'; 299 } 300 html += 'isExpected ? 'expected' : '') + '">' + row + ' '; 301 } 302 return html; 303 } 304 305 var html = ''; 306 if (g_results.uses_expectations_file) 307 html += ''; 308 309 var tableRowsHtml = tableRows(); 310 311 if (tableRowsHtml) { 312 html += 'Tests where results did not match expected results:
' + 313 ''; 323 } 324 325 function appendTestList(tests, header, tableId, fileSuffix, linkName) 326 { 327 tests.sort(); 328 329 html += '
' + 314 ' ' + tableRowsHtml + 'test ' + 315 'text results ' + 316 'image results ' + 317 'failure type '; 318 319 if (g_results.uses_expectations_file) 320 html += 'expected failure type '; 321 322 html += ''
+ header + 'tableId + '">'; 330 for (var i = 0; i < tests.length; i++) { 331 var test = tests[i]; 332 html += '<tbody><tr><td>' + testLink(test) + '</td><td>'; 333 334 if (fileSuffix.indexOf('actual') == -1) 335 html += resultLink(stripExtension(test), fileSuffix, linkName); 336 else { 337 var testObject = g_results.tests[test]; 338 if (testObject.is_missing_audio) 339 html += resultLink(stripExtension(test), '-actual.wav', 'audio result'); 340 if (testObject.is_missing_text) 341 html += resultLink(stripExtension(test), fileSuffix, linkName); 342 if (testObject.is_missing_image) 343 html += resultLink(stripExtension(test), '-actual.png', 'png result'); 344 } 345 346 html += '</td></tr></tbody>'; 347 } 348 html += '</table>' 349 } 350 351 if (g_newTests.length) 352 appendTestList(g_newTests, 'Tests that had no expected results (probably new):', 'new-tests-table', '-actual.txt', 'result'); 353 354 if (g_testsWithStderr.length) 355 appendTestList(g_testsWithStderr, 'Tests that had stderr output:', 'stderr-table', '-stderr.txt', 'stderr'); 356 357 if (g_hasHttpTests) { 358 html += '<p>httpd access log: <a href="access_log.txt">access_log.txt</a></p>' + 359 '<p>httpd error log: <a href="error_log.txt">error_log.txt</a></p>'; 360 } 361 362 document.write(html); 363 364 function toArray(nodeList) 365 { 366 return Array.prototype.slice.call(nodeList); 367 } 368 369 function trim(string) 370 { 371 return string.replace(/^[\s\xa0]+|[\s\xa0]+$/g, ''); 372 } 373 374 // Just a namespace for code management. 375 var TableSorter = {}; 376 377 TableSorter._forwardArrow = '<svg style="width:10px;height:10px"><polygon points="0,0 10,0 5,10" style="fill:#aaa"></svg>'; 378 379 TableSorter._backwardArrow = '<svg style="width:10px;height:10px"><polygon points="0,10 10,10 5,0" style="fill:#aaa"></svg>'; 380 381 TableSorter._sortedContents = function(header, arrow) 382 { 383 return arrow + ' ' + trim(header.textContent) + ' ' + arrow; 384 } 385 386 TableSorter._updateHeaderClassNames = function(newHeader) 387 { 388 var sortHeader = document.querySelector('.sortHeader'); 389 if (sortHeader) { 390 if (sortHeader == newHeader) { 391 var isAlreadyReversed = sortHeader.classList.contains('reversed'); 392 if (isAlreadyReversed) 393 sortHeader.classList.remove('reversed'); 394 else 395 sortHeader.classList.add('reversed'); 396 } else { 397 sortHeader.textContent = sortHeader.textContent; 398 sortHeader.classList.remove('sortHeader'); 399 sortHeader.classList.remove('reversed'); 400 } 401 } 402 403 newHeader.classList.add('sortHeader'); 404 } 405 406 TableSorter._textContent = function(tbodyRow, column) 407 { 408 return tbodyRow.querySelectorAll('td')[column].textContent; 409 } 410 411 TableSorter._sortRows = function(newHeader, reversed) 412 { 413 var testsTable = document.getElementById('results-table'); 414 var headers = toArray(testsTable.querySelectorAll('th')); 415 var sortColumn = headers.indexOf(newHeader); 416 417 var rows = toArray(testsTable.querySelectorAll('tbody')); 418 419 rows.sort(function(a, b) { 420 // Only need to support lexicographic sort for now. 421 var aText = TableSorter._textContent(a, sortColumn); 422 var bText = TableSorter._textContent(b, sortColumn); 423 424 // Forward sort equal values by test name. 425 if (sortColumn && aText == bText) { 426 var aTestName = TableSorter._textContent(a, 0); 427 var bTestName = TableSorter._textContent(b, 0); 428 if (aTestName == bTestName) 429 return 0; 430 return aTestName < bTestName ? -1 : 1; 431 } 432 433 if (reversed) 434 return aText < bText ? 1 : -1; 435 else 436 return aText < bText ? -1 : 1; 437 }); 438 439 for (var i = 0; i < rows.length; i++) 440 testsTable.appendChild(rows[i]); 441 } 442 443 TableSorter.sortColumn = function(columnNumber) 444 { 445 var newHeader = document.getElementById('results-table').querySelectorAll('th')[columnNumber]; 446 TableSorter._sort(newHeader); 447 } 448 449 TableSorter.handleClick = function(e) 450 { 451 var newHeader = e.target; 452 if (newHeader.localName != 'th') 453 return; 454 TableSorter._sort(newHeader); 455 } 456 457 TableSorter._sort = function(newHeader) 458 { 459 TableSorter._updateHeaderClassNames(newHeader); 460 461 var reversed = newHeader.classList.contains('reversed'); 462 var sortArrow = reversed ? TableSorter._backwardArrow : TableSorter._forwardArrow; 463 newHeader.innerHTML = TableSorter._sortedContents(newHeader, sortArrow); 464 465 TableSorter._sortRows(newHeader, reversed); 466 } 467 468 if (document.getElementById('results-table')) 469 document.getElementById('results-table').addEventListener('click', TableSorter.handleClick, false); 470 TableSorter.sortColumn(0); 471 472 var PixelZoomer = {}; 473 474 PixelZoomer._createContainer = function(e) 475 { 476 var tbody = parentOfType(e.target, 'tbody'); 477 var imageDiffLinks = tbody.querySelector('tr').querySelectorAll('a[href$=".png"]'); 478 479 var container = document.createElement('div'); 480 container.className = 'pixel-zoom-container'; 481 482 var html = ''; 483 for (var i = 0; i < imageDiffLinks.length; i++) 484 html += '
imageDiffLinks[i].href + '">'; 485 486 container.innerHTML = html; 487 document.body.appendChild(container); 488 489 PixelZoomer._position(e); 490 } 491 492 PixelZoomer._position = function(e) 493 { 494 var pageX = e.clientX; 495 var pageY = e.clientY; 496 var targetLocation = e.target.getBoundingClientRect(); 497 var x = pageX - targetLocation.left; 498 var y = pageY - targetLocation.top; 499 500 var zoomContainers = document.querySelectorAll('.pixel-zoom-container > .zoom-image-container'); 501 for (var i = 0; i < zoomContainers.length; i++) { 502 var container = zoomContainers[i]; 503 container.scrollLeft = x - container.offsetWidth / 2; 504 container.scrollTop = y - container.offsetHeight / 2; 505 } 506 } 507 508 PixelZoomer.handleMouseMove = function(e) { 509 if (PixelZoomer._mouseMoveTimeout) 510 clearTimeout(PixelZoomer._mouseMoveTimeout); 511 512 if (parentOfType(e.target, '.pixel-zoom-container')) 513 return; 514 515 var container = document.querySelector('.pixel-zoom-container'); 516 if (!e.target.src || e.target.src.indexOf('.png') == -1) { 517 if (container) 518 container.parentNode.removeChild(container); 519 return; 520 } 521 522 if (!container) { 523 PixelZoomer._mouseMoveTimeout = setTimeout(function() { 524 PixelZoomer._createContainer(e); 525 }, 200); 526 return; 527 } 528 529 PixelZoomer._position(e); 530 } 531 532 document.body.addEventListener('mousemove', PixelZoomer.handleMouseMove, false); 533 534 535 var unexpectedStyleNode = document.createElement('style'); 536 document.body.appendChild(unexpectedStyleNode); 537 538 function updateExpectedResults() 539 { 540 var checkBox = document.querySelector('.unexpected-results'); 541 if (!checkBox || checkBox.checked) 542 unexpectedStyleNode.innerText = '.expected { display: none; }'; 543 else 544 unexpectedStyleNode.innerText = ''; 545 } 546 547 updateExpectedResults(); 548 if (document.querySelector('.unexpected-results')) 549 document.querySelector('.unexpected-results').addEventListener('change', updateExpectedResults, false); 550 551 if (!g_hasTextFailures) 552 document.body.getElementById('text-results-header').textContent = ''; 553 if (!g_hasImageFailures) 554 document.body.getElementById('image-results-header').textContent = ''; 555 </script> 556