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