diff options
Diffstat (limited to 'uriloader/exthandler/tests/HandlerServiceTestUtils.jsm')
-rw-r--r-- | uriloader/exthandler/tests/HandlerServiceTestUtils.jsm | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/uriloader/exthandler/tests/HandlerServiceTestUtils.jsm b/uriloader/exthandler/tests/HandlerServiceTestUtils.jsm new file mode 100644 index 0000000000..72c551d654 --- /dev/null +++ b/uriloader/exthandler/tests/HandlerServiceTestUtils.jsm @@ -0,0 +1,241 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +/* + * Shared functions for tests related to invoking external handler applications. + */ + +"use strict"; + +var EXPORTED_SYMBOLS = ["HandlerServiceTestUtils"]; + +const { AppConstants } = ChromeUtils.import( + "resource://gre/modules/AppConstants.jsm" +); +const { XPCOMUtils } = ChromeUtils.import( + "resource://gre/modules/XPCOMUtils.jsm" +); +const { Assert } = ChromeUtils.import("resource://testing-common/Assert.jsm"); + +XPCOMUtils.defineLazyServiceGetter( + this, + "gExternalProtocolService", + "@mozilla.org/uriloader/external-protocol-service;1", + "nsIExternalProtocolService" +); +XPCOMUtils.defineLazyServiceGetter( + this, + "gMIMEService", + "@mozilla.org/mime;1", + "nsIMIMEService" +); +XPCOMUtils.defineLazyServiceGetter( + this, + "gHandlerService", + "@mozilla.org/uriloader/handler-service;1", + "nsIHandlerService" +); + +var HandlerServiceTestUtils = { + /** + * Retrieves the names of all the MIME types and protocols configured in the + * handler service instance currently under testing. + * + * @return Array of strings like "example/type" or "example-scheme", sorted + * alphabetically regardless of category. + */ + getAllHandlerInfoTypes() { + return Array.from(gHandlerService.enumerate(), info => info.type).sort(); + }, + + /** + * Retrieves all the configured handlers for MIME types and protocols. + * + * @note The nsIHandlerInfo instances returned by the "enumerate" method + * cannot be used for testing because they incorporate information from + * the operating system and also from the default nsIHandlerService + * instance, independently from what instance is under testing. + * + * @return Array of nsIHandlerInfo instances sorted by their "type" property. + */ + getAllHandlerInfos() { + return this.getAllHandlerInfoTypes().map(type => this.getHandlerInfo(type)); + }, + + /** + * Retrieves an nsIHandlerInfo for the given MIME type or protocol, which + * incorporates information from the operating system and also from the + * handler service instance currently under testing. + * + * @note If the handler service instance currently under testing is not the + * default one and the requested type is a MIME type, the returned + * nsIHandlerInfo will include information from the default + * nsIHandlerService instance. This cannot be avoided easily because the + * getMIMEInfoFromOS method is not exposed to JavaScript. + * + * @param type + * MIME type or scheme name of the nsIHandlerInfo to retrieve. + * + * @return The populated nsIHandlerInfo instance. + */ + getHandlerInfo(type) { + if (type.includes("/")) { + // We have to use the getFromTypeAndExtension method because we don't have + // access to getMIMEInfoFromOS. This means that we have to reset the data + // that may have been imported from the default nsIHandlerService instance + // and is not overwritten by fillHandlerInfo later. + let handlerInfo = gMIMEService.getFromTypeAndExtension(type, null); + if (AppConstants.platform == "android") { + // On Android, the first handler application is always the internal one. + while (handlerInfo.possibleApplicationHandlers.length > 1) { + handlerInfo.possibleApplicationHandlers.removeElementAt(1); + } + } else { + handlerInfo.possibleApplicationHandlers.clear(); + } + handlerInfo.setFileExtensions(""); + // Populate the object from the handler service instance under testing. + if (gHandlerService.exists(handlerInfo)) { + gHandlerService.fillHandlerInfo(handlerInfo, ""); + } + return handlerInfo; + } + + // Populate the protocol information from the handler service instance under + // testing, like the nsIExternalProtocolService::GetProtocolHandlerInfo + // method does on the default nsIHandlerService instance. + let osDefaultHandlerFound = {}; + let handlerInfo = gExternalProtocolService.getProtocolHandlerInfoFromOS( + type, + osDefaultHandlerFound + ); + if (gHandlerService.exists(handlerInfo)) { + gHandlerService.fillHandlerInfo(handlerInfo, ""); + } else { + gExternalProtocolService.setProtocolHandlerDefaults( + handlerInfo, + osDefaultHandlerFound.value + ); + } + return handlerInfo; + }, + + /** + * Creates an nsIHandlerInfo for the given MIME type or protocol, initialized + * to the default values for the current platform. + * + * @note For this method to work, the specified MIME type or protocol must not + * be configured in the default handler service instance or the one + * under testing, and must not be registered in the operating system. + * + * @param type + * MIME type or scheme name of the nsIHandlerInfo to create. + * + * @return The blank nsIHandlerInfo instance. + */ + getBlankHandlerInfo(type) { + let handlerInfo = this.getHandlerInfo(type); + + let preferredAction, preferredApplicationHandler; + if (AppConstants.platform == "android") { + // On Android, the default preferredAction for MIME types is useHelperApp. + // For protocols, we always behave as if an operating system provided + // handler existed, and as such we initialize them to useSystemDefault. + // This is because the AndroidBridge is not available in xpcshell tests. + preferredAction = type.includes("/") + ? Ci.nsIHandlerInfo.useHelperApp + : Ci.nsIHandlerInfo.useSystemDefault; + // On Android, the default handler application is always the internal one. + preferredApplicationHandler = { + name: "Android chooser", + }; + } else { + // On Desktop, the default preferredAction for MIME types is saveToDisk, + // while for protocols it is alwaysAsk. + preferredAction = type.includes("/") + ? Ci.nsIHandlerInfo.saveToDisk + : Ci.nsIHandlerInfo.alwaysAsk; + preferredApplicationHandler = null; + } + + this.assertHandlerInfoMatches(handlerInfo, { + type, + preferredAction, + alwaysAskBeforeHandling: true, + preferredApplicationHandler, + }); + return handlerInfo; + }, + + /** + * Checks whether an nsIHandlerInfo instance matches the provided object. + */ + assertHandlerInfoMatches(handlerInfo, expected) { + let expectedInterface = expected.type.includes("/") + ? Ci.nsIMIMEInfo + : Ci.nsIHandlerInfo; + Assert.ok(handlerInfo instanceof expectedInterface); + Assert.equal(handlerInfo.type, expected.type); + + if (!expected.preferredActionOSDependent) { + Assert.equal(handlerInfo.preferredAction, expected.preferredAction); + Assert.equal( + handlerInfo.alwaysAskBeforeHandling, + expected.alwaysAskBeforeHandling + ); + } + + if (expectedInterface == Ci.nsIMIMEInfo) { + let fileExtensionsEnumerator = handlerInfo.getFileExtensions(); + for (let expectedFileExtension of expected.fileExtensions || []) { + Assert.equal(fileExtensionsEnumerator.getNext(), expectedFileExtension); + } + Assert.ok(!fileExtensionsEnumerator.hasMore()); + } + + if (expected.preferredApplicationHandler) { + this.assertHandlerAppMatches( + handlerInfo.preferredApplicationHandler, + expected.preferredApplicationHandler + ); + } else { + Assert.equal(handlerInfo.preferredApplicationHandler, null); + } + + let handlerAppsArrayEnumerator = handlerInfo.possibleApplicationHandlers.enumerate(); + if (AppConstants.platform == "android") { + // On Android, the first handler application is always the internal one. + this.assertHandlerAppMatches(handlerAppsArrayEnumerator.getNext(), { + name: "Android chooser", + }); + } + for (let expectedHandlerApp of expected.possibleApplicationHandlers || []) { + this.assertHandlerAppMatches( + handlerAppsArrayEnumerator.getNext(), + expectedHandlerApp + ); + } + Assert.ok(!handlerAppsArrayEnumerator.hasMoreElements()); + }, + + /** + * Checks whether an nsIHandlerApp instance matches the provided object. + */ + assertHandlerAppMatches(handlerApp, expected) { + Assert.ok(handlerApp instanceof Ci.nsIHandlerApp); + Assert.equal(handlerApp.name, expected.name); + if (expected.executable) { + Assert.ok(handlerApp instanceof Ci.nsILocalHandlerApp); + Assert.ok(expected.executable.equals(handlerApp.executable)); + } else if (expected.uriTemplate) { + Assert.ok(handlerApp instanceof Ci.nsIWebHandlerApp); + Assert.equal(handlerApp.uriTemplate, expected.uriTemplate); + } else if (expected.service) { + Assert.ok(handlerApp instanceof Ci.nsIDBusHandlerApp); + Assert.equal(handlerApp.service, expected.service); + Assert.equal(handlerApp.method, expected.method); + Assert.equal(handlerApp.dBusInterface, expected.dBusInterface); + Assert.equal(handlerApp.objectPath, expected.objectPath); + } + }, +}; |