diff options
Diffstat (limited to 'src/mongo/unittest/unittest.h')
-rw-r--r-- | src/mongo/unittest/unittest.h | 738 |
1 files changed, 377 insertions, 361 deletions
diff --git a/src/mongo/unittest/unittest.h b/src/mongo/unittest/unittest.h index 030dd06681b..0ea7b8e4cc5 100644 --- a/src/mongo/unittest/unittest.h +++ b/src/mongo/unittest/unittest.h @@ -58,7 +58,9 @@ /** * Fails unless "EXPRESSION" is true. */ -#define ASSERT_TRUE(EXPRESSION) if (!(EXPRESSION)) FAIL("Expected: " #EXPRESSION) +#define ASSERT_TRUE(EXPRESSION) \ + if (!(EXPRESSION)) \ + FAIL("Expected: " #EXPRESSION) #define ASSERT(EXPRESSION) ASSERT_TRUE(EXPRESSION) /** @@ -79,8 +81,8 @@ /* * Binary comparison assertions. */ -#define ASSERT_EQUALS(a,b) ASSERT_EQ(a, b) -#define ASSERT_NOT_EQUALS(a,b) ASSERT_NE(a, b) +#define ASSERT_EQUALS(a, b) ASSERT_EQ(a, b) +#define ASSERT_NOT_EQUALS(a, b) ASSERT_NE(a, b) #define ASSERT_LESS_THAN(a, b) ASSERT_LT(a, b) #define ASSERT_NOT_LESS_THAN(a, b) ASSERT_GTE(a, b) #define ASSERT_GREATER_THAN(a, b) ASSERT_GT(a, b) @@ -88,8 +90,8 @@ #define ASSERT_LESS_THAN_OR_EQUALS(a, b) ASSERT_LTE(a, b) #define ASSERT_GREATER_THAN_OR_EQUALS(a, b) ASSERT_GTE(a, b) -#define ASSERT_EQ(a,b) _ASSERT_COMPARISON(EQ, a, b) -#define ASSERT_NE(a,b) _ASSERT_COMPARISON(NE, a, b) +#define ASSERT_EQ(a, b) _ASSERT_COMPARISON(EQ, a, b) +#define ASSERT_NE(a, b) _ASSERT_COMPARISON(NE, a, b) #define ASSERT_LT(a, b) _ASSERT_COMPARISON(LT, a, b) #define ASSERT_LTE(a, b) _ASSERT_COMPARISON(LTE, a, b) #define ASSERT_GT(a, b) _ASSERT_COMPARISON(GT, a, b) @@ -98,16 +100,16 @@ /** * Binary comparison utility macro. Do not use directly. */ -#define _ASSERT_COMPARISON(COMPARISON, a, b) \ - if (::mongo::unittest::ComparisonAssertion_##COMPARISON ca = ::mongo::unittest::ComparisonAssertion_##COMPARISON(__FILE__, __LINE__, #a, #b, a, b)) \ - ca.failure().stream() +#define _ASSERT_COMPARISON(COMPARISON, a, b) \ + if (::mongo::unittest::ComparisonAssertion_##COMPARISON ca = \ + ::mongo::unittest::ComparisonAssertion_##COMPARISON(__FILE__, __LINE__, #a, #b, a, b)) \ + ca.failure().stream() /** * Approximate equality assertion. Useful for comparisons on limited precision floating point * values. */ -#define ASSERT_APPROX_EQUAL(a, b, ABSOLUTE_ERR) \ - ASSERT_LTE(std::abs((a) - (b)), ABSOLUTE_ERR) +#define ASSERT_APPROX_EQUAL(a, b, ABSOLUTE_ERR) ASSERT_LTE(std::abs((a) - (b)), ABSOLUTE_ERR) /** * Verify that the evaluation of "EXPRESSION" throws an exception of type EXCEPTION_TYPE. @@ -116,19 +118,19 @@ * of a subtype of "EXCEPTION_TYPE", the test is considered a failure and further evaluation * halts. */ -#define ASSERT_THROWS(STATEMENT, EXCEPTION_TYPE) \ - ASSERT_THROWS_PRED(STATEMENT, \ - EXCEPTION_TYPE, \ - ::mongo::stdx::bind(::mongo::unittest::alwaysTrue)) +#define ASSERT_THROWS(STATEMENT, EXCEPTION_TYPE) \ + ASSERT_THROWS_PRED( \ + STATEMENT, EXCEPTION_TYPE, ::mongo::stdx::bind(::mongo::unittest::alwaysTrue)) /** * Behaves like ASSERT_THROWS, above, but also fails if calling what() on the thrown exception * does not return a string equal to EXPECTED_WHAT. */ -#define ASSERT_THROWS_WHAT(STATEMENT, EXCEPTION_TYPE, EXPECTED_WHAT) \ - ASSERT_THROWS_PRED(STATEMENT, \ - EXCEPTION_TYPE, \ - ::mongo::stdx::bind(std::equal_to<std::string>(), (EXPECTED_WHAT), \ +#define ASSERT_THROWS_WHAT(STATEMENT, EXCEPTION_TYPE, EXPECTED_WHAT) \ + ASSERT_THROWS_PRED(STATEMENT, \ + EXCEPTION_TYPE, \ + ::mongo::stdx::bind(std::equal_to<std::string>(), \ + (EXPECTED_WHAT), \ ::mongo::stdx::bind(&EXCEPTION_TYPE::what, \ ::mongo::stdx::placeholders::_1))) @@ -137,42 +139,38 @@ * does not return an error code equal to EXPECTED_CODE. */ #define ASSERT_THROWS_CODE(STATEMENT, EXCEPTION_TYPE, EXPECTED_CODE) \ - ASSERT_THROWS_PRED(STATEMENT, \ - EXCEPTION_TYPE, \ + ASSERT_THROWS_PRED(STATEMENT, \ + EXCEPTION_TYPE, \ ([](const EXCEPTION_TYPE& ex) { return (EXPECTED_CODE) == ex.getCode(); })) /** * Behaves like ASSERT_THROWS, above, but also fails if PREDICATE(ex) for the throw exception, ex, * is false. */ -#define ASSERT_THROWS_PRED(STATEMENT, EXCEPTION_TYPE, PREDICATE) do { \ - try { \ - STATEMENT; \ - FAIL("Expected statement " #STATEMENT \ - " to throw " #EXCEPTION_TYPE \ - " but it threw nothing."); \ - } catch (const EXCEPTION_TYPE& ex) { \ - if (!(PREDICATE(ex))) { \ - FAIL("Expected " #STATEMENT \ - " to throw an exception of type " \ - #EXCEPTION_TYPE \ - " where " #PREDICATE \ - "(ex) was true, but it was false."); \ - } \ - } \ +#define ASSERT_THROWS_PRED(STATEMENT, EXCEPTION_TYPE, PREDICATE) \ + do { \ + try { \ + STATEMENT; \ + FAIL("Expected statement " #STATEMENT " to throw " #EXCEPTION_TYPE \ + " but it threw nothing."); \ + } catch (const EXCEPTION_TYPE& ex) { \ + if (!(PREDICATE(ex))) { \ + FAIL("Expected " #STATEMENT " to throw an exception of type " #EXCEPTION_TYPE \ + " where " #PREDICATE "(ex) was true, but it was false."); \ + } \ + } \ } while (false) -#define ASSERT_STRING_CONTAINS(BIG_STRING, CONTAINS) do { \ - std::string myString( BIG_STRING ); \ - std::string myContains(CONTAINS); \ - if ( myString.find(myContains) == std::string::npos ) { \ - str::stream err; \ - err << "Expected to find " #CONTAINS " (" << myContains << \ - ") in " #BIG_STRING " (" << myString << ")"; \ - ::mongo::unittest::TestAssertionFailure(__FILE__, \ - __LINE__, \ - err).stream(); \ - } \ +#define ASSERT_STRING_CONTAINS(BIG_STRING, CONTAINS) \ + do { \ + std::string myString(BIG_STRING); \ + std::string myContains(CONTAINS); \ + if (myString.find(myContains) == std::string::npos) { \ + str::stream err; \ + err << "Expected to find " #CONTAINS " (" << myContains << ") in " #BIG_STRING " (" \ + << myString << ")"; \ + ::mongo::unittest::TestAssertionFailure(__FILE__, __LINE__, err).stream(); \ + } \ } while (false) /** @@ -184,15 +182,15 @@ * ASSERT_EQUALS(error_success, foo(invalidValue)); * } */ -#define TEST(CASE_NAME, TEST_NAME) \ - class _TEST_TYPE_NAME(CASE_NAME, TEST_NAME) : public ::mongo::unittest::Test { \ - private: \ - virtual void _doTest(); \ - \ - static const RegistrationAgent<_TEST_TYPE_NAME(CASE_NAME, TEST_NAME) > _agent; \ - }; \ - const ::mongo::unittest::Test::RegistrationAgent<_TEST_TYPE_NAME(CASE_NAME, TEST_NAME) > \ - _TEST_TYPE_NAME(CASE_NAME, TEST_NAME)::_agent(#CASE_NAME, #TEST_NAME); \ +#define TEST(CASE_NAME, TEST_NAME) \ + class _TEST_TYPE_NAME(CASE_NAME, TEST_NAME) : public ::mongo::unittest::Test { \ + private: \ + virtual void _doTest(); \ + \ + static const RegistrationAgent<_TEST_TYPE_NAME(CASE_NAME, TEST_NAME)> _agent; \ + }; \ + const ::mongo::unittest::Test::RegistrationAgent<_TEST_TYPE_NAME(CASE_NAME, TEST_NAME)> \ + _TEST_TYPE_NAME(CASE_NAME, TEST_NAME)::_agent(#CASE_NAME, #TEST_NAME); \ void _TEST_TYPE_NAME(CASE_NAME, TEST_NAME)::_doTest() /** @@ -211,330 +209,348 @@ * ASSERT_EQUALS(10, myVar); * } */ -#define TEST_F(FIXTURE_NAME, TEST_NAME) \ - class _TEST_TYPE_NAME(FIXTURE_NAME, TEST_NAME) : public FIXTURE_NAME { \ - private: \ - virtual void _doTest(); \ - \ - static const RegistrationAgent<_TEST_TYPE_NAME(FIXTURE_NAME, TEST_NAME) > _agent; \ - }; \ - const ::mongo::unittest::Test::RegistrationAgent<_TEST_TYPE_NAME(FIXTURE_NAME, TEST_NAME) > \ - _TEST_TYPE_NAME(FIXTURE_NAME, TEST_NAME)::_agent(#FIXTURE_NAME, #TEST_NAME); \ +#define TEST_F(FIXTURE_NAME, TEST_NAME) \ + class _TEST_TYPE_NAME(FIXTURE_NAME, TEST_NAME) : public FIXTURE_NAME { \ + private: \ + virtual void _doTest(); \ + \ + static const RegistrationAgent<_TEST_TYPE_NAME(FIXTURE_NAME, TEST_NAME)> _agent; \ + }; \ + const ::mongo::unittest::Test::RegistrationAgent<_TEST_TYPE_NAME(FIXTURE_NAME, TEST_NAME)> \ + _TEST_TYPE_NAME(FIXTURE_NAME, TEST_NAME)::_agent(#FIXTURE_NAME, #TEST_NAME); \ void _TEST_TYPE_NAME(FIXTURE_NAME, TEST_NAME)::_doTest() /** * Macro to construct a type name for a test, from its "CASE_NAME" and "TEST_NAME". * Do not use directly in test code. */ -#define _TEST_TYPE_NAME(CASE_NAME, TEST_NAME) \ - UnitTest__##CASE_NAME##__##TEST_NAME +#define _TEST_TYPE_NAME(CASE_NAME, TEST_NAME) UnitTest__##CASE_NAME##__##TEST_NAME namespace mongo { - namespace unittest { - - class Result; - - /** - * Gets a LogstreamBuilder for logging to the unittest log domain, which may have - * different target from the global log domain. - */ - mongo::logger::LogstreamBuilder log(); - - /** - * Type representing the function composing a test. - */ - typedef stdx::function<void (void)> TestFunction; - - /** - * Container holding a test function and its name. Suites - * contain lists of these. - */ - class TestHolder { - MONGO_DISALLOW_COPYING(TestHolder); - public: - TestHolder(const std::string& name, const TestFunction& fn) - : _name(name), _fn(fn) {} - - ~TestHolder() {} - void run() const { _fn(); } - std::string getName() const { return _name; } - - private: - std::string _name; - TestFunction _fn; - }; - - /** - * Base type for unit test fixtures. Also, the default fixture type used - * by the TEST() macro. - */ - class Test { - MONGO_DISALLOW_COPYING(Test); - public: - Test(); - virtual ~Test(); - - void run(); - - protected: - /** - * Registration agent for adding tests to suites, used by TEST macro. - */ - template <typename T> - class RegistrationAgent { - MONGO_DISALLOW_COPYING(RegistrationAgent); - public: - RegistrationAgent(const std::string& suiteName, const std::string& testName); - }; - - /** - * This exception class is used to exercise the testing framework itself. If a test - * case throws it, the framework would not consider it an error. - */ - class FixtureExceptionForTesting : public std::exception { - }; - - /** - * Starts capturing messages logged by code under test. - * - * Log messages will still also go to their default destination; this - * code simply adds an additional sink for log messages. - * - * Clears any previously captured log lines. - */ - void startCapturingLogMessages(); - - /** - * Stops capturing log messages logged by code under test. - */ - void stopCapturingLogMessages(); - - /** - * Gets a vector of strings, one log line per string, captured since - * the last call to startCapturingLogMessages() in this test. - */ - const std::vector<std::string>& getCapturedLogMessages() const { - return _capturedLogMessages; - } - - private: - /** - * Called on the test object before running the test. - */ - virtual void setUp(); - - /** - * Called on the test object after running the test. - */ - virtual void tearDown(); - - /** - * The test itself. - */ - virtual void _doTest() = 0; - - bool _isCapturingLogMessages; - std::vector<std::string> _capturedLogMessages; - logger::MessageLogDomain::AppenderHandle _captureAppenderHandle; - }; - - /** - * Representation of a collection of tests. - * - * One suite is constructed for each "CASE_NAME" when using the TEST macro. - * Additionally, tests that are part of dbtests are manually assigned to suites - * by the programmer by overriding setupTests() in a subclass of Suite. This - * approach is deprecated. - */ - class Suite { - MONGO_DISALLOW_COPYING(Suite); - public: - Suite( const std::string& name ); - virtual ~Suite(); - - template<class T> - void add() { add<T>(demangleName(typeid(T))); } - - template<class T , typename A > - void add( const A& a ) { - add(demangleName(typeid(T)), stdx::bind(&Suite::runTestObjectWithArg<T, A>, a)); - } - - template<class T> - void add(const std::string& name) { - add(name, &Suite::runTestObject<T>); - } - - void add(const std::string& name, const TestFunction& testFn); - - Result * run( const std::string& filter , int runsPerTest ); - - static int run( const std::vector<std::string>& suites , const std::string& filter , int runsPerTest ); - - /** - * Get a suite with the given name, creating it if necessary. - * - * The implementation of this function must be safe to call during the global static - * initialization block before main() executes. - */ - static Suite *getSuite(const std::string& name); - - protected: - virtual void setupTests(); - - private: - // TODO(C++11): Make this hold unique_ptrs. - typedef std::vector< std::shared_ptr<TestHolder> > TestHolderList; - - template <typename T> - static void runTestObject() { - T testObj; - testObj.run(); - } - - template <typename T, typename A> - static void runTestObjectWithArg(const A& a) { - T testObj(a); - testObj.run(); - } - - std::string _name; - TestHolderList _tests; - bool _ran; - - void registerSuite( const std::string& name , Suite* s ); - }; - - // A type that makes it easy to declare a self registering suite for old style test - // declarations. Suites are self registering so this is *not* a memory leak. - template<typename T> - struct SuiteInstance { - SuiteInstance() { - new T; - } - - template<typename U> - SuiteInstance(const U& u) { - new T(u); - } - }; - - /** - * Exception thrown when a test assertion fails. - * - * Typically thrown by helpers in the TestAssertion class and its ilk, below. - * - * NOTE(schwerin): This intentionally does _not_ extend std::exception, so that code under - * test that (foolishly?) catches std::exception won't swallow test failures. Doesn't - * protect you from code that foolishly catches ..., but you do what you can. - */ - class TestAssertionFailureException { - public: - TestAssertionFailureException(const std::string& theFile, - unsigned theLine, - const std::string& theMessage); - - const std::string& getFile() const { return _file; } - unsigned getLine() const { return _line; } - const std::string& getMessage() const { return _message; } - void setMessage(const std::string& message) { _message = message; } - - std::string toString() const; - - private: - std::string _file; - unsigned _line; - std::string _message; - }; - - class TestAssertionFailure { - public: - TestAssertionFailure( - const std::string& file, unsigned line, const std::string& message); - TestAssertionFailure(const TestAssertionFailure& other); - ~TestAssertionFailure() BOOST_NOEXCEPT_IF(false); - - TestAssertionFailure& operator=(const TestAssertionFailure& other); - - std::ostream& stream(); - private: - TestAssertionFailureException _exception; - std::ostringstream _stream; - bool _enabled; - }; - -#define DECLARE_COMPARISON_ASSERTION(NAME, OPERATOR) \ - class ComparisonAssertion_##NAME { \ - typedef void (ComparisonAssertion_##NAME::*bool_type)() const; \ - public: \ - template <typename A, typename B> \ - ComparisonAssertion_##NAME( \ - const std::string& theFile, \ - unsigned theLine, \ - StringData aExpression, \ - StringData bExpression, \ - const A& a, \ - const B& b) { \ - if (a OPERATOR b) { \ - return; \ - } \ - std::ostringstream os; \ - os << "Expected " << \ - aExpression << " " #OPERATOR " " << bExpression << \ - " (" << a << " " #OPERATOR " " << b << ")"; \ - _assertion.reset(new TestAssertionFailure( \ - theFile, \ - theLine, \ - os.str())); \ - } \ - operator bool_type() const { \ - return _assertion.get() ? &ComparisonAssertion_##NAME::comparison_failed : NULL; \ - } \ - TestAssertionFailure failure() { return *_assertion; } \ - private: \ - void comparison_failed() const {} \ - std::shared_ptr<TestAssertionFailure> _assertion; \ +namespace unittest { + +class Result; + +/** + * Gets a LogstreamBuilder for logging to the unittest log domain, which may have + * different target from the global log domain. + */ +mongo::logger::LogstreamBuilder log(); + +/** + * Type representing the function composing a test. + */ +typedef stdx::function<void(void)> TestFunction; + +/** + * Container holding a test function and its name. Suites + * contain lists of these. + */ +class TestHolder { + MONGO_DISALLOW_COPYING(TestHolder); + +public: + TestHolder(const std::string& name, const TestFunction& fn) : _name(name), _fn(fn) {} + + ~TestHolder() {} + void run() const { + _fn(); + } + std::string getName() const { + return _name; } -DECLARE_COMPARISON_ASSERTION(EQ, ==); -DECLARE_COMPARISON_ASSERTION(NE, !=); -DECLARE_COMPARISON_ASSERTION(LT, <); -DECLARE_COMPARISON_ASSERTION(LTE, <=); -DECLARE_COMPARISON_ASSERTION(GT, >); -DECLARE_COMPARISON_ASSERTION(GTE, >=); -#undef DECLARE_COMPARISON_ASSERTION +private: + std::string _name; + TestFunction _fn; +}; + +/** + * Base type for unit test fixtures. Also, the default fixture type used + * by the TEST() macro. + */ +class Test { + MONGO_DISALLOW_COPYING(Test); + +public: + Test(); + virtual ~Test(); + + void run(); + +protected: + /** + * Registration agent for adding tests to suites, used by TEST macro. + */ + template <typename T> + class RegistrationAgent { + MONGO_DISALLOW_COPYING(RegistrationAgent); + + public: + RegistrationAgent(const std::string& suiteName, const std::string& testName); + }; + + /** + * This exception class is used to exercise the testing framework itself. If a test + * case throws it, the framework would not consider it an error. + */ + class FixtureExceptionForTesting : public std::exception {}; + + /** + * Starts capturing messages logged by code under test. + * + * Log messages will still also go to their default destination; this + * code simply adds an additional sink for log messages. + * + * Clears any previously captured log lines. + */ + void startCapturingLogMessages(); + + /** + * Stops capturing log messages logged by code under test. + */ + void stopCapturingLogMessages(); + + /** + * Gets a vector of strings, one log line per string, captured since + * the last call to startCapturingLogMessages() in this test. + */ + const std::vector<std::string>& getCapturedLogMessages() const { + return _capturedLogMessages; + } + +private: + /** + * Called on the test object before running the test. + */ + virtual void setUp(); + + /** + * Called on the test object after running the test. + */ + virtual void tearDown(); + + /** + * The test itself. + */ + virtual void _doTest() = 0; + + bool _isCapturingLogMessages; + std::vector<std::string> _capturedLogMessages; + logger::MessageLogDomain::AppenderHandle _captureAppenderHandle; +}; + +/** + * Representation of a collection of tests. + * + * One suite is constructed for each "CASE_NAME" when using the TEST macro. + * Additionally, tests that are part of dbtests are manually assigned to suites + * by the programmer by overriding setupTests() in a subclass of Suite. This + * approach is deprecated. + */ +class Suite { + MONGO_DISALLOW_COPYING(Suite); + +public: + Suite(const std::string& name); + virtual ~Suite(); + + template <class T> + void add() { + add<T>(demangleName(typeid(T))); + } + + template <class T, typename A> + void add(const A& a) { + add(demangleName(typeid(T)), stdx::bind(&Suite::runTestObjectWithArg<T, A>, a)); + } + + template <class T> + void add(const std::string& name) { + add(name, &Suite::runTestObject<T>); + } + + void add(const std::string& name, const TestFunction& testFn); - /** - * Get the value out of a StatusWith<T>, or throw an exception if it is not OK. - */ - template <typename T> - const T& assertGet(const StatusWith<T>& swt) { - ASSERT_OK(swt.getStatus()); - return swt.getValue(); - } + Result* run(const std::string& filter, int runsPerTest); - template <typename T> - T assertGet(StatusWith<T>&& swt) { - ASSERT_OK(swt.getStatus()); - return std::move(swt.getValue()); - } + static int run(const std::vector<std::string>& suites, + const std::string& filter, + int runsPerTest); - /** - * Hack to support the runaway test observer in dbtests. This is a hook that - * unit test running harnesses (unittest_main and dbtests) must implement. - */ - void onCurrentTestNameChange( const std::string& testName ); + /** + * Get a suite with the given name, creating it if necessary. + * + * The implementation of this function must be safe to call during the global static + * initialization block before main() executes. + */ + static Suite* getSuite(const std::string& name); - /** - * Return a list of suite names. - */ - std::vector<std::string> getAllSuiteNames(); +protected: + virtual void setupTests(); + +private: + // TODO(C++11): Make this hold unique_ptrs. + typedef std::vector<std::shared_ptr<TestHolder>> TestHolderList; + + template <typename T> + static void runTestObject() { + T testObj; + testObj.run(); + } + + template <typename T, typename A> + static void runTestObjectWithArg(const A& a) { + T testObj(a); + testObj.run(); + } + + std::string _name; + TestHolderList _tests; + bool _ran; + + void registerSuite(const std::string& name, Suite* s); +}; + +// A type that makes it easy to declare a self registering suite for old style test +// declarations. Suites are self registering so this is *not* a memory leak. +template <typename T> +struct SuiteInstance { + SuiteInstance() { + new T; + } + + template <typename U> + SuiteInstance(const U& u) { + new T(u); + } +}; + +/** + * Exception thrown when a test assertion fails. + * + * Typically thrown by helpers in the TestAssertion class and its ilk, below. + * + * NOTE(schwerin): This intentionally does _not_ extend std::exception, so that code under + * test that (foolishly?) catches std::exception won't swallow test failures. Doesn't + * protect you from code that foolishly catches ..., but you do what you can. + */ +class TestAssertionFailureException { +public: + TestAssertionFailureException(const std::string& theFile, + unsigned theLine, + const std::string& theMessage); + + const std::string& getFile() const { + return _file; + } + unsigned getLine() const { + return _line; + } + const std::string& getMessage() const { + return _message; + } + void setMessage(const std::string& message) { + _message = message; + } + + std::string toString() const; + +private: + std::string _file; + unsigned _line; + std::string _message; +}; + +class TestAssertionFailure { +public: + TestAssertionFailure(const std::string& file, unsigned line, const std::string& message); + TestAssertionFailure(const TestAssertionFailure& other); + ~TestAssertionFailure() BOOST_NOEXCEPT_IF(false); + + TestAssertionFailure& operator=(const TestAssertionFailure& other); + + std::ostream& stream(); + +private: + TestAssertionFailureException _exception; + std::ostringstream _stream; + bool _enabled; +}; + +#define DECLARE_COMPARISON_ASSERTION(NAME, OPERATOR) \ + class ComparisonAssertion_##NAME { \ + typedef void (ComparisonAssertion_##NAME::*bool_type)() const; \ + \ + public: \ + template <typename A, typename B> \ + ComparisonAssertion_##NAME(const std::string& theFile, \ + unsigned theLine, \ + StringData aExpression, \ + StringData bExpression, \ + const A& a, \ + const B& b) { \ + if (a OPERATOR b) { \ + return; \ + } \ + std::ostringstream os; \ + os << "Expected " << aExpression << " " #OPERATOR " " << bExpression << " (" << a \ + << " " #OPERATOR " " << b << ")"; \ + _assertion.reset(new TestAssertionFailure(theFile, theLine, os.str())); \ + } \ + operator bool_type() const { \ + return _assertion.get() ? &ComparisonAssertion_##NAME::comparison_failed : NULL; \ + } \ + TestAssertionFailure failure() { \ + return *_assertion; \ + } \ + \ + private: \ + void comparison_failed() const {} \ + std::shared_ptr<TestAssertionFailure> _assertion; \ + } + +DECLARE_COMPARISON_ASSERTION(EQ, == ); +DECLARE_COMPARISON_ASSERTION(NE, != ); +DECLARE_COMPARISON_ASSERTION(LT, < ); +DECLARE_COMPARISON_ASSERTION(LTE, <= ); +DECLARE_COMPARISON_ASSERTION(GT, > ); +DECLARE_COMPARISON_ASSERTION(GTE, >= ); +#undef DECLARE_COMPARISON_ASSERTION + +/** + * Get the value out of a StatusWith<T>, or throw an exception if it is not OK. + */ +template <typename T> +const T& assertGet(const StatusWith<T>& swt) { + ASSERT_OK(swt.getStatus()); + return swt.getValue(); +} + +template <typename T> +T assertGet(StatusWith<T>&& swt) { + ASSERT_OK(swt.getStatus()); + return std::move(swt.getValue()); +} + +/** + * Hack to support the runaway test observer in dbtests. This is a hook that + * unit test running harnesses (unittest_main and dbtests) must implement. + */ +void onCurrentTestNameChange(const std::string& testName); + +/** + * Return a list of suite names. + */ +std::vector<std::string> getAllSuiteNames(); - inline bool alwaysTrue() { return true; } +inline bool alwaysTrue() { + return true; +} - } // namespace unittest +} // namespace unittest } // namespace mongo #include "mongo/unittest/unittest-inl.h" |