import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

View file

@ -0,0 +1,6 @@
"use strict";
module.exports = {
// Extend from the common devtools xpcshell eslintrc config.
"extends": "../../../.eslintrc.xpcshell.js"
};

View file

@ -0,0 +1,8 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
exports.exerciseLazyRequire = (name, path) => {
const o = {};
loader.lazyRequireGetter(o, name, path);
return o;
};

View file

@ -0,0 +1,60 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
var Cc = Components.classes;
var Ci = Components.interfaces;
var Cu = Components.utils;
var Cr = Components.results;
const {require, DevToolsLoader, devtools} = Cu.import("resource://devtools/shared/Loader.jsm", {});
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
const flags = require("devtools/shared/flags");
flags.testing = true;
do_register_cleanup(() => {
flags.testing = false;
});
// Register a console listener, so console messages don't just disappear
// into the ether.
// If for whatever reason the test needs to post console errors that aren't
// failures, set this to true.
var ALLOW_CONSOLE_ERRORS = false;
var errorCount = 0;
var listener = {
observe: function (aMessage) {
errorCount++;
try {
// If we've been given an nsIScriptError, then we can print out
// something nicely formatted, for tools like Emacs to pick up.
var scriptError = aMessage.QueryInterface(Ci.nsIScriptError);
dump(aMessage.sourceName + ":" + aMessage.lineNumber + ": " +
scriptErrorFlagsToKind(aMessage.flags) + ": " +
aMessage.errorMessage + "\n");
var string = aMessage.errorMessage;
} catch (x) {
// Be a little paranoid with message, as the whole goal here is to lose
// no information.
try {
var string = "" + aMessage.message;
} catch (x) {
var string = "<error converting error message to string>";
}
}
// Make sure we exit all nested event loops so that the test can finish.
while (DebuggerServer.xpcInspector.eventLoopNestLevel > 0) {
DebuggerServer.xpcInspector.exitNestedEventLoop();
}
if (!ALLOW_CONSOLE_ERRORS) {
do_throw("head_devtools.js got console message: " + string + "\n");
}
}
};
var consoleService = Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
consoleService.registerListener(listener);

View file

@ -0,0 +1,36 @@
/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Test DevToolsUtils.assert
ALLOW_CONSOLE_ERRORS = true;
function run_test() {
// Enable assertions.
flags.testing = true;
const { assert } = DevToolsUtils;
equal(typeof assert, "function");
try {
assert(true, "this assertion should not fail");
} catch (e) {
// If you catch assertion failures in practice, I will hunt you down. I get
// email notifications every time it happens.
ok(false, "Should not get an error for an assertion that should not fail. Got "
+ DevToolsUtils.safeErrorString(e));
}
let assertionFailed = false;
try {
assert(false, "this assertion should fail");
} catch (e) {
ok(e.message.startsWith("Assertion failure:"),
"Should be an assertion failure error");
assertionFailed = true;
}
ok(assertionFailed,
"The assertion should have failed, which should throw an error when assertions are enabled.");
}

View file

@ -0,0 +1,157 @@
/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Test async-utils.js
const {Task} = require("devtools/shared/task");
// |const| will not work because
// it will make the Promise object immutable before assigning.
// Using Object.defineProperty() instead.
Object.defineProperty(this, "Promise", {
value: require("promise"),
writable: false, configurable: false
});
const {asyncOnce, promiseInvoke, promiseCall} = require("devtools/shared/async-utils");
function run_test() {
do_test_pending();
Task.spawn(function* () {
yield test_async_args(asyncOnce);
yield test_async_return(asyncOnce);
yield test_async_throw(asyncOnce);
yield test_async_once();
yield test_async_invoke();
do_test_finished();
}).then(null, error => {
do_throw(error);
});
}
// Test that arguments are correctly passed through to the async function.
function test_async_args(async) {
let obj = {
method: async(function* (a, b) {
do_check_eq(this, obj);
do_check_eq(a, "foo");
do_check_eq(b, "bar");
})
};
return obj.method("foo", "bar");
}
// Test that the return value from the async function is resolution value of
// the promise.
function test_async_return(async) {
let obj = {
method: async(function* (a, b) {
return a + b;
})
};
return obj.method("foo", "bar").then(ret => {
do_check_eq(ret, "foobar");
});
}
// Test that the throwing from an async function rejects the promise.
function test_async_throw(async) {
let obj = {
method: async(function* () {
throw "boom";
})
};
return obj.method().then(null, error => {
do_check_eq(error, "boom");
});
}
// Test that asyncOnce only runs the async function once per instance and
// returns the same promise for that instance.
function test_async_once() {
let counter = 0;
function Foo() {}
Foo.prototype = {
ran: false,
method: asyncOnce(function* () {
yield Promise.resolve();
if (this.ran) {
do_throw("asyncOnce function unexpectedly ran twice on the same object");
}
this.ran = true;
return counter++;
})
};
let foo1 = new Foo();
let foo2 = new Foo();
let p1 = foo1.method();
let p2 = foo2.method();
do_check_neq(p1, p2);
let p3 = foo1.method();
do_check_eq(p1, p3);
do_check_false(foo1.ran);
let p4 = foo2.method();
do_check_eq(p2, p4);
do_check_false(foo2.ran);
return p1.then(ret => {
do_check_true(foo1.ran);
do_check_eq(ret, 0);
return p2;
}).then(ret => {
do_check_true(foo2.ran);
do_check_eq(ret, 1);
});
}
// Test invoke and call.
function test_async_invoke() {
return Task.spawn(function* () {
function func(a, b, expectedThis, callback) {
"use strict";
do_check_eq(a, "foo");
do_check_eq(b, "bar");
do_check_eq(this, expectedThis);
callback(a + b);
}
// Test call.
let callResult = yield promiseCall(func, "foo", "bar", undefined);
do_check_eq(callResult, "foobar");
// Test invoke.
let obj = { method: func };
let invokeResult = yield promiseInvoke(obj, obj.method, "foo", "bar", obj);
do_check_eq(invokeResult, "foobar");
// Test passing multiple values to the callback.
function multipleResults(callback) {
callback("foo", "bar");
}
let results = yield promiseCall(multipleResults);
do_check_eq(results.length, 2);
do_check_eq(results[0], "foo");
do_check_eq(results[1], "bar");
// Test throwing from the function.
function thrower() {
throw "boom";
}
yield promiseCall(thrower).then(null, error => {
do_check_eq(error, "boom");
});
});
}

