diff options
Diffstat (limited to '')
-rw-r--r-- | netwerk/test/unit/test_filestreams.js | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/netwerk/test/unit/test_filestreams.js b/netwerk/test/unit/test_filestreams.js new file mode 100644 index 0000000000..b1edf3d27b --- /dev/null +++ b/netwerk/test/unit/test_filestreams.js @@ -0,0 +1,300 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// We need the profile directory so the test harness will clean up our test +// files. +do_get_profile(); + +const OUTPUT_STREAM_CONTRACT_ID = "@mozilla.org/network/file-output-stream;1"; +const SAFE_OUTPUT_STREAM_CONTRACT_ID = + "@mozilla.org/network/safe-file-output-stream;1"; + +//////////////////////////////////////////////////////////////////////////////// +//// Helper Methods + +/** + * Generates a leafName for a file that does not exist, but does *not* + * create the file. Similar to createUnique except for the fact that createUnique + * does create the file. + * + * @param aFile + * The file to modify in order for it to have a unique leafname. + */ +function ensure_unique(aFile) { + ensure_unique.fileIndex = ensure_unique.fileIndex || 0; + + var leafName = aFile.leafName; + while (aFile.clone().exists()) { + aFile.leafName = leafName + "_" + ensure_unique.fileIndex++; + } +} + +/** + * Tests for files being accessed at the right time. Streams that use + * DEFER_OPEN should only open or create the file when an operation is + * done, and not during Init(). + * + * Note that for writing, we check for actual writing in test_NetUtil (async) + * and in sync_operations in this file (sync), whereas in this function we + * just check that the file is *not* created during init. + * + * @param aContractId + * The contract ID to use for the output stream + * @param aDeferOpen + * Whether to check with DEFER_OPEN or not + * @param aTrickDeferredOpen + * Whether we try to 'trick' deferred opens by changing the file object before + * the actual open. The stream should have a clone, so changes to the file + * object after Init and before Open should not affect it. + */ +function check_access(aContractId, aDeferOpen, aTrickDeferredOpen) { + const LEAF_NAME = "filestreams-test-file.tmp"; + const TRICKY_LEAF_NAME = "BetYouDidNotExpectThat.tmp"; + let file = Services.dirsvc.get("ProfD", Ci.nsIFile); + file.append(LEAF_NAME); + + // Writing + + ensure_unique(file); + let ostream = Cc[aContractId].createInstance(Ci.nsIFileOutputStream); + ostream.init( + file, + -1, + -1, + aDeferOpen ? Ci.nsIFileOutputStream.DEFER_OPEN : 0 + ); + Assert.equal(aDeferOpen, !file.clone().exists()); // If defer, should not exist and vice versa + if (aDeferOpen) { + // File should appear when we do write to it. + if (aTrickDeferredOpen) { + // See |@param aDeferOpen| in the JavaDoc comment for this function + file.leafName = TRICKY_LEAF_NAME; + } + ostream.write("data", 4); + if (aTrickDeferredOpen) { + file.leafName = LEAF_NAME; + } + // We did a write, so the file should now exist + Assert.ok(file.clone().exists()); + } + ostream.close(); + + // Reading + + ensure_unique(file); + let istream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance( + Ci.nsIFileInputStream + ); + var initOk, getOk; + try { + istream.init( + file, + -1, + 0, + aDeferOpen ? Ci.nsIFileInputStream.DEFER_OPEN : 0 + ); + initOk = true; + } catch (e) { + initOk = false; + } + try { + let fstream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance( + Ci.nsIFileInputStream + ); + fstream.init(file, -1, 0, 0); + getOk = true; + } catch (e) { + getOk = false; + } + + // If the open is deferred, then Init should succeed even though the file we + // intend to read does not exist, and then trying to read from it should + // fail. The other case is where the open is not deferred, and there we should + // get an error when we Init (and also when we try to read). + Assert.ok( + (aDeferOpen && initOk && !getOk) || (!aDeferOpen && !initOk && !getOk) + ); + istream.close(); +} + +/** + * We test async operations in test_NetUtil.js, and here test for simple sync + * operations on input streams. + * + * @param aDeferOpen + * Whether to use DEFER_OPEN in the streams. + */ +function sync_operations(aDeferOpen) { + const TEST_DATA = "this is a test string"; + const LEAF_NAME = "filestreams-test-file.tmp"; + + let file = Services.dirsvc.get("ProfD", Ci.nsIFile); + file.append(LEAF_NAME); + file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666); + + let ostream = Cc[OUTPUT_STREAM_CONTRACT_ID].createInstance( + Ci.nsIFileOutputStream + ); + ostream.init( + file, + -1, + -1, + aDeferOpen ? Ci.nsIFileOutputStream.DEFER_OPEN : 0 + ); + + ostream.write(TEST_DATA, TEST_DATA.length); + ostream.close(); + + let fstream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance( + Ci.nsIFileInputStream + ); + fstream.init(file, -1, 0, aDeferOpen ? Ci.nsIFileInputStream.DEFER_OPEN : 0); + + let cstream = Cc["@mozilla.org/intl/converter-input-stream;1"].createInstance( + Ci.nsIConverterInputStream + ); + cstream.init(fstream, "UTF-8", 0, 0); + + let string = {}; + cstream.readString(-1, string); + cstream.close(); + fstream.close(); + + Assert.equal(string.value, TEST_DATA); +} + +//////////////////////////////////////////////////////////////////////////////// +//// Tests + +function test_access() { + check_access(OUTPUT_STREAM_CONTRACT_ID, false, false); +} + +function test_access_trick() { + check_access(OUTPUT_STREAM_CONTRACT_ID, false, true); +} + +function test_access_defer() { + check_access(OUTPUT_STREAM_CONTRACT_ID, true, false); +} + +function test_access_defer_trick() { + check_access(OUTPUT_STREAM_CONTRACT_ID, true, true); +} + +function test_access_safe() { + check_access(SAFE_OUTPUT_STREAM_CONTRACT_ID, false, false); +} + +function test_access_safe_trick() { + check_access(SAFE_OUTPUT_STREAM_CONTRACT_ID, false, true); +} + +function test_access_safe_defer() { + check_access(SAFE_OUTPUT_STREAM_CONTRACT_ID, true, false); +} + +function test_access_safe_defer_trick() { + check_access(SAFE_OUTPUT_STREAM_CONTRACT_ID, true, true); +} + +function test_sync_operations() { + sync_operations(); +} + +function test_sync_operations_deferred() { + sync_operations(true); +} + +function do_test_zero_size_buffered(disableBuffering) { + const LEAF_NAME = "filestreams-test-file.tmp"; + const BUFFERSIZE = 4096; + + let file = Services.dirsvc.get("ProfD", Ci.nsIFile); + file.append(LEAF_NAME); + file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666); + + let fstream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance( + Ci.nsIFileInputStream + ); + fstream.init( + file, + -1, + 0, + Ci.nsIFileInputStream.CLOSE_ON_EOF | Ci.nsIFileInputStream.REOPEN_ON_REWIND + ); + + var buffered = Cc[ + "@mozilla.org/network/buffered-input-stream;1" + ].createInstance(Ci.nsIBufferedInputStream); + buffered.init(fstream, BUFFERSIZE); + + if (disableBuffering) { + buffered.QueryInterface(Ci.nsIStreamBufferAccess).disableBuffering(); + } + + // Scriptable input streams clamp read sizes to the return value of + // available(), so don't quite do what we want here. + let cstream = Cc["@mozilla.org/intl/converter-input-stream;1"].createInstance( + Ci.nsIConverterInputStream + ); + cstream.init(buffered, "UTF-8", 0, 0); + + Assert.equal(buffered.available(), 0); + + // Now try reading from this stream + let string = {}; + Assert.equal(cstream.readString(BUFFERSIZE, string), 0); + Assert.equal(string.value, ""); + + // Now check that available() throws + var exceptionThrown = false; + try { + Assert.equal(buffered.available(), 0); + } catch (e) { + exceptionThrown = true; + } + Assert.ok(exceptionThrown); + + // OK, now seek back to start + buffered.seek(Ci.nsISeekableStream.NS_SEEK_SET, 0); + + // Now check that available() does not throw + exceptionThrown = false; + try { + Assert.equal(buffered.available(), 0); + } catch (e) { + exceptionThrown = true; + } + Assert.ok(!exceptionThrown); +} + +function test_zero_size_buffered() { + do_test_zero_size_buffered(false); + do_test_zero_size_buffered(true); +} + +//////////////////////////////////////////////////////////////////////////////// +//// Test Runner + +var tests = [ + test_access, + test_access_trick, + test_access_defer, + test_access_defer_trick, + test_access_safe, + test_access_safe_trick, + test_access_safe_defer, + test_access_safe_defer_trick, + test_sync_operations, + test_sync_operations_deferred, + test_zero_size_buffered, +]; + +function run_test() { + tests.forEach(function (test) { + test(); + }); +} |