--- a/tests/test_buffer.c Wed Dec 10 23:27:32 2025 +0100 +++ b/tests/test_buffer.c Thu Dec 11 17:08:17 2025 +0100 @@ -40,13 +40,13 @@ CxBuffer buf; void *space = cxMalloc(alloc, 16); cxBufferInit(&buf, space, 16, alloc, CX_BUFFER_DEFAULT); - CX_TEST_ASSERT(buf.flush == NULL); CX_TEST_ASSERT(buf.space == space); CX_TEST_ASSERT((buf.flags & CX_BUFFER_AUTO_EXTEND) == 0); CX_TEST_ASSERT((buf.flags & CX_BUFFER_FREE_CONTENTS) == 0); CX_TEST_ASSERT(buf.pos == 0); CX_TEST_ASSERT(buf.size == 0); CX_TEST_ASSERT(buf.capacity == 16); + CX_TEST_ASSERT(buf.max_capacity == SIZE_MAX); CX_TEST_ASSERT(buf.allocator == alloc); cxBufferDestroy(&buf); CX_TEST_ASSERT(!cx_testing_allocator_verify(&talloc)); @@ -64,13 +64,13 @@ CxBuffer buf; void *space = cxMalloc(alloc, 16); cxBufferInit(&buf, space, 16, alloc, CX_BUFFER_AUTO_EXTEND); - CX_TEST_ASSERT(buf.flush == NULL); CX_TEST_ASSERT(buf.space == space); CX_TEST_ASSERT((buf.flags & CX_BUFFER_AUTO_EXTEND) == CX_BUFFER_AUTO_EXTEND); CX_TEST_ASSERT((buf.flags & CX_BUFFER_FREE_CONTENTS) == 0); CX_TEST_ASSERT(buf.pos == 0); CX_TEST_ASSERT(buf.size == 0); CX_TEST_ASSERT(buf.capacity == 16); + CX_TEST_ASSERT(buf.max_capacity == SIZE_MAX); CX_TEST_ASSERT(buf.allocator == alloc); cxBufferDestroy(&buf); CX_TEST_ASSERT(!cx_testing_allocator_verify(&talloc)); @@ -88,13 +88,13 @@ CxBuffer buf; void *space = cxMalloc(alloc, 16); cxBufferInit(&buf, space, 16, alloc, CX_BUFFER_FREE_CONTENTS); - CX_TEST_ASSERT(buf.flush == NULL); CX_TEST_ASSERT(buf.space == space); CX_TEST_ASSERT((buf.flags & CX_BUFFER_AUTO_EXTEND) == 0); CX_TEST_ASSERT((buf.flags & CX_BUFFER_FREE_CONTENTS) == CX_BUFFER_FREE_CONTENTS); CX_TEST_ASSERT(buf.pos == 0); CX_TEST_ASSERT(buf.size == 0); CX_TEST_ASSERT(buf.capacity == 16); + CX_TEST_ASSERT(buf.max_capacity == SIZE_MAX); CX_TEST_ASSERT(buf.allocator == alloc); CX_TEST_ASSERT(!cx_testing_allocator_verify(&talloc)); cxBufferDestroy(&buf); @@ -110,13 +110,13 @@ CX_TEST_DO { CxBuffer buf; cxBufferInit(&buf, NULL, 8, alloc, CX_BUFFER_DEFAULT); - CX_TEST_ASSERT(buf.flush == NULL); CX_TEST_ASSERT(buf.space != NULL); CX_TEST_ASSERT((buf.flags & CX_BUFFER_AUTO_EXTEND) == 0); CX_TEST_ASSERT((buf.flags & CX_BUFFER_FREE_CONTENTS) == CX_BUFFER_FREE_CONTENTS); CX_TEST_ASSERT(buf.pos == 0); CX_TEST_ASSERT(buf.size == 0); CX_TEST_ASSERT(buf.capacity == 8); + CX_TEST_ASSERT(buf.max_capacity == SIZE_MAX); CX_TEST_ASSERT(buf.allocator == alloc); CX_TEST_ASSERT(!cx_testing_allocator_verify(&talloc)); // space is still allocated cxBufferDestroy(&buf); @@ -134,13 +134,13 @@ void *space = cxMalloc(alloc, 16); buf = cxBufferCreate(space, 16, alloc, CX_BUFFER_FREE_CONTENTS); CX_TEST_ASSERT(buf != NULL); - CX_TEST_ASSERT(buf->flush == NULL); CX_TEST_ASSERT(buf->space == space); CX_TEST_ASSERT((buf->flags & CX_BUFFER_AUTO_EXTEND) == 0); CX_TEST_ASSERT((buf->flags & CX_BUFFER_FREE_CONTENTS) == CX_BUFFER_FREE_CONTENTS); CX_TEST_ASSERT(buf->pos == 0); CX_TEST_ASSERT(buf->size == 0); CX_TEST_ASSERT(buf->capacity == 16); + CX_TEST_ASSERT(buf->max_capacity == SIZE_MAX); CX_TEST_ASSERT(buf->allocator == alloc); cxBufferFree(buf); CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc)); @@ -153,13 +153,13 @@ CxBuffer *buf; buf = cxBufferCreate(NULL, 16, NULL, 0); CX_TEST_ASSERT(buf != NULL); - CX_TEST_ASSERT(buf->flush == NULL); CX_TEST_ASSERT(buf->space != NULL); CX_TEST_ASSERT((buf->flags & CX_BUFFER_AUTO_EXTEND) == 0); CX_TEST_ASSERT((buf->flags & CX_BUFFER_FREE_CONTENTS) == CX_BUFFER_FREE_CONTENTS); CX_TEST_ASSERT(buf->pos == 0); CX_TEST_ASSERT(buf->size == 0); CX_TEST_ASSERT(buf->capacity == 16); + CX_TEST_ASSERT(buf->max_capacity == SIZE_MAX); CX_TEST_ASSERT(buf->allocator == cxDefaultAllocator); cxBufferFree(buf); } @@ -214,6 +214,44 @@ cx_testing_allocator_destroy(&talloc); } +CX_TEST(test_buffer_maximum_capacity) { + CxBuffer buf; + cxBufferInit(&buf, NULL, 256, NULL, CX_BUFFER_AUTO_EXTEND); + CX_TEST_DO { + // set maximum capacity + CX_TEST_ASSERT(0 == cxBufferMaximumCapacity(&buf, 512)); + CX_TEST_ASSERT(buf.capacity == 256); + CX_TEST_ASSERT(buf.max_capacity == 512); + // increase maximum capacity again + CX_TEST_ASSERT(0 == cxBufferMaximumCapacity(&buf, 1024)); + CX_TEST_ASSERT(buf.capacity == 256); + CX_TEST_ASSERT(buf.max_capacity == 1024); + // try to reduce maximum capacity below current capacity + CX_TEST_ASSERT(0 != cxBufferMaximumCapacity(&buf, 128)); + CX_TEST_ASSERT(buf.capacity == 256); + CX_TEST_ASSERT(buf.max_capacity == 1024); + + // try to reserve more than the maximum + CX_TEST_ASSERT(0 == cxBufferMaximumCapacity(&buf, 512)); + CX_TEST_ASSERT(0 != cxBufferReserve(&buf, 600)); + CX_TEST_ASSERT(buf.capacity == 256); + CX_TEST_ASSERT(buf.max_capacity == 512); + CX_TEST_ASSERT(0 == cxBufferReserve(&buf, 512)); + CX_TEST_ASSERT(buf.capacity == 512); + CX_TEST_ASSERT(buf.max_capacity == 512); + + // make sure that cxBufferMinimumCapacity() is capped at the limit + CX_TEST_ASSERT(0 == cxBufferMaximumCapacity(&buf, 777)); + CX_TEST_ASSERT(0 != cxBufferMinimumCapacity(&buf, 800)); + CX_TEST_ASSERT(buf.capacity == 512); + CX_TEST_ASSERT(buf.max_capacity == 777); + CX_TEST_ASSERT(0 == cxBufferMinimumCapacity(&buf, 700)); + CX_TEST_ASSERT(buf.capacity == 777); + CX_TEST_ASSERT(buf.max_capacity == 777); + } + cxBufferDestroy(&buf); +} + CX_TEST(test_buffer_shrink) { CxTestingAllocator talloc; cx_testing_allocator_init(&talloc); @@ -764,15 +802,6 @@ } } -static size_t mock_write_limited_rate( - const void *ptr, - size_t size, - cx_attr_unused size_t nitems, - CxBuffer *buffer -) { - return cxBufferWrite(ptr, size, nitems > 2 ? 2 : nitems, buffer); -} - CX_TEST(test_buffer_write_size_one_fit) { CxBuffer buf; cxBufferInit(&buf, NULL, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT); @@ -928,47 +957,6 @@ cxBufferDestroy(&buf); } -CX_TEST(test_buffer_append_flush) { - CxBuffer buf, target; - cxBufferInit(&buf, NULL, 8, cxDefaultAllocator, CX_BUFFER_DEFAULT); - cxBufferInit(&target, NULL, 8, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND); - memcpy(buf.space, "prepXXXX", 8); - buf.capacity = 8; - buf.size = 6; - buf.pos = 4; - CxBufferFlushConfig flush; - flush.threshold = 0; - flush.blksize = 4; - flush.blkmax = 1; - flush.target = ⌖ - flush.wfunc = cxBufferWriteFunc; - cxBufferEnableFlushing(&buf, flush); - CX_TEST_DO{ - size_t written = cxBufferAppend("testing", 1, 7, &buf); - CX_TEST_ASSERT(written == 7); - CX_TEST_ASSERT(buf.size == 7); - CX_TEST_ASSERTM(buf.pos == 0, "position not correctly reset"); - CX_TEST_ASSERT(buf.capacity == 8); - CX_TEST_ASSERT(target.size == 6); - CX_TEST_ASSERT(target.pos == 6); - CX_TEST_ASSERT(0 == memcmp(buf.space, "testing", 7)); - CX_TEST_ASSERT(0 == memcmp(target.space, "prepXX", 6)); - // second test - position only shifted by one block - buf.pos = 6; - written = cxBufferAppend("foo", 1, 3, &buf); - CX_TEST_ASSERT(written == 3); - CX_TEST_ASSERT(buf.size == 6); - CX_TEST_ASSERTM(buf.pos == 2, "position not correctly adjusted"); - CX_TEST_ASSERT(buf.capacity == 8); - CX_TEST_ASSERT(target.size == 10); - CX_TEST_ASSERT(target.pos == 10); - CX_TEST_ASSERT(0 == memcmp(buf.space, "ingfoo", 6)); - CX_TEST_ASSERT(0 == memcmp(target.space, "prepXXtest", 10)); - } - cxBufferDestroy(&buf); - cxBufferDestroy(&target); -} - CX_TEST(test_buffer_put_fit) { CxBuffer buf; cxBufferInit(&buf, NULL, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT); @@ -1230,6 +1218,36 @@ cxBufferDestroy(&buf); } +CX_TEST(test_buffer_write_maximum_capacity_exceeded) { + CxBuffer buf; + cxBufferInit(&buf, NULL, 8, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND); + CX_TEST_DO { + cxBufferMaximumCapacity(&buf, 30); + size_t written = cxBufferPutString(&buf, "Hello, World!\nHello, Tester!"); + CX_TEST_ASSERT(written == 28); + CX_TEST_ASSERT(buf.capacity == 30); // would be 32 without limit! + CX_TEST_ASSERT(buf.pos == 28); + CX_TEST_ASSERT(buf.size == 28); + cxBufferMaximumCapacity(&buf, 34); + written = cxBufferPutString(&buf, "blubberbla"); + CX_TEST_ASSERT(written == 6); + CX_TEST_ASSERT(buf.capacity == 34); + CX_TEST_ASSERT(buf.pos == 34); + CX_TEST_ASSERT(buf.size == 34); + CX_TEST_ASSERT(0 == memcmp(buf.space, "Hello, World!\nHello, Tester!blubbe", 34)); + + // test multi-byte as well + cxBufferMaximumCapacity(&buf, 44); + written = cxBufferWrite("1234abcdABCD", 4, 3, &buf); + CX_TEST_ASSERT(written == 2); + CX_TEST_ASSERT(buf.capacity == 44); + CX_TEST_ASSERT(buf.pos == 42); + CX_TEST_ASSERT(buf.size == 42); + CX_TEST_ASSERT(0 == memcmp(buf.space, "Hello, World!\nHello, Tester!blubbe1234abcd", 42)); + } + cxBufferDestroy(&buf); +} + CX_TEST(test_buffer_write_only_overwrite) { CxBuffer buf; cxBufferInit(&buf, NULL, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT); @@ -1249,373 +1267,6 @@ cxBufferDestroy(&buf); } -CX_TEST(test_buffer_write_flush_at_capacity) { - CxBuffer buf, target; - cxBufferInit(&target, NULL, 8, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND); - cxBufferInit(&buf, NULL, 8, cxDefaultAllocator, CX_BUFFER_DEFAULT); - memset(buf.space, 0, 8); - cxBufferPutString(&buf, "prep"); - CX_TEST_DO { - CxBufferFlushConfig flush; - flush.threshold = 0; - flush.blksize = 32; - flush.blkmax = 1; - flush.target = ⌖ - flush.wfunc = cxBufferWriteFunc; - CX_TEST_ASSERT(0 == cxBufferEnableFlushing(&buf, flush)); - size_t written = cxBufferWrite("foo", 1, 3, &buf); - CX_TEST_ASSERT(written == 3); - CX_TEST_ASSERT(buf.pos == 7); - CX_TEST_ASSERT(buf.size == 7); - CX_TEST_ASSERT(target.pos == 0); - CX_TEST_ASSERT(target.size == 0); - written = cxBufferWrite("hello", 1, 5, &buf); - CX_TEST_ASSERT(written == 5); - CX_TEST_ASSERT(buf.pos == 5); - CX_TEST_ASSERT(buf.size == 5); - CX_TEST_ASSERT(buf.capacity == 8); - CX_TEST_ASSERT(target.pos == 7); - CX_TEST_ASSERT(target.size == 7); - CX_TEST_ASSERT(0 == memcmp(buf.space, "hello", 5)); - CX_TEST_ASSERT(0 == memcmp(target.space, "prepfoo", 7)); - } - cxBufferDestroy(&buf); - cxBufferDestroy(&target); -} - -CX_TEST(test_buffer_write_flush_at_threshold) { - CxBuffer buf, target; - cxBufferInit(&target, NULL, 8, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND); - cxBufferInit(&buf, NULL, 8, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND); - cxBufferPutString(&buf, "prep"); - CX_TEST_DO { - CxBufferFlushConfig flush; - flush.threshold = 16; - flush.blksize = 32; - flush.blkmax = 1; - flush.target = ⌖ - flush.wfunc = cxBufferWriteFunc; - CX_TEST_ASSERT(0 == cxBufferEnableFlushing(&buf, flush)); - size_t written = cxBufferWrite("foobar", 1, 6, &buf); - CX_TEST_ASSERT(written == 6); - CX_TEST_ASSERT(buf.pos == 10); - CX_TEST_ASSERT(buf.size == 10); - CX_TEST_ASSERT(buf.capacity == 16); - CX_TEST_ASSERT(target.pos == 0); - CX_TEST_ASSERT(target.size == 0); - written = cxBufferWrite("hello world", 1, 11, &buf); - CX_TEST_ASSERT(written == 11); - CX_TEST_ASSERT(buf.pos == 11); - CX_TEST_ASSERT(buf.size == 11); - CX_TEST_ASSERT(buf.capacity == 16); - CX_TEST_ASSERT(target.pos == 10); - CX_TEST_ASSERT(target.size == 10); - CX_TEST_ASSERT(0 == memcmp(buf.space, "hello", 5)); - CX_TEST_ASSERT(0 == memcmp(target.space, "prepfoobar", 10)); - } - cxBufferDestroy(&buf); - cxBufferDestroy(&target); -} - -CX_TEST(test_buffer_write_flush_rate_limited_and_buffer_too_small) { - // the idea is that the target only accepts two bytes and - // then gives up... accepts another two bytes, gives up, etc. - // and at the same time, the written string is too large for - // the buffer (buffer can take 8, we want to write 13) - CxBuffer buf, target; - cxBufferInit(&target, NULL, 8, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND); - cxBufferInit(&buf, NULL, 8, cxDefaultAllocator, CX_BUFFER_DEFAULT); - cxBufferPutString(&buf, "prep"); - CX_TEST_DO { - CxBufferFlushConfig flush; - flush.threshold = 0; - flush.blksize = 32; - flush.blkmax = 1; - flush.target = ⌖ - flush.wfunc = (cx_write_func)mock_write_limited_rate; - CX_TEST_ASSERT(0 == cxBufferEnableFlushing(&buf, flush)); - size_t written = cxBufferWrite("foo", 1, 3, &buf); - CX_TEST_ASSERT(written == 3); - CX_TEST_ASSERT(buf.pos == 7); - CX_TEST_ASSERT(buf.size == 7); - CX_TEST_ASSERT(target.pos == 0); - CX_TEST_ASSERT(target.size == 0); - written = cxBufferWrite("hello, world!", 1, 13, &buf); - // " world!" fits into this buffer, the remaining stuff is flushed out - CX_TEST_ASSERT(written == 13); - CX_TEST_ASSERT(buf.pos == 7); - CX_TEST_ASSERT(buf.size == 7); - CX_TEST_ASSERT(buf.capacity == 8); - CX_TEST_ASSERT(0 == memcmp(buf.space, " world!", 7)); - CX_TEST_ASSERT(target.pos == 13); - CX_TEST_ASSERT(target.size == 13); - CX_TEST_ASSERT(target.capacity >= 13); - CX_TEST_ASSERT(0 == memcmp(target.space, "prepfoohello,", 13)); - } - cxBufferDestroy(&buf); - cxBufferDestroy(&target); -} - -CX_TEST(test_buffer_write_flush_multibyte) { - // this test case tests that flushing works correctly even when the - // contents in the buffer are currently not aligned with the item size - CxBuffer buf, target; - cxBufferInit(&target, NULL, 8, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND); - cxBufferInit(&buf, NULL, 8, cxDefaultAllocator, CX_BUFFER_DEFAULT); - memset(buf.space, 0, 8); - cxBufferPutString(&buf, "pre"); - CX_TEST_DO { - CxBufferFlushConfig flush; - flush.threshold = 0; - flush.blksize = 4; // test blksize that is not aligned - flush.blkmax = 2; // test with two blocks - flush.target = ⌖ - flush.wfunc = cxBufferWriteFunc; - CX_TEST_ASSERT(0 == cxBufferEnableFlushing(&buf, flush)); - // first case: string fits after flush - size_t written = cxBufferWrite("foobar", 3, 2, &buf); - CX_TEST_ASSERT(written == 2); - CX_TEST_ASSERT(buf.pos == 6); - CX_TEST_ASSERT(buf.size == 6); - CX_TEST_ASSERT(target.pos == 3); - CX_TEST_ASSERT(target.size == 3); - CX_TEST_ASSERT(0 == memcmp(buf.space, "foobar", 6)); - CX_TEST_ASSERT(0 == memcmp(target.space, "pre", 3)); - // second case: string does not fit, data is relayed, but only two blocks! - written = cxBufferWrite("bazfooBAR", 3, 3, &buf); - CX_TEST_ASSERT(written == 3); - CX_TEST_ASSERT(buf.pos == 3); - CX_TEST_ASSERT(buf.size == 3); - CX_TEST_ASSERT(target.pos == 15); - CX_TEST_ASSERT(target.size == 15); - CX_TEST_ASSERT(0 == memcmp(buf.space, "BAR", 3)); - CX_TEST_ASSERT(0 == memcmp(target.space, "prefoobarbazfoo", 15)); - // third case: everything can be relayed, block size is large enough - buf.flush->blkmax = 3; - written = cxBufferWrite("abcdef012", 3, 3, &buf); - CX_TEST_ASSERT(written == 3); - CX_TEST_ASSERT(buf.pos == 0); - CX_TEST_ASSERT(buf.size == 0); - CX_TEST_ASSERT(target.pos == 27); - CX_TEST_ASSERT(target.size == 27); - CX_TEST_ASSERT(0 == memcmp(target.space, "prefoobarbazfooBARabcdef012", 27)); - } - cxBufferDestroy(&buf); - cxBufferDestroy(&target); -} - -CX_TEST(test_buffer_write_flush_misaligned) { - // this test case tests that flushing works correctly even when the - // contents in the buffer are currently not aligned with the item size - CxBuffer buf, target; - cxBufferInit(&target, NULL, 8, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND); - cxBufferInit(&buf, NULL, 8, cxDefaultAllocator, CX_BUFFER_DEFAULT); - cxBufferPutString(&buf, "prep"); - CX_TEST_DO { - CxBufferFlushConfig flush; - flush.threshold = 0; - flush.blksize = 32; - flush.blkmax = 1; - flush.target = ⌖ - flush.wfunc = cxBufferWriteFunc; - CX_TEST_ASSERT(0 == cxBufferEnableFlushing(&buf, flush)); - // first case: string fits after flush - size_t written = cxBufferWrite("foobar", 3, 2, &buf); - CX_TEST_ASSERT(written == 2); - CX_TEST_ASSERT(buf.pos == 7); - CX_TEST_ASSERT(buf.size == 7); - CX_TEST_ASSERT(target.pos == 3); - CX_TEST_ASSERT(target.size == 3); - CX_TEST_ASSERT(0 == memcmp(buf.space, "pfoobar", 7)); - CX_TEST_ASSERT(0 == memcmp(target.space, "pre", 3)); - // second case: string does not fit, relaying not possible due to misalignment - // string will be truncated (two items fit into buffer, the third does not) - written = cxBufferWrite("bazfoobar", 3, 3, &buf); - CX_TEST_ASSERT(written == 2); - CX_TEST_ASSERT(buf.pos == 7); - CX_TEST_ASSERT(buf.size == 7); - CX_TEST_ASSERT(target.pos == 9); - CX_TEST_ASSERT(target.size == 9); - CX_TEST_ASSERT(0 == memcmp(buf.space, "rbazfoo", 7)); - CX_TEST_ASSERT(0 == memcmp(target.space, "prepfooba", 9)); - } - cxBufferDestroy(&buf); - cxBufferDestroy(&target); -} - -CX_TEST(test_buffer_write_flush_target_full) { - CxBuffer buf, target; - // target does NOT auto-extend and can get completely full - cxBufferInit(&target, NULL, 8, cxDefaultAllocator, CX_BUFFER_DEFAULT); - cxBufferInit(&buf, NULL, 8, cxDefaultAllocator, CX_BUFFER_DEFAULT); - cxBufferPutString(&buf, "prep"); - CX_TEST_DO { - CxBufferFlushConfig flush; - flush.threshold = 0; - flush.blksize = 32; - flush.blkmax = 1; - flush.target = ⌖ - flush.wfunc = cxBufferWriteFunc; - CX_TEST_ASSERT(0 == cxBufferEnableFlushing(&buf, flush)); - // step one - flush 4 existing bytes, write 6 new bytes - size_t written = cxBufferWrite("foobar", 1, 6, &buf); - CX_TEST_ASSERT(written == 6); - CX_TEST_ASSERT(buf.pos == 6); - CX_TEST_ASSERT(buf.size == 6); - CX_TEST_ASSERT(target.pos == 4); - CX_TEST_ASSERT(target.size == 4); - CX_TEST_ASSERT(0 == memcmp(buf.space, "foobar", 6)); - CX_TEST_ASSERT(0 == memcmp(target.space, "prep", 4)); - // step two - can only flush 4 more bytes, but rest fits into buffer - written = cxBufferWrite("xyz", 1, 3, &buf); - CX_TEST_ASSERT(written == 3); - CX_TEST_ASSERT(buf.pos == 5); - CX_TEST_ASSERT(buf.size == 5); - CX_TEST_ASSERT(target.pos == 8); - CX_TEST_ASSERT(target.size == 8); - CX_TEST_ASSERT(0 == memcmp(buf.space, "arxyz", 5)); - CX_TEST_ASSERT(0 == memcmp(target.space, "prepfoob", 8)); - // step three - cannot flush more, but can write 3 more bytes - written = cxBufferWrite("123456", 1, 6, &buf); - CX_TEST_ASSERT(written == 3); - CX_TEST_ASSERT(buf.pos == 8); - CX_TEST_ASSERT(buf.size == 8); - CX_TEST_ASSERT(target.pos == 8); - CX_TEST_ASSERT(target.size == 8); - CX_TEST_ASSERT(0 == memcmp(buf.space, "arxyz123", 8)); - CX_TEST_ASSERT(0 == memcmp(target.space, "prepfoob", 8)); - // final test - cannot write anything more - written = cxBufferWrite("baz", 1, 3, &buf); - CX_TEST_ASSERT(written == 0); - CX_TEST_ASSERT(buf.pos == 8); - CX_TEST_ASSERT(buf.size == 8); - CX_TEST_ASSERT(target.pos == 8); - CX_TEST_ASSERT(target.size == 8); - CX_TEST_ASSERT(0 == memcmp(buf.space, "arxyz123", 8)); - CX_TEST_ASSERT(0 == memcmp(target.space, "prepfoob", 8)); - } - cxBufferDestroy(&buf); - cxBufferDestroy(&target); -} - -CX_TEST(test_buffer_write_flush_multibyte_target_full) { - CxBuffer buf, target; - cxBufferInit(&target, NULL, 12, cxDefaultAllocator, CX_BUFFER_DEFAULT); - cxBufferInit(&buf, NULL, 8, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND); - CX_TEST_DO { - CxBufferFlushConfig flush; - flush.threshold = 12; - flush.blksize = 8; - flush.blkmax = 2; - flush.target = ⌖ - flush.wfunc = cxBufferWriteFunc; - CX_TEST_ASSERT(0 == cxBufferEnableFlushing(&buf, flush)); - cxBufferPutString(&buf, "preparation"); - size_t written = cxBufferWrite("teststring", 2, 5, &buf); - CX_TEST_ASSERT(written == 5); - CX_TEST_ASSERT(buf.pos == 11); - CX_TEST_ASSERT(buf.size == 11); - CX_TEST_ASSERT(target.pos == 10); - CX_TEST_ASSERT(target.size == 10); - CX_TEST_ASSERT(0 == memcmp(buf.space, "nteststring", 11)); - CX_TEST_ASSERT(0 == memcmp(target.space, "preparatio", 10)); - // pop the misaligned byte from the buffer - cxBufferPop(&buf, 1, 1); - // write three more items, but only one fits into the target and one more into the buffer - written = cxBufferWrite("123456", 2, 3, &buf); - CX_TEST_ASSERT(written == 2); - CX_TEST_ASSERT(buf.pos == 12); - CX_TEST_ASSERT(buf.size == 12); - CX_TEST_ASSERT(target.pos == 12); - CX_TEST_ASSERT(target.size == 12); - CX_TEST_ASSERT(0 == memcmp(buf.space, "eststrin1234", 12)); - CX_TEST_ASSERT(0 == memcmp(target.space, "preparationt", 12)); - } - cxBufferDestroy(&buf); - cxBufferDestroy(&target); -} - -CX_TEST(test_buffer_write_large_data_flush_target_full) { - CxBuffer buf, target; - cxBufferInit(&target, NULL, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT); - cxBufferInit(&buf, NULL, 8, cxDefaultAllocator, CX_BUFFER_DEFAULT); - // simulate that the target is full: - target.pos = target.size = 16; - CX_TEST_DO { - CxBufferFlushConfig flush; - flush.threshold = 0; - flush.blksize = 32; - flush.blkmax = 1; - flush.target = ⌖ - flush.wfunc = cxBufferWriteFunc; - CX_TEST_ASSERT(0 == cxBufferEnableFlushing(&buf, flush)); - // write more bytes than the buffer can take, but the target is full - size_t written = cxBufferWrite("foobarfoobar", 1, 12, &buf); - CX_TEST_ASSERT(written == 0); - CX_TEST_ASSERT(buf.pos == 0); - CX_TEST_ASSERT(buf.size == 0); - CX_TEST_ASSERT(target.pos == 16); - CX_TEST_ASSERT(target.size == 16); - } - cxBufferDestroy(&buf); - cxBufferDestroy(&target); -} - -CX_TEST(test_buffer_write_flush_at_threshold_target_full) { - CxBuffer buf, target; - // target does NOT auto-extend and can get completely full - cxBufferInit(&target, NULL, 8, cxDefaultAllocator, CX_BUFFER_DEFAULT); - // source may auto-extend but flushes at a certain threshold - cxBufferInit(&buf, NULL, 8, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND); - cxBufferPutString(&buf, "prep"); - CX_TEST_DO { - CxBufferFlushConfig flush; - flush.threshold = 16; - flush.blksize = 4; - flush.blkmax = 2; - flush.target = ⌖ - flush.wfunc = cxBufferWriteFunc; - CX_TEST_ASSERT(0 == cxBufferEnableFlushing(&buf, flush)); - // step one - adding 6 bytes does not exceed the threshold - size_t written = cxBufferWrite("foobar", 1, 6, &buf); - CX_TEST_ASSERT(written == 6); - CX_TEST_ASSERT(buf.pos == 10); - CX_TEST_ASSERT(buf.size == 10); - CX_TEST_ASSERT(target.pos == 0); - CX_TEST_ASSERT(target.size == 0); - CX_TEST_ASSERT(0 == memcmp(buf.space, "prepfoobar", 10)); - // step two - adding 8 bytes is two too many, two blocks are flushed - written = cxBufferWrite("12345678", 1, 8, &buf); - CX_TEST_ASSERT(written == 8); - CX_TEST_ASSERT(buf.pos == 10); - CX_TEST_ASSERT(buf.size == 10); - CX_TEST_ASSERT(target.pos == 8); - CX_TEST_ASSERT(target.size == 8); - CX_TEST_ASSERT(0 == memcmp(buf.space, "ar12345678", 10)); - CX_TEST_ASSERT(0 == memcmp(target.space, "prepfoob", 8)); - // step three - cannot flush more, but can write 6 more bytes - written = cxBufferWrite("ABCDEFGH", 1, 8, &buf); - CX_TEST_ASSERT(written == 6); - CX_TEST_ASSERT(buf.pos == 16); - CX_TEST_ASSERT(buf.size == 16); - CX_TEST_ASSERT(target.pos == 8); - CX_TEST_ASSERT(target.size == 8); - CX_TEST_ASSERT(0 == memcmp(buf.space, "ar12345678ABCDEF", 16)); - CX_TEST_ASSERT(0 == memcmp(target.space, "prepfoob", 8)); - // final test - cannot write anything more - written = cxBufferWrite("baz", 1, 3, &buf); - CX_TEST_ASSERT(written == 0); - CX_TEST_ASSERT(buf.pos == 16); - CX_TEST_ASSERT(buf.size == 16); - CX_TEST_ASSERT(target.pos == 8); - CX_TEST_ASSERT(target.size == 8); - CX_TEST_ASSERT(0 == memcmp(buf.space, "ar12345678ABCDEF", 16)); - CX_TEST_ASSERT(0 == memcmp(target.space, "prepfoob", 8)); - } - cxBufferDestroy(&buf); - cxBufferDestroy(&target); -} - CX_TEST(test_buffer_pop) { CxBuffer buf; cxBufferInit(&buf, NULL, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT); @@ -1652,42 +1303,6 @@ cxBufferDestroy(&buf); } -CX_TEST(test_buffer_flush) { - CxBuffer buf, target; - cxBufferInit(&target, NULL, 8, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND); - cxBufferInit(&buf, NULL, 8, cxDefaultAllocator, CX_BUFFER_DEFAULT); - cxBufferPutString(&buf, "prepare"); - CX_TEST_DO { - CxBufferFlushConfig flush; - flush.threshold = 0; - flush.blksize = 2; - flush.blkmax = 2; - flush.target = ⌖ - flush.wfunc = cxBufferWriteFunc; - CX_TEST_ASSERT(0 == cxBufferEnableFlushing(&buf, flush)); - CX_TEST_ASSERT(buf.size == 7); - buf.pos = 5; - size_t flushed = cxBufferFlush(&buf); - CX_TEST_ASSERT(flushed == flush.blkmax * flush.blksize); - CX_TEST_ASSERT(buf.pos == 1); - CX_TEST_ASSERT(buf.size == 3); - CX_TEST_ASSERT(target.pos == 4); - CX_TEST_ASSERT(target.size == 4); - CX_TEST_ASSERT(0 == memcmp(buf.space, "are", 3)); - CX_TEST_ASSERT(0 == memcmp(target.space, "prep", 4)); - flushed = cxBufferFlush(&buf); - CX_TEST_ASSERT(flushed == 1); - CX_TEST_ASSERT(buf.pos == 0); - CX_TEST_ASSERT(buf.size == 2); - CX_TEST_ASSERT(target.pos == 5); - CX_TEST_ASSERT(target.size == 5); - CX_TEST_ASSERT(0 == memcmp(buf.space, "re", 2)); - CX_TEST_ASSERT(0 == memcmp(target.space, "prepa", 5)); - } - cxBufferDestroy(&buf); - cxBufferDestroy(&target); -} - CX_TEST(test_buffer_get) { CxBuffer buf; cxBufferInit(&buf, NULL, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT); @@ -1801,6 +1416,7 @@ cx_test_register(suite, test_buffer_create_defaulted_allocator); cx_test_register(suite, test_buffer_minimum_capacity_sufficient); cx_test_register(suite, test_buffer_minimum_capacity_extend); + cx_test_register(suite, test_buffer_maximum_capacity); cx_test_register(suite, test_buffer_shrink); cx_test_register(suite, test_buffer_shrink_copy_on_write); cx_test_register(suite, test_buffer_shrink_copy_on_extend); @@ -1845,7 +1461,6 @@ cx_test_register(suite, test_buffer_write_multibyte_extend); cx_test_register(suite, test_buffer_write_copy_on_write); cx_test_register(suite, test_buffer_append); - cx_test_register(suite, test_buffer_append_flush); cx_test_register(suite, test_buffer_put_fit); cx_test_register(suite, test_buffer_put_discard); cx_test_register(suite, test_buffer_put_extend); @@ -1858,18 +1473,9 @@ cx_test_register(suite, test_buffer_terminate); cx_test_register(suite, test_buffer_write_size_overflow); cx_test_register(suite, test_buffer_write_capacity_overflow); + cx_test_register(suite, test_buffer_write_maximum_capacity_exceeded); cx_test_register(suite, test_buffer_write_only_overwrite); - cx_test_register(suite, test_buffer_write_flush_at_capacity); - cx_test_register(suite, test_buffer_write_flush_at_threshold); - cx_test_register(suite, test_buffer_write_flush_at_threshold_target_full); - cx_test_register(suite, test_buffer_write_flush_rate_limited_and_buffer_too_small); - cx_test_register(suite, test_buffer_write_flush_multibyte); - cx_test_register(suite, test_buffer_write_flush_misaligned); - cx_test_register(suite, test_buffer_write_flush_target_full); - cx_test_register(suite, test_buffer_write_flush_multibyte_target_full); - cx_test_register(suite, test_buffer_write_large_data_flush_target_full); cx_test_register(suite, test_buffer_pop); - cx_test_register(suite, test_buffer_flush); cx_test_register(suite, test_buffer_get); cx_test_register(suite, test_buffer_get_eof); cx_test_register(suite, test_buffer_read);