summaryrefslogtreecommitdiffstats
path: root/netwerk/test/unit/test_file_partial_inputstream.js
diff options
context:
space:
mode:
Diffstat (limited to 'netwerk/test/unit/test_file_partial_inputstream.js')
-rw-r--r--netwerk/test/unit/test_file_partial_inputstream.js512
1 files changed, 512 insertions, 0 deletions
diff --git a/netwerk/test/unit/test_file_partial_inputstream.js b/netwerk/test/unit/test_file_partial_inputstream.js
new file mode 100644
index 000000000..6eb4a3ac8
--- /dev/null
+++ b/netwerk/test/unit/test_file_partial_inputstream.js
@@ -0,0 +1,512 @@
+/* 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/. */
+
+// Test nsIPartialFileInputStream
+// NOTE! These tests often use do_check_true(a == b) rather than
+// do_check_eq(a, b) to avoid outputting characters which confuse
+// the console
+
+var CC = Components.Constructor;
+const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
+ "nsIBinaryInputStream",
+ "setInputStream");
+const PR_RDONLY = 0x1; // see prio.h
+
+// We need the profile directory so the test harness will clean up our test
+// files.
+do_get_profile();
+
+var binary_test_file_name = "data/image.png";
+var text_test_file_name = "test_file_partial_inputstream.js";
+// This is a global variable since if it's passed as an argument stack traces
+// become unreadable.
+var test_file_data;
+
+function run_test()
+{
+ // Binary tests
+ let binaryFile = do_get_file(binary_test_file_name);
+ let size = binaryFile.fileSize;
+ // Want to make sure we're working with a large enough file
+ dump("**** binary file size is: " + size + " ****\n");
+ do_check_true(size > 65536);
+
+ let binaryStream = new BinaryInputStream(new_file_input_stream(binaryFile));
+ test_file_data = "";
+ while ((avail = binaryStream.available()) > 0) {
+ test_file_data += binaryStream.readBytes(avail);
+ }
+ do_check_eq(test_file_data.length, size);
+ binaryStream.close();
+
+ test_binary_portion(0, 10);
+ test_binary_portion(0, 20000);
+ test_binary_portion(0, size);
+ test_binary_portion(20000, 10);
+ test_binary_portion(20000, 20000);
+ test_binary_portion(20000, size-20000);
+ test_binary_portion(size-10, 10);
+ test_binary_portion(size-20000, 20000);
+ test_binary_portion(0, 0);
+ test_binary_portion(20000, 0);
+ test_binary_portion(size-1, 1);
+
+
+ // Text-file tests
+ let textFile = do_get_file(binary_test_file_name);
+ size = textFile.fileSize;
+ // Want to make sure we're working with a large enough file
+ dump("**** text file size is: " + size + " ****\n");
+ do_check_true(size > 7000);
+
+ let textStream = new BinaryInputStream(new_file_input_stream(textFile));
+ test_file_data = "";
+ while ((avail = textStream.available()) > 0)
+ test_file_data += textStream.readBytes(avail);
+ do_check_eq(test_file_data.length, size);
+ textStream.close();
+
+ test_text_portion(0, 100);
+ test_text_portion(0, size);
+ test_text_portion(5000, 1000);
+ test_text_portion(size-10, 10);
+ test_text_portion(size-5000, 5000);
+ test_text_portion(10, 0);
+ test_text_portion(size-1, 1);
+
+ // Test auto-closing files
+ // Test behavior when *not* autoclosing
+ let tempFile = create_temp_file("01234567890123456789");
+ let tempInputStream = new_partial_file_input_stream(tempFile, 5, 10);
+ tempInputStream.QueryInterface(Ci.nsILineInputStream);
+ do_check_eq(read_line_stream(tempInputStream)[1], "5678901234");
+ try {
+ // This fails on some platforms
+ tempFile.remove(false);
+ }
+ catch (ex) {
+ }
+ tempInputStream.QueryInterface(Ci.nsISeekableStream);
+ tempInputStream.seek(SET, 1);
+ do_check_eq(read_line_stream(tempInputStream)[1], "678901234");
+
+ // Test removing the file when autoclosing
+ tempFile = create_temp_file("01234567890123456789");
+ tempInputStream = new_partial_file_input_stream(tempFile, 5, 10,
+ Ci.nsIFileInputStream.CLOSE_ON_EOF |
+ Ci.nsIFileInputStream.REOPEN_ON_REWIND);
+ tempInputStream.QueryInterface(Ci.nsILineInputStream);
+ do_check_eq(read_line_stream(tempInputStream)[1], "5678901234");
+ tempFile.remove(false);
+ tempInputStream.QueryInterface(Ci.nsISeekableStream);
+ try {
+ // The seek should reopen the file, which should fail.
+ tempInputStream.seek(SET, 1);
+ do_check_true(false);
+ }
+ catch (ex) {
+ }
+
+ // Test editing the file when autoclosing
+ tempFile = create_temp_file("01234567890123456789");
+ tempInputStream = new_partial_file_input_stream(tempFile, 5, 10,
+ Ci.nsIFileInputStream.CLOSE_ON_EOF |
+ Ci.nsIFileInputStream.REOPEN_ON_REWIND);
+ tempInputStream.QueryInterface(Ci.nsILineInputStream);
+ do_check_eq(read_line_stream(tempInputStream)[1], "5678901234");
+ let ostream = Cc["@mozilla.org/network/file-output-stream;1"].
+ createInstance(Ci.nsIFileOutputStream);
+ ostream.init(tempFile, 0x02 | 0x08 | 0x20, // write, create, truncate
+ 0o666, 0);
+ let newData = "abcdefghijklmnopqrstuvwxyz";
+ ostream.write(newData, newData.length);
+ ostream.close();
+ tempInputStream.QueryInterface(Ci.nsISeekableStream);
+ tempInputStream.seek(SET, 1);
+ do_check_eq(read_line_stream(tempInputStream)[1], newData.substr(6,9));
+
+ // Test auto-delete and auto-close together
+ tempFile = create_temp_file("01234567890123456789");
+ tempInputStream = new_partial_file_input_stream(tempFile, 5, 10,
+ Ci.nsIFileInputStream.CLOSE_ON_EOF |
+ Ci.nsIFileInputStream.DELETE_ON_CLOSE);
+ tempInputStream.QueryInterface(Ci.nsILineInputStream);
+ do_check_eq(read_line_stream(tempInputStream)[1], "5678901234");
+ do_check_false(tempFile.exists());
+}
+
+function test_binary_portion(start, length) {
+ let subFile = create_temp_file(test_file_data.substr(start, length));
+
+ let streamTests = [
+ test_4k_read,
+ test_max_read,
+ test_seek,
+ test_seek_then_read,
+ ];
+
+ for (var test of streamTests) {
+ let fileStream = new_file_input_stream(subFile);
+ let partialStream = new_partial_file_input_stream(do_get_file(binary_test_file_name),
+ start, length);
+ test(fileStream, partialStream, length);
+ fileStream.close();
+ partialStream.close();
+ }
+}
+
+function test_4k_read(fileStreamA, fileStreamB) {
+ fileStreamA.QueryInterface(Ci.nsISeekableStream);
+ fileStreamB.QueryInterface(Ci.nsISeekableStream);
+ let streamA = new BinaryInputStream(fileStreamA);
+ let streamB = new BinaryInputStream(fileStreamB);
+
+ while(1) {
+ do_check_eq(fileStreamA.tell(), fileStreamB.tell());
+
+ let availA = streamA.available();
+ let availB = streamB.available();
+ do_check_eq(availA, availB);
+ if (availA == 0)
+ return;
+
+ let readSize = availA > 4096 ? 4096 : availA;
+
+ do_check_true(streamA.readBytes(readSize) ==
+ streamB.readBytes(readSize));
+ }
+}
+
+function test_max_read(fileStreamA, fileStreamB) {
+ fileStreamA.QueryInterface(Ci.nsISeekableStream);
+ fileStreamB.QueryInterface(Ci.nsISeekableStream);
+ let streamA = new BinaryInputStream(fileStreamA);
+ let streamB = new BinaryInputStream(fileStreamB);
+
+ while(1) {
+ do_check_eq(fileStreamA.tell(), fileStreamB.tell());
+
+ let availA = streamA.available();
+ let availB = streamB.available();
+ do_check_eq(availA, availB);
+ if (availA == 0)
+ return;
+
+ do_check_true(streamA.readBytes(availA) ==
+ streamB.readBytes(availB));
+ }
+}
+
+const SET = Ci.nsISeekableStream.NS_SEEK_SET;
+const CUR = Ci.nsISeekableStream.NS_SEEK_CUR;
+const END = Ci.nsISeekableStream.NS_SEEK_END;
+function test_seek(dummy, partialFileStream, size) {
+ // We can't test the "real" filestream here as our existing file streams
+ // are very broken and allows searching past the end of the file.
+
+ partialFileStream.QueryInterface(Ci.nsISeekableStream);
+
+ var tests = [
+ [SET, 0],
+ [SET, 5],
+ [SET, 1000],
+ [SET, size-10],
+ [SET, size-5],
+ [SET, size-1],
+ [SET, size],
+ [SET, size+10],
+ [SET, 0],
+ [CUR, 5],
+ [CUR, -5],
+ [SET, 5000],
+ [CUR, -100],
+ [CUR, 200],
+ [CUR, -5000],
+ [CUR, 5000],
+ [CUR, size * 2],
+ [SET, 1],
+ [CUR, -1],
+ [CUR, -1],
+ [CUR, -1],
+ [CUR, -1],
+ [CUR, -1],
+ [SET, size-1],
+ [CUR, 1],
+ [CUR, 1],
+ [CUR, 1],
+ [CUR, 1],
+ [CUR, 1],
+ [END, 0],
+ [END, -1],
+ [END, -5],
+ [END, -1000],
+ [END, -size+10],
+ [END, -size+5],
+ [END, -size+1],
+ [END, -size],
+ [END, -size-10],
+ [END, 10],
+ [CUR, 10],
+ [CUR, 10],
+ [CUR, 100],
+ [CUR, 1000],
+ [END, -1000],
+ [CUR, 100],
+ [CUR, 900],
+ [CUR, 100],
+ [CUR, 100],
+ ];
+
+ let pos = 0;
+ for (var test of tests) {
+ let didThrow = false;
+ try {
+ partialFileStream.seek(test[0], test[1]);
+ }
+ catch (ex) {
+ didThrow = true;
+ }
+
+ let newPos = test[0] == SET ? test[1] :
+ test[0] == CUR ? pos + test[1] :
+ size + test[1];
+ if (newPos > size || newPos < 0) {
+ do_check_true(didThrow);
+ }
+ else {
+ do_check_false(didThrow);
+ pos = newPos;
+ }
+
+ do_check_eq(partialFileStream.tell(), pos);
+ do_check_eq(partialFileStream.available(), size - pos);
+ }
+}
+
+function test_seek_then_read(fileStreamA, fileStreamB, size) {
+ // For now we only test seeking inside the file since our existing file
+ // streams behave very strange when seeking to past the end of the file.
+ if (size < 20000) {
+ return;
+ }
+
+ fileStreamA.QueryInterface(Ci.nsISeekableStream);
+ fileStreamB.QueryInterface(Ci.nsISeekableStream);
+ let streamA = new BinaryInputStream(fileStreamA);
+ let streamB = new BinaryInputStream(fileStreamB);
+
+ let read = {};
+
+ var tests = [
+ [SET, 0],
+ [read, 1000],
+ [read, 1000],
+ [SET, 5],
+ [read, 1000],
+ [read, 5000],
+ [CUR, 100],
+ [read, 1000],
+ [read, 5000],
+ [CUR, -100],
+ [read, 1000],
+ [CUR, -100],
+ [read, 5000],
+ [END, -10],
+ [read, 10],
+ [END, -100],
+ [read, 101],
+ [CUR, -100],
+ [read, 10],
+ [SET, 0],
+ [read, 20000],
+ [read, 1],
+ [read, 100],
+ ];
+
+ for (var test of tests) {
+ if (test[0] === read) {
+
+ let didThrowA = false;
+ let didThrowB = false;
+
+ let bytesA, bytesB;
+ try {
+ bytesA = streamA.readBytes(test[1]);
+ }
+ catch (ex) {
+ didThrowA = true;
+ }
+ try {
+ bytesB = streamB.readBytes(test[1]);
+ }
+ catch (ex) {
+ didThrowB = true;
+ }
+
+ do_check_eq(didThrowA, didThrowB);
+ do_check_true(bytesA == bytesB);
+ }
+ else {
+ fileStreamA.seek(test[0], test[1]);
+ fileStreamB.seek(test[0], test[1]);
+ }
+ do_check_eq(fileStreamA.tell(), fileStreamB.tell());
+ do_check_eq(fileStreamA.available(), fileStreamB.available());
+ }
+}
+
+function test_text_portion(start, length) {
+ let subFile = create_temp_file(test_file_data.substr(start, length));
+
+ let streamTests = [
+ test_readline,
+ test_seek_then_readline,
+ ];
+
+ for (var test of streamTests) {
+ let fileStream = new_file_input_stream(subFile)
+ .QueryInterface(Ci.nsILineInputStream);
+ let partialStream = new_partial_file_input_stream(do_get_file(binary_test_file_name),
+ start, length)
+ .QueryInterface(Ci.nsILineInputStream);
+ test(fileStream, partialStream, length);
+ fileStream.close();
+ partialStream.close();
+ }
+}
+
+function test_readline(fileStreamA, fileStreamB)
+{
+ let moreA = true, moreB;
+ while(moreA) {
+ let lineA, lineB;
+ [moreA, lineA] = read_line_stream(fileStreamA);
+ [moreB, lineB] = read_line_stream(fileStreamB);
+ do_check_eq(moreA, moreB);
+ do_check_true(lineA.value == lineB.value);
+ }
+}
+
+function test_seek_then_readline(fileStreamA, fileStreamB, size) {
+ // For now we only test seeking inside the file since our existing file
+ // streams behave very strange when seeking to past the end of the file.
+ if (size < 100) {
+ return;
+ }
+
+ fileStreamA.QueryInterface(Ci.nsISeekableStream);
+ fileStreamB.QueryInterface(Ci.nsISeekableStream);
+
+ let read = {};
+
+ var tests = [
+ [SET, 0],
+ [read, 5],
+ [read, 5],
+ [SET, 5],
+ [read, 5],
+ [read, 15],
+ [CUR, 100],
+ [read, 5],
+ [read, 15],
+ [CUR, -100],
+ [read, 5],
+ [CUR, -100],
+ [read, 25],
+ [END, -10],
+ [read, 1],
+ [END, -50],
+ [read, 30],
+ [read, 1],
+ [read, 1],
+ [CUR, -100],
+ [read, 1],
+ [SET, 0],
+ [read, 10000],
+ [read, 1],
+ [read, 1],
+ [SET, 0],
+ [read, 1],
+ ];
+
+ for (var test of tests) {
+ if (test[0] === read) {
+
+ for (let i = 0; i < test[1]; ++i) {
+ let didThrowA = false;
+ let didThrowB = false;
+
+ let lineA, lineB, moreA, moreB;
+ try {
+ [moreA, lineA] = read_line_stream(fileStreamA);
+ }
+ catch (ex) {
+ didThrowA = true;
+ }
+ try {
+ [moreB, lineB] = read_line_stream(fileStreamB);
+ }
+ catch (ex) {
+ didThrowB = true;
+ }
+
+ do_check_eq(didThrowA, didThrowB);
+ do_check_eq(moreA, moreB);
+ do_check_true(lineA == lineB);
+ do_check_eq(fileStreamA.tell(), fileStreamB.tell());
+ do_check_eq(fileStreamA.available(), fileStreamB.available());
+ if (!moreA)
+ break;
+ }
+ }
+ else {
+ if (!(test[0] == CUR && (test[1] > fileStreamA.available() ||
+ test[1] < -fileStreamA.tell()))) {
+ fileStreamA.seek(test[0], test[1]);
+ fileStreamB.seek(test[0], test[1]);
+ do_check_eq(fileStreamA.tell(), fileStreamB.tell());
+ do_check_eq(fileStreamA.available(), fileStreamB.available());
+ }
+ }
+ }
+}
+
+function read_line_stream(stream) {
+ let line = {};
+ let more = stream.readLine(line);
+ return [more, line.value];
+}
+
+function new_file_input_stream(file) {
+ var stream =
+ Cc["@mozilla.org/network/file-input-stream;1"]
+ .createInstance(Ci.nsIFileInputStream);
+ stream.init(file, PR_RDONLY, 0, 0);
+ return stream.QueryInterface(Ci.nsIInputStream);
+}
+
+function new_partial_file_input_stream(file, start, length, flags) {
+ var stream =
+ Cc["@mozilla.org/network/partial-file-input-stream;1"]
+ .createInstance(Ci.nsIPartialFileInputStream);
+ stream.init(file, start, length, PR_RDONLY, 0, flags || 0);
+ return stream.QueryInterface(Ci.nsIInputStream);
+}
+
+function create_temp_file(data) {
+ let file = Cc["@mozilla.org/file/directory_service;1"].
+ getService(Ci.nsIProperties).
+ get("ProfD", Ci.nsIFile);
+ file.append("fileinputstream-test-file.tmp");
+ file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
+
+ let ostream = Cc["@mozilla.org/network/file-output-stream;1"].
+ createInstance(Ci.nsIFileOutputStream);
+ ostream.init(file, 0x02 | 0x08 | 0x20, // write, create, truncate
+ 0o666, 0);
+ do_check_eq(ostream.write(data, data.length), data.length);
+ ostream.close();
+
+ return file;
+}