1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/netwerk/test/unit/test_file_partial_inputstream.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,512 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +// Test nsIPartialFileInputStream 1.9 +// NOTE! These tests often use do_check_true(a == b) rather than 1.10 +// do_check_eq(a, b) to avoid outputting characters which confuse 1.11 +// the console 1.12 + 1.13 +const CC = Components.Constructor; 1.14 +const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1", 1.15 + "nsIBinaryInputStream", 1.16 + "setInputStream"); 1.17 +const PR_RDONLY = 0x1; // see prio.h 1.18 + 1.19 +// We need the profile directory so the test harness will clean up our test 1.20 +// files. 1.21 +do_get_profile(); 1.22 + 1.23 +var binary_test_file_name = "data/image.png"; 1.24 +var text_test_file_name = "test_file_partial_inputstream.js"; 1.25 +// This is a global variable since if it's passed as an argument stack traces 1.26 +// become unreadable. 1.27 +var test_file_data; 1.28 + 1.29 +function run_test() 1.30 +{ 1.31 + // Binary tests 1.32 + let binaryFile = do_get_file(binary_test_file_name); 1.33 + let size = binaryFile.fileSize; 1.34 + // Want to make sure we're working with a large enough file 1.35 + dump("**** binary file size is: " + size + " ****\n"); 1.36 + do_check_true(size > 65536); 1.37 + 1.38 + let binaryStream = new BinaryInputStream(new_file_input_stream(binaryFile)); 1.39 + test_file_data = ""; 1.40 + while ((avail = binaryStream.available()) > 0) { 1.41 + test_file_data += binaryStream.readBytes(avail); 1.42 + } 1.43 + do_check_eq(test_file_data.length, size); 1.44 + binaryStream.close(); 1.45 + 1.46 + test_binary_portion(0, 10); 1.47 + test_binary_portion(0, 20000); 1.48 + test_binary_portion(0, size); 1.49 + test_binary_portion(20000, 10); 1.50 + test_binary_portion(20000, 20000); 1.51 + test_binary_portion(20000, size-20000); 1.52 + test_binary_portion(size-10, 10); 1.53 + test_binary_portion(size-20000, 20000); 1.54 + test_binary_portion(0, 0); 1.55 + test_binary_portion(20000, 0); 1.56 + test_binary_portion(size-1, 1); 1.57 + 1.58 + 1.59 + // Text-file tests 1.60 + let textFile = do_get_file(binary_test_file_name); 1.61 + size = textFile.fileSize; 1.62 + // Want to make sure we're working with a large enough file 1.63 + dump("**** text file size is: " + size + " ****\n"); 1.64 + do_check_true(size > 7000); 1.65 + 1.66 + let textStream = new BinaryInputStream(new_file_input_stream(textFile)); 1.67 + test_file_data = ""; 1.68 + while ((avail = textStream.available()) > 0) 1.69 + test_file_data += textStream.readBytes(avail); 1.70 + do_check_eq(test_file_data.length, size); 1.71 + textStream.close(); 1.72 + 1.73 + test_text_portion(0, 100); 1.74 + test_text_portion(0, size); 1.75 + test_text_portion(5000, 1000); 1.76 + test_text_portion(size-10, 10); 1.77 + test_text_portion(size-5000, 5000); 1.78 + test_text_portion(10, 0); 1.79 + test_text_portion(size-1, 1); 1.80 + 1.81 + // Test auto-closing files 1.82 + // Test behavior when *not* autoclosing 1.83 + let tempFile = create_temp_file("01234567890123456789"); 1.84 + let tempInputStream = new_partial_file_input_stream(tempFile, 5, 10); 1.85 + tempInputStream.QueryInterface(Ci.nsILineInputStream); 1.86 + do_check_eq(read_line_stream(tempInputStream)[1], "5678901234"); 1.87 + try { 1.88 + // This fails on some platforms 1.89 + tempFile.remove(false); 1.90 + } 1.91 + catch (ex) { 1.92 + } 1.93 + tempInputStream.QueryInterface(Ci.nsISeekableStream); 1.94 + tempInputStream.seek(SET, 1); 1.95 + do_check_eq(read_line_stream(tempInputStream)[1], "678901234"); 1.96 + 1.97 + // Test removing the file when autoclosing 1.98 + tempFile = create_temp_file("01234567890123456789"); 1.99 + tempInputStream = new_partial_file_input_stream(tempFile, 5, 10, 1.100 + Ci.nsIFileInputStream.CLOSE_ON_EOF | 1.101 + Ci.nsIFileInputStream.REOPEN_ON_REWIND); 1.102 + tempInputStream.QueryInterface(Ci.nsILineInputStream); 1.103 + do_check_eq(read_line_stream(tempInputStream)[1], "5678901234"); 1.104 + tempFile.remove(false); 1.105 + tempInputStream.QueryInterface(Ci.nsISeekableStream); 1.106 + try { 1.107 + // The seek should reopen the file, which should fail. 1.108 + tempInputStream.seek(SET, 1); 1.109 + do_check_true(false); 1.110 + } 1.111 + catch (ex) { 1.112 + } 1.113 + 1.114 + // Test editing the file when autoclosing 1.115 + tempFile = create_temp_file("01234567890123456789"); 1.116 + tempInputStream = new_partial_file_input_stream(tempFile, 5, 10, 1.117 + Ci.nsIFileInputStream.CLOSE_ON_EOF | 1.118 + Ci.nsIFileInputStream.REOPEN_ON_REWIND); 1.119 + tempInputStream.QueryInterface(Ci.nsILineInputStream); 1.120 + do_check_eq(read_line_stream(tempInputStream)[1], "5678901234"); 1.121 + let ostream = Cc["@mozilla.org/network/file-output-stream;1"]. 1.122 + createInstance(Ci.nsIFileOutputStream); 1.123 + ostream.init(tempFile, 0x02 | 0x08 | 0x20, // write, create, truncate 1.124 + 0666, 0); 1.125 + let newData = "abcdefghijklmnopqrstuvwxyz"; 1.126 + ostream.write(newData, newData.length); 1.127 + ostream.close(); 1.128 + tempInputStream.QueryInterface(Ci.nsISeekableStream); 1.129 + tempInputStream.seek(SET, 1); 1.130 + do_check_eq(read_line_stream(tempInputStream)[1], newData.substr(6,9)); 1.131 + 1.132 + // Test auto-delete and auto-close together 1.133 + tempFile = create_temp_file("01234567890123456789"); 1.134 + tempInputStream = new_partial_file_input_stream(tempFile, 5, 10, 1.135 + Ci.nsIFileInputStream.CLOSE_ON_EOF | 1.136 + Ci.nsIFileInputStream.DELETE_ON_CLOSE); 1.137 + tempInputStream.QueryInterface(Ci.nsILineInputStream); 1.138 + do_check_eq(read_line_stream(tempInputStream)[1], "5678901234"); 1.139 + do_check_false(tempFile.exists()); 1.140 +} 1.141 + 1.142 +function test_binary_portion(start, length) { 1.143 + let subFile = create_temp_file(test_file_data.substr(start, length)); 1.144 + 1.145 + let streamTests = [ 1.146 + test_4k_read, 1.147 + test_max_read, 1.148 + test_seek, 1.149 + test_seek_then_read, 1.150 + ]; 1.151 + 1.152 + for each(test in streamTests) { 1.153 + let fileStream = new_file_input_stream(subFile); 1.154 + let partialStream = new_partial_file_input_stream(do_get_file(binary_test_file_name), 1.155 + start, length); 1.156 + test(fileStream, partialStream, length); 1.157 + fileStream.close(); 1.158 + partialStream.close(); 1.159 + } 1.160 +} 1.161 + 1.162 +function test_4k_read(fileStreamA, fileStreamB) { 1.163 + fileStreamA.QueryInterface(Ci.nsISeekableStream); 1.164 + fileStreamB.QueryInterface(Ci.nsISeekableStream); 1.165 + let streamA = new BinaryInputStream(fileStreamA); 1.166 + let streamB = new BinaryInputStream(fileStreamB); 1.167 + 1.168 + while(1) { 1.169 + do_check_eq(fileStreamA.tell(), fileStreamB.tell()); 1.170 + 1.171 + let availA = streamA.available(); 1.172 + let availB = streamB.available(); 1.173 + do_check_eq(availA, availB); 1.174 + if (availA == 0) 1.175 + return; 1.176 + 1.177 + let readSize = availA > 4096 ? 4096 : availA; 1.178 + 1.179 + do_check_true(streamA.readBytes(readSize) == 1.180 + streamB.readBytes(readSize)); 1.181 + } 1.182 +} 1.183 + 1.184 +function test_max_read(fileStreamA, fileStreamB) { 1.185 + fileStreamA.QueryInterface(Ci.nsISeekableStream); 1.186 + fileStreamB.QueryInterface(Ci.nsISeekableStream); 1.187 + let streamA = new BinaryInputStream(fileStreamA); 1.188 + let streamB = new BinaryInputStream(fileStreamB); 1.189 + 1.190 + while(1) { 1.191 + do_check_eq(fileStreamA.tell(), fileStreamB.tell()); 1.192 + 1.193 + let availA = streamA.available(); 1.194 + let availB = streamB.available(); 1.195 + do_check_eq(availA, availB); 1.196 + if (availA == 0) 1.197 + return; 1.198 + 1.199 + do_check_true(streamA.readBytes(availA) == 1.200 + streamB.readBytes(availB)); 1.201 + } 1.202 +} 1.203 + 1.204 +const SET = Ci.nsISeekableStream.NS_SEEK_SET; 1.205 +const CUR = Ci.nsISeekableStream.NS_SEEK_CUR; 1.206 +const END = Ci.nsISeekableStream.NS_SEEK_END; 1.207 +function test_seek(dummy, partialFileStream, size) { 1.208 + // We can't test the "real" filestream here as our existing file streams 1.209 + // are very broken and allows searching past the end of the file. 1.210 + 1.211 + partialFileStream.QueryInterface(Ci.nsISeekableStream); 1.212 + 1.213 + tests = [ 1.214 + [SET, 0], 1.215 + [SET, 5], 1.216 + [SET, 1000], 1.217 + [SET, size-10], 1.218 + [SET, size-5], 1.219 + [SET, size-1], 1.220 + [SET, size], 1.221 + [SET, size+10], 1.222 + [SET, 0], 1.223 + [CUR, 5], 1.224 + [CUR, -5], 1.225 + [SET, 5000], 1.226 + [CUR, -100], 1.227 + [CUR, 200], 1.228 + [CUR, -5000], 1.229 + [CUR, 5000], 1.230 + [CUR, size * 2], 1.231 + [SET, 1], 1.232 + [CUR, -1], 1.233 + [CUR, -1], 1.234 + [CUR, -1], 1.235 + [CUR, -1], 1.236 + [CUR, -1], 1.237 + [SET, size-1], 1.238 + [CUR, 1], 1.239 + [CUR, 1], 1.240 + [CUR, 1], 1.241 + [CUR, 1], 1.242 + [CUR, 1], 1.243 + [END, 0], 1.244 + [END, -1], 1.245 + [END, -5], 1.246 + [END, -1000], 1.247 + [END, -size+10], 1.248 + [END, -size+5], 1.249 + [END, -size+1], 1.250 + [END, -size], 1.251 + [END, -size-10], 1.252 + [END, 10], 1.253 + [CUR, 10], 1.254 + [CUR, 10], 1.255 + [CUR, 100], 1.256 + [CUR, 1000], 1.257 + [END, -1000], 1.258 + [CUR, 100], 1.259 + [CUR, 900], 1.260 + [CUR, 100], 1.261 + [CUR, 100], 1.262 + ]; 1.263 + 1.264 + let pos = 0; 1.265 + for each(test in tests) { 1.266 + let didThrow = false; 1.267 + try { 1.268 + partialFileStream.seek(test[0], test[1]); 1.269 + } 1.270 + catch (ex) { 1.271 + didThrow = true; 1.272 + } 1.273 + 1.274 + let newPos = test[0] == SET ? test[1] : 1.275 + test[0] == CUR ? pos + test[1] : 1.276 + size + test[1]; 1.277 + if (newPos > size || newPos < 0) { 1.278 + do_check_true(didThrow); 1.279 + } 1.280 + else { 1.281 + do_check_false(didThrow); 1.282 + pos = newPos; 1.283 + } 1.284 + 1.285 + do_check_eq(partialFileStream.tell(), pos); 1.286 + do_check_eq(partialFileStream.available(), size - pos); 1.287 + } 1.288 +} 1.289 + 1.290 +function test_seek_then_read(fileStreamA, fileStreamB, size) { 1.291 + // For now we only test seeking inside the file since our existing file 1.292 + // streams behave very strange when seeking to past the end of the file. 1.293 + if (size < 20000) { 1.294 + return; 1.295 + } 1.296 + 1.297 + fileStreamA.QueryInterface(Ci.nsISeekableStream); 1.298 + fileStreamB.QueryInterface(Ci.nsISeekableStream); 1.299 + let streamA = new BinaryInputStream(fileStreamA); 1.300 + let streamB = new BinaryInputStream(fileStreamB); 1.301 + 1.302 + let read = {}; 1.303 + 1.304 + tests = [ 1.305 + [SET, 0], 1.306 + [read, 1000], 1.307 + [read, 1000], 1.308 + [SET, 5], 1.309 + [read, 1000], 1.310 + [read, 5000], 1.311 + [CUR, 100], 1.312 + [read, 1000], 1.313 + [read, 5000], 1.314 + [CUR, -100], 1.315 + [read, 1000], 1.316 + [CUR, -100], 1.317 + [read, 5000], 1.318 + [END, -10], 1.319 + [read, 10], 1.320 + [END, -100], 1.321 + [read, 101], 1.322 + [CUR, -100], 1.323 + [read, 10], 1.324 + [SET, 0], 1.325 + [read, 20000], 1.326 + [read, 1], 1.327 + [read, 100], 1.328 + ]; 1.329 + 1.330 + for each(test in tests) { 1.331 + if (test[0] === read) { 1.332 + 1.333 + let didThrowA = false; 1.334 + let didThrowB = false; 1.335 + 1.336 + let bytesA, bytesB; 1.337 + try { 1.338 + bytesA = streamA.readBytes(test[1]); 1.339 + } 1.340 + catch (ex) { 1.341 + didThrowA = true; 1.342 + } 1.343 + try { 1.344 + bytesB = streamB.readBytes(test[1]); 1.345 + } 1.346 + catch (ex) { 1.347 + didThrowB = true; 1.348 + } 1.349 + 1.350 + do_check_eq(didThrowA, didThrowB); 1.351 + do_check_true(bytesA == bytesB); 1.352 + } 1.353 + else { 1.354 + fileStreamA.seek(test[0], test[1]); 1.355 + fileStreamB.seek(test[0], test[1]); 1.356 + } 1.357 + do_check_eq(fileStreamA.tell(), fileStreamB.tell()); 1.358 + do_check_eq(fileStreamA.available(), fileStreamB.available()); 1.359 + } 1.360 +} 1.361 + 1.362 +function test_text_portion(start, length) { 1.363 + let subFile = create_temp_file(test_file_data.substr(start, length)); 1.364 + 1.365 + let streamTests = [ 1.366 + test_readline, 1.367 + test_seek_then_readline, 1.368 + ]; 1.369 + 1.370 + for each(test in streamTests) { 1.371 + let fileStream = new_file_input_stream(subFile) 1.372 + .QueryInterface(Ci.nsILineInputStream); 1.373 + let partialStream = new_partial_file_input_stream(do_get_file(binary_test_file_name), 1.374 + start, length) 1.375 + .QueryInterface(Ci.nsILineInputStream); 1.376 + test(fileStream, partialStream, length); 1.377 + fileStream.close(); 1.378 + partialStream.close(); 1.379 + } 1.380 +} 1.381 + 1.382 +function test_readline(fileStreamA, fileStreamB) 1.383 +{ 1.384 + let moreA = true, moreB; 1.385 + while(moreA) { 1.386 + let lineA, lineB; 1.387 + [moreA, lineA] = read_line_stream(fileStreamA); 1.388 + [moreB, lineB] = read_line_stream(fileStreamB); 1.389 + do_check_eq(moreA, moreB); 1.390 + do_check_true(lineA.value == lineB.value); 1.391 + } 1.392 +} 1.393 + 1.394 +function test_seek_then_readline(fileStreamA, fileStreamB, size) { 1.395 + // For now we only test seeking inside the file since our existing file 1.396 + // streams behave very strange when seeking to past the end of the file. 1.397 + if (size < 100) { 1.398 + return; 1.399 + } 1.400 + 1.401 + fileStreamA.QueryInterface(Ci.nsISeekableStream); 1.402 + fileStreamB.QueryInterface(Ci.nsISeekableStream); 1.403 + 1.404 + let read = {}; 1.405 + 1.406 + tests = [ 1.407 + [SET, 0], 1.408 + [read, 5], 1.409 + [read, 5], 1.410 + [SET, 5], 1.411 + [read, 5], 1.412 + [read, 15], 1.413 + [CUR, 100], 1.414 + [read, 5], 1.415 + [read, 15], 1.416 + [CUR, -100], 1.417 + [read, 5], 1.418 + [CUR, -100], 1.419 + [read, 25], 1.420 + [END, -10], 1.421 + [read, 1], 1.422 + [END, -50], 1.423 + [read, 30], 1.424 + [read, 1], 1.425 + [read, 1], 1.426 + [CUR, -100], 1.427 + [read, 1], 1.428 + [SET, 0], 1.429 + [read, 10000], 1.430 + [read, 1], 1.431 + [read, 1], 1.432 + [SET, 0], 1.433 + [read, 1], 1.434 + ]; 1.435 + 1.436 + for each(test in tests) { 1.437 + if (test[0] === read) { 1.438 + 1.439 + for (let i = 0; i < test[1]; ++i) { 1.440 + let didThrowA = false; 1.441 + let didThrowB = false; 1.442 + 1.443 + let lineA, lineB, moreA, moreB; 1.444 + try { 1.445 + [moreA, lineA] = read_line_stream(fileStreamA); 1.446 + } 1.447 + catch (ex) { 1.448 + didThrowA = true; 1.449 + } 1.450 + try { 1.451 + [moreB, lineB] = read_line_stream(fileStreamB); 1.452 + } 1.453 + catch (ex) { 1.454 + didThrowB = true; 1.455 + } 1.456 + 1.457 + do_check_eq(didThrowA, didThrowB); 1.458 + do_check_eq(moreA, moreB); 1.459 + do_check_true(lineA == lineB); 1.460 + do_check_eq(fileStreamA.tell(), fileStreamB.tell()); 1.461 + do_check_eq(fileStreamA.available(), fileStreamB.available()); 1.462 + if (!moreA) 1.463 + break; 1.464 + } 1.465 + } 1.466 + else { 1.467 + if (!(test[0] == CUR && (test[1] > fileStreamA.available() || 1.468 + test[1] < -fileStreamA.tell()))) { 1.469 + fileStreamA.seek(test[0], test[1]); 1.470 + fileStreamB.seek(test[0], test[1]); 1.471 + do_check_eq(fileStreamA.tell(), fileStreamB.tell()); 1.472 + do_check_eq(fileStreamA.available(), fileStreamB.available()); 1.473 + } 1.474 + } 1.475 + } 1.476 +} 1.477 + 1.478 +function read_line_stream(stream) { 1.479 + let line = {}; 1.480 + let more = stream.readLine(line); 1.481 + return [more, line.value]; 1.482 +} 1.483 + 1.484 +function new_file_input_stream(file) { 1.485 + var stream = 1.486 + Cc["@mozilla.org/network/file-input-stream;1"] 1.487 + .createInstance(Ci.nsIFileInputStream); 1.488 + stream.init(file, PR_RDONLY, 0, 0); 1.489 + return stream.QueryInterface(Ci.nsIInputStream); 1.490 +} 1.491 + 1.492 +function new_partial_file_input_stream(file, start, length, flags) { 1.493 + var stream = 1.494 + Cc["@mozilla.org/network/partial-file-input-stream;1"] 1.495 + .createInstance(Ci.nsIPartialFileInputStream); 1.496 + stream.init(file, start, length, PR_RDONLY, 0, flags || 0); 1.497 + return stream.QueryInterface(Ci.nsIInputStream); 1.498 +} 1.499 + 1.500 +function create_temp_file(data) { 1.501 + let file = Cc["@mozilla.org/file/directory_service;1"]. 1.502 + getService(Ci.nsIProperties). 1.503 + get("ProfD", Ci.nsIFile); 1.504 + file.append("fileinputstream-test-file.tmp"); 1.505 + file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666); 1.506 + 1.507 + let ostream = Cc["@mozilla.org/network/file-output-stream;1"]. 1.508 + createInstance(Ci.nsIFileOutputStream); 1.509 + ostream.init(file, 0x02 | 0x08 | 0x20, // write, create, truncate 1.510 + 0666, 0); 1.511 + do_check_eq(ostream.write(data, data.length), data.length); 1.512 + ostream.close(); 1.513 + 1.514 + return file; 1.515 +}