mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-17 23:35:34 +00:00
Bug 961665 - Tests for OS.File.read. r=froydnj
This commit is contained in:
parent
1b4b73d192
commit
bf44435306
@ -155,7 +155,6 @@ let test = maketest("Main", function main(test) {
|
||||
yield test_debug();
|
||||
yield test_info_features_detect();
|
||||
yield test_read_write();
|
||||
yield test_read_write_all();
|
||||
yield test_position();
|
||||
yield test_iter();
|
||||
yield test_exists();
|
||||
@ -303,92 +302,6 @@ let test_read_write = maketest("read_write", function read_write(test) {
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Test OS.File.writeAtomic
|
||||
*/
|
||||
let test_read_write_all = maketest("read_write_all", function read_write_all(test) {
|
||||
return Task.spawn(function() {
|
||||
let pathDest = OS.Path.join(OS.Constants.Path.tmpDir,
|
||||
"osfile async test read writeAtomic.tmp");
|
||||
let tmpPath = pathDest + ".tmp";
|
||||
|
||||
let test_with_options = function(options, suffix) {
|
||||
return Task.spawn(function() {
|
||||
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);
|
||||
test.ok(contents, "Obtained contents");
|
||||
let bytesWritten = yield OS.File.writeAtomic(pathDest, contents, options);
|
||||
test.is(contents.byteLength, bytesWritten, "Wrote the correct number of bytes (" + suffix + ")");
|
||||
|
||||
// Check that options are not altered
|
||||
test.is(Object.keys(options).length, Object.keys(optionsBackup).length,
|
||||
"The number of options was not changed");
|
||||
for (let k in options) {
|
||||
test.is(options[k], optionsBackup[k], "Option was not changed (" + suffix + ")");
|
||||
}
|
||||
yield reference_compare_files(pathSource, pathDest, test);
|
||||
|
||||
// Check that temporary file was removed or doesn't exist
|
||||
test.info("Compare complete");
|
||||
test.ok(!(new FileUtils.File(tmpPath).exists()), "No temporary file at the end of the run (" + suffix + ")");
|
||||
|
||||
// Check that writeAtomic fails if noOverwrite is true and the destination
|
||||
// file already exists!
|
||||
let view = new Uint8Array(contents.buffer, 10, 200);
|
||||
try {
|
||||
let opt = JSON.parse(JSON.stringify(options));
|
||||
opt.noOverwrite = true;
|
||||
yield OS.File.writeAtomic(pathDest, view, opt);
|
||||
test.fail("With noOverwrite, writeAtomic should have refused to overwrite file (" + suffix + ")");
|
||||
} catch (err) {
|
||||
test.info("With noOverwrite, writeAtomic correctly failed (" + suffix + ")");
|
||||
test.ok(err instanceof OS.File.Error, "writeAtomic correctly failed with a file error (" + suffix + ")");
|
||||
test.ok(err.becauseExists, "writeAtomic file error confirmed that the file already exists (" + suffix + ")");
|
||||
}
|
||||
yield reference_compare_files(pathSource, pathDest, test);
|
||||
test.ok(!(new FileUtils.File(tmpPath).exists()), "Temporary file was removed");
|
||||
|
||||
// Now write a subset
|
||||
let START = 10;
|
||||
let LENGTH = 100;
|
||||
view = new Uint8Array(contents.buffer, START, LENGTH);
|
||||
bytesWritten = yield OS.File.writeAtomic(pathDest, view, options);
|
||||
test.is(bytesWritten, LENGTH, "Partial write wrote the correct number of bytes (" + suffix + ")");
|
||||
let array2 = yield OS.File.read(pathDest);
|
||||
let view1 = new Uint8Array(contents.buffer, START, LENGTH);
|
||||
test.is(view1.length, array2.length, "Re-read partial write with the correct number of bytes (" + suffix + ")");
|
||||
let decoder = new TextDecoder();
|
||||
test.is(decoder.decode(view1), decoder.decode(array2), "Comparing re-read of partial write (" + suffix + ")");
|
||||
|
||||
// Write strings, default encoding
|
||||
let ARBITRARY_STRING = "aeiouyâêîôûçß•";
|
||||
yield OS.File.writeAtomic(pathDest, ARBITRARY_STRING, options);
|
||||
let array = yield OS.File.read(pathDest);
|
||||
let IN_STRING = decoder.decode(array);
|
||||
test.is(ARBITRARY_STRING, IN_STRING, "String write + read with default encoding works (" + suffix + ")");
|
||||
|
||||
let opt16 = JSON.parse(JSON.stringify(options));
|
||||
opt16.encoding = "utf-16";
|
||||
yield OS.File.writeAtomic(pathDest, ARBITRARY_STRING, opt16);
|
||||
array = yield OS.File.read(pathDest);
|
||||
IN_STRING = (new TextDecoder("utf-16")).decode(array);
|
||||
test.is(ARBITRARY_STRING, IN_STRING, "String write + read with utf-16 encoding works (" + suffix + ")");
|
||||
|
||||
// Cleanup.
|
||||
OS.File.remove(pathDest);
|
||||
});
|
||||
};
|
||||
|
||||
yield test_with_options({tmpPath: tmpPath}, "Renaming, not flushing");
|
||||
yield test_with_options({tmpPath: tmpPath, flush: true}, "Renaming, flushing");
|
||||
yield test_with_options({}, "Not renaming, not flushing");
|
||||
yield test_with_options({flush: true}, "Not renaming, flushing");
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Test file.{getPosition, setPosition}
|
||||
|
86
toolkit/components/osfile/tests/xpcshell/head.js
Normal file
86
toolkit/components/osfile/tests/xpcshell/head.js
Normal file
@ -0,0 +1,86 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
let {utils: Cu, interfaces: Ci} = Components;
|
||||
|
||||
let {OS} = Cu.import("resource://gre/modules/osfile.jsm", {});
|
||||
let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
let {Promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||
let {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
|
||||
let {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm", {});
|
||||
let {NetUtil} = Cu.import("resource://gre/modules/NetUtil.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(file,
|
||||
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);
|
||||
});
|
||||
};
|
@ -1,13 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/osfile.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js");
|
||||
|
||||
function run_test() {
|
||||
do_test_pending();
|
||||
run_next_test();
|
||||
|
@ -1,16 +1,18 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Test that functions throw the appropriate exceptions.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
let EXISTING_FILE = do_get_file("xpcshell.ini").path;
|
||||
|
||||
function run_test() {
|
||||
do_test_pending();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function test_typeerror() {
|
||||
// Tests on |open|
|
||||
|
||||
add_test_pair(function test_typeerror() {
|
||||
let exn;
|
||||
try {
|
||||
let fd = yield OS.File.open("/tmp", {no_such_key: 1});
|
||||
@ -22,6 +24,66 @@ add_task(function test_typeerror() {
|
||||
do_check_true(exn.constructor.name == "TypeError");
|
||||
});
|
||||
|
||||
add_task(function() {
|
||||
do_test_finished();
|
||||
// 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();
|
||||
}
|
||||
|
@ -6,7 +6,6 @@
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
|
||||
function run_test() {
|
||||
do_test_pending();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
@ -69,7 +68,3 @@ add_task(function test_error_attributes () {
|
||||
do_check_true(err.becauseNoSuchFile);
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function() {
|
||||
do_test_finished();
|
||||
});
|
||||
|
@ -4,10 +4,6 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/osfile.jsm", this);
|
||||
Cu.import("resource://gre/modules/Services.jsm", this);
|
||||
Cu.import("resource://gre/modules/ctypes.jsm", this);
|
||||
Cu.import("resource://testing-common/AppData.jsm", this);
|
||||
|
||||
|
100
toolkit/components/osfile/tests/xpcshell/test_read_write.js
Normal file
100
toolkit/components/osfile/tests/xpcshell/test_read_write.js
Normal file
@ -0,0 +1,100 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
let {utils: Cu} = Components;
|
||||
|
||||
let SHARED_PATH;
|
||||
|
||||
let 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 bytesWritten = yield OS.File.writeAtomic(DEST_PATH, contents, options);
|
||||
do_check_eq(contents.byteLength, 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!
|
||||
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;
|
||||
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);
|
||||
let view1 = new Uint8Array(contents.buffer, START, LENGTH);
|
||||
do_check_eq(view1.length, array2.length);
|
||||
let decoder = new TextDecoder();
|
||||
do_check_eq(decoder.decode(view1), decoder.decode(array2));
|
||||
|
||||
|
||||
// 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();
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
[DEFAULT]
|
||||
head =
|
||||
head = head.js
|
||||
tail =
|
||||
|
||||
[test_available_free_space.js]
|
||||
@ -25,6 +25,7 @@ tail =
|
||||
[test_open.js]
|
||||
[test_telemetry.js]
|
||||
[test_duration.js]
|
||||
[test_read_write.js]
|
||||
[test_compression.js]
|
||||
[test_osfile_writeAtomic_backupTo_option.js]
|
||||
[test_osfile_error.js]
|
||||
|
@ -40,6 +40,7 @@ function setup_osfile_crash_noerror() {
|
||||
|
||||
Services.prefs.setBoolPref("toolkit.osfile.debug.failshutdown", true);
|
||||
Services.prefs.setIntPref("toolkit.asyncshutdown.crash_timeout", 1);
|
||||
Services.prefs.setBoolPref("toolkit.osfile.native", false);
|
||||
|
||||
OS.File.getCurrentDirectory();
|
||||
Services.obs.notifyObservers(null, "profile-before-change", null);
|
||||
@ -68,6 +69,7 @@ function setup_osfile_crash_exn() {
|
||||
|
||||
Services.prefs.setBoolPref("toolkit.osfile.debug.failshutdown", true);
|
||||
Services.prefs.setIntPref("toolkit.asyncshutdown.crash_timeout", 1);
|
||||
Services.prefs.setBoolPref("toolkit.osfile.native", false);
|
||||
|
||||
OS.File.read("I do not exist");
|
||||
Services.obs.notifyObservers(null, "profile-before-change", null);
|
||||
@ -80,7 +82,6 @@ function after_osfile_crash_exn(mdump, extra) {
|
||||
let state = info.conditions[0].state;
|
||||
do_print("Keys: " + Object.keys(state).join(", "));
|
||||
do_check_eq(info.phase, "profile-before-change");
|
||||
do_check_true(state.launched);
|
||||
do_check_false(state.shutdown);
|
||||
do_check_true(state.worker);
|
||||
do_check_true(!!state.latestSent);
|
||||
|
Loading…
Reference in New Issue
Block a user