tests/test_buffer.cpp

Mon, 18 Dec 2023 15:13:26 +0100

author
Mike Becker <universe@uap-core.de>
date
Mon, 18 Dec 2023 15:13:26 +0100
changeset 761
61d5197d612b
parent 683
aa0d09f2d81c
child 789
9b2f5661bebd
permissions
-rw-r--r--

add cxBufferReset() - resolves #338

     1 /*
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3  *
     4  * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
     5  *
     6  * Redistribution and use in source and binary forms, with or without
     7  * modification, are permitted provided that the following conditions are met:
     8  *
     9  *   1. Redistributions of source code must retain the above copyright
    10  *      notice, this list of conditions and the following disclaimer.
    11  *
    12  *   2. Redistributions in binary form must reproduce the above copyright
    13  *      notice, this list of conditions and the following disclaimer in the
    14  *      documentation and/or other materials provided with the distribution.
    15  *
    16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    26  * POSSIBILITY OF SUCH DAMAGE.
    27  */
    29 #include "cx/buffer.h"
    31 #include <gtest/gtest.h>
    32 #include "util_allocator.h"
    34 class BufferFixture : public ::testing::Test {
    35 protected:
    36     void SetUp() override {
    37         cxBufferInit(&buf, nullptr, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
    38         buf.size = 6;
    39         buf.pos = 3;
    40     }
    42     void TearDown() override {
    43         cxBufferDestroy(&buf);
    44     }
    46     CxBuffer buf{};
    47 };
    49 static void expect_default_flush_config(CxBuffer *buf) {
    50     EXPECT_EQ(buf->flush_blkmax, 0);
    51     EXPECT_EQ(buf->flush_blksize, 4096);
    52     EXPECT_EQ(buf->flush_threshold, SIZE_MAX);
    53     EXPECT_EQ(buf->flush_func, nullptr);
    54     EXPECT_EQ(buf->flush_target, nullptr);
    55 }
    57 TEST(BufferInit, WrapSpace) {
    58     CxTestingAllocator alloc;
    59     CxBuffer buf;
    60     void *space = cxMalloc(&alloc, 16);
    61     cxBufferInit(&buf, space, 16, &alloc, CX_BUFFER_DEFAULT);
    62     expect_default_flush_config(&buf);
    63     EXPECT_EQ(buf.space, space);
    64     EXPECT_EQ(buf.flags & CX_BUFFER_AUTO_EXTEND, 0);
    65     EXPECT_EQ(buf.flags & CX_BUFFER_FREE_CONTENTS, 0);
    66     EXPECT_EQ(buf.pos, 0);
    67     EXPECT_EQ(buf.size, 0);
    68     EXPECT_EQ(buf.capacity, 16);
    69     EXPECT_EQ(buf.allocator, &alloc);
    70     cxBufferDestroy(&buf);
    71     EXPECT_FALSE(alloc.verify());
    72     cxFree(&alloc, space);
    73     EXPECT_TRUE(alloc.verify());
    74 }
    76 TEST(BufferInit, WrapSpaceAutoExtend) {
    77     CxTestingAllocator alloc;
    78     CxBuffer buf;
    79     void *space = cxMalloc(&alloc, 16);
    80     cxBufferInit(&buf, space, 16, &alloc, CX_BUFFER_AUTO_EXTEND);
    81     expect_default_flush_config(&buf);
    82     EXPECT_EQ(buf.space, space);
    83     EXPECT_EQ(buf.flags & CX_BUFFER_AUTO_EXTEND, CX_BUFFER_AUTO_EXTEND);
    84     EXPECT_EQ(buf.flags & CX_BUFFER_FREE_CONTENTS, 0);
    85     EXPECT_EQ(buf.pos, 0);
    86     EXPECT_EQ(buf.size, 0);
    87     EXPECT_EQ(buf.capacity, 16);
    88     EXPECT_EQ(buf.allocator, &alloc);
    89     cxBufferDestroy(&buf);
    90     EXPECT_FALSE(alloc.verify());
    91     cxFree(&alloc, space);
    92     EXPECT_TRUE(alloc.verify());
    93 }
    95 TEST(BufferInit, WrapSpaceAutoFree) {
    96     CxTestingAllocator alloc;
    97     CxBuffer buf;
    98     void *space = cxMalloc(&alloc, 16);
    99     cxBufferInit(&buf, space, 16, &alloc, CX_BUFFER_FREE_CONTENTS);
   100     expect_default_flush_config(&buf);
   101     EXPECT_EQ(buf.space, space);
   102     EXPECT_EQ(buf.flags & CX_BUFFER_AUTO_EXTEND, 0);
   103     EXPECT_EQ(buf.flags & CX_BUFFER_FREE_CONTENTS, CX_BUFFER_FREE_CONTENTS);
   104     EXPECT_EQ(buf.pos, 0);
   105     EXPECT_EQ(buf.size, 0);
   106     EXPECT_EQ(buf.capacity, 16);
   107     EXPECT_EQ(buf.allocator, &alloc);
   108     EXPECT_FALSE(alloc.verify());
   109     cxBufferDestroy(&buf);
   110     EXPECT_TRUE(alloc.verify());
   111 }
   113 TEST(BufferInit, FreshSpace) {
   114     CxTestingAllocator alloc;
   115     CxBuffer buf;
   116     cxBufferInit(&buf, nullptr, 8, &alloc, CX_BUFFER_DEFAULT);
   117     expect_default_flush_config(&buf);
   118     EXPECT_NE(buf.space, nullptr);
   119     EXPECT_EQ(buf.flags & CX_BUFFER_AUTO_EXTEND, 0);
   120     EXPECT_EQ(buf.flags & CX_BUFFER_FREE_CONTENTS, CX_BUFFER_FREE_CONTENTS);
   121     EXPECT_EQ(buf.pos, 0);
   122     EXPECT_EQ(buf.size, 0);
   123     EXPECT_EQ(buf.capacity, 8);
   124     EXPECT_EQ(buf.allocator, &alloc);
   125     EXPECT_FALSE(alloc.verify()); // space is still allocated
   126     cxBufferDestroy(&buf);
   127     EXPECT_TRUE(alloc.verify());
   128 }
   130 TEST(BufferInit, OnHeap) {
   131     CxTestingAllocator alloc;
   132     CxBuffer *buf;
   133     void *space = cxMalloc(&alloc, 16);
   134     buf = cxBufferCreate(space, 16, &alloc, CX_BUFFER_FREE_CONTENTS);
   135     EXPECT_NE(buf, nullptr);
   136     expect_default_flush_config(buf);
   137     EXPECT_EQ(buf->space, space);
   138     EXPECT_EQ(buf->flags & CX_BUFFER_AUTO_EXTEND, 0);
   139     EXPECT_EQ(buf->flags & CX_BUFFER_FREE_CONTENTS, CX_BUFFER_FREE_CONTENTS);
   140     EXPECT_EQ(buf->pos, 0);
   141     EXPECT_EQ(buf->size, 0);
   142     EXPECT_EQ(buf->capacity, 16);
   143     EXPECT_EQ(buf->allocator, &alloc);
   144     cxBufferFree(buf);
   145     EXPECT_TRUE(alloc.verify());
   146 }
   148 class BufferShiftFixture : public ::testing::Test {
   149 protected:
   150     void SetUp() override {
   151         ASSERT_TRUE(alloc.verify());
   152         cxBufferInit(&buf, nullptr, 16, &alloc, CX_BUFFER_DEFAULT);
   153         memcpy(buf.space, "test____________", 16);
   154         buf.capacity = 8; // purposely pretend that the buffer has less capacity s.t. we can test beyond the range
   155         buf.pos = 4;
   156         buf.size = 4;
   157     }
   159     void TearDown() override {
   160         cxBufferDestroy(&buf);
   161         EXPECT_TRUE(alloc.verify());
   162     }
   164     CxTestingAllocator alloc;
   165     CxBuffer buf{};
   166 };
   168 class BufferShiftLeft : public BufferShiftFixture {
   169 };
   171 TEST_F(BufferShiftLeft, Zero) {
   172     ASSERT_EQ(buf.pos, 4);
   173     ASSERT_EQ(buf.size, 4);
   174     int ret = cxBufferShiftLeft(&buf, 0);
   175     EXPECT_EQ(ret, 0);
   176     EXPECT_EQ(buf.pos, 4);
   177     EXPECT_EQ(buf.size, 4);
   178     EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
   179 }
   181 TEST_F(BufferShiftLeft, ZeroOffsetInterface) {
   182     ASSERT_EQ(buf.pos, 4);
   183     ASSERT_EQ(buf.size, 4);
   184     int ret = cxBufferShift(&buf, -0);
   185     EXPECT_EQ(ret, 0);
   186     EXPECT_EQ(buf.pos, 4);
   187     EXPECT_EQ(buf.size, 4);
   188     EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
   189 }
   191 TEST_F(BufferShiftLeft, Standard) {
   192     ASSERT_EQ(buf.pos, 4);
   193     ASSERT_EQ(buf.size, 4);
   194     int ret = cxBufferShiftLeft(&buf, 2);
   195     EXPECT_EQ(ret, 0);
   196     EXPECT_EQ(buf.pos, 2);
   197     EXPECT_EQ(buf.size, 2);
   198     EXPECT_TRUE(memcmp(buf.space, "stst________", 8) == 0);
   199 }
   201 TEST_F(BufferShiftLeft, Overshift) {
   202     ASSERT_LT(buf.pos, 6);
   203     ASSERT_LT(buf.size, 6);
   204     int ret = cxBufferShiftLeft(&buf, 6);
   205     EXPECT_EQ(ret, 0);
   206     EXPECT_EQ(buf.pos, 0);
   207     EXPECT_EQ(buf.size, 0);
   208     EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
   209 }
   211 TEST_F(BufferShiftLeft, OvershiftPosOnly) {
   212     buf.pos = 2;
   213     ASSERT_EQ(buf.size, 4);
   214     int ret = cxBufferShiftLeft(&buf, 3);
   215     EXPECT_EQ(ret, 0);
   216     EXPECT_EQ(buf.pos, 0);
   217     EXPECT_EQ(buf.size, 1);
   218     EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
   219 }
   221 TEST_F(BufferShiftLeft, OffsetInterface) {
   222     buf.pos = 3;
   223     ASSERT_EQ(buf.size, 4);
   224     int ret = cxBufferShift(&buf, -2);
   225     EXPECT_EQ(ret, 0);
   226     EXPECT_EQ(buf.pos, 1);
   227     EXPECT_EQ(buf.size, 2);
   228     EXPECT_TRUE(memcmp(buf.space, "stst________", 8) == 0);
   229 }
   231 class BufferShiftRight : public BufferShiftFixture {
   232 };
   234 TEST_F(BufferShiftRight, Zero) {
   235     ASSERT_EQ(buf.pos, 4);
   236     ASSERT_EQ(buf.size, 4);
   237     int ret = cxBufferShiftRight(&buf, 0);
   238     EXPECT_EQ(ret, 0);
   239     EXPECT_EQ(buf.pos, 4);
   240     EXPECT_EQ(buf.size, 4);
   241     EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
   242 }
   244 TEST_F(BufferShiftRight, ZeroOffsetInterface) {
   245     ASSERT_EQ(buf.pos, 4);
   246     ASSERT_EQ(buf.size, 4);
   247     int ret = cxBufferShift(&buf, +0);
   248     EXPECT_EQ(ret, 0);
   249     EXPECT_EQ(buf.pos, 4);
   250     EXPECT_EQ(buf.size, 4);
   251     EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
   252 }
   254 TEST_F(BufferShiftRight, Standard) {
   255     ASSERT_EQ(buf.pos, 4);
   256     ASSERT_EQ(buf.size, 4);
   257     int ret = cxBufferShiftRight(&buf, 3);
   258     EXPECT_EQ(ret, 0);
   259     EXPECT_EQ(buf.pos, 7);
   260     EXPECT_EQ(buf.size, 7);
   261     EXPECT_TRUE(memcmp(buf.space, "testest_____", 8) == 0);
   262 }
   264 TEST_F(BufferShiftRight, OvershiftDiscard) {
   265     ASSERT_EQ(buf.pos, 4);
   266     ASSERT_EQ(buf.size, 4);
   267     ASSERT_EQ(buf.capacity, 8);
   268     int ret = cxBufferShiftRight(&buf, 6);
   269     EXPECT_EQ(ret, 0);
   270     EXPECT_EQ(buf.pos, 8);
   271     EXPECT_EQ(buf.size, 8);
   272     EXPECT_EQ(buf.capacity, 8);
   273     EXPECT_TRUE(memcmp(buf.space, "test__te____", 8) == 0);
   274 }
   276 TEST_F(BufferShiftRight, OvershiftExtend) {
   277     ASSERT_EQ(buf.pos, 4);
   278     ASSERT_EQ(buf.size, 4);
   279     ASSERT_EQ(buf.capacity, 8);
   280     buf.flags |= CX_BUFFER_AUTO_EXTEND;
   281     int ret = cxBufferShiftRight(&buf, 6);
   282     EXPECT_EQ(ret, 0);
   283     EXPECT_EQ(buf.pos, 10);
   284     EXPECT_EQ(buf.size, 10);
   285     EXPECT_GE(buf.capacity, 10);
   286     EXPECT_TRUE(memcmp(buf.space, "test__test__", 8) == 0);
   287 }
   289 TEST_F(BufferShiftRight, OffsetInterface) {
   290     buf.pos = 3;
   291     ASSERT_EQ(buf.size, 4);
   292     int ret = cxBufferShift(&buf, 2);
   293     EXPECT_EQ(ret, 0);
   294     EXPECT_EQ(buf.pos, 5);
   295     EXPECT_EQ(buf.size, 6);
   296     EXPECT_TRUE(memcmp(buf.space, "tetest______", 8) == 0);
   297 }
   299 TEST(BufferMinimumCapacity, Sufficient) {
   300     CxTestingAllocator alloc;
   301     auto space = cxMalloc(&alloc, 8);
   302     CxBuffer buf;
   303     cxBufferInit(&buf, space, 8, &alloc, CX_BUFFER_FREE_CONTENTS);
   304     memcpy(space, "Testing", 8);
   305     buf.size = 8;
   306     cxBufferMinimumCapacity(&buf, 6);
   307     EXPECT_EQ(buf.capacity, 8);
   308     EXPECT_EQ(buf.size, 8);
   309     EXPECT_TRUE(memcmp(buf.space, "Testing", 8) == 0);
   310     cxBufferDestroy(&buf);
   311     EXPECT_TRUE(alloc.verify());
   312 }
   314 TEST(BufferMinimumCapacity, Extend) {
   315     CxTestingAllocator alloc;
   316     auto space = cxMalloc(&alloc, 8);
   317     CxBuffer buf;
   318     cxBufferInit(&buf, space, 8, &alloc, CX_BUFFER_FREE_CONTENTS); // NO auto extend!
   319     memcpy(space, "Testing", 8);
   320     buf.size = 8;
   321     cxBufferMinimumCapacity(&buf, 16);
   322     EXPECT_EQ(buf.capacity, 16);
   323     EXPECT_EQ(buf.size, 8);
   324     EXPECT_TRUE(memcmp(buf.space, "Testing", 8) == 0);
   325     cxBufferDestroy(&buf);
   326     EXPECT_TRUE(alloc.verify());
   327 }
   329 TEST(BufferClear, Test) {
   330     char space[16];
   331     strcpy(space, "clear test");
   332     CxBuffer buf;
   333     cxBufferInit(&buf, space, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
   334     ASSERT_EQ(buf.size, 0);
   335     // only clear the used part of the buffer
   336     cxBufferClear(&buf);
   337     EXPECT_EQ(memcmp(space, "clear test", 10), 0);
   338     buf.size = 5;
   339     buf.pos = 3;
   340     cxBufferClear(&buf);
   341     EXPECT_EQ(memcmp(space, "\0\0\0\0\0 test", 10), 0);
   342     EXPECT_EQ(buf.size, 0);
   343     EXPECT_EQ(buf.pos, 0);
   344     cxBufferDestroy(&buf);
   345 }
   347 TEST(BufferReset, Test) {
   348     char space[16];
   349     strcpy(space, "reset test");
   350     CxBuffer buf;
   351     cxBufferInit(&buf, space, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
   352     buf.size = 5;
   353     buf.pos = 3;
   354     cxBufferReset(&buf);
   355     EXPECT_EQ(memcmp(space, "reset test", 10), 0);
   356     EXPECT_EQ(buf.size, 0);
   357     EXPECT_EQ(buf.pos, 0);
   358     cxBufferDestroy(&buf);
   359 }
   361 class BufferWrite : public ::testing::Test {
   362 protected:
   363     CxBuffer buf{}, target{};
   365     void SetUp() override {
   366         cxBufferInit(&target, nullptr, 16, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND);
   367         cxBufferInit(&buf, nullptr, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
   368         buf.capacity = 8; // artificially reduce capacity to check OOB writes
   369         memset(buf.space, 0, 16);
   370         memcpy(buf.space, "prep", 4);
   371         buf.size = buf.pos = 4;
   372     }
   374     void TearDown() override {
   375         cxBufferDestroy(&buf);
   376         cxBufferDestroy(&target);
   377     }
   379     void enableFlushing() {
   380         buf.flush_target = &target;
   381         buf.flush_func = reinterpret_cast<cx_write_func>(cxBufferWrite);
   382         buf.flush_blkmax = 1;
   383     }
   384 };
   386 static size_t mock_write_limited_rate(
   387         void const *ptr,
   388         size_t size,
   389         __attribute__((unused)) size_t nitems,
   390         CxBuffer *buffer
   391 ) {
   392     // simulate limited target drain capacity
   393     static bool full = false;
   394     if (full) {
   395         full = false;
   396         return 0;
   397     } else {
   398         full = true;
   399         return cxBufferWrite(ptr, size, nitems > 2 ? 2 : nitems, buffer);
   400     }
   401 }
   403 TEST_F(BufferWrite, SizeOneFit) {
   404     const char *data = "test";
   405     ASSERT_EQ(buf.capacity, 8);
   406     ASSERT_EQ(buf.pos, 4);
   407     ASSERT_EQ(buf.size, 4);
   408     size_t written = cxBufferWrite(data, 1, 4, &buf);
   409     EXPECT_EQ(written, 4);
   410     EXPECT_EQ(buf.size, 8);
   411     EXPECT_EQ(buf.pos, 8);
   412     EXPECT_EQ(buf.capacity, 8);
   413     EXPECT_EQ(memcmp(buf.space, "preptest", 8), 0);
   414 }
   416 TEST_F(BufferWrite, SizeOneDiscard) {
   417     const char *data = "testing";
   418     ASSERT_EQ(buf.capacity, 8);
   419     ASSERT_EQ(buf.pos, 4);
   420     ASSERT_EQ(buf.size, 4);
   421     size_t written = cxBufferWrite(data, 1, 7, &buf);
   422     EXPECT_EQ(written, 4);
   423     EXPECT_EQ(buf.size, 8);
   424     EXPECT_EQ(buf.pos, 8);
   425     EXPECT_EQ(buf.capacity, 8);
   426     EXPECT_EQ(memcmp(buf.space, "preptest\0", 9), 0);
   427 }
   429 TEST_F(BufferWrite, SizeOneExtend) {
   430     buf.flags |= CX_BUFFER_AUTO_EXTEND;
   431     const char *data = "testing";
   432     ASSERT_EQ(buf.capacity, 8);
   433     ASSERT_EQ(buf.pos, 4);
   434     ASSERT_EQ(buf.size, 4);
   435     size_t written = cxBufferWrite(data, 1, 7, &buf);
   436     EXPECT_EQ(written, 7);
   437     EXPECT_EQ(buf.size, 11);
   438     EXPECT_EQ(buf.pos, 11);
   439     EXPECT_GE(buf.capacity, 11);
   440     EXPECT_EQ(memcmp(buf.space, "preptesting", 11), 0);
   441 }
   443 TEST_F(BufferWrite, MultibyteFit) {
   444     const char *data = "test";
   445     ASSERT_EQ(buf.capacity, 8);
   446     ASSERT_EQ(buf.pos, 4);
   447     ASSERT_EQ(buf.size, 4);
   448     size_t written = cxBufferWrite(data, 2, 2, &buf);
   449     EXPECT_EQ(written, 2);
   450     EXPECT_EQ(buf.size, 8);
   451     EXPECT_EQ(buf.pos, 8);
   452     EXPECT_EQ(buf.capacity, 8);
   453     EXPECT_EQ(memcmp(buf.space, "preptest", 8), 0);
   454 }
   456 TEST_F(BufferWrite, MultibyteDiscard) {
   457     const char *data = "testing";
   458     ASSERT_EQ(buf.capacity, 8);
   459     ASSERT_EQ(buf.size, 4);
   460     buf.pos = 3;
   461     size_t written = cxBufferWrite(data, 2, 4, &buf);
   462     // remember: whole elements are discarded if they do not fit
   463     EXPECT_EQ(written, 2);
   464     EXPECT_EQ(buf.size, 7);
   465     EXPECT_EQ(buf.pos, 7);
   466     EXPECT_EQ(buf.capacity, 8);
   467     EXPECT_EQ(memcmp(buf.space, "pretest\0", 8), 0);
   468 }
   470 TEST_F(BufferWrite, MultibyteExtend) {
   471     buf.flags |= CX_BUFFER_AUTO_EXTEND;
   472     const char *data = "tester";
   473     ASSERT_EQ(buf.capacity, 8);
   474     ASSERT_EQ(buf.size, 4);
   475     buf.pos = 3;
   476     size_t written = cxBufferWrite(data, 2, 3, &buf);
   477     // remember: whole elements are discarded if they do not fit
   478     EXPECT_EQ(written, 3);
   479     EXPECT_EQ(buf.size, 9);
   480     EXPECT_EQ(buf.pos, 9);
   481     EXPECT_GE(buf.capacity, 9);
   482     EXPECT_EQ(memcmp(buf.space, "pretester", 9), 0);
   483 }
   485 TEST_F(BufferWrite, PutcWrapperFit) {
   486     ASSERT_EQ(buf.capacity, 8);
   487     ASSERT_EQ(buf.pos, 4);
   488     ASSERT_EQ(buf.size, 4);
   489     int c = cxBufferPut(&buf, 0x200 | 'a');
   490     EXPECT_EQ(c, 'a');
   491     EXPECT_EQ(buf.size, 5);
   492     EXPECT_EQ(buf.pos, 5);
   493     EXPECT_EQ(buf.capacity, 8);
   494     EXPECT_EQ(memcmp(buf.space, "prepa\0", 6), 0);
   495 }
   497 TEST_F(BufferWrite, PutcWrapperDiscard) {
   498     ASSERT_EQ(buf.capacity, 8);
   499     ASSERT_EQ(buf.size, 4);
   500     buf.pos = 8;
   501     int c = cxBufferPut(&buf, 0x200 | 'a');
   502     EXPECT_EQ(c, EOF);
   503     EXPECT_EQ(buf.size, 4);
   504     EXPECT_EQ(buf.pos, 8);
   505     EXPECT_EQ(buf.capacity, 8);
   506     EXPECT_EQ(memcmp(buf.space, "prep\0\0\0\0\0", 9), 0);
   507 }
   509 TEST_F(BufferWrite, PutcWrapperExtend) {
   510     buf.flags |= CX_BUFFER_AUTO_EXTEND;
   511     ASSERT_EQ(buf.capacity, 8);
   512     ASSERT_EQ(buf.size, 4);
   513     buf.pos = 8;
   514     int c = cxBufferPut(&buf, 0x200 | 'a');
   515     EXPECT_EQ(c, 'a');
   516     EXPECT_EQ(buf.size, 9);
   517     EXPECT_EQ(buf.pos, 9);
   518     EXPECT_GE(buf.capacity, 9);
   519     EXPECT_EQ(memcmp(buf.space, "prep\0\0\0\0a", 9), 0);
   520 }
   522 TEST_F(BufferWrite, PutStringWrapperFit) {
   523     const char *data = "test";
   524     ASSERT_EQ(buf.capacity, 8);
   525     ASSERT_EQ(buf.pos, 4);
   526     ASSERT_EQ(buf.size, 4);
   527     size_t written = cxBufferPutString(&buf, data);
   528     EXPECT_EQ(written, 4);
   529     EXPECT_EQ(buf.size, 8);
   530     EXPECT_EQ(buf.pos, 8);
   531     EXPECT_EQ(buf.capacity, 8);
   532     EXPECT_EQ(memcmp(buf.space, "preptest", 8), 0);
   533 }
   535 TEST_F(BufferWrite, PutStringWrapperDiscard) {
   536     const char *data = "testing";
   537     ASSERT_EQ(buf.capacity, 8);
   538     ASSERT_EQ(buf.pos, 4);
   539     ASSERT_EQ(buf.size, 4);
   540     size_t written = cxBufferPutString(&buf, data);
   541     EXPECT_EQ(written, 4);
   542     EXPECT_EQ(buf.size, 8);
   543     EXPECT_EQ(buf.pos, 8);
   544     EXPECT_EQ(buf.capacity, 8);
   545     EXPECT_EQ(memcmp(buf.space, "preptest\0", 9), 0);
   546 }
   548 TEST_F(BufferWrite, PutStringWrapperExtend) {
   549     buf.flags |= CX_BUFFER_AUTO_EXTEND;
   550     const char *data = "testing";
   551     ASSERT_EQ(buf.capacity, 8);
   552     ASSERT_EQ(buf.pos, 4);
   553     ASSERT_EQ(buf.size, 4);
   554     size_t written = cxBufferPutString(&buf, data);
   555     EXPECT_EQ(written, 7);
   556     EXPECT_EQ(buf.size, 11);
   557     EXPECT_EQ(buf.pos, 11);
   558     EXPECT_GE(buf.capacity, 11);
   559     EXPECT_EQ(memcmp(buf.space, "preptesting", 11), 0);
   560 }
   562 TEST_F(BufferWrite, MultOverflow) {
   563     const char *data = "testing";
   564     ASSERT_EQ(buf.capacity, 8);
   565     ASSERT_EQ(buf.pos, 4);
   566     ASSERT_EQ(buf.size, 4);
   567     size_t written = cxBufferWrite(data, 8, SIZE_MAX / 4, &buf);
   568     EXPECT_EQ(written, 0);
   569     EXPECT_EQ(buf.capacity, 8);
   570     EXPECT_EQ(buf.pos, 4);
   571     EXPECT_EQ(buf.size, 4);
   572     EXPECT_EQ(memcmp(buf.space, "prep\0", 5), 0);
   573 }
   575 TEST_F(BufferWrite, MaxCapaOverflow) {
   576     buf.flags |= CX_BUFFER_AUTO_EXTEND;
   577     const char *data = "testing";
   578     ASSERT_EQ(buf.capacity, 8);
   579     ASSERT_EQ(buf.pos, 4);
   580     ASSERT_EQ(buf.size, 4);
   581     size_t written = cxBufferWrite(data, 1, SIZE_MAX - 2, &buf);
   582     EXPECT_EQ(written, 0);
   583     EXPECT_EQ(buf.capacity, 8);
   584     EXPECT_EQ(buf.pos, 4);
   585     EXPECT_EQ(buf.size, 4);
   586     EXPECT_EQ(memcmp(buf.space, "prep\0", 5), 0);
   587 }
   589 TEST_F(BufferWrite, OnlyOverwrite) {
   590     buf.flags |= CX_BUFFER_AUTO_EXTEND;
   591     ASSERT_EQ(buf.capacity, 8);
   592     memcpy(buf.space, "preptest", 8);
   593     buf.pos = 3;
   594     buf.size = 8;
   595     size_t written = cxBufferWrite("XXX", 2, 2, &buf);
   596     EXPECT_EQ(written, 2);
   597     EXPECT_EQ(buf.capacity, 8);
   598     EXPECT_EQ(buf.size, 8);
   599     EXPECT_EQ(buf.pos, 7);
   600     EXPECT_EQ(memcmp(buf.space, "preXXX\0t", 8), 0);
   601 }
   603 TEST_F(BufferWrite, FlushAtCapacity) {
   604     enableFlushing();
   605     ASSERT_EQ(buf.capacity, 8);
   606     ASSERT_EQ(buf.pos, 4);
   607     size_t written = cxBufferWrite("foo", 1, 3, &buf);
   608     EXPECT_EQ(written, 3);
   609     ASSERT_EQ(buf.pos, 7);
   610     ASSERT_EQ(buf.size, 7);
   611     ASSERT_EQ(target.pos, 0);
   612     ASSERT_EQ(target.size, 0);
   613     written = cxBufferWrite("hello", 1, 5, &buf);
   614     EXPECT_EQ(written, 5);
   615     EXPECT_EQ(buf.pos, 0);
   616     EXPECT_EQ(buf.size, 0);
   617     EXPECT_EQ(buf.capacity, 8);
   618     EXPECT_EQ(target.pos, 12);
   619     ASSERT_EQ(target.size, 12);
   620     EXPECT_EQ(memcmp(target.space, "prepfoohello", 12), 0);
   621 }
   623 TEST_F(BufferWrite, FlushAtThreshold) {
   624     enableFlushing();
   625     buf.flush_threshold = 12;
   626     buf.flags |= CX_BUFFER_AUTO_EXTEND;
   627     ASSERT_EQ(buf.capacity, 8);
   628     ASSERT_EQ(buf.pos, 4);
   629     size_t written = cxBufferWrite("foobar", 1, 6, &buf);
   630     EXPECT_EQ(written, 6);
   631     ASSERT_EQ(buf.pos, 10);
   632     ASSERT_EQ(buf.size, 10);
   633     ASSERT_GE(buf.capacity, 10);
   634     ASSERT_LE(buf.capacity, 12);
   635     ASSERT_EQ(target.pos, 0);
   636     ASSERT_EQ(target.size, 0);
   637     written = cxBufferWrite("hello", 1, 5, &buf);
   638     EXPECT_EQ(written, 5);
   639     EXPECT_EQ(buf.pos, 0);
   640     EXPECT_EQ(buf.size, 0);
   641     EXPECT_LE(buf.capacity, 12);
   642     EXPECT_EQ(target.pos, 15);
   643     ASSERT_EQ(target.size, 15);
   644     EXPECT_EQ(memcmp(target.space, "prepfoobarhello", 15), 0);
   645 }
   647 TEST_F(BufferWrite, FlushRateLimited) {
   648     enableFlushing();
   649     // limit the rate of the flush function and the capacity of the target
   650     target.capacity = 16;
   651     target.flags &= ~CX_BUFFER_AUTO_EXTEND;
   652     buf.flush_func = (cx_write_func) mock_write_limited_rate;
   653     ASSERT_EQ(buf.capacity, 8);
   654     ASSERT_EQ(buf.pos, 4);
   655     size_t written = cxBufferWrite("foo", 1, 3, &buf);
   656     EXPECT_EQ(written, 3);
   657     ASSERT_EQ(buf.pos, 7);
   658     ASSERT_EQ(buf.size, 7);
   659     ASSERT_EQ(target.pos, 0);
   660     ASSERT_EQ(target.size, 0);
   661     written = cxBufferWrite("hello, world!", 1, 13, &buf);
   662     // " world!" fits into this buffer, the remaining stuff is flushed out
   663     EXPECT_EQ(written, 13);
   664     EXPECT_EQ(buf.pos, 7);
   665     EXPECT_EQ(buf.size, 7);
   666     EXPECT_EQ(buf.capacity, 8);
   667     EXPECT_EQ(memcmp(buf.space, " world!", 7), 0);
   668     EXPECT_EQ(target.pos, 13);
   669     ASSERT_EQ(target.size, 13);
   670     EXPECT_EQ(target.capacity, 16);
   671     EXPECT_EQ(memcmp(target.space, "prepfoohello,", 13), 0);
   672 }
   674 class BufferSeek : public BufferFixture {
   675 };
   677 TEST_F(BufferSeek, SetZero) {
   678     int result = cxBufferSeek(&buf, 0, SEEK_SET);
   679     EXPECT_EQ(result, 0);
   680     EXPECT_EQ(buf.pos, 0);
   681 }
   683 TEST_F(BufferSeek, SetValid) {
   684     int result = cxBufferSeek(&buf, 5, SEEK_SET);
   685     EXPECT_EQ(result, 0);
   686     EXPECT_EQ(buf.pos, 5);
   687 }
   689 TEST_F(BufferSeek, SetInvalid) {
   690     ASSERT_EQ(buf.pos, 3);
   691     int result = cxBufferSeek(&buf, 6, SEEK_SET);
   692     EXPECT_NE(result, 0);
   693     EXPECT_EQ(buf.pos, 3);
   694 }
   696 TEST_F(BufferSeek, CurZero) {
   697     ASSERT_EQ(buf.pos, 3);
   698     int result = cxBufferSeek(&buf, 0, SEEK_CUR);
   699     EXPECT_EQ(result, 0);
   700     EXPECT_EQ(buf.pos, 3);
   701 }
   703 TEST_F(BufferSeek, CurValidPositive) {
   704     ASSERT_EQ(buf.pos, 3);
   705     int result = cxBufferSeek(&buf, 2, SEEK_CUR);
   706     EXPECT_EQ(result, 0);
   707     EXPECT_EQ(buf.pos, 5);
   708 }
   710 TEST_F(BufferSeek, CurValidNegative) {
   711     ASSERT_EQ(buf.pos, 3);
   712     int result = cxBufferSeek(&buf, -3, SEEK_CUR);
   713     EXPECT_EQ(result, 0);
   714     EXPECT_EQ(buf.pos, 0);
   715 }
   717 TEST_F(BufferSeek, CurInvalidPositive) {
   718     ASSERT_EQ(buf.pos, 3);
   719     int result = cxBufferSeek(&buf, 3, SEEK_CUR);
   720     EXPECT_NE(result, 0);
   721     EXPECT_EQ(buf.pos, 3);
   722 }
   724 TEST_F(BufferSeek, CurInvalidNegative) {
   725     ASSERT_EQ(buf.pos, 3);
   726     int result = cxBufferSeek(&buf, -4, SEEK_CUR);
   727     EXPECT_NE(result, 0);
   728     EXPECT_EQ(buf.pos, 3);
   729 }
   731 TEST_F(BufferSeek, EndZero) {
   732     ASSERT_EQ(buf.size, 6);
   733     int result = cxBufferSeek(&buf, 0, SEEK_END);
   734     // the (past-the-)end position is always invalid
   735     EXPECT_NE(result, 0);
   736     EXPECT_EQ(buf.pos, 3);
   737 }
   739 TEST_F(BufferSeek, EndValid) {
   740     ASSERT_EQ(buf.size, 6);
   741     int result = cxBufferSeek(&buf, -6, SEEK_END);
   742     EXPECT_EQ(result, 0);
   743     EXPECT_EQ(buf.pos, 0);
   744 }
   746 TEST_F(BufferSeek, EndInvalid) {
   747     ASSERT_EQ(buf.size, 6);
   748     int result = cxBufferSeek(&buf, 1, SEEK_END);
   749     EXPECT_NE(result, 0);
   750     EXPECT_EQ(buf.pos, 3);
   751 }
   753 TEST_F(BufferSeek, WhenceInvalid) {
   754     ASSERT_EQ(buf.size, 6);
   755     ASSERT_EQ(buf.pos, 3);
   756     int result = cxBufferSeek(&buf, 2, 9000);
   757     EXPECT_NE(result, 0);
   758     EXPECT_EQ(buf.size, 6);
   759     EXPECT_EQ(buf.pos, 3);
   760 }
   762 class BufferEof : public BufferFixture {
   763 };
   765 TEST_F(BufferEof, Reached) {
   766     buf.pos = buf.size;
   767     EXPECT_TRUE(cxBufferEof(&buf));
   768     buf.pos = buf.size - 1;
   769     ASSERT_FALSE(cxBufferEof(&buf));
   770     cxBufferPut(&buf, 'a');
   771     EXPECT_TRUE(cxBufferEof(&buf));
   772 }
   774 TEST_F(BufferEof, NotReached) {
   775     buf.pos = buf.size - 1;
   776     EXPECT_FALSE(cxBufferEof(&buf));
   777     buf.pos = 0;
   778     cxBufferWrite("test", 1, 5, &buf);
   779     EXPECT_FALSE(cxBufferEof(&buf));
   780 }
   782 class BufferRead : public ::testing::Test {
   783 protected:
   784     CxBuffer buf{};
   786     void SetUp() override {
   787         cxBufferInit(&buf, nullptr, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
   788         buf.capacity = 8; // artificially reduce capacity to check OOB writes
   789         memset(buf.space, 0, 16);
   790         memcpy(buf.space, "some data", 9);
   791         buf.size = 9;
   792     }
   794     void TearDown() override {
   795         cxBufferDestroy(&buf);
   796     }
   797 };
   799 TEST_F(BufferRead, GetByte) {
   800     buf.pos = 2;
   801     EXPECT_EQ(cxBufferGet(&buf), 'm');
   802     EXPECT_EQ(cxBufferGet(&buf), 'e');
   803     EXPECT_EQ(cxBufferGet(&buf), ' ');
   804     EXPECT_EQ(cxBufferGet(&buf), 'd');
   805     EXPECT_EQ(buf.pos, 6);
   806 }
   808 TEST_F(BufferRead, GetEof) {
   809     buf.pos = buf.size;
   810     EXPECT_EQ(cxBufferGet(&buf), EOF);
   811 }
   813 TEST_F(BufferRead, ReadWithinBounds) {
   814     buf.pos = 2;
   815     char target[4];
   816     auto read = cxBufferRead(&target, 1, 4, &buf);
   817     ASSERT_EQ(read, 4);
   818     EXPECT_EQ(memcmp(&target, "me d", 4), 0);
   819     EXPECT_EQ(buf.pos, 6);
   820 }
   822 TEST_F(BufferRead, ReadOutOfBounds) {
   823     buf.pos = 6;
   824     char target[4];
   825     auto read = cxBufferRead(&target, 1, 4, &buf);
   826     ASSERT_EQ(read, 3);
   827     EXPECT_EQ(memcmp(&target, "ata", 3), 0);
   828     EXPECT_EQ(buf.pos, 9);
   829 }
   831 TEST_F(BufferRead, ReadOutOfBoundsMultibyte) {
   832     buf.pos = 6;
   833     char target[4];
   834     target[2] = '\0';
   835     auto read = cxBufferRead(&target, 2, 2, &buf);
   836     ASSERT_EQ(read, 1);
   837     EXPECT_EQ(memcmp(&target, "at\0", 3), 0);
   838     EXPECT_EQ(buf.pos, 8);
   839 }
   841 TEST_F(BufferRead, ReadEof) {
   842     buf.pos = 9;
   843     char target[4];
   844     auto read = cxBufferRead(&target, 1, 1, &buf);
   845     ASSERT_EQ(read, 0);
   846     EXPECT_EQ(buf.pos, 9);
   847 }

mercurial