View file

@ -0,0 +1,133 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const { console, ConsoleAPI } = require("resource://gre/modules/Console.jsm");
const { ConsoleAPIListener } = require("devtools/server/actors/utils/webconsole-utils");
const Services = require("Services");
var seenMessages = 0;
var seenTypes = 0;
var callback = {
onConsoleAPICall: function (aMessage) {
if (aMessage.consoleID && aMessage.consoleID == "addon/foo") {
do_check_eq(aMessage.level, "warn");
do_check_eq(aMessage.arguments[0], "Warning from foo");
seenTypes |= 1;
} else if (aMessage.originAttributes &&
aMessage.originAttributes.addonId == "bar") {
do_check_eq(aMessage.level, "error");
do_check_eq(aMessage.arguments[0], "Error from bar");
seenTypes |= 2;
} else {
do_check_eq(aMessage.level, "log");
do_check_eq(aMessage.arguments[0], "Hello from default console");
seenTypes |= 4;
}
seenMessages++;
}
};
function createFakeAddonWindow({addonId} = {}) {
let baseURI = Services.io.newURI("about:blank", null, null);
let originAttributes = {addonId};
let principal = Services.scriptSecurityManager
.createCodebasePrincipal(baseURI, originAttributes);
let chromeWebNav = Services.appShell.createWindowlessBrowser(true);
let docShell = chromeWebNav.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell);
docShell.createAboutBlankContentViewer(principal);
let addonWindow = docShell.contentViewer.DOMDocument.defaultView;
return {addonWindow, chromeWebNav};
}
/**
* Tests that the consoleID property of the ConsoleAPI options gets passed
* through to console messages.
*/
function run_test() {
// console1 Test Console.jsm messages tagged by the Addon SDK
// are still filtered correctly.
let console1 = new ConsoleAPI({
consoleID: "addon/foo"
});
// console2 - WebExtension page's console messages tagged
// by 'originAttributes.addonId' are filtered correctly.
let {addonWindow, chromeWebNav} = createFakeAddonWindow({addonId: "bar"});
let console2 = addonWindow.console;
// console - Plain console object (messages are tagged with window ids
// and originAttributes, but the addonId will be empty).
console.log("Hello from default console");
console1.warn("Warning from foo");
console2.error("Error from bar");
let listener = new ConsoleAPIListener(null, callback);
listener.init();
let messages = listener.getCachedMessages();
seenTypes = 0;
seenMessages = 0;
messages.forEach(callback.onConsoleAPICall);
do_check_eq(seenMessages, 3);
do_check_eq(seenTypes, 7);
seenTypes = 0;
seenMessages = 0;
console.log("Hello from default console");
console1.warn("Warning from foo");
console2.error("Error from bar");
do_check_eq(seenMessages, 3);
do_check_eq(seenTypes, 7);
listener.destroy();
listener = new ConsoleAPIListener(null, callback, {addonId: "foo"});
listener.init();
messages = listener.getCachedMessages();
seenTypes = 0;
seenMessages = 0;
messages.forEach(callback.onConsoleAPICall);
do_check_eq(seenMessages, 2);
do_check_eq(seenTypes, 1);
seenTypes = 0;
seenMessages = 0;
console.log("Hello from default console");
console1.warn("Warning from foo");
console2.error("Error from bar");
do_check_eq(seenMessages, 1);
do_check_eq(seenTypes, 1);
listener.destroy();
listener = new ConsoleAPIListener(null, callback, {addonId: "bar"});
listener.init();
messages = listener.getCachedMessages();
seenTypes = 0;
seenMessages = 0;
messages.forEach(callback.onConsoleAPICall);
do_check_eq(seenMessages, 3);
do_check_eq(seenTypes, 2);
seenTypes = 0;
seenMessages = 0;
console.log("Hello from default console");
console1.warn("Warning from foo");
console2.error("Error from bar");
do_check_eq(seenMessages, 1);
do_check_eq(seenTypes, 2);
listener.destroy();
// Close the addon window's chromeWebNav.
chromeWebNav.close();
}

View file

@ -0,0 +1,136 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that the devtool's client-side CSS properties database is in sync with the values
* on the platform (in Nightly only). If they are not, then `mach devtools-css-db` needs
* to be run to make everything up to date. Nightly, aurora, beta, and release may have
* different CSS properties and values. These are based on preferences and compiler flags.
*
* This test broke uplifts as the database needed to be regenerated every uplift. The
* combination of compiler flags and preferences means that it's too difficult to
* statically determine which properties are enabled between Firefox releases.
*
* Because of these difficulties, the database only needs to be up to date with Nightly.
* It is a fallback that is only used if the remote debugging protocol doesn't support
* providing a CSS database, so it's ok if the provided properties don't exactly match
* the inspected target in this particular case.
*/
"use strict";
const DOMUtils = Components.classes["@mozilla.org/inspector/dom-utils;1"]
.getService(Components.interfaces.inIDOMUtils);
const {PSEUDO_ELEMENTS, CSS_PROPERTIES} = require("devtools/shared/css/generated/properties-db");
const {generateCssProperties} = require("devtools/server/actors/css-properties");
function run_test() {
const propertiesErrorMessage = "If this assertion fails, then the client side CSS " +
"properties list in devtools is out of sync with the " +
"CSS properties on the platform. To fix this " +
"assertion run `mach devtools-css-db` to re-generate " +
"the client side properties.";
// Check that the platform and client match for pseudo elements.
deepEqual(PSEUDO_ELEMENTS, DOMUtils.getCSSPseudoElementNames(), `The pseudo elements ` +
`match on the client and platform. ${propertiesErrorMessage}`);
/**
* Check that the platform and client match for the details on their CSS properties.
* Enumerate each property to aid in debugging.
*/
const platformProperties = generateCssProperties();
for (let propertyName in CSS_PROPERTIES) {
const platformProperty = platformProperties[propertyName];
const clientProperty = CSS_PROPERTIES[propertyName];
const deepEqual = isJsonDeepEqual(platformProperty, clientProperty);
if (deepEqual) {
ok(true, `The static database and platform match for "${propertyName}".`);
} else {
const prefMessage = `The static database and platform do not match ` +
`for "${propertyName}".`;
if (getPreference(propertyName) === false) {
ok(true, `${prefMessage} However, there is a preference for disabling this ` +
`property on the current build.`);
} else {
ok(false, `${prefMessage} ${propertiesErrorMessage}`);
}
}
}
/**
* Check that the list of properties on the platform and client are the same. If
* they are not, check that there may be preferences that are disabling them on the
* target platform.
*/
const mismatches = getKeyMismatches(platformProperties, CSS_PROPERTIES)
// Filter out OS-specific properties.
.filter(name => name && name.indexOf("-moz-osx-") === -1);
if (mismatches.length === 0) {
ok(true, "No client and platform CSS property database mismatches were found.");
}
mismatches.forEach(propertyName => {
ok(false, `The static database and platform do not agree on the property ` +
`"${propertyName}" ${propertiesErrorMessage}`);
});
}
/**
* Check JSON-serializable objects for deep equality.
*/
function isJsonDeepEqual(a, b) {
// Handle primitives.
if (a === b) {
return true;
}
// Handle arrays.
if (Array.isArray(a) && Array.isArray(b)) {
if (a.length !== b.length) {
return false;
}
for (let i = 0; i < a.length; i++) {
if (!isJsonDeepEqual(a[i], b[i])) {
return false;
}
}
return true;
}
// Handle objects
if (typeof a === "object" && typeof b === "object") {
for (let key in a) {
if (!isJsonDeepEqual(a[key], b[key])) {
return false;
}
}
return Object.keys(a).length === Object.keys(b).length;
}
// Not something handled by these cases, therefore not equal.
return false;
}
/**
* Take the keys of two objects, and return the ones that don't match.
*
* @param {Object} a
* @param {Object} b
* @return {Array} keys
*/
function getKeyMismatches(a, b) {
const aNames = Object.keys(a);
const bNames = Object.keys(b);
const aMismatches = aNames.filter(key => !bNames.includes(key));
const bMismatches = bNames.filter(key => {
return !aNames.includes(key) && !aMismatches.includes(key);
});
return aMismatches.concat(bMismatches);
}

