|
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 file, |
|
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; |
|
6 Cu.import("resource://gre/modules/Services.jsm"); |
|
7 Cu.import("resource://gre/modules/XPCOMUtils.jsm"); |
|
8 |
|
9 XPCOMUtils.defineLazyModuleGetter(this, "Promise", |
|
10 "resource://gre/modules/Promise.jsm"); |
|
11 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils", |
|
12 "resource://gre/modules/PlacesUtils.jsm"); |
|
13 |
|
14 const MANIFEST_PREFS = Services.prefs.getBranch("social.manifest."); |
|
15 const gProfD = do_get_profile(); |
|
16 |
|
17 const XULAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1"; |
|
18 const XULAPPINFO_CID = Components.ID("{c763b610-9d49-455a-bbd2-ede71682a1ac}"); |
|
19 |
|
20 function createAppInfo(id, name, version, platformVersion) { |
|
21 gAppInfo = { |
|
22 // nsIXULAppInfo |
|
23 vendor: "Mozilla", |
|
24 name: name, |
|
25 ID: id, |
|
26 version: version, |
|
27 appBuildID: "2007010101", |
|
28 platformVersion: platformVersion ? platformVersion : "1.0", |
|
29 platformBuildID: "2007010101", |
|
30 |
|
31 // nsIXULRuntime |
|
32 inSafeMode: false, |
|
33 logConsoleErrors: true, |
|
34 OS: "XPCShell", |
|
35 XPCOMABI: "noarch-spidermonkey", |
|
36 invalidateCachesOnRestart: function invalidateCachesOnRestart() { |
|
37 // Do nothing |
|
38 }, |
|
39 |
|
40 // nsICrashReporter |
|
41 annotations: {}, |
|
42 |
|
43 annotateCrashReport: function(key, data) { |
|
44 this.annotations[key] = data; |
|
45 }, |
|
46 |
|
47 QueryInterface: XPCOMUtils.generateQI([Ci.nsIXULAppInfo, |
|
48 Ci.nsIXULRuntime, |
|
49 Ci.nsICrashReporter, |
|
50 Ci.nsISupports]) |
|
51 }; |
|
52 |
|
53 var XULAppInfoFactory = { |
|
54 createInstance: function (outer, iid) { |
|
55 if (outer != null) |
|
56 throw Components.results.NS_ERROR_NO_AGGREGATION; |
|
57 return gAppInfo.QueryInterface(iid); |
|
58 } |
|
59 }; |
|
60 var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar); |
|
61 registrar.registerFactory(XULAPPINFO_CID, "XULAppInfo", |
|
62 XULAPPINFO_CONTRACTID, XULAppInfoFactory); |
|
63 } |
|
64 |
|
65 function initApp() { |
|
66 createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9"); |
|
67 // prepare a blocklist file for the blocklist service |
|
68 var blocklistFile = gProfD.clone(); |
|
69 blocklistFile.append("blocklist.xml"); |
|
70 if (blocklistFile.exists()) |
|
71 blocklistFile.remove(false); |
|
72 var source = do_get_file("blocklist.xml"); |
|
73 source.copyTo(gProfD, "blocklist.xml"); |
|
74 blocklistFile.lastModifiedTime = Date.now(); |
|
75 } |
|
76 |
|
77 function AsyncRunner() { |
|
78 do_test_pending(); |
|
79 do_register_cleanup((function () this.destroy()).bind(this)); |
|
80 |
|
81 this._callbacks = { |
|
82 done: do_test_finished, |
|
83 error: function (err) { |
|
84 // xpcshell test functions like do_check_eq throw NS_ERROR_ABORT on |
|
85 // failure. Ignore those so they aren't rethrown here. |
|
86 if (err !== Cr.NS_ERROR_ABORT) { |
|
87 if (err.stack) { |
|
88 err = err + " - See following stack:\n" + err.stack + |
|
89 "\nUseless do_throw stack"; |
|
90 } |
|
91 do_throw(err); |
|
92 } |
|
93 }, |
|
94 consoleError: function (scriptErr) { |
|
95 // Try to ensure the error is related to the test. |
|
96 let filename = scriptErr.sourceName || scriptErr.toString() || ""; |
|
97 if (filename.indexOf("/toolkit/components/social/") >= 0) |
|
98 do_throw(scriptErr); |
|
99 }, |
|
100 }; |
|
101 this._iteratorQueue = []; |
|
102 |
|
103 // This catches errors reported to the console, e.g., via Cu.reportError, but |
|
104 // not on the runner's stack. |
|
105 Cc["@mozilla.org/consoleservice;1"]. |
|
106 getService(Ci.nsIConsoleService). |
|
107 registerListener(this); |
|
108 } |
|
109 |
|
110 AsyncRunner.prototype = { |
|
111 |
|
112 appendIterator: function appendIterator(iter) { |
|
113 this._iteratorQueue.push(iter); |
|
114 }, |
|
115 |
|
116 next: function next(/* ... */) { |
|
117 if (!this._iteratorQueue.length) { |
|
118 this.destroy(); |
|
119 this._callbacks.done(); |
|
120 return; |
|
121 } |
|
122 |
|
123 // send() discards all arguments after the first, so there's no choice here |
|
124 // but to send only one argument to the yielder. |
|
125 let args = [arguments.length <= 1 ? arguments[0] : Array.slice(arguments)]; |
|
126 try { |
|
127 var val = this._iteratorQueue[0].send.apply(this._iteratorQueue[0], args); |
|
128 } |
|
129 catch (err if err instanceof StopIteration) { |
|
130 this._iteratorQueue.shift(); |
|
131 this.next(); |
|
132 return; |
|
133 } |
|
134 catch (err) { |
|
135 this._callbacks.error(err); |
|
136 } |
|
137 |
|
138 // val is an iterator => prepend it to the queue and start on it |
|
139 // val is otherwise truthy => call next |
|
140 if (val) { |
|
141 if (typeof(val) != "boolean") |
|
142 this._iteratorQueue.unshift(val); |
|
143 this.next(); |
|
144 } |
|
145 }, |
|
146 |
|
147 destroy: function destroy() { |
|
148 Cc["@mozilla.org/consoleservice;1"]. |
|
149 getService(Ci.nsIConsoleService). |
|
150 unregisterListener(this); |
|
151 this.destroy = function alreadyDestroyed() {}; |
|
152 }, |
|
153 |
|
154 observe: function observe(msg) { |
|
155 if (msg instanceof Ci.nsIScriptError && |
|
156 !(msg.flags & Ci.nsIScriptError.warningFlag)) |
|
157 { |
|
158 this._callbacks.consoleError(msg); |
|
159 } |
|
160 }, |
|
161 }; |
|
162 |
|
163 |
|
164 function promiseAddVisits(aPlaceInfo) |
|
165 { |
|
166 let deferred = Promise.defer(); |
|
167 let places = []; |
|
168 if (aPlaceInfo instanceof Ci.nsIURI) { |
|
169 places.push({ uri: aPlaceInfo }); |
|
170 } |
|
171 else if (Array.isArray(aPlaceInfo)) { |
|
172 places = places.concat(aPlaceInfo); |
|
173 } else { |
|
174 places.push(aPlaceInfo) |
|
175 } |
|
176 |
|
177 // Create mozIVisitInfo for each entry. |
|
178 let now = Date.now(); |
|
179 for (let i = 0; i < places.length; i++) { |
|
180 if (!places[i].title) { |
|
181 places[i].title = "test visit for " + places[i].uri.spec; |
|
182 } |
|
183 places[i].visits = [{ |
|
184 transitionType: places[i].transition === undefined ? Ci.nsINavHistoryService.TRANSITION_LINK |
|
185 : places[i].transition, |
|
186 visitDate: places[i].visitDate || (now++) * 1000, |
|
187 referrerURI: places[i].referrer |
|
188 }]; |
|
189 } |
|
190 |
|
191 PlacesUtils.asyncHistory.updatePlaces( |
|
192 places, |
|
193 { |
|
194 handleError: function handleError(aResultCode, aPlaceInfo) { |
|
195 let ex = new Components.Exception("Unexpected error in adding visits.", |
|
196 aResultCode); |
|
197 deferred.reject(ex); |
|
198 }, |
|
199 handleResult: function () {}, |
|
200 handleCompletion: function handleCompletion() { |
|
201 deferred.resolve(); |
|
202 } |
|
203 } |
|
204 ); |
|
205 |
|
206 return deferred.promise; |
|
207 } |
|
208 |
|
209 function promiseTopicObserved(aTopic) |
|
210 { |
|
211 let deferred = Promise.defer(); |
|
212 |
|
213 Services.obs.addObserver( |
|
214 function PTO_observe(aSubject, aTopic, aData) { |
|
215 Services.obs.removeObserver(PTO_observe, aTopic); |
|
216 deferred.resolve([aSubject, aData]); |
|
217 }, aTopic, false); |
|
218 |
|
219 return deferred.promise; |
|
220 } |
|
221 |
|
222 function promiseClearHistory() { |
|
223 let promise = promiseTopicObserved(PlacesUtils.TOPIC_EXPIRATION_FINISHED); |
|
224 do_execute_soon(function() PlacesUtils.bhistory.removeAllPages()); |
|
225 return promise; |
|
226 } |