1.1 --- a/tests/test_buffer.cpp Wed Jan 03 22:17:40 2024 +0100 1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 1.3 @@ -1,412 +0,0 @@ 1.4 -/* 1.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 1.6 - * 1.7 - * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved. 1.8 - * 1.9 - * Redistribution and use in source and binary forms, with or without 1.10 - * modification, are permitted provided that the following conditions are met: 1.11 - * 1.12 - * 1. Redistributions of source code must retain the above copyright 1.13 - * notice, this list of conditions and the following disclaimer. 1.14 - * 1.15 - * 2. Redistributions in binary form must reproduce the above copyright 1.16 - * notice, this list of conditions and the following disclaimer in the 1.17 - * documentation and/or other materials provided with the distribution. 1.18 - * 1.19 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 1.20 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1.21 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1.22 - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 1.23 - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 1.24 - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 1.25 - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 1.26 - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 1.27 - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 1.28 - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 1.29 - * POSSIBILITY OF SUCH DAMAGE. 1.30 - */ 1.31 - 1.32 -#include "cx/buffer.h" 1.33 - 1.34 -#include <gtest/gtest.h> 1.35 -#include "util_allocator.h" 1.36 - 1.37 -class BufferWrite : public ::testing::Test { 1.38 -protected: 1.39 - CxBuffer buf{}, target{}; 1.40 - 1.41 - void SetUp() override { 1.42 - cxBufferInit(&target, NULL, 16, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND); 1.43 - cxBufferInit(&buf, NULL, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT); 1.44 - buf.capacity = 8; // artificially reduce capacity to check OOB writes 1.45 - memset(buf.space, 0, 16); 1.46 - memcpy(buf.space, "prep", 4); 1.47 - buf.size = buf.pos = 4; 1.48 - } 1.49 - 1.50 - void TearDown() override { 1.51 - cxBufferDestroy(&buf); 1.52 - cxBufferDestroy(&target); 1.53 - } 1.54 - 1.55 - void enableFlushing() { 1.56 - buf.flush_target = ⌖ 1.57 - buf.flush_func = reinterpret_cast<cx_write_func>(cxBufferWrite); 1.58 - buf.flush_blkmax = 1; 1.59 - } 1.60 -}; 1.61 - 1.62 -static size_t mock_write_limited_rate( 1.63 - void const *ptr, 1.64 - size_t size, 1.65 - __attribute__((unused)) size_t nitems, 1.66 - CxBuffer *buffer 1.67 -) { 1.68 - // simulate limited target drain capacity 1.69 - static bool full = false; 1.70 - if (full) { 1.71 - full = false; 1.72 - return 0; 1.73 - } else { 1.74 - full = true; 1.75 - return cxBufferWrite(ptr, size, nitems > 2 ? 2 : nitems, buffer); 1.76 - } 1.77 -} 1.78 - 1.79 -TEST_F(BufferWrite, SizeOneFit) { 1.80 - const char *data = "test"; 1.81 - CX_TEST_ASSERT(buf.capacity == 8); 1.82 - CX_TEST_ASSERT(buf.pos == 4); 1.83 - CX_TEST_ASSERT(buf.size == 4); 1.84 - size_t written = cxBufferWrite(data, 1, 4, &buf); 1.85 - CX_TEST_ASSERT(written == 4); 1.86 - CX_TEST_ASSERT(buf.size == 8); 1.87 - CX_TEST_ASSERT(buf.pos == 8); 1.88 - CX_TEST_ASSERT(buf.capacity == 8); 1.89 - EXPECT_EQ(memcmp(buf.space, "preptest", 8), 0); 1.90 -} 1.91 - 1.92 -TEST_F(BufferWrite, SizeOneDiscard) { 1.93 - const char *data = "testing"; 1.94 - CX_TEST_ASSERT(buf.capacity == 8); 1.95 - CX_TEST_ASSERT(buf.pos == 4); 1.96 - CX_TEST_ASSERT(buf.size == 4); 1.97 - size_t written = cxBufferWrite(data, 1, 7, &buf); 1.98 - CX_TEST_ASSERT(written == 4); 1.99 - CX_TEST_ASSERT(buf.size == 8); 1.100 - CX_TEST_ASSERT(buf.pos == 8); 1.101 - CX_TEST_ASSERT(buf.capacity == 8); 1.102 - EXPECT_EQ(memcmp(buf.space, "preptest\0", 9), 0); 1.103 -} 1.104 - 1.105 -TEST_F(BufferWrite, SizeOneExtend) { 1.106 - buf.flags |= CX_BUFFER_AUTO_EXTEND; 1.107 - const char *data = "testing"; 1.108 - CX_TEST_ASSERT(buf.capacity == 8); 1.109 - CX_TEST_ASSERT(buf.pos == 4); 1.110 - CX_TEST_ASSERT(buf.size == 4); 1.111 - size_t written = cxBufferWrite(data, 1, 7, &buf); 1.112 - CX_TEST_ASSERT(written == 7); 1.113 - CX_TEST_ASSERT(buf.size == 11); 1.114 - CX_TEST_ASSERT(buf.pos == 11); 1.115 - EXPECT_GE(buf.capacity, 11); 1.116 - EXPECT_EQ(memcmp(buf.space, "preptesting", 11), 0); 1.117 -} 1.118 - 1.119 -TEST_F(BufferWrite, MultibyteFit) { 1.120 - const char *data = "test"; 1.121 - CX_TEST_ASSERT(buf.capacity == 8); 1.122 - CX_TEST_ASSERT(buf.pos == 4); 1.123 - CX_TEST_ASSERT(buf.size == 4); 1.124 - size_t written = cxBufferWrite(data, 2, 2, &buf); 1.125 - CX_TEST_ASSERT(written == 2); 1.126 - CX_TEST_ASSERT(buf.size == 8); 1.127 - CX_TEST_ASSERT(buf.pos == 8); 1.128 - CX_TEST_ASSERT(buf.capacity == 8); 1.129 - EXPECT_EQ(memcmp(buf.space, "preptest", 8), 0); 1.130 -} 1.131 - 1.132 -TEST_F(BufferWrite, MultibyteDiscard) { 1.133 - const char *data = "testing"; 1.134 - CX_TEST_ASSERT(buf.capacity == 8); 1.135 - CX_TEST_ASSERT(buf.size == 4); 1.136 - buf.pos = 3; 1.137 - size_t written = cxBufferWrite(data, 2, 4, &buf); 1.138 - // remember: whole elements are discarded if they do not fit 1.139 - CX_TEST_ASSERT(written == 2); 1.140 - CX_TEST_ASSERT(buf.size == 7); 1.141 - CX_TEST_ASSERT(buf.pos == 7); 1.142 - CX_TEST_ASSERT(buf.capacity == 8); 1.143 - EXPECT_EQ(memcmp(buf.space, "pretest\0", 8), 0); 1.144 -} 1.145 - 1.146 -TEST_F(BufferWrite, MultibyteExtend) { 1.147 - buf.flags |= CX_BUFFER_AUTO_EXTEND; 1.148 - const char *data = "tester"; 1.149 - CX_TEST_ASSERT(buf.capacity == 8); 1.150 - CX_TEST_ASSERT(buf.size == 4); 1.151 - buf.pos = 3; 1.152 - size_t written = cxBufferWrite(data, 2, 3, &buf); 1.153 - // remember: whole elements are discarded if they do not fit 1.154 - CX_TEST_ASSERT(written == 3); 1.155 - CX_TEST_ASSERT(buf.size == 9); 1.156 - CX_TEST_ASSERT(buf.pos == 9); 1.157 - EXPECT_GE(buf.capacity, 9); 1.158 - EXPECT_EQ(memcmp(buf.space, "pretester", 9), 0); 1.159 -} 1.160 - 1.161 -TEST_F(BufferWrite, PutcWrapperFit) { 1.162 - CX_TEST_ASSERT(buf.capacity == 8); 1.163 - CX_TEST_ASSERT(buf.pos == 4); 1.164 - CX_TEST_ASSERT(buf.size == 4); 1.165 - int c = cxBufferPut(&buf, 0x200 | 'a'); 1.166 - CX_TEST_ASSERT(c == 'a'); 1.167 - CX_TEST_ASSERT(buf.size == 5); 1.168 - CX_TEST_ASSERT(buf.pos == 5); 1.169 - CX_TEST_ASSERT(buf.capacity == 8); 1.170 - EXPECT_EQ(memcmp(buf.space, "prepa\0", 6), 0); 1.171 -} 1.172 - 1.173 -TEST_F(BufferWrite, PutcWrapperDiscard) { 1.174 - CX_TEST_ASSERT(buf.capacity == 8); 1.175 - CX_TEST_ASSERT(buf.size == 4); 1.176 - buf.pos = 8; 1.177 - int c = cxBufferPut(&buf, 0x200 | 'a'); 1.178 - CX_TEST_ASSERT(c == EOF); 1.179 - CX_TEST_ASSERT(buf.size == 4); 1.180 - CX_TEST_ASSERT(buf.pos == 8); 1.181 - CX_TEST_ASSERT(buf.capacity == 8); 1.182 - EXPECT_EQ(memcmp(buf.space, "prep\0\0\0\0\0", 9), 0); 1.183 -} 1.184 - 1.185 -TEST_F(BufferWrite, PutcWrapperExtend) { 1.186 - buf.flags |= CX_BUFFER_AUTO_EXTEND; 1.187 - CX_TEST_ASSERT(buf.capacity == 8); 1.188 - CX_TEST_ASSERT(buf.size == 4); 1.189 - buf.pos = 8; 1.190 - int c = cxBufferPut(&buf, 0x200 | 'a'); 1.191 - CX_TEST_ASSERT(c == 'a'); 1.192 - CX_TEST_ASSERT(buf.size == 9); 1.193 - CX_TEST_ASSERT(buf.pos == 9); 1.194 - EXPECT_GE(buf.capacity, 9); 1.195 - EXPECT_EQ(memcmp(buf.space, "prep\0\0\0\0a", 9), 0); 1.196 -} 1.197 - 1.198 -TEST_F(BufferWrite, PutStringWrapperFit) { 1.199 - const char *data = "test"; 1.200 - CX_TEST_ASSERT(buf.capacity == 8); 1.201 - CX_TEST_ASSERT(buf.pos == 4); 1.202 - CX_TEST_ASSERT(buf.size == 4); 1.203 - size_t written = cxBufferPutString(&buf, data); 1.204 - CX_TEST_ASSERT(written == 4); 1.205 - CX_TEST_ASSERT(buf.size == 8); 1.206 - CX_TEST_ASSERT(buf.pos == 8); 1.207 - CX_TEST_ASSERT(buf.capacity == 8); 1.208 - EXPECT_EQ(memcmp(buf.space, "preptest", 8), 0); 1.209 -} 1.210 - 1.211 -TEST_F(BufferWrite, PutStringWrapperDiscard) { 1.212 - const char *data = "testing"; 1.213 - CX_TEST_ASSERT(buf.capacity == 8); 1.214 - CX_TEST_ASSERT(buf.pos == 4); 1.215 - CX_TEST_ASSERT(buf.size == 4); 1.216 - size_t written = cxBufferPutString(&buf, data); 1.217 - CX_TEST_ASSERT(written == 4); 1.218 - CX_TEST_ASSERT(buf.size == 8); 1.219 - CX_TEST_ASSERT(buf.pos == 8); 1.220 - CX_TEST_ASSERT(buf.capacity == 8); 1.221 - EXPECT_EQ(memcmp(buf.space, "preptest\0", 9), 0); 1.222 -} 1.223 - 1.224 -TEST_F(BufferWrite, PutStringWrapperExtend) { 1.225 - buf.flags |= CX_BUFFER_AUTO_EXTEND; 1.226 - const char *data = "testing"; 1.227 - CX_TEST_ASSERT(buf.capacity == 8); 1.228 - CX_TEST_ASSERT(buf.pos == 4); 1.229 - CX_TEST_ASSERT(buf.size == 4); 1.230 - size_t written = cxBufferPutString(&buf, data); 1.231 - CX_TEST_ASSERT(written == 7); 1.232 - CX_TEST_ASSERT(buf.size == 11); 1.233 - CX_TEST_ASSERT(buf.pos == 11); 1.234 - EXPECT_GE(buf.capacity, 11); 1.235 - EXPECT_EQ(memcmp(buf.space, "preptesting", 11), 0); 1.236 -} 1.237 - 1.238 -TEST_F(BufferWrite, MultOverflow) { 1.239 - const char *data = "testing"; 1.240 - CX_TEST_ASSERT(buf.capacity == 8); 1.241 - CX_TEST_ASSERT(buf.pos == 4); 1.242 - CX_TEST_ASSERT(buf.size == 4); 1.243 - size_t written = cxBufferWrite(data, 8, SIZE_MAX / 4, &buf); 1.244 - CX_TEST_ASSERT(written == 0); 1.245 - CX_TEST_ASSERT(buf.capacity == 8); 1.246 - CX_TEST_ASSERT(buf.pos == 4); 1.247 - CX_TEST_ASSERT(buf.size == 4); 1.248 - EXPECT_EQ(memcmp(buf.space, "prep\0", 5), 0); 1.249 -} 1.250 - 1.251 -TEST_F(BufferWrite, MaxCapaOverflow) { 1.252 - buf.flags |= CX_BUFFER_AUTO_EXTEND; 1.253 - const char *data = "testing"; 1.254 - CX_TEST_ASSERT(buf.capacity == 8); 1.255 - CX_TEST_ASSERT(buf.pos == 4); 1.256 - CX_TEST_ASSERT(buf.size == 4); 1.257 - size_t written = cxBufferWrite(data, 1, SIZE_MAX - 2, &buf); 1.258 - CX_TEST_ASSERT(written == 0); 1.259 - CX_TEST_ASSERT(buf.capacity == 8); 1.260 - CX_TEST_ASSERT(buf.pos == 4); 1.261 - CX_TEST_ASSERT(buf.size == 4); 1.262 - EXPECT_EQ(memcmp(buf.space, "prep\0", 5), 0); 1.263 -} 1.264 - 1.265 -TEST_F(BufferWrite, OnlyOverwrite) { 1.266 - buf.flags |= CX_BUFFER_AUTO_EXTEND; 1.267 - CX_TEST_ASSERT(buf.capacity == 8); 1.268 - memcpy(buf.space, "preptest", 8); 1.269 - buf.pos = 3; 1.270 - buf.size = 8; 1.271 - size_t written = cxBufferWrite("XXX", 2, 2, &buf); 1.272 - CX_TEST_ASSERT(written == 2); 1.273 - CX_TEST_ASSERT(buf.capacity == 8); 1.274 - CX_TEST_ASSERT(buf.size == 8); 1.275 - CX_TEST_ASSERT(buf.pos == 7); 1.276 - EXPECT_EQ(memcmp(buf.space, "preXXX\0t", 8), 0); 1.277 -} 1.278 - 1.279 -TEST_F(BufferWrite, FlushAtCapacity) { 1.280 - enableFlushing(); 1.281 - CX_TEST_ASSERT(buf.capacity == 8); 1.282 - CX_TEST_ASSERT(buf.pos == 4); 1.283 - size_t written = cxBufferWrite("foo", 1, 3, &buf); 1.284 - CX_TEST_ASSERT(written == 3); 1.285 - CX_TEST_ASSERT(buf.pos == 7); 1.286 - CX_TEST_ASSERT(buf.size == 7); 1.287 - CX_TEST_ASSERT(target.pos == 0); 1.288 - CX_TEST_ASSERT(target.size == 0); 1.289 - written = cxBufferWrite("hello", 1, 5, &buf); 1.290 - CX_TEST_ASSERT(written == 5); 1.291 - CX_TEST_ASSERT(buf.pos == 0); 1.292 - CX_TEST_ASSERT(buf.size == 0); 1.293 - CX_TEST_ASSERT(buf.capacity == 8); 1.294 - CX_TEST_ASSERT(target.pos == 12); 1.295 - CX_TEST_ASSERT(target.size == 12); 1.296 - EXPECT_EQ(memcmp(target.space, "prepfoohello", 12), 0); 1.297 -} 1.298 - 1.299 -TEST_F(BufferWrite, FlushAtThreshold) { 1.300 - enableFlushing(); 1.301 - buf.flush_threshold = 12; 1.302 - buf.flags |= CX_BUFFER_AUTO_EXTEND; 1.303 - CX_TEST_ASSERT(buf.capacity == 8); 1.304 - CX_TEST_ASSERT(buf.pos == 4); 1.305 - size_t written = cxBufferWrite("foobar", 1, 6, &buf); 1.306 - CX_TEST_ASSERT(written == 6); 1.307 - CX_TEST_ASSERT(buf.pos == 10); 1.308 - CX_TEST_ASSERT(buf.size == 10); 1.309 - ASSERT_GE(buf.capacity, 10); 1.310 - ASSERT_LE(buf.capacity, 12); 1.311 - CX_TEST_ASSERT(target.pos == 0); 1.312 - CX_TEST_ASSERT(target.size == 0); 1.313 - written = cxBufferWrite("hello", 1, 5, &buf); 1.314 - CX_TEST_ASSERT(written == 5); 1.315 - CX_TEST_ASSERT(buf.pos == 0); 1.316 - CX_TEST_ASSERT(buf.size == 0); 1.317 - EXPECT_LE(buf.capacity, 12); 1.318 - CX_TEST_ASSERT(target.pos == 15); 1.319 - CX_TEST_ASSERT(target.size == 15); 1.320 - EXPECT_EQ(memcmp(target.space, "prepfoobarhello", 15), 0); 1.321 -} 1.322 - 1.323 -TEST_F(BufferWrite, FlushRateLimited) { 1.324 - enableFlushing(); 1.325 - // limit the rate of the flush function and the capacity of the target 1.326 - target.capacity = 16; 1.327 - target.flags &= ~CX_BUFFER_AUTO_EXTEND; 1.328 - buf.flush_func = (cx_write_func) mock_write_limited_rate; 1.329 - CX_TEST_ASSERT(buf.capacity == 8); 1.330 - CX_TEST_ASSERT(buf.pos == 4); 1.331 - size_t written = cxBufferWrite("foo", 1, 3, &buf); 1.332 - CX_TEST_ASSERT(written == 3); 1.333 - CX_TEST_ASSERT(buf.pos == 7); 1.334 - CX_TEST_ASSERT(buf.size == 7); 1.335 - CX_TEST_ASSERT(target.pos == 0); 1.336 - CX_TEST_ASSERT(target.size == 0); 1.337 - written = cxBufferWrite("hello, world!", 1, 13, &buf); 1.338 - // " world!" fits into this buffer, the remaining stuff is flushed out 1.339 - CX_TEST_ASSERT(written == 13); 1.340 - CX_TEST_ASSERT(buf.pos == 7); 1.341 - CX_TEST_ASSERT(buf.size == 7); 1.342 - CX_TEST_ASSERT(buf.capacity == 8); 1.343 - EXPECT_EQ(memcmp(buf.space, " world!", 7), 0); 1.344 - CX_TEST_ASSERT(target.pos == 13); 1.345 - CX_TEST_ASSERT(target.size == 13); 1.346 - CX_TEST_ASSERT(target.capacity == 16); 1.347 - EXPECT_EQ(memcmp(target.space, "prepfoohello,", 13), 0); 1.348 -} 1.349 - 1.350 -class BufferRead : public ::testing::Test { 1.351 -protected: 1.352 - CxBuffer buf{}; 1.353 - 1.354 - void SetUp() override { 1.355 - cxBufferInit(&buf, NULL, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT); 1.356 - buf.capacity = 8; // artificially reduce capacity to check OOB writes 1.357 - memset(buf.space, 0, 16); 1.358 - memcpy(buf.space, "some data", 9); 1.359 - buf.size = 9; 1.360 - } 1.361 - 1.362 - void TearDown() override { 1.363 - cxBufferDestroy(&buf); 1.364 - } 1.365 -}; 1.366 - 1.367 -TEST_F(BufferRead, GetByte) { 1.368 - buf.pos = 2; 1.369 - EXPECT_EQ(cxBufferGet(&buf), 'm'); 1.370 - EXPECT_EQ(cxBufferGet(&buf), 'e'); 1.371 - EXPECT_EQ(cxBufferGet(&buf), ' '); 1.372 - EXPECT_EQ(cxBufferGet(&buf), 'd'); 1.373 - CX_TEST_ASSERT(buf.pos == 6); 1.374 -} 1.375 - 1.376 -TEST_F(BufferRead, GetEof) { 1.377 - buf.pos = buf.size; 1.378 - EXPECT_EQ(cxBufferGet(&buf), EOF); 1.379 -} 1.380 - 1.381 -TEST_F(BufferRead, ReadWithinBounds) { 1.382 - buf.pos = 2; 1.383 - char target[4]; 1.384 - auto read = cxBufferRead(&target, 1, 4, &buf); 1.385 - CX_TEST_ASSERT(read == 4); 1.386 - EXPECT_EQ(memcmp(&target, "me d", 4), 0); 1.387 - CX_TEST_ASSERT(buf.pos == 6); 1.388 -} 1.389 - 1.390 -TEST_F(BufferRead, ReadOutOfBounds) { 1.391 - buf.pos = 6; 1.392 - char target[4]; 1.393 - auto read = cxBufferRead(&target, 1, 4, &buf); 1.394 - CX_TEST_ASSERT(read == 3); 1.395 - EXPECT_EQ(memcmp(&target, "ata", 3), 0); 1.396 - CX_TEST_ASSERT(buf.pos == 9); 1.397 -} 1.398 - 1.399 -TEST_F(BufferRead, ReadOutOfBoundsMultibyte) { 1.400 - buf.pos = 6; 1.401 - char target[4]; 1.402 - target[2] = '\0'; 1.403 - auto read = cxBufferRead(&target, 2, 2, &buf); 1.404 - CX_TEST_ASSERT(read == 1); 1.405 - EXPECT_EQ(memcmp(&target, "at\0", 3), 0); 1.406 - CX_TEST_ASSERT(buf.pos == 8); 1.407 -} 1.408 - 1.409 -TEST_F(BufferRead, ReadEof) { 1.410 - buf.pos = 9; 1.411 - char target[4]; 1.412 - auto read = cxBufferRead(&target, 1, 1, &buf); 1.413 - CX_TEST_ASSERT(read == 0); 1.414 - CX_TEST_ASSERT(buf.pos == 9); 1.415 -}