summaryrefslogtreecommitdiffstats
path: root/testing/modules/tests
diff options
context:
space:
mode:
Diffstat (limited to 'testing/modules/tests')
-rw-r--r--testing/modules/tests/browser/browser.ini1
-rw-r--r--testing/modules/tests/browser/browser_test_assert.js17
-rw-r--r--testing/modules/tests/xpcshell/test_assert.js358
-rw-r--r--testing/modules/tests/xpcshell/test_mockRegistrar.js51
-rw-r--r--testing/modules/tests/xpcshell/test_structuredlog.js145
-rw-r--r--testing/modules/tests/xpcshell/xpcshell.ini8
6 files changed, 580 insertions, 0 deletions
diff --git a/testing/modules/tests/browser/browser.ini b/testing/modules/tests/browser/browser.ini
new file mode 100644
index 000000000..4dcdddffc
--- /dev/null
+++ b/testing/modules/tests/browser/browser.ini
@@ -0,0 +1 @@
+[browser_test_assert.js]
diff --git a/testing/modules/tests/browser/browser_test_assert.js b/testing/modules/tests/browser/browser_test_assert.js
new file mode 100644
index 000000000..c7324be01
--- /dev/null
+++ b/testing/modules/tests/browser/browser_test_assert.js
@@ -0,0 +1,17 @@
+/* Any copyright is dedicated to the Public Domain.
+http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function test() {
+ export_assertions();
+
+ ok(true, "pass ok");
+ is(true, true, "pass is");
+ isnot(false, true, "pass isnot");
+ todo(false, "pass todo");
+ todo_is(false, true, "pass todo_is");
+ todo_isnot(true, true, "pass todo_isnot");
+ info("info message");
+
+ var func = is;
+ func(true, 1, "pass indirect is");
+}
diff --git a/testing/modules/tests/xpcshell/test_assert.js b/testing/modules/tests/xpcshell/test_assert.js
new file mode 100644
index 000000000..2fde67e0f
--- /dev/null
+++ b/testing/modules/tests/xpcshell/test_assert.js
@@ -0,0 +1,358 @@
+/* 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.deepEqual(new Date(NaN), new Date(NaN), "deepEqual invalid dates");
+
+ 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;
+ }
+ });
+
+ 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 - 1 == 2")
+ }
+
+ // Test XPCShell-test integration:
+ ok(true, "OK, this went well");
+ deepEqual(/a/g, /a/g, "deep equal should work on RegExp");
+ deepEqual(/a/igm, /a/igm, "deep equal should work on RegExp");
+ deepEqual({a: 4, b: "1"}, {b: "1", a: 4}, "deep equal should work on regular Object");
+ deepEqual(a1, a2, "deep equal should work on Array with Object properties");
+
+ // Test robustness of reporting:
+ equal(new ns.Assert.AssertionError({
+ actual: {
+ toJSON: function() {
+ throw "bam!";
+ }
+ },
+ expected: "foo",
+ operator: "="
+ }).message, "[object Object] = \"foo\"");
+
+ let message;
+ assert.greater(3, 2);
+ try {
+ assert.greater(2, 2);
+ } catch(e) {
+ message = e.toString().split("\n")[0];
+ }
+ assert.equal(message, "AssertionError: 2 > 2");
+
+ assert.greaterOrEqual(2, 2);
+ try {
+ assert.greaterOrEqual(1, 2);
+ } catch(e) {
+ message = e.toString().split("\n")[0];
+ }
+ assert.equal(message, "AssertionError: 1 >= 2");
+
+ assert.less(1, 2);
+ try {
+ assert.less(2, 2);
+ } catch(e) {
+ message = e.toString().split("\n")[0];
+ }
+ assert.equal(message, "AssertionError: 2 < 2");
+
+ assert.lessOrEqual(2, 2);
+ try {
+ assert.lessOrEqual(2, 1);
+ } catch(e) {
+ message = e.toString().split("\n")[0];
+ }
+ assert.equal(message, "AssertionError: 2 <= 1");
+
+ run_next_test();
+}
+
+add_task(function* test_rejects() {
+ let ns = {};
+ Components.utils.import("resource://testing-common/Assert.jsm", ns);
+ let assert = new ns.Assert();
+
+ // A helper function to test failures.
+ function* checkRejectsFails(err, expected) {
+ try {
+ yield assert.rejects(Promise.reject(err), expected);
+ ok(false, "should have thrown");
+ } catch(ex) {
+ deepEqual(ex, err, "Assert.rejects threw the original unexpected error");
+ }
+ }
+
+ // A "throwable" error that's not an actual Error().
+ let SomeErrorLikeThing = function() {};
+
+ // The actual tests...
+ // No "expected" or "message" values supplied.
+ yield assert.rejects(Promise.reject(new Error("oh no")));
+ yield assert.rejects(Promise.reject("oh no"));
+
+ // An explicit error object:
+ // An instance to check against.
+ yield assert.rejects(Promise.reject(new Error("oh no")), Error, "rejected");
+ // A regex to match against the message.
+ yield assert.rejects(Promise.reject(new Error("oh no")), /oh no/, "rejected");
+
+ // Failure cases:
+ // An instance to check against that doesn't match.
+ yield checkRejectsFails(new Error("something else"), SomeErrorLikeThing);
+ // A regex that doesn't match.
+ yield checkRejectsFails(new Error("something else"), /oh no/);
+
+ // Check simple string messages.
+ yield assert.rejects(Promise.reject("oh no"), /oh no/, "rejected");
+ // Wrong message.
+ yield checkRejectsFails("something else", /oh no/);
+});
diff --git a/testing/modules/tests/xpcshell/test_mockRegistrar.js b/testing/modules/tests/xpcshell/test_mockRegistrar.js
new file mode 100644
index 000000000..af890e2aa
--- /dev/null
+++ b/testing/modules/tests/xpcshell/test_mockRegistrar.js
@@ -0,0 +1,51 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+var {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://testing-common/MockRegistrar.jsm");
+
+function userInfo(username) {
+ this.username = username;
+}
+
+userInfo.prototype = {
+ fullname: "fullname",
+ emailAddress: "emailAddress",
+ domain: "domain",
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIUserInfo]),
+};
+
+function run_test () {
+ run_next_test();
+}
+
+add_test(function test_register() {
+ let localUserInfo = {
+ fullname: "fullname",
+ username: "localusername",
+ emailAddress: "emailAddress",
+ domain: "domain",
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIUserInfo]),
+ };
+
+ let userInfoCID = MockRegistrar.register("@mozilla.org/userinfo;1", localUserInfo);
+ Assert.equal(Cc["@mozilla.org/userinfo;1"].createInstance(Ci.nsIUserInfo).username, "localusername");
+ run_next_test();
+});
+
+add_test(function test_register_with_arguments() {
+ let userInfoCID = MockRegistrar.register("@mozilla.org/userinfo;1", userInfo, ["username"]);
+ Assert.equal(Cc["@mozilla.org/userinfo;1"].createInstance(Ci.nsIUserInfo).username, "username");
+ run_next_test();
+});
+
+add_test(function test_register_twice() {
+ let userInfoCID = MockRegistrar.register("@mozilla.org/userinfo;1", userInfo, ["originalname"]);
+ Assert.equal(Cc["@mozilla.org/userinfo;1"].createInstance(Ci.nsIUserInfo).username, "originalname");
+
+ let newUserInfoCID = MockRegistrar.register("@mozilla.org/userinfo;1", userInfo, ["newname"]);
+ Assert.equal(Cc["@mozilla.org/userinfo;1"].createInstance(Ci.nsIUserInfo).username, "newname");
+ run_next_test();
+});
diff --git a/testing/modules/tests/xpcshell/test_structuredlog.js b/testing/modules/tests/xpcshell/test_structuredlog.js
new file mode 100644
index 000000000..3a6fbb8ed
--- /dev/null
+++ b/testing/modules/tests/xpcshell/test_structuredlog.js
@@ -0,0 +1,145 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function run_test () {
+ Components.utils.import("resource://testing-common/StructuredLog.jsm");
+
+ let testBuffer = [];
+
+ let appendBuffer = function (msg) {
+ testBuffer.push(JSON.stringify(msg));
+ }
+
+ let assertLastMsg = function (refData) {
+ // Check all fields in refData agree with those in the
+ // last message logged, and pop that message.
+ let lastMsg = JSON.parse(testBuffer.pop());
+ for (let field in refData) {
+ deepEqual(lastMsg[field], refData[field]);
+ }
+ // The logger should always set the source to the logger name.
+ equal(lastMsg.source, "test_log");
+ // The source_file field is always set by the mutator function.
+ equal(lastMsg.source_file, "test_structuredlog.js");
+ }
+
+ let addFileName = function (data) {
+ data.source_file = "test_structuredlog.js";
+ }
+
+ let logger = new StructuredLogger("test_log", appendBuffer, [addFileName]);
+
+ // Test unstructured logging
+ logger.info("Test message");
+ assertLastMsg({
+ action: "log",
+ message: "Test message",
+ level: "INFO",
+ });
+
+ logger.info("Test message",
+ extra={foo: "bar"});
+ assertLastMsg({
+ action: "log",
+ message: "Test message",
+ level: "INFO",
+ extra: {foo: "bar"},
+ });
+
+ // Test end / start actions
+ logger.testStart("aTest");
+ assertLastMsg({
+ test: "aTest",
+ action: "test_start",
+ });
+
+ logger.testEnd("aTest", "OK");
+ assertLastMsg({
+ test: "aTest",
+ action: "test_end",
+ status: "OK"
+ });
+
+ // A failed test populates the "expected" field.
+ logger.testStart("aTest");
+ logger.testEnd("aTest", "FAIL", "PASS");
+ assertLastMsg({
+ action: "test_end",
+ test: "aTest",
+ status: "FAIL",
+ expected: "PASS"
+ });
+
+ // A failed test populates the "expected" field.
+ logger.testStart("aTest");
+ logger.testEnd("aTest", "FAIL", "PASS", null, "Many\nlines\nof\nstack\n");
+ assertLastMsg({
+ action: "test_end",
+ test: "aTest",
+ status: "FAIL",
+ expected: "PASS",
+ stack: "Many\nlines\nof\nstack\n"
+ });
+
+ // Skipped tests don't log failures
+ logger.testStart("aTest");
+ logger.testEnd("aTest", "SKIP", "PASS");
+ ok(!JSON.parse(testBuffer[testBuffer.length - 1]).hasOwnProperty("expected"));
+ assertLastMsg({
+ action: "test_end",
+ test: "aTest",
+ status: "SKIP"
+ });
+
+ logger.testStatus("aTest", "foo", "PASS", "PASS", "Passed test");
+ ok(!JSON.parse(testBuffer[testBuffer.length - 1]).hasOwnProperty("expected"));
+ assertLastMsg({
+ action: "test_status",
+ test: "aTest",
+ subtest: "foo",
+ status: "PASS",
+ message: "Passed test"
+ });
+
+ logger.testStatus("aTest", "bar", "FAIL");
+ assertLastMsg({
+ action: "test_status",
+ test: "aTest",
+ subtest: "bar",
+ status: "FAIL",
+ expected: "PASS"
+ });
+
+ logger.testStatus("aTest", "bar", "FAIL", "PASS", null,
+ "Many\nlines\nof\nstack\n");
+ assertLastMsg({
+ action: "test_status",
+ test: "aTest",
+ subtest: "bar",
+ status: "FAIL",
+ expected: "PASS",
+ stack: "Many\nlines\nof\nstack\n"
+ });
+
+ // Skipped tests don't log failures
+ logger.testStatus("aTest", "baz", "SKIP");
+ ok(!JSON.parse(testBuffer[testBuffer.length - 1]).hasOwnProperty("expected"));
+ assertLastMsg({
+ action: "test_status",
+ test: "aTest",
+ subtest: "baz",
+ status: "SKIP"
+ });
+
+ // Suite start and end messages.
+ logger.suiteStart(["aTest"]);
+ assertLastMsg({
+ action: "suite_start",
+ tests: ["aTest"],
+ });
+
+ logger.suiteEnd();
+ assertLastMsg({
+ action: "suite_end",
+ });
+}
diff --git a/testing/modules/tests/xpcshell/xpcshell.ini b/testing/modules/tests/xpcshell/xpcshell.ini
new file mode 100644
index 000000000..40dc9920e
--- /dev/null
+++ b/testing/modules/tests/xpcshell/xpcshell.ini
@@ -0,0 +1,8 @@
+[DEFAULT]
+head =
+tail =
+skip-if = toolkit == 'android' || toolkit == 'gonk'
+
+[test_assert.js]
+[test_mockRegistrar.js]
+[test_structuredlog.js]