test/test_buffer.cpp

Mon, 25 Jul 2022 15:40:27 +0200

author
Mike Becker <universe@uap-core.de>
date
Mon, 25 Jul 2022 15:40:27 +0200
changeset 569
cb63f3d1236a
parent 568
8eda32d09e3d
permissions
-rw-r--r--

#170 test cxBufferRead

     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 class BufferShiftFixture : public ::testing::Test {
   131 protected:
   132     void SetUp() override {
   133         ASSERT_TRUE(alloc.verify());
   134         cxBufferInit(&buf, nullptr, 16, &alloc, CX_BUFFER_DEFAULT);
   135         memcpy(buf.space, "test____________", 16);
   136         buf.capacity = 8; // purposely pretend that the buffer has less capacity s.t. we can test beyond the range
   137         buf.pos = 4;
   138         buf.size = 4;
   139     }
   141     void TearDown() override {
   142         cxBufferDestroy(&buf);
   143         EXPECT_TRUE(alloc.verify());
   144     }
   146     CxTestingAllocator alloc;
   147     CxBuffer buf{};
   148 };
   150 class BufferShiftLeft : public BufferShiftFixture {
   151 };
   153 TEST_F(BufferShiftLeft, Zero) {
   154     ASSERT_EQ(buf.pos, 4);
   155     ASSERT_EQ(buf.size, 4);
   156     int ret = cxBufferShiftLeft(&buf, 0);
   157     EXPECT_EQ(ret, 0);
   158     EXPECT_EQ(buf.pos, 4);
   159     EXPECT_EQ(buf.size, 4);
   160     EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
   161 }
   163 TEST_F(BufferShiftLeft, ZeroOffsetInterface) {
   164     ASSERT_EQ(buf.pos, 4);
   165     ASSERT_EQ(buf.size, 4);
   166     int ret = cxBufferShift(&buf, -0);
   167     EXPECT_EQ(ret, 0);
   168     EXPECT_EQ(buf.pos, 4);
   169     EXPECT_EQ(buf.size, 4);
   170     EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
   171 }
   173 TEST_F(BufferShiftLeft, Standard) {
   174     ASSERT_EQ(buf.pos, 4);
   175     ASSERT_EQ(buf.size, 4);
   176     int ret = cxBufferShiftLeft(&buf, 2);
   177     EXPECT_EQ(ret, 0);
   178     EXPECT_EQ(buf.pos, 2);
   179     EXPECT_EQ(buf.size, 2);
   180     EXPECT_TRUE(memcmp(buf.space, "stst________", 8) == 0);
   181 }
   183 TEST_F(BufferShiftLeft, Overshift) {
   184     ASSERT_LT(buf.pos, 6);
   185     ASSERT_LT(buf.size, 6);
   186     int ret = cxBufferShiftLeft(&buf, 6);
   187     EXPECT_EQ(ret, 0);
   188     EXPECT_EQ(buf.pos, 0);
   189     EXPECT_EQ(buf.size, 0);
   190     EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
   191 }
   193 TEST_F(BufferShiftLeft, OvershiftPosOnly) {
   194     buf.pos = 2;
   195     ASSERT_EQ(buf.size, 4);
   196     int ret = cxBufferShiftLeft(&buf, 3);
   197     EXPECT_EQ(ret, 0);
   198     EXPECT_EQ(buf.pos, 0);
   199     EXPECT_EQ(buf.size, 1);
   200     EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
   201 }
   203 TEST_F(BufferShiftLeft, OffsetInterface) {
   204     buf.pos = 3;
   205     ASSERT_EQ(buf.size, 4);
   206     int ret = cxBufferShift(&buf, -2);
   207     EXPECT_EQ(ret, 0);
   208     EXPECT_EQ(buf.pos, 1);
   209     EXPECT_EQ(buf.size, 2);
   210     EXPECT_TRUE(memcmp(buf.space, "stst________", 8) == 0);
   211 }
   213 class BufferShiftRight : public BufferShiftFixture {
   214 };
   216 TEST_F(BufferShiftRight, Zero) {
   217     ASSERT_EQ(buf.pos, 4);
   218     ASSERT_EQ(buf.size, 4);
   219     int ret = cxBufferShiftRight(&buf, 0);
   220     EXPECT_EQ(ret, 0);
   221     EXPECT_EQ(buf.pos, 4);
   222     EXPECT_EQ(buf.size, 4);
   223     EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
   224 }
   226 TEST_F(BufferShiftRight, ZeroOffsetInterface) {
   227     ASSERT_EQ(buf.pos, 4);
   228     ASSERT_EQ(buf.size, 4);
   229     int ret = cxBufferShift(&buf, +0);
   230     EXPECT_EQ(ret, 0);
   231     EXPECT_EQ(buf.pos, 4);
   232     EXPECT_EQ(buf.size, 4);
   233     EXPECT_TRUE(memcmp(buf.space, "test________", 8) == 0);
   234 }
   236 TEST_F(BufferShiftRight, Standard) {
   237     ASSERT_EQ(buf.pos, 4);
   238     ASSERT_EQ(buf.size, 4);
   239     int ret = cxBufferShiftRight(&buf, 3);
   240     EXPECT_EQ(ret, 0);
   241     EXPECT_EQ(buf.pos, 7);
   242     EXPECT_EQ(buf.size, 7);
   243     EXPECT_TRUE(memcmp(buf.space, "testest_____", 8) == 0);
   244 }
   246 TEST_F(BufferShiftRight, OvershiftDiscard) {
   247     ASSERT_EQ(buf.pos, 4);
   248     ASSERT_EQ(buf.size, 4);
   249     ASSERT_EQ(buf.capacity, 8);
   250     int ret = cxBufferShiftRight(&buf, 6);
   251     EXPECT_EQ(ret, 0);
   252     EXPECT_EQ(buf.pos, 8);
   253     EXPECT_EQ(buf.size, 8);
   254     EXPECT_EQ(buf.capacity, 8);
   255     EXPECT_TRUE(memcmp(buf.space, "test__te____", 8) == 0);
   256 }
   258 TEST_F(BufferShiftRight, OvershiftExtend) {
   259     ASSERT_EQ(buf.pos, 4);
   260     ASSERT_EQ(buf.size, 4);
   261     ASSERT_EQ(buf.capacity, 8);
   262     buf.flags |= CX_BUFFER_AUTO_EXTEND;
   263     int ret = cxBufferShiftRight(&buf, 6);
   264     EXPECT_EQ(ret, 0);
   265     EXPECT_EQ(buf.pos, 10);
   266     EXPECT_EQ(buf.size, 10);
   267     EXPECT_GE(buf.capacity, 10);
   268     EXPECT_TRUE(memcmp(buf.space, "test__test__", 8) == 0);
   269 }
   271 TEST_F(BufferShiftRight, OffsetInterface) {
   272     buf.pos = 3;
   273     ASSERT_EQ(buf.size, 4);
   274     int ret = cxBufferShift(&buf, 2);
   275     EXPECT_EQ(ret, 0);
   276     EXPECT_EQ(buf.pos, 5);
   277     EXPECT_EQ(buf.size, 6);
   278     EXPECT_TRUE(memcmp(buf.space, "tetest______", 8) == 0);
   279 }
   281 TEST(BufferMinimumCapacity, Sufficient) {
   282     CxTestingAllocator alloc;
   283     auto space = cxMalloc(&alloc, 8);
   284     CxBuffer buf;
   285     cxBufferInit(&buf, space, 8, &alloc, CX_BUFFER_FREE_CONTENTS);
   286     memcpy(space, "Testing", 8);
   287     buf.size = 8;
   288     cxBufferMinimumCapacity(&buf, 6);
   289     EXPECT_EQ(buf.capacity, 8);
   290     EXPECT_EQ(buf.size, 8);
   291     EXPECT_TRUE(memcmp(buf.space, "Testing", 8) == 0);
   292     cxBufferDestroy(&buf);
   293     EXPECT_TRUE(alloc.verify());
   294 }
   296 TEST(BufferMinimumCapacity, Extend) {
   297     CxTestingAllocator alloc;
   298     auto space = cxMalloc(&alloc, 8);
   299     CxBuffer buf;
   300     cxBufferInit(&buf, space, 8, &alloc, CX_BUFFER_FREE_CONTENTS); // NO auto extend!
   301     memcpy(space, "Testing", 8);
   302     buf.size = 8;
   303     cxBufferMinimumCapacity(&buf, 16);
   304     EXPECT_EQ(buf.capacity, 16);
   305     EXPECT_EQ(buf.size, 8);
   306     EXPECT_TRUE(memcmp(buf.space, "Testing", 8) == 0);
   307     cxBufferDestroy(&buf);
   308     EXPECT_TRUE(alloc.verify());
   309 }
   311 TEST(BufferClear, Test) {
   312     char space[16];
   313     strcpy(space, "clear test");
   314     CxBuffer buf;
   315     cxBufferInit(&buf, space, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
   316     ASSERT_EQ(buf.size, 0);
   317     // only clear the used part of the buffer
   318     cxBufferClear(&buf);
   319     EXPECT_EQ(memcmp(space, "clear test", 10), 0);
   320     buf.size = 5;
   321     buf.pos = 3;
   322     cxBufferClear(&buf);
   323     EXPECT_EQ(memcmp(space, "\0\0\0\0\0 test", 10), 0);
   324     EXPECT_EQ(buf.size, 0);
   325     EXPECT_EQ(buf.pos, 0);
   326     cxBufferDestroy(&buf);
   327 }
   329 class BufferWrite : public ::testing::Test {
   330 protected:
   331     CxBuffer buf{}, target{};
   333     void SetUp() override {
   334         cxBufferInit(&target, nullptr, 16, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND);
   335         cxBufferInit(&buf, nullptr, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
   336         buf.capacity = 8; // artificially reduce capacity to check OOB writes
   337         memset(buf.space, 0, 16);
   338         memcpy(buf.space, "prep", 4);
   339         buf.size = buf.pos = 4;
   340     }
   342     void TearDown() override {
   343         cxBufferDestroy(&buf);
   344         cxBufferDestroy(&target);
   345     }
   347     void enableFlushing() {
   348         buf.flush_target = &target;
   349         buf.flush_func = reinterpret_cast<cx_write_func>(cxBufferWrite);
   350         buf.flush_blkmax = 1;
   351     }
   352 };
   354 static size_t mock_write_limited_rate(
   355         void const *ptr,
   356         size_t size,
   357         __attribute__((unused)) size_t nitems,
   358         CxBuffer *buffer
   359 ) {
   360     // simulate limited target drain capacity
   361     static bool full = false;
   362     if (full) {
   363         full = false;
   364         return 0;
   365     } else {
   366         full = true;
   367         return cxBufferWrite(ptr, size, nitems > 2 ? 2 : nitems, buffer);
   368     }
   369 }
   371 TEST_F(BufferWrite, SizeOneFit) {
   372     const char *data = "test";
   373     ASSERT_EQ(buf.capacity, 8);
   374     ASSERT_EQ(buf.pos, 4);
   375     ASSERT_EQ(buf.size, 4);
   376     size_t written = cxBufferWrite(data, 1, 4, &buf);
   377     EXPECT_EQ(written, 4);
   378     EXPECT_EQ(buf.size, 8);
   379     EXPECT_EQ(buf.pos, 8);
   380     EXPECT_EQ(buf.capacity, 8);
   381     EXPECT_EQ(memcmp(buf.space, "preptest", 8), 0);
   382 }
   384 TEST_F(BufferWrite, SizeOneDiscard) {
   385     const char *data = "testing";
   386     ASSERT_EQ(buf.capacity, 8);
   387     ASSERT_EQ(buf.pos, 4);
   388     ASSERT_EQ(buf.size, 4);
   389     size_t written = cxBufferWrite(data, 1, 7, &buf);
   390     EXPECT_EQ(written, 4);
   391     EXPECT_EQ(buf.size, 8);
   392     EXPECT_EQ(buf.pos, 8);
   393     EXPECT_EQ(buf.capacity, 8);
   394     EXPECT_EQ(memcmp(buf.space, "preptest\0", 9), 0);
   395 }
   397 TEST_F(BufferWrite, SizeOneExtend) {
   398     buf.flags |= CX_BUFFER_AUTO_EXTEND;
   399     const char *data = "testing";
   400     ASSERT_EQ(buf.capacity, 8);
   401     ASSERT_EQ(buf.pos, 4);
   402     ASSERT_EQ(buf.size, 4);
   403     size_t written = cxBufferWrite(data, 1, 7, &buf);
   404     EXPECT_EQ(written, 7);
   405     EXPECT_EQ(buf.size, 11);
   406     EXPECT_EQ(buf.pos, 11);
   407     EXPECT_GE(buf.capacity, 11);
   408     EXPECT_EQ(memcmp(buf.space, "preptesting", 11), 0);
   409 }
   411 TEST_F(BufferWrite, MultibyteFit) {
   412     const char *data = "test";
   413     ASSERT_EQ(buf.capacity, 8);
   414     ASSERT_EQ(buf.pos, 4);
   415     ASSERT_EQ(buf.size, 4);
   416     size_t written = cxBufferWrite(data, 2, 2, &buf);
   417     EXPECT_EQ(written, 2);
   418     EXPECT_EQ(buf.size, 8);
   419     EXPECT_EQ(buf.pos, 8);
   420     EXPECT_EQ(buf.capacity, 8);
   421     EXPECT_EQ(memcmp(buf.space, "preptest", 8), 0);
   422 }
   424 TEST_F(BufferWrite, MultibyteDiscard) {
   425     const char *data = "testing";
   426     ASSERT_EQ(buf.capacity, 8);
   427     ASSERT_EQ(buf.size, 4);
   428     buf.pos = 3;
   429     size_t written = cxBufferWrite(data, 2, 4, &buf);
   430     // remember: whole elements are discarded if they do not fit
   431     EXPECT_EQ(written, 2);
   432     EXPECT_EQ(buf.size, 7);
   433     EXPECT_EQ(buf.pos, 7);
   434     EXPECT_EQ(buf.capacity, 8);
   435     EXPECT_EQ(memcmp(buf.space, "pretest\0", 8), 0);
   436 }
   438 TEST_F(BufferWrite, MultibyteExtend) {
   439     buf.flags |= CX_BUFFER_AUTO_EXTEND;
   440     const char *data = "tester";
   441     ASSERT_EQ(buf.capacity, 8);
   442     ASSERT_EQ(buf.size, 4);
   443     buf.pos = 3;
   444     size_t written = cxBufferWrite(data, 2, 3, &buf);
   445     // remember: whole elements are discarded if they do not fit
   446     EXPECT_EQ(written, 3);
   447     EXPECT_EQ(buf.size, 9);
   448     EXPECT_EQ(buf.pos, 9);
   449     EXPECT_GE(buf.capacity, 9);
   450     EXPECT_EQ(memcmp(buf.space, "pretester", 9), 0);
   451 }
   453 TEST_F(BufferWrite, PutcWrapperFit) {
   454     ASSERT_EQ(buf.capacity, 8);
   455     ASSERT_EQ(buf.pos, 4);
   456     ASSERT_EQ(buf.size, 4);
   457     int c = cxBufferPut(&buf, 0x200 | 'a');
   458     EXPECT_EQ(c, 'a');
   459     EXPECT_EQ(buf.size, 5);
   460     EXPECT_EQ(buf.pos, 5);
   461     EXPECT_EQ(buf.capacity, 8);
   462     EXPECT_EQ(memcmp(buf.space, "prepa\0", 6), 0);
   463 }
   465 TEST_F(BufferWrite, PutcWrapperDiscard) {
   466     ASSERT_EQ(buf.capacity, 8);
   467     ASSERT_EQ(buf.size, 4);
   468     buf.pos = 8;
   469     int c = cxBufferPut(&buf, 0x200 | 'a');
   470     EXPECT_EQ(c, EOF);
   471     EXPECT_EQ(buf.size, 4);
   472     EXPECT_EQ(buf.pos, 8);
   473     EXPECT_EQ(buf.capacity, 8);
   474     EXPECT_EQ(memcmp(buf.space, "prep\0\0\0\0\0", 9), 0);
   475 }
   477 TEST_F(BufferWrite, PutcWrapperExtend) {
   478     buf.flags |= CX_BUFFER_AUTO_EXTEND;
   479     ASSERT_EQ(buf.capacity, 8);
   480     ASSERT_EQ(buf.size, 4);
   481     buf.pos = 8;
   482     int c = cxBufferPut(&buf, 0x200 | 'a');
   483     EXPECT_EQ(c, 'a');
   484     EXPECT_EQ(buf.size, 9);
   485     EXPECT_EQ(buf.pos, 9);
   486     EXPECT_GE(buf.capacity, 9);
   487     EXPECT_EQ(memcmp(buf.space, "prep\0\0\0\0a", 9), 0);
   488 }
   490 TEST_F(BufferWrite, PutStringWrapperFit) {
   491     const char *data = "test";
   492     ASSERT_EQ(buf.capacity, 8);
   493     ASSERT_EQ(buf.pos, 4);
   494     ASSERT_EQ(buf.size, 4);
   495     size_t written = cxBufferPutString(&buf, data);
   496     EXPECT_EQ(written, 4);
   497     EXPECT_EQ(buf.size, 8);
   498     EXPECT_EQ(buf.pos, 8);
   499     EXPECT_EQ(buf.capacity, 8);
   500     EXPECT_EQ(memcmp(buf.space, "preptest", 8), 0);
   501 }
   503 TEST_F(BufferWrite, PutStringWrapperDiscard) {
   504     const char *data = "testing";
   505     ASSERT_EQ(buf.capacity, 8);
   506     ASSERT_EQ(buf.pos, 4);
   507     ASSERT_EQ(buf.size, 4);
   508     size_t written = cxBufferPutString(&buf, data);
   509     EXPECT_EQ(written, 4);
   510     EXPECT_EQ(buf.size, 8);
   511     EXPECT_EQ(buf.pos, 8);
   512     EXPECT_EQ(buf.capacity, 8);
   513     EXPECT_EQ(memcmp(buf.space, "preptest\0", 9), 0);
   514 }
   516 TEST_F(BufferWrite, PutStringWrapperExtend) {
   517     buf.flags |= CX_BUFFER_AUTO_EXTEND;
   518     const char *data = "testing";
   519     ASSERT_EQ(buf.capacity, 8);
   520     ASSERT_EQ(buf.pos, 4);
   521     ASSERT_EQ(buf.size, 4);
   522     size_t written = cxBufferPutString(&buf, data);
   523     EXPECT_EQ(written, 7);
   524     EXPECT_EQ(buf.size, 11);
   525     EXPECT_EQ(buf.pos, 11);
   526     EXPECT_GE(buf.capacity, 11);
   527     EXPECT_EQ(memcmp(buf.space, "preptesting", 11), 0);
   528 }
   530 TEST_F(BufferWrite, MultOverflow) {
   531     const char *data = "testing";
   532     ASSERT_EQ(buf.capacity, 8);
   533     ASSERT_EQ(buf.pos, 4);
   534     ASSERT_EQ(buf.size, 4);
   535     size_t written = cxBufferWrite(data, 8, SIZE_MAX / 4, &buf);
   536     EXPECT_EQ(written, 0);
   537     EXPECT_EQ(buf.capacity, 8);
   538     EXPECT_EQ(buf.pos, 4);
   539     EXPECT_EQ(buf.size, 4);
   540     EXPECT_EQ(memcmp(buf.space, "prep\0", 5), 0);
   541 }
   543 TEST_F(BufferWrite, MaxCapaOverflow) {
   544     buf.flags |= CX_BUFFER_AUTO_EXTEND;
   545     const char *data = "testing";
   546     ASSERT_EQ(buf.capacity, 8);
   547     ASSERT_EQ(buf.pos, 4);
   548     ASSERT_EQ(buf.size, 4);
   549     size_t written = cxBufferWrite(data, 1, SIZE_MAX - 2, &buf);
   550     EXPECT_EQ(written, 0);
   551     EXPECT_EQ(buf.capacity, 8);
   552     EXPECT_EQ(buf.pos, 4);
   553     EXPECT_EQ(buf.size, 4);
   554     EXPECT_EQ(memcmp(buf.space, "prep\0", 5), 0);
   555 }
   557 TEST_F(BufferWrite, OnlyOverwrite) {
   558     buf.flags |= CX_BUFFER_AUTO_EXTEND;
   559     ASSERT_EQ(buf.capacity, 8);
   560     memcpy(buf.space, "preptest", 8);
   561     buf.pos = 3;
   562     buf.size = 8;
   563     size_t written = cxBufferWrite("XXX", 2, 2, &buf);
   564     EXPECT_EQ(written, 2);
   565     EXPECT_EQ(buf.capacity, 8);
   566     EXPECT_EQ(buf.size, 8);
   567     EXPECT_EQ(buf.pos, 7);
   568     EXPECT_EQ(memcmp(buf.space, "preXXX\0t", 8), 0);
   569 }
   571 TEST_F(BufferWrite, FlushAtCapacity) {
   572     enableFlushing();
   573     ASSERT_EQ(buf.capacity, 8);
   574     ASSERT_EQ(buf.pos, 4);
   575     size_t written = cxBufferWrite("foo", 1, 3, &buf);
   576     EXPECT_EQ(written, 3);
   577     ASSERT_EQ(buf.pos, 7);
   578     ASSERT_EQ(buf.size, 7);
   579     ASSERT_EQ(target.pos, 0);
   580     ASSERT_EQ(target.size, 0);
   581     written = cxBufferWrite("hello", 1, 5, &buf);
   582     EXPECT_EQ(written, 5);
   583     EXPECT_EQ(buf.pos, 0);
   584     EXPECT_EQ(buf.size, 0);
   585     EXPECT_EQ(buf.capacity, 8);
   586     EXPECT_EQ(target.pos, 12);
   587     ASSERT_EQ(target.size, 12);
   588     EXPECT_EQ(memcmp(target.space, "prepfoohello", 12), 0);
   589 }
   591 TEST_F(BufferWrite, FlushAtThreshold) {
   592     enableFlushing();
   593     buf.flush_threshold = 12;
   594     buf.flags |= CX_BUFFER_AUTO_EXTEND;
   595     ASSERT_EQ(buf.capacity, 8);
   596     ASSERT_EQ(buf.pos, 4);
   597     size_t written = cxBufferWrite("foobar", 1, 6, &buf);
   598     EXPECT_EQ(written, 6);
   599     ASSERT_EQ(buf.pos, 10);
   600     ASSERT_EQ(buf.size, 10);
   601     ASSERT_GE(buf.capacity, 10);
   602     ASSERT_LE(buf.capacity, 12);
   603     ASSERT_EQ(target.pos, 0);
   604     ASSERT_EQ(target.size, 0);
   605     written = cxBufferWrite("hello", 1, 5, &buf);
   606     EXPECT_EQ(written, 5);
   607     EXPECT_EQ(buf.pos, 0);
   608     EXPECT_EQ(buf.size, 0);
   609     EXPECT_LE(buf.capacity, 12);
   610     EXPECT_EQ(target.pos, 15);
   611     ASSERT_EQ(target.size, 15);
   612     EXPECT_EQ(memcmp(target.space, "prepfoobarhello", 15), 0);
   613 }
   615 TEST_F(BufferWrite, FlushRateLimited) {
   616     enableFlushing();
   617     // limit the rate of the flush function and the capacity of the target
   618     target.capacity = 16;
   619     target.flags &= ~CX_BUFFER_AUTO_EXTEND;
   620     buf.flush_func = (cx_write_func) mock_write_limited_rate;
   621     ASSERT_EQ(buf.capacity, 8);
   622     ASSERT_EQ(buf.pos, 4);
   623     size_t written = cxBufferWrite("foo", 1, 3, &buf);
   624     EXPECT_EQ(written, 3);
   625     ASSERT_EQ(buf.pos, 7);
   626     ASSERT_EQ(buf.size, 7);
   627     ASSERT_EQ(target.pos, 0);
   628     ASSERT_EQ(target.size, 0);
   629     written = cxBufferWrite("hello, world!", 1, 13, &buf);
   630     // " world!" fits into this buffer, the remaining stuff is flushed out
   631     EXPECT_EQ(written, 13);
   632     EXPECT_EQ(buf.pos, 7);
   633     EXPECT_EQ(buf.size, 7);
   634     EXPECT_EQ(buf.capacity, 8);
   635     EXPECT_EQ(memcmp(buf.space, " world!", 7), 0);
   636     EXPECT_EQ(target.pos, 13);
   637     ASSERT_EQ(target.size, 13);
   638     EXPECT_EQ(target.capacity, 16);
   639     EXPECT_EQ(memcmp(target.space, "prepfoohello,", 13), 0);
   640 }
   642 class BufferSeek : public BufferFixture {
   643 };
   645 TEST_F(BufferSeek, SetZero) {
   646     int result = cxBufferSeek(&buf, 0, SEEK_SET);
   647     EXPECT_EQ(result, 0);
   648     EXPECT_EQ(buf.pos, 0);
   649 }
   651 TEST_F(BufferSeek, SetValid) {
   652     int result = cxBufferSeek(&buf, 5, SEEK_SET);
   653     EXPECT_EQ(result, 0);
   654     EXPECT_EQ(buf.pos, 5);
   655 }
   657 TEST_F(BufferSeek, SetInvalid) {
   658     ASSERT_EQ(buf.pos, 3);
   659     int result = cxBufferSeek(&buf, 6, SEEK_SET);
   660     EXPECT_NE(result, 0);
   661     EXPECT_EQ(buf.pos, 3);
   662 }
   664 TEST_F(BufferSeek, CurZero) {
   665     ASSERT_EQ(buf.pos, 3);
   666     int result = cxBufferSeek(&buf, 0, SEEK_CUR);
   667     EXPECT_EQ(result, 0);
   668     EXPECT_EQ(buf.pos, 3);
   669 }
   671 TEST_F(BufferSeek, CurValidPositive) {
   672     ASSERT_EQ(buf.pos, 3);
   673     int result = cxBufferSeek(&buf, 2, SEEK_CUR);
   674     EXPECT_EQ(result, 0);
   675     EXPECT_EQ(buf.pos, 5);
   676 }
   678 TEST_F(BufferSeek, CurValidNegative) {
   679     ASSERT_EQ(buf.pos, 3);
   680     int result = cxBufferSeek(&buf, -3, SEEK_CUR);
   681     EXPECT_EQ(result, 0);
   682     EXPECT_EQ(buf.pos, 0);
   683 }
   685 TEST_F(BufferSeek, CurInvalidPositive) {
   686     ASSERT_EQ(buf.pos, 3);
   687     int result = cxBufferSeek(&buf, 3, SEEK_CUR);
   688     EXPECT_NE(result, 0);
   689     EXPECT_EQ(buf.pos, 3);
   690 }
   692 TEST_F(BufferSeek, CurInvalidNegative) {
   693     ASSERT_EQ(buf.pos, 3);
   694     int result = cxBufferSeek(&buf, -4, SEEK_CUR);
   695     EXPECT_NE(result, 0);
   696     EXPECT_EQ(buf.pos, 3);
   697 }
   699 TEST_F(BufferSeek, EndZero) {
   700     ASSERT_EQ(buf.size, 6);
   701     int result = cxBufferSeek(&buf, 0, SEEK_END);
   702     // the (past-the-)end position is always invalid
   703     EXPECT_NE(result, 0);
   704     EXPECT_EQ(buf.pos, 3);
   705 }
   707 TEST_F(BufferSeek, EndValid) {
   708     ASSERT_EQ(buf.size, 6);
   709     int result = cxBufferSeek(&buf, -6, SEEK_END);
   710     EXPECT_EQ(result, 0);
   711     EXPECT_EQ(buf.pos, 0);
   712 }
   714 TEST_F(BufferSeek, EndInvalid) {
   715     ASSERT_EQ(buf.size, 6);
   716     int result = cxBufferSeek(&buf, 1, SEEK_END);
   717     EXPECT_NE(result, 0);
   718     EXPECT_EQ(buf.pos, 3);
   719 }
   721 TEST_F(BufferSeek, WhenceInvalid) {
   722     ASSERT_EQ(buf.size, 6);
   723     ASSERT_EQ(buf.pos, 3);
   724     int result = cxBufferSeek(&buf, 2, 9000);
   725     EXPECT_NE(result, 0);
   726     EXPECT_EQ(buf.size, 6);
   727     EXPECT_EQ(buf.pos, 3);
   728 }
   730 class BufferEof : public BufferFixture {
   731 };
   733 TEST_F(BufferEof, Reached) {
   734     buf.pos = buf.size;
   735     EXPECT_TRUE(cxBufferEof(&buf));
   736     buf.pos = buf.size - 1;
   737     ASSERT_FALSE(cxBufferEof(&buf));
   738     cxBufferPut(&buf, 'a');
   739     EXPECT_TRUE(cxBufferEof(&buf));
   740 }
   742 TEST_F(BufferEof, NotReached) {
   743     buf.pos = buf.size - 1;
   744     EXPECT_FALSE(cxBufferEof(&buf));
   745     buf.pos = 0;
   746     cxBufferWrite("test", 1, 5, &buf);
   747     EXPECT_FALSE(cxBufferEof(&buf));
   748 }
   750 class BufferRead : public ::testing::Test {
   751 protected:
   752     CxBuffer buf{};
   754     void SetUp() override {
   755         cxBufferInit(&buf, nullptr, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
   756         buf.capacity = 8; // artificially reduce capacity to check OOB writes
   757         memset(buf.space, 0, 16);
   758         memcpy(buf.space, "some data", 9);
   759         buf.size = 9;
   760     }
   762     void TearDown() override {
   763         cxBufferDestroy(&buf);
   764     }
   765 };
   767 TEST_F(BufferRead, GetByte) {
   768     buf.pos = 2;
   769     EXPECT_EQ(cxBufferGet(&buf), 'm');
   770     EXPECT_EQ(cxBufferGet(&buf), 'e');
   771     EXPECT_EQ(cxBufferGet(&buf), ' ');
   772     EXPECT_EQ(cxBufferGet(&buf), 'd');
   773     EXPECT_EQ(buf.pos, 6);
   774 }
   776 TEST_F(BufferRead, GetEof) {
   777     buf.pos = buf.size;
   778     EXPECT_EQ(cxBufferGet(&buf), EOF);
   779 }
   781 TEST_F(BufferRead, ReadWithinBounds) {
   782     buf.pos = 2;
   783     char target[4];
   784     auto read = cxBufferRead(&target, 1, 4, &buf);
   785     ASSERT_EQ(read, 4);
   786     EXPECT_EQ(memcmp(&target, "me d", 4), 0);
   787     EXPECT_EQ(buf.pos, 6);
   788 }
   790 TEST_F(BufferRead, ReadOutOfBounds) {
   791     buf.pos = 6;
   792     char target[4];
   793     auto read = cxBufferRead(&target, 1, 4, &buf);
   794     ASSERT_EQ(read, 3);
   795     EXPECT_EQ(memcmp(&target, "ata", 3), 0);
   796     EXPECT_EQ(buf.pos, 9);
   797 }
   799 TEST_F(BufferRead, ReadOutOfBoundsMultibyte) {
   800     buf.pos = 6;
   801     char target[4];
   802     target[2] = '\0';
   803     auto read = cxBufferRead(&target, 2, 2, &buf);
   804     ASSERT_EQ(read, 1);
   805     EXPECT_EQ(memcmp(&target, "at\0", 3), 0);
   806     EXPECT_EQ(buf.pos, 8);
   807 }
   809 TEST_F(BufferRead, ReadEof) {
   810     buf.pos = 9;
   811     char target[4];
   812     auto read = cxBufferRead(&target, 1, 1, &buf);
   813     ASSERT_EQ(read, 0);
   814     EXPECT_EQ(buf.pos, 9);
   815 }

mercurial