static void test_Seek_and_Tell(TestBatchRunner *runner) { int64_t gb1 = INT64_C(0x40000000); int64_t gb3 = gb1 * 3; int64_t gb6 = gb1 * 6; int64_t gb12 = gb1 * 12; FileHandle *fh = (FileHandle*)MockFileHandle_new(NULL, gb12); InStream *instream = InStream_open((Obj*)fh); InStreamIVARS *const ivars = InStream_IVARS(instream); InStream_Buf(instream, 10000); TEST_TRUE(runner, ivars->limit == ((char*)NULL) + 10000, "InStream_Buf sets limit"); InStream_Seek(instream, gb6); TEST_TRUE(runner, InStream_Tell(instream) == gb6, "Tell after seek forwards outside buffer"); TEST_TRUE(runner, ivars->buf == NULL, "Seek forwards outside buffer sets buf to NULL"); TEST_TRUE(runner, ivars->limit == NULL, "Seek forwards outside buffer sets limit to NULL"); TEST_TRUE(runner, FileWindow_IVARS(ivars->window)->offset == gb6, "Seek forwards outside buffer tracks pos in window offset"); InStream_Buf(instream, (size_t)gb1); TEST_TRUE(runner, ivars->limit == ((char*)NULL) + gb1, "InStream_Buf sets limit"); InStream_Seek(instream, gb6 + 10); TEST_TRUE(runner, InStream_Tell(instream) == gb6 + 10, "Tell after seek forwards within buffer"); TEST_TRUE(runner, ivars->buf == ((char*)NULL) + 10, "Seek within buffer sets buf"); TEST_TRUE(runner, ivars->limit == ((char*)NULL) + gb1, "Seek within buffer leaves limit alone"); InStream_Seek(instream, gb6 + 1); TEST_TRUE(runner, InStream_Tell(instream) == gb6 + 1, "Tell after seek backwards within buffer"); TEST_TRUE(runner, ivars->buf == ((char*)NULL) + 1, "Seek backwards within buffer sets buf"); TEST_TRUE(runner, ivars->limit == ((char*)NULL) + gb1, "Seek backwards within buffer leaves limit alone"); InStream_Seek(instream, gb3); TEST_TRUE(runner, InStream_Tell(instream) == gb3, "Tell after seek backwards outside buffer"); TEST_TRUE(runner, ivars->buf == NULL, "Seek backwards outside buffer sets buf to NULL"); TEST_TRUE(runner, ivars->limit == NULL, "Seek backwards outside buffer sets limit to NULL"); TEST_TRUE(runner, FileWindow_IVARS(ivars->window)->offset == gb3, "Seek backwards outside buffer tracks pos in window offset"); DECREF(instream); DECREF(fh); }
static void test_refill(TestBatchRunner *runner) { RAMFile *file = RAMFile_new(NULL, false); OutStream *outstream = OutStream_open((Obj*)file); InStream *instream; char scratch[5]; InStreamIVARS *ivars; for (int32_t i = 0; i < 1023; i++) { OutStream_Write_U8(outstream, 'x'); } OutStream_Write_U8(outstream, 'y'); OutStream_Write_U8(outstream, 'z'); OutStream_Close(outstream); instream = InStream_open((Obj*)file); ivars = InStream_IVARS(instream); InStream_Refill(instream); TEST_INT_EQ(runner, ivars->limit - ivars->buf, IO_STREAM_BUF_SIZE, "Refill"); TEST_INT_EQ(runner, (long)InStream_Tell(instream), 0, "Correct file pos after standing-start Refill()"); DECREF(instream); instream = InStream_open((Obj*)file); ivars = InStream_IVARS(instream); InStream_Fill(instream, 30); TEST_INT_EQ(runner, ivars->limit - ivars->buf, 30, "Fill()"); TEST_INT_EQ(runner, (long)InStream_Tell(instream), 0, "Correct file pos after standing-start Fill()"); DECREF(instream); instream = InStream_open((Obj*)file); ivars = InStream_IVARS(instream); InStream_Read_Bytes(instream, scratch, 5); TEST_INT_EQ(runner, ivars->limit - ivars->buf, IO_STREAM_BUF_SIZE - 5, "small read triggers refill"); DECREF(instream); instream = InStream_open((Obj*)file); ivars = InStream_IVARS(instream); TEST_INT_EQ(runner, InStream_Read_U8(instream), 'x', "Read_U8"); InStream_Seek(instream, 1023); TEST_INT_EQ(runner, (long)FileWindow_IVARS(ivars->window)->offset, 0, "no unnecessary refill on Seek"); TEST_INT_EQ(runner, (long)InStream_Tell(instream), 1023, "Seek/Tell"); TEST_INT_EQ(runner, InStream_Read_U8(instream), 'y', "correct data after in-buffer Seek()"); TEST_INT_EQ(runner, InStream_Read_U8(instream), 'z', "automatic Refill"); TEST_TRUE(runner, (FileWindow_IVARS(ivars->window)->offset != 0), "refilled"); DECREF(instream); DECREF(outstream); DECREF(file); }
static void test_Window(TestBatchRunner *runner) { String *test_filename = (String*)SSTR_WRAP_UTF8("_fstest", 7); FSFileHandle *fh; FileWindow *window = FileWindow_new(); FileWindowIVARS *const window_ivars = FileWindow_IVARS(window); uint32_t i; remove(Str_Get_Ptr8(test_filename)); fh = FSFH_open(test_filename, FH_CREATE | FH_WRITE_ONLY | FH_EXCLUSIVE); for (i = 0; i < 1024; i++) { FSFH_Write(fh, "foo ", 4); } if (!FSFH_Close(fh)) { RETHROW(INCREF(Err_get_error())); } // Reopen for reading. DECREF(fh); fh = FSFH_open(test_filename, FH_READ_ONLY); if (!fh) { RETHROW(INCREF(Err_get_error())); } Err_set_error(NULL); TEST_FALSE(runner, FSFH_Window(fh, window, -1, 4), "Window() with a negative offset returns false"); TEST_TRUE(runner, Err_get_error() != NULL, "Window() with a negative offset sets error"); Err_set_error(NULL); TEST_FALSE(runner, FSFH_Window(fh, window, 4000, 1000), "Window() past EOF returns false"); TEST_TRUE(runner, Err_get_error() != NULL, "Window() past EOF sets error"); TEST_TRUE(runner, FSFH_Window(fh, window, 1021, 2), "Window() returns true"); TEST_TRUE(runner, strncmp(window_ivars->buf - window_ivars->offset + 1021, "oo", 2) == 0, "Window()"); TEST_TRUE(runner, FSFH_Release_Window(fh, window), "Release_Window() returns true"); TEST_TRUE(runner, window_ivars->buf == NULL, "Release_Window() resets buf"); TEST_TRUE(runner, window_ivars->offset == 0, "Release_Window() resets offset"); TEST_TRUE(runner, window_ivars->len == 0, "Release_Window() resets len"); DECREF(window); DECREF(fh); remove(Str_Get_Ptr8(test_filename)); }