Bug 731779: Integrate the Add-on SDK loader and API libraries into Firefox (uplifting from addon-sdk a16bbd5772880b578a939eeb65102bca6560d494)
This commit is contained in:
349
addon-sdk/source/lib/sdk/test/assert.js
Normal file
349
addon-sdk/source/lib/sdk/test/assert.js
Normal file
@@ -0,0 +1,349 @@
|
||||
/* vim:ts=2:sts=2:sw=2:
|
||||
* 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";
|
||||
|
||||
module.metadata = {
|
||||
"stability": "unstable"
|
||||
};
|
||||
|
||||
const { isFunction, isNull, isObject, isString,
|
||||
isRegExp, isArray, isDate, isPrimitive,
|
||||
isUndefined, instanceOf, source } = require("../lang/type");
|
||||
|
||||
/**
|
||||
* The `AssertionError` is defined in assert.
|
||||
* @extends Error
|
||||
* @example
|
||||
* new assert.AssertionError({
|
||||
* message: message,
|
||||
* actual: actual,
|
||||
* expected: expected
|
||||
* })
|
||||
*/
|
||||
function AssertionError(options) {
|
||||
let assertionError = Object.create(AssertionError.prototype);
|
||||
|
||||
if (isString(options))
|
||||
options = { message: options };
|
||||
if ("actual" in options)
|
||||
assertionError.actual = options.actual;
|
||||
if ("expected" in options)
|
||||
assertionError.expected = options.expected;
|
||||
if ("operator" in options)
|
||||
assertionError.operator = options.operator;
|
||||
|
||||
assertionError.message = options.message;
|
||||
assertionError.stack = new Error().stack;
|
||||
return assertionError;
|
||||
}
|
||||
AssertionError.prototype = Object.create(Error.prototype, {
|
||||
constructor: { value: AssertionError },
|
||||
name: { value: "AssertionError", enumerable: true },
|
||||
toString: { value: function toString() {
|
||||
let value;
|
||||
if (this.message) {
|
||||
value = this.name + " : " + this.message;
|
||||
}
|
||||
else {
|
||||
value = [
|
||||
this.name + " : ",
|
||||
source(this.expected),
|
||||
this.operator,
|
||||
source(this.actual)
|
||||
].join(" ");
|
||||
}
|
||||
return value;
|
||||
}}
|
||||
});
|
||||
exports.AssertionError = AssertionError;
|
||||
|
||||
function Assert(logger) {
|
||||
return Object.create(Assert.prototype, { _log: { value: logger }});
|
||||
}
|
||||
Assert.prototype = {
|
||||
fail: function fail(e) {
|
||||
if (!e || typeof(e) !== 'object') {
|
||||
this._log.fail(e);
|
||||
return;
|
||||
}
|
||||
let message = e.message;
|
||||
if ('operator' in e) {
|
||||
message += [
|
||||
" -",
|
||||
source(e.expected),
|
||||
e.operator,
|
||||
source(e.actual)
|
||||
].join(" ");
|
||||
}
|
||||
this._log.fail(message);
|
||||
},
|
||||
pass: function pass(message) {
|
||||
this._log.pass(message);
|
||||
},
|
||||
error: function error(e) {
|
||||
this._log.exception(e);
|
||||
},
|
||||
ok: function ok(value, message) {
|
||||
if (!!!value) {
|
||||
this.fail({
|
||||
actual: value,
|
||||
expected: true,
|
||||
message: message,
|
||||
operator: "=="
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.pass(message);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* The equality assertion tests shallow, coercive equality with `==`.
|
||||
* @example
|
||||
* assert.equal(1, 1, "one is one");
|
||||
*/
|
||||
equal: function equal(actual, expected, message) {
|
||||
if (actual == expected) {
|
||||
this.pass(message);
|
||||
}
|
||||
else {
|
||||
this.fail({
|
||||
actual: actual,
|
||||
expected: expected,
|
||||
message: message,
|
||||
operator: "=="
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* The non-equality assertion tests for whether two objects are not equal
|
||||
* with `!=`.
|
||||
* @example
|
||||
* assert.notEqual(1, 2, "one is not two");
|
||||
*/
|
||||
notEqual: function notEqual(actual, expected, message) {
|
||||
if (actual != expected) {
|
||||
this.pass(message);
|
||||
}
|
||||
else {
|
||||
this.fail({
|
||||
actual: actual,
|
||||
expected: expected,
|
||||
message: message,
|
||||
operator: "!=",
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* The equivalence assertion tests a deep (with `===`) equality relation.
|
||||
* @example
|
||||
* assert.deepEqual({ a: "foo" }, { a: "foo" }, "equivalent objects")
|
||||
*/
|
||||
deepEqual: function deepEqual(actual, expected, message) {
|
||||
if (isDeepEqual(actual, expected)) {
|
||||
this.pass(message);
|
||||
}
|
||||
else {
|
||||
this.fail({
|
||||
actual: actual,
|
||||
expected: expected,
|
||||
message: message,
|
||||
operator: "deepEqual"
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* The non-equivalence assertion tests for any deep (with `===`) inequality.
|
||||
* @example
|
||||
* assert.notDeepEqual({ a: "foo" }, Object.create({ a: "foo" }),
|
||||
* "object's inherit from different prototypes");
|
||||
*/
|
||||
notDeepEqual: function notDeepEqual(actual, expected, message) {
|
||||
if (!isDeepEqual(actual, expected)) {
|
||||
this.pass(message);
|
||||
}
|
||||
else {
|
||||
this.fail({
|
||||
actual: actual,
|
||||
expected: expected,
|
||||
message: message,
|
||||
operator: "notDeepEqual"
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* The strict equality assertion tests strict equality, as determined by
|
||||
* `===`.
|
||||
* @example
|
||||
* assert.strictEqual(null, null, "`null` is `null`")
|
||||
*/
|
||||
strictEqual: function strictEqual(actual, expected, message) {
|
||||
if (actual === expected) {
|
||||
this.pass(message);
|
||||
}
|
||||
else {
|
||||
this.fail({
|
||||
actual: actual,
|
||||
expected: expected,
|
||||
message: message,
|
||||
operator: "==="
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* The strict non-equality assertion tests for strict inequality, as
|
||||
* determined by `!==`.
|
||||
* @example
|
||||
* assert.notStrictEqual(null, undefined, "`null` is not `undefined`");
|
||||
*/
|
||||
notStrictEqual: function notStrictEqual(actual, expected, message) {
|
||||
if (actual !== expected) {
|
||||
this.pass(message);
|
||||
}
|
||||
else {
|
||||
this.fail({
|
||||
actual: actual,
|
||||
expected: expected,
|
||||
message: message,
|
||||
operator: "!=="
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* The assertion whether or not given `block` throws an exception. If optional
|
||||
* `Error` argument is provided and it's type of function thrown error is
|
||||
* asserted to be an instance of it, if type of `Error` is string then message
|
||||
* of throw exception is asserted to contain it.
|
||||
* @param {Function} block
|
||||
* Function that is expected to throw.
|
||||
* @param {Error|RegExp} [Error]
|
||||
* Error constructor that is expected to be thrown or a string that
|
||||
* must be contained by a message of the thrown exception, or a RegExp
|
||||
* matching a message of the thrown exception.
|
||||
* @param {String} message
|
||||
* Description message
|
||||
*
|
||||
* @examples
|
||||
*
|
||||
* assert.throws(function block() {
|
||||
* doSomething(4)
|
||||
* }, "Object is expected", "Incorrect argument is passed");
|
||||
*
|
||||
* assert.throws(function block() {
|
||||
* Object.create(5)
|
||||
* }, TypeError, "TypeError is thrown");
|
||||
*/
|
||||
throws: function throws(block, Error, message) {
|
||||
let threw = false;
|
||||
let exception = null;
|
||||
|
||||
// If third argument is not provided and second argument is a string it
|
||||
// means that optional `Error` argument was not passed, so we shift
|
||||
// arguments.
|
||||
if (isString(Error) && isUndefined(message)) {
|
||||
message = Error;
|
||||
Error = undefined;
|
||||
}
|
||||
|
||||
// Executing given `block`.
|
||||
try {
|
||||
block();
|
||||
}
|
||||
catch (e) {
|
||||
threw = true;
|
||||
exception = e;
|
||||
}
|
||||
|
||||
// If exception was thrown and `Error` argument was not passed assert is
|
||||
// passed.
|
||||
if (threw && (isUndefined(Error) ||
|
||||
// If passed `Error` is RegExp using it's test method to
|
||||
// assert thrown exception message.
|
||||
(isRegExp(Error) && Error.test(exception.message)) ||
|
||||
// If passed `Error` is a constructor function testing if
|
||||
// thrown exception is an instance of it.
|
||||
(isFunction(Error) && instanceOf(exception, Error))))
|
||||
{
|
||||
this.pass(message);
|
||||
}
|
||||
|
||||
// Otherwise we report assertion failure.
|
||||
else {
|
||||
let failure = {
|
||||
message: message,
|
||||
operator: "throws"
|
||||
};
|
||||
|
||||
if (exception)
|
||||
failure.actual = exception;
|
||||
|
||||
if (Error)
|
||||
failure.expected = Error;
|
||||
|
||||
this.fail(failure);
|
||||
}
|
||||
}
|
||||
};
|
||||
exports.Assert = Assert;
|
||||
|
||||
function isDeepEqual(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 (isDate(actual) && isDate(expected)) {
|
||||
return actual.getTime() === expected.getTime();
|
||||
}
|
||||
|
||||
// XXX specification bug: this should be specified
|
||||
else if (isPrimitive(actual) || isPrimitive(expected)) {
|
||||
return expected === actual;
|
||||
}
|
||||
|
||||
// 7.3. Other pairs that do not both pass typeof value == "object",
|
||||
// equivalence is determined by ==.
|
||||
else if (!isObject(actual) && !isObject(expected)) {
|
||||
return actual == expected;
|
||||
}
|
||||
|
||||
// 7.4. 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 actual.prototype === expected.prototype &&
|
||||
isEquivalent(actual, expected);
|
||||
}
|
||||
}
|
||||
|
||||
function isEquivalent(a, b, stack) {
|
||||
let aKeys = Object.keys(a);
|
||||
let bKeys = Object.keys(b);
|
||||
|
||||
return aKeys.length === bKeys.length &&
|
||||
isArrayEquivalent(aKeys.sort(), bKeys.sort()) &&
|
||||
aKeys.every(function(key) {
|
||||
return isDeepEqual(a[key], b[key], stack)
|
||||
});
|
||||
}
|
||||
|
||||
function isArrayEquivalent(a, b, stack) {
|
||||
return isArray(a) && isArray(b) &&
|
||||
a.every(function(value, index) {
|
||||
return isDeepEqual(value, b[index]);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user