ztest: Update ztest with more powerful testing APIs

1. Test suites in prior ztest serve no purpose other than logical
ordering of tests into a named-group. Move the construct of setup and
teardown into the test suite and away from individual tests.
Additionally, add the constructs of before/after to the test suites.
This model more closely resembels other testing frameworks such as gTest
and Junit.
2. Test can be added to a suite by using ZTEST() or ZTEST_F() where _F
stands for fixture. In the case where _F is used, the argument `this`
will be provided with the type `struct suite_name##_fixture*`. Again,
this models other modern testing frameworks and allows the test to
directly access the already set up data related to the test suite.
3. Add the concept of test rules (from Junit). Rules are similar to the
before/after functions of the test suites but are global and run on all
suites. An example of a test rule can be to check that nothing was
logged to ERROR. The rule can cause the test to fail if anything was
logged to ERROR during an integration test. Another example would be a
rule that verifies that tests ran within some defined timeout.

Signed-off-by: Yuval Peress <peress@google.com>
This commit is contained in:
Yuval Peress 2021-10-20 14:01:43 -06:00 committed by Carles Cufí
parent 74faa18902
commit ab1caef8c3
22 changed files with 1504 additions and 352 deletions

View file

@ -141,4 +141,8 @@
#if defined(CONFIG_ZTEST)
ITERABLE_SECTION_RAM(ztest_suite_node, 4)
#if defined(CONFIG_ZTEST_NEW_API)
ITERABLE_SECTION_RAM(ztest_unit_test, 4)
ITERABLE_SECTION_RAM(ztest_test_rule, 4)
#endif /* CONFIG_ZTEST_NEW_API */
#endif /* CONFIG_ZTEST */

View file

@ -1 +1,2 @@
CONFIG_ZTEST=y
CONFIG_ZTEST_NEW_API=y

View file

@ -6,13 +6,16 @@
#include <ztest.h>
ZTEST_SUITE(framework_tests, NULL, NULL, NULL, NULL, NULL);
/**
* @brief Test Asserts
*
* This test verifies various assert macros provided by ztest.
*
*/
static void test_assert(void)
ZTEST(framework_tests, test_assert)
{
zassert_true(1, "1 was false");
zassert_false(0, "0 was true");
@ -21,12 +24,3 @@ static void test_assert(void)
zassert_equal(1, 1, "1 was not equal to 1");
zassert_equal_ptr(NULL, NULL, "NULL was not equal to NULL");
}
void test_main(void)
{
ztest_test_suite(framework_tests,
ztest_unit_test(test_assert)
);
ztest_run_test_suite(framework_tests);
}

View file

@ -1,2 +1,3 @@
CONFIG_ZTEST=y
CONFIG_ZTEST_NEW_API=y
CONFIG_IDLE_STACK_SIZE=4096

View file

@ -4,16 +4,10 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include <ztest.h>
void test_pytest(void)
ZTEST_SUITE(test_pytest, NULL, NULL, NULL, NULL, NULL);
ZTEST(test_pytest, test_pytest)
{
TC_PRINT("Hello world\n");
}
void test_main(void)
{
ztest_test_suite(test_pytest,
ztest_unit_test(test_pytest)
);
ztest_run_test_suite(test_pytest);
}

View file

@ -12,5 +12,17 @@ SECTIONS
KEEP(*(SORT_BY_NAME(._ztest_suite_node.static.*)))
_ztest_suite_node_list_end = .;
}
.data.ztest_unit_test_area : ALIGN(4)
{
_ztest_unit_test_list_start = .;
KEEP(*(SORT_BY_NAME(._ztest_unit_test.static.*)))
_ztest_unit_test_list_end = .;
}
.data.ztest_test_rule_area : ALIGN(4)
{
_ztest_test_rule_list_start = .;
KEEP(*(SORT_BY_NAME(._ztest_test_rule.static.*)))
_ztest_test_rule_list_end = .;
}
}
INSERT AFTER .data;

View file

@ -6,7 +6,9 @@ zephyr_include_directories(
)
zephyr_library()
zephyr_library_sources( src/ztest.c)
zephyr_library_sources( src/ztest_error_hook.c)
zephyr_library_sources_ifdef(CONFIG_ZTEST_MOCKING src/ztest_mock.c)
zephyr_library_sources_ifdef(CONFIG_ZTRESS src/ztress.c)
zephyr_library_sources_ifndef(CONFIG_ZTEST_NEW_API src/ztest.c)
zephyr_library_sources_ifdef(CONFIG_ZTEST_NEW_API src/ztest_new.c)
zephyr_library_sources( src/ztest_error_hook.c)
zephyr_library_sources_ifdef(CONFIG_ZTEST_NEW_API src/ztest_rules.c)
zephyr_library_sources_ifdef(CONFIG_ZTEST_MOCKING src/ztest_mock.c)
zephyr_library_sources_ifdef(CONFIG_ZTRESS src/ztress.c)

View file

