Mon, 01 Jan 2024 16:42:37 +0100
begin migration of buffer tests - relates to #342
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, NULL, 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 class BufferShiftFixture : public ::testing::Test {
50 protected:
51 void SetUp() override {
52 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
53 cxBufferInit(&buf, NULL, 16, &alloc, CX_BUFFER_DEFAULT);
54 memcpy(buf.space, "test____________", 16);
55 buf.capacity = 8; // purposely pretend that the buffer has less capacity s.t. we can test beyond the range
56 buf.pos = 4;
57 buf.size = 4;
58 }
60 void TearDown() override {
61 cxBufferDestroy(&buf);
62 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
63 }
65 CxTestingAllocator alloc;
66 CxBuffer buf{};
67 };
69 class BufferShiftLeft : public BufferShiftFixture {
70 };
72 TEST_F(BufferShiftLeft, Zero) {
73 CX_TEST_ASSERT(buf.pos == 4);
74 CX_TEST_ASSERT(buf.size == 4);
75 int ret = cxBufferShiftLeft(&buf, 0);
76 CX_TEST_ASSERT(ret == 0);
77 CX_TEST_ASSERT(buf.pos == 4);
78 CX_TEST_ASSERT(buf.size == 4);
79 CX_TEST_ASSERT(memcmp(buf.space, "test________", 8) == 0);
80 }
82 TEST_F(BufferShiftLeft, ZeroOffsetInterface) {
83 CX_TEST_ASSERT(buf.pos == 4);
84 CX_TEST_ASSERT(buf.size == 4);
85 int ret = cxBufferShift(&buf, -0);
86 CX_TEST_ASSERT(ret == 0);
87 CX_TEST_ASSERT(buf.pos == 4);
88 CX_TEST_ASSERT(buf.size == 4);
89 CX_TEST_ASSERT(memcmp(buf.space, "test________", 8) == 0);
90 }
92 TEST_F(BufferShiftLeft, Standard) {
93 CX_TEST_ASSERT(buf.pos == 4);
94 CX_TEST_ASSERT(buf.size == 4);
95 int ret = cxBufferShiftLeft(&buf, 2);
96 CX_TEST_ASSERT(ret == 0);
97 CX_TEST_ASSERT(buf.pos == 2);
98 CX_TEST_ASSERT(buf.size == 2);
99 CX_TEST_ASSERT(memcmp(buf.space, "stst________", 8) == 0);
100 }
102 TEST_F(BufferShiftLeft, Overshift) {
103 ASSERT_LT(buf.pos, 6);
104 ASSERT_LT(buf.size, 6);
105 int ret = cxBufferShiftLeft(&buf, 6);
106 CX_TEST_ASSERT(ret == 0);
107 CX_TEST_ASSERT(buf.pos == 0);
108 CX_TEST_ASSERT(buf.size == 0);
109 CX_TEST_ASSERT(memcmp(buf.space, "test________", 8) == 0);
110 }
112 TEST_F(BufferShiftLeft, OvershiftPosOnly) {
113 buf.pos = 2;
114 CX_TEST_ASSERT(buf.size == 4);
115 int ret = cxBufferShiftLeft(&buf, 3);
116 CX_TEST_ASSERT(ret == 0);
117 CX_TEST_ASSERT(buf.pos == 0);
118 CX_TEST_ASSERT(buf.size == 1);
119 CX_TEST_ASSERT(memcmp(buf.space, "test________", 8) == 0);
120 }
122 TEST_F(BufferShiftLeft, OffsetInterface) {
123 buf.pos = 3;
124 CX_TEST_ASSERT(buf.size == 4);
125 int ret = cxBufferShift(&buf, -2);
126 CX_TEST_ASSERT(ret == 0);
127 CX_TEST_ASSERT(buf.pos == 1);
128 CX_TEST_ASSERT(buf.size == 2);
129 CX_TEST_ASSERT(memcmp(buf.space, "stst________", 8) == 0);
130 }
132 TEST_F(BufferShiftRight, Zero) {
133 CX_TEST_ASSERT(buf.pos == 4);
134 CX_TEST_ASSERT(buf.size == 4);
135 int ret = cxBufferShiftRight(&buf, 0);
136 CX_TEST_ASSERT(ret == 0);
137 CX_TEST_ASSERT(buf.pos == 4);
138 CX_TEST_ASSERT(buf.size == 4);
139 CX_TEST_ASSERT(memcmp(buf.space, "test________", 8) == 0);
140 }
142 TEST_F(BufferShiftRight, ZeroOffsetInterface) {
143 CX_TEST_ASSERT(buf.pos == 4);
144 CX_TEST_ASSERT(buf.size == 4);
145 int ret = cxBufferShift(&buf, +0);
146 CX_TEST_ASSERT(ret == 0);
147 CX_TEST_ASSERT(buf.pos == 4);
148 CX_TEST_ASSERT(buf.size == 4);
149 CX_TEST_ASSERT(memcmp(buf.space, "test________", 8) == 0);
150 }
152 TEST_F(BufferShiftRight, Standard) {
153 CX_TEST_ASSERT(buf.pos == 4);
154 CX_TEST_ASSERT(buf.size == 4);
155 int ret = cxBufferShiftRight(&buf, 3);
156 CX_TEST_ASSERT(ret == 0);
157 CX_TEST_ASSERT(buf.pos == 7);
158 CX_TEST_ASSERT(buf.size == 7);
159 CX_TEST_ASSERT(memcmp(buf.space, "testest_____", 8) == 0);
160 }
162 TEST_F(BufferShiftRight, OvershiftDiscard) {
163 CX_TEST_ASSERT(buf.pos == 4);
164 CX_TEST_ASSERT(buf.size == 4);
165 CX_TEST_ASSERT(buf.capacity == 8);
166 int ret = cxBufferShiftRight(&buf, 6);
167 CX_TEST_ASSERT(ret == 0);
168 CX_TEST_ASSERT(buf.pos == 8);
169 CX_TEST_ASSERT(buf.size == 8);
170 CX_TEST_ASSERT(buf.capacity == 8);
171 CX_TEST_ASSERT(memcmp(buf.space, "test__te____", 8) == 0);
172 }
174 TEST_F(BufferShiftRight, OvershiftExtend) {
175 CX_TEST_ASSERT(buf.pos == 4);
176 CX_TEST_ASSERT(buf.size == 4);
177 CX_TEST_ASSERT(buf.capacity == 8);
178 buf.flags |= CX_BUFFER_AUTO_EXTEND;
179 int ret = cxBufferShiftRight(&buf, 6);
180 CX_TEST_ASSERT(ret == 0);
181 CX_TEST_ASSERT(buf.pos == 10);
182 CX_TEST_ASSERT(buf.size == 10);
183 EXPECT_GE(buf.capacity, 10);
184 CX_TEST_ASSERT(memcmp(buf.space, "test__test__", 8) == 0);
185 }
187 TEST_F(BufferShiftRight, OffsetInterface) {
188 buf.pos = 3;
189 CX_TEST_ASSERT(buf.size == 4);
190 int ret = cxBufferShift(&buf, 2);
191 CX_TEST_ASSERT(ret == 0);
192 CX_TEST_ASSERT(buf.pos == 5);
193 CX_TEST_ASSERT(buf.size == 6);
194 CX_TEST_ASSERT(memcmp(buf.space, "tetest______", 8) == 0);
195 }
197 class BufferWrite : public ::testing::Test {
198 protected:
199 CxBuffer buf{}, target{};
201 void SetUp() override {
202 cxBufferInit(&target, NULL, 16, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND);
203 cxBufferInit(&buf, NULL, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
204 buf.capacity = 8; // artificially reduce capacity to check OOB writes
205 memset(buf.space, 0, 16);
206 memcpy(buf.space, "prep", 4);
207 buf.size = buf.pos = 4;
208 }
210 void TearDown() override {
211 cxBufferDestroy(&buf);
212 cxBufferDestroy(&target);
213 }
215 void enableFlushing() {
216 buf.flush_target = ⌖
217 buf.flush_func = reinterpret_cast<cx_write_func>(cxBufferWrite);
218 buf.flush_blkmax = 1;
219 }
220 };
222 static size_t mock_write_limited_rate(
223 void const *ptr,
224 size_t size,
225 __attribute__((unused)) size_t nitems,
226 CxBuffer *buffer
227 ) {
228 // simulate limited target drain capacity
229 static bool full = false;
230 if (full) {
231 full = false;
232 return 0;
233 } else {
234 full = true;
235 return cxBufferWrite(ptr, size, nitems > 2 ? 2 : nitems, buffer);
236 }
237 }
239 TEST_F(BufferWrite, SizeOneFit) {
240 const char *data = "test";
241 CX_TEST_ASSERT(buf.capacity == 8);
242 CX_TEST_ASSERT(buf.pos == 4);
243 CX_TEST_ASSERT(buf.size == 4);
244 size_t written = cxBufferWrite(data, 1, 4, &buf);
245 CX_TEST_ASSERT(written == 4);
246 CX_TEST_ASSERT(buf.size == 8);
247 CX_TEST_ASSERT(buf.pos == 8);
248 CX_TEST_ASSERT(buf.capacity == 8);
249 EXPECT_EQ(memcmp(buf.space, "preptest", 8), 0);
250 }
252 TEST_F(BufferWrite, SizeOneDiscard) {
253 const char *data = "testing";
254 CX_TEST_ASSERT(buf.capacity == 8);
255 CX_TEST_ASSERT(buf.pos == 4);
256 CX_TEST_ASSERT(buf.size == 4);
257 size_t written = cxBufferWrite(data, 1, 7, &buf);
258 CX_TEST_ASSERT(written == 4);
259 CX_TEST_ASSERT(buf.size == 8);
260 CX_TEST_ASSERT(buf.pos == 8);
261 CX_TEST_ASSERT(buf.capacity == 8);
262 EXPECT_EQ(memcmp(buf.space, "preptest\0", 9), 0);
263 }
265 TEST_F(BufferWrite, SizeOneExtend) {
266 buf.flags |= CX_BUFFER_AUTO_EXTEND;
267 const char *data = "testing";
268 CX_TEST_ASSERT(buf.capacity == 8);
269 CX_TEST_ASSERT(buf.pos == 4);
270 CX_TEST_ASSERT(buf.size == 4);
271 size_t written = cxBufferWrite(data, 1, 7, &buf);
272 CX_TEST_ASSERT(written == 7);
273 CX_TEST_ASSERT(buf.size == 11);
274 CX_TEST_ASSERT(buf.pos == 11);
275 EXPECT_GE(buf.capacity, 11);
276 EXPECT_EQ(memcmp(buf.space, "preptesting", 11), 0);
277 }
279 TEST_F(BufferWrite, MultibyteFit) {
280 const char *data = "test";
281 CX_TEST_ASSERT(buf.capacity == 8);
282 CX_TEST_ASSERT(buf.pos == 4);
283 CX_TEST_ASSERT(buf.size == 4);
284 size_t written = cxBufferWrite(data, 2, 2, &buf);
285 CX_TEST_ASSERT(written == 2);
286 CX_TEST_ASSERT(buf.size == 8);
287 CX_TEST_ASSERT(buf.pos == 8);
288 CX_TEST_ASSERT(buf.capacity == 8);
289 EXPECT_EQ(memcmp(buf.space, "preptest", 8), 0);
290 }
292 TEST_F(BufferWrite, MultibyteDiscard) {
293 const char *data = "testing";
294 CX_TEST_ASSERT(buf.capacity == 8);
295 CX_TEST_ASSERT(buf.size == 4);
296 buf.pos = 3;
297 size_t written = cxBufferWrite(data, 2, 4, &buf);
298 // remember: whole elements are discarded if they do not fit
299 CX_TEST_ASSERT(written == 2);
300 CX_TEST_ASSERT(buf.size == 7);
301 CX_TEST_ASSERT(buf.pos == 7);
302 CX_TEST_ASSERT(buf.capacity == 8);
303 EXPECT_EQ(memcmp(buf.space, "pretest\0", 8), 0);
304 }
306 TEST_F(BufferWrite, MultibyteExtend) {
307 buf.flags |= CX_BUFFER_AUTO_EXTEND;
308 const char *data = "tester";
309 CX_TEST_ASSERT(buf.capacity == 8);
310 CX_TEST_ASSERT(buf.size == 4);
311 buf.pos = 3;
312 size_t written = cxBufferWrite(data, 2, 3, &buf);
313 // remember: whole elements are discarded if they do not fit
314 CX_TEST_ASSERT(written == 3);
315 CX_TEST_ASSERT(buf.size == 9);
316 CX_TEST_ASSERT(buf.pos == 9);
317 EXPECT_GE(buf.capacity, 9);
318 EXPECT_EQ(memcmp(buf.space, "pretester", 9), 0);
319 }
321 TEST_F(BufferWrite, PutcWrapperFit) {
322 CX_TEST_ASSERT(buf.capacity == 8);
323 CX_TEST_ASSERT(buf.pos == 4);
324 CX_TEST_ASSERT(buf.size == 4);
325 int c = cxBufferPut(&buf, 0x200 | 'a');
326 CX_TEST_ASSERT(c == 'a');
327 CX_TEST_ASSERT(buf.size == 5);
328 CX_TEST_ASSERT(buf.pos == 5);
329 CX_TEST_ASSERT(buf.capacity == 8);
330 EXPECT_EQ(memcmp(buf.space, "prepa\0", 6), 0);
331 }
333 TEST_F(BufferWrite, PutcWrapperDiscard) {
334 CX_TEST_ASSERT(buf.capacity == 8);
335 CX_TEST_ASSERT(buf.size == 4);
336 buf.pos = 8;
337 int c = cxBufferPut(&buf, 0x200 | 'a');
338 CX_TEST_ASSERT(c == EOF);
339 CX_TEST_ASSERT(buf.size == 4);
340 CX_TEST_ASSERT(buf.pos == 8);
341 CX_TEST_ASSERT(buf.capacity == 8);
342 EXPECT_EQ(memcmp(buf.space, "prep\0\0\0\0\0", 9), 0);
343 }
345 TEST_F(BufferWrite, PutcWrapperExtend) {
346 buf.flags |= CX_BUFFER_AUTO_EXTEND;
347 CX_TEST_ASSERT(buf.capacity == 8);
348 CX_TEST_ASSERT(buf.size == 4);
349 buf.pos = 8;
350 int c = cxBufferPut(&buf, 0x200 | 'a');
351 CX_TEST_ASSERT(c == 'a');
352 CX_TEST_ASSERT(buf.size == 9);
353 CX_TEST_ASSERT(buf.pos == 9);
354 EXPECT_GE(buf.capacity, 9);
355 EXPECT_EQ(memcmp(buf.space, "prep\0\0\0\0a", 9), 0);
356 }
358 TEST_F(BufferWrite, PutStringWrapperFit) {
359 const char *data = "test";
360 CX_TEST_ASSERT(buf.capacity == 8);
361 CX_TEST_ASSERT(buf.pos == 4);
362 CX_TEST_ASSERT(buf.size == 4);
363 size_t written = cxBufferPutString(&buf, data);
364 CX_TEST_ASSERT(written == 4);
365 CX_TEST_ASSERT(buf.size == 8);
366 CX_TEST_ASSERT(buf.pos == 8);
367 CX_TEST_ASSERT(buf.capacity == 8);
368 EXPECT_EQ(memcmp(buf.space, "preptest", 8), 0);
369 }
371 TEST_F(BufferWrite, PutStringWrapperDiscard) {
372 const char *data = "testing";
373 CX_TEST_ASSERT(buf.capacity == 8);
374 CX_TEST_ASSERT(buf.pos == 4);
375 CX_TEST_ASSERT(buf.size == 4);
376 size_t written = cxBufferPutString(&buf, data);
377 CX_TEST_ASSERT(written == 4);
378 CX_TEST_ASSERT(buf.size == 8);
379 CX_TEST_ASSERT(buf.pos == 8);
380 CX_TEST_ASSERT(buf.capacity == 8);
381 EXPECT_EQ(memcmp(buf.space, "preptest\0", 9), 0);
382 }
384 TEST_F(BufferWrite, PutStringWrapperExtend) {
385 buf.flags |= CX_BUFFER_AUTO_EXTEND;
386 const char *data = "testing";
387 CX_TEST_ASSERT(buf.capacity == 8);
388 CX_TEST_ASSERT(buf.pos == 4);
389 CX_TEST_ASSERT(buf.size == 4);
390 size_t written = cxBufferPutString(&buf, data);
391 CX_TEST_ASSERT(written == 7);
392 CX_TEST_ASSERT(buf.size == 11);
393 CX_TEST_ASSERT(buf.pos == 11);
394 EXPECT_GE(buf.capacity, 11);
395 EXPECT_EQ(memcmp(buf.space, "preptesting", 11), 0);
396 }
398 TEST_F(BufferWrite, MultOverflow) {
399 const char *data = "testing";
400 CX_TEST_ASSERT(buf.capacity == 8);
401 CX_TEST_ASSERT(buf.pos == 4);
402 CX_TEST_ASSERT(buf.size == 4);
403 size_t written = cxBufferWrite(data, 8, SIZE_MAX / 4, &buf);
404 CX_TEST_ASSERT(written == 0);
405 CX_TEST_ASSERT(buf.capacity == 8);
406 CX_TEST_ASSERT(buf.pos == 4);
407 CX_TEST_ASSERT(buf.size == 4);
408 EXPECT_EQ(memcmp(buf.space, "prep\0", 5), 0);
409 }
411 TEST_F(BufferWrite, MaxCapaOverflow) {
412 buf.flags |= CX_BUFFER_AUTO_EXTEND;
413 const char *data = "testing";
414 CX_TEST_ASSERT(buf.capacity == 8);
415 CX_TEST_ASSERT(buf.pos == 4);
416 CX_TEST_ASSERT(buf.size == 4);
417 size_t written = cxBufferWrite(data, 1, SIZE_MAX - 2, &buf);
418 CX_TEST_ASSERT(written == 0);
419 CX_TEST_ASSERT(buf.capacity == 8);
420 CX_TEST_ASSERT(buf.pos == 4);
421 CX_TEST_ASSERT(buf.size == 4);
422 EXPECT_EQ(memcmp(buf.space, "prep\0", 5), 0);
423 }
425 TEST_F(BufferWrite, OnlyOverwrite) {
426 buf.flags |= CX_BUFFER_AUTO_EXTEND;
427 CX_TEST_ASSERT(buf.capacity == 8);
428 memcpy(buf.space, "preptest", 8);
429 buf.pos = 3;
430 buf.size = 8;
431 size_t written = cxBufferWrite("XXX", 2, 2, &buf);
432 CX_TEST_ASSERT(written == 2);
433 CX_TEST_ASSERT(buf.capacity == 8);
434 CX_TEST_ASSERT(buf.size == 8);
435 CX_TEST_ASSERT(buf.pos == 7);
436 EXPECT_EQ(memcmp(buf.space, "preXXX\0t", 8), 0);
437 }
439 TEST_F(BufferWrite, FlushAtCapacity) {
440 enableFlushing();
441 CX_TEST_ASSERT(buf.capacity == 8);
442 CX_TEST_ASSERT(buf.pos == 4);
443 size_t written = cxBufferWrite("foo", 1, 3, &buf);
444 CX_TEST_ASSERT(written == 3);
445 CX_TEST_ASSERT(buf.pos == 7);
446 CX_TEST_ASSERT(buf.size == 7);
447 CX_TEST_ASSERT(target.pos == 0);
448 CX_TEST_ASSERT(target.size == 0);
449 written = cxBufferWrite("hello", 1, 5, &buf);
450 CX_TEST_ASSERT(written == 5);
451 CX_TEST_ASSERT(buf.pos == 0);
452 CX_TEST_ASSERT(buf.size == 0);
453 CX_TEST_ASSERT(buf.capacity == 8);
454 CX_TEST_ASSERT(target.pos == 12);
455 CX_TEST_ASSERT(target.size == 12);
456 EXPECT_EQ(memcmp(target.space, "prepfoohello", 12), 0);
457 }
459 TEST_F(BufferWrite, FlushAtThreshold) {
460 enableFlushing();
461 buf.flush_threshold = 12;
462 buf.flags |= CX_BUFFER_AUTO_EXTEND;
463 CX_TEST_ASSERT(buf.capacity == 8);
464 CX_TEST_ASSERT(buf.pos == 4);
465 size_t written = cxBufferWrite("foobar", 1, 6, &buf);
466 CX_TEST_ASSERT(written == 6);
467 CX_TEST_ASSERT(buf.pos == 10);
468 CX_TEST_ASSERT(buf.size == 10);
469 ASSERT_GE(buf.capacity, 10);
470 ASSERT_LE(buf.capacity, 12);
471 CX_TEST_ASSERT(target.pos == 0);
472 CX_TEST_ASSERT(target.size == 0);
473 written = cxBufferWrite("hello", 1, 5, &buf);
474 CX_TEST_ASSERT(written == 5);
475 CX_TEST_ASSERT(buf.pos == 0);
476 CX_TEST_ASSERT(buf.size == 0);
477 EXPECT_LE(buf.capacity, 12);
478 CX_TEST_ASSERT(target.pos == 15);
479 CX_TEST_ASSERT(target.size == 15);
480 EXPECT_EQ(memcmp(target.space, "prepfoobarhello", 15), 0);
481 }
483 TEST_F(BufferWrite, FlushRateLimited) {
484 enableFlushing();
485 // limit the rate of the flush function and the capacity of the target
486 target.capacity = 16;
487 target.flags &= ~CX_BUFFER_AUTO_EXTEND;
488 buf.flush_func = (cx_write_func) mock_write_limited_rate;
489 CX_TEST_ASSERT(buf.capacity == 8);
490 CX_TEST_ASSERT(buf.pos == 4);
491 size_t written = cxBufferWrite("foo", 1, 3, &buf);
492 CX_TEST_ASSERT(written == 3);
493 CX_TEST_ASSERT(buf.pos == 7);
494 CX_TEST_ASSERT(buf.size == 7);
495 CX_TEST_ASSERT(target.pos == 0);
496 CX_TEST_ASSERT(target.size == 0);
497 written = cxBufferWrite("hello, world!", 1, 13, &buf);
498 // " world!" fits into this buffer, the remaining stuff is flushed out
499 CX_TEST_ASSERT(written == 13);
500 CX_TEST_ASSERT(buf.pos == 7);
501 CX_TEST_ASSERT(buf.size == 7);
502 CX_TEST_ASSERT(buf.capacity == 8);
503 EXPECT_EQ(memcmp(buf.space, " world!", 7), 0);
504 CX_TEST_ASSERT(target.pos == 13);
505 CX_TEST_ASSERT(target.size == 13);
506 CX_TEST_ASSERT(target.capacity == 16);
507 EXPECT_EQ(memcmp(target.space, "prepfoohello,", 13), 0);
508 }
511 TEST_F(BufferEof, Reached) {
512 buf.pos = buf.size;
513 CX_TEST_ASSERT(cxBufferEof(&buf));
514 buf.pos = buf.size - 1;
515 CX_TEST_ASSERT(!cxBufferEof(&buf));
516 cxBufferPut(&buf, 'a');
517 CX_TEST_ASSERT(cxBufferEof(&buf));
518 }
520 TEST_F(BufferEof, NotReached) {
521 buf.pos = buf.size - 1;
522 CX_TEST_ASSERT(!cxBufferEof(&buf));
523 buf.pos = 0;
524 cxBufferWrite("test", 1, 5, &buf);
525 CX_TEST_ASSERT(!cxBufferEof(&buf));
526 }
528 class BufferRead : public ::testing::Test {
529 protected:
530 CxBuffer buf{};
532 void SetUp() override {
533 cxBufferInit(&buf, NULL, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT);
534 buf.capacity = 8; // artificially reduce capacity to check OOB writes
535 memset(buf.space, 0, 16);
536 memcpy(buf.space, "some data", 9);
537 buf.size = 9;
538 }
540 void TearDown() override {
541 cxBufferDestroy(&buf);
542 }
543 };
545 TEST_F(BufferRead, GetByte) {
546 buf.pos = 2;
547 EXPECT_EQ(cxBufferGet(&buf), 'm');
548 EXPECT_EQ(cxBufferGet(&buf), 'e');
549 EXPECT_EQ(cxBufferGet(&buf), ' ');
550 EXPECT_EQ(cxBufferGet(&buf), 'd');
551 CX_TEST_ASSERT(buf.pos == 6);
552 }
554 TEST_F(BufferRead, GetEof) {
555 buf.pos = buf.size;
556 EXPECT_EQ(cxBufferGet(&buf), EOF);
557 }
559 TEST_F(BufferRead, ReadWithinBounds) {
560 buf.pos = 2;
561 char target[4];
562 auto read = cxBufferRead(&target, 1, 4, &buf);
563 CX_TEST_ASSERT(read == 4);
564 EXPECT_EQ(memcmp(&target, "me d", 4), 0);
565 CX_TEST_ASSERT(buf.pos == 6);
566 }
568 TEST_F(BufferRead, ReadOutOfBounds) {
569 buf.pos = 6;
570 char target[4];
571 auto read = cxBufferRead(&target, 1, 4, &buf);
572 CX_TEST_ASSERT(read == 3);
573 EXPECT_EQ(memcmp(&target, "ata", 3), 0);
574 CX_TEST_ASSERT(buf.pos == 9);
575 }
577 TEST_F(BufferRead, ReadOutOfBoundsMultibyte) {
578 buf.pos = 6;
579 char target[4];
580 target[2] = '\0';
581 auto read = cxBufferRead(&target, 2, 2, &buf);
582 CX_TEST_ASSERT(read == 1);
583 EXPECT_EQ(memcmp(&target, "at\0", 3), 0);
584 CX_TEST_ASSERT(buf.pos == 8);
585 }
587 TEST_F(BufferRead, ReadEof) {
588 buf.pos = 9;
589 char target[4];
590 auto read = cxBufferRead(&target, 1, 1, &buf);
591 CX_TEST_ASSERT(read == 0);
592 CX_TEST_ASSERT(buf.pos == 9);
593 }