netwerk/test/unit/test_file_partial_inputstream.js

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 // Test nsIPartialFileInputStream
michael@0 6 // NOTE! These tests often use do_check_true(a == b) rather than
michael@0 7 // do_check_eq(a, b) to avoid outputting characters which confuse
michael@0 8 // the console
michael@0 9
michael@0 10 const CC = Components.Constructor;
michael@0 11 const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
michael@0 12 "nsIBinaryInputStream",
michael@0 13 "setInputStream");
michael@0 14 const PR_RDONLY = 0x1; // see prio.h
michael@0 15
michael@0 16 // We need the profile directory so the test harness will clean up our test
michael@0 17 // files.
michael@0 18 do_get_profile();
michael@0 19
michael@0 20 var binary_test_file_name = "data/image.png";
michael@0 21 var text_test_file_name = "test_file_partial_inputstream.js";
michael@0 22 // This is a global variable since if it's passed as an argument stack traces
michael@0 23 // become unreadable.
michael@0 24 var test_file_data;
michael@0 25
michael@0 26 function run_test()
michael@0 27 {
michael@0 28 // Binary tests
michael@0 29 let binaryFile = do_get_file(binary_test_file_name);
michael@0 30 let size = binaryFile.fileSize;
michael@0 31 // Want to make sure we're working with a large enough file
michael@0 32 dump("**** binary file size is: " + size + " ****\n");
michael@0 33 do_check_true(size > 65536);
michael@0 34
michael@0 35 let binaryStream = new BinaryInputStream(new_file_input_stream(binaryFile));
michael@0 36 test_file_data = "";
michael@0 37 while ((avail = binaryStream.available()) > 0) {
michael@0 38 test_file_data += binaryStream.readBytes(avail);
michael@0 39 }
michael@0 40 do_check_eq(test_file_data.length, size);
michael@0 41 binaryStream.close();
michael@0 42
michael@0 43 test_binary_portion(0, 10);
michael@0 44 test_binary_portion(0, 20000);
michael@0 45 test_binary_portion(0, size);
michael@0 46 test_binary_portion(20000, 10);
michael@0 47 test_binary_portion(20000, 20000);
michael@0 48 test_binary_portion(20000, size-20000);
michael@0 49 test_binary_portion(size-10, 10);
michael@0 50 test_binary_portion(size-20000, 20000);
michael@0 51 test_binary_portion(0, 0);
michael@0 52 test_binary_portion(20000, 0);
michael@0 53 test_binary_portion(size-1, 1);
michael@0 54
michael@0 55
michael@0 56 // Text-file tests
michael@0 57 let textFile = do_get_file(binary_test_file_name);
michael@0 58 size = textFile.fileSize;
michael@0 59 // Want to make sure we're working with a large enough file
michael@0 60 dump("**** text file size is: " + size + " ****\n");
michael@0 61 do_check_true(size > 7000);
michael@0 62
michael@0 63 let textStream = new BinaryInputStream(new_file_input_stream(textFile));
michael@0 64 test_file_data = "";
michael@0 65 while ((avail = textStream.available()) > 0)
michael@0 66 test_file_data += textStream.readBytes(avail);
michael@0 67 do_check_eq(test_file_data.length, size);
michael@0 68 textStream.close();
michael@0 69
michael@0 70 test_text_portion(0, 100);
michael@0 71 test_text_portion(0, size);
michael@0 72 test_text_portion(5000, 1000);
michael@0 73 test_text_portion(size-10, 10);
michael@0 74 test_text_portion(size-5000, 5000);
michael@0 75 test_text_portion(10, 0);
michael@0 76 test_text_portion(size-1, 1);
michael@0 77
michael@0 78 // Test auto-closing files
michael@0 79 // Test behavior when *not* autoclosing
michael@0 80 let tempFile = create_temp_file("01234567890123456789");
michael@0 81 let tempInputStream = new_partial_file_input_stream(tempFile, 5, 10);
michael@0 82 tempInputStream.QueryInterface(Ci.nsILineInputStream);
michael@0 83 do_check_eq(read_line_stream(tempInputStream)[1], "5678901234");
michael@0 84 try {
michael@0 85 // This fails on some platforms
michael@0 86 tempFile.remove(false);
michael@0 87 }
michael@0 88 catch (ex) {
michael@0 89 }
michael@0 90 tempInputStream.QueryInterface(Ci.nsISeekableStream);
michael@0 91 tempInputStream.seek(SET, 1);
michael@0 92 do_check_eq(read_line_stream(tempInputStream)[1], "678901234");
michael@0 93
michael@0 94 // Test removing the file when autoclosing
michael@0 95 tempFile = create_temp_file("01234567890123456789");
michael@0 96 tempInputStream = new_partial_file_input_stream(tempFile, 5, 10,
michael@0 97 Ci.nsIFileInputStream.CLOSE_ON_EOF |
michael@0 98 Ci.nsIFileInputStream.REOPEN_ON_REWIND);
michael@0 99 tempInputStream.QueryInterface(Ci.nsILineInputStream);
michael@0 100 do_check_eq(read_line_stream(tempInputStream)[1], "5678901234");
michael@0 101 tempFile.remove(false);
michael@0 102 tempInputStream.QueryInterface(Ci.nsISeekableStream);
michael@0 103 try {
michael@0 104 // The seek should reopen the file, which should fail.
michael@0 105 tempInputStream.seek(SET, 1);
michael@0 106 do_check_true(false);
michael@0 107 }
michael@0 108 catch (ex) {
michael@0 109 }
michael@0 110
michael@0 111 // Test editing the file when autoclosing
michael@0 112 tempFile = create_temp_file("01234567890123456789");
michael@0 113 tempInputStream = new_partial_file_input_stream(tempFile, 5, 10,
michael@0 114 Ci.nsIFileInputStream.CLOSE_ON_EOF |
michael@0 115 Ci.nsIFileInputStream.REOPEN_ON_REWIND);
michael@0 116 tempInputStream.QueryInterface(Ci.nsILineInputStream);
michael@0 117 do_check_eq(read_line_stream(tempInputStream)[1], "5678901234");
michael@0 118 let ostream = Cc["@mozilla.org/network/file-output-stream;1"].
michael@0 119 createInstance(Ci.nsIFileOutputStream);
michael@0 120 ostream.init(tempFile, 0x02 | 0x08 | 0x20, // write, create, truncate
michael@0 121 0666, 0);
michael@0 122 let newData = "abcdefghijklmnopqrstuvwxyz";
michael@0 123 ostream.write(newData, newData.length);
michael@0 124 ostream.close();
michael@0 125 tempInputStream.QueryInterface(Ci.nsISeekableStream);
michael@0 126 tempInputStream.seek(SET, 1);
michael@0 127 do_check_eq(read_line_stream(tempInputStream)[1], newData.substr(6,9));
michael@0 128
michael@0 129 // Test auto-delete and auto-close together
michael@0 130 tempFile = create_temp_file("01234567890123456789");
michael@0 131 tempInputStream = new_partial_file_input_stream(tempFile, 5, 10,
michael@0 132 Ci.nsIFileInputStream.CLOSE_ON_EOF |
michael@0 133 Ci.nsIFileInputStream.DELETE_ON_CLOSE);
michael@0 134 tempInputStream.QueryInterface(Ci.nsILineInputStream);
michael@0 135 do_check_eq(read_line_stream(tempInputStream)[1], "5678901234");
michael@0 136 do_check_false(tempFile.exists());
michael@0 137 }
michael@0 138
michael@0 139 function test_binary_portion(start, length) {
michael@0 140 let subFile = create_temp_file(test_file_data.substr(start, length));
michael@0 141
michael@0 142 let streamTests = [
michael@0 143 test_4k_read,
michael@0 144 test_max_read,
michael@0 145 test_seek,
michael@0 146 test_seek_then_read,
michael@0 147 ];
michael@0 148
michael@0 149 for each(test in streamTests) {
michael@0 150 let fileStream = new_file_input_stream(subFile);
michael@0 151 let partialStream = new_partial_file_input_stream(do_get_file(binary_test_file_name),
michael@0 152 start, length);
michael@0 153 test(fileStream, partialStream, length);
michael@0 154 fileStream.close();
michael@0 155 partialStream.close();
michael@0 156 }
michael@0 157 }
michael@0 158
michael@0 159 function test_4k_read(fileStreamA, fileStreamB) {
michael@0 160 fileStreamA.QueryInterface(Ci.nsISeekableStream);
michael@0 161 fileStreamB.QueryInterface(Ci.nsISeekableStream);
michael@0 162 let streamA = new BinaryInputStream(fileStreamA);
michael@0 163 let streamB = new BinaryInputStream(fileStreamB);
michael@0 164
michael@0 165 while(1) {
michael@0 166 do_check_eq(fileStreamA.tell(), fileStreamB.tell());
michael@0 167
michael@0 168 let availA = streamA.available();
michael@0 169 let availB = streamB.available();
michael@0 170 do_check_eq(availA, availB);
michael@0 171 if (availA == 0)
michael@0 172 return;
michael@0 173
michael@0 174 let readSize = availA > 4096 ? 4096 : availA;
michael@0 175
michael@0 176 do_check_true(streamA.readBytes(readSize) ==
michael@0 177 streamB.readBytes(readSize));
michael@0 178 }
michael@0 179 }
michael@0 180
michael@0 181 function test_max_read(fileStreamA, fileStreamB) {
michael@0 182 fileStreamA.QueryInterface(Ci.nsISeekableStream);
michael@0 183 fileStreamB.QueryInterface(Ci.nsISeekableStream);
michael@0 184 let streamA = new BinaryInputStream(fileStreamA);
michael@0 185 let streamB = new BinaryInputStream(fileStreamB);
michael@0 186
michael@0 187 while(1) {
michael@0 188 do_check_eq(fileStreamA.tell(), fileStreamB.tell());
michael@0 189
michael@0 190 let availA = streamA.available();
michael@0 191 let availB = streamB.available();
michael@0 192 do_check_eq(availA, availB);
michael@0 193 if (availA == 0)
michael@0 194 return;
michael@0 195
michael@0 196 do_check_true(streamA.readBytes(availA) ==
michael@0 197 streamB.readBytes(availB));
michael@0 198 }
michael@0 199 }
michael@0 200
michael@0 201 const SET = Ci.nsISeekableStream.NS_SEEK_SET;
michael@0 202 const CUR = Ci.nsISeekableStream.NS_SEEK_CUR;
michael@0 203 const END = Ci.nsISeekableStream.NS_SEEK_END;
michael@0 204 function test_seek(dummy, partialFileStream, size) {
michael@0 205 // We can't test the "real" filestream here as our existing file streams
michael@0 206 // are very broken and allows searching past the end of the file.
michael@0 207
michael@0 208 partialFileStream.QueryInterface(Ci.nsISeekableStream);
michael@0 209
michael@0 210 tests = [
michael@0 211 [SET, 0],
michael@0 212 [SET, 5],
michael@0 213 [SET, 1000],
michael@0 214 [SET, size-10],
michael@0 215 [SET, size-5],
michael@0 216 [SET, size-1],
michael@0 217 [SET, size],
michael@0 218 [SET, size+10],
michael@0 219 [SET, 0],
michael@0 220 [CUR, 5],
michael@0 221 [CUR, -5],
michael@0 222 [SET, 5000],
michael@0 223 [CUR, -100],
michael@0 224 [CUR, 200],
michael@0 225 [CUR, -5000],
michael@0 226 [CUR, 5000],
michael@0 227 [CUR, size * 2],
michael@0 228 [SET, 1],
michael@0 229 [CUR, -1],
michael@0 230 [CUR, -1],
michael@0 231 [CUR, -1],
michael@0 232 [CUR, -1],
michael@0 233 [CUR, -1],
michael@0 234 [SET, size-1],
michael@0 235 [CUR, 1],
michael@0 236 [CUR, 1],
michael@0 237 [CUR, 1],
michael@0 238 [CUR, 1],
michael@0 239 [CUR, 1],
michael@0 240 [END, 0],
michael@0 241 [END, -1],
michael@0 242 [END, -5],
michael@0 243 [END, -1000],
michael@0 244 [END, -size+10],
michael@0 245 [END, -size+5],
michael@0 246 [END, -size+1],
michael@0 247 [END, -size],
michael@0 248 [END, -size-10],
michael@0 249 [END, 10],
michael@0 250 [CUR, 10],
michael@0 251 [CUR, 10],
michael@0 252 [CUR, 100],
michael@0 253 [CUR, 1000],
michael@0 254 [END, -1000],
michael@0 255 [CUR, 100],
michael@0 256 [CUR, 900],
michael@0 257 [CUR, 100],
michael@0 258 [CUR, 100],
michael@0 259 ];
michael@0 260
michael@0 261 let pos = 0;
michael@0 262 for each(test in tests) {
michael@0 263 let didThrow = false;
michael@0 264 try {
michael@0 265 partialFileStream.seek(test[0], test[1]);
michael@0 266 }
michael@0 267 catch (ex) {
michael@0 268 didThrow = true;
michael@0 269 }
michael@0 270
michael@0 271 let newPos = test[0] == SET ? test[1] :
michael@0 272 test[0] == CUR ? pos + test[1] :
michael@0 273 size + test[1];
michael@0 274 if (newPos > size || newPos < 0) {
michael@0 275 do_check_true(didThrow);
michael@0 276 }
michael@0 277 else {
michael@0 278 do_check_false(didThrow);
michael@0 279 pos = newPos;
michael@0 280 }
michael@0 281
michael@0 282 do_check_eq(partialFileStream.tell(), pos);
michael@0 283 do_check_eq(partialFileStream.available(), size - pos);
michael@0 284 }
michael@0 285 }
michael@0 286
michael@0 287 function test_seek_then_read(fileStreamA, fileStreamB, size) {
michael@0 288 // For now we only test seeking inside the file since our existing file
michael@0 289 // streams behave very strange when seeking to past the end of the file.
michael@0 290 if (size < 20000) {
michael@0 291 return;
michael@0 292 }
michael@0 293
michael@0 294 fileStreamA.QueryInterface(Ci.nsISeekableStream);
michael@0 295 fileStreamB.QueryInterface(Ci.nsISeekableStream);
michael@0 296 let streamA = new BinaryInputStream(fileStreamA);
michael@0 297 let streamB = new BinaryInputStream(fileStreamB);
michael@0 298
michael@0 299 let read = {};
michael@0 300
michael@0 301 tests = [
michael@0 302 [SET, 0],
michael@0 303 [read, 1000],
michael@0 304 [read, 1000],
michael@0 305 [SET, 5],
michael@0 306 [read, 1000],
michael@0 307 [read, 5000],
michael@0 308 [CUR, 100],
michael@0 309 [read, 1000],
michael@0 310 [read, 5000],
michael@0 311 [CUR, -100],
michael@0 312 [read, 1000],
michael@0 313 [CUR, -100],
michael@0 314 [read, 5000],
michael@0 315 [END, -10],
michael@0 316 [read, 10],
michael@0 317 [END, -100],
michael@0 318 [read, 101],
michael@0 319 [CUR, -100],
michael@0 320 [read, 10],
michael@0 321 [SET, 0],
michael@0 322 [read, 20000],
michael@0 323 [read, 1],
michael@0 324 [read, 100],
michael@0 325 ];
michael@0 326
michael@0 327 for each(test in tests) {
michael@0 328 if (test[0] === read) {
michael@0 329
michael@0 330 let didThrowA = false;
michael@0 331 let didThrowB = false;
michael@0 332
michael@0 333 let bytesA, bytesB;
michael@0 334 try {
michael@0 335 bytesA = streamA.readBytes(test[1]);
michael@0 336 }
michael@0 337 catch (ex) {
michael@0 338 didThrowA = true;
michael@0 339 }
michael@0 340 try {
michael@0 341 bytesB = streamB.readBytes(test[1]);
michael@0 342 }
michael@0 343 catch (ex) {
michael@0 344 didThrowB = true;
michael@0 345 }
michael@0 346
michael@0 347 do_check_eq(didThrowA, didThrowB);
michael@0 348 do_check_true(bytesA == bytesB);
michael@0 349 }
michael@0 350 else {
michael@0 351 fileStreamA.seek(test[0], test[1]);
michael@0 352 fileStreamB.seek(test[0], test[1]);
michael@0 353 }
michael@0 354 do_check_eq(fileStreamA.tell(), fileStreamB.tell());
michael@0 355 do_check_eq(fileStreamA.available(), fileStreamB.available());
michael@0 356 }
michael@0 357 }
michael@0 358
michael@0 359 function test_text_portion(start, length) {
michael@0 360 let subFile = create_temp_file(test_file_data.substr(start, length));
michael@0 361
michael@0 362 let streamTests = [
michael@0 363 test_readline,
michael@0 364 test_seek_then_readline,
michael@0 365 ];
michael@0 366
michael@0 367 for each(test in streamTests) {
michael@0 368 let fileStream = new_file_input_stream(subFile)
michael@0 369 .QueryInterface(Ci.nsILineInputStream);
michael@0 370 let partialStream = new_partial_file_input_stream(do_get_file(binary_test_file_name),
michael@0 371 start, length)
michael@0 372 .QueryInterface(Ci.nsILineInputStream);
michael@0 373 test(fileStream, partialStream, length);
michael@0 374 fileStream.close();
michael@0 375 partialStream.close();
michael@0 376 }
michael@0 377 }
michael@0 378
michael@0 379 function test_readline(fileStreamA, fileStreamB)
michael@0 380 {
michael@0 381 let moreA = true, moreB;
michael@0 382 while(moreA) {
michael@0 383 let lineA, lineB;
michael@0 384 [moreA, lineA] = read_line_stream(fileStreamA);
michael@0 385 [moreB, lineB] = read_line_stream(fileStreamB);
michael@0 386 do_check_eq(moreA, moreB);
michael@0 387 do_check_true(lineA.value == lineB.value);
michael@0 388 }
michael@0 389 }
michael@0 390
michael@0 391 function test_seek_then_readline(fileStreamA, fileStreamB, size) {
michael@0 392 // For now we only test seeking inside the file since our existing file
michael@0 393 // streams behave very strange when seeking to past the end of the file.
michael@0 394 if (size < 100) {
michael@0 395 return;
michael@0 396 }
michael@0 397
michael@0 398 fileStreamA.QueryInterface(Ci.nsISeekableStream);
michael@0 399 fileStreamB.QueryInterface(Ci.nsISeekableStream);
michael@0 400
michael@0 401 let read = {};
michael@0 402
michael@0 403 tests = [
michael@0 404 [SET, 0],
michael@0 405 [read, 5],
michael@0 406 [read, 5],
michael@0 407 [SET, 5],
michael@0 408 [read, 5],
michael@0 409 [read, 15],
michael@0 410 [CUR, 100],
michael@0 411 [read, 5],
michael@0 412 [read, 15],
michael@0 413 [CUR, -100],
michael@0 414 [read, 5],
michael@0 415 [CUR, -100],
michael@0 416 [read, 25],
michael@0 417 [END, -10],
michael@0 418 [read, 1],
michael@0 419 [END, -50],
michael@0 420 [read, 30],
michael@0 421 [read, 1],
michael@0 422 [read, 1],
michael@0 423 [CUR, -100],
michael@0 424 [read, 1],
michael@0 425 [SET, 0],
michael@0 426 [read, 10000],
michael@0 427 [read, 1],
michael@0 428 [read, 1],
michael@0 429 [SET, 0],
michael@0 430 [read, 1],
michael@0 431 ];
michael@0 432
michael@0 433 for each(test in tests) {
michael@0 434 if (test[0] === read) {
michael@0 435
michael@0 436 for (let i = 0; i < test[1]; ++i) {
michael@0 437 let didThrowA = false;
michael@0 438 let didThrowB = false;
michael@0 439
michael@0 440 let lineA, lineB, moreA, moreB;
michael@0 441 try {
michael@0 442 [moreA, lineA] = read_line_stream(fileStreamA);
michael@0 443 }
michael@0 444 catch (ex) {
michael@0 445 didThrowA = true;
michael@0 446 }
michael@0 447 try {
michael@0 448 [moreB, lineB] = read_line_stream(fileStreamB);
michael@0 449 }
michael@0 450 catch (ex) {
michael@0 451 didThrowB = true;
michael@0 452 }
michael@0 453
michael@0 454 do_check_eq(didThrowA, didThrowB);
michael@0 455 do_check_eq(moreA, moreB);
michael@0 456 do_check_true(lineA == lineB);
michael@0 457 do_check_eq(fileStreamA.tell(), fileStreamB.tell());
michael@0 458 do_check_eq(fileStreamA.available(), fileStreamB.available());
michael@0 459 if (!moreA)
michael@0 460 break;
michael@0 461 }
michael@0 462 }
michael@0 463 else {
michael@0 464 if (!(test[0] == CUR && (test[1] > fileStreamA.available() ||
michael@0 465 test[1] < -fileStreamA.tell()))) {
michael@0 466 fileStreamA.seek(test[0], test[1]);
michael@0 467 fileStreamB.seek(test[0], test[1]);
michael@0 468 do_check_eq(fileStreamA.tell(), fileStreamB.tell());
michael@0 469 do_check_eq(fileStreamA.available(), fileStreamB.available());
michael@0 470 }
michael@0 471 }
michael@0 472 }
michael@0 473 }
michael@0 474
michael@0 475 function read_line_stream(stream) {
michael@0 476 let line = {};
michael@0 477 let more = stream.readLine(line);
michael@0 478 return [more, line.value];
michael@0 479 }
michael@0 480
michael@0 481 function new_file_input_stream(file) {
michael@0 482 var stream =
michael@0 483 Cc["@mozilla.org/network/file-input-stream;1"]
michael@0 484 .createInstance(Ci.nsIFileInputStream);
michael@0 485 stream.init(file, PR_RDONLY, 0, 0);
michael@0 486 return stream.QueryInterface(Ci.nsIInputStream);
michael@0 487 }
michael@0 488
michael@0 489 function new_partial_file_input_stream(file, start, length, flags) {
michael@0 490 var stream =
michael@0 491 Cc["@mozilla.org/network/partial-file-input-stream;1"]
michael@0 492 .createInstance(Ci.nsIPartialFileInputStream);
michael@0 493 stream.init(file, start, length, PR_RDONLY, 0, flags || 0);
michael@0 494 return stream.QueryInterface(Ci.nsIInputStream);
michael@0 495 }
michael@0 496
michael@0 497 function create_temp_file(data) {
michael@0 498 let file = Cc["@mozilla.org/file/directory_service;1"].
michael@0 499 getService(Ci.nsIProperties).
michael@0 500 get("ProfD", Ci.nsIFile);
michael@0 501 file.append("fileinputstream-test-file.tmp");
michael@0 502 file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
michael@0 503
michael@0 504 let ostream = Cc["@mozilla.org/network/file-output-stream;1"].
michael@0 505 createInstance(Ci.nsIFileOutputStream);
michael@0 506 ostream.init(file, 0x02 | 0x08 | 0x20, // write, create, truncate
michael@0 507 0666, 0);
michael@0 508 do_check_eq(ostream.write(data, data.length), data.length);
michael@0 509 ostream.close();
michael@0 510
michael@0 511 return file;
michael@0 512 }

mercurial