|
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 "use strict"; |
|
5 |
|
6 var unload = require("sdk/system/unload"); |
|
7 var { Loader, LoaderWithHookedConsole } = require("sdk/test/loader"); |
|
8 |
|
9 exports.testUnloading = function(assert) { |
|
10 let { loader, messages } = LoaderWithHookedConsole(module); |
|
11 var ul = loader.require("sdk/system/unload"); |
|
12 var unloadCalled = 0; |
|
13 function unload() { |
|
14 unloadCalled++; |
|
15 throw new Error("error"); |
|
16 } |
|
17 ul.when(unload); |
|
18 |
|
19 // This should be ignored, as we already registered it |
|
20 ul.when(unload); |
|
21 |
|
22 function unload2() { unloadCalled++; } |
|
23 ul.when(unload2); |
|
24 loader.unload(); |
|
25 assert.equal(unloadCalled, 2, |
|
26 "Unloader functions are called on unload."); |
|
27 assert.equal(messages.length, 1, |
|
28 "One unload handler threw exception 1/2"); |
|
29 assert.equal(messages[0].type, "exception", |
|
30 "One unload handler threw exception 2/2"); |
|
31 }; |
|
32 |
|
33 exports.testEnsure = function(assert) { |
|
34 assert.throws(function() { unload.ensure({}); }, |
|
35 /object has no 'unload' property/, |
|
36 "passing obj with no unload prop should fail"); |
|
37 assert.throws(function() { unload.ensure({}, "destroy"); }, |
|
38 /object has no 'destroy' property/, |
|
39 "passing obj with no custom unload prop should fail"); |
|
40 |
|
41 var called = 0; |
|
42 var obj = {unload: function() { called++; }}; |
|
43 |
|
44 unload.ensure(obj); |
|
45 obj.unload(); |
|
46 assert.equal(called, 1, |
|
47 "unload() should be called"); |
|
48 obj.unload(); |
|
49 assert.equal(called, 1, |
|
50 "unload() should be called only once"); |
|
51 }; |
|
52 |
|
53 /** |
|
54 * Check that destructors are called only once with Traits. |
|
55 * - check that public API is calling the destructor and unregister it, |
|
56 * - check that composed traits with multiple ensure calls, leads to only |
|
57 * one destructor call. |
|
58 */ |
|
59 exports.testEnsureWithTraits = function(assert) { |
|
60 let { Trait } = require("sdk/deprecated/traits"); |
|
61 let loader = Loader(module); |
|
62 let ul = loader.require("sdk/system/unload"); |
|
63 |
|
64 let called = 0; |
|
65 let composedCalled = 0; |
|
66 let composedTrait = Trait.compose({ |
|
67 constructor: function () { |
|
68 // We have to give "public interface" of this trait, as we want to |
|
69 // call public `unload` method and ensure that we call it only once, |
|
70 // either when we call this public function manually or on add-on unload |
|
71 ul.ensure(this._public); |
|
72 }, |
|
73 unload: function unload() { |
|
74 composedCalled++; |
|
75 } |
|
76 }); |
|
77 let obj = Trait.compose( |
|
78 composedTrait.resolve({ |
|
79 constructor: "_constructor", |
|
80 unload : "_unload" |
|
81 }), { |
|
82 constructor: function constructor() { |
|
83 // Same thing applies here, we need to pass public interface |
|
84 ul.ensure(this._public); |
|
85 this._constructor(); |
|
86 }, |
|
87 unload: function unload() { |
|
88 called++; |
|
89 this._unload(); |
|
90 } |
|
91 })(); |
|
92 |
|
93 obj.unload(); |
|
94 assert.equal(called, 1, |
|
95 "unload() should be called"); |
|
96 |
|
97 assert.equal(composedCalled, 1, |
|
98 "composed object unload() should be called"); |
|
99 |
|
100 obj.unload(); |
|
101 assert.equal(called, 1, |
|
102 "unload() should be called only once"); |
|
103 assert.equal(composedCalled, 1, |
|
104 "composed object unload() should be called only once"); |
|
105 |
|
106 loader.unload(); |
|
107 assert.equal(called, 1, |
|
108 "unload() should be called only once, after addon unload"); |
|
109 assert.equal(composedCalled, 1, |
|
110 "composed object unload() should be called only once, " + |
|
111 "after addon unload"); |
|
112 }; |
|
113 |
|
114 exports.testEnsureWithTraitsPrivate = function(assert) { |
|
115 let { Trait } = require("sdk/deprecated/traits"); |
|
116 let loader = Loader(module); |
|
117 let ul = loader.require("sdk/system/unload"); |
|
118 |
|
119 let called = 0; |
|
120 let privateObj = null; |
|
121 let obj = Trait.compose({ |
|
122 constructor: function constructor() { |
|
123 // This time wa don't have to give public interface, |
|
124 // as we want to call a private method: |
|
125 ul.ensure(this, "_unload"); |
|
126 privateObj = this; |
|
127 }, |
|
128 _unload: function unload() { |
|
129 called++; |
|
130 this._unload(); |
|
131 } |
|
132 })(); |
|
133 |
|
134 loader.unload(); |
|
135 assert.equal(called, 1, |
|
136 "unload() should be called"); |
|
137 |
|
138 privateObj._unload(); |
|
139 assert.equal(called, 1, |
|
140 "_unload() should be called only once, after addon unload"); |
|
141 }; |
|
142 |
|
143 exports.testReason = function (assert) { |
|
144 var reason = "Reason doesn't actually have to be anything in particular."; |
|
145 var loader = Loader(module); |
|
146 var ul = loader.require("sdk/system/unload"); |
|
147 ul.when(function (rsn) { |
|
148 assert.equal(rsn, reason, |
|
149 "when() reason should be reason given to loader"); |
|
150 }); |
|
151 var obj = { |
|
152 unload: function (rsn) { |
|
153 assert.equal(rsn, reason, |
|
154 "ensure() reason should be reason given to loader"); |
|
155 } |
|
156 }; |
|
157 ul.ensure(obj); |
|
158 loader.unload(reason); |
|
159 }; |
|
160 |
|
161 require("sdk/test").run(exports); |