| /* |
| * Copyright (c) 2016 Intel Corporation |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <zephyr/ztest.h> |
| #include <zephyr/irq_offload.h> |
| #include <zephyr/sys/ring_buffer.h> |
| |
| #include <zephyr/logging/log.h> |
| LOG_MODULE_REGISTER(test); |
| |
| /** |
| * @defgroup lib_ringbuffer_tests Ringbuffer |
| * @ingroup all_tests |
| * @{ |
| * @} |
| */ |
| |
| RING_BUF_ITEM_DECLARE_POW2(ring_buf1, 8); |
| |
| #define TYPE 1 |
| #define VALUE 2 |
| #define INITIAL_SIZE 2 |
| |
| |
| #define RINGBUFFER_SIZE 5 |
| #define DATA_MAX_SIZE 3 |
| #define POW 2 |
| extern void test_ringbuffer_concurrent(void); |
| extern void test_ringbuffer_zerocpy_stress(void); |
| extern void test_ringbuffer_cpy_stress(void); |
| extern void test_ringbuffer_item_stress(void); |
| /** |
| * @brief Test APIs of ring buffer |
| * |
| * @details |
| * Test Objective: |
| * - Define and initialize a ring buffer and |
| * the ring buffer copy data out of the array by |
| * ring_buf_item_put(), and then ring buffer data |
| * is copied into the array by ring_buf_item_get() |
| * return error when full/empty. |
| * |
| * Testing techniques: |
| * - Interface testing |
| * - Dynamic analysis and testing |
| * - Equivalence classes and input partition testing |
| * - Structural test coverage(entry points,statements,branches) |
| * |
| * Prerequisite Conditions: |
| * - Define and initialize a ringbuffer by using macro |
| * RING_BUF_ITEM_DECLARE_POW2 |
| * |
| * Input Specifications: |
| * - N/A |
| * |
| * Test Procedure: |
| * -# Defined an array with some data items that ready for being |
| * put. |
| * -# Put data items with "while loop". |
| * -# Check if an error will be seen when the ringbuffer is full. |
| * -# Get data items from the ringbuffer. |
| * -# Check if the data put are equal to the data got. |
| * -# Going on getting data from the ringbuffer. |
| * -# Check if an error will be seen when the ringbuffer is empty. |
| * |
| * Expected Test Result: |
| * - Data items pushed shall be equal to what are gotten. And |
| * An error shall be shown up when an item is put into a full ringbuffer or |
| * get some items from an empty ringbuffer. |
| * |
| * Pass/Fail Criteria: |
| * - Success if test result of step 3.5,7 is passed. Otherwise, failure. |
| * |
| * Assumptions and Constraints: |
| * - N/A |
| * |
| * @ingroup lib_ringbuffer_tests |
| * |
| * @see ring_buf_item_put, ring_buf_item_get |
| */ |
| ZTEST(ringbuffer_api, test_ring_buffer_main) |
| { |
| int ret, put_count, i; |
| uint32_t getdata[6]; |
| uint8_t getsize, getval; |
| uint16_t gettype; |
| int dsize = INITIAL_SIZE; |
| |
| __aligned(sizeof(uint32_t)) char rb_data[] = "ABCDEFGHIJKLMNOPQRSTUVWX"; |
| put_count = 0; |
| |
| while (1) { |
| ret = ring_buf_item_put(&ring_buf1, TYPE, VALUE, |
| (uint32_t *)rb_data, dsize); |
| if (ret == -EMSGSIZE) { |
| LOG_DBG("ring buffer is full"); |
| break; |
| } |
| LOG_DBG("inserted %d chunks, %d remaining", dsize, |
| ring_buf_space_get(&ring_buf1)); |
| dsize = (dsize + 1) % RING_BUF_ITEM_SIZEOF(rb_data); |
| put_count++; |
| } |
| |
| getsize = INITIAL_SIZE - 1; |
| ret = ring_buf_item_get(&ring_buf1, &gettype, &getval, |
| getdata, &getsize); |
| if (ret != -EMSGSIZE) { |
| LOG_DBG("Allowed retrieval with insufficient " |
| "destination buffer space"); |
| zassert_true((getsize == INITIAL_SIZE), |
| "Correct size wasn't reported back to the caller"); |
| } |
| |
| for (i = 0; i < put_count; i++) { |
| getsize = RING_BUF_ITEM_SIZEOF(getdata); |
| ret = ring_buf_item_get(&ring_buf1, &gettype, &getval, getdata, |
| &getsize); |
| zassert_true((ret == 0), "Couldn't retrieve a stored value"); |
| LOG_DBG("got %u chunks of type %u and val %u, %u remaining", |
| getsize, gettype, getval, |
| ring_buf_item_space_get(&ring_buf1)); |
| |
| zassert_true((memcmp((char *)getdata, rb_data, |
| getsize * sizeof(uint32_t)) == 0), "data corrupted"); |
| zassert_true((gettype == TYPE), "type information corrupted"); |
| zassert_true((getval == VALUE), "value information corrupted"); |
| } |
| |
| getsize = RING_BUF_ITEM_SIZEOF(getdata); |
| ret = ring_buf_item_get(&ring_buf1, &gettype, &getval, getdata, |
| &getsize); |
| zassert_true((ret == -EAGAIN), "Got data out of an empty buffer"); |
| } |
| |
| /**TESTPOINT: init via RING_BUF_ITEM_DECLARE_POW2*/ |
| RING_BUF_ITEM_DECLARE_POW2(ringbuf_pow2, POW); |
| |
| /**TESTPOINT: init via RING_BUF_ITEM_DECLARE*/ |
| /** |
| * @brief define a ring buffer with arbitrary size |
| * |
| * @see RING_BUF_ITEM_DECLARE(), RING_BUF_DECLARE() |
| */ |
| RING_BUF_ITEM_DECLARE(ringbuf_size, RINGBUFFER_SIZE); |
| |
| RING_BUF_DECLARE(ringbuf_raw, RINGBUFFER_SIZE); |
| |
| static struct ring_buf ringbuf, *pbuf; |
| |
| static uint32_t buffer[RINGBUFFER_SIZE]; |
| |
| static struct { |
| uint8_t length; |
| uint8_t value; |
| uint16_t type; |
| uint32_t buffer[DATA_MAX_SIZE]; |
| } data[] = { |
| { 0, 32, 1, {} }, |
| { 1, 76, 54, { 0x89ab } }, |
| { 3, 0xff, 0xffff, { 0x0f0f, 0xf0f0, 0xff00 } } |
| }; |
| |
| /*entry of contexts*/ |
| static void tringbuf_put(const void *p) |
| { |
| int index = POINTER_TO_INT(p); |
| /**TESTPOINT: ring buffer put*/ |
| int ret = ring_buf_item_put(pbuf, data[index].type, data[index].value, |
| data[index].buffer, data[index].length); |
| |
| zassert_equal(ret, 0); |
| } |
| |
| static void tringbuf_get(const void *p) |
| { |
| uint16_t type; |
| uint8_t value, size32 = DATA_MAX_SIZE; |
| uint32_t rx_data[DATA_MAX_SIZE]; |
| int ret, index = POINTER_TO_INT(p); |
| |
| /**TESTPOINT: ring buffer get*/ |
| ret = ring_buf_item_get(pbuf, &type, &value, rx_data, &size32); |
| zassert_equal(ret, 0); |
| zassert_equal(type, data[index].type); |
| zassert_equal(value, data[index].value); |
| zassert_equal(size32, data[index].length); |
| zassert_equal(memcmp(rx_data, data[index].buffer, size32), 0); |
| } |
| |
| static void tringbuf_get_discard(const void *p) |
| { |
| uint16_t type; |
| uint8_t value, size32; |
| int ret, index = POINTER_TO_INT(p); |
| |
| /**TESTPOINT: ring buffer get*/ |
| ret = ring_buf_item_get(pbuf, &type, &value, NULL, &size32); |
| zassert_equal(ret, 0); |
| zassert_equal(type, data[index].type); |
| zassert_equal(value, data[index].value); |
| zassert_equal(size32, data[index].length); |
| } |
| |
| /*test cases*/ |
| ZTEST(ringbuffer_api, test_ringbuffer_init) |
| { |
| /**TESTPOINT: init via ring_buf_item_init*/ |
| ring_buf_item_init(&ringbuf, RINGBUFFER_SIZE, buffer); |
| zassert_true(ring_buf_is_empty(&ringbuf)); |
| zassert_equal(ring_buf_item_space_get(&ringbuf), RINGBUFFER_SIZE); |
| } |
| |
| ZTEST(ringbuffer_api, test_ringbuffer_declare_pow2) |
| { |
| zassert_true(ring_buf_is_empty(&ringbuf_pow2)); |
| zassert_equal(ring_buf_item_space_get(&ringbuf_pow2), (1 << POW)); |
| } |
| |
| ZTEST(ringbuffer_api, test_ringbuffer_declare_size) |
| { |
| zassert_true(ring_buf_is_empty(&ringbuf_size)); |
| zassert_equal(ring_buf_item_space_get(&ringbuf_size), RINGBUFFER_SIZE, |
| NULL); |
| } |
| |
| /** |
| * @brief verify that ringbuffer can be placed in any user-controlled memory |
| * |
| * @details |
| * Test Objective: |
| * - define and initialize a ring buffer by struct ring_buf, |
| * then passing data by thread to verify the ringbuffer |
| * if it works to be placed in any user-controlled memory. |
| * |
| * Testing techniques: |
| * - Interface testing |
| * - Dynamic analysis and testing |
| * - Structural test coverage(entry points,statements,branches) |
| * |
| * Prerequisite Conditions: |
| * - Define and initialize a ringbuffer by using struct ring_buf |
| * - Define a pointer of ring buffer type. |
| * |
| * Input Specifications: |
| * - N/A |
| * |
| * Test Procedure: |
| * -# Put data items into a ringbuffer |
| * -# Get data items from a ringbuffer |
| * -# Check if data items pushed are equal to what are gotten. |
| * -# Repeat 1,2,3 to verify the ringbuffer is working normally. |
| * |
| * Expected Test Result: |
| * - data items pushed shall be equal to what are gotten. |
| * |
| * Pass/Fail Criteria: |
| * - Success if test result of step 3,4 is passed. Otherwise, failure. |
| * |
| * Assumptions and Constraints: |
| * - N/A |
| * |
| * @ingroup lib_ringbuffer_tests |
| * |
| * @see ring_buf_item_put, ring_buf_item_get |
| */ |
| ZTEST(ringbuffer_api, test_ringbuffer_put_get_thread) |
| { |
| pbuf = &ringbuf; |
| for (int i = 0; i < 1000; i++) { |
| tringbuf_put((const void *)0); |
| tringbuf_put((const void *)1); |
| tringbuf_get((const void *)0); |
| tringbuf_get((const void *)1); |
| tringbuf_put((const void *)2); |
| zassert_false(ring_buf_is_empty(pbuf)); |
| tringbuf_get((const void *)2); |
| zassert_true(ring_buf_is_empty(pbuf)); |
| } |
| } |
| |
| ZTEST(ringbuffer_api, test_ringbuffer_put_get_isr) |
| { |
| pbuf = &ringbuf; |
| irq_offload(tringbuf_put, (const void *)0); |
| irq_offload(tringbuf_put, (const void *)1); |
| irq_offload(tringbuf_get, (const void *)0); |
| irq_offload(tringbuf_get, (const void *)1); |
| irq_offload(tringbuf_put, (const void *)2); |
| zassert_false(ring_buf_is_empty(pbuf)); |
| irq_offload(tringbuf_get, (const void *)2); |
| zassert_true(ring_buf_is_empty(pbuf)); |
| } |
| |
| ZTEST(ringbuffer_api, test_ringbuffer_put_get_thread_isr) |
| { |
| pbuf = &ringbuf; |
| tringbuf_put((const void *)0); |
| irq_offload(tringbuf_put, (const void *)1); |
| tringbuf_get((const void *)0); |
| irq_offload(tringbuf_get, (const void *)1); |
| tringbuf_put((const void *)2); |
| irq_offload(tringbuf_get, (const void *)2); |
| } |
| |
| ZTEST(ringbuffer_api, test_ringbuffer_put_get_discard) |
| { |
| pbuf = &ringbuf; |
| tringbuf_put((const void *)0); |
| tringbuf_put((const void *)1); |
| zassert_false(ring_buf_is_empty(pbuf)); |
| tringbuf_get_discard((const void *)0); |
| tringbuf_get_discard((const void *)1); |
| zassert_true(ring_buf_is_empty(pbuf)); |
| } |
| |
| /** |
| * @brief verify that ringbuffer can be placed in any user-controlled memory |
| * |
| * @details |
| * Test Objective: |
| * - define and initialize a ring buffer by macro RING_BUF_ITEM_DECLARE_POW2, |
| * then passing data by thread and isr to verify the ringbuffer |
| * if it works to be placed in any user-controlled memory. |
| * |
| * Testing techniques: |
| * - Interface testing |
| * - Dynamic analysis and testing |
| * - Structural test coverage(entry points,statements,branches) |
| * |
| * Prerequisite Conditions: |
| * - Define and initialize a ringbuffer by RING_BUF_ITEM_DECLARE_POW2 |
| * - Define a pointer of ring_buffer type. |
| * |
| * Input Specifications: |
| * - N/A |
| * |
| * Test Procedure: |
| * -# Put data items into the ringbuffer by a thread |
| * -# Put data items into the ringbuffer by a ISR |
| * -# Get data items from the ringbuffer by the thread |
| * -# Check if data items pushed are equal to what are gotten. |
| * -# Get data items from the ringbuffer by the ISR |
| * -# Check if data items pushed are equal to what are gotten. |
| * -# Put data items into the ringbuffer by the thread |
| * -# Get data items from the ringbuffer by the ISR |
| * -# Check if data items pushed are equal to what are gotten. |
| * |
| * Expected Test Result: |
| * - data items pushed shall be equal to what are gotten. |
| * |
| * Pass/Fail Criteria: |
| * - Success if test result of step 4,6,9 is passed. Otherwise, failure. |
| * |
| * Assumptions and Constraints: |
| * - N/A |
| * |
| * @ingroup lib_ringbuffer_tests |
| * |
| * @see ring_buf_item_put, ring_buf_item_get |
| */ |
| ZTEST(ringbuffer_api, test_ringbuffer_pow2_put_get_thread_isr) |
| { |
| pbuf = &ringbuf_pow2; |
| tringbuf_put((const void *)0); |
| irq_offload(tringbuf_put, (const void *)1); |
| tringbuf_get((const void *)0); |
| irq_offload(tringbuf_get, (const void *)1); |
| tringbuf_put((const void *)1); |
| irq_offload(tringbuf_get, (const void *)1); |
| } |
| |
| /** |
| * @brief verify that ringbuffer can be placed in any user-controlled memory |
| * |
| * @details |
| * Test Objective: |
| * - define and initialize a ring buffer by macro RING_BUF_ITEM_DECLARE, |
| * then passing data by thread and isr to verify the ringbuffer |
| * if it works to be placed in any user-controlled memory. |
| * |
| * Testing techniques: |
| * - Interface testing |
| * - Dynamic analysis and testing |
| * - Structural test coverage(entry points,statements,branches) |
| * |
| * Prerequisite Conditions: |
| * - Define and initialize a ringbuffer by RING_BUF_ITEM_DECLARE |
| * - Define a pointer of ring buffer type. |
| * |
| * Input Specifications: |
| * - N/A |
| * |
| * Test Procedure: |
| * -# Put data items into the ringbuffer by a thread |
| * -# Put data items into the ringbuffer by a ISR |
| * -# Get data items from the ringbuffer by the thread |
| * -# Check if data items pushed are equal to what are gotten. |
| * -# Get data items from the ringbuffer by the ISR |
| * -# Check if data items pushed are equal to what are gotten. |
| * -# Put data items into the ringbuffer by the thread |
| * -# Get data items from the ringbuffer by the ISR |
| * -# Check if data items pushed are equal to what are gotten. |
| * |
| * Expected Test Result: |
| * - data items pushed shall be equal to what are gotten. |
| * |
| * Pass/Fail Criteria: |
| * - Success if test result of step 4,6,9 is passed. Otherwise, failure. |
| * |
| * Assumptions and Constraints: |
| * - N/A |
| * |
| * @ingroup lib_ringbuffer_tests |
| * |
| * @see ring_buf_item_put, ring_buf_item_get |
| */ |
| ZTEST(ringbuffer_api, test_ringbuffer_size_put_get_thread_isr) |
| { |
| pbuf = &ringbuf_size; |
| tringbuf_put((const void *)0); |
| irq_offload(tringbuf_put, (const void *)1); |
| tringbuf_get((const void *)0); |
| irq_offload(tringbuf_get, (const void *)1); |
| tringbuf_put((const void *)2); |
| irq_offload(tringbuf_get, (const void *)2); |
| } |
| |
| /** |
| * @brief verify that ringbuffer can be placed in any user-controlled memory |
| * |
| * @details |
| * Test Objective: |
| * - define and initialize a ring buffer by macro RING_BUF_DECLARE, |
| * then verify data is passed between ring buffer and array |
| * |
| * Testing techniques: |
| * - Interface testing |
| * - Dynamic analysis and testing |
| * - Structural test coverage(entry points,statements,branches) |
| * |
| * Prerequisite Conditions: |
| * - Define and initialize a ringbuffer by RING_BUF_DECLARE |
| * |
| * Input Specifications: |
| * - N/A |
| * |
| * Test Procedure: |
| * -# Define two arrays(inbuf,outbuf) and initialize inbuf |
| * -# Put and get data with "for loop" |
| * -# Check if data size pushed is equal to what are gotten. |
| * -# Then initialize the output buffer |
| * -# Put data with different size to check if data size |
| * pushed is equal to what are gotten. |
| * |
| * Expected Test Result: |
| * - data items pushed shall be equal to what are gotten. |
| * |
| * Pass/Fail Criteria: |
| * - Success if test result of step 4,5 is passed. Otherwise, failure. |
| * |
| * Assumptions and Constraints: |
| * - N/A |
| * |
| * @ingroup lib_ringbuffer_tests |
| * |
| * @see ring_buf_put, ring_buf_get |
| */ |
| ZTEST(ringbuffer_api, test_ringbuffer_raw) |
| { |
| int i; |
| uint8_t inbuf[RINGBUFFER_SIZE]; |
| uint8_t outbuf[RINGBUFFER_SIZE]; |
| size_t in_size; |
| size_t out_size; |
| |
| /* Initialize test buffer. */ |
| for (i = 0; i < RINGBUFFER_SIZE; i++) { |
| inbuf[i] = i; |
| } |
| |
| for (i = 0; i < 10; i++) { |
| memset(outbuf, 0, sizeof(outbuf)); |
| in_size = ring_buf_put(&ringbuf_raw, inbuf, |
| RINGBUFFER_SIZE - 2); |
| out_size = ring_buf_get(&ringbuf_raw, outbuf, |
| RINGBUFFER_SIZE - 2); |
| |
| zassert_true(in_size == RINGBUFFER_SIZE - 2); |
| zassert_true(in_size == out_size); |
| zassert_true(memcmp(inbuf, outbuf, RINGBUFFER_SIZE - 2) == 0, |
| NULL); |
| } |
| |
| memset(outbuf, 0, sizeof(outbuf)); |
| in_size = ring_buf_put(&ringbuf_raw, inbuf, |
| RINGBUFFER_SIZE); |
| zassert_equal(in_size, RINGBUFFER_SIZE); |
| |
| in_size = ring_buf_put(&ringbuf_raw, inbuf, |
| 1); |
| zassert_equal(in_size, 0); |
| |
| out_size = ring_buf_get(&ringbuf_raw, outbuf, |
| RINGBUFFER_SIZE); |
| |
| zassert_true(out_size == RINGBUFFER_SIZE); |
| |
| out_size = ring_buf_get(&ringbuf_raw, outbuf, |
| RINGBUFFER_SIZE + 1); |
| zassert_true(out_size == 0); |
| zassert_true(ring_buf_is_empty(&ringbuf_raw)); |
| |
| /* Validate that raw bytes can be discarded */ |
| in_size = ring_buf_put(&ringbuf_raw, inbuf, |
| RINGBUFFER_SIZE); |
| zassert_equal(in_size, RINGBUFFER_SIZE); |
| |
| out_size = ring_buf_get(&ringbuf_raw, NULL, |
| RINGBUFFER_SIZE); |
| zassert_true(out_size == RINGBUFFER_SIZE); |
| |
| out_size = ring_buf_get(&ringbuf_raw, NULL, |
| RINGBUFFER_SIZE + 1); |
| zassert_true(out_size == 0); |
| zassert_true(ring_buf_is_empty(&ringbuf_raw)); |
| } |
| |
| ZTEST(ringbuffer_api, test_ringbuffer_alloc_put) |
| { |
| uint8_t outputbuf[RINGBUFFER_SIZE]; |
| uint8_t inputbuf[] = {1, 2, 3, 4}; |
| uint32_t read_size; |
| uint32_t allocated; |
| uint8_t *data; |
| int err; |
| |
| ring_buf_init(&ringbuf_raw, RINGBUFFER_SIZE, ringbuf_raw.buffer); |
| |
| allocated = ring_buf_put_claim(&ringbuf_raw, &data, 1); |
| zassert_true(allocated == 1U); |
| |
| |
| allocated = ring_buf_put_claim(&ringbuf_raw, &data, |
| RINGBUFFER_SIZE - 1); |
| zassert_true(allocated == RINGBUFFER_SIZE - 1); |
| |
| /* Putting too much returns error */ |
| err = ring_buf_put_finish(&ringbuf_raw, RINGBUFFER_SIZE + 1); |
| zassert_true(err != 0); |
| |
| err = ring_buf_put_finish(&ringbuf_raw, 1); |
| zassert_true(err == 0); |
| |
| err = ring_buf_put_finish(&ringbuf_raw, RINGBUFFER_SIZE - 1); |
| zassert_true(err == -EINVAL); |
| |
| read_size = ring_buf_get(&ringbuf_raw, outputbuf, |
| RINGBUFFER_SIZE); |
| zassert_true(read_size == 1); |
| |
| for (int i = 0; i < 10; i++) { |
| allocated = ring_buf_put_claim(&ringbuf_raw, &data, 2); |
| if (allocated == 2U) { |
| data[0] = inputbuf[0]; |
| data[1] = inputbuf[1]; |
| } else { |
| data[0] = inputbuf[0]; |
| ring_buf_put_claim(&ringbuf_raw, &data, 1); |
| data[0] = inputbuf[1]; |
| } |
| |
| allocated = ring_buf_put_claim(&ringbuf_raw, &data, 2); |
| if (allocated == 2U) { |
| data[0] = inputbuf[2]; |
| data[1] = inputbuf[3]; |
| } else { |
| data[0] = inputbuf[2]; |
| ring_buf_put_claim(&ringbuf_raw, &data, 1); |
| data[0] = inputbuf[3]; |
| } |
| |
| err = ring_buf_put_finish(&ringbuf_raw, 4); |
| zassert_true(err == 0); |
| |
| read_size = ring_buf_get(&ringbuf_raw, |
| outputbuf, 4); |
| zassert_true(read_size == 4U); |
| |
| zassert_true(memcmp(outputbuf, inputbuf, 4) == 0); |
| } |
| } |
| |
| ZTEST(ringbuffer_api, test_byte_put_free) |
| { |
| uint8_t indata[] = {1, 2, 3, 4, 5}; |
| int err; |
| uint32_t granted; |
| uint8_t *data; |
| |
| ring_buf_init(&ringbuf_raw, RINGBUFFER_SIZE, ringbuf_raw.buffer); |
| |
| /* Ring buffer is empty */ |
| granted = ring_buf_get_claim(&ringbuf_raw, &data, RINGBUFFER_SIZE); |
| zassert_true(granted == 0U); |
| |
| for (int i = 0; i < 10; i++) { |
| ring_buf_put(&ringbuf_raw, indata, |
| RINGBUFFER_SIZE-2); |
| |
| granted = ring_buf_get_claim(&ringbuf_raw, &data, |
| RINGBUFFER_SIZE); |
| |
| if (granted == (RINGBUFFER_SIZE-2)) { |
| zassert_true(memcmp(indata, data, granted) == 0); |
| } else if (granted < (RINGBUFFER_SIZE-2)) { |
| /* When buffer wraps, operation is split. */ |
| uint32_t granted_1 = granted; |
| |
| zassert_true(memcmp(indata, data, granted) == 0); |
| granted = ring_buf_get_claim(&ringbuf_raw, &data, |
| RINGBUFFER_SIZE); |
| |
| zassert_true((granted + granted_1) == |
| RINGBUFFER_SIZE - 2, NULL); |
| zassert_true(memcmp(&indata[granted_1], data, granted) |
| == 0, NULL); |
| } else { |
| zassert_true(false); |
| } |
| |
| /* Freeing more than possible case. */ |
| err = ring_buf_get_finish(&ringbuf_raw, RINGBUFFER_SIZE-1); |
| zassert_true(err != 0); |
| |
| err = ring_buf_get_finish(&ringbuf_raw, RINGBUFFER_SIZE-2); |
| zassert_true(err == 0); |
| } |
| } |
| |
| ZTEST(ringbuffer_api, test_capacity) |
| { |
| uint32_t capacity; |
| |
| ring_buf_init(&ringbuf_raw, RINGBUFFER_SIZE, ringbuf_raw.buffer); |
| |
| capacity = ring_buf_capacity_get(&ringbuf_raw); |
| zassert_equal(RINGBUFFER_SIZE, capacity, |
| "Unexpected capacity"); |
| } |
| |
| ZTEST(ringbuffer_api, test_size) |
| { |
| uint32_t size; |
| static uint8_t buf[RINGBUFFER_SIZE]; |
| |
| ring_buf_init(&ringbuf_raw, sizeof(buf), ringbuf_raw.buffer); |
| |
| /* Test 0 */ |
| size = ring_buf_size_get(&ringbuf_raw); |
| zassert_equal(0, size, "wrong size: exp: %u act: %u", 0, size); |
| |
| /* Test 1 */ |
| ring_buf_put(&ringbuf_raw, "x", 1); |
| size = ring_buf_size_get(&ringbuf_raw); |
| zassert_equal(1, size, "wrong size: exp: %u act: %u", 1, size); |
| |
| /* Test N */ |
| ring_buf_reset(&ringbuf_raw); |
| ring_buf_put(&ringbuf_raw, buf, sizeof(buf)); |
| size = ring_buf_size_get(&ringbuf_raw); |
| zassert_equal(sizeof(buf), size, "wrong size: exp: %u: actual: %u", sizeof(buf), size); |
| |
| /* Test N - 2 with wrap-around */ |
| ring_buf_put(&ringbuf_raw, buf, sizeof(buf)); |
| ring_buf_get(&ringbuf_raw, NULL, 3); |
| ring_buf_put(&ringbuf_raw, "x", 1); |
| |
| size = ring_buf_size_get(&ringbuf_raw); |
| zassert_equal(sizeof(buf) - 2, size, "wrong size: exp: %u: actual: %u", sizeof(buf) - 2, |
| size); |
| } |
| |
| ZTEST(ringbuffer_api, test_peek) |
| { |
| uint32_t size; |
| uint8_t byte = 0x42; |
| static uint8_t buf[RINGBUFFER_SIZE]; |
| |
| ring_buf_init(&ringbuf_raw, sizeof(buf), ringbuf_raw.buffer); |
| |
| /* Test 0 */ |
| size = ring_buf_peek(&ringbuf_raw, (uint8_t *)0x1, 42424242); |
| zassert_equal(0, size, "wrong peek size: exp: %u: actual: %u", 0, size); |
| |
| /* Test 1 */ |
| ring_buf_put(&ringbuf_raw, "*", 1); |
| size = ring_buf_peek(&ringbuf_raw, &byte, 1); |
| zassert_equal(1, size, "wrong peek size: exp: %u: actual: %u", 1, size); |
| zassert_equal('*', byte, "wrong buffer contents: exp: %u: actual: %u", '*', byte); |
| size = ring_buf_size_get(&ringbuf_raw); |
| zassert_equal(1, size, "wrong buffer size: exp: %u: actual: %u", 1, size); |
| |
| /* Test N */ |
| ring_buf_reset(&ringbuf_raw); |
| for (size = 0; size < sizeof(buf); ++size) { |
| buf[size] = 'A' + (size % ('Z' - 'A' + 1)); |
| } |
| |
| ring_buf_put(&ringbuf_raw, buf, sizeof(buf)); |
| memset(buf, '*', sizeof(buf)); /* fill with pattern */ |
| |
| size = ring_buf_peek(&ringbuf_raw, buf, sizeof(buf)); |
| zassert_equal(sizeof(buf), size, "wrong peek size: exp: %u: actual: %u", sizeof(buf), size); |
| size = ring_buf_size_get(&ringbuf_raw); |
| zassert_equal(sizeof(buf), size, "wrong buffer size: exp: %u: actual: %u", sizeof(buf), |
| size); |
| |
| for (size = 0; size < sizeof(buf); ++size) { |
| ringbuf_raw.buffer[size] = 'A' + (size % ('Z' - 'A' + 1)); |
| } |
| |
| zassert_equal(0, memcmp(buf, ringbuf_raw.buffer, sizeof(buf)), |
| "content validation failed"); |
| } |
| |
| ZTEST(ringbuffer_api, test_reset) |
| { |
| uint8_t indata[] = {1, 2, 3, 4, 5}; |
| uint8_t outdata[RINGBUFFER_SIZE]; |
| uint8_t *outbuf; |
| uint32_t len; |
| uint32_t out_len; |
| uint32_t granted; |
| uint32_t space; |
| |
| ring_buf_init(&ringbuf_raw, RINGBUFFER_SIZE, ringbuf_raw.buffer); |
| |
| len = 3; |
| out_len = ring_buf_put(&ringbuf_raw, indata, len); |
| zassert_equal(out_len, len); |
| |
| out_len = ring_buf_get(&ringbuf_raw, outdata, len); |
| zassert_equal(out_len, len); |
| |
| space = ring_buf_space_get(&ringbuf_raw); |
| zassert_equal(space, RINGBUFFER_SIZE); |
| |
| /* Even though ringbuffer is empty, full buffer cannot be allocated |
| * because internal pointers are not at the beginning. |
| */ |
| granted = ring_buf_put_claim(&ringbuf_raw, &outbuf, RINGBUFFER_SIZE); |
| zassert_false(granted == RINGBUFFER_SIZE); |
| |
| /* After reset full buffer can be allocated. */ |
| ring_buf_reset(&ringbuf_raw); |
| granted = ring_buf_put_claim(&ringbuf_raw, &outbuf, RINGBUFFER_SIZE); |
| zassert_true(granted == RINGBUFFER_SIZE); |
| } |
| |
| static uint32_t ringbuf_stored[RINGBUFFER_SIZE]; |
| |
| /** |
| * @brief verify the array stored by ringbuf |
| * |
| * @details |
| * Test Objective: |
| * - Define a buffer stored by ringbuffer. Verify that the address |
| * of the buffer is contiguous.And also verify that data can pass |
| * between buffer and ringbuffer. |
| * |
| * Testing techniques: |
| * - Interface testing |
| * - Dynamic analysis and testing |
| * - Structural test coverage(entry points,statements,branches) |
| * |
| * Prerequisite Conditions: |
| * - Define an array that changes as the system changes. |
| * |
| * Input Specifications: |
| * - N/A |
| * |
| * Test Procedure: |
| * -# Define two buffers(input and output) |
| * -# Put data from input buffer into the ringbuffer |
| * and check if put data are successful. |
| * -# Check if the address stored by ringbuf is contiguous. |
| * -# Get data from the ringbuffer and put them into output buffer |
| * and check if getting data are successful. |
| * |
| * Expected Test Result: |
| * - All assertions can pass. |
| * |
| * Pass/Fail Criteria: |
| * - Success if test result of step 2,3,4,5 is passed. Otherwise, failure. |
| * |
| * Assumptions and Constraints: |
| * - N/A |
| * |
| * @ingroup lib_ringbuffer_tests |
| * |
| * @see ring_buf_item_put, ring_buf_item_get |
| */ |
| ZTEST(ringbuffer_api, test_ringbuffer_array_perf) |
| { |
| struct ring_buf buf_ii; |
| uint32_t input[3] = {0xaa, 0xbb, 0xcc}; |
| uint32_t output[3] = {0}; |
| uint16_t type = 0; |
| uint8_t value = 0, size = 3; |
| |
| ring_buf_item_init(&buf_ii, RINGBUFFER_SIZE, ringbuf_stored); |
| |
| /*Data from the beginning of the array can be copied into the ringbuf*/ |
| zassert_true(ring_buf_item_put(&buf_ii, 1, 2, input, 3) == 0); |
| |
| /*Verify the address stored by ringbuf is contiguous*/ |
| for (int i = 0; i < 3; i++) { |
| uint32_t *buf32 = (uint32_t *)buf_ii.buffer; |
| |
| zassert_equal(input[i], buf32[i+1]); |
| } |
| |
| /*Data from the end of the ringbuf can be copied into the array*/ |
| zassert_true(ring_buf_item_get(&buf_ii, &type, &value, |
| output, &size) == 0, NULL); |
| |
| /*Verify the ringbuf defined is working*/ |
| for (int i = 0; i < 3; i++) { |
| zassert_equal(input[i], output[i]); |
| } |
| } |
| |
| ZTEST(ringbuffer_api, test_ringbuffer_partial_putting) |
| { |
| uint8_t indata[RINGBUFFER_SIZE]; |
| uint8_t outdata[RINGBUFFER_SIZE]; |
| uint32_t len; |
| uint32_t len2; |
| uint32_t req_len; |
| uint8_t *ptr; |
| |
| ring_buf_reset(&ringbuf_raw); |
| |
| for (int i = 0; i < 100; i++) { |
| req_len = (i % RINGBUFFER_SIZE) + 1; |
| len = ring_buf_put(&ringbuf_raw, indata, req_len); |
| zassert_equal(req_len, len); |
| |
| len = ring_buf_get(&ringbuf_raw, outdata, req_len); |
| zassert_equal(req_len, len); |
| |
| req_len = 2; |
| len = ring_buf_put_claim(&ringbuf_raw, &ptr, req_len); |
| zassert_equal(len, req_len); |
| |
| req_len = RINGBUFFER_SIZE; |
| len = ring_buf_put_claim(&ringbuf_raw, &ptr, req_len); |
| len2 = ring_buf_put_claim(&ringbuf_raw, &ptr, req_len); |
| zassert_equal(len + len2, req_len - 2); |
| |
| ring_buf_put_finish(&ringbuf_raw, req_len); |
| |
| len = ring_buf_get(&ringbuf_raw, indata, req_len); |
| zassert_equal(len, req_len); |
| } |
| } |
| |
| ZTEST(ringbuffer_api, test_ringbuffer_partial_getting) |
| { |
| uint8_t indata[RINGBUFFER_SIZE]; |
| uint8_t outdata[RINGBUFFER_SIZE]; |
| uint32_t len; |
| uint32_t len2; |
| uint32_t req_len; |
| uint8_t *ptr; |
| |
| ring_buf_reset(&ringbuf_raw); |
| |
| for (int i = 0; i < 100; i++) { |
| req_len = (i % RINGBUFFER_SIZE) + 1; |
| len = ring_buf_put(&ringbuf_raw, indata, req_len); |
| zassert_equal(req_len, len); |
| |
| len = ring_buf_get(&ringbuf_raw, outdata, req_len); |
| zassert_equal(req_len, len); |
| |
| req_len = sizeof(indata); |
| len = ring_buf_put(&ringbuf_raw, indata, req_len); |
| zassert_equal(req_len, len); |
| |
| len = ring_buf_get_claim(&ringbuf_raw, &ptr, 2); |
| zassert_equal(len, 2); |
| |
| len = ring_buf_get_claim(&ringbuf_raw, &ptr, RINGBUFFER_SIZE); |
| len2 = ring_buf_get_claim(&ringbuf_raw, &ptr, RINGBUFFER_SIZE); |
| zassert_equal(len + len2, RINGBUFFER_SIZE - 2); |
| |
| ring_buf_get_finish(&ringbuf_raw, RINGBUFFER_SIZE); |
| } |
| } |
| |
| ZTEST(ringbuffer_api, test_ringbuffer_equal_bufs) |
| { |
| struct ring_buf buf_ii; |
| uint8_t *data; |
| uint32_t claimed; |
| uint8_t buf[8]; |
| size_t halfsize = sizeof(buf)/2; |
| |
| ring_buf_init(&buf_ii, sizeof(buf), buf); |
| |
| for (int i = 0; i < 100; i++) { |
| claimed = ring_buf_put_claim(&buf_ii, &data, halfsize); |
| zassert_equal(claimed, halfsize); |
| ring_buf_put_finish(&buf_ii, claimed); |
| |
| claimed = ring_buf_get_claim(&buf_ii, &data, halfsize); |
| zassert_equal(claimed, halfsize); |
| ring_buf_get_finish(&buf_ii, claimed); |
| } |
| } |
| |
| ZTEST(ringbuffer_api, test_ringbuffer_performance) |
| { |
| uint8_t buf[16]; |
| static struct ring_buf rbuf; |
| uint8_t indata[16]; |
| uint8_t outdata[16]; |
| uint8_t *ptr; |
| uint32_t timestamp; |
| int loop = 1000; |
| |
| ring_buf_init(&rbuf, sizeof(buf), buf); |
| |
| /* Test performance of copy put get 1 byte */ |
| timestamp = k_cycle_get_32(); |
| for (int i = 0; i < loop; i++) { |
| ring_buf_put(&rbuf, indata, 1); |
| ring_buf_get(&rbuf, outdata, 1); |
| } |
| timestamp = k_cycle_get_32() - timestamp; |
| PRINT("1 byte put-get, avg cycles: %d\n", timestamp/loop); |
| |
| /* Test performance of copy put get 1 byte */ |
| ring_buf_reset(&rbuf); |
| timestamp = k_cycle_get_32(); |
| for (int i = 0; i < loop; i++) { |
| ring_buf_put(&rbuf, indata, 4); |
| ring_buf_get(&rbuf, outdata, 4); |
| } |
| timestamp = k_cycle_get_32() - timestamp; |
| PRINT("4 byte put-get, avg cycles: %d\n", timestamp/loop); |
| |
| /* Test performance of put claim finish 1 byte */ |
| ring_buf_reset(&rbuf); |
| timestamp = k_cycle_get_32(); |
| for (int i = 0; i < loop; i++) { |
| ring_buf_put_claim(&rbuf, &ptr, 1); |
| ring_buf_put_finish(&rbuf, 1); |
| ring_buf_get(&rbuf, outdata, 1); |
| } |
| timestamp = k_cycle_get_32() - timestamp; |
| PRINT("1 byte put claim-finish, avg cycles: %d\n", timestamp/loop); |
| |
| /* Test performance of put claim finish 5 byte */ |
| ring_buf_reset(&rbuf); |
| timestamp = k_cycle_get_32(); |
| for (int i = 0; i < loop; i++) { |
| ring_buf_put_claim(&rbuf, &ptr, 5); |
| ring_buf_put_finish(&rbuf, 5); |
| ring_buf_get(&rbuf, outdata, 5); |
| } |
| timestamp = k_cycle_get_32() - timestamp; |
| PRINT("5 byte put claim-finish, avg cycles: %d\n", timestamp/loop); |
| |
| /* Test performance of copy put claim finish 5 byte */ |
| ring_buf_reset(&rbuf); |
| timestamp = k_cycle_get_32(); |
| for (int i = 0; i < loop; i++) { |
| ring_buf_put(&rbuf, indata, 5); |
| ring_buf_get_claim(&rbuf, &ptr, 5); |
| ring_buf_get_finish(&rbuf, 5); |
| } |
| timestamp = k_cycle_get_32() - timestamp; |
| PRINT("5 byte get claim-finish, avg cycles: %d\n", timestamp/loop); |
| } |
| |
| /*test case main entry*/ |
| ZTEST_SUITE(ringbuffer_api, NULL, NULL, NULL, NULL, NULL); |