|
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 = ⌖ |
|
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 } |