diff options
author | Billy Donahue <billy.donahue@mongodb.com> | 2019-10-02 00:03:00 +0000 |
---|---|---|
committer | evergreen <evergreen@mongodb.com> | 2019-10-02 00:03:00 +0000 |
commit | 6adefc73b4990253e4f277b49b119db1a05b7490 (patch) | |
tree | cbad4fe8afa2418bd2b7b4bd33303b0e6be66bc6 /src/mongo/unittest/death_test.h | |
parent | dfb22aca7b1e62693fd5272d37239a40000c3d0e (diff) | |
download | mongo-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.h | 103 |
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 |