michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; michael@0: Cu.import("resource://gre/modules/Services.jsm"); michael@0: Cu.import("resource://gre/modules/XPCOMUtils.jsm"); michael@0: michael@0: XPCOMUtils.defineLazyModuleGetter(this, "Promise", michael@0: "resource://gre/modules/Promise.jsm"); michael@0: XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils", michael@0: "resource://gre/modules/PlacesUtils.jsm"); michael@0: michael@0: const MANIFEST_PREFS = Services.prefs.getBranch("social.manifest."); michael@0: const gProfD = do_get_profile(); michael@0: michael@0: const XULAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1"; michael@0: const XULAPPINFO_CID = Components.ID("{c763b610-9d49-455a-bbd2-ede71682a1ac}"); michael@0: michael@0: function createAppInfo(id, name, version, platformVersion) { michael@0: gAppInfo = { michael@0: // nsIXULAppInfo michael@0: vendor: "Mozilla", michael@0: name: name, michael@0: ID: id, michael@0: version: version, michael@0: appBuildID: "2007010101", michael@0: platformVersion: platformVersion ? platformVersion : "1.0", michael@0: platformBuildID: "2007010101", michael@0: michael@0: // nsIXULRuntime michael@0: inSafeMode: false, michael@0: logConsoleErrors: true, michael@0: OS: "XPCShell", michael@0: XPCOMABI: "noarch-spidermonkey", michael@0: invalidateCachesOnRestart: function invalidateCachesOnRestart() { michael@0: // Do nothing michael@0: }, michael@0: michael@0: // nsICrashReporter michael@0: annotations: {}, michael@0: michael@0: annotateCrashReport: function(key, data) { michael@0: this.annotations[key] = data; michael@0: }, michael@0: michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.nsIXULAppInfo, michael@0: Ci.nsIXULRuntime, michael@0: Ci.nsICrashReporter, michael@0: Ci.nsISupports]) michael@0: }; michael@0: michael@0: var XULAppInfoFactory = { michael@0: createInstance: function (outer, iid) { michael@0: if (outer != null) michael@0: throw Components.results.NS_ERROR_NO_AGGREGATION; michael@0: return gAppInfo.QueryInterface(iid); michael@0: } michael@0: }; michael@0: var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar); michael@0: registrar.registerFactory(XULAPPINFO_CID, "XULAppInfo", michael@0: XULAPPINFO_CONTRACTID, XULAppInfoFactory); michael@0: } michael@0: michael@0: function initApp() { michael@0: createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9"); michael@0: // prepare a blocklist file for the blocklist service michael@0: var blocklistFile = gProfD.clone(); michael@0: blocklistFile.append("blocklist.xml"); michael@0: if (blocklistFile.exists()) michael@0: blocklistFile.remove(false); michael@0: var source = do_get_file("blocklist.xml"); michael@0: source.copyTo(gProfD, "blocklist.xml"); michael@0: blocklistFile.lastModifiedTime = Date.now(); michael@0: } michael@0: michael@0: function AsyncRunner() { michael@0: do_test_pending(); michael@0: do_register_cleanup((function () this.destroy()).bind(this)); michael@0: michael@0: this._callbacks = { michael@0: done: do_test_finished, michael@0: error: function (err) { michael@0: // xpcshell test functions like do_check_eq throw NS_ERROR_ABORT on michael@0: // failure. Ignore those so they aren't rethrown here. michael@0: if (err !== Cr.NS_ERROR_ABORT) { michael@0: if (err.stack) { michael@0: err = err + " - See following stack:\n" + err.stack + michael@0: "\nUseless do_throw stack"; michael@0: } michael@0: do_throw(err); michael@0: } michael@0: }, michael@0: consoleError: function (scriptErr) { michael@0: // Try to ensure the error is related to the test. michael@0: let filename = scriptErr.sourceName || scriptErr.toString() || ""; michael@0: if (filename.indexOf("/toolkit/components/social/") >= 0) michael@0: do_throw(scriptErr); michael@0: }, michael@0: }; michael@0: this._iteratorQueue = []; michael@0: michael@0: // This catches errors reported to the console, e.g., via Cu.reportError, but michael@0: // not on the runner's stack. michael@0: Cc["@mozilla.org/consoleservice;1"]. michael@0: getService(Ci.nsIConsoleService). michael@0: registerListener(this); michael@0: } michael@0: michael@0: AsyncRunner.prototype = { michael@0: michael@0: appendIterator: function appendIterator(iter) { michael@0: this._iteratorQueue.push(iter); michael@0: }, michael@0: michael@0: next: function next(/* ... */) { michael@0: if (!this._iteratorQueue.length) { michael@0: this.destroy(); michael@0: this._callbacks.done(); michael@0: return; michael@0: } michael@0: michael@0: // send() discards all arguments after the first, so there's no choice here michael@0: // but to send only one argument to the yielder. michael@0: let args = [arguments.length <= 1 ? arguments[0] : Array.slice(arguments)]; michael@0: try { michael@0: var val = this._iteratorQueue[0].send.apply(this._iteratorQueue[0], args); michael@0: } michael@0: catch (err if err instanceof StopIteration) { michael@0: this._iteratorQueue.shift(); michael@0: this.next(); michael@0: return; michael@0: } michael@0: catch (err) { michael@0: this._callbacks.error(err); michael@0: } michael@0: michael@0: // val is an iterator => prepend it to the queue and start on it michael@0: // val is otherwise truthy => call next michael@0: if (val) { michael@0: if (typeof(val) != "boolean") michael@0: this._iteratorQueue.unshift(val); michael@0: this.next(); michael@0: } michael@0: }, michael@0: michael@0: destroy: function destroy() { michael@0: Cc["@mozilla.org/consoleservice;1"]. michael@0: getService(Ci.nsIConsoleService). michael@0: unregisterListener(this); michael@0: this.destroy = function alreadyDestroyed() {}; michael@0: }, michael@0: michael@0: observe: function observe(msg) { michael@0: if (msg instanceof Ci.nsIScriptError && michael@0: !(msg.flags & Ci.nsIScriptError.warningFlag)) michael@0: { michael@0: this._callbacks.consoleError(msg); michael@0: } michael@0: }, michael@0: }; michael@0: michael@0: michael@0: function promiseAddVisits(aPlaceInfo) michael@0: { michael@0: let deferred = Promise.defer(); michael@0: let places = []; michael@0: if (aPlaceInfo instanceof Ci.nsIURI) { michael@0: places.push({ uri: aPlaceInfo }); michael@0: } michael@0: else if (Array.isArray(aPlaceInfo)) { michael@0: places = places.concat(aPlaceInfo); michael@0: } else { michael@0: places.push(aPlaceInfo) michael@0: } michael@0: michael@0: // Create mozIVisitInfo for each entry. michael@0: let now = Date.now(); michael@0: for (let i = 0; i < places.length; i++) { michael@0: if (!places[i].title) { michael@0: places[i].title = "test visit for " + places[i].uri.spec; michael@0: } michael@0: places[i].visits = [{ michael@0: transitionType: places[i].transition === undefined ? Ci.nsINavHistoryService.TRANSITION_LINK michael@0: : places[i].transition, michael@0: visitDate: places[i].visitDate || (now++) * 1000, michael@0: referrerURI: places[i].referrer michael@0: }]; michael@0: } michael@0: michael@0: PlacesUtils.asyncHistory.updatePlaces( michael@0: places, michael@0: { michael@0: handleError: function handleError(aResultCode, aPlaceInfo) { michael@0: let ex = new Components.Exception("Unexpected error in adding visits.", michael@0: aResultCode); michael@0: deferred.reject(ex); michael@0: }, michael@0: handleResult: function () {}, michael@0: handleCompletion: function handleCompletion() { michael@0: deferred.resolve(); michael@0: } michael@0: } michael@0: ); michael@0: michael@0: return deferred.promise; michael@0: } michael@0: michael@0: function promiseTopicObserved(aTopic) michael@0: { michael@0: let deferred = Promise.defer(); michael@0: michael@0: Services.obs.addObserver( michael@0: function PTO_observe(aSubject, aTopic, aData) { michael@0: Services.obs.removeObserver(PTO_observe, aTopic); michael@0: deferred.resolve([aSubject, aData]); michael@0: }, aTopic, false); michael@0: michael@0: return deferred.promise; michael@0: } michael@0: michael@0: function promiseClearHistory() { michael@0: let promise = promiseTopicObserved(PlacesUtils.TOPIC_EXPIRATION_FINISHED); michael@0: do_execute_soon(function() PlacesUtils.bhistory.removeAllPages()); michael@0: return promise; michael@0: }