View file

@ -0,0 +1,242 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// This file is a copy of layout/style/test/test_csslexer.js, modified
// to use both our pure-JS lexer and the DOMUtils lexer for
// cross-checking.
"use strict";
const jsLexer = require("devtools/shared/css/lexer");
const domutils = Components.classes["@mozilla.org/inspector/dom-utils;1"]
.getService(Components.interfaces.inIDOMUtils);
// An object that acts like a CSSLexer but verifies that the DOM lexer
// and the JS lexer do the same thing.
function DoubleLexer(input) {
do_print("DoubleLexer input: " + input);
this.domLexer = domutils.getCSSLexer(input);
this.jsLexer = jsLexer.getCSSLexer(input);
}
DoubleLexer.prototype = {
checkState: function () {
equal(this.domLexer.lineNumber, this.jsLexer.lineNumber,
"check line number");
equal(this.domLexer.columnNumber, this.jsLexer.columnNumber,
"check column number");
},
get lineNumber() {
return this.domLexer.lineNumber;
},
get columnNumber() {
return this.domLexer.columnNumber;
},
performEOFFixup: function (inputString, preserveBackslash) {
let d = this.domLexer.performEOFFixup(inputString, preserveBackslash);
let j = this.jsLexer.performEOFFixup(inputString, preserveBackslash);
equal(d, j);
return d;
},
mungeNumber: function (token) {
if (token && (token.tokenType === "number" ||
token.tokenType === "percentage") &&
!token.isInteger) {
// The JS lexer does its computations in double, but the
// platform lexer does its computations in float. Account for
// this discrepancy in a way that's sufficient for this test.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1163047
token.number = parseFloat(token.number.toPrecision(8));
}
},
nextToken: function () {
// Check state both before and after.
this.checkState();
let d = this.domLexer.nextToken();
let j = this.jsLexer.nextToken();
this.mungeNumber(d);
this.mungeNumber(j);
deepEqual(d, j);
this.checkState();
return d;
}
};
function test_lexer(cssText, tokenTypes) {
let lexer = new DoubleLexer(cssText);
let reconstructed = "";
let lastTokenEnd = 0;
let i = 0;
while (true) {
let token = lexer.nextToken();
if (!token) {
break;
}
let combined = token.tokenType;
if (token.text) {
combined += ":" + token.text;
}
equal(combined, tokenTypes[i]);
ok(token.endOffset > token.startOffset);
equal(token.startOffset, lastTokenEnd);
lastTokenEnd = token.endOffset;
reconstructed += cssText.substring(token.startOffset, token.endOffset);
++i;
}
// Ensure that we saw the correct number of tokens.
equal(i, tokenTypes.length);
// Ensure that the reported offsets cover all the text.
equal(reconstructed, cssText);
}
var LEX_TESTS = [
["simple", ["ident:simple"]],
["simple: { hi; }",
["ident:simple", "symbol::",
"whitespace", "symbol:{",
"whitespace", "ident:hi",
"symbol:;", "whitespace",
"symbol:}"]],
["/* whatever */", ["comment"]],
["'string'", ["string:string"]],
['"string"', ["string:string"]],
["rgb(1,2,3)", ["function:rgb", "number",
"symbol:,", "number",
"symbol:,", "number",
"symbol:)"]],
["@media", ["at:media"]],
["#hibob", ["id:hibob"]],
["#123", ["hash:123"]],
["23px", ["dimension:px"]],
["23%", ["percentage"]],
["url(http://example.com)", ["url:http://example.com"]],
["url('http://example.com')", ["url:http://example.com"]],
["url( 'http://example.com' )",
["url:http://example.com"]],
// In CSS Level 3, this is an ordinary URL, not a BAD_URL.
["url(http://example.com", ["url:http://example.com"]],
// See bug 1153981 to understand why this gets a SYMBOL token.
["url(http://example.com @", ["bad_url:http://example.com", "symbol:@"]],
["quo\\ting", ["ident:quoting"]],
["'bad string\n", ["bad_string:bad string", "whitespace"]],
["~=", ["includes"]],
["|=", ["dashmatch"]],
["^=", ["beginsmatch"]],
["$=", ["endsmatch"]],
["*=", ["containsmatch"]],
// URANGE may be on the way out, and it isn't used by devutils, so
// let's skip it.
["<!-- html comment -->", ["htmlcomment", "whitespace", "ident:html",
"whitespace", "ident:comment", "whitespace",
"htmlcomment"]],
// earlier versions of CSS had "bad comment" tokens, but in level 3,
// unterminated comments are just comments.
["/* bad comment", ["comment"]]
];
function test_lexer_linecol(cssText, locations) {
let lexer = new DoubleLexer(cssText);
let i = 0;
while (true) {
let token = lexer.nextToken();
let startLine = lexer.lineNumber;
let startColumn = lexer.columnNumber;
// We do this in a bit of a funny way so that we can also test the
// location of the EOF.
let combined = ":" + startLine + ":" + startColumn;
if (token) {
combined = token.tokenType + combined;
}
equal(combined, locations[i]);
++i;
if (!token) {
break;
}
}
// Ensure that we saw the correct number of tokens.
equal(i, locations.length);
}
function test_lexer_eofchar(cssText, argText, expectedAppend,
expectedNoAppend) {
let lexer = new DoubleLexer(cssText);
while (lexer.nextToken()) {
// Nothing.
}
do_print("EOF char test, input = " + cssText);
let result = lexer.performEOFFixup(argText, true);
equal(result, expectedAppend);
result = lexer.performEOFFixup(argText, false);
equal(result, expectedNoAppend);
}
var LINECOL_TESTS = [
["simple", ["ident:0:0", ":0:6"]],
["\n stuff", ["whitespace:0:0", "ident:1:4", ":1:9"]],
['"string with \\\nnewline" \r\n', ["string:0:0", "whitespace:1:8",
":2:0"]]
];
var EOFCHAR_TESTS = [
["hello", "hello"],
["hello \\", "hello \\\\", "hello \\\uFFFD"],
["'hello", "'hello'"],
["\"hello", "\"hello\""],
["'hello\\", "'hello\\\\'", "'hello'"],
["\"hello\\", "\"hello\\\\\"", "\"hello\""],
["/*hello", "/*hello*/"],
["/*hello*", "/*hello*/"],
["/*hello\\", "/*hello\\*/"],
["url(hello", "url(hello)"],
["url('hello", "url('hello')"],
["url(\"hello", "url(\"hello\")"],
["url(hello\\", "url(hello\\\\)", "url(hello\\\uFFFD)"],
["url('hello\\", "url('hello\\\\')", "url('hello')"],
["url(\"hello\\", "url(\"hello\\\\\")", "url(\"hello\")"],
];
function run_test() {
let text, result;
for ([text, result] of LEX_TESTS) {
test_lexer(text, result);
}
for ([text, result] of LINECOL_TESTS) {
test_lexer_linecol(text, result);
}
let expectedAppend, expectedNoAppend;
for ([text, expectedAppend, expectedNoAppend] of EOFCHAR_TESTS) {
if (!expectedNoAppend) {
expectedNoAppend = expectedAppend;
}
test_lexer_eofchar(text, text, expectedAppend, expectedNoAppend);
}
// Ensure that passing a different inputString to performEOFFixup
// doesn't cause an assertion trying to strip a backslash from the
// end of an empty string.
test_lexer_eofchar("'\\", "", "\\'", "'");
}

