addon-sdk/source/test/test-system-events.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/addon-sdk/source/test/test-system-events.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,278 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +const events = require("sdk/system/events");
     1.9 +const self = require("sdk/self");
    1.10 +const { Cc, Ci, Cu } = require("chrome");
    1.11 +const { setTimeout } = require("sdk/timers");
    1.12 +const { Loader, LoaderWithHookedConsole2 } = require("sdk/test/loader");
    1.13 +const nsIObserverService = Cc["@mozilla.org/observer-service;1"].
    1.14 +                           getService(Ci.nsIObserverService);
    1.15 +
    1.16 +let isConsoleEvent = (topic) =>
    1.17 +  !!~["console-api-log-event", "console-storage-cache-event"].indexOf(topic)
    1.18 +
    1.19 +exports["test basic"] = function(assert) {
    1.20 +  let type = Date.now().toString(32);
    1.21 +
    1.22 +  let timesCalled = 0;
    1.23 +  function handler({subject, data}) { timesCalled++; };
    1.24 +
    1.25 +  events.on(type, handler);
    1.26 +  events.emit(type, { data: "yo yo" });
    1.27 +
    1.28 +  assert.equal(timesCalled, 1, "event handler was called");
    1.29 +
    1.30 +  events.off(type, handler);
    1.31 +  events.emit(type, { data: "no way" });
    1.32 +
    1.33 +  assert.equal(timesCalled, 1, "removed handler is no longer called");
    1.34 +
    1.35 +  events.once(type, handler);
    1.36 +  events.emit(type, { data: "and we meet again" });
    1.37 +  events.emit(type, { data: "it's always hard to say bye" });
    1.38 +
    1.39 +  assert.equal(timesCalled, 2, "handlers added via once are triggered once");
    1.40 +}
    1.41 +
    1.42 +exports["test simple argument passing"] = function (assert) {
    1.43 +  let type = Date.now().toString(32);
    1.44 +
    1.45 +  let lastArg;
    1.46 +  function handler({data}) { lastArg = data; }
    1.47 +  events.on(type, handler);
    1.48 +
    1.49 +  [true, false, 100, 0, 'a string', ''].forEach(arg => {
    1.50 +    events.emit(type, arg);
    1.51 +    assert.strictEqual(lastArg, arg + '',
    1.52 +      'event emitted for ' + arg + ' has correct data value');
    1.53 +
    1.54 +    events.emit(type, { data: arg });
    1.55 +    assert.strictEqual(lastArg, arg + '',
    1.56 +      'event emitted for ' + arg + ' has correct data value when a property on an object');
    1.57 +  });
    1.58 +
    1.59 +  [null, undefined, {}].forEach(arg => {
    1.60 +    events.emit(type, arg);
    1.61 +    assert.strictEqual(lastArg, null,
    1.62 +      'emitting ' + arg + ' gets null data');
    1.63 +  });
    1.64 +
    1.65 +  events.off(type, handler);
    1.66 +};
    1.67 +
    1.68 +exports["test error reporting"] = function(assert) {
    1.69 +  let { loader, messages } = LoaderWithHookedConsole2(module);
    1.70 +
    1.71 +  let events = loader.require("sdk/system/events");
    1.72 +  function brokenHandler(subject, data) { throw new Error("foo"); };
    1.73 +
    1.74 +  let lineNumber;
    1.75 +  try { brokenHandler() } catch (error) { lineNumber = error.lineNumber }
    1.76 +
    1.77 +  let errorType = Date.now().toString(32);
    1.78 +
    1.79 +  events.on(errorType, brokenHandler);
    1.80 +  events.emit(errorType, { data: "yo yo" });
    1.81 +
    1.82 +  assert.equal(messages.length, 2, "Got an exception");
    1.83 +  assert.equal(messages[0], "console.error: " + self.name + ": \n",
    1.84 +               "error is logged");
    1.85 +  let text = messages[1];
    1.86 +  assert.ok(text.indexOf("Error: foo") >= 0, "error message is logged");
    1.87 +  assert.ok(text.indexOf(module.uri) >= 0, "module uri is logged");
    1.88 +  assert.ok(text.indexOf(lineNumber) >= 0, "error line is logged");
    1.89 +
    1.90 +  events.off(errorType, brokenHandler);
    1.91 +
    1.92 +  loader.unload();
    1.93 +};
    1.94 +
    1.95 +exports["test listeners are GC-ed"] = function(assert, done) {
    1.96 +  let receivedFromWeak = [];
    1.97 +  let receivedFromStrong = [];
    1.98 +  let loader = Loader(module);
    1.99 +  let events = loader.require('sdk/system/events');
   1.100 +
   1.101 +  let type = 'test-listeners-are-garbage-collected';
   1.102 +  function handler(event) { receivedFromStrong.push(event); }
   1.103 +  function weakHandler(event) { receivedFromWeak.push(event); }
   1.104 +
   1.105 +  events.on(type, handler, true);
   1.106 +  events.on(type, weakHandler);
   1.107 +
   1.108 +  events.emit(type, { data: 1 });
   1.109 +  assert.equal(receivedFromStrong.length, 1, "strong listener invoked");
   1.110 +  assert.equal(receivedFromWeak.length, 1, "weak listener invoked");
   1.111 +
   1.112 +  handler = weakHandler = null;
   1.113 +
   1.114 +  Cu.schedulePreciseGC(function() {
   1.115 +    events.emit(type, { data: 2 });
   1.116 +
   1.117 +    assert.equal(receivedFromWeak.length, 1, "weak listener was GC-ed");
   1.118 +    assert.equal(receivedFromStrong.length, 2, "strong listener was invoked");
   1.119 +
   1.120 +    loader.unload();
   1.121 +    done();
   1.122 +  });
   1.123 +};
   1.124 +
   1.125 +exports["test alive listeners are removed on unload"] = function(assert) {
   1.126 +  let receivedFromWeak = [];
   1.127 +  let receivedFromStrong = [];
   1.128 +  let loader = Loader(module);
   1.129 +  let events = loader.require('sdk/system/events');
   1.130 +
   1.131 +  let type = 'test-alive-listeners-are-removed';
   1.132 +  const handler = (event) => receivedFromStrong.push(event);
   1.133 +  const weakHandler = (event) => receivedFromWeak.push(event); 
   1.134 +
   1.135 +  events.on(type, handler, true);
   1.136 +  events.on(type, weakHandler);
   1.137 +
   1.138 +  events.emit(type, { data: 1 });
   1.139 +  assert.equal(receivedFromStrong.length, 1, "strong listener invoked");
   1.140 +  assert.equal(receivedFromWeak.length, 1, "weak listener invoked");
   1.141 +
   1.142 +  loader.unload();
   1.143 +  events.emit(type, { data: 2 });
   1.144 +
   1.145 +  assert.equal(receivedFromWeak.length, 1, "weak listener was removed");
   1.146 +  assert.equal(receivedFromStrong.length, 1, "strong listener was removed");
   1.147 +};
   1.148 +
   1.149 +exports["test handle nsIObserverService notifications"] = function(assert) {
   1.150 +  let ios = Cc['@mozilla.org/network/io-service;1']
   1.151 +            .getService(Ci.nsIIOService);
   1.152 +
   1.153 +  let uri = ios.newURI("http://www.foo.com", null, null);
   1.154 +
   1.155 +  let type = Date.now().toString(32);
   1.156 +  let timesCalled = 0;
   1.157 +  let lastSubject = null;
   1.158 +  let lastData = null;
   1.159 +  let lastType = null;
   1.160 +
   1.161 +  function handler({ subject, data, type }) {
   1.162 +    // Ignores internal console events
   1.163 +    if (isConsoleEvent(type))
   1.164 +      return;
   1.165 +    timesCalled++;
   1.166 +    lastSubject = subject;
   1.167 +    lastData = data;
   1.168 +    lastType = type;
   1.169 +  };
   1.170 +
   1.171 +  events.on(type, handler);
   1.172 +  nsIObserverService.notifyObservers(uri, type, "some data");
   1.173 +
   1.174 +  assert.equal(timesCalled, 1, "notification invokes handler");
   1.175 +  assert.equal(lastType, type, "event.type is notification topic");
   1.176 +  assert.equal(lastSubject, uri, "event.subject is notification subject");
   1.177 +  assert.equal(lastData, "some data", "event.data is notification data");
   1.178 +
   1.179 +  function customSubject() {}
   1.180 +  function customData() {}
   1.181 +
   1.182 +  events.emit(type, { data: customData, subject: customSubject });
   1.183 +
   1.184 +  assert.equal(timesCalled, 2, "notification invokes handler");
   1.185 +  assert.equal(lastType, type, "event.type is notification topic");
   1.186 +  assert.equal(lastSubject, customSubject,
   1.187 +               "event.subject is wrapped & unwrapped");
   1.188 +  assert.equal(lastData, customData, "event.data is wrapped & unwrapped");
   1.189 +
   1.190 +  events.off(type, handler);
   1.191 +
   1.192 +  nsIObserverService.notifyObservers(null, type, "some data");
   1.193 +
   1.194 +  assert.equal(timesCalled, 2, "event handler is removed");
   1.195 +
   1.196 +  events.on("*", handler);
   1.197 +
   1.198 +  nsIObserverService.notifyObservers(null, type, "more data");
   1.199 +
   1.200 +  assert.equal(timesCalled, 3, "notification invokes * handler");
   1.201 +  assert.equal(lastType, type, "event.type is notification topic");
   1.202 +  assert.equal(lastSubject, null,
   1.203 +               "event.subject is notification subject");
   1.204 +  assert.equal(lastData, "more data", "event.data is notification data");
   1.205 +
   1.206 +  events.off("*", handler);
   1.207 +
   1.208 +  nsIObserverService.notifyObservers(null, type, "last data");
   1.209 +
   1.210 +  assert.equal(timesCalled, 3, "* event handler is removed");
   1.211 +};
   1.212 +
   1.213 +exports["test emit to nsIObserverService observers"] = function(assert) {
   1.214 +  let ios = Cc['@mozilla.org/network/io-service;1']
   1.215 +            .getService(Ci.nsIIOService);
   1.216 +
   1.217 +  let uri = ios.newURI("http://www.foo.com", null, null);
   1.218 +  let timesCalled = 0;
   1.219 +  let lastSubject = null;
   1.220 +  let lastData = null;
   1.221 +  let lastTopic = null;
   1.222 +
   1.223 +  var topic = Date.now().toString(32)
   1.224 +  let nsIObserver = {
   1.225 +    QueryInterface: function() {
   1.226 +      return nsIObserver;
   1.227 +    },
   1.228 +    observe: function(subject, topic, data) {
   1.229 +      // Ignores internal console events
   1.230 +      if (isConsoleEvent(topic))
   1.231 +        return;
   1.232 +      timesCalled = timesCalled + 1;
   1.233 +      lastSubject = subject;
   1.234 +      lastData = data;
   1.235 +      lastTopic = topic;
   1.236 +    }
   1.237 +  };
   1.238 +
   1.239 +  nsIObserverService.addObserver(nsIObserver, topic, false);
   1.240 +
   1.241 +  events.emit(topic, { subject: uri, data: "some data" });
   1.242 +
   1.243 +  assert.equal(timesCalled, 1, "emit notifies observers");
   1.244 +  assert.equal(lastTopic, topic, "event type is notification topic");
   1.245 +  assert.equal(lastSubject.wrappedJSObject.object, uri,
   1.246 +               "event.subject is notification subject");
   1.247 +  assert.equal(lastData, "some data", "event.data is notification data");
   1.248 +  function customSubject() {}
   1.249 +  function customData() {}
   1.250 +  events.emit(topic, { subject: customSubject, data: customData });
   1.251 +
   1.252 +  assert.equal(timesCalled, 2, "emit notifies observers");
   1.253 +  assert.equal(lastTopic, topic, "event.type is notification");
   1.254 +  assert.equal(lastSubject.wrappedJSObject.object, customSubject,
   1.255 +               "event.subject is notification subject");
   1.256 +  assert.equal(lastData, customData, "event.data is notification data");
   1.257 +
   1.258 +  nsIObserverService.removeObserver(nsIObserver, topic);
   1.259 +
   1.260 +  events.emit(topic, { data: "more data" });
   1.261 +
   1.262 +  assert.equal(timesCalled, 2, "removed observers no longer invoked");
   1.263 +
   1.264 +  nsIObserverService.addObserver(nsIObserver, "*", false);
   1.265 +
   1.266 +  events.emit(topic, { data: "data again" });
   1.267 +
   1.268 +  assert.equal(timesCalled, 3, "emit notifies * observers");
   1.269 +
   1.270 +  assert.equal(lastTopic, topic, "event.type is notification");
   1.271 +  assert.equal(lastSubject, null,
   1.272 +               "event.subject is notification subject");
   1.273 +  assert.equal(lastData, "data again", "event.data is notification data");
   1.274 +
   1.275 +  nsIObserverService.removeObserver(nsIObserver, "*");
   1.276 +
   1.277 +  events.emit(topic, { data: "last data" });
   1.278 +  assert.equal(timesCalled, 3, "removed observers no longer invoked");
   1.279 +}
   1.280 +
   1.281 +require("test").run(exports);

mercurial