gecko-dev/addon-sdk/source/test/test-observers.js

184 строки
4.7 KiB
JavaScript

/* 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);