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); }
void TextTermStepper_read_key_frame(TextTermStepper *self, InStream *instream) { const uint32_t text_len = InStream_Read_C32(instream); CharBuf *value; char *ptr; // Allocate space. if (self->value == NULL) { self->value = (Obj*)CB_new(text_len); } value = (CharBuf*)self->value; ptr = CB_Grow(value, text_len); // Set the value text. InStream_Read_Bytes(instream, ptr, text_len); CB_Set_Size(value, text_len); if (!StrHelp_utf8_valid(ptr, text_len)) { THROW(ERR, "Invalid UTF-8 sequence in '%o' at byte %i64", InStream_Get_Filename(instream), InStream_Tell(instream) - text_len); } // Null-terminate. ptr[text_len] = '\0'; }
void TextTermStepper_Read_Delta_IMP(TextTermStepper *self, InStream *instream) { TextTermStepperIVARS *const ivars = TextTermStepper_IVARS(self); const uint32_t text_overlap = InStream_Read_C32(instream); const uint32_t finish_chars_len = InStream_Read_C32(instream); const uint32_t total_text_len = text_overlap + finish_chars_len; // Allocate space. CharBuf *charbuf = (CharBuf*)ivars->value; char *ptr = CB_Grow(charbuf, total_text_len); // Set the value text. InStream_Read_Bytes(instream, ptr + text_overlap, finish_chars_len); CB_Set_Size(charbuf, total_text_len); if (!StrHelp_utf8_valid(ptr, total_text_len)) { THROW(ERR, "Invalid UTF-8 sequence in '%o' at byte %i64", InStream_Get_Filename(instream), InStream_Tell(instream) - finish_chars_len); } // Null-terminate. ptr[total_text_len] = '\0'; // Invalidate string. DECREF(ivars->string); ivars->string = NULL; }
static void test_Clone_and_Reopen(TestBatchRunner *runner) { String *foo = SSTR_WRAP_C("foo"); String *bar = SSTR_WRAP_C("bar"); RAMFile *file = RAMFile_new(NULL, false); OutStream *outstream = OutStream_open((Obj*)file); RAMFileHandle *fh; InStream *instream; InStream *clone; InStream *reopened; for (uint8_t i = 0; i < 26; i++) { OutStream_Write_U8(outstream, 'a' + i); } OutStream_Close(outstream); fh = RAMFH_open(foo, FH_READ_ONLY, file); instream = InStream_open((Obj*)fh); InStream_Seek(instream, 1); TEST_TRUE(runner, Str_Equals(InStream_Get_Filename(instream), (Obj*)foo), "Get_Filename"); clone = InStream_Clone(instream); TEST_TRUE(runner, Str_Equals(InStream_Get_Filename(clone), (Obj*)foo), "Clones have same filename"); TEST_TRUE(runner, InStream_Length(instream) == InStream_Length(clone), "Clones have same length"); TEST_TRUE(runner, InStream_Read_U8(instream) == InStream_Read_U8(clone), "Clones start at same file position"); reopened = InStream_Reopen(instream, bar, 25, 1); TEST_TRUE(runner, Str_Equals(InStream_Get_Filename(reopened), (Obj*)bar), "Reopened InStreams take new filename"); TEST_TRUE(runner, InStream_Read_U8(reopened) == 'z', "Reopened stream starts at supplied offset"); TEST_TRUE(runner, InStream_Length(reopened) == 1, "Reopened stream uses supplied length"); TEST_TRUE(runner, InStream_Tell(reopened) == 1, "Tell() uses supplied offset for reopened stream"); InStream_Seek(reopened, 0); TEST_TRUE(runner, InStream_Read_U8(reopened) == 'z', "Seek() uses supplied offset for reopened stream"); DECREF(reopened); DECREF(clone); DECREF(instream); DECREF(outstream); DECREF(fh); DECREF(file); }
static void test_Buf(TestBatchRunner *runner) { RAMFile *file = RAMFile_new(NULL, false); OutStream *outstream = OutStream_open((Obj*)file); size_t size = IO_STREAM_BUF_SIZE * 2 + 5; InStream *instream; char *buf; for (uint32_t i = 0; i < size; i++) { OutStream_Write_U8(outstream, 'a'); } OutStream_Close(outstream); instream = InStream_open((Obj*)file); InStreamIVARS *const ivars = InStream_IVARS(instream); buf = InStream_Buf(instream, 5); TEST_INT_EQ(runner, ivars->limit - buf, IO_STREAM_BUF_SIZE, "Small request bumped up"); buf += IO_STREAM_BUF_SIZE - 10; // 10 bytes left in buffer. InStream_Advance_Buf(instream, buf); buf = InStream_Buf(instream, 10); TEST_INT_EQ(runner, ivars->limit - buf, 10, "Exact request doesn't trigger refill"); buf = InStream_Buf(instream, 11); TEST_INT_EQ(runner, ivars->limit - buf, IO_STREAM_BUF_SIZE, "Requesting over limit triggers refill"); int64_t expected = InStream_Length(instream) - InStream_Tell(instream); char *buff = InStream_Buf(instream, 100000); int64_t got = PTR_TO_I64(ivars->limit) - PTR_TO_I64(buff); TEST_TRUE(runner, got == expected, "Requests greater than file size get pared down"); DECREF(instream); DECREF(outstream); DECREF(file); }