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