tests/test_buffer.cpp

Wed, 03 Jan 2024 22:17:40 +0100

author
Mike Becker <universe@uap-core.de>
date
Wed, 03 Jan 2024 22:17:40 +0100
changeset 792
3ca984931e1d
parent 789
9b2f5661bebd
permissions
-rw-r--r--

migrate more buffer tests - relates to #342

only read and write tests are remaining now

     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 BufferWrite : public ::testing::Test {
    35 protected:
    36     CxBuffer buf{}, target{};
    38     void SetUp() override {
    39         cxBufferInit(&target, NULL, 16, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND);
    40         cxBufferInit(&buf, NULL, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
    41         buf.capacity = 8; // artificially reduce capacity to check OOB writes
    42         memset(buf.space, 0, 16);
    43         memcpy(buf.space, "prep", 4);
    44         buf.size = buf.pos = 4;
    45     }
    47     void TearDown() override {
    48         cxBufferDestroy(&buf);
    49         cxBufferDestroy(&target);
    50     }
    52     void enableFlushing() {
    53         buf.flush_target = &target;
    54         buf.flush_func = reinterpret_cast<cx_write_func>(cxBufferWrite);
    55         buf.flush_blkmax = 1;
    56     }
    57 };
    59 static size_t mock_write_limited_rate(
    60         void const *ptr,
    61         size_t size,
    62         __attribute__((unused)) size_t nitems,
    63         CxBuffer *buffer
    64 ) {
    65     // simulate limited target drain capacity
    66     static bool full = false;
    67     if (full) {
    68         full = false;
    69         return 0;
    70     } else {
    71         full = true;
    72         return cxBufferWrite(ptr, size, nitems > 2 ? 2 : nitems, buffer);
    73     }
    74 }
    76 TEST_F(BufferWrite, SizeOneFit) {
    77     const char *data = "test";
    78     CX_TEST_ASSERT(buf.capacity == 8);
    79     CX_TEST_ASSERT(buf.pos == 4);
    80     CX_TEST_ASSERT(buf.size == 4);
    81     size_t written = cxBufferWrite(data, 1, 4, &buf);
    82     CX_TEST_ASSERT(written == 4);
    83     CX_TEST_ASSERT(buf.size == 8);
    84     CX_TEST_ASSERT(buf.pos == 8);
    85     CX_TEST_ASSERT(buf.capacity == 8);
    86     EXPECT_EQ(memcmp(buf.space, "preptest", 8), 0);
    87 }
    89 TEST_F(BufferWrite, SizeOneDiscard) {
    90     const char *data = "testing";
    91     CX_TEST_ASSERT(buf.capacity == 8);
    92     CX_TEST_ASSERT(buf.pos == 4);
    93     CX_TEST_ASSERT(buf.size == 4);
    94     size_t written = cxBufferWrite(data, 1, 7, &buf);
    95     CX_TEST_ASSERT(written == 4);
    96     CX_TEST_ASSERT(buf.size == 8);
    97     CX_TEST_ASSERT(buf.pos == 8);
    98     CX_TEST_ASSERT(buf.capacity == 8);
    99     EXPECT_EQ(memcmp(buf.space, "preptest\0", 9), 0);
   100 }
   102 TEST_F(BufferWrite, SizeOneExtend) {
   103     buf.flags |= CX_BUFFER_AUTO_EXTEND;
   104     const char *data = "testing";
   105     CX_TEST_ASSERT(buf.capacity == 8);
   106     CX_TEST_ASSERT(buf.pos == 4);
   107     CX_TEST_ASSERT(buf.size == 4);
   108     size_t written = cxBufferWrite(data, 1, 7, &buf);
   109     CX_TEST_ASSERT(written == 7);
   110     CX_TEST_ASSERT(buf.size == 11);
   111     CX_TEST_ASSERT(buf.pos == 11);
   112     EXPECT_GE(buf.capacity, 11);
   113     EXPECT_EQ(memcmp(buf.space, "preptesting", 11), 0);
   114 }
   116 TEST_F(BufferWrite, MultibyteFit) {
   117     const char *data = "test";
   118     CX_TEST_ASSERT(buf.capacity == 8);
   119     CX_TEST_ASSERT(buf.pos == 4);
   120     CX_TEST_ASSERT(buf.size == 4);
   121     size_t written = cxBufferWrite(data, 2, 2, &buf);
   122     CX_TEST_ASSERT(written == 2);
   123     CX_TEST_ASSERT(buf.size == 8);
   124     CX_TEST_ASSERT(buf.pos == 8);
   125     CX_TEST_ASSERT(buf.capacity == 8);
   126     EXPECT_EQ(memcmp(buf.space, "preptest", 8), 0);
   127 }
   129 TEST_F(BufferWrite, MultibyteDiscard) {
   130     const char *data = "testing";
   131     CX_TEST_ASSERT(buf.capacity == 8);
   132     CX_TEST_ASSERT(buf.size == 4);
   133     buf.pos = 3;
   134     size_t written = cxBufferWrite(data, 2, 4, &buf);
   135     // remember: whole elements are discarded if they do not fit
   136     CX_TEST_ASSERT(written == 2);
   137     CX_TEST_ASSERT(buf.size == 7);
   138     CX_TEST_ASSERT(buf.pos == 7);
   139     CX_TEST_ASSERT(buf.capacity == 8);
   140     EXPECT_EQ(memcmp(buf.space, "pretest\0", 8), 0);
   141 }
   143 TEST_F(BufferWrite, MultibyteExtend) {
   144     buf.flags |= CX_BUFFER_AUTO_EXTEND;
   145     const char *data = "tester";
   146     CX_TEST_ASSERT(buf.capacity == 8);
   147     CX_TEST_ASSERT(buf.size == 4);
   148     buf.pos = 3;
   149     size_t written = cxBufferWrite(data, 2, 3, &buf);
   150     // remember: whole elements are discarded if they do not fit
   151     CX_TEST_ASSERT(written == 3);
   152     CX_TEST_ASSERT(buf.size == 9);
   153     CX_TEST_ASSERT(buf.pos == 9);
   154     EXPECT_GE(buf.capacity, 9);
   155     EXPECT_EQ(memcmp(buf.space, "pretester", 9), 0);
   156 }
   158 TEST_F(BufferWrite, PutcWrapperFit) {
   159     CX_TEST_ASSERT(buf.capacity == 8);
   160     CX_TEST_ASSERT(buf.pos == 4);
   161     CX_TEST_ASSERT(buf.size == 4);
   162     int c = cxBufferPut(&buf, 0x200 | 'a');
   163     CX_TEST_ASSERT(c == 'a');
   164     CX_TEST_ASSERT(buf.size == 5);
   165     CX_TEST_ASSERT(buf.pos == 5);
   166     CX_TEST_ASSERT(buf.capacity == 8);
   167     EXPECT_EQ(memcmp(buf.space, "prepa\0", 6), 0);
   168 }
   170 TEST_F(BufferWrite, PutcWrapperDiscard) {
   171     CX_TEST_ASSERT(buf.capacity == 8);
   172     CX_TEST_ASSERT(buf.size == 4);
   173     buf.pos = 8;
   174     int c = cxBufferPut(&buf, 0x200 | 'a');
   175     CX_TEST_ASSERT(c == EOF);
   176     CX_TEST_ASSERT(buf.size == 4);
   177     CX_TEST_ASSERT(buf.pos == 8);
   178     CX_TEST_ASSERT(buf.capacity == 8);
   179     EXPECT_EQ(memcmp(buf.space, "prep\0\0\0\0\0", 9), 0);
   180 }
   182 TEST_F(BufferWrite, PutcWrapperExtend) {
   183     buf.flags |= CX_BUFFER_AUTO_EXTEND;
   184     CX_TEST_ASSERT(buf.capacity == 8);
   185     CX_TEST_ASSERT(buf.size == 4);
   186     buf.pos = 8;
   187     int c = cxBufferPut(&buf, 0x200 | 'a');
   188     CX_TEST_ASSERT(c == 'a');
   189     CX_TEST_ASSERT(buf.size == 9);
   190     CX_TEST_ASSERT(buf.pos == 9);
   191     EXPECT_GE(buf.capacity, 9);
   192     EXPECT_EQ(memcmp(buf.space, "prep\0\0\0\0a", 9), 0);
   193 }
   195 TEST_F(BufferWrite, PutStringWrapperFit) {
   196     const char *data = "test";
   197     CX_TEST_ASSERT(buf.capacity == 8);
   198     CX_TEST_ASSERT(buf.pos == 4);
   199     CX_TEST_ASSERT(buf.size == 4);
   200     size_t written = cxBufferPutString(&buf, data);
   201     CX_TEST_ASSERT(written == 4);
   202     CX_TEST_ASSERT(buf.size == 8);
   203     CX_TEST_ASSERT(buf.pos == 8);
   204     CX_TEST_ASSERT(buf.capacity == 8);
   205     EXPECT_EQ(memcmp(buf.space, "preptest", 8), 0);
   206 }
   208 TEST_F(BufferWrite, PutStringWrapperDiscard) {
   209     const char *data = "testing";
   210     CX_TEST_ASSERT(buf.capacity == 8);
   211     CX_TEST_ASSERT(buf.pos == 4);
   212     CX_TEST_ASSERT(buf.size == 4);
   213     size_t written = cxBufferPutString(&buf, data);
   214     CX_TEST_ASSERT(written == 4);
   215     CX_TEST_ASSERT(buf.size == 8);
   216     CX_TEST_ASSERT(buf.pos == 8);
   217     CX_TEST_ASSERT(buf.capacity == 8);
   218     EXPECT_EQ(memcmp(buf.space, "preptest\0", 9), 0);
   219 }
   221 TEST_F(BufferWrite, PutStringWrapperExtend) {
   222     buf.flags |= CX_BUFFER_AUTO_EXTEND;
   223     const char *data = "testing";
   224     CX_TEST_ASSERT(buf.capacity == 8);
   225     CX_TEST_ASSERT(buf.pos == 4);
   226     CX_TEST_ASSERT(buf.size == 4);
   227     size_t written = cxBufferPutString(&buf, data);
   228     CX_TEST_ASSERT(written == 7);
   229     CX_TEST_ASSERT(buf.size == 11);
   230     CX_TEST_ASSERT(buf.pos == 11);
   231     EXPECT_GE(buf.capacity, 11);
   232     EXPECT_EQ(memcmp(buf.space, "preptesting", 11), 0);
   233 }
   235 TEST_F(BufferWrite, MultOverflow) {
   236     const char *data = "testing";
   237     CX_TEST_ASSERT(buf.capacity == 8);
   238     CX_TEST_ASSERT(buf.pos == 4);
   239     CX_TEST_ASSERT(buf.size == 4);
   240     size_t written = cxBufferWrite(data, 8, SIZE_MAX / 4, &buf);
   241     CX_TEST_ASSERT(written == 0);
   242     CX_TEST_ASSERT(buf.capacity == 8);
   243     CX_TEST_ASSERT(buf.pos == 4);
   244     CX_TEST_ASSERT(buf.size == 4);
   245     EXPECT_EQ(memcmp(buf.space, "prep\0", 5), 0);
   246 }
   248 TEST_F(BufferWrite, MaxCapaOverflow) {
   249     buf.flags |= CX_BUFFER_AUTO_EXTEND;
   250     const char *data = "testing";
   251     CX_TEST_ASSERT(buf.capacity == 8);
   252     CX_TEST_ASSERT(buf.pos == 4);
   253     CX_TEST_ASSERT(buf.size == 4);
   254     size_t written = cxBufferWrite(data, 1, SIZE_MAX - 2, &buf);
   255     CX_TEST_ASSERT(written == 0);
   256     CX_TEST_ASSERT(buf.capacity == 8);
   257     CX_TEST_ASSERT(buf.pos == 4);
   258     CX_TEST_ASSERT(buf.size == 4);
   259     EXPECT_EQ(memcmp(buf.space, "prep\0", 5), 0);
   260 }
   262 TEST_F(BufferWrite, OnlyOverwrite) {
   263     buf.flags |= CX_BUFFER_AUTO_EXTEND;
   264     CX_TEST_ASSERT(buf.capacity == 8);
   265     memcpy(buf.space, "preptest", 8);
   266     buf.pos = 3;
   267     buf.size = 8;
   268     size_t written = cxBufferWrite("XXX", 2, 2, &buf);
   269     CX_TEST_ASSERT(written == 2);
   270     CX_TEST_ASSERT(buf.capacity == 8);
   271     CX_TEST_ASSERT(buf.size == 8);
   272     CX_TEST_ASSERT(buf.pos == 7);
   273     EXPECT_EQ(memcmp(buf.space, "preXXX\0t", 8), 0);
   274 }
   276 TEST_F(BufferWrite, FlushAtCapacity) {
   277     enableFlushing();
   278     CX_TEST_ASSERT(buf.capacity == 8);
   279     CX_TEST_ASSERT(buf.pos == 4);
   280     size_t written = cxBufferWrite("foo", 1, 3, &buf);
   281     CX_TEST_ASSERT(written == 3);
   282     CX_TEST_ASSERT(buf.pos == 7);
   283     CX_TEST_ASSERT(buf.size == 7);
   284     CX_TEST_ASSERT(target.pos == 0);
   285     CX_TEST_ASSERT(target.size == 0);
   286     written = cxBufferWrite("hello", 1, 5, &buf);
   287     CX_TEST_ASSERT(written == 5);
   288     CX_TEST_ASSERT(buf.pos == 0);
   289     CX_TEST_ASSERT(buf.size == 0);
   290     CX_TEST_ASSERT(buf.capacity == 8);
   291     CX_TEST_ASSERT(target.pos == 12);
   292     CX_TEST_ASSERT(target.size == 12);
   293     EXPECT_EQ(memcmp(target.space, "prepfoohello", 12), 0);
   294 }
   296 TEST_F(BufferWrite, FlushAtThreshold) {
   297     enableFlushing();
   298     buf.flush_threshold = 12;
   299     buf.flags |= CX_BUFFER_AUTO_EXTEND;
   300     CX_TEST_ASSERT(buf.capacity == 8);
   301     CX_TEST_ASSERT(buf.pos == 4);
   302     size_t written = cxBufferWrite("foobar", 1, 6, &buf);
   303     CX_TEST_ASSERT(written == 6);
   304     CX_TEST_ASSERT(buf.pos == 10);
   305     CX_TEST_ASSERT(buf.size == 10);
   306     ASSERT_GE(buf.capacity, 10);
   307     ASSERT_LE(buf.capacity, 12);
   308     CX_TEST_ASSERT(target.pos == 0);
   309     CX_TEST_ASSERT(target.size == 0);
   310     written = cxBufferWrite("hello", 1, 5, &buf);
   311     CX_TEST_ASSERT(written == 5);
   312     CX_TEST_ASSERT(buf.pos == 0);
   313     CX_TEST_ASSERT(buf.size == 0);
   314     EXPECT_LE(buf.capacity, 12);
   315     CX_TEST_ASSERT(target.pos == 15);
   316     CX_TEST_ASSERT(target.size == 15);
   317     EXPECT_EQ(memcmp(target.space, "prepfoobarhello", 15), 0);
   318 }
   320 TEST_F(BufferWrite, FlushRateLimited) {
   321     enableFlushing();
   322     // limit the rate of the flush function and the capacity of the target
   323     target.capacity = 16;
   324     target.flags &= ~CX_BUFFER_AUTO_EXTEND;
   325     buf.flush_func = (cx_write_func) mock_write_limited_rate;
   326     CX_TEST_ASSERT(buf.capacity == 8);
   327     CX_TEST_ASSERT(buf.pos == 4);
   328     size_t written = cxBufferWrite("foo", 1, 3, &buf);
   329     CX_TEST_ASSERT(written == 3);
   330     CX_TEST_ASSERT(buf.pos == 7);
   331     CX_TEST_ASSERT(buf.size == 7);
   332     CX_TEST_ASSERT(target.pos == 0);
   333     CX_TEST_ASSERT(target.size == 0);
   334     written = cxBufferWrite("hello, world!", 1, 13, &buf);
   335     // " world!" fits into this buffer, the remaining stuff is flushed out
   336     CX_TEST_ASSERT(written == 13);
   337     CX_TEST_ASSERT(buf.pos == 7);
   338     CX_TEST_ASSERT(buf.size == 7);
   339     CX_TEST_ASSERT(buf.capacity == 8);
   340     EXPECT_EQ(memcmp(buf.space, " world!", 7), 0);
   341     CX_TEST_ASSERT(target.pos == 13);
   342     CX_TEST_ASSERT(target.size == 13);
   343     CX_TEST_ASSERT(target.capacity == 16);
   344     EXPECT_EQ(memcmp(target.space, "prepfoohello,", 13), 0);
   345 }
   347 class BufferRead : public ::testing::Test {
   348 protected:
   349     CxBuffer buf{};
   351     void SetUp() override {
   352         cxBufferInit(&buf, NULL, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
   353         buf.capacity = 8; // artificially reduce capacity to check OOB writes
   354         memset(buf.space, 0, 16);
   355         memcpy(buf.space, "some data", 9);
   356         buf.size = 9;
   357     }
   359     void TearDown() override {
   360         cxBufferDestroy(&buf);
   361     }
   362 };
   364 TEST_F(BufferRead, GetByte) {
   365     buf.pos = 2;
   366     EXPECT_EQ(cxBufferGet(&buf), 'm');
   367     EXPECT_EQ(cxBufferGet(&buf), 'e');
   368     EXPECT_EQ(cxBufferGet(&buf), ' ');
   369     EXPECT_EQ(cxBufferGet(&buf), 'd');
   370     CX_TEST_ASSERT(buf.pos == 6);
   371 }
   373 TEST_F(BufferRead, GetEof) {
   374     buf.pos = buf.size;
   375     EXPECT_EQ(cxBufferGet(&buf), EOF);
   376 }
   378 TEST_F(BufferRead, ReadWithinBounds) {
   379     buf.pos = 2;
   380     char target[4];
   381     auto read = cxBufferRead(&target, 1, 4, &buf);
   382     CX_TEST_ASSERT(read == 4);
   383     EXPECT_EQ(memcmp(&target, "me d", 4), 0);
   384     CX_TEST_ASSERT(buf.pos == 6);
   385 }
   387 TEST_F(BufferRead, ReadOutOfBounds) {
   388     buf.pos = 6;
   389     char target[4];
   390     auto read = cxBufferRead(&target, 1, 4, &buf);
   391     CX_TEST_ASSERT(read == 3);
   392     EXPECT_EQ(memcmp(&target, "ata", 3), 0);
   393     CX_TEST_ASSERT(buf.pos == 9);
   394 }
   396 TEST_F(BufferRead, ReadOutOfBoundsMultibyte) {
   397     buf.pos = 6;
   398     char target[4];
   399     target[2] = '\0';
   400     auto read = cxBufferRead(&target, 2, 2, &buf);
   401     CX_TEST_ASSERT(read == 1);
   402     EXPECT_EQ(memcmp(&target, "at\0", 3), 0);
   403     CX_TEST_ASSERT(buf.pos == 8);
   404 }
   406 TEST_F(BufferRead, ReadEof) {
   407     buf.pos = 9;
   408     char target[4];
   409     auto read = cxBufferRead(&target, 1, 1, &buf);
   410     CX_TEST_ASSERT(read == 0);
   411     CX_TEST_ASSERT(buf.pos == 9);
   412 }

mercurial