tests/test_buffer.c

changeset 1571
25ead2ffb9b5
parent 1542
197450c2b0b3
--- 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);

mercurial