--- a/toolkit/content/tests/browser/Makefile.in
+++ b/toolkit/content/tests/browser/Makefile.in
@@ -37,21 +37,25 @@
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = toolkit/content/tests/browser
include $(DEPTH)/config/autoconf.mk
+
+DIRS = \
+ common \
+ data \
+ $(NULL)
+
include $(topsrcdir)/config/rules.mk
_BROWSER_FILES = \
- bug471962_testpage_inner.sjs \
- bug471962_testpage_outer.sjs \
browser_bug471962.js \
$(NULL)
# browser_keyevents_during_autoscrolling.js cannot start the autoscrolling by
# synthesizeMouse with middle button on linux, therefore, disable it temporarily
ifneq ($(MOZ_WIDGET_TOOLKIT),gtk2)
_BROWSER_FILES += browser_keyevents_during_autoscrolling.js
endif
--- a/toolkit/content/tests/browser/browser_bug471962.js
+++ b/toolkit/content/tests/browser/browser_bug471962.js
@@ -29,297 +29,116 @@
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
-function test()
-{
- const Cc = Components.classes;
- const Ci = Components.interfaces;
- const Cu = Components.utils;
- const Cr = Components.results;
- const Cm = Components.manager;
+/**
+ * Test for bug 471962 <https://bugzilla.mozilla.org/show_bug.cgi?id=471962>:
+ * When saving an inner frame as file only, the POST data of the outer page is
+ * sent to the address of the inner page.
+ */
+function test() {
+
+ // --- Testing support library ---
- Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+ // Import the toolkit test support library in the scope of the current test.
+ // This operation also defines the common constants Cc, Ci, Cu, Cr and Cm.
+ Components.classes["@mozilla.org/moz/jssubscript-loader;1"].
+ getService(Components.interfaces.mozIJSSubScriptLoader).loadSubScript(
+ "chrome://mochikit/content/browser/toolkit/content/tests/browser/common/_loadAll.js",
+ this);
- // --- Mock nsIFilePicker implementation ---
+ // --- Test implementation ---
+
+ const kBaseUrl =
+ "http://localhost:8888/browser/toolkit/content/tests/browser/data/";
- var componentRegistrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
-
- var originalFilePickerFactory;
- var mockFilePickerFactory;
- var destFile;
+ function FramePostData_TestGenerator() {
+ // Display the outer page, and wait for it to be loaded. Loading the URI
+ // doesn't generally raise any exception, but if an error page is
+ // displayed, an exception will occur later during the test.
+ gBrowser.addEventListener("pageshow", testRunner.continueTest, false);
+ gBrowser.loadURI(kBaseUrl + "post_form_outer.sjs");
+ yield;
+ gBrowser.removeEventListener("pageshow", testRunner.continueTest, false);
- // Note: The original class name is platform-dependent, however it is not
- // important that we restore the exact class name when we restore the
- // original factory.
- const kFilePickerCID = "{bd57cee8-1dd1-11b2-9fe7-95cf4709aea3}";
- const kFilePickerContractID = "@mozilla.org/filepicker;1";
- const kFilePickerPossibleClassName = "File Picker";
+ try {
+ // Submit the form in the outer page, then wait for both the outer
+ // document and the inner frame to be loaded again.
+ gBrowser.addEventListener("DOMContentLoaded",
+ testRunner.continueAfterTwoEvents, false);
+ try {
+ gBrowser.contentDocument.getElementById("postForm").submit();
+ yield;
+ }
+ finally {
+ // Remove the event listener, even if an exception occurred for any
+ // reason (for example, the requested element does not exist).
+ gBrowser.removeEventListener("DOMContentLoaded",
+ testRunner.continueAfterTwoEvents, false);
+ }
+
+ // Save a reference to the inner frame in the reloaded page for later.
+ var innerFrame = gBrowser.contentDocument.getElementById("innerFrame");
- function registerMockFilePickerFactory() {
- // This file picker implementation is tailored for this test and returns
- // the file specified in destFile, and a filter index of kSaveAsType_URL.
- // The file is overwritten if it exists.
- var mockFilePicker = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIFilePicker]),
- init: function(aParent, aTitle, aMode) { },
- appendFilters: function(aFilterMask) { },
- appendFilter: function(aTitle, aFilter) { },
- defaultString: "",
- defaultExtension: "",
- set filterIndex() { },
- get filterIndex() {
- return 1; // kSaveAsType_URL
- },
- displayDirectory: null,
- get file() {
- return destFile.clone();
- },
- get fileURL() {
- return Cc["@mozilla.org/network/io-service;1"].
- getService(Ci.nsIIOService).newFileURI(destFile);
- },
- get files() {
- throw Cr.NS_ERROR_NOT_IMPLEMENTED;
- },
- show: function() {
- // Assume we overwrite the file if it exists
- return (destFile.exists() ?
- Ci.nsIFilePicker.returnReplace :
- Ci.nsIFilePicker.returnOK);
+ // Submit the form in the inner page.
+ gBrowser.addEventListener("DOMContentLoaded",
+ testRunner.continueTest, false);
+ try {
+ innerFrame.contentDocument.getElementById("postForm").submit();
+ yield;
}
- };
+ finally {
+ // Remove the event listener, even if an exception occurred for any
+ // reason (for example, the requested element does not exist).
+ gBrowser.removeEventListener("DOMContentLoaded",
+ testRunner.continueTest, false);
+ }
- mockFilePickerFactory = {
- createInstance: function(aOuter, aIid) {
- if (aOuter != null)
- throw Cr.NS_ERROR_NO_AGGREGATION;
- return mockFilePicker.QueryInterface(aIid);
- }
- };
-
- // Preserve the original factory
- originalFilePickerFactory = Cm.getClassObject(Cc[kFilePickerContractID],
- Ci.nsIFactory);
+ // Create the folder the page will be saved into.
+ var destDir = createTemporarySaveDirectory();
+ try {
+ // Call the appropriate save function defined in contentAreaUtils.js.
+ mockFilePickerSettings.destDir = destDir;
+ mockFilePickerSettings.filterIndex = 1; // kSaveAsType_URL
+ callSaveWithMockObjects(function() {
+ var docToSave = innerFrame.contentDocument;
+ // We call internalSave instead of saveDocument to bypass the history
+ // cache.
+ internalSave(docToSave.location.href, docToSave, null, null,
+ docToSave.contentType, false, null, null,
+ docToSave.referrer ? makeURI(docToSave.referrer) : null,
+ false, null);
+ });
- // Register the mock factory
- componentRegistrar.registerFactory(
- Components.ID(kFilePickerCID),
- "Mock File Picker Implementation",
- kFilePickerContractID,
- mockFilePickerFactory
- );
- }
+ // Wait for the download to finish, and exit if it wasn't successful.
+ var downloadSuccess = yield;
+ if (!downloadSuccess)
+ throw "Unexpected failure, the inner frame couldn't be saved!";
+
+ // Read the entire saved file.
+ var fileContents = readShortFile(mockFilePickerResults.selectedFile);
- function unregisterMockFilePickerFactory() {
- // Free references to the mock factory
- componentRegistrar.unregisterFactory(
- Components.ID(kFilePickerCID),
- mockFilePickerFactory
- );
-
- // Restore the original factory
- componentRegistrar.registerFactory(
- Components.ID(kFilePickerCID),
- kFilePickerPossibleClassName,
- kFilePickerContractID,
- originalFilePickerFactory
- );
+ // Check if outer POST data is found.
+ const searchPattern = "inputfield=outer";
+ ok(fileContents.indexOf(searchPattern) === -1,
+ "The saved inner frame does not contain outer POST data");
+ }
+ finally {
+ // Clean up the saved file.
+ destDir.remove(true);
+ }
+ }
+ finally {
+ // Replace the current tab with a clean one.
+ gBrowser.addTab();
+ gBrowser.removeCurrentTab();
+ }
}
- // --- Mock nsITransfer implementation ---
-
- var originalTransferFactory;
- var mockTransferFactory;
- var downloadIsSuccessful = true;
-
- const kDownloadCID = "{e3fa9d0a-1dd1-11b2-bdef-8c720b597445}";
- const kTransferContractID = "@mozilla.org/transfer;1";
- const kDownloadClassName = "Download";
-
- function registerMockTransferFactory() {
- // This "transfer" object implementation is tailored for this test, and
- // continues the test when the download is completed.
- var mockTransfer = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
- Ci.nsIWebProgressListener2,
- Ci.nsITransfer]),
-
- // --- nsIWebProgressListener interface functions ---
-
- onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus) {
- // If at least one notification reported an error, the download failed
- if (aStatus != Cr.NS_OK)
- downloadIsSuccessful = false;
-
- // If the download is finished
- if ((aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) &&
- (aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK))
- // Continue the test, reporting the success or failure condition
- onDownloadFinished(downloadIsSuccessful);
- },
- onProgressChange: function(aWebProgress, aRequest, aCurSelfProgress,
- aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress) { },
- onLocationChange: function(aWebProgress, aRequest, aLocation) { },
- onStatusChange: function(aWebProgress, aRequest, aStatus, aMessage) {
- // If at least one notification reported an error, the download failed
- if (aStatus != Cr.NS_OK)
- downloadIsSuccessful = false;
- },
- onSecurityChange: function(aWebProgress, aRequest, aState) { },
-
- // --- nsIWebProgressListener2 interface functions ---
-
- onProgressChange64: function(aWebProgress, aRequest, aCurSelfProgress,
- aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress) { },
- onRefreshAttempted: function(aWebProgress, aRefreshURI, aMillis,
- aSameURI) { },
-
- // --- nsITransfer interface functions ---
-
- init: function(aSource, aTarget, aDisplayName, aMIMEInfo, aStartTime,
- aTempFile, aCancelable) { }
- };
-
- mockTransferFactory = {
- createInstance: function(aOuter, aIid) {
- if (aOuter != null)
- throw Cr.NS_ERROR_NO_AGGREGATION;
- return mockTransfer.QueryInterface(aIid);
- }
- };
-
- // Preserve the original factory
- originalTransferFactory = Cm.getClassObject(Cc[kTransferContractID],
- Ci.nsIFactory);
-
- // Register the mock factory
- componentRegistrar.registerFactory(
- Components.ID(kDownloadCID),
- "Mock Transfer Implementation",
- kTransferContractID,
- mockTransferFactory
- );
- }
-
- function unregisterMockTransferFactory() {
- // Free references to the mock factory
- componentRegistrar.unregisterFactory(
- Components.ID(kDownloadCID),
- mockTransferFactory
- );
-
- // Restore the original factory
- componentRegistrar.registerFactory(
- Components.ID(kDownloadCID),
- kDownloadClassName,
- kTransferContractID,
- originalTransferFactory
- );
- }
-
- // --- Test procedure ---
-
- var innerFrame;
+ // --- Run the test ---
- function startTest() {
- waitForExplicitFinish();
-
- // Display the outer page
- gBrowser.addEventListener("pageshow", onPageShow, false);
- gBrowser.loadURI("http://localhost:8888/browser/toolkit/content/tests/browser/bug471962_testpage_outer.sjs");
- }
-
- function onPageShow() {
- gBrowser.removeEventListener("pageshow", onPageShow, false);
-
- // Submit the form in the outer page, then wait for both the outer
- // document and the inner frame to be loaded again
- gBrowser.addEventListener("DOMContentLoaded", waitForTwoReloads, false);
- gBrowser.contentDocument.getElementById("postForm").submit();
- }
-
- var isFirstReload = true;
-
- function waitForTwoReloads() {
- // The first time this function is called, do nothing
- if (isFirstReload) {
- isFirstReload = false;
- return;
- }
-
- // The second time, go on with the normal test flow
- gBrowser.removeEventListener("DOMContentLoaded", waitForTwoReloads, false);
-
- // Save a reference to the inner frame in the reloaded page for later
- innerFrame = gBrowser.contentDocument.getElementById("innerFrame");
-
- // Submit the form in the inner page
- gBrowser.addEventListener("DOMContentLoaded", onInnerSubmitted, false);
- innerFrame.contentDocument.getElementById("postForm").submit();
- }
-
- function onInnerSubmitted() {
- gBrowser.removeEventListener("DOMContentLoaded", onInnerSubmitted, false);
-
- // Determine the path where the inner page will be saved
- destFile = Cc["@mozilla.org/file/directory_service;1"].
- getService(Ci.nsIProperties).get("TmpD", Ci.nsIFile);
- destFile.append("testsave_bug471962.html");
-
- // Call the internal save function defined in contentAreaUtils.js, while
- // replacing the file picker component with a mock implementation that
- // returns the path of the temporary file, and the download component with
- // an implementation that does not depend on the download manager
- registerMockFilePickerFactory();
- registerMockTransferFactory();
- var docToSave = innerFrame.contentDocument;
- // We call internalSave instead of saveDocument to bypass the history cache
- internalSave(docToSave.location.href, docToSave, null, null,
- docToSave.contentType, false, null, null,
- docToSave.referrer ? makeURI(docToSave.referrer) : null,
- false, null);
- unregisterMockTransferFactory();
- unregisterMockFilePickerFactory();
- }
-
- function onDownloadFinished(aSuccess) {
- // Abort the test if the download wasn't successful
- if (!aSuccess) {
- ok(false, "Unexpected failure, the inner frame couldn't be saved!");
- finish();
- return;
- }
-
- // Read the entire file
- var inputStream = Cc["@mozilla.org/network/file-input-stream;1"].
- createInstance(Ci.nsIFileInputStream);
- inputStream.init(destFile, -1, 0, 0);
- var scrInputStream = Cc["@mozilla.org/scriptableinputstream;1"].
- createInstance(Ci.nsIScriptableInputStream);
- scrInputStream.init(inputStream);
- var fileContents = scrInputStream.
- read(1048576); // The file is much shorter than 1 MB
- scrInputStream.close();
- inputStream.close();
-
- // Check if outer POST data is found
- const searchPattern = "inputfield=outer";
- ok(fileContents.indexOf(searchPattern) === -1,
- "The saved inner frame does not contain outer POST data");
-
- // Replace the current tab with a clean one
- gBrowser.addTab();
- gBrowser.removeCurrentTab();
-
- // Clean up and exit
- destFile.remove(false);
- finish();
- }
-
- // Start the test now that all the inner functions are defined
- startTest();
+ testRunner.runTest(FramePostData_TestGenerator);
}
copy from toolkit/content/tests/browser/Makefile.in
copy to toolkit/content/tests/browser/common/Makefile.in
--- a/toolkit/content/tests/browser/Makefile.in
+++ b/toolkit/content/tests/browser/common/Makefile.in
@@ -30,31 +30,29 @@
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
-DEPTH = ../../../..
+DEPTH = ../../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
-relativesrcdir = toolkit/content/tests/browser
+relativesrcdir = toolkit/content/tests/browser/common
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
-_BROWSER_FILES = \
- bug471962_testpage_inner.sjs \
- bug471962_testpage_outer.sjs \
- browser_bug471962.js \
+# If you add files here, add them to "_loadAll.js" too.
+_COMMON_FILES = \
+ _loadAll.js \
+ mockFilePicker.js \
+ mockObjects.js \
+ mockTransferForContinuing.js \
+ testRunner.js \
+ toolkitFunctions.js \
$(NULL)
-# browser_keyevents_during_autoscrolling.js cannot start the autoscrolling by
-# synthesizeMouse with middle button on linux, therefore, disable it temporarily
-ifneq ($(MOZ_WIDGET_TOOLKIT),gtk2)
-_BROWSER_FILES += browser_keyevents_during_autoscrolling.js
-endif
-
-libs:: $(_BROWSER_FILES)
+libs:: $(_COMMON_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/toolkit/content/tests/browser/common/_loadAll.js
@@ -0,0 +1,72 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla XUL Toolkit Testing Code.
+ *
+ * The Initial Developer of the Original Code is
+ * Paolo Amadini <http://www.amadzone.org/>.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**
+ * This file loads the entire library of testing objects and functions.
+ */
+
+// Define the shortcuts required by the included files.
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+const Cr = Components.results;
+const Cm = Components.manager;
+
+// Execute the following code while keeping the current scope clean.
+void(function (scriptScope) {
+ const kBaseUrl =
+ "chrome://mochikit/content/browser/toolkit/content/tests/browser/common/";
+
+ // If you add files here, add them to "Makefile.in" too.
+ var scriptNames = [
+ "mockObjects.js",
+ "testRunner.js",
+
+ // To be included after the files above.
+ "mockFilePicker.js",
+ "mockTransferForContinuing.js",
+ "toolkitFunctions.js",
+ ];
+
+ // Include all the required scripts.
+ var scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
+ getService(Ci.mozIJSSubScriptLoader);
+ for (let [, scriptName] in Iterator(scriptNames)) {
+ // Ensure that the subscript is loaded in the scope where this script is
+ // being executed, which is not necessarily the global scope.
+ scriptLoader.loadSubScript(kBaseUrl + scriptName, scriptScope);
+ }
+}(this));
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/toolkit/content/tests/browser/common/mockFilePicker.js
@@ -0,0 +1,116 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla XUL Toolkit Testing Code.
+ *
+ * The Initial Developer of the Original Code is
+ * Paolo Amadini <http://www.amadzone.org/>.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+var mockFilePickerSettings = {
+ /**
+ * File object pointing to the directory where the files will be saved.
+ * The files will be saved with the default name, and will be overwritten
+ * if they exist.
+ */
+ destDir: null,
+
+ /**
+ * Index of the filter to be returned by the file picker, or -1 to return
+ * the filter proposed by the caller.
+ */
+ filterIndex: -1
+};
+
+var mockFilePickerResults = {
+ /**
+ * File object corresponding to the last automatically selected file.
+ */
+ selectedFile: null,
+
+ /**
+ * Index of the filter that was set on the file picker by the caller.
+ */
+ proposedFilterIndex: -1
+};
+
+/**
+ * This file picker implementation uses the global settings defined in
+ * mockFilePickerSettings, and updates the mockFilePickerResults object
+ * when its "show" method is called.
+ */
+function MockFilePicker() { };
+MockFilePicker.prototype = {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIFilePicker]),
+ init: function(aParent, aTitle, aMode) { },
+ appendFilters: function(aFilterMask) { },
+ appendFilter: function(aTitle, aFilter) { },
+ defaultString: "",
+ defaultExtension: "",
+ filterIndex: 0,
+ displayDirectory: null,
+ file: null,
+ get fileURL() {
+ return Cc["@mozilla.org/network/io-service;1"].
+ getService(Ci.nsIIOService).newFileURI(this.file);
+ },
+ get files() {
+ throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+ },
+ show: function MFP_show() {
+ // Select the destination file with the specified default file name. If the
+ // default file name was never specified or was set to an empty string by
+ // the caller, ensure that a fallback file name is used.
+ this.file = mockFilePickerSettings.destDir.clone();
+ this.file.append(this.defaultString || "no_default_file_name");
+ // Store the current file picker settings for testing them later.
+ mockFilePickerResults.selectedFile = this.file.clone();
+ mockFilePickerResults.proposedFilterIndex = this.filterIndex;
+ // Select a different file filter if required.
+ if (mockFilePickerSettings.filterIndex != -1)
+ this.filterIndex = mockFilePickerSettings.filterIndex;
+ // Assume we overwrite the file if it exists.
+ return (this.file.exists() ?
+ Ci.nsIFilePicker.returnReplace :
+ Ci.nsIFilePicker.returnOK);
+ }
+};
+
+// Create an instance of a MockObjectRegisterer whose methods can be used to
+// temporarily replace the default "@mozilla.org/filepicker;1" object factory
+// with one that provides the mock implementation above. To activate the mock
+// object factory, call the "register" method. Starting from that moment, all
+// the file picker objects that are requested will be mock objects, until the
+// "unregister" method is called.
+var mockFilePickerRegisterer =
+ new MockObjectRegisterer("@mozilla.org/filepicker;1",
+ MockFilePicker);
new file mode 100644
--- /dev/null
+++ b/toolkit/content/tests/browser/common/mockObjects.js
@@ -0,0 +1,130 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla XUL Toolkit Testing Code.
+ *
+ * The Initial Developer of the Original Code is
+ * Paolo Amadini <http://www.amadzone.org/>.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**
+ * Allows registering a mock XPCOM component, that temporarily replaces the
+ * original one when an object implementing a given ContractID is requested
+ * using createInstance.
+ *
+ * @param aContractID
+ * The ContractID of the component to replace, for example
+ * "@mozilla.org/filepicker;1".
+ *
+ * @param aReplacementCtor
+ * The constructor function for the JavaScript object that will be
+ * created every time createInstance is called. This object must
+ * implement QueryInterface and provide the XPCOM interfaces required by
+ * the specified ContractID (for example
+ * Components.interfaces.nsIFilePicker).
+ */
+function MockObjectRegisterer(aContractID, aReplacementCtor)
+{
+ this._contractID = aContractID;
+ this._replacementCtor = aReplacementCtor;
+}
+
+MockObjectRegisterer.prototype = {
+ /**
+ * Replaces the current factory with one that returns a new mock object.
+ *
+ * After register() has been called, it is mandatory to call unregister() to
+ * restore the original component. Usually, you should use a try-catch block
+ * to ensure that unregister() is called.
+ */
+ register: function MOR_register() {
+ if (this._originalFactory)
+ throw new Exception("Invalid object state when calling register()");
+
+ // Define a factory that creates a new object using the given constructor.
+ var providedConstructor = this._replacementCtor;
+ this._mockFactory = {
+ createInstance: function MF_createInstance(aOuter, aIid) {
+ if (aOuter != null)
+ throw Cr.NS_ERROR_NO_AGGREGATION;
+ return new providedConstructor().QueryInterface(aIid);
+ }
+ };
+
+ // Preserve the original factory.
+ this._originalFactory = Cm.getClassObjectByContractID(this._contractID,
+ Ci.nsIFactory);
+
+ // Replace the original factory with the mock one.
+ var classInfo = this._originalFactory.QueryInterface(Ci.nsIClassInfo);
+ var componentRegistrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
+ componentRegistrar.registerFactory(classInfo.classID,
+ "Mock " + classInfo.classDescription,
+ this._contractID,
+ this._mockFactory);
+ },
+
+ /**
+ * Restores the original factory.
+ */
+ unregister: function MOR_unregister() {
+ if (!this._originalFactory)
+ throw new Exception("Invalid object state when calling unregister()");
+
+ // Free references to the mock factory.
+ var classInfo = this._originalFactory.QueryInterface(Ci.nsIClassInfo);
+ var componentRegistrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
+ componentRegistrar.unregisterFactory(classInfo.classID,
+ this._mockFactory);
+
+ // Restore the original factory.
+ componentRegistrar.registerFactory(classInfo.classID,
+ classInfo.classDescription,
+ this._contractID,
+ this._originalFactory);
+
+ // Allow registering a mock factory again later.
+ this._originalFactory = null;
+ this._mockFactory = null;
+ },
+
+ // --- Private methods and properties ---
+
+ /**
+ * The original nsIFactory for the component being replaced, or null when the
+ * original component is in place.
+ */
+ _originalFactory: null,
+
+ /**
+ * The nsIFactory that was automatically generated by this object.
+ */
+ _mockFactory: null
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/content/tests/browser/common/mockTransferForContinuing.js
@@ -0,0 +1,107 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla XUL Toolkit Testing Code.
+ *
+ * The Initial Developer of the Original Code is
+ * Paolo Amadini <http://www.amadzone.org/>.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+/**
+ * This "transfer" object implementation continues the currently running test
+ * when the download is completed, reporting true for success or false for
+ * failure as the first argument of the testRunner.continueTest function.
+ */
+function MockTransferForContinuing()
+{
+ this._downloadIsSuccessful = true;
+}
+
+MockTransferForContinuing.prototype = {
+ QueryInterface: XPCOMUtils.generateQI([
+ Ci.nsIWebProgressListener,
+ Ci.nsIWebProgressListener2,
+ Ci.nsITransfer,
+ ]),
+
+ //////////////////////////////////////////////////////////////////////////////
+ //// nsIWebProgressListener
+
+ onStateChange: function MTFC_onStateChange(aWebProgress, aRequest,
+ aStateFlags, aStatus) {
+ // If at least one notification reported an error, the download failed.
+ if (!Components.isSuccessCode(aStatus))
+ this._downloadIsSuccessful = false;
+
+ // If the download is finished
+ if ((aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) &&
+ (aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK))
+ // Continue the test, reporting the success or failure condition.
+ testRunner.continueTest(this._downloadIsSuccessful);
+ },
+ onProgressChange: function(aWebProgress, aRequest, aCurSelfProgress,
+ aMaxSelfProgress, aCurTotalProgress,
+ aMaxTotalProgress) { },
+ onLocationChange: function(aWebProgress, aRequest, aLocation) { },
+ onStatusChange: function MTFC_onStatusChange(aWebProgress, aRequest, aStatus,
+ aMessage) {
+ // If at least one notification reported an error, the download failed.
+ if (!Components.isSuccessCode(aStatus))
+ this._downloadIsSuccessful = false;
+ },
+ onSecurityChange: function(aWebProgress, aRequest, aState) { },
+
+ //////////////////////////////////////////////////////////////////////////////
+ //// nsIWebProgressListener2
+
+ onProgressChange64: function(aWebProgress, aRequest, aCurSelfProgress,
+ aMaxSelfProgress, aCurTotalProgress,
+ aMaxTotalProgress) { },
+ onRefreshAttempted: function(aWebProgress, aRefreshURI, aMillis,
+ aSameURI) { },
+
+ //////////////////////////////////////////////////////////////////////////////
+ //// nsITransfer
+
+ init: function(aSource, aTarget, aDisplayName, aMIMEInfo, aStartTime,
+ aTempFile, aCancelable) { }
+};
+
+// Create an instance of a MockObjectRegisterer whose methods can be used to
+// temporarily replace the default "@mozilla.org/transfer;1" object factory with
+// one that provides the mock implementation above. To activate the mock object
+// factory, call the "register" method. Starting from that moment, all the
+// transfer objects that are requested will be mock objects, until the
+// "unregister" method is called.
+var mockTransferForContinuingRegisterer =
+ new MockObjectRegisterer("@mozilla.org/transfer;1",
+ MockTransferForContinuing);
new file mode 100644
--- /dev/null
+++ b/toolkit/content/tests/browser/common/testRunner.js
@@ -0,0 +1,171 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla XUL Toolkit Testing Code.
+ *
+ * The Initial Developer of the Original Code is
+ * Paolo Amadini <http://www.amadzone.org/>.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**
+ * Runs a browser-chrome test defined through a generator function.
+ *
+ * This object is a singleton, initialized automatically when this script is
+ * included. Every browser-chrome test file includes a new copy of this script.
+ */
+var testRunner = {
+ _testIterator: null,
+ _lastEventResult: undefined,
+ _testRunning: false,
+ _eventRaised: false,
+
+ // --- Main test runner ---
+
+ /**
+ * Runs the test described by the provided generator function asynchronously.
+ *
+ * Calling yield in the generator will cause it to wait until continueTest is
+ * called. The parameter provided to continueTest will be the return value of
+ * the yield operator.
+ *
+ * @param aGenerator
+ * Test generator function. The function will be called with no
+ * arguments to retrieve its iterator.
+ */
+ runTest: function TR_runTest(aGenerator) {
+ waitForExplicitFinish();
+ testRunner._testIterator = aGenerator();
+ testRunner.continueTest();
+ },
+
+ /**
+ * Continues the currently running test.
+ *
+ * @param aEventResult
+ * This will be the return value of the yield operator in the test.
+ */
+ continueTest: function TR_continueTest(aEventResult) {
+ // Store the last event result, or set it to undefined.
+ testRunner._lastEventResult = aEventResult;
+
+ // Never reenter the main loop, but notify that the event has been raised.
+ if (testRunner._testRunning) {
+ testRunner._eventRaised = true;
+ return;
+ }
+
+ // Enter the main iteration loop.
+ testRunner._testRunning = true;
+ try {
+ do {
+ // Call the iterator, but don't leave the loop if the expected event is
+ // raised during the execution of the generator.
+ testRunner._eventRaised = false;
+ testRunner._testIterator.send(testRunner._lastEventResult);
+ } while (testRunner._eventRaised);
+ }
+ catch (e) {
+ // This block catches exceptions raised by the generator, including the
+ // normal StopIteration exception. Unexpected exceptions are reported as
+ // test failures.
+ if (!(e instanceof StopIteration))
+ ok(false, e);
+ // In any case, stop the tests in this file.
+ finish();
+ }
+
+ // Wait for the next event or finish.
+ testRunner._testRunning = false;
+ },
+
+ // --- Auxiliary functions ---
+
+ _isFirstEvent: true,
+
+ /**
+ * Continues the running test every second time this function is called.
+ */
+ continueAfterTwoEvents: function TR_continueAfterTwoEvents() {
+ if (testRunner._isFirstEvent) {
+ testRunner._isFirstEvent = false;
+ return;
+ }
+ testRunner._isFirstEvent = true;
+ testRunner.continueTest();
+ },
+
+ // --- Support for multiple tests ---
+
+ /**
+ * This generator function yields each value obtained by the given generators,
+ * in the order they are specified in the array.
+ *
+ * @param aArrayOfGenerators
+ * Array of generator functions. The functions will be called with no
+ * arguments to retrieve their iterators.
+ *
+ * @return
+ * The iterator generated by this generator function.
+ */
+ chainGenerator: function TR_chainGenerator(aArrayOfGenerators) {
+ // Obtain each iterator in turn.
+ for (let [, curGenerator] in Iterator(aArrayOfGenerators)) {
+ var curIterator = curGenerator();
+ // Call each iterator until it completes, while ensuring propagation of
+ // both the the values provided to and returned by the yield operator.
+ try {
+ var value = undefined;
+ while (true) {
+ value = yield curIterator.send(value);
+ }
+ }
+ catch(e if e instanceof StopIteration) {
+ // The iterator has finished providing all the values.
+ }
+ }
+ },
+
+ /**
+ * Runs multiple tests.
+ *
+ * This function operates asynchronously. Because of this, it should be called
+ * by the last line of a test script.
+ *
+ * @param aArrayOfTestGenerators
+ * Array containing references to the test generator functions to run.
+ *
+ * @see #runTest
+ */
+ runTests: function TR_runTests(aArrayOfTestGenerators) {
+ testRunner.runTest(function() {
+ return testRunner.chainGenerator(aArrayOfTestGenerators);
+ });
+ }
+};
new file mode 100644
--- /dev/null
+++ b/toolkit/content/tests/browser/common/toolkitFunctions.js
@@ -0,0 +1,114 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla XUL Toolkit Testing Code.
+ *
+ * The Initial Developer of the Original Code is
+ * Paolo Amadini <http://www.amadzone.org/>.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**
+ * Provides a temporary save directory.
+ *
+ * @return
+ * nsIFile pointing to the new or existing directory.
+ */
+function createTemporarySaveDirectory() {
+ var saveDir = Cc["@mozilla.org/file/directory_service;1"].
+ getService(Ci.nsIProperties).get("TmpD", Ci.nsIFile);
+ saveDir.append("testsavedir");
+ if (!saveDir.exists())
+ saveDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
+ return saveDir;
+}
+
+/**
+ * Calls the provided save function while replacing the file picker component
+ * with a mock implementation that returns a temporary file path and custom
+ * filters, and the download component with an implementation that does not
+ * depend on the download manager.
+ *
+ * @param aSaveFunction
+ * The function to call. This is usually the subject of the entire test
+ * being run.
+ */
+function callSaveWithMockObjects(aSaveFunction) {
+ // Call the provided function while the mock object factories are in place and
+ // ensure that, even in case of exceptions during the function's execution,
+ // the mock object factories are unregistered before proceeding with the other
+ // tests in the suite.
+ mockFilePickerRegisterer.register();
+ try {
+ mockTransferForContinuingRegisterer.register();
+ try {
+ aSaveFunction();
+ }
+ finally {
+ mockTransferForContinuingRegisterer.unregister();
+ }
+ }
+ finally {
+ mockFilePickerRegisterer.unregister();
+ }
+}
+
+/**
+ * Reads the contents of the provided short file (up to 1 MiB).
+ *
+ * @param aFile
+ * nsIFile object pointing to the file to be read.
+ *
+ * @return
+ * String containing the raw octets read from the file.
+ */
+function readShortFile(aFile) {
+ var inputStream = Cc["@mozilla.org/network/file-input-stream;1"].
+ createInstance(Ci.nsIFileInputStream);
+ inputStream.init(aFile, -1, 0, 0);
+ try {
+ var scrInputStream = Cc["@mozilla.org/scriptableinputstream;1"].
+ createInstance(Ci.nsIScriptableInputStream);
+ scrInputStream.init(inputStream);
+ try {
+ // Assume that the file is much shorter than 1 MiB.
+ return scrInputStream.read(1048576);
+ }
+ finally {
+ // Close the scriptable stream after reading, even if the operation
+ // failed.
+ scrInputStream.close();
+ }
+ }
+ finally {
+ // Close the stream after reading, if it is still open, even if the read
+ // operation failed.
+ inputStream.close();
+ }
+}
copy from toolkit/content/tests/browser/Makefile.in
copy to toolkit/content/tests/browser/data/Makefile.in
--- a/toolkit/content/tests/browser/Makefile.in
+++ b/toolkit/content/tests/browser/data/Makefile.in
@@ -30,31 +30,24 @@
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
-DEPTH = ../../../..
+DEPTH = ../../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
-relativesrcdir = toolkit/content/tests/browser
+relativesrcdir = toolkit/content/tests/browser/data
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
-_BROWSER_FILES = \
- bug471962_testpage_inner.sjs \
- bug471962_testpage_outer.sjs \
- browser_bug471962.js \
+_DATA_FILES = \
+ post_form_inner.sjs \
+ post_form_outer.sjs \
$(NULL)
-# browser_keyevents_during_autoscrolling.js cannot start the autoscrolling by
-# synthesizeMouse with middle button on linux, therefore, disable it temporarily
-ifneq ($(MOZ_WIDGET_TOOLKIT),gtk2)
-_BROWSER_FILES += browser_keyevents_during_autoscrolling.js
-endif
-
-libs:: $(_BROWSER_FILES)
+libs:: $(_DATA_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
rename from toolkit/content/tests/browser/bug471962_testpage_inner.sjs
rename to toolkit/content/tests/browser/data/post_form_inner.sjs
--- a/toolkit/content/tests/browser/bug471962_testpage_inner.sjs
+++ b/toolkit/content/tests/browser/data/post_form_inner.sjs
@@ -48,17 +48,17 @@ function handleRequest(request, response
Inner POST data: ';
var bodyStream = new BinaryInputStream(request.bodyInputStream);
var bytes = [], avail = 0;
while ((avail = bodyStream.available()) > 0)
body += String.fromCharCode.apply(String, bodyStream.readByteArray(avail));
body +=
- '<form id="postForm" action="bug471962_testpage_inner.sjs" method="post">\
+ '<form id="postForm" action="post_form_inner.sjs" method="post">\
<input type="text" name="inputfield" value="inner">\
<input type="submit">\
</form>\
</body>\
</html>';
response.bodyOutputStream.write(body, body.length);
}
rename from toolkit/content/tests/browser/bug471962_testpage_outer.sjs
rename to toolkit/content/tests/browser/data/post_form_outer.sjs
--- a/toolkit/content/tests/browser/bug471962_testpage_outer.sjs
+++ b/toolkit/content/tests/browser/data/post_form_outer.sjs
@@ -48,20 +48,20 @@ function handleRequest(request, response
Outer POST data: ';
var bodyStream = new BinaryInputStream(request.bodyInputStream);
var bytes = [], avail = 0;
while ((avail = bodyStream.available()) > 0)
body += String.fromCharCode.apply(String, bodyStream.readByteArray(avail));
body +=
- '<form id="postForm" action="bug471962_testpage_outer.sjs" method="post">\
+ '<form id="postForm" action="post_form_outer.sjs" method="post">\
<input type="text" name="inputfield" value="outer">\
<input type="submit">\
</form>\
\
- <iframe id="innerFrame" src="bug471962_testpage_inner.sjs" width="400" height="200">\
+ <iframe id="innerFrame" src="post_form_inner.sjs" width="400" height="200">\
\
</body>\
</html>';
response.bodyOutputStream.write(body, body.length);
}