Feature/zephyr ztest (#118)

* Leverage (older) embedded unit tests into external unit tests build upon copy of Zephyr's ztest library and CMake.

* Expand top-level CMake build to run external unit tests.

* Expand Zephyr module extension to run external unit tests via west or sanitycheck.

Co-authored-by: Gregory Shue <gregory.shue@legrand.us>
This commit is contained in:
Greg Shue
2020-09-16 05:33:34 -07:00
committed by GitHub
parent a7b2e94cb7
commit 19869dccdb
399 changed files with 21885 additions and 5 deletions
+77
View File
@@ -0,0 +1,77 @@
/* printk.h - low-level debug output */
/*
* Copyright (c) 2010-2012, 2014 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
* Modified from zephyr_v2.2.0 include/sys/printk.h
* because:
* 1. This port will never be run in the Zephyr kernel.
* This repository is extended to be a Zephyr module for that.
*
* Modifications:
* a. Code conditionally compiled on the following CPP symbols were deleted
* (as they were kernel-specific):
* CONFIG_PRINTK
* KERNEL
* b. Inclusion of The following header files were removed as irrelevant.
* <toolchain.h>
* <inttypes.h>
*/
#ifndef ZEPHYR_INCLUDE_SYS_PRINTK_H_
#define ZEPHYR_INCLUDE_SYS_PRINTK_H_
#include <stddef.h>
#include <stdarg.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
*
* @brief Print kernel debugging message.
*
* This routine prints a kernel debugging message to the system console.
* Output is send immediately, without any mutual exclusion or buffering.
*
* A basic set of conversion specifier characters are supported:
* - signed decimal: \%d, \%i
* - unsigned decimal: \%u
* - unsigned hexadecimal: \%x (\%X is treated as \%x)
* - pointer: \%p
* - string: \%s
* - character: \%c
* - percent: \%\%
*
* Field width (with or without leading zeroes) is supported.
* Length attributes h, hh, l, ll and z are supported. However, integral
* values with %lld and %lli are only printed if they fit in a long
* otherwise 'ERR' is printed. Full 64-bit values may be printed with %llx.
* Flags and precision attributes are not supported.
*
* @param fmt Format string.
* @param ... Optional list of format arguments.
*
* @return N/A
*/
extern void printk(const char *fmt, ...);
extern void vprintk(const char *fmt, va_list ap);
//GAS: useful? #warning "z_vprintk is not supported in this port of ztest"
static inline void z_vprintk(int (*out)(int f, void *c), void *ctx,
const char *fmt, va_list ap)
{
(void)(out);
(void)(ctx);
(void)(fmt);
(void)(ap);
}
#ifdef __cplusplus
}
#endif
#endif
+170
View File
@@ -0,0 +1,170 @@
/* tc_utilities.h - testcase utilities header file */
/*
* Copyright (c) 2012-2015 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __TC_UTIL_H__
#define __TC_UTIL_H__
#include <zephyr.h>
#include <string.h>
#ifdef CONFIG_SHELL
#include <shell/shell.h>
#endif
#include <sys/printk.h>
#if defined CONFIG_ZTEST_TC_UTIL_USER_OVERRIDE
#include <tc_util_user_override.h>
#endif
#ifndef PRINT_DATA
#define PRINT_DATA(fmt, ...) printk(fmt, ##__VA_ARGS__)
#endif
#if defined CONFIG_ARCH_POSIX
#include "posix_board_if.h"
#endif
/**
* @def TC_PRINT_RUNID
* @brief Report a Run ID
*
* When the CPP symbol \c TC_RUNID is defined (for example, from the
* compile environment), print the defined string ``RunID:
* <TC_RUNID>`` when called (TC_END_REPORT() will also call it).
*
* This is used mainly when automating the execution and running of
* multiple test cases, to verify that the expected image is being
* executed (as sometimes the targets fail to flash or reset
* properly).
*
* TC_RUNID is any string, that will be converted to a string literal.
*/
#define TC_STR_HELPER(x) #x
#define TC_STR(x) TC_STR_HELPER(x)
#ifdef TC_RUNID
#define TC_PRINT_RUNID PRINT_DATA("RunID: " TC_STR(TC_RUNID) "\n")
#else
#define TC_PRINT_RUNID do {} while (0)
#endif
#ifndef PRINT_LINE
#define PRINT_LINE \
PRINT_DATA( \
"============================================================" \
"=======\n")
#endif
/* stack size and priority for test suite task */
#define TASK_STACK_SIZE (1024 * 2)
#define FMT_ERROR "%s - %s@%d. "
#define TC_PASS 0
#define TC_FAIL 1
#define TC_SKIP 2
#ifndef TC_PASS_STR
#define TC_PASS_STR "PASS"
#endif
#ifndef TC_FAIL_STR
#define TC_FAIL_STR "FAIL"
#endif
#ifndef TC_SKIP_STR
#define TC_SKIP_STR "SKIP"
#endif
static inline const char *TC_RESULT_TO_STR(int result)
{
switch (result) {
case TC_PASS:
return TC_PASS_STR;
case TC_FAIL:
return TC_FAIL_STR;
case TC_SKIP:
return TC_SKIP_STR;
default:
return "?";
}
}
#ifndef TC_ERROR
#define TC_ERROR(fmt, ...) \
do { \
PRINT_DATA(FMT_ERROR, "FAIL", __func__, __LINE__); \
PRINT_DATA(fmt, ##__VA_ARGS__); \
} while (0)
#endif
#ifndef TC_PRINT
#define TC_PRINT(fmt, ...) PRINT_DATA(fmt, ##__VA_ARGS__)
#endif
#ifndef TC_START
#define TC_START(name) PRINT_DATA("starting test - %s\n", name)
#endif
#ifndef TC_END
#define TC_END(result, fmt, ...) PRINT_DATA(fmt, ##__VA_ARGS__)
#endif
#ifndef Z_TC_END_RESULT
/* prints result and the function name */
#define Z_TC_END_RESULT(result, func) \
do { \
TC_END(result, "%s - %s\n", TC_RESULT_TO_STR(result), func); \
PRINT_LINE; \
} while (0)
#endif
#ifndef TC_END_RESULT
#define TC_END_RESULT(result) \
Z_TC_END_RESULT((result), __func__)
#endif
#if defined(CONFIG_ARCH_POSIX)
#define TC_END_POST(result) posix_exit(result)
#else
#define TC_END_POST(result)
#endif /* CONFIG_ARCH_POSIX */
#ifndef TC_END_REPORT
#define TC_END_REPORT(result) \
do { \
PRINT_LINE; \
TC_PRINT_RUNID; \
TC_END(result, \
"PROJECT EXECUTION %s\n", \
(result) == TC_PASS ? "SUCCESSFUL" : "FAILED"); \
TC_END_POST(result); \
} while (0)
#endif
#if defined(CONFIG_SHELL)
#define TC_CMD_DEFINE(name) \
static int cmd_##name(const struct shell *shell, size_t argc, \
char **argv) \
{ \
TC_START(__func__); \
name(); \
TC_END_RESULT(TC_PASS); \
return 0; \
}
#define TC_CMD_ITEM(name) cmd_##name
#else
#define TC_CMD_DEFINE(name) \
int cmd_##name(int argc, char *argv[]) \
{ \
TC_START(__func__); \
name(); \
TC_END_RESULT(TC_PASS); \
return 0; \
}
#define TC_CMD_ITEM(name) {STRINGIFY(name), cmd_##name, "none"}
#endif
#endif /* __TC_UTIL_H__ */
+85
View File
@@ -0,0 +1,85 @@
/* test_utils.h - TinyCrypt interface to common functions for tests */
/*
* Copyright (C) 2015 by Intel Corporation, All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __TEST_UTILS_H__
#define __TEST_UTILS_H__
#include <tc_util.h>
#include <tinycrypt/constants.h>
static inline void show_str(const char *label, const u8_t *s, size_t len)
{
u32_t i;
TC_PRINT("%s = ", label);
for (i = 0U; i < (u32_t)len; ++i) {
TC_PRINT("%02x", s[i]);
}
TC_PRINT("\n");
}
static inline
void fatal(u32_t testnum, const void *expected, size_t expectedlen,
const void *computed, size_t computedlen)
{
TC_ERROR("\tTest #%d Failed!\n", testnum);
show_str("\t\tExpected", expected, expectedlen);
show_str("\t\tComputed ", computed, computedlen);
TC_PRINT("\n");
}
static inline
u32_t check_result(u32_t testnum, const void *expected,
size_t expectedlen, const void *computed,
size_t computedlen, u32_t verbose)
{
u32_t result = TC_PASS;
ARG_UNUSED(verbose);
if (expectedlen != computedlen) {
TC_ERROR("The length of the computed buffer (%zu)",
computedlen);
TC_ERROR("does not match the expected length (%zu).",
expectedlen);
result = TC_FAIL;
} else {
if (memcmp(computed, expected, computedlen) != 0) {
fatal(testnum, expected, expectedlen,
computed, computedlen);
result = TC_FAIL;
}
}
return result;
}
#endif
+24
View File
@@ -0,0 +1,24 @@
/*
* Copyright (c) 2015 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_ZEPHYR_H_
#define ZEPHYR_INCLUDE_ZEPHYR_H_
/*
* Applications can identify whether they are built for Zephyr by
* macro below. (It may be already defined by a makefile or toolchain.)
*/
#ifndef __ZEPHYR__
#define __ZEPHYR__
#endif
//GAS: rm? #include <kernel.h>
//GAS: add?
#define Z_STRINGIFY(x) #x
#define STRINGIFY(s) Z_STRINGIFY(s)
#endif /* ZEPHYR_INCLUDE_ZEPHYR_H_ */
+33
View File
@@ -0,0 +1,33 @@
/*
* Copyright (c) 2017 Linaro Limited
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_ZEPHYR_TYPES_H_
#define ZEPHYR_INCLUDE_ZEPHYR_TYPES_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef signed char s8_t;
typedef signed short s16_t;
typedef signed int s32_t;
typedef signed long long s64_t;
typedef unsigned char u8_t;
typedef unsigned short u16_t;
typedef unsigned int u32_t;
typedef unsigned long long u64_t;
/* 32 bits on ILP32 builds, 64 bits on LP64 builts */
typedef unsigned long ulong_t;
#ifdef __cplusplus
}
#endif
#endif /* ZEPHYR_INCLUDE_ZEPHYR_TYPES_H_ */
+83
View File
@@ -0,0 +1,83 @@
/*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*
* Modified from zephyr_v2.2.0 subsys/testsuite/ztest/include/ztest.h
* 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. Code conditionally compiled on the following CPP symbols were deleted
* (as they were kernel-specific):
* KERNEL
*/
/**
* @file
*
* @brief Zephyr testing suite
*/
/**
* @brief Zephyr Tests
* @defgroup all_tests Zephyr Tests
* @{
* @}
*/
#ifndef __ZTEST_H__
#define __ZTEST_H__
/**
* @defgroup ztest Zephyr testing suite
*/
#if !defined(CONFIG_ZTEST) && !defined(ZTEST_UNITTEST)
#error "You need to add CONFIG_ZTEST to your config file."
#endif
#define CONFIG_STDOUT_CONSOLE 1
#define CONFIG_ZTEST_ASSERT_VERBOSE 1
#define CONFIG_ZTEST_MOCKING
#define CONFIG_NUM_COOP_PRIORITIES 16
#define CONFIG_COOP_ENABLED 1
#define CONFIG_PREEMPT_ENABLED 1
#define CONFIG_MP_NUM_CPUS 1
#define CONFIG_SYS_CLOCK_TICKS_PER_SEC 100
#define CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC 10000000
/* FIXME: Properly integrate with Zephyr's arch specific code */
#define CONFIG_X86 1
#define CONFIG_PRINTK 1
#ifdef __cplusplus
extern "C" {
#endif
struct esf;
typedef struct esf z_arch_esf_t;
#ifdef __cplusplus
}
#endif
#include <sys/printk.h>
#define PRINT printk
#include <zephyr.h>
#include <ztest_assert.h>
#include <ztest_mock.h>
#include <ztest_test.h>
#include <tc_util.h>
#ifdef __cplusplus
extern "C" {
#endif
void test_main(void);
#ifdef __cplusplus
}
#endif
#endif /* __ZTEST_H__ */
+225
View File
@@ -0,0 +1,225 @@
/*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
*
* @brief Zephyr testing framework assertion macros
*/
#ifndef __ZTEST_ASSERT_H__
#define __ZTEST_ASSERT_H__
#include <ztest.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
void ztest_test_fail(void);
#if CONFIG_ZTEST_ASSERT_VERBOSE == 0
static inline void z_zassert_(bool cond, const char *file, int line)
{
if (cond == false) {
PRINT("\n Assertion failed at %s:%d\n",
file, line);
ztest_test_fail();
}
}
#define z_zassert(cond, default_msg, file, line, func, msg, ...) \
z_zassert_(cond, file, line)
#else /* CONFIG_ZTEST_ASSERT_VERBOSE != 0 */
static inline void z_zassert(bool cond,
const char *default_msg,
const char *file,
int line, const char *func,
const char *msg, ...)
{
if (cond == false) {
va_list vargs;
va_start(vargs, msg);
PRINT("\n Assertion failed at %s:%d: %s: %s\n",
file, line, func, default_msg);
vprintk(msg, vargs);
printk("\n");
va_end(vargs);
ztest_test_fail();
}
#if CONFIG_ZTEST_ASSERT_VERBOSE == 2
else {
PRINT("\n Assertion succeeded at %s:%d (%s)\n",
file, line, func);
}
#endif
}
#endif /* CONFIG_ZTEST_ASSERT_VERBOSE */
/**
* @defgroup ztest_assert Ztest assertion macros
* @ingroup ztest
*
* This module provides assertions when using Ztest.
*
* @{
*/
/**
* @brief Fail the test, if @a cond is false
*
* You probably don't need to call this macro directly. You should
* instead use zassert_{condition} macros below.
*
* @param cond Condition to check
* @param msg Optional, can be NULL. Message to print if @a cond is false.
* @param default_msg Message to print if @a cond is false
*/
#define zassert(cond, default_msg, msg, ...) \
z_zassert(cond, msg ? ("(" default_msg ")") : (default_msg), \
__FILE__, __LINE__, __func__, msg ? msg : "", ##__VA_ARGS__)
/**
* @brief Assert that this function call won't be reached
* @param msg Optional message to print if the assertion fails
*/
#define zassert_unreachable(msg, ...) zassert(0, "Reached unreachable code", \
msg, ##__VA_ARGS__)
/**
* @brief Assert that @a cond is true
* @param cond Condition to check
* @param msg Optional message to print if the assertion fails
*/
#define zassert_true(cond, msg, ...) zassert(cond, #cond " is false", \
msg, ##__VA_ARGS__)
/**
* @brief Assert that @a cond is false
* @param cond Condition to check
* @param msg Optional message to print if the assertion fails
*/
#define zassert_false(cond, msg, ...) zassert(!(cond), #cond " is true", \
msg, ##__VA_ARGS__)
/**
* @brief Assert that @a ptr is NULL
* @param ptr Pointer to compare
* @param msg Optional message to print if the assertion fails
*/
#define zassert_is_null(ptr, msg, ...) zassert((ptr) == NULL, \
#ptr " is not NULL", \
msg, ##__VA_ARGS__)
/**
* @brief Assert that @a ptr is not NULL
* @param ptr Pointer to compare
* @param msg Optional message to print if the assertion fails
*/
#define zassert_not_null(ptr, msg, ...) zassert((ptr) != NULL, \
#ptr " is NULL", msg, \
##__VA_ARGS__)
/**
* @brief Assert that @a a equals @a b
*
* @a a and @a b won't be converted and will be compared directly.
*
* @param a Value to compare
* @param b Value to compare
* @param msg Optional message to print if the assertion fails
*/
#define zassert_equal(a, b, msg, ...) zassert((a) == (b), \
#a " not equal to " #b, \
msg, ##__VA_ARGS__)
/**
* @brief Assert that @a a does not equal @a b
*
* @a a and @a b won't be converted and will be compared directly.
*
* @param a Value to compare
* @param b Value to compare
* @param msg Optional message to print if the assertion fails
*/
#define zassert_not_equal(a, b, msg, ...) zassert((a) != (b), \
#a " equal to " #b, \
msg, ##__VA_ARGS__)
/**
* @brief Assert that @a a equals @a b
*
* @a a and @a b will be converted to `void *` before comparing.
*
* @param a Value to compare
* @param b Value to compare
* @param msg Optional message to print if the assertion fails
*/
#define zassert_equal_ptr(a, b, msg, ...) \
zassert((void *)(a) == (void *)(b), #a " not equal to " #b, \
msg, ##__VA_ARGS__)
/**
* @brief Assert that @a a is within @a b with delta @a d
*
* @param a Value to compare
* @param b Value to compare
* @param d Delta
* @param msg Optional message to print if the assertion fails
*/
#define zassert_within(a, b, d, msg, ...) \
zassert(((a) > ((b) - (d))) && ((a) < ((b) + (d))), \
#a " not within " #b " +/- " #d, \
msg, ##__VA_ARGS__)
/**
* @brief Assert that 2 memory buffers have the same contents
*
* This macro calls the final memory comparison assertion macro.
* Using double expansion allows providing some arguments by macros that
* would expand to more than one values (ANSI-C99 defines that all the macro
* arguments have to be expanded before macro call).
*
* @param ... Arguments, see @ref zassert_mem_equal__
* for real arguments accepted.
*/
#define zassert_mem_equal(...) \
zassert_mem_equal__(__VA_ARGS__)
/**
* @brief Internal assert that 2 memory buffers have the same contents
*
* @note This is internal macro, to be used as a second expansion.
* See @ref zassert_mem_equal.
*
* @param buf Buffer to compare
* @param exp Buffer with expected contents
* @param size Size of buffers
* @param msg Optional message to print if the assertion fails
*/
#define zassert_mem_equal__(buf, exp, size, msg, ...) \
zassert(memcmp(buf, exp, size) == 0, #buf " not equal to " #exp, \
msg, ##__VA_ARGS__)
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __ZTEST_ASSERT_H__ */
+119
View File
@@ -0,0 +1,119 @@
/*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
*
* @brief Ztest mocking support
*/
#ifndef __ZTEST_MOCK_H__
#define __ZTEST_MOCK_H__
/**
* @defgroup ztest_mock Ztest mocking support
* @ingroup ztest
*
* This module provides simple mocking functions for unit testing. These
* need CONFIG_ZTEST_MOCKING=y.
*
* @{
*/
/**
* @brief Tell function @a func to expect the value @a value for @a param
*
* When using ztest_check_expected_value(), tell that the value of @a param
* should be @a value. The value will internally be stored as an `uintptr_t`.
*
* @param func Function in question
* @param param Parameter for which the value should be set
* @param value Value for @a param
*/
#define ztest_expect_value(func, param, value) \
z_ztest_expect_value(STRINGIFY(func), STRINGIFY(param), \
(uintptr_t)(value))
/**
* @brief If @a param doesn't match the value set by ztest_expect_value(),
* fail the test
*
* This will first check that does @a param have a value to be expected, and
* then checks whether the value of the parameter is equal to the expected
* value. If either of these checks fail, the current test will fail. This
* must be called from the called function.
*
* @param param Parameter to check
*/
#define ztest_check_expected_value(param) \
z_ztest_check_expected_value(__func__, STRINGIFY(param), \
(uintptr_t)(param))
/**
* @brief Tell @a func that it should return @a value
*
* @param func Function that should return @a value
* @param value Value to return from @a func
*/
#define ztest_returns_value(func, value) \
z_ztest_returns_value(STRINGIFY(func), (uintptr_t)(value))
/**
* @brief Get the return value for current function
*
* The return value must have been set previously with ztest_returns_value().
* If no return value exists, the current test will fail.
*
* @returns The value the current function should return
*/
#define ztest_get_return_value() \
z_ztest_get_return_value(__func__)
/**
* @brief Get the return value as a pointer for current function
*
* The return value must have been set previously with ztest_returns_value().
* If no return value exists, the current test will fail.
*
* @returns The value the current function should return as a `void *`
*/
#define ztest_get_return_value_ptr() \
((void *)z_ztest_get_return_value(__func__))
/**
* @}
*/
#ifdef CONFIG_ZTEST_MOCKING
#include <zephyr/types.h>
#ifdef __cplusplus
extern "C" {
#endif
void z_init_mock(void);
int z_cleanup_mock(void);
void z_ztest_expect_value(const char *fn, const char *name, uintptr_t value);
void z_ztest_check_expected_value(const char *fn, const char *param,
uintptr_t value);
void z_ztest_returns_value(const char *fn, uintptr_t value);
uintptr_t z_ztest_get_return_value(const char *fn);
#ifdef __cplusplus
}
#endif
#else /* !CONFIG_ZTEST_MOCKING */
#define z_init_mock()
#define z_cleanup_mock() 0
#endif /* CONFIG_ZTEST_MOCKING */
#endif /* __ZTEST_H__ */
+208
View File
@@ -0,0 +1,208 @@
/*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
*
* @brief Zephyr testing framework _test.
*
* 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. Code conditionally compiled on the following CPP symbols were deleted
* (as they were kernel-specific):
* CONFIG_USERSPACE
* CONFIG_SMP
* KERNEL
* b. Inclusion of The following header files were removed as irrelevant.
* <app_memory/app_memdomain.h>
* c. syscall declarations and inclusions.
*/
#ifndef __ZTEST_TEST_H__
#define __ZTEST_TEST_H__
#ifdef __cplusplus
extern "C" {
#endif
struct unit_test {
const char *name;
void (*test)(void);
void (*setup)(void);
void (*teardown)(void);
u32_t thread_options;
};
void z_ztest_run_test_suite(const char *name, struct unit_test *suite);
/**
* @defgroup ztest_test Ztest testing macros
* @ingroup ztest
*
* This module eases the testing process by providing helpful macros and other
* testing structures.
*
* @{
*/
/**
* @brief Fail the currently running test.
*
* This is the function called from failed assertions and the like. You
* probably don't need to call it yourself.
*/
void ztest_test_fail(void);
/**
* @brief Pass the currently running test.
*
* Normally a test passes just by returning without an assertion failure.
* However, if the success case for your test involves a fatal fault,
* you can call this function from k_sys_fatal_error_handler to indicate that
* the test passed before aborting the thread.
*/
void ztest_test_pass(void);
/**
* @brief Skip the current test.
*
*/
void ztest_test_skip(void);
/**
* @brief Do nothing, successfully.
*
* Unit test / setup function / teardown function that does
* nothing, successfully. Can be used as a parameter to
* ztest_unit_test_setup_teardown().
*/
static inline void unit_test_noop(void)
{
}
/**
* @brief Define a test with setup and teardown functions
*
* This should be called as an argument to ztest_test_suite. The test will
* be run in the following order: @a setup, @a fn, @a teardown.
*
* @param fn Main test function
* @param setup Setup function
* @param teardown Teardown function
*/
#define ztest_unit_test_setup_teardown(fn, setup, teardown) { \
STRINGIFY(fn), fn, setup, teardown, 0 \
}
/**
* @brief Define a user mode test with setup and teardown functions
*
* This should be called as an argument to ztest_test_suite. The test will
* be run in the following order: @a setup, @a fn, @a teardown. ALL
* test functions will be run in user mode, and only if CONFIG_USERSPACE
* is enabled, otherwise this is the same as ztest_unit_test_setup_teardown().
*
* @param fn Main test function
* @param setup Setup function
* @param teardown Teardown function
*/
#define ztest_user_unit_test_setup_teardown(fn, setup, teardown) { \
STRINGIFY(fn), fn, setup, teardown, K_USER \
}
/**
* @brief Define a test function
*
* This should be called as an argument to ztest_test_suite.
*
* @param fn Test function
*/
#define ztest_unit_test(fn) \
ztest_unit_test_setup_teardown(fn, unit_test_noop, unit_test_noop)
/**
* @brief Define a test function that should run as a user thread
*
* This should be called as an argument to ztest_test_suite.
* If CONFIG_USERSPACE is not enabled, this is functionally identical to
* ztest_unit_test().
*
* @param fn Test function
*/
#define ztest_user_unit_test(fn) \
ztest_user_unit_test_setup_teardown(fn, unit_test_noop, unit_test_noop)
/**
* @brief Define a SMP-unsafe test function
*
* As ztest_unit_test(), but ensures all test code runs on only
* one CPU when in SMP.
*
* @param fn Test function
*/
#define ztest_1cpu_unit_test(fn) ztest_unit_test(fn)
/**
* @brief Define a SMP-unsafe test function that should run as a user thread
*
* As ztest_user_unit_test(), but ensures all test code runs on only
* one CPU when in SMP.
*
* @param fn Test function
*/
#define ztest_1cpu_user_unit_test(fn) ztest_user_unit_test(fn)
/* definitions for use with testing application shared memory */
#define ZTEST_DMEM
#define ZTEST_BMEM
#define ZTEST_SECTION .data
/**
* @brief Define a test suite
*
* This function should be called in the following fashion:
* ```{.c}
* ztest_test_suite(test_suite_name,
* ztest_unit_test(test_function),
* ztest_unit_test(test_other_function)
* );
*
* ztest_run_test_suite(test_suite_name);
* ```
*
* @param suite Name of the testing suite
*/
#define ztest_test_suite(suite, ...) \
static ZTEST_DMEM struct unit_test _##suite[] = { \
__VA_ARGS__, { 0 } \
}
/**
* @brief Run the specified test suite.
*
* @param suite Test suite to run.
*/
#define ztest_run_test_suite(suite) \
z_ztest_run_test_suite(#suite, _##suite)
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __ZTEST_ASSERT_H__ */
+202
View File
@@ -0,0 +1,202 @@
/*
* 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>
/* ZTEST_DMEM and ZTEST_BMEM are used for the application shared memory test */
ZTEST_DMEM enum {
TEST_PHASE_SETUP,
TEST_PHASE_TEST,
TEST_PHASE_TEARDOWN,
TEST_PHASE_FRAMEWORK
} phase = TEST_PHASE_FRAMEWORK;
static ZTEST_BMEM int test_status;
static int cleanup_test(struct unit_test *test)
{
int ret = TC_PASS;
int mock_status;
mock_status = z_cleanup_mock();
if (!ret && mock_status == 1) {
PRINT("Test %s failed: Unused mock parameter values\n",
test->name);
ret = TC_FAIL;
} else if (!ret && mock_status == 2) {
PRINT("Test %s failed: Unused mock return values\n",
test->name);
ret = TC_FAIL;
}
return ret;
}
static void run_test_functions(struct unit_test *test)
{
phase = TEST_PHASE_SETUP;
test->setup();
phase = TEST_PHASE_TEST;
test->test();
}
#include <setjmp.h>
#include <signal.h>
#include <string.h>
#include <stdlib.h>
#define FAIL_FAST 0
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)
{
raise(SIGABRT);
}
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[] = {
"setup",
"unit test",
"teardown",
};
#if defined(_WIN32)
PRINT(" %d", sig);
#else /* defined(_WIN32) */
PRINT(" %s", strsignal(sig));
#endif /* defined(_WIN32) */
switch (phase) {
case TEST_PHASE_SETUP:
case TEST_PHASE_TEST:
case TEST_PHASE_TEARDOWN:
PRINT(" at %s function\n", phase_str[phase]);
longjmp(test_fail, 1);
case TEST_PHASE_FRAMEWORK:
PRINT("\n");
longjmp(stack_fail, 1);
}
}
static void init_testing(void)
{
signal(SIGABRT, handle_signal);
signal(SIGSEGV, handle_signal);
if (setjmp(stack_fail)) {
PRINT("Test suite crashed.");
exit(1);
}
}
static int run_test(struct unit_test *test)
{
int ret = TC_PASS;
TC_START(test->name);
if (setjmp(test_fail)) {
ret = TC_FAIL;
goto out;
}
if (setjmp(test_pass)) {
ret = TC_PASS;
goto out;
}
if (setjmp(test_skip)) {
ret = TC_SKIP;
goto out;
}
run_test_functions(test);
out:
ret |= cleanup_test(test);
Z_TC_END_RESULT(ret, test->name);
return ret;
}
void z_ztest_run_test_suite(const char *name, struct unit_test *suite)
{
int fail = 0;
if (test_status < 0) {
return;
}
init_testing();
PRINT("Running test suite %s\n", name);
PRINT_LINE;
while (suite->test) {
fail += run_test(suite);
suite++;
if (fail && FAIL_FAST) {
break;
}
}
if (fail) {
TC_PRINT("Test suite %s failed.\n", name);
} else {
TC_PRINT("Test suite %s succeeded\n", name);
}
test_status = (test_status || fail) ? 1 : 0;
}
void end_report(void)
{
if (test_status) {
TC_END_REPORT(TC_FAIL);
} else {
TC_END_REPORT(TC_PASS);
}
}
int main(void)
{
z_init_mock();
test_main();
end_report();
return test_status;
}
+196
View File
@@ -0,0 +1,196 @@
/*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*
* Modified from zephyr_v2.2.0 subsys/testsuite/ztest/src/ztest_mock.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. Code conditionally compiled on the following CPP symbols were deleted
* (as they were kernel-specific):
* KERNEL
*/
#include <ztest.h>
#include <zephyr/types.h>
#include <string.h>
#include <stdio.h>
struct parameter {
struct parameter *next;
const char *fn;
const char *name;
uintptr_t value;
};
#include <stdlib.h>
#include <stdarg.h>
static void free_parameter(struct parameter *param)
{
free(param);
}
static struct parameter *alloc_parameter(void)
{
struct parameter *param;
param = calloc(1, sizeof(struct parameter));
if (!param) {
PRINT("Failed to allocate mock parameter\n");
ztest_test_fail();
}
return param;
}
void z_init_mock(void)
{
}
void printk(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
}
void vprintk(const char *fmt, va_list ap)
{
vprintf(fmt, ap);
}
static struct parameter *find_and_delete_value(struct parameter *param,
const char *fn,
const char *name)
{
struct parameter *value;
if (!param->next) {
return NULL;
}
if (strcmp(param->next->name, name) || strcmp(param->next->fn, fn)) {
return find_and_delete_value(param->next, fn, name);
}
value = param->next;
param->next = param->next->next;
value->next = NULL;
return value;
}
static void insert_value(struct parameter *param, const char *fn,
const char *name, uintptr_t val)
{
struct parameter *value;
value = alloc_parameter();
value->fn = fn;
value->name = name;
value->value = val;
/* Seek to end of linked list to ensure correct discovery order in find_and_delete_value */
while (param->next) {
param = param->next;
}
/* Append to end of linked list */
value->next = param->next;
param->next = value;
}
static struct parameter parameter_list = { NULL, "", "", 0 };
static struct parameter return_value_list = { NULL, "", "", 0 };
void z_ztest_expect_value(const char *fn, const char *name, uintptr_t val)
{
insert_value(&parameter_list, fn, name, val);
}
void z_ztest_check_expected_value(const char *fn, const char *name,
uintptr_t val)
{
struct parameter *param;
uintptr_t expected;
param = find_and_delete_value(&parameter_list, fn, name);
if (!param) {
PRINT("Failed to find parameter %s for %s\n", name, fn);
ztest_test_fail();
}
expected = param->value;
free_parameter(param);
if (expected != val) {
/* 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);
ztest_test_fail();
}
}
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, "");
if (!param) {
PRINT("Failed to find return value for function %s\n", fn);
ztest_test_fail();
}
value = param->value;
free_parameter(param);
return value;
}
static void free_param_list(struct parameter *param)
{
struct parameter *next;
while (param) {
next = param->next;
free_parameter(param);
param = next;
}
}
int z_cleanup_mock(void)
{
int fail = 0;
if (parameter_list.next) {
fail = 1;
}
if (return_value_list.next) {
fail = 2;
}
free_param_list(parameter_list.next);
free_param_list(return_value_list.next);
parameter_list.next = NULL;
return_value_list.next = NULL;
return fail;
}