1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/tools/reftest/reftest.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2052 @@ 1.4 +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / 1.5 +/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#if BOOTSTRAP 1.11 +this.EXPORTED_SYMBOLS = ["OnRefTestLoad"]; 1.12 +#endif 1.13 + 1.14 + 1.15 +const CC = Components.classes; 1.16 +const CI = Components.interfaces; 1.17 +const CR = Components.results; 1.18 + 1.19 +const XHTML_NS = "http://www.w3.org/1999/xhtml"; 1.20 +const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; 1.21 + 1.22 +const NS_LOCAL_FILE_CONTRACTID = "@mozilla.org/file/local;1"; 1.23 +const NS_GFXINFO_CONTRACTID = "@mozilla.org/gfx/info;1"; 1.24 +const IO_SERVICE_CONTRACTID = "@mozilla.org/network/io-service;1"; 1.25 +const DEBUG_CONTRACTID = "@mozilla.org/xpcom/debug;1"; 1.26 +const NS_LOCALFILEINPUTSTREAM_CONTRACTID = 1.27 + "@mozilla.org/network/file-input-stream;1"; 1.28 +const NS_SCRIPTSECURITYMANAGER_CONTRACTID = 1.29 + "@mozilla.org/scriptsecuritymanager;1"; 1.30 +const NS_REFTESTHELPER_CONTRACTID = 1.31 + "@mozilla.org/reftest-helper;1"; 1.32 +const NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX = 1.33 + "@mozilla.org/network/protocol;1?name="; 1.34 +const NS_XREAPPINFO_CONTRACTID = 1.35 + "@mozilla.org/xre/app-info;1"; 1.36 +const NS_DIRECTORY_SERVICE_CONTRACTID = 1.37 + "@mozilla.org/file/directory_service;1"; 1.38 +const NS_OBSERVER_SERVICE_CONTRACTID = 1.39 + "@mozilla.org/observer-service;1"; 1.40 + 1.41 +Components.utils.import("resource://gre/modules/FileUtils.jsm"); 1.42 + 1.43 +var gLoadTimeout = 0; 1.44 +var gTimeoutHook = null; 1.45 +var gRemote = false; 1.46 +var gIgnoreWindowSize = false; 1.47 +var gShuffle = false; 1.48 +var gTotalChunks = 0; 1.49 +var gThisChunk = 0; 1.50 +var gContainingWindow = null; 1.51 +var gURLFilterRegex = null; 1.52 +const FOCUS_FILTER_ALL_TESTS = "all"; 1.53 +const FOCUS_FILTER_NEEDS_FOCUS_TESTS = "needs-focus"; 1.54 +const FOCUS_FILTER_NON_NEEDS_FOCUS_TESTS = "non-needs-focus"; 1.55 +var gFocusFilterMode = FOCUS_FILTER_ALL_TESTS; 1.56 + 1.57 +// "<!--CLEAR-->" 1.58 +const BLANK_URL_FOR_CLEARING = "data:text/html;charset=UTF-8,%3C%21%2D%2DCLEAR%2D%2D%3E"; 1.59 + 1.60 +var gBrowser; 1.61 +// Are we testing web content loaded in a separate process? 1.62 +var gBrowserIsRemote; // bool 1.63 +// Are we using <iframe mozbrowser>? 1.64 +var gBrowserIsIframe; // bool 1.65 +var gBrowserMessageManager; 1.66 +var gCanvas1, gCanvas2; 1.67 +// gCurrentCanvas is non-null between InitCurrentCanvasWithSnapshot and the next 1.68 +// RecordResult. 1.69 +var gCurrentCanvas = null; 1.70 +var gURLs; 1.71 +// Map from URI spec to the number of times it remains to be used 1.72 +var gURIUseCounts; 1.73 +// Map from URI spec to the canvas rendered for that URI 1.74 +var gURICanvases; 1.75 +var gTestResults = { 1.76 + // Successful... 1.77 + Pass: 0, 1.78 + LoadOnly: 0, 1.79 + // Unexpected... 1.80 + Exception: 0, 1.81 + FailedLoad: 0, 1.82 + UnexpectedFail: 0, 1.83 + UnexpectedPass: 0, 1.84 + AssertionUnexpected: 0, 1.85 + AssertionUnexpectedFixed: 0, 1.86 + // Known problems... 1.87 + KnownFail : 0, 1.88 + AssertionKnown: 0, 1.89 + Random : 0, 1.90 + Skip: 0, 1.91 + Slow: 0, 1.92 +}; 1.93 +var gTotalTests = 0; 1.94 +var gState; 1.95 +var gCurrentURL; 1.96 +var gTestLog = []; 1.97 +var gServer; 1.98 +var gCount = 0; 1.99 +var gAssertionCount = 0; 1.100 + 1.101 +var gIOService; 1.102 +var gDebug; 1.103 +var gWindowUtils; 1.104 + 1.105 +var gSlowestTestTime = 0; 1.106 +var gSlowestTestURL; 1.107 + 1.108 +var gDrawWindowFlags; 1.109 + 1.110 +var gExpectingProcessCrash = false; 1.111 +var gExpectedCrashDumpFiles = []; 1.112 +var gUnexpectedCrashDumpFiles = { }; 1.113 +var gCrashDumpDir; 1.114 +var gFailedNoPaint = false; 1.115 + 1.116 +// The enabled-state of the test-plugins, stored so they can be reset later 1.117 +var gTestPluginEnabledStates = null; 1.118 + 1.119 +const TYPE_REFTEST_EQUAL = '=='; 1.120 +const TYPE_REFTEST_NOTEQUAL = '!='; 1.121 +const TYPE_LOAD = 'load'; // test without a reference (just test that it does 1.122 + // not assert, crash, hang, or leak) 1.123 +const TYPE_SCRIPT = 'script'; // test contains individual test results 1.124 + 1.125 +// The order of these constants matters, since when we have a status 1.126 +// listed for a *manifest*, we combine the status with the status for 1.127 +// the test by using the *larger*. 1.128 +// FIXME: In the future, we may also want to use this rule for combining 1.129 +// statuses that are on the same line (rather than making the last one 1.130 +// win). 1.131 +const EXPECTED_PASS = 0; 1.132 +const EXPECTED_FAIL = 1; 1.133 +const EXPECTED_RANDOM = 2; 1.134 +const EXPECTED_DEATH = 3; // test must be skipped to avoid e.g. crash/hang 1.135 +const EXPECTED_FUZZY = 4; 1.136 + 1.137 +// types of preference value we might want to set for a specific test 1.138 +const PREF_BOOLEAN = 0; 1.139 +const PREF_STRING = 1; 1.140 +const PREF_INTEGER = 2; 1.141 + 1.142 +var gPrefsToRestore = []; 1.143 + 1.144 +const gProtocolRE = /^\w+:/; 1.145 +const gPrefItemRE = /^(|test-|ref-)pref\((.+?),(.*)\)$/; 1.146 + 1.147 +var gHttpServerPort = -1; 1.148 + 1.149 +// whether to run slow tests or not 1.150 +var gRunSlowTests = true; 1.151 + 1.152 +// whether we should skip caching canvases 1.153 +var gNoCanvasCache = false; 1.154 + 1.155 +var gRecycledCanvases = new Array(); 1.156 + 1.157 +// By default we just log to stdout 1.158 +var gDumpLog = dump; 1.159 +var gVerbose = false; 1.160 + 1.161 +// Only dump the sandbox once, because it doesn't depend on the 1.162 +// manifest URL (yet!). 1.163 +var gDumpedConditionSandbox = false; 1.164 + 1.165 +function LogWarning(str) 1.166 +{ 1.167 + gDumpLog("REFTEST INFO | " + str + "\n"); 1.168 + gTestLog.push(str); 1.169 +} 1.170 + 1.171 +function LogInfo(str) 1.172 +{ 1.173 + if (gVerbose) 1.174 + gDumpLog("REFTEST INFO | " + str + "\n"); 1.175 + gTestLog.push(str); 1.176 +} 1.177 + 1.178 +function FlushTestLog() 1.179 +{ 1.180 + if (!gVerbose) { 1.181 + // In verbose mode, we've dumped all these messages already. 1.182 + for (var i = 0; i < gTestLog.length; ++i) { 1.183 + gDumpLog("REFTEST INFO | Saved log: " + gTestLog[i] + "\n"); 1.184 + } 1.185 + } 1.186 + gTestLog = []; 1.187 +} 1.188 + 1.189 +function AllocateCanvas() 1.190 +{ 1.191 + if (gRecycledCanvases.length > 0) 1.192 + return gRecycledCanvases.shift(); 1.193 + 1.194 + var canvas = gContainingWindow.document.createElementNS(XHTML_NS, "canvas"); 1.195 + var r = gBrowser.getBoundingClientRect(); 1.196 + canvas.setAttribute("width", Math.ceil(r.width)); 1.197 + canvas.setAttribute("height", Math.ceil(r.height)); 1.198 + 1.199 + return canvas; 1.200 +} 1.201 + 1.202 +function ReleaseCanvas(canvas) 1.203 +{ 1.204 + // store a maximum of 2 canvases, if we're not caching 1.205 + if (!gNoCanvasCache || gRecycledCanvases.length < 2) 1.206 + gRecycledCanvases.push(canvas); 1.207 +} 1.208 + 1.209 +function IDForEventTarget(event) 1.210 +{ 1.211 + try { 1.212 + return "'" + event.target.getAttribute('id') + "'"; 1.213 + } catch (ex) { 1.214 + return "<unknown>"; 1.215 + } 1.216 +} 1.217 + 1.218 +function getTestPlugin(aName) { 1.219 + var ph = CC["@mozilla.org/plugin/host;1"].getService(CI.nsIPluginHost); 1.220 + var tags = ph.getPluginTags(); 1.221 + 1.222 + // Find the test plugin 1.223 + for (var i = 0; i < tags.length; i++) { 1.224 + if (tags[i].name == aName) 1.225 + return tags[i]; 1.226 + } 1.227 + 1.228 + LogWarning("Failed to find the test-plugin."); 1.229 + return null; 1.230 +} 1.231 + 1.232 +this.OnRefTestLoad = function OnRefTestLoad(win) 1.233 +{ 1.234 + gCrashDumpDir = CC[NS_DIRECTORY_SERVICE_CONTRACTID] 1.235 + .getService(CI.nsIProperties) 1.236 + .get("ProfD", CI.nsIFile); 1.237 + gCrashDumpDir.append("minidumps"); 1.238 + 1.239 + var env = CC["@mozilla.org/process/environment;1"]. 1.240 + getService(CI.nsIEnvironment); 1.241 + gVerbose = !!env.get("MOZ_REFTEST_VERBOSE"); 1.242 + 1.243 + var prefs = Components.classes["@mozilla.org/preferences-service;1"]. 1.244 + getService(Components.interfaces.nsIPrefBranch); 1.245 + try { 1.246 + gBrowserIsRemote = prefs.getBoolPref("browser.tabs.remote.autostart"); 1.247 + } catch (e) { 1.248 + gBrowserIsRemote = false; 1.249 + } 1.250 + 1.251 + try { 1.252 + gBrowserIsIframe = prefs.getBoolPref("reftest.browser.iframe.enabled"); 1.253 + } catch (e) { 1.254 + gBrowserIsIframe = false; 1.255 + } 1.256 + 1.257 + if (win === undefined || win == null) { 1.258 + win = window; 1.259 + } 1.260 + if (gContainingWindow == null && win != null) { 1.261 + gContainingWindow = win; 1.262 + } 1.263 + 1.264 + if (gBrowserIsIframe) { 1.265 + gBrowser = gContainingWindow.document.createElementNS(XHTML_NS, "iframe"); 1.266 + gBrowser.setAttribute("mozbrowser", ""); 1.267 + gBrowser.setAttribute("mozapp", prefs.getCharPref("browser.manifestURL")); 1.268 + } else { 1.269 + gBrowser = gContainingWindow.document.createElementNS(XUL_NS, "xul:browser"); 1.270 + } 1.271 + gBrowser.setAttribute("id", "browser"); 1.272 + gBrowser.setAttribute("type", "content-primary"); 1.273 + gBrowser.setAttribute("remote", gBrowserIsRemote ? "true" : "false"); 1.274 + gBrowser.setAttribute("mozasyncpanzoom", "true"); 1.275 + // Make sure the browser element is exactly 800x1000, no matter 1.276 + // what size our window is 1.277 + gBrowser.setAttribute("style", "min-width: 800px; min-height: 1000px; max-width: 800px; max-height: 1000px"); 1.278 + 1.279 +#ifdef BOOTSTRAP 1.280 +#ifdef REFTEST_B2G 1.281 + var doc = gContainingWindow.document.getElementsByTagName("html")[0]; 1.282 +#else 1.283 + var doc = gContainingWindow.document.getElementById('main-window'); 1.284 +#endif 1.285 + while (doc.hasChildNodes()) { 1.286 + doc.removeChild(doc.firstChild); 1.287 + } 1.288 + doc.appendChild(gBrowser); 1.289 +#else 1.290 + document.getElementById("reftest-window").appendChild(gBrowser); 1.291 +#endif 1.292 + 1.293 + // reftests should have the test plugins enabled, not click-to-play 1.294 + let plugin1 = getTestPlugin("Test Plug-in"); 1.295 + let plugin2 = getTestPlugin("Second Test Plug-in"); 1.296 + if (plugin1 && plugin2) { 1.297 + gTestPluginEnabledStates = [plugin1.enabledState, plugin2.enabledState]; 1.298 + plugin1.enabledState = CI.nsIPluginTag.STATE_ENABLED; 1.299 + plugin2.enabledState = CI.nsIPluginTag.STATE_ENABLED; 1.300 + } else { 1.301 + LogWarning("Could not get test plugin tags."); 1.302 + } 1.303 + 1.304 + gBrowserMessageManager = gBrowser.QueryInterface(CI.nsIFrameLoaderOwner) 1.305 + .frameLoader.messageManager; 1.306 + // The content script waits for the initial onload, then notifies 1.307 + // us. 1.308 + RegisterMessageListenersAndLoadContentScript(); 1.309 +} 1.310 + 1.311 +function InitAndStartRefTests() 1.312 +{ 1.313 + /* These prefs are optional, so we don't need to spit an error to the log */ 1.314 + try { 1.315 + var prefs = Components.classes["@mozilla.org/preferences-service;1"]. 1.316 + getService(Components.interfaces.nsIPrefBranch); 1.317 + } catch(e) { 1.318 + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | EXCEPTION: " + e + "\n"); 1.319 + } 1.320 + 1.321 + try { 1.322 + prefs.setBoolPref("android.widget_paints_background", false); 1.323 + } catch (e) {} 1.324 + 1.325 + /* set the gLoadTimeout */ 1.326 + try { 1.327 + gLoadTimeout = prefs.getIntPref("reftest.timeout"); 1.328 + } catch(e) { 1.329 + gLoadTimeout = 5 * 60 * 1000; //5 minutes as per bug 479518 1.330 + } 1.331 + 1.332 + /* Get the logfile for android tests */ 1.333 + try { 1.334 + var logFile = prefs.getCharPref("reftest.logFile"); 1.335 + if (logFile) { 1.336 + try { 1.337 + var f = FileUtils.File(logFile); 1.338 + var mfl = FileUtils.openFileOutputStream(f, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE); 1.339 + // Set to mirror to stdout as well as the file 1.340 + gDumpLog = function (msg) { 1.341 +#ifdef BOOTSTRAP 1.342 +#ifdef REFTEST_B2G 1.343 + dump(msg); 1.344 +#else 1.345 + //NOTE: on android-xul, we have a libc crash if we do a dump with %7s in the string 1.346 +#endif 1.347 +#else 1.348 + dump(msg); 1.349 +#endif 1.350 + mfl.write(msg, msg.length); 1.351 + }; 1.352 + } 1.353 + catch(e) { 1.354 + // If there is a problem, just use stdout 1.355 + gDumpLog = dump; 1.356 + } 1.357 + } 1.358 + } catch(e) {} 1.359 + 1.360 + try { 1.361 + gRemote = prefs.getBoolPref("reftest.remote"); 1.362 + } catch(e) { 1.363 + gRemote = false; 1.364 + } 1.365 + 1.366 + try { 1.367 + gIgnoreWindowSize = prefs.getBoolPref("reftest.ignoreWindowSize"); 1.368 + } catch(e) { 1.369 + gIgnoreWindowSize = false; 1.370 + } 1.371 + 1.372 + /* Support for running a chunk (subset) of tests. In separate try as this is optional */ 1.373 + try { 1.374 + gTotalChunks = prefs.getIntPref("reftest.totalChunks"); 1.375 + gThisChunk = prefs.getIntPref("reftest.thisChunk"); 1.376 + } 1.377 + catch(e) { 1.378 + gTotalChunks = 0; 1.379 + gThisChunk = 0; 1.380 + } 1.381 + 1.382 + try { 1.383 + gURLFilterRegex = new RegExp(prefs.getCharPref("reftest.filter")); 1.384 + } catch(e) {} 1.385 + 1.386 + try { 1.387 + gFocusFilterMode = prefs.getCharPref("reftest.focusFilterMode"); 1.388 + } catch(e) {} 1.389 + 1.390 + gWindowUtils = gContainingWindow.QueryInterface(CI.nsIInterfaceRequestor).getInterface(CI.nsIDOMWindowUtils); 1.391 + if (!gWindowUtils || !gWindowUtils.compareCanvases) 1.392 + throw "nsIDOMWindowUtils inteface missing"; 1.393 + 1.394 + gIOService = CC[IO_SERVICE_CONTRACTID].getService(CI.nsIIOService); 1.395 + gDebug = CC[DEBUG_CONTRACTID].getService(CI.nsIDebug2); 1.396 + 1.397 + RegisterProcessCrashObservers(); 1.398 + 1.399 + if (gRemote) { 1.400 + gServer = null; 1.401 + } else { 1.402 + // not all gecko applications autoregister xpcom components 1.403 + if (CC["@mozilla.org/server/jshttp;1"] === undefined) { 1.404 + var file = CC["@mozilla.org/file/directory_service;1"]. 1.405 + getService(CI.nsIProperties).get("ProfD", CI.nsIFile); 1.406 + file.appendRelativePath("extensions/reftest@mozilla.org/chrome.manifest"); 1.407 + 1.408 + registrar = Components.manager.QueryInterface(CI.nsIComponentRegistrar); 1.409 + registrar.autoRegister(file); 1.410 + } 1.411 + gServer = CC["@mozilla.org/server/jshttp;1"]. 1.412 + createInstance(CI.nsIHttpServer); 1.413 + } 1.414 + try { 1.415 + if (gServer) 1.416 + StartHTTPServer(); 1.417 + } catch (ex) { 1.418 + //gBrowser.loadURI('data:text/plain,' + ex); 1.419 + ++gTestResults.Exception; 1.420 + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | EXCEPTION: " + ex + "\n"); 1.421 + DoneTests(); 1.422 + } 1.423 + 1.424 + // Focus the content browser. 1.425 + if (gFocusFilterMode != FOCUS_FILTER_NON_NEEDS_FOCUS_TESTS) { 1.426 + gBrowser.focus(); 1.427 + } 1.428 + 1.429 + StartTests(); 1.430 +} 1.431 + 1.432 +function StartHTTPServer() 1.433 +{ 1.434 + gServer.registerContentType("sjs", "sjs"); 1.435 + gServer.start(-1); 1.436 + gHttpServerPort = gServer.identity.primaryPort; 1.437 +} 1.438 + 1.439 +// Perform a Fisher-Yates shuffle of the array. 1.440 +function Shuffle(array) 1.441 +{ 1.442 + for (var i = array.length - 1; i > 0; i--) { 1.443 + var j = Math.floor(Math.random() * (i + 1)); 1.444 + var temp = array[i]; 1.445 + array[i] = array[j]; 1.446 + array[j] = temp; 1.447 + } 1.448 +} 1.449 + 1.450 +function StartTests() 1.451 +{ 1.452 + var uri; 1.453 +#if BOOTSTRAP 1.454 + /* These prefs are optional, so we don't need to spit an error to the log */ 1.455 + try { 1.456 + var prefs = Components.classes["@mozilla.org/preferences-service;1"]. 1.457 + getService(Components.interfaces.nsIPrefBranch); 1.458 + } catch(e) { 1.459 + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | EXCEPTION: " + e + "\n"); 1.460 + } 1.461 + 1.462 + try { 1.463 + gNoCanvasCache = prefs.getIntPref("reftest.nocache"); 1.464 + } catch(e) { 1.465 + gNoCanvasCache = false; 1.466 + } 1.467 + 1.468 + try { 1.469 + gShuffle = prefs.getBoolPref("reftest.shuffle"); 1.470 + } catch (e) { 1.471 + gShuffle = false; 1.472 + } 1.473 + 1.474 + try { 1.475 + gRunSlowTests = prefs.getIntPref("reftest.skipslowtests"); 1.476 + } catch(e) { 1.477 + gRunSlowTests = false; 1.478 + } 1.479 + 1.480 + try { 1.481 + uri = prefs.getCharPref("reftest.uri"); 1.482 + } catch(e) { 1.483 + uri = ""; 1.484 + } 1.485 + 1.486 + if (uri == "") { 1.487 + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | Unable to find reftest.uri pref. Please ensure your profile is setup properly\n"); 1.488 + DoneTests(); 1.489 + } 1.490 +#else 1.491 + try { 1.492 + // Need to read the manifest once we have gHttpServerPort.. 1.493 + var args = window.arguments[0].wrappedJSObject; 1.494 + 1.495 + if ("nocache" in args && args["nocache"]) 1.496 + gNoCanvasCache = true; 1.497 + 1.498 + if ("skipslowtests" in args && args.skipslowtests) 1.499 + gRunSlowTests = false; 1.500 + 1.501 + uri = args.uri; 1.502 + } catch (e) { 1.503 + ++gTestResults.Exception; 1.504 + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | EXCEPTION: " + ex + "\n"); 1.505 + DoneTests(); 1.506 + } 1.507 +#endif 1.508 + 1.509 + if (gShuffle) { 1.510 + gNoCanvasCache = true; 1.511 + } 1.512 + 1.513 + try { 1.514 + ReadTopManifest(uri); 1.515 + BuildUseCounts(); 1.516 + 1.517 + // Filter tests which will be skipped to get a more even distribution when chunking 1.518 + // tURLs is a temporary array containing all active tests 1.519 + var tURLs = new Array(); 1.520 + for (var i = 0; i < gURLs.length; ++i) { 1.521 + if (gURLs[i].expected == EXPECTED_DEATH) 1.522 + continue; 1.523 + 1.524 + if (gURLs[i].needsFocus && !Focus()) 1.525 + continue; 1.526 + 1.527 + if (gURLs[i].slow && !gRunSlowTests) 1.528 + continue; 1.529 + 1.530 + tURLs.push(gURLs[i]); 1.531 + } 1.532 + 1.533 + gDumpLog("REFTEST INFO | Discovered " + gURLs.length + " tests, after filtering SKIP tests, we have " + tURLs.length + "\n"); 1.534 + 1.535 + if (gTotalChunks > 0 && gThisChunk > 0) { 1.536 + // Calculate start and end indices of this chunk if tURLs array were 1.537 + // divided evenly 1.538 + var testsPerChunk = tURLs.length / gTotalChunks; 1.539 + var start = Math.round((gThisChunk-1) * testsPerChunk); 1.540 + var end = Math.round(gThisChunk * testsPerChunk); 1.541 + 1.542 + // Map these indices onto the gURLs array. This avoids modifying the 1.543 + // gURLs array which prevents skipped tests from showing up in the log 1.544 + start = gThisChunk == 1 ? 0 : gURLs.indexOf(tURLs[start]); 1.545 + end = gThisChunk == gTotalChunks ? gURLs.length : gURLs.indexOf(tURLs[end + 1]) - 1; 1.546 + gURLs = gURLs.slice(start, end); 1.547 + 1.548 + gDumpLog("REFTEST INFO | Running chunk " + gThisChunk + " out of " + gTotalChunks + " chunks. "); 1.549 + gDumpLog("tests " + (start+1) + "-" + end + "/" + gURLs.length + "\n"); 1.550 + } 1.551 + 1.552 + if (gShuffle) { 1.553 + Shuffle(gURLs); 1.554 + } 1.555 + 1.556 + gTotalTests = gURLs.length; 1.557 + 1.558 + if (!gTotalTests) 1.559 + throw "No tests to run"; 1.560 + 1.561 + gURICanvases = {}; 1.562 + StartCurrentTest(); 1.563 + } catch (ex) { 1.564 + //gBrowser.loadURI('data:text/plain,' + ex); 1.565 + ++gTestResults.Exception; 1.566 + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | EXCEPTION: " + ex + "\n"); 1.567 + DoneTests(); 1.568 + } 1.569 +} 1.570 + 1.571 +function OnRefTestUnload() 1.572 +{ 1.573 + let plugin1 = getTestPlugin("Test Plug-in"); 1.574 + let plugin2 = getTestPlugin("Second Test Plug-in"); 1.575 + if (plugin1 && plugin2) { 1.576 + plugin1.enabledState = gTestPluginEnabledStates[0]; 1.577 + plugin2.enabledState = gTestPluginEnabledStates[1]; 1.578 + } else { 1.579 + LogWarning("Failed to get test plugin tags."); 1.580 + } 1.581 +} 1.582 + 1.583 +// Read all available data from an input stream and return it 1.584 +// as a string. 1.585 +function getStreamContent(inputStream) 1.586 +{ 1.587 + var streamBuf = ""; 1.588 + var sis = CC["@mozilla.org/scriptableinputstream;1"]. 1.589 + createInstance(CI.nsIScriptableInputStream); 1.590 + sis.init(inputStream); 1.591 + 1.592 + var available; 1.593 + while ((available = sis.available()) != 0) { 1.594 + streamBuf += sis.read(available); 1.595 + } 1.596 + 1.597 + return streamBuf; 1.598 +} 1.599 + 1.600 +// Build the sandbox for fails-if(), etc., condition evaluation. 1.601 +function BuildConditionSandbox(aURL) { 1.602 + var sandbox = new Components.utils.Sandbox(aURL.spec); 1.603 + var xr = CC[NS_XREAPPINFO_CONTRACTID].getService(CI.nsIXULRuntime); 1.604 + var appInfo = CC[NS_XREAPPINFO_CONTRACTID].getService(CI.nsIXULAppInfo); 1.605 + sandbox.isDebugBuild = gDebug.isDebugBuild; 1.606 + sandbox.xulRuntime = {widgetToolkit: xr.widgetToolkit, OS: xr.OS, __exposedProps__: { widgetToolkit: "r", OS: "r", XPCOMABI: "r", shell: "r" } }; 1.607 + 1.608 + // xr.XPCOMABI throws exception for configurations without full ABI 1.609 + // support (mobile builds on ARM) 1.610 + try { 1.611 + sandbox.xulRuntime.XPCOMABI = xr.XPCOMABI; 1.612 + } catch(e) { 1.613 + sandbox.xulRuntime.XPCOMABI = ""; 1.614 + } 1.615 + 1.616 + var testRect = gBrowser.getBoundingClientRect(); 1.617 + sandbox.smallScreen = false; 1.618 + if (gContainingWindow.innerWidth < 800 || gContainingWindow.innerHeight < 1000) { 1.619 + sandbox.smallScreen = true; 1.620 + } 1.621 + 1.622 + var gfxInfo = (NS_GFXINFO_CONTRACTID in CC) && CC[NS_GFXINFO_CONTRACTID].getService(CI.nsIGfxInfo); 1.623 + try { 1.624 + sandbox.d2d = gfxInfo.D2DEnabled; 1.625 + } catch (e) { 1.626 + sandbox.d2d = false; 1.627 + } 1.628 + var info = gfxInfo.getInfo(); 1.629 + sandbox.azureQuartz = info.AzureCanvasBackend == "quartz"; 1.630 + sandbox.azureSkia = info.AzureCanvasBackend == "skia"; 1.631 + sandbox.azureSkiaGL = info.AzureSkiaAccelerated; // FIXME: assumes GL right now 1.632 + // true if we are using the same Azure backend for rendering canvas and content 1.633 + sandbox.contentSameGfxBackendAsCanvas = info.AzureContentBackend == info.AzureCanvasBackend 1.634 + || (info.AzureContentBackend == "none" && info.AzureCanvasBackend == "cairo"); 1.635 + 1.636 + sandbox.layersGPUAccelerated = 1.637 + gWindowUtils.layerManagerType != "Basic"; 1.638 + sandbox.layersOpenGL = 1.639 + gWindowUtils.layerManagerType == "OpenGL"; 1.640 + sandbox.layersOMTC = 1.641 + gWindowUtils.layerManagerRemote == true; 1.642 + 1.643 + // Shortcuts for widget toolkits. 1.644 + sandbox.B2G = xr.widgetToolkit == "gonk"; 1.645 + sandbox.B2GDT = appInfo.name.toLowerCase() == "b2g" && !sandbox.B2G; 1.646 + sandbox.Android = xr.OS == "Android" && !sandbox.B2G; 1.647 + sandbox.cocoaWidget = xr.widgetToolkit == "cocoa"; 1.648 + sandbox.gtk2Widget = xr.widgetToolkit == "gtk2"; 1.649 + sandbox.qtWidget = xr.widgetToolkit == "qt"; 1.650 + sandbox.winWidget = xr.widgetToolkit == "windows"; 1.651 + 1.652 + if (sandbox.Android) { 1.653 + var sysInfo = CC["@mozilla.org/system-info;1"].getService(CI.nsIPropertyBag2); 1.654 + 1.655 + // This is currently used to distinguish Android 4.0.3 (SDK version 15) 1.656 + // and later from Android 2.x 1.657 + sandbox.AndroidVersion = sysInfo.getPropertyAsInt32("version"); 1.658 + } 1.659 + 1.660 +#if MOZ_ASAN 1.661 + sandbox.AddressSanitizer = true; 1.662 +#else 1.663 + sandbox.AddressSanitizer = false; 1.664 +#endif 1.665 + 1.666 +#if MOZ_WEBRTC 1.667 + sandbox.webrtc = true; 1.668 +#else 1.669 + sandbox.webrtc = false; 1.670 +#endif 1.671 + 1.672 + var hh = CC[NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX + "http"]. 1.673 + getService(CI.nsIHttpProtocolHandler); 1.674 + sandbox.http = { __exposedProps__: {} }; 1.675 + for each (var prop in [ "userAgent", "appName", "appVersion", 1.676 + "vendor", "vendorSub", 1.677 + "product", "productSub", 1.678 + "platform", "oscpu", "language", "misc" ]) { 1.679 + sandbox.http[prop] = hh[prop]; 1.680 + sandbox.http.__exposedProps__[prop] = "r"; 1.681 + } 1.682 + 1.683 + // Set OSX to the Mac OS X version for Mac, and 0 otherwise. 1.684 + var osxmatch = /Mac OS X (\d+.\d+)$/.exec(hh.oscpu); 1.685 + sandbox.OSX = osxmatch ? parseFloat(osxmatch[1]) : 0; 1.686 + 1.687 + // see if we have the test plugin available, 1.688 + // and set a sandox prop accordingly 1.689 + var navigator = gContainingWindow.navigator; 1.690 + var testPlugin = navigator.plugins["Test Plug-in"]; 1.691 + sandbox.haveTestPlugin = !!testPlugin; 1.692 + 1.693 + // Set a flag on sandbox if the windows default theme is active 1.694 + var box = gContainingWindow.document.createElement("box"); 1.695 + box.setAttribute("id", "_box_windowsDefaultTheme"); 1.696 + gContainingWindow.document.documentElement.appendChild(box); 1.697 + sandbox.windowsDefaultTheme = (gContainingWindow.getComputedStyle(box, null).display == "none"); 1.698 + gContainingWindow.document.documentElement.removeChild(box); 1.699 + 1.700 + var prefs = CC["@mozilla.org/preferences-service;1"]. 1.701 + getService(CI.nsIPrefBranch); 1.702 + try { 1.703 + sandbox.nativeThemePref = !prefs.getBoolPref("mozilla.widget.disable-native-theme"); 1.704 + } catch (e) { 1.705 + sandbox.nativeThemePref = true; 1.706 + } 1.707 + 1.708 + sandbox.prefs = { 1.709 + __exposedProps__: { 1.710 + getBoolPref: 'r', 1.711 + getIntPref: 'r', 1.712 + }, 1.713 + _prefs: prefs, 1.714 + getBoolPref: function(p) { return this._prefs.getBoolPref(p); }, 1.715 + getIntPref: function(p) { return this._prefs.getIntPref(p); } 1.716 + } 1.717 + 1.718 + sandbox.testPluginIsOOP = function () { 1.719 + try { 1.720 + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); 1.721 + } catch (ex) {} 1.722 + 1.723 + var prefservice = Components.classes["@mozilla.org/preferences-service;1"] 1.724 + .getService(CI.nsIPrefBranch); 1.725 + 1.726 + var testPluginIsOOP = false; 1.727 + if (navigator.platform.indexOf("Mac") == 0) { 1.728 + var xulRuntime = Components.classes["@mozilla.org/xre/app-info;1"] 1.729 + .getService(CI.nsIXULAppInfo) 1.730 + .QueryInterface(CI.nsIXULRuntime); 1.731 + if (xulRuntime.XPCOMABI.match(/x86-/)) { 1.732 + try { 1.733 + testPluginIsOOP = prefservice.getBoolPref("dom.ipc.plugins.enabled.i386.test.plugin"); 1.734 + } catch (e) { 1.735 + testPluginIsOOP = prefservice.getBoolPref("dom.ipc.plugins.enabled.i386"); 1.736 + } 1.737 + } 1.738 + else if (xulRuntime.XPCOMABI.match(/x86_64-/)) { 1.739 + try { 1.740 + testPluginIsOOP = prefservice.getBoolPref("dom.ipc.plugins.enabled.x86_64.test.plugin"); 1.741 + } catch (e) { 1.742 + testPluginIsOOP = prefservice.getBoolPref("dom.ipc.plugins.enabled.x86_64"); 1.743 + } 1.744 + } 1.745 + } 1.746 + else { 1.747 + testPluginIsOOP = prefservice.getBoolPref("dom.ipc.plugins.enabled"); 1.748 + } 1.749 + 1.750 + return testPluginIsOOP; 1.751 + }; 1.752 + 1.753 + // Tests shouldn't care about this except for when they need to 1.754 + // crash the content process 1.755 + sandbox.browserIsRemote = gBrowserIsRemote; 1.756 + 1.757 + // Distinguish the Fennecs: 1.758 + sandbox.xulFennec = sandbox.Android && sandbox.browserIsRemote; 1.759 + sandbox.nativeFennec = sandbox.Android && !sandbox.browserIsRemote; 1.760 + 1.761 + if (!gDumpedConditionSandbox) { 1.762 + dump("REFTEST INFO | Dumping JSON representation of sandbox \n"); 1.763 + dump("REFTEST INFO | " + JSON.stringify(sandbox) + " \n"); 1.764 + gDumpedConditionSandbox = true; 1.765 + } 1.766 + return sandbox; 1.767 +} 1.768 + 1.769 +function AddPrefSettings(aWhere, aPrefName, aPrefValExpression, aSandbox, aTestPrefSettings, aRefPrefSettings) 1.770 +{ 1.771 + var prefVal = Components.utils.evalInSandbox("(" + aPrefValExpression + ")", aSandbox); 1.772 + var prefType; 1.773 + var valType = typeof(prefVal); 1.774 + if (valType == "boolean") { 1.775 + prefType = PREF_BOOLEAN; 1.776 + } else if (valType == "string") { 1.777 + prefType = PREF_STRING; 1.778 + } else if (valType == "number" && (parseInt(prefVal) == prefVal)) { 1.779 + prefType = PREF_INTEGER; 1.780 + } else { 1.781 + return false; 1.782 + } 1.783 + var setting = { name: aPrefName, 1.784 + type: prefType, 1.785 + value: prefVal }; 1.786 + if (aWhere != "ref-") { 1.787 + aTestPrefSettings.push(setting); 1.788 + } 1.789 + if (aWhere != "test-") { 1.790 + aRefPrefSettings.push(setting); 1.791 + } 1.792 + return true; 1.793 +} 1.794 + 1.795 +function ReadTopManifest(aFileURL) 1.796 +{ 1.797 + gURLs = new Array(); 1.798 + var url = gIOService.newURI(aFileURL, null, null); 1.799 + if (!url) 1.800 + throw "Expected a file or http URL for the manifest."; 1.801 + ReadManifest(url, EXPECTED_PASS); 1.802 +} 1.803 + 1.804 +function AddTestItem(aTest) 1.805 +{ 1.806 + if (gURLFilterRegex && !gURLFilterRegex.test(aTest.url1.spec)) 1.807 + return; 1.808 + if (gFocusFilterMode == FOCUS_FILTER_NEEDS_FOCUS_TESTS && 1.809 + !aTest.needsFocus) 1.810 + return; 1.811 + if (gFocusFilterMode == FOCUS_FILTER_NON_NEEDS_FOCUS_TESTS && 1.812 + aTest.needsFocus) 1.813 + return; 1.814 + gURLs.push(aTest); 1.815 +} 1.816 + 1.817 +// Note: If you materially change the reftest manifest parsing, 1.818 +// please keep the parser in print-manifest-dirs.py in sync. 1.819 +function ReadManifest(aURL, inherited_status) 1.820 +{ 1.821 + var secMan = CC[NS_SCRIPTSECURITYMANAGER_CONTRACTID] 1.822 + .getService(CI.nsIScriptSecurityManager); 1.823 + 1.824 + var listURL = aURL; 1.825 + var channel = gIOService.newChannelFromURI(aURL); 1.826 + var inputStream = channel.open(); 1.827 + if (channel instanceof Components.interfaces.nsIHttpChannel 1.828 + && channel.responseStatus != 200) { 1.829 + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | HTTP ERROR : " + 1.830 + channel.responseStatus + "\n"); 1.831 + } 1.832 + var streamBuf = getStreamContent(inputStream); 1.833 + inputStream.close(); 1.834 + var lines = streamBuf.split(/\n|\r|\r\n/); 1.835 + 1.836 + // Build the sandbox for fails-if(), etc., condition evaluation. 1.837 + var sandbox = BuildConditionSandbox(aURL); 1.838 + var lineNo = 0; 1.839 + var urlprefix = ""; 1.840 + var defaultTestPrefSettings = [], defaultRefPrefSettings = []; 1.841 + for each (var str in lines) { 1.842 + ++lineNo; 1.843 + if (str.charAt(0) == "#") 1.844 + continue; // entire line was a comment 1.845 + var i = str.search(/\s+#/); 1.846 + if (i >= 0) 1.847 + str = str.substring(0, i); 1.848 + // strip leading and trailing whitespace 1.849 + str = str.replace(/^\s*/, '').replace(/\s*$/, ''); 1.850 + if (!str || str == "") 1.851 + continue; 1.852 + var items = str.split(/\s+/); // split on whitespace 1.853 + 1.854 + if (items[0] == "url-prefix") { 1.855 + if (items.length != 2) 1.856 + throw "url-prefix requires one url in manifest file " + aURL.spec + " line " + lineNo; 1.857 + urlprefix = items[1]; 1.858 + continue; 1.859 + } 1.860 + 1.861 + if (items[0] == "default-preferences") { 1.862 + var m; 1.863 + var item; 1.864 + defaultTestPrefSettings = []; 1.865 + defaultRefPrefSettings = []; 1.866 + items.shift(); 1.867 + while ((item = items.shift())) { 1.868 + if (!(m = item.match(gPrefItemRE))) { 1.869 + throw "Unexpected item in default-preferences list in manifest file " + aURL.spec + " line " + lineNo; 1.870 + } 1.871 + if (!AddPrefSettings(m[1], m[2], m[3], sandbox, defaultTestPrefSettings, defaultRefPrefSettings)) { 1.872 + throw "Error in pref value in manifest file " + aURL.spec + " line " + lineNo; 1.873 + } 1.874 + } 1.875 + continue; 1.876 + } 1.877 + 1.878 + var expected_status = EXPECTED_PASS; 1.879 + var allow_silent_fail = false; 1.880 + var minAsserts = 0; 1.881 + var maxAsserts = 0; 1.882 + var needs_focus = false; 1.883 + var slow = false; 1.884 + var testPrefSettings = defaultTestPrefSettings.concat(); 1.885 + var refPrefSettings = defaultRefPrefSettings.concat(); 1.886 + var fuzzy_max_delta = 2; 1.887 + var fuzzy_max_pixels = 1; 1.888 + 1.889 + while (items[0].match(/^(fails|needs-focus|random|skip|asserts|slow|require-or|silentfail|pref|test-pref|ref-pref|fuzzy)/)) { 1.890 + var item = items.shift(); 1.891 + var stat; 1.892 + var cond; 1.893 + var m = item.match(/^(fails|random|skip|silentfail)-if(\(.*\))$/); 1.894 + if (m) { 1.895 + stat = m[1]; 1.896 + // Note: m[2] contains the parentheses, and we want them. 1.897 + cond = Components.utils.evalInSandbox(m[2], sandbox); 1.898 + } else if (item.match(/^(fails|random|skip)$/)) { 1.899 + stat = item; 1.900 + cond = true; 1.901 + } else if (item == "needs-focus") { 1.902 + needs_focus = true; 1.903 + cond = false; 1.904 + } else if ((m = item.match(/^asserts\((\d+)(-\d+)?\)$/))) { 1.905 + cond = false; 1.906 + minAsserts = Number(m[1]); 1.907 + maxAsserts = (m[2] == undefined) ? minAsserts 1.908 + : Number(m[2].substring(1)); 1.909 + } else if ((m = item.match(/^asserts-if\((.*?),(\d+)(-\d+)?\)$/))) { 1.910 + cond = false; 1.911 + if (Components.utils.evalInSandbox("(" + m[1] + ")", sandbox)) { 1.912 + minAsserts = Number(m[2]); 1.913 + maxAsserts = 1.914 + (m[3] == undefined) ? minAsserts 1.915 + : Number(m[3].substring(1)); 1.916 + } 1.917 + } else if (item == "slow") { 1.918 + cond = false; 1.919 + slow = true; 1.920 + } else if ((m = item.match(/^require-or\((.*?)\)$/))) { 1.921 + var args = m[1].split(/,/); 1.922 + if (args.length != 2) { 1.923 + throw "Error 7 in manifest file " + aURL.spec + " line " + lineNo + ": wrong number of args to require-or"; 1.924 + } 1.925 + var [precondition_str, fallback_action] = args; 1.926 + var preconditions = precondition_str.split(/&&/); 1.927 + cond = false; 1.928 + for each (var precondition in preconditions) { 1.929 + if (precondition === "debugMode") { 1.930 + // Currently unimplemented. Requires asynchronous 1.931 + // JSD call + getting an event while no JS is running 1.932 + stat = fallback_action; 1.933 + cond = true; 1.934 + break; 1.935 + } else if (precondition === "true") { 1.936 + // For testing 1.937 + } else { 1.938 + // Unknown precondition. Assume it is unimplemented. 1.939 + stat = fallback_action; 1.940 + cond = true; 1.941 + break; 1.942 + } 1.943 + } 1.944 + } else if ((m = item.match(/^slow-if\((.*?)\)$/))) { 1.945 + cond = false; 1.946 + if (Components.utils.evalInSandbox("(" + m[1] + ")", sandbox)) 1.947 + slow = true; 1.948 + } else if (item == "silentfail") { 1.949 + cond = false; 1.950 + allow_silent_fail = true; 1.951 + } else if ((m = item.match(gPrefItemRE))) { 1.952 + cond = false; 1.953 + if (!AddPrefSettings(m[1], m[2], m[3], sandbox, testPrefSettings, refPrefSettings)) { 1.954 + throw "Error in pref value in manifest file " + aURL.spec + " line " + lineNo; 1.955 + } 1.956 + } else if ((m = item.match(/^fuzzy\((\d+),(\d+)\)$/))) { 1.957 + cond = false; 1.958 + expected_status = EXPECTED_FUZZY; 1.959 + fuzzy_max_delta = Number(m[1]); 1.960 + fuzzy_max_pixels = Number(m[2]); 1.961 + } else if ((m = item.match(/^fuzzy-if\((.*?),(\d+),(\d+)\)$/))) { 1.962 + cond = false; 1.963 + if (Components.utils.evalInSandbox("(" + m[1] + ")", sandbox)) { 1.964 + expected_status = EXPECTED_FUZZY; 1.965 + fuzzy_max_delta = Number(m[2]); 1.966 + fuzzy_max_pixels = Number(m[3]); 1.967 + } 1.968 + } else { 1.969 + throw "Error 1 in manifest file " + aURL.spec + " line " + lineNo; 1.970 + } 1.971 + 1.972 + if (cond) { 1.973 + if (stat == "fails") { 1.974 + expected_status = EXPECTED_FAIL; 1.975 + } else if (stat == "random") { 1.976 + expected_status = EXPECTED_RANDOM; 1.977 + } else if (stat == "skip") { 1.978 + expected_status = EXPECTED_DEATH; 1.979 + } else if (stat == "silentfail") { 1.980 + allow_silent_fail = true; 1.981 + } 1.982 + } 1.983 + } 1.984 + 1.985 + expected_status = Math.max(expected_status, inherited_status); 1.986 + 1.987 + if (minAsserts > maxAsserts) { 1.988 + throw "Bad range in manifest file " + aURL.spec + " line " + lineNo; 1.989 + } 1.990 + 1.991 + var runHttp = false; 1.992 + var httpDepth; 1.993 + if (items[0] == "HTTP") { 1.994 + runHttp = (aURL.scheme == "file"); // We can't yet run the local HTTP server 1.995 + // for non-local reftests. 1.996 + httpDepth = 0; 1.997 + items.shift(); 1.998 + } else if (items[0].match(/HTTP\(\.\.(\/\.\.)*\)/)) { 1.999 + // Accept HTTP(..), HTTP(../..), HTTP(../../..), etc. 1.1000 + runHttp = (aURL.scheme == "file"); // We can't yet run the local HTTP server 1.1001 + // for non-local reftests. 1.1002 + httpDepth = (items[0].length - 5) / 3; 1.1003 + items.shift(); 1.1004 + } 1.1005 + 1.1006 + // do not prefix the url for include commands or urls specifying 1.1007 + // a protocol 1.1008 + if (urlprefix && items[0] != "include") { 1.1009 + if (items.length > 1 && !items[1].match(gProtocolRE)) { 1.1010 + items[1] = urlprefix + items[1]; 1.1011 + } 1.1012 + if (items.length > 2 && !items[2].match(gProtocolRE)) { 1.1013 + items[2] = urlprefix + items[2]; 1.1014 + } 1.1015 + } 1.1016 + 1.1017 + var principal = secMan.getSimpleCodebasePrincipal(aURL); 1.1018 + 1.1019 + if (items[0] == "include") { 1.1020 + if (items.length != 2 || runHttp) 1.1021 + throw "Error 2 in manifest file " + aURL.spec + " line " + lineNo; 1.1022 + var incURI = gIOService.newURI(items[1], null, listURL); 1.1023 + secMan.checkLoadURIWithPrincipal(principal, incURI, 1.1024 + CI.nsIScriptSecurityManager.DISALLOW_SCRIPT); 1.1025 + ReadManifest(incURI, expected_status); 1.1026 + } else if (items[0] == TYPE_LOAD) { 1.1027 + if (items.length != 2 || 1.1028 + (expected_status != EXPECTED_PASS && 1.1029 + expected_status != EXPECTED_DEATH)) 1.1030 + throw "Error 3 in manifest file " + aURL.spec + " line " + lineNo; 1.1031 + var [testURI] = runHttp 1.1032 + ? ServeFiles(principal, httpDepth, 1.1033 + listURL, [items[1]]) 1.1034 + : [gIOService.newURI(items[1], null, listURL)]; 1.1035 + var prettyPath = runHttp 1.1036 + ? gIOService.newURI(items[1], null, listURL).spec 1.1037 + : testURI.spec; 1.1038 + secMan.checkLoadURIWithPrincipal(principal, testURI, 1.1039 + CI.nsIScriptSecurityManager.DISALLOW_SCRIPT); 1.1040 + AddTestItem({ type: TYPE_LOAD, 1.1041 + expected: expected_status, 1.1042 + allowSilentFail: allow_silent_fail, 1.1043 + prettyPath: prettyPath, 1.1044 + minAsserts: minAsserts, 1.1045 + maxAsserts: maxAsserts, 1.1046 + needsFocus: needs_focus, 1.1047 + slow: slow, 1.1048 + prefSettings1: testPrefSettings, 1.1049 + prefSettings2: refPrefSettings, 1.1050 + fuzzyMaxDelta: fuzzy_max_delta, 1.1051 + fuzzyMaxPixels: fuzzy_max_pixels, 1.1052 + url1: testURI, 1.1053 + url2: null }); 1.1054 + } else if (items[0] == TYPE_SCRIPT) { 1.1055 + if (items.length != 2) 1.1056 + throw "Error 4 in manifest file " + aURL.spec + " line " + lineNo; 1.1057 + var [testURI] = runHttp 1.1058 + ? ServeFiles(principal, httpDepth, 1.1059 + listURL, [items[1]]) 1.1060 + : [gIOService.newURI(items[1], null, listURL)]; 1.1061 + var prettyPath = runHttp 1.1062 + ? gIOService.newURI(items[1], null, listURL).spec 1.1063 + : testURI.spec; 1.1064 + secMan.checkLoadURIWithPrincipal(principal, testURI, 1.1065 + CI.nsIScriptSecurityManager.DISALLOW_SCRIPT); 1.1066 + AddTestItem({ type: TYPE_SCRIPT, 1.1067 + expected: expected_status, 1.1068 + allowSilentFail: allow_silent_fail, 1.1069 + prettyPath: prettyPath, 1.1070 + minAsserts: minAsserts, 1.1071 + maxAsserts: maxAsserts, 1.1072 + needsFocus: needs_focus, 1.1073 + slow: slow, 1.1074 + prefSettings1: testPrefSettings, 1.1075 + prefSettings2: refPrefSettings, 1.1076 + fuzzyMaxDelta: fuzzy_max_delta, 1.1077 + fuzzyMaxPixels: fuzzy_max_pixels, 1.1078 + url1: testURI, 1.1079 + url2: null }); 1.1080 + } else if (items[0] == TYPE_REFTEST_EQUAL || items[0] == TYPE_REFTEST_NOTEQUAL) { 1.1081 + if (items.length != 3) 1.1082 + throw "Error 5 in manifest file " + aURL.spec + " line " + lineNo; 1.1083 + var [testURI, refURI] = runHttp 1.1084 + ? ServeFiles(principal, httpDepth, 1.1085 + listURL, [items[1], items[2]]) 1.1086 + : [gIOService.newURI(items[1], null, listURL), 1.1087 + gIOService.newURI(items[2], null, listURL)]; 1.1088 + var prettyPath = runHttp 1.1089 + ? gIOService.newURI(items[1], null, listURL).spec 1.1090 + : testURI.spec; 1.1091 + secMan.checkLoadURIWithPrincipal(principal, testURI, 1.1092 + CI.nsIScriptSecurityManager.DISALLOW_SCRIPT); 1.1093 + secMan.checkLoadURIWithPrincipal(principal, refURI, 1.1094 + CI.nsIScriptSecurityManager.DISALLOW_SCRIPT); 1.1095 + AddTestItem({ type: items[0], 1.1096 + expected: expected_status, 1.1097 + allowSilentFail: allow_silent_fail, 1.1098 + prettyPath: prettyPath, 1.1099 + minAsserts: minAsserts, 1.1100 + maxAsserts: maxAsserts, 1.1101 + needsFocus: needs_focus, 1.1102 + slow: slow, 1.1103 + prefSettings1: testPrefSettings, 1.1104 + prefSettings2: refPrefSettings, 1.1105 + fuzzyMaxDelta: fuzzy_max_delta, 1.1106 + fuzzyMaxPixels: fuzzy_max_pixels, 1.1107 + url1: testURI, 1.1108 + url2: refURI }); 1.1109 + } else { 1.1110 + throw "Error 6 in manifest file " + aURL.spec + " line " + lineNo; 1.1111 + } 1.1112 + } 1.1113 +} 1.1114 + 1.1115 +function AddURIUseCount(uri) 1.1116 +{ 1.1117 + if (uri == null) 1.1118 + return; 1.1119 + 1.1120 + var spec = uri.spec; 1.1121 + if (spec in gURIUseCounts) { 1.1122 + gURIUseCounts[spec]++; 1.1123 + } else { 1.1124 + gURIUseCounts[spec] = 1; 1.1125 + } 1.1126 +} 1.1127 + 1.1128 +function BuildUseCounts() 1.1129 +{ 1.1130 + gURIUseCounts = {}; 1.1131 + for (var i = 0; i < gURLs.length; ++i) { 1.1132 + var url = gURLs[i]; 1.1133 + if (url.expected != EXPECTED_DEATH && 1.1134 + (url.type == TYPE_REFTEST_EQUAL || 1.1135 + url.type == TYPE_REFTEST_NOTEQUAL)) { 1.1136 + if (url.prefSettings1.length == 0) { 1.1137 + AddURIUseCount(gURLs[i].url1); 1.1138 + } 1.1139 + if (url.prefSettings2.length == 0) { 1.1140 + AddURIUseCount(gURLs[i].url2); 1.1141 + } 1.1142 + } 1.1143 + } 1.1144 +} 1.1145 + 1.1146 +function ServeFiles(manifestPrincipal, depth, aURL, files) 1.1147 +{ 1.1148 + var listURL = aURL.QueryInterface(CI.nsIFileURL); 1.1149 + var directory = listURL.file.parent; 1.1150 + 1.1151 + // Allow serving a tree that's an ancestor of the directory containing 1.1152 + // the files so that they can use resources in ../ (etc.). 1.1153 + var dirPath = "/"; 1.1154 + while (depth > 0) { 1.1155 + dirPath = "/" + directory.leafName + dirPath; 1.1156 + directory = directory.parent; 1.1157 + --depth; 1.1158 + } 1.1159 + 1.1160 + gCount++; 1.1161 + var path = "/" + Date.now() + "/" + gCount; 1.1162 + gServer.registerDirectory(path + "/", directory); 1.1163 + 1.1164 + var secMan = CC[NS_SCRIPTSECURITYMANAGER_CONTRACTID] 1.1165 + .getService(CI.nsIScriptSecurityManager); 1.1166 + 1.1167 + var testbase = gIOService.newURI("http://localhost:" + gHttpServerPort + 1.1168 + path + dirPath, null, null); 1.1169 + 1.1170 + function FileToURI(file) 1.1171 + { 1.1172 + // Only serve relative URIs via the HTTP server, not absolute 1.1173 + // ones like about:blank. 1.1174 + var testURI = gIOService.newURI(file, null, testbase); 1.1175 + 1.1176 + // XXX necessary? manifestURL guaranteed to be file, others always HTTP 1.1177 + secMan.checkLoadURIWithPrincipal(manifestPrincipal, testURI, 1.1178 + CI.nsIScriptSecurityManager.DISALLOW_SCRIPT); 1.1179 + 1.1180 + return testURI; 1.1181 + } 1.1182 + 1.1183 + return files.map(FileToURI); 1.1184 +} 1.1185 + 1.1186 +// Return true iff this window is focused when this function returns. 1.1187 +function Focus() 1.1188 +{ 1.1189 + var fm = CC["@mozilla.org/focus-manager;1"].getService(CI.nsIFocusManager); 1.1190 + fm.focusedWindow = gContainingWindow; 1.1191 +#ifdef XP_MACOSX 1.1192 + try { 1.1193 + var dock = CC["@mozilla.org/widget/macdocksupport;1"].getService(CI.nsIMacDockSupport); 1.1194 + dock.activateApplication(true); 1.1195 + } catch(ex) { 1.1196 + } 1.1197 +#endif // XP_MACOSX 1.1198 + return true; 1.1199 +} 1.1200 + 1.1201 +function Blur() 1.1202 +{ 1.1203 + // On non-remote reftests, this will transfer focus to the dummy window 1.1204 + // we created to hold focus for non-needs-focus tests. Buggy tests 1.1205 + // (ones which require focus but don't request needs-focus) will then 1.1206 + // fail. 1.1207 + gContainingWindow.blur(); 1.1208 +} 1.1209 + 1.1210 +function StartCurrentTest() 1.1211 +{ 1.1212 + gTestLog = []; 1.1213 + 1.1214 + // make sure we don't run tests that are expected to kill the browser 1.1215 + while (gURLs.length > 0) { 1.1216 + var test = gURLs[0]; 1.1217 + if (test.expected == EXPECTED_DEATH) { 1.1218 + ++gTestResults.Skip; 1.1219 + gDumpLog("REFTEST TEST-KNOWN-FAIL | " + test.url1.spec + " | (SKIP)\n"); 1.1220 + gURLs.shift(); 1.1221 + } else if (test.needsFocus && !Focus()) { 1.1222 + // FIXME: Marking this as a known fail is dangerous! What 1.1223 + // if it starts failing all the time? 1.1224 + ++gTestResults.Skip; 1.1225 + gDumpLog("REFTEST TEST-KNOWN-FAIL | " + test.url1.spec + " | (SKIPPED; COULDN'T GET FOCUS)\n"); 1.1226 + gURLs.shift(); 1.1227 + } else if (test.slow && !gRunSlowTests) { 1.1228 + ++gTestResults.Slow; 1.1229 + gDumpLog("REFTEST TEST-KNOWN-SLOW | " + test.url1.spec + " | (SLOW)\n"); 1.1230 + gURLs.shift(); 1.1231 + } else { 1.1232 + break; 1.1233 + } 1.1234 + } 1.1235 + 1.1236 + if (gURLs.length == 0) { 1.1237 + RestoreChangedPreferences(); 1.1238 + DoneTests(); 1.1239 + } 1.1240 + else { 1.1241 + gDumpLog("REFTEST TEST-START | " + gURLs[0].prettyPath + "\n"); 1.1242 + if (!gURLs[0].needsFocus) { 1.1243 + Blur(); 1.1244 + } 1.1245 + var currentTest = gTotalTests - gURLs.length; 1.1246 + gContainingWindow.document.title = "reftest: " + currentTest + " / " + gTotalTests + 1.1247 + " (" + Math.floor(100 * (currentTest / gTotalTests)) + "%)"; 1.1248 + StartCurrentURI(1); 1.1249 + } 1.1250 +} 1.1251 + 1.1252 +function StartCurrentURI(aState) 1.1253 +{ 1.1254 + gState = aState; 1.1255 + gCurrentURL = gURLs[0]["url" + aState].spec; 1.1256 + 1.1257 + RestoreChangedPreferences(); 1.1258 + 1.1259 + var prefSettings = gURLs[0]["prefSettings" + aState]; 1.1260 + if (prefSettings.length > 0) { 1.1261 + var prefs = Components.classes["@mozilla.org/preferences-service;1"]. 1.1262 + getService(Components.interfaces.nsIPrefBranch); 1.1263 + var badPref = undefined; 1.1264 + try { 1.1265 + prefSettings.forEach(function(ps) { 1.1266 + var oldVal; 1.1267 + if (ps.type == PREF_BOOLEAN) { 1.1268 + try { 1.1269 + oldVal = prefs.getBoolPref(ps.name); 1.1270 + } catch (e) { 1.1271 + badPref = "boolean preference '" + ps.name + "'"; 1.1272 + throw "bad pref"; 1.1273 + } 1.1274 + } else if (ps.type == PREF_STRING) { 1.1275 + try { 1.1276 + oldVal = prefs.getCharPref(ps.name); 1.1277 + } catch (e) { 1.1278 + badPref = "string preference '" + ps.name + "'"; 1.1279 + throw "bad pref"; 1.1280 + } 1.1281 + } else if (ps.type == PREF_INTEGER) { 1.1282 + try { 1.1283 + oldVal = prefs.getIntPref(ps.name); 1.1284 + } catch (e) { 1.1285 + badPref = "integer preference '" + ps.name + "'"; 1.1286 + throw "bad pref"; 1.1287 + } 1.1288 + } else { 1.1289 + throw "internal error - unknown preference type"; 1.1290 + } 1.1291 + if (oldVal != ps.value) { 1.1292 + gPrefsToRestore.push( { name: ps.name, 1.1293 + type: ps.type, 1.1294 + value: oldVal } ); 1.1295 + var value = ps.value; 1.1296 + if (ps.type == PREF_BOOLEAN) { 1.1297 + prefs.setBoolPref(ps.name, value); 1.1298 + } else if (ps.type == PREF_STRING) { 1.1299 + prefs.setCharPref(ps.name, value); 1.1300 + value = '"' + value + '"'; 1.1301 + } else if (ps.type == PREF_INTEGER) { 1.1302 + prefs.setIntPref(ps.name, value); 1.1303 + } 1.1304 + gDumpLog("SET PREFERENCE pref(" + ps.name + "," + value + ")\n"); 1.1305 + } 1.1306 + }); 1.1307 + } catch (e) { 1.1308 + if (e == "bad pref") { 1.1309 + var test = gURLs[0]; 1.1310 + if (test.expected == EXPECTED_FAIL) { 1.1311 + gDumpLog("REFTEST TEST-KNOWN-FAIL | " + test.url1.spec + 1.1312 + " | (SKIPPED; " + badPref + " not known or wrong type)\n"); 1.1313 + ++gTestResults.Skip; 1.1314 + } else { 1.1315 + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + test.url1.spec + 1.1316 + " | " + badPref + " not known or wrong type\n"); 1.1317 + ++gTestResults.UnexpectedFail; 1.1318 + } 1.1319 + } else { 1.1320 + throw e; 1.1321 + } 1.1322 + } 1.1323 + if (badPref != undefined) { 1.1324 + // skip the test that had a bad preference 1.1325 + gURLs.shift(); 1.1326 + 1.1327 + StartCurrentTest(); 1.1328 + return; 1.1329 + } 1.1330 + } 1.1331 + 1.1332 + if (prefSettings.length == 0 && 1.1333 + gURICanvases[gCurrentURL] && 1.1334 + (gURLs[0].type == TYPE_REFTEST_EQUAL || 1.1335 + gURLs[0].type == TYPE_REFTEST_NOTEQUAL) && 1.1336 + gURLs[0].maxAsserts == 0) { 1.1337 + // Pretend the document loaded --- RecordResult will notice 1.1338 + // there's already a canvas for this URL 1.1339 + gContainingWindow.setTimeout(RecordResult, 0); 1.1340 + } else { 1.1341 + var currentTest = gTotalTests - gURLs.length; 1.1342 + gDumpLog("REFTEST TEST-LOAD | " + gCurrentURL + " | " + currentTest + " / " + gTotalTests + 1.1343 + " (" + Math.floor(100 * (currentTest / gTotalTests)) + "%)\n"); 1.1344 + LogInfo("START " + gCurrentURL); 1.1345 + var type = gURLs[0].type 1.1346 + if (TYPE_SCRIPT == type) { 1.1347 + SendLoadScriptTest(gCurrentURL, gLoadTimeout); 1.1348 + } else { 1.1349 + SendLoadTest(type, gCurrentURL, gLoadTimeout); 1.1350 + } 1.1351 + } 1.1352 +} 1.1353 + 1.1354 +function DoneTests() 1.1355 +{ 1.1356 + gDumpLog("REFTEST FINISHED: Slowest test took " + gSlowestTestTime + 1.1357 + "ms (" + gSlowestTestURL + ")\n"); 1.1358 + 1.1359 + gDumpLog("REFTEST INFO | Result summary:\n"); 1.1360 + var count = gTestResults.Pass + gTestResults.LoadOnly; 1.1361 + gDumpLog("REFTEST INFO | Successful: " + count + " (" + 1.1362 + gTestResults.Pass + " pass, " + 1.1363 + gTestResults.LoadOnly + " load only)\n"); 1.1364 + count = gTestResults.Exception + gTestResults.FailedLoad + 1.1365 + gTestResults.UnexpectedFail + gTestResults.UnexpectedPass + 1.1366 + gTestResults.AssertionUnexpected + 1.1367 + gTestResults.AssertionUnexpectedFixed; 1.1368 + gDumpLog("REFTEST INFO | Unexpected: " + count + " (" + 1.1369 + gTestResults.UnexpectedFail + " unexpected fail, " + 1.1370 + gTestResults.UnexpectedPass + " unexpected pass, " + 1.1371 + gTestResults.AssertionUnexpected + " unexpected asserts, " + 1.1372 + gTestResults.AssertionUnexpectedFixed + " unexpected fixed asserts, " + 1.1373 + gTestResults.FailedLoad + " failed load, " + 1.1374 + gTestResults.Exception + " exception)\n"); 1.1375 + count = gTestResults.KnownFail + gTestResults.AssertionKnown + 1.1376 + gTestResults.Random + gTestResults.Skip + gTestResults.Slow; 1.1377 + gDumpLog("REFTEST INFO | Known problems: " + count + " (" + 1.1378 + gTestResults.KnownFail + " known fail, " + 1.1379 + gTestResults.AssertionKnown + " known asserts, " + 1.1380 + gTestResults.Random + " random, " + 1.1381 + gTestResults.Skip + " skipped, " + 1.1382 + gTestResults.Slow + " slow)\n"); 1.1383 + 1.1384 + gDumpLog("REFTEST INFO | Total canvas count = " + gRecycledCanvases.length + "\n"); 1.1385 + 1.1386 + gDumpLog("REFTEST TEST-START | Shutdown\n"); 1.1387 + function onStopped() { 1.1388 + let appStartup = CC["@mozilla.org/toolkit/app-startup;1"].getService(CI.nsIAppStartup); 1.1389 + appStartup.quit(CI.nsIAppStartup.eForceQuit); 1.1390 + } 1.1391 + if (gServer) { 1.1392 + gServer.stop(onStopped); 1.1393 + } 1.1394 + else { 1.1395 + onStopped(); 1.1396 + } 1.1397 +} 1.1398 + 1.1399 +function UpdateCanvasCache(url, canvas) 1.1400 +{ 1.1401 + var spec = url.spec; 1.1402 + 1.1403 + --gURIUseCounts[spec]; 1.1404 + 1.1405 + if (gNoCanvasCache || gURIUseCounts[spec] == 0) { 1.1406 + ReleaseCanvas(canvas); 1.1407 + delete gURICanvases[spec]; 1.1408 + } else if (gURIUseCounts[spec] > 0) { 1.1409 + gURICanvases[spec] = canvas; 1.1410 + } else { 1.1411 + throw "Use counts were computed incorrectly"; 1.1412 + } 1.1413 +} 1.1414 + 1.1415 +// Recompute drawWindow flags for every drawWindow operation. 1.1416 +// We have to do this every time since our window can be 1.1417 +// asynchronously resized (e.g. by the window manager, to make 1.1418 +// it fit on screen) at unpredictable times. 1.1419 +// Fortunately this is pretty cheap. 1.1420 +function DoDrawWindow(ctx, x, y, w, h) 1.1421 +{ 1.1422 + var flags = ctx.DRAWWINDOW_DRAW_CARET | ctx.DRAWWINDOW_DRAW_VIEW; 1.1423 + var testRect = gBrowser.getBoundingClientRect(); 1.1424 + if (gIgnoreWindowSize || 1.1425 + (0 <= testRect.left && 1.1426 + 0 <= testRect.top && 1.1427 + gContainingWindow.innerWidth >= testRect.right && 1.1428 + gContainingWindow.innerHeight >= testRect.bottom)) { 1.1429 + // We can use the window's retained layer manager 1.1430 + // because the window is big enough to display the entire 1.1431 + // browser element 1.1432 + flags |= ctx.DRAWWINDOW_USE_WIDGET_LAYERS; 1.1433 + } else if (gBrowserIsRemote) { 1.1434 + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gCurrentURL + " | can't drawWindow remote content\n"); 1.1435 + ++gTestResults.Exception; 1.1436 + } 1.1437 + 1.1438 + if (gDrawWindowFlags != flags) { 1.1439 + // Every time the flags change, dump the new state. 1.1440 + gDrawWindowFlags = flags; 1.1441 + var flagsStr = "DRAWWINDOW_DRAW_CARET | DRAWWINDOW_DRAW_VIEW"; 1.1442 + if (flags & ctx.DRAWWINDOW_USE_WIDGET_LAYERS) { 1.1443 + flagsStr += " | DRAWWINDOW_USE_WIDGET_LAYERS"; 1.1444 + } else { 1.1445 + // Output a special warning because we need to be able to detect 1.1446 + // this whenever it happens. 1.1447 + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | WARNING: USE_WIDGET_LAYERS disabled\n"); 1.1448 + } 1.1449 + gDumpLog("REFTEST INFO | drawWindow flags = " + flagsStr + 1.1450 + "; window size = " + gContainingWindow.innerWidth + "," + gContainingWindow.innerHeight + 1.1451 + "; test browser size = " + testRect.width + "," + testRect.height + 1.1452 + "\n"); 1.1453 + } 1.1454 + 1.1455 + LogInfo("DoDrawWindow " + x + "," + y + "," + w + "," + h); 1.1456 + ctx.drawWindow(gContainingWindow, x, y, w, h, "rgb(255,255,255)", 1.1457 + gDrawWindowFlags); 1.1458 +} 1.1459 + 1.1460 +function InitCurrentCanvasWithSnapshot() 1.1461 +{ 1.1462 + LogInfo("Initializing canvas snapshot"); 1.1463 + 1.1464 + if (gURLs[0].type == TYPE_LOAD || gURLs[0].type == TYPE_SCRIPT) { 1.1465 + // We don't want to snapshot this kind of test 1.1466 + return false; 1.1467 + } 1.1468 + 1.1469 + if (!gCurrentCanvas) { 1.1470 + gCurrentCanvas = AllocateCanvas(); 1.1471 + } 1.1472 + 1.1473 + var ctx = gCurrentCanvas.getContext("2d"); 1.1474 + DoDrawWindow(ctx, 0, 0, gCurrentCanvas.width, gCurrentCanvas.height); 1.1475 + return true; 1.1476 +} 1.1477 + 1.1478 +function UpdateCurrentCanvasForInvalidation(rects) 1.1479 +{ 1.1480 + LogInfo("Updating canvas for invalidation"); 1.1481 + 1.1482 + if (!gCurrentCanvas) { 1.1483 + return; 1.1484 + } 1.1485 + 1.1486 + var ctx = gCurrentCanvas.getContext("2d"); 1.1487 + for (var i = 0; i < rects.length; ++i) { 1.1488 + var r = rects[i]; 1.1489 + // Set left/top/right/bottom to pixel boundaries 1.1490 + var left = Math.floor(r.left); 1.1491 + var top = Math.floor(r.top); 1.1492 + var right = Math.ceil(r.right); 1.1493 + var bottom = Math.ceil(r.bottom); 1.1494 + 1.1495 + ctx.save(); 1.1496 + ctx.translate(left, top); 1.1497 + DoDrawWindow(ctx, left, top, right - left, bottom - top); 1.1498 + ctx.restore(); 1.1499 + } 1.1500 +} 1.1501 + 1.1502 +function UpdateWholeCurrentCanvasForInvalidation() 1.1503 +{ 1.1504 + LogInfo("Updating entire canvas for invalidation"); 1.1505 + 1.1506 + if (!gCurrentCanvas) { 1.1507 + return; 1.1508 + } 1.1509 + 1.1510 + var ctx = gCurrentCanvas.getContext("2d"); 1.1511 + DoDrawWindow(ctx, 0, 0, gCurrentCanvas.width, gCurrentCanvas.height); 1.1512 +} 1.1513 + 1.1514 +function RecordResult(testRunTime, errorMsg, scriptResults) 1.1515 +{ 1.1516 + LogInfo("RecordResult fired"); 1.1517 + 1.1518 + // Keep track of which test was slowest, and how long it took. 1.1519 + if (testRunTime > gSlowestTestTime) { 1.1520 + gSlowestTestTime = testRunTime; 1.1521 + gSlowestTestURL = gCurrentURL; 1.1522 + } 1.1523 + 1.1524 + // Not 'const ...' because of 'EXPECTED_*' value dependency. 1.1525 + var outputs = {}; 1.1526 + const randomMsg = "(EXPECTED RANDOM)"; 1.1527 + outputs[EXPECTED_PASS] = { 1.1528 + true: {s: "TEST-PASS" , n: "Pass"}, 1.1529 + false: {s: "TEST-UNEXPECTED-FAIL" , n: "UnexpectedFail"} 1.1530 + }; 1.1531 + outputs[EXPECTED_FAIL] = { 1.1532 + true: {s: "TEST-UNEXPECTED-PASS" , n: "UnexpectedPass"}, 1.1533 + false: {s: "TEST-KNOWN-FAIL" , n: "KnownFail"} 1.1534 + }; 1.1535 + outputs[EXPECTED_RANDOM] = { 1.1536 + true: {s: "TEST-PASS" + randomMsg , n: "Random"}, 1.1537 + false: {s: "TEST-KNOWN-FAIL" + randomMsg, n: "Random"} 1.1538 + }; 1.1539 + outputs[EXPECTED_FUZZY] = outputs[EXPECTED_PASS]; 1.1540 + 1.1541 + var output; 1.1542 + 1.1543 + if (gURLs[0].type == TYPE_LOAD) { 1.1544 + ++gTestResults.LoadOnly; 1.1545 + gDumpLog("REFTEST TEST-PASS | " + gURLs[0].prettyPath + " | (LOAD ONLY)\n"); 1.1546 + gCurrentCanvas = null; 1.1547 + FinishTestItem(); 1.1548 + return; 1.1549 + } 1.1550 + if (gURLs[0].type == TYPE_SCRIPT) { 1.1551 + var expected = gURLs[0].expected; 1.1552 + 1.1553 + if (errorMsg) { 1.1554 + // Force an unexpected failure to alert the test author to fix the test. 1.1555 + expected = EXPECTED_PASS; 1.1556 + } else if (scriptResults.length == 0) { 1.1557 + // This failure may be due to a JavaScript Engine bug causing 1.1558 + // early termination of the test. If we do not allow silent 1.1559 + // failure, report an error. 1.1560 + if (!gURLs[0].allowSilentFail) 1.1561 + errorMsg = "No test results reported. (SCRIPT)\n"; 1.1562 + else 1.1563 + gDumpLog("REFTEST INFO | An expected silent failure occurred \n"); 1.1564 + } 1.1565 + 1.1566 + if (errorMsg) { 1.1567 + output = outputs[expected][false]; 1.1568 + ++gTestResults[output.n]; 1.1569 + var result = "REFTEST " + output.s + " | " + 1.1570 + gURLs[0].prettyPath + " | " + // the URL being tested 1.1571 + errorMsg; 1.1572 + 1.1573 + gDumpLog(result); 1.1574 + FinishTestItem(); 1.1575 + return; 1.1576 + } 1.1577 + 1.1578 + var anyFailed = scriptResults.some(function(result) { return !result.passed; }); 1.1579 + var outputPair; 1.1580 + if (anyFailed && expected == EXPECTED_FAIL) { 1.1581 + // If we're marked as expected to fail, and some (but not all) tests 1.1582 + // passed, treat those tests as though they were marked random 1.1583 + // (since we can't tell whether they were really intended to be 1.1584 + // marked failing or not). 1.1585 + outputPair = { true: outputs[EXPECTED_RANDOM][true], 1.1586 + false: outputs[expected][false] }; 1.1587 + } else { 1.1588 + outputPair = outputs[expected]; 1.1589 + } 1.1590 + var index = 0; 1.1591 + scriptResults.forEach(function(result) { 1.1592 + var output = outputPair[result.passed]; 1.1593 + 1.1594 + ++gTestResults[output.n]; 1.1595 + result = "REFTEST " + output.s + " | " + 1.1596 + gURLs[0].prettyPath + " | " + // the URL being tested 1.1597 + result.description + " item " + (++index) + "\n"; 1.1598 + gDumpLog(result); 1.1599 + }); 1.1600 + 1.1601 + if (anyFailed && expected == EXPECTED_PASS) { 1.1602 + FlushTestLog(); 1.1603 + } 1.1604 + 1.1605 + FinishTestItem(); 1.1606 + return; 1.1607 + } 1.1608 + 1.1609 + if (gURLs[0]["prefSettings" + gState].length == 0 && 1.1610 + gURICanvases[gCurrentURL]) { 1.1611 + gCurrentCanvas = gURICanvases[gCurrentURL]; 1.1612 + } 1.1613 + if (gCurrentCanvas == null) { 1.1614 + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gCurrentURL + " | program error managing snapshots\n"); 1.1615 + ++gTestResults.Exception; 1.1616 + } 1.1617 + if (gState == 1) { 1.1618 + gCanvas1 = gCurrentCanvas; 1.1619 + } else { 1.1620 + gCanvas2 = gCurrentCanvas; 1.1621 + } 1.1622 + gCurrentCanvas = null; 1.1623 + 1.1624 + ResetRenderingState(); 1.1625 + 1.1626 + switch (gState) { 1.1627 + case 1: 1.1628 + // First document has been loaded. 1.1629 + // Proceed to load the second document. 1.1630 + 1.1631 + CleanUpCrashDumpFiles(); 1.1632 + StartCurrentURI(2); 1.1633 + break; 1.1634 + case 2: 1.1635 + // Both documents have been loaded. Compare the renderings and see 1.1636 + // if the comparison result matches the expected result specified 1.1637 + // in the manifest. 1.1638 + 1.1639 + // number of different pixels 1.1640 + var differences; 1.1641 + // whether the two renderings match: 1.1642 + var equal; 1.1643 + var maxDifference = {}; 1.1644 + 1.1645 + differences = gWindowUtils.compareCanvases(gCanvas1, gCanvas2, maxDifference); 1.1646 + equal = (differences == 0); 1.1647 + 1.1648 + // what is expected on this platform (PASS, FAIL, or RANDOM) 1.1649 + var expected = gURLs[0].expected; 1.1650 + 1.1651 + if (maxDifference.value > 0 && maxDifference.value <= gURLs[0].fuzzyMaxDelta && 1.1652 + differences <= gURLs[0].fuzzyMaxPixels) { 1.1653 + if (equal) { 1.1654 + throw "Inconsistent result from compareCanvases."; 1.1655 + } 1.1656 + equal = expected == EXPECTED_FUZZY; 1.1657 + gDumpLog("REFTEST fuzzy match\n"); 1.1658 + } 1.1659 + 1.1660 + // whether the comparison result matches what is in the manifest 1.1661 + var test_passed = (equal == (gURLs[0].type == TYPE_REFTEST_EQUAL)) && !gFailedNoPaint; 1.1662 + 1.1663 + output = outputs[expected][test_passed]; 1.1664 + 1.1665 + ++gTestResults[output.n]; 1.1666 + 1.1667 + // It's possible that we failed both reftest-no-paint and the normal comparison, but we don't 1.1668 + // have a way to annotate these separately, so just print an error for the no-paint failure. 1.1669 + if (gFailedNoPaint) { 1.1670 + if (expected == EXPECTED_FAIL) { 1.1671 + gDumpLog("REFTEST TEST-KNOWN-FAIL | " + gURLs[0].prettyPath + " | failed reftest-no-paint\n"); 1.1672 + } else { 1.1673 + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gURLs[0].prettyPath + " | failed reftest-no-paint\n"); 1.1674 + } 1.1675 + } else { 1.1676 + var result = "REFTEST " + output.s + " | " + 1.1677 + gURLs[0].prettyPath + " | "; // the URL being tested 1.1678 + switch (gURLs[0].type) { 1.1679 + case TYPE_REFTEST_NOTEQUAL: 1.1680 + result += "image comparison (!=)"; 1.1681 + break; 1.1682 + case TYPE_REFTEST_EQUAL: 1.1683 + result += "image comparison (==)"; 1.1684 + break; 1.1685 + } 1.1686 + 1.1687 + if (!test_passed && expected == EXPECTED_PASS || 1.1688 + !test_passed && expected == EXPECTED_FUZZY || 1.1689 + test_passed && expected == EXPECTED_FAIL) { 1.1690 + if (!equal) { 1.1691 + result += ", max difference: " + maxDifference.value + ", number of differing pixels: " + differences + "\n"; 1.1692 + result += "REFTEST IMAGE 1 (TEST): " + gCanvas1.toDataURL() + "\n"; 1.1693 + result += "REFTEST IMAGE 2 (REFERENCE): " + gCanvas2.toDataURL() + "\n"; 1.1694 + } else { 1.1695 + result += "\n"; 1.1696 + result += "REFTEST IMAGE: " + gCanvas1.toDataURL() + "\n"; 1.1697 + } 1.1698 + } else { 1.1699 + result += "\n"; 1.1700 + } 1.1701 + 1.1702 + gDumpLog(result); 1.1703 + } 1.1704 + 1.1705 + if (!test_passed && expected == EXPECTED_PASS) { 1.1706 + FlushTestLog(); 1.1707 + } 1.1708 + 1.1709 + if (gURLs[0].prefSettings1.length == 0) { 1.1710 + UpdateCanvasCache(gURLs[0].url1, gCanvas1); 1.1711 + } 1.1712 + if (gURLs[0].prefSettings2.length == 0) { 1.1713 + UpdateCanvasCache(gURLs[0].url2, gCanvas2); 1.1714 + } 1.1715 + 1.1716 + CleanUpCrashDumpFiles(); 1.1717 + FinishTestItem(); 1.1718 + break; 1.1719 + default: 1.1720 + throw "Unexpected state."; 1.1721 + } 1.1722 +} 1.1723 + 1.1724 +function LoadFailed(why) 1.1725 +{ 1.1726 + ++gTestResults.FailedLoad; 1.1727 + // Once bug 896840 is fixed, this can go away, but for now it will give log 1.1728 + // output that is TBPL starable for bug 789751 and bug 720452. 1.1729 + if (!why) { 1.1730 + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | load failed with unknown reason\n"); 1.1731 + } 1.1732 + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + 1.1733 + gURLs[0]["url" + gState].spec + " | load failed: " + why + "\n"); 1.1734 + FlushTestLog(); 1.1735 + FinishTestItem(); 1.1736 +} 1.1737 + 1.1738 +function RemoveExpectedCrashDumpFiles() 1.1739 +{ 1.1740 + if (gExpectingProcessCrash) { 1.1741 + for each (let crashFilename in gExpectedCrashDumpFiles) { 1.1742 + let file = gCrashDumpDir.clone(); 1.1743 + file.append(crashFilename); 1.1744 + if (file.exists()) { 1.1745 + file.remove(false); 1.1746 + } 1.1747 + } 1.1748 + } 1.1749 + gExpectedCrashDumpFiles.length = 0; 1.1750 +} 1.1751 + 1.1752 +function FindUnexpectedCrashDumpFiles() 1.1753 +{ 1.1754 + if (!gCrashDumpDir.exists()) { 1.1755 + return; 1.1756 + } 1.1757 + 1.1758 + let entries = gCrashDumpDir.directoryEntries; 1.1759 + if (!entries) { 1.1760 + return; 1.1761 + } 1.1762 + 1.1763 + let foundCrashDumpFile = false; 1.1764 + while (entries.hasMoreElements()) { 1.1765 + let file = entries.getNext().QueryInterface(CI.nsIFile); 1.1766 + let path = String(file.path); 1.1767 + if (path.match(/\.(dmp|extra)$/) && !gUnexpectedCrashDumpFiles[path]) { 1.1768 + if (!foundCrashDumpFile) { 1.1769 + ++gTestResults.UnexpectedFail; 1.1770 + foundCrashDumpFile = true; 1.1771 + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gCurrentURL + 1.1772 + " | This test left crash dumps behind, but we weren't expecting it to!\n"); 1.1773 + } 1.1774 + gDumpLog("REFTEST INFO | Found unexpected crash dump file " + path + 1.1775 + ".\n"); 1.1776 + gUnexpectedCrashDumpFiles[path] = true; 1.1777 + } 1.1778 + } 1.1779 +} 1.1780 + 1.1781 +function CleanUpCrashDumpFiles() 1.1782 +{ 1.1783 + RemoveExpectedCrashDumpFiles(); 1.1784 + FindUnexpectedCrashDumpFiles(); 1.1785 + gExpectingProcessCrash = false; 1.1786 +} 1.1787 + 1.1788 +function FinishTestItem() 1.1789 +{ 1.1790 + // Replace document with BLANK_URL_FOR_CLEARING in case there are 1.1791 + // assertions when unloading. 1.1792 + gDumpLog("REFTEST INFO | Loading a blank page\n"); 1.1793 + // After clearing, content will notify us of the assertion count 1.1794 + // and tests will continue. 1.1795 + SetAsyncScroll(false); 1.1796 + SendClear(); 1.1797 + gFailedNoPaint = false; 1.1798 +} 1.1799 + 1.1800 +function DoAssertionCheck(numAsserts) 1.1801 +{ 1.1802 + if (gDebug.isDebugBuild) { 1.1803 + if (gBrowserIsRemote) { 1.1804 + // Count chrome-process asserts too when content is out of 1.1805 + // process. 1.1806 + var newAssertionCount = gDebug.assertionCount; 1.1807 + var numLocalAsserts = newAssertionCount - gAssertionCount; 1.1808 + gAssertionCount = newAssertionCount; 1.1809 + 1.1810 + numAsserts += numLocalAsserts; 1.1811 + } 1.1812 + 1.1813 + var minAsserts = gURLs[0].minAsserts; 1.1814 + var maxAsserts = gURLs[0].maxAsserts; 1.1815 + 1.1816 + var expectedAssertions = "expected " + minAsserts; 1.1817 + if (minAsserts != maxAsserts) { 1.1818 + expectedAssertions += " to " + maxAsserts; 1.1819 + } 1.1820 + expectedAssertions += " assertions"; 1.1821 + 1.1822 + if (numAsserts < minAsserts) { 1.1823 + ++gTestResults.AssertionUnexpectedFixed; 1.1824 + gDumpLog("REFTEST TEST-UNEXPECTED-PASS | " + gURLs[0].prettyPath + 1.1825 + " | assertion count " + numAsserts + " is less than " + 1.1826 + expectedAssertions + "\n"); 1.1827 + } else if (numAsserts > maxAsserts) { 1.1828 + ++gTestResults.AssertionUnexpected; 1.1829 + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gURLs[0].prettyPath + 1.1830 + " | assertion count " + numAsserts + " is more than " + 1.1831 + expectedAssertions + "\n"); 1.1832 + } else if (numAsserts != 0) { 1.1833 + ++gTestResults.AssertionKnown; 1.1834 + gDumpLog("REFTEST TEST-KNOWN-FAIL | " + gURLs[0].prettyPath + 1.1835 + " | assertion count " + numAsserts + " matches " + 1.1836 + expectedAssertions + "\n"); 1.1837 + } 1.1838 + } 1.1839 + 1.1840 + gDumpLog("REFTEST TEST-END | " + gURLs[0].prettyPath + "\n"); 1.1841 + 1.1842 + // And start the next test. 1.1843 + gURLs.shift(); 1.1844 + StartCurrentTest(); 1.1845 +} 1.1846 + 1.1847 +function ResetRenderingState() 1.1848 +{ 1.1849 + SendResetRenderingState(); 1.1850 + // We would want to clear any viewconfig here, if we add support for it 1.1851 +} 1.1852 + 1.1853 +function RestoreChangedPreferences() 1.1854 +{ 1.1855 + if (gPrefsToRestore.length > 0) { 1.1856 + var prefs = Components.classes["@mozilla.org/preferences-service;1"]. 1.1857 + getService(Components.interfaces.nsIPrefBranch); 1.1858 + gPrefsToRestore.reverse(); 1.1859 + gPrefsToRestore.forEach(function(ps) { 1.1860 + var value = ps.value; 1.1861 + if (ps.type == PREF_BOOLEAN) { 1.1862 + prefs.setBoolPref(ps.name, value); 1.1863 + } else if (ps.type == PREF_STRING) { 1.1864 + prefs.setCharPref(ps.name, value); 1.1865 + value = '"' + value + '"'; 1.1866 + } else if (ps.type == PREF_INTEGER) { 1.1867 + prefs.setIntPref(ps.name, value); 1.1868 + } 1.1869 + gDumpLog("RESTORE PREFERENCE pref(" + ps.name + "," + value + ")\n"); 1.1870 + }); 1.1871 + gPrefsToRestore = []; 1.1872 + } 1.1873 +} 1.1874 + 1.1875 +function RegisterMessageListenersAndLoadContentScript() 1.1876 +{ 1.1877 + gBrowserMessageManager.addMessageListener( 1.1878 + "reftest:AssertionCount", 1.1879 + function (m) { RecvAssertionCount(m.json.count); } 1.1880 + ); 1.1881 + gBrowserMessageManager.addMessageListener( 1.1882 + "reftest:ContentReady", 1.1883 + function (m) { return RecvContentReady() } 1.1884 + ); 1.1885 + gBrowserMessageManager.addMessageListener( 1.1886 + "reftest:Exception", 1.1887 + function (m) { RecvException(m.json.what) } 1.1888 + ); 1.1889 + gBrowserMessageManager.addMessageListener( 1.1890 + "reftest:FailedLoad", 1.1891 + function (m) { RecvFailedLoad(m.json.why); } 1.1892 + ); 1.1893 + gBrowserMessageManager.addMessageListener( 1.1894 + "reftest:FailedNoPaint", 1.1895 + function (m) { RecvFailedNoPaint(); } 1.1896 + ); 1.1897 + gBrowserMessageManager.addMessageListener( 1.1898 + "reftest:InitCanvasWithSnapshot", 1.1899 + function (m) { return RecvInitCanvasWithSnapshot(); } 1.1900 + ); 1.1901 + gBrowserMessageManager.addMessageListener( 1.1902 + "reftest:Log", 1.1903 + function (m) { RecvLog(m.json.type, m.json.msg); } 1.1904 + ); 1.1905 + gBrowserMessageManager.addMessageListener( 1.1906 + "reftest:ScriptResults", 1.1907 + function (m) { RecvScriptResults(m.json.runtimeMs, m.json.error, m.json.results); } 1.1908 + ); 1.1909 + gBrowserMessageManager.addMessageListener( 1.1910 + "reftest:TestDone", 1.1911 + function (m) { RecvTestDone(m.json.runtimeMs); } 1.1912 + ); 1.1913 + gBrowserMessageManager.addMessageListener( 1.1914 + "reftest:UpdateCanvasForInvalidation", 1.1915 + function (m) { RecvUpdateCanvasForInvalidation(m.json.rects); } 1.1916 + ); 1.1917 + gBrowserMessageManager.addMessageListener( 1.1918 + "reftest:UpdateWholeCanvasForInvalidation", 1.1919 + function (m) { RecvUpdateWholeCanvasForInvalidation(); } 1.1920 + ); 1.1921 + gBrowserMessageManager.addMessageListener( 1.1922 + "reftest:ExpectProcessCrash", 1.1923 + function (m) { RecvExpectProcessCrash(); } 1.1924 + ); 1.1925 + gBrowserMessageManager.addMessageListener( 1.1926 + "reftest:EnableAsyncScroll", 1.1927 + function (m) { SetAsyncScroll(true); } 1.1928 + ); 1.1929 + 1.1930 + gBrowserMessageManager.loadFrameScript("chrome://reftest/content/reftest-content.js", true, true); 1.1931 +} 1.1932 + 1.1933 +function SetAsyncScroll(enabled) 1.1934 +{ 1.1935 + gBrowser.QueryInterface(CI.nsIFrameLoaderOwner).frameLoader.renderMode = 1.1936 + enabled ? CI.nsIFrameLoader.RENDER_MODE_ASYNC_SCROLL : 1.1937 + CI.nsIFrameLoader.RENDER_MODE_DEFAULT; 1.1938 +} 1.1939 + 1.1940 +function RecvAssertionCount(count) 1.1941 +{ 1.1942 + DoAssertionCheck(count); 1.1943 +} 1.1944 + 1.1945 +function RecvContentReady() 1.1946 +{ 1.1947 + InitAndStartRefTests(); 1.1948 + return { remote: gBrowserIsRemote }; 1.1949 +} 1.1950 + 1.1951 +function RecvException(what) 1.1952 +{ 1.1953 + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gCurrentURL + " | " + what + "\n"); 1.1954 + ++gTestResults.Exception; 1.1955 +} 1.1956 + 1.1957 +function RecvFailedLoad(why) 1.1958 +{ 1.1959 + LoadFailed(why); 1.1960 +} 1.1961 + 1.1962 +function RecvFailedNoPaint() 1.1963 +{ 1.1964 + gFailedNoPaint = true; 1.1965 +} 1.1966 + 1.1967 +function RecvInitCanvasWithSnapshot() 1.1968 +{ 1.1969 + var painted = InitCurrentCanvasWithSnapshot(); 1.1970 + return { painted: painted }; 1.1971 +} 1.1972 + 1.1973 +function RecvLog(type, msg) 1.1974 +{ 1.1975 + msg = "[CONTENT] "+ msg; 1.1976 + if (type == "info") { 1.1977 + LogInfo(msg); 1.1978 + } else if (type == "warning") { 1.1979 + LogWarning(msg); 1.1980 + } else { 1.1981 + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gCurrentURL + " | unknown log type " + type + "\n"); 1.1982 + ++gTestResults.Exception; 1.1983 + } 1.1984 +} 1.1985 + 1.1986 +function RecvScriptResults(runtimeMs, error, results) 1.1987 +{ 1.1988 + RecordResult(runtimeMs, error, results); 1.1989 +} 1.1990 + 1.1991 +function RecvTestDone(runtimeMs) 1.1992 +{ 1.1993 + RecordResult(runtimeMs, '', [ ]); 1.1994 +} 1.1995 + 1.1996 +function RecvUpdateCanvasForInvalidation(rects) 1.1997 +{ 1.1998 + UpdateCurrentCanvasForInvalidation(rects); 1.1999 +} 1.2000 + 1.2001 +function RecvUpdateWholeCanvasForInvalidation() 1.2002 +{ 1.2003 + UpdateWholeCurrentCanvasForInvalidation(); 1.2004 +} 1.2005 + 1.2006 +function OnProcessCrashed(subject, topic, data) 1.2007 +{ 1.2008 + var id; 1.2009 + subject = subject.QueryInterface(CI.nsIPropertyBag2); 1.2010 + if (topic == "plugin-crashed") { 1.2011 + id = subject.getPropertyAsAString("pluginDumpID"); 1.2012 + } else if (topic == "ipc:content-shutdown") { 1.2013 + id = subject.getPropertyAsAString("dumpID"); 1.2014 + } 1.2015 + if (id) { 1.2016 + gExpectedCrashDumpFiles.push(id + ".dmp"); 1.2017 + gExpectedCrashDumpFiles.push(id + ".extra"); 1.2018 + } 1.2019 +} 1.2020 + 1.2021 +function RegisterProcessCrashObservers() 1.2022 +{ 1.2023 + var os = CC[NS_OBSERVER_SERVICE_CONTRACTID] 1.2024 + .getService(CI.nsIObserverService); 1.2025 + os.addObserver(OnProcessCrashed, "plugin-crashed", false); 1.2026 + os.addObserver(OnProcessCrashed, "ipc:content-shutdown", false); 1.2027 +} 1.2028 + 1.2029 +function RecvExpectProcessCrash() 1.2030 +{ 1.2031 + gExpectingProcessCrash = true; 1.2032 +} 1.2033 + 1.2034 +function SendClear() 1.2035 +{ 1.2036 + gBrowserMessageManager.sendAsyncMessage("reftest:Clear"); 1.2037 +} 1.2038 + 1.2039 +function SendLoadScriptTest(uri, timeout) 1.2040 +{ 1.2041 + gBrowserMessageManager.sendAsyncMessage("reftest:LoadScriptTest", 1.2042 + { uri: uri, timeout: timeout }); 1.2043 +} 1.2044 + 1.2045 +function SendLoadTest(type, uri, timeout) 1.2046 +{ 1.2047 + gBrowserMessageManager.sendAsyncMessage("reftest:LoadTest", 1.2048 + { type: type, uri: uri, timeout: timeout } 1.2049 + ); 1.2050 +} 1.2051 + 1.2052 +function SendResetRenderingState() 1.2053 +{ 1.2054 + gBrowserMessageManager.sendAsyncMessage("reftest:ResetRenderingState"); 1.2055 +}