userver: userver/utest/test_case_macros.hpp Source File
Loading...
Searching...
No Matches
test_case_macros.hpp
1#pragma once
2
3#include <cstddef>
4#include <functional>
5#include <memory>
6#include <string>
7
8#include <gtest/gtest.h>
9
10USERVER_NAMESPACE_BEGIN
11
12namespace utest::impl {
13
14class EnrichedTestBase {
15public:
16 virtual ~EnrichedTestBase() = default;
17 virtual void SetUp() = 0;
18 virtual void TearDown() = 0;
19 virtual void TestBody() = 0;
20};
21
22enum class DeathTestsEnabled : bool {};
23
24// The work horse of the test suite. Takes a test class returned by 'factory'
25// in a 'std::unique_ptr' and runs the usual test cycle (mimicking gtest),
26// all in a coroutine environment.
27void DoRunTest(std::size_t thread_count, DeathTestsEnabled, std::function<std::unique_ptr<EnrichedTestBase>()> factory);
28
29void RunSetUpTestSuite(void (*set_up_test_suite)());
30void RunTearDownTestSuite(void (*tear_down_test_suite)());
31
32// Inherits from the user's fixture (or '::testing::Test') and makes the test
33// methods public ('SetUp', 'TearDown'). The fixture is further inherited from
34// (and "enriched") in inline-created test classes
35// (IMPL_UTEST_HIDE_ENRICHED_FROM_IDE).
36template <typename UserFixture>
37// NOLINTNEXTLINE(fuchsia-multiple-inheritance)
38class EnrichedFixture : public UserFixture, public EnrichedTestBase {
39protected:
40 void SetUp() override { return UserFixture::SetUp(); }
41 void TearDown() override { return UserFixture::TearDown(); }
42
43private:
44 using EnrichedTestBase::TestBody;
45};
46
47template <typename Base, typename UserFixture>
48class WithStaticMethods : public Base {
49public:
50 static void SetUpTestSuite() { RunSetUpTestSuite(&UserFixture::SetUpTestSuite); }
51
52 static void TearDownTestSuite() { RunTearDownTestSuite(&UserFixture::TearDownTestSuite); }
53};
54
55// 'TestLauncher' and 'TestLauncherParametric' take the enriched user's test
56// class and run it in a coroutine environment via 'DoRunTest'.
57template <typename UserFixture>
58class TestLauncher : public WithStaticMethods<::testing::Test, UserFixture> {
59public:
60 // Called from UTEST_F, TYPED_UTEST and TYPED_UTEST_P macros
61 template <typename EnrichedTest>
62 static void RunTest(std::size_t thread_count, bool death_tests_enabled) {
63 utest::impl::DoRunTest(thread_count, DeathTestsEnabled{death_tests_enabled}, [] {
64 return std::make_unique<EnrichedTest>();
65 });
66 }
67};
68
69template <typename UserFixture>
70class TestLauncherParametric
71 : public WithStaticMethods<::testing::TestWithParam<typename UserFixture::ParamType>, UserFixture> {
72public:
73 // Called from the UTEST_P macro
74 template <typename EnrichedTest>
75 static void RunTest(std::size_t thread_count, bool death_tests_enabled) {
76 using ParamType = typename UserFixture::ParamType;
77 const auto& parameter = ::testing::TestWithParam<ParamType>::GetParam();
78
79 // It seems impossible to seamlessly proxy 'ParamType' from the launcher to
80 // the enriched fixture without using gtest internals.
81 auto factory = std::make_unique<testing::internal::ParameterizedTestFactory<EnrichedTest>>(parameter);
82
83 utest::impl::DoRunTest(thread_count, DeathTestsEnabled{death_tests_enabled}, [&] {
84 return std::unique_ptr<EnrichedTest>{dynamic_cast<EnrichedTest*>(factory->CreateTest())};
85 });
86 }
87};
88
89template <template <typename> typename UserFixture, typename T>
90using TestLauncherTyped = TestLauncher<UserFixture<T>>;
91
92// For TYPED_TEST_SUITE and INSTANTIATE_TYPED_TEST_SUITE_P
93struct DefaultNameGenerator final {
94 template <typename T>
95 static std::string GetName(int i) {
96 return std::to_string(i);
97 }
98};
99
100constexpr bool CheckTestSuiteNameSuffix(std::string_view str, std::string_view suffix) {
101 return str.size() >= suffix.size() && str.substr(str.size() - suffix.size()) == suffix;
102}
103
104} // namespace utest::impl
105
106USERVER_NAMESPACE_END
107
108// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
109#define IMPL_UTEST_NON_PARENTHESIZED(identifier) identifier
110
111// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
112#define IMPL_UTEST_NAMESPACE_NAME(test_suite_name) test_suite_name##_##Utest
113
114// Enriched fixtures are nested into IMPL_UTEST_HIDE_ENRICHED_FROM_IDE namespace
115// so that IDEs don't find them and don't show in "Run a single Test".
116// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
117#define IMPL_UTEST_HIDE_ENRICHED_FROM_IDE(test_suite_name, test_name) test_suite_name##_##test_name##_##Utest
118
119// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
120#define IMPL_UTEST_USER_FIXTURE(test_suite_name) test_suite_name##_##UtestFixture
121
122// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
123#define IMPL_UTEST_MAKE_USER_FIXTURE_ALIAS(test_suite_name)
124 using IMPL_UTEST_USER_FIXTURE(test_suite_name) = IMPL_UTEST_NON_PARENTHESIZED(test_suite_name)
125
126// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
127#define IMPL_UTEST_MAKE_USER_FIXTURE_ALIAS_TYPED(test_suite_name)
128 template <typename UtestTypeParamImpl>
129 using IMPL_UTEST_USER_FIXTURE(test_suite_name) = IMPL_UTEST_NON_PARENTHESIZED(test_suite_name)<UtestTypeParamImpl>
130
131// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
132#define IMPL_UTEST_HIDE_USER_FIXTURE_BY_TEST_LAUNCHER(test_suite_name, test_launcher_template)
133 using IMPL_UTEST_NON_PARENTHESIZED(test_suite_name) = IMPL_UTEST_NON_PARENTHESIZED(test_launcher_template
134 )<IMPL_UTEST_USER_FIXTURE(test_suite_name)>;
135
136// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
137#define IMPL_UTEST_HIDE_USER_FIXTURE_BY_TEST_LAUNCHER_TYPED(test_suite_name)
138 template <typename UtestTypeParamImpl>
139 using IMPL_UTEST_NON_PARENTHESIZED(test_suite_name) = USERVER_NAMESPACE::utest::impl::TestLauncherTyped<
140 IMPL_UTEST_USER_FIXTURE(test_suite_name),
141 UtestTypeParamImpl>;
142
143// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
144#define IMPL_UTEST_TEST(test_suite_name, test_name, thread_count, death_tests_enabled)
145 struct IMPL_UTEST_HIDE_ENRICHED_FROM_IDE(test_suite_name, test_name) final {
146 class EnrichedTest final : public USERVER_NAMESPACE::utest::impl::EnrichedFixture<::testing::Test> {
147 void TestBody() override;
148 };
149 };
150 TEST(test_suite_name, test_name) {
151 using EnrichedTest = IMPL_UTEST_HIDE_ENRICHED_FROM_IDE(test_suite_name, test_name)::EnrichedTest;
152 USERVER_NAMESPACE::utest::impl::TestLauncher<::testing::Test>::RunTest<
153 EnrichedTest>(thread_count, death_tests_enabled);
154 }
155 void IMPL_UTEST_HIDE_ENRICHED_FROM_IDE(test_suite_name, test_name)::EnrichedTest::TestBody()
156
157// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
158#define IMPL_UTEST_ANY_BEGIN(test_suite_name, test_name, test_launcher_template)
159 IMPL_UTEST_MAKE_USER_FIXTURE_ALIAS(test_suite_name);
160 struct IMPL_UTEST_HIDE_ENRICHED_FROM_IDE(test_suite_name, test_name) final {
161 class EnrichedTest final
162 : public USERVER_NAMESPACE::utest::impl::EnrichedFixture<IMPL_UTEST_USER_FIXTURE(test_suite_name)> {
163 void TestBody() override;
164 };
165 };
166 /* The 'namespace' trick is used to make gtest use our 'test_launcher' \
167 * instead of 'test_suite_name' fixture */
168 namespace IMPL_UTEST_NAMESPACE_NAME(test_suite_name) {
169 IMPL_UTEST_HIDE_USER_FIXTURE_BY_TEST_LAUNCHER(test_suite_name, test_launcher_template)
170
171// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
172#define IMPL_UTEST_ANY_END(test_suite_name, test_name, thread_count, death_tests_enabled)
173 /* test header goes here */ {
174 using EnrichedTest = IMPL_UTEST_HIDE_ENRICHED_FROM_IDE(test_suite_name, test_name)::EnrichedTest;
175 this->RunTest<EnrichedTest>(thread_count, death_tests_enabled);
176 }
177 } /* namespace */
178 void IMPL_UTEST_HIDE_ENRICHED_FROM_IDE(test_suite_name, test_name)::EnrichedTest::TestBody()
179
180// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
181#define IMPL_UTEST_TEST_F(test_suite_name, test_name, thread_count, death_tests_enabled)
182 IMPL_UTEST_ANY_BEGIN(test_suite_name, test_name, USERVER_NAMESPACE::utest::impl::TestLauncher)
183 TEST_F(test_suite_name, test_name)
184 IMPL_UTEST_ANY_END(test_suite_name, test_name, thread_count, death_tests_enabled)
185
186// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
187#define IMPL_UTEST_TEST_P(test_suite_name, test_name, thread_count, death_tests_enabled)
188 IMPL_UTEST_ANY_BEGIN(test_suite_name, test_name, USERVER_NAMESPACE::utest::impl::TestLauncherParametric)
189 TEST_P(test_suite_name, test_name)
190 IMPL_UTEST_ANY_END(test_suite_name, test_name, thread_count, death_tests_enabled)
191
192// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
193#define IMPL_UTEST_TYPED_ANY_BEGIN(test_suite_name, test_name)
195 struct IMPL_UTEST_HIDE_ENRICHED_FROM_IDE(test_suite_name, test_name) final {
196 template <typename UtestTypeParamImpl>
197 using UtestUserFixture = IMPL_UTEST_USER_FIXTURE(test_suite_name)<UtestTypeParamImpl>;
198
199 template <typename UtestTypeParamImpl>
200 class EnrichedTest
201 : public USERVER_NAMESPACE::utest::impl::EnrichedFixture<UtestUserFixture<UtestTypeParamImpl>> {
202 using TypeParam = UtestTypeParamImpl;
203 using TestFixture = IMPL_UTEST_NON_PARENTHESIZED(test_suite_name)<TypeParam>;
204 void TestBody() override;
205 };
206 };
207 /* The 'namespace' trick is used to make gtest use our 'TestLauncher' \
208 * instead of 'test_suite_name' fixture */
209 namespace IMPL_UTEST_NAMESPACE_NAME(test_suite_name) {
210
211// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
212#define IMPL_UTEST_TYPED_ANY_END(test_suite_name, test_name, thread_count, death_tests_enabled)
213 /* test header goes here */ {
214 using EnrichedTest = IMPL_UTEST_HIDE_ENRICHED_FROM_IDE(test_suite_name, test_name)::EnrichedTest<TypeParam>;
215 this->template RunTest<EnrichedTest>(thread_count, death_tests_enabled);
216 }
217 } /* namespace */
218 template <typename UtestTypeParamImpl>
219 void IMPL_UTEST_HIDE_ENRICHED_FROM_IDE(test_suite_name, test_name)::EnrichedTest<UtestTypeParamImpl>::TestBody()
220
221// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
222#define IMPL_UTEST_TYPED_TEST(test_suite_name, test_name, thread_count, death_tests_enabled)
223 IMPL_UTEST_TYPED_ANY_BEGIN(test_suite_name, test_name)
224 TYPED_TEST(test_suite_name, test_name)
225 IMPL_UTEST_TYPED_ANY_END(test_suite_name, test_name, thread_count, death_tests_enabled)
226
227// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
228#define IMPL_UTEST_TYPED_TEST_P(test_suite_name, test_name, thread_count, death_tests_enabled)
229 IMPL_UTEST_TYPED_ANY_BEGIN(test_suite_name, test_name)
230 TYPED_TEST_P(test_suite_name, test_name)
231 IMPL_UTEST_TYPED_ANY_END(test_suite_name, test_name, thread_count, death_tests_enabled)