Skip to content

Commit a9c5987

Browse files
jenswetmaribu
authored andcommitted
core/irq: Add C++ wrapper
1 parent 89ef35f commit a9c5987

File tree

11 files changed

+653
-0
lines changed

11 files changed

+653
-0
lines changed

pkg/fff/Makefile.include

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,6 @@ INCLUDES += -I$(PKGDIRBASE)/fff
33
# There's nothing to build in this package, it's used as a header only library.
44
# So it's declared as a pseudo-module
55
PSEUDOMODULES += fff
6+
7+
# Tests don't need pedantic. Pedantic throws errors in variadic macros when compiling for C++
8+
CXXEXFLAGS += -Wno-pedantic

sys/include/cppunit.hpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright (C) 2021 Jens Wetterich <[email protected]>
3+
*
4+
* This file is subject to the terms and conditions of the GNU Lesser
5+
* General Public License v2.1. See the file LICENSE in the top level
6+
* directory for more details.
7+
*/
8+
/**
9+
* @ingroup sys
10+
* @defgroup unittests_cpp C++ Unittests
11+
* @brief RIOT unit tests for C++
12+
* @details The C++ unit test framework syntax is loosely based on
13+
* GoogleTest, but offers far less functionality.
14+
* For mocking the package @ref pkg_fff can be used.
15+
* @{
16+
* @file
17+
* @brief RIOT unit tests for C++
18+
* @details The C++ unit test framework syntax is loosely based on GoogleTest,
19+
* but offers far less functionality.
20+
* For mocking the package @ref pkg_fff can be used.
21+
* @author Jens Wetterich <[email protected]>
22+
*
23+
*/
24+
#ifndef CPPUNIT_H
25+
#define CPPUNIT_H
26+
#if __cplusplus >= 201103L || defined(DOXYGEN)
27+
#include "cppunit/cppunit_base.hpp"
28+
#include "cppunit/cppunit_expect.hpp"
29+
#include "cppunit/cppunit_fff.hpp"
30+
#else
31+
#error This library needs C++11 and newer
32+
#endif
33+
#endif
34+
/** @} */
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
/*
2+
* Copyright (C) 2021 Jens Wetterich <[email protected]>
3+
*
4+
* This file is subject to the terms and conditions of the GNU Lesser
5+
* General Public License v2.1. See the file LICENSE in the top level
6+
* directory for more details.
7+
*/
8+
/**
9+
* @addtogroup unittests_cpp
10+
* @{
11+
* @file
12+
* @brief RIOT unit tests for C++ base classes and macros
13+
* @author Jens Wetterich <[email protected]>
14+
*
15+
*/
16+
#ifndef CPPUNIT_BASE_H
17+
#define CPPUNIT_BASE_H
18+
#if __cplusplus >= 201103L || defined(DOXYGEN)
19+
#include <array>
20+
#include <cstdio>
21+
#include <cstring>
22+
#include <type_traits>
23+
#ifndef CPPUNIT_SUITE_CNT
24+
/**
25+
* @brief Maximum amount of tests in one test suite
26+
*/
27+
#define CPPUNIT_SUITE_CNT (10)
28+
#endif
29+
/**
30+
* @brief RIOT C++ namespace
31+
*/
32+
namespace riot {
33+
/**
34+
* @brief namespace for cpp unit tests
35+
*/
36+
namespace testing {
37+
/**
38+
* @brief Test base class
39+
* @details Should not be instantiated directly.
40+
* @sa #TEST(suite, name) macro
41+
*/
42+
class test {
43+
private:
44+
bool suc = true; ///< indicates success of the test after running
45+
public:
46+
/**
47+
* @brief Run the test
48+
* @details Should not be called directly, only via macros
49+
* @sa #RUN_SUITE(name)
50+
* @return whether the test completed without errors
51+
*/
52+
virtual bool run() = 0;
53+
/**
54+
* @brief Indicate failure during test run
55+
* @details Should be called by assertions macros
56+
* @sa #EXPECT_EQ(expected, actual, msg)
57+
* @sa #EXPECT_STREQ(expected, actual, msg)
58+
* @sa #EXPECT_FFF_CALL_COUNT(name, count)
59+
* @sa #EXPECT_FFF_CALL_PARAMS(mock, ...)
60+
*/
61+
void fail() {
62+
suc = false;
63+
}
64+
/**
65+
* @brief Check whether the test completed successfully
66+
* @return whether the test completed without errors
67+
*/
68+
bool success() const {
69+
return suc;
70+
}
71+
};
72+
/**
73+
* @brief Test suite base class
74+
* @details Should not be instantiated directly.
75+
* To customize a test suite with custom set_up and tear down methods,
76+
* inherit from this class and override set_up() and/or tear_down().
77+
* They will before / after every test.
78+
* @sa #TEST_SUITE(name) macro
79+
* @sa #TEST_SUITE_F(suite, name) macro
80+
* @sa test_suite::set_up()
81+
* @sa test_suite::tear_down()
82+
*/
83+
class test_suite {
84+
protected:
85+
bool suc = true; ///< Indicates success of all tests after running the suite
86+
std::array<test*, CPPUNIT_SUITE_CNT> tests{}; ///< array of tests to run
87+
public:
88+
/**
89+
* @brief method to run before each test
90+
*/
91+
virtual void set_up() {
92+
}
93+
/**
94+
* @brief method to run after each test
95+
*/
96+
virtual void tear_down() {
97+
}
98+
/**
99+
* @brief get the name of the test suite
100+
* @return name string
101+
*/
102+
virtual const char* get_name() const {
103+
return "";
104+
};
105+
/**
106+
* @brief Run all tests in the suite
107+
*/
108+
virtual void run() {
109+
printf("----\nStarting Test suite %s\n", get_name());
110+
for (auto test : tests) {
111+
if (test) {
112+
suc = test->run() && suc;
113+
}
114+
}
115+
printf("Suite %s completed: %s\n----\n", get_name(), suc ? "SUCCESS" : "FAILURE");
116+
}
117+
/**
118+
* @brief Run all tests in the suite
119+
*/
120+
void addTest(test* test) {
121+
for (int i = 0; i < CPPUNIT_SUITE_CNT; i++) {
122+
if (!tests[i]) {
123+
tests[i] = test;
124+
break;
125+
}
126+
}
127+
}
128+
};
129+
}// namespace testing
130+
}// namespace riot
131+
/**
132+
* @brief Run the test suite \a name
133+
* @hideinitializer
134+
* @param[in] name Name of the suite
135+
*/
136+
#define RUN_SUITE(name) test_suite_##name.run();
137+
138+
/**
139+
* @brief Instantiate a test suite with custom test fixture
140+
* @hideinitializer
141+
* @param[in] suite Name of the custom test fixture class
142+
* @param[in] name Instantiation name of the suite
143+
*/
144+
#define TEST_SUITE_F(suite, name) \
145+
static_assert(sizeof(#suite) > 1, "test fixture class must not be empty"); \
146+
static_assert(sizeof(#name) > 1, "test_suite name must not be empty"); \
147+
class test_suite_##name : public suite { \
148+
const char* get_name() const override { \
149+
return #name; \
150+
}; \
151+
}; \
152+
test_suite_##name test_suite_##name;
153+
154+
/**
155+
* @brief Instantiate a test suite
156+
* @hideinitializer
157+
* @param[in] name Instantiation name of the suite
158+
*/
159+
#define TEST_SUITE(name) TEST_SUITE_F(::riot::testing::test_suite, name)
160+
161+
/**
162+
* @brief Begin the definition of a test
163+
* @details Insert the test body after the macro
164+
* @hideinitializer
165+
* @param[in] suite Name of the suite to add the test to
166+
* @param[in] name Instantiation name of the test
167+
*/
168+
#define TEST(suite, name) \
169+
class Test_##name : public ::riot::testing::test { \
170+
private: \
171+
void test_body(); \
172+
\
173+
public: \
174+
Test_##name() { \
175+
test_suite_##suite.addTest(this); \
176+
} \
177+
bool run() { \
178+
test_suite_##suite.set_up(); \
179+
printf("Running test " #name "...\n"); \
180+
test_body(); \
181+
printf("Test " #name ": %s\n", success() ? "SUCCESS" : "FAILURE"); \
182+
test_suite_##suite.tear_down(); \
183+
return success(); \
184+
}; \
185+
}; \
186+
void Test_##name::test_body()
187+
#else
188+
#error This library needs C++11 and newer
189+
#endif
190+
#endif
191+
/** @} */
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright (C) 2021 Jens Wetterich <[email protected]>
3+
*
4+
* This file is subject to the terms and conditions of the GNU Lesser
5+
* General Public License v2.1. See the file LICENSE in the top level
6+
* directory for more details.
7+
*/
8+
/**
9+
* @addtogroup unittests_cpp
10+
* @{
11+
* @file
12+
* @brief RIOT unit tests for C++ assertion macros
13+
* @author Jens Wetterich <[email protected]>
14+
*
15+
*/
16+
#ifndef CPPUNIT_EXPECT_H
17+
#define CPPUNIT_EXPECT_H
18+
#if __cplusplus >= 201103L || defined(DOXYGEN)
19+
/**
20+
* @brief Expect equality of the \a actual and \a expected value
21+
* @hideinitializer
22+
* @param[in] expected Expected value
23+
* @param[in] actual Actual value
24+
* @param[in] msg Message to print in case of failure
25+
*/
26+
#define EXPECT_EQ(expected, actual, msg) \
27+
static_assert(std::is_integral<decltype(expected)>::value, \
28+
"EXPECT_EQ requires an integral type "); \
29+
if ((actual) != (expected)) { \
30+
fail(); \
31+
if (std::is_same<decltype(expected), bool>::value) { \
32+
printf("Expected: %s, actual: %s\n" msg "\n", (expected) ? "true" : "false", \
33+
(actual) ? "true" : "false"); \
34+
} \
35+
else if (std::is_unsigned<decltype(expected)>::value) { \
36+
printf("Expected: %u, actual: %u\n" msg "\n", static_cast<unsigned>(expected), \
37+
static_cast<unsigned>(actual)); \
38+
} \
39+
else { \
40+
printf("Expected: %d, actual: %d\n" msg "\n", static_cast<int>(expected), \
41+
static_cast<int>(actual)); \
42+
} \
43+
}
44+
/**
45+
* @brief Expect string equality of the \a actual and \a expected value
46+
* @details Interprets both values as const char* string
47+
* @hideinitializer
48+
* @param[in] expected Expected value
49+
* @param[in] actual Actual value
50+
* @param[in] msg Message to print in case of failure
51+
*/
52+
#define EXPECT_STREQ(expected, actual, msg) \
53+
auto expected_str = static_cast<const char*>(expected); \
54+
auto actual_str = static_cast<const char*>(actual); \
55+
if (strcmp(expected_str, actual_str) != 0) { \
56+
fail(); \
57+
printf(msg " not equal! Expected: %s, actual: %s\n", expected_str, actual_str); \
58+
}
59+
#else
60+
#error This library needs C++11 and newer
61+
#endif
62+
#endif
63+
/** @} */

0 commit comments

Comments
 (0)