userver: userver/utest/test_case_macros.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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)