mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-08 16:27:31 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
7
toolkit/components/osfile/tests/mochi/.eslintrc.js
Normal file
7
toolkit/components/osfile/tests/mochi/.eslintrc.js
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"../../../../../testing/mochitest/chrome.eslintrc.js"
|
||||
]
|
||||
};
|
||||
15
toolkit/components/osfile/tests/mochi/chrome.ini
Normal file
15
toolkit/components/osfile/tests/mochi/chrome.ini
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
[DEFAULT]
|
||||
skip-if = os == 'android'
|
||||
support-files =
|
||||
main_test_osfile_async.js
|
||||
worker_handler.js
|
||||
worker_test_osfile_comms.js
|
||||
worker_test_osfile_front.js
|
||||
worker_test_osfile_shared.js
|
||||
worker_test_osfile_unix.js
|
||||
worker_test_osfile_win.js
|
||||
|
||||
[test_osfile_async.xul]
|
||||
[test_osfile_back.xul]
|
||||
[test_osfile_comms.xul]
|
||||
[test_osfile_front.xul]
|
||||
443
toolkit/components/osfile/tests/mochi/main_test_osfile_async.js
Normal file
443
toolkit/components/osfile/tests/mochi/main_test_osfile_async.js
Normal file
|
|
@ -0,0 +1,443 @@
|
|||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm");
|
||||
Components.utils.import("resource://gre/modules/Task.jsm");
|
||||
Components.utils.import("resource://gre/modules/AsyncShutdown.jsm");
|
||||
|
||||
// The following are used to compare against a well-tested reference
|
||||
// implementation of file I/O.
|
||||
Components.utils.import("resource://gre/modules/NetUtil.jsm");
|
||||
Components.utils.import("resource://gre/modules/FileUtils.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
var myok = ok;
|
||||
var myis = is;
|
||||
var myinfo = info;
|
||||
var myisnot = isnot;
|
||||
|
||||
var isPromise = function ispromise(value) {
|
||||
return value != null && typeof value == "object" && "then" in value;
|
||||
};
|
||||
|
||||
var maketest = function(prefix, test) {
|
||||
let utils = {
|
||||
ok: function ok(t, m) {
|
||||
myok(t, prefix + ": " + m);
|
||||
},
|
||||
is: function is(l, r, m) {
|
||||
myis(l, r, prefix + ": " + m);
|
||||
},
|
||||
isnot: function isnot(l, r, m) {
|
||||
myisnot(l, r, prefix + ": " + m);
|
||||
},
|
||||
info: function info(m) {
|
||||
myinfo(prefix + ": " + m);
|
||||
},
|
||||
fail: function fail(m) {
|
||||
utils.ok(false, m);
|
||||
},
|
||||
okpromise: function okpromise(t, m) {
|
||||
return t.then(
|
||||
function onSuccess() {
|
||||
util.ok(true, m);
|
||||
},
|
||||
function onFailure() {
|
||||
util.ok(false, m);
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
return function runtest() {
|
||||
utils.info("Entering");
|
||||
try {
|
||||
let result = test.call(this, utils);
|
||||
if (!isPromise(result)) {
|
||||
throw new TypeError("The test did not return a promise");
|
||||
}
|
||||
utils.info("This was a promise");
|
||||
// The test returns a promise
|
||||
result = result.then(function test_complete() {
|
||||
utils.info("Complete");
|
||||
}, function catch_uncaught_errors(err) {
|
||||
utils.fail("Uncaught error " + err);
|
||||
if (err && typeof err == "object" && "message" in err) {
|
||||
utils.fail("(" + err.message + ")");
|
||||
}
|
||||
if (err && typeof err == "object" && "stack" in err) {
|
||||
utils.fail("at " + err.stack);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
} catch (x) {
|
||||
utils.fail("Error " + x + " at " + x.stack);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Fetch asynchronously the contents of a file using xpcom.
|
||||
*
|
||||
* Used for comparing xpcom-based results to os.file-based results.
|
||||
*
|
||||
* @param {string} path The _absolute_ path to the file.
|
||||
* @return {promise}
|
||||
* @resolves {string} The contents of the file.
|
||||
*/
|
||||
var reference_fetch_file = function reference_fetch_file(path, test) {
|
||||
test.info("Fetching file " + path);
|
||||
let promise = Promise.defer();
|
||||
let file = new FileUtils.File(path);
|
||||
NetUtil.asyncFetch({
|
||||
uri: NetUtil.newURI(file),
|
||||
loadUsingSystemPrincipal: true
|
||||
}, function(stream, status) {
|
||||
if (!Components.isSuccessCode(status)) {
|
||||
promise.reject(status);
|
||||
return;
|
||||
}
|
||||
let result, reject;
|
||||
try {
|
||||
result = NetUtil.readInputStreamToString(stream, stream.available());
|
||||
} catch (x) {
|
||||
reject = x;
|
||||
}
|
||||
stream.close();
|
||||
if (reject) {
|
||||
promise.reject(reject);
|
||||
} else {
|
||||
promise.resolve(result);
|
||||
}
|
||||
});
|
||||
|
||||
return promise.promise;
|
||||
};
|
||||
|
||||
/**
|
||||
* Compare asynchronously the contents two files using xpcom.
|
||||
*
|
||||
* Used for comparing xpcom-based results to os.file-based results.
|
||||
*
|
||||
* @param {string} a The _absolute_ path to the first file.
|
||||
* @param {string} b The _absolute_ path to the second file.
|
||||
*
|
||||
* @resolves {null}
|
||||
*/
|
||||
var reference_compare_files = function reference_compare_files(a, b, test) {
|
||||
test.info("Comparing files " + a + " and " + b);
|
||||
let a_contents = yield reference_fetch_file(a, test);
|
||||
let b_contents = yield reference_fetch_file(b, test);
|
||||
is(a_contents, b_contents, "Contents of files " + a + " and " + b + " match");
|
||||
};
|
||||
|
||||
var reference_dir_contents = function reference_dir_contents(path) {
|
||||
let result = [];
|
||||
let entries = new FileUtils.File(path).directoryEntries;
|
||||
while (entries.hasMoreElements()) {
|
||||
let entry = entries.getNext().QueryInterface(Components.interfaces.nsILocalFile);
|
||||
result.push(entry.path);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
// Set/Unset OS.Shared.DEBUG, OS.Shared.TEST and a console listener.
|
||||
function toggleDebugTest (pref, consoleListener) {
|
||||
Services.prefs.setBoolPref("toolkit.osfile.log", pref);
|
||||
Services.prefs.setBoolPref("toolkit.osfile.log.redirect", pref);
|
||||
Services.console[pref ? "registerListener" : "unregisterListener"](
|
||||
consoleListener);
|
||||
}
|
||||
|
||||
var test = maketest("Main", function main(test) {
|
||||
return Task.spawn(function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
yield test_stat();
|
||||
yield test_debug();
|
||||
yield test_info_features_detect();
|
||||
yield test_position();
|
||||
yield test_iter();
|
||||
yield test_exists();
|
||||
yield test_debug_test();
|
||||
info("Test is over");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* A file that we know exists and that can be used for reading.
|
||||
*/
|
||||
var EXISTING_FILE = OS.Path.join("chrome", "toolkit", "components",
|
||||
"osfile", "tests", "mochi", "main_test_osfile_async.js");
|
||||
|
||||
/**
|
||||
* Test OS.File.stat and OS.File.prototype.stat
|
||||
*/
|
||||
var test_stat = maketest("stat", function stat(test) {
|
||||
return Task.spawn(function() {
|
||||
// Open a file and stat it
|
||||
let file = yield OS.File.open(EXISTING_FILE);
|
||||
let stat1;
|
||||
|
||||
try {
|
||||
test.info("Stating file");
|
||||
stat1 = yield file.stat();
|
||||
test.ok(true, "stat has worked " + stat1);
|
||||
test.ok(stat1, "stat is not empty");
|
||||
} finally {
|
||||
yield file.close();
|
||||
}
|
||||
|
||||
// Stat the same file without opening it
|
||||
test.info("Stating a file without opening it");
|
||||
let stat2 = yield OS.File.stat(EXISTING_FILE);
|
||||
test.ok(true, "stat 2 has worked " + stat2);
|
||||
test.ok(stat2, "stat 2 is not empty");
|
||||
for (let key in stat2) {
|
||||
test.is("" + stat1[key], "" + stat2[key], "Stat field " + key + "is the same");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Test feature detection using OS.File.Info.prototype on main thread
|
||||
*/
|
||||
var test_info_features_detect = maketest("features_detect", function features_detect(test) {
|
||||
return Task.spawn(function() {
|
||||
if (OS.Constants.Win) {
|
||||
// see if winBirthDate is defined
|
||||
if ("winBirthDate" in OS.File.Info.prototype) {
|
||||
test.ok(true, "winBirthDate is defined");
|
||||
} else {
|
||||
test.fail("winBirthDate not defined though we are under Windows");
|
||||
}
|
||||
} else if (OS.Constants.libc) {
|
||||
// see if unixGroup is defined
|
||||
if ("unixGroup" in OS.File.Info.prototype) {
|
||||
test.ok(true, "unixGroup is defined");
|
||||
} else {
|
||||
test.fail("unixGroup is not defined though we are under Unix");
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Test file.{getPosition, setPosition}
|
||||
*/
|
||||
var test_position = maketest("position", function position(test) {
|
||||
return Task.spawn(function() {
|
||||
let file = yield OS.File.open(EXISTING_FILE);
|
||||
|
||||
try {
|
||||
let view = yield file.read();
|
||||
test.info("First batch of content read");
|
||||
let CHUNK_SIZE = 178;// An arbitrary number of bytes to read from the file
|
||||
let pos = yield file.getPosition();
|
||||
test.info("Obtained position");
|
||||
test.is(pos, view.byteLength, "getPosition returned the end of the file");
|
||||
pos = yield file.setPosition(-CHUNK_SIZE, OS.File.POS_END);
|
||||
test.info("Changed position");
|
||||
test.is(pos, view.byteLength - CHUNK_SIZE, "setPosition returned the correct position");
|
||||
|
||||
let view2 = yield file.read();
|
||||
test.info("Read the end of the file");
|
||||
for (let i = 0; i < CHUNK_SIZE; ++i) {
|
||||
if (view2[i] != view[i + view.byteLength - CHUNK_SIZE]) {
|
||||
test.is(view2[i], view[i], "setPosition put us in the right position");
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
yield file.close();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Test OS.File.prototype.{DirectoryIterator}
|
||||
*/
|
||||
var test_iter = maketest("iter", function iter(test) {
|
||||
return Task.spawn(function() {
|
||||
let currentDir = yield OS.File.getCurrentDirectory();
|
||||
|
||||
// Trivial walks through the directory
|
||||
test.info("Preparing iteration");
|
||||
let iterator = new OS.File.DirectoryIterator(currentDir);
|
||||
let temporary_file_name = OS.Path.join(currentDir, "empty-temporary-file.tmp");
|
||||
try {
|
||||
yield OS.File.remove(temporary_file_name);
|
||||
} catch (err) {
|
||||
// Ignore errors removing file
|
||||
}
|
||||
let allFiles1 = yield iterator.nextBatch();
|
||||
test.info("Obtained all files through nextBatch");
|
||||
test.isnot(allFiles1.length, 0, "There is at least one file");
|
||||
test.isnot(allFiles1[0].path, null, "Files have a path");
|
||||
|
||||
// Ensure that we have the same entries with |reference_dir_contents|
|
||||
let referenceEntries = new Set();
|
||||
for (let entry of reference_dir_contents(currentDir)) {
|
||||
referenceEntries.add(entry);
|
||||
}
|
||||
test.is(referenceEntries.size, allFiles1.length, "All the entries in the directory have been listed");
|
||||
for (let entry of allFiles1) {
|
||||
test.ok(referenceEntries.has(entry.path), "File " + entry.path + " effectively exists");
|
||||
// Ensure that we have correct isDir and isSymLink
|
||||
// Current directory is {objdir}/_tests/testing/mochitest/, assume it has some dirs and symlinks.
|
||||
var f = new FileUtils.File(entry.path);
|
||||
test.is(entry.isDir, f.isDirectory(), "Get file " + entry.path + " isDir correctly");
|
||||
test.is(entry.isSymLink, f.isSymlink(), "Get file " + entry.path + " isSymLink correctly");
|
||||
}
|
||||
|
||||
yield iterator.close();
|
||||
test.info("Closed iterator");
|
||||
|
||||
test.info("Double closing DirectoryIterator");
|
||||
iterator = new OS.File.DirectoryIterator(currentDir);
|
||||
yield iterator.close();
|
||||
yield iterator.close(); //double closing |DirectoryIterator|
|
||||
test.ok(true, "|DirectoryIterator| was closed twice successfully");
|
||||
|
||||
let allFiles2 = [];
|
||||
let i = 0;
|
||||
iterator = new OS.File.DirectoryIterator(currentDir);
|
||||
yield iterator.forEach(function(entry, index) {
|
||||
test.is(i++, index, "Getting the correct index");
|
||||
allFiles2.push(entry);
|
||||
});
|
||||
test.info("Obtained all files through forEach");
|
||||
is(allFiles1.length, allFiles2.length, "Both runs returned the same number of files");
|
||||
for (let i = 0; i < allFiles1.length; ++i) {
|
||||
if (allFiles1[i].path != allFiles2[i].path) {
|
||||
test.is(allFiles1[i].path, allFiles2[i].path, "Both runs return the same files");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Testing batch iteration + whether an iteration can be stopped early
|
||||
let BATCH_LENGTH = 10;
|
||||
test.info("Getting some files through nextBatch");
|
||||
yield iterator.close();
|
||||
|
||||
iterator = new OS.File.DirectoryIterator(currentDir);
|
||||
let someFiles1 = yield iterator.nextBatch(BATCH_LENGTH);
|
||||
let someFiles2 = yield iterator.nextBatch(BATCH_LENGTH);
|
||||
yield iterator.close();
|
||||
|
||||
iterator = new OS.File.DirectoryIterator(currentDir);
|
||||
yield iterator.forEach(function cb(entry, index, iterator) {
|
||||
if (index < BATCH_LENGTH) {
|
||||
test.is(entry.path, someFiles1[index].path, "Both runs return the same files (part 1)");
|
||||
} else if (index < 2*BATCH_LENGTH) {
|
||||
test.is(entry.path, someFiles2[index - BATCH_LENGTH].path, "Both runs return the same files (part 2)");
|
||||
} else if (index == 2 * BATCH_LENGTH) {
|
||||
test.info("Attempting to stop asynchronous forEach");
|
||||
return iterator.close();
|
||||
} else {
|
||||
test.fail("Can we stop an asynchronous forEach? " + index);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
yield iterator.close();
|
||||
|
||||
// Ensuring that we find new files if they appear
|
||||
let file = yield OS.File.open(temporary_file_name, { write: true } );
|
||||
file.close();
|
||||
iterator = new OS.File.DirectoryIterator(currentDir);
|
||||
try {
|
||||
let files = yield iterator.nextBatch();
|
||||
is(files.length, allFiles1.length + 1, "The directory iterator has noticed the new file");
|
||||
let exists = yield iterator.exists();
|
||||
test.ok(exists, "After nextBatch, iterator detects that the directory exists");
|
||||
} finally {
|
||||
yield iterator.close();
|
||||
}
|
||||
|
||||
// Ensuring that opening a non-existing directory fails consistently
|
||||
// once iteration starts.
|
||||
try {
|
||||
iterator = null;
|
||||
iterator = new OS.File.DirectoryIterator("/I do not exist");
|
||||
let exists = yield iterator.exists();
|
||||
test.ok(!exists, "Before any iteration, iterator detects that the directory doesn't exist");
|
||||
let exn = null;
|
||||
try {
|
||||
yield iterator.next();
|
||||
} catch (ex if ex instanceof OS.File.Error && ex.becauseNoSuchFile) {
|
||||
exn = ex;
|
||||
let exists = yield iterator.exists();
|
||||
test.ok(!exists, "After one iteration, iterator detects that the directory doesn't exist");
|
||||
}
|
||||
test.ok(exn, "Iterating through a directory that does not exist has failed with becauseNoSuchFile");
|
||||
} finally {
|
||||
if (iterator) {
|
||||
iterator.close();
|
||||
}
|
||||
}
|
||||
test.ok(!!iterator, "The directory iterator for a non-existing directory was correctly created");
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Test OS.File.prototype.{exists}
|
||||
*/
|
||||
var test_exists = maketest("exists", function exists(test) {
|
||||
return Task.spawn(function() {
|
||||
let fileExists = yield OS.File.exists(EXISTING_FILE);
|
||||
test.ok(fileExists, "file exists");
|
||||
fileExists = yield OS.File.exists(EXISTING_FILE + ".tmp");
|
||||
test.ok(!fileExists, "file does not exists");
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Test changes to OS.Shared.DEBUG flag.
|
||||
*/
|
||||
var test_debug = maketest("debug", function debug(test) {
|
||||
return Task.spawn(function() {
|
||||
function testSetDebugPref (pref) {
|
||||
try {
|
||||
Services.prefs.setBoolPref("toolkit.osfile.log", pref);
|
||||
} catch (x) {
|
||||
test.fail("Setting OS.Shared.DEBUG to " + pref +
|
||||
" should not cause error.");
|
||||
} finally {
|
||||
test.is(OS.Shared.DEBUG, pref, "OS.Shared.DEBUG is set correctly.");
|
||||
}
|
||||
}
|
||||
testSetDebugPref(true);
|
||||
let workerDEBUG = yield OS.File.GET_DEBUG();
|
||||
test.is(workerDEBUG, true, "Worker's DEBUG is set.");
|
||||
testSetDebugPref(false);
|
||||
workerDEBUG = yield OS.File.GET_DEBUG();
|
||||
test.is(workerDEBUG, false, "Worker's DEBUG is unset.");
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Test logging in the main thread with set OS.Shared.DEBUG and
|
||||
* OS.Shared.TEST flags.
|
||||
*/
|
||||
var test_debug_test = maketest("debug_test", function debug_test(test) {
|
||||
return Task.spawn(function () {
|
||||
// Create a console listener.
|
||||
let consoleListener = {
|
||||
observe: function (aMessage) {
|
||||
// Ignore unexpected messages.
|
||||
if (!(aMessage instanceof Components.interfaces.nsIConsoleMessage)) {
|
||||
return;
|
||||
}
|
||||
if (aMessage.message.indexOf("TEST OS") < 0) {
|
||||
return;
|
||||
}
|
||||
test.ok(true, "DEBUG TEST messages are logged correctly.");
|
||||
}
|
||||
};
|
||||
toggleDebugTest(true, consoleListener);
|
||||
// Execution of OS.File.exist method will trigger OS.File.LOG several times.
|
||||
let fileExists = yield OS.File.exists(EXISTING_FILE);
|
||||
toggleDebugTest(false, consoleListener);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
23
toolkit/components/osfile/tests/mochi/test_osfile_async.xul
Normal file
23
toolkit/components/osfile/tests/mochi/test_osfile_async.xul
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<window title="Testing async I/O with OS.File"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="test();">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
|
||||
<script type="application/javascript"
|
||||
src="main_test_osfile_async.js"/>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display:none;"></div>
|
||||
<pre id="test"></pre>
|
||||
</body>
|
||||
<label id="test-result"/>
|
||||
</window>
|
||||
46
toolkit/components/osfile/tests/mochi/test_osfile_back.xul
Normal file
46
toolkit/components/osfile/tests/mochi/test_osfile_back.xul
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<window title="Testing OS.File on a chrome worker thread"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="test();">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
|
||||
<script type="application/javascript"
|
||||
src="worker_handler.js"/>
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
let worker;
|
||||
|
||||
function test() {
|
||||
ok(true, "test_osfile.xul: Starting test");
|
||||
if (navigator.platform.indexOf("Win") != -1) {
|
||||
ok(true, "test_osfile.xul: Using Windows test suite");
|
||||
worker = new ChromeWorker("worker_test_osfile_win.js");
|
||||
} else {
|
||||
ok(true, "test_osfile.xul: Using Unix test suite");
|
||||
worker = new ChromeWorker("worker_test_osfile_unix.js");
|
||||
}
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
ok(true, "test_osfile.xul: Chrome worker created");
|
||||
dump("MAIN: go\n");
|
||||
worker_handler(worker);
|
||||
worker.postMessage(0);
|
||||
ok(true, "test_osfile.xul: Test in progress");
|
||||
};
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display:none;"></div>
|
||||
<pre id="test"></pre>
|
||||
</body>
|
||||
<label id="test-result"/>
|
||||
</window>
|
||||
84
toolkit/components/osfile/tests/mochi/test_osfile_comms.xul
Normal file
84
toolkit/components/osfile/tests/mochi/test_osfile_comms.xul
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<window title="Testing OS.File on a chrome worker thread"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="test();">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
"use strict";
|
||||
|
||||
let worker;
|
||||
|
||||
let test = function test() {
|
||||
SimpleTest.info("test_osfile_comms.xul: Starting test");
|
||||
Components.utils.import("resource://gre/modules/ctypes.jsm");
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
worker = new ChromeWorker("worker_test_osfile_comms.js");
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
try {
|
||||
worker.onerror = function onerror(error) {
|
||||
SimpleTest.ok(false, "received error "+error);
|
||||
}
|
||||
worker.onmessage = function onmessage(msg) {
|
||||
Components.utils.forceShrinkingGC();
|
||||
switch (msg.data.kind) {
|
||||
case "is":
|
||||
SimpleTest.ok(msg.data.outcome, msg.data.description +
|
||||
" ("+ msg.data.a + " ==? " + msg.data.b + ")" );
|
||||
return;
|
||||
case "isnot":
|
||||
SimpleTest.ok(msg.data.outcome, msg.data.description +
|
||||
" ("+ msg.data.a + " !=? " + msg.data.b + ")" );
|
||||
return;
|
||||
case "ok":
|
||||
SimpleTest.ok(msg.data.condition, msg.data.description);
|
||||
return;
|
||||
case "info":
|
||||
SimpleTest.info(msg.data.description);
|
||||
return;
|
||||
case "finish":
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
case "value":
|
||||
SimpleTest.ok(true, "test_osfile_comms.xul: Received value " + JSON.stringify(msg.data.value));
|
||||
let type = eval(msg.data.typename);
|
||||
let check = eval(msg.data.check);
|
||||
let value = msg.data.value;
|
||||
let deserialized = type.fromMsg(value);
|
||||
check(deserialized, "Main thread test: ");
|
||||
return;
|
||||
default:
|
||||
SimpleTest.ok(false, "test_osfile_comms.xul: wrong message "+JSON.stringify(msg.data));
|
||||
return;
|
||||
}
|
||||
};
|
||||
worker.postMessage(0)
|
||||
ok(true, "Worker launched");
|
||||
} catch(x) {
|
||||
// As we have set |waitForExplicitFinish|, we add this fallback
|
||||
// in case of uncaught error, to ensure that the test does not
|
||||
// just freeze.
|
||||
ok(false, "Caught exception " + x + " at " + x.stack);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
};
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display:none;"></div>
|
||||
<pre id="test"></pre>
|
||||
</body>
|
||||
<label id="test-result"/>
|
||||
</window>
|
||||
44
toolkit/components/osfile/tests/mochi/test_osfile_front.xul
Normal file
44
toolkit/components/osfile/tests/mochi/test_osfile_front.xul
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<window title="Testing OS.File on a chrome worker thread"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="test();">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
|
||||
<script type="application/javascript"
|
||||
src="worker_handler.js"/>
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
let worker;
|
||||
let main = this;
|
||||
|
||||
function test() {
|
||||
info("test_osfile_front.xul: Starting test");
|
||||
|
||||
// Test the OS.File worker
|
||||
|
||||
worker = new ChromeWorker("worker_test_osfile_front.js");
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
info("test_osfile_front.xul: Chrome worker created");
|
||||
dump("MAIN: go\n");
|
||||
worker_handler(worker);
|
||||
worker.postMessage(0);
|
||||
ok(true, "test_osfile_front.xul: Test in progress");
|
||||
};
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display:none;"></div>
|
||||
<pre id="test"></pre>
|
||||
</body>
|
||||
<label id="test-result"/>
|
||||
</window>
|
||||
34
toolkit/components/osfile/tests/mochi/worker_handler.js
Normal file
34
toolkit/components/osfile/tests/mochi/worker_handler.js
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function worker_handler(worker) {
|
||||
worker.onerror = function(error) {
|
||||
error.preventDefault();
|
||||
ok(false, "Worker error " + error.message);
|
||||
}
|
||||
worker.onmessage = function(msg) {
|
||||
ok(true, "MAIN: onmessage " + JSON.stringify(msg.data));
|
||||
switch (msg.data.kind) {
|
||||
case "is":
|
||||
SimpleTest.ok(msg.data.outcome, msg.data.description +
|
||||
"( "+ msg.data.a + " ==? " + msg.data.b + ")" );
|
||||
return;
|
||||
case "isnot":
|
||||
SimpleTest.ok(msg.data.outcome, msg.data.description +
|
||||
"( "+ msg.data.a + " !=? " + msg.data.b + ")" );
|
||||
return;
|
||||
case "ok":
|
||||
SimpleTest.ok(msg.data.condition, msg.data.description);
|
||||
return;
|
||||
case "info":
|
||||
SimpleTest.info(msg.data.description);
|
||||
return;
|
||||
case "finish":
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
default:
|
||||
SimpleTest.ok(false, "test_osfile.xul: wrong message " + JSON.stringify(msg.data));
|
||||
return;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
importScripts('worker_test_osfile_shared.js');
|
||||
|
||||
// The set of samples for communications test. Declare as a global
|
||||
// variable to prevent this from being garbage-collected too early.
|
||||
var samples;
|
||||
|
||||
self.onmessage = function(msg) {
|
||||
info("Initializing");
|
||||
self.onmessage = function on_unexpected_message(msg) {
|
||||
throw new Error("Unexpected message " + JSON.stringify(msg.data));
|
||||
};
|
||||
importScripts("resource://gre/modules/osfile.jsm");
|
||||
info("Initialization complete");
|
||||
|
||||
samples = [
|
||||
{ typename: "OS.Shared.Type.char.in_ptr",
|
||||
valuedescr: "String",
|
||||
value: "This is a test",
|
||||
type: OS.Shared.Type.char.in_ptr,
|
||||
check: function check_string(candidate, prefix) {
|
||||
is(candidate, "This is a test", prefix);
|
||||
}},
|
||||
{ typename: "OS.Shared.Type.char.in_ptr",
|
||||
valuedescr: "Typed array",
|
||||
value: (function() {
|
||||
let view = new Uint8Array(15);
|
||||
for (let i = 0; i < 15; ++i) {
|
||||
view[i] = i;
|
||||
}
|
||||
return view;
|
||||
})(),
|
||||
type: OS.Shared.Type.char.in_ptr,
|
||||
check: function check_ArrayBuffer(candidate, prefix) {
|
||||
for (let i = 0; i < 15; ++i) {
|
||||
is(candidate[i], i % 256, prefix + "Checking that the contents of the ArrayBuffer were preserved");
|
||||
}
|
||||
}},
|
||||
{ typename: "OS.Shared.Type.char.in_ptr",
|
||||
valuedescr: "Pointer",
|
||||
value: new OS.Shared.Type.char.in_ptr.implementation(1),
|
||||
type: OS.Shared.Type.char.in_ptr,
|
||||
check: function check_ptr(candidate, prefix) {
|
||||
let address = ctypes.cast(candidate, ctypes.uintptr_t).value.toString();
|
||||
is(address, "1", prefix + "Checking that the pointer address was preserved");
|
||||
}},
|
||||
{ typename: "OS.Shared.Type.char.in_ptr",
|
||||
valuedescr: "C array",
|
||||
value: (function() {
|
||||
let buf = new (ctypes.ArrayType(ctypes.uint8_t, 15))();
|
||||
for (let i = 0; i < 15; ++i) {
|
||||
buf[i] = i % 256;
|
||||
}
|
||||
return buf;
|
||||
})(),
|
||||
type: OS.Shared.Type.char.in_ptr,
|
||||
check: function check_array(candidate, prefix) {
|
||||
let cast = ctypes.cast(candidate, ctypes.uint8_t.ptr);
|
||||
for (let i = 0; i < 15; ++i) {
|
||||
is(cast.contents, i % 256, prefix + "Checking that the contents of the C array were preserved, index " + i);
|
||||
cast = cast.increment();
|
||||
}
|
||||
}
|
||||
},
|
||||
{ typename: "OS.File.Error",
|
||||
valuedescr: "OS Error",
|
||||
type: OS.File.Error,
|
||||
value: new OS.File.Error("foo", 1),
|
||||
check: function check_error(candidate, prefix) {
|
||||
ok(candidate instanceof OS.File.Error,
|
||||
prefix + "Error is an OS.File.Error");
|
||||
ok(candidate.unixErrno == 1 || candidate.winLastError == 1,
|
||||
prefix + "Error code is correct");
|
||||
try {
|
||||
let string = candidate.toString();
|
||||
info(prefix + ".toString() works " + string);
|
||||
} catch (x) {
|
||||
ok(false, prefix + ".toString() fails " + x);
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
samples.forEach(function test(sample) {
|
||||
let type = sample.type;
|
||||
let value = sample.value;
|
||||
let check = sample.check;
|
||||
info("Testing handling of type " + sample.typename + " communicating " + sample.valuedescr);
|
||||
|
||||
// 1. Test serialization
|
||||
let serialized;
|
||||
let exn;
|
||||
try {
|
||||
serialized = type.toMsg(value);
|
||||
} catch (ex) {
|
||||
exn = ex;
|
||||
}
|
||||
is(exn, null, "Can I serialize the following value? " + value +
|
||||
" aka " + JSON.stringify(value));
|
||||
if (exn) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ("data" in serialized) {
|
||||
// Unwrap from `Meta`
|
||||
serialized = serialized.data;
|
||||
}
|
||||
|
||||
// 2. Test deserialization
|
||||
let deserialized;
|
||||
try {
|
||||
deserialized = type.fromMsg(serialized);
|
||||
} catch (ex) {
|
||||
exn = ex;
|
||||
}
|
||||
is(exn, null, "Can I deserialize the following message? " + serialized
|
||||
+ " aka " + JSON.stringify(serialized));
|
||||
if (exn) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. Local test deserialized value
|
||||
info("Running test on deserialized value " + deserialized +
|
||||
" aka " + JSON.stringify(deserialized));
|
||||
check(deserialized, "Local test: ");
|
||||
|
||||
// 4. Test sending serialized
|
||||
info("Attempting to send message");
|
||||
try {
|
||||
self.postMessage({kind:"value",
|
||||
typename: sample.typename,
|
||||
value: serialized,
|
||||
check: check.toSource()});
|
||||
} catch (ex) {
|
||||
exn = ex;
|
||||
}
|
||||
is(exn, null, "Can I send the following message? " + serialized
|
||||
+ " aka " + JSON.stringify(serialized));
|
||||
});
|
||||
|
||||
finish();
|
||||
};
|
||||
|
|
@ -0,0 +1,566 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
importScripts('worker_test_osfile_shared.js');
|
||||
importScripts("resource://gre/modules/workers/require.js");
|
||||
|
||||
var SharedAll = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm");
|
||||
SharedAll.Config.DEBUG = true;
|
||||
|
||||
function should_throw(f) {
|
||||
try {
|
||||
f();
|
||||
} catch (x) {
|
||||
return x;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
self.onmessage = function onmessage_start(msg) {
|
||||
self.onmessage = function onmessage_ignored(msg) {
|
||||
log("ignored message " + JSON.stringify(msg.data));
|
||||
};
|
||||
try {
|
||||
test_init();
|
||||
test_open_existing_file();
|
||||
test_open_non_existing_file();
|
||||
test_flush_open_file();
|
||||
test_copy_existing_file();
|
||||
test_position();
|
||||
test_move_file();
|
||||
test_iter_dir();
|
||||
test_info();
|
||||
test_path();
|
||||
test_exists_file();
|
||||
test_remove_file();
|
||||
} catch (x) {
|
||||
log("Catching error: " + x);
|
||||
log("Stack: " + x.stack);
|
||||
log("Source: " + x.toSource());
|
||||
ok(false, x.toString() + "\n" + x.stack);
|
||||
}
|
||||
finish();
|
||||
};
|
||||
|
||||
function test_init() {
|
||||
info("Starting test_init");
|
||||
importScripts("resource://gre/modules/osfile.jsm");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that we can open an existing file.
|
||||
*/
|
||||
function test_open_existing_file()
|
||||
{
|
||||
info("Starting test_open_existing");
|
||||
let file = OS.File.open("chrome/toolkit/components/osfile/tests/mochi/worker_test_osfile_unix.js");
|
||||
file.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that opening a file that does not exist fails with the right error.
|
||||
*/
|
||||
function test_open_non_existing_file()
|
||||
{
|
||||
info("Starting test_open_non_existing");
|
||||
let exn;
|
||||
try {
|
||||
let file = OS.File.open("/I do not exist");
|
||||
} catch (x) {
|
||||
exn = x;
|
||||
info("test_open_non_existing_file: Exception detail " + exn);
|
||||
}
|
||||
ok(!!exn, "test_open_non_existing_file: Exception was raised ");
|
||||
ok(exn instanceof OS.File.Error, "test_open_non_existing_file: Exception was a OS.File.Error");
|
||||
ok(exn.becauseNoSuchFile, "test_open_non_existing_file: Exception confirms that the file does not exist");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that to ensure that |foo.flush()| does not
|
||||
* cause an error, where |foo| is an open file.
|
||||
*/
|
||||
function test_flush_open_file()
|
||||
{
|
||||
info("Starting test_flush_open_file");
|
||||
let tmp = "test_flush.tmp";
|
||||
let file = OS.File.open(tmp, {create: true, write: true});
|
||||
file.flush();
|
||||
file.close();
|
||||
OS.File.remove(tmp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function for comparing two files (or a prefix of two files).
|
||||
*
|
||||
* This function returns nothing but fails of both files (or prefixes)
|
||||
* are not identical.
|
||||
*
|
||||
* @param {string} test The name of the test (used for logging).
|
||||
* @param {string} sourcePath The name of the first file.
|
||||
* @param {string} destPath The name of the second file.
|
||||
* @param {number=} prefix If specified, only compare the |prefix|
|
||||
* first bytes of |sourcePath| and |destPath|.
|
||||
*/
|
||||
function compare_files(test, sourcePath, destPath, prefix)
|
||||
{
|
||||
info(test + ": Comparing " + sourcePath + " and " + destPath);
|
||||
let source = OS.File.open(sourcePath);
|
||||
let dest = OS.File.open(destPath);
|
||||
info("Files are open");
|
||||
let sourceResult, destResult;
|
||||
try {
|
||||
if (prefix != undefined) {
|
||||
sourceResult = source.read(prefix);
|
||||
destResult = dest.read(prefix);
|
||||
} else {
|
||||
sourceResult = source.read();
|
||||
destResult = dest.read();
|
||||
}
|
||||
is(sourceResult.length, destResult.length, test + ": Both files have the same size");
|
||||
for (let i = 0; i < sourceResult.length; ++i) {
|
||||
if (sourceResult[i] != destResult[i]) {
|
||||
is(sourceResult[i] != destResult[i], test + ": Comparing char " + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
source.close();
|
||||
dest.close();
|
||||
}
|
||||
info(test + ": Comparison complete");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that copying a file using |copy| works.
|
||||
*/
|
||||
function test_copy_existing_file()
|
||||
{
|
||||
let src_file_name =
|
||||
OS.Path.join("chrome", "toolkit", "components", "osfile", "tests", "mochi",
|
||||
"worker_test_osfile_front.js");
|
||||
let tmp_file_name = "test_osfile_front.tmp";
|
||||
info("Starting test_copy_existing");
|
||||
OS.File.copy(src_file_name, tmp_file_name);
|
||||
|
||||
info("test_copy_existing: Copy complete");
|
||||
compare_files("test_copy_existing", src_file_name, tmp_file_name);
|
||||
|
||||
// Create a bogus file with arbitrary content, then attempt to overwrite
|
||||
// it with |copy|.
|
||||
let dest = OS.File.open(tmp_file_name, {trunc: true});
|
||||
let buf = new Uint8Array(50);
|
||||
dest.write(buf);
|
||||
dest.close();
|
||||
|
||||
OS.File.copy(src_file_name, tmp_file_name);
|
||||
|
||||
compare_files("test_copy_existing 2", src_file_name, tmp_file_name);
|
||||
|
||||
// Attempt to overwrite with noOverwrite
|
||||
let exn;
|
||||
try {
|
||||
OS.File.copy(src_file_name, tmp_file_name, {noOverwrite: true});
|
||||
} catch(x) {
|
||||
exn = x;
|
||||
}
|
||||
ok(!!exn, "test_copy_existing: noOverwrite prevents overwriting existing files");
|
||||
|
||||
info("test_copy_existing: Cleaning up");
|
||||
OS.File.remove(tmp_file_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that moving a file works.
|
||||
*/
|
||||
function test_move_file()
|
||||
{
|
||||
info("test_move_file: Starting");
|
||||
// 1. Copy file into a temporary file
|
||||
let src_file_name =
|
||||
OS.Path.join("chrome", "toolkit", "components", "osfile", "tests", "mochi",
|
||||
"worker_test_osfile_front.js");
|
||||
let tmp_file_name = "test_osfile_front.tmp";
|
||||
let tmp2_file_name = "test_osfile_front.tmp2";
|
||||
OS.File.copy(src_file_name, tmp_file_name);
|
||||
|
||||
info("test_move_file: Copy complete");
|
||||
|
||||
// 2. Move
|
||||
OS.File.move(tmp_file_name, tmp2_file_name);
|
||||
|
||||
info("test_move_file: Move complete");
|
||||
|
||||
// 3. Check that destination exists
|
||||
compare_files("test_move_file", src_file_name, tmp2_file_name);
|
||||
|
||||
// 4. Check that original file does not exist anymore
|
||||
let exn;
|
||||
try {
|
||||
OS.File.open(tmp_file_name);
|
||||
} catch (x) {
|
||||
exn = x;
|
||||
}
|
||||
ok(!!exn, "test_move_file: Original file has been removed");
|
||||
|
||||
info("test_move_file: Cleaning up");
|
||||
OS.File.remove(tmp2_file_name);
|
||||
}
|
||||
|
||||
function test_iter_dir()
|
||||
{
|
||||
info("test_iter_dir: Starting");
|
||||
|
||||
// Create a file, to be sure that it exists
|
||||
let tmp_file_name = "test_osfile_front.tmp";
|
||||
let tmp_file = OS.File.open(tmp_file_name, {write: true, trunc:true});
|
||||
tmp_file.close();
|
||||
|
||||
let parent = OS.File.getCurrentDirectory();
|
||||
info("test_iter_dir: directory " + parent);
|
||||
let iterator = new OS.File.DirectoryIterator(parent);
|
||||
info("test_iter_dir: iterator created");
|
||||
let encountered_tmp_file = false;
|
||||
for (let entry in iterator) {
|
||||
// Checking that |name| can be decoded properly
|
||||
info("test_iter_dir: encountering entry " + entry.name);
|
||||
|
||||
if (entry.name == tmp_file_name) {
|
||||
encountered_tmp_file = true;
|
||||
isnot(entry.isDir, "test_iter_dir: The temporary file is not a directory");
|
||||
isnot(entry.isSymLink, "test_iter_dir: The temporary file is not a link");
|
||||
}
|
||||
|
||||
let file;
|
||||
let success = true;
|
||||
try {
|
||||
file = OS.File.open(entry.path);
|
||||
} catch (x) {
|
||||
if (x.becauseNoSuchFile) {
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
if (file) {
|
||||
file.close();
|
||||
}
|
||||
ok(success, "test_iter_dir: Entry " + entry.path + " exists");
|
||||
|
||||
if (OS.Win) {
|
||||
// We assume that the files are at least as recent as 2009.
|
||||
// Since this test was written in 2011 and some of our packaging
|
||||
// sets dates arbitrarily to 2010, this should be safe.
|
||||
let year = new Date().getFullYear();
|
||||
let creation = entry.winCreationDate;
|
||||
ok(creation, "test_iter_dir: Windows creation date exists: " + creation);
|
||||
ok(creation.getFullYear() >= 2009 && creation.getFullYear() <= year, "test_iter_dir: consistent creation date");
|
||||
|
||||
let lastWrite = entry.winLastWriteDate;
|
||||
ok(lastWrite, "test_iter_dir: Windows lastWrite date exists: " + lastWrite);
|
||||
ok(lastWrite.getFullYear() >= 2009 && lastWrite.getFullYear() <= year, "test_iter_dir: consistent lastWrite date");
|
||||
|
||||
let lastAccess = entry.winLastAccessDate;
|
||||
ok(lastAccess, "test_iter_dir: Windows lastAccess date exists: " + lastAccess);
|
||||
ok(lastAccess.getFullYear() >= 2009 && lastAccess.getFullYear() <= year, "test_iter_dir: consistent lastAccess date");
|
||||
}
|
||||
|
||||
}
|
||||
ok(encountered_tmp_file, "test_iter_dir: We have found the temporary file");
|
||||
|
||||
info("test_iter_dir: Cleaning up");
|
||||
iterator.close();
|
||||
|
||||
// Testing nextBatch()
|
||||
iterator = new OS.File.DirectoryIterator(parent);
|
||||
let allentries = [];
|
||||
for (let x in iterator) {
|
||||
allentries.push(x);
|
||||
}
|
||||
iterator.close();
|
||||
|
||||
ok(allentries.length >= 14, "test_iter_dir: Meta-check: the test directory should contain at least 14 items");
|
||||
|
||||
iterator = new OS.File.DirectoryIterator(parent);
|
||||
let firstten = iterator.nextBatch(10);
|
||||
is(firstten.length, 10, "test_iter_dir: nextBatch(10) returns 10 items");
|
||||
for (let i = 0; i < firstten.length; ++i) {
|
||||
is(allentries[i].path, firstten[i].path, "test_iter_dir: Checking that batch returns the correct entries");
|
||||
}
|
||||
let nextthree = iterator.nextBatch(3);
|
||||
is(nextthree.length, 3, "test_iter_dir: nextBatch(3) returns 3 items");
|
||||
for (let i = 0; i < nextthree.length; ++i) {
|
||||
is(allentries[i + firstten.length].path, nextthree[i].path, "test_iter_dir: Checking that batch 2 returns the correct entries");
|
||||
}
|
||||
let everythingelse = iterator.nextBatch();
|
||||
ok(everythingelse.length >= 1, "test_iter_dir: nextBatch() returns at least one item");
|
||||
for (let i = 0; i < everythingelse.length; ++i) {
|
||||
is(allentries[i + firstten.length + nextthree.length].path, everythingelse[i].path, "test_iter_dir: Checking that batch 3 returns the correct entries");
|
||||
}
|
||||
is(iterator.nextBatch().length, 0, "test_iter_dir: Once there is nothing left, nextBatch returns an empty array");
|
||||
iterator.close();
|
||||
|
||||
iterator = new OS.File.DirectoryIterator(parent);
|
||||
iterator.close();
|
||||
is(iterator.nextBatch().length, 0, "test_iter_dir: nextBatch on closed iterator returns an empty array");
|
||||
|
||||
iterator = new OS.File.DirectoryIterator(parent);
|
||||
let allentries2 = iterator.nextBatch();
|
||||
is(allentries.length, allentries2.length, "test_iter_dir: Checking that getBatch(null) returns the right number of entries");
|
||||
for (let i = 0; i < allentries.length; ++i) {
|
||||
is(allentries[i].path, allentries2[i].path, "test_iter_dir: Checking that getBatch(null) returns everything in the right order");
|
||||
}
|
||||
iterator.close();
|
||||
|
||||
// Test forEach
|
||||
iterator = new OS.File.DirectoryIterator(parent);
|
||||
let index = 0;
|
||||
iterator.forEach(
|
||||
function cb(entry, aIndex, aIterator) {
|
||||
is(index, aIndex, "test_iter_dir: Checking that forEach index is correct");
|
||||
ok(iterator == aIterator, "test_iter_dir: Checking that right iterator is passed");
|
||||
if (index < 10) {
|
||||
is(allentries[index].path, entry.path, "test_iter_dir: Checking that forEach entry is correct");
|
||||
} else if (index == 10) {
|
||||
iterator.close();
|
||||
} else {
|
||||
ok(false, "test_iter_dir: Checking that forEach can be stopped early");
|
||||
}
|
||||
++index;
|
||||
});
|
||||
iterator.close();
|
||||
|
||||
//test for prototype |OS.File.DirectoryIterator.unixAsFile|
|
||||
if ("unixAsFile" in OS.File.DirectoryIterator.prototype) {
|
||||
info("testing property unixAsFile");
|
||||
let path = OS.Path.join("chrome", "toolkit", "components", "osfile", "tests", "mochi");
|
||||
iterator = new OS.File.DirectoryIterator(path);
|
||||
|
||||
let dir_file = iterator.unixAsFile();// return |File|
|
||||
let stat0 = dir_file.stat();
|
||||
let stat1 = OS.File.stat(path);
|
||||
|
||||
let unix_info_to_string = function unix_info_to_string(info) {
|
||||
return "| " + info.unixMode + " | " + info.unixOwner + " | " + info.unixGroup + " | " + info.creationDate + " | " + info.lastModificationDate + " | " + info.lastAccessDate + " | " + info.size + " |";
|
||||
};
|
||||
|
||||
let s0_string = unix_info_to_string(stat0);
|
||||
let s1_string = unix_info_to_string(stat1);
|
||||
|
||||
ok(stat0.isDir, "unixAsFile returned a directory");
|
||||
is(s0_string, s1_string, "unixAsFile returned the correct file");
|
||||
dir_file.close();
|
||||
iterator.close();
|
||||
}
|
||||
info("test_iter_dir: Complete");
|
||||
}
|
||||
|
||||
function test_position() {
|
||||
info("test_position: Starting");
|
||||
|
||||
ok("POS_START" in OS.File, "test_position: POS_START exists");
|
||||
ok("POS_CURRENT" in OS.File, "test_position: POS_CURRENT exists");
|
||||
ok("POS_END" in OS.File, "test_position: POS_END exists");
|
||||
|
||||
let ARBITRARY_POSITION = 321;
|
||||
let src_file_name =
|
||||
OS.Path.join("chrome", "toolkit", "components", "osfile", "tests", "mochi",
|
||||
"worker_test_osfile_front.js");
|
||||
|
||||
let file = OS.File.open(src_file_name);
|
||||
is(file.getPosition(), 0, "test_position: Initial position is 0");
|
||||
|
||||
let size = 0 + file.stat().size; // Hack: We can remove this 0 + once 776259 has landed
|
||||
|
||||
file.setPosition(ARBITRARY_POSITION, OS.File.POS_START);
|
||||
is(file.getPosition(), ARBITRARY_POSITION, "test_position: Setting position from start");
|
||||
|
||||
file.setPosition(0, OS.File.POS_START);
|
||||
is(file.getPosition(), 0, "test_position: Setting position from start back to 0");
|
||||
|
||||
file.setPosition(ARBITRARY_POSITION);
|
||||
is(file.getPosition(), ARBITRARY_POSITION, "test_position: Setting position without argument");
|
||||
|
||||
file.setPosition(-ARBITRARY_POSITION, OS.File.POS_END);
|
||||
is(file.getPosition(), size - ARBITRARY_POSITION, "test_position: Setting position from end");
|
||||
|
||||
file.setPosition(ARBITRARY_POSITION, OS.File.POS_CURRENT);
|
||||
is(file.getPosition(), size, "test_position: Setting position from current");
|
||||
|
||||
file.close();
|
||||
info("test_position: Complete");
|
||||
}
|
||||
|
||||
function test_info() {
|
||||
info("test_info: Starting");
|
||||
|
||||
let filename = "test_info.tmp";
|
||||
let size = 261;// An arbitrary file length
|
||||
let start = new Date();
|
||||
|
||||
// Cleanup any leftover from previous tests
|
||||
try {
|
||||
OS.File.remove(filename);
|
||||
info("test_info: Cleaned up previous garbage");
|
||||
} catch (x) {
|
||||
if (!x.becauseNoSuchFile) {
|
||||
throw x;
|
||||
}
|
||||
info("test_info: No previous garbage");
|
||||
}
|
||||
|
||||
let file = OS.File.open(filename, {trunc: true});
|
||||
let buf = new ArrayBuffer(size);
|
||||
file._write(buf, size);
|
||||
file.close();
|
||||
|
||||
// Test OS.File.stat on new file
|
||||
let stat = OS.File.stat(filename);
|
||||
ok(!!stat, "test_info: info acquired");
|
||||
ok(!stat.isDir, "test_info: file is not a directory");
|
||||
is(stat.isSymLink, false, "test_info: file is not a link");
|
||||
is(stat.size.toString(), size, "test_info: correct size");
|
||||
|
||||
let stop = new Date();
|
||||
|
||||
// We round down/up by 1s as file system precision is lower than
|
||||
// Date precision (no clear specifications about that, but it seems
|
||||
// that this can be a little over 1 second under ext3 and 2 seconds
|
||||
// under FAT).
|
||||
let SLOPPY_FILE_SYSTEM_ADJUSTMENT = 3000;
|
||||
let startMs = start.getTime() - SLOPPY_FILE_SYSTEM_ADJUSTMENT;
|
||||
let stopMs = stop.getTime() + SLOPPY_FILE_SYSTEM_ADJUSTMENT;
|
||||
info("Testing stat with bounds [ " + startMs + ", " + stopMs +" ]");
|
||||
|
||||
(function() {
|
||||
let birth;
|
||||
if ("winBirthDate" in stat) {
|
||||
birth = stat.winBirthDate;
|
||||
} else if ("macBirthDate" in stat) {
|
||||
birth = stat.macBirthDate;
|
||||
} else {
|
||||
ok(true, "Skipping birthdate test");
|
||||
return;
|
||||
}
|
||||
ok(birth.getTime() <= stopMs,
|
||||
"test_info: platformBirthDate is consistent");
|
||||
// Note: Previous versions of this test checked whether the file
|
||||
// has been created after the start of the test. Unfortunately,
|
||||
// this sometimes failed under Windows, in specific circumstances:
|
||||
// if the file has been removed at the start of the test and
|
||||
// recreated immediately, the Windows file system detects this and
|
||||
// decides that the file was actually truncated rather than
|
||||
// recreated, hence that it should keep its previous creation
|
||||
// date. Debugging hilarity ensues.
|
||||
});
|
||||
|
||||
let change = stat.lastModificationDate;
|
||||
info("Testing lastModificationDate: " + change);
|
||||
ok(change.getTime() >= startMs && change.getTime() <= stopMs,
|
||||
"test_info: lastModificationDate is consistent");
|
||||
|
||||
// Test OS.File.prototype.stat on new file
|
||||
file = OS.File.open(filename);
|
||||
try {
|
||||
stat = file.stat();
|
||||
} finally {
|
||||
file.close();
|
||||
}
|
||||
|
||||
ok(!!stat, "test_info: info acquired 2");
|
||||
ok(!stat.isDir, "test_info: file is not a directory 2");
|
||||
ok(!stat.isSymLink, "test_info: file is not a link 2");
|
||||
is(stat.size.toString(), size, "test_info: correct size 2");
|
||||
|
||||
stop = new Date();
|
||||
|
||||
// Round up/down as above
|
||||
startMs = start.getTime() - SLOPPY_FILE_SYSTEM_ADJUSTMENT;
|
||||
stopMs = stop.getTime() + SLOPPY_FILE_SYSTEM_ADJUSTMENT;
|
||||
info("Testing stat 2 with bounds [ " + startMs + ", " + stopMs +" ]");
|
||||
|
||||
let access = stat.lastAccessDate;
|
||||
info("Testing lastAccessDate: " + access);
|
||||
ok(access.getTime() >= startMs && access.getTime() <= stopMs,
|
||||
"test_info: lastAccessDate is consistent");
|
||||
|
||||
change = stat.lastModificationDate;
|
||||
info("Testing lastModificationDate 2: " + change);
|
||||
ok(change.getTime() >= startMs && change.getTime() <= stopMs,
|
||||
"test_info: lastModificationDate 2 is consistent");
|
||||
|
||||
// Test OS.File.stat on directory
|
||||
stat = OS.File.stat(OS.File.getCurrentDirectory());
|
||||
ok(!!stat, "test_info: info on directory acquired");
|
||||
ok(stat.isDir, "test_info: directory is a directory");
|
||||
|
||||
info("test_info: Complete");
|
||||
}
|
||||
|
||||
// Note that most of the features of path are tested in
|
||||
// worker_test_osfile_{unix, win}.js
|
||||
function test_path()
|
||||
{
|
||||
info("test_path: starting");
|
||||
let abcd = OS.Path.join("a", "b", "c", "d");
|
||||
is(OS.Path.basename(abcd), "d", "basename of a/b/c/d");
|
||||
|
||||
let abc = OS.Path.join("a", "b", "c");
|
||||
is(OS.Path.dirname(abcd), abc, "dirname of a/b/c/d");
|
||||
|
||||
let abdotsc = OS.Path.join("a", "b", "..", "c");
|
||||
is(OS.Path.normalize(abdotsc), OS.Path.join("a", "c"), "normalize a/b/../c");
|
||||
|
||||
let adotsdotsdots = OS.Path.join("a", "..", "..", "..");
|
||||
is(OS.Path.normalize(adotsdotsdots), OS.Path.join("..", ".."), "normalize a/../../..");
|
||||
|
||||
info("test_path: Complete");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the file |exists| method.
|
||||
*/
|
||||
function test_exists_file()
|
||||
{
|
||||
let file_name = OS.Path.join("chrome", "toolkit", "components" ,"osfile",
|
||||
"tests", "mochi", "test_osfile_front.xul");
|
||||
info("test_exists_file: starting");
|
||||
ok(OS.File.exists(file_name), "test_exists_file: file exists (OS.File.exists)");
|
||||
ok(!OS.File.exists(file_name + ".tmp"), "test_exists_file: file does not exists (OS.File.exists)");
|
||||
|
||||
let dir_name = OS.Path.join("chrome", "toolkit", "components" ,"osfile",
|
||||
"tests", "mochi");
|
||||
ok(OS.File.exists(dir_name), "test_exists_file: directory exists");
|
||||
ok(!OS.File.exists(dir_name) + ".tmp", "test_exists_file: directory does not exist");
|
||||
|
||||
info("test_exists_file: complete");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the file |remove| method.
|
||||
*/
|
||||
function test_remove_file()
|
||||
{
|
||||
let absent_file_name = "test_osfile_front_absent.tmp";
|
||||
|
||||
// Check that removing absent files is handled correctly
|
||||
let exn = should_throw(function() {
|
||||
OS.File.remove(absent_file_name, {ignoreAbsent: false});
|
||||
});
|
||||
ok(!!exn, "test_remove_file: throws if there is no such file");
|
||||
|
||||
exn = should_throw(function() {
|
||||
OS.File.remove(absent_file_name, {ignoreAbsent: true});
|
||||
OS.File.remove(absent_file_name);
|
||||
});
|
||||
ok(!exn, "test_remove_file: ignoreAbsent works");
|
||||
|
||||
if (OS.Win) {
|
||||
let file_name = "test_osfile_front_file_to_remove.tmp";
|
||||
let file = OS.File.open(file_name, {write: true});
|
||||
file.close();
|
||||
ok(OS.File.exists(file_name), "test_remove_file: test file exists");
|
||||
OS.Win.File.SetFileAttributes(file_name,
|
||||
OS.Constants.Win.FILE_ATTRIBUTE_READONLY);
|
||||
OS.File.remove(file_name);
|
||||
ok(!OS.File.exists(file_name),
|
||||
"test_remove_file: test file has been removed");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function log(text) {
|
||||
dump("WORKER " + text + "\n");
|
||||
}
|
||||
|
||||
function send(message) {
|
||||
self.postMessage(message);
|
||||
}
|
||||
|
||||
function finish() {
|
||||
send({kind: "finish"});
|
||||
}
|
||||
|
||||
function ok(condition, description) {
|
||||
send({kind: "ok", condition: !!condition, description: "" + description});
|
||||
}
|
||||
|
||||
function is(a, b, description) {
|
||||
let outcome = a == b; // Need to decide outcome here, as not everything can be serialized
|
||||
send({kind: "is", outcome: outcome, description: "" + description, a: "" + a, b: "" + b});
|
||||
}
|
||||
|
||||
function isnot(a, b, description) {
|
||||
let outcome = a != b; // Need to decide outcome here, as not everything can be serialized
|
||||
send({kind: "isnot", outcome: outcome, description: "" + description, a: "" + a, b: "" + b});
|
||||
}
|
||||
|
||||
function info(description) {
|
||||
send({kind: "info", description: "" + description});
|
||||
}
|
||||
201
toolkit/components/osfile/tests/mochi/worker_test_osfile_unix.js
Normal file
201
toolkit/components/osfile/tests/mochi/worker_test_osfile_unix.js
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
importScripts('worker_test_osfile_shared.js');
|
||||
|
||||
self.onmessage = function(msg) {
|
||||
log("received message "+JSON.stringify(msg.data));
|
||||
self.onmessage = function(msg) {
|
||||
log("ignored message "+JSON.stringify(msg.data));
|
||||
};
|
||||
test_init();
|
||||
test_getcwd();
|
||||
test_open_close();
|
||||
test_create_file();
|
||||
test_access();
|
||||
test_read_write();
|
||||
test_passing_undefined();
|
||||
finish();
|
||||
};
|
||||
|
||||
function test_init() {
|
||||
info("Starting test_init");
|
||||
importScripts("resource://gre/modules/osfile.jsm");
|
||||
}
|
||||
|
||||
function test_open_close() {
|
||||
info("Starting test_open_close");
|
||||
is(typeof OS.Unix.File.open, "function", "OS.Unix.File.open is a function");
|
||||
let file = OS.Unix.File.open("chrome/toolkit/components/osfile/tests/mochi/worker_test_osfile_unix.js", OS.Constants.libc.O_RDONLY, 0);
|
||||
isnot(file, -1, "test_open_close: opening succeeded");
|
||||
info("Close: "+OS.Unix.File.close.toSource());
|
||||
let result = OS.Unix.File.close(file);
|
||||
is(result, 0, "test_open_close: close succeeded");
|
||||
|
||||
file = OS.Unix.File.open("/i do not exist", OS.Constants.libc.O_RDONLY, 0);
|
||||
is(file, -1, "test_open_close: opening of non-existing file failed");
|
||||
is(ctypes.errno, OS.Constants.libc.ENOENT, "test_open_close: error is ENOENT");
|
||||
}
|
||||
|
||||
function test_create_file()
|
||||
{
|
||||
info("Starting test_create_file");
|
||||
let file = OS.Unix.File.open("test.tmp", OS.Constants.libc.O_RDWR
|
||||
| OS.Constants.libc.O_CREAT
|
||||
| OS.Constants.libc.O_TRUNC,
|
||||
OS.Constants.libc.S_IRWXU);
|
||||
isnot(file, -1, "test_create_file: file created");
|
||||
OS.Unix.File.close(file);
|
||||
}
|
||||
|
||||
function test_access()
|
||||
{
|
||||
info("Starting test_access");
|
||||
let file = OS.Unix.File.open("test1.tmp", OS.Constants.libc.O_RDWR
|
||||
| OS.Constants.libc.O_CREAT
|
||||
| OS.Constants.libc.O_TRUNC,
|
||||
OS.Constants.libc.S_IRWXU);
|
||||
let result = OS.Unix.File.access("test1.tmp", OS.Constants.libc.R_OK | OS.Constants.libc.W_OK | OS.Constants.libc.X_OK | OS.Constants.libc.F_OK);
|
||||
is(result, 0, "first call to access() succeeded");
|
||||
OS.Unix.File.close(file);
|
||||
|
||||
file = OS.Unix.File.open("test1.tmp", OS.Constants.libc.O_WRONLY
|
||||
| OS.Constants.libc.O_CREAT
|
||||
| OS.Constants.libc.O_TRUNC,
|
||||
OS.Constants.libc.S_IWUSR);
|
||||
|
||||
info("test_access: preparing second call to access()");
|
||||
result = OS.Unix.File.access("test2.tmp", OS.Constants.libc.R_OK
|
||||
| OS.Constants.libc.W_OK
|
||||
| OS.Constants.libc.X_OK
|
||||
| OS.Constants.libc.F_OK);
|
||||
is(result, -1, "test_access: second call to access() failed as expected");
|
||||
is(ctypes.errno, OS.Constants.libc.ENOENT, "This is the correct error");
|
||||
OS.Unix.File.close(file);
|
||||
}
|
||||
|
||||
function test_getcwd()
|
||||
{
|
||||
let array = new (ctypes.ArrayType(ctypes.char, 32768))();
|
||||
let path = OS.Unix.File.getcwd(array, array.length);
|
||||
if (ctypes.char.ptr(path).isNull()) {
|
||||
ok(false, "test_get_cwd: getcwd returned null, errno: " + ctypes.errno);
|
||||
}
|
||||
let path2;
|
||||
if (OS.Unix.File.get_current_dir_name) {
|
||||
path2 = OS.Unix.File.get_current_dir_name();
|
||||
} else {
|
||||
path2 = OS.Unix.File.getwd_auto(null);
|
||||
}
|
||||
if (ctypes.char.ptr(path2).isNull()) {
|
||||
ok(false, "test_get_cwd: getwd_auto/get_current_dir_name returned null, errno: " + ctypes.errno);
|
||||
}
|
||||
is(path.readString(), path2.readString(), "test_get_cwd: getcwd and getwd return the same path");
|
||||
}
|
||||
|
||||
function test_read_write()
|
||||
{
|
||||
let output_name = "osfile_copy.tmp";
|
||||
// Copy file
|
||||
let input = OS.Unix.File.open(
|
||||
"chrome/toolkit/components/osfile/tests/mochi/worker_test_osfile_unix.js",
|
||||
OS.Constants.libc.O_RDONLY, 0);
|
||||
isnot(input, -1, "test_read_write: input file opened");
|
||||
let output = OS.Unix.File.open("osfile_copy.tmp", OS.Constants.libc.O_RDWR
|
||||
| OS.Constants.libc.O_CREAT
|
||||
| OS.Constants.libc.O_TRUNC,
|
||||
OS.Constants.libc.S_IRWXU);
|
||||
isnot(output, -1, "test_read_write: output file opened");
|
||||
|
||||
let array = new (ctypes.ArrayType(ctypes.char, 4096))();
|
||||
let bytes = -1;
|
||||
let total = 0;
|
||||
while (true) {
|
||||
bytes = OS.Unix.File.read(input, array, 4096);
|
||||
ok(bytes != undefined, "test_read_write: bytes is defined");
|
||||
isnot(bytes, -1, "test_read_write: no read error");
|
||||
let write_from = 0;
|
||||
if (bytes == 0) {
|
||||
break;
|
||||
}
|
||||
while (bytes > 0) {
|
||||
let ptr = array.addressOfElement(write_from);
|
||||
// Note: |write| launches an exception in case of error
|
||||
let written = OS.Unix.File.write(output, array, bytes);
|
||||
isnot(written, -1, "test_read_write: no write error");
|
||||
write_from += written;
|
||||
bytes -= written;
|
||||
}
|
||||
total += write_from;
|
||||
}
|
||||
info("test_read_write: copy complete " + total);
|
||||
|
||||
// Compare files
|
||||
let result;
|
||||
info("SEEK_SET: " + OS.Constants.libc.SEEK_SET);
|
||||
info("Input: " + input + "(" + input.toSource() + ")");
|
||||
info("Output: " + output + "(" + output.toSource() + ")");
|
||||
result = OS.Unix.File.lseek(input, 0, OS.Constants.libc.SEEK_SET);
|
||||
info("Result of lseek: " + result);
|
||||
isnot(result, -1, "test_read_write: input seek succeeded " + ctypes.errno);
|
||||
result = OS.Unix.File.lseek(output, 0, OS.Constants.libc.SEEK_SET);
|
||||
isnot(result, -1, "test_read_write: output seek succeeded " + ctypes.errno);
|
||||
|
||||
let array2 = new (ctypes.ArrayType(ctypes.char, 4096))();
|
||||
let bytes2 = -1;
|
||||
let pos = 0;
|
||||
while (true) {
|
||||
bytes = OS.Unix.File.read(input, array, 4096);
|
||||
isnot(bytes, -1, "test_read_write: input read succeeded");
|
||||
bytes2 = OS.Unix.File.read(output, array2, 4096);
|
||||
isnot(bytes, -1, "test_read_write: output read succeeded");
|
||||
is(bytes > 0, bytes2 > 0, "Both files contain data or neither does "+bytes+", "+bytes2);
|
||||
if (bytes == 0) {
|
||||
break;
|
||||
}
|
||||
if (bytes != bytes2) {
|
||||
// This would be surprising, but theoretically possible with a
|
||||
// remote file system, I believe.
|
||||
bytes = Math.min(bytes, bytes2);
|
||||
pos += bytes;
|
||||
result = OS.Unix.File.lseek(input, pos, OS.Constants.libc.SEEK_SET);
|
||||
isnot(result, -1, "test_read_write: input seek succeeded");
|
||||
result = OS.Unix.File.lseek(output, pos, OS.Constants.libc.SEEK_SET);
|
||||
isnot(result, -1, "test_read_write: output seek succeeded");
|
||||
} else {
|
||||
pos += bytes;
|
||||
}
|
||||
for (let i = 0; i < bytes; ++i) {
|
||||
if (array[i] != array2[i]) {
|
||||
ok(false, "Files do not match at position " + i
|
||||
+ " ("+array[i] + "/"+array2[i] + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
info("test_read_write test complete");
|
||||
result = OS.Unix.File.close(input);
|
||||
isnot(result, -1, "test_read_write: input close succeeded");
|
||||
result = OS.Unix.File.close(output);
|
||||
isnot(result, -1, "test_read_write: output close succeeded");
|
||||
result = OS.Unix.File.unlink(output_name);
|
||||
isnot(result, -1, "test_read_write: input remove succeeded");
|
||||
info("test_read_write cleanup complete");
|
||||
}
|
||||
|
||||
function test_passing_undefined()
|
||||
{
|
||||
info("Testing that an exception gets thrown when an FFI function is passed undefined");
|
||||
let exceptionRaised = false;
|
||||
|
||||
try {
|
||||
let file = OS.Unix.File.open(undefined, OS.Constants.libc.O_RDWR
|
||||
| OS.Constants.libc.O_CREAT
|
||||
| OS.Constants.libc.O_TRUNC,
|
||||
OS.Constants.libc.S_IRWXU);
|
||||
} catch(e if e instanceof TypeError && e.message.indexOf("open") > -1) {
|
||||
exceptionRaised = true;
|
||||
}
|
||||
|
||||
ok(exceptionRaised, "test_passing_undefined: exception gets thrown")
|
||||
}
|
||||
|
||||
211
toolkit/components/osfile/tests/mochi/worker_test_osfile_win.js
Normal file
211
toolkit/components/osfile/tests/mochi/worker_test_osfile_win.js
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
importScripts('worker_test_osfile_shared.js');
|
||||
|
||||
self.onmessage = function(msg) {
|
||||
self.onmessage = function(msg) {
|
||||
log("ignored message "+JSON.stringify(msg.data));
|
||||
};
|
||||
|
||||
test_init();
|
||||
test_GetCurrentDirectory();
|
||||
test_OpenClose();
|
||||
test_CreateFile();
|
||||
test_ReadWrite();
|
||||
test_passing_undefined();
|
||||
finish();
|
||||
};
|
||||
|
||||
function test_init() {
|
||||
info("Starting test_init");
|
||||
importScripts("resource://gre/modules/osfile.jsm");
|
||||
}
|
||||
|
||||
function test_OpenClose() {
|
||||
info("Starting test_OpenClose");
|
||||
is(typeof OS.Win.File.CreateFile, "function", "OS.Win.File.CreateFile is a function");
|
||||
is(OS.Win.File.CloseHandle(OS.Constants.Win.INVALID_HANDLE_VALUE), true, "CloseHandle returns true given the invalid handle");
|
||||
is(OS.Win.File.FindClose(OS.Constants.Win.INVALID_HANDLE_VALUE), true, "FindClose returns true given the invalid handle");
|
||||
isnot(OS.Constants.Win.GENERIC_READ, undefined, "GENERIC_READ exists");
|
||||
isnot(OS.Constants.Win.FILE_SHARE_READ, undefined, "FILE_SHARE_READ exists");
|
||||
isnot(OS.Constants.Win.FILE_ATTRIBUTE_NORMAL, undefined, "FILE_ATTRIBUTE_NORMAL exists");
|
||||
let file = OS.Win.File.CreateFile(
|
||||
"chrome\\toolkit\\components\\osfile\\tests\\mochi\\worker_test_osfile_win.js",
|
||||
OS.Constants.Win.GENERIC_READ,
|
||||
0,
|
||||
null,
|
||||
OS.Constants.Win.OPEN_EXISTING,
|
||||
0,
|
||||
null);
|
||||
info("test_OpenClose: Passed open");
|
||||
isnot(file, OS.Constants.Win.INVALID_HANDLE_VALUE, "test_OpenClose: file opened");
|
||||
let result = OS.Win.File.CloseHandle(file);
|
||||
isnot(result, 0, "test_OpenClose: close succeeded");
|
||||
|
||||
file = OS.Win.File.CreateFile(
|
||||
"\\I do not exist",
|
||||
OS.Constants.Win.GENERIC_READ,
|
||||
OS.Constants.Win.FILE_SHARE_READ,
|
||||
null,
|
||||
OS.Constants.Win.OPEN_EXISTING,
|
||||
OS.Constants.Win.FILE_ATTRIBUTE_NORMAL,
|
||||
null);
|
||||
is(file, OS.Constants.Win.INVALID_HANDLE_VALUE, "test_OpenClose: cannot open non-existing file");
|
||||
is(ctypes.winLastError, OS.Constants.Win.ERROR_FILE_NOT_FOUND, "test_OpenClose: error is ERROR_FILE_NOT_FOUND");
|
||||
}
|
||||
|
||||
function test_CreateFile()
|
||||
{
|
||||
info("Starting test_CreateFile");
|
||||
let file = OS.Win.File.CreateFile(
|
||||
"test.tmp",
|
||||
OS.Constants.Win.GENERIC_READ | OS.Constants.Win.GENERIC_WRITE,
|
||||
OS.Constants.Win.FILE_SHARE_READ | OS.Constants.FILE_SHARE_WRITE,
|
||||
null,
|
||||
OS.Constants.Win.CREATE_ALWAYS,
|
||||
OS.Constants.Win.FILE_ATTRIBUTE_NORMAL,
|
||||
null);
|
||||
isnot(file, OS.Constants.Win.INVALID_HANDLE_VALUE, "test_CreateFile: opening succeeded");
|
||||
let result = OS.Win.File.CloseHandle(file);
|
||||
isnot(result, 0, "test_CreateFile: close succeeded");
|
||||
}
|
||||
|
||||
function test_GetCurrentDirectory()
|
||||
{
|
||||
let array = new (ctypes.ArrayType(ctypes.char16_t, 4096))();
|
||||
let result = OS.Win.File.GetCurrentDirectory(4096, array);
|
||||
ok(result < array.length, "test_GetCurrentDirectory: length sufficient");
|
||||
ok(result > 0, "test_GetCurrentDirectory: length != 0");
|
||||
}
|
||||
|
||||
function test_ReadWrite()
|
||||
{
|
||||
info("Starting test_ReadWrite");
|
||||
let output_name = "osfile_copy.tmp";
|
||||
// Copy file
|
||||
let input = OS.Win.File.CreateFile(
|
||||
"chrome\\toolkit\\components\\osfile\\tests\\mochi\\worker_test_osfile_win.js",
|
||||
OS.Constants.Win.GENERIC_READ,
|
||||
0,
|
||||
null,
|
||||
OS.Constants.Win.OPEN_EXISTING,
|
||||
0,
|
||||
null);
|
||||
isnot(input, OS.Constants.Win.INVALID_HANDLE_VALUE, "test_ReadWrite: input file opened");
|
||||
let output = OS.Win.File.CreateFile(
|
||||
"osfile_copy.tmp",
|
||||
OS.Constants.Win.GENERIC_READ | OS.Constants.Win.GENERIC_WRITE,
|
||||
0,
|
||||
null,
|
||||
OS.Constants.Win.CREATE_ALWAYS,
|
||||
OS.Constants.Win.FILE_ATTRIBUTE_NORMAL,
|
||||
null);
|
||||
isnot(output, OS.Constants.Win.INVALID_HANDLE_VALUE, "test_ReadWrite: output file opened");
|
||||
let array = new (ctypes.ArrayType(ctypes.char, 4096))();
|
||||
let bytes_read = new ctypes.uint32_t(0);
|
||||
let bytes_read_ptr = bytes_read.address();
|
||||
log("We have a pointer for bytes read: "+bytes_read_ptr);
|
||||
let bytes_written = new ctypes.uint32_t(0);
|
||||
let bytes_written_ptr = bytes_written.address();
|
||||
log("We have a pointer for bytes written: "+bytes_written_ptr);
|
||||
log("test_ReadWrite: buffer and pointers ready");
|
||||
let result;
|
||||
while (true) {
|
||||
log("test_ReadWrite: reading");
|
||||
result = OS.Win.File.ReadFile(input, array, 4096, bytes_read_ptr, null);
|
||||
isnot (result, 0, "test_ReadWrite: read success");
|
||||
let write_from = 0;
|
||||
let bytes_left = bytes_read;
|
||||
log("test_ReadWrite: read chunk complete " + bytes_left.value);
|
||||
if (bytes_left.value == 0) {
|
||||
break;
|
||||
}
|
||||
while (bytes_left.value > 0) {
|
||||
log("test_ReadWrite: writing "+bytes_left.value);
|
||||
let ptr = array.addressOfElement(write_from);
|
||||
// Note: |WriteFile| launches an exception in case of error
|
||||
result = OS.Win.File.WriteFile(output, array, bytes_left, bytes_written_ptr, null);
|
||||
isnot (result, 0, "test_ReadWrite: write success");
|
||||
write_from += bytes_written;
|
||||
bytes_left -= bytes_written;
|
||||
}
|
||||
}
|
||||
info("test_ReadWrite: copy complete");
|
||||
|
||||
// Compare files
|
||||
result = OS.Win.File.SetFilePointer(input, 0, null, OS.Constants.Win.FILE_BEGIN);
|
||||
isnot (result, OS.Constants.Win.INVALID_SET_FILE_POINTER, "test_ReadWrite: input reset");
|
||||
|
||||
result = OS.Win.File.SetFilePointer(output, 0, null, OS.Constants.Win.FILE_BEGIN);
|
||||
isnot (result, OS.Constants.Win.INVALID_SET_FILE_POINTER, "test_ReadWrite: output reset");
|
||||
|
||||
let array2 = new (ctypes.ArrayType(ctypes.char, 4096))();
|
||||
let bytes_read2 = new ctypes.uint32_t(0);
|
||||
let bytes_read2_ptr = bytes_read2.address();
|
||||
let pos = 0;
|
||||
while (true) {
|
||||
result = OS.Win.File.ReadFile(input, array, 4096, bytes_read_ptr, null);
|
||||
isnot(result, 0, "test_ReadWrite: input read succeeded");
|
||||
|
||||
result = OS.Win.File.ReadFile(output, array2, 4096, bytes_read2_ptr, null);
|
||||
isnot(result, 0, "test_ReadWrite: output read succeeded");
|
||||
|
||||
is(bytes_read.value > 0, bytes_read2.value > 0,
|
||||
"Both files contain data or neither does " + bytes_read.value + ", " + bytes_read2.value);
|
||||
if (bytes_read.value == 0) {
|
||||
break;
|
||||
}
|
||||
let bytes;
|
||||
if (bytes_read.value != bytes_read2.value) {
|
||||
// This would be surprising, but theoretically possible with a
|
||||
// remote file system, I believe.
|
||||
bytes = Math.min(bytes_read.value, bytes_read2.value);
|
||||
pos += bytes;
|
||||
result = OS.Win.File.SetFilePointer(input, pos, null, OS.Constants.Win.FILE_BEGIN);
|
||||
isnot(result, 0, "test_ReadWrite: input seek succeeded");
|
||||
|
||||
result = OS.Win.File.SetFilePointer(output, pos, null, OS.Constants.Win.FILE_BEGIN);
|
||||
isnot(result, 0, "test_ReadWrite: output seek succeeded");
|
||||
|
||||
} else {
|
||||
bytes = bytes_read.value;
|
||||
pos += bytes;
|
||||
}
|
||||
for (let i = 0; i < bytes; ++i) {
|
||||
if (array[i] != array2[i]) {
|
||||
ok(false, "Files do not match at position " + i
|
||||
+ " ("+array[i] + "/"+array2[i] + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
info("test_ReadWrite test complete");
|
||||
result = OS.Win.File.CloseHandle(input);
|
||||
isnot(result, 0, "test_ReadWrite: inpout close succeeded");
|
||||
result = OS.Win.File.CloseHandle(output);
|
||||
isnot(result, 0, "test_ReadWrite: outpout close succeeded");
|
||||
result = OS.Win.File.DeleteFile(output_name);
|
||||
isnot(result, 0, "test_ReadWrite: output remove succeeded");
|
||||
info("test_ReadWrite cleanup complete");
|
||||
}
|
||||
|
||||
function test_passing_undefined()
|
||||
{
|
||||
info("Testing that an exception gets thrown when an FFI function is passed undefined");
|
||||
let exceptionRaised = false;
|
||||
|
||||
try {
|
||||
let file = OS.Win.File.CreateFile(
|
||||
undefined,
|
||||
OS.Constants.Win.GENERIC_READ,
|
||||
0,
|
||||
null,
|
||||
OS.Constants.Win.OPEN_EXISTING,
|
||||
0,
|
||||
null);
|
||||
} catch(e if e instanceof TypeError && e.message.indexOf("CreateFile") > -1) {
|
||||
exceptionRaised = true;
|
||||
}
|
||||
|
||||
ok(exceptionRaised, "test_passing_undefined: exception gets thrown")
|
||||
}
|
||||
7
toolkit/components/osfile/tests/xpcshell/.eslintrc.js
Normal file
7
toolkit/components/osfile/tests/xpcshell/.eslintrc.js
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"../../../../../testing/xpcshell/xpcshell.eslintrc.js"
|
||||
]
|
||||
};
|
||||
99
toolkit/components/osfile/tests/xpcshell/head.js
Normal file
99
toolkit/components/osfile/tests/xpcshell/head.js
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
var {utils: Cu, interfaces: Ci} = Components;
|
||||
|
||||
var {XPCOMUtils} = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
|
||||
|
||||
// Bug 1014484 can only be reproduced by loading OS.File first from the
|
||||
// CommonJS loader, so we do not want OS.File to be loaded eagerly for
|
||||
// all the tests in this directory.
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
||||
"resource://gre/modules/osfile.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
||||
"resource://gre/modules/FileUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||
"resource://gre/modules/NetUtil.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
||||
"resource://gre/modules/Services.jsm");
|
||||
|
||||
var {Promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||
var {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
|
||||
|
||||
Services.prefs.setBoolPref("toolkit.osfile.log", true);
|
||||
|
||||
/**
|
||||
* As add_task, but execute the test both with native operations and
|
||||
* without.
|
||||
*/
|
||||
function add_test_pair(generator) {
|
||||
add_task(function*() {
|
||||
do_print("Executing test " + generator.name + " with native operations");
|
||||
Services.prefs.setBoolPref("toolkit.osfile.native", true);
|
||||
return Task.spawn(generator);
|
||||
});
|
||||
add_task(function*() {
|
||||
do_print("Executing test " + generator.name + " without native operations");
|
||||
Services.prefs.setBoolPref("toolkit.osfile.native", false);
|
||||
return Task.spawn(generator);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch asynchronously the contents of a file using xpcom.
|
||||
*
|
||||
* Used for comparing xpcom-based results to os.file-based results.
|
||||
*
|
||||
* @param {string} path The _absolute_ path to the file.
|
||||
* @return {promise}
|
||||
* @resolves {string} The contents of the file.
|
||||
*/
|
||||
function reference_fetch_file(path, test) {
|
||||
do_print("Fetching file " + path);
|
||||
let deferred = Promise.defer();
|
||||
let file = new FileUtils.File(path);
|
||||
NetUtil.asyncFetch({
|
||||
uri: NetUtil.newURI(file),
|
||||
loadUsingSystemPrincipal: true
|
||||
}, function(stream, status) {
|
||||
if (!Components.isSuccessCode(status)) {
|
||||
deferred.reject(status);
|
||||
return;
|
||||
}
|
||||
let result, reject;
|
||||
try {
|
||||
result = NetUtil.readInputStreamToString(stream, stream.available());
|
||||
} catch (x) {
|
||||
reject = x;
|
||||
}
|
||||
stream.close();
|
||||
if (reject) {
|
||||
deferred.reject(reject);
|
||||
} else {
|
||||
deferred.resolve(result);
|
||||
}
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
/**
|
||||
* Compare asynchronously the contents two files using xpcom.
|
||||
*
|
||||
* Used for comparing xpcom-based results to os.file-based results.
|
||||
*
|
||||
* @param {string} a The _absolute_ path to the first file.
|
||||
* @param {string} b The _absolute_ path to the second file.
|
||||
*
|
||||
* @resolves {null}
|
||||
*/
|
||||
function reference_compare_files(a, b, test) {
|
||||
return Task.spawn(function*() {
|
||||
do_print("Comparing files " + a + " and " + b);
|
||||
let a_contents = yield reference_fetch_file(a, test);
|
||||
let b_contents = yield reference_fetch_file(b, test);
|
||||
do_check_eq(a_contents, b_contents);
|
||||
});
|
||||
};
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
do_register_cleanup(function() {
|
||||
Services.prefs.setBoolPref("toolkit.osfile.log", false);
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
Services.prefs.setBoolPref("toolkit.osfile.log", true);
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test OS.File.getAvailableFreeSpace
|
||||
*/
|
||||
add_task(function() {
|
||||
// Set up profile. We will use profile path to query for available free
|
||||
// space.
|
||||
do_get_profile();
|
||||
|
||||
let dir = OS.Constants.Path.profileDir;
|
||||
|
||||
// Sanity checking for the test
|
||||
do_check_true((yield OS.File.exists(dir)));
|
||||
|
||||
// Query for available bytes for user
|
||||
let availableBytes = yield OS.File.getAvailableFreeSpace(dir);
|
||||
|
||||
do_check_true(!!availableBytes);
|
||||
do_check_true(availableBytes > 0);
|
||||
});
|
||||
98
toolkit/components/osfile/tests/xpcshell/test_compression.js
Normal file
98
toolkit/components/osfile/tests/xpcshell/test_compression.js
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
|
||||
function run_test() {
|
||||
do_test_pending();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function test_compress_lz4() {
|
||||
let path = OS.Path.join(OS.Constants.Path.tmpDir, "compression.lz");
|
||||
let length = 1024;
|
||||
let array = new Uint8Array(length);
|
||||
for (let i = 0; i < array.byteLength; ++i) {
|
||||
array[i] = i;
|
||||
}
|
||||
let arrayAsString = Array.prototype.join.call(array);
|
||||
|
||||
do_print("Writing data with lz4 compression");
|
||||
let bytes = yield OS.File.writeAtomic(path, array, { compression: "lz4" });
|
||||
do_print("Compressed " + length + " bytes into " + bytes);
|
||||
|
||||
do_print("Reading back with lz4 decompression");
|
||||
let decompressed = yield OS.File.read(path, { compression: "lz4" });
|
||||
do_print("Decompressed into " + decompressed.byteLength + " bytes");
|
||||
do_check_eq(arrayAsString, Array.prototype.join.call(decompressed));
|
||||
});
|
||||
|
||||
add_task(function test_uncompressed() {
|
||||
do_print("Writing data without compression");
|
||||
let path = OS.Path.join(OS.Constants.Path.tmpDir, "no_compression.tmp");
|
||||
let array = new Uint8Array(1024);
|
||||
for (let i = 0; i < array.byteLength; ++i) {
|
||||
array[i] = i;
|
||||
}
|
||||
let bytes = yield OS.File.writeAtomic(path, array); // No compression
|
||||
|
||||
let exn;
|
||||
// Force decompression, reading should fail
|
||||
try {
|
||||
yield OS.File.read(path, { compression: "lz4" });
|
||||
} catch (ex) {
|
||||
exn = ex;
|
||||
}
|
||||
do_check_true(!!exn);
|
||||
// Check the exception message (and that it contains the file name)
|
||||
do_check_true(exn.message.indexOf(`Invalid header (no magic number) - Data: ${ path }`) != -1);
|
||||
});
|
||||
|
||||
add_task(function test_no_header() {
|
||||
let path = OS.Path.join(OS.Constants.Path.tmpDir, "no_header.tmp");
|
||||
let array = new Uint8Array(8).fill(0,0); // Small array with no header
|
||||
|
||||
do_print("Writing data with no header");
|
||||
|
||||
let bytes = yield OS.File.writeAtomic(path, array); // No compression
|
||||
let exn;
|
||||
// Force decompression, reading should fail
|
||||
try {
|
||||
yield OS.File.read(path, { compression: "lz4" });
|
||||
} catch (ex) {
|
||||
exn = ex;
|
||||
}
|
||||
do_check_true(!!exn);
|
||||
// Check the exception message (and that it contains the file name)
|
||||
do_check_true(exn.message.indexOf(`Buffer is too short (no header) - Data: ${ path }`) != -1);
|
||||
});
|
||||
|
||||
add_task(function test_invalid_content() {
|
||||
let path = OS.Path.join(OS.Constants.Path.tmpDir, "invalid_content.tmp");
|
||||
let arr1 = new Uint8Array([109, 111, 122, 76, 122, 52, 48, 0]);
|
||||
let arr2 = new Uint8Array(248).fill(1,0);
|
||||
|
||||
let array = new Uint8Array(arr1.length + arr2.length);
|
||||
array.set(arr1);
|
||||
array.set(arr2, arr1.length);
|
||||
|
||||
do_print("Writing invalid data (with a valid header and only ones after that)");
|
||||
|
||||
let bytes = yield OS.File.writeAtomic(path, array); // No compression
|
||||
let exn;
|
||||
// Force decompression, reading should fail
|
||||
try {
|
||||
yield OS.File.read(path, { compression: "lz4" });
|
||||
} catch (ex) {
|
||||
exn = ex;
|
||||
}
|
||||
do_check_true(!!exn);
|
||||
// Check the exception message (and that it contains the file name)
|
||||
do_check_true(exn.message.indexOf(`Invalid content: Decompression stopped at 0 - Data: ${ path }`) != -1);
|
||||
});
|
||||
|
||||
add_task(function() {
|
||||
do_test_finished();
|
||||
});
|
||||
31
toolkit/components/osfile/tests/xpcshell/test_constants.js
Normal file
31
toolkit/components/osfile/tests/xpcshell/test_constants.js
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm", this);
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
// Test that OS.Constants is defined correctly.
|
||||
add_task(function* check_definition() {
|
||||
do_check_true(OS.Constants!=null);
|
||||
do_check_true(!!OS.Constants.Win || !!OS.Constants.libc);
|
||||
do_check_true(OS.Constants.Path!=null);
|
||||
do_check_true(OS.Constants.Sys!=null);
|
||||
//check system name
|
||||
if (OS.Constants.Sys.Name == "Gonk") {
|
||||
// Services.appinfo.OS doesn't know the difference between Gonk and Android
|
||||
do_check_eq(Services.appinfo.OS, "Android");
|
||||
} else {
|
||||
do_check_eq(Services.appinfo.OS, OS.Constants.Sys.Name);
|
||||
}
|
||||
|
||||
//check if using DEBUG build
|
||||
if (Components.classes["@mozilla.org/xpcom/debug;1"].getService(Components.interfaces.nsIDebug2).isDebugBuild == true) {
|
||||
do_check_true(OS.Constants.Sys.DEBUG);
|
||||
} else {
|
||||
do_check_true(typeof(OS.Constants.Sys.DEBUG) == 'undefined');
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
"use strict";
|
||||
|
||||
function run_test() {
|
||||
do_test_pending();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to ensure that deprecation warning is issued on use
|
||||
* of creationDate.
|
||||
*/
|
||||
add_task(function test_deprecatedCreationDate () {
|
||||
let deferred = Promise.defer();
|
||||
let consoleListener = {
|
||||
observe: function (aMessage) {
|
||||
if(aMessage.message.indexOf("Field 'creationDate' is deprecated.") > -1) {
|
||||
do_print("Deprecation message printed");
|
||||
do_check_true(true);
|
||||
Services.console.unregisterListener(consoleListener);
|
||||
deferred.resolve();
|
||||
}
|
||||
}
|
||||
};
|
||||
let currentDir = yield OS.File.getCurrentDirectory();
|
||||
let path = OS.Path.join(currentDir, "test_creationDate.js");
|
||||
|
||||
Services.console.registerListener(consoleListener);
|
||||
(yield OS.File.stat(path)).creationDate;
|
||||
});
|
||||
|
||||
add_task(do_test_finished);
|
||||
91
toolkit/components/osfile/tests/xpcshell/test_duration.js
Normal file
91
toolkit/components/osfile/tests/xpcshell/test_duration.js
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
var {OS} = Components.utils.import("resource://gre/modules/osfile.jsm", {});
|
||||
var {Services} = Components.utils.import("resource://gre/modules/Services.jsm", {});
|
||||
|
||||
/**
|
||||
* Test optional duration reporting that can be used for telemetry.
|
||||
*/
|
||||
add_task(function* duration() {
|
||||
Services.prefs.setBoolPref("toolkit.osfile.log", true);
|
||||
// Options structure passed to a OS.File copy method.
|
||||
let copyOptions = {
|
||||
// This field should be overridden with the actual duration
|
||||
// measurement.
|
||||
outExecutionDuration: null
|
||||
};
|
||||
let currentDir = yield OS.File.getCurrentDirectory();
|
||||
let pathSource = OS.Path.join(currentDir, "test_duration.js");
|
||||
let copyFile = pathSource + ".bak";
|
||||
function testOptions(options, name) {
|
||||
do_print("Checking outExecutionDuration for operation: " + name);
|
||||
do_print(name + ": Gathered method duration time: " +
|
||||
options.outExecutionDuration + "ms");
|
||||
// Making sure that duration was updated.
|
||||
do_check_eq(typeof options.outExecutionDuration, "number");
|
||||
do_check_true(options.outExecutionDuration >= 0);
|
||||
};
|
||||
// Testing duration of OS.File.copy.
|
||||
yield OS.File.copy(pathSource, copyFile, copyOptions);
|
||||
testOptions(copyOptions, "OS.File.copy");
|
||||
yield OS.File.remove(copyFile);
|
||||
|
||||
// Trying an operation where options are cloned.
|
||||
let pathDest = OS.Path.join(OS.Constants.Path.tmpDir,
|
||||
"osfile async test read writeAtomic.tmp");
|
||||
let tmpPath = pathDest + ".tmp";
|
||||
let readOptions = {
|
||||
outExecutionDuration: null
|
||||
};
|
||||
let contents = yield OS.File.read(pathSource, undefined, readOptions);
|
||||
testOptions(readOptions, "OS.File.read");
|
||||
// Options structure passed to a OS.File writeAtomic method.
|
||||
let writeAtomicOptions = {
|
||||
// This field should be first initialized with the actual
|
||||
// duration measurement then progressively incremented.
|
||||
outExecutionDuration: null,
|
||||
tmpPath: tmpPath
|
||||
};
|
||||
yield OS.File.writeAtomic(pathDest, contents, writeAtomicOptions);
|
||||
testOptions(writeAtomicOptions, "OS.File.writeAtomic");
|
||||
yield OS.File.remove(pathDest);
|
||||
|
||||
do_print("Ensuring that we can use outExecutionDuration to accumulate durations");
|
||||
|
||||
let ARBITRARY_BASE_DURATION = 5;
|
||||
copyOptions = {
|
||||
// This field should now be incremented with the actual duration
|
||||
// measurement.
|
||||
outExecutionDuration: ARBITRARY_BASE_DURATION
|
||||
};
|
||||
let backupDuration = ARBITRARY_BASE_DURATION;
|
||||
// Testing duration of OS.File.copy.
|
||||
yield OS.File.copy(pathSource, copyFile, copyOptions);
|
||||
|
||||
do_check_true(copyOptions.outExecutionDuration >= backupDuration);
|
||||
|
||||
backupDuration = copyOptions.outExecutionDuration;
|
||||
yield OS.File.remove(copyFile, copyOptions);
|
||||
do_check_true(copyOptions.outExecutionDuration >= backupDuration);
|
||||
|
||||
// Trying an operation where options are cloned.
|
||||
// Options structure passed to a OS.File writeAtomic method.
|
||||
writeAtomicOptions = {
|
||||
// This field should be overridden with the actual duration
|
||||
// measurement.
|
||||
outExecutionDuration: copyOptions.outExecutionDuration,
|
||||
tmpPath: tmpPath
|
||||
};
|
||||
backupDuration = writeAtomicOptions.outExecutionDuration;
|
||||
|
||||
yield OS.File.writeAtomic(pathDest, contents, writeAtomicOptions);
|
||||
do_check_true(copyOptions.outExecutionDuration >= backupDuration);
|
||||
OS.File.remove(pathDest);
|
||||
|
||||
// Testing an operation that doesn't take arguments at all
|
||||
let file = yield OS.File.open(pathSource);
|
||||
yield file.stat();
|
||||
yield file.close();
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
89
toolkit/components/osfile/tests/xpcshell/test_exception.js
Normal file
89
toolkit/components/osfile/tests/xpcshell/test_exception.js
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Test that functions throw the appropriate exceptions.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
var EXISTING_FILE = do_get_file("xpcshell.ini").path;
|
||||
|
||||
|
||||
// Tests on |open|
|
||||
|
||||
add_test_pair(function test_typeerror() {
|
||||
let exn;
|
||||
try {
|
||||
let fd = yield OS.File.open("/tmp", {no_such_key: 1});
|
||||
do_print("Fd: " + fd);
|
||||
} catch (ex) {
|
||||
exn = ex;
|
||||
}
|
||||
do_print("Exception: " + exn);
|
||||
do_check_true(exn.constructor.name == "TypeError");
|
||||
});
|
||||
|
||||
// Tests on |read|
|
||||
|
||||
add_test_pair(function* test_bad_encoding() {
|
||||
do_print("Testing with a wrong encoding");
|
||||
try {
|
||||
yield OS.File.read(EXISTING_FILE, { encoding: "baby-speak-encoded" });
|
||||
do_throw("Should have thrown with an ex.becauseInvalidArgument");
|
||||
} catch (ex if ex.becauseInvalidArgument) {
|
||||
do_print("Wrong encoding caused the correct exception");
|
||||
}
|
||||
|
||||
try {
|
||||
yield OS.File.read(EXISTING_FILE, { encoding: 4 });
|
||||
do_throw("Should have thrown a TypeError");
|
||||
} catch (ex if ex.constructor.name == "TypeError") {
|
||||
// Note that TypeError doesn't carry across compartments
|
||||
do_print("Non-string encoding caused the correct exception");
|
||||
}
|
||||
});
|
||||
|
||||
add_test_pair(function* test_bad_compression() {
|
||||
do_print("Testing with a non-existing compression");
|
||||
try {
|
||||
yield OS.File.read(EXISTING_FILE, { compression: "mmmh-crunchy" });
|
||||
do_throw("Should have thrown with an ex.becauseInvalidArgument");
|
||||
} catch (ex if ex.becauseInvalidArgument) {
|
||||
do_print("Wrong encoding caused the correct exception");
|
||||
}
|
||||
|
||||
do_print("Testing with a bad type for option compression");
|
||||
try {
|
||||
yield OS.File.read(EXISTING_FILE, { compression: 5 });
|
||||
do_throw("Should have thrown a TypeError");
|
||||
} catch (ex if ex.constructor.name == "TypeError") {
|
||||
// Note that TypeError doesn't carry across compartments
|
||||
do_print("Non-string encoding caused the correct exception");
|
||||
}
|
||||
});
|
||||
|
||||
add_test_pair(function* test_bad_bytes() {
|
||||
do_print("Testing with a bad type for option bytes");
|
||||
try {
|
||||
yield OS.File.read(EXISTING_FILE, { bytes: "five" });
|
||||
do_throw("Should have thrown a TypeError");
|
||||
} catch (ex if ex.constructor.name == "TypeError") {
|
||||
// Note that TypeError doesn't carry across compartments
|
||||
do_print("Non-number bytes caused the correct exception");
|
||||
}
|
||||
});
|
||||
|
||||
add_test_pair(function* read_non_existent() {
|
||||
do_print("Testing with a non-existent file");
|
||||
try {
|
||||
yield OS.File.read("I/do/not/exist");
|
||||
do_throw("Should have thrown with an ex.becauseNoSuchFile");
|
||||
} catch (ex if ex.becauseNoSuchFile) {
|
||||
do_print("Correct exceptions");
|
||||
}
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
/* 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/. */
|
||||
|
||||
function run_test() {
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
Components.utils.import("resource://gre/modules/FileUtils.jsm");
|
||||
|
||||
let isWindows = ("@mozilla.org/windows-registry-key;1" in Components.classes);
|
||||
|
||||
// Test cases for filePathToURI
|
||||
let paths = isWindows ? [
|
||||
'C:\\',
|
||||
'C:\\test',
|
||||
'C:\\test\\',
|
||||
'C:\\test%2f',
|
||||
'C:\\test\\test\\test',
|
||||
'C:\\test;+%',
|
||||
'C:\\test?action=index\\',
|
||||
'C:\\test\ test',
|
||||
'\\\\C:\\a\\b\\c',
|
||||
'\\\\Server\\a\\b\\c',
|
||||
|
||||
// note that per http://support.microsoft.com/kb/177506 (under more info),
|
||||
// the following characters are allowed on Windows:
|
||||
'C:\\char^',
|
||||
'C:\\char&',
|
||||
'C:\\char\'',
|
||||
'C:\\char@',
|
||||
'C:\\char{',
|
||||
'C:\\char}',
|
||||
'C:\\char[',
|
||||
'C:\\char]',
|
||||
'C:\\char,',
|
||||
'C:\\char$',
|
||||
'C:\\char=',
|
||||
'C:\\char!',
|
||||
'C:\\char-',
|
||||
'C:\\char#',
|
||||
'C:\\char(',
|
||||
'C:\\char)',
|
||||
'C:\\char%',
|
||||
'C:\\char.',
|
||||
'C:\\char+',
|
||||
'C:\\char~',
|
||||
'C:\\char_'
|
||||
] : [
|
||||
'/',
|
||||
'/test',
|
||||
'/test/',
|
||||
'/test%2f',
|
||||
'/test/test/test',
|
||||
'/test;+%',
|
||||
'/test?action=index/',
|
||||
'/test\ test',
|
||||
'/punctuation/;,/?:@&=+$-_.!~*\'()[]"#',
|
||||
'/CasePreserving'
|
||||
];
|
||||
|
||||
// some additional URIs to test, beyond those generated from paths
|
||||
let uris = isWindows ? [
|
||||
'file:///C:/test/',
|
||||
'file://localhost/C:/test',
|
||||
'file:///c:/test/test.txt',
|
||||
//'file:///C:/foo%2f', // trailing, encoded slash
|
||||
'file:///C:/%3f%3F',
|
||||
'file:///C:/%3b%3B',
|
||||
'file:///C:/%3c%3C', // not one of the special-cased ? or ;
|
||||
'file:///C:/%78', // 'x', not usually uri encoded
|
||||
'file:///C:/test#frag', // a fragment identifier
|
||||
'file:///C:/test?action=index' // an actual query component
|
||||
] : [
|
||||
'file:///test/',
|
||||
'file://localhost/test',
|
||||
'file:///test/test.txt',
|
||||
'file:///foo%2f', // trailing, encoded slash
|
||||
'file:///%3f%3F',
|
||||
'file:///%3b%3B',
|
||||
'file:///%3c%3C', // not one of the special-cased ? or ;
|
||||
'file:///%78', // 'x', not usually uri encoded
|
||||
'file:///test#frag', // a fragment identifier
|
||||
'file:///test?action=index' // an actual query component
|
||||
];
|
||||
|
||||
for (let path of paths) {
|
||||
// convert that to a uri using FileUtils and Services, which toFileURI is trying to model
|
||||
let file = FileUtils.File(path);
|
||||
let uri = Services.io.newFileURI(file).spec;
|
||||
do_check_eq(uri, OS.Path.toFileURI(path));
|
||||
|
||||
// keep the resulting URI to try the reverse, except for "C:\" for which the
|
||||
// behavior of nsIFileURL and OS.File is inconsistent
|
||||
if (path != "C:\\") {
|
||||
uris.push(uri);
|
||||
}
|
||||
}
|
||||
|
||||
for (let uri of uris) {
|
||||
// convert URIs to paths with nsIFileURI, which fromFileURI is trying to model
|
||||
let path = Services.io.newURI(uri, null, null).QueryInterface(Components.interfaces.nsIFileURL).file.path;
|
||||
do_check_eq(path, OS.Path.fromFileURI(uri));
|
||||
}
|
||||
|
||||
// check that non-file URLs aren't allowed
|
||||
let thrown = false;
|
||||
try {
|
||||
OS.Path.fromFileURI('http://test.com')
|
||||
} catch (e) {
|
||||
do_check_eq(e.message, "fromFileURI expects a file URI");
|
||||
thrown = true;
|
||||
}
|
||||
do_check_true(thrown);
|
||||
}
|
||||
37
toolkit/components/osfile/tests/xpcshell/test_loader.js
Normal file
37
toolkit/components/osfile/tests/xpcshell/test_loader.js
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Test that OS.File can be loaded using the CommonJS loader.
|
||||
*/
|
||||
|
||||
var { Loader } = Components.utils.import('resource://gre/modules/commonjs/toolkit/loader.js', {});
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
|
||||
add_task(function*() {
|
||||
let dataDir = Services.io.newFileURI(do_get_file("test_loader/", true)).spec + "/";
|
||||
let loader = Loader.Loader({
|
||||
paths: {'': dataDir }
|
||||
});
|
||||
|
||||
let require = Loader.Require(loader, Loader.Module('module_test_loader', 'foo'));
|
||||
do_print("Require is ready");
|
||||
try {
|
||||
require('module_test_loader');
|
||||
} catch (error) {
|
||||
dump('Bootstrap error: ' +
|
||||
(error.message ? error.message : String(error)) + '\n' +
|
||||
(error.stack || error.fileName + ': ' + error.lineNumber) + '\n');
|
||||
|
||||
throw error;
|
||||
}
|
||||
|
||||
do_print("Require has worked");
|
||||
});
|
||||
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Load OS.File from a module loaded with the CommonJS/addon-sdk loader
|
||||
|
||||
var {Cu} = require("chrome");
|
||||
Cu.import('resource://gre/modules/osfile.jsm');
|
||||
74
toolkit/components/osfile/tests/xpcshell/test_logging.js
Normal file
74
toolkit/components/osfile/tests/xpcshell/test_logging.js
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
/**
|
||||
* Tests logging by passing OS.Shared.LOG both an object with its own
|
||||
* toString method, and one with the default.
|
||||
*/
|
||||
function run_test() {
|
||||
do_test_pending();
|
||||
let messageCount = 0;
|
||||
|
||||
do_print("Test starting");
|
||||
|
||||
// Create a console listener.
|
||||
let consoleListener = {
|
||||
observe: function (aMessage) {
|
||||
//Ignore unexpected messages.
|
||||
if (!(aMessage instanceof Components.interfaces.nsIConsoleMessage)) {
|
||||
return;
|
||||
}
|
||||
// This is required, as printing to the |Services.console|
|
||||
// while in the observe function causes an exception.
|
||||
do_execute_soon(function() {
|
||||
do_print("Observing message " + aMessage.message);
|
||||
if (aMessage.message.indexOf("TEST OS") < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
++messageCount;
|
||||
if(messageCount == 1) {
|
||||
do_check_eq(aMessage.message, "TEST OS {\"name\":\"test\"}\n");
|
||||
}
|
||||
if(messageCount == 2) {
|
||||
do_check_eq(aMessage.message, "TEST OS name is test\n");
|
||||
toggleConsoleListener(false);
|
||||
do_test_finished();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Set/Unset the console listener.
|
||||
function toggleConsoleListener (pref) {
|
||||
do_print("Setting console listener: " + pref);
|
||||
Services.prefs.setBoolPref("toolkit.osfile.log", pref);
|
||||
Services.prefs.setBoolPref("toolkit.osfile.log.redirect", pref);
|
||||
Services.console[pref ? "registerListener" : "unregisterListener"](
|
||||
consoleListener);
|
||||
}
|
||||
|
||||
toggleConsoleListener(true);
|
||||
|
||||
let objectDefault = {name: "test"};
|
||||
let CustomToString = function() {
|
||||
this.name = "test";
|
||||
};
|
||||
CustomToString.prototype.toString = function() {
|
||||
return "name is " + this.name;
|
||||
};
|
||||
let objectCustom = new CustomToString();
|
||||
|
||||
do_print(OS.Shared.LOG.toSource());
|
||||
|
||||
do_print("Logging 1");
|
||||
OS.Shared.LOG(objectDefault);
|
||||
|
||||
do_print("Logging 2");
|
||||
OS.Shared.LOG(objectCustom);
|
||||
// Once both messages are observed OS.Shared.DEBUG, and OS.Shared.TEST
|
||||
// are reset to false.
|
||||
}
|
||||
|
||||
142
toolkit/components/osfile/tests/xpcshell/test_makeDir.js
Normal file
142
toolkit/components/osfile/tests/xpcshell/test_makeDir.js
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
var Path = OS.Path;
|
||||
var profileDir;
|
||||
|
||||
do_register_cleanup(function() {
|
||||
Services.prefs.setBoolPref("toolkit.osfile.log", false);
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test OS.File.makeDir
|
||||
*/
|
||||
|
||||
add_task(function init() {
|
||||
// Set up profile. We create the directory in the profile, because the profile
|
||||
// is removed after every test run.
|
||||
do_get_profile();
|
||||
profileDir = OS.Constants.Path.profileDir;
|
||||
Services.prefs.setBoolPref("toolkit.osfile.log", true);
|
||||
});
|
||||
|
||||
/**
|
||||
* Basic use
|
||||
*/
|
||||
|
||||
add_task(function* test_basic() {
|
||||
let dir = Path.join(profileDir, "directory");
|
||||
|
||||
// Sanity checking for the test
|
||||
do_check_false((yield OS.File.exists(dir)));
|
||||
|
||||
// Make a directory
|
||||
yield OS.File.makeDir(dir);
|
||||
|
||||
//check if the directory exists
|
||||
yield OS.File.stat(dir);
|
||||
|
||||
// Make a directory that already exists, this should succeed
|
||||
yield OS.File.makeDir(dir);
|
||||
|
||||
// Make a directory with ignoreExisting
|
||||
yield OS.File.makeDir(dir, {ignoreExisting: true});
|
||||
|
||||
// Make a directory with ignoreExisting false
|
||||
let exception = null;
|
||||
try {
|
||||
yield OS.File.makeDir(dir, {ignoreExisting: false});
|
||||
} catch (ex) {
|
||||
exception = ex;
|
||||
}
|
||||
|
||||
do_check_true(!!exception);
|
||||
do_check_true(exception instanceof OS.File.Error);
|
||||
do_check_true(exception.becauseExists);
|
||||
});
|
||||
|
||||
// Make a root directory that already exists
|
||||
add_task(function* test_root() {
|
||||
if (OS.Constants.Win) {
|
||||
yield OS.File.makeDir("C:");
|
||||
yield OS.File.makeDir("C:\\");
|
||||
} else {
|
||||
yield OS.File.makeDir("/");
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Creating subdirectories
|
||||
*/
|
||||
add_task(function test_option_from() {
|
||||
let dir = Path.join(profileDir, "a", "b", "c");
|
||||
|
||||
// Sanity checking for the test
|
||||
do_check_false((yield OS.File.exists(dir)));
|
||||
|
||||
// Make a directory
|
||||
yield OS.File.makeDir(dir, {from: profileDir});
|
||||
|
||||
//check if the directory exists
|
||||
yield OS.File.stat(dir);
|
||||
|
||||
// Make a directory that already exists, this should succeed
|
||||
yield OS.File.makeDir(dir);
|
||||
|
||||
// Make a directory with ignoreExisting
|
||||
yield OS.File.makeDir(dir, {ignoreExisting: true});
|
||||
|
||||
// Make a directory with ignoreExisting false
|
||||
let exception = null;
|
||||
try {
|
||||
yield OS.File.makeDir(dir, {ignoreExisting: false});
|
||||
} catch (ex) {
|
||||
exception = ex;
|
||||
}
|
||||
|
||||
do_check_true(!!exception);
|
||||
do_check_true(exception instanceof OS.File.Error);
|
||||
do_check_true(exception.becauseExists);
|
||||
|
||||
// Make a directory without |from| and fail
|
||||
let dir2 = Path.join(profileDir, "g", "h", "i");
|
||||
exception = null;
|
||||
try {
|
||||
yield OS.File.makeDir(dir2);
|
||||
} catch (ex) {
|
||||
exception = ex;
|
||||
}
|
||||
|
||||
do_check_true(!!exception);
|
||||
do_check_true(exception instanceof OS.File.Error);
|
||||
do_check_true(exception.becauseNoSuchFile);
|
||||
|
||||
// Test edge cases on paths
|
||||
|
||||
let dir3 = Path.join(profileDir, "d", "", "e", "f");
|
||||
do_check_false((yield OS.File.exists(dir3)));
|
||||
yield OS.File.makeDir(dir3, {from: profileDir});
|
||||
do_check_true((yield OS.File.exists(dir3)));
|
||||
|
||||
let dir4;
|
||||
if (OS.Constants.Win) {
|
||||
// Test that we can create a directory recursively even
|
||||
// if we have too many "\\".
|
||||
dir4 = profileDir + "\\\\g";
|
||||
} else {
|
||||
dir4 = profileDir + "////g";
|
||||
}
|
||||
do_check_false((yield OS.File.exists(dir4)));
|
||||
yield OS.File.makeDir(dir4, {from: profileDir});
|
||||
do_check_true((yield OS.File.exists(dir4)));
|
||||
});
|
||||
70
toolkit/components/osfile/tests/xpcshell/test_open.js
Normal file
70
toolkit/components/osfile/tests/xpcshell/test_open.js
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test OS.File.open for reading:
|
||||
* - with an existing file (should succeed);
|
||||
* - with a non-existing file (should fail);
|
||||
* - with inconsistent arguments (should fail).
|
||||
*/
|
||||
add_task(function() {
|
||||
// Attempt to open a file that does not exist, ensure that it yields the
|
||||
// appropriate error.
|
||||
try {
|
||||
let fd = yield OS.File.open(OS.Path.join(".", "This file does not exist"));
|
||||
do_check_true(false, "File opening 1 succeeded (it should fail)");
|
||||
} catch (err if err instanceof OS.File.Error && err.becauseNoSuchFile) {
|
||||
do_print("File opening 1 failed " + err);
|
||||
}
|
||||
|
||||
// Attempt to open a file with the wrong args, so that it fails before
|
||||
// serialization, ensure that it yields the appropriate error.
|
||||
do_print("Attempting to open a file with wrong arguments");
|
||||
try {
|
||||
let fd = yield OS.File.open(1, 2, 3);
|
||||
do_check_true(false, "File opening 2 succeeded (it should fail)" + fd);
|
||||
} catch (err) {
|
||||
do_print("File opening 2 failed " + err);
|
||||
do_check_false(err instanceof OS.File.Error,
|
||||
"File opening 2 returned something that is not a file error");
|
||||
do_check_true(err.constructor.name == "TypeError",
|
||||
"File opening 2 returned a TypeError");
|
||||
}
|
||||
|
||||
// Attempt to open a file correctly
|
||||
do_print("Attempting to open a file correctly");
|
||||
let openedFile = yield OS.File.open(OS.Path.join(do_get_cwd().path, "test_open.js"));
|
||||
do_print("File opened correctly");
|
||||
|
||||
do_print("Attempting to close a file correctly");
|
||||
yield openedFile.close();
|
||||
|
||||
do_print("Attempting to close a file again");
|
||||
yield openedFile.close();
|
||||
});
|
||||
|
||||
/**
|
||||
* Test the error thrown by OS.File.open when attempting to open a directory
|
||||
* that does not exist.
|
||||
*/
|
||||
add_task(function test_error_attributes () {
|
||||
|
||||
let dir = OS.Path.join(do_get_profile().path, "test_osfileErrorAttrs");
|
||||
let fpath = OS.Path.join(dir, "test_error_attributes.txt");
|
||||
|
||||
try {
|
||||
yield OS.File.open(fpath, {truncate: true}, {});
|
||||
do_check_true(false, "Opening path suceeded (it should fail) " + fpath);
|
||||
} catch (err) {
|
||||
do_check_true(err instanceof OS.File.Error);
|
||||
do_check_true(err.becauseNoSuchFile);
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
|
||||
/**
|
||||
* A trivial test ensuring that we can call osfile from xpcshell.
|
||||
* (see bug 808161)
|
||||
*/
|
||||
|
||||
function run_test() {
|
||||
do_test_pending();
|
||||
OS.File.getCurrentDirectory().then(
|
||||
do_test_finished,
|
||||
do_test_finished
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
"use strict";
|
||||
|
||||
do_print("starting tests");
|
||||
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
Components.utils.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
/**
|
||||
* A test to check that the |append| mode flag is correctly implemented.
|
||||
* (see bug 925865)
|
||||
*/
|
||||
|
||||
function setup_mode(mode) {
|
||||
// Complete mode.
|
||||
let realMode = {
|
||||
read: true,
|
||||
write: true
|
||||
};
|
||||
for (let k in mode) {
|
||||
realMode[k] = mode[k];
|
||||
}
|
||||
return realMode;
|
||||
}
|
||||
|
||||
// Test append mode.
|
||||
function test_append(mode) {
|
||||
let path = OS.Path.join(OS.Constants.Path.tmpDir,
|
||||
"test_osfile_async_append.tmp");
|
||||
|
||||
// Clear any left-over files from previous runs.
|
||||
try {
|
||||
yield OS.File.remove(path);
|
||||
} catch (ex if ex.becauseNoSuchFile) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
try {
|
||||
mode = setup_mode(mode);
|
||||
mode.append = true;
|
||||
if (mode.trunc) {
|
||||
// Pre-fill file with some data to see if |trunc| actually works.
|
||||
yield OS.File.writeAtomic(path, new Uint8Array(500));
|
||||
}
|
||||
let file = yield OS.File.open(path, mode);
|
||||
try {
|
||||
yield file.write(new Uint8Array(1000));
|
||||
yield file.setPosition(0, OS.File.POS_START);
|
||||
yield file.read(100);
|
||||
// Should be at offset 100, length 1000 now.
|
||||
yield file.write(new Uint8Array(100));
|
||||
// Should be at offset 1100, length 1100 now.
|
||||
let stat = yield file.stat();
|
||||
do_check_eq(1100, stat.size);
|
||||
} finally {
|
||||
yield file.close();
|
||||
}
|
||||
} catch(ex) {
|
||||
try {
|
||||
yield OS.File.remove(path);
|
||||
} catch (ex if ex.becauseNoSuchFile) {
|
||||
// ignore.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test no-append mode.
|
||||
function test_no_append(mode) {
|
||||
let path = OS.Path.join(OS.Constants.Path.tmpDir,
|
||||
"test_osfile_async_noappend.tmp");
|
||||
|
||||
// Clear any left-over files from previous runs.
|
||||
try {
|
||||
yield OS.File.remove(path);
|
||||
} catch (ex if ex.becauseNoSuchFile) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
try {
|
||||
mode = setup_mode(mode);
|
||||
mode.append = false;
|
||||
if (mode.trunc) {
|
||||
// Pre-fill file with some data to see if |trunc| actually works.
|
||||
yield OS.File.writeAtomic(path, new Uint8Array(500));
|
||||
}
|
||||
let file = yield OS.File.open(path, mode);
|
||||
try {
|
||||
yield file.write(new Uint8Array(1000));
|
||||
yield file.setPosition(0, OS.File.POS_START);
|
||||
yield file.read(100);
|
||||
// Should be at offset 100, length 1000 now.
|
||||
yield file.write(new Uint8Array(100));
|
||||
// Should be at offset 200, length 1000 now.
|
||||
let stat = yield file.stat();
|
||||
do_check_eq(1000, stat.size);
|
||||
} finally {
|
||||
yield file.close();
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
yield OS.File.remove(path);
|
||||
} catch (ex if ex.becauseNoSuchFile) {
|
||||
// ignore.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var test_flags = [
|
||||
{},
|
||||
{create:true},
|
||||
{trunc:true}
|
||||
];
|
||||
function run_test() {
|
||||
do_test_pending();
|
||||
|
||||
for (let t of test_flags) {
|
||||
add_task(test_append.bind(null, t));
|
||||
add_task(test_no_append.bind(null, t));
|
||||
}
|
||||
add_task(do_test_finished);
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
Components.utils.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
function run_test() {
|
||||
do_test_pending();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to ensure that {bytes:} in options to |write| is correctly
|
||||
* preserved.
|
||||
*/
|
||||
add_task(function* test_bytes() {
|
||||
let path = OS.Path.join(OS.Constants.Path.tmpDir,
|
||||
"test_osfile_async_bytes.tmp");
|
||||
let file = yield OS.File.open(path, {trunc: true, read: true, write: true});
|
||||
try {
|
||||
try {
|
||||
// 1. Test write, by supplying {bytes:} options smaller than the actual
|
||||
// buffer.
|
||||
yield file.write(new Uint8Array(2048), {bytes: 1024});
|
||||
do_check_eq((yield file.stat()).size, 1024);
|
||||
|
||||
// 2. Test that passing nullish values for |options| still works.
|
||||
yield file.setPosition(0, OS.File.POS_END);
|
||||
yield file.write(new Uint8Array(1024), null);
|
||||
yield file.write(new Uint8Array(1024), undefined);
|
||||
do_check_eq((yield file.stat()).size, 3072);
|
||||
} finally {
|
||||
yield file.close();
|
||||
}
|
||||
} finally {
|
||||
yield OS.File.remove(path);
|
||||
}
|
||||
});
|
||||
|
||||
add_task(do_test_finished);
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
Components.utils.import("resource://gre/modules/FileUtils.jsm");
|
||||
Components.utils.import("resource://gre/modules/NetUtil.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm");
|
||||
Components.utils.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
function run_test() {
|
||||
do_test_pending();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
/**
|
||||
* A file that we know exists and that can be used for reading.
|
||||
*/
|
||||
var EXISTING_FILE = "test_osfile_async_copy.js";
|
||||
|
||||
/**
|
||||
* Fetch asynchronously the contents of a file using xpcom.
|
||||
*
|
||||
* Used for comparing xpcom-based results to os.file-based results.
|
||||
*
|
||||
* @param {string} path The _absolute_ path to the file.
|
||||
* @return {promise}
|
||||
* @resolves {string} The contents of the file.
|
||||
*/
|
||||
var reference_fetch_file = function reference_fetch_file(path) {
|
||||
let promise = Promise.defer();
|
||||
let file = new FileUtils.File(path);
|
||||
NetUtil.asyncFetch({
|
||||
uri: NetUtil.newURI(file),
|
||||
loadUsingSystemPrincipal: true
|
||||
}, function(stream, status) {
|
||||
if (!Components.isSuccessCode(status)) {
|
||||
promise.reject(status);
|
||||
return;
|
||||
}
|
||||
let result, reject;
|
||||
try {
|
||||
result = NetUtil.readInputStreamToString(stream, stream.available());
|
||||
} catch (x) {
|
||||
reject = x;
|
||||
}
|
||||
stream.close();
|
||||
if (reject) {
|
||||
promise.reject(reject);
|
||||
} else {
|
||||
promise.resolve(result);
|
||||
}
|
||||
});
|
||||
|
||||
return promise.promise;
|
||||
};
|
||||
|
||||
/**
|
||||
* Compare asynchronously the contents two files using xpcom.
|
||||
*
|
||||
* Used for comparing xpcom-based results to os.file-based results.
|
||||
*
|
||||
* @param {string} a The _absolute_ path to the first file.
|
||||
* @param {string} b The _absolute_ path to the second file.
|
||||
*
|
||||
* @resolves {null}
|
||||
*/
|
||||
var reference_compare_files = function reference_compare_files(a, b) {
|
||||
let a_contents = yield reference_fetch_file(a);
|
||||
let b_contents = yield reference_fetch_file(b);
|
||||
// Not using do_check_eq to avoid dumping the whole file to the log.
|
||||
// It is OK to === compare here, as both variables contain a string.
|
||||
do_check_true(a_contents === b_contents);
|
||||
};
|
||||
|
||||
/**
|
||||
* Test to ensure that OS.File.copy works.
|
||||
*/
|
||||
function test_copymove(options = {}) {
|
||||
let source = OS.Path.join((yield OS.File.getCurrentDirectory()),
|
||||
EXISTING_FILE);
|
||||
let dest = OS.Path.join(OS.Constants.Path.tmpDir,
|
||||
"test_osfile_async_copy_dest.tmp");
|
||||
let dest2 = OS.Path.join(OS.Constants.Path.tmpDir,
|
||||
"test_osfile_async_copy_dest2.tmp");
|
||||
try {
|
||||
// 1. Test copy.
|
||||
yield OS.File.copy(source, dest, options);
|
||||
yield reference_compare_files(source, dest);
|
||||
// 2. Test subsequent move.
|
||||
yield OS.File.move(dest, dest2);
|
||||
yield reference_compare_files(source, dest2);
|
||||
// 3. Check that the moved file was really moved.
|
||||
do_check_eq((yield OS.File.exists(dest)), false);
|
||||
} finally {
|
||||
try {
|
||||
yield OS.File.remove(dest);
|
||||
} catch (ex if ex.becauseNoSuchFile) {
|
||||
// ignore
|
||||
}
|
||||
try {
|
||||
yield OS.File.remove(dest2);
|
||||
} catch (ex if ex.becauseNoSuchFile) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Regular copy test.
|
||||
add_task(test_copymove);
|
||||
// Userland copy test.
|
||||
add_task(test_copymove.bind(null, {unixUserland: true}));
|
||||
|
||||
add_task(do_test_finished);
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
Components.utils.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
function run_test() {
|
||||
do_test_pending();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to ensure that |File.prototype.flush| is available in the async API.
|
||||
*/
|
||||
|
||||
add_task(function test_flush() {
|
||||
let path = OS.Path.join(OS.Constants.Path.tmpDir,
|
||||
"test_osfile_async_flush.tmp");
|
||||
let file = yield OS.File.open(path, {trunc: true, write: true});
|
||||
try {
|
||||
try {
|
||||
yield file.flush();
|
||||
} finally {
|
||||
yield file.close();
|
||||
}
|
||||
} finally {
|
||||
yield OS.File.remove(path);
|
||||
}
|
||||
});
|
||||
|
||||
add_task(do_test_finished);
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/ctypes.jsm");
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
Components.utils.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
/**
|
||||
* A test to check that .getPosition/.setPosition work with large files.
|
||||
* (see bug 952997)
|
||||
*/
|
||||
|
||||
// Test setPosition/getPosition.
|
||||
function test_setPosition(forward, current, backward) {
|
||||
let path = OS.Path.join(OS.Constants.Path.tmpDir,
|
||||
"test_osfile_async_largefiles.tmp");
|
||||
|
||||
// Clear any left-over files from previous runs.
|
||||
try {
|
||||
yield OS.File.remove(path);
|
||||
} catch (ex if ex.becauseNoSuchFile) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
try {
|
||||
let file = yield OS.File.open(path, {write:true, append:false});
|
||||
try {
|
||||
let pos = 0;
|
||||
|
||||
// 1. seek forward from start
|
||||
do_print("Moving forward: " + forward);
|
||||
yield file.setPosition(forward, OS.File.POS_START);
|
||||
pos += forward;
|
||||
do_check_eq((yield file.getPosition()), pos);
|
||||
|
||||
// 2. seek forward from current position
|
||||
do_print("Moving current: " + current);
|
||||
yield file.setPosition(current, OS.File.POS_CURRENT);
|
||||
pos += current;
|
||||
do_check_eq((yield file.getPosition()), pos);
|
||||
|
||||
// 3. seek backward from current position
|
||||
do_print("Moving current backward: " + backward);
|
||||
yield file.setPosition(-backward, OS.File.POS_CURRENT);
|
||||
pos -= backward;
|
||||
do_check_eq((yield file.getPosition()), pos);
|
||||
|
||||
} finally {
|
||||
yield file.setPosition(0, OS.File.POS_START);
|
||||
yield file.close();
|
||||
}
|
||||
} catch(ex) {
|
||||
try {
|
||||
yield OS.File.remove(path);
|
||||
} catch (ex if ex.becauseNoSuchFile) {
|
||||
// ignore.
|
||||
}
|
||||
do_throw(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// Test setPosition/getPosition expected failures.
|
||||
function test_setPosition_failures() {
|
||||
let path = OS.Path.join(OS.Constants.Path.tmpDir,
|
||||
"test_osfile_async_largefiles.tmp");
|
||||
|
||||
// Clear any left-over files from previous runs.
|
||||
try {
|
||||
yield OS.File.remove(path);
|
||||
} catch (ex if ex.becauseNoSuchFile) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
try {
|
||||
let file = yield OS.File.open(path, {write:true, append:false});
|
||||
try {
|
||||
let pos = 0;
|
||||
|
||||
// 1. Use an invalid position value
|
||||
try {
|
||||
yield file.setPosition(0.5, OS.File.POS_START);
|
||||
do_throw("Shouldn't have succeeded");
|
||||
} catch (ex) {
|
||||
do_check_true(ex.toString().includes("can't pass"));
|
||||
}
|
||||
// Since setPosition should have bailed, it shouldn't have moved the
|
||||
// file pointer at all.
|
||||
do_check_eq((yield file.getPosition()), 0);
|
||||
|
||||
// 2. Use an invalid position value
|
||||
try {
|
||||
yield file.setPosition(0xffffffff + 0.5, OS.File.POS_START);
|
||||
do_throw("Shouldn't have succeeded");
|
||||
} catch (ex) {
|
||||
do_check_true(ex.toString().includes("can't pass"));
|
||||
}
|
||||
// Since setPosition should have bailed, it shouldn't have moved the
|
||||
// file pointer at all.
|
||||
do_check_eq((yield file.getPosition()), 0);
|
||||
|
||||
// 3. Use a position that cannot be represented as a double
|
||||
try {
|
||||
// Not all numbers after 9007199254740992 can be represented as a
|
||||
// double. E.g. in js 9007199254740992 + 1 == 9007199254740992
|
||||
yield file.setPosition(9007199254740992, OS.File.POS_START);
|
||||
yield file.setPosition(1, OS.File.POS_CURRENT);
|
||||
do_throw("Shouldn't have succeeded");
|
||||
} catch (ex) {
|
||||
do_print(ex.toString());
|
||||
do_check_true(!!ex);
|
||||
}
|
||||
|
||||
} finally {
|
||||
yield file.setPosition(0, OS.File.POS_START);
|
||||
yield file.close();
|
||||
try {
|
||||
yield OS.File.remove(path);
|
||||
} catch (ex if ex.becauseNoSuchFile) {
|
||||
// ignore.
|
||||
}
|
||||
}
|
||||
} catch(ex) {
|
||||
do_throw(ex);
|
||||
}
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
// First verify stuff works for small values.
|
||||
add_task(test_setPosition.bind(null, 0, 100, 50));
|
||||
add_task(test_setPosition.bind(null, 1000, 100, 50));
|
||||
add_task(test_setPosition.bind(null, 1000, -100, -50));
|
||||
|
||||
if (OS.Constants.Win || ctypes.off_t.size >= 8) {
|
||||
// Now verify stuff still works for large values.
|
||||
// 1. Multiple small seeks, which add up to > MAXINT32
|
||||
add_task(test_setPosition.bind(null, 0x7fffffff, 0x7fffffff, 0));
|
||||
// 2. Plain large seek, that should end up at 0 again.
|
||||
// 0xffffffff also happens to be the INVALID_SET_FILE_POINTER value on
|
||||
// Windows, so this also tests the error handling
|
||||
add_task(test_setPosition.bind(null, 0, 0xffffffff, 0xffffffff));
|
||||
// 3. Multiple large seeks that should end up > MAXINT32.
|
||||
add_task(test_setPosition.bind(null, 0xffffffff, 0xffffffff, 0xffffffff));
|
||||
// 5. Multiple large seeks with negative offsets.
|
||||
add_task(test_setPosition.bind(null, 0xffffffff, -0x7fffffff, 0x7fffffff));
|
||||
|
||||
// 6. Check failures
|
||||
add_task(test_setPosition_failures);
|
||||
}
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
|
|
@ -0,0 +1,211 @@
|
|||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
Components.utils.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
/**
|
||||
* A test to ensure that OS.File.setDates and OS.File.prototype.setDates are
|
||||
* working correctly.
|
||||
* (see bug 924916)
|
||||
*/
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
// Non-prototypical tests, operating on path names.
|
||||
add_task(function* test_nonproto() {
|
||||
// First, create a file we can mess with.
|
||||
let path = OS.Path.join(OS.Constants.Path.tmpDir,
|
||||
"test_osfile_async_setDates_nonproto.tmp");
|
||||
yield OS.File.writeAtomic(path, new Uint8Array(1));
|
||||
|
||||
try {
|
||||
// 1. Try to set some well known dates.
|
||||
// We choose multiples of 2000ms, because the time stamp resolution of
|
||||
// the underlying OS might not support something more precise.
|
||||
const accDate = 2000;
|
||||
const modDate = 4000;
|
||||
{
|
||||
yield OS.File.setDates(path, accDate, modDate);
|
||||
let stat = yield OS.File.stat(path);
|
||||
do_check_eq(accDate, stat.lastAccessDate.getTime());
|
||||
do_check_eq(modDate, stat.lastModificationDate.getTime());
|
||||
}
|
||||
|
||||
// 2.1 Try to omit modificationDate (which should then default to
|
||||
// |Date.now()|, expect for resolution differences).
|
||||
{
|
||||
yield OS.File.setDates(path, accDate);
|
||||
let stat = yield OS.File.stat(path);
|
||||
do_check_eq(accDate, stat.lastAccessDate.getTime());
|
||||
do_check_neq(modDate, stat.lastModificationDate.getTime());
|
||||
}
|
||||
|
||||
// 2.2 Try to omit accessDate as well (which should then default to
|
||||
// |Date.now()|, expect for resolution differences).
|
||||
{
|
||||
yield OS.File.setDates(path);
|
||||
let stat = yield OS.File.stat(path);
|
||||
do_check_neq(accDate, stat.lastAccessDate.getTime());
|
||||
do_check_neq(modDate, stat.lastModificationDate.getTime());
|
||||
}
|
||||
|
||||
// 3. Repeat 1., but with Date objects this time
|
||||
{
|
||||
yield OS.File.setDates(path, new Date(accDate), new Date(modDate));
|
||||
let stat = yield OS.File.stat(path);
|
||||
do_check_eq(accDate, stat.lastAccessDate.getTime());
|
||||
do_check_eq(modDate, stat.lastModificationDate.getTime());
|
||||
}
|
||||
|
||||
// 4. Check that invalid params will cause an exception/rejection.
|
||||
{
|
||||
for (let p of ["invalid", new Uint8Array(1), NaN]) {
|
||||
try {
|
||||
yield OS.File.setDates(path, p, modDate);
|
||||
do_throw("Invalid access date should have thrown for: " + p);
|
||||
} catch (ex) {
|
||||
let stat = yield OS.File.stat(path);
|
||||
do_check_eq(accDate, stat.lastAccessDate.getTime());
|
||||
do_check_eq(modDate, stat.lastModificationDate.getTime());
|
||||
}
|
||||
try {
|
||||
yield OS.File.setDates(path, accDate, p);
|
||||
do_throw("Invalid modification date should have thrown for: " + p);
|
||||
} catch (ex) {
|
||||
let stat = yield OS.File.stat(path);
|
||||
do_check_eq(accDate, stat.lastAccessDate.getTime());
|
||||
do_check_eq(modDate, stat.lastModificationDate.getTime());
|
||||
}
|
||||
try {
|
||||
yield OS.File.setDates(path, p, p);
|
||||
do_throw("Invalid dates should have thrown for: " + p);
|
||||
} catch (ex) {
|
||||
let stat = yield OS.File.stat(path);
|
||||
do_check_eq(accDate, stat.lastAccessDate.getTime());
|
||||
do_check_eq(modDate, stat.lastModificationDate.getTime());
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
// Remove the temp file again
|
||||
yield OS.File.remove(path);
|
||||
}
|
||||
});
|
||||
|
||||
// Prototypical tests, operating on |File| handles.
|
||||
add_task(function* test_proto() {
|
||||
if (OS.Constants.Sys.Name == "Android" || OS.Constants.Sys.Name == "Gonk") {
|
||||
do_print("File.prototype.setDates is not implemented for Android/B2G");
|
||||
do_check_eq(OS.File.prototype.setDates, undefined);
|
||||
return;
|
||||
}
|
||||
|
||||
// First, create a file we can mess with.
|
||||
let path = OS.Path.join(OS.Constants.Path.tmpDir,
|
||||
"test_osfile_async_setDates_proto.tmp");
|
||||
yield OS.File.writeAtomic(path, new Uint8Array(1));
|
||||
|
||||
try {
|
||||
let fd = yield OS.File.open(path, {write: true});
|
||||
|
||||
try {
|
||||
// 1. Try to set some well known dates.
|
||||
// We choose multiples of 2000ms, because the time stamp resolution of
|
||||
// the underlying OS might not support something more precise.
|
||||
const accDate = 2000;
|
||||
const modDate = 4000;
|
||||
{
|
||||
yield fd.setDates(accDate, modDate);
|
||||
let stat = yield fd.stat();
|
||||
do_check_eq(accDate, stat.lastAccessDate.getTime());
|
||||
do_check_eq(modDate, stat.lastModificationDate.getTime());
|
||||
}
|
||||
|
||||
// 2.1 Try to omit modificationDate (which should then default to
|
||||
// |Date.now()|, expect for resolution differences).
|
||||
{
|
||||
yield fd.setDates(accDate);
|
||||
let stat = yield fd.stat();
|
||||
do_check_eq(accDate, stat.lastAccessDate.getTime());
|
||||
do_check_neq(modDate, stat.lastModificationDate.getTime());
|
||||
}
|
||||
|
||||
// 2.2 Try to omit accessDate as well (which should then default to
|
||||
// |Date.now()|, expect for resolution differences).
|
||||
{
|
||||
yield fd.setDates();
|
||||
let stat = yield fd.stat();
|
||||
do_check_neq(accDate, stat.lastAccessDate.getTime());
|
||||
do_check_neq(modDate, stat.lastModificationDate.getTime());
|
||||
}
|
||||
|
||||
// 3. Repeat 1., but with Date objects this time
|
||||
{
|
||||
yield fd.setDates(new Date(accDate), new Date(modDate));
|
||||
let stat = yield fd.stat();
|
||||
do_check_eq(accDate, stat.lastAccessDate.getTime());
|
||||
do_check_eq(modDate, stat.lastModificationDate.getTime());
|
||||
}
|
||||
|
||||
// 4. Check that invalid params will cause an exception/rejection.
|
||||
{
|
||||
for (let p of ["invalid", new Uint8Array(1), NaN]) {
|
||||
try {
|
||||
yield fd.setDates(p, modDate);
|
||||
do_throw("Invalid access date should have thrown for: " + p);
|
||||
} catch (ex) {
|
||||
let stat = yield fd.stat();
|
||||
do_check_eq(accDate, stat.lastAccessDate.getTime());
|
||||
do_check_eq(modDate, stat.lastModificationDate.getTime());
|
||||
}
|
||||
try {
|
||||
yield fd.setDates(accDate, p);
|
||||
do_throw("Invalid modification date should have thrown for: " + p);
|
||||
} catch (ex) {
|
||||
let stat = yield fd.stat();
|
||||
do_check_eq(accDate, stat.lastAccessDate.getTime());
|
||||
do_check_eq(modDate, stat.lastModificationDate.getTime());
|
||||
}
|
||||
try {
|
||||
yield fd.setDates(p, p);
|
||||
do_throw("Invalid dates should have thrown for: " + p);
|
||||
} catch (ex) {
|
||||
let stat = yield fd.stat();
|
||||
do_check_eq(accDate, stat.lastAccessDate.getTime());
|
||||
do_check_eq(modDate, stat.lastModificationDate.getTime());
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
yield fd.close();
|
||||
}
|
||||
} finally {
|
||||
// Remove the temp file again
|
||||
yield OS.File.remove(path);
|
||||
}
|
||||
});
|
||||
|
||||
// Tests setting dates on directories.
|
||||
add_task(function* test_dirs() {
|
||||
let path = OS.Path.join(OS.Constants.Path.tmpDir,
|
||||
"test_osfile_async_setDates_dir");
|
||||
yield OS.File.makeDir(path);
|
||||
|
||||
try {
|
||||
// 1. Try to set some well known dates.
|
||||
// We choose multiples of 2000ms, because the time stamp resolution of
|
||||
// the underlying OS might not support something more precise.
|
||||
const accDate = 2000;
|
||||
const modDate = 4000;
|
||||
{
|
||||
yield OS.File.setDates(path, accDate, modDate);
|
||||
let stat = yield OS.File.stat(path);
|
||||
do_check_eq(accDate, stat.lastAccessDate.getTime());
|
||||
do_check_eq(modDate, stat.lastModificationDate.getTime());
|
||||
}
|
||||
} finally {
|
||||
yield OS.File.removeEmptyDir(path);
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* A test to ensure that OS.File.setPermissions and
|
||||
* OS.File.prototype.setPermissions are all working correctly.
|
||||
* (see bug 1001849)
|
||||
* These functions are currently Unix-specific. The manifest skips
|
||||
* the test on Windows.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Helper function for test logging: prints a POSIX file permission mode as an
|
||||
* octal number, with a leading '0' per C (not JS) convention. When the
|
||||
* numeric value is 0o777 or lower, it is padded on the left with zeroes to
|
||||
* four digits wide.
|
||||
* Sample outputs: 0022, 0644, 04755.
|
||||
*/
|
||||
function format_mode(mode) {
|
||||
if (mode <= 0o777) {
|
||||
return ("0000" + mode.toString(8)).slice(-4);
|
||||
} else {
|
||||
return "0" + mode.toString(8);
|
||||
}
|
||||
}
|
||||
|
||||
const _umask = OS.Constants.Sys.umask;
|
||||
do_print("umask: " + format_mode(_umask));
|
||||
|
||||
/**
|
||||
* Compute the mode that a file should have after applying the umask,
|
||||
* whatever it happens to be.
|
||||
*/
|
||||
function apply_umask(mode) {
|
||||
return mode & ~_umask;
|
||||
}
|
||||
|
||||
// Sequence of setPermission parameters and expected file mode. The first test
|
||||
// checks the permissions when the file is first created.
|
||||
var testSequence = [
|
||||
[null, apply_umask(0o600)],
|
||||
[{ unixMode: 0o4777 }, apply_umask(0o4777)],
|
||||
[{ unixMode: 0o4777, unixHonorUmask: false }, 0o4777],
|
||||
[{ unixMode: 0o4777, unixHonorUmask: true }, apply_umask(0o4777)],
|
||||
[undefined, apply_umask(0o600)],
|
||||
[{ unixMode: 0o666 }, apply_umask(0o666)],
|
||||
[{ unixMode: 0o600 }, apply_umask(0o600)],
|
||||
[{ unixMode: 0 }, 0],
|
||||
[{}, apply_umask(0o600)],
|
||||
];
|
||||
|
||||
// Test application to paths.
|
||||
add_task(function* test_path_setPermissions() {
|
||||
let path = OS.Path.join(OS.Constants.Path.tmpDir,
|
||||
"test_osfile_async_setPermissions_path.tmp");
|
||||
yield OS.File.writeAtomic(path, new Uint8Array(1));
|
||||
|
||||
try {
|
||||
for (let [options, expectedMode] of testSequence) {
|
||||
if (options !== null) {
|
||||
do_print("Setting permissions to " + JSON.stringify(options));
|
||||
yield OS.File.setPermissions(path, options);
|
||||
}
|
||||
|
||||
let stat = yield OS.File.stat(path);
|
||||
do_check_eq(format_mode(stat.unixMode), format_mode(expectedMode));
|
||||
}
|
||||
} finally {
|
||||
yield OS.File.remove(path);
|
||||
}
|
||||
});
|
||||
|
||||
// Test application to open files.
|
||||
add_task(function* test_file_setPermissions() {
|
||||
let path = OS.Path.join(OS.Constants.Path.tmpDir,
|
||||
"test_osfile_async_setPermissions_file.tmp");
|
||||
yield OS.File.writeAtomic(path, new Uint8Array(1));
|
||||
|
||||
try {
|
||||
let fd = yield OS.File.open(path, { write: true });
|
||||
try {
|
||||
for (let [options, expectedMode] of testSequence) {
|
||||
if (options !== null) {
|
||||
do_print("Setting permissions to " + JSON.stringify(options));
|
||||
yield fd.setPermissions(options);
|
||||
}
|
||||
|
||||
let stat = yield fd.stat();
|
||||
do_check_eq(format_mode(stat.unixMode), format_mode(expectedMode));
|
||||
}
|
||||
} finally {
|
||||
yield fd.close();
|
||||
}
|
||||
} finally {
|
||||
yield OS.File.remove(path);
|
||||
}
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
Components.utils.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
function run_test() {
|
||||
do_test_pending();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function test_closed() {
|
||||
OS.Shared.DEBUG = true;
|
||||
let currentDir = yield OS.File.getCurrentDirectory();
|
||||
do_print("Open a file, ensure that we can call stat()");
|
||||
let path = OS.Path.join(currentDir, "test_osfile_closed.js");
|
||||
let file = yield OS.File.open(path);
|
||||
yield file.stat();
|
||||
do_check_true(true);
|
||||
|
||||
yield file.close();
|
||||
|
||||
do_print("Ensure that we cannot stat() on closed file");
|
||||
let exn;
|
||||
try {
|
||||
yield file.stat();
|
||||
} catch (ex) {
|
||||
exn = ex;
|
||||
}
|
||||
do_print("Ensure that this raises the correct error");
|
||||
do_check_true(!!exn);
|
||||
do_check_true(exn instanceof OS.File.Error);
|
||||
do_check_true(exn.becauseClosed);
|
||||
|
||||
do_print("Ensure that we cannot read() on closed file");
|
||||
exn = null;
|
||||
try {
|
||||
yield file.read();
|
||||
} catch (ex) {
|
||||
exn = ex;
|
||||
}
|
||||
do_print("Ensure that this raises the correct error");
|
||||
do_check_true(!!exn);
|
||||
do_check_true(exn instanceof OS.File.Error);
|
||||
do_check_true(exn.becauseClosed);
|
||||
|
||||
});
|
||||
|
||||
add_task(do_test_finished);
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
var {OS: {File, Path, Constants}} = Components.utils.import("resource://gre/modules/osfile.jsm", {});
|
||||
Components.utils.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* testFileError_with_writeAtomic() {
|
||||
let DEFAULT_CONTENTS = "default contents" + Math.random();
|
||||
let path = Path.join(Constants.Path.tmpDir,
|
||||
"testFileError.tmp");
|
||||
yield File.remove(path);
|
||||
yield File.writeAtomic(path, DEFAULT_CONTENTS);
|
||||
let exception;
|
||||
try {
|
||||
yield File.writeAtomic(path, DEFAULT_CONTENTS, { noOverwrite: true });
|
||||
} catch (ex) {
|
||||
exception = ex;
|
||||
}
|
||||
do_check_true(exception instanceof File.Error);
|
||||
do_check_true(exception.path == path);
|
||||
});
|
||||
|
||||
add_task(function* testFileError_with_makeDir() {
|
||||
let path = Path.join(Constants.Path.tmpDir,
|
||||
"directory");
|
||||
yield File.removeDir(path);
|
||||
yield File.makeDir(path);
|
||||
let exception;
|
||||
try {
|
||||
yield File.makeDir(path, { ignoreExisting: false });
|
||||
} catch (ex) {
|
||||
exception = ex;
|
||||
}
|
||||
do_check_true(exception instanceof File.Error);
|
||||
do_check_true(exception.path == path);
|
||||
});
|
||||
|
||||
add_task(function* testFileError_with_move() {
|
||||
let DEFAULT_CONTENTS = "default contents" + Math.random();
|
||||
let sourcePath = Path.join(Constants.Path.tmpDir,
|
||||
"src.tmp");
|
||||
let destPath = Path.join(Constants.Path.tmpDir,
|
||||
"dest.tmp");
|
||||
yield File.remove(sourcePath);
|
||||
yield File.remove(destPath);
|
||||
yield File.writeAtomic(sourcePath, DEFAULT_CONTENTS);
|
||||
yield File.writeAtomic(destPath, DEFAULT_CONTENTS);
|
||||
let exception;
|
||||
try {
|
||||
yield File.move(sourcePath, destPath, { noOverwrite: true });
|
||||
} catch (ex) {
|
||||
exception = ex;
|
||||
}
|
||||
do_print(exception);
|
||||
do_check_true(exception instanceof File.Error);
|
||||
do_check_true(exception.path == sourcePath);
|
||||
});
|
||||
100
toolkit/components/osfile/tests/xpcshell/test_osfile_kill.js
Normal file
100
toolkit/components/osfile/tests/xpcshell/test_osfile_kill.js
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
|
||||
// We want the actual global to get at the internals since Scheduler is not
|
||||
// exported.
|
||||
var AsyncFrontGlobal = Components.utils.import(
|
||||
"resource://gre/modules/osfile/osfile_async_front.jsm",
|
||||
null);
|
||||
var Scheduler = AsyncFrontGlobal.Scheduler;
|
||||
|
||||
/**
|
||||
* Verify that Scheduler.kill() interacts with other OS.File requests correctly,
|
||||
* and that no requests are lost. This is relevant because on B2G we
|
||||
* auto-kill the worker periodically, making it very possible for valid requests
|
||||
* to be interleaved with the automatic kill().
|
||||
*
|
||||
* This test is being created with the fix for Bug 1125989 where `kill` queue
|
||||
* management was found to be buggy. It is a glass-box test that explicitly
|
||||
* re-creates the observed failure situation; it is not guaranteed to prevent
|
||||
* all future regressions. The following is a detailed explanation of the test
|
||||
* for your benefit if this test ever breaks or you are wondering what was the
|
||||
* point of all this. You might want to skim the code below first.
|
||||
*
|
||||
* OS.File maintains a `queue` of operations to be performed. This queue is
|
||||
* nominally implemented as a chain of promises. Every time a new job is
|
||||
* OS.File.push()ed, it effectively becomes the new `queue` promise. (An
|
||||
* extra promise is interposed with a rejection handler to avoid the rejection
|
||||
* cascading, but that does not matter for our purposes.)
|
||||
*
|
||||
* The flaw in `kill` was that it would wait for the `queue` to complete before
|
||||
* replacing `queue`. As a result, another OS.File operation could use `push`
|
||||
* (by way of OS.File.post()) to also use .then() on the same `queue` promise.
|
||||
* Accordingly, assuming that promise was not yet resolved (due to a pending
|
||||
* OS.File request), when it was resolved, both the task scheduled in `kill`
|
||||
* and in `post` would be triggered. Both of those tasks would run until
|
||||
* encountering a call to worker.post().
|
||||
*
|
||||
* Re-creating this race is not entirely trivial because of the large number of
|
||||
* promises used by the code causing control flow to repeatedly be deferred. In
|
||||
* a slightly simpler world we could run the follwing in the same turn of the
|
||||
* event loop and trigger the problem.
|
||||
* - any OS.File request
|
||||
* - Scheduler.kill()
|
||||
* - any OS.File request
|
||||
*
|
||||
* However, we need the Scheduler.kill task to reach the point where it is
|
||||
* waiting on the same `queue` that another task has been scheduled against.
|
||||
* Since the `kill` task yields on the `killQueue` promise prior to yielding
|
||||
* on `queue`, however, some turns of the event loop are required. Happily,
|
||||
* for us, as discussed above, the problem triggers when we have two promises
|
||||
* scheduled on the `queue`, so we can just wait to schedule the second OS.File
|
||||
* request on the queue. (Note that because of the additional then() added to
|
||||
* eat rejections, there is an important difference between the value of
|
||||
* `queue` and the value returned by the first OS.File request.)
|
||||
*/
|
||||
add_task(function* test_kill_race() {
|
||||
// Ensure the worker has been created and that SET_DEBUG has taken effect.
|
||||
// We have chosen OS.File.exists for our tests because it does not trigger
|
||||
// a rejection and we absolutely do not care what the operation is other
|
||||
// than it does not invoke a native fast-path.
|
||||
yield OS.File.exists('foo.foo');
|
||||
|
||||
do_print('issuing first request');
|
||||
let firstRequest = OS.File.exists('foo.bar');
|
||||
let secondRequest;
|
||||
let secondResolved = false;
|
||||
|
||||
// As noted in our big block comment, we want to wait to schedule the
|
||||
// second request so that it races `kill`'s call to `worker.post`. Having
|
||||
// ourselves wait on the same promise, `queue`, and registering ourselves
|
||||
// before we issue the kill request means we will get run before the `kill`
|
||||
// task resumes and allow us to precisely create the desired race.
|
||||
Scheduler.queue.then(function() {
|
||||
do_print('issuing second request');
|
||||
secondRequest = OS.File.exists('foo.baz');
|
||||
secondRequest.then(function() {
|
||||
secondResolved = true;
|
||||
});
|
||||
});
|
||||
|
||||
do_print('issuing kill request');
|
||||
let killRequest = Scheduler.kill({ reset: true, shutdown: false });
|
||||
|
||||
// Wait on the killRequest so that we can schedule a new OS.File request
|
||||
// after it completes...
|
||||
yield killRequest;
|
||||
// ...because our ordering guarantee ensures that there is at most one
|
||||
// worker (and this usage here should not be vulnerable even with the
|
||||
// bug present), so when this completes the secondRequest has either been
|
||||
// resolved or lost.
|
||||
yield OS.File.exists('foo.goz');
|
||||
|
||||
ok(secondResolved,
|
||||
'The second request was resolved so we avoided the bug. Victory!');
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* A test to ensure that OS.File.setPermissions and
|
||||
* OS.File.prototype.setPermissions are all working correctly.
|
||||
* (see bug 1022816)
|
||||
* The manifest tests on Windows.
|
||||
*/
|
||||
|
||||
// Sequence of setPermission parameters.
|
||||
var testSequence = [
|
||||
[ { winAttributes: { readOnly: true, system: true, hidden: true } },
|
||||
{ readOnly: true, system: true, hidden: true } ],
|
||||
[ { winAttributes: { readOnly: false } },
|
||||
{ readOnly: false, system: true, hidden: true } ],
|
||||
[ { winAttributes: { system: false } },
|
||||
{ readOnly: false, system: false, hidden: true } ],
|
||||
[ { winAttributes: { hidden: false } },
|
||||
{ readOnly: false, system: false, hidden: false } ],
|
||||
[ { winAttributes: {readOnly: true, system: false, hidden: false} },
|
||||
{ readOnly: true, system: false, hidden: false } ],
|
||||
[ { winAttributes: {readOnly: false, system: true, hidden: false} },
|
||||
{ readOnly: false, system: true, hidden: false } ],
|
||||
[ { winAttributes: {readOnly: false, system: false, hidden: true} },
|
||||
{ readOnly: false, system: false, hidden: true } ],
|
||||
];
|
||||
|
||||
// Test application to paths.
|
||||
add_task(function* test_path_setPermissions() {
|
||||
let path = OS.Path.join(OS.Constants.Path.tmpDir,
|
||||
"test_osfile_win_async_setPermissions_path.tmp");
|
||||
yield OS.File.writeAtomic(path, new Uint8Array(1));
|
||||
|
||||
try {
|
||||
for (let [options, attributesExpected] of testSequence) {
|
||||
if (options !== null) {
|
||||
do_print("Setting permissions to " + JSON.stringify(options));
|
||||
yield OS.File.setPermissions(path, options);
|
||||
}
|
||||
|
||||
let stat = yield OS.File.stat(path);
|
||||
do_print("Got stat winAttributes: " + JSON.stringify(stat.winAttributes));
|
||||
|
||||
do_check_eq(stat.winAttributes.readOnly, attributesExpected.readOnly);
|
||||
do_check_eq(stat.winAttributes.system, attributesExpected.system);
|
||||
do_check_eq(stat.winAttributes.hidden, attributesExpected.hidden);
|
||||
|
||||
}
|
||||
} finally {
|
||||
yield OS.File.remove(path);
|
||||
}
|
||||
});
|
||||
|
||||
// Test application to open files.
|
||||
add_task(function* test_file_setPermissions() {
|
||||
let path = OS.Path.join(OS.Constants.Path.tmpDir,
|
||||
"test_osfile_win_async_setPermissions_file.tmp");
|
||||
yield OS.File.writeAtomic(path, new Uint8Array(1));
|
||||
|
||||
try {
|
||||
let fd = yield OS.File.open(path, { write: true });
|
||||
try {
|
||||
for (let [options, attributesExpected] of testSequence) {
|
||||
if (options !== null) {
|
||||
do_print("Setting permissions to " + JSON.stringify(options));
|
||||
yield fd.setPermissions(options);
|
||||
}
|
||||
|
||||
let stat = yield fd.stat();
|
||||
do_print("Got stat winAttributes: " + JSON.stringify(stat.winAttributes));
|
||||
do_check_eq(stat.winAttributes.readOnly, attributesExpected.readOnly);
|
||||
do_check_eq(stat.winAttributes.system, attributesExpected.system);
|
||||
do_check_eq(stat.winAttributes.hidden, attributesExpected.hidden);
|
||||
}
|
||||
} finally {
|
||||
yield fd.close();
|
||||
}
|
||||
} finally {
|
||||
yield OS.File.remove(path);
|
||||
}
|
||||
});
|
||||
|
||||
// Test application to Check setPermissions on a non-existant file path.
|
||||
add_task(function* test_non_existant_file_path_setPermissions() {
|
||||
let path = OS.Path.join(OS.Constants.Path.tmpDir,
|
||||
"test_osfile_win_async_setPermissions_path.tmp");
|
||||
Assert.rejects(OS.File.setPermissions(path, {winAttributes: {readOnly: true}}),
|
||||
/The system cannot find the file specified/,
|
||||
"setPermissions failed as expected on a non-existant file path");
|
||||
});
|
||||
|
||||
// Test application to Check setPermissions on a invalid file handle.
|
||||
add_task(function* test_closed_file_handle_setPermissions() {
|
||||
let path = OS.Path.join(OS.Constants.Path.tmpDir,
|
||||
"test_osfile_win_async_setPermissions_path.tmp");
|
||||
yield OS.File.writeAtomic(path, new Uint8Array(1));
|
||||
|
||||
try {
|
||||
let fd = yield OS.File.open(path, { write: true });
|
||||
yield fd.close();
|
||||
Assert.rejects(fd.setPermissions(path, {winAttributes: {readOnly: true}}),
|
||||
/The handle is invalid/,
|
||||
"setPermissions failed as expected on a invalid file handle");
|
||||
} finally {
|
||||
yield OS.File.remove(path);
|
||||
}
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
var {OS: {File, Path, Constants}} = Components.utils.import("resource://gre/modules/osfile.jsm", {});
|
||||
Components.utils.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
/**
|
||||
* Remove all temporary files and back up files, including
|
||||
* test_backupTo_option_with_tmpPath.tmp
|
||||
* test_backupTo_option_with_tmpPath.tmp.backup
|
||||
* test_backupTo_option_without_tmpPath.tmp
|
||||
* test_backupTo_option_without_tmpPath.tmp.backup
|
||||
* test_non_backupTo_option.tmp
|
||||
* test_non_backupTo_option.tmp.backup
|
||||
* test_backupTo_option_without_destination_file.tmp
|
||||
* test_backupTo_option_without_destination_file.tmp.backup
|
||||
* test_backupTo_option_with_backup_file.tmp
|
||||
* test_backupTo_option_with_backup_file.tmp.backup
|
||||
*/
|
||||
function clearFiles() {
|
||||
return Task.spawn(function () {
|
||||
let files = ["test_backupTo_option_with_tmpPath.tmp",
|
||||
"test_backupTo_option_without_tmpPath.tmp",
|
||||
"test_non_backupTo_option.tmp",
|
||||
"test_backupTo_option_without_destination_file.tmp",
|
||||
"test_backupTo_option_with_backup_file.tmp"];
|
||||
for (let file of files) {
|
||||
let path = Path.join(Constants.Path.tmpDir, file);
|
||||
yield File.remove(path);
|
||||
yield File.remove(path + ".backup");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* init() {
|
||||
yield clearFiles();
|
||||
});
|
||||
|
||||
/**
|
||||
* test when
|
||||
* |backupTo| specified
|
||||
* |tmpPath| specified
|
||||
* destination file exists
|
||||
* @result destination file will be backed up
|
||||
*/
|
||||
add_task(function* test_backupTo_option_with_tmpPath() {
|
||||
let DEFAULT_CONTENTS = "default contents" + Math.random();
|
||||
let WRITE_CONTENTS = "abc" + Math.random();
|
||||
let path = Path.join(Constants.Path.tmpDir,
|
||||
"test_backupTo_option_with_tmpPath.tmp");
|
||||
yield File.writeAtomic(path, DEFAULT_CONTENTS);
|
||||
yield File.writeAtomic(path, WRITE_CONTENTS, { tmpPath: path + ".tmp",
|
||||
backupTo: path + ".backup" });
|
||||
do_check_true((yield File.exists(path + ".backup")));
|
||||
let contents = yield File.read(path + ".backup");
|
||||
do_check_eq(DEFAULT_CONTENTS, (new TextDecoder()).decode(contents));
|
||||
});
|
||||
|
||||
/**
|
||||
* test when
|
||||
* |backupTo| specified
|
||||
* |tmpPath| not specified
|
||||
* destination file exists
|
||||
* @result destination file will be backed up
|
||||
*/
|
||||
add_task(function* test_backupTo_option_without_tmpPath() {
|
||||
let DEFAULT_CONTENTS = "default contents" + Math.random();
|
||||
let WRITE_CONTENTS = "abc" + Math.random();
|
||||
let path = Path.join(Constants.Path.tmpDir,
|
||||
"test_backupTo_option_without_tmpPath.tmp");
|
||||
yield File.writeAtomic(path, DEFAULT_CONTENTS);
|
||||
yield File.writeAtomic(path, WRITE_CONTENTS, { backupTo: path + ".backup" });
|
||||
do_check_true((yield File.exists(path + ".backup")));
|
||||
let contents = yield File.read(path + ".backup");
|
||||
do_check_eq(DEFAULT_CONTENTS, (new TextDecoder()).decode(contents));
|
||||
});
|
||||
|
||||
/**
|
||||
* test when
|
||||
* |backupTo| not specified
|
||||
* |tmpPath| not specified
|
||||
* destination file exists
|
||||
* @result destination file will not be backed up
|
||||
*/
|
||||
add_task(function* test_non_backupTo_option() {
|
||||
let DEFAULT_CONTENTS = "default contents" + Math.random();
|
||||
let WRITE_CONTENTS = "abc" + Math.random();
|
||||
let path = Path.join(Constants.Path.tmpDir,
|
||||
"test_non_backupTo_option.tmp");
|
||||
yield File.writeAtomic(path, DEFAULT_CONTENTS);
|
||||
yield File.writeAtomic(path, WRITE_CONTENTS);
|
||||
do_check_false((yield File.exists(path + ".backup")));
|
||||
});
|
||||
|
||||
/**
|
||||
* test when
|
||||
* |backupTo| specified
|
||||
* |tmpPath| not specified
|
||||
* destination file not exists
|
||||
* @result no back up file exists
|
||||
*/
|
||||
add_task(function* test_backupTo_option_without_destination_file() {
|
||||
let DEFAULT_CONTENTS = "default contents" + Math.random();
|
||||
let WRITE_CONTENTS = "abc" + Math.random();
|
||||
let path = Path.join(Constants.Path.tmpDir,
|
||||
"test_backupTo_option_without_destination_file.tmp");
|
||||
yield File.remove(path);
|
||||
yield File.writeAtomic(path, WRITE_CONTENTS, { backupTo: path + ".backup" });
|
||||
do_check_false((yield File.exists(path + ".backup")));
|
||||
});
|
||||
|
||||
/**
|
||||
* test when
|
||||
* |backupTo| specified
|
||||
* |tmpPath| not specified
|
||||
* backup file exists
|
||||
* destination file exists
|
||||
* @result destination file will be backed up
|
||||
*/
|
||||
add_task(function* test_backupTo_option_with_backup_file() {
|
||||
let DEFAULT_CONTENTS = "default contents" + Math.random();
|
||||
let WRITE_CONTENTS = "abc" + Math.random();
|
||||
let path = Path.join(Constants.Path.tmpDir,
|
||||
"test_backupTo_option_with_backup_file.tmp");
|
||||
yield File.writeAtomic(path, DEFAULT_CONTENTS);
|
||||
|
||||
yield File.writeAtomic(path + ".backup", new Uint8Array(1000));
|
||||
|
||||
yield File.writeAtomic(path, WRITE_CONTENTS, { backupTo: path + ".backup" });
|
||||
do_check_true((yield File.exists(path + ".backup")));
|
||||
let contents = yield File.read(path + ".backup");
|
||||
do_check_eq(DEFAULT_CONTENTS, (new TextDecoder()).decode(contents));
|
||||
});
|
||||
|
||||
add_task(function* cleanup() {
|
||||
yield clearFiles();
|
||||
});
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
var SHARED_PATH;
|
||||
|
||||
add_task(function* init() {
|
||||
do_get_profile();
|
||||
SHARED_PATH = OS.Path.join(OS.Constants.Path.profileDir, "test_osfile_write_zerobytes.tmp");
|
||||
});
|
||||
|
||||
add_test_pair(function* test_osfile_writeAtomic_zerobytes() {
|
||||
let encoder = new TextEncoder();
|
||||
let string1 = "";
|
||||
let outbin = encoder.encode(string1);
|
||||
yield OS.File.writeAtomic(SHARED_PATH, outbin);
|
||||
|
||||
let decoder = new TextDecoder();
|
||||
let bin = yield OS.File.read(SHARED_PATH);
|
||||
let string2 = decoder.decode(bin);
|
||||
// Checking if writeAtomic supports writing encoded zero-byte strings
|
||||
Assert.equal(string2, string1, "Read the expected (empty) string.");
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
159
toolkit/components/osfile/tests/xpcshell/test_path.js
Normal file
159
toolkit/components/osfile/tests/xpcshell/test_path.js
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm", this);
|
||||
Services.prefs.setBoolPref("toolkit.osfile.test.syslib_necessary", false);
|
||||
// We don't need libc/kernel32.dll for this test
|
||||
|
||||
var ImportWin = {};
|
||||
var ImportUnix = {};
|
||||
Components.utils.import("resource://gre/modules/osfile/ospath_win.jsm", ImportWin);
|
||||
Components.utils.import("resource://gre/modules/osfile/ospath_unix.jsm", ImportUnix);
|
||||
|
||||
var Win = ImportWin;
|
||||
var Unix = ImportUnix;
|
||||
|
||||
function do_check_fail(f)
|
||||
{
|
||||
try {
|
||||
let result = f();
|
||||
do_print("Failed do_check_fail: " + result);
|
||||
do_check_true(false);
|
||||
} catch (ex) {
|
||||
do_check_true(true);
|
||||
}
|
||||
};
|
||||
|
||||
function run_test()
|
||||
{
|
||||
do_print("Testing Windows paths");
|
||||
|
||||
do_print("Backslash-separated, no drive");
|
||||
do_check_eq(Win.basename("a\\b"), "b");
|
||||
do_check_eq(Win.basename("a\\b\\"), "");
|
||||
do_check_eq(Win.basename("abc"), "abc");
|
||||
do_check_eq(Win.dirname("a\\b"), "a");
|
||||
do_check_eq(Win.dirname("a\\b\\"), "a\\b");
|
||||
do_check_eq(Win.dirname("a\\\\\\\\b"), "a");
|
||||
do_check_eq(Win.dirname("abc"), ".");
|
||||
do_check_eq(Win.normalize("\\a\\b\\c"), "\\a\\b\\c");
|
||||
do_check_eq(Win.normalize("\\a\\b\\\\\\\\c"), "\\a\\b\\c");
|
||||
do_check_eq(Win.normalize("\\a\\b\\c\\\\\\"), "\\a\\b\\c");
|
||||
do_check_eq(Win.normalize("\\a\\b\\c\\..\\..\\..\\d\\e\\f"), "\\d\\e\\f");
|
||||
do_check_eq(Win.normalize("a\\b\\c\\..\\..\\..\\d\\e\\f"), "d\\e\\f");
|
||||
do_check_fail(() => Win.normalize("\\a\\b\\c\\..\\..\\..\\..\\d\\e\\f"));
|
||||
|
||||
do_check_eq(Win.join("\\tmp", "foo", "bar"), "\\tmp\\foo\\bar", "join \\tmp,foo,bar");
|
||||
do_check_eq(Win.join("\\tmp", "\\foo", "bar"), "\\foo\\bar", "join \\tmp,\\foo,bar");
|
||||
do_check_eq(Win.winGetDrive("\\tmp"), null);
|
||||
do_check_eq(Win.winGetDrive("\\tmp\\a\\b\\c\\d\\e"), null);
|
||||
do_check_eq(Win.winGetDrive("\\"), null);
|
||||
|
||||
|
||||
do_print("Backslash-separated, with a drive");
|
||||
do_check_eq(Win.basename("c:a\\b"), "b");
|
||||
do_check_eq(Win.basename("c:a\\b\\"), "");
|
||||
do_check_eq(Win.basename("c:abc"), "abc");
|
||||
do_check_eq(Win.dirname("c:a\\b"), "c:a");
|
||||
do_check_eq(Win.dirname("c:a\\b\\"), "c:a\\b");
|
||||
do_check_eq(Win.dirname("c:a\\\\\\\\b"), "c:a");
|
||||
do_check_eq(Win.dirname("c:abc"), "c:");
|
||||
let options = {
|
||||
winNoDrive: true
|
||||
};
|
||||
do_check_eq(Win.dirname("c:a\\b", options), "a");
|
||||
do_check_eq(Win.dirname("c:a\\b\\", options), "a\\b");
|
||||
do_check_eq(Win.dirname("c:a\\\\\\\\b", options), "a");
|
||||
do_check_eq(Win.dirname("c:abc", options), ".");
|
||||
do_check_eq(Win.join("c:", "abc"), "c:\\abc", "join c:,abc");
|
||||
|
||||
do_check_eq(Win.normalize("c:"), "c:\\");
|
||||
do_check_eq(Win.normalize("c:\\"), "c:\\");
|
||||
do_check_eq(Win.normalize("c:\\a\\b\\c"), "c:\\a\\b\\c");
|
||||
do_check_eq(Win.normalize("c:\\a\\b\\\\\\\\c"), "c:\\a\\b\\c");
|
||||
do_check_eq(Win.normalize("c:\\\\\\\\a\\b\\c"), "c:\\a\\b\\c");
|
||||
do_check_eq(Win.normalize("c:\\a\\b\\c\\\\\\"), "c:\\a\\b\\c");
|
||||
do_check_eq(Win.normalize("c:\\a\\b\\c\\..\\..\\..\\d\\e\\f"), "c:\\d\\e\\f");
|
||||
do_check_eq(Win.normalize("c:a\\b\\c\\..\\..\\..\\d\\e\\f"), "c:\\d\\e\\f");
|
||||
do_check_fail(() => Win.normalize("c:\\a\\b\\c\\..\\..\\..\\..\\d\\e\\f"));
|
||||
|
||||
do_check_eq(Win.join("c:\\", "foo"), "c:\\foo", "join c:\,foo");
|
||||
do_check_eq(Win.join("c:\\tmp", "foo", "bar"), "c:\\tmp\\foo\\bar", "join c:\\tmp,foo,bar");
|
||||
do_check_eq(Win.join("c:\\tmp", "\\foo", "bar"), "c:\\foo\\bar", "join c:\\tmp,\\foo,bar");
|
||||
do_check_eq(Win.join("c:\\tmp", "c:\\foo", "bar"), "c:\\foo\\bar", "join c:\\tmp,c:\\foo,bar");
|
||||
do_check_eq(Win.join("c:\\tmp", "c:foo", "bar"), "c:\\foo\\bar", "join c:\\tmp,c:foo,bar");
|
||||
do_check_eq(Win.winGetDrive("c:"), "c:");
|
||||
do_check_eq(Win.winGetDrive("c:\\"), "c:");
|
||||
do_check_eq(Win.winGetDrive("c:abc"), "c:");
|
||||
do_check_eq(Win.winGetDrive("c:abc\\d\\e\\f\\g"), "c:");
|
||||
do_check_eq(Win.winGetDrive("c:\\abc"), "c:");
|
||||
do_check_eq(Win.winGetDrive("c:\\abc\\d\\e\\f\\g"), "c:");
|
||||
|
||||
do_print("Forwardslash-separated, no drive");
|
||||
do_check_eq(Win.normalize("/a/b/c"), "\\a\\b\\c");
|
||||
do_check_eq(Win.normalize("/a/b////c"), "\\a\\b\\c");
|
||||
do_check_eq(Win.normalize("/a/b/c///"), "\\a\\b\\c");
|
||||
do_check_eq(Win.normalize("/a/b/c/../../../d/e/f"), "\\d\\e\\f");
|
||||
do_check_eq(Win.normalize("a/b/c/../../../d/e/f"), "d\\e\\f");
|
||||
|
||||
do_print("Forwardslash-separated, with a drive");
|
||||
do_check_eq(Win.normalize("c:/"), "c:\\");
|
||||
do_check_eq(Win.normalize("c:/a/b/c"), "c:\\a\\b\\c");
|
||||
do_check_eq(Win.normalize("c:/a/b////c"), "c:\\a\\b\\c");
|
||||
do_check_eq(Win.normalize("c:////a/b/c"), "c:\\a\\b\\c");
|
||||
do_check_eq(Win.normalize("c:/a/b/c///"), "c:\\a\\b\\c");
|
||||
do_check_eq(Win.normalize("c:/a/b/c/../../../d/e/f"), "c:\\d\\e\\f");
|
||||
do_check_eq(Win.normalize("c:a/b/c/../../../d/e/f"), "c:\\d\\e\\f");
|
||||
|
||||
do_print("Backslash-separated, UNC-style");
|
||||
do_check_eq(Win.basename("\\\\a\\b"), "b");
|
||||
do_check_eq(Win.basename("\\\\a\\b\\"), "");
|
||||
do_check_eq(Win.basename("\\\\abc"), "");
|
||||
do_check_eq(Win.dirname("\\\\a\\b"), "\\\\a");
|
||||
do_check_eq(Win.dirname("\\\\a\\b\\"), "\\\\a\\b");
|
||||
do_check_eq(Win.dirname("\\\\a\\\\\\\\b"), "\\\\a");
|
||||
do_check_eq(Win.dirname("\\\\abc"), "\\\\abc");
|
||||
do_check_eq(Win.normalize("\\\\a\\b\\c"), "\\\\a\\b\\c");
|
||||
do_check_eq(Win.normalize("\\\\a\\b\\\\\\\\c"), "\\\\a\\b\\c");
|
||||
do_check_eq(Win.normalize("\\\\a\\b\\c\\\\\\"), "\\\\a\\b\\c");
|
||||
do_check_eq(Win.normalize("\\\\a\\b\\c\\..\\..\\d\\e\\f"), "\\\\a\\d\\e\\f");
|
||||
do_check_fail(() => Win.normalize("\\\\a\\b\\c\\..\\..\\..\\d\\e\\f"));
|
||||
|
||||
do_check_eq(Win.join("\\\\a\\tmp", "foo", "bar"), "\\\\a\\tmp\\foo\\bar");
|
||||
do_check_eq(Win.join("\\\\a\\tmp", "\\foo", "bar"), "\\\\a\\foo\\bar");
|
||||
do_check_eq(Win.join("\\\\a\\tmp", "\\\\foo\\", "bar"), "\\\\foo\\bar");
|
||||
do_check_eq(Win.winGetDrive("\\\\"), null);
|
||||
do_check_eq(Win.winGetDrive("\\\\c"), "\\\\c");
|
||||
do_check_eq(Win.winGetDrive("\\\\c\\abc"), "\\\\c");
|
||||
|
||||
do_print("Testing unix paths");
|
||||
do_check_eq(Unix.basename("a/b"), "b");
|
||||
do_check_eq(Unix.basename("a/b/"), "");
|
||||
do_check_eq(Unix.basename("abc"), "abc");
|
||||
do_check_eq(Unix.dirname("a/b"), "a");
|
||||
do_check_eq(Unix.dirname("a/b/"), "a/b");
|
||||
do_check_eq(Unix.dirname("a////b"), "a");
|
||||
do_check_eq(Unix.dirname("abc"), ".");
|
||||
do_check_eq(Unix.normalize("/a/b/c"), "/a/b/c");
|
||||
do_check_eq(Unix.normalize("/a/b////c"), "/a/b/c");
|
||||
do_check_eq(Unix.normalize("////a/b/c"), "/a/b/c");
|
||||
do_check_eq(Unix.normalize("/a/b/c///"), "/a/b/c");
|
||||
do_check_eq(Unix.normalize("/a/b/c/../../../d/e/f"), "/d/e/f");
|
||||
do_check_eq(Unix.normalize("a/b/c/../../../d/e/f"), "d/e/f");
|
||||
do_check_fail(() => Unix.normalize("/a/b/c/../../../../d/e/f"));
|
||||
|
||||
do_check_eq(Unix.join("/tmp", "foo", "bar"), "/tmp/foo/bar", "join /tmp,foo,bar");
|
||||
do_check_eq(Unix.join("/tmp", "/foo", "bar"), "/foo/bar", "join /tmp,/foo,bar");
|
||||
|
||||
do_print("Testing the presence of ospath.jsm");
|
||||
let Scope = {};
|
||||
try {
|
||||
Components.utils.import("resource://gre/modules/osfile/ospath.jsm", Scope);
|
||||
} catch (ex) {
|
||||
// Can't load ospath
|
||||
}
|
||||
do_check_true(!!Scope.basename);
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource://gre/modules/ctypes.jsm", this);
|
||||
Cu.import("resource://testing-common/AppData.jsm", this);
|
||||
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function compare_paths(ospath, key) {
|
||||
let file;
|
||||
try {
|
||||
file = Services.dirsvc.get(key, Components.interfaces.nsIFile);
|
||||
} catch(ex) {}
|
||||
|
||||
if (file) {
|
||||
do_check_true(!!ospath);
|
||||
do_check_eq(ospath, file.path);
|
||||
} else {
|
||||
do_print("WARNING: " + key + " is not defined. Test may not be testing anything!");
|
||||
do_check_false(!!ospath);
|
||||
}
|
||||
}
|
||||
|
||||
// Some path constants aren't set up until the profile is available. This
|
||||
// test verifies that behavior.
|
||||
add_task(function* test_before_after_profile() {
|
||||
do_check_null(OS.Constants.Path.profileDir);
|
||||
do_check_null(OS.Constants.Path.localProfileDir);
|
||||
do_check_null(OS.Constants.Path.userApplicationDataDir);
|
||||
|
||||
do_get_profile();
|
||||
do_check_true(!!OS.Constants.Path.profileDir);
|
||||
do_check_true(!!OS.Constants.Path.localProfileDir);
|
||||
|
||||
// UAppData is still null because the xpcshell profile doesn't set it up.
|
||||
// This test is mostly here to fail in case behavior of do_get_profile() ever
|
||||
// changes. We want to know if our assumptions no longer hold!
|
||||
do_check_null(OS.Constants.Path.userApplicationDataDir);
|
||||
|
||||
yield makeFakeAppDir();
|
||||
do_check_true(!!OS.Constants.Path.userApplicationDataDir);
|
||||
|
||||
// FUTURE: verify AppData too (bug 964291).
|
||||
});
|
||||
|
||||
// Test simple paths
|
||||
add_task(function* test_simple_paths() {
|
||||
do_check_true(!!OS.Constants.Path.tmpDir);
|
||||
compare_paths(OS.Constants.Path.tmpDir, "TmpD");
|
||||
|
||||
});
|
||||
|
||||
// Test presence of paths that only exist on Desktop platforms
|
||||
add_task(function* test_desktop_paths() {
|
||||
if (OS.Constants.Sys.Name == "Android" || OS.Constants.Sys.Name == "Gonk") {
|
||||
return;
|
||||
}
|
||||
do_check_true(!!OS.Constants.Path.desktopDir);
|
||||
do_check_true(!!OS.Constants.Path.homeDir);
|
||||
|
||||
compare_paths(OS.Constants.Path.homeDir, "Home");
|
||||
compare_paths(OS.Constants.Path.desktopDir, "Desk");
|
||||
compare_paths(OS.Constants.Path.userApplicationDataDir, "UAppData");
|
||||
|
||||
compare_paths(OS.Constants.Path.winAppDataDir, "AppData");
|
||||
compare_paths(OS.Constants.Path.winStartMenuProgsDir, "Progs");
|
||||
|
||||
compare_paths(OS.Constants.Path.macUserLibDir, "ULibDir");
|
||||
compare_paths(OS.Constants.Path.macLocalApplicationsDir, "LocApp");
|
||||
compare_paths(OS.Constants.Path.macTrashDir, "Trsh");
|
||||
});
|
||||
|
||||
// Open libxul
|
||||
add_task(function* test_libxul() {
|
||||
ctypes.open(OS.Constants.Path.libxul);
|
||||
do_print("Linked to libxul");
|
||||
});
|
||||
38
toolkit/components/osfile/tests/xpcshell/test_queue.js
Normal file
38
toolkit/components/osfile/tests/xpcshell/test_queue.js
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
// Check if Scheduler.queue returned by OS.File.queue is resolved initially.
|
||||
add_task(function* check_init() {
|
||||
yield OS.File.queue;
|
||||
do_print("Function resolved");
|
||||
});
|
||||
|
||||
// Check if Scheduler.queue returned by OS.File.queue is resolved
|
||||
// after an operation is successful.
|
||||
add_task(function* check_success() {
|
||||
do_print("Attempting to open a file correctly");
|
||||
let openedFile = yield OS.File.open(OS.Path.join(do_get_cwd().path, "test_queue.js"));
|
||||
do_print("File opened correctly");
|
||||
yield OS.File.queue;
|
||||
do_print("Function resolved");
|
||||
});
|
||||
|
||||
// Check if Scheduler.queue returned by OS.File.queue is resolved
|
||||
// after an operation fails.
|
||||
add_task(function* check_failure() {
|
||||
let exception;
|
||||
try {
|
||||
do_print("Attempting to open a non existing file");
|
||||
yield OS.File.open(OS.Path.join(".", "Bigfoot"));
|
||||
} catch (err) {
|
||||
exception = err;
|
||||
yield OS.File.queue;
|
||||
}
|
||||
do_check_true(exception!=null);
|
||||
do_print("Function resolved");
|
||||
});
|
||||
103
toolkit/components/osfile/tests/xpcshell/test_read_write.js
Normal file
103
toolkit/components/osfile/tests/xpcshell/test_read_write.js
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
var {utils: Cu} = Components;
|
||||
|
||||
var SHARED_PATH;
|
||||
|
||||
var EXISTING_FILE = do_get_file("xpcshell.ini").path;
|
||||
|
||||
add_task(function* init() {
|
||||
do_get_profile();
|
||||
SHARED_PATH = OS.Path.join(OS.Constants.Path.profileDir, "test_osfile_read.tmp");
|
||||
});
|
||||
|
||||
|
||||
// Check that OS.File.read() is executed after the previous operation
|
||||
add_test_pair(function* ordering() {
|
||||
let string1 = "Initial state " + Math.random();
|
||||
let string2 = "After writing " + Math.random();
|
||||
yield OS.File.writeAtomic(SHARED_PATH, string1);
|
||||
OS.File.writeAtomic(SHARED_PATH, string2);
|
||||
let string3 = yield OS.File.read(SHARED_PATH, { encoding: "utf-8" });
|
||||
do_check_eq(string3, string2);
|
||||
});
|
||||
|
||||
add_test_pair(function* read_write_all() {
|
||||
let DEST_PATH = SHARED_PATH + Math.random();
|
||||
let TMP_PATH = DEST_PATH + ".tmp";
|
||||
|
||||
let test_with_options = function(options, suffix) {
|
||||
return Task.spawn(function*() {
|
||||
do_print("Running test read_write_all with options " + JSON.stringify(options));
|
||||
let TEST = "read_write_all " + suffix;
|
||||
|
||||
let optionsBackup = JSON.parse(JSON.stringify(options));
|
||||
|
||||
// Check that read + writeAtomic performs a correct copy
|
||||
let currentDir = yield OS.File.getCurrentDirectory();
|
||||
let pathSource = OS.Path.join(currentDir, EXISTING_FILE);
|
||||
let contents = yield OS.File.read(pathSource);
|
||||
do_check_true(!!contents); // Content is not empty
|
||||
let bytesRead = contents.byteLength;
|
||||
|
||||
let bytesWritten = yield OS.File.writeAtomic(DEST_PATH, contents, options);
|
||||
do_check_eq(bytesRead, bytesWritten); // Correct number of bytes written
|
||||
|
||||
// Check that options are not altered
|
||||
do_check_eq(JSON.stringify(options), JSON.stringify(optionsBackup));
|
||||
yield reference_compare_files(pathSource, DEST_PATH, TEST);
|
||||
|
||||
// Check that temporary file was removed or never created exist
|
||||
do_check_false(new FileUtils.File(TMP_PATH).exists());
|
||||
|
||||
// Check that writeAtomic fails if noOverwrite is true and the destination
|
||||
// file already exists!
|
||||
contents = new Uint8Array(300);
|
||||
let view = new Uint8Array(contents.buffer, 10, 200);
|
||||
try {
|
||||
let opt = JSON.parse(JSON.stringify(options));
|
||||
opt.noOverwrite = true;
|
||||
yield OS.File.writeAtomic(DEST_PATH, view, opt);
|
||||
do_throw("With noOverwrite, writeAtomic should have refused to overwrite file (" + suffix + ")");
|
||||
} catch (err if err instanceof OS.File.Error && err.becauseExists) {
|
||||
do_print("With noOverwrite, writeAtomic correctly failed (" + suffix + ")");
|
||||
}
|
||||
yield reference_compare_files(pathSource, DEST_PATH, TEST);
|
||||
|
||||
// Check that temporary file was removed or never created
|
||||
do_check_false(new FileUtils.File(TMP_PATH).exists());
|
||||
|
||||
// Now write a subset
|
||||
let START = 10;
|
||||
let LENGTH = 100;
|
||||
contents = new Uint8Array(300);
|
||||
for (var i = 0; i < contents.byteLength; i++)
|
||||
contents[i] = i % 256;
|
||||
view = new Uint8Array(contents.buffer, START, LENGTH);
|
||||
bytesWritten = yield OS.File.writeAtomic(DEST_PATH, view, options);
|
||||
do_check_eq(bytesWritten, LENGTH);
|
||||
|
||||
let array2 = yield OS.File.read(DEST_PATH);
|
||||
do_check_eq(LENGTH, array2.length);
|
||||
for (var i = 0; i < LENGTH; i++)
|
||||
do_check_eq(array2[i], (i + START) % 256);
|
||||
|
||||
// Cleanup.
|
||||
yield OS.File.remove(DEST_PATH);
|
||||
yield OS.File.remove(TMP_PATH);
|
||||
});
|
||||
};
|
||||
|
||||
yield test_with_options({tmpPath: TMP_PATH}, "Renaming, not flushing");
|
||||
yield test_with_options({tmpPath: TMP_PATH, flush: true}, "Renaming, flushing");
|
||||
yield test_with_options({}, "Not renaming, not flushing");
|
||||
yield test_with_options({flush: true}, "Not renaming, flushing");
|
||||
});
|
||||
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
56
toolkit/components/osfile/tests/xpcshell/test_remove.js
Normal file
56
toolkit/components/osfile/tests/xpcshell/test_remove.js
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
Components.utils.import("resource://gre/modules/Task.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
do_register_cleanup(function() {
|
||||
Services.prefs.setBoolPref("toolkit.osfile.log", false);
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
Services.prefs.setBoolPref("toolkit.osfile.log", true);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_ignoreAbsent() {
|
||||
let absent_file_name = "test_osfile_front_absent.tmp";
|
||||
|
||||
// Removing absent files should throw if "ignoreAbsent" is true.
|
||||
yield Assert.rejects(OS.File.remove(absent_file_name, {ignoreAbsent: false}),
|
||||
"OS.File.remove throws if there is no such file.");
|
||||
|
||||
// Removing absent files should not throw if "ignoreAbsent" is true or not
|
||||
// defined.
|
||||
let exception = null;
|
||||
try {
|
||||
yield OS.File.remove(absent_file_name, {ignoreAbsent: true});
|
||||
yield OS.File.remove(absent_file_name);
|
||||
} catch (ex) {
|
||||
exception = ex;
|
||||
}
|
||||
Assert.ok(!exception, "OS.File.remove should not throw when not requested.");
|
||||
});
|
||||
|
||||
add_task(function* test_ignoreAbsent_directory_missing() {
|
||||
let absent_file_name = OS.Path.join("absent_parent", "test.tmp");
|
||||
|
||||
// Removing absent files should throw if "ignoreAbsent" is true.
|
||||
yield Assert.rejects(OS.File.remove(absent_file_name, {ignoreAbsent: false}),
|
||||
"OS.File.remove throws if there is no such file.");
|
||||
|
||||
// Removing files from absent directories should not throw if "ignoreAbsent"
|
||||
// is true or not defined.
|
||||
let exception = null;
|
||||
try {
|
||||
yield OS.File.remove(absent_file_name, {ignoreAbsent: true});
|
||||
yield OS.File.remove(absent_file_name);
|
||||
} catch (ex) {
|
||||
exception = ex;
|
||||
}
|
||||
Assert.ok(!exception, "OS.File.remove should not throw when not requested.");
|
||||
});
|
||||
177
toolkit/components/osfile/tests/xpcshell/test_removeDir.js
Normal file
177
toolkit/components/osfile/tests/xpcshell/test_removeDir.js
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
Components.utils.import("resource://gre/modules/Task.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
do_register_cleanup(function() {
|
||||
Services.prefs.setBoolPref("toolkit.osfile.log", false);
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
Services.prefs.setBoolPref("toolkit.osfile.log", true);
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function() {
|
||||
// Set up profile. We create the directory in the profile, because the profile
|
||||
// is removed after every test run.
|
||||
do_get_profile();
|
||||
|
||||
let file = OS.Path.join(OS.Constants.Path.profileDir, "file");
|
||||
let dir = OS.Path.join(OS.Constants.Path.profileDir, "directory");
|
||||
let file1 = OS.Path.join(dir, "file1");
|
||||
let file2 = OS.Path.join(dir, "file2");
|
||||
let subDir = OS.Path.join(dir, "subdir");
|
||||
let fileInSubDir = OS.Path.join(subDir, "file");
|
||||
|
||||
// Sanity checking for the test
|
||||
do_check_false((yield OS.File.exists(dir)));
|
||||
|
||||
// Remove non-existent directory
|
||||
let exception = null;
|
||||
try {
|
||||
yield OS.File.removeDir(dir, {ignoreAbsent: false});
|
||||
} catch (ex) {
|
||||
exception = ex;
|
||||
}
|
||||
|
||||
do_check_true(!!exception);
|
||||
do_check_true(exception instanceof OS.File.Error);
|
||||
|
||||
// Remove non-existent directory with ignoreAbsent
|
||||
yield OS.File.removeDir(dir, {ignoreAbsent: true});
|
||||
yield OS.File.removeDir(dir);
|
||||
|
||||
// Remove file with ignoreAbsent: false
|
||||
yield OS.File.writeAtomic(file, "content", { tmpPath: file + ".tmp" });
|
||||
exception = null;
|
||||
try {
|
||||
yield OS.File.removeDir(file, {ignoreAbsent: false});
|
||||
} catch (ex) {
|
||||
exception = ex;
|
||||
}
|
||||
|
||||
do_check_true(!!exception);
|
||||
do_check_true(exception instanceof OS.File.Error);
|
||||
|
||||
// Remove empty directory
|
||||
yield OS.File.makeDir(dir);
|
||||
yield OS.File.removeDir(dir);
|
||||
do_check_false((yield OS.File.exists(dir)));
|
||||
|
||||
// Remove directory that contains one file
|
||||
yield OS.File.makeDir(dir);
|
||||
yield OS.File.writeAtomic(file1, "content", { tmpPath: file1 + ".tmp" });
|
||||
yield OS.File.removeDir(dir);
|
||||
do_check_false((yield OS.File.exists(dir)));
|
||||
|
||||
// Remove directory that contains multiple files
|
||||
yield OS.File.makeDir(dir);
|
||||
yield OS.File.writeAtomic(file1, "content", { tmpPath: file1 + ".tmp" });
|
||||
yield OS.File.writeAtomic(file2, "content", { tmpPath: file2 + ".tmp" });
|
||||
yield OS.File.removeDir(dir);
|
||||
do_check_false((yield OS.File.exists(dir)));
|
||||
|
||||
// Remove directory that contains a file and a directory
|
||||
yield OS.File.makeDir(dir);
|
||||
yield OS.File.writeAtomic(file1, "content", { tmpPath: file1 + ".tmp" });
|
||||
yield OS.File.makeDir(subDir);
|
||||
yield OS.File.writeAtomic(fileInSubDir, "content", { tmpPath: fileInSubDir + ".tmp" });
|
||||
yield OS.File.removeDir(dir);
|
||||
do_check_false((yield OS.File.exists(dir)));
|
||||
});
|
||||
|
||||
add_task(function* test_unix_symlink() {
|
||||
// Windows does not implement OS.File.unixSymLink()
|
||||
if (OS.Constants.Win) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Android / B2G file systems typically don't support symlinks.
|
||||
if (OS.Constants.Sys.Name == "Android") {
|
||||
return;
|
||||
}
|
||||
|
||||
let file = OS.Path.join(OS.Constants.Path.profileDir, "file");
|
||||
let dir = OS.Path.join(OS.Constants.Path.profileDir, "directory");
|
||||
let file1 = OS.Path.join(dir, "file1");
|
||||
|
||||
// This test will create the following directory structure:
|
||||
// <profileDir>/file (regular file)
|
||||
// <profileDir>/file.link => file (symlink)
|
||||
// <profileDir>/directory (directory)
|
||||
// <profileDir>/linkdir => directory (directory)
|
||||
// <profileDir>/directory/file1 (regular file)
|
||||
// <profileDir>/directory3 (directory)
|
||||
// <profileDir>/directory3/file3 (directory)
|
||||
// <profileDir>/directory/link2 => ../directory3 (regular file)
|
||||
|
||||
// Sanity checking for the test
|
||||
do_check_false((yield OS.File.exists(dir)));
|
||||
|
||||
yield OS.File.writeAtomic(file, "content", { tmpPath: file + ".tmp" });
|
||||
do_check_true((yield OS.File.exists(file)));
|
||||
let info = yield OS.File.stat(file, {unixNoFollowingLinks: true});
|
||||
do_check_false(info.isDir);
|
||||
do_check_false(info.isSymLink);
|
||||
|
||||
yield OS.File.unixSymLink(file, file + ".link");
|
||||
do_check_true((yield OS.File.exists(file + ".link")));
|
||||
info = yield OS.File.stat(file + ".link", {unixNoFollowingLinks: true});
|
||||
do_check_false(info.isDir);
|
||||
do_check_true(info.isSymLink);
|
||||
info = yield OS.File.stat(file + ".link");
|
||||
do_check_false(info.isDir);
|
||||
do_check_false(info.isSymLink);
|
||||
yield OS.File.remove(file + ".link");
|
||||
do_check_false((yield OS.File.exists(file + ".link")));
|
||||
|
||||
yield OS.File.makeDir(dir);
|
||||
do_check_true((yield OS.File.exists(dir)));
|
||||
info = yield OS.File.stat(dir, {unixNoFollowingLinks: true});
|
||||
do_check_true(info.isDir);
|
||||
do_check_false(info.isSymLink);
|
||||
|
||||
let link = OS.Path.join(OS.Constants.Path.profileDir, "linkdir");
|
||||
|
||||
yield OS.File.unixSymLink(dir, link);
|
||||
do_check_true((yield OS.File.exists(link)));
|
||||
info = yield OS.File.stat(link, {unixNoFollowingLinks: true});
|
||||
do_check_false(info.isDir);
|
||||
do_check_true(info.isSymLink);
|
||||
info = yield OS.File.stat(link);
|
||||
do_check_true(info.isDir);
|
||||
do_check_false(info.isSymLink);
|
||||
|
||||
let dir3 = OS.Path.join(OS.Constants.Path.profileDir, "directory3");
|
||||
let file3 = OS.Path.join(dir3, "file3");
|
||||
let link2 = OS.Path.join(dir, "link2");
|
||||
|
||||
yield OS.File.writeAtomic(file1, "content", { tmpPath: file1 + ".tmp" });
|
||||
do_check_true((yield OS.File.exists(file1)));
|
||||
yield OS.File.makeDir(dir3);
|
||||
do_check_true((yield OS.File.exists(dir3)));
|
||||
yield OS.File.writeAtomic(file3, "content", { tmpPath: file3 + ".tmp" });
|
||||
do_check_true((yield OS.File.exists(file3)));
|
||||
yield OS.File.unixSymLink("../directory3", link2);
|
||||
do_check_true((yield OS.File.exists(link2)));
|
||||
|
||||
yield OS.File.removeDir(link);
|
||||
do_check_false((yield OS.File.exists(link)));
|
||||
do_check_true((yield OS.File.exists(file1)));
|
||||
yield OS.File.removeDir(dir);
|
||||
do_check_false((yield OS.File.exists(dir)));
|
||||
do_check_true((yield OS.File.exists(file3)));
|
||||
yield OS.File.removeDir(dir3);
|
||||
do_check_false((yield OS.File.exists(dir3)));
|
||||
|
||||
// This task will be executed only on Unix-like systems.
|
||||
// Please do not add tests independent to operating systems here
|
||||
// or implement symlink() on Windows.
|
||||
});
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
do_register_cleanup(function() {
|
||||
Services.prefs.setBoolPref("toolkit.osfile.log", false);
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
Services.prefs.setBoolPref("toolkit.osfile.log", true);
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test OS.File.removeEmptyDir
|
||||
*/
|
||||
add_task(function() {
|
||||
// Set up profile. We create the directory in the profile, because the profile
|
||||
// is removed after every test run.
|
||||
do_get_profile();
|
||||
|
||||
let dir = OS.Path.join(OS.Constants.Path.profileDir, "directory");
|
||||
|
||||
// Sanity checking for the test
|
||||
do_check_false((yield OS.File.exists(dir)));
|
||||
|
||||
// Remove non-existent directory
|
||||
yield OS.File.removeEmptyDir(dir);
|
||||
|
||||
// Remove non-existent directory with ignoreAbsent
|
||||
yield OS.File.removeEmptyDir(dir, {ignoreAbsent: true});
|
||||
|
||||
// Remove non-existent directory with ignoreAbsent false
|
||||
let exception = null;
|
||||
try {
|
||||
yield OS.File.removeEmptyDir(dir, {ignoreAbsent: false});
|
||||
} catch (ex) {
|
||||
exception = ex;
|
||||
}
|
||||
|
||||
do_check_true(!!exception);
|
||||
do_check_true(exception instanceof OS.File.Error);
|
||||
do_check_true(exception.becauseNoSuchFile);
|
||||
|
||||
// Remove empty directory
|
||||
yield OS.File.makeDir(dir);
|
||||
yield OS.File.removeEmptyDir(dir);
|
||||
do_check_false((yield OS.File.exists(dir)));
|
||||
});
|
||||
95
toolkit/components/osfile/tests/xpcshell/test_reset.js
Normal file
95
toolkit/components/osfile/tests/xpcshell/test_reset.js
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
var Path = OS.Constants.Path;
|
||||
|
||||
add_task(function* init() {
|
||||
do_get_profile();
|
||||
});
|
||||
|
||||
add_task(function* reset_before_launching() {
|
||||
do_print("Reset without launching OS.File, it shouldn't break");
|
||||
yield OS.File.resetWorker();
|
||||
});
|
||||
|
||||
add_task(function* transparent_reset() {
|
||||
for (let i = 1; i < 3; ++i) {
|
||||
do_print("Do stome stuff before and after " + i + " reset(s), " +
|
||||
"it shouldn't break");
|
||||
let CONTENT = "some content " + i;
|
||||
let path = OS.Path.join(Path.profileDir, "tmp");
|
||||
yield OS.File.writeAtomic(path, CONTENT);
|
||||
for (let j = 0; j < i; ++j) {
|
||||
yield OS.File.resetWorker();
|
||||
}
|
||||
let data = yield OS.File.read(path);
|
||||
let string = (new TextDecoder()).decode(data);
|
||||
do_check_eq(string, CONTENT);
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* file_open_cannot_reset() {
|
||||
let TEST_FILE = OS.Path.join(Path.profileDir, "tmp-" + Math.random());
|
||||
do_print("Leaking file descriptor " + TEST_FILE + ", we shouldn't be able to reset");
|
||||
let openedFile = yield OS.File.open(TEST_FILE, { create: true} );
|
||||
let thrown = false;
|
||||
try {
|
||||
yield OS.File.resetWorker();
|
||||
} catch (ex if ex.message.indexOf(OS.Path.basename(TEST_FILE)) != -1 ) {
|
||||
thrown = true;
|
||||
}
|
||||
do_check_true(thrown);
|
||||
|
||||
do_print("Closing the file, we should now be able to reset");
|
||||
yield openedFile.close();
|
||||
yield OS.File.resetWorker();
|
||||
});
|
||||
|
||||
add_task(function* dir_open_cannot_reset() {
|
||||
let TEST_DIR = yield OS.File.getCurrentDirectory();
|
||||
do_print("Leaking directory " + TEST_DIR + ", we shouldn't be able to reset");
|
||||
let iterator = new OS.File.DirectoryIterator(TEST_DIR);
|
||||
let thrown = false;
|
||||
try {
|
||||
yield OS.File.resetWorker();
|
||||
} catch (ex if ex.message.indexOf(OS.Path.basename(TEST_DIR)) != -1 ) {
|
||||
thrown = true;
|
||||
}
|
||||
do_check_true(thrown);
|
||||
|
||||
do_print("Closing the directory, we should now be able to reset");
|
||||
yield iterator.close();
|
||||
yield OS.File.resetWorker();
|
||||
});
|
||||
|
||||
add_task(function* race_against_itself() {
|
||||
do_print("Attempt to get resetWorker() to race against itself");
|
||||
// Arbitrary operation, just to wake up the worker
|
||||
try {
|
||||
yield OS.File.read("/foo");
|
||||
} catch (ex) {
|
||||
}
|
||||
|
||||
let all = [];
|
||||
for (let i = 0; i < 100; ++i) {
|
||||
all.push(OS.File.resetWorker());
|
||||
}
|
||||
|
||||
yield Promise.all(all);
|
||||
});
|
||||
|
||||
|
||||
add_task(function* finish_with_a_reset() {
|
||||
do_print("Reset without waiting for the result");
|
||||
// Arbitrary operation, just to wake up the worker
|
||||
try {
|
||||
yield OS.File.read("/foo");
|
||||
} catch (ex) {
|
||||
}
|
||||
// Now reset
|
||||
/*don't yield*/ OS.File.resetWorker();
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
98
toolkit/components/osfile/tests/xpcshell/test_shutdown.js
Normal file
98
toolkit/components/osfile/tests/xpcshell/test_shutdown.js
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
Components.utils.import("resource://gre/modules/Services.jsm", this);
|
||||
Components.utils.import("resource://gre/modules/Promise.jsm", this);
|
||||
Components.utils.import("resource://gre/modules/Task.jsm", this);
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm", this);
|
||||
|
||||
add_task(function init() {
|
||||
do_get_profile();
|
||||
});
|
||||
|
||||
/**
|
||||
* Test logging of file descriptors leaks.
|
||||
*/
|
||||
add_task(function system_shutdown() {
|
||||
|
||||
// Test that unclosed files cause warnings
|
||||
// Test that unclosed directories cause warnings
|
||||
// Test that closed files do not cause warnings
|
||||
// Test that closed directories do not cause warnings
|
||||
function testLeaksOf(resource, topic) {
|
||||
return Task.spawn(function() {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
// Register observer
|
||||
Services.prefs.setBoolPref("toolkit.asyncshutdown.testing", true);
|
||||
Services.prefs.setBoolPref("toolkit.osfile.log", true);
|
||||
Services.prefs.setBoolPref("toolkit.osfile.log.redirect", true);
|
||||
Services.prefs.setCharPref("toolkit.osfile.test.shutdown.observer", topic);
|
||||
|
||||
let observer = function(aMessage) {
|
||||
try {
|
||||
do_print("Got message: " + aMessage);
|
||||
if (!(aMessage instanceof Components.interfaces.nsIConsoleMessage)) {
|
||||
return;
|
||||
}
|
||||
let message = aMessage.message;
|
||||
do_print("Got message: " + message);
|
||||
if (message.indexOf("TEST OS Controller WARNING") < 0) {
|
||||
return;
|
||||
}
|
||||
do_print("Got message: " + message + ", looking for resource " + resource);
|
||||
if (message.indexOf(resource) < 0) {
|
||||
return;
|
||||
}
|
||||
do_print("Resource: " + resource + " found");
|
||||
do_execute_soon(deferred.resolve);
|
||||
} catch (ex) {
|
||||
do_execute_soon(function() {
|
||||
deferred.reject(ex);
|
||||
});
|
||||
}
|
||||
};
|
||||
Services.console.registerListener(observer);
|
||||
Services.obs.notifyObservers(null, topic, null);
|
||||
do_timeout(1000, function() {
|
||||
do_print("Timeout while waiting for resource: " + resource);
|
||||
deferred.reject("timeout");
|
||||
});
|
||||
|
||||
let resolved = false;
|
||||
try {
|
||||
yield deferred.promise;
|
||||
resolved = true;
|
||||
} catch (ex if ex == "timeout") {
|
||||
resolved = false;
|
||||
}
|
||||
Services.console.unregisterListener(observer);
|
||||
Services.prefs.clearUserPref("toolkit.osfile.log");
|
||||
Services.prefs.clearUserPref("toolkit.osfile.log.redirect");
|
||||
Services.prefs.clearUserPref("toolkit.osfile.test.shutdown.observer");
|
||||
Services.prefs.clearUserPref("toolkit.async_shutdown.testing", true);
|
||||
|
||||
throw new Task.Result(resolved);
|
||||
});
|
||||
}
|
||||
|
||||
let TEST_DIR = OS.Path.join((yield OS.File.getCurrentDirectory()), "..");
|
||||
do_print("Testing for leaks of directory iterator " + TEST_DIR);
|
||||
let iterator = new OS.File.DirectoryIterator(TEST_DIR);
|
||||
do_print("At this stage, we leak the directory");
|
||||
do_check_true((yield testLeaksOf(TEST_DIR, "test.shutdown.dir.leak")));
|
||||
yield iterator.close();
|
||||
do_print("At this stage, we don't leak the directory anymore");
|
||||
do_check_false((yield testLeaksOf(TEST_DIR, "test.shutdown.dir.noleak")));
|
||||
|
||||
let TEST_FILE = OS.Path.join(OS.Constants.Path.profileDir, "test");
|
||||
do_print("Testing for leaks of file descriptor: " + TEST_FILE);
|
||||
let openedFile = yield OS.File.open(TEST_FILE, { create: true} );
|
||||
do_print("At this stage, we leak the file");
|
||||
do_check_true((yield testLeaksOf(TEST_FILE, "test.shutdown.file.leak")));
|
||||
yield openedFile.close();
|
||||
do_print("At this stage, we don't leak the file anymore");
|
||||
do_check_false((yield testLeaksOf(TEST_FILE, "test.shutdown.file.leak.2")));
|
||||
});
|
||||
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
63
toolkit/components/osfile/tests/xpcshell/test_telemetry.js
Normal file
63
toolkit/components/osfile/tests/xpcshell/test_telemetry.js
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
"use strict";
|
||||
|
||||
var {OS: {File, Path, Constants}} = Components.utils.import("resource://gre/modules/osfile.jsm", {});
|
||||
var {Services} = Components.utils.import("resource://gre/modules/Services.jsm", {});
|
||||
|
||||
// Ensure that we have a profile but that the OS.File worker is not launched
|
||||
add_task(function* init() {
|
||||
do_get_profile();
|
||||
yield File.resetWorker();
|
||||
});
|
||||
|
||||
function getCount(histogram) {
|
||||
if (histogram == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let total = 0;
|
||||
for (let i of histogram.counts) {
|
||||
total += i;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
// Ensure that launching the OS.File worker adds data to the relevant
|
||||
// histograms
|
||||
add_task(function* test_startup() {
|
||||
let LAUNCH = "OSFILE_WORKER_LAUNCH_MS";
|
||||
let READY = "OSFILE_WORKER_READY_MS";
|
||||
|
||||
let before = Services.telemetry.histogramSnapshots;
|
||||
|
||||
// Launch the OS.File worker
|
||||
yield File.getCurrentDirectory();
|
||||
|
||||
let after = Services.telemetry.histogramSnapshots;
|
||||
|
||||
|
||||
do_print("Ensuring that we have recorded measures for histograms");
|
||||
do_check_eq(getCount(after[LAUNCH]), getCount(before[LAUNCH]) + 1);
|
||||
do_check_eq(getCount(after[READY]), getCount(before[READY]) + 1);
|
||||
|
||||
do_print("Ensuring that launh <= ready");
|
||||
do_check_true(after[LAUNCH].sum <= after[READY].sum);
|
||||
});
|
||||
|
||||
// Ensure that calling writeAtomic adds data to the relevant histograms
|
||||
add_task(function* test_writeAtomic() {
|
||||
let LABEL = "OSFILE_WRITEATOMIC_JANK_MS";
|
||||
|
||||
let before = Services.telemetry.histogramSnapshots;
|
||||
|
||||
// Perform a write.
|
||||
let path = Path.join(Constants.Path.profileDir, "test_osfile_telemetry.tmp");
|
||||
yield File.writeAtomic(path, LABEL, { tmpPath: path + ".tmp" } );
|
||||
|
||||
let after = Services.telemetry.histogramSnapshots;
|
||||
|
||||
do_check_eq(getCount(after[LABEL]), getCount(before[LABEL]) + 1);
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
88
toolkit/components/osfile/tests/xpcshell/test_unique.js
Normal file
88
toolkit/components/osfile/tests/xpcshell/test_unique.js
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
Components.utils.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function testFiles(filename) {
|
||||
return Task.spawn(function() {
|
||||
const MAX_TRIES = 10;
|
||||
let profileDir = OS.Constants.Path.profileDir;
|
||||
let path = OS.Path.join(profileDir, filename);
|
||||
|
||||
// Ensure that openUnique() uses the file name if there is no file with that name already.
|
||||
let openedFile = yield OS.File.openUnique(path);
|
||||
do_print("\nCreate new file: " + openedFile.path);
|
||||
yield openedFile.file.close();
|
||||
let exists = yield OS.File.exists(openedFile.path);
|
||||
do_check_true(exists);
|
||||
do_check_eq(path, openedFile.path);
|
||||
let fileInfo = yield OS.File.stat(openedFile.path);
|
||||
do_check_true(fileInfo.size == 0);
|
||||
|
||||
// Ensure that openUnique() creates a new file name using a HEX number, as the original name is already taken.
|
||||
openedFile = yield OS.File.openUnique(path);
|
||||
do_print("\nCreate unique HEX file: " + openedFile.path);
|
||||
yield openedFile.file.close();
|
||||
exists = yield OS.File.exists(openedFile.path);
|
||||
do_check_true(exists);
|
||||
fileInfo = yield OS.File.stat(openedFile.path);
|
||||
do_check_true(fileInfo.size == 0);
|
||||
|
||||
// Ensure that openUnique() generates different file names each time, using the HEX number algorithm
|
||||
let filenames = new Set();
|
||||
for (let i=0; i < MAX_TRIES; i++) {
|
||||
openedFile = yield OS.File.openUnique(path);
|
||||
yield openedFile.file.close();
|
||||
filenames.add(openedFile.path);
|
||||
}
|
||||
|
||||
do_check_eq(filenames.size, MAX_TRIES);
|
||||
|
||||
// Ensure that openUnique() creates a new human readable file name using, as the original name is already taken.
|
||||
openedFile = yield OS.File.openUnique(path, {humanReadable : true});
|
||||
do_print("\nCreate unique Human Readable file: " + openedFile.path);
|
||||
yield openedFile.file.close();
|
||||
exists = yield OS.File.exists(openedFile.path);
|
||||
do_check_true(exists);
|
||||
fileInfo = yield OS.File.stat(openedFile.path);
|
||||
do_check_true(fileInfo.size == 0);
|
||||
|
||||
// Ensure that openUnique() generates different human readable file names each time
|
||||
filenames = new Set();
|
||||
for (let i=0; i < MAX_TRIES; i++) {
|
||||
openedFile = yield OS.File.openUnique(path, {humanReadable : true});
|
||||
yield openedFile.file.close();
|
||||
filenames.add(openedFile.path);
|
||||
}
|
||||
|
||||
do_check_eq(filenames.size, MAX_TRIES);
|
||||
|
||||
let exn;
|
||||
try {
|
||||
for (let i=0; i < 100; i++) {
|
||||
openedFile = yield OS.File.openUnique(path, {humanReadable : true});
|
||||
yield openedFile.file.close();
|
||||
}
|
||||
} catch (ex) {
|
||||
exn = ex;
|
||||
}
|
||||
|
||||
do_print("Ensure that this raises the correct error");
|
||||
do_check_true(!!exn);
|
||||
do_check_true(exn instanceof OS.File.Error);
|
||||
do_check_true(exn.becauseExists);
|
||||
});
|
||||
}
|
||||
|
||||
add_task(function test_unique() {
|
||||
OS.Shared.DEBUG = true;
|
||||
// Tests files with extension
|
||||
yield testFiles("dummy_unique_file.txt");
|
||||
// Tests files with no extension
|
||||
yield testFiles("dummy_unique_file_no_ext");
|
||||
});
|
||||
51
toolkit/components/osfile/tests/xpcshell/xpcshell.ini
Normal file
51
toolkit/components/osfile/tests/xpcshell/xpcshell.ini
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
[DEFAULT]
|
||||
head = head.js
|
||||
tail =
|
||||
|
||||
support-files =
|
||||
test_loader/module_test_loader.js
|
||||
|
||||
[test_available_free_space.js]
|
||||
[test_compression.js]
|
||||
[test_constants.js]
|
||||
[test_creationDate.js]
|
||||
[test_duration.js]
|
||||
[test_exception.js]
|
||||
[test_file_URL_conversion.js]
|
||||
[test_loader.js]
|
||||
[test_logging.js]
|
||||
[test_makeDir.js]
|
||||
[test_open.js]
|
||||
[test_osfile_async.js]
|
||||
[test_osfile_async_append.js]
|
||||
[test_osfile_async_bytes.js]
|
||||
[test_osfile_async_copy.js]
|
||||
[test_osfile_async_flush.js]
|
||||
[test_osfile_async_largefiles.js]
|
||||
[test_osfile_async_setDates.js]
|
||||
# Unimplemented on Windows (bug 1022816).
|
||||
# Spurious failure on Android test farm due to non-POSIX behavior of
|
||||
# filesystem backing /mnt/sdcard (not worth trying to fix).
|
||||
[test_osfile_async_setPermissions.js]
|
||||
skip-if = os == "win" || os == "android"
|
||||
[test_osfile_closed.js]
|
||||
[test_osfile_error.js]
|
||||
[test_osfile_kill.js]
|
||||
# Windows test
|
||||
[test_osfile_win_async_setPermissions.js]
|
||||
skip-if = os != "win"
|
||||
[test_osfile_writeAtomic_backupTo_option.js]
|
||||
[test_osfile_writeAtomic_zerobytes.js]
|
||||
[test_path.js]
|
||||
[test_path_constants.js]
|
||||
[test_queue.js]
|
||||
[test_read_write.js]
|
||||
requesttimeoutfactor = 4
|
||||
[test_remove.js]
|
||||
[test_removeDir.js]
|
||||
requesttimeoutfactor = 4
|
||||
[test_removeEmptyDir.js]
|
||||
[test_reset.js]
|
||||
[test_shutdown.js]
|
||||
[test_telemetry.js]
|
||||
[test_unique.js]
|
||||
Loading…
Add table
Add a link
Reference in a new issue