layout/tools/reftest/reftest.js

Fri, 16 Jan 2015 04:50:19 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 04:50:19 +0100
branch
TOR_BUG_9701
changeset 13
44a2da4a2ab2
permissions
-rw-r--r--

Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32

     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();
  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];
  1009             if (items.length > 2 && !items[2].match(gProtocolRE)) {
  1010                 items[2] = urlprefix + items[2];
  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;
  1112 function AddURIUseCount(uri)
  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;
  1125 function BuildUseCounts()
  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);
  1136             if (url.prefSettings2.length == 0) {
  1137                 AddURIUseCount(gURLs[i].url2);
  1143 function ServeFiles(manifestPrincipal, depth, aURL, files)
  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;
  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)
  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;
  1180     return files.map(FileToURI);
  1183 // Return true iff this window is focused when this function returns.
  1184 function Focus()
  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) {
  1194 #endif // XP_MACOSX
  1195     return true;
  1198 function Blur()
  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();
  1207 function StartCurrentTest()
  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;
  1233     if (gURLs.length == 0) {
  1234         RestoreChangedPreferences();
  1235         DoneTests();
  1237     else {
  1238         gDumpLog("REFTEST TEST-START | " + gURLs[0].prettyPath + "\n");
  1239         if (!gURLs[0].needsFocus) {
  1240             Blur();
  1242         var currentTest = gTotalTests - gURLs.length;
  1243         gContainingWindow.document.title = "reftest: " + currentTest + " / " + gTotalTests +
  1244             " (" + Math.floor(100 * (currentTest / gTotalTests)) + "%)";
  1245         StartCurrentURI(1);
  1249 function StartCurrentURI(aState)
  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";
  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";
  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";
  1285                 } else {
  1286                     throw "internal error - unknown preference type";
  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);
  1301                     gDumpLog("SET PREFERENCE pref(" + ps.name + "," + value + ")\n");
  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;
  1316             } else {
  1317                 throw e;
  1320         if (badPref != undefined) {
  1321             // skip the test that had a bad preference
  1322             gURLs.shift();
  1324             StartCurrentTest();
  1325             return;
  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);
  1351 function DoneTests()
  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);
  1388     if (gServer) {
  1389         gServer.stop(onStopped);
  1391     else {
  1392         onStopped();
  1396 function UpdateCanvasCache(url, canvas)
  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";
  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)
  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;
  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");
  1446         gDumpLog("REFTEST INFO | drawWindow flags = " + flagsStr +
  1447                  "; window size = " + gContainingWindow.innerWidth + "," + gContainingWindow.innerHeight +
  1448                  "; test browser size = " + testRect.width + "," + testRect.height +
  1449                  "\n");
  1452     LogInfo("DoDrawWindow " + x + "," + y + "," + w + "," + h);
  1453     ctx.drawWindow(gContainingWindow, x, y, w, h, "rgb(255,255,255)",
  1454                    gDrawWindowFlags);
  1457 function InitCurrentCanvasWithSnapshot()
  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;
  1466     if (!gCurrentCanvas) {
  1467         gCurrentCanvas = AllocateCanvas();
  1470     var ctx = gCurrentCanvas.getContext("2d");
  1471     DoDrawWindow(ctx, 0, 0, gCurrentCanvas.width, gCurrentCanvas.height);
  1472     return true;
  1475 function UpdateCurrentCanvasForInvalidation(rects)
  1477     LogInfo("Updating canvas for invalidation");
  1479     if (!gCurrentCanvas) {
  1480         return;
  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();
  1499 function UpdateWholeCurrentCanvasForInvalidation()
  1501     LogInfo("Updating entire canvas for invalidation");
  1503     if (!gCurrentCanvas) {
  1504         return;
  1507     var ctx = gCurrentCanvas.getContext("2d");
  1508     DoDrawWindow(ctx, 0, 0, gCurrentCanvas.width, gCurrentCanvas.height);
  1511 function RecordResult(testRunTime, errorMsg, scriptResults)
  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;
  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;
  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");
  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;
  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];
  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();
  1602         FinishTestItem();
  1603         return;
  1606     if (gURLs[0]["prefSettings" + gState].length == 0 &&
  1607         gURICanvases[gCurrentURL]) {
  1608         gCurrentCanvas = gURICanvases[gCurrentURL];
  1610     if (gCurrentCanvas == null) {
  1611         gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gCurrentURL + " | program error managing snapshots\n");
  1612         ++gTestResults.Exception;
  1614     if (gState == 1) {
  1615         gCanvas1 = gCurrentCanvas;
  1616     } else {
  1617         gCanvas2 = gCurrentCanvas;
  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.";
  1653                 equal = expected == EXPECTED_FUZZY;
  1654                 gDumpLog("REFTEST fuzzy match\n");
  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");
  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;
  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";
  1695                 } else {
  1696                     result += "\n";
  1699                 gDumpLog(result);
  1702             if (!test_passed && expected == EXPECTED_PASS) {
  1703                 FlushTestLog();
  1706             if (gURLs[0].prefSettings1.length == 0) {
  1707                 UpdateCanvasCache(gURLs[0].url1, gCanvas1);
  1709             if (gURLs[0].prefSettings2.length == 0) {
  1710                 UpdateCanvasCache(gURLs[0].url2, gCanvas2);
  1713             CleanUpCrashDumpFiles();
  1714             FinishTestItem();
  1715             break;
  1716         default:
  1717             throw "Unexpected state.";
  1721 function LoadFailed(why)
  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");
  1729     gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " +
  1730          gURLs[0]["url" + gState].spec + " | load failed: " + why + "\n");
  1731     FlushTestLog();
  1732     FinishTestItem();
  1735 function RemoveExpectedCrashDumpFiles()
  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);
  1746     gExpectedCrashDumpFiles.length = 0;
  1749 function FindUnexpectedCrashDumpFiles()
  1751     if (!gCrashDumpDir.exists()) {
  1752         return;
  1755     let entries = gCrashDumpDir.directoryEntries;
  1756     if (!entries) {
  1757         return;
  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");
  1771             gDumpLog("REFTEST INFO | Found unexpected crash dump file " + path +
  1772                      ".\n");
  1773             gUnexpectedCrashDumpFiles[path] = true;
  1778 function CleanUpCrashDumpFiles()
  1780     RemoveExpectedCrashDumpFiles();
  1781     FindUnexpectedCrashDumpFiles();
  1782     gExpectingProcessCrash = false;
  1785 function FinishTestItem()
  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;
  1797 function DoAssertionCheck(numAsserts)
  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;
  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;
  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");
  1837     gDumpLog("REFTEST TEST-END | " + gURLs[0].prettyPath + "\n");
  1839     // And start the next test.
  1840     gURLs.shift();
  1841     StartCurrentTest();
  1844 function ResetRenderingState()
  1846     SendResetRenderingState();
  1847     // We would want to clear any viewconfig here, if we add support for it
  1850 function RestoreChangedPreferences()
  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);
  1866             gDumpLog("RESTORE PREFERENCE pref(" + ps.name + "," + value + ")\n");
  1867         });
  1868         gPrefsToRestore = [];
  1872 function RegisterMessageListenersAndLoadContentScript()
  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);
  1930 function SetAsyncScroll(enabled)
  1932     gBrowser.QueryInterface(CI.nsIFrameLoaderOwner).frameLoader.renderMode =
  1933         enabled ? CI.nsIFrameLoader.RENDER_MODE_ASYNC_SCROLL :
  1934                   CI.nsIFrameLoader.RENDER_MODE_DEFAULT;
  1937 function RecvAssertionCount(count)
  1939     DoAssertionCheck(count);
  1942 function RecvContentReady()
  1944     InitAndStartRefTests();
  1945     return { remote: gBrowserIsRemote };
  1948 function RecvException(what)
  1950     gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gCurrentURL + " | " + what + "\n");
  1951     ++gTestResults.Exception;
  1954 function RecvFailedLoad(why)
  1956     LoadFailed(why);
  1959 function RecvFailedNoPaint()
  1961     gFailedNoPaint = true;
  1964 function RecvInitCanvasWithSnapshot()
  1966     var painted = InitCurrentCanvasWithSnapshot();
  1967     return { painted: painted };
  1970 function RecvLog(type, msg)
  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;
  1983 function RecvScriptResults(runtimeMs, error, results)
  1985     RecordResult(runtimeMs, error, results);
  1988 function RecvTestDone(runtimeMs)
  1990     RecordResult(runtimeMs, '', [ ]);
  1993 function RecvUpdateCanvasForInvalidation(rects)
  1995     UpdateCurrentCanvasForInvalidation(rects);
  1998 function RecvUpdateWholeCanvasForInvalidation()
  2000     UpdateWholeCurrentCanvasForInvalidation();
  2003 function OnProcessCrashed(subject, topic, data)
  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");
  2012     if (id) {
  2013         gExpectedCrashDumpFiles.push(id + ".dmp");
  2014         gExpectedCrashDumpFiles.push(id + ".extra");
  2018 function RegisterProcessCrashObservers()
  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);
  2026 function RecvExpectProcessCrash()
  2028     gExpectingProcessCrash = true;
  2031 function SendClear()
  2033     gBrowserMessageManager.sendAsyncMessage("reftest:Clear");
  2036 function SendLoadScriptTest(uri, timeout)
  2038     gBrowserMessageManager.sendAsyncMessage("reftest:LoadScriptTest",
  2039                                             { uri: uri, timeout: timeout });
  2042 function SendLoadTest(type, uri, timeout)
  2044     gBrowserMessageManager.sendAsyncMessage("reftest:LoadTest",
  2045                                             { type: type, uri: uri, timeout: timeout }
  2046     );
  2049 function SendResetRenderingState()
  2051     gBrowserMessageManager.sendAsyncMessage("reftest:ResetRenderingState");

mercurial