1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-12-18 11:03:50 +01:00

sys/isrpipe: add unit tests

This patch adds unit tests for the isrpipe module.
This commit is contained in:
Joshua DeWeese 2025-04-01 12:42:56 -04:00 committed by Joshua DeWeese
parent 9774a0ce48
commit a749e3493d
5 changed files with 391 additions and 0 deletions

View File

@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,2 @@
USEMODULE += isrpipe
USEMODULE += isrpipe_read_timeout

View File

@ -0,0 +1,95 @@
/*
* Copyright (c) 2025 Prime Controls, Inc.(R)
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
#include <errno.h>
#include <string.h>
#include "embUnit/embUnit.h"
#include "isrpipe/read_timeout.h"
#include "tests-isrpipe.h"
static void test_read_timeout(void)
{
uint8_t buffer[2] = {0};
uint8_t read_buf[2];
isrpipe_t pipe;
int res;
/* prep the pipe */
isrpipe_init(&pipe, buffer, ARRAY_SIZE(buffer));
/* test timeout */
res = isrpipe_read_timeout(&pipe, read_buf, ARRAY_SIZE(read_buf), 1);
TEST_ASSERT_EQUAL_INT(-ETIMEDOUT, res);
TEST_ASSERT_EQUAL_INT(0, isrpipe_write_one(&pipe, 1));
TEST_ASSERT_EQUAL_INT(0, isrpipe_write_one(&pipe, 2));
/* pipe now holds 1, 2 */
/* test successful read */
res = isrpipe_read_timeout(&pipe, read_buf, ARRAY_SIZE(read_buf), 1);
TEST_ASSERT_EQUAL_INT(ARRAY_SIZE(read_buf), res);
/* pipe now empty */
TEST_ASSERT_EQUAL_INT(0, isrpipe_write_one(&pipe, 3));
/* pipe now holds 3 */
/* test partial read */
res = isrpipe_read_timeout(&pipe, read_buf, ARRAY_SIZE(read_buf), 1);
TEST_ASSERT_EQUAL_INT(1, res);
}
static void test_read_all_timeout(void)
{
uint8_t buffer[2] = {0};
uint8_t read_buf[2];
isrpipe_t pipe;
int res;
/* prep the pipe */
isrpipe_init(&pipe, buffer, ARRAY_SIZE(buffer));
/* test timeout */
res = isrpipe_read_all_timeout(&pipe, read_buf, ARRAY_SIZE(read_buf), 1);
TEST_ASSERT_EQUAL_INT(-ETIMEDOUT, res);
TEST_ASSERT_EQUAL_INT(0, isrpipe_write_one(&pipe, 1));
TEST_ASSERT_EQUAL_INT(0, isrpipe_write_one(&pipe, 2));
/* pipe now holds 1, 2 */
/* test successful read */
res = isrpipe_read_all_timeout(&pipe, read_buf, ARRAY_SIZE(read_buf), 1);
TEST_ASSERT_EQUAL_INT(ARRAY_SIZE(read_buf), res);
/* pipe now empty */
TEST_ASSERT_EQUAL_INT(0, isrpipe_write_one(&pipe, 3));
/* pipe now holds 3 */
/* test timeout - isrpipe_read_all_timeout() does not allow partial reads */
res = isrpipe_read_all_timeout(&pipe, read_buf, ARRAY_SIZE(read_buf), 1);
TEST_ASSERT_EQUAL_INT(-ETIMEDOUT, res);
}
Test *tests_isrpipe_read_timeout_tests(void)
{
EMB_UNIT_TESTFIXTURES(fixtures) {
new_TestFixture(test_read_timeout),
new_TestFixture(test_read_all_timeout),
};
EMB_UNIT_TESTCALLER(isrpipe_tests, NULL, NULL, fixtures);
return (Test *)&isrpipe_tests;
}

View File

