michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: "use strict"; michael@0: michael@0: michael@0: const { id: addonID, name: addonName } = require("sdk/self"); michael@0: const { Cc, Ci, Cu } = require("chrome"); michael@0: const { Loader, LoaderWithHookedConsole2 } = require("sdk/test/loader"); michael@0: const { InputPort } = require("sdk/input/system"); michael@0: const { OutputPort } = require("sdk/output/system"); michael@0: michael@0: const { removeObserver, addObserver, michael@0: notifyObservers } = Cc["@mozilla.org/observer-service;1"]. michael@0: getService(Ci.nsIObserverService); michael@0: michael@0: const { lift, start, stop, send } = require("sdk/event/utils"); michael@0: michael@0: const isConsoleEvent = topic => michael@0: ["console-api-log-event", michael@0: "console-storage-cache-event"].indexOf(topic) >= 0; michael@0: michael@0: const message = x => ({wrappedJSObject: {data: x}}); michael@0: michael@0: exports["test start / stop ports"] = assert => { michael@0: const input = new InputPort({ id: Date.now().toString(32), initial: {data:0} }); michael@0: const topic = input.topic; michael@0: michael@0: assert.ok(topic.contains(addonID), "topics are namespaced to add-on"); michael@0: michael@0: const xs = lift(({data}) => "x:" + data, input); michael@0: const ys = lift(({data}) => "y:" + data, input); michael@0: michael@0: assert.deepEqual(input.value, {data:0}, "initila value is set"); michael@0: assert.deepEqual(xs.value, "x:0", "initial value is mapped"); michael@0: assert.deepEqual(ys.value, "y:0", "initial value is mapped"); michael@0: michael@0: notifyObservers(message(1), topic, null); michael@0: michael@0: assert.deepEqual(input.value, {data:0}, "no message received on input port"); michael@0: assert.deepEqual(xs.value, "x:0", "no message received on xs"); michael@0: assert.deepEqual(ys.value, "y:0", "no message received on ys"); michael@0: michael@0: start(xs); michael@0: michael@0: michael@0: notifyObservers(message(2), topic, null); michael@0: michael@0: assert.deepEqual(input.value, {data:2}, "message received on input port"); michael@0: assert.deepEqual(xs.value, "x:2", "message received on xs"); michael@0: assert.deepEqual(ys.value, "y:2", "no message received on (not started) ys"); michael@0: michael@0: michael@0: notifyObservers(message(3), topic, null); michael@0: michael@0: michael@0: assert.deepEqual(input.value, {data:3}, "message received on input port"); michael@0: assert.deepEqual(xs.value, "x:3", "message received on xs"); michael@0: assert.deepEqual(ys.value, "y:3", "message received on ys"); michael@0: michael@0: michael@0: notifyObservers(message(4), topic, null); michael@0: michael@0: assert.deepEqual(input.value, {data:4}, "message received on input port"); michael@0: assert.deepEqual(xs.value, "x:4", "message not received on (stopped) xs"); michael@0: assert.deepEqual(ys.value, "y:4", "message received on ys"); michael@0: michael@0: michael@0: stop(input); michael@0: michael@0: notifyObservers(message(5), topic, null); michael@0: michael@0: assert.deepEqual(input.value, {data:4}, "message note received on input port"); michael@0: assert.deepEqual(xs.value, "x:4", "message not received on (stopped) xs"); michael@0: assert.deepEqual(ys.value, "y:4", "message not received on (stopped) ys"); michael@0: }; michael@0: michael@0: exports["test send messages to nsIObserverService"] = assert => { michael@0: let messages = []; michael@0: michael@0: const { newURI } = Cc['@mozilla.org/network/io-service;1']. michael@0: getService(Ci.nsIIOService); michael@0: michael@0: const output = new OutputPort({ id: Date.now().toString(32), sync: true }); michael@0: const topic = output.topic; michael@0: michael@0: const observer = { michael@0: QueryInterface: function() { michael@0: return this; michael@0: }, michael@0: observe: (subject, topic, data) => { michael@0: // Ignores internal console events michael@0: if (!isConsoleEvent(topic)) { michael@0: messages.push({ michael@0: topic: topic, michael@0: subject: subject michael@0: }); michael@0: } michael@0: } michael@0: }; michael@0: michael@0: addObserver(observer, topic, false); michael@0: michael@0: send(output, null); michael@0: assert.deepEqual(messages.shift(), { topic: topic, subject: null }, michael@0: "null message received"); michael@0: michael@0: michael@0: const uri = newURI("http://www.foo.com", null, null); michael@0: send(output, uri); michael@0: michael@0: assert.deepEqual(messages.shift(), { topic: topic, subject: uri }, michael@0: "message received"); michael@0: michael@0: michael@0: function customSubject() {} michael@0: send(output, customSubject); michael@0: michael@0: let message = messages.shift(); michael@0: assert.equal(message.topic, topic, "topic was received"); michael@0: assert.equal(message.subject.wrappedJSObject, customSubject, michael@0: "custom subject is received"); michael@0: michael@0: removeObserver(observer, topic); michael@0: michael@0: send(output, { data: "more data" }); michael@0: michael@0: assert.deepEqual(messages, [], michael@0: "no more data received"); michael@0: michael@0: addObserver(observer, "*", false); michael@0: michael@0: send(output, { data: "data again" }); michael@0: michael@0: message = messages.shift(); michael@0: assert.equal(message.topic, topic, "topic was received"); michael@0: assert.deepEqual(message.subject.wrappedJSObject, michael@0: { data: "data again" }, michael@0: "wrapped message received"); michael@0: michael@0: removeObserver(observer, "*"); michael@0: michael@0: send(output, { data: "last data" }); michael@0: assert.deepEqual(messages, [], michael@0: "no more data received"); michael@0: michael@0: assert.throws(() => send(output, "hi"), michael@0: /Unsupproted message type: `string`/, michael@0: "strings can't be send"); michael@0: michael@0: assert.throws(() => send(output, 4), michael@0: /Unsupproted message type: `number`/, michael@0: "numbers can't be send"); michael@0: michael@0: assert.throws(() => send(output, void(0)), michael@0: /Unsupproted message type: `undefined`/, michael@0: "undefineds can't be send"); michael@0: michael@0: assert.throws(() => send(output, true), michael@0: /Unsupproted message type: `boolean`/, michael@0: "booleans can't be send"); michael@0: }; michael@0: michael@0: exports["test async OutputPort"] = (assert, done) => { michael@0: let async = false; michael@0: const output = new OutputPort({ id: Date.now().toString(32) }); michael@0: const observer = { michael@0: observe: (subject, topic, data) => { michael@0: removeObserver(observer, topic); michael@0: assert.equal(topic, output.topic, "correct topic"); michael@0: assert.deepEqual(subject.wrappedJSObject, {foo: "bar"}, "message received"); michael@0: assert.ok(async, "message received async"); michael@0: done(); michael@0: } michael@0: }; michael@0: addObserver(observer, output.topic, false); michael@0: send(output, {foo: "bar"}); michael@0: michael@0: assert.throws(() => send(output, "boom"), "can only send object"); michael@0: async = true; michael@0: }; michael@0: michael@0: exports["test explicit output topic"] = (assert, done) => { michael@0: const topic = Date.now().toString(32); michael@0: const output = new OutputPort({ topic: topic }); michael@0: const observer = { michael@0: observe: (subject, topic, data) => { michael@0: removeObserver(observer, topic); michael@0: assert.deepEqual(subject.wrappedJSObject, {foo: "bar"}, "message received"); michael@0: done(); michael@0: } michael@0: }; michael@0: michael@0: assert.equal(output.topic, topic, "given topic is used"); michael@0: michael@0: addObserver(observer, topic, false); michael@0: send(output, {foo: "bar"}); michael@0: }; michael@0: michael@0: exports["test explicit input topic"] = (assert) => { michael@0: const topic = Date.now().toString(32); michael@0: const input = new InputPort({ topic: topic }); michael@0: michael@0: start(input); michael@0: assert.equal(input.topic, topic, "given topic is used"); michael@0: michael@0: michael@0: notifyObservers({wrappedJSObject: {foo: "bar"}}, topic, null); michael@0: michael@0: assert.deepEqual(input.value, {foo: "bar"}, "message received"); michael@0: }; michael@0: michael@0: michael@0: exports["test receive what was send"] = assert => { michael@0: const id = Date.now().toString(32); michael@0: const input = new InputPort({ id: id, initial: 0}); michael@0: const output = new OutputPort({ id: id, sync: true }); michael@0: michael@0: assert.ok(input.topic.contains(addonID), michael@0: "input topic is namespaced to addon"); michael@0: assert.equal(input.topic, output.topic, michael@0: "input & output get same topics from id."); michael@0: michael@0: start(input); michael@0: michael@0: assert.equal(input.value, 0, "initial value is set"); michael@0: michael@0: send(output, { data: 1 }); michael@0: assert.deepEqual(input.value, {data: 1}, "message unwrapped"); michael@0: michael@0: send(output, []); michael@0: assert.deepEqual(input.value, [], "array message unwrapped"); michael@0: michael@0: send(output, null); michael@0: assert.deepEqual(input.value, null, "null message received"); michael@0: michael@0: send(output, new String("message")); michael@0: assert.deepEqual(input.value, new String("message"), michael@0: "string instance received"); michael@0: michael@0: send(output, /pattern/); michael@0: assert.deepEqual(input.value, /pattern/, "regexp received"); michael@0: michael@0: assert.throws(() => send(output, "hi"), michael@0: /Unsupproted message type: `string`/, michael@0: "strings can't be send"); michael@0: michael@0: assert.throws(() => send(output, 4), michael@0: /Unsupproted message type: `number`/, michael@0: "numbers can't be send"); michael@0: michael@0: assert.throws(() => send(output, void(0)), michael@0: /Unsupproted message type: `undefined`/, michael@0: "undefineds can't be send"); michael@0: michael@0: assert.throws(() => send(output, true), michael@0: /Unsupproted message type: `boolean`/, michael@0: "booleans can't be send"); michael@0: michael@0: stop(input); michael@0: }; michael@0: michael@0: michael@0: exports["-test error reporting"] = function(assert) { michael@0: let { loader, messages } = LoaderWithHookedConsole2(module); michael@0: const { start, stop, lift } = loader.require("sdk/event/utils"); michael@0: const { InputPort } = loader.require("sdk/input/system"); michael@0: const { OutputPort } = loader.require("sdk/output/system"); michael@0: const id = "error:" + Date.now().toString(32); michael@0: michael@0: const raise = x => { if (x) throw new Error("foo"); }; michael@0: michael@0: const input = new InputPort({ id: id }); michael@0: const output = new OutputPort({ id: id, sync: true }); michael@0: const xs = lift(raise, input); michael@0: michael@0: assert.equal(input.value, null, "initial inherited"); michael@0: michael@0: send(output, { data: "yo yo" }); michael@0: michael@0: assert.deepEqual(messages, [], "nothing happend yet"); michael@0: michael@0: start(xs); michael@0: michael@0: send(output, { data: "first" }); michael@0: michael@0: assert.equal(messages.length, 4, "Got an exception"); michael@0: michael@0: michael@0: assert.equal(messages[0], "console.error: " + addonName + ": \n", michael@0: "error is logged"); michael@0: michael@0: assert.ok(/Unhandled error/.test(messages[1]), michael@0: "expected error message"); michael@0: michael@0: loader.unload(); michael@0: }; michael@0: michael@0: exports["test unload ends input port"] = assert => { michael@0: const loader = Loader(module); michael@0: const { start, stop, lift } = loader.require("sdk/event/utils"); michael@0: const { InputPort } = loader.require("sdk/input/system"); michael@0: michael@0: const id = "unload!" + Date.now().toString(32); michael@0: const input = new InputPort({ id: id }); michael@0: michael@0: start(input); michael@0: notifyObservers(message(1), input.topic, null); michael@0: assert.deepEqual(input.value, {data: 1}, "message received"); michael@0: michael@0: notifyObservers(message(2), input.topic, null); michael@0: assert.deepEqual(input.value, {data: 2}, "message received"); michael@0: michael@0: loader.unload(); michael@0: notifyObservers(message(3), input.topic, null); michael@0: assert.deepEqual(input.value, {data: 2}, "message wasn't received"); michael@0: }; michael@0: michael@0: require("sdk/test").run(exports);