@ -10,6 +10,12 @@ config ZTEST
if ZTEST
config ZTEST_NEW_API
bool "Use the new Ztest API"
help
Enables the new Ztest APIs for creating suites and unit tests in
separate compilational units as well as the new 'rules' API.
config ZTEST_STACKSIZE
int "Test function thread stack size"
default 2048 if COVERAGE_GCOV
@ -73,6 +79,20 @@ config ZTEST_ASSERT_HOOK
error test case. Remember to add ignore_fault tag in yaml file when
using twister to run testing.
if ZTEST_NEW_API
menu "ztest provided rules"
config ZTEST_RULE_1CPU
bool "Run all the tests on a single CPU"
help
This rule will call z_test_1cpu_start before each unit test and
ztest_1cpu_stop after each test.
endmenu
endif # ZTEST_NEW_API
endif # ZTEST
config ZTEST_MOCKING

View file

@ -1,302 +1,32 @@
/*
* Copyright (c) 2016 Intel Corporation
* Copyright (c) 2021 Google LLC
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
*
* @brief Zephyr testing framework _test.
*/
#ifndef ZEPHYR_TESTSUITE_INCLUDE_ZTEST_TEST_H_
#define ZEPHYR_TESTSUITE_INCLUDE_ZTEST_TEST_H_
#ifndef ZEPHYR_TESTSUITE_ZTEST_TEST_H_
#define ZEPHYR_TESTSUITE_ZTEST_TEST_H_
#include <app_memory/app_memdomain.h>
#include <init.h>
#include <stdbool.h>
#ifdef CONFIG_ZTEST_NEW_API
#include <ztest_test_new.h>
#else
#include <ztest_test_deprecated.h>
#endif /* !CONFIG_ZTEST_NEW_API */
#ifdef __cplusplus
extern "C" {
#endif
struct unit_test {
const char *name;
void (*test)(void);
void (*setup)(void);
void (*teardown)(void);
uint32_t thread_options;
};
/**
* Stats about a ztest suite
*/
struct ztest_suite_stats {
/** The number of times that the suite ran */
uint32_t run_count;
/** The number of times that the suite was skipped */
uint32_t skip_count;
/** The number of times that the suite failed */
uint32_t fail_count;
};
/**
* A single node of test suite. Each node should be added to a single linker section which will
* allow ztest_run_registered_test_suites() to iterate over the various nodes.
*/
struct ztest_suite_node {
/** The name of the test suite. */
const char *name;
/** Pointer to the test suite. */
struct unit_test *suite;
/**
* An optional predicate function to determine if the test should run. If NULL, then the
* test will only run once on the first attempt.
*
* @param state The current state of the test application.
* @return True if the suite should be run; false to skip.
*/
bool (*predicate)(const void *state);
/** Stats */
struct ztest_suite_stats stats;
};
extern struct ztest_suite_node _ztest_suite_node_list_start[];
extern struct ztest_suite_node _ztest_suite_node_list_end[];
/**
* Create and register a ztest suite. Using this macro creates a new test suite (using
* ztest_test_suite). It then creates a struct ztest_suite_node in a specific linker section.
*
* Tests can then be run by calling ztest_run_registered_test_suites(const void *state) by passing
* in the current state. See the documentation for ztest_run_registered_test_suites for more info.
*
* @param SUITE_NAME The name of the suite (see ztest_test_suite for more info)
* @param PREDICATE A function to test against the state and determine if the test should run.
* @param args Varargs placeholder for the remaining arguments passed for the unit tests.
*/
#define ztest_register_test_suite(SUITE_NAME, PREDICATE, args...) \
ztest_test_suite(SUITE_NAME, ##args); \
static STRUCT_SECTION_ITERABLE(ztest_suite_node, z_ztest_test_node_##SUITE_NAME) = { \
.name = #SUITE_NAME, \
.suite = _##SUITE_NAME, \
.predicate = PREDICATE, \
};
/**
* Run the registered unit tests which return true from their pragma function.
*
* @param state The current state of the machine as it relates to the test executable.
* @return The number of tests that ran.
*/
int ztest_run_registered_test_suites(const void *state);
/**
* @brief Fails the test if any of the registered tests did not run.
*
* When registering test suites, a pragma function can be provided to determine WHEN the test should
* run. It is possible that a test suite could be registered but the pragma always prevents it from
* running. In cases where a test should make sure that ALL suites ran at least once, this function
* may be called at the end of test_main(). It will cause the test to fail if any suite was
* registered but never ran.
*/
void ztest_verify_all_registered_test_suites_ran(void);
/**
* @brief Run a test suite.
*
* Internal implementation. Do not call directly. This will run the full test suite along with some
* checks for fast failures and initialization.
*
* @param name The name of the suite to run.
* @param suite Pointer to the first unit test.
* @return Negative value if the test suite never ran; otherwise, return the number of failures.
*/
int 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)
__syscall void z_test_1cpu_start(void);
__syscall void z_test_1cpu_stop(void);
/**
* @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
*/
#ifdef CONFIG_SMP
#define ztest_1cpu_unit_test(fn) \
ztest_unit_test_setup_teardown(fn, z_test_1cpu_start, z_test_1cpu_stop)
#else
#define ztest_1cpu_unit_test(fn) ztest_unit_test(fn)
#endif
/**
* @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
*/
#ifdef CONFIG_SMP
#define ztest_1cpu_user_unit_test(fn) \
ztest_user_unit_test_setup_teardown(fn, z_test_1cpu_start, z_test_1cpu_stop)
#else
#define ztest_1cpu_user_unit_test(fn) ztest_user_unit_test(fn)
#endif
/* definitions for use with testing application shared memory */
#ifdef CONFIG_USERSPACE
#define ZTEST_DMEM K_APP_DMEM(ztest_mem_partition)
#define ZTEST_BMEM K_APP_BMEM(ztest_mem_partition)
#define ZTEST_SECTION K_APP_DMEM_SECTION(ztest_mem_partition)
extern struct k_mem_partition ztest_mem_partition;
#else
#define ZTEST_DMEM
#define ZTEST_BMEM
#define ZTEST_SECTION .data
#endif
/**
* @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)
/**
* @}
*/
#ifndef ZTEST_UNITTEST
#include <syscalls/ztest_test.h>
#endif
#ifdef __cplusplus
}
#endif
#endif /* ZEPHYR_TESTSUITE_ZTEST_TEST_H_ */
#ifndef ZTEST_UNITTEST
#include <syscalls/ztest_test.h>
#endif
#endif /* ZEPHYR_TESTSUITE_INCLUDE_ZTEST_TEST_H_ */

