test/test_buffer.cpp

changeset 653
e081643aae2a
parent 569
cb63f3d1236a
equal deleted inserted replaced
652:bf817b825ed2 653:e081643aae2a
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 */
28
29 #include "cx/buffer.h"
30
31 #include <gtest/gtest.h>
32 #include "util_allocator.h"
33
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 }
41
42 void TearDown() override {
43 cxBufferDestroy(&buf);
44 }
45
46 CxBuffer buf{};
47 };
48
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 }
56
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 }
75
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 }
94
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 }
112
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 }
129
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 }
140
141 void TearDown() override {
142 cxBufferDestroy(&buf);
143 EXPECT_TRUE(alloc.verify());
144 }
145
146 CxTestingAllocator alloc;
147 CxBuffer buf{};
148 };
149
150 class BufferShiftLeft : public BufferShiftFixture {
151 };
152
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 }
162
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 }
172
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 }
182
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 }
192
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 }
202
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 }
212
213 class BufferShiftRight : public BufferShiftFixture {
214 };
215
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 }
225
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 }
235
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 }
245
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 }
257
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 }
270
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 }
280
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 }
295
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 }
310
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 }
328
329 class BufferWrite : public ::testing::Test {
330 protected:
331 CxBuffer buf{}, target{};
332
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 }
341
342 void TearDown() override {
343 cxBufferDestroy(&buf);
344 cxBufferDestroy(&target);
345 }
346
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 };
353
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 }
370
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 }
383
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 }
396
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 }
410
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 }
423
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 }
437
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 }
452
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 }
464
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 }
476
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 }
489
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 }
502
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 }
515
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 }
529
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 }
542
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 }
556
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 }
570
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 }
590
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 }
614
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 }
641
642 class BufferSeek : public BufferFixture {
643 };
644
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 }
650
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 }
656
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 }
663
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 }
670
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 }
677
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 }
684
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 }
691
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 }
698
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 }
706
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 }
713
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 }
720
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 }
729
730 class BufferEof : public BufferFixture {
731 };
732
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 }
741
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 }
749
750 class BufferRead : public ::testing::Test {
751 protected:
752 CxBuffer buf{};
753
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 }
761
762 void TearDown() override {
763 cxBufferDestroy(&buf);
764 }
765 };
766
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 }
775
776 TEST_F(BufferRead, GetEof) {
777 buf.pos = buf.size;
778 EXPECT_EQ(cxBufferGet(&buf), EOF);
779 }
780
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 }
789
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 }
798
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 }
808
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