summaryrefslogtreecommitdiffstats
path: root/addon-sdk/source/test/test-observers.js
diff options
context:
space:
mode:
Diffstat (limited to 'addon-sdk/source/test/test-observers.js')
-rw-r--r--addon-sdk/source/test/test-observers.js183
1 files changed, 183 insertions, 0 deletions
diff --git a/addon-sdk/source/test/test-observers.js b/addon-sdk/source/test/test-observers.js
new file mode 100644
index 000000000..4f15a87f1
--- /dev/null
+++ b/addon-sdk/source/test/test-observers.js
@@ -0,0 +1,183 @@
+/* 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";
+
+const { Loader } = require("sdk/test/loader");
+const { isWeak, WeakReference } = require("sdk/core/reference");
+const { subscribe, unsubscribe,
+ observe, Observer } = require("sdk/core/observer");
+const { Class } = require("sdk/core/heritage");
+
+const { Cc, Ci, Cu } = require("chrome");
+const { notifyObservers } = Cc["@mozilla.org/observer-service;1"].
+ getService(Ci.nsIObserverService);
+const { defer } = require("sdk/core/promise");
+
+const message = x => ({wrappedJSObject: x});
+
+exports["test subscribe unsubscribe"] = assert => {
+ const topic = Date.now().toString(32);
+ const Subscriber = Class({
+ extends: Observer,
+ initialize: function(observe) {
+ this.observe = observe;
+ }
+ });
+ observe.define(Subscriber, (x, subject, _, data) =>
+ x.observe(subject.wrappedJSObject.x));
+
+ let xs = [];
+ const x = Subscriber((...rest) => xs.push(...rest));
+
+ let ys = [];
+ const y = Subscriber((...rest) => ys.push(...rest));
+
+ const publish = (topic, data) =>
+ notifyObservers(message(data), topic, null);
+
+ publish({x:0});
+
+ subscribe(x, topic);
+
+ publish(topic, {x:1});
+
+ subscribe(y, topic);
+
+ publish(topic, {x:2});
+ publish(topic + "!", {x: 2.5});
+
+ unsubscribe(x, topic);
+
+ publish(topic, {x:3});
+
+ subscribe(y, topic);
+
+ publish(topic, {x:4});
+
+ subscribe(x, topic);
+
+ publish(topic, {x:5});
+
+ unsubscribe(x, topic);
+ unsubscribe(y, topic);
+
+ publish(topic, {x:6});
+
+ assert.deepEqual(xs, [1, 2, 5]);
+ assert.deepEqual(ys, [2, 3, 4, 5]);
+}
+
+exports["test weak observers are GC-ed on unload"] = (assert, end) => {
+ const topic = Date.now().toString(32);
+ const loader = Loader(module);
+ const { Observer, observe,
+ subscribe, unsubscribe } = loader.require("sdk/core/observer");
+ const { isWeak, WeakReference } = loader.require("sdk/core/reference");
+
+ const MyObserver = Class({
+ extends: Observer,
+ initialize: function(observe) {
+ this.observe = observe;
+ }
+ });
+ observe.define(MyObserver, (x, ...rest) => x.observe(...rest));
+
+ const MyWeakObserver = Class({
+ extends: MyObserver,
+ implements: [WeakReference]
+ });
+
+ let xs = [];
+ let ys = [];
+ let x = new MyObserver((subject, topic, data) => {
+ xs.push(subject.wrappedJSObject, topic, data);
+ });
+ let y = new MyWeakObserver((subject, topic, data) => {
+ ys.push(subject.wrappedJSObject, topic, data);
+ });
+
+ subscribe(x, topic);
+ subscribe(y, topic);
+
+
+ notifyObservers(message({ foo: 1 }), topic, null);
+ x = null;
+ y = null;
+ loader.unload();
+
+ Cu.schedulePreciseGC(() => {
+
+ notifyObservers(message({ bar: 2 }), topic, ":)");
+
+ assert.deepEqual(xs, [{ foo: 1 }, topic, null,
+ { bar: 2 }, topic, ":)"],
+ "non week observer is kept");
+
+ assert.deepEqual(ys, [{ foo: 1 }, topic, null],
+ "week observer was GC-ed");
+
+ end();
+ });
+};
+
+exports["test weak observer unsubscribe"] = function*(assert) {
+ const loader = Loader(module);
+ const { Observer, observe, subscribe, unsubscribe } = loader.require("sdk/core/observer");
+ const { WeakReference } = loader.require("sdk/core/reference");
+
+ let sawNotification = false;
+ let firstWait = defer();
+ let secondWait = defer();
+
+ const WeakObserver = Class({
+ extends: Observer,
+ implements: [WeakReference],
+ observe: function() {
+ sawNotification = true;
+ firstWait.resolve();
+ }
+ });
+
+ const StrongObserver = Class({
+ extends: Observer,
+ observe: function() {
+ secondWait.resolve();
+ }
+ });
+
+ observe.define(Observer, (x, ...rest) => x.observe(...rest));
+
+ let weakObserver = new WeakObserver;
+ let strongObserver = new StrongObserver();
+ subscribe(weakObserver, "test-topic");
+ subscribe(strongObserver, "test-wait");
+
+ notifyObservers(null, "test-topic", null);
+ yield firstWait.promise;
+
+ assert.ok(sawNotification, "Should have seen notification before GC");
+ sawNotification = false;
+
+ yield loader.require("sdk/test/memory").gc();
+
+ notifyObservers(null, "test-topic", null);
+ notifyObservers(null, "test-wait", null);
+ yield secondWait.promise;
+
+ assert.ok(sawNotification, "Should have seen notification after GC");
+ sawNotification = false;
+
+ try {
+ unsubscribe(weakObserver, "test-topic");
+ unsubscribe(strongObserver, "test-wait");
+ assert.pass("Should not have seen an exception");
+ }
+ catch (e) {
+ assert.fail("Should not have seen an exception");
+ }
+
+ loader.unload();
+};
+
+require("sdk/test").run(exports);