test_filestreams.js (8311B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 // We need the profile directory so the test harness will clean up our test 7 // files. 8 do_get_profile(); 9 10 const OUTPUT_STREAM_CONTRACT_ID = "@mozilla.org/network/file-output-stream;1"; 11 const SAFE_OUTPUT_STREAM_CONTRACT_ID = 12 "@mozilla.org/network/safe-file-output-stream;1"; 13 14 //////////////////////////////////////////////////////////////////////////////// 15 //// Helper Methods 16 17 /** 18 * Generates a leafName for a file that does not exist, but does *not* 19 * create the file. Similar to createUnique except for the fact that createUnique 20 * does create the file. 21 * 22 * @param aFile 23 * The file to modify in order for it to have a unique leafname. 24 */ 25 function ensure_unique(aFile) { 26 ensure_unique.fileIndex = ensure_unique.fileIndex || 0; 27 28 var leafName = aFile.leafName; 29 while (aFile.clone().exists()) { 30 aFile.leafName = leafName + "_" + ensure_unique.fileIndex++; 31 } 32 } 33 34 /** 35 * Tests for files being accessed at the right time. Streams that use 36 * DEFER_OPEN should only open or create the file when an operation is 37 * done, and not during Init(). 38 * 39 * Note that for writing, we check for actual writing in test_NetUtil (async) 40 * and in sync_operations in this file (sync), whereas in this function we 41 * just check that the file is *not* created during init. 42 * 43 * @param aContractId 44 * The contract ID to use for the output stream 45 * @param aDeferOpen 46 * Whether to check with DEFER_OPEN or not 47 * @param aTrickDeferredOpen 48 * Whether we try to 'trick' deferred opens by changing the file object before 49 * the actual open. The stream should have a clone, so changes to the file 50 * object after Init and before Open should not affect it. 51 */ 52 function check_access(aContractId, aDeferOpen, aTrickDeferredOpen) { 53 const LEAF_NAME = "filestreams-test-file.tmp"; 54 const TRICKY_LEAF_NAME = "BetYouDidNotExpectThat.tmp"; 55 let file = Services.dirsvc.get("ProfD", Ci.nsIFile); 56 file.append(LEAF_NAME); 57 58 // Writing 59 60 ensure_unique(file); 61 let ostream = Cc[aContractId].createInstance(Ci.nsIFileOutputStream); 62 ostream.init( 63 file, 64 -1, 65 -1, 66 aDeferOpen ? Ci.nsIFileOutputStream.DEFER_OPEN : 0 67 ); 68 Assert.equal(aDeferOpen, !file.clone().exists()); // If defer, should not exist and vice versa 69 if (aDeferOpen) { 70 // File should appear when we do write to it. 71 if (aTrickDeferredOpen) { 72 // See |@param aDeferOpen| in the JavaDoc comment for this function 73 file.leafName = TRICKY_LEAF_NAME; 74 } 75 ostream.write("data", 4); 76 if (aTrickDeferredOpen) { 77 file.leafName = LEAF_NAME; 78 } 79 // We did a write, so the file should now exist 80 Assert.ok(file.clone().exists()); 81 } 82 ostream.close(); 83 84 // Reading 85 86 ensure_unique(file); 87 let istream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance( 88 Ci.nsIFileInputStream 89 ); 90 var initOk, getOk; 91 try { 92 istream.init( 93 file, 94 -1, 95 0, 96 aDeferOpen ? Ci.nsIFileInputStream.DEFER_OPEN : 0 97 ); 98 initOk = true; 99 } catch (e) { 100 initOk = false; 101 } 102 try { 103 let fstream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance( 104 Ci.nsIFileInputStream 105 ); 106 fstream.init(file, -1, 0, 0); 107 getOk = true; 108 } catch (e) { 109 getOk = false; 110 } 111 112 // If the open is deferred, then Init should succeed even though the file we 113 // intend to read does not exist, and then trying to read from it should 114 // fail. The other case is where the open is not deferred, and there we should 115 // get an error when we Init (and also when we try to read). 116 Assert.ok( 117 (aDeferOpen && initOk && !getOk) || (!aDeferOpen && !initOk && !getOk) 118 ); 119 istream.close(); 120 } 121 122 /** 123 * We test async operations in test_NetUtil.js, and here test for simple sync 124 * operations on input streams. 125 * 126 * @param aDeferOpen 127 * Whether to use DEFER_OPEN in the streams. 128 */ 129 function sync_operations(aDeferOpen) { 130 const TEST_DATA = "this is a test string"; 131 const LEAF_NAME = "filestreams-test-file.tmp"; 132 133 let file = Services.dirsvc.get("ProfD", Ci.nsIFile); 134 file.append(LEAF_NAME); 135 file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666); 136 137 let ostream = Cc[OUTPUT_STREAM_CONTRACT_ID].createInstance( 138 Ci.nsIFileOutputStream 139 ); 140 ostream.init( 141 file, 142 -1, 143 -1, 144 aDeferOpen ? Ci.nsIFileOutputStream.DEFER_OPEN : 0 145 ); 146 147 ostream.write(TEST_DATA, TEST_DATA.length); 148 ostream.close(); 149 150 let fstream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance( 151 Ci.nsIFileInputStream 152 ); 153 fstream.init(file, -1, 0, aDeferOpen ? Ci.nsIFileInputStream.DEFER_OPEN : 0); 154 155 let cstream = Cc["@mozilla.org/intl/converter-input-stream;1"].createInstance( 156 Ci.nsIConverterInputStream 157 ); 158 cstream.init(fstream, "UTF-8", 0, 0); 159 160 let string = {}; 161 cstream.readString(-1, string); 162 cstream.close(); 163 fstream.close(); 164 165 Assert.equal(string.value, TEST_DATA); 166 } 167 168 //////////////////////////////////////////////////////////////////////////////// 169 //// Tests 170 171 function test_access() { 172 check_access(OUTPUT_STREAM_CONTRACT_ID, false, false); 173 } 174 175 function test_access_trick() { 176 check_access(OUTPUT_STREAM_CONTRACT_ID, false, true); 177 } 178 179 function test_access_defer() { 180 check_access(OUTPUT_STREAM_CONTRACT_ID, true, false); 181 } 182 183 function test_access_defer_trick() { 184 check_access(OUTPUT_STREAM_CONTRACT_ID, true, true); 185 } 186 187 function test_access_safe() { 188 check_access(SAFE_OUTPUT_STREAM_CONTRACT_ID, false, false); 189 } 190 191 function test_access_safe_trick() { 192 check_access(SAFE_OUTPUT_STREAM_CONTRACT_ID, false, true); 193 } 194 195 function test_access_safe_defer() { 196 check_access(SAFE_OUTPUT_STREAM_CONTRACT_ID, true, false); 197 } 198 199 function test_access_safe_defer_trick() { 200 check_access(SAFE_OUTPUT_STREAM_CONTRACT_ID, true, true); 201 } 202 203 function test_sync_operations() { 204 sync_operations(); 205 } 206 207 function test_sync_operations_deferred() { 208 sync_operations(true); 209 } 210 211 function do_test_zero_size_buffered(disableBuffering) { 212 const LEAF_NAME = "filestreams-test-file.tmp"; 213 const BUFFERSIZE = 4096; 214 215 let file = Services.dirsvc.get("ProfD", Ci.nsIFile); 216 file.append(LEAF_NAME); 217 file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666); 218 219 let fstream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance( 220 Ci.nsIFileInputStream 221 ); 222 fstream.init( 223 file, 224 -1, 225 0, 226 Ci.nsIFileInputStream.CLOSE_ON_EOF | Ci.nsIFileInputStream.REOPEN_ON_REWIND 227 ); 228 229 var buffered = Cc[ 230 "@mozilla.org/network/buffered-input-stream;1" 231 ].createInstance(Ci.nsIBufferedInputStream); 232 buffered.init(fstream, BUFFERSIZE); 233 234 if (disableBuffering) { 235 buffered.QueryInterface(Ci.nsIStreamBufferAccess).disableBuffering(); 236 } 237 238 // Scriptable input streams clamp read sizes to the return value of 239 // available(), so don't quite do what we want here. 240 let cstream = Cc["@mozilla.org/intl/converter-input-stream;1"].createInstance( 241 Ci.nsIConverterInputStream 242 ); 243 cstream.init(buffered, "UTF-8", 0, 0); 244 245 Assert.equal(buffered.available(), 0); 246 247 // Now try reading from this stream 248 let string = {}; 249 Assert.equal(cstream.readString(BUFFERSIZE, string), 0); 250 Assert.equal(string.value, ""); 251 252 // Now check that available() throws 253 var exceptionThrown = false; 254 try { 255 Assert.equal(buffered.available(), 0); 256 } catch (e) { 257 exceptionThrown = true; 258 } 259 Assert.ok(exceptionThrown); 260 261 // OK, now seek back to start 262 buffered.seek(Ci.nsISeekableStream.NS_SEEK_SET, 0); 263 264 // Now check that available() does not throw 265 exceptionThrown = false; 266 try { 267 Assert.equal(buffered.available(), 0); 268 } catch (e) { 269 exceptionThrown = true; 270 } 271 Assert.ok(!exceptionThrown); 272 } 273 274 function test_zero_size_buffered() { 275 do_test_zero_size_buffered(false); 276 do_test_zero_size_buffered(true); 277 } 278 279 //////////////////////////////////////////////////////////////////////////////// 280 //// Test Runner 281 282 var tests = [ 283 test_access, 284 test_access_trick, 285 test_access_defer, 286 test_access_defer_trick, 287 test_access_safe, 288 test_access_safe_trick, 289 test_access_safe_defer, 290 test_access_safe_defer_trick, 291 test_sync_operations, 292 test_sync_operations_deferred, 293 test_zero_size_buffered, 294 ]; 295 296 function run_test() { 297 tests.forEach(function (test) { 298 test(); 299 }); 300 }