summaryrefslogtreecommitdiff
path: root/src/mongo/unittest/death_test.h
diff options
context:
space:
mode:
authorBilly Donahue <billy.donahue@mongodb.com>2019-10-02 00:03:00 +0000
committerevergreen <evergreen@mongodb.com>2019-10-02 00:03:00 +0000
commit6adefc73b4990253e4f277b49b119db1a05b7490 (patch)
treecbad4fe8afa2418bd2b7b4bd33303b0e6be66bc6 /src/mongo/unittest/death_test.h
parentdfb22aca7b1e62693fd5272d37239a40000c3d0e (diff)
downloadmongo-6adefc73b4990253e4f277b49b119db1a05b7490.tar.gz
SERVER-43367 unittest framework refactor/fixes
- Segregate old-style dbtests into their own Suite initialization system: OldStyleSuiteSpecification. This is where the funky deprecated features can live on without interfering with the Suite API. It also gives us a searchable base class to identify them in the future. OldStyleSuite has `setupTests()` and an `add<T>()` that Suite does not have. Suite API can shrink when it doesn't have to support these dbtest adaptor features. Suite only needs non-template `add(name, callback)`. - Add OldStyleSuiteInitializer to some dbtests that were missing it! These didn't use SuiteInstance to register themselves and were incorrect. They would self register, resulting in _allSuites() holding a std::shared_ptr to a static-duration Suite object! - Change `getSuite()` to return `Suite&` instead of `Suite*`. - No more "self-registering" in Suite constructor. Registration must be done as a separate post-construction step. This removes some unusual lifetime management code and is easier to document. Suite::getSuite(name) is the only way to make a Suite, and it does the make_shared and registration calls with a pseudo-private ConstructorEnable idiom. - Suite->run() returns std::unique_ptr<Result> instead of raw `Result*`. It's virtual to support OldStyleSuite behavior. - Suite._ran does nothing. Removed. - Result.cur does nothing. Removed. - Switch to pass-by-value and std::move for most ctor args. - Add explicit on 1-arg ctors. - Get rid of TestHolder. It's just a 2-field struct. - use fmt instead of snprintf - TEST and TEST_F macros: generate TEST_TYPE once. - TEST and TEST_F macros: inline the _agent variable. - Mark _doRun as `override`. - Terminology: replace CASE_NAME with SUITE_NAME. - rename DeathTestImpl -> DeathTestBase - move getDeathTestPattern into the test as a static member function - refactor out some repetition from the comparator decl macros - use if-constexpr and diamond relops to clean up the ComparisonAssertion class. - dbtests: conditionally skip some add<T> calls - further dedup (DEATH_)TEST(_F) macros
Diffstat (limited to 'src/mongo/unittest/death_test.h')
-rw-r--r--src/mongo/unittest/death_test.h103
1 files changed, 49 insertions, 54 deletions
diff --git a/src/mongo/unittest/death_test.h b/src/mongo/unittest/death_test.h
index 9e1735b81e7..85e681a1a3a 100644
--- a/src/mongo/unittest/death_test.h
+++ b/src/mongo/unittest/death_test.h
@@ -29,13 +29,14 @@
#pragma once
+#include <functional>
#include <memory>
#include <string>
#include "mongo/unittest/unittest.h"
/**
- * Constructs a single death test named "TEST_NAME" within the test case "CASE_NAME".
+ * Constructs a single death test named `TEST_NAME` within the test suite `SUITE_NAME`.
*
* The test only succeeds if the process terminates abnormally, e.g. through an fassert
* failure or deadly signal.
@@ -44,77 +45,71 @@
* in your death test, start them in the test body, or use DEATH_TEST_F and start them
* in the setUp() method of the fixture.
*/
-#define DEATH_TEST(CASE_NAME, TEST_NAME, MATCH_EXPR) \
- class UNIT_TEST_DETAIL_TEST_TYPE_NAME(CASE_NAME, TEST_NAME) : public ::mongo::unittest::Test { \
- private: \
- virtual void _doTest(); \
- \
- static const RegistrationAgent< \
- ::mongo::unittest::DeathTest<UNIT_TEST_DETAIL_TEST_TYPE_NAME(CASE_NAME, TEST_NAME)>> \
- _agent; \
- }; \
- const ::mongo::unittest::Test::RegistrationAgent< \
- ::mongo::unittest::DeathTest<UNIT_TEST_DETAIL_TEST_TYPE_NAME(CASE_NAME, TEST_NAME)>> \
- UNIT_TEST_DETAIL_TEST_TYPE_NAME(CASE_NAME, TEST_NAME)::_agent(#CASE_NAME, #TEST_NAME); \
- std::string getDeathTestPattern(UNIT_TEST_DETAIL_TEST_TYPE_NAME(CASE_NAME, TEST_NAME)*) { \
- return MATCH_EXPR; \
- } \
- void UNIT_TEST_DETAIL_TEST_TYPE_NAME(CASE_NAME, TEST_NAME)::_doTest()
+#define DEATH_TEST(SUITE_NAME, TEST_NAME, MATCH_EXPR) \
+ DEATH_TEST_DEFINE_(SUITE_NAME, TEST_NAME, MATCH_EXPR, ::mongo::unittest::Test)
/**
* Constructs a single test named TEST_NAME that has access to a common fixture
- * named "FIXTURE_NAME".
+ * named `FIXTURE_NAME`, which will be used as the Suite name.
*
* See description of DEATH_TEST for more details on death tests.
*/
-#define DEATH_TEST_F(FIXTURE_NAME, TEST_NAME, MATCH_EXPR) \
- class UNIT_TEST_DETAIL_TEST_TYPE_NAME(FIXTURE_NAME, TEST_NAME) : public FIXTURE_NAME { \
- private: \
- virtual void _doTest(); \
- \
- static const RegistrationAgent<::mongo::unittest::DeathTest< \
- UNIT_TEST_DETAIL_TEST_TYPE_NAME(FIXTURE_NAME, TEST_NAME)>> \
- _agent; \
- }; \
- const ::mongo::unittest::Test::RegistrationAgent< \
- ::mongo::unittest::DeathTest<UNIT_TEST_DETAIL_TEST_TYPE_NAME(FIXTURE_NAME, TEST_NAME)>> \
- UNIT_TEST_DETAIL_TEST_TYPE_NAME(FIXTURE_NAME, TEST_NAME)::_agent(#FIXTURE_NAME, \
- #TEST_NAME); \
- std::string getDeathTestPattern(UNIT_TEST_DETAIL_TEST_TYPE_NAME(FIXTURE_NAME, TEST_NAME)*) { \
- return MATCH_EXPR; \
- } \
- void UNIT_TEST_DETAIL_TEST_TYPE_NAME(FIXTURE_NAME, TEST_NAME)::_doTest()
-
-namespace mongo {
-namespace unittest {
-
-class DeathTestImpl : public Test {
- DeathTestImpl(const DeathTestImpl&) = delete;
- DeathTestImpl& operator=(const DeathTestImpl&) = delete;
+#define DEATH_TEST_F(FIXTURE_NAME, TEST_NAME, MATCH_EXPR) \
+ DEATH_TEST_DEFINE_(FIXTURE_NAME, TEST_NAME, MATCH_EXPR, FIXTURE_NAME)
+#define DEATH_TEST_DEFINE_(SUITE_NAME, TEST_NAME, MATCH_EXPR, TEST_BASE) \
+ DEATH_TEST_DEFINE_PRIMITIVE_(SUITE_NAME, \
+ TEST_NAME, \
+ MATCH_EXPR, \
+ UNIT_TEST_DETAIL_TEST_TYPE_NAME(SUITE_NAME, TEST_NAME), \
+ TEST_BASE)
+
+#define DEATH_TEST_DEFINE_PRIMITIVE_(SUITE_NAME, TEST_NAME, MATCH_EXPR, TEST_TYPE, TEST_BASE) \
+ class TEST_TYPE : public TEST_BASE { \
+ public: \
+ static std::string getPattern() { \
+ return MATCH_EXPR; \
+ } \
+ \
+ private: \
+ void _doTest() override; \
+ static inline const RegistrationAgent<::mongo::unittest::DeathTest<TEST_TYPE>> _agent{ \
+ #SUITE_NAME, #TEST_NAME}; \
+ }; \
+ void TEST_TYPE::_doTest()
+
+namespace mongo::unittest {
+
+class DeathTestBase : public Test {
protected:
- explicit DeathTestImpl(std::function<std::unique_ptr<Test>()> makeTest);
+ DeathTestBase() = default;
private:
+ // Forks, executes _doMakeTest() in the child process to create a Test, then runs that Test.
void _doTest() final;
- virtual std::string getPattern() = 0;
- const std::function<std::unique_ptr<Test>()> _makeTest;
+
+ // Customization points for derived DeathTest classes.
+ virtual std::unique_ptr<Test> _doMakeTest() = 0;
+ virtual std::string _doGetPattern() = 0;
};
template <typename T>
-class DeathTest : public DeathTestImpl {
+class DeathTest : public DeathTestBase {
public:
- static const std::string pattern;
-
template <typename... Args>
- DeathTest(Args&&... args)
- : DeathTestImpl([args...]() { return std::make_unique<T>(args...); }) {}
+ explicit DeathTest(Args&&... args)
+ : _makeTest([args...] { return std::make_unique<T>(args...); }) {}
private:
- std::string getPattern() override {
- return getDeathTestPattern(static_cast<T*>(nullptr));
+ std::string _doGetPattern() override {
+ return T::getPattern();
+ }
+
+ std::unique_ptr<Test> _doMakeTest() override {
+ return _makeTest();
}
+
+ std::function<std::unique_ptr<Test>()> _makeTest;
};
-} // namespace unittest
-} // namespace mongo
+} // namespace mongo::unittest