View file

@ -0,0 +1,32 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const defer = require("devtools/shared/defer");
function testResolve() {
const deferred = defer();
deferred.resolve("success");
return deferred.promise;
}
function testReject() {
const deferred = defer();
deferred.reject("error");
return deferred.promise;
}
add_task(function* () {
const success = yield testResolve();
equal(success, "success");
let error;
try {
yield testReject();
} catch (e) {
error = e;
}
equal(error, "error");
});

View file

@ -0,0 +1,68 @@
/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Test DevToolsUtils.defineLazyPrototypeGetter
function Class() {}
DevToolsUtils.defineLazyPrototypeGetter(Class.prototype, "foo", () => []);
function run_test() {
test_prototype_attributes();
test_instance_attributes();
test_multiple_instances();
test_callback_receiver();
}
function test_prototype_attributes() {
// Check that the prototype has a getter property with expected attributes.
let descriptor = Object.getOwnPropertyDescriptor(Class.prototype, "foo");
do_check_eq(typeof descriptor.get, "function");
do_check_eq(descriptor.set, undefined);
do_check_eq(descriptor.enumerable, false);
do_check_eq(descriptor.configurable, true);
}
function test_instance_attributes() {
// Instances should not have an own property until the lazy getter has been
// activated.
let instance = new Class();
do_check_false(instance.hasOwnProperty("foo"));
instance.foo;
do_check_true(instance.hasOwnProperty("foo"));
// Check that the instance has an own property with the expecred value and
// attributes after the lazy getter is activated.
let descriptor = Object.getOwnPropertyDescriptor(instance, "foo");
do_check_true(descriptor.value instanceof Array);
do_check_eq(descriptor.writable, true);
do_check_eq(descriptor.enumerable, false);
do_check_eq(descriptor.configurable, true);
}
function test_multiple_instances() {
let instance1 = new Class();
let instance2 = new Class();
let foo1 = instance1.foo;
let foo2 = instance2.foo;
// Check that the lazy getter returns the expected type of value.
do_check_true(foo1 instanceof Array);
do_check_true(foo2 instanceof Array);
// Make sure the lazy getter runs once and only once per instance.
do_check_eq(instance1.foo, foo1);
do_check_eq(instance2.foo, foo2);
// Make sure each instance gets its own unique value.
do_check_neq(foo1, foo2);
}
function test_callback_receiver() {
function Foo() {}
DevToolsUtils.defineLazyPrototypeGetter(Foo.prototype, "foo", function () {
return this;
});
// Check that the |this| value in the callback is the instance itself.
let instance = new Foo();
do_check_eq(instance.foo, instance);
}

View file

@ -0,0 +1,48 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* Client request stacks should span the entire process from before making the
* request to handling the reply from the server. The server frames are not
* included, nor can they be in most cases, since the server can be a remote
* device.
*/
var { executeSoon } = require("devtools/shared/DevToolsUtils");
var promise = require("promise");
var defer = require("devtools/shared/defer");
var Services = require("Services");
var asyncStackEnabled =
Services.prefs.getBoolPref("javascript.options.asyncstack");
do_register_cleanup(() => {
Services.prefs.setBoolPref("javascript.options.asyncstack",
asyncStackEnabled);
});
add_task(function* () {
Services.prefs.setBoolPref("javascript.options.asyncstack", true);
yield waitForTick();
let stack = Components.stack;
while (stack) {
do_print(stack.name);
if (stack.name == "waitForTick") {
// Reached back to outer function before executeSoon
ok(true, "Complete stack");
return;
}
stack = stack.asyncCaller || stack.caller;
}
ok(false, "Incomplete stack");
});
function waitForTick() {
let deferred = defer();
executeSoon(deferred.resolve);
return deferred.promise;
}