View file

@ -0,0 +1,291 @@
/*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
*
* @brief Zephyr testing framework _test_deprecated.
*/
#ifndef ZEPHYR_TESTSUITE_ZTEST_TEST_H_
#define ZEPHYR_TESTSUITE_ZTEST_TEST_H_
#include <app_memory/app_memdomain.h>
#include <init.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
struct unit_test {
const char *name;
void (*test)(void);
void (*setup)(void);
void (*teardown)(void);
uint32_t thread_options;
};
/**
* Stats about a ztest suite
*/
struct ztest_suite_stats {
/** The number of times that the suite ran */
uint32_t run_count;
/** The number of times that the suite was skipped */
uint32_t skip_count;
/** The number of times that the suite failed */
uint32_t fail_count;
};
/**
* A single node of test suite. Each node should be added to a single linker section which will
* allow ztest_run_registered_test_suites() to iterate over the various nodes.
*/
struct ztest_suite_node {
/** The name of the test suite. */
const char *name;
/** Pointer to the test suite. */
struct unit_test *suite;
/**
* An optional predicate function to determine if the test should run. If NULL, then the
* test will only run once on the first attempt.
*
* @param state The current state of the test application.
* @return True if the suite should be run; false to skip.
*/
bool (*predicate)(const void *state);
/** Stats */
struct ztest_suite_stats stats;
};
extern struct ztest_suite_node _ztest_suite_node_list_start[];
extern struct ztest_suite_node _ztest_suite_node_list_end[];
/**
* Create and register a ztest suite. Using this macro creates a new test suite (using
* ztest_test_suite). It then creates a struct ztest_suite_node in a specific linker section.
*
* Tests can then be run by calling ztest_run_registered_test_suites(const void *state) by passing
* in the current state. See the documentation for ztest_run_registered_test_suites for more info.
*
* @param SUITE_NAME The name of the suite (see ztest_test_suite for more info)
* @param PREDICATE A function to test against the state and determine if the test should run.
* @param args Varargs placeholder for the remaining arguments passed for the unit tests.
*/
#define ztest_register_test_suite(SUITE_NAME, PREDICATE, args...) \
ztest_test_suite(SUITE_NAME, ##args); \
static STRUCT_SECTION_ITERABLE(ztest_suite_node, z_ztest_test_node_##SUITE_NAME) = { \
.name = #SUITE_NAME, \
.suite = _##SUITE_NAME, \
.predicate = PREDICATE, \
};
/**
* Run the registered unit tests which return true from their pragma function.
*
* @param state The current state of the machine as it relates to the test executable.
* @return The number of tests that ran.
*/
int ztest_run_registered_test_suites(const void *state);
/**
* @brief Fails the test if any of the registered tests did not run.
*
* When registering test suites, a pragma function can be provided to determine WHEN the test should
* run. It is possible that a test suite could be registered but the pragma always prevents it from
* running. In cases where a test should make sure that ALL suites ran at least once, this function
* may be called at the end of test_main(). It will cause the test to fail if any suite was
* registered but never ran.
*/
void ztest_verify_all_registered_test_suites_ran(void);
/**
* @brief Run a test suite.
*
* Internal implementation. Do not call directly. This will run the full test suite along with some
* checks for fast failures and initialization.
*
* @param name The name of the suite to run.
* @param suite Pointer to the first unit test.
* @return Negative value if the test suite never ran; otherwise, return the number of failures.
*/
int z_ztest_run_test_suite(const char *name, struct unit_test *suite);
/**
* @defgroup ztest_test_deprecated 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
*/
#ifdef CONFIG_SMP
#define ztest_1cpu_unit_test(fn) \
ztest_unit_test_setup_teardown(fn, z_test_1cpu_start, z_test_1cpu_stop)
#else
#define ztest_1cpu_unit_test(fn) ztest_unit_test(fn)
#endif
/**
* @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
*/
#ifdef CONFIG_SMP
#define ztest_1cpu_user_unit_test(fn) \
ztest_user_unit_test_setup_teardown(fn, z_test_1cpu_start, z_test_1cpu_stop)
#else
#define ztest_1cpu_user_unit_test(fn) ztest_user_unit_test(fn)
#endif
/* definitions for use with testing application shared memory */
#ifdef CONFIG_USERSPACE
#define ZTEST_DMEM K_APP_DMEM(ztest_mem_partition)
#define ZTEST_BMEM K_APP_BMEM(ztest_mem_partition)
#define ZTEST_SECTION K_APP_DMEM_SECTION(ztest_mem_partition)
extern struct k_mem_partition ztest_mem_partition;
#else
#define ZTEST_DMEM
#define ZTEST_BMEM
#define ZTEST_SECTION .data
#endif
/**
* @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 /* ZEPHYR_TESTSUITE_ZTEST_TEST_H_ */

View file

@ -0,0 +1,317 @@
/*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
*
* @brief Zephyr testing framework _test.
*/
#ifndef ZEPHYR_TESTSUITE_ZTEST_TEST_H_
#define ZEPHYR_TESTSUITE_ZTEST_TEST_H_
#include <app_memory/app_memdomain.h>
#include <init.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
struct ztest_unit_test {
const char *test_suite_name;
const char *name;
void (*test)(void *data);
uint32_t thread_options;
};
extern struct ztest_unit_test _ztest_unit_test_list_start[];
extern struct ztest_unit_test _ztest_unit_test_list_end[];
/**
* Stats about a ztest suite
*/
struct ztest_suite_stats {
/** The number of times that the suite ran */
uint32_t run_count;
/** The number of times that the suite was skipped */
uint32_t skip_count;
/** The number of times that the suite failed */
uint32_t fail_count;
};
/**
* A single node of test suite. Each node should be added to a single linker section which will
* allow ztest_run_test_suites() to iterate over the various nodes.
*/
struct ztest_suite_node {
/** The name of the test suite. */
const char *name;
/**
* Setup function to run before running this suite
*
* @return Pointer to the data structure that will be used throughout this test suite
*/
void *(*setup)(void);
/**
* Function to run before each test in this suite
*
* @param data The test suite's data returned from setup()
*/
void (*before)(void *data);
/**
* Function to run after each test in this suite
*
* @param data The test suite's data returned from setup()
*/
void (*after)(void *data);
/**
* Teardown function to run after running this suite
*
* @param data The test suite's data returned from setup()
*/
void (*teardown)(void *data);
/**
* An optional predicate function to determine if the test should run. If NULL, then the
* test will only run once on the first attempt.
*
* @param state The current state of the test application.
* @return True if the suite should be run; false to skip.
*/
bool (*predicate)(const void *state);
/** Stats */
struct ztest_suite_stats stats;
};
extern struct ztest_suite_node _ztest_suite_node_list_start[];
extern struct ztest_suite_node _ztest_suite_node_list_end[];
/**
* Create and register a ztest suite. Using this macro creates a new test suite (using
* ztest_test_suite). It then creates a struct ztest_suite_node in a specific linker section.
*
* Tests can then be run by calling ztest_run_test_suites(const void *state) by passing
* in the current state. See the documentation for ztest_run_test_suites for more info.
*
* @param SUITE_NAME The name of the suite (see ztest_test_suite for more info)
* @param PREDICATE A function to test against the state and determine if the test should run.
* @param setup_fn The setup function to call before running this test suite
* @param before_fn The function to call before each unit test in this suite
* @param after_fn The function to call after each unit test in this suite
* @param teardown_fn The function to call after running all the tests in this suite
*/
#define ZTEST_SUITE(SUITE_NAME, PREDICATE, setup_fn, before_fn, after_fn, teardown_fn) \
static STRUCT_SECTION_ITERABLE(ztest_suite_node, z_ztest_test_node_##SUITE_NAME) = { \
.name = #SUITE_NAME, \
.setup = (setup_fn), \
.before = (before_fn), \
.after = (after_fn), \
.teardown = (teardown_fn), \
.predicate = PREDICATE, \
}
/**
* Run the registered unit tests which return true from their pragma function.
*
* @param state The current state of the machine as it relates to the test executable.
* @return The number of tests that ran.
*/
int ztest_run_test_suites(const void *state);
/**
* @brief Fails the test if any of the registered tests did not run.
*
* When registering test suites, a pragma function can be provided to determine WHEN the test should
* run. It is possible that a test suite could be registered but the pragma always prevents it from
* running. In cases where a test should make sure that ALL suites ran at least once, this function
* may be called at the end of test_main(). It will cause the test to fail if any suite was
* registered but never ran.
*/
void ztest_verify_all_test_suites_ran(void);
/**
* @brief Run a test suite.
*
* Internal implementation. Do not call directly. This will run the full test suite along with some
* checks for fast failures and initialization.
*
* @param name The name of the suite to run.
* @return Negative value if the test suite never ran; otherwise, return the number of failures.
*/
int z_ztest_run_test_suite(const char *name);
/**
* @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)
{
}
#define Z_TEST(suite, fn, t_options, use_fixture) \
static void _##suite##_##fn##_wrapper(void *data); \
static void suite##_##fn( \
COND_CODE_1(use_fixture, (struct suite##_fixture *this), (void))); \
static STRUCT_SECTION_ITERABLE(ztest_unit_test, z_ztest_unit_test_##suite##_##fn) = { \
.test_suite_name = STRINGIFY(suite), \
.name = STRINGIFY(fn), \
.test = (_##suite##_##fn##_wrapper), \
.thread_options = t_options, \
}; \
static void _##suite##_##fn##_wrapper(void *data) \
{ \
COND_CODE_1(use_fixture, (suite##_##fn((struct suite##_fixture *)data);), \
(ARG_UNUSED(data); suite##_##fn();)) \
} \
static inline void suite##_##fn( \
COND_CODE_1(use_fixture, (struct suite##_fixture *this), (void)))
#define Z_ZTEST(suite, fn, t_options) Z_TEST(suite, fn, t_options, 0)
#define Z_ZTEST_F(suite, fn, t_options) Z_TEST(suite, fn, t_options, 1)
/**
* @brief Create and register a new unit test.
*
* Calling this macro will create a new unit test and attach it to the declared `suite`. The `suite`
* does not need to be defined in the same compilational unit.
*
* @param suite The name of the test suite to attach this test
* @param fn The test function to call.
*/
#define ZTEST(suite, fn) Z_ZTEST(suite, fn, 0)
/**
* @brief Define a test function that should run as a user thread
*
* This macro behaves exactly the same as ZTEST, but calls the test function in user space if
* `CONFIG_USERSPACE` was enabled.
*
* @param suite The name of the test suite to attach this test
* @param fn The test function to call.
*/
#define ZTEST_USER(suite, fn) Z_ZTEST(suite, fn, COND_CODE_1(CONFIG_USERSPACE, (K_USER), (0)))
/**
* @brief Define a test function
*
* This macro behaves exactly the same as ZTEST(), but the function takes an argument for the
* fixture of type `struct suite##_fixture*` named `this`.
*
* @param suite The name of the test suite to attach this test
* @param fn The test function to call.
*/
#define ZTEST_F(suite, fn) Z_ZTEST_F(suite, fn, 0)
/**
* @brief Define a test function that should run as a user thread
*
* If CONFIG_USERSPACE is not enabled, this is functionally identical to ZTEST_F(). The test
* function takes a single fixture argument of type `struct suite##_fixture*` named `this`.
*
* @param suite The name of the test suite to attach this test
* @param fn The test function to call.
*/
#define ZTEST_USER_F(suite, fn) Z_ZTEST_F(suite, fn, COND_CODE_1(CONFIG_USERSPACE, (K_USER), (0)))
typedef void (*ztest_rule_cb)(const struct ztest_unit_test *test, void *data);
struct ztest_test_rule {
ztest_rule_cb before_each;
ztest_rule_cb after_each;
};
#define ZTEST_RULE(name, before_each_fn, after_each_fn) \
static STRUCT_SECTION_ITERABLE(ztest_test_rule, z_ztest_test_rule_##name) = { \
.before_each = (before_each_fn), \
.after_each = (after_each_fn), \
}
extern struct ztest_test_rule _ztest_test_rule_list_start[];
extern struct ztest_test_rule _ztest_test_rule_list_end[];
/**
* @brief A 'before' function to use in test suites that just need to start 1cpu
*
* Ignores data, and calls z_test_1cpu_start()
*
* @param data The test suite's data
*/
void ztest_simple_1cpu_before(void *data);
/**
* @brief A 'after' function to use in test suites that just need to stop 1cpu
*
* Ignores data, and calls z_test_1cpu_stop()
*
* @param data The test suite's data
*/
void ztest_simple_1cpu_after(void *data);
/* definitions for use with testing application shared memory */
#ifdef CONFIG_USERSPACE
#define ZTEST_DMEM K_APP_DMEM(ztest_mem_partition)
#define ZTEST_BMEM K_APP_BMEM(ztest_mem_partition)
#define ZTEST_SECTION K_APP_DMEM_SECTION(ztest_mem_partition)
extern struct k_mem_partition ztest_mem_partition;
#else
#define ZTEST_DMEM
#define ZTEST_BMEM
#define ZTEST_SECTION .data
#endif
/**
* @brief Run the specified test suite.
*
* @param suite Test suite to run.
*/
#define ztest_run_test_suite(suite) z_ztest_run_test_suite(STRINGIFY(suite))
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* ZEPHYR_TESTSUITE_ZTEST_TEST_H_ */

View file

@ -0,0 +1,627 @@
/*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <ztest.h>
#include <stdio.h>
#include <app_memory/app_memdomain.h>
#ifdef CONFIG_USERSPACE
#include <sys/libc-hooks.h>
#endif
#include <sys/reboot.h>
#include <logging/log_ctrl.h>
#ifdef KERNEL
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 */
ZTEST_DMEM enum {
TEST_PHASE_SETUP,
TEST_PHASE_BEFORE,
TEST_PHASE_TEST,
TEST_PHASE_AFTER,
TEST_PHASE_TEARDOWN,
TEST_PHASE_FRAMEWORK
} phase = TEST_PHASE_FRAMEWORK;
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 ztest_unit_test *test)
{
int ret = TC_PASS;
int mock_status;
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);
ret = TC_FAIL;
} else if (!ret && mock_status == 2) {
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;
char tname[CONFIG_THREAD_MAX_NAME_LEN];
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);
if (IS_ENABLED(CONFIG_THREAD_NAME)) {
snprintk(tname, CONFIG_THREAD_MAX_NAME_LEN, "cpuhold%02d", i);
k_thread_name_set(&cpuhold_threads[i], tname);
}
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_rules(bool is_before, struct ztest_unit_test *test, void *data)
{
for (struct ztest_test_rule *rule = _ztest_test_rule_list_start;
rule < _ztest_test_rule_list_end; ++rule) {
if (is_before && rule->before_each) {
rule->before_each(test, data);
} else if (!is_before && rule->after_each) {
rule->after_each(test, data);
}
}
}
static void run_test_functions(struct ztest_suite_node *suite, struct ztest_unit_test *test,
void *data)
{
phase = TEST_PHASE_TEST;
test->test(data);
}
#ifndef KERNEL
/* Static code analysis tool can raise a violation that the standard header
* <setjmp.h> shall not be used.
*
* setjmp is using in a test code, not in a runtime code, it is acceptable.
* It is a deliberate deviation.
*/
#include <setjmp.h> /* parasoft-suppress MISRAC2012-RULE_21_4-a MISRAC2012-RULE_21_4-b*/
#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 stack_fail;
void ztest_test_fail(void)
{
raise(SIGABRT);
}
void ztest_test_pass(void)
{
longjmp(test_pass, 1);
}
static void handle_signal(int sig)
{
static const char *const phase_str[] = {
"setup",
"unit test",
"teardown",
};
PRINT(" %s", strsignal(sig));
switch (phase) {
case TEST_PHASE_SETUP:
case TEST_PHASE_BEFORE:
case TEST_PHASE_TEST:
case TEST_PHASE_AFTER:
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 ztest_suite_node *suite, struct ztest_unit_test *test, void *data)
{
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;
}
run_test_functions(suite, test, data);
out:
ret |= cleanup_test(test);
Z_TC_END_RESULT(ret, test->name);
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();
}
void ztest_simple_1cpu_before(void *data)
{
ARG_UNUSED(data);
z_test_1cpu_start();
}
void ztest_simple_1cpu_after(void *data)
{
ARG_UNUSED(data);
z_test_1cpu_stop();
}
static void init_testing(void)
{
k_object_access_all_grant(&ztest_thread);
}
static void test_cb(void *a, void *b, void *c)
{
struct ztest_suite_node *suite = a;
struct ztest_unit_test *test = b;
test_result = 1;
run_test_functions(suite, test, c);
test_result = 0;
}
static int run_test(struct ztest_suite_node *suite, struct ztest_unit_test *test, void *data)
{
int ret = TC_PASS;
TC_START(test->name);
phase = TEST_PHASE_BEFORE;
if (suite->before) {
suite->before(data);
}
run_test_rules(/*is_before=*/true, test, data);
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, suite, test, data,
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(suite, test, data);
}
phase = TEST_PHASE_AFTER;
if (suite->after != NULL) {
suite->after(data);
}
run_test_rules(/*is_before=*/false, test, data);
phase = TEST_PHASE_FRAMEWORK;
/* Flush all logs in case deferred mode and default logging thread are used. */
while (IS_ENABLED(CONFIG_TEST_LOGGING_FLUSH_AFTER_TEST) &&
IS_ENABLED(CONFIG_LOG_PROCESS_THREAD) &&
log_data_pending()) {
k_msleep(100);
}
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 */
static struct ztest_suite_node *ztest_find_test_suite(const char *name)
{
struct ztest_suite_node *node;
for (node = _ztest_suite_node_list_start; node < _ztest_suite_node_list_end; ++node) {
if (strcmp(name, node->name) == 0) {
return node;
}
}
return NULL;
}
struct ztest_unit_test *ztest_get_next_test(const char *suite, struct ztest_unit_test *prev)
{
struct ztest_unit_test *test = (prev == NULL) ? _ztest_unit_test_list_start : prev + 1;
for (; test < _ztest_unit_test_list_end; ++test) {
if (strcmp(suite, test->test_suite_name) == 0) {
return test;
}
}
return NULL;
}
static int z_ztest_run_test_suite_ptr(struct ztest_suite_node *suite)
{
struct ztest_unit_test *test = NULL;
void *data = NULL;
int fail = 0;
if (test_status < 0) {
return test_status;
}
if (suite == NULL) {
test_status = 1;
return -1;
}
init_testing();
TC_SUITE_START(suite->name);
phase = TEST_PHASE_SETUP;
if (suite->setup != NULL) {
data = suite->setup();
}
while ((test = ztest_get_next_test(suite->name, test)) != NULL) {
fail += run_test(suite, test, data);
if (fail && FAIL_FAST) {
break;
}
}
TC_SUITE_END(suite->name, (fail > 0 ? TC_FAIL : TC_PASS));
phase = TEST_PHASE_TEARDOWN;
if (suite->teardown != NULL) {
suite->teardown(data);
}
test_status = (test_status || fail) ? 1 : 0;
return fail;
}
int z_ztest_run_test_suite(const char *name)
{
return z_ztest_run_test_suite_ptr(ztest_find_test_suite(name));
}
void end_report(void)
{
if (test_status) {
TC_END_REPORT(TC_FAIL);
} else {
TC_END_REPORT(TC_PASS);
}
}
#ifdef CONFIG_USERSPACE
K_APPMEM_PARTITION_DEFINE(ztest_mem_partition);
#endif
int ztest_run_test_suites(const void *state)
{
struct ztest_suite_node *ptr;
int count = 0;
for (ptr = _ztest_suite_node_list_start; ptr < _ztest_suite_node_list_end; ++ptr) {
struct ztest_suite_stats *stats = &ptr->stats;
bool should_run = true;
if (ptr->predicate != NULL) {
should_run = ptr->predicate(state);
} else {
/* If predicate is NULL, only run this test once. */
should_run = stats->run_count == 0;
}
if (should_run) {
int fail = z_ztest_run_test_suite_ptr(ptr);
count++;
stats->run_count++;
stats->fail_count += (fail != 0) ? 1 : 0;
} else {
stats->skip_count++;
}
}
return count;
}
void ztest_verify_all_test_suites_ran(void)
{
bool all_tests_run = true;
struct ztest_suite_node *ptr;
for (ptr = _ztest_suite_node_list_start; ptr < _ztest_suite_node_list_end; ++ptr) {
if (ptr->stats.run_count < 1) {
PRINT("ERROR: Test '%s' did not run.\n", ptr->name);
all_tests_run = false;
}
}
if (!all_tests_run) {
test_status = 1;
}
}
void __weak test_main(void)
{
ztest_run_test_suites(NULL);
ztest_verify_all_test_suites_ran();
}
#ifndef KERNEL
int main(void)
{
z_init_mock();
test_main();
end_report();
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

View file

@ -0,0 +1,23 @@
/*
* Copyright 2021 Google LLC
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <ztest.h>
#ifdef CONFIG_ZTEST_RULE_1CPU
static void one_cpu_rule_before_each(const struct ztest_unit_test *test, void *data)
{
ARG_UNUSED(test);
ARG_UNUSED(data);
z_test_1cpu_start();
}
static void one_cpu_rule_after_each(const struct ztest_unit_test *test, void *data)
{
ARG_UNUSED(test);
ARG_UNUSED(data);
z_test_1cpu_stop();
}
ZTEST_RULE(one_cpu, one_cpu_rule_before_each, one_cpu_rule_after_each);
#endif /* CONFIG_ZTEST_RULE_1CPU */

View file

@ -1,5 +1,6 @@
CONFIG_MAIN_THREAD_PRIORITY=5
CONFIG_ZTEST=y
CONFIG_ZTEST_NEW_API=y
CONFIG_TEST_USERSPACE=y
CONFIG_TEST_LOGGING_DEFAULTS=n
CONFIG_LOG=y

View file

@ -9,12 +9,3 @@
#include <string.h>
#include "test.inc"
void test_cxx(void);
void test_cc(void);
void test_main(void)
{
test_cc();
test_cxx();
}

View file

@ -627,20 +627,15 @@ static void test_log_panic(void)
mock_log_backend_validate(&backend1, true);
}
/* Disable backends because same suite may be excuted again but compiled by C++ */
static void log_api_suite_teardown(void)
/* Disable backends because same suite may be executed again but compiled by C++ */
static void log_api_suite_teardown(void *data)
{
ARG_UNUSED(data);
log_backend_disable(&backend1);
log_backend_disable(&backend2);
}
/*test case main entry*/
#if __cplusplus
extern "C" void test_cxx(void);
void test_cxx(void)
#else
void test_cc(void)
#endif
static void *log_api_suite_setup(void)
{
PRINT("Configuration:\n");
PRINT("\t Mode: %s\n",
@ -654,17 +649,35 @@ void test_cc(void)
#if __cplusplus
PRINT("\t C++: yes\n");
#endif
ztest_test_suite(test_log_api,
ztest_unit_test(test_log_various_messages),
ztest_unit_test(test_log_backend_runtime_filtering),
ztest_unit_test(test_log_overflow),
ztest_unit_test(test_log_arguments),
ztest_unit_test(test_log_from_declared_module),
ztest_unit_test(test_log_msg_dropped_notification),
ztest_unit_test(test_log_panic)
);
ztest_run_test_suite(test_log_api);
log_api_suite_teardown();
return NULL;
}
static void log_api_suite_before(void *data)
{
ARG_UNUSED(data);
while(LOG_PROCESS()) {
}
}
#define WRAP_TEST(test_name, suffix) \
ZTEST(test_log_api_##suffix, test_name##_##suffix) \
{ \
test_name(); \
}
#if __cplusplus
#define TEST_SUFFIX cxx
#else
#define TEST_SUFFIX cc
#endif
#define TEST_SUITE_NAME test_log_api_ ## TEST_SUFFIX
ZTEST_SUITE(TEST_SUITE_NAME, NULL, log_api_suite_setup,
log_api_suite_before, NULL, log_api_suite_teardown);
WRAP_TEST(test_log_various_messages, TEST_SUFFIX)
WRAP_TEST(test_log_backend_runtime_filtering, TEST_SUFFIX)
WRAP_TEST(test_log_overflow, TEST_SUFFIX)
WRAP_TEST(test_log_arguments, TEST_SUFFIX)
WRAP_TEST(test_log_from_declared_module, TEST_SUFFIX)
WRAP_TEST(test_log_msg_dropped_notification, TEST_SUFFIX)
WRAP_TEST(test_log_panic, TEST_SUFFIX)

View file

@ -2,7 +2,7 @@
cmake_minimum_required(VERSION 3.20.0)
if(BOARD STREQUAL unit_testing)
list(APPEND SOURCES src/main.c)
list(APPEND SOURCES src/main_deprecated.c)
find_package(ZephyrUnittest REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(base)
@ -10,6 +10,5 @@ else()
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(base)
FILE(GLOB app_sources src/*.c)
target_sources(app PRIVATE ${app_sources})
target_sources(app PRIVATE src/main.c)
endif()

View file

@ -1,2 +1,3 @@
CONFIG_ZTEST=y
CONFIG_ZTEST_NEW_API=y
CONFIG_ZTEST_ASSERT_VERBOSE=0

View file

@ -1,2 +1,3 @@
CONFIG_ZTEST=y
CONFIG_ZTEST_NEW_API=y
CONFIG_ZTEST_ASSERT_VERBOSE=1

View file

@ -1,2 +1,3 @@
CONFIG_ZTEST=y
CONFIG_ZTEST_NEW_API=y
CONFIG_ZTEST_ASSERT_VERBOSE=2

View file

@ -6,11 +6,13 @@
#include <ztest.h>
static void test_empty_test(void)
ZTEST_SUITE(framework_tests, NULL, NULL, NULL, NULL, NULL);
ZTEST(framework_tests, test_empty_test)
{
}
static void test_assert_tests(void)
ZTEST(framework_tests, test_assert_tests)
{
zassert_true(1, NULL);
zassert_false(0, NULL);
@ -20,7 +22,7 @@ static void test_assert_tests(void)
zassert_equal_ptr(NULL, NULL, NULL);
}
static void test_assert_mem_equal(void)
ZTEST(framework_tests, test_assert_mem_equal)
{
static const uint32_t expected[4] = {
0x1234,
@ -33,13 +35,94 @@ static void test_assert_mem_equal(void)
zassert_mem_equal(actual, expected, sizeof(expected), NULL);
}
void test_main(void)
{
ztest_test_suite(framework_tests,
ztest_unit_test(test_empty_test),
ztest_unit_test(test_assert_tests),
ztest_unit_test(test_assert_mem_equal)
);
/***************************************************************************************************
* Sample fixture tests
**************************************************************************************************/
ztest_run_test_suite(framework_tests);
struct fixture_tests_fixture {
};
static struct fixture_tests_fixture test_fixture;
static void *fixture_tests_setup(void)
{
return &test_fixture;
}
ZTEST_SUITE(fixture_tests, NULL, fixture_tests_setup, NULL, NULL, NULL);
ZTEST_F(fixture_tests, test_fixture_pointer)
{
zassert_equal_ptr(&test_fixture, this, "Test fixture should be at 0x%x but was at 0x%x",
&test_fixture, this);
}
/***************************************************************************************************
* Sample rule tests
**************************************************************************************************/
enum rule_state {
RULE_STATE_SETUP = 0,
RULE_STATE_BEFORE_EACH,
RULE_STATE_TEST,
RULE_STATE_AFTER_EACH,
};
struct rules_tests_fixture {
enum rule_state state;
};
static struct rules_tests_fixture rule_tests_fixture;
static void rule_before_each(const struct ztest_unit_test *test, void *data)
{
if (strcmp(test->test_suite_name, "rules_tests") == 0 &&
strcmp(test->name, "test_rules_before_after") == 0) {
struct rules_tests_fixture *fixture = data;
zassert_equal_ptr(&rule_tests_fixture, data,
"Data expected to point to rule_state");
zassert_equal(fixture->state, RULE_STATE_SETUP, "Unexpected state");
fixture->state = RULE_STATE_BEFORE_EACH;
}
}
static void rule_after_each(const struct ztest_unit_test *test, void *data)
{
if (strcmp(test->test_suite_name, "rules_tests") == 0 &&
strcmp(test->name, "test_rules_before_after") == 0) {
struct rules_tests_fixture *fixture = data;
zassert_equal_ptr(&rule_tests_fixture, data,
"Data expected to point to rule_state");
zassert_equal(fixture->state, RULE_STATE_TEST, "Unexpected state");
fixture->state = RULE_STATE_AFTER_EACH;
}
}
static void *rule_test_setup(void)
{
rule_tests_fixture.state = RULE_STATE_SETUP;
return &rule_tests_fixture;
}
static void rule_test_teardown(void *data)
{
struct rules_tests_fixture *fixture = data;
/*
* Normally, we wouldn't assert here, but it's the only way to test that the rule's
* after_each function was called.
*/
zassert_equal(fixture->state, RULE_STATE_AFTER_EACH, "Unexpected state");
}
ZTEST_RULE(verify_before_after_rule, rule_before_each, rule_after_each);
ZTEST_SUITE(rules_tests, NULL, rule_test_setup, NULL, NULL, rule_test_teardown);
ZTEST_F(rules_tests, test_rules_before_after)
{
zassert_equal(this->state, RULE_STATE_BEFORE_EACH, "Unexpected state");
this->state = RULE_STATE_TEST;
}

View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <ztest.h>
static void test_empty_test(void)
{
}
static void test_assert_tests(void)
{
zassert_true(1, NULL);
zassert_false(0, NULL);
zassert_is_null(NULL, NULL);
zassert_not_null("foo", NULL);
zassert_equal(1, 1, NULL);
zassert_equal_ptr(NULL, NULL, NULL);
}
static void test_assert_mem_equal(void)
{
static const uint32_t expected[4] = {
0x1234,
0x5678,
0x9ABC,
0xDEF0
};
uint32_t actual[4] = {0};
memcpy(actual, expected, sizeof(actual));
zassert_mem_equal(actual, expected, sizeof(expected), NULL);
}
void test_main(void)
{
ztest_test_suite(framework_tests,
ztest_unit_test(test_empty_test),
ztest_unit_test(test_assert_tests),
ztest_unit_test(test_assert_mem_equal)
);
ztest_run_test_suite(framework_tests);
}