1 /*
2 * Copyright (c) 2016 Intel Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <ztest.h>
18 #include <irq_offload.h>
19 #include <sys/ring_buffer.h>
20
21 #include <logging/log.h>
22 LOG_MODULE_REGISTER(test);
23
24 /* Max size is used internally in the algorithm. Value is decreased in the test
25 * to trigger rewind algorithm.
26 */
27 #undef RING_BUFFER_MAX_SIZE
28 #define RING_BUFFER_MAX_SIZE 0x00000200
29
30 /* Use global variable that can be modified by the test. */
31 uint32_t test_rewind_threshold = RING_BUFFER_MAX_SIZE;
32
ring_buf_get_rewind_threshold(void)33 uint32_t ring_buf_get_rewind_threshold(void)
34 {
35 return test_rewind_threshold;
36 }
37
38 /**
39 * @defgroup lib_ringbuffer_tests Ringbuffer
40 * @ingroup all_tests
41 * @{
42 * @}
43 */
44
45 RING_BUF_ITEM_DECLARE_POW2(ring_buf1, 8);
46
47 #define TYPE 1
48 #define VALUE 2
49 #define INITIAL_SIZE 2
50
51
52 #define RINGBUFFER_SIZE 5
53 #define DATA_MAX_SIZE 3
54 #define POW 2
55 extern void test_ringbuffer_concurrent(void);
56 extern void test_ringbuffer_shpsc(void);
57 extern void test_ringbuffer_spshc(void);
58 extern void test_ringbuffer_cpy_shpsc(void);
59 extern void test_ringbuffer_cpy_spshc(void);
60 extern void test_ringbuffer_item_shpsc(void);
61 extern void test_ringbuffer_item_spshc(void);
62 /**
63 * @brief Test APIs of ring buffer
64 *
65 * @details
66 * Test Objective:
67 * - Define and initialize a ring buffer and
68 * the ring buffer copy data out of the array by
69 * ring_buf_item_put(), and then ring buffer data
70 * is copied into the array by ring_buf_item_get()
71 * return error when full/empty.
72 *
73 * Testing techniques:
74 * - Interface testing
75 * - Dynamic analysis and testing
76 * - Equivalence classes and input partition testing
77 * - Structural test coverage(entry points,statements,branches)
78 *
79 * Prerequisite Conditions:
80 * - Define and initialize a ringbuffer by using macro
81 * RING_BUF_ITEM_DECLARE_POW2
82 *
83 * Input Specifications:
84 * - N/A
85 *
86 * Test Procedure:
87 * -# Defined an array with some data items that ready for being
88 * put.
89 * -# Put data items with "while loop".
90 * -# Check if an error will be seen when the ringbuffer is full.
91 * -# Get data items from the ringbuffer.
92 * -# Check if the data put are equal to the data got.
93 * -# Going on getting data from the ringbuffer.
94 * -# Check if an error will be seen when the ringbuffer is empty.
95 *
96 * Expected Test Result:
97 * - Data items pushed shall be equal to what are gotten. And
98 * An error shall be shown up when an item is put into a full ringbutter or
99 * get some items from an empty ringbuffer.
100 *
101 * Pass/Fail Criteria:
102 * - Success if test result of step 3.5,7 is passed. Otherwise, failure.
103 *
104 * Assumptions and Constraints:
105 * - N/A
106 *
107 * @ingroup lib_ringbuffer_tests
108 *
109 * @see ring_buf_item_put, ring_buf_item_get
110 */
test_ring_buffer_main(void)111 void test_ring_buffer_main(void)
112 {
113 int ret, put_count, i;
114 uint32_t getdata[6];
115 uint8_t getsize, getval;
116 uint16_t gettype;
117 int dsize = INITIAL_SIZE;
118
119 __aligned(sizeof(uint32_t)) char rb_data[] = "ABCDEFGHIJKLMNOPQRSTUVWX";
120 put_count = 0;
121
122 while (1) {
123 ret = ring_buf_item_put(&ring_buf1, TYPE, VALUE,
124 (uint32_t *)rb_data, dsize);
125 if (ret == -EMSGSIZE) {
126 LOG_DBG("ring buffer is full");
127 break;
128 }
129 LOG_DBG("inserted %d chunks, %d remaining", dsize,
130 ring_buf_space_get(&ring_buf1));
131 dsize = (dsize + 1) % SIZE32_OF(rb_data);
132 put_count++;
133 }
134
135 getsize = INITIAL_SIZE - 1;
136 ret = ring_buf_item_get(&ring_buf1, &gettype, &getval,
137 getdata, &getsize);
138 if (ret != -EMSGSIZE) {
139 LOG_DBG("Allowed retreival with insufficient "
140 "destination buffer space");
141 zassert_true((getsize == INITIAL_SIZE),
142 "Correct size wasn't reported back to the caller");
143 }
144
145 for (i = 0; i < put_count; i++) {
146 getsize = SIZE32_OF(getdata);
147 ret = ring_buf_item_get(&ring_buf1, &gettype, &getval, getdata,
148 &getsize);
149 zassert_true((ret == 0), "Couldn't retrieve a stored value");
150 LOG_DBG("got %u chunks of type %u and val %u, %u remaining",
151 getsize, gettype, getval,
152 ring_buf_space_get(&ring_buf1));
153
154 zassert_true((memcmp((char *)getdata, rb_data,
155 getsize * sizeof(uint32_t)) == 0), "data corrupted");
156 zassert_true((gettype == TYPE), "type information corrupted");
157 zassert_true((getval == VALUE), "value information corrupted");
158 }
159
160 getsize = SIZE32_OF(getdata);
161 ret = ring_buf_item_get(&ring_buf1, &gettype, &getval, getdata,
162 &getsize);
163 zassert_true((ret == -EAGAIN), "Got data out of an empty buffer");
164 }
165
166 /**TESTPOINT: init via RING_BUF_ITEM_DECLARE_POW2*/
167 RING_BUF_ITEM_DECLARE_POW2(ringbuf_pow2, POW);
168
169 /**TESTPOINT: init via RING_BUF_ITEM_DECLARE_SIZE*/
170 /**
171 * @brief define a ring buffer with arbitrary size
172 *
173 * @see RING_BUF_ITEM_DECLARE_SIZE(),RING_BUF_DECLARE()
174 */
175 RING_BUF_ITEM_DECLARE_SIZE(ringbuf_size, RINGBUFFER_SIZE);
176
177 RING_BUF_DECLARE(ringbuf_raw, RINGBUFFER_SIZE);
178
179 static struct ring_buf ringbuf, *pbuf;
180
181 static uint32_t buffer[RINGBUFFER_SIZE];
182
183 static struct {
184 uint8_t length;
185 uint8_t value;
186 uint16_t type;
187 uint32_t buffer[DATA_MAX_SIZE];
188 } data[] = {
189 { 0, 32, 1, {} },
190 { 1, 76, 54, { 0x89ab } },
191 { 3, 0xff, 0xffff, { 0x0f0f, 0xf0f0, 0xff00 } }
192 };
193
194 /*entry of contexts*/
tringbuf_put(const void * p)195 static void tringbuf_put(const void *p)
196 {
197 int index = POINTER_TO_INT(p);
198 /**TESTPOINT: ring buffer put*/
199 int ret = ring_buf_item_put(pbuf, data[index].type, data[index].value,
200 data[index].buffer, data[index].length);
201
202 zassert_equal(ret, 0, NULL);
203 }
204
tringbuf_get(const void * p)205 static void tringbuf_get(const void *p)
206 {
207 uint16_t type;
208 uint8_t value, size32 = DATA_MAX_SIZE;
209 uint32_t rx_data[DATA_MAX_SIZE];
210 int ret, index = POINTER_TO_INT(p);
211
212 /**TESTPOINT: ring buffer get*/
213 ret = ring_buf_item_get(pbuf, &type, &value, rx_data, &size32);
214 zassert_equal(ret, 0, NULL);
215 zassert_equal(type, data[index].type, NULL);
216 zassert_equal(value, data[index].value, NULL);
217 zassert_equal(size32, data[index].length, NULL);
218 zassert_equal(memcmp(rx_data, data[index].buffer, size32), 0, NULL);
219 }
220
tringbuf_get_discard(const void * p)221 static void tringbuf_get_discard(const void *p)
222 {
223 uint16_t type;
224 uint8_t value, size32;
225 int ret, index = POINTER_TO_INT(p);
226
227 /**TESTPOINT: ring buffer get*/
228 ret = ring_buf_item_get(pbuf, &type, &value, NULL, &size32);
229 zassert_equal(ret, 0, NULL);
230 zassert_equal(type, data[index].type, NULL);
231 zassert_equal(value, data[index].value, NULL);
232 zassert_equal(size32, data[index].length, NULL);
233 }
234
235 /*test cases*/
test_ringbuffer_init(void)236 void test_ringbuffer_init(void)
237 {
238 /**TESTPOINT: init via ring_buf_init*/
239 ring_buf_init(&ringbuf, RINGBUFFER_SIZE, buffer);
240 zassert_true(ring_buf_is_empty(&ringbuf), NULL);
241 zassert_equal(ring_buf_space_get(&ringbuf), RINGBUFFER_SIZE, NULL);
242 }
243
test_ringbuffer_declare_pow2(void)244 void test_ringbuffer_declare_pow2(void)
245 {
246 zassert_true(ring_buf_is_empty(&ringbuf_pow2), NULL);
247 zassert_equal(ring_buf_space_get(&ringbuf_pow2), (1 << POW), NULL);
248 }
249
test_ringbuffer_declare_size(void)250 void test_ringbuffer_declare_size(void)
251 {
252 zassert_true(ring_buf_is_empty(&ringbuf_size), NULL);
253 zassert_equal(ring_buf_space_get(&ringbuf_size), RINGBUFFER_SIZE,
254 NULL);
255 }
256
257 /**
258 * @brief verify that ringbuffer can be placed in any user-controlled memory
259 *
260 * @details
261 * Test Objective:
262 * - define and initialize a ring buffer by struct ring_buf,
263 * then passing data by thread to verify the ringbuffer
264 * if it works to be placed in any user-controlled memory.
265 *
266 * Testing techniques:
267 * - Interface testing
268 * - Dynamic analysis and testing
269 * - Structural test coverage(entry points,statements,branches)
270 *
271 * Prerequisite Conditions:
272 * - Define and initialize a ringbuffer by using struct ring_buf
273 * - Define a pointer of ring buffer type.
274 *
275 * Input Specifications:
276 * - N/A
277 *
278 * Test Procedure:
279 * -# Put data items into a ringbuffer
280 * -# Get data items from a ringbuffer
281 * -# Check if data items pushed are equal to what are gotten.
282 * -# Repeat 1,2,3 to verify the ringbuffer is working normally.
283 *
284 * Expected Test Result:
285 * - data items pushed shall be equal to what are gotten.
286 *
287 * Pass/Fail Criteria:
288 * - Success if test result of step 3,4 is passed. Otherwise, failure.
289 *
290 * Assumptions and Constraints:
291 * - N/A
292 *
293 * @ingroup lib_ringbuffer_tests
294 *
295 * @see ring_buf_item_put, ring_buf_item_get
296 */
test_ringbuffer_put_get_thread(void)297 void test_ringbuffer_put_get_thread(void)
298 {
299 pbuf = &ringbuf;
300 for (int i = 0; i < 1000; i++) {
301 tringbuf_put((const void *)0);
302 tringbuf_put((const void *)1);
303 tringbuf_get((const void *)0);
304 tringbuf_get((const void *)1);
305 tringbuf_put((const void *)2);
306 zassert_false(ring_buf_is_empty(pbuf), NULL);
307 tringbuf_get((const void *)2);
308 zassert_true(ring_buf_is_empty(pbuf), NULL);
309 }
310 }
311
test_ringbuffer_put_get_isr(void)312 void test_ringbuffer_put_get_isr(void)
313 {
314 pbuf = &ringbuf;
315 irq_offload(tringbuf_put, (const void *)0);
316 irq_offload(tringbuf_put, (const void *)1);
317 irq_offload(tringbuf_get, (const void *)0);
318 irq_offload(tringbuf_get, (const void *)1);
319 irq_offload(tringbuf_put, (const void *)2);
320 zassert_false(ring_buf_is_empty(pbuf), NULL);
321 irq_offload(tringbuf_get, (const void *)2);
322 zassert_true(ring_buf_is_empty(pbuf), NULL);
323 }
324
test_ringbuffer_put_get_thread_isr(void)325 void test_ringbuffer_put_get_thread_isr(void)
326 {
327 pbuf = &ringbuf;
328 tringbuf_put((const void *)0);
329 irq_offload(tringbuf_put, (const void *)1);
330 tringbuf_get((const void *)0);
331 irq_offload(tringbuf_get, (const void *)1);
332 tringbuf_put((const void *)2);
333 irq_offload(tringbuf_get, (const void *)2);
334 }
335
test_ringbuffer_put_get_discard(void)336 void test_ringbuffer_put_get_discard(void)
337 {
338 pbuf = &ringbuf;
339 tringbuf_put((const void *)0);
340 tringbuf_put((const void *)1);
341 zassert_false(ring_buf_is_empty(pbuf), NULL);
342 tringbuf_get_discard((const void *)0);
343 tringbuf_get_discard((const void *)1);
344 zassert_true(ring_buf_is_empty(pbuf), NULL);
345 }
346
347 /**
348 * @brief verify that ringbuffer can be placed in any user-controlled memory
349 *
350 * @details
351 * Test Objective:
352 * - define and initialize a ring buffer by macro RING_BUF_ITEM_DECLARE_POW2,
353 * then passing data by thread and isr to verify the ringbuffer
354 * if it works to be placed in any user-controlled memory.
355 *
356 * Testing techniques:
357 * - Interface testing
358 * - Dynamic analysis and testing
359 * - Structural test coverage(entry points,statements,branches)
360 *
361 * Prerequisite Conditions:
362 * - Define and initialize a ringbuffer by RING_BUF_ITEM_DECLARE_POW2
363 * - Define a pointer of ring_buffer type.
364 *
365 * Input Specifications:
366 * - N/A
367 *
368 * Test Procedure:
369 * -# Put data items into the ringbuffer by a thread
370 * -# Put data items into the ringbuffer by a ISR
371 * -# Get data items from the ringbuffer by the thread
372 * -# Check if data items pushed are equal to what are gotten.
373 * -# Get data items from the ringbuffer by the ISR
374 * -# Check if data items pushed are equal to what are gotten.
375 * -# Put data items into the ringbuffer by the thread
376 * -# Get data items from the ringbuffer by the ISR
377 * -# Check if data items pushed are equal to what are gotten.
378 *
379 * Expected Test Result:
380 * - data items pushed shall be equal to what are gotten.
381 *
382 * Pass/Fail Criteria:
383 * - Success if test result of step 4,6,9 is passed. Otherwise, failure.
384 *
385 * Assumptions and Constraints:
386 * - N/A
387 *
388 * @ingroup lib_ringbuffer_tests
389 *
390 * @see ring_buf_item_put, ring_buf_item_get
391 */
test_ringbuffer_pow2_put_get_thread_isr(void)392 void test_ringbuffer_pow2_put_get_thread_isr(void)
393 {
394 pbuf = &ringbuf_pow2;
395 tringbuf_put((const void *)0);
396 irq_offload(tringbuf_put, (const void *)1);
397 tringbuf_get((const void *)0);
398 irq_offload(tringbuf_get, (const void *)1);
399 tringbuf_put((const void *)1);
400 irq_offload(tringbuf_get, (const void *)1);
401 }
402
403 /**
404 * @brief verify that ringbuffer can be placed in any user-controlled memory
405 *
406 * @details
407 * Test Objective:
408 * - define and initialize a ring buffer by macro RING_BUF_ITEM_DECLARE_SIZE,
409 * then passing data by thread and isr to verify the ringbuffer
410 * if it works to be placed in any user-controlled memory.
411 *
412 * Testing techniques:
413 * - Interface testing
414 * - Dynamic analysis and testing
415 * - Structural test coverage(entry points,statements,branches)
416 *
417 * Prerequisite Conditions:
418 * - Define and initialize a ringbuffer by RING_BUF_ITEM_DECLARE_SIZE
419 * - Define a pointer of ring buffer type.
420 *
421 * Input Specifications:
422 * - N/A
423 *
424 * Test Procedure:
425 * -# Put data items into the ringbuffer by a thread
426 * -# Put data items into the ringbuffer by a ISR
427 * -# Get data items from the ringbuffer by the thread
428 * -# Check if data items pushed are equal to what are gotten.
429 * -# Get data items from the ringbuffer by the ISR
430 * -# Check if data items pushed are equal to what are gotten.
431 * -# Put data items into the ringbuffer by the thread
432 * -# Get data items from the ringbuffer by the ISR
433 * -# Check if data items pushed are equal to what are gotten.
434 *
435 * Expected Test Result:
436 * - data items pushed shall be equal to what are gotten.
437 *
438 * Pass/Fail Criteria:
439 * - Success if test result of step 4,6,9 is passed. Otherwise, failure.
440 *
441 * Assumptions and Constraints:
442 * - N/A
443 *
444 * @ingroup lib_ringbuffer_tests
445 *
446 * @see ring_buf_item_put, ring_buf_item_get
447 */
test_ringbuffer_size_put_get_thread_isr(void)448 void test_ringbuffer_size_put_get_thread_isr(void)
449 {
450 pbuf = &ringbuf_size;
451 tringbuf_put((const void *)0);
452 irq_offload(tringbuf_put, (const void *)1);
453 tringbuf_get((const void *)0);
454 irq_offload(tringbuf_get, (const void *)1);
455 tringbuf_put((const void *)2);
456 irq_offload(tringbuf_get, (const void *)2);
457 }
458
459 /**
460 * @brief verify that ringbuffer can be placed in any user-controlled memory
461 *
462 * @details
463 * Test Objective:
464 * - define and initialize a ring buffer by macro RING_BUF_DECLARE,
465 * then verify data is passed between ring buffer and array
466 *
467 * Testing techniques:
468 * - Interface testing
469 * - Dynamic analysis and testing
470 * - Structural test coverage(entry points,statements,branches)
471 *
472 * Prerequisite Conditions:
473 * - Define and initialize a ringbuffer by RING_BUF_DECLARE
474 *
475 * Input Specifications:
476 * - N/A
477 *
478 * Test Procedure:
479 * -# Define two arrays(inbuf,outbuf) and initialize inbuf
480 * -# Put and get data with "for loop"
481 * -# Check if data size pushed is equal to what are gotten.
482 * -# Then initialize the output buffer
483 * -# Put data with different size to check if data size
484 * pushed is equal to what are gotten.
485 *
486 * Expected Test Result:
487 * - data items pushed shall be equal to what are gotten.
488 *
489 * Pass/Fail Criteria:
490 * - Success if test result of step 4,5 is passed. Otherwise, failure.
491 *
492 * Assumptions and Constraints:
493 * - N/A
494 *
495 * @ingroup lib_ringbuffer_tests
496 *
497 * @see ring_buf_put, ring_buf_get
498 */
test_ringbuffer_raw(void)499 void test_ringbuffer_raw(void)
500 {
501 int i;
502 uint8_t inbuf[RINGBUFFER_SIZE];
503 uint8_t outbuf[RINGBUFFER_SIZE];
504 size_t in_size;
505 size_t out_size;
506
507 /* Initialize test buffer. */
508 for (i = 0; i < RINGBUFFER_SIZE; i++) {
509 inbuf[i] = i;
510 }
511
512 for (i = 0; i < 10; i++) {
513 memset(outbuf, 0, sizeof(outbuf));
514 in_size = ring_buf_put(&ringbuf_raw, inbuf,
515 RINGBUFFER_SIZE - 2);
516 out_size = ring_buf_get(&ringbuf_raw, outbuf,
517 RINGBUFFER_SIZE - 2);
518
519 zassert_true(in_size == RINGBUFFER_SIZE - 2, NULL);
520 zassert_true(in_size == out_size, NULL);
521 zassert_true(memcmp(inbuf, outbuf, RINGBUFFER_SIZE - 2) == 0,
522 NULL);
523 }
524
525 memset(outbuf, 0, sizeof(outbuf));
526 in_size = ring_buf_put(&ringbuf_raw, inbuf,
527 RINGBUFFER_SIZE);
528 zassert_equal(in_size, RINGBUFFER_SIZE, NULL);
529
530 in_size = ring_buf_put(&ringbuf_raw, inbuf,
531 1);
532 zassert_equal(in_size, 0, NULL);
533
534 out_size = ring_buf_get(&ringbuf_raw, outbuf,
535 RINGBUFFER_SIZE);
536
537 zassert_true(out_size == RINGBUFFER_SIZE, NULL);
538
539 out_size = ring_buf_get(&ringbuf_raw, outbuf,
540 RINGBUFFER_SIZE + 1);
541 zassert_true(out_size == 0, NULL);
542 zassert_true(ring_buf_is_empty(&ringbuf_raw), NULL);
543
544 /* Validate that raw bytes can be discarded */
545 in_size = ring_buf_put(&ringbuf_raw, inbuf,
546 RINGBUFFER_SIZE);
547 zassert_equal(in_size, RINGBUFFER_SIZE, NULL);
548
549 out_size = ring_buf_get(&ringbuf_raw, NULL,
550 RINGBUFFER_SIZE);
551 zassert_true(out_size == RINGBUFFER_SIZE, NULL);
552
553 out_size = ring_buf_get(&ringbuf_raw, NULL,
554 RINGBUFFER_SIZE + 1);
555 zassert_true(out_size == 0, NULL);
556 zassert_true(ring_buf_is_empty(&ringbuf_raw), NULL);
557 }
558
test_ringbuffer_alloc_put(void)559 void test_ringbuffer_alloc_put(void)
560 {
561 uint8_t outputbuf[RINGBUFFER_SIZE];
562 uint8_t inputbuf[] = {1, 2, 3, 4};
563 uint32_t read_size;
564 uint32_t allocated;
565 uint32_t sum_allocated;
566 uint8_t *data;
567 int err;
568
569 ring_buf_init(&ringbuf_raw, RINGBUFFER_SIZE, ringbuf_raw.buf.buf8);
570
571 allocated = ring_buf_put_claim(&ringbuf_raw, &data, 1);
572 sum_allocated = allocated;
573 zassert_true(allocated == 1U, NULL);
574
575
576 allocated = ring_buf_put_claim(&ringbuf_raw, &data,
577 RINGBUFFER_SIZE - 1);
578 sum_allocated += allocated;
579 zassert_true(allocated == RINGBUFFER_SIZE - 1, NULL);
580
581 /* Putting too much returns error */
582 err = ring_buf_put_finish(&ringbuf_raw, RINGBUFFER_SIZE + 1);
583 zassert_true(err != 0, NULL);
584
585 err = ring_buf_put_finish(&ringbuf_raw, 1);
586 zassert_true(err == 0, NULL);
587
588 err = ring_buf_put_finish(&ringbuf_raw, RINGBUFFER_SIZE - 1);
589 zassert_true(err == 0, NULL);
590
591 read_size = ring_buf_get(&ringbuf_raw, outputbuf,
592 RINGBUFFER_SIZE);
593 zassert_true(read_size == RINGBUFFER_SIZE, NULL);
594
595 for (int i = 0; i < 10; i++) {
596 allocated = ring_buf_put_claim(&ringbuf_raw, &data, 2);
597 if (allocated == 2U) {
598 data[0] = inputbuf[0];
599 data[1] = inputbuf[1];
600 } else {
601 data[0] = inputbuf[0];
602 ring_buf_put_claim(&ringbuf_raw, &data, 1);
603 data[0] = inputbuf[1];
604 }
605
606 allocated = ring_buf_put_claim(&ringbuf_raw, &data, 2);
607 if (allocated == 2U) {
608 data[0] = inputbuf[2];
609 data[1] = inputbuf[3];
610 } else {
611 data[0] = inputbuf[2];
612 ring_buf_put_claim(&ringbuf_raw, &data, 1);
613 data[0] = inputbuf[3];
614 }
615
616 err = ring_buf_put_finish(&ringbuf_raw, 4);
617 zassert_true(err == 0, NULL);
618
619 read_size = ring_buf_get(&ringbuf_raw,
620 outputbuf, 4);
621 zassert_true(read_size == 4U, NULL);
622
623 zassert_true(memcmp(outputbuf, inputbuf, 4) == 0, NULL);
624 }
625 }
626
test_byte_put_free(void)627 void test_byte_put_free(void)
628 {
629 uint8_t indata[] = {1, 2, 3, 4, 5};
630 int err;
631 uint32_t granted;
632 uint8_t *data;
633
634 ring_buf_init(&ringbuf_raw, RINGBUFFER_SIZE, ringbuf_raw.buf.buf8);
635
636 /* Ring buffer is empty */
637 granted = ring_buf_get_claim(&ringbuf_raw, &data, RINGBUFFER_SIZE);
638 zassert_true(granted == 0U, NULL);
639
640 for (int i = 0; i < 10; i++) {
641 ring_buf_put(&ringbuf_raw, indata,
642 RINGBUFFER_SIZE-2);
643
644 granted = ring_buf_get_claim(&ringbuf_raw, &data,
645 RINGBUFFER_SIZE);
646
647 if (granted == (RINGBUFFER_SIZE-2)) {
648 zassert_true(memcmp(indata, data, granted) == 0, NULL);
649 } else if (granted < (RINGBUFFER_SIZE-2)) {
650 /* When buffer wraps, operation is split. */
651 uint32_t granted_1 = granted;
652
653 zassert_true(memcmp(indata, data, granted) == 0, NULL);
654 granted = ring_buf_get_claim(&ringbuf_raw, &data,
655 RINGBUFFER_SIZE);
656
657 zassert_true((granted + granted_1) ==
658 RINGBUFFER_SIZE - 2, NULL);
659 zassert_true(memcmp(&indata[granted_1], data, granted)
660 == 0, NULL);
661 } else {
662 zassert_true(false, NULL);
663 }
664
665 /* Freeing more than possible case. */
666 err = ring_buf_get_finish(&ringbuf_raw, RINGBUFFER_SIZE-1);
667 zassert_true(err != 0, NULL);
668
669 err = ring_buf_get_finish(&ringbuf_raw, RINGBUFFER_SIZE-2);
670 zassert_true(err == 0, NULL);
671 }
672 }
673
test_capacity(void)674 void test_capacity(void)
675 {
676 uint32_t capacity;
677
678 ring_buf_init(&ringbuf_raw, RINGBUFFER_SIZE, ringbuf_raw.buf.buf8);
679
680 /* capacity equals buffer size dedicated for ring buffer - 1 because
681 * 1 byte is used for distinguishing between full and empty state.
682 */
683 capacity = ring_buf_capacity_get(&ringbuf_raw);
684 zassert_equal(RINGBUFFER_SIZE, capacity,
685 "Unexpected capacity");
686 }
687
test_size(void)688 void test_size(void)
689 {
690 uint32_t size;
691 static uint8_t buf[RINGBUFFER_SIZE];
692
693 ring_buf_init(&ringbuf_raw, sizeof(buf), ringbuf_raw.buf.buf8);
694
695 /* Test 0 */
696 size = ring_buf_size_get(&ringbuf_raw);
697 zassert_equal(0, size, "wrong size: exp: %u act: %u", 0, size);
698
699 /* Test 1 */
700 ring_buf_put(&ringbuf_raw, "x", 1);
701 size = ring_buf_size_get(&ringbuf_raw);
702 zassert_equal(1, size, "wrong size: exp: %u act: %u", 1, size);
703
704 /* Test N */
705 ring_buf_reset(&ringbuf_raw);
706 ring_buf_put(&ringbuf_raw, buf, sizeof(buf));
707 size = ring_buf_size_get(&ringbuf_raw);
708 zassert_equal(sizeof(buf), size, "wrong size: exp: %u: actual: %u", sizeof(buf), size);
709
710 /* Test N - 2 with wrap-around */
711 ring_buf_put(&ringbuf_raw, buf, sizeof(buf));
712 ring_buf_get(&ringbuf_raw, NULL, 3);
713 ring_buf_put(&ringbuf_raw, "x", 1);
714
715 size = ring_buf_size_get(&ringbuf_raw);
716 zassert_equal(sizeof(buf) - 2, size, "wrong size: exp: %u: actual: %u", sizeof(buf) - 2,
717 size);
718 }
719
test_peek(void)720 void test_peek(void)
721 {
722 uint32_t size;
723 uint8_t byte = 0x42;
724 static uint8_t buf[RINGBUFFER_SIZE];
725
726 ring_buf_init(&ringbuf_raw, sizeof(buf), ringbuf_raw.buf.buf8);
727
728 /* Test 0 */
729 size = ring_buf_peek(&ringbuf_raw, (uint8_t *)0x1, 42424242);
730 zassert_equal(0, size, "wrong peek size: exp: %u: actual: %u", 0, size);
731
732 /* Test 1 */
733 ring_buf_put(&ringbuf_raw, "*", 1);
734 size = ring_buf_peek(&ringbuf_raw, &byte, 1);
735 zassert_equal(1, size, "wrong peek size: exp: %u: actual: %u", 1, size);
736 zassert_equal('*', byte, "wrong buffer contents: exp: %u: actual: %u", '*', byte);
737 size = ring_buf_size_get(&ringbuf_raw);
738 zassert_equal(1, size, "wrong buffer size: exp: %u: actual: %u", 1, size);
739
740 /* Test N */
741 ring_buf_reset(&ringbuf_raw);
742 for (size = 0; size < sizeof(buf); ++size) {
743 buf[size] = 'A' + (size % ('Z' - 'A' + 1));
744 }
745
746 ring_buf_put(&ringbuf_raw, buf, sizeof(buf));
747 memset(buf, '*', sizeof(buf)); /* fill with pattern */
748
749 size = ring_buf_peek(&ringbuf_raw, buf, sizeof(buf));
750 zassert_equal(sizeof(buf), size, "wrong peek size: exp: %u: actual: %u", sizeof(buf), size);
751 size = ring_buf_size_get(&ringbuf_raw);
752 zassert_equal(sizeof(buf), size, "wrong buffer size: exp: %u: actual: %u", sizeof(buf),
753 size);
754
755 for (size = 0; size < sizeof(buf); ++size) {
756 ringbuf_raw.buf.buf8[size] = 'A' + (size % ('Z' - 'A' + 1));
757 }
758
759 zassert_equal(0, memcmp(buf, ringbuf_raw.buf.buf8, sizeof(buf)),
760 "content validation failed");
761 }
762
test_reset(void)763 void test_reset(void)
764 {
765 uint8_t indata[] = {1, 2, 3, 4, 5};
766 uint8_t outdata[RINGBUFFER_SIZE];
767 uint8_t *outbuf;
768 uint32_t len;
769 uint32_t out_len;
770 uint32_t granted;
771 uint32_t space;
772
773 ring_buf_init(&ringbuf_raw, RINGBUFFER_SIZE, ringbuf_raw.buf.buf8);
774
775 len = 3;
776 out_len = ring_buf_put(&ringbuf_raw, indata, len);
777 zassert_equal(out_len, len, NULL);
778
779 out_len = ring_buf_get(&ringbuf_raw, outdata, len);
780 zassert_equal(out_len, len, NULL);
781
782 space = ring_buf_space_get(&ringbuf_raw);
783 zassert_equal(space, RINGBUFFER_SIZE, NULL);
784
785 /* Even though ringbuffer is empty, full buffer cannot be allocated
786 * because internal pointers are not at the beginning.
787 */
788 granted = ring_buf_put_claim(&ringbuf_raw, &outbuf, RINGBUFFER_SIZE);
789 zassert_false(granted == RINGBUFFER_SIZE, NULL);
790
791 /* After reset full buffer can be allocated. */
792 ring_buf_reset(&ringbuf_raw);
793 granted = ring_buf_put_claim(&ringbuf_raw, &outbuf, RINGBUFFER_SIZE);
794 zassert_true(granted == RINGBUFFER_SIZE, NULL);
795 }
796
797 #ifdef CONFIG_64BIT
798 static uint64_t ringbuf_stored[RINGBUFFER_SIZE];
799 #else
800 static uint32_t ringbuf_stored[RINGBUFFER_SIZE];
801 #endif
802
803 /**
804 * @brief verify the array stored by ringbuf
805 *
806 * @details
807 * Test Objective:
808 * - Define a buffer stored by ringbuffer and keep that the buffer's size
809 * is always equal to the pointer's size. Verify that the address
810 * of the buffer is contiguous.And also verify that data can pass
811 * between buffer and ringbuffer.
812 *
813 * Testing techniques:
814 * - Interface testing
815 * - Dynamic analysis and testing
816 * - Structural test coverage(entry points,statements,branches)
817 *
818 * Prerequisite Conditions:
819 * - Define an array that changes as the system changes.
820 *
821 * Input Specifications:
822 * - N/A
823 *
824 * Test Procedure:
825 * -# Define two buffers(input and output)
826 * -# Put data from input buffer into the ringbuffer
827 * and check if put data are successful.
828 * -# Check if the address stored by ringbuf is contiguous.
829 * -# Get data from the ringbuffer and put them into output buffer
830 * and check if getting data are successful.
831 * -# Then check if the size of array stored by ringbuf is
832 * equal to the size of pointer
833 *
834 * Expected Test Result:
835 * - All assertions can pass.
836 *
837 * Pass/Fail Criteria:
838 * - Success if test result of step 2,3,4,5 is passed. Otherwise, failure.
839 *
840 * Assumptions and Constraints:
841 * - N/A
842 *
843 * @ingroup lib_ringbuffer_tests
844 *
845 * @see ring_buf_item_put, ring_buf_item_get
846 */
test_ringbuffer_array_perf(void)847 void test_ringbuffer_array_perf(void)
848 {
849 struct ring_buf buf_ii;
850 uint32_t input[3] = {0xaa, 0xbb, 0xcc};
851 uint32_t output[3] = {0};
852 uint16_t type = 0;
853 uint8_t value = 0, size = 3;
854 void *tp;
855
856 ring_buf_init(&buf_ii, RINGBUFFER_SIZE, ringbuf_stored);
857
858 /*Data from the beginning of the array can be copied into the ringbuf*/
859 zassert_true(ring_buf_item_put(&buf_ii, 1, 2, input, 3) == 0, NULL);
860
861 /*Verify the address stored by ringbuf is contiguous*/
862 for (int i = 0; i < 3; i++) {
863 zassert_equal(input[i], buf_ii.buf.buf32[i+1], NULL);
864 }
865
866 /*Data from the end of the ringbuf can be copied into the array*/
867 zassert_true(ring_buf_item_get(&buf_ii, &type, &value,
868 output, &size) == 0, NULL);
869
870 /*Verify the ringbuf defined is working*/
871 for (int i = 0; i < 3; i++) {
872 zassert_equal(input[i], output[i], NULL);
873 }
874
875 /*The size of array stored by ringbuf is equal to the size of pointer*/
876 zassert_equal(sizeof(tp), sizeof(ringbuf_stored[0]), NULL);
877 }
878
test_ringbuffer_partial_putting(void)879 void test_ringbuffer_partial_putting(void)
880 {
881 uint8_t indata[RINGBUFFER_SIZE];
882 uint8_t outdata[RINGBUFFER_SIZE];
883 uint32_t len;
884 uint32_t len2;
885 uint32_t req_len;
886 uint8_t *ptr;
887
888 ring_buf_reset(&ringbuf_raw);
889
890 for (int i = 0; i < 100; i++) {
891 req_len = (i % RINGBUFFER_SIZE) + 1;
892 len = ring_buf_put(&ringbuf_raw, indata, req_len);
893 zassert_equal(req_len, len, NULL);
894
895 len = ring_buf_get(&ringbuf_raw, outdata, req_len);
896 zassert_equal(req_len, len, NULL);
897
898 req_len = 2;
899 len = ring_buf_put_claim(&ringbuf_raw, &ptr, 2);
900 zassert_equal(len, 2, NULL);
901
902 len = ring_buf_put_claim(&ringbuf_raw, &ptr, RINGBUFFER_SIZE);
903 len2 = ring_buf_put_claim(&ringbuf_raw, &ptr, RINGBUFFER_SIZE);
904 zassert_equal(len + len2, RINGBUFFER_SIZE - 2, NULL);
905
906 ring_buf_put_finish(&ringbuf_raw, RINGBUFFER_SIZE);
907
908 req_len = RINGBUFFER_SIZE;
909 len = ring_buf_get(&ringbuf_raw, indata, req_len);
910 zassert_equal(len, req_len, NULL);
911 }
912 }
913
test_ringbuffer_partial_getting(void)914 void test_ringbuffer_partial_getting(void)
915 {
916 uint8_t indata[RINGBUFFER_SIZE];
917 uint8_t outdata[RINGBUFFER_SIZE];
918 uint32_t len;
919 uint32_t len2;
920 uint32_t req_len;
921 uint8_t *ptr;
922
923 ring_buf_reset(&ringbuf_raw);
924
925 for (int i = 0; i < 100; i++) {
926 req_len = (i % RINGBUFFER_SIZE) + 1;
927 len = ring_buf_put(&ringbuf_raw, indata, req_len);
928 zassert_equal(req_len, len, NULL);
929
930 len = ring_buf_get(&ringbuf_raw, outdata, req_len);
931 zassert_equal(req_len, len, NULL);
932
933 req_len = sizeof(indata);
934 len = ring_buf_put(&ringbuf_raw, indata, req_len);
935 zassert_equal(req_len, len, NULL);
936
937 len = ring_buf_get_claim(&ringbuf_raw, &ptr, 2);
938 zassert_equal(len, 2, NULL);
939
940 len = ring_buf_get_claim(&ringbuf_raw, &ptr, RINGBUFFER_SIZE);
941 len2 = ring_buf_get_claim(&ringbuf_raw, &ptr, RINGBUFFER_SIZE);
942 zassert_equal(len + len2, RINGBUFFER_SIZE - 2, NULL);
943
944 ring_buf_get_finish(&ringbuf_raw, RINGBUFFER_SIZE);
945 }
946 }
947
test_ringbuffer_equal_bufs(void)948 void test_ringbuffer_equal_bufs(void)
949 {
950 struct ring_buf buf_ii;
951 uint8_t *data;
952 uint32_t claimed;
953 uint8_t buf[8];
954 size_t halfsize = sizeof(buf)/2;
955
956 ring_buf_init(&buf_ii, sizeof(buf), buf);
957
958 for (int i = 0; i < 100; i++) {
959 claimed = ring_buf_put_claim(&buf_ii, &data, halfsize);
960 zassert_equal(claimed, halfsize, NULL);
961 ring_buf_put_finish(&buf_ii, claimed);
962
963 claimed = ring_buf_get_claim(&buf_ii, &data, halfsize);
964 zassert_equal(claimed, halfsize, NULL);
965 ring_buf_get_finish(&buf_ii, claimed);
966 }
967 }
968
test_ringbuffer_performance(void)969 void test_ringbuffer_performance(void)
970 {
971 uint8_t buf[16];
972 static struct ring_buf rbuf;
973 uint8_t indata[16];
974 uint8_t outdata[16];
975 uint8_t *ptr;
976 uint32_t timestamp;
977 int loop = 1000;
978
979 ring_buf_init(&rbuf, sizeof(buf), buf);
980
981 /* Test performance of copy put get 1 byte */
982 timestamp = k_cycle_get_32();
983 for (int i = 0; i < loop; i++) {
984 ring_buf_put(&rbuf, indata, 1);
985 ring_buf_get(&rbuf, outdata, 1);
986 }
987 timestamp = k_cycle_get_32() - timestamp;
988 PRINT("1 byte put-get, avg cycles: %d\n", timestamp/loop);
989
990 /* Test performance of copy put get 1 byte */
991 ring_buf_reset(&rbuf);
992 timestamp = k_cycle_get_32();
993 for (int i = 0; i < loop; i++) {
994 ring_buf_put(&rbuf, indata, 4);
995 ring_buf_get(&rbuf, outdata, 4);
996 }
997 timestamp = k_cycle_get_32() - timestamp;
998 PRINT("4 byte put-get, avg cycles: %d\n", timestamp/loop);
999
1000 /* Test performance of put claim finish 1 byte */
1001 ring_buf_reset(&rbuf);
1002 timestamp = k_cycle_get_32();
1003 for (int i = 0; i < loop; i++) {
1004 ring_buf_put_claim(&rbuf, &ptr, 1);
1005 ring_buf_put_finish(&rbuf, 1);
1006 ring_buf_get(&rbuf, outdata, 1);
1007 }
1008 timestamp = k_cycle_get_32() - timestamp;
1009 PRINT("1 byte put claim-finish, avg cycles: %d\n", timestamp/loop);
1010
1011 /* Test performance of put claim finish 5 byte */
1012 ring_buf_reset(&rbuf);
1013 timestamp = k_cycle_get_32();
1014 for (int i = 0; i < loop; i++) {
1015 ring_buf_put_claim(&rbuf, &ptr, 5);
1016 ring_buf_put_finish(&rbuf, 5);
1017 ring_buf_get(&rbuf, outdata, 5);
1018 }
1019 timestamp = k_cycle_get_32() - timestamp;
1020 PRINT("5 byte put claim-finish, avg cycles: %d\n", timestamp/loop);
1021
1022 /* Test performance of copy put claim finish 5 byte */
1023 ring_buf_reset(&rbuf);
1024 timestamp = k_cycle_get_32();
1025 for (int i = 0; i < loop; i++) {
1026 ring_buf_put(&rbuf, indata, 5);
1027 ring_buf_get_claim(&rbuf, &ptr, 5);
1028 ring_buf_get_finish(&rbuf, 5);
1029 }
1030 timestamp = k_cycle_get_32() - timestamp;
1031 PRINT("5 byte get claim-finish, avg cycles: %d\n", timestamp/loop);
1032 }
1033
1034 /*test case main entry*/
test_main(void)1035 void test_main(void)
1036 {
1037 ztest_test_suite(test_ringbuffer_api,
1038 ztest_unit_test(test_ringbuffer_init),/*keep init first!*/
1039 ztest_unit_test(test_ringbuffer_declare_pow2),
1040 ztest_unit_test(test_ringbuffer_declare_size),
1041 ztest_unit_test(test_ringbuffer_put_get_thread),
1042 ztest_unit_test(test_ringbuffer_put_get_isr),
1043 ztest_unit_test(test_ringbuffer_put_get_thread_isr),
1044 ztest_unit_test(test_ringbuffer_put_get_discard),
1045 ztest_unit_test(test_ringbuffer_pow2_put_get_thread_isr),
1046 ztest_unit_test(test_ringbuffer_size_put_get_thread_isr),
1047 ztest_unit_test(test_ringbuffer_array_perf),
1048 ztest_unit_test(test_ringbuffer_partial_putting),
1049 ztest_unit_test(test_ringbuffer_partial_getting),
1050 ztest_unit_test(test_ring_buffer_main),
1051 ztest_unit_test(test_ringbuffer_raw),
1052 ztest_unit_test(test_ringbuffer_alloc_put),
1053 ztest_unit_test(test_byte_put_free),
1054 ztest_unit_test(test_ringbuffer_equal_bufs),
1055 ztest_unit_test(test_capacity),
1056 ztest_unit_test(test_size),
1057 ztest_unit_test(test_peek),
1058 ztest_unit_test(test_reset),
1059 ztest_unit_test(test_ringbuffer_performance),
1060 ztest_unit_test(test_ringbuffer_concurrent),
1061 ztest_unit_test(test_ringbuffer_shpsc),
1062 ztest_unit_test(test_ringbuffer_spshc),
1063 ztest_unit_test(test_ringbuffer_cpy_shpsc),
1064 ztest_unit_test(test_ringbuffer_cpy_spshc),
1065 ztest_unit_test(test_ringbuffer_item_shpsc),
1066 ztest_unit_test(test_ringbuffer_item_spshc)
1067 );
1068 ztest_run_test_suite(test_ringbuffer_api);
1069 }
1070