View file

@ -0,0 +1,76 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Tests for DevToolsUtils.fetch BOM detection.
const CC = Components.Constructor;
const { HttpServer } = Cu.import("resource://testing-common/httpd.js", {});
const BinaryOutputStream = CC("@mozilla.org/binaryoutputstream;1",
"nsIBinaryOutputStream", "setOutputStream");
function write8(bos) {
bos.write8(0xef);
bos.write8(0xbb);
bos.write8(0xbf);
bos.write8(0x68);
bos.write8(0xc4);
bos.write8(0xb1);
}
function write16be(bos) {
bos.write8(0xfe);
bos.write8(0xff);
bos.write8(0x00);
bos.write8(0x68);
bos.write8(0x01);
bos.write8(0x31);
}
function write16le(bos) {
bos.write8(0xff);
bos.write8(0xfe);
bos.write8(0x68);
bos.write8(0x00);
bos.write8(0x31);
bos.write8(0x01);
}
function getHandler(writer) {
return function (request, response) {
response.setStatusLine(request.httpVersion, 200, "OK");
let bos = new BinaryOutputStream(response.bodyOutputStream);
writer(bos);
};
}
const server = new HttpServer();
server.registerDirectory("/", do_get_cwd());
server.registerPathHandler("/u8", getHandler(write8));
server.registerPathHandler("/u16be", getHandler(write16be));
server.registerPathHandler("/u16le", getHandler(write16le));
server.start(-1);
const port = server.identity.primaryPort;
const serverURL = "http://localhost:" + port;
do_register_cleanup(() => {
return new Promise(resolve => server.stop(resolve));
});
add_task(function* () {
yield test_one(serverURL + "/u8", "UTF-8");
yield test_one(serverURL + "/u16be", "UTF-16BE");
yield test_one(serverURL + "/u16le", "UTF-16LE");
});
function* test_one(url, encoding) {
// Be sure to set the encoding to something that will yield an
// invalid result if BOM sniffing is not done.
yield DevToolsUtils.fetch(url, { charset: "ISO-8859-1" }).then(({content}) => {
do_check_eq(content, "hı", "The content looks correct for " + encoding);
});
}

View file

@ -0,0 +1,31 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Tests for DevToolsUtils.fetch on chrome:// URI's.
const URL_FOUND = "chrome://devtools-shared/locale/debugger.properties";
const URL_NOT_FOUND = "chrome://this/is/not/here.js";
/**
* Test that non-existent files are handled correctly.
*/
add_task(function* test_missing() {
yield DevToolsUtils.fetch(URL_NOT_FOUND).then(result => {
do_print(result);
ok(false, "fetch resolved unexpectedly for non-existent chrome:// URI");
}, () => {
ok(true, "fetch rejected as the chrome:// URI was non-existent.");
});
});
/**
* Tests that existing files are handled correctly.
*/
add_task(function* test_normal() {
yield DevToolsUtils.fetch(URL_FOUND).then(result => {
notDeepEqual(result.content, "",
"chrome:// URI seems to be read correctly.");
});
});

View file

@ -0,0 +1,104 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Tests for DevToolsUtils.fetch on file:// URI's.
const { FileUtils } = Cu.import("resource://gre/modules/FileUtils.jsm", {});
const { OS } = Cu.import("resource://gre/modules/osfile.jsm", {});
const TEST_CONTENT = "aéd";
// The TEST_CONTENT encoded as UTF-8.
const UTF8_TEST_BUFFER = new Uint8Array([0x61, 0xc3, 0xa9, 0x64]);
// The TEST_CONTENT encoded as ISO 8859-1.
const ISO_8859_1_BUFFER = new Uint8Array([0x61, 0xe9, 0x64]);
/**
* Tests that URLs with arrows pointing to an actual source are handled properly
* (bug 808960). For example 'resource://gre/modules/XPIProvider.jsm ->
* file://l10n.js' should load 'file://l10n.js'.
*/
add_task(function* test_arrow_urls() {
let { path } = createTemporaryFile(".js");
let url = "resource://gre/modules/XPIProvider.jsm -> file://" + path;
yield OS.File.writeAtomic(path, TEST_CONTENT, { encoding: "utf-8" });
let { content } = yield DevToolsUtils.fetch(url);
deepEqual(content, TEST_CONTENT, "The file contents were correctly read.");
});
/**
* Tests that empty files are read correctly.
*/
add_task(function* test_empty() {
let { path } = createTemporaryFile();
let { content } = yield DevToolsUtils.fetch("file://" + path);
deepEqual(content, "", "The empty file was read correctly.");
});
/**
* Tests that UTF-8 encoded files are correctly read.
*/
add_task(function* test_encoding_utf8() {
let { path } = createTemporaryFile();
yield OS.File.writeAtomic(path, UTF8_TEST_BUFFER);
let { content } = yield DevToolsUtils.fetch(path);
deepEqual(content, TEST_CONTENT,
"The UTF-8 encoded file was correctly read.");
});
/**
* Tests that ISO 8859-1 (Latin-1) encoded files are correctly read.
*/
add_task(function* test_encoding_iso_8859_1() {
let { path } = createTemporaryFile();
yield OS.File.writeAtomic(path, ISO_8859_1_BUFFER);
let { content } = yield DevToolsUtils.fetch(path);
deepEqual(content, TEST_CONTENT,
"The ISO 8859-1 encoded file was correctly read.");
});
/**
* Test that non-existent files are handled correctly.
*/
add_task(function* test_missing() {
yield DevToolsUtils.fetch("file:///file/not/found.right").then(result => {
do_print(result);
ok(false, "Fetch resolved unexpectedly when the file was not found.");
}, () => {
ok(true, "Fetch rejected as expected because the file was not found.");
});
});
/**
* Test that URLs without file:// scheme work.
*/
add_task(function* test_schemeless_files() {
let { path } = createTemporaryFile();
yield OS.File.writeAtomic(path, TEST_CONTENT, { encoding: "utf-8" });
let { content } = yield DevToolsUtils.fetch(path);
deepEqual(content, TEST_CONTENT, "The content was correct.");
});
/**
* Creates a temporary file that is removed after the test completes.
*/
function createTemporaryFile(extension) {
let name = "test_fetch-file-" + Math.random() + (extension || "");
let file = FileUtils.getFile("TmpD", [name]);
file.create(Ci.nsIFile.NORMAL_FILE_TYPE, parseInt("0755", 8));
do_register_cleanup(() => {
file.remove(false);
});
return file;
}

