Make a builder group support+expect multiple loads.
[WebKit-https.git] / Tools / TestResultServer / static-dashboards / flakiness_dashboard_unittests.js
1 // Copyright (C) 2011 Google Inc. All rights reserved.
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are
5 // met:
6 //
7 //     * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 //     * Redistributions in binary form must reproduce the above
10 // copyright notice, this list of conditions and the following disclaimer
11 // in the documentation and/or other materials provided with the
12 // distribution.
13 //     * Neither the name of Google Inc. nor the names of its
14 // contributors may be used to endorse or promote products derived from
15 // this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 function resetGlobals()
30 {
31     allExpectations = null;
32     allTests = null;
33     g_expectations = '';
34     g_resultsByBuilder = {};
35     g_builders = {};
36     g_allExpectations = null;
37     g_allTests = null;
38     g_currentState = {};
39     g_crossDashboardState = {};
40     for (var key in g_defaultCrossDashboardStateValues)
41         g_crossDashboardState[key] = g_defaultCrossDashboardStateValues[key];
42 }
43
44 function runExpectationsTest(builder, test, expectations, modifiers)
45 {
46     g_builders[builder] = true;
47
48     // Put in some dummy results. processExpectations expects the test to be
49     // there.
50     var tests = {};
51     tests[test] = {'results': [[100, 'F']], 'times': [[100, 0]]};
52     g_resultsByBuilder[builder] = {'tests': tests};
53
54     processExpectations();
55     var resultsForTest = createResultsObjectForTest(test, builder);
56     populateExpectationsData(resultsForTest);
57
58     var message = 'Builder: ' + resultsForTest.builder + ' test: ' + resultsForTest.test;
59     equal(resultsForTest.expectations, expectations, message);
60     equal(resultsForTest.modifiers, modifiers, message);
61 }
62
63 test('flattenTrie', 1, function() {
64     resetGlobals();
65     var tests = {
66         'bar.html': {'results': [[100, 'F']], 'times': [[100, 0]]},
67         'foo': {
68             'bar': {
69                 'baz.html': {'results': [[100, 'F']], 'times': [[100, 0]]},
70             }
71         }
72     };
73     var expectedFlattenedTests = {
74         'bar.html': {'results': [[100, 'F']], 'times': [[100, 0]]},
75         'foo/bar/baz.html': {'results': [[100, 'F']], 'times': [[100, 0]]},
76     };
77     equal(JSON.stringify(flattenTrie(tests)), JSON.stringify(expectedFlattenedTests))
78 });
79
80 test('releaseFail', 2, function() {
81     resetGlobals();
82     var builder = 'Webkit Win';
83     var test = 'foo/1.html';
84     var expectationsArray = [
85         {'modifiers': 'RELEASE', 'expectations': 'FAIL'}
86     ];
87     g_expectations = 'RELEASE : ' + test + ' = FAIL';
88     runExpectationsTest(builder, test, 'FAIL', 'RELEASE');
89 });
90
91 test('releaseFailDebugCrashReleaseBuilder', 2, function() {
92     resetGlobals();
93     var builder = 'Webkit Win';
94     var test = 'foo/1.html';
95     var expectationsArray = [
96         {'modifiers': 'RELEASE', 'expectations': 'FAIL'},
97         {'modifiers': 'DEBUG', 'expectations': 'CRASH'}
98     ];
99     g_expectations = 'RELEASE : ' + test + ' = FAIL\n' +
100         'DEBUG : ' + test + ' = CRASH';
101     runExpectationsTest(builder, test, 'FAIL', 'RELEASE');
102 });
103
104 test('releaseFailDebugCrashDebugBuilder', 2, function() {
105     resetGlobals();
106     var builder = 'Webkit Win (dbg)';
107     var test = 'foo/1.html';
108     var expectationsArray = [
109         {'modifiers': 'RELEASE', 'expectations': 'FAIL'},
110         {'modifiers': 'DEBUG', 'expectations': 'CRASH'}
111     ];
112     g_expectations = 'RELEASE : ' + test + ' = FAIL\n' +
113         'DEBUG : ' + test + ' = CRASH';
114     runExpectationsTest(builder, test, 'CRASH', 'DEBUG');
115 });
116
117 test('overrideJustBuildType', 12, function() {
118     resetGlobals();
119     var test = 'bar/1.html';
120     g_expectations = 'WONTFIX : bar = FAIL PASS TIMEOUT\n' +
121         'WONTFIX MAC : ' + test + ' = FAIL\n' +
122         'LINUX DEBUG : ' + test + ' = CRASH';
123     
124     runExpectationsTest('Webkit Win', test, 'FAIL PASS TIMEOUT', 'WONTFIX');
125     runExpectationsTest('Webkit Win (dbg)(3)', test, 'FAIL PASS TIMEOUT', 'WONTFIX');
126     runExpectationsTest('Webkit Linux', test, 'FAIL PASS TIMEOUT', 'WONTFIX');
127     runExpectationsTest('Webkit Linux (dbg)(3)', test, 'CRASH', 'LINUX DEBUG');
128     runExpectationsTest('Webkit Mac10.5', test, 'FAIL', 'WONTFIX MAC');
129     runExpectationsTest('Webkit Mac10.5 (dbg)(3)', test, 'FAIL', 'WONTFIX MAC');
130 });
131
132 test('platformAndBuildType', 88, function() {
133     var runPlatformAndBuildTypeTest = function(builder, expectedPlatform, expectedBuildType) {
134         g_perBuilderPlatformAndBuildType = {};
135         buildInfo = platformAndBuildType(builder);
136         var message = 'Builder: ' + builder;
137         equal(buildInfo.platform, expectedPlatform, message);
138         equal(buildInfo.buildType, expectedBuildType, message);
139     }
140     runPlatformAndBuildTypeTest('Webkit Win (deps)', 'XP', 'RELEASE');
141     runPlatformAndBuildTypeTest('Webkit Win (deps)(dbg)(1)', 'XP', 'DEBUG');
142     runPlatformAndBuildTypeTest('Webkit Win (deps)(dbg)(2)', 'XP', 'DEBUG');
143     runPlatformAndBuildTypeTest('Webkit Linux (deps)', 'LUCID', 'RELEASE');
144     runPlatformAndBuildTypeTest('Webkit Linux (deps)(dbg)(1)', 'LUCID', 'DEBUG');
145     runPlatformAndBuildTypeTest('Webkit Linux (deps)(dbg)(2)', 'LUCID', 'DEBUG');
146     runPlatformAndBuildTypeTest('Webkit Mac10.6 (deps)', 'SNOWLEOPARD', 'RELEASE');
147     runPlatformAndBuildTypeTest('Webkit Mac10.6 (deps)(dbg)(1)', 'SNOWLEOPARD', 'DEBUG');
148     runPlatformAndBuildTypeTest('Webkit Mac10.6 (deps)(dbg)(2)', 'SNOWLEOPARD', 'DEBUG');
149     runPlatformAndBuildTypeTest('Webkit Win', 'XP', 'RELEASE');
150     runPlatformAndBuildTypeTest('Webkit Vista', 'VISTA', 'RELEASE');
151     runPlatformAndBuildTypeTest('Webkit Win7', 'WIN7', 'RELEASE');
152     runPlatformAndBuildTypeTest('Webkit Win (dbg)(1)', 'XP', 'DEBUG');
153     runPlatformAndBuildTypeTest('Webkit Win (dbg)(2)', 'XP', 'DEBUG');
154     runPlatformAndBuildTypeTest('Webkit Linux', 'LUCID', 'RELEASE');
155     runPlatformAndBuildTypeTest('Webkit Linux 32', 'LUCID', 'RELEASE');
156     runPlatformAndBuildTypeTest('Webkit Linux (dbg)(1)', 'LUCID', 'DEBUG');
157     runPlatformAndBuildTypeTest('Webkit Linux (dbg)(2)', 'LUCID', 'DEBUG');
158     runPlatformAndBuildTypeTest('Webkit Mac10.5', 'LEOPARD', 'RELEASE');
159     runPlatformAndBuildTypeTest('Webkit Mac10.5 (dbg)(1)', 'LEOPARD', 'DEBUG');
160     runPlatformAndBuildTypeTest('Webkit Mac10.5 (dbg)(2)', 'LEOPARD', 'DEBUG');
161     runPlatformAndBuildTypeTest('Webkit Mac10.6', 'SNOWLEOPARD', 'RELEASE');
162     runPlatformAndBuildTypeTest('Webkit Mac10.6 (dbg)', 'SNOWLEOPARD', 'DEBUG');
163     runPlatformAndBuildTypeTest('XP Tests', 'XP', 'RELEASE');
164     runPlatformAndBuildTypeTest('Interactive Tests (dbg)', 'XP', 'DEBUG');
165     
166     g_crossDashboardState.group = '@ToT - webkit.org';
167     g_crossDashboardState.testType = 'layout-tests';
168     runPlatformAndBuildTypeTest('Chromium Win Release (Tests)', 'XP', 'RELEASE');
169     runPlatformAndBuildTypeTest('Chromium Linux Release (Tests)', 'LUCID', 'RELEASE');
170     runPlatformAndBuildTypeTest('Chromium Mac Release (Tests)', 'SNOWLEOPARD', 'RELEASE');
171     
172     // FIXME: These platforms should match whatever we use in the TestExpectations format.
173     runPlatformAndBuildTypeTest('Lion Release (Tests)', 'APPLE_LION', 'RELEASE');
174     runPlatformAndBuildTypeTest('Lion Debug (Tests)', 'APPLE_LION', 'DEBUG');
175     runPlatformAndBuildTypeTest('Leopard Intel Release (Tests)', 'APPLE_LEOPARD', 'RELEASE');
176     runPlatformAndBuildTypeTest('Leopard Intel Debug (Tests)', 'APPLE_LEOPARD', 'DEBUG');
177     runPlatformAndBuildTypeTest('SnowLeopard Intel Release (Tests)', 'APPLE_SNOWLEOPARD', 'RELEASE');
178     runPlatformAndBuildTypeTest('SnowLeopard Intel Leaks', 'APPLE_SNOWLEOPARD', 'RELEASE');
179     runPlatformAndBuildTypeTest('SnowLeopard Intel Debug (Tests)', 'APPLE_SNOWLEOPARD', 'DEBUG');
180     runPlatformAndBuildTypeTest('GTK Linux 32-bit Release', 'GTK_LINUX', 'RELEASE');
181     runPlatformAndBuildTypeTest('GTK Linux 32-bit Debug', 'GTK_LINUX', 'DEBUG');
182     runPlatformAndBuildTypeTest('GTK Linux 64-bit Debug', 'GTK_LINUX', 'DEBUG');
183     runPlatformAndBuildTypeTest('Qt Linux Release', 'QT_LINUX', 'RELEASE');
184     runPlatformAndBuildTypeTest('Windows 7 Release (Tests)', 'APPLE_WIN7', 'RELEASE');
185     runPlatformAndBuildTypeTest('Windows XP Debug (Tests)', 'APPLE_XP', 'DEBUG');
186     
187     // FIXME: Should WebKit2 be it's own platform?
188     runPlatformAndBuildTypeTest('SnowLeopard Intel Release (WebKit2 Tests)', 'APPLE_SNOWLEOPARD', 'RELEASE');
189     runPlatformAndBuildTypeTest('SnowLeopard Intel Debug (WebKit2 Tests)', 'APPLE_SNOWLEOPARD', 'DEBUG');
190     runPlatformAndBuildTypeTest('Windows 7 Release (WebKit2 Tests)', 'APPLE_WIN7', 'RELEASE');    
191 });
192
193 test('realModifiers', 3, function() {
194     equal(realModifiers('BUGFOO LINUX LEOPARD WIN DEBUG SLOW'), 'SLOW');
195     equal(realModifiers('BUGFOO LUCID MAC XP RELEASE SKIP'), 'SKIP');
196     equal(realModifiers('BUGFOO'), '');
197 });
198
199 test('allTestsWithSamePlatformAndBuildType', 14, function() {
200     // FIXME: test that allTestsWithSamePlatformAndBuildType actually returns the right set of tests.
201     for (var i = 0; i < PLATFORMS.length; i++)
202         ok(g_allTestsByPlatformAndBuildType[PLATFORMS[i]]);
203 });
204
205 test('filterBugs',4, function() {
206     var filtered = filterBugs('SKIP BUG123 BUGCR123 BUGWK123 SLOW BUG_TONY DEBUG')
207     equal(filtered.modifiers, 'SKIP SLOW DEBUG');
208     equal(filtered.bugs, 'BUG123 BUGCR123 BUGWK123 BUG_TONY');
209
210     filtered = filterBugs('SKIP SLOW DEBUG')
211     equal(filtered.modifiers, 'SKIP SLOW DEBUG');
212     equal(filtered.bugs, '');
213 });
214
215 test('getExpectations', 12, function() {
216     resetGlobals();
217     g_builders['WebKit Win'] = true;
218     g_resultsByBuilder = {
219         'WebKit Win': {
220             'tests': {
221                 'foo/test1.html': {'results': [[100, 'F']], 'times': [[100, 0]]},
222                 'foo/test3.html': {'results': [[100, 'F']], 'times': [[100, 0]]},
223                 'test1.html': {'results': [[100, 'F']], 'times': [[100, 0]]}
224             }
225         }
226     }
227
228     g_expectations = 'BUG123 : foo = FAIL PASS CRASH\n' +
229         'RELEASE BUGFOO : foo/test1.html = FAIL\n' +
230         'DEBUG : foo/test1.html = CRASH\n' +
231         'BUG456 : foo/test2.html = FAIL\n' +
232         'LINUX DEBUG : foo/test2.html = CRASH\n' +
233         'RELEASE : test1.html = FAIL\n' +
234         'DEBUG : test1.html = CRASH\n' +
235         'WIN7 : http/tests/appcache/interrupted-update.html = TIMEOUT\n' +
236         'MAC LINUX XP VISTA : http/tests/appcache/interrupted-update.html = FAIL\n';
237
238     processExpectations();
239     
240     var expectations = getExpectations('foo/test1.html', 'XP', 'DEBUG');
241     equal(JSON.stringify(expectations), '{"modifiers":"DEBUG","expectations":"CRASH"}');
242
243     var expectations = getExpectations('foo/test1.html', 'LUCID', 'RELEASE');
244     equal(JSON.stringify(expectations), '{"modifiers":"RELEASE BUGFOO","expectations":"FAIL"}');
245
246     var expectations = getExpectations('foo/test2.html', 'LUCID', 'RELEASE');
247     equal(JSON.stringify(expectations), '{"modifiers":"BUG456","expectations":"FAIL"}');
248
249     var expectations = getExpectations('foo/test2.html', 'LEOPARD', 'DEBUG');
250     equal(JSON.stringify(expectations), '{"modifiers":"BUG456","expectations":"FAIL"}');
251
252     var expectations = getExpectations('foo/test2.html', 'LUCID', 'DEBUG');
253     equal(JSON.stringify(expectations), '{"modifiers":"LINUX DEBUG","expectations":"CRASH"}');
254
255     var expectations = getExpectations('foo/test3.html', 'LUCID', 'DEBUG');
256     equal(JSON.stringify(expectations), '{"modifiers":"BUG123","expectations":"FAIL PASS CRASH"}');
257
258     var expectations = getExpectations('test1.html', 'XP', 'DEBUG');
259     equal(JSON.stringify(expectations), '{"modifiers":"DEBUG","expectations":"CRASH"}');
260
261     var expectations = getExpectations('test1.html', 'LUCID', 'RELEASE');
262     equal(JSON.stringify(expectations), '{"modifiers":"RELEASE","expectations":"FAIL"}');
263
264     var expectations = getExpectations('http/tests/appcache/interrupted-update.html', 'WIN7', 'RELEASE');
265     equal(JSON.stringify(expectations), '{"modifiers":"WIN7","expectations":"TIMEOUT"}');
266
267     var expectations = getExpectations('http/tests/appcache/interrupted-update.html', 'LEOPARD', 'RELEASE');
268     equal(JSON.stringify(expectations), '{"modifiers":"MAC LINUX XP VISTA","expectations":"FAIL"}');
269
270     var expectations = getExpectations('http/tests/appcache/interrupted-update.html', 'LUCID', 'RELEASE');
271     equal(JSON.stringify(expectations), '{"modifiers":"MAC LINUX XP VISTA","expectations":"FAIL"}');
272
273     var expectations = getExpectations('http/tests/appcache/interrupted-update.html', 'VISTA', 'RELEASE');
274     equal(JSON.stringify(expectations), '{"modifiers":"MAC LINUX XP VISTA","expectations":"FAIL"}');
275 });
276
277 test('substringList', 2, function() {
278     g_crossDashboardState.testType = 'gtest';
279     g_currentState.tests = 'test.FLAKY_foo test.FAILS_foo1 test.DISABLED_foo2 test.MAYBE_foo3 test.foo4';
280     equal(substringList().toString(), 'test.foo,test.foo1,test.foo2,test.foo3,test.foo4');
281
282     g_crossDashboardState.testType = 'layout-tests';
283     g_currentState.tests = 'foo/bar.FLAKY_foo.html';
284     equal(substringList().toString(), 'foo/bar.FLAKY_foo.html');
285 });
286
287 test('htmlForTestsWithExpectationsButNoFailures', 4, function() {
288     var builder = 'WebKit Win';
289     g_perBuilderWithExpectationsButNoFailures[builder] = ['passing-test1.html', 'passing-test2.html'];
290     g_perBuilderSkippedPaths[builder] = ['skipped-test1.html'];
291     g_resultsByBuilder[builder] = { buildNumbers: [5, 4, 3, 1] };
292
293     g_currentState.showUnexpectedPasses = true;
294     g_currentState.showSkipped = true;
295
296     g_crossDashboardState.group = '@ToT - chromium.org';
297     g_crossDashboardState.testType = 'layout-tests';
298     
299     var container = document.createElement('div');
300     container.innerHTML = htmlForTestsWithExpectationsButNoFailures(builder);
301     equal(container.querySelectorAll('#passing-tests > div').length, 2);
302     equal(container.querySelectorAll('#skipped-tests > div').length, 1);
303     
304     g_currentState.showUnexpectedPasses = false;
305     g_currentState.showSkipped = false;
306     
307     var container = document.createElement('div');
308     container.innerHTML = htmlForTestsWithExpectationsButNoFailures(builder);
309     equal(container.querySelectorAll('#passing-tests > div').length, 0);
310     equal(container.querySelectorAll('#skipped-tests > div').length, 0);
311 });
312
313 test('headerForTestTableHtml', 1, function() {
314     var container = document.createElement('div');
315     container.innerHTML = headerForTestTableHtml();
316     equal(container.querySelectorAll('input').length, 5);
317 });
318
319 test('htmlForTestTypeSwitcherGroup', 6, function() {
320     var container = document.createElement('div');
321     g_crossDashboardState.testType = 'ui_tests';
322     container.innerHTML = htmlForTestTypeSwitcher();
323     var selects = container.querySelectorAll('select');
324     equal(selects.length, 3);
325     var group = selects[2];
326     equal(group.parentNode.textContent.indexOf('Group:'), 0);
327     equal(group.children.length, 3);
328
329     g_crossDashboardState.testType = 'layout-tests';
330     container.innerHTML = htmlForTestTypeSwitcher();
331     var selects = container.querySelectorAll('select');
332     equal(selects.length, 3);
333     var group = selects[2];
334     equal(group.parentNode.textContent.indexOf('Group:'), 0);
335     equal(group.children.length, 3);
336 });
337
338 test('htmlForIndividualTestOnAllBuilders', 1, function() {
339     resetGlobals();
340     equal(htmlForIndividualTestOnAllBuilders('foo/nonexistant.html'), '<div class="not-found">Test not found. Either it does not exist, is skipped or passes on all platforms.</div>');
341 });
342
343 test('htmlForIndividualTestOnAllBuildersWithResultsLinksNonexistant', 1, function() {
344     resetGlobals();
345     equal(htmlForIndividualTestOnAllBuildersWithResultsLinks('foo/nonexistant.html'),
346         '<div class="not-found">Test not found. Either it does not exist, is skipped or passes on all platforms.</div>' +
347         '<div class=expectations test=foo/nonexistant.html>' +
348             '<div>' +
349                 '<span class=link onclick="setQueryParameter(\'showExpectations\', true)">Show results</span> | ' +
350                 '<span class=link onclick="setQueryParameter(\'showLargeExpectations\', true)">Show large thumbnails</span> | ' +
351                 '<b>Only shows actual results/diffs from the most recent *failure* on each bot.</b>' +
352             '</div>' +
353         '</div>');
354 });
355
356 test('htmlForIndividualTestOnAllBuildersWithResultsLinks', 1, function() {
357     resetGlobals();
358     var test = 'dummytest.html';
359     var builderName = 'dummyBuilder';
360     g_testToResultsMap[test] = [createResultsObjectForTest(test, builderName)];
361
362     equal(htmlForIndividualTestOnAllBuildersWithResultsLinks(test),
363         '<table class=test-table><thead><tr>' +
364                 '<th sortValue=test><div class=table-header-content><span></span><span class=header-text>test</span></div></th>' +
365                 '<th sortValue=bugs><div class=table-header-content><span></span><span class=header-text>bugs</span></div></th>' +
366                 '<th sortValue=modifiers><div class=table-header-content><span></span><span class=header-text>modifiers</span></div></th>' +
367                 '<th sortValue=expectations><div class=table-header-content><span></span><span class=header-text>expectations</span></div></th>' +
368                 '<th sortValue=slowest><div class=table-header-content><span></span><span class=header-text>slowest run</span></div></th>' +
369                 '<th sortValue=flakiness colspan=10000><div class=table-header-content><span></span><span class=header-text>flakiness (numbers are runtimes in seconds)</span></div></th>' +
370             '</tr></thead>' +
371             '<tbody></tbody>' +
372         '</table>' +
373         '<div>The following builders either don\'t run this test (e.g. it\'s skipped) or all runs passed:</div>' +
374         '<div class=skipped-builder-list>' +
375             '<div class=skipped-builder>Webkit Linux</div>' +
376             '<div class=skipped-builder>Webkit Linux (dbg)</div>' +
377             '<div class=skipped-builder>Webkit Mac10.5</div>' +
378             '<div class=skipped-builder>Webkit Win</div>' +
379         '</div>' +
380         '<div class=expectations test=dummytest.html>' +
381             '<div><span class=link onclick="setQueryParameter(\'showExpectations\', true)">Show results</span> | ' +
382             '<span class=link onclick="setQueryParameter(\'showLargeExpectations\', true)">Show large thumbnails</span> | ' +
383             '<b>Only shows actual results/diffs from the most recent *failure* on each bot.</b></div>' +
384         '</div>');
385 });
386
387 test('htmlForIndividualTestOnAllBuildersWithResultsLinksWebkitMaster', 1, function() {
388     resetGlobals();
389     var test = 'dummytest.html';
390     var builderName = 'dummyBuilder';
391     BUILDER_TO_MASTER[builderName] = WEBKIT_BUILDER_MASTER;
392     g_testToResultsMap[test] = [createResultsObjectForTest(test, builderName)];
393
394     equal(htmlForIndividualTestOnAllBuildersWithResultsLinks(test),
395         '<table class=test-table><thead><tr>' +
396                 '<th sortValue=test><div class=table-header-content><span></span><span class=header-text>test</span></div></th>' +
397                 '<th sortValue=bugs><div class=table-header-content><span></span><span class=header-text>bugs</span></div></th>' +
398                 '<th sortValue=modifiers><div class=table-header-content><span></span><span class=header-text>modifiers</span></div></th>' +
399                 '<th sortValue=expectations><div class=table-header-content><span></span><span class=header-text>expectations</span></div></th>' +
400                 '<th sortValue=slowest><div class=table-header-content><span></span><span class=header-text>slowest run</span></div></th>' +
401                 '<th sortValue=flakiness colspan=10000><div class=table-header-content><span></span><span class=header-text>flakiness (numbers are runtimes in seconds)</span></div></th>' +
402             '</tr></thead>' +
403             '<tbody></tbody>' +
404         '</table>' +
405         '<div>The following builders either don\'t run this test (e.g. it\'s skipped) or all runs passed:</div>' +
406         '<div class=skipped-builder-list>' +
407             '<div class=skipped-builder>Webkit Linux</div>' +
408             '<div class=skipped-builder>Webkit Linux (dbg)</div>' +
409             '<div class=skipped-builder>Webkit Mac10.5</div>' +
410             '<div class=skipped-builder>Webkit Win</div>' +
411         '</div>' +
412         '<div class=expectations test=dummytest.html>' +
413             '<div><span class=link onclick="setQueryParameter(\'showExpectations\', true)">Show results</span> | ' +
414             '<span class=link onclick="setQueryParameter(\'showLargeExpectations\', true)">Show large thumbnails</span>' +
415             '<form onsubmit="setQueryParameter(\'revision\', revision.value);return false;">' +
416                 'Show results for WebKit revision: <input name=revision placeholder="e.g. 65540" value="" id=revision-input>' +
417             '</form></div>' +
418         '</div>');
419 });
420
421 test('htmlForIndividualTests', 4, function() {
422     resetGlobals();
423     var test1 = 'foo/nonexistant.html';
424     var test2 = 'bar/nonexistant.html';
425
426     g_currentState.showChrome = false;
427
428     var tests = [test1, test2];
429     equal(htmlForIndividualTests(tests),
430         '<h2><a href="http://trac.webkit.org/browser/trunk/LayoutTests/foo/nonexistant.html" target="_blank">foo/nonexistant.html</a></h2>' +
431         htmlForIndividualTestOnAllBuilders(test1) + 
432         '<div class=expectations test=foo/nonexistant.html>' +
433             '<div><span class=link onclick=\"setQueryParameter(\'showExpectations\', true)\">Show results</span> | ' +
434             '<span class=link onclick=\"setQueryParameter(\'showLargeExpectations\', true)\">Show large thumbnails</span> | ' +
435             '<b>Only shows actual results/diffs from the most recent *failure* on each bot.</b></div>' +
436         '</div>' +
437         '<hr>' +
438         '<h2><a href="http://trac.webkit.org/browser/trunk/LayoutTests/bar/nonexistant.html" target="_blank">bar/nonexistant.html</a></h2>' +
439         htmlForIndividualTestOnAllBuilders(test2) +
440         '<div class=expectations test=bar/nonexistant.html>' +
441             '<div><span class=link onclick=\"setQueryParameter(\'showExpectations\', true)\">Show results</span> | ' +
442             '<span class=link onclick=\"setQueryParameter(\'showLargeExpectations\', true)\">Show large thumbnails</span> | ' +
443             '<b>Only shows actual results/diffs from the most recent *failure* on each bot.</b></div>' +
444         '</div>');
445
446     tests = [test1];
447     equal(htmlForIndividualTests(tests), htmlForIndividualTestOnAllBuilders(test1) +
448         '<div class=expectations test=foo/nonexistant.html>' +
449             '<div><span class=link onclick=\"setQueryParameter(\'showExpectations\', true)\">Show results</span> | ' +
450             '<span class=link onclick=\"setQueryParameter(\'showLargeExpectations\', true)\">Show large thumbnails</span> | ' +
451             '<b>Only shows actual results/diffs from the most recent *failure* on each bot.</b></div>' +
452         '</div>');
453
454     g_currentState.showChrome = true;
455
456     equal(htmlForIndividualTests(tests),
457         '<h2><a href="http://trac.webkit.org/browser/trunk/LayoutTests/foo/nonexistant.html" target="_blank">foo/nonexistant.html</a></h2>' +
458         htmlForIndividualTestOnAllBuildersWithResultsLinks(test1));
459
460     tests = [test1, test2];
461     equal(htmlForIndividualTests(tests),
462         '<h2><a href="http://trac.webkit.org/browser/trunk/LayoutTests/foo/nonexistant.html" target="_blank">foo/nonexistant.html</a></h2>' +
463         htmlForIndividualTestOnAllBuildersWithResultsLinks(test1) + '<hr>' +
464         '<h2><a href="http://trac.webkit.org/browser/trunk/LayoutTests/bar/nonexistant.html" target="_blank">bar/nonexistant.html</a></h2>' +
465         htmlForIndividualTestOnAllBuildersWithResultsLinks(test2));
466 });
467
468 test('htmlForSingleTestRow', 1, function() {
469     resetGlobals();
470     var builder = 'dummyBuilder';
471     BUILDER_TO_MASTER[builder] = CHROMIUM_WEBKIT_BUILDER_MASTER;
472     var test = createResultsObjectForTest('foo/exists.html', builder);
473     g_currentState.showCorrectExpectations = true;
474     g_resultsByBuilder[builder] = {buildNumbers: [2, 1], webkitRevision: [1234, 1233]};
475     test.rawResults = [[1, 'F'], [2, 'I']];
476     test.rawTimes = [[1, 0], [2, 5]];
477     var expected = '<tr>' +
478         '<td class="test-link"><span class="link" onclick="setQueryParameter(\'tests\',\'foo/exists.html\');">foo/exists.html</span>' +
479         '<td class=options-container><a href="https://bugs.webkit.org/enter_bug.cgi?assigned_to=webkit-unassigned%40lists.webkit.org&product=WebKit&form_name=enter_bug&component=Tools%20%2F%20Tests&short_desc=Layout%20Test%20foo%2Fexists.html%20is%20failing&comment=The%20following%20layout%20test%20is%20failing%20on%20%5Binsert%20platform%5D%0A%0Afoo%2Fexists.html%0A%0AProbable%20cause%3A%0A%0A%5Binsert%20probable%20cause%5D" class="file-bug">FILE BUG</a>' +
480         '<td class=options-container>' +
481             '<td class=options-container>' +
482                 '<td><td title="TEXT. Click for more info." class="results F merge" onclick=\'showPopupForBuild(event, "dummyBuilder",0,"foo/exists.html")\'>&nbsp;' +
483                 '<td title="IMAGE. Click for more info." class="results I" onclick=\'showPopupForBuild(event, "dummyBuilder",1,"foo/exists.html")\'>5';
484
485     equal(htmlForSingleTestRow(test), expected);
486 });
487
488 test('lookupVirtualTestSuite', 2, function() {
489     equal(lookupVirtualTestSuite('fast/canvas/foo.html'), '');
490     equal(lookupVirtualTestSuite('platform/chromium/virtual/gpu/fast/canvas/foo.html'), 'platform/chromium/virtual/gpu/fast/canvas');
491 });
492
493 test('baseTest', 2, function() {
494     equal(baseTest('fast/canvas/foo.html', ''), 'fast/canvas/foo.html');
495     equal(baseTest('platform/chromium/virtual/gpu/fast/canvas/foo.html', 'platform/chromium/virtual/gpu/fast/canvas'), 'fast/canvas/foo.html');
496 });
497
498 // FIXME: Create builders_tests.js and move this there.
499 test('generateChromiumDepsFyiGpuBuildersFromBuilderList', 1, function() {
500     var builderList = ["Linux Audio", "Linux Release (ATI)", "Linux Release (Intel)", "Mac Release (ATI)", "Win7 Audio", "Win7 Release (ATI)", "Win7 Release (Intel)", "WinXP Debug (NVIDIA)", "WinXP Release (NVIDIA)"];
501     var expectedBuilders = [["Linux Release (ATI)", 2], ["Linux Release (Intel)"], ["Mac Release (ATI)"], ["Win7 Release (ATI)"], ["Win7 Release (Intel)"], ["WinXP Debug (NVIDIA)"], ["WinXP Release (NVIDIA)"] ];
502     deepEqual(generateBuildersFromBuilderList(builderList, isChromiumDepsFyiGpuTestRunner), expectedBuilders);
503 });
504
505 test('generateChromiumTipOfTreeGpuBuildersFromBuilderList', 1, function() {
506     var builderList = ["Chrome Frame Tests", "GPU Linux (NVIDIA)", "GPU Linux (dbg) (NVIDIA)", "GPU Mac", "GPU Mac (dbg)", "GPU Win7 (NVIDIA)", "GPU Win7 (dbg) (NVIDIA)", "Linux Perf",
507         "Linux Tests", "Linux Valgrind", "Mac Builder (dbg)", "Mac10.6 Perf", "Mac10.6 Tests", "Vista Perf", "Vista Tests", "Webkit Linux", "Webkit Linux ASAN", "Webkit Linux (dbg)", "Webkit Linux (deps)",
508         "Webkit Linux 32", "Webkit Mac Builder", "Webkit Mac Builder (dbg)", "Webkit Mac Builder (deps)", "Webkit Mac10.5", "Webkit Mac10.5 (dbg)(1)", "Webkit Mac10.5 (dbg)(2)",
509         "Webkit Mac10.6", "Webkit Mac10.6 (dbg)", "Webkit Mac10.6 (deps)", "Webkit Mac10.7", "Webkit Vista", "Webkit Win", "Webkit Win (dbg)(1)", "Webkit Win (dbg)(2)",
510         "Webkit Win (deps)", "Webkit Win Builder", "Webkit Win Builder (dbg)", "Webkit Win Builder (deps)", "Webkit Win7", "Win (dbg)", "Win Builder"];
511     var expectedBuilders = [["GPU Linux (NVIDIA)", 2], ["GPU Linux (dbg) (NVIDIA)"], ["GPU Mac"], ["GPU Mac (dbg)"], ["GPU Win7 (NVIDIA)"], ["GPU Win7 (dbg) (NVIDIA)"]];
512     deepEqual(generateBuildersFromBuilderList(builderList, isChromiumTipOfTreeGpuTestRunner), expectedBuilders);
513 });
514
515 test('generateWebkitBuildersFromBuilderList', 1, function() {
516     var builderList = ["Chromium Android Release", "Chromium Linux Release", "Chromium Linux Release (Grid Layout)", "Chromium Linux Release (Perf)", "Chromium Linux Release (Tests)",
517         "Chromium Mac Release", "Chromium Mac Release (Perf)", "Chromium Mac Release (Tests)", "Chromium Win Release", "Chromium Win Release (Perf)", "Chromium Win Release (Tests)",
518         "EFL Linux Release", "GTK Linux 32-bit Release", "GTK Linux 64-bit Debug", "GTK Linux 64-bit Release", "Lion Debug (Build)", "Lion Debug (Tests)", "Lion Debug (WebKit2 Tests)",
519         "Lion Leaks", "Lion Release (Build)", "Lion Release (Perf)", "Lion Release (Tests)", "Lion Release (WebKit2 Tests)", "Qt Linux 64-bit Release (Perf)",
520         "Qt Linux 64-bit Release (WebKit2 Perf)", "Qt Linux ARMv7 Release", "Qt Linux MIPS Release", "Qt Linux Release", "Qt Linux Release minimal", "Qt Linux SH4 Release",
521         "Qt SnowLeopard Release", "Qt Windows 32-bit Debug", "Qt Windows 32-bit Release", "SnowLeopard Intel Debug (Build)", "SnowLeopard Intel Debug (Tests)",
522         "SnowLeopard Intel Debug (WebKit2 Tests)", "SnowLeopard Intel Release (Build)", "SnowLeopard Intel Release (Tests)", "SnowLeopard Intel Release (WebKit2 Tests)",
523         "WinCE Release (Build)", "WinCairo Release", "Windows 7 Release (Tests)", "Windows 7 Release (WebKit2 Tests)", "Windows Debug (Build)", "Windows Release (Build)", "Windows XP Debug (Tests)"];
524     var expectedBuilders = [["Chromium Linux Release (Tests)", 2], ["Chromium Mac Release (Tests)"], ["Chromium Win Release (Tests)"], ["GTK Linux 32-bit Release"], ["GTK Linux 64-bit Debug"],
525         ["GTK Linux 64-bit Release"], ["Lion Debug (Tests)"], ["Lion Debug (WebKit2 Tests)"], ["Lion Release (Tests)"], ["Lion Release (WebKit2 Tests)"], ["Qt Linux Release"],
526         ["SnowLeopard Intel Debug (Tests)"], ["SnowLeopard Intel Debug (WebKit2 Tests)"], ["SnowLeopard Intel Release (Tests)"], ["SnowLeopard Intel Release (WebKit2 Tests)"]];
527     deepEqual(generateBuildersFromBuilderList(builderList, isWebkitTestRunner), expectedBuilders);
528 });
529
530 test('generateChromiumWebkitTipOfTreeBuildersFromBuilderList', 1, function() {
531     var builderList = ["Chrome Frame Tests", "GPU Linux (NVIDIA)", "GPU Linux (dbg) (NVIDIA)", "GPU Mac", "GPU Mac (dbg)", "GPU Win7 (NVIDIA)", "GPU Win7 (dbg) (NVIDIA)", "Linux Perf", "Linux Tests",
532         "Linux Valgrind", "Mac Builder (dbg)", "Mac10.6 Perf", "Mac10.6 Tests", "Vista Perf", "Vista Tests", "Webkit Linux", "Webkit Linux ASAN",  "Webkit Linux (dbg)", "Webkit Linux (deps)", "Webkit Linux 32",
533         "Webkit Mac Builder", "Webkit Mac Builder (dbg)", "Webkit Mac Builder (deps)", "Webkit Mac10.5", "Webkit Mac10.5 (dbg)(1)", "Webkit Mac10.5 (dbg)(2)", "Webkit Mac10.6", "Webkit Mac10.6 (dbg)",
534         "Webkit Mac10.6 (deps)", "Webkit Mac10.7", "Webkit Vista", "Webkit Win", "Webkit Win (dbg)(1)", "Webkit Win (dbg)(2)", "Webkit Win (deps)", "Webkit Win Builder", "Webkit Win Builder (dbg)",
535         "Webkit Win Builder (deps)", "Webkit Win7", "Win (dbg)", "Win Builder"];
536     var expectedBuilders = [["Webkit Linux", 2], ["Webkit Linux (dbg)"], ["Webkit Linux 32"], ["Webkit Mac10.5"], ["Webkit Mac10.5 (dbg)(1)"], ["Webkit Mac10.5 (dbg)(2)"], ["Webkit Mac10.6"],
537         ["Webkit Mac10.6 (dbg)"], ["Webkit Mac10.7"], ["Webkit Vista"], ["Webkit Win"], ["Webkit Win (dbg)(1)"], ["Webkit Win (dbg)(2)"], ["Webkit Win7"]];
538     deepEqual(generateBuildersFromBuilderList(builderList, isChromiumWebkitTipOfTreeTestRunner), expectedBuilders);
539 });
540
541 test('generateChromiumWebkitDepsBuildersFromBuilderList', 1, function() {
542     var builderList = ["Chrome Frame Tests", "GPU Linux (NVIDIA)", "GPU Linux (dbg) (NVIDIA)", "GPU Mac", "GPU Mac (dbg)", "GPU Win7 (NVIDIA)", "GPU Win7 (dbg) (NVIDIA)", "Linux Perf", "Linux Tests",
543         "Linux Valgrind", "Mac Builder (dbg)", "Mac10.6 Perf", "Mac10.6 Tests", "Vista Perf", "Vista Tests", "Webkit Linux", "Webkit Linux ASAN",  "Webkit Linux (dbg)", "Webkit Linux (deps)", "Webkit Linux 32",
544         "Webkit Mac Builder", "Webkit Mac Builder (dbg)", "Webkit Mac Builder (deps)", "Webkit Mac10.5", "Webkit Mac10.5 (dbg)(1)", "Webkit Mac10.5 (dbg)(2)", "Webkit Mac10.6", "Webkit Mac10.6 (dbg)",
545         "Webkit Mac10.6 (deps)", "Webkit Mac10.7", "Webkit Vista", "Webkit Win", "Webkit Win (dbg)(1)", "Webkit Win (dbg)(2)", "Webkit Win (deps)", "Webkit Win Builder", "Webkit Win Builder (dbg)",
546         "Webkit Win Builder (deps)", "Webkit Win7", "Win (dbg)", "Win Builder"];
547     var expectedBuilders = [["Webkit Linux (deps)", 2], ["Webkit Mac10.6 (deps)"], ["Webkit Win (deps)"]];
548     deepEqual(generateBuildersFromBuilderList(builderList, isChromiumWebkitDepsTestRunner), expectedBuilders);
549 });
550
551 test('generateChromiumDepsGTestBuildersFromBuilderList', 1, function() {
552     var builderList = ["Android Builder", "Chrome Frame Tests (ie6)", "Chrome Frame Tests (ie7)", "Chrome Frame Tests (ie8)", "Interactive Tests (dbg)", "Linux", "Linux Builder (dbg)",
553         "Linux Builder (dbg)(shared)", "Linux Builder x64", "Linux Clang (dbg)", "Linux Sync", "Linux Tests (dbg)(1)", "Linux Tests (dbg)(2)", "Linux Tests (dbg)(shared)", "Linux Tests x64",
554         "Linux x64", "Mac", "Mac 10.5 Tests (dbg)(1)", "Mac 10.5 Tests (dbg)(2)", "Mac 10.5 Tests (dbg)(3)", "Mac 10.5 Tests (dbg)(4)", "Mac 10.6 Tests (dbg)(1)", "Mac 10.6 Tests (dbg)(2)",
555         "Mac 10.6 Tests (dbg)(3)", "Mac 10.6 Tests (dbg)(4)", "Mac Builder", "Mac Builder (dbg)", "Mac10.5 Tests (1)", "Mac10.5 Tests (2)", "Mac10.5 Tests (3)", "Mac10.6 Sync",
556         "Mac10.6 Tests (1)", "Mac10.6 Tests (2)", "Mac10.6 Tests (3)", "NACL Tests", "NACL Tests (x64)", "Vista Tests (1)", "Vista Tests (2)", "Vista Tests (3)", "Win", "Win Aura",
557         "Win Builder", "Win Builder (dbg)", "Win Builder 2010 (dbg)", "Win7 Sync", "Win7 Tests (1)", "Win7 Tests (2)", "Win7 Tests (3)", "Win7 Tests (dbg)(1)", "Win7 Tests (dbg)(2)",
558         "Win7 Tests (dbg)(3)", "Win7 Tests (dbg)(4)", "Win7 Tests (dbg)(5)", "Win7 Tests (dbg)(6)", "XP Tests (1)", "XP Tests (2)", "XP Tests (3)", "XP Tests (dbg)(1)", "XP Tests (dbg)(2)",
559         "XP Tests (dbg)(3)", "XP Tests (dbg)(4)", "XP Tests (dbg)(5)", "XP Tests (dbg)(6)"];
560     var expectedBuilders = [["Interactive Tests (dbg)", 2], ["Linux Tests (dbg)(1)"], ["Linux Tests (dbg)(2)"], ["Linux Tests (dbg)(shared)"], ["Linux Tests x64"], ["Mac 10.5 Tests (dbg)(1)"],
561         ["Mac 10.5 Tests (dbg)(2)"], ["Mac 10.5 Tests (dbg)(3)"], ["Mac 10.5 Tests (dbg)(4)"], ["Mac 10.6 Tests (dbg)(1)"], ["Mac 10.6 Tests (dbg)(2)"], ["Mac 10.6 Tests (dbg)(3)"],
562         ["Mac 10.6 Tests (dbg)(4)"], ["Mac10.5 Tests (1)"], ["Mac10.5 Tests (2)"], ["Mac10.5 Tests (3)"], ["Mac10.6 Tests (1)"], ["Mac10.6 Tests (2)"], ["Mac10.6 Tests (3)"], ["NACL Tests"],
563         ["NACL Tests (x64)"], ["Vista Tests (1)"], ["Vista Tests (2)"], ["Vista Tests (3)"], ["Win7 Tests (1)"], ["Win7 Tests (2)"], ["Win7 Tests (3)"], ["Win7 Tests (dbg)(1)"],
564         ["Win7 Tests (dbg)(2)"], ["Win7 Tests (dbg)(3)"], ["Win7 Tests (dbg)(4)"], ["Win7 Tests (dbg)(5)"], ["Win7 Tests (dbg)(6)"], ["XP Tests (1)"], ["XP Tests (2)"], ["XP Tests (3)"],
565         ["XP Tests (dbg)(1)"], ["XP Tests (dbg)(2)"], ["XP Tests (dbg)(3)"], ["XP Tests (dbg)(4)"], ["XP Tests (dbg)(5)"], ["XP Tests (dbg)(6)"]];
566     deepEqual(generateBuildersFromBuilderList(builderList, isChromiumDepsGTestRunner), expectedBuilders);
567 });
568
569 test('generateChromiumDepsCrosGTestBuildersFromBuilderList', 1, function() {
570     var builderList = ["ChromiumOS (amd64)", "ChromiumOS (arm)", "ChromiumOS (tegra2)", "ChromiumOS (x86)", "Linux ChromiumOS (Clang dbg)", "Linux ChromiumOS Builder", "Linux ChromiumOS Builder (dbg)",
571         "Linux ChromiumOS Tests (1)", "Linux ChromiumOS Tests (2)", "Linux ChromiumOS Tests (dbg)(1)", "Linux ChromiumOS Tests (dbg)(2)", "Linux ChromiumOS Tests (dbg)(3)"];
572     var expectedBuilders = [["Linux ChromiumOS Tests (1)", 2], ["Linux ChromiumOS Tests (2)"], ["Linux ChromiumOS Tests (dbg)(1)"], ["Linux ChromiumOS Tests (dbg)(2)"], ["Linux ChromiumOS Tests (dbg)(3)"]];
573     deepEqual(generateBuildersFromBuilderList(builderList, isChromiumDepsCrosGTestRunner), expectedBuilders);
574 });
575
576 test('generateChromiumTipOfTreeGTestBuildersFromBuilderList', 1, function() {
577     var builderList = ["Chrome Frame Tests", "GPU Linux (NVIDIA)", "GPU Linux (dbg) (NVIDIA)", "GPU Mac", "GPU Mac (dbg)", "GPU Win7 (NVIDIA)", "GPU Win7 (dbg) (NVIDIA)", "Linux Perf",
578         "Linux Tests", "Linux Valgrind", "Mac Builder (dbg)", "Mac10.6 Perf", "Mac10.6 Tests", "Vista Perf", "Vista Tests", "Webkit Linux", "Webkit Linux (dbg)", "Webkit Linux (deps)",
579         "Webkit Linux 32", "Webkit Mac Builder", "Webkit Mac Builder (dbg)", "Webkit Mac Builder (deps)", "Webkit Mac10.5", "Webkit Mac10.5 (dbg)(1)", "Webkit Mac10.5 (dbg)(2)",
580         "Webkit Mac10.6", "Webkit Mac10.6 (dbg)", "Webkit Mac10.6 (deps)", "Webkit Mac10.7", "Webkit Vista", "Webkit Win", "Webkit Win (dbg)(1)", "Webkit Win (dbg)(2)",
581         "Webkit Win (deps)", "Webkit Win Builder", "Webkit Win Builder (dbg)", "Webkit Win Builder (deps)", "Webkit Win7", "Win (dbg)", "Win Builder"];
582     var expectedBuilders = [['Linux Tests', BuilderGroup.DEFAULT_BUILDER], ['Mac10.6 Tests'], ['Vista Tests'], ['Win (dbg)']];
583     deepEqual(generateBuildersFromBuilderList(builderList, isChromiumTipOfTreeGTestRunner), expectedBuilders);
584 });
585
586 test('queryHashAsMap', 2, function() {
587     equal(window.location.hash, '#useTestData=true');
588     deepEqual(queryHashAsMap(), {useTestData: 'true'});
589 });
590
591 test('parseCrossDashboardParameters', 2, function() {
592     equal(window.location.hash, '#useTestData=true');
593     parseCrossDashboardParameters();
594
595     var expectedParameters = {};
596     for (var key in g_defaultCrossDashboardStateValues)
597         expectedParameters[key] = g_defaultCrossDashboardStateValues[key];
598     expectedParameters.useTestData = true;
599
600     deepEqual(g_crossDashboardState, expectedParameters);
601 });
602
603 test('diffStates', 5, function() {
604     var newState = {a: 1, b: 2};
605     deepEqual(diffStates(null, newState), newState);
606
607     var oldState = {a: 1};
608     deepEqual(diffStates(oldState, newState), {b: 2});
609
610     // FIXME: This is kind of weird. I think the existing users of this code work correctly, but it's a confusing result.
611     var oldState = {c: 1};
612     deepEqual(diffStates(oldState, newState), {a:1, b: 2});
613
614     var oldState = {a: 1, b: 2};
615     deepEqual(diffStates(oldState, newState), {});
616
617     var oldState = {a: 2, b: 3};
618     deepEqual(diffStates(oldState, newState), {a: 1, b: 2});
619 });
620
621 test('addBuilderLoadErrors', 1, function() {
622     clearErrors();
623     g_hasDoneInitialPageGeneration = false;
624     g_buildersThatFailedToLoad = ['builder1', 'builder2'];
625     g_staleBuilders = ['staleBuilder1'];
626     addBuilderLoadErrors();
627     equal(g_errorMessages, 'ERROR: Failed to get data from builder1,builder2.<br>ERROR: Data from staleBuilder1 is more than 1 day stale.<br>');
628 });
629
630 test('builderGroupIsToTWebKitAttribute', 2, function() {
631     var dummyMaster = new BuilderMaster('dummy.org', 'http://build.dummy.org');
632     var testBuilderGroups = {
633         '@ToT - dummy.org': new BuilderGroup(BuilderGroup.TOT_WEBKIT),
634         '@DEPS - dummy.org': new BuilderGroup(BuilderGroup.DEPS_WEBKIT),
635     }
636     testBuilderGroups['@ToT - dummy.org'].expectedGroups = 1;
637     testBuilderGroups['@DEPS - dummy.org'].expectedGroups = 1;
638
639     var testJSONData = "{ \"Dummy Builder 1\": null, \"Dummy Builder 2\": null }";
640     onBuilderListLoad(testBuilderGroups,  function() { return true; }, dummyMaster, '@ToT - dummy.org', BuilderGroup.TOT_WEBKIT, JSON.parse(testJSONData));
641     equal(testBuilderGroups['@ToT - dummy.org'].isToTWebKit, true);
642     onBuilderListLoad(testBuilderGroups,  function() { return true; }, dummyMaster, '@DEPS - dummy.org', BuilderGroup.DEPS_WEBKIT, JSON.parse(testJSONData));
643     equal(testBuilderGroups['@DEPS - dummy.org'].isToTWebKit, false);
644 });
645
646 test('builderGroupExpectedGroups', 4, function() {
647     var dummyMaster = new BuilderMaster('dummy.org', 'http://build.dummy.org');
648     var testBuilderGroups = {
649         '@ToT - dummy.org': new BuilderGroup(BuilderGroup.TOT_WEBKIT),
650     }
651     testBuilderGroups['@ToT - dummy.org'].expectedGroups = 3;
652
653     var testJSONData = "{ \"Dummy Builder 1\": null }";
654     equal(testBuilderGroups['@ToT - dummy.org'].expectedGroups, 3);
655     onBuilderListLoad(testBuilderGroups,  function() { return true; }, dummyMaster, '@ToT - dummy.org', BuilderGroup.TOT_WEBKIT, JSON.parse(testJSONData));
656     equal(testBuilderGroups['@ToT - dummy.org'].groups, 1);
657     var testJSONData = "{ \"Dummy Builder 2\": null }";
658     onBuilderListLoad(testBuilderGroups,  function() { return true; }, dummyMaster, '@ToT - dummy.org', BuilderGroup.TOT_WEBKIT, JSON.parse(testJSONData));
659     equal(testBuilderGroups['@ToT - dummy.org'].groups, 2);
660     onErrorLoadingBuilderList('http://build.dummy.org', testBuilderGroups,  '@ToT - dummy.org');
661     equal(testBuilderGroups['@ToT - dummy.org'].groups, 3);
662 });
663
664 test('sortTests', 4, function() {
665     var test1 = createResultsObjectForTest('foo/test1.html', 'dummyBuilder');
666     var test2 = createResultsObjectForTest('foo/test2.html', 'dummyBuilder');
667     var test3 = createResultsObjectForTest('foo/test3.html', 'dummyBuilder');
668     test1.modifiers = 'b';
669     test2.modifiers = 'a';
670     test3.modifiers = '';
671
672     var tests = [test1, test2, test3];
673     sortTests(tests, 'modifiers', FORWARD);
674     deepEqual(tests, [test2, test1, test3]);
675     sortTests(tests, 'modifiers', BACKWARD);
676     deepEqual(tests, [test3, test1, test2]);
677
678     test1.bugs = 'b';
679     test2.bugs = 'a';
680     test3.bugs = '';
681
682     var tests = [test1, test2, test3];
683     sortTests(tests, 'bugs', FORWARD);
684     deepEqual(tests, [test2, test1, test3]);
685     sortTests(tests, 'bugs', BACKWARD);
686     deepEqual(tests, [test3, test1, test2]);
687 });
688
689 test('popup', 2, function() {
690     showPopup(document.body, 'dummy content');
691     ok(document.querySelector('#popup'));
692     hidePopup();
693     ok(!document.querySelector('#popup'));
694 });
695
696 test('gpuResultsPath', 3, function() {
697   equal(gpuResultsPath('777777', 'Win7 Release (ATI)'), '777777_Win7_Release_ATI_');
698   equal(gpuResultsPath('123', 'GPU Linux (dbg)(NVIDIA)'), '123_GPU_Linux_dbg_NVIDIA_');
699   equal(gpuResultsPath('12345', 'GPU Mac'), '12345_GPU_Mac');
700 });