Bug 1075438 - Removed readTo function from two files and fixed read function to work without readTo.Also removed the test for readTo function from mochi and xpcshell tests. r=Yoric

This commit is contained in:
Gaurav Rai 2014-10-27 06:59:00 +01:00
parent 9bddd229c3
commit cd3b29d584
5 changed files with 20 additions and 324 deletions

View File

@ -618,39 +618,6 @@ File.prototype = {
); );
}, },
/**
* Read a number of bytes from the file and into a buffer.
*
* @param {Typed array | C pointer} buffer This buffer will be
* modified by another thread. Using this buffer before the |read|
* operation has completed is a BAD IDEA.
* @param {JSON} options
*
* @return {promise}
* @resolves {number} The number of bytes effectively read.
* @rejects {OS.File.Error}
*/
readTo: function readTo(buffer, options = {}) {
// If |buffer| is a typed array and there is no |bytes| options, we
// need to extract the |byteLength| now, as it will be lost by
// communication.
// Options might be a nullish value, so better check for that before using
// the |in| operator.
if (isTypedArray(buffer) && !(options && "bytes" in options)) {
// Preserve reference to option |outExecutionDuration|, if it is passed.
options = clone(options, ["outExecutionDuration"]);
options.bytes = buffer.byteLength;
}
// Note: Type.void_t.out_ptr.toMsg ensures that
// - the buffer is effectively shared (not neutered) between both
// threads;
// - we take care of any |byteOffset|.
return Scheduler.post("File_prototype_readTo",
[this._fdmsg,
Type.void_t.out_ptr.toMsg(buffer),
options],
buffer/*Ensure that |buffer| is not gc-ed*/);
},
/** /**
* Write bytes from a buffer to this file. * Write bytes from a buffer to this file.
* *

View File

@ -52,43 +52,22 @@ AbstractFile.prototype = {
/** /**
* Read bytes from this file to a new buffer. * Read bytes from this file to a new buffer.
* *
* @param {number=} bytes If unspecified, read all the remaining bytes from * @param {number=} maybeBytes (deprecated, please use options.bytes)
* this file. If specified, read |bytes| bytes, or less if the file does notclone
* contain that many bytes.
* @param {JSON} options * @param {JSON} options
* @return {Uint8Array} An array containing the bytes read. * @return {Uint8Array} An array containing the bytes read.
*/ */
read: function read(bytes, options = {}) { read: function read(maybeBytes, options = {}) {
options = clone(options); if (typeof maybeBytes === "object") {
options.bytes = bytes == null ? this.stat().size : bytes; // Caller has skipped `maybeBytes` and provided an options object.
let buffer = new Uint8Array(options.bytes); options = clone(maybeBytes);
let size = this.readTo(buffer, options); maybeBytes = null;
if (size == options.bytes) {
return buffer;
} else { } else {
return buffer.subarray(0, size); options = clone(options || {});
} }
}, if(!("bytes" in options)) {
options.bytes = maybeBytes == null ? this.stat().size : maybeBytes;
/** }
* Read bytes from this file to an existing buffer. let buffer = new Uint8Array(options.bytes);
*
* Note that, by default, this function may perform several I/O
* operations to ensure that the buffer is as full as possible.
*
* @param {Typed Array | C pointer} buffer The buffer in which to
* store the bytes. The buffer must be large enough to
* accomodate |bytes| bytes.
* @param {*=} options Optionally, an object that may contain the
* following fields:
* - {number} bytes The number of |bytes| to write from the buffer. If
* unspecified, this is |buffer.byteLength|. Note that |bytes| is required
* if |buffer| is a C pointer.
*
* @return {number} The number of bytes actually read, which may be
* less than |bytes| if the file did not contain that many bytes left.
*/
readTo: function readTo(buffer, options = {}) {
let {ptr, bytes} = SharedAll.normalizeToPointer(buffer, options.bytes); let {ptr, bytes} = SharedAll.normalizeToPointer(buffer, options.bytes);
let pos = 0; let pos = 0;
while (pos < bytes) { while (pos < bytes) {
@ -99,8 +78,11 @@ AbstractFile.prototype = {
pos += chunkSize; pos += chunkSize;
ptr = SharedAll.offsetBy(ptr, chunkSize); ptr = SharedAll.offsetBy(ptr, chunkSize);
} }
if (pos == options.bytes) {
return pos; return buffer;
} else {
return buffer.subarray(0, pos);
}
}, },
/** /**

View File

@ -152,7 +152,6 @@ let test = maketest("Main", function main(test) {
yield test_stat(); yield test_stat();
yield test_debug(); yield test_debug();
yield test_info_features_detect(); yield test_info_features_detect();
yield test_read_write();
yield test_position(); yield test_position();
yield test_iter(); yield test_iter();
yield test_exists(); yield test_exists();
@ -220,62 +219,6 @@ let test_info_features_detect = maketest("features_detect", function features_de
}); });
}); });
/**
* Test OS.File.prototype.{read, readTo, write}
*/
let test_read_write = maketest("read_write", function read_write(test) {
return Task.spawn(function() {
// Test readTo/write
let currentDir = yield OS.File.getCurrentDirectory();
let pathSource = OS.Path.join(currentDir, EXISTING_FILE);
let pathDest = OS.Path.join(OS.Constants.Path.tmpDir,
"osfile async test.tmp");
let fileSource = yield OS.File.open(pathSource);
test.info("Input file opened");
let fileDest = yield OS.File.open(pathDest,
{ truncate: true, read: true, write: true});
test.info("Output file opened");
let stat = yield fileSource.stat();
test.info("Input stat worked");
let size = stat.size;
let array = new Uint8Array(size);
try {
test.info("Now calling readTo");
let readLength = yield fileSource.readTo(array);
test.info("ReadTo worked");
test.is(readLength, size, "ReadTo got all bytes");
let writeLength = yield fileDest.write(array);
test.info("Write worked");
test.is(writeLength, size, "Write wrote all bytes");
// Test read
yield fileSource.setPosition(0);
let readAllResult = yield fileSource.read();
test.info("ReadAll worked");
test.is(readAllResult.length, size, "ReadAll read all bytes");
test.is(Array.prototype.join.call(readAllResult),
Array.prototype.join.call(array),
"ReadAll result is correct");
} finally {
// Close stuff
yield fileSource.close();
yield fileDest.close();
test.info("Files are closed");
}
stat = yield OS.File.stat(pathDest);
test.is(stat.size, size, "Both files have the same size");
yield reference_compare_files(pathSource, pathDest, test);
// Cleanup.
OS.File.remove(pathDest);
});
});
/** /**
* Test file.{getPosition, setPosition} * Test file.{getPosition, setPosition}
*/ */
@ -284,13 +227,8 @@ let test_position = maketest("position", function position(test) {
let file = yield OS.File.open(EXISTING_FILE); let file = yield OS.File.open(EXISTING_FILE);
try { try {
let stat = yield file.stat(); let view = yield file.read();
test.info("Obtained file length");
let view = new Uint8Array(stat.size);
yield file.readTo(view);
test.info("First batch of content read"); test.info("First batch of content read");
let CHUNK_SIZE = 178;// An arbitrary number of bytes to read from the file let CHUNK_SIZE = 178;// An arbitrary number of bytes to read from the file
let pos = yield file.getPosition(); let pos = yield file.getPosition();
test.info("Obtained position"); test.info("Obtained position");
@ -299,8 +237,7 @@ let test_position = maketest("position", function position(test) {
test.info("Changed position"); test.info("Changed position");
test.is(pos, view.byteLength - CHUNK_SIZE, "setPosition returned the correct position"); test.is(pos, view.byteLength - CHUNK_SIZE, "setPosition returned the correct position");
let view2 = new Uint8Array(CHUNK_SIZE); let view2 = yield file.read();
yield file.readTo(view2);
test.info("Read the end of the file"); test.info("Read the end of the file");
for (let i = 0; i < CHUNK_SIZE; ++i) { for (let i = 0; i < CHUNK_SIZE; ++i) {
if (view2[i] != view[i + view.byteLength - CHUNK_SIZE]) { if (view2[i] != view[i + view.byteLength - CHUNK_SIZE]) {

View File

@ -27,7 +27,6 @@ self.onmessage = function onmessage_start(msg) {
test_open_non_existing_file(); test_open_non_existing_file();
test_flush_open_file(); test_flush_open_file();
test_copy_existing_file(); test_copy_existing_file();
test_readall_writeall_file();
test_position(); test_position();
test_move_file(); test_move_file();
test_iter_dir(); test_iter_dir();
@ -184,190 +183,6 @@ function compare_files(test, sourcePath, destPath, prefix)
info(test + ": Comparison complete"); info(test + ": Comparison complete");
} }
function test_readall_writeall_file()
{
let src_file_name =
OS.Path.join("chrome", "toolkit", "components", "osfile", "tests", "mochi",
"worker_test_osfile_front.js");
let tmp_file_name =
OS.Path.join(OS.Constants.Path.tmpDir, "test_osfile_front.tmp");
info("Starting test_readall_writeall_file");
// read, ArrayBuffer
let source = OS.File.open(src_file_name);
let dest = OS.File.open(tmp_file_name, {write: true, trunc:true});
let size = source.stat().size;
let buf = new Uint8Array(size);
let readResult = source.readTo(buf);
is(readResult, size, "test_readall_writeall_file: read the right number of bytes");
dest.write(buf);
info("test_readall_writeall_file: copy complete (manual allocation)");
source.close();
dest.close();
compare_files("test_readall_writeall_file (manual allocation)", src_file_name, tmp_file_name);
OS.File.remove(tmp_file_name);
// read, C buffer
source = OS.File.open(src_file_name);
dest = OS.File.open(tmp_file_name, {write: true, trunc:true});
buf = new ArrayBuffer(size);
let ptr = OS.Shared.Type.voidptr_t.implementation(buf);
readResult = source.readTo(ptr, {bytes: size});
is(readResult, size, "test_readall_writeall_file: read the right number of bytes (C buffer)");
dest.write(ptr, {bytes: size});
info("test_readall_writeall_file: copy complete (C buffer)");
source.close();
dest.close();
compare_files("test_readall_writeall_file (C buffer)", src_file_name, tmp_file_name);
OS.File.remove(tmp_file_name);
// read/write, C buffer, missing |bytes| option
source = OS.File.open(src_file_name);
dest = OS.File.open(tmp_file_name, {write: true, trunc:true});
let exn = should_throw(function() { source.readTo(ptr); });
ok(exn != null && exn instanceof TypeError, "test_readall_writeall_file: read with C pointer and without bytes fails with the correct error");
exn = should_throw(function() { dest.write(ptr); });
ok(exn != null && exn instanceof TypeError, "test_readall_writeall_file: write with C pointer and without bytes fails with the correct error");
source.close();
dest.close();
// readTo, ArrayBuffer + offset
let OFFSET = 12;
let LEFT = size - OFFSET;
buf = new ArrayBuffer(size);
let offset_view = new Uint8Array(buf, OFFSET);
source = OS.File.open(src_file_name);
dest = OS.File.open(tmp_file_name, {write: true, trunc:true});
readResult = source.readTo(offset_view);
is(readResult, LEFT, "test_readall_writeall_file: read the right number of bytes (with offset)");
dest.write(offset_view);
is(dest.stat().size, LEFT, "test_readall_writeall_file: wrote the right number of bytes (with offset)");
info("test_readall_writeall_file: copy complete (with offset)");
source.close();
dest.close();
compare_files("test_readall_writeall_file (with offset)", src_file_name, tmp_file_name, LEFT);
OS.File.remove(tmp_file_name);
// read
buf = new Uint8Array(size);
source = OS.File.open(src_file_name);
dest = OS.File.open(tmp_file_name, {write: true, trunc:true});
readResult = source.read();
is(readResult.length, size, "test_readall_writeall_file: read the right number of bytes (auto allocation)");
dest.write(readResult);
info("test_readall_writeall_file: copy complete (auto allocation)");
source.close();
dest.close();
compare_files("test_readall_writeall_file (auto allocation)", src_file_name, tmp_file_name);
OS.File.remove(tmp_file_name);
// File.readAll
readResult = OS.File.read(src_file_name);
is(readResult.length, size, "test_readall_writeall_file: read the right number of bytes (OS.File.readAll)");
// File.writeAtomic on top of nothing
OS.File.writeAtomic(tmp_file_name, readResult,
{tmpPath: tmp_file_name + ".tmp"});
try {
let stat = OS.File.stat(tmp_file_name);
info("readAll + writeAtomic created a file");
is(stat.size, size, "readAll + writeAtomic created a file of the right size");
} catch (x) {
ok(false, "readAll + writeAtomic somehow failed");
if(x.becauseNoSuchFile) {
ok(false, "readAll + writeAtomic did not create file");
}
}
compare_files("test_readall_writeall_file (OS.File.readAll + writeAtomic)",
src_file_name, tmp_file_name);
exn = null;
try {
let stat = OS.File.stat(tmp_file_name + ".tmp");
} catch (x) {
exn = x;
}
ok(!!exn, "readAll + writeAtomic cleaned up after itself");
// File.writeAtomic on top of existing file
// Remove content and set arbitrary size, to avoid potential false negatives
dest = OS.File.open(tmp_file_name, {write: true, trunc:true});
dest.setPosition(1234);
dest.close();
OS.File.writeAtomic(tmp_file_name, readResult,
{tmpPath: tmp_file_name + ".tmp"});
compare_files("test_readall_writeall_file (OS.File.readAll + writeAtomic 2)",
src_file_name, tmp_file_name);
// File.writeAtomic on top of existing file but without overwritten the file
exn = null;
try {
let view = new Uint8Array(readResult.buffer, 10, 200);
OS.File.writeAtomic(tmp_file_name, view,
{ tmpPath: tmp_file_name + ".tmp", noOverwrite: true});
} catch (x) {
exn = x;
}
ok(exn && exn instanceof OS.File.Error && exn.becauseExists, "writeAtomic fails if file already exists with noOverwrite option");
// Check file was not overwritten.
compare_files("test_readall_writeall_file (OS.File.readAll + writeAtomic check file was not overwritten)",
src_file_name, tmp_file_name);
// Ensure that File.writeAtomic fails if no temporary file name is provided
// (FIXME: Remove this test as part of bug 793660)
exn = null;
try {
OS.File.writeAtomic(tmp_file_name, readResult.buffer,
{bytes: readResult.length});
} catch (x) {
exn = x;
}
ok(!!exn && exn instanceof TypeError, "writeAtomic fails if tmpPath is not provided");
// Check that writeAtomic fails when destination path is undefined
exn = null;
try {
let path = undefined;
let options = {tmpPath: tmp_file_name};
OS.File.writeAtomic(path, readResult.buffer, options);
} catch (x) {
exn = x;
}
ok(!!exn && exn instanceof TypeError, "writeAtomic fails if path is undefined");
// Check that writeAtomic fails when destination path is an empty string
exn = null;
try {
let path = "";
let options = {tmpPath: tmp_file_name};
OS.File.writeAtomic(path, readResult.buffer, options);
} catch (x) {
exn = x;
}
ok(!!exn && exn instanceof TypeError, "writeAtomic fails if path is an empty string");
// Cleanup.
OS.File.remove(tmp_file_name);
}
/** /**
* Test that copying a file using |copy| works. * Test that copying a file using |copy| works.
*/ */

View File

@ -9,7 +9,7 @@ function run_test() {
} }
/** /**
* Test to ensure that {bytes:} in options to |readTo| and |write| are correctly * Test to ensure that {bytes:} in options to |write| is correctly
* preserved. * preserved.
*/ */
add_task(function* test_bytes() { add_task(function* test_bytes() {
@ -23,12 +23,7 @@ add_task(function* test_bytes() {
yield file.write(new Uint8Array(2048), {bytes: 1024}); yield file.write(new Uint8Array(2048), {bytes: 1024});
do_check_eq((yield file.stat()).size, 1024); do_check_eq((yield file.stat()).size, 1024);
// 2. Test same for |readTo|. // 2. Test that passing nullish values for |options| still works.
yield file.setPosition(0, OS.File.POS_START);
let read = yield file.readTo(new Uint8Array(1024), {bytes: 512});
do_check_eq(read, 512);
// 3. Test that passing nullish values for |options| still works.
yield file.setPosition(0, OS.File.POS_END); yield file.setPosition(0, OS.File.POS_END);
yield file.write(new Uint8Array(1024), null); yield file.write(new Uint8Array(1024), null);
yield file.write(new Uint8Array(1024), undefined); yield file.write(new Uint8Array(1024), undefined);