michael@0: /* Any copyright is dedicated to the Public Domain. michael@0: * http://creativecommons.org/publicdomain/zero/1.0/ */ michael@0: michael@0: "use strict"; michael@0: michael@0: Components.utils.import("resource://gre/modules/ctypes.jsm"); michael@0: Components.utils.import("resource://gre/modules/osfile.jsm"); michael@0: Components.utils.import("resource://gre/modules/Task.jsm"); michael@0: michael@0: /** michael@0: * A test to check that .getPosition/.setPosition work with large files. michael@0: * (see bug 952997) michael@0: */ michael@0: michael@0: // Test setPosition/getPosition. michael@0: function test_setPosition(forward, current, backward) { michael@0: let path = OS.Path.join(OS.Constants.Path.tmpDir, michael@0: "test_osfile_async_largefiles.tmp"); michael@0: michael@0: // Clear any left-over files from previous runs. michael@0: try { michael@0: yield OS.File.remove(path); michael@0: } catch (ex if ex.becauseNoSuchFile) { michael@0: // ignore michael@0: } michael@0: michael@0: try { michael@0: let file = yield OS.File.open(path, {write:true, append:false}); michael@0: try { michael@0: let pos = 0; michael@0: michael@0: // 1. seek forward from start michael@0: do_print("Moving forward: " + forward); michael@0: yield file.setPosition(forward, OS.File.POS_START); michael@0: pos += forward; michael@0: do_check_eq((yield file.getPosition()), pos); michael@0: michael@0: // 2. seek forward from current position michael@0: do_print("Moving current: " + current); michael@0: yield file.setPosition(current, OS.File.POS_CURRENT); michael@0: pos += current; michael@0: do_check_eq((yield file.getPosition()), pos); michael@0: michael@0: // 3. seek backward from current position michael@0: do_print("Moving current backward: " + backward); michael@0: yield file.setPosition(-backward, OS.File.POS_CURRENT); michael@0: pos -= backward; michael@0: do_check_eq((yield file.getPosition()), pos); michael@0: michael@0: } finally { michael@0: yield file.setPosition(0, OS.File.POS_START); michael@0: yield file.close(); michael@0: } michael@0: } catch(ex) { michael@0: try { michael@0: yield OS.File.remove(path); michael@0: } catch (ex if ex.becauseNoSuchFile) { michael@0: // ignore. michael@0: } michael@0: do_throw(ex); michael@0: } michael@0: } michael@0: michael@0: // Test setPosition/getPosition expected failures. michael@0: function test_setPosition_failures() { michael@0: let path = OS.Path.join(OS.Constants.Path.tmpDir, michael@0: "test_osfile_async_largefiles.tmp"); michael@0: michael@0: // Clear any left-over files from previous runs. michael@0: try { michael@0: yield OS.File.remove(path); michael@0: } catch (ex if ex.becauseNoSuchFile) { michael@0: // ignore michael@0: } michael@0: michael@0: try { michael@0: let file = yield OS.File.open(path, {write:true, append:false}); michael@0: try { michael@0: let pos = 0; michael@0: michael@0: // 1. Use an invalid position value michael@0: try { michael@0: yield file.setPosition(0.5, OS.File.POS_START); michael@0: do_throw("Shouldn't have succeeded"); michael@0: } catch (ex) { michael@0: do_check_true(ex.toString().contains("expected type")); michael@0: } michael@0: // Since setPosition should have bailed, it shouldn't have moved the michael@0: // file pointer at all. michael@0: do_check_eq((yield file.getPosition()), 0); michael@0: michael@0: // 2. Use an invalid position value michael@0: try { michael@0: yield file.setPosition(0xffffffff + 0.5, OS.File.POS_START); michael@0: do_throw("Shouldn't have succeeded"); michael@0: } catch (ex) { michael@0: do_check_true(ex.toString().contains("expected type")); michael@0: } michael@0: // Since setPosition should have bailed, it shouldn't have moved the michael@0: // file pointer at all. michael@0: do_check_eq((yield file.getPosition()), 0); michael@0: michael@0: // 3. Use a position that cannot be represented as a double michael@0: try { michael@0: // Not all numbers after 9007199254740992 can be represented as a michael@0: // double. E.g. in js 9007199254740992 + 1 == 9007199254740992 michael@0: yield file.setPosition(9007199254740992, OS.File.POS_START); michael@0: yield file.setPosition(1, OS.File.POS_CURRENT); michael@0: do_throw("Shouldn't have succeeded"); michael@0: } catch (ex) { michael@0: do_print(ex.toString()); michael@0: do_check_true(!!ex); michael@0: } michael@0: michael@0: } finally { michael@0: yield file.setPosition(0, OS.File.POS_START); michael@0: yield file.close(); michael@0: try { michael@0: yield OS.File.remove(path); michael@0: } catch (ex if ex.becauseNoSuchFile) { michael@0: // ignore. michael@0: } michael@0: } michael@0: } catch(ex) { michael@0: do_throw(ex); michael@0: } michael@0: } michael@0: michael@0: function run_test() { michael@0: // First verify stuff works for small values. michael@0: add_task(test_setPosition.bind(null, 0, 100, 50)); michael@0: add_task(test_setPosition.bind(null, 1000, 100, 50)); michael@0: add_task(test_setPosition.bind(null, 1000, -100, -50)); michael@0: michael@0: if (OS.Constants.Win || ctypes.off_t.size >= 8) { michael@0: // Now verify stuff still works for large values. michael@0: // 1. Multiple small seeks, which add up to > MAXINT32 michael@0: add_task(test_setPosition.bind(null, 0x7fffffff, 0x7fffffff, 0)); michael@0: // 2. Plain large seek, that should end up at 0 again. michael@0: // 0xffffffff also happens to be the INVALID_SET_FILE_POINTER value on michael@0: // Windows, so this also tests the error handling michael@0: add_task(test_setPosition.bind(null, 0, 0xffffffff, 0xffffffff)); michael@0: // 3. Multiple large seeks that should end up > MAXINT32. michael@0: add_task(test_setPosition.bind(null, 0xffffffff, 0xffffffff, 0xffffffff)); michael@0: // 5. Multiple large seeks with negative offsets. michael@0: add_task(test_setPosition.bind(null, 0xffffffff, -0x7fffffff, 0x7fffffff)); michael@0: michael@0: // 6. Check failures michael@0: add_task(test_setPosition_failures); michael@0: } michael@0: michael@0: run_next_test(); michael@0: }