summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorZixun LI <[email protected]>2025-11-27 12:01:33 +0100
committerZixun LI <[email protected]>2025-11-27 12:01:33 +0100
commit2e8d193c732bb211ebff8badff16a84775db42ff (patch)
tree9a3410e65711df25559524b760447ff68fdd316a /test
parentb997ec725812d2f6a573610ba0dd817f271eddea (diff)
parent5ef55bfa30d6f8cf175b3d327f621c76aae7b138 (diff)
Merge remote-tracking branch 'tinyusb/master' into hcd_fsdev
Signed-off-by: Zixun LI <[email protected]>
Diffstat (limited to 'test')
-rwxr-xr-xtest/hil/hil_test.py88
-rw-r--r--test/unit-test/CMakeLists.txt132
-rw-r--r--test/unit-test/project.yml1
-rw-r--r--test/unit-test/test/test_common_func.c110
-rw-r--r--test/unit-test/test/test_fifo.c397
5 files changed, 599 insertions, 129 deletions
diff --git a/test/hil/hil_test.py b/test/hil/hil_test.py
index 3a11cee13..ba0826bd3 100755
--- a/test/hil/hil_test.py
+++ b/test/hil/hil_test.py
@@ -32,6 +32,13 @@ import random
import re
import sys
import time
+import warnings
+
+# Suppress pkg_resources deprecation warning from fs module
+warnings.filterwarnings("ignore", message="pkg_resources is deprecated")
+# Suppress pyfatfs unclean unmount warning
+warnings.filterwarnings("ignore", message="Filesystem was not cleanly unmounted")
+
import serial
import subprocess
import json
@@ -41,6 +48,7 @@ import fs
import hashlib
import ctypes
from pymtp import MTP
+import string
ENUM_TIMEOUT = 30
@@ -50,6 +58,7 @@ STATUS_SKIPPED = "\033[33mSkipped\033[0m"
verbose = False
test_only = []
+build_dir = 'cmake-build'
WCH_RISCV_CONTENT = """
adapter driver wlinke
@@ -395,41 +404,71 @@ def test_device_cdc_dual_ports(board):
]
ser = [open_serial_dev(p) for p in port]
- str_test = [ b"test_no1", b"test_no2" ]
- # Echo test write to each port and read back
- for i in range(len(str_test)):
- s = str_test[i]
- l = len(s)
- ser[i].write(s)
- ser[i].flush()
- rd = [ ser[i].read(l) for i in range(len(ser)) ]
- assert rd[0] == s.lower(), f'Port1 wrong data: expected {s.lower()} was {rd[0]}'
- assert rd[1] == s.upper(), f'Port2 wrong data: expected {s.upper()} was {rd[1]}'
+ def rand_ascii(length):
+ return "".join(random.choices(string.ascii_letters + string.digits, k=length)).encode("ascii")
+
+ sizes = [32, 64, 128, 256, 512, random.randint(2000, 5000)]
+
+ def write_and_check(writer, payload):
+ size = len(payload)
+ for s in ser:
+ s.reset_input_buffer()
+ rd0 = b''
+ rd1 = b''
+ offset = 0
+ # Write in chunks of random 1-64 bytes (device has 64-byte buffer)
+ while offset < size:
+ chunk_size = min(random.randint(1, 64), size - offset)
+ ser[writer].write(payload[offset:offset + chunk_size])
+ ser[writer].flush()
+ rd0 += ser[0].read(chunk_size)
+ rd1 += ser[1].read(chunk_size)
+ offset += chunk_size
+ assert rd0 == payload.lower(), f'Port0 wrong data ({size}): expected {payload.lower()[:16]}... was {rd0[:16]}'
+ assert rd1 == payload.upper(), f'Port1 wrong data ({size}): expected {payload.upper()[:16]}... was {rd1[:16]}'
+
+ for size in sizes:
+ payload0 = rand_ascii(size)
+ write_and_check(0, payload0)
+
+ payload1 = rand_ascii(size)
+ write_and_check(1, payload1)
ser[0].close()
ser[1].close()
def test_device_cdc_msc(board):
uid = board['uid']
- # Echo test
+ # CDC Echo test
port = get_serial_dev(uid, 'TinyUSB', "TinyUSB_Device", 0)
ser = open_serial_dev(port)
- test_str = b"test_str"
- ser.write(test_str)
- ser.flush()
- rd_str = ser.read(len(test_str))
+ def rand_ascii(length):
+ return "".join(random.choices(string.ascii_letters + string.digits, k=length)).encode("ascii")
+
+ sizes = [32, 64, 128, 256, 512, random.randint(2000, 5000)]
+ for size in sizes:
+ test_str = rand_ascii(size)
+ rd_str = b''
+ offset = 0
+ # Write in chunks of random 1-64 bytes (device has 64-byte buffer)
+ while offset < size:
+ chunk_size = min(random.randint(1, 64), size - offset)
+ ser.write(test_str[offset:offset + chunk_size])
+ ser.flush()
+ rd_str += ser.read(chunk_size)
+ offset += chunk_size
+ assert rd_str == test_str, f'CDC wrong data ({size} bytes):\n expected: {test_str}\n received: {rd_str}'
ser.close()
- assert rd_str == test_str, f'CDC wrong data: expected: {test_str} was {rd_str}'
- # Block test
- data = read_disk_file(uid,0,'README.TXT')
+ # MSC Block test
+ data = read_disk_file(uid, 0, 'README.TXT')
readme = \
- b"This is tinyusb's MassStorage Class demo.\r\n\r\n\
+ b"This is tinyusb's MassStorage Class demo.\r\n\r\n\
If you find any bugs or get any questions, feel free to file an\r\n\
issue at github.com/hathach/tinyusb"
- assert data == readme, 'MSC wrong data'
+ assert data == readme, f'MSC wrong data in README.TXT\n expected: {readme.decode()}\n received: {data.decode()}'
def test_device_cdc_msc_freertos(board):
@@ -611,9 +650,7 @@ def test_example(board, f1, example):
if f1 != "":
f1_str = '-f1_' + f1.replace(' ', '_')
- fw_dir = f'{TINYUSB_ROOT}/cmake-build/cmake-build-{name}{f1_str}/{example}'
- if not os.path.exists(fw_dir):
- fw_dir = f'{TINYUSB_ROOT}/examples/cmake-build-{name}{f1_str}/{example}'
+ fw_dir = f'{TINYUSB_ROOT}/{build_dir}/cmake-build-{name}{f1_str}/{example}'
fw_name = f'{fw_dir}/{os.path.basename(example)}'
print(f'{name+f1_str:40} {example:30} ...', end='')
@@ -625,7 +662,7 @@ def test_example(board, f1, example):
print(f'Flashing {fw_name}.elf')
# flash firmware. It may fail randomly, retry a few times
- max_rety = 3
+ max_rety = 1
start_s = time.time()
for i in range(max_rety):
ret = globals()[f'flash_{board["flasher"]["name"].lower()}'](board, fw_name)
@@ -701,6 +738,7 @@ def main():
"""
global verbose
global test_only
+ global build_dir
duration = time.time()
@@ -709,6 +747,7 @@ def main():
parser.add_argument('-b', '--board', action='append', default=[], help='Boards to test, all if not specified')
parser.add_argument('-s', '--skip', action='append', default=[], help='Skip boards from test')
parser.add_argument('-t', '--test-only', action='append', default=[], help='Tests to run, all if not specified')
+ parser.add_argument('-B', '--build', default='cmake-build', help='Build folder name (default: cmake-build)')
parser.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
args = parser.parse_args()
@@ -717,6 +756,7 @@ def main():
skip_boards = args.skip
verbose = args.verbose
test_only = args.test_only
+ build_dir = args.build
# if config file is not found, try to find it in the same directory as this script
if not os.path.exists(config_file):
diff --git a/test/unit-test/CMakeLists.txt b/test/unit-test/CMakeLists.txt
new file mode 100644
index 000000000..7172f5575
--- /dev/null
+++ b/test/unit-test/CMakeLists.txt
@@ -0,0 +1,132 @@
+cmake_minimum_required(VERSION 3.20)
+
+project(tinyusb_unit_tests LANGUAGES C)
+
+set(CMAKE_C_STANDARD 99)
+set(CMAKE_C_STANDARD_REQUIRED ON)
+set(CMAKE_C_EXTENSIONS ON)
+
+# Command to invoke Ceedling. Supports multi-word commands such as "bundle exec ceedling".
+set(CEEDLING_COMMAND "ceedling" CACHE STRING "Command used to invoke Ceedling (Ruby gem).")
+separate_arguments(CEEDLING_COMMAND_LIST NATIVE_COMMAND "${CEEDLING_COMMAND}")
+if (CEEDLING_COMMAND_LIST STREQUAL "")
+ message(FATAL_ERROR "CEEDLING_COMMAND is empty; set it to a valid Ceedling invocation.")
+endif ()
+
+list(GET CEEDLING_COMMAND_LIST 0 CEEDLING_LAUNCHER)
+find_program(CEEDLING_LAUNCHER_PATH NAMES ${CEEDLING_LAUNCHER})
+if (NOT CEEDLING_LAUNCHER_PATH)
+ message(FATAL_ERROR "Could not find '${CEEDLING_LAUNCHER}' on PATH; adjust CEEDLING_COMMAND or PATH.")
+endif ()
+list(REMOVE_AT CEEDLING_COMMAND_LIST 0)
+list(INSERT CEEDLING_COMMAND_LIST 0 ${CEEDLING_LAUNCHER_PATH})
+
+set(CEEDLING_WORKDIR ${CMAKE_CURRENT_LIST_DIR})
+set(CEEDLING_BUILD_DIR ${CEEDLING_WORKDIR}/_build)
+
+# Helper to add a Ceedling-backed test target that compiles into a real CMake executable.
+function(add_ceedling_test TARGET_NAME TEST_SOURCE PRODUCT_SOURCES MOCK_SOURCES)
+ set(runner ${CEEDLING_BUILD_DIR}/test/runners/${TARGET_NAME}_runner.c)
+
+ add_custom_target(ceedling_gen_${TARGET_NAME}
+ COMMAND ${CEEDLING_COMMAND_LIST} test:${TARGET_NAME}
+ WORKING_DIRECTORY ${CEEDLING_WORKDIR}
+ BYPRODUCTS ${runner}
+ USES_TERMINAL
+ COMMENT "Generate Ceedling runner/mocks for ${TARGET_NAME}"
+ )
+
+ add_executable(${TARGET_NAME}
+ ${TEST_SOURCE}
+ ${runner}
+ ${MOCK_SOURCES}
+ ${CEEDLING_BUILD_DIR}/vendor/unity/src/unity.c
+ ${CEEDLING_BUILD_DIR}/vendor/cmock/src/cmock.c
+ ${PRODUCT_SOURCES}
+ )
+
+ set_source_files_properties(
+ ${runner}
+ ${MOCK_SOURCES}
+ ${CEEDLING_BUILD_DIR}/vendor/unity/src/unity.c
+ ${CEEDLING_BUILD_DIR}/vendor/cmock/src/cmock.c
+ PROPERTIES GENERATED TRUE
+ )
+
+ add_dependencies(${TARGET_NAME} ceedling_gen_${TARGET_NAME})
+
+ target_include_directories(${TARGET_NAME} PRIVATE
+ ${CEEDLING_WORKDIR}/test
+ ${CEEDLING_WORKDIR}/test/support
+ ${CEEDLING_BUILD_DIR}/test/runners
+ ${CEEDLING_BUILD_DIR}/test/mocks/${TARGET_NAME}
+ ${CEEDLING_BUILD_DIR}/vendor/unity/src
+ ${CEEDLING_BUILD_DIR}/vendor/cmock/src
+ ${CEEDLING_WORKDIR}/../../src
+ ${CEEDLING_WORKDIR}/../../src/common
+ ${CEEDLING_WORKDIR}/../../src/device
+ ${CEEDLING_WORKDIR}/../../src/class
+ ${CEEDLING_WORKDIR}/../../src/class/msc
+ ${CEEDLING_WORKDIR}/../../src/host
+ ${CEEDLING_WORKDIR}/../../src/typec
+ ${CEEDLING_WORKDIR}/../../src/osal
+ )
+
+ target_compile_definitions(${TARGET_NAME} PRIVATE _UNITY_TEST_)
+ target_compile_options(${TARGET_NAME} PRIVATE -Wall -Wextra)
+ add_test(NAME ${TARGET_NAME} COMMAND ${TARGET_NAME})
+endfunction()
+
+# Custom targets to keep plain Ceedling entry-points available.
+add_custom_target(ceedling_all
+ COMMAND ${CEEDLING_COMMAND_LIST} test:all
+ WORKING_DIRECTORY ${CEEDLING_WORKDIR}
+ USES_TERMINAL
+ COMMENT "Run Ceedling (Unity) unit tests"
+ )
+
+add_custom_target(ceedling_clean
+ COMMAND ${CEEDLING_COMMAND_LIST} clean
+ WORKING_DIRECTORY ${CEEDLING_WORKDIR}
+ USES_TERMINAL
+ COMMENT "Clean Ceedling build outputs"
+ )
+
+add_custom_target(ceedling_clobber
+ COMMAND ${CEEDLING_COMMAND_LIST} clobber
+ WORKING_DIRECTORY ${CEEDLING_WORKDIR}
+ USES_TERMINAL
+ COMMENT "Clobber Ceedling build outputs"
+ )
+
+# Per-test wiring: mocks are generated under _build/test/mocks/<name>/.
+add_ceedling_test(
+ test_common_func
+ ${CEEDLING_WORKDIR}/test/test_common_func.c
+ ""
+ ""
+ )
+
+add_ceedling_test(
+ test_fifo
+ ${CEEDLING_WORKDIR}/test/test_fifo.c
+ ${CEEDLING_WORKDIR}/../../src/common/tusb_fifo.c
+ ""
+ )
+target_compile_definitions(test_fifo PRIVATE CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32=1)
+
+add_ceedling_test(
+ test_usbd
+ ${CEEDLING_WORKDIR}/test/device/usbd/test_usbd.c
+ "${CEEDLING_WORKDIR}/../../src/tusb.c;${CEEDLING_WORKDIR}/../../src/device/usbd.c;${CEEDLING_WORKDIR}/../../src/device/usbd_control.c;${CEEDLING_WORKDIR}/../../src/common/tusb_fifo.c"
+ "${CEEDLING_BUILD_DIR}/test/mocks/test_usbd/mock_dcd.c;${CEEDLING_BUILD_DIR}/test/mocks/test_usbd/mock_msc_device.c"
+ )
+
+add_ceedling_test(
+ test_msc_device
+ ${CEEDLING_WORKDIR}/test/device/msc/test_msc_device.c
+ "${CEEDLING_WORKDIR}/../../src/tusb.c;${CEEDLING_WORKDIR}/../../src/device/usbd.c;${CEEDLING_WORKDIR}/../../src/device/usbd_control.c;${CEEDLING_WORKDIR}/../../src/class/msc/msc_device.c;${CEEDLING_WORKDIR}/../../src/common/tusb_fifo.c"
+ "${CEEDLING_BUILD_DIR}/test/mocks/test_msc_device/mock_dcd.c"
+ )
+
+enable_testing()
diff --git a/test/unit-test/project.yml b/test/unit-test/project.yml
index 6c86b0205..d971d098d 100644
--- a/test/unit-test/project.yml
+++ b/test/unit-test/project.yml
@@ -128,6 +128,7 @@
:defines:
:test:
- _UNITY_TEST_
+ - CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32
:release: []
# Enable to inject name of a test as a unique compilation symbol into its respective executable build.
diff --git a/test/unit-test/test/test_common_func.c b/test/unit-test/test/test_common_func.c
index 981531dd7..8afcc5b2b 100644
--- a/test/unit-test/test/test_common_func.c
+++ b/test/unit-test/test/test_common_func.c
@@ -80,3 +80,113 @@ void test_TU_ARGS_NUM(void)
TEST_ASSERT_EQUAL(31, TU_ARGS_NUM(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31));
TEST_ASSERT_EQUAL(32, TU_ARGS_NUM(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, a32));
}
+
+void test_tu_scatter_read32(void) {
+ // Test data: 0x04030201
+ uint8_t buf1[] = {0x01, 0x02, 0x03, 0x04};
+ uint8_t buf2[] = {0x05, 0x06, 0x07, 0x08};
+
+ // len1=1, len2=0: read 1 byte from buf1
+ TEST_ASSERT_EQUAL_HEX32(0x01, tu_scatter_read32(buf1, 1, buf2, 0));
+
+ // len1=1, len2=1: read 1 byte from buf1, 1 byte from buf2
+ TEST_ASSERT_EQUAL_HEX32(0x0501, tu_scatter_read32(buf1, 1, buf2, 1));
+
+ // len1=1, len2=2: read 1 byte from buf1, 2 bytes from buf2
+ TEST_ASSERT_EQUAL_HEX32(0x060501, tu_scatter_read32(buf1, 1, buf2, 2));
+
+ // len1=1, len2=3: read 1 byte from buf1, 3 bytes from buf2
+ TEST_ASSERT_EQUAL_HEX32(0x07060501, tu_scatter_read32(buf1, 1, buf2, 3));
+
+ // len1=2, len2=0: read 2 bytes from buf1
+ TEST_ASSERT_EQUAL_HEX32(0x0201, tu_scatter_read32(buf1, 2, buf2, 0));
+
+ // len1=2, len2=1: read 2 bytes from buf1, 1 byte from buf2
+ TEST_ASSERT_EQUAL_HEX32(0x050201, tu_scatter_read32(buf1, 2, buf2, 1));
+
+ // len1=2, len2=2: read 2 bytes from buf1, 2 bytes from buf2
+ TEST_ASSERT_EQUAL_HEX32(0x06050201, tu_scatter_read32(buf1, 2, buf2, 2));
+
+ // len1=3, len2=0: read 3 bytes from buf1
+ TEST_ASSERT_EQUAL_HEX32(0x030201, tu_scatter_read32(buf1, 3, buf2, 0));
+
+ // len1=3, len2=1: read 3 bytes from buf1, 1 byte from buf2
+ TEST_ASSERT_EQUAL_HEX32(0x05030201, tu_scatter_read32(buf1, 3, buf2, 1));
+}
+
+void test_tu_scatter_write32(void) {
+ uint8_t buf1[4];
+ uint8_t buf2[4];
+
+ // len1=1, len2=0: write 1 byte to buf1
+ memset(buf1, 0, sizeof(buf1));
+ memset(buf2, 0, sizeof(buf2));
+ tu_scatter_write32(0x01, buf1, 1, buf2, 0);
+ TEST_ASSERT_EQUAL_HEX8(0x01, buf1[0]);
+ TEST_ASSERT_EQUAL_HEX8(0x00, buf2[0]);
+
+ // len1=1, len2=1: write 1 byte to buf1, 1 byte to buf2
+ memset(buf1, 0, sizeof(buf1));
+ memset(buf2, 0, sizeof(buf2));
+ tu_scatter_write32(0x0201, buf1, 1, buf2, 1);
+ TEST_ASSERT_EQUAL_HEX8(0x01, buf1[0]);
+ TEST_ASSERT_EQUAL_HEX8(0x02, buf2[0]);
+
+ // len1=1, len2=2: write 1 byte to buf1, 2 bytes to buf2
+ memset(buf1, 0, sizeof(buf1));
+ memset(buf2, 0, sizeof(buf2));
+ tu_scatter_write32(0x030201, buf1, 1, buf2, 2);
+ TEST_ASSERT_EQUAL_HEX8(0x01, buf1[0]);
+ TEST_ASSERT_EQUAL_HEX8(0x02, buf2[0]);
+ TEST_ASSERT_EQUAL_HEX8(0x03, buf2[1]);
+
+ // len1=1, len2=3: write 1 byte to buf1, 3 bytes to buf2
+ memset(buf1, 0, sizeof(buf1));
+ memset(buf2, 0, sizeof(buf2));
+ tu_scatter_write32(0x04030201, buf1, 1, buf2, 3);
+ TEST_ASSERT_EQUAL_HEX8(0x01, buf1[0]);
+ TEST_ASSERT_EQUAL_HEX8(0x02, buf2[0]);
+ TEST_ASSERT_EQUAL_HEX8(0x03, buf2[1]);
+ TEST_ASSERT_EQUAL_HEX8(0x04, buf2[2]);
+
+ // len1=2, len2=0: write 2 bytes to buf1
+ memset(buf1, 0, sizeof(buf1));
+ memset(buf2, 0, sizeof(buf2));
+ tu_scatter_write32(0x0201, buf1, 2, buf2, 0);
+ TEST_ASSERT_EQUAL_HEX8(0x01, buf1[0]);
+ TEST_ASSERT_EQUAL_HEX8(0x02, buf1[1]);
+
+ // len1=2, len2=1: write 2 bytes to buf1, 1 byte to buf2
+ memset(buf1, 0, sizeof(buf1));
+ memset(buf2, 0, sizeof(buf2));
+ tu_scatter_write32(0x030201, buf1, 2, buf2, 1);
+ TEST_ASSERT_EQUAL_HEX8(0x01, buf1[0]);
+ TEST_ASSERT_EQUAL_HEX8(0x02, buf1[1]);
+ TEST_ASSERT_EQUAL_HEX8(0x03, buf2[0]);
+
+ // len1=2, len2=2: write 2 bytes to buf1, 2 bytes to buf2
+ memset(buf1, 0, sizeof(buf1));
+ memset(buf2, 0, sizeof(buf2));
+ tu_scatter_write32(0x04030201, buf1, 2, buf2, 2);
+ TEST_ASSERT_EQUAL_HEX8(0x01, buf1[0]);
+ TEST_ASSERT_EQUAL_HEX8(0x02, buf1[1]);
+ TEST_ASSERT_EQUAL_HEX8(0x03, buf2[0]);
+ TEST_ASSERT_EQUAL_HEX8(0x04, buf2[1]);
+
+ // len1=3, len2=0: write 3 bytes to buf1
+ memset(buf1, 0, sizeof(buf1));
+ memset(buf2, 0, sizeof(buf2));
+ tu_scatter_write32(0x030201, buf1, 3, buf2, 0);
+ TEST_ASSERT_EQUAL_HEX8(0x01, buf1[0]);
+ TEST_ASSERT_EQUAL_HEX8(0x02, buf1[1]);
+ TEST_ASSERT_EQUAL_HEX8(0x03, buf1[2]);
+
+ // len1=3, len2=1: write 3 bytes to buf1, 1 byte to buf2
+ memset(buf1, 0, sizeof(buf1));
+ memset(buf2, 0, sizeof(buf2));
+ tu_scatter_write32(0x04030201, buf1, 3, buf2, 1);
+ TEST_ASSERT_EQUAL_HEX8(0x01, buf1[0]);
+ TEST_ASSERT_EQUAL_HEX8(0x02, buf1[1]);
+ TEST_ASSERT_EQUAL_HEX8(0x03, buf1[2]);
+ TEST_ASSERT_EQUAL_HEX8(0x04, buf2[0]);
+}
diff --git a/test/unit-test/test/test_fifo.c b/test/unit-test/test/test_fifo.c
index 3b4deb33e..35bbeaa62 100644
--- a/test/unit-test/test/test_fifo.c
+++ b/test/unit-test/test/test_fifo.c
@@ -30,51 +30,52 @@
#include "osal/osal.h"
#include "tusb_fifo.h"
-#define FIFO_SIZE 64
-uint8_t tu_ff_buf[FIFO_SIZE * sizeof(uint8_t)];
+#define FIFO_SIZE 64
+uint8_t tu_ff_buf[FIFO_SIZE * sizeof(uint8_t)];
tu_fifo_t tu_ff = TU_FIFO_INIT(tu_ff_buf, FIFO_SIZE, uint8_t, false);
-tu_fifo_t* ff = &tu_ff;
+tu_fifo_t *ff = &tu_ff;
tu_fifo_buffer_info_t info;
uint8_t test_data[4096];
uint8_t rd_buf[FIFO_SIZE];
-void setUp(void)
-{
+void setUp(void) {
tu_fifo_clear(ff);
memset(&info, 0, sizeof(tu_fifo_buffer_info_t));
- for(int i=0; i<sizeof(test_data); i++) test_data[i] = i;
+ for (size_t i = 0; i < sizeof(test_data); i++) {
+ test_data[i] = i;
+ }
memset(rd_buf, 0, sizeof(rd_buf));
}
-void tearDown(void)
-{
+void tearDown(void) {
}
//--------------------------------------------------------------------+
// Tests
//--------------------------------------------------------------------+
-void test_normal(void)
-{
- for(uint8_t i=0; i < FIFO_SIZE; i++) tu_fifo_write(ff, &i);
+void test_normal(void) {
+ for (uint8_t i = 0; i < FIFO_SIZE; i++) {
+ tu_fifo_write(ff, &i);
+ }
- for(uint8_t i=0; i < FIFO_SIZE; i++)
- {
+ for (uint8_t i = 0; i < FIFO_SIZE; i++) {
uint8_t c;
tu_fifo_read(ff, &c);
TEST_ASSERT_EQUAL(i, c);
}
}
-void test_item_size(void)
-{
- uint8_t ff4_buf[FIFO_SIZE * sizeof(uint32_t)];
+void test_item_size(void) {
+ uint8_t ff4_buf[FIFO_SIZE * sizeof(uint32_t)];
tu_fifo_t ff4 = TU_FIFO_INIT(ff4_buf, FIFO_SIZE, uint32_t, false);
- uint32_t data4[2*FIFO_SIZE];
- for(uint32_t i=0; i<sizeof(data4)/4; i++) data4[i] = i;
+ uint32_t data4[2 * FIFO_SIZE];
+ for (uint32_t i = 0; i < sizeof(data4) / 4; i++) {
+ data4[i] = i;
+ }
// fill up fifo
tu_fifo_write_n(&ff4, data4, FIFO_SIZE);
@@ -84,78 +85,77 @@ void test_item_size(void)
// read 0 -> 4
rd_count = tu_fifo_read_n(&ff4, rd_buf4, 5);
- TEST_ASSERT_EQUAL( 5, rd_count );
- TEST_ASSERT_EQUAL_UINT32_ARRAY( data4, rd_buf4, rd_count ); // 0 -> 4
+ TEST_ASSERT_EQUAL(5, rd_count);
+ TEST_ASSERT_EQUAL_UINT32_ARRAY(data4, rd_buf4, rd_count); // 0 -> 4
- tu_fifo_write_n(&ff4, data4+FIFO_SIZE, 5);
+ tu_fifo_write_n(&ff4, data4 + FIFO_SIZE, 5);
// read all 5 -> 68
rd_count = tu_fifo_read_n(&ff4, rd_buf4, FIFO_SIZE);
- TEST_ASSERT_EQUAL( FIFO_SIZE, rd_count );
- TEST_ASSERT_EQUAL_UINT32_ARRAY( data4+5, rd_buf4, rd_count ); // 5 -> 68
+ TEST_ASSERT_EQUAL(FIFO_SIZE, rd_count);
+ TEST_ASSERT_EQUAL_UINT32_ARRAY(data4 + 5, rd_buf4, rd_count); // 5 -> 68
}
-void test_read_n(void)
-{
+void test_read_n(void) {
uint16_t rd_count;
// fill up fifo
- for(uint8_t i=0; i < FIFO_SIZE; i++) tu_fifo_write(ff, test_data+i);
+ for (uint8_t i = 0; i < FIFO_SIZE; i++) {
+ tu_fifo_write(ff, test_data + i);
+ }
// case 1: Read index + count < depth
// read 0 -> 4
rd_count = tu_fifo_read_n(ff, rd_buf, 5);
- TEST_ASSERT_EQUAL( 5, rd_count );
- TEST_ASSERT_EQUAL_MEMORY( test_data, rd_buf, rd_count ); // 0 -> 4
+ TEST_ASSERT_EQUAL(5, rd_count);
+ TEST_ASSERT_EQUAL_MEMORY(test_data, rd_buf, rd_count); // 0 -> 4
// case 2: Read index + count > depth
// write 10, 11, 12
- tu_fifo_write(ff, test_data+FIFO_SIZE);
- tu_fifo_write(ff, test_data+FIFO_SIZE+1);
- tu_fifo_write(ff, test_data+FIFO_SIZE+2);
+ tu_fifo_write(ff, test_data + FIFO_SIZE);
+ tu_fifo_write(ff, test_data + FIFO_SIZE + 1);
+ tu_fifo_write(ff, test_data + FIFO_SIZE + 2);
rd_count = tu_fifo_read_n(ff, rd_buf, 7);
- TEST_ASSERT_EQUAL( 7, rd_count );
+ TEST_ASSERT_EQUAL(7, rd_count);
- TEST_ASSERT_EQUAL_MEMORY( test_data+5, rd_buf, rd_count ); // 5 -> 11
+ TEST_ASSERT_EQUAL_MEMORY(test_data + 5, rd_buf, rd_count); // 5 -> 11
// Should only read until empty
- TEST_ASSERT_EQUAL( FIFO_SIZE-5+3-7, tu_fifo_read_n(ff, rd_buf, 100) );
+ TEST_ASSERT_EQUAL(FIFO_SIZE - 5 + 3 - 7, tu_fifo_read_n(ff, rd_buf, 100));
}
-void test_write_n(void)
-{
+void test_write_n(void) {
// case 1: wr + count < depth
tu_fifo_write_n(ff, test_data, 32); // wr = 32, count = 32
uint16_t rd_count;
rd_count = tu_fifo_read_n(ff, rd_buf, 16); // wr = 32, count = 16
- TEST_ASSERT_EQUAL( 16, rd_count );
- TEST_ASSERT_EQUAL_MEMORY( test_data, rd_buf, rd_count );
+ TEST_ASSERT_EQUAL(16, rd_count);
+ TEST_ASSERT_EQUAL_MEMORY(test_data, rd_buf, rd_count);
// case 2: wr + count > depth
- tu_fifo_write_n(ff, test_data+32, 40); // wr = 72 -> 8, count = 56
+ tu_fifo_write_n(ff, test_data + 32, 40); // wr = 72 -> 8, count = 56
- tu_fifo_read_n(ff, rd_buf, 32); // count = 24
- TEST_ASSERT_EQUAL_MEMORY( test_data+16, rd_buf, rd_count);
+ tu_fifo_read_n(ff, rd_buf, 32); // count = 24
+ TEST_ASSERT_EQUAL_MEMORY(test_data + 16, rd_buf, rd_count);
TEST_ASSERT_EQUAL(24, tu_fifo_count(ff));
}
-void test_write_double_overflowed(void)
-{
+void test_write_double_overflowed(void) {
tu_fifo_set_overwritable(ff, true);
- uint8_t rd_buf[FIFO_SIZE] = { 0 };
- uint8_t* buf = test_data;
+ uint8_t rd_buf[FIFO_SIZE] = {0};
+ uint8_t *buf = test_data;
// full
buf += tu_fifo_write_n(ff, buf, FIFO_SIZE);
TEST_ASSERT_EQUAL(FIFO_SIZE, tu_fifo_count(ff));
// write more, should still full
- buf += tu_fifo_write_n(ff, buf, FIFO_SIZE-8);
+ buf += tu_fifo_write_n(ff, buf, FIFO_SIZE - 8);
TEST_ASSERT_EQUAL(FIFO_SIZE, tu_fifo_count(ff));
// double overflowed: in total, write more than > 2*FIFO_SIZE
@@ -165,14 +165,13 @@ void test_write_double_overflowed(void)
// reading back should give back data from last FIFO_SIZE write
tu_fifo_read_n(ff, rd_buf, FIFO_SIZE);
- TEST_ASSERT_EQUAL_MEMORY(buf-16, rd_buf+FIFO_SIZE-16, 16);
+ TEST_ASSERT_EQUAL_MEMORY(buf - 16, rd_buf + FIFO_SIZE - 16, 16);
// TODO whole buffer should match, but we deliberately not implement it
// TEST_ASSERT_EQUAL_MEMORY(buf-FIFO_SIZE, rd_buf, FIFO_SIZE);
}
-static uint16_t help_write(uint16_t total, uint16_t n)
-{
+static uint16_t help_write(uint16_t total, uint16_t n) {
tu_fifo_write_n(ff, test_data, n);
total = tu_min16(FIFO_SIZE, total + n);
@@ -182,8 +181,7 @@ static uint16_t help_write(uint16_t total, uint16_t n)
return total;
}
-void test_write_overwritable2(void)
-{
+void test_write_overwritable2(void) {
tu_fifo_set_overwritable(ff, true);
// based on actual crash tests detected by fuzzing
@@ -202,13 +200,15 @@ void test_write_overwritable2(void)
total = help_write(total, 192);
}
-void test_peek(void)
-{
+void test_peek(void) {
uint8_t temp;
- temp = 10; tu_fifo_write(ff, &temp);
- temp = 20; tu_fifo_write(ff, &temp);
- temp = 30; tu_fifo_write(ff, &temp);
+ temp = 10;
+ tu_fifo_write(ff, &temp);
+ temp = 20;
+ tu_fifo_write(ff, &temp);
+ temp = 30;
+ tu_fifo_write(ff, &temp);
temp = 0;
@@ -222,12 +222,13 @@ void test_peek(void)
TEST_ASSERT_EQUAL(30, temp);
}
-void test_get_read_info_when_no_wrap()
-{
+void test_get_read_info_when_no_wrap() {
uint8_t ch = 1;
// write 6 items
- for(uint8_t i=0; i < 6; i++) tu_fifo_write(ff, &ch);
+ for (uint8_t i = 0; i < 6; i++) {
+ tu_fifo_write(ff, &ch);
+ }
// read 2 items
tu_fifo_read(ff, &ch);
@@ -235,22 +236,25 @@ void test_get_read_info_when_no_wrap()
tu_fifo_get_read_info(ff, &info);
- TEST_ASSERT_EQUAL(4, info.len_lin);
- TEST_ASSERT_EQUAL(0, info.len_wrap);
+ TEST_ASSERT_EQUAL(4, info.linear.len);
+ TEST_ASSERT_EQUAL(0, info.wrapped.len);
- TEST_ASSERT_EQUAL_PTR(ff->buffer+2, info.ptr_lin);
- TEST_ASSERT_NULL(info.ptr_wrap);
+ TEST_ASSERT_EQUAL_PTR(ff->buffer + 2, info.linear.ptr);
+ TEST_ASSERT_NULL(info.wrapped.ptr);
}
-void test_get_read_info_when_wrapped()
-{
+void test_get_read_info_when_wrapped() {
uint8_t ch = 1;
// make fifo full
- for(uint8_t i=0; i < FIFO_SIZE; i++) tu_fifo_write(ff, &ch);
+ for (uint8_t i = 0; i < FIFO_SIZE; i++) {
+ tu_fifo_write(ff, &ch);
+ }
// read 6 items
- for(uint8_t i=0; i < 6; i++) tu_fifo_read(ff, &ch);
+ for (uint8_t i = 0; i < 6; i++) {
+ tu_fifo_read(ff, &ch);
+ }
// write 2 items
tu_fifo_write(ff, &ch);
@@ -258,15 +262,14 @@ void test_get_read_info_when_wrapped()
tu_fifo_get_read_info(ff, &info);
- TEST_ASSERT_EQUAL(FIFO_SIZE-6, info.len_lin);
- TEST_ASSERT_EQUAL(2, info.len_wrap);
+ TEST_ASSERT_EQUAL(FIFO_SIZE - 6, info.linear.len);
+ TEST_ASSERT_EQUAL(2, info.wrapped.len);
- TEST_ASSERT_EQUAL_PTR(ff->buffer+6, info.ptr_lin);
- TEST_ASSERT_EQUAL_PTR(ff->buffer, info.ptr_wrap);
+ TEST_ASSERT_EQUAL_PTR(ff->buffer + 6, info.linear.ptr);
+ TEST_ASSERT_EQUAL_PTR(ff->buffer, info.wrapped.ptr);
}
-void test_get_write_info_when_no_wrap()
-{
+void test_get_write_info_when_no_wrap() {
uint8_t ch = 1;
// write 2 items
@@ -275,20 +278,21 @@ void test_get_write_info_when_no_wrap()
tu_fifo_get_write_info(ff, &info);
- TEST_ASSERT_EQUAL(FIFO_SIZE-2, info.len_lin);
- TEST_ASSERT_EQUAL(0, info.len_wrap);
+ TEST_ASSERT_EQUAL(FIFO_SIZE - 2, info.linear.len);
+ TEST_ASSERT_EQUAL(0, info.wrapped.len);
- TEST_ASSERT_EQUAL_PTR(ff->buffer+2, info .ptr_lin);
+ TEST_ASSERT_EQUAL_PTR(ff->buffer + 2, info.linear.ptr);
// application should check len instead of ptr.
- // TEST_ASSERT_NULL(info.ptr_wrap);
+ // TEST_ASSERT_NULL(info.wrapped.ptr);
}
-void test_get_write_info_when_wrapped()
-{
+void test_get_write_info_when_wrapped() {
uint8_t ch = 1;
// write 6 items
- for(uint8_t i=0; i < 6; i++) tu_fifo_write(ff, &ch);
+ for (uint8_t i = 0; i < 6; i++) {
+ tu_fifo_write(ff, &ch);
+ }
// read 2 items
tu_fifo_read(ff, &ch);
@@ -296,68 +300,67 @@ void test_get_write_info_when_wrapped()
tu_fifo_get_write_info(ff, &info);
- TEST_ASSERT_EQUAL(FIFO_SIZE-6, info.len_lin);
- TEST_ASSERT_EQUAL(2, info.len_wrap);
+ TEST_ASSERT_EQUAL(FIFO_SIZE - 6, info.linear.len);
+ TEST_ASSERT_EQUAL(2, info.wrapped.len);
- TEST_ASSERT_EQUAL_PTR(ff->buffer+6, info .ptr_lin);
- TEST_ASSERT_EQUAL_PTR(ff->buffer, info.ptr_wrap);
+ TEST_ASSERT_EQUAL_PTR(ff->buffer + 6, info.linear.ptr);
+ TEST_ASSERT_EQUAL_PTR(ff->buffer, info.wrapped.ptr);
}
-void test_empty(void)
-{
+void test_empty(void) {
uint8_t temp;
TEST_ASSERT_TRUE(tu_fifo_empty(ff));
// read info
tu_fifo_get_read_info(ff, &info);
- TEST_ASSERT_EQUAL(0, info.len_lin);
- TEST_ASSERT_EQUAL(0, info.len_wrap);
+ TEST_ASSERT_EQUAL(0, info.linear.len);
+ TEST_ASSERT_EQUAL(0, info.wrapped.len);
- TEST_ASSERT_NULL(info.ptr_lin);
- TEST_ASSERT_NULL(info.ptr_wrap);
+ TEST_ASSERT_NULL(info.linear.ptr);
+ TEST_ASSERT_NULL(info.wrapped.ptr);
// write info
tu_fifo_get_write_info(ff, &info);
- TEST_ASSERT_EQUAL(FIFO_SIZE, info.len_lin);
- TEST_ASSERT_EQUAL(0, info.len_wrap);
+ TEST_ASSERT_EQUAL(FIFO_SIZE, info.linear.len);
+ TEST_ASSERT_EQUAL(0, info.wrapped.len);
- TEST_ASSERT_EQUAL_PTR(ff->buffer, info .ptr_lin);
+ TEST_ASSERT_EQUAL_PTR(ff->buffer, info.linear.ptr);
// application should check len instead of ptr.
- // TEST_ASSERT_NULL(info.ptr_wrap);
+ // TEST_ASSERT_NULL(info.wrapped.ptr);
// write 1 then re-check empty
tu_fifo_write(ff, &temp);
TEST_ASSERT_FALSE(tu_fifo_empty(ff));
}
-void test_full(void)
-{
+void test_full(void) {
TEST_ASSERT_FALSE(tu_fifo_full(ff));
- for(uint8_t i=0; i < FIFO_SIZE; i++) tu_fifo_write(ff, &i);
+ for (uint8_t i = 0; i < FIFO_SIZE; i++) {
+ tu_fifo_write(ff, &i);
+ }
TEST_ASSERT_TRUE(tu_fifo_full(ff));
// read info
tu_fifo_get_read_info(ff, &info);
- TEST_ASSERT_EQUAL(FIFO_SIZE, info.len_lin);
- TEST_ASSERT_EQUAL(0, info.len_wrap);
+ TEST_ASSERT_EQUAL(FIFO_SIZE, info.linear.len);
+ TEST_ASSERT_EQUAL(0, info.wrapped.len);
- TEST_ASSERT_EQUAL_PTR(ff->buffer, info.ptr_lin);
+ TEST_ASSERT_EQUAL_PTR(ff->buffer, info.linear.ptr);
// skip this, application must check len instead of buffer
- // TEST_ASSERT_NULL(info.ptr_wrap);
+ // TEST_ASSERT_NULL(info.wrapped.ptr);
// write info
}
-void test_rd_idx_wrap()
-{
+void test_rd_idx_wrap(void) {
tu_fifo_t ff10;
- uint8_t buf[10];
- uint8_t dst[10];
+ uint8_t buf[10];
+ uint8_t dst[10];
tu_fifo_config(&ff10, buf, 10, 1, 1);
@@ -376,3 +379,187 @@ void test_rd_idx_wrap()
TEST_ASSERT_EQUAL(n, 2);
TEST_ASSERT_EQUAL(ff10.rd_idx, 6);
}
+
+void test_advance_write_pointer_cases(void) {
+ tu_fifo_clear(ff);
+
+ tu_fifo_advance_write_pointer(ff, 3);
+ TEST_ASSERT_EQUAL(3, ff->wr_idx);
+ TEST_ASSERT_EQUAL(3, tu_fifo_count(ff));
+
+ // advance to cross depth but stay within 0..2*depth window
+ ff->wr_idx = FIFO_SIZE - 2; // 62
+ ff->rd_idx = 0;
+ tu_fifo_advance_write_pointer(ff, 10); // 62 + 10 = 72 within window
+ TEST_ASSERT_EQUAL(72, ff->wr_idx);
+ TEST_ASSERT_EQUAL(FIFO_SIZE, tu_fifo_count(ff));
+
+ // advance past the unused index space (beyond 2*depth)
+ ff->wr_idx = (uint16_t)(2 * FIFO_SIZE - 3); // 125
+ ff->rd_idx = 0;
+ tu_fifo_advance_write_pointer(ff, 6); // forces wrap across unused space
+ TEST_ASSERT_EQUAL(3, ff->wr_idx);
+ TEST_ASSERT_EQUAL(3, tu_fifo_count(ff));
+}
+
+void test_advance_read_pointer_cases(void) {
+ tu_fifo_clear(ff);
+
+ ff->wr_idx = 6;
+ tu_fifo_advance_read_pointer(ff, 3);
+ TEST_ASSERT_EQUAL(3, ff->rd_idx);
+ TEST_ASSERT_EQUAL(3, tu_fifo_count(ff));
+
+ ff->wr_idx = FIFO_SIZE + 10; // 74
+ ff->rd_idx = FIFO_SIZE - 10; // 54
+ tu_fifo_advance_read_pointer(ff, 20); // move to match write index within window
+ TEST_ASSERT_EQUAL(74, ff->rd_idx);
+ TEST_ASSERT_EQUAL(0, tu_fifo_count(ff));
+
+ ff->wr_idx = 9;
+ ff->rd_idx = (uint16_t)(2 * FIFO_SIZE - 1); // 127
+ tu_fifo_advance_read_pointer(ff, 6); // crosses unused index space
+ TEST_ASSERT_EQUAL(5, ff->rd_idx);
+ TEST_ASSERT_EQUAL(4, tu_fifo_count(ff));
+}
+
+void test_write_n_fixed_addr_rw32_nowrap(void) {
+ tu_fifo_clear(ff);
+
+ volatile uint32_t reg = 0x11223344;
+ uint8_t expected[8] = {0x44, 0x33, 0x22, 0x11, 0x44, 0x33, 0x22, 0x11};
+
+ for (uint8_t n = 1; n <= 8; n++) {
+ tu_fifo_clear(ff);
+ uint16_t written = tu_fifo_write_n_access_mode(ff, (const void *)&reg, n, TU_FIFO_FIXED_ADDR_RW32);
+ TEST_ASSERT_EQUAL(n, written);
+ TEST_ASSERT_EQUAL(n, tu_fifo_count(ff));
+
+ uint8_t out[8] = {0};
+ tu_fifo_read_n(ff, out, n);
+ TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, out, n);
+ }
+}
+
+void test_write_n_fixed_addr_rw32_wrapped(void) {
+ tu_fifo_clear(ff);
+
+ volatile uint32_t reg = 0xA1B2C3D4;
+ uint8_t expected[8] = {0xD4, 0xC3, 0xB2, 0xA1, 0xD4, 0xC3, 0xB2, 0xA1};
+
+ for (uint8_t n = 1; n <= 8; n++) {
+ tu_fifo_clear(ff);
+ // Position the fifo near the end so writes wrap
+ ff->wr_idx = FIFO_SIZE - 3;
+ ff->rd_idx = FIFO_SIZE - 3;
+
+ uint16_t written = tu_fifo_write_n_access_mode(ff, (const void *)&reg, n, TU_FIFO_FIXED_ADDR_RW32);
+ TEST_ASSERT_EQUAL(n, written);
+ TEST_ASSERT_EQUAL(n, tu_fifo_count(ff));
+
+ uint8_t out[8] = {0};
+ tu_fifo_read_n(ff, out, n);
+ TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, out, n);
+ }
+}
+
+void test_read_n_fixed_addr_rw32_nowrap(void) {
+ uint8_t pattern[8] = {0x10, 0x21, 0x32, 0x43, 0x54, 0x65, 0x76, 0x87};
+ uint32_t reg_expected[8] = {
+ 0x00000010, 0x00002110, 0x00322110, 0x43322110, 0x00000054, 0x00006554, 0x00766554, 0x87766554};
+
+ for (uint8_t n = 1; n <= 8; n++) {
+ tu_fifo_clear(ff);
+ tu_fifo_write_n(ff, pattern, 8);
+
+ uint32_t reg = 0;
+ uint16_t read_cnt = tu_fifo_read_n_access_mode(ff, &reg, n, TU_FIFO_FIXED_ADDR_RW32);
+ TEST_ASSERT_EQUAL(n, read_cnt);
+ TEST_ASSERT_EQUAL(8 - n, tu_fifo_count(ff));
+
+ TEST_ASSERT_EQUAL_HEX32(reg_expected[n - 1], reg);
+ }
+}
+
+void test_read_n_fixed_addr_rw32_wrapped(void) {
+ uint8_t pattern[8] = {0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87};
+ uint32_t reg_expected[8] = {
+ 0x000000F0, 0x0000E1F0, 0x00D2E1F0, 0xC3D2E1F0, 0x000000B4, 0x0000A5B4, 0x0096A5B4, 0x8796A5B4};
+
+ for (uint8_t n = 1; n <= 8; n++) {
+ tu_fifo_clear(ff);
+ ff->rd_idx = FIFO_SIZE - 2;
+ ff->wr_idx = (uint16_t)(ff->rd_idx + n);
+
+ for (uint8_t i = 0; i < n; i++) {
+ uint8_t idx = (uint8_t)((ff->rd_idx + i) % FIFO_SIZE);
+ ff->buffer[idx] = pattern[i];
+ }
+
+ uint32_t reg = 0;
+ uint16_t read_cnt = tu_fifo_read_n_access_mode(ff, &reg, n, TU_FIFO_FIXED_ADDR_RW32);
+ TEST_ASSERT_EQUAL(n, read_cnt);
+ TEST_ASSERT_EQUAL(0, tu_fifo_count(ff));
+
+ TEST_ASSERT_EQUAL_HEX32(reg_expected[n - 1], reg);
+ }
+}
+
+void test_get_read_info_advanced_cases(void) {
+ tu_fifo_clear(ff);
+
+ ff->wr_idx = 20;
+ ff->rd_idx = 2;
+ tu_fifo_get_read_info(ff, &info);
+ TEST_ASSERT_EQUAL(18, info.linear.len);
+ TEST_ASSERT_EQUAL(0, info.wrapped.len);
+ TEST_ASSERT_EQUAL_PTR(ff->buffer + 2, info.linear.ptr);
+ TEST_ASSERT_NULL(info.wrapped.ptr);
+
+ ff->wr_idx = 68; // ptr = 4
+ ff->rd_idx = 56; // ptr = 56
+ tu_fifo_get_read_info(ff, &info);
+ TEST_ASSERT_EQUAL(8, info.linear.len);
+ TEST_ASSERT_EQUAL(4, info.wrapped.len);
+ TEST_ASSERT_EQUAL_PTR(ff->buffer + 56, info.linear.ptr);
+ TEST_ASSERT_EQUAL_PTR(ff->buffer, info.wrapped.ptr);
+}
+
+void test_get_write_info_advanced_cases(void) {
+ tu_fifo_clear(ff);
+
+ ff->wr_idx = 10;
+ ff->rd_idx = 104; // ptr = 40
+ tu_fifo_get_write_info(ff, &info);
+ TEST_ASSERT_EQUAL(30, info.linear.len);
+ TEST_ASSERT_EQUAL(0, info.wrapped.len);
+ TEST_ASSERT_EQUAL_PTR(ff->buffer + 10, info.linear.ptr);
+ TEST_ASSERT_NULL(info.wrapped.ptr);
+
+ ff->wr_idx = 60;
+ ff->rd_idx = 20;
+ tu_fifo_get_write_info(ff, &info);
+ TEST_ASSERT_EQUAL(4, info.linear.len);
+ TEST_ASSERT_EQUAL(20, info.wrapped.len);
+ TEST_ASSERT_EQUAL_PTR(ff->buffer + 60, info.linear.ptr);
+ TEST_ASSERT_EQUAL_PTR(ff->buffer, info.wrapped.ptr);
+}
+
+void test_correct_read_pointer_cases(void) {
+ tu_fifo_clear(ff);
+
+ // wr beyond depth: rd should be wr - depth
+ ff->wr_idx = FIFO_SIZE + 6; // 70
+ tu_fifo_correct_read_pointer(ff);
+ TEST_ASSERT_EQUAL(6, ff->rd_idx);
+
+ // wr exactly at depth: rd should wrap to zero
+ ff->wr_idx = FIFO_SIZE;
+ tu_fifo_correct_read_pointer(ff);
+ TEST_ASSERT_EQUAL(0, ff->rd_idx);
+
+ // wr below depth: rd should be wr + depth
+ ff->wr_idx = 10;
+ tu_fifo_correct_read_pointer(ff);
+ TEST_ASSERT_EQUAL(FIFO_SIZE + 10, ff->rd_idx);
+}