tests/test_buffer.c

changeset 1110
a0e9be7ed131
parent 1030
06091e067bee
child 1112
22dc2163fffd
--- a/tests/test_buffer.c	Sun Jan 05 14:03:30 2025 +0100
+++ b/tests/test_buffer.c	Sun Jan 05 18:19:42 2025 +0100
@@ -31,14 +31,6 @@
 
 #include "cx/buffer.h"
 
-static CX_TEST_SUBROUTINE(expect_default_flush_config, CxBuffer *buf) {
-    CX_TEST_ASSERT(buf->flush_blkmax == 0);
-    CX_TEST_ASSERT(buf->flush_blksize == 4096);
-    CX_TEST_ASSERT(buf->flush_threshold == SIZE_MAX);
-    CX_TEST_ASSERT(buf->flush_func == NULL);
-    CX_TEST_ASSERT(buf->flush_target == NULL);
-}
-
 CX_TEST(test_buffer_init_wrap_space) {
     CxTestingAllocator talloc;
     cx_testing_allocator_init(&talloc);
@@ -47,7 +39,7 @@
         CxBuffer buf;
         void *space = cxMalloc(alloc, 16);
         cxBufferInit(&buf, space, 16, alloc, CX_BUFFER_DEFAULT);
-        CX_TEST_CALL_SUBROUTINE(expect_default_flush_config, &buf);
+        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);
@@ -71,7 +63,7 @@
         CxBuffer buf;
         void *space = cxMalloc(alloc, 16);
         cxBufferInit(&buf, space, 16, alloc, CX_BUFFER_AUTO_EXTEND);
-        CX_TEST_CALL_SUBROUTINE(expect_default_flush_config, &buf);
+        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);
@@ -95,7 +87,7 @@
         CxBuffer buf;
         void *space = cxMalloc(alloc, 16);
         cxBufferInit(&buf, space, 16, alloc, CX_BUFFER_FREE_CONTENTS);
-        CX_TEST_CALL_SUBROUTINE(expect_default_flush_config, &buf);
+        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);
@@ -117,7 +109,7 @@
     CX_TEST_DO {
         CxBuffer buf;
         cxBufferInit(&buf, NULL, 8, alloc, CX_BUFFER_DEFAULT);
-        CX_TEST_CALL_SUBROUTINE(expect_default_flush_config, &buf);
+        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);
@@ -141,7 +133,7 @@
         void *space = cxMalloc(alloc, 16);
         buf = cxBufferCreate(space, 16, alloc, CX_BUFFER_FREE_CONTENTS);
         CX_TEST_ASSERT(buf != NULL);
-        CX_TEST_CALL_SUBROUTINE(expect_default_flush_config, buf);
+        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);
@@ -642,15 +634,7 @@
         cx_attr_unused size_t nitems,
         CxBuffer *buffer
 ) {
-    // simulate limited target drain capacity
-    static bool full = false;
-    if (full) {
-        full = false;
-        return 0;
-    } else {
-        full = true;
-        return cxBufferWrite(ptr, size, nitems > 2 ? 2 : nitems, buffer);
-    }
+    return cxBufferWrite(ptr, size, nitems > 2 ? 2 : nitems, buffer);
 }
 
 CX_TEST(test_buffer_write_size_one_fit) {
@@ -1090,15 +1074,18 @@
 
 CX_TEST(test_buffer_write_flush_at_capacity) {
     CxBuffer buf, target;
-    cxBufferInit(&target, NULL, 16, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND);
-    cxBufferInit(&buf, NULL, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
-    memcpy(buf.space, "prep\0\0\0\0\0\0\0\0\0\0\0\0", 16);
-    buf.capacity = 8;
-    buf.size = buf.pos = 4;
-    buf.flush_target = ⌖
-    buf.flush_func = (cx_write_func)cxBufferWrite;
-    buf.flush_blkmax = 1;
+    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 = (cx_write_func)cxBufferWrite;
+        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);
@@ -1107,12 +1094,13 @@
         CX_TEST_ASSERT(target.size == 0);
         written = cxBufferWrite("hello", 1, 5, &buf);
         CX_TEST_ASSERT(written == 5);
-        CX_TEST_ASSERT(buf.pos == 0);
-        CX_TEST_ASSERT(buf.size == 0);
+        CX_TEST_ASSERT(buf.pos == 5);
+        CX_TEST_ASSERT(buf.size == 5);
         CX_TEST_ASSERT(buf.capacity == 8);
-        CX_TEST_ASSERT(target.pos == 12);
-        CX_TEST_ASSERT(target.size == 12);
-        CX_TEST_ASSERT(0 == memcmp(target.space, "prepfoohello", 12));
+        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);
@@ -1120,17 +1108,17 @@
 
 CX_TEST(test_buffer_write_flush_at_threshold) {
     CxBuffer buf, target;
-    cxBufferInit(&target, NULL, 16, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND);
-    cxBufferInit(&buf, NULL, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
-    memcpy(buf.space, "prep\0\0\0\0\0\0\0\0\0\0\0\0", 16);
-    buf.capacity = 8;
-    buf.size = buf.pos = 4;
-    buf.flush_target = ⌖
-    buf.flush_func = (cx_write_func)cxBufferWrite;
-    buf.flush_blkmax = 1;
-    buf.flush_threshold = 12;
-    buf.flags |= CX_BUFFER_AUTO_EXTEND;
+    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 = 12;
+        flush.blksize = 32;
+        flush.blkmax = 1;
+        flush.target = ⌖
+        flush.wfunc = (cx_write_func)cxBufferWrite;
+        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);
@@ -1141,31 +1129,35 @@
         CX_TEST_ASSERT(target.size == 0);
         written = cxBufferWrite("hello", 1, 5, &buf);
         CX_TEST_ASSERT(written == 5);
-        CX_TEST_ASSERT(buf.pos == 0);
-        CX_TEST_ASSERT(buf.size == 0);
+        CX_TEST_ASSERT(buf.pos == 5);
+        CX_TEST_ASSERT(buf.size == 5);
         CX_TEST_ASSERT(buf.capacity <= 12);
-        CX_TEST_ASSERT(target.pos == 15);
-        CX_TEST_ASSERT(target.size == 15);
-        CX_TEST_ASSERT(0 == memcmp(target.space, "prepfoobarhello", 15));
+        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) {
+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, 16, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND);
-    cxBufferInit(&buf, NULL, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
-    memcpy(buf.space, "prep\0\0\0\0\0\0\0\0\0\0\0\0", 16);
-    buf.capacity = 8;
-    buf.size = buf.pos = 4;
-    buf.flush_target = &target;
-    buf.flush_blkmax = 1;
-    // limit the rate of the flush function and the capacity of the target
-    buf.flush_func = (cx_write_func) mock_write_limited_rate;
-    target.capacity = 16;
-    target.flags &= ~CX_BUFFER_AUTO_EXTEND;
+    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 = &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);
@@ -1181,13 +1173,49 @@
         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 == 16);
+        CX_TEST_ASSERT(target.capacity >= 13);
         CX_TEST_ASSERT(0 == memcmp(target.space, "prepfoohello,", 13));
     }
     cxBufferDestroy(&buf);
     cxBufferDestroy(&target);
 }
 
+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 = &target;
+        flush.wfunc = (cx_write_func)cxBufferWrite;
+        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);
@@ -1348,7 +1376,8 @@
     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_rate_limited);
+    cx_test_register(suite, test_buffer_write_flush_rate_limited_and_buffer_too_small);
+    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