mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 19:04:45 +00:00
Bug 873126: introduce a common JS Assert library. r=gps,Unfocused
This commit is contained in:
parent
889c94f45f
commit
8df0f8d1aa
426
testing/modules/Assert.jsm
Normal file
426
testing/modules/Assert.jsm
Normal file
@ -0,0 +1,426 @@
|
||||
/* 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"
|
||||
];
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
let 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) {
|
||||
return truncate(JSON.stringify(error.actual, replacer)) + " " +
|
||||
(error.operator ? error.operator + " " : "") +
|
||||
truncate(JSON.stringify(error.expected, replacer));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 = options.message || getMessage(this);
|
||||
// The part of the stack that comes from this module is not interesting.
|
||||
let stack = Components.stack;
|
||||
do {
|
||||
stack = stack.caller;
|
||||
} while(stack.filename && stack.filename.contains("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
|
||||
}
|
||||
});
|
||||
|
||||
let 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, 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")) {
|
||||
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);
|
||||
};
|
@ -4,4 +4,5 @@
|
||||
|
||||
TESTING_JS_MODULES := \
|
||||
AppInfo.jsm \
|
||||
Assert.jsm \
|
||||
$(NULL)
|
||||
|
@ -4,3 +4,4 @@
|
||||
# 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/.
|
||||
|
||||
XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell/xpcshell.ini']
|
||||
|
281
testing/modules/tests/xpcshell/test_assert.js
Normal file
281
testing/modules/tests/xpcshell/test_assert.js
Normal file
@ -0,0 +1,281 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Test cases borrowed and adapted from:
|
||||
// https://github.com/joyent/node/blob/6101eb184db77d0b11eb96e48744e57ecce4b73d/test/simple/test-assert.js
|
||||
// MIT license: http://opensource.org/licenses/MIT
|
||||
|
||||
function run_test() {
|
||||
let ns = {};
|
||||
Components.utils.import("resource://testing-common/Assert.jsm", ns);
|
||||
let assert = new ns.Assert();
|
||||
|
||||
function makeBlock(f, ...args) {
|
||||
return function() {
|
||||
return f.apply(assert, args);
|
||||
};
|
||||
}
|
||||
|
||||
function protoCtrChain(o) {
|
||||
let result = [];
|
||||
while (o = o.__proto__) {
|
||||
result.push(o.constructor);
|
||||
}
|
||||
return result.join();
|
||||
}
|
||||
|
||||
function indirectInstanceOf(obj, cls) {
|
||||
if (obj instanceof cls) {
|
||||
return true;
|
||||
}
|
||||
let clsChain = protoCtrChain(cls.prototype);
|
||||
let objChain = protoCtrChain(obj);
|
||||
return objChain.slice(-clsChain.length) === clsChain;
|
||||
};
|
||||
|
||||
assert.ok(indirectInstanceOf(ns.Assert.AssertionError.prototype, Error),
|
||||
"Assert.AssertionError instanceof Error");
|
||||
|
||||
assert.throws(makeBlock(assert.ok, false),
|
||||
ns.Assert.AssertionError, "ok(false)");
|
||||
|
||||
assert.ok(true, "ok(true)");
|
||||
|
||||
assert.ok("test", "ok('test')");
|
||||
|
||||
assert.throws(makeBlock(assert.equal, true, false), ns.Assert.AssertionError, "equal");
|
||||
|
||||
assert.equal(null, null, "equal");
|
||||
|
||||
assert.equal(undefined, undefined, "equal");
|
||||
|
||||
assert.equal(null, undefined, "equal");
|
||||
|
||||
assert.equal(true, true, "equal");
|
||||
|
||||
assert.notEqual(true, false, "notEqual");
|
||||
|
||||
assert.throws(makeBlock(assert.notEqual, true, true),
|
||||
ns.Assert.AssertionError, "notEqual");
|
||||
|
||||
assert.throws(makeBlock(assert.strictEqual, 2, "2"),
|
||||
ns.Assert.AssertionError, "strictEqual");
|
||||
|
||||
assert.throws(makeBlock(assert.strictEqual, null, undefined),
|
||||
ns.Assert.AssertionError, "strictEqual");
|
||||
|
||||
assert.notStrictEqual(2, "2", "notStrictEqual");
|
||||
|
||||
// deepEquals joy!
|
||||
// 7.2
|
||||
assert.deepEqual(new Date(2000, 3, 14), new Date(2000, 3, 14), "deepEqual date");
|
||||
|
||||
assert.throws(makeBlock(assert.deepEqual, new Date(), new Date(2000, 3, 14)),
|
||||
ns.Assert.AssertionError,
|
||||
"deepEqual date");
|
||||
|
||||
// 7.3
|
||||
assert.deepEqual(/a/, /a/);
|
||||
assert.deepEqual(/a/g, /a/g);
|
||||
assert.deepEqual(/a/i, /a/i);
|
||||
assert.deepEqual(/a/m, /a/m);
|
||||
assert.deepEqual(/a/igm, /a/igm);
|
||||
assert.throws(makeBlock(assert.deepEqual, /ab/, /a/));
|
||||
assert.throws(makeBlock(assert.deepEqual, /a/g, /a/));
|
||||
assert.throws(makeBlock(assert.deepEqual, /a/i, /a/));
|
||||
assert.throws(makeBlock(assert.deepEqual, /a/m, /a/));
|
||||
assert.throws(makeBlock(assert.deepEqual, /a/igm, /a/im));
|
||||
|
||||
let re1 = /a/;
|
||||
re1.lastIndex = 3;
|
||||
assert.throws(makeBlock(assert.deepEqual, re1, /a/));
|
||||
|
||||
// 7.4
|
||||
assert.deepEqual(4, "4", "deepEqual == check");
|
||||
assert.deepEqual(true, 1, "deepEqual == check");
|
||||
assert.throws(makeBlock(assert.deepEqual, 4, "5"),
|
||||
ns.Assert.AssertionError,
|
||||
"deepEqual == check");
|
||||
|
||||
// 7.5
|
||||
// having the same number of owned properties && the same set of keys
|
||||
assert.deepEqual({a: 4}, {a: 4});
|
||||
assert.deepEqual({a: 4, b: "2"}, {a: 4, b: "2"});
|
||||
assert.deepEqual([4], ["4"]);
|
||||
assert.throws(makeBlock(assert.deepEqual, {a: 4}, {a: 4, b: true}),
|
||||
ns.Assert.AssertionError);
|
||||
assert.deepEqual(["a"], {0: "a"});
|
||||
|
||||
let a1 = [1, 2, 3];
|
||||
let a2 = [1, 2, 3];
|
||||
a1.a = "test";
|
||||
a1.b = true;
|
||||
a2.b = true;
|
||||
a2.a = "test";
|
||||
assert.throws(makeBlock(assert.deepEqual, Object.keys(a1), Object.keys(a2)),
|
||||
ns.Assert.AssertionError);
|
||||
assert.deepEqual(a1, a2);
|
||||
|
||||
let nbRoot = {
|
||||
toString: function() { return this.first + " " + this.last; }
|
||||
};
|
||||
|
||||
function nameBuilder(first, last) {
|
||||
this.first = first;
|
||||
this.last = last;
|
||||
return this;
|
||||
}
|
||||
nameBuilder.prototype = nbRoot;
|
||||
|
||||
function nameBuilder2(first, last) {
|
||||
this.first = first;
|
||||
this.last = last;
|
||||
return this;
|
||||
}
|
||||
nameBuilder2.prototype = nbRoot;
|
||||
|
||||
let nb1 = new nameBuilder("Ryan", "Dahl");
|
||||
let nb2 = new nameBuilder2("Ryan", "Dahl");
|
||||
|
||||
assert.deepEqual(nb1, nb2);
|
||||
|
||||
nameBuilder2.prototype = Object;
|
||||
nb2 = new nameBuilder2("Ryan", "Dahl");
|
||||
assert.throws(makeBlock(assert.deepEqual, nb1, nb2), ns.Assert.AssertionError);
|
||||
|
||||
// String literal + object
|
||||
assert.throws(makeBlock(assert.deepEqual, "a", {}), ns.Assert.AssertionError);
|
||||
|
||||
// Testing the throwing
|
||||
function thrower(errorConstructor) {
|
||||
throw new errorConstructor("test");
|
||||
}
|
||||
let aethrow = makeBlock(thrower, ns.Assert.AssertionError);
|
||||
aethrow = makeBlock(thrower, ns.Assert.AssertionError);
|
||||
|
||||
// the basic calls work
|
||||
assert.throws(makeBlock(thrower, ns.Assert.AssertionError),
|
||||
ns.Assert.AssertionError, "message");
|
||||
assert.throws(makeBlock(thrower, ns.Assert.AssertionError), ns.Assert.AssertionError);
|
||||
assert.throws(makeBlock(thrower, ns.Assert.AssertionError));
|
||||
|
||||
// if not passing an error, catch all.
|
||||
assert.throws(makeBlock(thrower, TypeError));
|
||||
|
||||
// when passing a type, only catch errors of the appropriate type
|
||||
let threw = false;
|
||||
try {
|
||||
assert.throws(makeBlock(thrower, TypeError), ns.Assert.AssertionError);
|
||||
} catch (e) {
|
||||
threw = true;
|
||||
assert.ok(e instanceof TypeError, "type");
|
||||
}
|
||||
assert.equal(true, threw,
|
||||
"Assert.throws with an explicit error is eating extra errors",
|
||||
ns.Assert.AssertionError);
|
||||
threw = false;
|
||||
|
||||
function ifError(err) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
assert.throws(function() {
|
||||
ifError(new Error("test error"));
|
||||
});
|
||||
|
||||
// make sure that validating using constructor really works
|
||||
threw = false;
|
||||
try {
|
||||
assert.throws(
|
||||
function() {
|
||||
throw ({});
|
||||
},
|
||||
Array
|
||||
);
|
||||
} catch (e) {
|
||||
threw = true;
|
||||
}
|
||||
assert.ok(threw, "wrong constructor validation");
|
||||
|
||||
// use a RegExp to validate error message
|
||||
assert.throws(makeBlock(thrower, TypeError), /test/);
|
||||
|
||||
// use a fn to validate error object
|
||||
assert.throws(makeBlock(thrower, TypeError), function(err) {
|
||||
if ((err instanceof TypeError) && /test/.test(err)) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
// Make sure deepEqual doesn't loop forever on circular refs
|
||||
|
||||
let b = {};
|
||||
b.b = b;
|
||||
|
||||
let c = {};
|
||||
c.b = c;
|
||||
|
||||
let gotError = false;
|
||||
try {
|
||||
assert.deepEqual(b, c);
|
||||
} catch (e) {
|
||||
gotError = true;
|
||||
}
|
||||
|
||||
dump("All OK\n");
|
||||
assert.ok(gotError);
|
||||
|
||||
function testAssertionMessage(actual, expected) {
|
||||
try {
|
||||
assert.equal(actual, "");
|
||||
} catch (e) {
|
||||
assert.equal(e.toString(),
|
||||
["AssertionError:", expected, "==", '""'].join(" "));
|
||||
}
|
||||
}
|
||||
testAssertionMessage(undefined, '"undefined"');
|
||||
testAssertionMessage(null, "null");
|
||||
testAssertionMessage(true, "true");
|
||||
testAssertionMessage(false, "false");
|
||||
testAssertionMessage(0, "0");
|
||||
testAssertionMessage(100, "100");
|
||||
testAssertionMessage(NaN, '"NaN"');
|
||||
testAssertionMessage(Infinity, '"Infinity"');
|
||||
testAssertionMessage(-Infinity, '"-Infinity"');
|
||||
testAssertionMessage("", '""');
|
||||
testAssertionMessage("foo", '"foo"');
|
||||
testAssertionMessage([], "[]");
|
||||
testAssertionMessage([1, 2, 3], "[1,2,3]");
|
||||
testAssertionMessage(/a/, '"/a/"');
|
||||
testAssertionMessage(/abc/gim, '"/abc/gim"');
|
||||
testAssertionMessage(function f() {}, '"function f() {}"');
|
||||
testAssertionMessage({}, "{}");
|
||||
testAssertionMessage({a: undefined, b: null}, '{"a":"undefined","b":null}');
|
||||
testAssertionMessage({a: NaN, b: Infinity, c: -Infinity},
|
||||
'{"a":"NaN","b":"Infinity","c":"-Infinity"}');
|
||||
|
||||
// https://github.com/joyent/node/issues/2893
|
||||
try {
|
||||
assert.throws(function () {
|
||||
ifError(null);
|
||||
});
|
||||
} catch (e) {
|
||||
threw = true;
|
||||
assert.equal(e.message, "Missing expected exception..");
|
||||
}
|
||||
assert.ok(threw);
|
||||
|
||||
// https://github.com/joyent/node/issues/5292
|
||||
try {
|
||||
assert.equal(1, 2);
|
||||
} catch (e) {
|
||||
assert.equal(e.toString().split("\n")[0], "AssertionError: 1 == 2")
|
||||
}
|
||||
|
||||
try {
|
||||
assert.equal(1, 2, "oh no");
|
||||
} catch (e) {
|
||||
assert.equal(e.toString().split("\n")[0], "AssertionError: oh no")
|
||||
}
|
||||
}
|
5
testing/modules/tests/xpcshell/xpcshell.ini
Normal file
5
testing/modules/tests/xpcshell/xpcshell.ini
Normal file
@ -0,0 +1,5 @@
|
||||
[DEFAULT]
|
||||
head =
|
||||
tail =
|
||||
|
||||
[test_assert.js]
|
@ -184,6 +184,15 @@ function _do_quit() {
|
||||
}
|
||||
|
||||
function _format_exception_stack(stack) {
|
||||
if (typeof stack == "object" && stack.caller) {
|
||||
let frame = stack;
|
||||
let strStack = "";
|
||||
while (frame != null) {
|
||||
strStack += frame + "\n";
|
||||
frame = frame.caller;
|
||||
}
|
||||
stack = strStack;
|
||||
}
|
||||
// frame is of the form "fname@file:line"
|
||||
let frame_regexp = new RegExp("(.*)@(.*):(\\d*)", "g");
|
||||
return stack.split("\n").reduce(function(stack_msg, frame) {
|
||||
|
Loading…
Reference in New Issue
Block a user