|
1 /* Any copyright is dedicated to the Public Domain. |
|
2 http://creativecommons.org/publicdomain/zero/1.0/ */ |
|
3 |
|
4 Cu.import("resource://services-common/async.js"); |
|
5 Cu.import("resource://testing-common/services-common/utils.js"); |
|
6 |
|
7 let provider = { |
|
8 getFile: function(prop, persistent) { |
|
9 persistent.value = true; |
|
10 switch (prop) { |
|
11 case "ExtPrefDL": |
|
12 return [Services.dirsvc.get("CurProcD", Ci.nsIFile)]; |
|
13 default: |
|
14 throw Cr.NS_ERROR_FAILURE; |
|
15 } |
|
16 }, |
|
17 QueryInterface: XPCOMUtils.generateQI([Ci.nsIDirectoryServiceProvider]) |
|
18 }; |
|
19 Services.dirsvc.QueryInterface(Ci.nsIDirectoryService).registerProvider(provider); |
|
20 |
|
21 // This is needed for loadAddonTestFunctions(). |
|
22 let gGlobalScope = this; |
|
23 |
|
24 function ExtensionsTestPath(path) { |
|
25 if (path[0] != "/") { |
|
26 throw Error("Path must begin with '/': " + path); |
|
27 } |
|
28 |
|
29 return "../../../../toolkit/mozapps/extensions/test/xpcshell" + path; |
|
30 } |
|
31 |
|
32 /** |
|
33 * Loads the AddonManager test functions by importing its test file. |
|
34 * |
|
35 * This should be called in the global scope of any test file needing to |
|
36 * interface with the AddonManager. It should only be called once, or the |
|
37 * universe will end. |
|
38 */ |
|
39 function loadAddonTestFunctions() { |
|
40 const path = ExtensionsTestPath("/head_addons.js"); |
|
41 let file = do_get_file(path); |
|
42 let uri = Services.io.newFileURI(file); |
|
43 Services.scriptloader.loadSubScript(uri.spec, gGlobalScope); |
|
44 createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2"); |
|
45 } |
|
46 |
|
47 function getAddonInstall(name) { |
|
48 let f = do_get_file(ExtensionsTestPath("/addons/" + name + ".xpi")); |
|
49 let cb = Async.makeSyncCallback(); |
|
50 AddonManager.getInstallForFile(f, cb); |
|
51 |
|
52 return Async.waitForSyncCallback(cb); |
|
53 } |
|
54 |
|
55 /** |
|
56 * Obtains an addon from the add-on manager by id. |
|
57 * |
|
58 * This is merely a synchronous wrapper. |
|
59 * |
|
60 * @param id |
|
61 * ID of add-on to fetch |
|
62 * @return addon object on success or undefined or null on failure |
|
63 */ |
|
64 function getAddonFromAddonManagerByID(id) { |
|
65 let cb = Async.makeSyncCallback(); |
|
66 AddonManager.getAddonByID(id, cb); |
|
67 return Async.waitForSyncCallback(cb); |
|
68 } |
|
69 |
|
70 /** |
|
71 * Installs an add-on synchronously from an addonInstall |
|
72 * |
|
73 * @param install addonInstall instance to install |
|
74 */ |
|
75 function installAddonFromInstall(install) { |
|
76 let cb = Async.makeSyncCallback(); |
|
77 let listener = {onInstallEnded: cb}; |
|
78 AddonManager.addInstallListener(listener); |
|
79 install.install(); |
|
80 Async.waitForSyncCallback(cb); |
|
81 AddonManager.removeAddonListener(listener); |
|
82 |
|
83 do_check_neq(null, install.addon); |
|
84 do_check_neq(null, install.addon.syncGUID); |
|
85 |
|
86 return install.addon; |
|
87 } |
|
88 |
|
89 /** |
|
90 * Convenience function to install an add-on from the extensions unit tests. |
|
91 * |
|
92 * @param name |
|
93 * String name of add-on to install. e.g. test_install1 |
|
94 * @return addon object that was installed |
|
95 */ |
|
96 function installAddon(name) { |
|
97 let install = getAddonInstall(name); |
|
98 do_check_neq(null, install); |
|
99 return installAddonFromInstall(install); |
|
100 } |
|
101 |
|
102 /** |
|
103 * Convenience function to uninstall an add-on synchronously. |
|
104 * |
|
105 * @param addon |
|
106 * Addon instance to uninstall |
|
107 */ |
|
108 function uninstallAddon(addon) { |
|
109 let cb = Async.makeSyncCallback(); |
|
110 let listener = {onUninstalled: function(uninstalled) { |
|
111 if (uninstalled.id == addon.id) { |
|
112 AddonManager.removeAddonListener(listener); |
|
113 cb(uninstalled); |
|
114 } |
|
115 }}; |
|
116 |
|
117 AddonManager.addAddonListener(listener); |
|
118 addon.uninstall(); |
|
119 Async.waitForSyncCallback(cb); |
|
120 } |
|
121 |
|
122 function generateNewKeys(collectionKeys, collections=null) { |
|
123 let wbo = collectionKeys.generateNewKeysWBO(collections); |
|
124 let modified = new_timestamp(); |
|
125 collectionKeys.setContents(wbo.cleartext, modified); |
|
126 } |
|
127 |
|
128 // Helpers for testing open tabs. |
|
129 // These reflect part of the internal structure of TabEngine, |
|
130 // and stub part of Service.wm. |
|
131 |
|
132 function mockShouldSkipWindow (win) { |
|
133 return win.closed || |
|
134 win.mockIsPrivate; |
|
135 } |
|
136 |
|
137 function mockGetTabState (tab) { |
|
138 return tab; |
|
139 } |
|
140 |
|
141 function mockGetWindowEnumerator(url, numWindows, numTabs) { |
|
142 let elements = []; |
|
143 for (let w = 0; w < numWindows; ++w) { |
|
144 let tabs = []; |
|
145 let win = { |
|
146 closed: false, |
|
147 mockIsPrivate: false, |
|
148 gBrowser: { |
|
149 tabs: tabs, |
|
150 }, |
|
151 }; |
|
152 elements.push(win); |
|
153 |
|
154 for (let t = 0; t < numTabs; ++t) { |
|
155 tabs.push(TestingUtils.deepCopy({ |
|
156 index: 1, |
|
157 entries: [{ |
|
158 url: ((typeof url == "string") ? url : url()), |
|
159 title: "title" |
|
160 }], |
|
161 attributes: { |
|
162 image: "image" |
|
163 }, |
|
164 lastAccessed: 1499 |
|
165 })); |
|
166 } |
|
167 } |
|
168 |
|
169 // Always include a closed window and a private window. |
|
170 elements.push({ |
|
171 closed: true, |
|
172 mockIsPrivate: false, |
|
173 gBrowser: { |
|
174 tabs: [], |
|
175 }, |
|
176 }); |
|
177 |
|
178 elements.push({ |
|
179 closed: false, |
|
180 mockIsPrivate: true, |
|
181 gBrowser: { |
|
182 tabs: [], |
|
183 }, |
|
184 }); |
|
185 |
|
186 return { |
|
187 hasMoreElements: function () { |
|
188 return elements.length; |
|
189 }, |
|
190 getNext: function () { |
|
191 return elements.shift(); |
|
192 }, |
|
193 }; |
|
194 } |