test/test_buffer.cpp

Tue, 04 Oct 2022 19:25:07 +0200

author
Mike Becker <universe@uap-core.de>
date
Tue, 04 Oct 2022 19:25:07 +0200
changeset 591
7df0bcaecffa
parent 569
cb63f3d1236a
permissions
-rw-r--r--

fix over-optimization of strstr

1. it's actually less performant to frequently read bytes
from an array instead of using the native word length
2. the SBO buffer should be local and not static to allow
multi-threading usage

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

mercurial