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