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