Files
palemoon27/testing/modules/Assert.jsm
T
roytam1 06d185e815 import changes from `dev' branch of rmottola/Arctic-Fox:
- var-let (4514fc8c5f)
- Bug 1191897, add a flag for popups which allow shortcut keys to not be consumed, fixes shortcuts not working when an e10s select popup is open, r=neil (c3d788f65c)
- Bug 1181897 - Do not scale down <img> elements passed to setDragImage. r=roc (b9db4b2c2f)
- Bug 1204442 nsIDragService::FireDragEventAtSource() shouldn't be available from script because it takes a value of mozilla::EventMessage r=smaug, sr=smaug (6d357d54a7)
- Bug 1202176, adjust coordinates from device to css pixels when drag popup moves, r=tn (d6fa56dc59)
- Bug 1204944, convert drag position coordinates properly, r=mstange (0ff3b815b4)
- Bug 1205511 - Make nsBaseDragService::mImage[X|Y] strongly typed. r=enn (47d68b017a)
- Bug 1205511 - Make nsMenuPopupFrame::MoveTo()'s arguments strongly typed. r=enn (c29c16b9ce)
- Bug 1205511 - Give nsPresContext a method that returns the CSS to device pixel scale. r=dbaron (e91a754991)
- Bug 1205511 - Add overloaded operators for multiplying and dividing an IntPointTyped by a ScaleFactor[2D]. r=kats (f857857c94)
- Bug 1188172 - Don't update the resolution/SPCSPS for meta-viewport changes before the first-paint. r=botond (0d7eeda1c8)
- Bug 1168487 - Update the last use site of ScrollbarAreaToExcludeFromCompositionBoundsFor to use LD pixels. r=tn (af1d65d14a)
- Bug 1197592 - Don't set an SPCSPS in the mobile viewport manager if APZ zooming is not enabled. r=botond (eb2b3d3bf3)
- Bug 1180267 - Don't set root displayport margins from the mobile viewport manager unless the C++ APZ is enabled. r=botond (982b57a6f3)
- Bug 976616 - Part 1: Call ProcessViewportInfo when meta viewport is changed. r=bholley (0df9aaad5c)
- Bug 976616 - Part 2: Update mobile viewport on DOMMetaChanged event. r=kats (97244f0a2f)
- Bug 976616 - Part 3: Enable meta viewport tests for Fennec. r=kats (16de4304dc)
- Bug 976616 - Part 4: Add test for dynamic meta viewport updates. r=kats (c3af1ba028)
- Bug 1198839 - Don't update the displayport from the MVM unless there is already on the content. r=botond (a86c335313)
- Bug 1205511 - Document that nsIDragService.dragMoved() takes its arguments in LayoutDevice pixels. r=enn IGNORE IDL (comment change only) (ea1f24c65e)
- Bug 1180267 - Ensure that the desktop-mode viewport for Fennec is based on a 980 CSS pixel width rather than the screen size. r=snorp (365c12249c)
- Bug 1200402 - Ignore desktop mode for about: pages. r=snorp,khuey (3d64772abe)
- Bug 1197824 - Remove unused state and normalize others. r=botond (58ed2bb53b)
- Bug 1197824 - Allow zooming in desktop mode. r=botond (dbded0fdf7)
- Bug 1200303 - Support meta-viewport changes in ZoomConstraintsClient as well. r=miketaylr (bb5ebee8ed)
- Bug 1197824 - Support the browser.ui.zoom.force-user-scalable pref in the gecko zoom-constraints codepath. r=botond (0292f794c6)
- Bug 1197824 - Constrain the min/max zoom if zooming is not allowed. r=botond (26ae1656ba)
- Bug 1197824 - Remove the mAllowDoubleTapZoom field from nsViewportInfo as it is not needed. r=botond (00455cf30c)
- Bug 1189837 - Subtract scrollbars in LD pixels rather than CSS pixels. r=mstange (8801383234)
- Bug 1210399 - IonMonkey: MIPS: Safe for races. r=lth (5be49e2198)
- Bug 1202367 - reinitialize expected value in CAS loop. patch=hev, r=sstangl, push=lth (438272bb96)
- Bug 1210733 - Record source filenames independently of the script coverage. r=terrence (3a90b1a660)
- Bug 1211546 - Unbreak the non-unified build. (r=sfink, r=nbp, r=shu) (4b290fffac)
- Bug 977338 - Remove AtomicOperations-inl.h, r=lth (0015c7a398)
- Bug 1202713 - Fix the CSS viewport dimensions for desktop mode. r=snorp (763a55b6aa)
- Bug 1024343: The document should not stop animations when it is being swapped. r=smaug (ba2d43f308)
- Bug 1200093 - Don't rely on finding the widget for a document in order to get the css-to-ld scale. r=botond (bf359f6c76)
- Bug 1205511 - Use nsPresContext::DevToCSSPixelScale() where appropriate. r=kats (631a8fe6ae)
- Bug 1204994 - part 0 - separate debugging use counters check from value check; r=bz (d8771157eb)
- Bug 1204994 - part 2 - rename all USE_COUNTER_* histograms to USE_COUNTER2_* histograms; r=bz,vladan (8a86ee4560)
- Bug 1202895 - Fix shift-reload check for setting up service worker. r=bkelly (61309332e6)
- let-var (315a834c4d)
- Bug 1193469 - Make mozSettings more defensive. r=gwagner (9c4aeb2721)
- Bug 1187419 - Make sure SettingsRequestManager is only loaded in parent. r=gwagner (98bfca7a44)
- Bug 1156231 - enable data registration recovery. r=hsinyi (f886c81ce3)
- Bug 1159591 - Part 1: Add MMI tests for call barring, call waiting, clip, clir, pin2, puk2 and ussd. r=aknow (96ba4e4a89)
- Bug 1149433 - Set hangUpLocal in rejectCall. r=hsinyi (43aec5ea64)
- Bug 1147842 - Fix defect of setting call started time. r=hsinyi (dbf6a5516a)
- Bug 1145079 - Fix defect for calling isEmergencyOnly. r=hsinyi (8ba883d37e)
2022-09-05 10:46:01 +08:00

480 lines
15 KiB
JavaScript

/* 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/. */
// http://wiki.commonjs.org/wiki/Unit_Testing/1.0
// When you see a javadoc comment that contains a number, it's a reference to a
// specific section of the CommonJS spec.
//
// Originally from narwhal.js (http://narwhaljs.org)
// Copyright (c) 2009 Thomas Robinson <280north.com>
// MIT license: http://opensource.org/licenses/MIT
"use strict";
this.EXPORTED_SYMBOLS = [
"Assert"
];
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
"resource://gre/modules/Promise.jsm");
/**
* 1. The assert module provides functions that throw AssertionError's when
* particular conditions are not met.
*
* To use the module you'll need to instantiate it first, which allows consumers
* to override certain behavior on the newly obtained instance. For examples,
* see the javadoc comments for the `report` member function.
*/
var Assert = this.Assert = function(reporterFunc) {
if (reporterFunc)
this.setReporter(reporterFunc);
};
function instanceOf(object, type) {
return Object.prototype.toString.call(object) == "[object " + type + "]";
}
function replacer(key, value) {
if (value === undefined) {
return "" + value;
}
if (typeof value === "number" && (isNaN(value) || !isFinite(value))) {
return value.toString();
}
if (typeof value === "function" || instanceOf(value, "RegExp")) {
return value.toString();
}
return value;
}
const kTruncateLength = 128;
function truncate(text, newLength = kTruncateLength) {
if (typeof text == "string") {
return text.length < newLength ? text : text.slice(0, newLength);
} else {
return text;
}
}
function getMessage(error, prefix = "") {
let actual, expected;
// Wrap calls to JSON.stringify in try...catch blocks, as they may throw. If
// so, fall back to toString().
try {
actual = JSON.stringify(error.actual, replacer);
} catch (ex) {
actual = Object.prototype.toString.call(error.actual);
}
try {
expected = JSON.stringify(error.expected, replacer);
} catch (ex) {
expected = Object.prototype.toString.call(error.expected);
}
let message = prefix;
if (error.operator) {
message += (prefix ? " - " : "") + truncate(actual) + " " + error.operator +
" " + truncate(expected);
}
return message;
}
/**
* 2. The AssertionError is defined in assert.
*
* Example:
* new assert.AssertionError({
* message: message,
* actual: actual,
* expected: expected,
* operator: operator
* });
*
* At present only the four keys mentioned above are used and
* understood by the spec. Implementations or sub modules can pass
* other keys to the AssertionError's constructor - they will be
* ignored.
*/
Assert.AssertionError = function(options) {
this.name = "AssertionError";
this.actual = options.actual;
this.expected = options.expected;
this.operator = options.operator;
this.message = getMessage(this, options.message);
// The part of the stack that comes from this module is not interesting.
let stack = Components.stack;
do {
stack = stack.asyncCaller || stack.caller;
} while(stack.filename && stack.filename.includes("Assert.jsm"))
this.stack = stack;
};
// assert.AssertionError instanceof Error
Assert.AssertionError.prototype = Object.create(Error.prototype, {
constructor: {
value: Assert.AssertionError,
enumerable: false,
writable: true,
configurable: true
}
});
var proto = Assert.prototype;
proto._reporter = null;
/**
* Set a custom assertion report handler function. Arguments passed in to this
* function are:
* err (AssertionError|null) An error object when the assertion failed or null
* when it passed
* message (string) Message describing the assertion
* stack (stack) Stack trace of the assertion function
*
* Example:
* ```js
* Assert.setReporter(function customReporter(err, message, stack) {
* if (err) {
* do_report_result(false, err.message, err.stack);
* } else {
* do_report_result(true, message, stack);
* }
* });
* ```
*
* @param reporterFunc
* (function) Report handler function
*/
proto.setReporter = function(reporterFunc) {
this._reporter = reporterFunc;
};
/**
* 3. All of the following functions must throw an AssertionError when a
* corresponding condition is not met, with a message that may be undefined if
* not provided. All assertion methods provide both the actual and expected
* values to the assertion error for display purposes.
*
* This report method only throws errors on assertion failures, as per spec,
* but consumers of this module (think: xpcshell-test, mochitest) may want to
* override this default implementation.
*
* Example:
* ```js
* // The following will report an assertion failure.
* this.report(1 != 2, 1, 2, "testing JS number math!", "==");
* ```
*
* @param failed
* (boolean) Indicates if the assertion failed or not
* @param actual
* (mixed) The result of evaluating the assertion
* @param expected (optional)
* (mixed) Expected result from the test author
* @param message (optional)
* (string) Short explanation of the expected result
* @param operator (optional)
* (string) Operation qualifier used by the assertion method (ex: '==')
*/
proto.report = function(failed, actual, expected, message, operator) {
let err = new Assert.AssertionError({
message: message,
actual: actual,
expected: expected,
operator: operator
});
if (!this._reporter) {
// If no custom reporter is set, throw the error.
if (failed) {
throw err;
}
} else {
this._reporter(failed ? err : null, err.message, err.stack);
}
};
/**
* 4. Pure assertion tests whether a value is truthy, as determined by !!guard.
* assert.ok(guard, message_opt);
* This statement is equivalent to assert.equal(true, !!guard, message_opt);.
* To test strictly for the value true, use assert.strictEqual(true, guard,
* message_opt);.
*
* @param value
* (mixed) Test subject to be evaluated as truthy
* @param message (optional)
* (string) Short explanation of the expected result
*/
proto.ok = function(value, message) {
this.report(!value, value, true, message, "==");
};
/**
* 5. The equality assertion tests shallow, coercive equality with ==.
* assert.equal(actual, expected, message_opt);
*
* @param actual
* (mixed) Test subject to be evaluated as equivalent to `expected`
* @param expected
* (mixed) Test reference to evaluate against `actual`
* @param message (optional)
* (string) Short explanation of the expected result
*/
proto.equal = function equal(actual, expected, message) {
this.report(actual != expected, actual, expected, message, "==");
};
/**
* 6. The non-equality assertion tests for whether two objects are not equal
* with != assert.notEqual(actual, expected, message_opt);
*
* @param actual
* (mixed) Test subject to be evaluated as NOT equivalent to `expected`
* @param expected
* (mixed) Test reference to evaluate against `actual`
* @param message (optional)
* (string) Short explanation of the expected result
*/
proto.notEqual = function notEqual(actual, expected, message) {
this.report(actual == expected, actual, expected, message, "!=");
};
/**
* 7. The equivalence assertion tests a deep equality relation.
* assert.deepEqual(actual, expected, message_opt);
*
* We check using the most exact approximation of equality between two objects
* to keep the chance of false positives to a minimum.
* `JSON.stringify` is not designed to be used for this purpose; objects may
* have ambiguous `toJSON()` implementations that would influence the test.
*
* @param actual
* (mixed) Test subject to be evaluated as equivalent to `expected`, including nested properties
* @param expected
* (mixed) Test reference to evaluate against `actual`
* @param message (optional)
* (string) Short explanation of the expected result
*/
proto.deepEqual = function deepEqual(actual, expected, message) {
this.report(!_deepEqual(actual, expected), actual, expected, message, "deepEqual");
};
function _deepEqual(actual, expected) {
// 7.1. All identical values are equivalent, as determined by ===.
if (actual === expected) {
return true;
// 7.2. If the expected value is a Date object, the actual value is
// equivalent if it is also a Date object that refers to the same time.
} else if (instanceOf(actual, "Date") && instanceOf(expected, "Date")) {
if (isNaN(actual.getTime()) && isNaN(expected.getTime()))
return true;
return actual.getTime() === expected.getTime();
// 7.3 If the expected value is a RegExp object, the actual value is
// equivalent if it is also a RegExp object with the same source and
// properties (`global`, `multiline`, `lastIndex`, `ignoreCase`).
} else if (instanceOf(actual, "RegExp") && instanceOf(expected, "RegExp")) {
return actual.source === expected.source &&
actual.global === expected.global &&
actual.multiline === expected.multiline &&
actual.lastIndex === expected.lastIndex &&
actual.ignoreCase === expected.ignoreCase;
// 7.4. Other pairs that do not both pass typeof value == "object",
// equivalence is determined by ==.
} else if (typeof actual != "object" && typeof expected != "object") {
return actual == expected;
// 7.5 For all other Object pairs, including Array objects, equivalence is
// determined by having the same number of owned properties (as verified
// with Object.prototype.hasOwnProperty.call), the same set of keys
// (although not necessarily the same order), equivalent values for every
// corresponding key, and an identical 'prototype' property. Note: this
// accounts for both named and indexed properties on Arrays.
} else {
return objEquiv(actual, expected);
}
}
function isUndefinedOrNull(value) {
return value === null || value === undefined;
}
function isArguments(object) {
return instanceOf(object, "Arguments");
}
function objEquiv(a, b) {
if (isUndefinedOrNull(a) || isUndefinedOrNull(b)) {
return false;
}
// An identical 'prototype' property.
if (a.prototype !== b.prototype) {
return false;
}
// Object.keys may be broken through screwy arguments passing. Converting to
// an array solves the problem.
if (isArguments(a)) {
if (!isArguments(b)) {
return false;
}
a = pSlice.call(a);
b = pSlice.call(b);
return _deepEqual(a, b);
}
let ka, kb, key, i;
try {
ka = Object.keys(a);
kb = Object.keys(b);
} catch (e) {
// Happens when one is a string literal and the other isn't
return false;
}
// Having the same number of owned properties (keys incorporates
// hasOwnProperty)
if (ka.length != kb.length)
return false;
// The same set of keys (although not necessarily the same order),
ka.sort();
kb.sort();
// Equivalent values for every corresponding key, and possibly expensive deep
// test
for (i = ka.length - 1; i >= 0; i--) {
key = ka[i];
if (!_deepEqual(a[key], b[key])) {
return false;
}
}
return true;
}
/**
* 8. The non-equivalence assertion tests for any deep inequality.
* assert.notDeepEqual(actual, expected, message_opt);
*
* @param actual
* (mixed) Test subject to be evaluated as NOT equivalent to `expected`, including nested properties
* @param expected
* (mixed) Test reference to evaluate against `actual`
* @param message (optional)
* (string) Short explanation of the expected result
*/
proto.notDeepEqual = function notDeepEqual(actual, expected, message) {
this.report(_deepEqual(actual, expected), actual, expected, message, "notDeepEqual");
};
/**
* 9. The strict equality assertion tests strict equality, as determined by ===.
* assert.strictEqual(actual, expected, message_opt);
*
* @param actual
* (mixed) Test subject to be evaluated as strictly equivalent to `expected`
* @param expected
* (mixed) Test reference to evaluate against `actual`
* @param message (optional)
* (string) Short explanation of the expected result
*/
proto.strictEqual = function strictEqual(actual, expected, message) {
this.report(actual !== expected, actual, expected, message, "===");
};
/**
* 10. The strict non-equality assertion tests for strict inequality, as
* determined by !==. assert.notStrictEqual(actual, expected, message_opt);
*
* @param actual
* (mixed) Test subject to be evaluated as NOT strictly equivalent to `expected`
* @param expected
* (mixed) Test reference to evaluate against `actual`
* @param message (optional)
* (string) Short explanation of the expected result
*/
proto.notStrictEqual = function notStrictEqual(actual, expected, message) {
this.report(actual === expected, actual, expected, message, "!==");
};
function expectedException(actual, expected) {
if (!actual || !expected) {
return false;
}
if (instanceOf(expected, "RegExp")) {
return expected.test(actual);
} else if (actual instanceof expected) {
return true;
} else if (expected.call({}, actual) === true) {
return true;
}
return false;
}
/**
* 11. Expected to throw an error:
* assert.throws(block, Error_opt, message_opt);
*
* @param block
* (function) Function block to evaluate and catch eventual thrown errors
* @param expected (optional)
* (mixed) Test reference to evaluate against the thrown result from `block`
* @param message (optional)
* (string) Short explanation of the expected result
*/
proto.throws = function(block, expected, message) {
let actual;
if (typeof expected === "string") {
message = expected;
expected = null;
}
try {
block();
} catch (e) {
actual = e;
}
message = (expected && expected.name ? " (" + expected.name + ")." : ".") +
(message ? " " + message : ".");
if (!actual) {
this.report(true, actual, expected, "Missing expected exception" + message);
}
if ((actual && expected && !expectedException(actual, expected))) {
throw actual;
}
this.report(false, expected, expected, message);
};
/**
* A promise that is expected to reject:
* assert.rejects(promise, expected, message);
*
* @param promise
* (promise) A promise that is expected to reject
* @param expected (optional)
* (mixed) Test reference to evaluate against the rejection result
* @param message (optional)
* (string) Short explanation of the expected result
*/
proto.rejects = function(promise, expected, message) {
return new Promise((resolve, reject) => {
if (typeof expected === "string") {
message = expected;
expected = null;
}
return promise.then(
() => this.report(true, null, expected, "Missing expected exception " + message),
err => {
if (expected && !expectedException(err, expected)) {
reject(err);
return;
}
this.report(false, err, expected, message);
resolve();
}
).then(null, reject);
});
};