View file

@ -0,0 +1,61 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Tests for DevToolsUtils.fetch on http:// URI's.
const { HttpServer } = Cu.import("resource://testing-common/httpd.js", {});
const server = new HttpServer();
server.registerDirectory("/", do_get_cwd());
server.registerPathHandler("/cached.json", cacheRequestHandler);
server.start(-1);
const port = server.identity.primaryPort;
const serverURL = "http://localhost:" + port;
const CACHED_URL = serverURL + "/cached.json";
const NORMAL_URL = serverURL + "/test_fetch-http.js";
function cacheRequestHandler(request, response) {
do_print("Got request for " + request.path);
response.setHeader("Cache-Control", "max-age=10000", false);
response.setStatusLine(request.httpVersion, 200, "OK");
response.setHeader("Content-Type", "application/json", false);
let body = "[" + Math.random() + "]";
response.bodyOutputStream.write(body, body.length);
}
do_register_cleanup(() => {
return new Promise(resolve => server.stop(resolve));
});
add_task(function* test_normal() {
yield DevToolsUtils.fetch(NORMAL_URL).then(({content}) => {
ok(content.includes("The content looks correct."),
"The content looks correct.");
});
});
add_task(function* test_caching() {
let initialContent = null;
do_print("Performing the first request.");
yield DevToolsUtils.fetch(CACHED_URL).then(({content}) => {
do_print("Got the first response: " + content);
initialContent = content;
});
do_print("Performing another request, expecting to get cached response.");
yield DevToolsUtils.fetch(CACHED_URL).then(({content}) => {
deepEqual(content, initialContent, "The content was loaded from cache.");
});
do_print("Performing a third request with cache bypassed.");
let opts = { loadFromCache: false };
yield DevToolsUtils.fetch(CACHED_URL, opts).then(({content}) => {
notDeepEqual(content, initialContent,
"The URL wasn't loaded from cache with loadFromCache: false.");
});
});

View file

@ -0,0 +1,31 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Tests for DevToolsUtils.fetch on resource:// URI's.
const URL_FOUND = "resource://devtools/shared/DevToolsUtils.js";
const URL_NOT_FOUND = "resource://devtools/this/is/not/here.js";
/**
* Test that non-existent files are handled correctly.
*/
add_task(function* test_missing() {
yield DevToolsUtils.fetch(URL_NOT_FOUND).then(result => {
do_print(result);
ok(false, "fetch resolved unexpectedly for non-existent resource:// URI");
}, () => {
ok(true, "fetch rejected as the resource:// URI was non-existent.");
});
});
/**
* Tests that existing files are handled correctly.
*/
add_task(function* test_normal() {
yield DevToolsUtils.fetch(URL_FOUND).then(result => {
notDeepEqual(result.content, "",
"resource:// URI seems to be read correctly.");
});
});

View file

@ -0,0 +1,24 @@
/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Test ThreadSafeDevToolsUtils.flatten
function run_test() {
const { flatten } = DevToolsUtils;
const flat = flatten([["a", "b", "c"],
["d", "e", "f"],
["g", "h", "i"]]);
equal(flat.length, 9);
equal(flat[0], "a");
equal(flat[1], "b");
equal(flat[2], "c");
equal(flat[3], "d");
equal(flat[4], "e");
equal(flat[5], "f");
equal(flat[6], "g");
equal(flat[7], "h");
equal(flat[8], "i");
}

View file

@ -0,0 +1,133 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const Services = require("Services");
const {
EXPAND_TAB,
TAB_SIZE,
DETECT_INDENT,
getIndentationFromPrefs,
getIndentationFromIteration,
getIndentationFromString,
} = require("devtools/shared/indentation");
function test_indent_from_prefs() {
Services.prefs.setBoolPref(DETECT_INDENT, true);
equal(getIndentationFromPrefs(), false,
"getIndentationFromPrefs returning false");
Services.prefs.setIntPref(TAB_SIZE, 73);
Services.prefs.setBoolPref(EXPAND_TAB, false);
Services.prefs.setBoolPref(DETECT_INDENT, false);
deepEqual(getIndentationFromPrefs(), {indentUnit: 73, indentWithTabs: true},
"getIndentationFromPrefs basic test");
}
const TESTS = [
{
desc: "two spaces",
input: [
"/*",
" * tricky comment block",
" */",
"div {",
" color: red;",
" background: blue;",
"}",
" ",
"span {",
" padding-left: 10px;",
"}"
],
expected: {indentUnit: 2, indentWithTabs: false}
},
{
desc: "four spaces",
input: [
"var obj = {",
" addNumbers: function() {",
" var x = 5;",
" var y = 18;",
" return x + y;",
" },",
" ",
" /*",
" * Do some stuff to two numbers",
" * ",
" * @param x",
" * @param y",
" * ",
" * @return the result of doing stuff",
" */",
" subtractNumbers: function(x, y) {",
" var x += 7;",
" var y += 18;",
" var result = x - y;",
" result %= 2;",
" }",
"}"
],
expected: {indentUnit: 4, indentWithTabs: false}
},
{
desc: "tabs",
input: [
"/*",
" * tricky comment block",
" */",
"div {",
"\tcolor: red;",
"\tbackground: blue;",
"}",
"",
"span {",
"\tpadding-left: 10px;",
"}"
],
expected: {indentUnit: 2, indentWithTabs: true}
},
{
desc: "no indent",
input: [
"var x = 0;",
" // stray thing",
"var y = 9;",
" ",
""
],
expected: {indentUnit: 2, indentWithTabs: false}
},
];
function test_indent_detection() {
Services.prefs.setIntPref(TAB_SIZE, 2);
Services.prefs.setBoolPref(EXPAND_TAB, true);
Services.prefs.setBoolPref(DETECT_INDENT, true);
for (let test of TESTS) {
let iterFn = function (start, end, callback) {
test.input.slice(start, end).forEach(callback);
};
deepEqual(getIndentationFromIteration(iterFn), test.expected,
"test getIndentationFromIteration " + test.desc);
}
for (let test of TESTS) {
deepEqual(getIndentationFromString(test.input.join("\n")), test.expected,
"test getIndentationFromString " + test.desc);
}
}
function run_test() {
try {
test_indent_from_prefs();
test_indent_detection();
} finally {
Services.prefs.clearUserPref(TAB_SIZE);
Services.prefs.clearUserPref(EXPAND_TAB);
Services.prefs.clearUserPref(DETECT_INDENT);
}
}

