Issue 187 enable skipped ztest suites (#189)
* Fix some ztests that were skipped * Expose bacapp_same_value() * Fix bacapp, ptransfer tests * Fix bugs in Load_Control object & tests * refactor days functions from datetime module * fix legacy ctests * Add bacnet/basic/sys/days.[ch] to Zephyr build * Update ztest to match from Zephyr v2.6.0; update ringbuf, datetime to build * Fixup ztest test for object/acc * Fix bvlc_address_from_ascii; enable/fix bvlc test * Comment cleanup * test/bacnet/basic/object/lc partially enabled * Fix bacapp_decode_data_len return status on erroneous input * fix ztest include fatal error * fix ztest strsignal reference fatal error * fix zassert_mem_equal reference syntax error * fix zassert_mem_equal reference syntax error Co-authored-by: Gregory Shue <gregory.shue@legrand.us> Co-authored-by: Steve Karg <skarg@users.sourceforge.net>
This commit is contained in:
+322
-34
@@ -2,26 +2,26 @@
|
||||
* Copyright (c) 2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Modified from zephyr_v2.2.0 subsys/testsuite/ztest/src/ztest.c
|
||||
* because:
|
||||
* 1. This port will never be run in the Zephyr kernel.
|
||||
* This repository is extended to be a Zephyr module for that.
|
||||
* 2. This port will not support multiple CPUs or toolchains.
|
||||
*
|
||||
* Modifications:
|
||||
* a. Deleted code conditionally compiled on the following CPP symbols:
|
||||
* (as they were kernel-specific):
|
||||
* CONFIG_USERSPACE
|
||||
* KERNEL
|
||||
* b. Removed irrelevant inclusion of the following header files:
|
||||
* <app_memory/app_memdomain.h>
|
||||
* <power/reboot.h>
|
||||
* c. Addition of test_skip functionality missing from non-kernel paths.
|
||||
*/
|
||||
|
||||
#include <ztest.h>
|
||||
#include <stdio.h>
|
||||
#include <tc_util.h>
|
||||
#if 0
|
||||
#include <app_memory/app_memdomain.h>
|
||||
#ifdef CONFIG_USERSPACE
|
||||
#include <sys/libc-hooks.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef KERNEL
|
||||
#include <sys/reboot.h>
|
||||
static struct k_thread ztest_thread;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARCH_POSIX
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
/* ZTEST_DMEM and ZTEST_BMEM are used for the application shared memory test */
|
||||
|
||||
@@ -34,6 +34,31 @@ ZTEST_DMEM enum {
|
||||
|
||||
static ZTEST_BMEM int test_status;
|
||||
|
||||
/**
|
||||
* @brief Try to shorten a filename by removing the current directory
|
||||
*
|
||||
* This helps to reduce the very long filenames in assertion failures. It
|
||||
* removes the current directory from the filename and returns the rest.
|
||||
* This makes assertions a lot more readable, and sometimes they fit on one
|
||||
* line.
|
||||
*
|
||||
* @param file Filename to check
|
||||
* @returns Shortened filename, or @file if it could not be shortened
|
||||
*/
|
||||
const char *ztest_relative_filename(const char *file)
|
||||
{
|
||||
#ifdef CONFIG_ARCH_POSIX
|
||||
const char *cwd;
|
||||
char buf[200];
|
||||
|
||||
cwd = getcwd(buf, sizeof(buf));
|
||||
if (cwd && strlen(file) > strlen(cwd) &&
|
||||
!strncmp(file, cwd, strlen(cwd)))
|
||||
return file + strlen(cwd) + 1; /* move past the trailing '/' */
|
||||
#endif
|
||||
return file;
|
||||
}
|
||||
|
||||
static int cleanup_test(struct unit_test *test)
|
||||
{
|
||||
int ret = TC_PASS;
|
||||
@@ -41,6 +66,16 @@ static int cleanup_test(struct unit_test *test)
|
||||
|
||||
mock_status = z_cleanup_mock();
|
||||
|
||||
#ifdef KERNEL
|
||||
/* we need to remove the ztest_thread information from the timeout_q.
|
||||
* Because we reuse the same k_thread structure this would
|
||||
* causes some problems.
|
||||
*/
|
||||
if (IS_ENABLED(CONFIG_MULTITHREADING)) {
|
||||
k_thread_abort(&ztest_thread);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!ret && mock_status == 1) {
|
||||
PRINT("Test %s failed: Unused mock parameter values\n",
|
||||
test->name);
|
||||
@@ -49,11 +84,123 @@ static int cleanup_test(struct unit_test *test)
|
||||
PRINT("Test %s failed: Unused mock return values\n",
|
||||
test->name);
|
||||
ret = TC_FAIL;
|
||||
} else {
|
||||
;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef KERNEL
|
||||
#ifdef CONFIG_SMP
|
||||
#define NUM_CPUHOLD (CONFIG_MP_NUM_CPUS - 1)
|
||||
#else
|
||||
#define NUM_CPUHOLD 0
|
||||
#endif
|
||||
#define CPUHOLD_STACK_SZ (512 + CONFIG_TEST_EXTRA_STACKSIZE)
|
||||
|
||||
static struct k_thread cpuhold_threads[NUM_CPUHOLD];
|
||||
K_KERNEL_STACK_ARRAY_DEFINE(cpuhold_stacks, NUM_CPUHOLD, CPUHOLD_STACK_SZ);
|
||||
static struct k_sem cpuhold_sem;
|
||||
volatile int cpuhold_active;
|
||||
|
||||
/* "Holds" a CPU for use with the "1cpu" test cases. Note that we
|
||||
* can't use tools like the cpumask feature because we have tests that
|
||||
* may need to control that configuration themselves. We do this at
|
||||
* the lowest level, but locking interrupts directly and spinning.
|
||||
*/
|
||||
static void cpu_hold(void *arg1, void *arg2, void *arg3)
|
||||
{
|
||||
ARG_UNUSED(arg1);
|
||||
ARG_UNUSED(arg2);
|
||||
ARG_UNUSED(arg3);
|
||||
unsigned int key = arch_irq_lock();
|
||||
uint32_t dt, start_ms = k_uptime_get_32();
|
||||
|
||||
k_sem_give(&cpuhold_sem);
|
||||
|
||||
#if defined(CONFIG_ARM64) && defined(CONFIG_FPU_SHARING)
|
||||
/*
|
||||
* We'll be spinning with IRQs disabled. The flush-your-FPU request
|
||||
* IPI will never be serviced during that time. Therefore we flush
|
||||
* the FPU preemptively here to prevent any other CPU waiting after
|
||||
* this CPU forever and deadlock the system.
|
||||
*/
|
||||
extern void z_arm64_flush_local_fpu(void);
|
||||
z_arm64_flush_local_fpu();
|
||||
#endif
|
||||
|
||||
while (cpuhold_active) {
|
||||
k_busy_wait(1000);
|
||||
}
|
||||
|
||||
/* Holding the CPU via spinning is expensive, and abusing this
|
||||
* for long-running test cases tends to overload the CI system
|
||||
* (qemu runs separate CPUs in different threads, but the CI
|
||||
* logic views it as one "job") and cause other test failures.
|
||||
*/
|
||||
dt = k_uptime_get_32() - start_ms;
|
||||
zassert_true(dt < 3000,
|
||||
"1cpu test took too long (%d ms)", dt);
|
||||
arch_irq_unlock(key);
|
||||
}
|
||||
|
||||
void z_impl_z_test_1cpu_start(void)
|
||||
{
|
||||
cpuhold_active = 1;
|
||||
#ifdef CONFIG_THREAD_NAME
|
||||
char tname[CONFIG_THREAD_MAX_NAME_LEN];
|
||||
#endif
|
||||
k_sem_init(&cpuhold_sem, 0, 999);
|
||||
|
||||
/* Spawn N-1 threads to "hold" the other CPUs, waiting for
|
||||
* each to signal us that it's locked and spinning.
|
||||
*
|
||||
* Note that NUM_CPUHOLD can be a value that causes coverity
|
||||
* to flag the following loop as DEADCODE so suppress the warning.
|
||||
*/
|
||||
/* coverity[DEADCODE] */
|
||||
for (int i = 0; i < NUM_CPUHOLD; i++) {
|
||||
k_thread_create(&cpuhold_threads[i],
|
||||
cpuhold_stacks[i], CPUHOLD_STACK_SZ,
|
||||
(k_thread_entry_t) cpu_hold, NULL, NULL, NULL,
|
||||
K_HIGHEST_THREAD_PRIO, 0, K_NO_WAIT);
|
||||
#ifdef CONFIG_THREAD_NAME
|
||||
snprintk(tname, CONFIG_THREAD_MAX_NAME_LEN, "cpuhold%02d", i);
|
||||
k_thread_name_set(&cpuhold_threads[i], tname);
|
||||
#endif
|
||||
k_sem_take(&cpuhold_sem, K_FOREVER);
|
||||
}
|
||||
}
|
||||
|
||||
void z_impl_z_test_1cpu_stop(void)
|
||||
{
|
||||
cpuhold_active = 0;
|
||||
|
||||
/* Note that NUM_CPUHOLD can be a value that causes coverity
|
||||
* to flag the following loop as DEADCODE so suppress the warning.
|
||||
*/
|
||||
/* coverity[DEADCODE] */
|
||||
for (int i = 0; i < NUM_CPUHOLD; i++) {
|
||||
k_thread_abort(&cpuhold_threads[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USERSPACE
|
||||
void z_vrfy_z_test_1cpu_start(void)
|
||||
{
|
||||
z_impl_z_test_1cpu_start();
|
||||
}
|
||||
#include <syscalls/z_test_1cpu_start_mrsh.c>
|
||||
|
||||
void z_vrfy_z_test_1cpu_stop(void)
|
||||
{
|
||||
z_impl_z_test_1cpu_stop();
|
||||
}
|
||||
#include <syscalls/z_test_1cpu_stop_mrsh.c>
|
||||
#endif /* CONFIG_USERSPACE */
|
||||
#endif
|
||||
|
||||
static void run_test_functions(struct unit_test *test)
|
||||
{
|
||||
phase = TEST_PHASE_SETUP;
|
||||
@@ -62,6 +209,7 @@ static void run_test_functions(struct unit_test *test)
|
||||
test->test();
|
||||
}
|
||||
|
||||
#ifndef KERNEL
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
@@ -71,7 +219,6 @@ static void run_test_functions(struct unit_test *test)
|
||||
|
||||
static jmp_buf test_fail;
|
||||
static jmp_buf test_pass;
|
||||
static jmp_buf test_skip;
|
||||
static jmp_buf stack_fail;
|
||||
|
||||
void ztest_test_fail(void)
|
||||
@@ -84,11 +231,6 @@ void ztest_test_pass(void)
|
||||
longjmp(test_pass, 1);
|
||||
}
|
||||
|
||||
void ztest_test_skip(void)
|
||||
{
|
||||
longjmp(test_skip, 1);
|
||||
}
|
||||
|
||||
static void handle_signal(int sig)
|
||||
{
|
||||
static const char *const phase_str[] = {
|
||||
@@ -141,11 +283,6 @@ static int run_test(struct unit_test *test)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (setjmp(test_skip)) {
|
||||
ret = TC_SKIP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
run_test_functions(test);
|
||||
out:
|
||||
ret |= cleanup_test(test);
|
||||
@@ -154,6 +291,112 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#else /* KERNEL */
|
||||
|
||||
/* Zephyr's probably going to cause all tests to fail if one test fails, so
|
||||
* skip the rest of tests if one of them fails
|
||||
*/
|
||||
#ifdef CONFIG_ZTEST_FAIL_FAST
|
||||
#define FAIL_FAST 1
|
||||
#else
|
||||
#define FAIL_FAST 0
|
||||
#endif
|
||||
|
||||
K_THREAD_STACK_DEFINE(ztest_thread_stack, CONFIG_ZTEST_STACKSIZE +
|
||||
CONFIG_TEST_EXTRA_STACKSIZE);
|
||||
static ZTEST_BMEM int test_result;
|
||||
|
||||
static void test_finalize(void)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_MULTITHREADING)) {
|
||||
k_thread_abort(&ztest_thread);
|
||||
k_thread_abort(k_current_get());
|
||||
}
|
||||
}
|
||||
|
||||
void ztest_test_fail(void)
|
||||
{
|
||||
test_result = -1;
|
||||
test_finalize();
|
||||
}
|
||||
|
||||
void ztest_test_pass(void)
|
||||
{
|
||||
test_result = 0;
|
||||
test_finalize();
|
||||
}
|
||||
|
||||
void ztest_test_skip(void)
|
||||
{
|
||||
test_result = -2;
|
||||
test_finalize();
|
||||
}
|
||||
|
||||
static void init_testing(void)
|
||||
{
|
||||
k_object_access_all_grant(&ztest_thread);
|
||||
}
|
||||
|
||||
static void test_cb(void *a, void *dummy2, void *dummy)
|
||||
{
|
||||
struct unit_test *test = (struct unit_test *)a;
|
||||
|
||||
ARG_UNUSED(dummy2);
|
||||
ARG_UNUSED(dummy);
|
||||
|
||||
test_result = 1;
|
||||
run_test_functions(test);
|
||||
test_result = 0;
|
||||
}
|
||||
|
||||
static int run_test(struct unit_test *test)
|
||||
{
|
||||
int ret = TC_PASS;
|
||||
|
||||
TC_START(test->name);
|
||||
|
||||
if (IS_ENABLED(CONFIG_MULTITHREADING)) {
|
||||
k_thread_create(&ztest_thread, ztest_thread_stack,
|
||||
K_THREAD_STACK_SIZEOF(ztest_thread_stack),
|
||||
(k_thread_entry_t) test_cb, (struct unit_test *)test,
|
||||
NULL, NULL, CONFIG_ZTEST_THREAD_PRIORITY,
|
||||
test->thread_options | K_INHERIT_PERMS,
|
||||
K_FOREVER);
|
||||
|
||||
if (test->name != NULL) {
|
||||
k_thread_name_set(&ztest_thread, test->name);
|
||||
}
|
||||
k_thread_start(&ztest_thread);
|
||||
k_thread_join(&ztest_thread, K_FOREVER);
|
||||
} else {
|
||||
test_result = 1;
|
||||
run_test_functions(test);
|
||||
}
|
||||
|
||||
phase = TEST_PHASE_TEARDOWN;
|
||||
test->teardown();
|
||||
phase = TEST_PHASE_FRAMEWORK;
|
||||
|
||||
if (test_result == -1) {
|
||||
ret = TC_FAIL;
|
||||
}
|
||||
|
||||
if (!test_result || !FAIL_FAST) {
|
||||
ret |= cleanup_test(test);
|
||||
}
|
||||
|
||||
if (test_result == -2) {
|
||||
Z_TC_END_RESULT(TC_SKIP, test->name);
|
||||
} else {
|
||||
Z_TC_END_RESULT(ret, test->name);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* !KERNEL */
|
||||
|
||||
void z_ztest_run_test_suite(const char *name, struct unit_test *suite)
|
||||
{
|
||||
int fail = 0;
|
||||
@@ -164,8 +407,7 @@ void z_ztest_run_test_suite(const char *name, struct unit_test *suite)
|
||||
|
||||
init_testing();
|
||||
|
||||
PRINT("Running test suite %s\n", name);
|
||||
PRINT_LINE;
|
||||
TC_SUITE_START(name);
|
||||
while (suite->test) {
|
||||
fail += run_test(suite);
|
||||
suite++;
|
||||
@@ -174,11 +416,7 @@ void z_ztest_run_test_suite(const char *name, struct unit_test *suite)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (fail) {
|
||||
TC_PRINT("Test suite %s failed.\n", name);
|
||||
} else {
|
||||
TC_PRINT("Test suite %s succeeded\n", name);
|
||||
}
|
||||
TC_SUITE_END(name, (fail > 0 ? TC_FAIL : TC_PASS));
|
||||
|
||||
test_status = (test_status || fail) ? 1 : 0;
|
||||
}
|
||||
@@ -192,6 +430,11 @@ void end_report(void)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USERSPACE
|
||||
K_APPMEM_PARTITION_DEFINE(ztest_mem_partition);
|
||||
#endif
|
||||
|
||||
#ifndef KERNEL
|
||||
int main(void)
|
||||
{
|
||||
z_init_mock();
|
||||
@@ -200,3 +443,48 @@ int main(void)
|
||||
|
||||
return test_status;
|
||||
}
|
||||
#else
|
||||
void main(void)
|
||||
{
|
||||
#ifdef CONFIG_USERSPACE
|
||||
/* Partition containing globals tagged with ZTEST_DMEM and ZTEST_BMEM
|
||||
* macros. Any variables that user code may reference need to be
|
||||
* placed in this partition if no other memory domain configuration
|
||||
* is made.
|
||||
*/
|
||||
k_mem_domain_add_partition(&k_mem_domain_default,
|
||||
&ztest_mem_partition);
|
||||
#ifdef Z_MALLOC_PARTITION_EXISTS
|
||||
/* Allow access to malloc() memory */
|
||||
k_mem_domain_add_partition(&k_mem_domain_default,
|
||||
&z_malloc_partition);
|
||||
#endif
|
||||
#endif /* CONFIG_USERSPACE */
|
||||
|
||||
z_init_mock();
|
||||
test_main();
|
||||
end_report();
|
||||
if (IS_ENABLED(CONFIG_ZTEST_RETEST_IF_PASSED)) {
|
||||
static __noinit struct {
|
||||
uint32_t magic;
|
||||
uint32_t boots;
|
||||
} state;
|
||||
const uint32_t magic = 0x152ac523;
|
||||
|
||||
if (state.magic != magic) {
|
||||
state.magic = magic;
|
||||
state.boots = 0;
|
||||
}
|
||||
state.boots += 1;
|
||||
if (test_status == 0) {
|
||||
PRINT("Reset board #%u to test again\n",
|
||||
state.boots);
|
||||
k_msleep(10);
|
||||
sys_reboot(SYS_REBOOT_COLD);
|
||||
} else {
|
||||
PRINT("Failed after %u attempts\n", state.boots);
|
||||
state.boots = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <zephyr.h>
|
||||
#include <ztest.h>
|
||||
|
||||
|
||||
#if defined(CONFIG_ZTEST_FATAL_HOOK)
|
||||
/* This is a flag indicate if treating fatal error as expected, then take
|
||||
* action dealing with it. It's SMP-safe.
|
||||
*/
|
||||
ZTEST_BMEM volatile bool fault_in_isr;
|
||||
ZTEST_BMEM volatile k_tid_t valid_fault_tid;
|
||||
|
||||
static inline void reset_stored_fault_status(void)
|
||||
{
|
||||
valid_fault_tid = NULL;
|
||||
fault_in_isr = false;
|
||||
}
|
||||
|
||||
void z_impl_ztest_set_fault_valid(bool valid)
|
||||
{
|
||||
if (valid) {
|
||||
if (k_is_in_isr()) {
|
||||
fault_in_isr = true;
|
||||
} else {
|
||||
valid_fault_tid = k_current_get();
|
||||
}
|
||||
} else {
|
||||
reset_stored_fault_status();
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_USERSPACE)
|
||||
static inline void z_vrfy_ztest_set_fault_valid(bool valid)
|
||||
{
|
||||
z_impl_ztest_set_fault_valid(valid);
|
||||
}
|
||||
#include <syscalls/ztest_set_fault_valid_mrsh.c>
|
||||
#endif
|
||||
|
||||
__weak void ztest_post_fatal_error_hook(unsigned int reason,
|
||||
const z_arch_esf_t *pEsf)
|
||||
{
|
||||
}
|
||||
|
||||
void k_sys_fatal_error_handler(unsigned int reason, const z_arch_esf_t *pEsf)
|
||||
{
|
||||
k_tid_t curr_tid = k_current_get();
|
||||
bool valid_fault = (curr_tid == valid_fault_tid) || fault_in_isr;
|
||||
|
||||
printk("Caught system error -- reason %d %d\n", reason, valid_fault);
|
||||
|
||||
if (valid_fault) {
|
||||
printk("Fatal error expected as part of test case.\n");
|
||||
|
||||
/* reset back to normal */
|
||||
reset_stored_fault_status();
|
||||
|
||||
/* do some action after expected fatal error happened */
|
||||
ztest_post_fatal_error_hook(reason, pEsf);
|
||||
} else {
|
||||
printk("Fatal error was unexpected, aborting...\n");
|
||||
k_fatal_halt(reason);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(CONFIG_ZTEST_ASSERT_HOOK)
|
||||
/* This is a flag indicate if treating assert fail as expected, then take
|
||||
* action dealing with it. It's SMP-safe.
|
||||
*/
|
||||
ZTEST_BMEM volatile bool assert_in_isr;
|
||||
ZTEST_BMEM volatile k_tid_t valid_assert_tid;
|
||||
|
||||
static inline void reset_stored_assert_status(void)
|
||||
{
|
||||
valid_assert_tid = NULL;
|
||||
assert_in_isr = 0;
|
||||
}
|
||||
|
||||
void z_impl_ztest_set_assert_valid(bool valid)
|
||||
{
|
||||
if (valid) {
|
||||
if (k_is_in_isr()) {
|
||||
assert_in_isr = true;
|
||||
} else {
|
||||
valid_assert_tid = k_current_get();
|
||||
}
|
||||
} else {
|
||||
reset_stored_assert_status();
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_USERSPACE)
|
||||
static inline void z_vrfy_ztest_set_assert_valid(bool valid)
|
||||
{
|
||||
z_impl_ztest_set_assert_valid(valid);
|
||||
}
|
||||
#include <syscalls/ztest_set_assert_valid_mrsh.c>
|
||||
#endif
|
||||
|
||||
__weak void ztest_post_assert_fail_hook(void)
|
||||
{
|
||||
k_thread_abort(k_current_get());
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ASSERT_NO_FILE_INFO
|
||||
void assert_post_action(void)
|
||||
#else
|
||||
void assert_post_action(const char *file, unsigned int line)
|
||||
#endif
|
||||
{
|
||||
#ifndef CONFIG_ASSERT_NO_FILE_INFO
|
||||
ARG_UNUSED(file);
|
||||
ARG_UNUSED(line);
|
||||
#endif
|
||||
|
||||
printk("Caught assert failed\n");
|
||||
|
||||
if ((k_current_get() == valid_assert_tid) || assert_in_isr) {
|
||||
printk("Assert error expected as part of test case.\n");
|
||||
|
||||
/* reset back to normal */
|
||||
reset_stored_assert_status();
|
||||
|
||||
/* It won't go back to caller when assert failed, and it
|
||||
* will terminate the thread.
|
||||
*/
|
||||
ztest_post_assert_fail_hook();
|
||||
} else {
|
||||
printk("Assert failed was unexpected, aborting...\n");
|
||||
#ifdef CONFIG_USERSPACE
|
||||
/* User threads aren't allowed to induce kernel panics; generate
|
||||
* an oops instead.
|
||||
*/
|
||||
if (k_is_user_context()) {
|
||||
k_oops();
|
||||
}
|
||||
#endif
|
||||
k_panic();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
+180
-17
@@ -3,22 +3,32 @@
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Modified from zephyr_v2.2.0 subsys/testsuite/ztest/src/ztest_mock.c
|
||||
* because:
|
||||
* From zephyr_v2.6.0 subsys/testsuite/ztest/src/ztest_mock.c
|
||||
* NOTE:
|
||||
* 1. This port will never be run in the Zephyr kernel.
|
||||
* This repository is extended to be a Zephyr module for that.
|
||||
* 2. This port will not support multiple CPUs or toolchains.
|
||||
*
|
||||
* Modifications:
|
||||
* a. Code conditionally compiled on the following CPP symbols were deleted
|
||||
* (as they were kernel-specific):
|
||||
* KERNEL
|
||||
*/
|
||||
|
||||
#ifdef KERNEL
|
||||
#error Why is KERNEL defined by hered?
|
||||
#endif
|
||||
#include <ztest.h>
|
||||
#ifdef KERNEL
|
||||
#error Why is KERNEL defined by hered?
|
||||
#endif
|
||||
#include <zephyr/types.h>
|
||||
#ifdef KERNEL
|
||||
#error Why is KERNEL defined by hered?
|
||||
#endif
|
||||
#include <string.h>
|
||||
#ifdef KERNEL
|
||||
#error Why is KERNEL defined by hered?
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#ifdef KERNEL
|
||||
#error Why is KERNEL defined by hered?
|
||||
#endif
|
||||
|
||||
struct parameter {
|
||||
struct parameter *next;
|
||||
@@ -27,6 +37,8 @@ struct parameter {
|
||||
uintptr_t value;
|
||||
};
|
||||
|
||||
#ifndef KERNEL
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
@@ -50,7 +62,6 @@ static struct parameter *alloc_parameter(void)
|
||||
|
||||
void z_init_mock(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void printk(const char *fmt, ...)
|
||||
@@ -66,10 +77,89 @@ void vprintk(const char *fmt, va_list ap)
|
||||
{
|
||||
vprintf(fmt, ap);
|
||||
}
|
||||
#else
|
||||
|
||||
/*
|
||||
* FIXME: move to sys_io.h once the argument signature for bitmap has
|
||||
* been fixed to void* or similar GH-2825
|
||||
*/
|
||||
#define BITS_PER_UL (8 * sizeof(unsigned long int))
|
||||
#define DEFINE_BITFIELD(name, bits) \
|
||||
unsigned long int(name)[((bits) + BITS_PER_UL - 1) / BITS_PER_UL]
|
||||
|
||||
static inline int sys_bitfield_find_first_clear(const unsigned long *bitmap,
|
||||
const unsigned int bits)
|
||||
{
|
||||
const size_t words = (bits + BITS_PER_UL - 1) / BITS_PER_UL;
|
||||
size_t cnt;
|
||||
unsigned int long neg_bitmap;
|
||||
|
||||
/*
|
||||
* By bitwise negating the bitmap, we are actually implementing
|
||||
* ffc (find first clear) using ffs (find first set).
|
||||
*/
|
||||
for (cnt = 0; cnt < words; cnt++) {
|
||||
neg_bitmap = ~bitmap[cnt];
|
||||
if (neg_bitmap == 0) {
|
||||
/* All full. Try next word. */
|
||||
continue;
|
||||
} else if (neg_bitmap == ~0UL) {
|
||||
/* First bit is free */
|
||||
return cnt * BITS_PER_UL;
|
||||
} else {
|
||||
const unsigned int bit = (cnt * BITS_PER_UL) +
|
||||
__builtin_ffsl(neg_bitmap) - 1;
|
||||
/* Ensure first free bit is within total bits count */
|
||||
if (bit < bits) {
|
||||
return bit;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static DEFINE_BITFIELD(params_allocation, CONFIG_ZTEST_PARAMETER_COUNT);
|
||||
static struct parameter params[CONFIG_ZTEST_PARAMETER_COUNT];
|
||||
|
||||
static void free_parameter(struct parameter *param)
|
||||
{
|
||||
unsigned int allocation_index = param - params;
|
||||
|
||||
if (param == NULL)
|
||||
return;
|
||||
__ASSERT(allocation_index < CONFIG_ZTEST_PARAMETER_COUNT,
|
||||
"param %p given to free is not in the static buffer %p:%u",
|
||||
param, params, CONFIG_ZTEST_PARAMETER_COUNT);
|
||||
sys_bitfield_clear_bit((mem_addr_t)params_allocation, allocation_index);
|
||||
}
|
||||
|
||||
static struct parameter *alloc_parameter(void)
|
||||
{
|
||||
int allocation_index;
|
||||
struct parameter *param;
|
||||
|
||||
allocation_index = sys_bitfield_find_first_clear(
|
||||
params_allocation, CONFIG_ZTEST_PARAMETER_COUNT);
|
||||
if (allocation_index == -1) {
|
||||
printk("No more mock parameters available for allocation\n");
|
||||
ztest_test_fail();
|
||||
}
|
||||
sys_bitfield_set_bit((mem_addr_t)params_allocation, allocation_index);
|
||||
param = params + allocation_index;
|
||||
(void)memset(param, 0, sizeof(*param));
|
||||
return param;
|
||||
}
|
||||
|
||||
void z_init_mock(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static struct parameter *find_and_delete_value(struct parameter *param,
|
||||
const char *fn,
|
||||
const char *name)
|
||||
const char *fn, const char *name)
|
||||
{
|
||||
struct parameter *value;
|
||||
|
||||
@@ -117,7 +207,7 @@ void z_ztest_expect_value(const char *fn, const char *name, uintptr_t val)
|
||||
}
|
||||
|
||||
void z_ztest_check_expected_value(const char *fn, const char *name,
|
||||
uintptr_t val)
|
||||
uintptr_t val)
|
||||
{
|
||||
struct parameter *param;
|
||||
uintptr_t expected;
|
||||
@@ -135,23 +225,91 @@ void z_ztest_check_expected_value(const char *fn, const char *name,
|
||||
/* We need to cast these values since the toolchain doesn't
|
||||
* provide inttypes.h
|
||||
*/
|
||||
PRINT("%s received wrong value: Got %lu, expected %lu\n",
|
||||
fn, (unsigned long)val, (unsigned long)expected);
|
||||
PRINT("%s:%s received wrong value: Got %lu, expected %lu\n", fn,
|
||||
name, (unsigned long)val, (unsigned long)expected);
|
||||
ztest_test_fail();
|
||||
}
|
||||
}
|
||||
|
||||
void z_ztest_returns_value(const char *fn, uintptr_t value)
|
||||
void z_ztest_expect_data(const char *fn, const char *name, void *val)
|
||||
{
|
||||
insert_value(¶meter_list, fn, name, (uintptr_t)val);
|
||||
}
|
||||
|
||||
void z_ztest_check_expected_data(const char *fn, const char *name, void *data,
|
||||
uint32_t length)
|
||||
{
|
||||
struct parameter *param;
|
||||
void *expected;
|
||||
|
||||
param = find_and_delete_value(¶meter_list, fn, name);
|
||||
if (!param) {
|
||||
PRINT("Failed to find parameter %s for %s\n", name, fn);
|
||||
/* No return from this function but for coverity reasons
|
||||
* put a return after to avoid the warning of a null
|
||||
* dereference of param below.
|
||||
*/
|
||||
ztest_test_fail();
|
||||
return;
|
||||
}
|
||||
|
||||
expected = (void *)param->value;
|
||||
free_parameter(param);
|
||||
|
||||
if (expected == NULL && data != NULL) {
|
||||
PRINT("%s:%s received null pointer\n", fn, name);
|
||||
ztest_test_fail();
|
||||
} else if (data == NULL && expected != NULL) {
|
||||
PRINT("%s:%s received data while expected null pointer\n", fn,
|
||||
name);
|
||||
ztest_test_fail();
|
||||
} else if (data != NULL) {
|
||||
if (memcmp(data, expected, length) != 0) {
|
||||
PRINT("%s:%s data provided don't match\n", fn, name);
|
||||
ztest_test_fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void z_ztest_return_data(const char *fn, const char *name, void *val)
|
||||
{
|
||||
insert_value(¶meter_list, fn, name, (uintptr_t)val);
|
||||
}
|
||||
|
||||
void z_ztest_copy_return_data(const char *fn, const char *name, void *data,
|
||||
uint32_t length)
|
||||
{
|
||||
struct parameter *param;
|
||||
void *return_data;
|
||||
|
||||
if (data == NULL) {
|
||||
PRINT("%s:%s received null pointer\n", fn, name);
|
||||
ztest_test_fail();
|
||||
return;
|
||||
}
|
||||
|
||||
param = find_and_delete_value(¶meter_list, fn, name);
|
||||
if (!param) {
|
||||
PRINT("Failed to find parameter %s for %s\n", name, fn);
|
||||
memset(data, 0, length);
|
||||
ztest_test_fail();
|
||||
} else {
|
||||
return_data = (void *)param->value;
|
||||
free_parameter(param);
|
||||
memcpy(data, return_data, length);
|
||||
}
|
||||
}
|
||||
|
||||
void z_ztest_returns_value(const char *fn, uintptr_t value)
|
||||
{
|
||||
insert_value(&return_value_list, fn, "", value);
|
||||
}
|
||||
|
||||
|
||||
uintptr_t z_ztest_get_return_value(const char *fn)
|
||||
{
|
||||
uintptr_t value;
|
||||
struct parameter *param = find_and_delete_value(&return_value_list,
|
||||
fn, "");
|
||||
struct parameter *param =
|
||||
find_and_delete_value(&return_value_list, fn, "");
|
||||
|
||||
if (!param) {
|
||||
PRINT("Failed to find return value for function %s\n", fn);
|
||||
@@ -180,9 +338,14 @@ int z_cleanup_mock(void)
|
||||
int fail = 0;
|
||||
|
||||
if (parameter_list.next) {
|
||||
PRINT("Parameter not used by mock: %s:%s\n",
|
||||
parameter_list.next->fn,
|
||||
parameter_list.next->name);
|
||||
fail = 1;
|
||||
}
|
||||
if (return_value_list.next) {
|
||||
PRINT("Return value no used by mock: %s\n",
|
||||
return_value_list.next->fn);
|
||||
fail = 2;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user