Skip to content

Commit 5623f54

Browse files
legrand-gregshuenashif
authored andcommitted
fff: Add fff_extensions.h, RETURN_HANDLED_CONTEXT()
Add supplementary header <zephyr/fff_extensions.h>. Add macro to fff_extensions.h for simplifying definition of custom fake functions needing call-unique information for producing desired output data. When an array of custom fake context structures is defined and the return field within the first structure instance is registered with the standard SET_RETURN_SEQ() macro of FFF, the RETURN_HANDLED_CONTEXT() macro provides the inverse logic to recover the context structure for this called instance. The body of the custom fake handler is provided to the RETURN_HANDLED_CONTEXT() macro for appropriate execution and access to the custom fake parameters. A test suite is also provided to verify macro implementation and illustrate usage. It is at: zephyr/tests/subsys/testsuite/fff_fake_contexts/ This code was verified by: 1. (Pass) west build -p always \ -b unit_testing tests/subsys/testsuite/fff_fake_contexts/ && \ ./build/testbinary 2. (Pass) west build -p always \ -b native_posix tests/subsys/testsuite/fff_fake_contexts/ && \ ./build/zephyr/zephyr.exe 3. (Pass) ./scripts/twister -p unit_testing \ -T tests/subsys/testsuite/fff_fake_contexts/ 4. (Pass) ./scripts/twister -p native_posix \ -T tests/subsys/testsuite/fff_fake_contexts/ 5. (Pass) cd doc && build html-fast Fix #55246 Signed-off-by: Gregory Shue <[email protected]>
1 parent 2b66410 commit 5623f54

File tree

12 files changed

+658
-2
lines changed

12 files changed

+658
-2
lines changed

doc/develop/test/ztest.rst

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -520,13 +520,14 @@ Example output for a failed macro from
520520
.. doxygengroup:: ztest_assume
521521

522522

523-
.. _mocking-fff:
524-
525523
Ztress
526524
======
527525

528526
.. doxygengroup:: ztest_ztress
529527

528+
529+
.. _mocking-fff:
530+
530531
Mocking via FFF
531532
===============
532533

@@ -544,6 +545,9 @@ devicetree bindings for more information:
544545
- :dtcompatible:`zephyr,fake-can`
545546
- :dtcompatible:`zephyr,fake-eeprom`
546547

548+
Zephyr also has defined extensions to FFF for simplified declarations of fake functions.
549+
See :ref:`FFF Extensions <fff-extensions>`.
550+
547551
Customizing Test Output
548552
***********************
549553
The way output is presented when running tests can be customized.
@@ -594,4 +598,13 @@ For example
594598
$ zephyr.exe -test="fixture_tests::test_fixture_pointer,framework_tests::test_assert_mem_equal"
595599
$ zephyr.exe -test="framework_tests::*"
596600
601+
602+
.. _fff-extensions:
603+
604+
FFF Extensions
605+
**************
606+
607+
.. doxygengroup:: fff_extensions
608+
609+
597610
.. _FFF: https://github.com/meekrosoft/fff

