tests/test_buffer.cpp

Sun, 21 May 2023 16:22:09 +0200

author
Mike Becker <universe@uap-core.de>
date
Sun, 21 May 2023 16:22:09 +0200
changeset 710
2dd409ed056f
parent 683
aa0d09f2d81c
child 761
61d5197d612b
permissions
-rw-r--r--

fix const-ness of non-mutating iterator creation for maps

     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 class BufferWrite : public ::testing::Test {
   348 protected:
   349     CxBuffer buf{}, target{};
   351     void SetUp() override {
   352         cxBufferInit(&target, nullptr, 16, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND);
   353         cxBufferInit(&buf, nullptr, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
   354         buf.capacity = 8; // artificially reduce capacity to check OOB writes
   355         memset(buf.space, 0, 16);
   356         memcpy(buf.space, "prep", 4);
   357         buf.size = buf.pos = 4;
   358     }
   360     void TearDown() override {
   361         cxBufferDestroy(&buf);
   362         cxBufferDestroy(&target);
   363     }
   365     void enableFlushing() {
   366         buf.flush_target = &target;
   367         buf.flush_func = reinterpret_cast<cx_write_func>(cxBufferWrite);
   368         buf.flush_blkmax = 1;
   369     }
   370 };
   372 static size_t mock_write_limited_rate(
   373         void const *ptr,
   374         size_t size,
   375         __attribute__((unused)) size_t nitems,
   376         CxBuffer *buffer
   377 ) {
   378     // simulate limited target drain capacity
   379     static bool full = false;
   380     if (full) {
   381         full = false;
   382         return 0;
   383     } else {
   384         full = true;
   385         return cxBufferWrite(ptr, size, nitems > 2 ? 2 : nitems, buffer);
   386     }
   387 }
   389 TEST_F(BufferWrite, SizeOneFit) {
   390     const char *data = "test";
   391     ASSERT_EQ(buf.capacity, 8);
   392     ASSERT_EQ(buf.pos, 4);
   393     ASSERT_EQ(buf.size, 4);
   394     size_t written = cxBufferWrite(data, 1, 4, &buf);
   395     EXPECT_EQ(written, 4);
   396     EXPECT_EQ(buf.size, 8);
   397     EXPECT_EQ(buf.pos, 8);
   398     EXPECT_EQ(buf.capacity, 8);
   399     EXPECT_EQ(memcmp(buf.space, "preptest", 8), 0);
   400 }
   402 TEST_F(BufferWrite, SizeOneDiscard) {
   403     const char *data = "testing";
   404     ASSERT_EQ(buf.capacity, 8);
   405     ASSERT_EQ(buf.pos, 4);
   406     ASSERT_EQ(buf.size, 4);
   407     size_t written = cxBufferWrite(data, 1, 7, &buf);
   408     EXPECT_EQ(written, 4);
   409     EXPECT_EQ(buf.size, 8);
   410     EXPECT_EQ(buf.pos, 8);
   411     EXPECT_EQ(buf.capacity, 8);
   412     EXPECT_EQ(memcmp(buf.space, "preptest\0", 9), 0);
   413 }
   415 TEST_F(BufferWrite, SizeOneExtend) {
   416     buf.flags |= CX_BUFFER_AUTO_EXTEND;
   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, 7);
   423     EXPECT_EQ(buf.size, 11);
   424     EXPECT_EQ(buf.pos, 11);
   425     EXPECT_GE(buf.capacity, 11);
   426     EXPECT_EQ(memcmp(buf.space, "preptesting", 11), 0);
   427 }
   429 TEST_F(BufferWrite, MultibyteFit) {
   430     const char *data = "test";
   431     ASSERT_EQ(buf.capacity, 8);
   432     ASSERT_EQ(buf.pos, 4);
   433     ASSERT_EQ(buf.size, 4);
   434     size_t written = cxBufferWrite(data, 2, 2, &buf);
   435     EXPECT_EQ(written, 2);
   436     EXPECT_EQ(buf.size, 8);
   437     EXPECT_EQ(buf.pos, 8);
   438     EXPECT_EQ(buf.capacity, 8);
   439     EXPECT_EQ(memcmp(buf.space, "preptest", 8), 0);
   440 }
   442 TEST_F(BufferWrite, MultibyteDiscard) {
   443     const char *data = "testing";
   444     ASSERT_EQ(buf.capacity, 8);
   445     ASSERT_EQ(buf.size, 4);
   446     buf.pos = 3;
   447     size_t written = cxBufferWrite(data, 2, 4, &buf);
   448     // remember: whole elements are discarded if they do not fit
   449     EXPECT_EQ(written, 2);
   450     EXPECT_EQ(buf.size, 7);
   451     EXPECT_EQ(buf.pos, 7);
   452     EXPECT_EQ(buf.capacity, 8);
   453     EXPECT_EQ(memcmp(buf.space, "pretest\0", 8), 0);
   454 }
   456 TEST_F(BufferWrite, MultibyteExtend) {
   457     buf.flags |= CX_BUFFER_AUTO_EXTEND;
   458     const char *data = "tester";
   459     ASSERT_EQ(buf.capacity, 8);
   460     ASSERT_EQ(buf.size, 4);
   461     buf.pos = 3;
   462     size_t written = cxBufferWrite(data, 2, 3, &buf);
   463     // remember: whole elements are discarded if they do not fit
   464     EXPECT_EQ(written, 3);
   465     EXPECT_EQ(buf.size, 9);
   466     EXPECT_EQ(buf.pos, 9);
   467     EXPECT_GE(buf.capacity, 9);
   468     EXPECT_EQ(memcmp(buf.space, "pretester", 9), 0);
   469 }
   471 TEST_F(BufferWrite, PutcWrapperFit) {
   472     ASSERT_EQ(buf.capacity, 8);
   473     ASSERT_EQ(buf.pos, 4);
   474     ASSERT_EQ(buf.size, 4);
   475     int c = cxBufferPut(&buf, 0x200 | 'a');
   476     EXPECT_EQ(c, 'a');
   477     EXPECT_EQ(buf.size, 5);
   478     EXPECT_EQ(buf.pos, 5);
   479     EXPECT_EQ(buf.capacity, 8);
   480     EXPECT_EQ(memcmp(buf.space, "prepa\0", 6), 0);
   481 }
   483 TEST_F(BufferWrite, PutcWrapperDiscard) {
   484     ASSERT_EQ(buf.capacity, 8);
   485     ASSERT_EQ(buf.size, 4);
   486     buf.pos = 8;
   487     int c = cxBufferPut(&buf, 0x200 | 'a');
   488     EXPECT_EQ(c, EOF);
   489     EXPECT_EQ(buf.size, 4);
   490     EXPECT_EQ(buf.pos, 8);
   491     EXPECT_EQ(buf.capacity, 8);
   492     EXPECT_EQ(memcmp(buf.space, "prep\0\0\0\0\0", 9), 0);
   493 }
   495 TEST_F(BufferWrite, PutcWrapperExtend) {
   496     buf.flags |= CX_BUFFER_AUTO_EXTEND;
   497     ASSERT_EQ(buf.capacity, 8);
   498     ASSERT_EQ(buf.size, 4);
   499     buf.pos = 8;
   500     int c = cxBufferPut(&buf, 0x200 | 'a');
   501     EXPECT_EQ(c, 'a');
   502     EXPECT_EQ(buf.size, 9);
   503     EXPECT_EQ(buf.pos, 9);
   504     EXPECT_GE(buf.capacity, 9);
   505     EXPECT_EQ(memcmp(buf.space, "prep\0\0\0\0a", 9), 0);
   506 }
   508 TEST_F(BufferWrite, PutStringWrapperFit) {
   509     const char *data = "test";
   510     ASSERT_EQ(buf.capacity, 8);
   511     ASSERT_EQ(buf.pos, 4);
   512     ASSERT_EQ(buf.size, 4);
   513     size_t written = cxBufferPutString(&buf, data);
   514     EXPECT_EQ(written, 4);
   515     EXPECT_EQ(buf.size, 8);
   516     EXPECT_EQ(buf.pos, 8);
   517     EXPECT_EQ(buf.capacity, 8);
   518     EXPECT_EQ(memcmp(buf.space, "preptest", 8), 0);
   519 }
   521 TEST_F(BufferWrite, PutStringWrapperDiscard) {
   522     const char *data = "testing";
   523     ASSERT_EQ(buf.capacity, 8);
   524     ASSERT_EQ(buf.pos, 4);
   525     ASSERT_EQ(buf.size, 4);
   526     size_t written = cxBufferPutString(&buf, data);
   527     EXPECT_EQ(written, 4);
   528     EXPECT_EQ(buf.size, 8);
   529     EXPECT_EQ(buf.pos, 8);
   530     EXPECT_EQ(buf.capacity, 8);
   531     EXPECT_EQ(memcmp(buf.space, "preptest\0", 9), 0);
   532 }
   534 TEST_F(BufferWrite, PutStringWrapperExtend) {
   535     buf.flags |= CX_BUFFER_AUTO_EXTEND;
   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, 7);
   542     EXPECT_EQ(buf.size, 11);
   543     EXPECT_EQ(buf.pos, 11);
   544     EXPECT_GE(buf.capacity, 11);
   545     EXPECT_EQ(memcmp(buf.space, "preptesting", 11), 0);
   546 }
   548 TEST_F(BufferWrite, MultOverflow) {
   549     const char *data = "testing";
   550     ASSERT_EQ(buf.capacity, 8);
   551     ASSERT_EQ(buf.pos, 4);
   552     ASSERT_EQ(buf.size, 4);
   553     size_t written = cxBufferWrite(data, 8, SIZE_MAX / 4, &buf);
   554     EXPECT_EQ(written, 0);
   555     EXPECT_EQ(buf.capacity, 8);
   556     EXPECT_EQ(buf.pos, 4);
   557     EXPECT_EQ(buf.size, 4);
   558     EXPECT_EQ(memcmp(buf.space, "prep\0", 5), 0);
   559 }
   561 TEST_F(BufferWrite, MaxCapaOverflow) {
   562     buf.flags |= CX_BUFFER_AUTO_EXTEND;
   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, 1, SIZE_MAX - 2, &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, OnlyOverwrite) {
   576     buf.flags |= CX_BUFFER_AUTO_EXTEND;
   577     ASSERT_EQ(buf.capacity, 8);
   578     memcpy(buf.space, "preptest", 8);
   579     buf.pos = 3;
   580     buf.size = 8;
   581     size_t written = cxBufferWrite("XXX", 2, 2, &buf);
   582     EXPECT_EQ(written, 2);
   583     EXPECT_EQ(buf.capacity, 8);
   584     EXPECT_EQ(buf.size, 8);
   585     EXPECT_EQ(buf.pos, 7);
   586     EXPECT_EQ(memcmp(buf.space, "preXXX\0t", 8), 0);
   587 }
   589 TEST_F(BufferWrite, FlushAtCapacity) {
   590     enableFlushing();
   591     ASSERT_EQ(buf.capacity, 8);
   592     ASSERT_EQ(buf.pos, 4);
   593     size_t written = cxBufferWrite("foo", 1, 3, &buf);
   594     EXPECT_EQ(written, 3);
   595     ASSERT_EQ(buf.pos, 7);
   596     ASSERT_EQ(buf.size, 7);
   597     ASSERT_EQ(target.pos, 0);
   598     ASSERT_EQ(target.size, 0);
   599     written = cxBufferWrite("hello", 1, 5, &buf);
   600     EXPECT_EQ(written, 5);
   601     EXPECT_EQ(buf.pos, 0);
   602     EXPECT_EQ(buf.size, 0);
   603     EXPECT_EQ(buf.capacity, 8);
   604     EXPECT_EQ(target.pos, 12);
   605     ASSERT_EQ(target.size, 12);
   606     EXPECT_EQ(memcmp(target.space, "prepfoohello", 12), 0);
   607 }
   609 TEST_F(BufferWrite, FlushAtThreshold) {
   610     enableFlushing();
   611     buf.flush_threshold = 12;
   612     buf.flags |= CX_BUFFER_AUTO_EXTEND;
   613     ASSERT_EQ(buf.capacity, 8);
   614     ASSERT_EQ(buf.pos, 4);
   615     size_t written = cxBufferWrite("foobar", 1, 6, &buf);
   616     EXPECT_EQ(written, 6);
   617     ASSERT_EQ(buf.pos, 10);
   618     ASSERT_EQ(buf.size, 10);
   619     ASSERT_GE(buf.capacity, 10);
   620     ASSERT_LE(buf.capacity, 12);
   621     ASSERT_EQ(target.pos, 0);
   622     ASSERT_EQ(target.size, 0);
   623     written = cxBufferWrite("hello", 1, 5, &buf);
   624     EXPECT_EQ(written, 5);
   625     EXPECT_EQ(buf.pos, 0);
   626     EXPECT_EQ(buf.size, 0);
   627     EXPECT_LE(buf.capacity, 12);
   628     EXPECT_EQ(target.pos, 15);
   629     ASSERT_EQ(target.size, 15);
   630     EXPECT_EQ(memcmp(target.space, "prepfoobarhello", 15), 0);
   631 }
   633 TEST_F(BufferWrite, FlushRateLimited) {
   634     enableFlushing();
   635     // limit the rate of the flush function and the capacity of the target
   636     target.capacity = 16;
   637     target.flags &= ~CX_BUFFER_AUTO_EXTEND;
   638     buf.flush_func = (cx_write_func) mock_write_limited_rate;
   639     ASSERT_EQ(buf.capacity, 8);
   640     ASSERT_EQ(buf.pos, 4);
   641     size_t written = cxBufferWrite("foo", 1, 3, &buf);
   642     EXPECT_EQ(written, 3);
   643     ASSERT_EQ(buf.pos, 7);
   644     ASSERT_EQ(buf.size, 7);
   645     ASSERT_EQ(target.pos, 0);
   646     ASSERT_EQ(target.size, 0);
   647     written = cxBufferWrite("hello, world!", 1, 13, &buf);
   648     // " world!" fits into this buffer, the remaining stuff is flushed out
   649     EXPECT_EQ(written, 13);
   650     EXPECT_EQ(buf.pos, 7);
   651     EXPECT_EQ(buf.size, 7);
   652     EXPECT_EQ(buf.capacity, 8);
   653     EXPECT_EQ(memcmp(buf.space, " world!", 7), 0);
   654     EXPECT_EQ(target.pos, 13);
   655     ASSERT_EQ(target.size, 13);
   656     EXPECT_EQ(target.capacity, 16);
   657     EXPECT_EQ(memcmp(target.space, "prepfoohello,", 13), 0);
   658 }
   660 class BufferSeek : public BufferFixture {
   661 };
   663 TEST_F(BufferSeek, SetZero) {
   664     int result = cxBufferSeek(&buf, 0, SEEK_SET);
   665     EXPECT_EQ(result, 0);
   666     EXPECT_EQ(buf.pos, 0);
   667 }
   669 TEST_F(BufferSeek, SetValid) {
   670     int result = cxBufferSeek(&buf, 5, SEEK_SET);
   671     EXPECT_EQ(result, 0);
   672     EXPECT_EQ(buf.pos, 5);
   673 }
   675 TEST_F(BufferSeek, SetInvalid) {
   676     ASSERT_EQ(buf.pos, 3);
   677     int result = cxBufferSeek(&buf, 6, SEEK_SET);
   678     EXPECT_NE(result, 0);
   679     EXPECT_EQ(buf.pos, 3);
   680 }
   682 TEST_F(BufferSeek, CurZero) {
   683     ASSERT_EQ(buf.pos, 3);
   684     int result = cxBufferSeek(&buf, 0, SEEK_CUR);
   685     EXPECT_EQ(result, 0);
   686     EXPECT_EQ(buf.pos, 3);
   687 }
   689 TEST_F(BufferSeek, CurValidPositive) {
   690     ASSERT_EQ(buf.pos, 3);
   691     int result = cxBufferSeek(&buf, 2, SEEK_CUR);
   692     EXPECT_EQ(result, 0);
   693     EXPECT_EQ(buf.pos, 5);
   694 }
   696 TEST_F(BufferSeek, CurValidNegative) {
   697     ASSERT_EQ(buf.pos, 3);
   698     int result = cxBufferSeek(&buf, -3, SEEK_CUR);
   699     EXPECT_EQ(result, 0);
   700     EXPECT_EQ(buf.pos, 0);
   701 }
   703 TEST_F(BufferSeek, CurInvalidPositive) {
   704     ASSERT_EQ(buf.pos, 3);
   705     int result = cxBufferSeek(&buf, 3, SEEK_CUR);
   706     EXPECT_NE(result, 0);
   707     EXPECT_EQ(buf.pos, 3);
   708 }
   710 TEST_F(BufferSeek, CurInvalidNegative) {
   711     ASSERT_EQ(buf.pos, 3);
   712     int result = cxBufferSeek(&buf, -4, SEEK_CUR);
   713     EXPECT_NE(result, 0);
   714     EXPECT_EQ(buf.pos, 3);
   715 }
   717 TEST_F(BufferSeek, EndZero) {
   718     ASSERT_EQ(buf.size, 6);
   719     int result = cxBufferSeek(&buf, 0, SEEK_END);
   720     // the (past-the-)end position is always invalid
   721     EXPECT_NE(result, 0);
   722     EXPECT_EQ(buf.pos, 3);
   723 }
   725 TEST_F(BufferSeek, EndValid) {
   726     ASSERT_EQ(buf.size, 6);
   727     int result = cxBufferSeek(&buf, -6, SEEK_END);
   728     EXPECT_EQ(result, 0);
   729     EXPECT_EQ(buf.pos, 0);
   730 }
   732 TEST_F(BufferSeek, EndInvalid) {
   733     ASSERT_EQ(buf.size, 6);
   734     int result = cxBufferSeek(&buf, 1, SEEK_END);
   735     EXPECT_NE(result, 0);
   736     EXPECT_EQ(buf.pos, 3);
   737 }
   739 TEST_F(BufferSeek, WhenceInvalid) {
   740     ASSERT_EQ(buf.size, 6);
   741     ASSERT_EQ(buf.pos, 3);
   742     int result = cxBufferSeek(&buf, 2, 9000);
   743     EXPECT_NE(result, 0);
   744     EXPECT_EQ(buf.size, 6);
   745     EXPECT_EQ(buf.pos, 3);
   746 }
   748 class BufferEof : public BufferFixture {
   749 };
   751 TEST_F(BufferEof, Reached) {
   752     buf.pos = buf.size;
   753     EXPECT_TRUE(cxBufferEof(&buf));
   754     buf.pos = buf.size - 1;
   755     ASSERT_FALSE(cxBufferEof(&buf));
   756     cxBufferPut(&buf, 'a');
   757     EXPECT_TRUE(cxBufferEof(&buf));
   758 }
   760 TEST_F(BufferEof, NotReached) {
   761     buf.pos = buf.size - 1;
   762     EXPECT_FALSE(cxBufferEof(&buf));
   763     buf.pos = 0;
   764     cxBufferWrite("test", 1, 5, &buf);
   765     EXPECT_FALSE(cxBufferEof(&buf));
   766 }
   768 class BufferRead : public ::testing::Test {
   769 protected:
   770     CxBuffer buf{};
   772     void SetUp() override {
   773         cxBufferInit(&buf, nullptr, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
   774         buf.capacity = 8; // artificially reduce capacity to check OOB writes
   775         memset(buf.space, 0, 16);
   776         memcpy(buf.space, "some data", 9);
   777         buf.size = 9;
   778     }
   780     void TearDown() override {
   781         cxBufferDestroy(&buf);
   782     }
   783 };
   785 TEST_F(BufferRead, GetByte) {
   786     buf.pos = 2;
   787     EXPECT_EQ(cxBufferGet(&buf), 'm');
   788     EXPECT_EQ(cxBufferGet(&buf), 'e');
   789     EXPECT_EQ(cxBufferGet(&buf), ' ');
   790     EXPECT_EQ(cxBufferGet(&buf), 'd');
   791     EXPECT_EQ(buf.pos, 6);
   792 }
   794 TEST_F(BufferRead, GetEof) {
   795     buf.pos = buf.size;
   796     EXPECT_EQ(cxBufferGet(&buf), EOF);
   797 }
   799 TEST_F(BufferRead, ReadWithinBounds) {
   800     buf.pos = 2;
   801     char target[4];
   802     auto read = cxBufferRead(&target, 1, 4, &buf);
   803     ASSERT_EQ(read, 4);
   804     EXPECT_EQ(memcmp(&target, "me d", 4), 0);
   805     EXPECT_EQ(buf.pos, 6);
   806 }
   808 TEST_F(BufferRead, ReadOutOfBounds) {
   809     buf.pos = 6;
   810     char target[4];
   811     auto read = cxBufferRead(&target, 1, 4, &buf);
   812     ASSERT_EQ(read, 3);
   813     EXPECT_EQ(memcmp(&target, "ata", 3), 0);
   814     EXPECT_EQ(buf.pos, 9);
   815 }
   817 TEST_F(BufferRead, ReadOutOfBoundsMultibyte) {
   818     buf.pos = 6;
   819     char target[4];
   820     target[2] = '\0';
   821     auto read = cxBufferRead(&target, 2, 2, &buf);
   822     ASSERT_EQ(read, 1);
   823     EXPECT_EQ(memcmp(&target, "at\0", 3), 0);
   824     EXPECT_EQ(buf.pos, 8);
   825 }
   827 TEST_F(BufferRead, ReadEof) {
   828     buf.pos = 9;
   829     char target[4];
   830     auto read = cxBufferRead(&target, 1, 1, &buf);
   831     ASSERT_EQ(read, 0);
   832     EXPECT_EQ(buf.pos, 9);
   833 }

mercurial