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