doc/zephyr.doxyfile.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -925,6 +925,7 @@ INPUT = @ZEPHYR_BASE@/doc/_doxygen/mainpage.md \
925925
@ZEPHYR_BASE@/kernel/include/kernel_arch_interface.h \
926926
@ZEPHYR_BASE@/include/ \
927927
@ZEPHYR_BASE@/lib/libc/minimal/include/ \
928+
@ZEPHYR_BASE@/subsys/testsuite/include/ \
928929
@ZEPHYR_BASE@/subsys/testsuite/ztest/include/ \
929930
@ZEPHYR_BASE@/tests/kernel/
930931

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
* Copyright(c) 2023 Legrand North America, LLC.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/**
8+
* @file
9+
*
10+
* @brief Zephyr testing framework FFF extension macros
11+
*/
12+
13+
#ifndef ZEPHYR_SUBSYS_TESTSUITE_INCLUDE_ZEPHYR_FFF_EXTENSIONS_H_
14+
#define ZEPHYR_SUBSYS_TESTSUITE_INCLUDE_ZEPHYR_FFF_EXTENSIONS_H_
15+
16+
#include <zephyr/fff.h>
17+
#include <zephyr/sys/util.h> /* for CONTAINER_OF */
18+
19+
/**
20+
* @defgroup fff_extensions FFF extensions
21+
* @ingroup all_tests
22+
*
23+
* This module provides extensions to FFF for simplifying the
24+
* configuration and usage of fakes.
25+
*
26+
* @{
27+
*/
28+
29+
30+
/**
31+
* @brief Wrap custom fake body to extract defined context struct
32+
*
33+
* Add extension macro for simplified creation of
34+
* fake functions needing call-specific context data.
35+
*
36+
* This macro enables a fake to be implemented as follows and
37+
* requires no familiarity with the inner workings of FFF.
38+
*
39+
* @code
40+
* struct FUNCNAME##_custom_fake_context
41+
* {
42+
* struct instance * const instance;
43+
* int result;
44+
* };
45+
*
46+
* int FUNCNAME##_custom_fake(
47+
* const struct instance **instance_out)
48+
* {
49+
* RETURN_HANDLED_CONTEXT(
50+
* FUNCNAME,
51+
* struct FUNCNAME##_custom_fake_context,
52+
* result,
53+
* context,
54+
* {
55+
* if (context != NULL)
56+
* {
57+
* if (context->result == 0)
58+
* {
59+
* if (instance_out != NULL)
60+
* {
61+
* *instance_out = context->instance;
62+
* }
63+
* }
64+
* return context->result;
65+
* }
66+
* return FUNCNAME##_fake.return_val;
67+
* }
68+
* );
69+
* }
70+
* @endcode
71+
*
72+
* @param FUNCNAME Name of function being faked
73+
* @param CONTEXTTYPE type of custom defined fake context struct
74+
* @param RESULTFIELD name of field holding the return type & value
75+
* @param CONTEXTPTRNAME expected name of pointer to custom defined fake context struct
76+
* @param HANDLERBODY in-line custom fake handling logic
77+
*/
78+
79+
#define RETURN_HANDLED_CONTEXT(FUNCNAME, \
80+
CONTEXTTYPE, RESULTFIELD, CONTEXTPTRNAME, HANDLERBODY) \
81+
if (FUNCNAME##_fake.return_val_seq_len) { \
82+
CONTEXTTYPE * const contexts = \
83+
CONTAINER_OF(FUNCNAME##_fake.return_val_seq, \
84+
CONTEXTTYPE, RESULTFIELD); \
85+
size_t const seq_idx = (FUNCNAME##_fake.return_val_seq_idx < \
86+
FUNCNAME##_fake.return_val_seq_len) ? \
87+
FUNCNAME##_fake.return_val_seq_idx++ :\
88+
FUNCNAME##_fake.return_val_seq_idx - 1;\
89+
CONTEXTTYPE * const CONTEXTPTRNAME = &contexts[seq_idx]; \
90+
HANDLERBODY; \
91+
} \
92+
return FUNCNAME##_fake.return_val
93+
94+
/**
95+
* @}
96+
*/
97+
98+
#endif /* ZEPHYR_SUBSYS_TESTSUITE_INCLUDE_ZEPHYR_FFF_EXTENSIONS_H_ */
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Copyright (c) 2023 Legrand North America, LLC.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
cmake_minimum_required(VERSION 3.20.0)
5+
if(BOARD STREQUAL unit_testing)
6+
find_package(Zephyr COMPONENTS unittest REQUIRED HINTS $ENV{ZEPHYR_BASE})
7+
set(target testbinary)
8+
else()
9+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
10+
set(target app)
11+
endif()
12+
13+
project(base)
14+
target_sources(${target} PRIVATE
15+
src/code_under_test.c
16+
src/main.c
17+
src/fakes/called_API.c
18+
)
19+
20+
target_include_directories(${target} PRIVATE
21+
${CMAKE_CURRENT_SOURCE_DIR}/src
22+
${CMAKE_CURRENT_SOURCE_DIR}/include
23+
)
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright (c) 2023 Legrand North America, LLC.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef ZEPHYR_TESTS_SUBSYS_TESTSUITE_FFF_FAKE_CONTEXTS_INCLUDE_ZEPHYR_CALLED_API_H_
8+
#define ZEPHYR_TESTS_SUBSYS_TESTSUITE_FFF_FAKE_CONTEXTS_INCLUDE_ZEPHYR_CALLED_API_H_
9+
10+
#include <errno.h>
11+
12+
#ifdef __cplusplus
13+
extern "C" {
14+
#endif
15+
16+
/* A container struct for hidden instance data */
17+
struct called_API_info;
18+
19+
/**
20+
* @brief Provide an instance handle to a session of the called_API.
21+
*
22+
* This API is defined for the code_under_test() example to call.
23+
* It represents a routine which provides call-unique data to the caller
24+
* as well as providing a return value. This requires the _custom_fake
25+
* implementation to serve the data from a custom_fake context struture,
26+
* where each call needs to return a unique, configured value.
27+
*
28+
* @param instance_out Session instance handle for caller to use.
29+
*
30+
* @return zero(0) upon success, with *instance_out updated.
31+
* @return -EINVAL if invalid parameter(s)
32+
* @return -E2BIG if more calls were made than expected.
33+
*/
34+
int called_API_open(const struct called_API_info **instance_out);
35+
36+
/**
37+
* @brief Return an instance handle to a session of the called_API.
38+
*
39+
* This API is defined for the code_under_test() example to call.
40+
* It represents a routine which requires specific data from the caller
41+
* as well as providing a return value. This is defined to
42+
* have the code_under_test call multiple functions to illustrate
43+
* a way to verify a specific calling sequence was made
44+
*
45+
* @param instance Session instance handle provided by called_API_open
46+
*
47+
* @return zero(0) upon success, with instance invalidated.
48+
* @return -EINVAL if invalid parameter(s)
49+
* @return -E2BIG if more calls were made than expected.
50+
*/
51+
int called_API_close(const struct called_API_info *instance);
52+
53+
#ifdef __cplusplus
54+
}
55+
#endif
56+
57+
#endif /* ZEPHYR_TESTS_SUBSYS_TESTSUITE_FFF_FAKE_CONTEXTS_INCLUDE_ZEPHYR_CALLED_API_H_ */
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright (c) 2023 Legrand North America, LLC.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef ZEPHYR_TESTS_SUBSYS_TESTSUITE_FFF_FAKE_CONTEXTS_INCLUDE_ZEPHYR_CODE_UNDER_TEST_H_
8+
#define ZEPHYR_TESTS_SUBSYS_TESTSUITE_FFF_FAKE_CONTEXTS_INCLUDE_ZEPHYR_CODE_UNDER_TEST_H_
9+
10+
#include <errno.h>
11+
12+
#ifdef __cplusplus
13+
extern "C" {
14+
#endif
15+
16+
/**
17+
* @brief Opens and closes called_API session twice
18+
*
19+
* This routine loops twice on opening/closing a called_API session.
20+
* Failures cause early termination of the loop, and the error number
21+
* from the called routine is returned by this routine. This routine
22+
* is designed for exercising custom_fake routines that need to use
23+
* call-specific data.
24+
*
25+
* @return zero(0) upon success
26+
* @return -EINVAL if invalid parameter(s)
27+
* @return -E2BIG if more calls were made than expected.
28+
*/
29+
int code_under_test(void);
30+
31+
#ifdef __cplusplus
32+
}
33+
#endif
34+
35+
#endif /* ZEPHYR_TESTS_SUBSYS_TESTSUITE_FFF_FAKE_CONTEXTS_INCLUDE_ZEPHYR_CODE_UNDER_TEST_H_ */
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Copyright (c) 2023 Legrand North America, LLC.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
CONFIG_ZTEST=y
5+
CONFIG_ZTEST_NEW_API=y
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright (c) 2023 Legrand North America, LLC.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <stdio.h> /* NULL */
8+
#include <zephyr/called_API.h>
9+
#include <zephyr/code_under_test.h>
10+
11+
12+
int code_under_test(void)
13+
{
14+
int result = 0;
15+
16+
for (int i = 0; i < 2; ++i) {
17+
const struct called_API_info *called_API = NULL;
18+
19+
result = called_API_open(&called_API);
20+
if (result != 0) {
21+
break;
22+
}
23+
24+
result = called_API_close(called_API);
25+
if (result != 0) {
26+
break;
27+
}
28+
29+
}
30+
31+
return result;
32+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/*
2+
* Copyright (c) 2023 Legrand North America, LLC.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/fff.h>
8+
9+
#include "fakes/called_API.h"
10+
11+
DEFINE_FAKE_VALUE_FUNC(int, called_API_open, const struct called_API_info **);
12+
DEFINE_FAKE_VALUE_FUNC(int, called_API_close, const struct called_API_info *);
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright (c) 2023 Legrand North America, LLC.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef ZEPHYR_TESTS_SUBSYS_TESTSUITE_FFF_FAKE_CONTEXTS_FAKES_CALLED_API_H_
8+
#define ZEPHYR_TESTS_SUBSYS_TESTSUITE_FFF_FAKE_CONTEXTS_FAKES_CALLED_API_H_
9+
10+
#include <zephyr/fff.h>
11+
#include <zephyr/called_API.h>
12+
13+
#define ZEPHYR_CALLED_API_FFF_FAKES_LIST(FAKE) \
14+
FAKE(called_API_open) \
15+
FAKE(called_API_close) \
16+
17+
18+
#ifdef __cplusplus
19+
extern "C" {
20+
#endif
21+
22+
DECLARE_FAKE_VALUE_FUNC(int, called_API_open, const struct called_API_info **);
23+
DECLARE_FAKE_VALUE_FUNC(int, called_API_close, const struct called_API_info *);
24+
25+
#ifdef __cplusplus
26+
}
27+
#endif
28+
29+
#endif /* ZEPHYR_TESTS_SUBSYS_TESTSUITE_FFF_FAKE_CONTEXTS_FAKES_CALLED_API_H_ */

0 commit comments

Comments
 (0)