| Differences between
and this patch
- a/LayoutTests/ChangeLog +10 lines
Lines 1-3 a/LayoutTests/ChangeLog_sec1
1
2011-04-28  Ojan Vafai  <ojan@chromium.org>
2
3
        Reviewed by NOBODY (OOPS!).
4
5
        use a hierarchical data structure to store results json
6
        https://bugs.webkit.org/show_bug.cgi?id=59736
7
8
        * fast/harness/resources/results-test.js:
9
        * fast/harness/results.html:
10
1
2011-04-28  Mark Pilgrim  <pilgrim@chromium.org>
11
2011-04-28  Mark Pilgrim  <pilgrim@chromium.org>
2
12
3
        Reviewed by Tony Chang.
13
        Reviewed by Tony Chang.
- a/LayoutTests/fast/harness/resources/results-test.js -45 / +61 lines
Lines 113-129 function runSingleRowTest(results, isExpected, textResults, imageResults) a/LayoutTests/fast/harness/resources/results-test.js_sec1
113
function runTests()
113
function runTests()
114
{
114
{
115
    var results = mockResults();
115
    var results = mockResults();
116
    results.tests['foo/bar.html'] = mockExpectation('PASS', 'TEXT');
116
    var subtree = results.tests['foo'] = {}
117
    subtree['bar.html'] = mockExpectation('PASS', 'TEXT');
117
    runTest(results, function() {
118
    runTest(results, function() {
118
        assertTrue(document.getElementById('image-results-header').textContent == '');
119
        assertTrue(document.getElementById('image-results-header').textContent == '');
119
        assertTrue(document.getElementById('text-results-header').textContent != '');
120
        assertTrue(document.getElementById('text-results-header').textContent != '');
120
    });
121
    });
121
    
122
    
122
    results = mockResults();
123
    results = mockResults();
123
    results.tests['foo/bar.html'] = mockExpectation('TEXT', 'MISSING');
124
    var subtree = results.tests['foo'] = {}
124
    results.tests['foo/bar.html'].is_missing_text = true;
125
    subtree['bar.html'] = mockExpectation('TEXT', 'MISSING');
125
    results.tests['foo/bar.html'].is_missing_audio = true;
126
    subtree['bar.html'].is_missing_text = true;
126
    results.tests['foo/bar.html'].is_missing_image = true;
127
    subtree['bar.html'].is_missing_audio = true;
128
    subtree['bar.html'].is_missing_image = true;
127
    runTest(results, function() {
129
    runTest(results, function() {
128
        assertTrue(!document.getElementById('results-table'));
130
        assertTrue(!document.getElementById('results-table'));
129
        assertTrue(document.querySelector('#new-tests-table .test-link').textContent == 'foo/bar.html');
131
        assertTrue(document.querySelector('#new-tests-table .test-link').textContent == 'foo/bar.html');
Lines 133-149 function runTests() a/LayoutTests/fast/harness/resources/results-test.js_sec2
133
    });
135
    });
134
136
135
    results = mockResults();
137
    results = mockResults();
136
    results.tests['foo/bar.html'] = mockExpectation('PASS', 'TEXT');
138
    var subtree = results.tests['foo'] = {}
137
    results.tests['foo/bar.html'].has_stderr = true;
139
    subtree['bar.html'] = mockExpectation('PASS', 'TEXT');
140
    subtree['bar.html'].has_stderr = true;
138
    runTest(results, function() {
141
    runTest(results, function() {
139
        assertTrue(document.getElementById('results-table'));
142
        assertTrue(document.getElementById('results-table'));
140
        assertTrue(document.querySelector('#stderr-table .result-link').textContent == 'stderr');
143
        assertTrue(document.querySelector('#stderr-table .result-link').textContent == 'stderr');
141
    });
144
    });
142
145
143
    results = mockResults();
146
    results = mockResults();
144
    results.tests['foo/bar.html'] = mockExpectation('TEXT', 'PASS');
147
    var subtree = results.tests['foo'] = {}
145
    results.tests['foo/bar1.html'] = mockExpectation('CRASH', 'PASS');
148
    subtree['bar.html'] = mockExpectation('TEXT', 'PASS');
146
    results.tests['foo/bar2.html'] = mockExpectation('IMAGE', 'PASS');
149
    subtree['bar1.html'] = mockExpectation('CRASH', 'PASS');
150
    subtree['bar2.html'] = mockExpectation('IMAGE', 'PASS');
147
    runTest(results, function() {
151
    runTest(results, function() {
148
        assertTrue(!document.getElementById('results-table'));
152
        assertTrue(!document.getElementById('results-table'));
149
153
Lines 159-170 function runTests() a/LayoutTests/fast/harness/resources/results-test.js_sec3
159
    });
163
    });
160
164
161
    results = mockResults();
165
    results = mockResults();
162
    results.tests['foo/bar.html'] = mockExpectation('TEXT', 'PASS');
166
    var subtree = results.tests['foo'] = {}
163
    results.tests['foo/bar-missing.html'] = mockExpectation('TEXT', 'MISSING');
167
    subtree['bar.html'] = mockExpectation('TEXT', 'PASS');
164
    results.tests['foo/bar-missing.html'].is_missing_text = true;
168
    subtree['bar-missing.html'] = mockExpectation('TEXT', 'MISSING');
165
    results.tests['foo/bar-stderr.html'] = mockExpectation('PASS', 'TEXT');
169
    subtree['bar-missing.html'].is_missing_text = true;
166
    results.tests['foo/bar-stderr.html'].has_stderr = true;
170
    subtree['bar-stderr.html'] = mockExpectation('PASS', 'TEXT');
167
    results.tests['foo/bar-unexpected-pass.html'] = mockExpectation('TEXT', 'PASS');
171
    subtree['bar-stderr.html'].has_stderr = true;
172
    subtree['bar-unexpected-pass.html'] = mockExpectation('TEXT', 'PASS');
168
    runTest(results, function() {
173
    runTest(results, function() {
169
        assertTrue(document.querySelectorAll('tbody tr').length == 5);
174
        assertTrue(document.querySelectorAll('tbody tr').length == 5);
170
        expandAllExpectations();
175
        expandAllExpectations();
Lines 191-198 function runTests() a/LayoutTests/fast/harness/resources/results-test.js_sec4
191
    });
196
    });
192
197
193
    results = mockResults();
198
    results = mockResults();
194
    results.tests['foo/bar.html'] = mockExpectation('PASS', 'TEXT');
199
    var subtree = results.tests['foo'] = {}
195
    results.tests['foo/bar-expected-fail.html'] = mockExpectation('TEXT', 'TEXT');
200
    subtree['bar.html'] = mockExpectation('PASS', 'TEXT');
201
    subtree['bar-expected-fail.html'] = mockExpectation('TEXT', 'TEXT');
196
    runTest(results, function() {
202
    runTest(results, function() {
197
        assertTrue(document.querySelectorAll('.expected').length == 1);
203
        assertTrue(document.querySelectorAll('.expected').length == 1);
198
        assertTrue(document.querySelector('.expected .test-link').textContent == 'foo/bar-expected-fail.html');
204
        assertTrue(document.querySelector('.expected .test-link').textContent == 'foo/bar-expected-fail.html');
Lines 210-243 function runTests() a/LayoutTests/fast/harness/resources/results-test.js_sec5
210
        assertTrue(document.querySelectorAll('.results-row').length == 2);
216
        assertTrue(document.querySelectorAll('.results-row').length == 2);
211
    });
217
    });
212
  
218
  
213
    runDefaultSingleRowTest('foo/bar-skip.html', 'TEXT', 'SKIP', true, '', '');
219
    runDefaultSingleRowTest('bar-skip.html', 'TEXT', 'SKIP', true, '', '');
214
    runDefaultSingleRowTest('foo/bar-flaky-fail.html', 'PASS FAIL', 'TEXT', true, 'expected actual diff ', '');
220
    runDefaultSingleRowTest('bar-flaky-fail.html', 'PASS FAIL', 'TEXT', true, 'expected actual diff ', '');
215
    runDefaultSingleRowTest('foo/bar-flaky-fail-unexpected.html', 'PASS TEXT', 'IMAGE', false, '', 'expected actual diff ');
221
    runDefaultSingleRowTest('bar-flaky-fail-unexpected.html', 'PASS TEXT', 'IMAGE', false, '', 'expected actual diff ');
216
    runDefaultSingleRowTest('foo/bar-crash.html', 'TEXT', 'CRASH', false, 'stack ', '');
222
    runDefaultSingleRowTest('bar-crash.html', 'TEXT', 'CRASH', false, 'stack ', '');
217
    runDefaultSingleRowTest('foo/bar-audio.html', 'TEXT', 'AUDIO', false, 'expected actual ', '');
223
    runDefaultSingleRowTest('bar-audio.html', 'TEXT', 'AUDIO', false, 'expected actual ', '');
218
    runDefaultSingleRowTest('foo/bar-timeout.html', 'TEXT', 'TIMEOUT', false, 'expected actual diff ', '');
224
    runDefaultSingleRowTest('bar-timeout.html', 'TEXT', 'TIMEOUT', false, 'expected actual diff ', '');
219
    runDefaultSingleRowTest('foo/bar-image.html', 'TEXT', 'IMAGE', false, '', 'expected actual diff ');
225
    runDefaultSingleRowTest('bar-image.html', 'TEXT', 'IMAGE', false, '', 'expected actual diff ');
220
    runDefaultSingleRowTest('foo/bar-image-plus-text.html', 'TEXT', 'IMAGE+TEXT', false, 'expected actual diff ', 'expected actual diff ');
226
    runDefaultSingleRowTest('bar-image-plus-text.html', 'TEXT', 'IMAGE+TEXT', false, 'expected actual diff ', 'expected actual diff ');
221
227
222
    results = mockResults();
228
    results = mockResults();
223
    results.tests['foo/bar-reftest.html'] = mockExpectation('PASS', 'IMAGE');
229
    results.tests['bar-reftest.html'] = mockExpectation('PASS', 'IMAGE');
224
    results.tests['foo/bar-reftest.html'].is_reftest = true;
230
    results.tests['bar-reftest.html'].is_reftest = true;
225
    runSingleRowTest(results, false, '', 'ref html expected actual diff ');
231
    runSingleRowTest(results, false, '', 'ref html expected actual diff ');
226
232
227
    results = mockResults();
233
    results = mockResults();
228
    results.tests['foo/bar-reftest-mismatch.html'] = mockExpectation('PASS', 'IMAGE');
234
    results.tests['bar-reftest-mismatch.html'] = mockExpectation('PASS', 'IMAGE');
229
    results.tests['foo/bar-reftest-mismatch.html'].is_mismatch_reftest = true;
235
    results.tests['bar-reftest-mismatch.html'].is_mismatch_reftest = true;
230
    runSingleRowTest(results, false, '', 'ref mismatch html actual ');
236
    runSingleRowTest(results, false, '', 'ref mismatch html actual ');
231
237
232
    results = mockResults();
238
    results = mockResults();
233
    results.tests['foo/bar-flaky-pass.html'] = mockExpectation('PASS FAIL', 'PASS');
239
    var subtree = results.tests['foo'] = {}
240
    subtree['bar-flaky-pass.html'] = mockExpectation('PASS FAIL', 'PASS');
234
    runTest(results, function() {
241
    runTest(results, function() {
235
        // FIXME: should a PASS FAIL test that passes go in the unexpected passes table?
242
        // FIXME: should a PASS FAIL test that passes go in the unexpected passes table?
236
        assertTrue(document.body.textContent.indexOf('foo/bar-flaky-pass.html') == -1);
243
        assertTrue(document.body.textContent.indexOf('foo/bar-flaky-pass.html') == -1);
237
    });
244
    });
238
245
239
    results = mockResults();
246
    results = mockResults();
240
    results.tests['foo/bar-really-long-path-that-should-probably-wrap-because-otherwise-the-table-will-be-too-wide.html'] = mockExpectation('PASS', 'TEXT');
247
    var subtree = results.tests['foo'] = {}
248
    subtree['bar-really-long-path-that-should-probably-wrap-because-otherwise-the-table-will-be-too-wide.html'] = mockExpectation('PASS', 'TEXT');
241
    runTest(results, function() {
249
    runTest(results, function() {
242
        document.body.style.width = '800px';
250
        document.body.style.width = '800px';
243
        var links = document.querySelectorAll('tbody a');
251
        var links = document.querySelectorAll('tbody a');
Lines 247-253 function runTests() a/LayoutTests/fast/harness/resources/results-test.js_sec6
247
    });
255
    });
248
256
249
    results = mockResults();
257
    results = mockResults();
250
    results.tests['foo/bar.html'] = mockExpectation('TEXT', 'TEXT');
258
    var subtree = results.tests['foo'] = {}
259
    subtree['bar.html'] = mockExpectation('TEXT', 'TEXT');
251
    results.uses_expectations_file = false;
260
    results.uses_expectations_file = false;
252
    runTest(results, function() {
261
    runTest(results, function() {
253
        assertTrue(document.querySelectorAll('tbody td').length == 4);
262
        assertTrue(document.querySelectorAll('tbody td').length == 4);
Lines 255-261 function runTests() a/LayoutTests/fast/harness/resources/results-test.js_sec7
255
    });
264
    });
256
265
257
    results = mockResults();
266
    results = mockResults();
258
    results.tests['foo/bar.html'] = mockExpectation('TEXT', 'TEXT');
267
    var subtree = results.tests['foo'] = {}
268
    subtree['bar.html'] = mockExpectation('TEXT', 'TEXT');
259
    results.has_pretty_patch = true;
269
    results.has_pretty_patch = true;
260
    runTest(results, function() {
270
    runTest(results, function() {
261
        assertTrue(document.querySelector('tbody td:nth-child(2)').textContent.indexOf('pretty diff') != -1);
271
        assertTrue(document.querySelector('tbody td:nth-child(2)').textContent.indexOf('pretty diff') != -1);
Lines 263-269 function runTests() a/LayoutTests/fast/harness/resources/results-test.js_sec8
263
    });
273
    });
264
274
265
    results = mockResults();
275
    results = mockResults();
266
    results.tests['foo/bar.html'] = mockExpectation('TEXT', 'TEXT');
276
    var subtree = results.tests['foo'] = {}
277
    subtree['bar.html'] = mockExpectation('TEXT', 'TEXT');
267
    results.has_wdiff = true;
278
    results.has_wdiff = true;
268
    runTest(results, function() {
279
    runTest(results, function() {
269
        assertTrue(document.querySelector('tbody td:nth-child(2)').textContent.indexOf('wdiff') != -1);
280
        assertTrue(document.querySelector('tbody td:nth-child(2)').textContent.indexOf('wdiff') != -1);
Lines 271-281 function runTests() a/LayoutTests/fast/harness/resources/results-test.js_sec9
271
    });
282
    });
272
    
283
    
273
    results = mockResults();
284
    results = mockResults();
274
    results.tests['foo/bar.html'] = mockExpectation('TEXT', 'PASS');
285
    var subtree = results.tests['foo'] = {}
275
    results.tests['foo/bar-1.html'] = mockExpectation('TEXT', 'CRASH');
286
    subtree['bar.html'] = mockExpectation('TEXT', 'PASS');
276
    results.tests['foo/bar-5.html'] = mockExpectation('TEXT', 'IMAGE+TEXT');
287
    subtree['bar-1.html'] = mockExpectation('TEXT', 'CRASH');
277
    results.tests['foo/bar-3.html'] = mockExpectation('PASS', 'TEXT');
288
    subtree['bar-5.html'] = mockExpectation('TEXT', 'IMAGE+TEXT');
278
    results.tests['foo/bar-2.html'] = mockExpectation('PASS', 'IMAGE');
289
    subtree['bar-3.html'] = mockExpectation('PASS', 'TEXT');
290
    subtree['bar-2.html'] = mockExpectation('PASS', 'IMAGE');
279
    runTest(results, function() {
291
    runTest(results, function() {
280
        // FIXME: This just ensures we don't get a JS error.
292
        // FIXME: This just ensures we don't get a JS error.
281
        // Verify that the sort is correct and that inline expanded expectations
293
        // Verify that the sort is correct and that inline expanded expectations
Lines 295-301 function runTests() a/LayoutTests/fast/harness/resources/results-test.js_sec10
295
    });
307
    });
296
308
297
    results = mockResults();
309
    results = mockResults();
298
    results.tests['foo/bar-5.html'] = mockExpectation('TEXT', 'IMAGE+TEXT');
310
    var subtree = results.tests['foo'] = {}
311
    subtree['bar-5.html'] = mockExpectation('TEXT', 'IMAGE+TEXT');
299
    runTest(results, function() {
312
    runTest(results, function() {
300
        expandAllExpectations();
313
        expandAllExpectations();
301
        var png = document.querySelector('[src*="bar-5-expected.png"]');
314
        var png = document.querySelector('[src*="bar-5-expected.png"]');
Lines 313-336 function runTests() a/LayoutTests/fast/harness/resources/results-test.js_sec11
313
    });
326
    });
314
    
327
    
315
    results = mockResults();
328
    results = mockResults();
316
    results.tests['fullscreen/full-screen-api.html'] = mockExpectation('TEXT', 'IMAGE+TEXT');
329
    var subtree = results.tests['fullscreen'] = {}
330
    subtree['full-screen-api.html'] = mockExpectation('TEXT', 'IMAGE+TEXT');
317
    runTest(results, function() {
331
    runTest(results, function() {
318
        var expectedHref = 'file://' + results.layout_tests_dir + '/fullscreen/full-screen-api.html';
332
        var expectedHref = 'file://' + results.layout_tests_dir + '/fullscreen/full-screen-api.html';
319
        assertTrue(document.querySelector('tbody td:first-child a').href == expectedHref);
333
        assertTrue(document.querySelector('tbody td:first-child a').href == expectedHref);
320
    });
334
    });
321
    
335
322
    var oldShouldUseTracLinks = shouldUseTracLinks;
336
    var oldShouldUseTracLinks = shouldUseTracLinks;
323
    shouldUseTracLinks = function() { return true; };
337
    shouldUseTracLinks = function() { return true; };
324
    
338
    
325
    results = mockResults();
339
    results = mockResults();
326
    results.tests['fullscreen/full-screen-api.html'] = mockExpectation('TEXT', 'IMAGE+TEXT');
340
    var subtree = results.tests['fullscreen'] = {}
341
    subtree['full-screen-api.html'] = mockExpectation('TEXT', 'IMAGE+TEXT');
327
    runTest(results, function() {
342
    runTest(results, function() {
328
        var expectedHref = 'http://trac.webkit.org/export/' + results.revision + '/trunk/LayoutTests/fullscreen/full-screen-api.html';
343
        var expectedHref = 'http://trac.webkit.org/export/' + results.revision + '/trunk/LayoutTests/fullscreen/full-screen-api.html';
329
        assertTrue(document.querySelector('tbody td:first-child a').href == expectedHref);
344
        assertTrue(document.querySelector('tbody td:first-child a').href == expectedHref);
330
    });
345
    });
331
346
332
    results = mockResults();
347
    results = mockResults();
333
    results.tests['fullscreen/full-screen-api.html'] = mockExpectation('TEXT', 'IMAGE+TEXT');
348
    var subtree = results.tests['fullscreen'] = {}
349
    subtree['full-screen-api.html'] = mockExpectation('TEXT', 'IMAGE+TEXT');
334
    results.revision = '';
350
    results.revision = '';
335
    runTest(results, function() {
351
    runTest(results, function() {
336
        var expectedHref = 'http://trac.webkit.org/browser/trunk/LayoutTests/fullscreen/full-screen-api.html';
352
        var expectedHref = 'http://trac.webkit.org/browser/trunk/LayoutTests/fullscreen/full-screen-api.html';
- a/LayoutTests/fast/harness/results.html -70 / +116 lines
Lines 289-376 function resultLink(testPrefix, suffix, contents) a/LayoutTests/fast/harness/results.html_sec1
289
    return '<a class=result-link href="' + testPrefix + suffix + '">' + contents + '</a> ';
289
    return '<a class=result-link href="' + testPrefix + suffix + '">' + contents + '</a> ';
290
}
290
}
291
291
292
function tableRows()
292
function testObjectFor(test)
293
{
293
{
294
    var html = '';
294
    var parts = test.split('/');
295
    for (var test in globalState().results.tests) {
295
    var tree = globalState().results.tests;
296
        if (globalState().results.tests[test].has_stderr)
296
    for (var i = 0; i < parts.length; i++) {
297
            globalState().testsWithStderr.push(test);
297
        if (parts[i] in tree)
298
298
            tree = tree[parts[i]];
299
        globalState().hasHttpTests = globalState().hasHttpTests || test.indexOf('http/') == 0;
299
        else {
300
300
            console.error('Test not in the results tree: ' + test);
301
        var actual = globalState().results.tests[test].actual;
301
            return null;
302
        if (actual == 'MISSING') {
303
            // FIXME: make sure that new-run-webkit-tests spits out an -actual.txt file for
304
            // tests with MISSING results.
305
            globalState().newTests.push(test);
306
            continue;
307
        }
302
        }
303
    }
304
    return tree;
305
}
308
306
309
        var expected = globalState().results.tests[test].expected || 'PASS';
307
function processGlobalStateFor(testObject)
310
        var isExpected = actual == 'SKIP';
308
{
311
        if (!isExpected && globalState().results.uses_expectations_file) {
309
    var test = testObject.name;
312
            var expectedArray = expected.split(' ');
310
    if (testObject.has_stderr)
313
            if (expectedArray.indexOf(actual) != -1)
311
        globalState().testsWithStderr.push(test);
314
                isExpected = true;
315
            else if (expectedArray.indexOf('FAIL') != -1)
316
                isExpected = actual == 'IMAGE' || actual == 'TEXT' || actual == 'IMAGE+TEXT';
317
        }
318
312
319
        if (actual == 'PASS') {
313
    globalState().hasHttpTests = globalState().hasHttpTests || test.indexOf('http/') == 0;
320
            if (!isExpected && expected != 'PASS')
321
                globalState().unexpectedPassTests.push(test);            
322
            continue;
323
        }
324
314
325
        var row = '<td>' + testLink(test) + '</td>';
315
    var actual = testObject.actual;
326
        var test_prefix = stripExtension(test);
316
    if (actual == 'MISSING') {
327
317
        // FIXME: make sure that new-run-webkit-tests spits out an -actual.txt file for
328
        row += '<td>';
318
        // tests with MISSING results.
329
        if (actual == 'CRASH')
319
        globalState().newTests.push(test);
330
            row += resultLink(test_prefix, '-stack.txt', 'stack');
320
        return;
331
        else if (actual == 'AUDIO') {
321
    }
332
            row += resultLink(test_prefix, '-expected.wav', 'expected');
333
            row += resultLink(test_prefix, '-actual.wav', 'actual');
334
        } else if (actual.indexOf('TEXT') != -1 || actual == 'TIMEOUT') {
335
            // FIXME: only include timeout actual/expected results here if we actually spit out results for timeout tests.
336
            globalState().hasTextFailures = true;
337
            row += resultLink(test_prefix, '-expected.txt', 'expected') +
338
                resultLink(test_prefix, '-actual.txt', 'actual') +
339
                resultLink(test_prefix, '-diff.txt', 'diff');
340
      
341
            if (globalState().results.has_pretty_patch)
342
                row += resultLink(test_prefix, '-pretty-diff.html', 'pretty diff');
343
344
            if (globalState().results.has_wdiff)
345
                row += resultLink(test_prefix, '-wdiff.html', 'wdiff');
346
        }
347
322
348
        row += '</td><td>';
323
    var expected = testObject.expected || 'PASS';
324
    testObject.isExpected = actual == 'SKIP';
325
    if (!testObject.isExpected && globalState().results.uses_expectations_file) {
326
        var expectedArray = expected.split(' ');
327
        if (expectedArray.indexOf(actual) != -1)
328
            testObject.isExpected = true;
329
        else if (expectedArray.indexOf('FAIL') != -1)
330
            testObject.isExpected = actual == 'IMAGE' || actual == 'TEXT' || actual == 'IMAGE+TEXT';
331
    }
349
332
350
        if (actual.indexOf('IMAGE') != -1) {
333
    if (actual == 'PASS' && expected != 'PASS' && !testObject.isExpected)
351
            globalState().hasImageFailures = true;
334
        globalState().unexpectedPassTests.push(test);            
335
}
336
337
function tableRow(testObject)
338
{    
339
    var actual = testObject.actual;
340
    if (actual == 'PASS')
341
        return '';
342
343
    var row = '<td>' + testLink(testObject.name) + '</td>';
344
    var test_prefix = stripExtension(testObject.name);
345
346
    row += '<td>';
347
348
    if (actual == 'CRASH')
349
        row += resultLink(test_prefix, '-stack.txt', 'stack');
350
    else if (actual == 'AUDIO') {
351
        row += resultLink(test_prefix, '-expected.wav', 'expected');
352
        row += resultLink(test_prefix, '-actual.wav', 'actual');
353
    } else if (actual.indexOf('TEXT') != -1 || actual == 'TIMEOUT') {
354
        // FIXME: only include timeout actual/expected results here if we actually spit out results for timeout tests.
355
        globalState().hasTextFailures = true;
356
        row += resultLink(test_prefix, '-expected.txt', 'expected') +
357
            resultLink(test_prefix, '-actual.txt', 'actual') +
358
            resultLink(test_prefix, '-diff.txt', 'diff');
359
  
360
        if (globalState().results.has_pretty_patch)
361
            row += resultLink(test_prefix, '-pretty-diff.html', 'pretty diff');
362
363
        if (globalState().results.has_wdiff)
364
            row += resultLink(test_prefix, '-wdiff.html', 'wdiff');
365
    }
366
367
    row += '</td><td>';
352
368
353
            if (globalState().results.tests[test].is_mismatch_reftest) {
369
    if (actual.indexOf('IMAGE') != -1) {
354
                row += resultLink(test_prefix, '-expected-mismatch.html', 'ref mismatch html') +
370
        globalState().hasImageFailures = true;
355
                    resultLink(test_prefix, '-actual.png', 'actual');
356
            } else {
357
                if (globalState().results.tests[test].is_reftest)
358
                    row += resultLink(test_prefix, '-expected.html', 'ref html');
359
371
360
                row += resultLink(test_prefix, '-expected.png', 'expected') +
372
        if (testObject.is_mismatch_reftest) {
361
                    resultLink(test_prefix, '-actual.png', 'actual') +
373
            row += resultLink(test_prefix, '-expected-mismatch.html', 'ref mismatch html') +
362
                    resultLink(test_prefix, '-diff.png', 'diff');
374
                resultLink(test_prefix, '-actual.png', 'actual');
363
            }
375
        } else {
376
            if (testObject.is_reftest)
377
                row += resultLink(test_prefix, '-expected.html', 'ref html');
378
379
            row += resultLink(test_prefix, '-expected.png', 'expected') +
380
                resultLink(test_prefix, '-actual.png', 'actual') +
381
                resultLink(test_prefix, '-diff.png', 'diff');
364
        }
382
        }
383
    }
365
384
366
        row += '</td>';
385
    row += '</td>';
367
        row += '<td>' + actual + '</td>';
386
    row += '<td>' + actual + '</td>';
368
387
369
        if (globalState().results.uses_expectations_file)
388
    if (globalState().results.uses_expectations_file)
370
          row += '<td>' + expected + '</td>';
389
      row += '<td>' + testObject.expected + '</td>';
371
390
372
        html += '<tbody class="' + (isExpected ? 'expected' : '') + '"><tr>' + row + '</tr></tbody>';
391
    return '<tbody class="' + (testObject.isExpected ? 'expected' : '') + '"><tr>' + row + '</tr></tbody>';
392
}
393
394
function forEachTest(handler, opt_tree, opt_prefix)
395
{
396
    var tree = opt_tree || globalState().results.tests;
397
    var prefix = opt_prefix || '';
398
399
    for (var key in tree) {
400
        var newPrefix = prefix ? (prefix + '/' + key) : key;
401
        if ('actual' in tree[key]) {
402
            var testObject = tree[key];
403
            testObject.name = newPrefix;
404
            handler(testObject);
405
        } else
406
            forEachTest(handler, tree[key], newPrefix);
373
    }
407
    }
408
}
409
410
function tableRows()
411
{
412
    var html = '';
413
    forEachTest(function(testObject) {
414
        processGlobalStateFor(testObject)
415
        var test = testObject.name;
416
        if (globalState().unexpectedPassTests.indexOf(test) == -1 &&
417
            globalState().newTests.indexOf(test) == -1)
418
            html += tableRow(testObject);
419
    });
374
    return html;
420
    return html;
375
}
421
}
376
422
Lines 390-398 function testList(tests, header, tableId) a/LayoutTests/fast/harness/results.html_sec2
390
        if (tableId == 'stderr-table')
436
        if (tableId == 'stderr-table')
391
            html += resultLink(stripExtension(test), '-stderr.txt', 'stderr');
437
            html += resultLink(stripExtension(test), '-stderr.txt', 'stderr');
392
        else if (tableId == 'passes-table')
438
        else if (tableId == 'passes-table')
393
            html += globalState().results.tests[test].expected;
439
            html += testObjectFor(test).expected;
394
        else if (tableId == 'new-tests-table') {
440
        else if (tableId == 'new-tests-table') {
395
            var testObject = globalState().results.tests[test];
441
            var testObject = testObjectFor(test);
396
            if (testObject.is_missing_audio)
442
            if (testObject.is_missing_audio)
397
                html += resultLink(stripExtension(test), '-actual.wav', 'audio result');
443
                html += resultLink(stripExtension(test), '-actual.wav', 'audio result');
398
            if (testObject.is_missing_text)
444
            if (testObject.is_missing_text)
- a/Tools/ChangeLog +31 lines
Lines 1-3 a/Tools/ChangeLog_sec1
1
2011-04-28  Ojan Vafai  <ojan@chromium.org>
2
3
        Reviewed by NOBODY (OOPS!).
4
5
        use a hierarchical data structure to store results json
6
        https://bugs.webkit.org/show_bug.cgi?id=59736
7
8
        Instead of a map from test name to results dict, we now store a hierarchical
9
        data structure.
10
11
        Old: { foo/bar/baz.html: results_dict, foo/bar/baz2.html: results_dict }
12
        New:
13
        { foo: {
14
            bar: {
15
              baz.html: results_dict,
16
              baz2.html: results_dict } } }
17
18
        This cut ~52% of the size of times_ms.json. I expect it will cut
19
        30-40% of full_results.json and unexpected_results.json.
20
21
        * Scripts/webkitpy/common/net/resultsjsonparser.py:
22
        * Scripts/webkitpy/common/net/resultsjsonparser_unittest.py:
23
        * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py:
24
        Using os.sep was just wrong since relative_test_filename canonicalizes separators.
25
        * Scripts/webkitpy/layout_tests/layout_package/manager.py:
26
        * Scripts/webkitpy/layout_tests/layout_package/printing.py:
27
        * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
28
        * Scripts/webkitpy/tool/commands/rebaselineserver.py:
29
        Instead of plumbing through the change to all of the rebaselineserver
30
        python and JS, just convert to the old format after reading in the json.
31
1
2011-04-28  Eric Seidel  <eric@webkit.org>
32
2011-04-28  Eric Seidel  <eric@webkit.org>
2
33
3
        Reviewed by Adam Barth.
34
        Reviewed by Adam Barth.
- a/Tools/Scripts/webkitpy/common/net/resultsjsonparser.py -1 / +20 lines
Lines 37-42 except ImportError: a/Tools/Scripts/webkitpy/common/net/resultsjsonparser.py_sec1
37
from webkitpy.layout_tests.layout_package import json_results_generator, test_expectations, test_results, test_failures
37
from webkitpy.layout_tests.layout_package import json_results_generator, test_expectations, test_results, test_failures
38
38
39
39
40
# These are helper functions for navigating the results json structure.
41
def for_each_test(tree, handler, prefix=''):
42
    for key in tree:
43
        new_prefix = (prefix + '/' + key) if prefix else key
44
        if 'actual' not in tree[key]:
45
            for_each_test(tree[key], handler, new_prefix)
46
        else:
47
            handler(new_prefix, tree[key])
48
49
50
def result_for_test(tree, test):
51
    parts = test.split('/')
52
    for part in parts:
53
        tree = tree[part]
54
    return tree
55
56
40
# Wrapper around the dictionaries returned from the json.
57
# Wrapper around the dictionaries returned from the json.
41
# Eventually the .json should just serialize the TestFailure objects
58
# Eventually the .json should just serialize the TestFailure objects
42
# directly and we won't need this.
59
# directly and we won't need this.
Lines 96-102 class ResultsJSONParser(object): a/Tools/Scripts/webkitpy/common/net/resultsjsonparser.py_sec2
96
        content_string = json_results_generator.strip_json_wrapper(json_string)
113
        content_string = json_results_generator.strip_json_wrapper(json_string)
97
        json_dict = json.loads(content_string)
114
        json_dict = json.loads(content_string)
98
115
99
        json_results = [JSONTestResult(test_name, results_dict) for test_name, results_dict in json_dict['tests'].items()]
116
        json_results = []
117
        for_each_test(json_dict['tests'], lambda test, result: json_results.append(JSONTestResult(test, result)))
118
100
        # FIXME: What's the short sexy python way to filter None?
119
        # FIXME: What's the short sexy python way to filter None?
101
        # I would use [foo.bar() for foo in foos if foo.bar()] but bar() is expensive.
120
        # I would use [foo.bar() for foo in foos if foo.bar()] but bar() is expensive.
102
        non_passing_results = [result.test_result() for result in json_results if not result.did_pass()]
121
        non_passing_results = [result.test_result() for result in json_results if not result.did_pass()]
- a/Tools/Scripts/webkitpy/common/net/resultsjsonparser_unittest.py -8 / +16 lines
Lines 37-56 class ResultsJSONParserTest(unittest.TestCase): a/Tools/Scripts/webkitpy/common/net/resultsjsonparser_unittest.py_sec1
37
    # The real files have no whitespace, but newlines make this much more readable.
37
    # The real files have no whitespace, but newlines make this much more readable.
38
    _example_unexpected_results_json = """ADD_RESULTS({
38
    _example_unexpected_results_json = """ADD_RESULTS({
39
    "tests": {
39
    "tests": {
40
        "fast\/dom\/prototype-inheritance.html": {
40
        "fast": {
41
            "expected": "PASS",
41
            "dom": {
42
            "actual": "TEXT"
42
                "prototype-inheritance.html": {
43
                    "expected": "PASS",
44
                    "actual": "TEXT"
45
                }
46
            }
43
        },
47
        },
44
        "svg\/dynamic-updates\/SVGFEDropShadowElement-dom-stdDeviation-attr.html": {
48
        "svg": {
45
            "expected": "PASS",
49
            "dynamic-updates": {
46
            "actual": "IMAGE",
50
                "SVGFEDropShadowElement-dom-stdDeviation-attr.html": {
47
            "has_stderr": true
51
                    "expected": "PASS",
52
                    "actual": "IMAGE",
53
                    "has_stderr": true
54
                }
55
            }
48
        }
56
        }
49
    },
57
    },
50
    "skipped": 450,
58
    "skipped": 450,
51
    "num_regressions": 15,
59
    "num_regressions": 15,
52
    "layout_tests_dir": "\/b\/build\/slave\/Webkit_Mac10_5\/build\/src\/third_party\/WebKit\/LayoutTests",
60
    "layout_tests_dir": "\/b\/build\/slave\/Webkit_Mac10_5\/build\/src\/third_party\/WebKit\/LayoutTests",
53
    "version": 1,
61
    "version": 3,
54
    "num_passes": 77,
62
    "num_passes": 77,
55
    "has_pretty_patch": false,
63
    "has_pretty_patch": false,
56
    "fixable": 1220,
64
    "fixable": 1220,
- a/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py -1 / +1 lines
Lines 88-94 def test_timings_trie(port, individual_test_timings): a/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py_sec1
88
            # FIXME: Handle this better. Non-layout tests shouldn't be relativized.
88
            # FIXME: Handle this better. Non-layout tests shouldn't be relativized.
89
            test = test_result.filename
89
            test = test_result.filename
90
90
91
        parts = test.split(os.sep)
91
        parts = test.split('/')
92
        current_map = trie
92
        current_map = trie
93
        for i, part in enumerate(parts):
93
        for i, part in enumerate(parts):
94
            if i == (len(parts) - 1):
94
            if i == (len(parts) - 1):
- a/Tools/Scripts/webkitpy/layout_tests/layout_package/manager.py -2 / +21 lines
Lines 96-102 def summarize_results(port_obj, expectations, result_summary, retry_summary, tes a/Tools/Scripts/webkitpy/layout_tests/layout_package/manager.py_sec1
96
        'tests': a dict of tests -> {'expected': '...', 'actual': '...'}
96
        'tests': a dict of tests -> {'expected': '...', 'actual': '...'}
97
    """
97
    """
98
    results = {}
98
    results = {}
99
    results['version'] = 2
99
    results['version'] = 3
100
100
101
    tbe = result_summary.tests_by_expectation
101
    tbe = result_summary.tests_by_expectation
102
    tbt = result_summary.tests_by_timeline
102
    tbt = result_summary.tests_by_timeline
Lines 177-183 def summarize_results(port_obj, expectations, result_summary, retry_summary, tes a/Tools/Scripts/webkitpy/layout_tests/layout_package/manager.py_sec2
177
        if test_failures.FailureMissingImage in failure_types or test_failures.FailureMissingImageHash in failure_types:
177
        if test_failures.FailureMissingImage in failure_types or test_failures.FailureMissingImageHash in failure_types:
178
            test_dict['is_missing_image'] = True
178
            test_dict['is_missing_image'] = True
179
179
180
        tests[test] = test_dict
180
        # Store test hierarchically by directory. e.g.
181
        # foo/bar/baz.html: test_dict
182
        # foo/bar/baz1.html: test_dict
183
        #
184
        # becomes
185
        # foo: {
186
        #     bar: {
187
        #         baz.html: test_dict,
188
        #         baz1.html: test_dict
189
        #     }
190
        # }
191
        parts = test.split('/')
192
        current_map = tests
193
        for i, part in enumerate(parts):
194
            if i == (len(parts) - 1):
195
                current_map[part] = test_dict
196
                break
197
            if part not in current_map:
198
                current_map[part] = {}
199
            current_map = current_map[part]
181
200
182
    results['tests'] = tests
201
    results['tests'] = tests
183
    results['num_passes'] = num_passes
202
    results['num_passes'] = num_passes
- a/Tools/Scripts/webkitpy/layout_tests/layout_package/printing.py -2 / +5 lines
Lines 32-37 a/Tools/Scripts/webkitpy/layout_tests/layout_package/printing.py_sec1
32
import logging
32
import logging
33
import optparse
33
import optparse
34
34
35
from webkitpy.common.net import resultsjsonparser
35
from webkitpy.layout_tests.layout_package import metered_stream
36
from webkitpy.layout_tests.layout_package import metered_stream
36
from webkitpy.layout_tests.layout_package import test_expectations
37
from webkitpy.layout_tests.layout_package import test_expectations
37
38
Lines 454-460 class Printer(object): a/Tools/Scripts/webkitpy/layout_tests/layout_package/printing.py_sec2
454
        flaky = {}
455
        flaky = {}
455
        regressions = {}
456
        regressions = {}
456
457
457
        for test, results in unexpected_results['tests'].iteritems():
458
        def add_result(test, results):
458
            actual = results['actual'].split(" ")
459
            actual = results['actual'].split(" ")
459
            expected = results['expected'].split(" ")
460
            expected = results['expected'].split(" ")
460
            if actual == ['PASS']:
461
            if actual == ['PASS']:
Lines 476-481 class Printer(object): a/Tools/Scripts/webkitpy/layout_tests/layout_package/printing.py_sec3
476
            else:
477
            else:
477
                _add_to_dict_of_lists(regressions, results['actual'], test)
478
                _add_to_dict_of_lists(regressions, results['actual'], test)
478
479
480
        resultsjsonparser.for_each_test(unexpected_results['tests'], add_result)
481
479
        if len(passes) or len(flaky) or len(regressions):
482
        if len(passes) or len(flaky) or len(regressions):
480
            self._buildbot_stream.write("\n")
483
            self._buildbot_stream.write("\n")
481
484
Lines 497-503 class Printer(object): a/Tools/Scripts/webkitpy/layout_tests/layout_package/printing.py_sec4
497
                tests.sort()
500
                tests.sort()
498
501
499
                for test in tests:
502
                for test in tests:
500
                    result = unexpected_results['tests'][test]
503
                    result = resultsjsonparser.result_for_test(unexpected_results['tests'], test)
501
                    actual = result['actual'].split(" ")
504
                    actual = result['actual'].split(" ")
502
                    expected = result['expected'].split(" ")
505
                    expected = result['expected'].split(" ")
503
                    result = TestExpectationsFile.EXPECTATIONS[key.lower()]
506
                    result = TestExpectationsFile.EXPECTATIONS[key.lower()]
- a/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py -1 / +2 lines
Lines 38-43 import os a/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py_sec1
38
import signal
38
import signal
39
import sys
39
import sys
40
40
41
from webkitpy.common.net import resultsjsonparser
41
from webkitpy.layout_tests import layout_package
42
from webkitpy.layout_tests import layout_package
42
from webkitpy.layout_tests.layout_package import json_results_generator
43
from webkitpy.layout_tests.layout_package import json_results_generator
43
from webkitpy.layout_tests.layout_package import printing
44
from webkitpy.layout_tests.layout_package import printing
Lines 179-185 def _gather_unexpected_results(port): a/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py_sec2
179
        unexpected_results_filename = filesystem.join(results_directory, "unexpected_results.json")
180
        unexpected_results_filename = filesystem.join(results_directory, "unexpected_results.json")
180
        if filesystem.exists(unexpected_results_filename):
181
        if filesystem.exists(unexpected_results_filename):
181
            results = json_results_generator.load_json(filesystem, unexpected_results_filename)
182
            results = json_results_generator.load_json(filesystem, unexpected_results_filename)
182
            last_unexpected_results = results['tests'].keys()
183
            resultsjsonparser.for_each_test(results['tests'], lambda test, result: last_unexpected_results.append(test))
183
    return last_unexpected_results
184
    return last_unexpected_results
184
185
185
186
- a/Tools/Scripts/webkitpy/tool/commands/rebaselineserver.py -4 / +13 lines
Lines 47-52 from optparse import make_option a/Tools/Scripts/webkitpy/tool/commands/rebaselineserver.py_sec1
47
from wsgiref.handlers import format_date_time
47
from wsgiref.handlers import format_date_time
48
48
49
from webkitpy.common import system
49
from webkitpy.common import system
50
from webkitpy.common.net import resultsjsonparser
50
from webkitpy.layout_tests.layout_package import json_results_generator
51
from webkitpy.layout_tests.layout_package import json_results_generator
51
from webkitpy.layout_tests.port import factory
52
from webkitpy.layout_tests.port import factory
52
from webkitpy.layout_tests.port.webkit import WebKitPort
53
from webkitpy.layout_tests.port.webkit import WebKitPort
Lines 431-440 class RebaselineServer(AbstractDeclarativeCommand): a/Tools/Scripts/webkitpy/tool/commands/rebaselineserver.py_sec2
431
            scm)
432
            scm)
432
433
433
        print 'Gathering current baselines...'
434
        print 'Gathering current baselines...'
434
        for test_file, test_json in results_json['tests'].items():
435
        # Rebaseline server and it's associated JavaScript expected the tests subtree to
435
            test_json['state'] = STATE_NEEDS_REBASELINE
436
        # be key-value pairs instead of hierarchical.
436
            test_path = filesystem.join(layout_tests_directory, test_file)
437
        # FIXME: make the rebaseline server use the hierarchical tree.
437
            test_json['baselines'] = _get_test_baselines(test_file, test_config)
438
        new_tests_subtree = {}
439
440
        def gather_baselines(test, result):
441
            result['state'] = STATE_NEEDS_REBASELINE
442
            result['baselines'] = _get_test_baselines(test, test_config)
443
            new_tests_subtree[test] = result
444
445
        resultsjsonparser.for_each_test(results_json['tests'], gather_baselines)
446
        results_json['tests'] = new_tests_subtree
438
447
439
        server_url = "http://localhost:%d/" % options.httpd_port
448
        server_url = "http://localhost:%d/" % options.httpd_port
440
        print "Starting server at %s" % server_url
449
        print "Starting server at %s" % server_url

Return to Bug 59736