View file

@ -0,0 +1,20 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Ensure that each instance of the Dev Tools loader contains its own loader
* instance, and also returns unique objects. This ensures there is no sharing
* in place between loaders.
*/
function run_test() {
let loader1 = new DevToolsLoader();
let loader2 = new DevToolsLoader();
let indent1 = loader1.require("devtools/shared/indentation");
let indent2 = loader2.require("devtools/shared/indentation");
do_check_true(indent1 !== indent2);
do_check_true(loader1._provider !== loader2._provider);
do_check_true(loader1._provider.loader !== loader2._provider.loader);
}

View file

@ -0,0 +1,60 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const { addDebuggerToGlobal } = Cu.import("resource://gre/modules/jsdebugger.jsm", {});
addDebuggerToGlobal(this);
/**
* Ensure that sandboxes created via the Dev Tools loader respect the
* invisibleToDebugger flag.
*/
function run_test() {
visible_loader();
invisible_loader();
}
function visible_loader() {
let loader = new DevToolsLoader();
loader.invisibleToDebugger = false;
loader.require("devtools/shared/indentation");
let dbg = new Debugger();
let sandbox = loader._provider.loader.sharedGlobalSandbox;
try {
dbg.addDebuggee(sandbox);
do_check_true(true);
} catch (e) {
do_throw("debugger could not add visible value");
}
// Check that for common loader used for tabs, promise modules is Promise.jsm
// Which is required to support unhandled promises rejection in mochitests
const promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
do_check_eq(loader.require("promise"), promise);
}
function invisible_loader() {
let loader = new DevToolsLoader();
loader.invisibleToDebugger = true;
loader.require("devtools/shared/indentation");
let dbg = new Debugger();
let sandbox = loader._provider.loader.sharedGlobalSandbox;
try {
dbg.addDebuggee(sandbox);
do_throw("debugger added invisible value");
} catch (e) {
do_check_true(true);
}
// But for browser toolbox loader, promise is loaded as a regular modules out
// of Promise-backend.js, that to be invisible to the debugger and not step
// into it.
const promise = loader.require("promise");
const promiseModule = loader._provider.loader.modules["resource://gre/modules/Promise-backend.js"];
do_check_eq(promise, promiseModule.exports);
}

View file

@ -0,0 +1,25 @@
/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Test ThreadSafeDevToolsUtils.isSet
function run_test() {
const { isSet } = DevToolsUtils;
equal(isSet(new Set()), true);
equal(isSet(new Map()), false);
equal(isSet({}), false);
equal(isSet("I swear I'm a Set"), false);
equal(isSet(5), false);
const systemPrincipal = Cc["@mozilla.org/systemprincipal;1"]
.createInstance(Ci.nsIPrincipal);
const sandbox = new Cu.Sandbox(systemPrincipal);
equal(isSet(Cu.evalInSandbox("new Set()", sandbox)), true);
equal(isSet(Cu.evalInSandbox("new Map()", sandbox)), false);
equal(isSet(Cu.evalInSandbox("({})", sandbox)), false);
equal(isSet(Cu.evalInSandbox("'I swear I\\'m a Set'", sandbox)), false);
equal(isSet(Cu.evalInSandbox("5", sandbox)), false);
}

View file

@ -0,0 +1,29 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
/**
* This unit test makes sure the plural form for Irish Gaeilge is working by
* using the makeGetter method instead of using the default language (by
* development), English.
*/
const {PluralForm} = require("devtools/shared/plural-form");
function run_test() {
// English has 2 plural forms
do_check_eq(2, PluralForm.numForms());
// Make sure for good inputs, things work as expected
for (let num = 0; num <= 200; num++) {
do_check_eq(num == 1 ? "word" : "words", PluralForm.get(num, "word;words"));
}
// Not having enough plural forms defaults to the first form
do_check_eq("word", PluralForm.get(2, "word"));
// Empty forms defaults to the first form
do_check_eq("word", PluralForm.get(2, "word;"));
}

View file

@ -0,0 +1,38 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
/**
* This unit test makes sure the plural form for Irish Gaeilge is working by
* using the makeGetter method instead of using the default language (by
* development), English.
*/
const {PluralForm} = require("devtools/shared/plural-form");
function run_test() {
// Irish is plural rule #11
let [get, numForms] = PluralForm.makeGetter(11);
// Irish has 5 plural forms
do_check_eq(5, numForms());
// I don't really know Irish, so I'll stick in some dummy text
let words = "is 1;is 2;is 3-6;is 7-10;everything else";
let test = function (text, low, high) {
for (let num = low; num <= high; num++) {
do_check_eq(text, get(num, words));
}
};
// Make sure for good inputs, things work as expected
test("everything else", 0, 0);
test("is 1", 1, 1);
test("is 2", 2, 2);
test("is 3-6", 3, 6);
test("is 7-10", 7, 10);
test("everything else", 11, 200);
}

View file

@ -0,0 +1,68 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Test prettifyCSS.
"use strict";
const {prettifyCSS} = require("devtools/shared/inspector/css-logic");
const TESTS = [
{ name: "simple test",
input: "div { font-family:'Arial Black', Arial, sans-serif; }",
expected: [
"div {",
"\tfont-family:'Arial Black', Arial, sans-serif;",
"}"
]
},
{ name: "whitespace before open brace",
input: "div{}",
expected: [
"div {",
"}"
]
},
{ name: "minified with trailing newline",
input: "\nbody{background:white;}div{font-size:4em;color:red}span{color:green;}\n",
expected: [
"body {",
"\tbackground:white;",
"}",
"div {",
"\tfont-size:4em;",
"\tcolor:red",
"}",
"span {",
"\tcolor:green;",
"}"
]
},
{ name: "leading whitespace",
input: "\n div{color: red;}",
expected: [
"div {",
"\tcolor: red;",
"}"
]
},
];
function run_test() {
// Note that prettifyCSS.LINE_SEPARATOR is computed lazily, so we
// ensure it is set.
prettifyCSS("");
for (let test of TESTS) {
do_print(test.name);
let input = test.input.split("\n").join(prettifyCSS.LINE_SEPARATOR);
let output = prettifyCSS(input);
let expected = test.expected.join(prettifyCSS.LINE_SEPARATOR) +
prettifyCSS.LINE_SEPARATOR;
equal(output, expected, test.name);
}
}

