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

branch
TOR_BUG_9701
changeset 10
ac0c01689b40
equal deleted inserted replaced
-1:000000000000 0:c4f528d5c4b0
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 const events = require("sdk/system/events");
6 const self = require("sdk/self");
7 const { Cc, Ci, Cu } = require("chrome");
8 const { setTimeout } = require("sdk/timers");
9 const { Loader, LoaderWithHookedConsole2 } = require("sdk/test/loader");
10 const nsIObserverService = Cc["@mozilla.org/observer-service;1"].
11 getService(Ci.nsIObserverService);
12
13 let isConsoleEvent = (topic) =>
14 !!~["console-api-log-event", "console-storage-cache-event"].indexOf(topic)
15
16 exports["test basic"] = function(assert) {
17 let type = Date.now().toString(32);
18
19 let timesCalled = 0;
20 function handler({subject, data}) { timesCalled++; };
21
22 events.on(type, handler);
23 events.emit(type, { data: "yo yo" });
24
25 assert.equal(timesCalled, 1, "event handler was called");
26
27 events.off(type, handler);
28 events.emit(type, { data: "no way" });
29
30 assert.equal(timesCalled, 1, "removed handler is no longer called");
31
32 events.once(type, handler);
33 events.emit(type, { data: "and we meet again" });
34 events.emit(type, { data: "it's always hard to say bye" });
35
36 assert.equal(timesCalled, 2, "handlers added via once are triggered once");
37 }
38
39 exports["test simple argument passing"] = function (assert) {
40 let type = Date.now().toString(32);
41
42 let lastArg;
43 function handler({data}) { lastArg = data; }
44 events.on(type, handler);
45
46 [true, false, 100, 0, 'a string', ''].forEach(arg => {
47 events.emit(type, arg);
48 assert.strictEqual(lastArg, arg + '',
49 'event emitted for ' + arg + ' has correct data value');
50
51 events.emit(type, { data: arg });
52 assert.strictEqual(lastArg, arg + '',
53 'event emitted for ' + arg + ' has correct data value when a property on an object');
54 });
55
56 [null, undefined, {}].forEach(arg => {
57 events.emit(type, arg);
58 assert.strictEqual(lastArg, null,
59 'emitting ' + arg + ' gets null data');
60 });
61
62 events.off(type, handler);
63 };
64
65 exports["test error reporting"] = function(assert) {
66 let { loader, messages } = LoaderWithHookedConsole2(module);
67
68 let events = loader.require("sdk/system/events");
69 function brokenHandler(subject, data) { throw new Error("foo"); };
70
71 let lineNumber;
72 try { brokenHandler() } catch (error) { lineNumber = error.lineNumber }
73
74 let errorType = Date.now().toString(32);
75
76 events.on(errorType, brokenHandler);
77 events.emit(errorType, { data: "yo yo" });
78
79 assert.equal(messages.length, 2, "Got an exception");
80 assert.equal(messages[0], "console.error: " + self.name + ": \n",
81 "error is logged");
82 let text = messages[1];
83 assert.ok(text.indexOf("Error: foo") >= 0, "error message is logged");
84 assert.ok(text.indexOf(module.uri) >= 0, "module uri is logged");
85 assert.ok(text.indexOf(lineNumber) >= 0, "error line is logged");
86
87 events.off(errorType, brokenHandler);
88
89 loader.unload();
90 };
91
92 exports["test listeners are GC-ed"] = function(assert, done) {
93 let receivedFromWeak = [];
94 let receivedFromStrong = [];
95 let loader = Loader(module);
96 let events = loader.require('sdk/system/events');
97
98 let type = 'test-listeners-are-garbage-collected';
99 function handler(event) { receivedFromStrong.push(event); }
100 function weakHandler(event) { receivedFromWeak.push(event); }
101
102 events.on(type, handler, true);
103 events.on(type, weakHandler);
104
105 events.emit(type, { data: 1 });
106 assert.equal(receivedFromStrong.length, 1, "strong listener invoked");
107 assert.equal(receivedFromWeak.length, 1, "weak listener invoked");
108
109 handler = weakHandler = null;
110
111 Cu.schedulePreciseGC(function() {
112 events.emit(type, { data: 2 });
113
114 assert.equal(receivedFromWeak.length, 1, "weak listener was GC-ed");
115 assert.equal(receivedFromStrong.length, 2, "strong listener was invoked");
116
117 loader.unload();
118 done();
119 });
120 };
121
122 exports["test alive listeners are removed on unload"] = function(assert) {
123 let receivedFromWeak = [];
124 let receivedFromStrong = [];
125 let loader = Loader(module);
126 let events = loader.require('sdk/system/events');
127
128 let type = 'test-alive-listeners-are-removed';
129 const handler = (event) => receivedFromStrong.push(event);
130 const weakHandler = (event) => receivedFromWeak.push(event);
131
132 events.on(type, handler, true);
133 events.on(type, weakHandler);
134
135 events.emit(type, { data: 1 });
136 assert.equal(receivedFromStrong.length, 1, "strong listener invoked");
137 assert.equal(receivedFromWeak.length, 1, "weak listener invoked");
138
139 loader.unload();
140 events.emit(type, { data: 2 });
141
142 assert.equal(receivedFromWeak.length, 1, "weak listener was removed");
143 assert.equal(receivedFromStrong.length, 1, "strong listener was removed");
144 };
145
146 exports["test handle nsIObserverService notifications"] = function(assert) {
147 let ios = Cc['@mozilla.org/network/io-service;1']
148 .getService(Ci.nsIIOService);
149
150 let uri = ios.newURI("http://www.foo.com", null, null);
151
152 let type = Date.now().toString(32);
153 let timesCalled = 0;
154 let lastSubject = null;
155 let lastData = null;
156 let lastType = null;
157
158 function handler({ subject, data, type }) {
159 // Ignores internal console events
160 if (isConsoleEvent(type))
161 return;
162 timesCalled++;
163 lastSubject = subject;
164 lastData = data;
165 lastType = type;
166 };
167
168 events.on(type, handler);
169 nsIObserverService.notifyObservers(uri, type, "some data");
170
171 assert.equal(timesCalled, 1, "notification invokes handler");
172 assert.equal(lastType, type, "event.type is notification topic");
173 assert.equal(lastSubject, uri, "event.subject is notification subject");
174 assert.equal(lastData, "some data", "event.data is notification data");
175
176 function customSubject() {}
177 function customData() {}
178
179 events.emit(type, { data: customData, subject: customSubject });
180
181 assert.equal(timesCalled, 2, "notification invokes handler");
182 assert.equal(lastType, type, "event.type is notification topic");
183 assert.equal(lastSubject, customSubject,
184 "event.subject is wrapped & unwrapped");
185 assert.equal(lastData, customData, "event.data is wrapped & unwrapped");
186
187 events.off(type, handler);
188
189 nsIObserverService.notifyObservers(null, type, "some data");
190
191 assert.equal(timesCalled, 2, "event handler is removed");
192
193 events.on("*", handler);
194
195 nsIObserverService.notifyObservers(null, type, "more data");
196
197 assert.equal(timesCalled, 3, "notification invokes * handler");
198 assert.equal(lastType, type, "event.type is notification topic");
199 assert.equal(lastSubject, null,
200 "event.subject is notification subject");
201 assert.equal(lastData, "more data", "event.data is notification data");
202
203 events.off("*", handler);
204
205 nsIObserverService.notifyObservers(null, type, "last data");
206
207 assert.equal(timesCalled, 3, "* event handler is removed");
208 };
209
210 exports["test emit to nsIObserverService observers"] = function(assert) {
211 let ios = Cc['@mozilla.org/network/io-service;1']
212 .getService(Ci.nsIIOService);
213
214 let uri = ios.newURI("http://www.foo.com", null, null);
215 let timesCalled = 0;
216 let lastSubject = null;
217 let lastData = null;
218 let lastTopic = null;
219
220 var topic = Date.now().toString(32)
221 let nsIObserver = {
222 QueryInterface: function() {
223 return nsIObserver;
224 },
225 observe: function(subject, topic, data) {
226 // Ignores internal console events
227 if (isConsoleEvent(topic))
228 return;
229 timesCalled = timesCalled + 1;
230 lastSubject = subject;
231 lastData = data;
232 lastTopic = topic;
233 }
234 };
235
236 nsIObserverService.addObserver(nsIObserver, topic, false);
237
238 events.emit(topic, { subject: uri, data: "some data" });
239
240 assert.equal(timesCalled, 1, "emit notifies observers");
241 assert.equal(lastTopic, topic, "event type is notification topic");
242 assert.equal(lastSubject.wrappedJSObject.object, uri,
243 "event.subject is notification subject");
244 assert.equal(lastData, "some data", "event.data is notification data");
245 function customSubject() {}
246 function customData() {}
247 events.emit(topic, { subject: customSubject, data: customData });
248
249 assert.equal(timesCalled, 2, "emit notifies observers");
250 assert.equal(lastTopic, topic, "event.type is notification");
251 assert.equal(lastSubject.wrappedJSObject.object, customSubject,
252 "event.subject is notification subject");
253 assert.equal(lastData, customData, "event.data is notification data");
254
255 nsIObserverService.removeObserver(nsIObserver, topic);
256
257 events.emit(topic, { data: "more data" });
258
259 assert.equal(timesCalled, 2, "removed observers no longer invoked");
260
261 nsIObserverService.addObserver(nsIObserver, "*", false);
262
263 events.emit(topic, { data: "data again" });
264
265 assert.equal(timesCalled, 3, "emit notifies * observers");
266
267 assert.equal(lastTopic, topic, "event.type is notification");
268 assert.equal(lastSubject, null,
269 "event.subject is notification subject");
270 assert.equal(lastData, "data again", "event.data is notification data");
271
272 nsIObserverService.removeObserver(nsIObserver, "*");
273
274 events.emit(topic, { data: "last data" });
275 assert.equal(timesCalled, 3, "removed observers no longer invoked");
276 }
277
278 require("test").run(exports);

mercurial