Wed, 31 Dec 2014 13:27:57 +0100
Ignore runtime configuration files generated during quality assurance.
1 /* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- /
2 /* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #if BOOTSTRAP
8 this.EXPORTED_SYMBOLS = ["OnRefTestLoad"];
9 #endif
12 const CC = Components.classes;
13 const CI = Components.interfaces;
14 const CR = Components.results;
16 const XHTML_NS = "http://www.w3.org/1999/xhtml";
17 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
19 const NS_LOCAL_FILE_CONTRACTID = "@mozilla.org/file/local;1";
20 const NS_GFXINFO_CONTRACTID = "@mozilla.org/gfx/info;1";
21 const IO_SERVICE_CONTRACTID = "@mozilla.org/network/io-service;1";
22 const DEBUG_CONTRACTID = "@mozilla.org/xpcom/debug;1";
23 const NS_LOCALFILEINPUTSTREAM_CONTRACTID =
24 "@mozilla.org/network/file-input-stream;1";
25 const NS_SCRIPTSECURITYMANAGER_CONTRACTID =
26 "@mozilla.org/scriptsecuritymanager;1";
27 const NS_REFTESTHELPER_CONTRACTID =
28 "@mozilla.org/reftest-helper;1";
29 const NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX =
30 "@mozilla.org/network/protocol;1?name=";
31 const NS_XREAPPINFO_CONTRACTID =
32 "@mozilla.org/xre/app-info;1";
33 const NS_DIRECTORY_SERVICE_CONTRACTID =
34 "@mozilla.org/file/directory_service;1";
35 const NS_OBSERVER_SERVICE_CONTRACTID =
36 "@mozilla.org/observer-service;1";
38 Components.utils.import("resource://gre/modules/FileUtils.jsm");
40 var gLoadTimeout = 0;
41 var gTimeoutHook = null;
42 var gRemote = false;
43 var gIgnoreWindowSize = false;
44 var gShuffle = false;
45 var gTotalChunks = 0;
46 var gThisChunk = 0;
47 var gContainingWindow = null;
48 var gURLFilterRegex = null;
49 const FOCUS_FILTER_ALL_TESTS = "all";
50 const FOCUS_FILTER_NEEDS_FOCUS_TESTS = "needs-focus";
51 const FOCUS_FILTER_NON_NEEDS_FOCUS_TESTS = "non-needs-focus";
52 var gFocusFilterMode = FOCUS_FILTER_ALL_TESTS;
54 // "<!--CLEAR-->"
55 const BLANK_URL_FOR_CLEARING = "data:text/html;charset=UTF-8,%3C%21%2D%2DCLEAR%2D%2D%3E";
57 var gBrowser;
58 // Are we testing web content loaded in a separate process?
59 var gBrowserIsRemote; // bool
60 // Are we using <iframe mozbrowser>?
61 var gBrowserIsIframe; // bool
62 var gBrowserMessageManager;
63 var gCanvas1, gCanvas2;
64 // gCurrentCanvas is non-null between InitCurrentCanvasWithSnapshot and the next
65 // RecordResult.
66 var gCurrentCanvas = null;
67 var gURLs;
68 // Map from URI spec to the number of times it remains to be used
69 var gURIUseCounts;
70 // Map from URI spec to the canvas rendered for that URI
71 var gURICanvases;
72 var gTestResults = {
73 // Successful...
74 Pass: 0,
75 LoadOnly: 0,
76 // Unexpected...
77 Exception: 0,
78 FailedLoad: 0,
79 UnexpectedFail: 0,
80 UnexpectedPass: 0,
81 AssertionUnexpected: 0,
82 AssertionUnexpectedFixed: 0,
83 // Known problems...
84 KnownFail : 0,
85 AssertionKnown: 0,
86 Random : 0,
87 Skip: 0,
88 Slow: 0,
89 };
90 var gTotalTests = 0;
91 var gState;
92 var gCurrentURL;
93 var gTestLog = [];
94 var gServer;
95 var gCount = 0;
96 var gAssertionCount = 0;
98 var gIOService;
99 var gDebug;
100 var gWindowUtils;
102 var gSlowestTestTime = 0;
103 var gSlowestTestURL;
105 var gDrawWindowFlags;
107 var gExpectingProcessCrash = false;
108 var gExpectedCrashDumpFiles = [];
109 var gUnexpectedCrashDumpFiles = { };
110 var gCrashDumpDir;
111 var gFailedNoPaint = false;
113 // The enabled-state of the test-plugins, stored so they can be reset later
114 var gTestPluginEnabledStates = null;
116 const TYPE_REFTEST_EQUAL = '==';
117 const TYPE_REFTEST_NOTEQUAL = '!=';
118 const TYPE_LOAD = 'load'; // test without a reference (just test that it does
119 // not assert, crash, hang, or leak)
120 const TYPE_SCRIPT = 'script'; // test contains individual test results
122 // The order of these constants matters, since when we have a status
123 // listed for a *manifest*, we combine the status with the status for
124 // the test by using the *larger*.
125 // FIXME: In the future, we may also want to use this rule for combining
126 // statuses that are on the same line (rather than making the last one
127 // win).
128 const EXPECTED_PASS = 0;
129 const EXPECTED_FAIL = 1;
130 const EXPECTED_RANDOM = 2;
131 const EXPECTED_DEATH = 3; // test must be skipped to avoid e.g. crash/hang
132 const EXPECTED_FUZZY = 4;
134 // types of preference value we might want to set for a specific test
135 const PREF_BOOLEAN = 0;
136 const PREF_STRING = 1;
137 const PREF_INTEGER = 2;
139 var gPrefsToRestore = [];
141 const gProtocolRE = /^\w+:/;
142 const gPrefItemRE = /^(|test-|ref-)pref\((.+?),(.*)\)$/;
144 var gHttpServerPort = -1;
146 // whether to run slow tests or not
147 var gRunSlowTests = true;
149 // whether we should skip caching canvases
150 var gNoCanvasCache = false;
152 var gRecycledCanvases = new Array();
154 // By default we just log to stdout
155 var gDumpLog = dump;
156 var gVerbose = false;
158 // Only dump the sandbox once, because it doesn't depend on the
159 // manifest URL (yet!).
160 var gDumpedConditionSandbox = false;
162 function LogWarning(str)
163 {
164 gDumpLog("REFTEST INFO | " + str + "\n");
165 gTestLog.push(str);
166 }
168 function LogInfo(str)
169 {
170 if (gVerbose)
171 gDumpLog("REFTEST INFO | " + str + "\n");
172 gTestLog.push(str);
173 }
175 function FlushTestLog()
176 {
177 if (!gVerbose) {
178 // In verbose mode, we've dumped all these messages already.
179 for (var i = 0; i < gTestLog.length; ++i) {
180 gDumpLog("REFTEST INFO | Saved log: " + gTestLog[i] + "\n");
181 }
182 }
183 gTestLog = [];
184 }
186 function AllocateCanvas()
187 {
188 if (gRecycledCanvases.length > 0)
189 return gRecycledCanvases.shift();
191 var canvas = gContainingWindow.document.createElementNS(XHTML_NS, "canvas");
192 var r = gBrowser.getBoundingClientRect();
193 canvas.setAttribute("width", Math.ceil(r.width));
194 canvas.setAttribute("height", Math.ceil(r.height));
196 return canvas;
197 }
199 function ReleaseCanvas(canvas)
200 {
201 // store a maximum of 2 canvases, if we're not caching
202 if (!gNoCanvasCache || gRecycledCanvases.length < 2)
203 gRecycledCanvases.push(canvas);
204 }
206 function IDForEventTarget(event)
207 {
208 try {
209 return "'" + event.target.getAttribute('id') + "'";
210 } catch (ex) {
211 return "<unknown>";
212 }
213 }
215 function getTestPlugin(aName) {
216 var ph = CC["@mozilla.org/plugin/host;1"].getService(CI.nsIPluginHost);
217 var tags = ph.getPluginTags();
219 // Find the test plugin
220 for (var i = 0; i < tags.length; i++) {
221 if (tags[i].name == aName)
222 return tags[i];
223 }
225 LogWarning("Failed to find the test-plugin.");
226 return null;
227 }
229 this.OnRefTestLoad = function OnRefTestLoad(win)
230 {
231 gCrashDumpDir = CC[NS_DIRECTORY_SERVICE_CONTRACTID]
232 .getService(CI.nsIProperties)
233 .get("ProfD", CI.nsIFile);
234 gCrashDumpDir.append("minidumps");
236 var env = CC["@mozilla.org/process/environment;1"].
237 getService(CI.nsIEnvironment);
238 gVerbose = !!env.get("MOZ_REFTEST_VERBOSE");
240 var prefs = Components.classes["@mozilla.org/preferences-service;1"].
241 getService(Components.interfaces.nsIPrefBranch);
242 try {
243 gBrowserIsRemote = prefs.getBoolPref("browser.tabs.remote.autostart");
244 } catch (e) {
245 gBrowserIsRemote = false;
246 }
248 try {
249 gBrowserIsIframe = prefs.getBoolPref("reftest.browser.iframe.enabled");
250 } catch (e) {
251 gBrowserIsIframe = false;
252 }
254 if (win === undefined || win == null) {
255 win = window;
256 }
257 if (gContainingWindow == null && win != null) {
258 gContainingWindow = win;
259 }
261 if (gBrowserIsIframe) {
262 gBrowser = gContainingWindow.document.createElementNS(XHTML_NS, "iframe");
263 gBrowser.setAttribute("mozbrowser", "");
264 gBrowser.setAttribute("mozapp", prefs.getCharPref("browser.manifestURL"));
265 } else {
266 gBrowser = gContainingWindow.document.createElementNS(XUL_NS, "xul:browser");
267 }
268 gBrowser.setAttribute("id", "browser");
269 gBrowser.setAttribute("type", "content-primary");
270 gBrowser.setAttribute("remote", gBrowserIsRemote ? "true" : "false");
271 gBrowser.setAttribute("mozasyncpanzoom", "true");
272 // Make sure the browser element is exactly 800x1000, no matter
273 // what size our window is
274 gBrowser.setAttribute("style", "min-width: 800px; min-height: 1000px; max-width: 800px; max-height: 1000px");
276 #ifdef BOOTSTRAP
277 #ifdef REFTEST_B2G
278 var doc = gContainingWindow.document.getElementsByTagName("html")[0];
279 #else
280 var doc = gContainingWindow.document.getElementById('main-window');
281 #endif
282 while (doc.hasChildNodes()) {
283 doc.removeChild(doc.firstChild);
284 }
285 doc.appendChild(gBrowser);
286 #else
287 document.getElementById("reftest-window").appendChild(gBrowser);
288 #endif
290 // reftests should have the test plugins enabled, not click-to-play
291 let plugin1 = getTestPlugin("Test Plug-in");
292 let plugin2 = getTestPlugin("Second Test Plug-in");
293 if (plugin1 && plugin2) {
294 gTestPluginEnabledStates = [plugin1.enabledState, plugin2.enabledState];
295 plugin1.enabledState = CI.nsIPluginTag.STATE_ENABLED;
296 plugin2.enabledState = CI.nsIPluginTag.STATE_ENABLED;
297 } else {
298 LogWarning("Could not get test plugin tags.");
299 }
301 gBrowserMessageManager = gBrowser.QueryInterface(CI.nsIFrameLoaderOwner)
302 .frameLoader.messageManager;
303 // The content script waits for the initial onload, then notifies
304 // us.
305 RegisterMessageListenersAndLoadContentScript();
306 }
308 function InitAndStartRefTests()
309 {
310 /* These prefs are optional, so we don't need to spit an error to the log */
311 try {
312 var prefs = Components.classes["@mozilla.org/preferences-service;1"].
313 getService(Components.interfaces.nsIPrefBranch);
314 } catch(e) {
315 gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | EXCEPTION: " + e + "\n");
316 }
318 try {
319 prefs.setBoolPref("android.widget_paints_background", false);
320 } catch (e) {}
322 /* set the gLoadTimeout */
323 try {
324 gLoadTimeout = prefs.getIntPref("reftest.timeout");
325 } catch(e) {
326 gLoadTimeout = 5 * 60 * 1000; //5 minutes as per bug 479518
327 }
329 /* Get the logfile for android tests */
330 try {
331 var logFile = prefs.getCharPref("reftest.logFile");
332 if (logFile) {
333 try {
334 var f = FileUtils.File(logFile);
335 var mfl = FileUtils.openFileOutputStream(f, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE);
336 // Set to mirror to stdout as well as the file
337 gDumpLog = function (msg) {
338 #ifdef BOOTSTRAP
339 #ifdef REFTEST_B2G
340 dump(msg);
341 #else
342 //NOTE: on android-xul, we have a libc crash if we do a dump with %7s in the string
343 #endif
344 #else
345 dump(msg);
346 #endif
347 mfl.write(msg, msg.length);
348 };
349 }
350 catch(e) {
351 // If there is a problem, just use stdout
352 gDumpLog = dump;
353 }
354 }
355 } catch(e) {}
357 try {
358 gRemote = prefs.getBoolPref("reftest.remote");
359 } catch(e) {
360 gRemote = false;
361 }
363 try {
364 gIgnoreWindowSize = prefs.getBoolPref("reftest.ignoreWindowSize");
365 } catch(e) {
366 gIgnoreWindowSize = false;
367 }
369 /* Support for running a chunk (subset) of tests. In separate try as this is optional */
370 try {
371 gTotalChunks = prefs.getIntPref("reftest.totalChunks");
372 gThisChunk = prefs.getIntPref("reftest.thisChunk");
373 }
374 catch(e) {
375 gTotalChunks = 0;
376 gThisChunk = 0;
377 }
379 try {
380 gURLFilterRegex = new RegExp(prefs.getCharPref("reftest.filter"));
381 } catch(e) {}
383 try {
384 gFocusFilterMode = prefs.getCharPref("reftest.focusFilterMode");
385 } catch(e) {}
387 gWindowUtils = gContainingWindow.QueryInterface(CI.nsIInterfaceRequestor).getInterface(CI.nsIDOMWindowUtils);
388 if (!gWindowUtils || !gWindowUtils.compareCanvases)
389 throw "nsIDOMWindowUtils inteface missing";
391 gIOService = CC[IO_SERVICE_CONTRACTID].getService(CI.nsIIOService);
392 gDebug = CC[DEBUG_CONTRACTID].getService(CI.nsIDebug2);
394 RegisterProcessCrashObservers();
396 if (gRemote) {
397 gServer = null;
398 } else {
399 // not all gecko applications autoregister xpcom components
400 if (CC["@mozilla.org/server/jshttp;1"] === undefined) {
401 var file = CC["@mozilla.org/file/directory_service;1"].
402 getService(CI.nsIProperties).get("ProfD", CI.nsIFile);
403 file.appendRelativePath("extensions/reftest@mozilla.org/chrome.manifest");
405 registrar = Components.manager.QueryInterface(CI.nsIComponentRegistrar);
406 registrar.autoRegister(file);
407 }
408 gServer = CC["@mozilla.org/server/jshttp;1"].
409 createInstance(CI.nsIHttpServer);
410 }
411 try {
412 if (gServer)
413 StartHTTPServer();
414 } catch (ex) {
415 //gBrowser.loadURI('data:text/plain,' + ex);
416 ++gTestResults.Exception;
417 gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | EXCEPTION: " + ex + "\n");
418 DoneTests();
419 }
421 // Focus the content browser.
422 if (gFocusFilterMode != FOCUS_FILTER_NON_NEEDS_FOCUS_TESTS) {
423 gBrowser.focus();
424 }
426 StartTests();
427 }
429 function StartHTTPServer()
430 {
431 gServer.registerContentType("sjs", "sjs");
432 gServer.start(-1);
433 gHttpServerPort = gServer.identity.primaryPort;
434 }
436 // Perform a Fisher-Yates shuffle of the array.
437 function Shuffle(array)
438 {
439 for (var i = array.length - 1; i > 0; i--) {
440 var j = Math.floor(Math.random() * (i + 1));
441 var temp = array[i];
442 array[i] = array[j];
443 array[j] = temp;
444 }
445 }
447 function StartTests()
448 {
449 var uri;
450 #if BOOTSTRAP
451 /* These prefs are optional, so we don't need to spit an error to the log */
452 try {
453 var prefs = Components.classes["@mozilla.org/preferences-service;1"].
454 getService(Components.interfaces.nsIPrefBranch);
455 } catch(e) {
456 gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | EXCEPTION: " + e + "\n");
457 }
459 try {
460 gNoCanvasCache = prefs.getIntPref("reftest.nocache");
461 } catch(e) {
462 gNoCanvasCache = false;
463 }
465 try {
466 gShuffle = prefs.getBoolPref("reftest.shuffle");
467 } catch (e) {
468 gShuffle = false;
469 }
471 try {
472 gRunSlowTests = prefs.getIntPref("reftest.skipslowtests");
473 } catch(e) {
474 gRunSlowTests = false;
475 }
477 try {
478 uri = prefs.getCharPref("reftest.uri");
479 } catch(e) {
480 uri = "";
481 }
483 if (uri == "") {
484 gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | Unable to find reftest.uri pref. Please ensure your profile is setup properly\n");
485 DoneTests();
486 }
487 #else
488 try {
489 // Need to read the manifest once we have gHttpServerPort..
490 var args = window.arguments[0].wrappedJSObject;
492 if ("nocache" in args && args["nocache"])
493 gNoCanvasCache = true;
495 if ("skipslowtests" in args && args.skipslowtests)
496 gRunSlowTests = false;
498 uri = args.uri;
499 } catch (e) {
500 ++gTestResults.Exception;
501 gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | EXCEPTION: " + ex + "\n");
502 DoneTests();
503 }
504 #endif
506 if (gShuffle) {
507 gNoCanvasCache = true;
508 }
510 try {
511 ReadTopManifest(uri);
512 BuildUseCounts();
514 // Filter tests which will be skipped to get a more even distribution when chunking
515 // tURLs is a temporary array containing all active tests
516 var tURLs = new Array();
517 for (var i = 0; i < gURLs.length; ++i) {
518 if (gURLs[i].expected == EXPECTED_DEATH)
519 continue;
521 if (gURLs[i].needsFocus && !Focus())
522 continue;
524 if (gURLs[i].slow && !gRunSlowTests)
525 continue;
527 tURLs.push(gURLs[i]);
528 }
530 gDumpLog("REFTEST INFO | Discovered " + gURLs.length + " tests, after filtering SKIP tests, we have " + tURLs.length + "\n");
532 if (gTotalChunks > 0 && gThisChunk > 0) {
533 // Calculate start and end indices of this chunk if tURLs array were
534 // divided evenly
535 var testsPerChunk = tURLs.length / gTotalChunks;
536 var start = Math.round((gThisChunk-1) * testsPerChunk);
537 var end = Math.round(gThisChunk * testsPerChunk);
539 // Map these indices onto the gURLs array. This avoids modifying the
540 // gURLs array which prevents skipped tests from showing up in the log
541 start = gThisChunk == 1 ? 0 : gURLs.indexOf(tURLs[start]);
542 end = gThisChunk == gTotalChunks ? gURLs.length : gURLs.indexOf(tURLs[end + 1]) - 1;
543 gURLs = gURLs.slice(start, end);
545 gDumpLog("REFTEST INFO | Running chunk " + gThisChunk + " out of " + gTotalChunks + " chunks. ");
546 gDumpLog("tests " + (start+1) + "-" + end + "/" + gURLs.length + "\n");
547 }
549 if (gShuffle) {
550 Shuffle(gURLs);
551 }
553 gTotalTests = gURLs.length;
555 if (!gTotalTests)
556 throw "No tests to run";
558 gURICanvases = {};
559 StartCurrentTest();
560 } catch (ex) {
561 //gBrowser.loadURI('data:text/plain,' + ex);
562 ++gTestResults.Exception;
563 gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | EXCEPTION: " + ex + "\n");
564 DoneTests();
565 }
566 }
568 function OnRefTestUnload()
569 {
570 let plugin1 = getTestPlugin("Test Plug-in");
571 let plugin2 = getTestPlugin("Second Test Plug-in");
572 if (plugin1 && plugin2) {
573 plugin1.enabledState = gTestPluginEnabledStates[0];
574 plugin2.enabledState = gTestPluginEnabledStates[1];
575 } else {
576 LogWarning("Failed to get test plugin tags.");
577 }
578 }
580 // Read all available data from an input stream and return it
581 // as a string.
582 function getStreamContent(inputStream)
583 {
584 var streamBuf = "";
585 var sis = CC["@mozilla.org/scriptableinputstream;1"].
586 createInstance(CI.nsIScriptableInputStream);
587 sis.init(inputStream);
589 var available;
590 while ((available = sis.available()) != 0) {
591 streamBuf += sis.read(available);
592 }
594 return streamBuf;
595 }
597 // Build the sandbox for fails-if(), etc., condition evaluation.
598 function BuildConditionSandbox(aURL) {
599 var sandbox = new Components.utils.Sandbox(aURL.spec);
600 var xr = CC[NS_XREAPPINFO_CONTRACTID].getService(CI.nsIXULRuntime);
601 var appInfo = CC[NS_XREAPPINFO_CONTRACTID].getService(CI.nsIXULAppInfo);
602 sandbox.isDebugBuild = gDebug.isDebugBuild;
603 sandbox.xulRuntime = {widgetToolkit: xr.widgetToolkit, OS: xr.OS, __exposedProps__: { widgetToolkit: "r", OS: "r", XPCOMABI: "r", shell: "r" } };
605 // xr.XPCOMABI throws exception for configurations without full ABI
606 // support (mobile builds on ARM)
607 try {
608 sandbox.xulRuntime.XPCOMABI = xr.XPCOMABI;
609 } catch(e) {
610 sandbox.xulRuntime.XPCOMABI = "";
611 }
613 var testRect = gBrowser.getBoundingClientRect();
614 sandbox.smallScreen = false;
615 if (gContainingWindow.innerWidth < 800 || gContainingWindow.innerHeight < 1000) {
616 sandbox.smallScreen = true;
617 }
619 var gfxInfo = (NS_GFXINFO_CONTRACTID in CC) && CC[NS_GFXINFO_CONTRACTID].getService(CI.nsIGfxInfo);
620 try {
621 sandbox.d2d = gfxInfo.D2DEnabled;
622 } catch (e) {
623 sandbox.d2d = false;
624 }
625 var info = gfxInfo.getInfo();
626 sandbox.azureQuartz = info.AzureCanvasBackend == "quartz";
627 sandbox.azureSkia = info.AzureCanvasBackend == "skia";
628 sandbox.azureSkiaGL = info.AzureSkiaAccelerated; // FIXME: assumes GL right now
629 // true if we are using the same Azure backend for rendering canvas and content
630 sandbox.contentSameGfxBackendAsCanvas = info.AzureContentBackend == info.AzureCanvasBackend
631 || (info.AzureContentBackend == "none" && info.AzureCanvasBackend == "cairo");
633 sandbox.layersGPUAccelerated =
634 gWindowUtils.layerManagerType != "Basic";
635 sandbox.layersOpenGL =
636 gWindowUtils.layerManagerType == "OpenGL";
637 sandbox.layersOMTC =
638 gWindowUtils.layerManagerRemote == true;
640 // Shortcuts for widget toolkits.
641 sandbox.B2G = xr.widgetToolkit == "gonk";
642 sandbox.B2GDT = appInfo.name.toLowerCase() == "b2g" && !sandbox.B2G;
643 sandbox.Android = xr.OS == "Android" && !sandbox.B2G;
644 sandbox.cocoaWidget = xr.widgetToolkit == "cocoa";
645 sandbox.gtk2Widget = xr.widgetToolkit == "gtk2";
646 sandbox.qtWidget = xr.widgetToolkit == "qt";
647 sandbox.winWidget = xr.widgetToolkit == "windows";
649 if (sandbox.Android) {
650 var sysInfo = CC["@mozilla.org/system-info;1"].getService(CI.nsIPropertyBag2);
652 // This is currently used to distinguish Android 4.0.3 (SDK version 15)
653 // and later from Android 2.x
654 sandbox.AndroidVersion = sysInfo.getPropertyAsInt32("version");
655 }
657 #if MOZ_ASAN
658 sandbox.AddressSanitizer = true;
659 #else
660 sandbox.AddressSanitizer = false;
661 #endif
663 #if MOZ_WEBRTC
664 sandbox.webrtc = true;
665 #else
666 sandbox.webrtc = false;
667 #endif
669 var hh = CC[NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX + "http"].
670 getService(CI.nsIHttpProtocolHandler);
671 sandbox.http = { __exposedProps__: {} };
672 for each (var prop in [ "userAgent", "appName", "appVersion",
673 "vendor", "vendorSub",
674 "product", "productSub",
675 "platform", "oscpu", "language", "misc" ]) {
676 sandbox.http[prop] = hh[prop];
677 sandbox.http.__exposedProps__[prop] = "r";
678 }
680 // Set OSX to the Mac OS X version for Mac, and 0 otherwise.
681 var osxmatch = /Mac OS X (\d+.\d+)$/.exec(hh.oscpu);
682 sandbox.OSX = osxmatch ? parseFloat(osxmatch[1]) : 0;
684 // see if we have the test plugin available,
685 // and set a sandox prop accordingly
686 var navigator = gContainingWindow.navigator;
687 var testPlugin = navigator.plugins["Test Plug-in"];
688 sandbox.haveTestPlugin = !!testPlugin;
690 // Set a flag on sandbox if the windows default theme is active
691 var box = gContainingWindow.document.createElement("box");
692 box.setAttribute("id", "_box_windowsDefaultTheme");
693 gContainingWindow.document.documentElement.appendChild(box);
694 sandbox.windowsDefaultTheme = (gContainingWindow.getComputedStyle(box, null).display == "none");
695 gContainingWindow.document.documentElement.removeChild(box);
697 var prefs = CC["@mozilla.org/preferences-service;1"].
698 getService(CI.nsIPrefBranch);
699 try {
700 sandbox.nativeThemePref = !prefs.getBoolPref("mozilla.widget.disable-native-theme");
701 } catch (e) {
702 sandbox.nativeThemePref = true;
703 }
705 sandbox.prefs = {
706 __exposedProps__: {
707 getBoolPref: 'r',
708 getIntPref: 'r',
709 },
710 _prefs: prefs,
711 getBoolPref: function(p) { return this._prefs.getBoolPref(p); },
712 getIntPref: function(p) { return this._prefs.getIntPref(p); }
713 }
715 sandbox.testPluginIsOOP = function () {
716 try {
717 netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
718 } catch (ex) {}
720 var prefservice = Components.classes["@mozilla.org/preferences-service;1"]
721 .getService(CI.nsIPrefBranch);
723 var testPluginIsOOP = false;
724 if (navigator.platform.indexOf("Mac") == 0) {
725 var xulRuntime = Components.classes["@mozilla.org/xre/app-info;1"]
726 .getService(CI.nsIXULAppInfo)
727 .QueryInterface(CI.nsIXULRuntime);
728 if (xulRuntime.XPCOMABI.match(/x86-/)) {
729 try {
730 testPluginIsOOP = prefservice.getBoolPref("dom.ipc.plugins.enabled.i386.test.plugin");
731 } catch (e) {
732 testPluginIsOOP = prefservice.getBoolPref("dom.ipc.plugins.enabled.i386");
733 }
734 }
735 else if (xulRuntime.XPCOMABI.match(/x86_64-/)) {
736 try {
737 testPluginIsOOP = prefservice.getBoolPref("dom.ipc.plugins.enabled.x86_64.test.plugin");
738 } catch (e) {
739 testPluginIsOOP = prefservice.getBoolPref("dom.ipc.plugins.enabled.x86_64");
740 }
741 }
742 }
743 else {
744 testPluginIsOOP = prefservice.getBoolPref("dom.ipc.plugins.enabled");
745 }
747 return testPluginIsOOP;
748 };
750 // Tests shouldn't care about this except for when they need to
751 // crash the content process
752 sandbox.browserIsRemote = gBrowserIsRemote;
754 // Distinguish the Fennecs:
755 sandbox.xulFennec = sandbox.Android && sandbox.browserIsRemote;
756 sandbox.nativeFennec = sandbox.Android && !sandbox.browserIsRemote;
758 if (!gDumpedConditionSandbox) {
759 dump("REFTEST INFO | Dumping JSON representation of sandbox \n");
760 dump("REFTEST INFO | " + JSON.stringify(sandbox) + " \n");
761 gDumpedConditionSandbox = true;
762 }
763 return sandbox;
764 }
766 function AddPrefSettings(aWhere, aPrefName, aPrefValExpression, aSandbox, aTestPrefSettings, aRefPrefSettings)
767 {
768 var prefVal = Components.utils.evalInSandbox("(" + aPrefValExpression + ")", aSandbox);
769 var prefType;
770 var valType = typeof(prefVal);
771 if (valType == "boolean") {
772 prefType = PREF_BOOLEAN;
773 } else if (valType == "string") {
774 prefType = PREF_STRING;
775 } else if (valType == "number" && (parseInt(prefVal) == prefVal)) {
776 prefType = PREF_INTEGER;
777 } else {
778 return false;
779 }
780 var setting = { name: aPrefName,
781 type: prefType,
782 value: prefVal };
783 if (aWhere != "ref-") {
784 aTestPrefSettings.push(setting);
785 }
786 if (aWhere != "test-") {
787 aRefPrefSettings.push(setting);
788 }
789 return true;
790 }
792 function ReadTopManifest(aFileURL)
793 {
794 gURLs = new Array();
795 var url = gIOService.newURI(aFileURL, null, null);
796 if (!url)
797 throw "Expected a file or http URL for the manifest.";
798 ReadManifest(url, EXPECTED_PASS);
799 }
801 function AddTestItem(aTest)
802 {
803 if (gURLFilterRegex && !gURLFilterRegex.test(aTest.url1.spec))
804 return;
805 if (gFocusFilterMode == FOCUS_FILTER_NEEDS_FOCUS_TESTS &&
806 !aTest.needsFocus)
807 return;
808 if (gFocusFilterMode == FOCUS_FILTER_NON_NEEDS_FOCUS_TESTS &&
809 aTest.needsFocus)
810 return;
811 gURLs.push(aTest);
812 }
814 // Note: If you materially change the reftest manifest parsing,
815 // please keep the parser in print-manifest-dirs.py in sync.
816 function ReadManifest(aURL, inherited_status)
817 {
818 var secMan = CC[NS_SCRIPTSECURITYMANAGER_CONTRACTID]
819 .getService(CI.nsIScriptSecurityManager);
821 var listURL = aURL;
822 var channel = gIOService.newChannelFromURI(aURL);
823 var inputStream = channel.open();
824 if (channel instanceof Components.interfaces.nsIHttpChannel
825 && channel.responseStatus != 200) {
826 gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | HTTP ERROR : " +
827 channel.responseStatus + "\n");
828 }
829 var streamBuf = getStreamContent(inputStream);
830 inputStream.close();
831 var lines = streamBuf.split(/\n|\r|\r\n/);
833 // Build the sandbox for fails-if(), etc., condition evaluation.
834 var sandbox = BuildConditionSandbox(aURL);
835 var lineNo = 0;
836 var urlprefix = "";
837 var defaultTestPrefSettings = [], defaultRefPrefSettings = [];
838 for each (var str in lines) {
839 ++lineNo;
840 if (str.charAt(0) == "#")
841 continue; // entire line was a comment
842 var i = str.search(/\s+#/);
843 if (i >= 0)
844 str = str.substring(0, i);
845 // strip leading and trailing whitespace
846 str = str.replace(/^\s*/, '').replace(/\s*$/, '');
847 if (!str || str == "")
848 continue;
849 var items = str.split(/\s+/); // split on whitespace
851 if (items[0] == "url-prefix") {
852 if (items.length != 2)
853 throw "url-prefix requires one url in manifest file " + aURL.spec + " line " + lineNo;
854 urlprefix = items[1];
855 continue;
856 }
858 if (items[0] == "default-preferences") {
859 var m;
860 var item;
861 defaultTestPrefSettings = [];
862 defaultRefPrefSettings = [];
863 items.shift();
864 while ((item = items.shift())) {
865 if (!(m = item.match(gPrefItemRE))) {
866 throw "Unexpected item in default-preferences list in manifest file " + aURL.spec + " line " + lineNo;
867 }
868 if (!AddPrefSettings(m[1], m[2], m[3], sandbox, defaultTestPrefSettings, defaultRefPrefSettings)) {
869 throw "Error in pref value in manifest file " + aURL.spec + " line " + lineNo;
870 }
871 }
872 continue;
873 }
875 var expected_status = EXPECTED_PASS;
876 var allow_silent_fail = false;
877 var minAsserts = 0;
878 var maxAsserts = 0;
879 var needs_focus = false;
880 var slow = false;
881 var testPrefSettings = defaultTestPrefSettings.concat();
882 var refPrefSettings = defaultRefPrefSettings.concat();
883 var fuzzy_max_delta = 2;
884 var fuzzy_max_pixels = 1;
886 while (items[0].match(/^(fails|needs-focus|random|skip|asserts|slow|require-or|silentfail|pref|test-pref|ref-pref|fuzzy)/)) {
887 var item = items.shift();
888 var stat;
889 var cond;
890 var m = item.match(/^(fails|random|skip|silentfail)-if(\(.*\))$/);
891 if (m) {
892 stat = m[1];
893 // Note: m[2] contains the parentheses, and we want them.
894 cond = Components.utils.evalInSandbox(m[2], sandbox);
895 } else if (item.match(/^(fails|random|skip)$/)) {
896 stat = item;
897 cond = true;
898 } else if (item == "needs-focus") {
899 needs_focus = true;
900 cond = false;
901 } else if ((m = item.match(/^asserts\((\d+)(-\d+)?\)$/))) {
902 cond = false;
903 minAsserts = Number(m[1]);
904 maxAsserts = (m[2] == undefined) ? minAsserts
905 : Number(m[2].substring(1));
906 } else if ((m = item.match(/^asserts-if\((.*?),(\d+)(-\d+)?\)$/))) {
907 cond = false;
908 if (Components.utils.evalInSandbox("(" + m[1] + ")", sandbox)) {
909 minAsserts = Number(m[2]);
910 maxAsserts =
911 (m[3] == undefined) ? minAsserts
912 : Number(m[3].substring(1));
913 }
914 } else if (item == "slow") {
915 cond = false;
916 slow = true;
917 } else if ((m = item.match(/^require-or\((.*?)\)$/))) {
918 var args = m[1].split(/,/);
919 if (args.length != 2) {
920 throw "Error 7 in manifest file " + aURL.spec + " line " + lineNo + ": wrong number of args to require-or";
921 }
922 var [precondition_str, fallback_action] = args;
923 var preconditions = precondition_str.split(/&&/);
924 cond = false;
925 for each (var precondition in preconditions) {
926 if (precondition === "debugMode") {
927 // Currently unimplemented. Requires asynchronous
928 // JSD call + getting an event while no JS is running
929 stat = fallback_action;
930 cond = true;
931 break;
932 } else if (precondition === "true") {
933 // For testing
934 } else {
935 // Unknown precondition. Assume it is unimplemented.
936 stat = fallback_action;
937 cond = true;
938 break;
939 }
940 }
941 } else if ((m = item.match(/^slow-if\((.*?)\)$/))) {
942 cond = false;
943 if (Components.utils.evalInSandbox("(" + m[1] + ")", sandbox))
944 slow = true;
945 } else if (item == "silentfail") {
946 cond = false;
947 allow_silent_fail = true;
948 } else if ((m = item.match(gPrefItemRE))) {
949 cond = false;
950 if (!AddPrefSettings(m[1], m[2], m[3], sandbox, testPrefSettings, refPrefSettings)) {
951 throw "Error in pref value in manifest file " + aURL.spec + " line " + lineNo;
952 }
953 } else if ((m = item.match(/^fuzzy\((\d+),(\d+)\)$/))) {
954 cond = false;
955 expected_status = EXPECTED_FUZZY;
956 fuzzy_max_delta = Number(m[1]);
957 fuzzy_max_pixels = Number(m[2]);
958 } else if ((m = item.match(/^fuzzy-if\((.*?),(\d+),(\d+)\)$/))) {
959 cond = false;
960 if (Components.utils.evalInSandbox("(" + m[1] + ")", sandbox)) {
961 expected_status = EXPECTED_FUZZY;
962 fuzzy_max_delta = Number(m[2]);
963 fuzzy_max_pixels = Number(m[3]);
964 }
965 } else {
966 throw "Error 1 in manifest file " + aURL.spec + " line " + lineNo;
967 }
969 if (cond) {
970 if (stat == "fails") {
971 expected_status = EXPECTED_FAIL;
972 } else if (stat == "random") {
973 expected_status = EXPECTED_RANDOM;
974 } else if (stat == "skip") {
975 expected_status = EXPECTED_DEATH;
976 } else if (stat == "silentfail") {
977 allow_silent_fail = true;
978 }
979 }
980 }
982 expected_status = Math.max(expected_status, inherited_status);
984 if (minAsserts > maxAsserts) {
985 throw "Bad range in manifest file " + aURL.spec + " line " + lineNo;
986 }
988 var runHttp = false;
989 var httpDepth;
990 if (items[0] == "HTTP") {
991 runHttp = (aURL.scheme == "file"); // We can't yet run the local HTTP server
992 // for non-local reftests.
993 httpDepth = 0;
994 items.shift();
995 } else if (items[0].match(/HTTP\(\.\.(\/\.\.)*\)/)) {
996 // Accept HTTP(..), HTTP(../..), HTTP(../../..), etc.
997 runHttp = (aURL.scheme == "file"); // We can't yet run the local HTTP server
998 // for non-local reftests.
999 httpDepth = (items[0].length - 5) / 3;
1000 items.shift();
1001 }
1003 // do not prefix the url for include commands or urls specifying
1004 // a protocol
1005 if (urlprefix && items[0] != "include") {
1006 if (items.length > 1 && !items[1].match(gProtocolRE)) {
1007 items[1] = urlprefix + items[1];
1008 }
1009 if (items.length > 2 && !items[2].match(gProtocolRE)) {
1010 items[2] = urlprefix + items[2];
1011 }
1012 }
1014 var principal = secMan.getSimpleCodebasePrincipal(aURL);
1016 if (items[0] == "include") {
1017 if (items.length != 2 || runHttp)
1018 throw "Error 2 in manifest file " + aURL.spec + " line " + lineNo;
1019 var incURI = gIOService.newURI(items[1], null, listURL);
1020 secMan.checkLoadURIWithPrincipal(principal, incURI,
1021 CI.nsIScriptSecurityManager.DISALLOW_SCRIPT);
1022 ReadManifest(incURI, expected_status);
1023 } else if (items[0] == TYPE_LOAD) {
1024 if (items.length != 2 ||
1025 (expected_status != EXPECTED_PASS &&
1026 expected_status != EXPECTED_DEATH))
1027 throw "Error 3 in manifest file " + aURL.spec + " line " + lineNo;
1028 var [testURI] = runHttp
1029 ? ServeFiles(principal, httpDepth,
1030 listURL, [items[1]])
1031 : [gIOService.newURI(items[1], null, listURL)];
1032 var prettyPath = runHttp
1033 ? gIOService.newURI(items[1], null, listURL).spec
1034 : testURI.spec;
1035 secMan.checkLoadURIWithPrincipal(principal, testURI,
1036 CI.nsIScriptSecurityManager.DISALLOW_SCRIPT);
1037 AddTestItem({ type: TYPE_LOAD,
1038 expected: expected_status,
1039 allowSilentFail: allow_silent_fail,
1040 prettyPath: prettyPath,
1041 minAsserts: minAsserts,
1042 maxAsserts: maxAsserts,
1043 needsFocus: needs_focus,
1044 slow: slow,
1045 prefSettings1: testPrefSettings,
1046 prefSettings2: refPrefSettings,
1047 fuzzyMaxDelta: fuzzy_max_delta,
1048 fuzzyMaxPixels: fuzzy_max_pixels,
1049 url1: testURI,
1050 url2: null });
1051 } else if (items[0] == TYPE_SCRIPT) {
1052 if (items.length != 2)
1053 throw "Error 4 in manifest file " + aURL.spec + " line " + lineNo;
1054 var [testURI] = runHttp
1055 ? ServeFiles(principal, httpDepth,
1056 listURL, [items[1]])
1057 : [gIOService.newURI(items[1], null, listURL)];
1058 var prettyPath = runHttp
1059 ? gIOService.newURI(items[1], null, listURL).spec
1060 : testURI.spec;
1061 secMan.checkLoadURIWithPrincipal(principal, testURI,
1062 CI.nsIScriptSecurityManager.DISALLOW_SCRIPT);
1063 AddTestItem({ type: TYPE_SCRIPT,
1064 expected: expected_status,
1065 allowSilentFail: allow_silent_fail,
1066 prettyPath: prettyPath,
1067 minAsserts: minAsserts,
1068 maxAsserts: maxAsserts,
1069 needsFocus: needs_focus,
1070 slow: slow,
1071 prefSettings1: testPrefSettings,
1072 prefSettings2: refPrefSettings,
1073 fuzzyMaxDelta: fuzzy_max_delta,
1074 fuzzyMaxPixels: fuzzy_max_pixels,
1075 url1: testURI,
1076 url2: null });
1077 } else if (items[0] == TYPE_REFTEST_EQUAL || items[0] == TYPE_REFTEST_NOTEQUAL) {
1078 if (items.length != 3)
1079 throw "Error 5 in manifest file " + aURL.spec + " line " + lineNo;
1080 var [testURI, refURI] = runHttp
1081 ? ServeFiles(principal, httpDepth,
1082 listURL, [items[1], items[2]])
1083 : [gIOService.newURI(items[1], null, listURL),
1084 gIOService.newURI(items[2], null, listURL)];
1085 var prettyPath = runHttp
1086 ? gIOService.newURI(items[1], null, listURL).spec
1087 : testURI.spec;
1088 secMan.checkLoadURIWithPrincipal(principal, testURI,
1089 CI.nsIScriptSecurityManager.DISALLOW_SCRIPT);
1090 secMan.checkLoadURIWithPrincipal(principal, refURI,
1091 CI.nsIScriptSecurityManager.DISALLOW_SCRIPT);
1092 AddTestItem({ type: items[0],
1093 expected: expected_status,
1094 allowSilentFail: allow_silent_fail,
1095 prettyPath: prettyPath,
1096 minAsserts: minAsserts,
1097 maxAsserts: maxAsserts,
1098 needsFocus: needs_focus,
1099 slow: slow,
1100 prefSettings1: testPrefSettings,
1101 prefSettings2: refPrefSettings,
1102 fuzzyMaxDelta: fuzzy_max_delta,
1103 fuzzyMaxPixels: fuzzy_max_pixels,
1104 url1: testURI,
1105 url2: refURI });
1106 } else {
1107 throw "Error 6 in manifest file " + aURL.spec + " line " + lineNo;
1108 }
1109 }
1110 }
1112 function AddURIUseCount(uri)
1113 {
1114 if (uri == null)
1115 return;
1117 var spec = uri.spec;
1118 if (spec in gURIUseCounts) {
1119 gURIUseCounts[spec]++;
1120 } else {
1121 gURIUseCounts[spec] = 1;
1122 }
1123 }
1125 function BuildUseCounts()
1126 {
1127 gURIUseCounts = {};
1128 for (var i = 0; i < gURLs.length; ++i) {
1129 var url = gURLs[i];
1130 if (url.expected != EXPECTED_DEATH &&
1131 (url.type == TYPE_REFTEST_EQUAL ||
1132 url.type == TYPE_REFTEST_NOTEQUAL)) {
1133 if (url.prefSettings1.length == 0) {
1134 AddURIUseCount(gURLs[i].url1);
1135 }
1136 if (url.prefSettings2.length == 0) {
1137 AddURIUseCount(gURLs[i].url2);
1138 }
1139 }
1140 }
1141 }
1143 function ServeFiles(manifestPrincipal, depth, aURL, files)
1144 {
1145 var listURL = aURL.QueryInterface(CI.nsIFileURL);
1146 var directory = listURL.file.parent;
1148 // Allow serving a tree that's an ancestor of the directory containing
1149 // the files so that they can use resources in ../ (etc.).
1150 var dirPath = "/";
1151 while (depth > 0) {
1152 dirPath = "/" + directory.leafName + dirPath;
1153 directory = directory.parent;
1154 --depth;
1155 }
1157 gCount++;
1158 var path = "/" + Date.now() + "/" + gCount;
1159 gServer.registerDirectory(path + "/", directory);
1161 var secMan = CC[NS_SCRIPTSECURITYMANAGER_CONTRACTID]
1162 .getService(CI.nsIScriptSecurityManager);
1164 var testbase = gIOService.newURI("http://localhost:" + gHttpServerPort +
1165 path + dirPath, null, null);
1167 function FileToURI(file)
1168 {
1169 // Only serve relative URIs via the HTTP server, not absolute
1170 // ones like about:blank.
1171 var testURI = gIOService.newURI(file, null, testbase);
1173 // XXX necessary? manifestURL guaranteed to be file, others always HTTP
1174 secMan.checkLoadURIWithPrincipal(manifestPrincipal, testURI,
1175 CI.nsIScriptSecurityManager.DISALLOW_SCRIPT);
1177 return testURI;
1178 }
1180 return files.map(FileToURI);
1181 }
1183 // Return true iff this window is focused when this function returns.
1184 function Focus()
1185 {
1186 var fm = CC["@mozilla.org/focus-manager;1"].getService(CI.nsIFocusManager);
1187 fm.focusedWindow = gContainingWindow;
1188 #ifdef XP_MACOSX
1189 try {
1190 var dock = CC["@mozilla.org/widget/macdocksupport;1"].getService(CI.nsIMacDockSupport);
1191 dock.activateApplication(true);
1192 } catch(ex) {
1193 }
1194 #endif // XP_MACOSX
1195 return true;
1196 }
1198 function Blur()
1199 {
1200 // On non-remote reftests, this will transfer focus to the dummy window
1201 // we created to hold focus for non-needs-focus tests. Buggy tests
1202 // (ones which require focus but don't request needs-focus) will then
1203 // fail.
1204 gContainingWindow.blur();
1205 }
1207 function StartCurrentTest()
1208 {
1209 gTestLog = [];
1211 // make sure we don't run tests that are expected to kill the browser
1212 while (gURLs.length > 0) {
1213 var test = gURLs[0];
1214 if (test.expected == EXPECTED_DEATH) {
1215 ++gTestResults.Skip;
1216 gDumpLog("REFTEST TEST-KNOWN-FAIL | " + test.url1.spec + " | (SKIP)\n");
1217 gURLs.shift();
1218 } else if (test.needsFocus && !Focus()) {
1219 // FIXME: Marking this as a known fail is dangerous! What
1220 // if it starts failing all the time?
1221 ++gTestResults.Skip;
1222 gDumpLog("REFTEST TEST-KNOWN-FAIL | " + test.url1.spec + " | (SKIPPED; COULDN'T GET FOCUS)\n");
1223 gURLs.shift();
1224 } else if (test.slow && !gRunSlowTests) {
1225 ++gTestResults.Slow;
1226 gDumpLog("REFTEST TEST-KNOWN-SLOW | " + test.url1.spec + " | (SLOW)\n");
1227 gURLs.shift();
1228 } else {
1229 break;
1230 }
1231 }
1233 if (gURLs.length == 0) {
1234 RestoreChangedPreferences();
1235 DoneTests();
1236 }
1237 else {
1238 gDumpLog("REFTEST TEST-START | " + gURLs[0].prettyPath + "\n");
1239 if (!gURLs[0].needsFocus) {
1240 Blur();
1241 }
1242 var currentTest = gTotalTests - gURLs.length;
1243 gContainingWindow.document.title = "reftest: " + currentTest + " / " + gTotalTests +
1244 " (" + Math.floor(100 * (currentTest / gTotalTests)) + "%)";
1245 StartCurrentURI(1);
1246 }
1247 }
1249 function StartCurrentURI(aState)
1250 {
1251 gState = aState;
1252 gCurrentURL = gURLs[0]["url" + aState].spec;
1254 RestoreChangedPreferences();
1256 var prefSettings = gURLs[0]["prefSettings" + aState];
1257 if (prefSettings.length > 0) {
1258 var prefs = Components.classes["@mozilla.org/preferences-service;1"].
1259 getService(Components.interfaces.nsIPrefBranch);
1260 var badPref = undefined;
1261 try {
1262 prefSettings.forEach(function(ps) {
1263 var oldVal;
1264 if (ps.type == PREF_BOOLEAN) {
1265 try {
1266 oldVal = prefs.getBoolPref(ps.name);
1267 } catch (e) {
1268 badPref = "boolean preference '" + ps.name + "'";
1269 throw "bad pref";
1270 }
1271 } else if (ps.type == PREF_STRING) {
1272 try {
1273 oldVal = prefs.getCharPref(ps.name);
1274 } catch (e) {
1275 badPref = "string preference '" + ps.name + "'";
1276 throw "bad pref";
1277 }
1278 } else if (ps.type == PREF_INTEGER) {
1279 try {
1280 oldVal = prefs.getIntPref(ps.name);
1281 } catch (e) {
1282 badPref = "integer preference '" + ps.name + "'";
1283 throw "bad pref";
1284 }
1285 } else {
1286 throw "internal error - unknown preference type";
1287 }
1288 if (oldVal != ps.value) {
1289 gPrefsToRestore.push( { name: ps.name,
1290 type: ps.type,
1291 value: oldVal } );
1292 var value = ps.value;
1293 if (ps.type == PREF_BOOLEAN) {
1294 prefs.setBoolPref(ps.name, value);
1295 } else if (ps.type == PREF_STRING) {
1296 prefs.setCharPref(ps.name, value);
1297 value = '"' + value + '"';
1298 } else if (ps.type == PREF_INTEGER) {
1299 prefs.setIntPref(ps.name, value);
1300 }
1301 gDumpLog("SET PREFERENCE pref(" + ps.name + "," + value + ")\n");
1302 }
1303 });
1304 } catch (e) {
1305 if (e == "bad pref") {
1306 var test = gURLs[0];
1307 if (test.expected == EXPECTED_FAIL) {
1308 gDumpLog("REFTEST TEST-KNOWN-FAIL | " + test.url1.spec +
1309 " | (SKIPPED; " + badPref + " not known or wrong type)\n");
1310 ++gTestResults.Skip;
1311 } else {
1312 gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + test.url1.spec +
1313 " | " + badPref + " not known or wrong type\n");
1314 ++gTestResults.UnexpectedFail;
1315 }
1316 } else {
1317 throw e;
1318 }
1319 }
1320 if (badPref != undefined) {
1321 // skip the test that had a bad preference
1322 gURLs.shift();
1324 StartCurrentTest();
1325 return;
1326 }
1327 }
1329 if (prefSettings.length == 0 &&
1330 gURICanvases[gCurrentURL] &&
1331 (gURLs[0].type == TYPE_REFTEST_EQUAL ||
1332 gURLs[0].type == TYPE_REFTEST_NOTEQUAL) &&
1333 gURLs[0].maxAsserts == 0) {
1334 // Pretend the document loaded --- RecordResult will notice
1335 // there's already a canvas for this URL
1336 gContainingWindow.setTimeout(RecordResult, 0);
1337 } else {
1338 var currentTest = gTotalTests - gURLs.length;
1339 gDumpLog("REFTEST TEST-LOAD | " + gCurrentURL + " | " + currentTest + " / " + gTotalTests +
1340 " (" + Math.floor(100 * (currentTest / gTotalTests)) + "%)\n");
1341 LogInfo("START " + gCurrentURL);
1342 var type = gURLs[0].type
1343 if (TYPE_SCRIPT == type) {
1344 SendLoadScriptTest(gCurrentURL, gLoadTimeout);
1345 } else {
1346 SendLoadTest(type, gCurrentURL, gLoadTimeout);
1347 }
1348 }
1349 }
1351 function DoneTests()
1352 {
1353 gDumpLog("REFTEST FINISHED: Slowest test took " + gSlowestTestTime +
1354 "ms (" + gSlowestTestURL + ")\n");
1356 gDumpLog("REFTEST INFO | Result summary:\n");
1357 var count = gTestResults.Pass + gTestResults.LoadOnly;
1358 gDumpLog("REFTEST INFO | Successful: " + count + " (" +
1359 gTestResults.Pass + " pass, " +
1360 gTestResults.LoadOnly + " load only)\n");
1361 count = gTestResults.Exception + gTestResults.FailedLoad +
1362 gTestResults.UnexpectedFail + gTestResults.UnexpectedPass +
1363 gTestResults.AssertionUnexpected +
1364 gTestResults.AssertionUnexpectedFixed;
1365 gDumpLog("REFTEST INFO | Unexpected: " + count + " (" +
1366 gTestResults.UnexpectedFail + " unexpected fail, " +
1367 gTestResults.UnexpectedPass + " unexpected pass, " +
1368 gTestResults.AssertionUnexpected + " unexpected asserts, " +
1369 gTestResults.AssertionUnexpectedFixed + " unexpected fixed asserts, " +
1370 gTestResults.FailedLoad + " failed load, " +
1371 gTestResults.Exception + " exception)\n");
1372 count = gTestResults.KnownFail + gTestResults.AssertionKnown +
1373 gTestResults.Random + gTestResults.Skip + gTestResults.Slow;
1374 gDumpLog("REFTEST INFO | Known problems: " + count + " (" +
1375 gTestResults.KnownFail + " known fail, " +
1376 gTestResults.AssertionKnown + " known asserts, " +
1377 gTestResults.Random + " random, " +
1378 gTestResults.Skip + " skipped, " +
1379 gTestResults.Slow + " slow)\n");
1381 gDumpLog("REFTEST INFO | Total canvas count = " + gRecycledCanvases.length + "\n");
1383 gDumpLog("REFTEST TEST-START | Shutdown\n");
1384 function onStopped() {
1385 let appStartup = CC["@mozilla.org/toolkit/app-startup;1"].getService(CI.nsIAppStartup);
1386 appStartup.quit(CI.nsIAppStartup.eForceQuit);
1387 }
1388 if (gServer) {
1389 gServer.stop(onStopped);
1390 }
1391 else {
1392 onStopped();
1393 }
1394 }
1396 function UpdateCanvasCache(url, canvas)
1397 {
1398 var spec = url.spec;
1400 --gURIUseCounts[spec];
1402 if (gNoCanvasCache || gURIUseCounts[spec] == 0) {
1403 ReleaseCanvas(canvas);
1404 delete gURICanvases[spec];
1405 } else if (gURIUseCounts[spec] > 0) {
1406 gURICanvases[spec] = canvas;
1407 } else {
1408 throw "Use counts were computed incorrectly";
1409 }
1410 }
1412 // Recompute drawWindow flags for every drawWindow operation.
1413 // We have to do this every time since our window can be
1414 // asynchronously resized (e.g. by the window manager, to make
1415 // it fit on screen) at unpredictable times.
1416 // Fortunately this is pretty cheap.
1417 function DoDrawWindow(ctx, x, y, w, h)
1418 {
1419 var flags = ctx.DRAWWINDOW_DRAW_CARET | ctx.DRAWWINDOW_DRAW_VIEW;
1420 var testRect = gBrowser.getBoundingClientRect();
1421 if (gIgnoreWindowSize ||
1422 (0 <= testRect.left &&
1423 0 <= testRect.top &&
1424 gContainingWindow.innerWidth >= testRect.right &&
1425 gContainingWindow.innerHeight >= testRect.bottom)) {
1426 // We can use the window's retained layer manager
1427 // because the window is big enough to display the entire
1428 // browser element
1429 flags |= ctx.DRAWWINDOW_USE_WIDGET_LAYERS;
1430 } else if (gBrowserIsRemote) {
1431 gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gCurrentURL + " | can't drawWindow remote content\n");
1432 ++gTestResults.Exception;
1433 }
1435 if (gDrawWindowFlags != flags) {
1436 // Every time the flags change, dump the new state.
1437 gDrawWindowFlags = flags;
1438 var flagsStr = "DRAWWINDOW_DRAW_CARET | DRAWWINDOW_DRAW_VIEW";
1439 if (flags & ctx.DRAWWINDOW_USE_WIDGET_LAYERS) {
1440 flagsStr += " | DRAWWINDOW_USE_WIDGET_LAYERS";
1441 } else {
1442 // Output a special warning because we need to be able to detect
1443 // this whenever it happens.
1444 gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | WARNING: USE_WIDGET_LAYERS disabled\n");
1445 }
1446 gDumpLog("REFTEST INFO | drawWindow flags = " + flagsStr +
1447 "; window size = " + gContainingWindow.innerWidth + "," + gContainingWindow.innerHeight +
1448 "; test browser size = " + testRect.width + "," + testRect.height +
1449 "\n");
1450 }
1452 LogInfo("DoDrawWindow " + x + "," + y + "," + w + "," + h);
1453 ctx.drawWindow(gContainingWindow, x, y, w, h, "rgb(255,255,255)",
1454 gDrawWindowFlags);
1455 }
1457 function InitCurrentCanvasWithSnapshot()
1458 {
1459 LogInfo("Initializing canvas snapshot");
1461 if (gURLs[0].type == TYPE_LOAD || gURLs[0].type == TYPE_SCRIPT) {
1462 // We don't want to snapshot this kind of test
1463 return false;
1464 }
1466 if (!gCurrentCanvas) {
1467 gCurrentCanvas = AllocateCanvas();
1468 }
1470 var ctx = gCurrentCanvas.getContext("2d");
1471 DoDrawWindow(ctx, 0, 0, gCurrentCanvas.width, gCurrentCanvas.height);
1472 return true;
1473 }
1475 function UpdateCurrentCanvasForInvalidation(rects)
1476 {
1477 LogInfo("Updating canvas for invalidation");
1479 if (!gCurrentCanvas) {
1480 return;
1481 }
1483 var ctx = gCurrentCanvas.getContext("2d");
1484 for (var i = 0; i < rects.length; ++i) {
1485 var r = rects[i];
1486 // Set left/top/right/bottom to pixel boundaries
1487 var left = Math.floor(r.left);
1488 var top = Math.floor(r.top);
1489 var right = Math.ceil(r.right);
1490 var bottom = Math.ceil(r.bottom);
1492 ctx.save();
1493 ctx.translate(left, top);
1494 DoDrawWindow(ctx, left, top, right - left, bottom - top);
1495 ctx.restore();
1496 }
1497 }
1499 function UpdateWholeCurrentCanvasForInvalidation()
1500 {
1501 LogInfo("Updating entire canvas for invalidation");
1503 if (!gCurrentCanvas) {
1504 return;
1505 }
1507 var ctx = gCurrentCanvas.getContext("2d");
1508 DoDrawWindow(ctx, 0, 0, gCurrentCanvas.width, gCurrentCanvas.height);
1509 }
1511 function RecordResult(testRunTime, errorMsg, scriptResults)
1512 {
1513 LogInfo("RecordResult fired");
1515 // Keep track of which test was slowest, and how long it took.
1516 if (testRunTime > gSlowestTestTime) {
1517 gSlowestTestTime = testRunTime;
1518 gSlowestTestURL = gCurrentURL;
1519 }
1521 // Not 'const ...' because of 'EXPECTED_*' value dependency.
1522 var outputs = {};
1523 const randomMsg = "(EXPECTED RANDOM)";
1524 outputs[EXPECTED_PASS] = {
1525 true: {s: "TEST-PASS" , n: "Pass"},
1526 false: {s: "TEST-UNEXPECTED-FAIL" , n: "UnexpectedFail"}
1527 };
1528 outputs[EXPECTED_FAIL] = {
1529 true: {s: "TEST-UNEXPECTED-PASS" , n: "UnexpectedPass"},
1530 false: {s: "TEST-KNOWN-FAIL" , n: "KnownFail"}
1531 };
1532 outputs[EXPECTED_RANDOM] = {
1533 true: {s: "TEST-PASS" + randomMsg , n: "Random"},
1534 false: {s: "TEST-KNOWN-FAIL" + randomMsg, n: "Random"}
1535 };
1536 outputs[EXPECTED_FUZZY] = outputs[EXPECTED_PASS];
1538 var output;
1540 if (gURLs[0].type == TYPE_LOAD) {
1541 ++gTestResults.LoadOnly;
1542 gDumpLog("REFTEST TEST-PASS | " + gURLs[0].prettyPath + " | (LOAD ONLY)\n");
1543 gCurrentCanvas = null;
1544 FinishTestItem();
1545 return;
1546 }
1547 if (gURLs[0].type == TYPE_SCRIPT) {
1548 var expected = gURLs[0].expected;
1550 if (errorMsg) {
1551 // Force an unexpected failure to alert the test author to fix the test.
1552 expected = EXPECTED_PASS;
1553 } else if (scriptResults.length == 0) {
1554 // This failure may be due to a JavaScript Engine bug causing
1555 // early termination of the test. If we do not allow silent
1556 // failure, report an error.
1557 if (!gURLs[0].allowSilentFail)
1558 errorMsg = "No test results reported. (SCRIPT)\n";
1559 else
1560 gDumpLog("REFTEST INFO | An expected silent failure occurred \n");
1561 }
1563 if (errorMsg) {
1564 output = outputs[expected][false];
1565 ++gTestResults[output.n];
1566 var result = "REFTEST " + output.s + " | " +
1567 gURLs[0].prettyPath + " | " + // the URL being tested
1568 errorMsg;
1570 gDumpLog(result);
1571 FinishTestItem();
1572 return;
1573 }
1575 var anyFailed = scriptResults.some(function(result) { return !result.passed; });
1576 var outputPair;
1577 if (anyFailed && expected == EXPECTED_FAIL) {
1578 // If we're marked as expected to fail, and some (but not all) tests
1579 // passed, treat those tests as though they were marked random
1580 // (since we can't tell whether they were really intended to be
1581 // marked failing or not).
1582 outputPair = { true: outputs[EXPECTED_RANDOM][true],
1583 false: outputs[expected][false] };
1584 } else {
1585 outputPair = outputs[expected];
1586 }
1587 var index = 0;
1588 scriptResults.forEach(function(result) {
1589 var output = outputPair[result.passed];
1591 ++gTestResults[output.n];
1592 result = "REFTEST " + output.s + " | " +
1593 gURLs[0].prettyPath + " | " + // the URL being tested
1594 result.description + " item " + (++index) + "\n";
1595 gDumpLog(result);
1596 });
1598 if (anyFailed && expected == EXPECTED_PASS) {
1599 FlushTestLog();
1600 }
1602 FinishTestItem();
1603 return;
1604 }
1606 if (gURLs[0]["prefSettings" + gState].length == 0 &&
1607 gURICanvases[gCurrentURL]) {
1608 gCurrentCanvas = gURICanvases[gCurrentURL];
1609 }
1610 if (gCurrentCanvas == null) {
1611 gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gCurrentURL + " | program error managing snapshots\n");
1612 ++gTestResults.Exception;
1613 }
1614 if (gState == 1) {
1615 gCanvas1 = gCurrentCanvas;
1616 } else {
1617 gCanvas2 = gCurrentCanvas;
1618 }
1619 gCurrentCanvas = null;
1621 ResetRenderingState();
1623 switch (gState) {
1624 case 1:
1625 // First document has been loaded.
1626 // Proceed to load the second document.
1628 CleanUpCrashDumpFiles();
1629 StartCurrentURI(2);
1630 break;
1631 case 2:
1632 // Both documents have been loaded. Compare the renderings and see
1633 // if the comparison result matches the expected result specified
1634 // in the manifest.
1636 // number of different pixels
1637 var differences;
1638 // whether the two renderings match:
1639 var equal;
1640 var maxDifference = {};
1642 differences = gWindowUtils.compareCanvases(gCanvas1, gCanvas2, maxDifference);
1643 equal = (differences == 0);
1645 // what is expected on this platform (PASS, FAIL, or RANDOM)
1646 var expected = gURLs[0].expected;
1648 if (maxDifference.value > 0 && maxDifference.value <= gURLs[0].fuzzyMaxDelta &&
1649 differences <= gURLs[0].fuzzyMaxPixels) {
1650 if (equal) {
1651 throw "Inconsistent result from compareCanvases.";
1652 }
1653 equal = expected == EXPECTED_FUZZY;
1654 gDumpLog("REFTEST fuzzy match\n");
1655 }
1657 // whether the comparison result matches what is in the manifest
1658 var test_passed = (equal == (gURLs[0].type == TYPE_REFTEST_EQUAL)) && !gFailedNoPaint;
1660 output = outputs[expected][test_passed];
1662 ++gTestResults[output.n];
1664 // It's possible that we failed both reftest-no-paint and the normal comparison, but we don't
1665 // have a way to annotate these separately, so just print an error for the no-paint failure.
1666 if (gFailedNoPaint) {
1667 if (expected == EXPECTED_FAIL) {
1668 gDumpLog("REFTEST TEST-KNOWN-FAIL | " + gURLs[0].prettyPath + " | failed reftest-no-paint\n");
1669 } else {
1670 gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gURLs[0].prettyPath + " | failed reftest-no-paint\n");
1671 }
1672 } else {
1673 var result = "REFTEST " + output.s + " | " +
1674 gURLs[0].prettyPath + " | "; // the URL being tested
1675 switch (gURLs[0].type) {
1676 case TYPE_REFTEST_NOTEQUAL:
1677 result += "image comparison (!=)";
1678 break;
1679 case TYPE_REFTEST_EQUAL:
1680 result += "image comparison (==)";
1681 break;
1682 }
1684 if (!test_passed && expected == EXPECTED_PASS ||
1685 !test_passed && expected == EXPECTED_FUZZY ||
1686 test_passed && expected == EXPECTED_FAIL) {
1687 if (!equal) {
1688 result += ", max difference: " + maxDifference.value + ", number of differing pixels: " + differences + "\n";
1689 result += "REFTEST IMAGE 1 (TEST): " + gCanvas1.toDataURL() + "\n";
1690 result += "REFTEST IMAGE 2 (REFERENCE): " + gCanvas2.toDataURL() + "\n";
1691 } else {
1692 result += "\n";
1693 result += "REFTEST IMAGE: " + gCanvas1.toDataURL() + "\n";
1694 }
1695 } else {
1696 result += "\n";
1697 }
1699 gDumpLog(result);
1700 }
1702 if (!test_passed && expected == EXPECTED_PASS) {
1703 FlushTestLog();
1704 }
1706 if (gURLs[0].prefSettings1.length == 0) {
1707 UpdateCanvasCache(gURLs[0].url1, gCanvas1);
1708 }
1709 if (gURLs[0].prefSettings2.length == 0) {
1710 UpdateCanvasCache(gURLs[0].url2, gCanvas2);
1711 }
1713 CleanUpCrashDumpFiles();
1714 FinishTestItem();
1715 break;
1716 default:
1717 throw "Unexpected state.";
1718 }
1719 }
1721 function LoadFailed(why)
1722 {
1723 ++gTestResults.FailedLoad;
1724 // Once bug 896840 is fixed, this can go away, but for now it will give log
1725 // output that is TBPL starable for bug 789751 and bug 720452.
1726 if (!why) {
1727 gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | load failed with unknown reason\n");
1728 }
1729 gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " +
1730 gURLs[0]["url" + gState].spec + " | load failed: " + why + "\n");
1731 FlushTestLog();
1732 FinishTestItem();
1733 }
1735 function RemoveExpectedCrashDumpFiles()
1736 {
1737 if (gExpectingProcessCrash) {
1738 for each (let crashFilename in gExpectedCrashDumpFiles) {
1739 let file = gCrashDumpDir.clone();
1740 file.append(crashFilename);
1741 if (file.exists()) {
1742 file.remove(false);
1743 }
1744 }
1745 }
1746 gExpectedCrashDumpFiles.length = 0;
1747 }
1749 function FindUnexpectedCrashDumpFiles()
1750 {
1751 if (!gCrashDumpDir.exists()) {
1752 return;
1753 }
1755 let entries = gCrashDumpDir.directoryEntries;
1756 if (!entries) {
1757 return;
1758 }
1760 let foundCrashDumpFile = false;
1761 while (entries.hasMoreElements()) {
1762 let file = entries.getNext().QueryInterface(CI.nsIFile);
1763 let path = String(file.path);
1764 if (path.match(/\.(dmp|extra)$/) && !gUnexpectedCrashDumpFiles[path]) {
1765 if (!foundCrashDumpFile) {
1766 ++gTestResults.UnexpectedFail;
1767 foundCrashDumpFile = true;
1768 gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gCurrentURL +
1769 " | This test left crash dumps behind, but we weren't expecting it to!\n");
1770 }
1771 gDumpLog("REFTEST INFO | Found unexpected crash dump file " + path +
1772 ".\n");
1773 gUnexpectedCrashDumpFiles[path] = true;
1774 }
1775 }
1776 }
1778 function CleanUpCrashDumpFiles()
1779 {
1780 RemoveExpectedCrashDumpFiles();
1781 FindUnexpectedCrashDumpFiles();
1782 gExpectingProcessCrash = false;
1783 }
1785 function FinishTestItem()
1786 {
1787 // Replace document with BLANK_URL_FOR_CLEARING in case there are
1788 // assertions when unloading.
1789 gDumpLog("REFTEST INFO | Loading a blank page\n");
1790 // After clearing, content will notify us of the assertion count
1791 // and tests will continue.
1792 SetAsyncScroll(false);
1793 SendClear();
1794 gFailedNoPaint = false;
1795 }
1797 function DoAssertionCheck(numAsserts)
1798 {
1799 if (gDebug.isDebugBuild) {
1800 if (gBrowserIsRemote) {
1801 // Count chrome-process asserts too when content is out of
1802 // process.
1803 var newAssertionCount = gDebug.assertionCount;
1804 var numLocalAsserts = newAssertionCount - gAssertionCount;
1805 gAssertionCount = newAssertionCount;
1807 numAsserts += numLocalAsserts;
1808 }
1810 var minAsserts = gURLs[0].minAsserts;
1811 var maxAsserts = gURLs[0].maxAsserts;
1813 var expectedAssertions = "expected " + minAsserts;
1814 if (minAsserts != maxAsserts) {
1815 expectedAssertions += " to " + maxAsserts;
1816 }
1817 expectedAssertions += " assertions";
1819 if (numAsserts < minAsserts) {
1820 ++gTestResults.AssertionUnexpectedFixed;
1821 gDumpLog("REFTEST TEST-UNEXPECTED-PASS | " + gURLs[0].prettyPath +
1822 " | assertion count " + numAsserts + " is less than " +
1823 expectedAssertions + "\n");
1824 } else if (numAsserts > maxAsserts) {
1825 ++gTestResults.AssertionUnexpected;
1826 gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gURLs[0].prettyPath +
1827 " | assertion count " + numAsserts + " is more than " +
1828 expectedAssertions + "\n");
1829 } else if (numAsserts != 0) {
1830 ++gTestResults.AssertionKnown;
1831 gDumpLog("REFTEST TEST-KNOWN-FAIL | " + gURLs[0].prettyPath +
1832 " | assertion count " + numAsserts + " matches " +
1833 expectedAssertions + "\n");
1834 }
1835 }
1837 gDumpLog("REFTEST TEST-END | " + gURLs[0].prettyPath + "\n");
1839 // And start the next test.
1840 gURLs.shift();
1841 StartCurrentTest();
1842 }
1844 function ResetRenderingState()
1845 {
1846 SendResetRenderingState();
1847 // We would want to clear any viewconfig here, if we add support for it
1848 }
1850 function RestoreChangedPreferences()
1851 {
1852 if (gPrefsToRestore.length > 0) {
1853 var prefs = Components.classes["@mozilla.org/preferences-service;1"].
1854 getService(Components.interfaces.nsIPrefBranch);
1855 gPrefsToRestore.reverse();
1856 gPrefsToRestore.forEach(function(ps) {
1857 var value = ps.value;
1858 if (ps.type == PREF_BOOLEAN) {
1859 prefs.setBoolPref(ps.name, value);
1860 } else if (ps.type == PREF_STRING) {
1861 prefs.setCharPref(ps.name, value);
1862 value = '"' + value + '"';
1863 } else if (ps.type == PREF_INTEGER) {
1864 prefs.setIntPref(ps.name, value);
1865 }
1866 gDumpLog("RESTORE PREFERENCE pref(" + ps.name + "," + value + ")\n");
1867 });
1868 gPrefsToRestore = [];
1869 }
1870 }
1872 function RegisterMessageListenersAndLoadContentScript()
1873 {
1874 gBrowserMessageManager.addMessageListener(
1875 "reftest:AssertionCount",
1876 function (m) { RecvAssertionCount(m.json.count); }
1877 );
1878 gBrowserMessageManager.addMessageListener(
1879 "reftest:ContentReady",
1880 function (m) { return RecvContentReady() }
1881 );
1882 gBrowserMessageManager.addMessageListener(
1883 "reftest:Exception",
1884 function (m) { RecvException(m.json.what) }
1885 );
1886 gBrowserMessageManager.addMessageListener(
1887 "reftest:FailedLoad",
1888 function (m) { RecvFailedLoad(m.json.why); }
1889 );
1890 gBrowserMessageManager.addMessageListener(
1891 "reftest:FailedNoPaint",
1892 function (m) { RecvFailedNoPaint(); }
1893 );
1894 gBrowserMessageManager.addMessageListener(
1895 "reftest:InitCanvasWithSnapshot",
1896 function (m) { return RecvInitCanvasWithSnapshot(); }
1897 );
1898 gBrowserMessageManager.addMessageListener(
1899 "reftest:Log",
1900 function (m) { RecvLog(m.json.type, m.json.msg); }
1901 );
1902 gBrowserMessageManager.addMessageListener(
1903 "reftest:ScriptResults",
1904 function (m) { RecvScriptResults(m.json.runtimeMs, m.json.error, m.json.results); }
1905 );
1906 gBrowserMessageManager.addMessageListener(
1907 "reftest:TestDone",
1908 function (m) { RecvTestDone(m.json.runtimeMs); }
1909 );
1910 gBrowserMessageManager.addMessageListener(
1911 "reftest:UpdateCanvasForInvalidation",
1912 function (m) { RecvUpdateCanvasForInvalidation(m.json.rects); }
1913 );
1914 gBrowserMessageManager.addMessageListener(
1915 "reftest:UpdateWholeCanvasForInvalidation",
1916 function (m) { RecvUpdateWholeCanvasForInvalidation(); }
1917 );
1918 gBrowserMessageManager.addMessageListener(
1919 "reftest:ExpectProcessCrash",
1920 function (m) { RecvExpectProcessCrash(); }
1921 );
1922 gBrowserMessageManager.addMessageListener(
1923 "reftest:EnableAsyncScroll",
1924 function (m) { SetAsyncScroll(true); }
1925 );
1927 gBrowserMessageManager.loadFrameScript("chrome://reftest/content/reftest-content.js", true, true);
1928 }
1930 function SetAsyncScroll(enabled)
1931 {
1932 gBrowser.QueryInterface(CI.nsIFrameLoaderOwner).frameLoader.renderMode =
1933 enabled ? CI.nsIFrameLoader.RENDER_MODE_ASYNC_SCROLL :
1934 CI.nsIFrameLoader.RENDER_MODE_DEFAULT;
1935 }
1937 function RecvAssertionCount(count)
1938 {
1939 DoAssertionCheck(count);
1940 }
1942 function RecvContentReady()
1943 {
1944 InitAndStartRefTests();
1945 return { remote: gBrowserIsRemote };
1946 }
1948 function RecvException(what)
1949 {
1950 gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gCurrentURL + " | " + what + "\n");
1951 ++gTestResults.Exception;
1952 }
1954 function RecvFailedLoad(why)
1955 {
1956 LoadFailed(why);
1957 }
1959 function RecvFailedNoPaint()
1960 {
1961 gFailedNoPaint = true;
1962 }
1964 function RecvInitCanvasWithSnapshot()
1965 {
1966 var painted = InitCurrentCanvasWithSnapshot();
1967 return { painted: painted };
1968 }
1970 function RecvLog(type, msg)
1971 {
1972 msg = "[CONTENT] "+ msg;
1973 if (type == "info") {
1974 LogInfo(msg);
1975 } else if (type == "warning") {
1976 LogWarning(msg);
1977 } else {
1978 gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gCurrentURL + " | unknown log type " + type + "\n");
1979 ++gTestResults.Exception;
1980 }
1981 }
1983 function RecvScriptResults(runtimeMs, error, results)
1984 {
1985 RecordResult(runtimeMs, error, results);
1986 }
1988 function RecvTestDone(runtimeMs)
1989 {
1990 RecordResult(runtimeMs, '', [ ]);
1991 }
1993 function RecvUpdateCanvasForInvalidation(rects)
1994 {
1995 UpdateCurrentCanvasForInvalidation(rects);
1996 }
1998 function RecvUpdateWholeCanvasForInvalidation()
1999 {
2000 UpdateWholeCurrentCanvasForInvalidation();
2001 }
2003 function OnProcessCrashed(subject, topic, data)
2004 {
2005 var id;
2006 subject = subject.QueryInterface(CI.nsIPropertyBag2);
2007 if (topic == "plugin-crashed") {
2008 id = subject.getPropertyAsAString("pluginDumpID");
2009 } else if (topic == "ipc:content-shutdown") {
2010 id = subject.getPropertyAsAString("dumpID");
2011 }
2012 if (id) {
2013 gExpectedCrashDumpFiles.push(id + ".dmp");
2014 gExpectedCrashDumpFiles.push(id + ".extra");
2015 }
2016 }
2018 function RegisterProcessCrashObservers()
2019 {
2020 var os = CC[NS_OBSERVER_SERVICE_CONTRACTID]
2021 .getService(CI.nsIObserverService);
2022 os.addObserver(OnProcessCrashed, "plugin-crashed", false);
2023 os.addObserver(OnProcessCrashed, "ipc:content-shutdown", false);
2024 }
2026 function RecvExpectProcessCrash()
2027 {
2028 gExpectingProcessCrash = true;
2029 }
2031 function SendClear()
2032 {
2033 gBrowserMessageManager.sendAsyncMessage("reftest:Clear");
2034 }
2036 function SendLoadScriptTest(uri, timeout)
2037 {
2038 gBrowserMessageManager.sendAsyncMessage("reftest:LoadScriptTest",
2039 { uri: uri, timeout: timeout });
2040 }
2042 function SendLoadTest(type, uri, timeout)
2043 {
2044 gBrowserMessageManager.sendAsyncMessage("reftest:LoadTest",
2045 { type: type, uri: uri, timeout: timeout }
2046 );
2047 }
2049 function SendResetRenderingState()
2050 {
2051 gBrowserMessageManager.sendAsyncMessage("reftest:ResetRenderingState");
2052 }