View file

@ -0,0 +1,20 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Test require
// Ensure that DevtoolsLoader.require doesn't spawn multiple
// loader/modules when early cached
function testBug1091706() {
let loader = new DevToolsLoader();
let require = loader.require;
let indent1 = require("devtools/shared/indentation");
let indent2 = require("devtools/shared/indentation");
do_check_true(indent1 === indent2);
}
function run_test() {
testBug1091706();
}

View file

@ -0,0 +1,32 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Test devtools.lazyRequireGetter
function run_test() {
const name = "asyncUtils";
const path = "devtools/shared/async-utils";
const o = {};
devtools.lazyRequireGetter(o, name, path);
const asyncUtils = require(path);
// XXX: do_check_eq only works on primitive types, so we have this
// do_check_true of an equality expression.
do_check_true(o.asyncUtils === asyncUtils);
// A non-main loader should get a new object via |lazyRequireGetter|, just
// as it would via a direct |require|.
const o2 = {};
let loader = new DevToolsLoader();
// We have to init the loader by loading any module before lazyRequireGetter is available
loader.require("devtools/shared/DevToolsUtils");
loader.lazyRequireGetter(o2, name, path);
do_check_true(o2.asyncUtils !== asyncUtils);
// A module required via a non-main loader that then uses |lazyRequireGetter|
// should also get the same object from that non-main loader.
let exposeLoader = loader.require("xpcshell-test/exposeLoader");
const o3 = exposeLoader.exerciseLazyRequire(name, path);
do_check_true(o3.asyncUtils === o2.asyncUtils);
}

View file

@ -0,0 +1,19 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Test require using "raw!".
function run_test() {
let loader = new DevToolsLoader();
let require = loader.require;
let variableFileContents = require("raw!devtools/client/themes/variables.css");
ok(variableFileContents.length > 0, "raw browserRequire worked");
let propertiesFileContents = require("raw!devtools/client/locales/shared.properties");
ok(propertiesFileContents.length > 0, "unprefixed properties raw require worked");
let chromePropertiesFileContents =
require("raw!chrome://devtools/locale/shared.properties");
ok(chromePropertiesFileContents.length > 0, "prefixed properties raw require worked");
}

View file

@ -0,0 +1,58 @@
/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Test DevToolsUtils.safeErrorString
function run_test() {
test_with_error();
test_with_tricky_error();
test_with_string();
test_with_thrower();
test_with_psychotic();
}
function test_with_error() {
let s = DevToolsUtils.safeErrorString(new Error("foo bar"));
// Got the message.
do_check_true(s.includes("foo bar"));
// Got the stack.
do_check_true(s.includes("test_with_error"));
do_check_true(s.includes("test_safeErrorString.js"));
// Got the lineNumber and columnNumber.
do_check_true(s.includes("Line"));
do_check_true(s.includes("column"));
}
function test_with_tricky_error() {
let e = new Error("batman");
e.stack = { toString: Object.create(null) };
let s = DevToolsUtils.safeErrorString(e);
// Still got the message, despite a bad stack property.
do_check_true(s.includes("batman"));
}
function test_with_string() {
let s = DevToolsUtils.safeErrorString("not really an error");
// Still get the message.
do_check_true(s.includes("not really an error"));
}
function test_with_thrower() {
let s = DevToolsUtils.safeErrorString({
toString: () => {
throw new Error("Muahahaha");
}
});
// Still don't fail, get string back.
do_check_eq(typeof s, "string");
}
function test_with_psychotic() {
let s = DevToolsUtils.safeErrorString({
toString: () => Object.create(null)
});
// Still get a string out, and no exceptions thrown
do_check_eq(typeof s, "string");
do_check_eq(s, "[object Object]");
}

View file

@ -0,0 +1,45 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Test stack.js.
function run_test() {
let loader = new DevToolsLoader();
let require = loader.require;
const {StackFrameCache} = require("devtools/server/actors/utils/stack");
let cache = new StackFrameCache();
cache.initFrames();
let baseFrame = {
line: 23,
column: 77,
source: "nowhere",
functionDisplayName: "nobody",
parent: null,
asyncParent: null,
asyncCause: null
};
cache.addFrame(baseFrame);
let event = cache.makeEvent();
do_check_eq(event[0], null);
do_check_eq(event[1].functionDisplayName, "nobody");
do_check_eq(event.length, 2);
cache.addFrame({
line: 24,
column: 78,
source: "nowhere",
functionDisplayName: "still nobody",
parent: null,
asyncParent: baseFrame,
asyncCause: "async"
});
event = cache.makeEvent();
do_check_eq(event[0].functionDisplayName, "still nobody");
do_check_eq(event[0].parent, 0);
do_check_eq(event[0].asyncParent, 1);
do_check_eq(event.length, 1);
}

View file

@ -0,0 +1,40 @@
[DEFAULT]
tags = devtools
head = head_devtools.js
tail =
firefox-appdir = browser
skip-if = toolkit == 'android'
support-files =
exposeLoader.js
[test_assert.js]
[test_csslexer.js]
[test_css-properties-db.js]
# This test only enforces that the CSS database is up to date with nightly. The DB is
# only used when inspecting a target that doesn't support the getCSSDatabase actor.
# CSS properties are behind compile-time flags, and there is no automatic rebuild
# process for uplifts, so this test breaks on uplift.
run-if = nightly_build
[test_fetch-bom.js]
[test_fetch-chrome.js]
[test_fetch-file.js]
[test_fetch-http.js]
[test_fetch-resource.js]
[test_flatten.js]
[test_indentation.js]
[test_independent_loaders.js]
[test_invisible_loader.js]
[test_isSet.js]
[test_safeErrorString.js]
[test_defineLazyPrototypeGetter.js]
[test_async-utils.js]
[test_console_filtering.js]
[test_pluralForm-english.js]
[test_pluralForm-makeGetter.js]
[test_prettifyCSS.js]
[test_require_lazy.js]
[test_require_raw.js]
[test_require.js]
[test_stack.js]
[test_defer.js]
[test_executeSoon.js]