diff --git a/browser/extensions/formautofill/test/unit/head.js b/browser/extensions/formautofill/test/unit/head.js index 6e4dd22d3752..e384368ac886 100644 --- a/browser/extensions/formautofill/test/unit/head.js +++ b/browser/extensions/formautofill/test/unit/head.js @@ -15,7 +15,6 @@ Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/NetUtil.jsm"); Cu.import("resource://gre/modules/ObjectUtils.jsm"); Cu.import("resource://gre/modules/FormLikeFactory.jsm"); -Cu.import("resource://testing-common/FileTestUtils.jsm"); Cu.import("resource://testing-common/MockDocument.jsm"); Cu.import("resource://testing-common/TestUtils.jsm"); @@ -52,10 +51,43 @@ if (!extensionDir.exists()) { } Components.manager.addBootstrappedManifestLocation(extensionDir); -// Returns a reference to a temporary file that is guaranteed not to exist and -// is cleaned up later. See FileTestUtils.getTempFile for details. +// While the previous test file should have deleted all the temporary files it +// used, on Windows these might still be pending deletion on the physical file +// system. Thus, start from a new base number every time, to make a collision +// with a file that is still pending deletion highly unlikely. +let gFileCounter = Math.floor(Math.random() * 1000000); + +/** + * Returns a reference to a temporary file, that is guaranteed not to exist, and + * to have never been created before. + * + * @param {string} leafName + * Suggested leaf name for the file to be created. + * + * @returns {nsIFile} pointing to a non-existent file in a temporary directory. + * + * @note It is not enough to delete the file if it exists, or to delete the file + * after calling nsIFile.createUnique, because on Windows the delete + * operation in the file system may still be pending, preventing a new + * file with the same name to be created. + */ function getTempFile(leafName) { - return FileTestUtils.getTempFile(leafName); + // Prepend a serial number to the extension in the suggested leaf name. + let [base, ext] = DownloadPaths.splitBaseNameAndExtension(leafName); + let finalLeafName = base + "-" + gFileCounter + ext; + gFileCounter++; + + // Get a file reference under the temporary directory for this test file. + let file = FileUtils.getFile("TmpD", [finalLeafName]); + do_check_false(file.exists()); + + do_register_cleanup(function() { + if (file.exists()) { + file.remove(false); + } + }); + + return file; } async function initProfileStorage(fileName, records, collectionName = "addresses") { diff --git a/netwerk/test/unit/test_backgroundfilesaver.js b/netwerk/test/unit/test_backgroundfilesaver.js index a55eb9e0840d..21f860e2ee48 100644 --- a/netwerk/test/unit/test_backgroundfilesaver.js +++ b/netwerk/test/unit/test_backgroundfilesaver.js @@ -18,8 +18,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "Services", "resource://gre/modules/Services.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "FileTestUtils", - "resource://testing-common/FileTestUtils.jsm"); const BackgroundFileSaverOutputStream = Components.Constructor( "@mozilla.org/network/background-file-saver;1?mode=outputstream", @@ -63,11 +61,17 @@ const TEST_DATA_LONG = new Array(1 + DESIRED_LENGTH / 256).join(TEST_256_CHARS); do_check_eq(TEST_DATA_LONG.length, DESIRED_LENGTH); /** - * Returns a reference to a temporary file that is guaranteed not to exist and - * is cleaned up later. See FileTestUtils.getTempFile for details. + * Returns a reference to a temporary file. If the file is then created, it + * will be removed when tests in this file finish. */ -function getTempFile(leafName) { - return FileTestUtils.getTempFile(leafName); +function getTempFile(aLeafName) { + let file = FileUtils.getFile("TmpD", [aLeafName]); + do_register_cleanup(function GTF_cleanup() { + if (file.exists()) { + file.remove(false); + } + }); + return file; } /** diff --git a/netwerk/test/unit/test_signature_extraction.js b/netwerk/test/unit/test_signature_extraction.js index 66ab1a08b2f7..7843d377d4dd 100644 --- a/netwerk/test/unit/test_signature_extraction.js +++ b/netwerk/test/unit/test_signature_extraction.js @@ -17,8 +17,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "FileUtils", "resource://gre/modules/FileUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "FileTestUtils", - "resource://testing-common/FileTestUtils.jsm"); const BackgroundFileSaverOutputStream = Components.Constructor( "@mozilla.org/network/background-file-saver;1?mode=outputstream", @@ -32,11 +30,17 @@ const StringInputStream = Components.Constructor( const TEST_FILE_NAME_1 = "test-backgroundfilesaver-1.txt"; /** - * Returns a reference to a temporary file that is guaranteed not to exist and - * is cleaned up later. See FileTestUtils.getTempFile for details. + * Returns a reference to a temporary file. If the file is then created, it + * will be removed when tests in this file finish. */ -function getTempFile(leafName) { - return FileTestUtils.getTempFile(leafName); +function getTempFile(aLeafName) { + let file = FileUtils.getFile("TmpD", [aLeafName]); + do_register_cleanup(function GTF_cleanup() { + if (file.exists()) { + file.remove(false); + } + }); + return file; } /** diff --git a/testing/modules/FileTestUtils.jsm b/testing/modules/FileTestUtils.jsm deleted file mode 100644 index 3712082b4dda..000000000000 --- a/testing/modules/FileTestUtils.jsm +++ /dev/null @@ -1,74 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * Provides testing functions dealing with local files and their contents. - */ - -"use strict"; - -this.EXPORTED_SYMBOLS = [ - "FileTestUtils", -]; - -const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; - -Cu.import("resource://gre/modules/AsyncShutdown.jsm", this); -Cu.import("resource://gre/modules/DownloadPaths.jsm", this); -Cu.import("resource://gre/modules/FileUtils.jsm", this); -Cu.import("resource://gre/modules/XPCOMUtils.jsm", this); -Cu.import("resource://testing-common/Assert.jsm", this); - -let gFileCounter = 1; - -this.FileTestUtils = { - /** - * Returns a reference to a temporary file that is guaranteed not to exist and - * to have never been created before. If a file or a directory with this name - * is created by the test, it will be deleted when all tests terminate. - * - * @param suggestedName [optional] - * Any extension on this template file name will be preserved. If this - * is unspecified, the returned file name will have the generic ".dat" - * extension, which may indicate either a binary or a text data file. - * - * @return nsIFile pointing to a non-existent file in a temporary directory. - * - * @note It is not enough to delete the file if it exists, or to delete the - * file after calling nsIFile.createUnique, because on Windows the - * delete operation in the file system may still be pending, preventing - * a new file with the same name to be created. - */ - getTempFile(suggestedName = "test.dat") { - // Prepend a serial number to the extension in the suggested leaf name. - let [base, ext] = DownloadPaths.splitBaseNameAndExtension(suggestedName); - let leafName = base + "-" + gFileCounter + ext; - gFileCounter++; - - // Get a file reference under the temporary directory for this test file. - let file = this._globalTemporaryDirectory.clone(); - file.append(leafName); - Assert.ok(!file.exists(), "Sanity check the temporary file doesn't exist."); - return file; - }, -}; - -/** - * Returns a reference to a global temporary directory that will be deleted - * when all tests terminate. - */ -XPCOMUtils.defineLazyGetter(FileTestUtils, "_globalTemporaryDirectory", () => { - // While previous test runs should have deleted their temporary directories, - // on Windows they might still be pending deletion on the physical file - // system. This makes a simple nsIFile.createUnique call unreliable, and we - // have to use a random number to make a collision unlikely. - let randomNumber = Math.floor(Math.random() * 1000000); - let dir = FileUtils.getFile("TmpD", ["testdir-" + randomNumber]); - dir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); - AsyncShutdown.profileBeforeChange.addBlocker("Removing test files", () => { - // Note that this may fail if any test leaves inaccessible files behind. - dir.remove(true); - }); - return dir; -}); diff --git a/testing/modules/TestUtils.jsm b/testing/modules/TestUtils.jsm index b24339dc8f1f..bd356341b18b 100644 --- a/testing/modules/TestUtils.jsm +++ b/testing/modules/TestUtils.jsm @@ -2,18 +2,13 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -/** - * Contains a limited number of testing functions that are commonly used in a - * wide variety of situations, for example waiting for an event loop tick or an - * observer notification. +/* + * This module implements a number of utilities useful for testing. * - * More complex functions are likely to belong to a separate test-only module. - * Examples include Assert.jsm for generic assertions, FileTestUtils.jsm to work - * with local files and their contents, and BrowserTestUtils.jsm to work with - * browser windows and tabs. - * - * Individual components also offer testing functions to other components, for - * example LoginTestUtils.jsm. + * Additions to this module should be generic and useful to testing multiple + * features. Utilities only useful to a sepcific testing framework should live + * in a module specific to that framework, such as BrowserTestUtils.jsm in the + * case of mochitest-browser-chrome. */ "use strict"; diff --git a/testing/modules/moz.build b/testing/modules/moz.build index 88b1ad089aa0..c5cc79651c61 100644 --- a/testing/modules/moz.build +++ b/testing/modules/moz.build @@ -13,7 +13,6 @@ TESTING_JS_MODULES += [ 'AppInfo.jsm', 'Assert.jsm', 'CoverageUtils.jsm', - 'FileTestUtils.jsm', 'MockRegistrar.jsm', 'sinon-2.3.2.js', 'StructuredLog.jsm', diff --git a/toolkit/components/jsdownloads/test/browser/head.js b/toolkit/components/jsdownloads/test/browser/head.js index 49b4d58c9c86..ece04e766657 100644 --- a/toolkit/components/jsdownloads/test/browser/head.js +++ b/toolkit/components/jsdownloads/test/browser/head.js @@ -30,19 +30,48 @@ XPCOMUtils.defineLazyModuleGetter(this, "HttpServer", "resource://testing-common/httpd.js"); XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "FileTestUtils", - "resource://testing-common/FileTestUtils.jsm"); const TEST_TARGET_FILE_NAME_PDF = "test-download.pdf"; // Support functions +// While the previous test file should have deleted all the temporary files it +// used, on Windows these might still be pending deletion on the physical file +// system. Thus, start from a new base number every time, to make a collision +// with a file that is still pending deletion highly unlikely. +var gFileCounter = Math.floor(Math.random() * 1000000); + /** - * Returns a reference to a temporary file that is guaranteed not to exist and - * is cleaned up later. See FileTestUtils.getTempFile for details. + * Returns a reference to a temporary file, that is guaranteed not to exist, and + * to have never been created before. + * + * @param aLeafName + * Suggested leaf name for the file to be created. + * + * @return nsIFile pointing to a non-existent file in a temporary directory. + * + * @note It is not enough to delete the file if it exists, or to delete the file + * after calling nsIFile.createUnique, because on Windows the delete + * operation in the file system may still be pending, preventing a new + * file with the same name to be created. */ -function getTempFile(leafName) { - return FileTestUtils.getTempFile(leafName); +function getTempFile(aLeafName) { + // Prepend a serial number to the extension in the suggested leaf name. + let [base, ext] = DownloadPaths.splitBaseNameAndExtension(aLeafName); + let leafName = base + "-" + gFileCounter + ext; + gFileCounter++; + + // Get a file reference under the temporary directory for this test file. + let file = FileUtils.getFile("TmpD", [leafName]); + ok(!file.exists(), "Temp file does not exist"); + + registerCleanupFunction(function() { + if (file.exists()) { + file.remove(false); + } + }); + + return file; } function promiseBrowserLoaded(browser) { diff --git a/toolkit/components/jsdownloads/test/unit/head.js b/toolkit/components/jsdownloads/test/unit/head.js index e980f4a05ca4..608287909131 100644 --- a/toolkit/components/jsdownloads/test/unit/head.js +++ b/toolkit/components/jsdownloads/test/unit/head.js @@ -37,8 +37,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "Services", "resource://gre/modules/Services.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "FileTestUtils", - "resource://testing-common/FileTestUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "MockRegistrar", "resource://testing-common/MockRegistrar.jsm"); @@ -103,12 +101,54 @@ function httpUrl(aFileName) { aFileName; } +// While the previous test file should have deleted all the temporary files it +// used, on Windows these might still be pending deletion on the physical file +// system. Thus, start from a new base number every time, to make a collision +// with a file that is still pending deletion highly unlikely. +var gFileCounter = Math.floor(Math.random() * 1000000); + /** - * Returns a reference to a temporary file that is guaranteed not to exist and - * is cleaned up later. See FileTestUtils.getTempFile for details. + * Returns a reference to a temporary file, that is guaranteed not to exist, and + * to have never been created before. + * + * @param aLeafName + * Suggested leaf name for the file to be created. + * + * @return nsIFile pointing to a non-existent file in a temporary directory. + * + * @note It is not enough to delete the file if it exists, or to delete the file + * after calling nsIFile.createUnique, because on Windows the delete + * operation in the file system may still be pending, preventing a new + * file with the same name to be created. */ -function getTempFile(leafName) { - return FileTestUtils.getTempFile(leafName); +function getTempFile(aLeafName) { + // Prepend a serial number to the extension in the suggested leaf name. + let [base, ext] = DownloadPaths.splitBaseNameAndExtension(aLeafName); + let leafName = base + "-" + gFileCounter + ext; + gFileCounter++; + + // Get a file reference under the temporary directory for this test file. + let file = FileUtils.getFile("TmpD", [leafName]); + do_check_false(file.exists()); + + do_register_cleanup(function() { + try { + file.remove(false); + } catch (e) { + if (!(e instanceof Components.Exception && + (e.result == Cr.NS_ERROR_FILE_ACCESS_DENIED || + e.result == Cr.NS_ERROR_FILE_TARGET_DOES_NOT_EXIST || + e.result == Cr.NS_ERROR_FILE_NOT_FOUND))) { + throw e; + } + // On Windows, we may get an access denied error if the file existed before, + // and was recently deleted. + // Don't bother checking file.exists() as that may also cause an access + // denied error. + } + }); + + return file; } /** diff --git a/toolkit/components/jsdownloads/test/unit/test_DownloadPaths.js b/toolkit/components/jsdownloads/test/unit/test_DownloadPaths.js index 70778bf98088..5b86eabe10d2 100644 --- a/toolkit/components/jsdownloads/test/unit/test_DownloadPaths.js +++ b/toolkit/components/jsdownloads/test/unit/test_DownloadPaths.js @@ -7,6 +7,21 @@ Cu.import("resource://gre/modules/AppConstants.jsm"); +/** + * Provides a temporary save directory. + * + * @returns 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, 0o755); + } + return saveDir; +} + function testSanitize(leafName, expectedLeafName) { do_check_eq(DownloadPaths.sanitize(leafName), expectedLeafName); } @@ -116,36 +131,39 @@ add_task(async function test_splitBaseNameAndExtension() { }); add_task(async function test_createNiceUniqueFile() { - var destDir = FileTestUtils.getTempFile("destdir"); - destDir.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); - - // Single extension. - var tempFile = destDir.clone(); - tempFile.append("test.txt"); - testCreateNiceUniqueFile(tempFile, "test.txt"); - testCreateNiceUniqueFile(tempFile, "test(1).txt"); - testCreateNiceUniqueFile(tempFile, "test(2).txt"); - - // Double extension. - tempFile.leafName = "test.tar.gz"; - testCreateNiceUniqueFile(tempFile, "test.tar.gz"); - testCreateNiceUniqueFile(tempFile, "test(1).tar.gz"); - testCreateNiceUniqueFile(tempFile, "test(2).tar.gz"); - - // Test automatic shortening of long file names. We don't know exactly how - // many characters are removed, because it depends on the name of the folder - // where the file is located. - tempFile.leafName = new Array(256).join("T") + ".txt"; - var newFile = DownloadPaths.createNiceUniqueFile(tempFile); - do_check_true(newFile.leafName.length < tempFile.leafName.length); - do_check_eq(newFile.leafName.slice(-4), ".txt"); - - // Creating a valid file name from an invalid one is not always possible. - tempFile.append("file-under-long-directory.txt"); + var destDir = createTemporarySaveDirectory(); try { - DownloadPaths.createNiceUniqueFile(tempFile); - do_throw("Exception expected with a long parent directory name."); - } catch (e) { - // An exception is expected, but we don't know which one exactly. + // Single extension. + var tempFile = destDir.clone(); + tempFile.append("test.txt"); + testCreateNiceUniqueFile(tempFile, "test.txt"); + testCreateNiceUniqueFile(tempFile, "test(1).txt"); + testCreateNiceUniqueFile(tempFile, "test(2).txt"); + + // Double extension. + tempFile.leafName = "test.tar.gz"; + testCreateNiceUniqueFile(tempFile, "test.tar.gz"); + testCreateNiceUniqueFile(tempFile, "test(1).tar.gz"); + testCreateNiceUniqueFile(tempFile, "test(2).tar.gz"); + + // Test automatic shortening of long file names. We don't know exactly how + // many characters are removed, because it depends on the name of the folder + // where the file is located. + tempFile.leafName = new Array(256).join("T") + ".txt"; + var newFile = DownloadPaths.createNiceUniqueFile(tempFile); + do_check_true(newFile.leafName.length < tempFile.leafName.length); + do_check_eq(newFile.leafName.slice(-4), ".txt"); + + // Creating a valid file name from an invalid one is not always possible. + tempFile.append("file-under-long-directory.txt"); + try { + DownloadPaths.createNiceUniqueFile(tempFile); + do_throw("Exception expected with a long parent directory name."); + } catch (e) { + // An exception is expected, but we don't know which one exactly. + } + } finally { + // Clean up the temporary directory. + destDir.remove(true); } }); diff --git a/toolkit/components/passwordmgr/test/unit/head.js b/toolkit/components/passwordmgr/test/unit/head.js index 2905f333247c..cd46a4f2ba63 100644 --- a/toolkit/components/passwordmgr/test/unit/head.js +++ b/toolkit/components/passwordmgr/test/unit/head.js @@ -12,7 +12,6 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/LoginRecipes.jsm"); Cu.import("resource://gre/modules/LoginHelper.jsm"); -Cu.import("resource://testing-common/FileTestUtils.jsm"); Cu.import("resource://testing-common/LoginTestUtils.jsm"); Cu.import("resource://testing-common/MockDocument.jsm"); @@ -41,12 +40,47 @@ function run_test() // Global helpers +// Some of these functions are already implemented in other parts of the source +// tree, see bug 946708 about sharing more code. + +// While the previous test file should have deleted all the temporary files it +// used, on Windows these might still be pending deletion on the physical file +// system. Thus, start from a new base number every time, to make a collision +// with a file that is still pending deletion highly unlikely. +let gFileCounter = Math.floor(Math.random() * 1000000); + /** - * Returns a reference to a temporary file that is guaranteed not to exist and - * is cleaned up later. See FileTestUtils.getTempFile for details. + * Returns a reference to a temporary file, that is guaranteed not to exist, and + * to have never been created before. + * + * @param aLeafName + * Suggested leaf name for the file to be created. + * + * @return nsIFile pointing to a non-existent file in a temporary directory. + * + * @note It is not enough to delete the file if it exists, or to delete the file + * after calling nsIFile.createUnique, because on Windows the delete + * operation in the file system may still be pending, preventing a new + * file with the same name to be created. */ -function getTempFile(leafName) { - return FileTestUtils.getTempFile(leafName); +function getTempFile(aLeafName) +{ + // Prepend a serial number to the extension in the suggested leaf name. + let [base, ext] = DownloadPaths.splitBaseNameAndExtension(aLeafName); + let leafName = base + "-" + gFileCounter + ext; + gFileCounter++; + + // Get a file reference under the temporary directory for this test file. + let file = FileUtils.getFile("TmpD", [leafName]); + do_check_false(file.exists()); + + do_register_cleanup(function() { + if (file.exists()) { + file.remove(false); + } + }); + + return file; } const RecipeHelpers = { diff --git a/toolkit/components/reputationservice/test/unit/test_app_rep_windows.js b/toolkit/components/reputationservice/test/unit/test_app_rep_windows.js index 96a107bedea1..f69d03022d28 100644 --- a/toolkit/components/reputationservice/test/unit/test_app_rep_windows.js +++ b/toolkit/components/reputationservice/test/unit/test_app_rep_windows.js @@ -16,8 +16,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "FileUtils", "resource://gre/modules/FileUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "FileTestUtils", - "resource://testing-common/FileTestUtils.jsm"); const BackgroundFileSaverOutputStream = Components.Constructor( "@mozilla.org/network/background-file-saver;1?mode=outputstream", @@ -39,6 +37,20 @@ var gHttpServer = null; const appRepURLPref = "browser.safebrowsing.downloads.remote.url"; const remoteEnabledPref = "browser.safebrowsing.downloads.remote.enabled"; +/** + * Returns a reference to a temporary file. If the file is then created, it + * will be removed when tests in this file finish. + */ +function getTempFile(aLeafName) { + let file = FileUtils.getFile("TmpD", [aLeafName]); + do_register_cleanup(function GTF_cleanup() { + if (file.exists()) { + file.remove(false); + } + }); + return file; +} + function readFileToString(aFilename) { let f = do_get_file(aFilename); let stream = Cc["@mozilla.org/network/file-input-stream;1"] @@ -306,7 +318,7 @@ add_task(async function test_signature_whitelists() { "http://localhost:4444/throw"); // Use BackgroundFileSaver to extract the signature on Windows. - let destFile = FileTestUtils.getTempFile(TEST_FILE_NAME_1); + let destFile = getTempFile(TEST_FILE_NAME_1); let data = readFileToString("data/signed_win.exe"); let saver = new BackgroundFileSaverOutputStream(); diff --git a/toolkit/modules/tests/xpcshell/test_JSONFile.js b/toolkit/modules/tests/xpcshell/test_JSONFile.js index 0f22496f708b..d10f01f4303a 100644 --- a/toolkit/modules/tests/xpcshell/test_JSONFile.js +++ b/toolkit/modules/tests/xpcshell/test_JSONFile.js @@ -15,15 +15,40 @@ XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "JSONFile", "resource://gre/modules/JSONFile.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "FileTestUtils", - "resource://testing-common/FileTestUtils.jsm"); + +let gFileCounter = Math.floor(Math.random() * 1000000); /** - * Returns a reference to a temporary file that is guaranteed not to exist and - * is cleaned up later. See FileTestUtils.getTempFile for details. + * Returns a reference to a temporary file, that is guaranteed not to exist, and + * to have never been created before. + * + * @param aLeafName + * Suggested leaf name for the file to be created. + * + * @return nsIFile pointing to a non-existent file in a temporary directory. + * + * @note It is not enough to delete the file if it exists, or to delete the file + * after calling nsIFile.createUnique, because on Windows the delete + * operation in the file system may still be pending, preventing a new + * file with the same name to be created. */ -function getTempFile(leafName) { - return FileTestUtils.getTempFile(leafName); +function getTempFile(aLeafName) { + // Prepend a serial number to the extension in the suggested leaf name. + let [base, ext] = DownloadPaths.splitBaseNameAndExtension(aLeafName); + let leafName = base + "-" + gFileCounter + ext; + gFileCounter++; + + // Get a file reference under the temporary directory for this test file. + let file = FileUtils.getFile("TmpD", [leafName]); + do_check_false(file.exists()); + + do_register_cleanup(function() { + if (file.exists()) { + file.remove(false); + } + }); + + return file; } const TEST_STORE_FILE_NAME = "test-store.json"; diff --git a/uriloader/exthandler/tests/mochitest/browser_download_privatebrowsing.js b/uriloader/exthandler/tests/mochitest/browser_download_privatebrowsing.js index e5ff8e38199c..3bcbb1fba240 100644 --- a/uriloader/exthandler/tests/mochitest/browser_download_privatebrowsing.js +++ b/uriloader/exthandler/tests/mochitest/browser_download_privatebrowsing.js @@ -10,9 +10,58 @@ Cu.import("resource://gre/modules/Downloads.jsm", this); Cu.import("resource://gre/modules/DownloadPaths.jsm", this); -Cu.import("resource://testing-common/FileTestUtils.jsm", this); Cu.import("resource://testing-common/MockRegistrar.jsm", this); +const TEST_TARGET_FILE_NAME = "test-download.txt"; + +// While the previous test file should have deleted all the temporary files it +// used, on Windows these might still be pending deletion on the physical file +// system. Thus, start from a new base number every time, to make a collision +// with a file that is still pending deletion highly unlikely. +let gFileCounter = Math.floor(Math.random() * 1000000); + +/** + * Returns a reference to a temporary file, that is guaranteed not to exist, and + * to have never been created before. + * + * @param aLeafName + * Suggested leaf name for the file to be created. + * + * @return nsIFile pointing to a non-existent file in a temporary directory. + * + * @note It is not enough to delete the file if it exists, or to delete the file + * after calling nsIFile.createUnique, because on Windows the delete + * operation in the file system may still be pending, preventing a new + * file with the same name to be created. + */ +function getTempFile(aLeafName) { + // Prepend a serial number to the extension in the suggested leaf name. + let [base, ext] = DownloadPaths.splitBaseNameAndExtension(aLeafName); + let leafName = base + "-" + gFileCounter + ext; + gFileCounter++; + + // Get a file reference under the temporary directory for this test file. + let file = FileUtils.getFile("TmpD", [leafName]); + Assert.ok(!file.exists()); + + registerCleanupFunction(() => { + try { + file.remove(false); + } catch (ex) { + // On Windows, we may get an access denied error if the file existed + // before, and was recently deleted. + if (!(ex instanceof Components.Exception && + (ex.result == Cr.NS_ERROR_FILE_ACCESS_DENIED || + ex.result == Cr.NS_ERROR_FILE_TARGET_DOES_NOT_EXIST || + ex.result == Cr.NS_ERROR_FILE_NOT_FOUND))) { + throw ex; + } + } + }); + + return file; +} + add_task(async function test_setup() { // Save downloads to disk without showing the dialog. let cid = MockRegistrar.register("@mozilla.org/helperapplauncherdialog;1", { @@ -22,7 +71,7 @@ add_task(async function test_setup() { }, promptForSaveToFileAsync(launcher) { // The dialog should create the empty placeholder file. - let file = FileTestUtils.getTempFile(); + let file = getTempFile(TEST_TARGET_FILE_NAME); file.create(Ci.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE); launcher.saveDestinationAvailable(file); },