@ -0,0 +1,243 @@
/*
* Copyright (c) 2025 Prime Controls, Inc.(R)
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
#include <string.h>
#include "embUnit/embUnit.h"
#include "isrpipe.h"
#include "tests-isrpipe.h"
#include "ztimer.h"
/* ISR pipe to test */
static uint8_t _buffer[8];
static isrpipe_t _pipe;
/* reader thread's stack */
static char _reader_stack[THREAD_STACKSIZE_TINY];
/* entry point of reader thread */
static void* _reader_thread(void *arg)
{
uint8_t *read_buf = arg;
/* get the size of the read_buffer */
unsigned read_buf_size = read_buf[0];
/* keep reading until read_buf is full */
while (read_buf_size) {
const int res = isrpipe_read(&_pipe, read_buf, read_buf_size);
read_buf += res;
read_buf_size -= res;
}
thread_zombify();
return NULL;
}
static void setup_up(void)
{
/* clear buffer contents from previous tests */
memset(_buffer, 0, sizeof(_buffer));
/* prep the pipe */
isrpipe_init(&_pipe, _buffer, ARRAY_SIZE(_buffer));
}
static void test_init(void)
{
/* statically initialized isrpipe */
static const isrpipe_t pipe = ISRPIPE_INIT(_buffer);
/* check that static and runtime init produces the same result */
TEST_ASSERT_EQUAL_INT(0, memcmp(&_pipe, &pipe, sizeof(isrpipe_t)));
}
static void test_write_then_read(void)
{
const uint8_t write_buf[] = {1, 2, 3, 4, 5, 6};
uint8_t read_buf[2];
int res;
res = isrpipe_write(&_pipe, write_buf, ARRAY_SIZE(write_buf));
TEST_ASSERT_EQUAL_INT(ARRAY_SIZE(write_buf), res);
/* pipe now holds 1, 2, 3, 4, 5, 6 */
res = isrpipe_read(&_pipe, read_buf, 1);
TEST_ASSERT_EQUAL_INT(1, res);
TEST_ASSERT_EQUAL_INT(1, read_buf[0]);
/* pipe now holds 2, 3, 4, 5, 6 */
res = isrpipe_read(&_pipe, read_buf, 2);
TEST_ASSERT_EQUAL_INT(2, res);
TEST_ASSERT_EQUAL_INT(2, read_buf[0]);
TEST_ASSERT_EQUAL_INT(3, read_buf[1]);
/* pipe now holds 4, 5, 6 */
res = isrpipe_read(&_pipe, read_buf, 1);
TEST_ASSERT_EQUAL_INT(1, res);
TEST_ASSERT_EQUAL_INT(4, read_buf[0]);
/* pipe now holds 5, 6 */
res = isrpipe_read(&_pipe, read_buf, 2);
TEST_ASSERT_EQUAL_INT(2, res);
TEST_ASSERT_EQUAL_INT(5, read_buf[0]);
TEST_ASSERT_EQUAL_INT(6, read_buf[1]);
/* pipe now empty */
}
static void test_read_then_write(void)
{
uint8_t read_buf[3] = {0}; /* init contents to all zeros */
thread_t *writer_thread = thread_get_active();
const unsigned writer_priority = thread_get_priority(writer_thread);
const unsigned reader_priority = 0;
/* check assumptions */
TEST_ASSERT(writer_priority > reader_priority);
/* sneaky way to tell reader thread the size of the read_buf */
read_buf[0] = ARRAY_SIZE(read_buf);
/* create reader thread with priority higher than writer thread so that write
can only happen once reading blocks on the empty pipe */
const int reader_pid = thread_create(_reader_stack, sizeof(_reader_stack),
reader_priority, 0, _reader_thread, read_buf, "reader");
/* check assumptions */
TEST_ASSERT(reader_pid >= 0);
/* reader thread should have preempted us, but is now blocked by reading
from the empty pipe, which yielded the CPU back to us */
/* write to the pipe a byte at a time to demonstrate that the reader is
unblocking with each byte and placing the bytes into read_buf */
for (unsigned i = 0; i < ARRAY_SIZE(read_buf); i++) {
/* test that read_buf[i] is not equal to the value we are about to send
through the pipe */
TEST_ASSERT(i != read_buf[i]);
/* write a byte, reader thread will then unblock and write it into
read_buf[i] */
TEST_ASSERT_EQUAL_INT(0, isrpipe_write_one(&_pipe, i));
/* check that reader got the byte from the pipe and put it into
read_buf[i]*/
TEST_ASSERT_EQUAL_INT(i, read_buf[i]);
}
/* cleanup */
TEST_ASSERT_EQUAL_INT(1, thread_kill_zombie(reader_pid));
}
static void test_overflow(void)
{
int res;
/* completely fill the pipe */
for (unsigned i = 0; i < ARRAY_SIZE(_buffer); i++) {
TEST_ASSERT_EQUAL_INT(0, isrpipe_write_one(&_pipe, i));
}
/* pipe is now full */
/* isrpipe_write_one() should return -1 for error */
TEST_ASSERT_EQUAL_INT(-1, isrpipe_write_one(&_pipe, -1));
/* isrpipe_write() should return 0 bytes written */
const uint8_t write_buf[] = {1, 2, 3};
res = isrpipe_write(&_pipe, write_buf, ARRAY_SIZE(write_buf));
TEST_ASSERT_EQUAL_INT(0, res);
}
static void test_underflow(void)
{
const uint8_t write_buf[] = {1, 2, 3};
uint8_t read_buf[ARRAY_SIZE(write_buf) + 1];
int res;
res = isrpipe_write(&_pipe, write_buf, ARRAY_SIZE(write_buf));
TEST_ASSERT_EQUAL_INT(ARRAY_SIZE(write_buf), res);
/* pipe now holds 1, 2, 3 */
/* try to read more data than is in pipe */
res = isrpipe_read(&_pipe, read_buf, ARRAY_SIZE(read_buf));
TEST_ASSERT_EQUAL_INT(ARRAY_SIZE(write_buf), res);
}
static void test_write_one(void)
{
uint8_t read_buf[3];
int res;
TEST_ASSERT_EQUAL_INT(0, isrpipe_write_one(&_pipe, 1));
TEST_ASSERT_EQUAL_INT(0, isrpipe_write_one(&_pipe, 2));
TEST_ASSERT_EQUAL_INT(0, isrpipe_write_one(&_pipe, 3));
/* pipe now holds 1, 2, 3 */
TEST_ASSERT_EQUAL_INT(1, isrpipe_read(&_pipe, read_buf, 1));
TEST_ASSERT_EQUAL_INT(1, read_buf[0]);
/* pipe now holds 2, 3 */
TEST_ASSERT_EQUAL_INT(1, isrpipe_read(&_pipe, read_buf, 1));
TEST_ASSERT_EQUAL_INT(2, read_buf[0]);
/* pipe now holds 3 */
TEST_ASSERT_EQUAL_INT(1, isrpipe_read(&_pipe, read_buf, 1));
TEST_ASSERT_EQUAL_INT(3, read_buf[0]);
/* pipe now empty */
TEST_ASSERT_EQUAL_INT(0, isrpipe_write_one(&_pipe, 4));
TEST_ASSERT_EQUAL_INT(0, isrpipe_write_one(&_pipe, 5));
TEST_ASSERT_EQUAL_INT(0, isrpipe_write_one(&_pipe, 6));
/* pipe now holds 4, 5, 6 */
res = isrpipe_read(&_pipe, read_buf, ARRAY_SIZE(read_buf));
TEST_ASSERT_EQUAL_INT(ARRAY_SIZE(read_buf), res);
TEST_ASSERT_EQUAL_INT(4, read_buf[0]);
TEST_ASSERT_EQUAL_INT(5, read_buf[1]);
TEST_ASSERT_EQUAL_INT(6, read_buf[2]);
/* pipe now empty */
}
Test *tests_isrpipe_tests(void)
{
EMB_UNIT_TESTFIXTURES(fixtures) {
new_TestFixture(test_init),
new_TestFixture(test_write_then_read),
new_TestFixture(test_read_then_write),
new_TestFixture(test_overflow),
new_TestFixture(test_underflow),
new_TestFixture(test_write_one),
};
EMB_UNIT_TESTCALLER(isrpipe_tests, setup_up, NULL, fixtures);
return (Test *)&isrpipe_tests;
}
void tests_isrpipe(void)
{
TESTS_RUN(tests_isrpipe_tests());
TESTS_RUN(tests_isrpipe_read_timeout_tests());
}

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2025 Prime Controls, Inc.(R)
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
#pragma once
/**
* @addtogroup unittests
* @{
*
* @file
* @brief Unittests for ISR pipe
*
* @author Joshua DeWeese <jdeweese@primecontrols.com>
*/
#include "embUnit.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Entry point of the test suite
*/
void tests_isrpipe(void);
/**
* @brief Generates tests for isrpipe.h
*
* @return embUnit tests if successful, NULL if not.
*/
Test *tests_isrpipe_tests(void);
/**
* @brief Generates tests for isrpipe/read_timeout.h
*
* @return embUnit tests if successful, NULL if not.
*/
Test *tests_isrpipe_read_timeout_tests(void);
#ifdef __cplusplus
}
#endif
/** @} */