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