1 
2 /**
3  *    Copyright (C) 2018-present MongoDB, Inc.
4  *
5  *    This program is free software: you can redistribute it and/or modify
6  *    it under the terms of the Server Side Public License, version 1,
7  *    as published by MongoDB, Inc.
8  *
9  *    This program is distributed in the hope that it will be useful,
10  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *    Server Side Public License for more details.
13  *
14  *    You should have received a copy of the Server Side Public License
15  *    along with this program. If not, see
16  *    <http://www.mongodb.com/licensing/server-side-public-license>.
17  *
18  *    As a special exception, the copyright holders give permission to link the
19  *    code of portions of this program with the OpenSSL library under certain
20  *    conditions as described in each individual source file and distribute
21  *    linked combinations including the program with the OpenSSL library. You
22  *    must comply with the Server Side Public License in all respects for
23  *    all of the code used other than as permitted herein. If you modify file(s)
24  *    with this exception, you may extend this exception to your version of the
25  *    file(s), but you are not obligated to do so. If you do not wish to do so,
26  *    delete this exception statement from your version. If you delete this
27  *    exception statement from all source files in the program, then also delete
28  *    it in the license file.
29  */
30 
31 /*
32  * A C++ unit testing framework.
33  *
34  * For examples of basic usage, see mongo/unittest/unittest_test.cpp.
35  */
36 
37 #pragma once
38 
39 #include <cmath>
40 #include <sstream>
41 #include <string>
42 #include <utility>
43 #include <vector>
44 
45 #include "mongo/base/status_with.h"
46 #include "mongo/logger/logstream_builder.h"
47 #include "mongo/logger/message_log_domain.h"
48 #include "mongo/stdx/functional.h"
49 #include "mongo/unittest/bson_test_util.h"
50 #include "mongo/unittest/unittest_helpers.h"
51 #include "mongo/util/assert_util.h"
52 #include "mongo/util/mongoutils/str.h"
53 
54 /**
55  * Fail unconditionally, reporting the given message.
56  */
57 #define FAIL(MESSAGE) ::mongo::unittest::TestAssertionFailure(__FILE__, __LINE__, MESSAGE).stream()
58 
59 /**
60  * Fails unless "EXPRESSION" is true.
61  */
62 #define ASSERT_TRUE(EXPRESSION) \
63     if (!(EXPRESSION))          \
64     FAIL("Expected: " #EXPRESSION)
65 #define ASSERT(EXPRESSION) ASSERT_TRUE(EXPRESSION)
66 
67 /**
68  * Fails if "EXPRESSION" is true.
69  */
70 #define ASSERT_FALSE(EXPRESSION) ASSERT(!(EXPRESSION))
71 
72 /**
73  * Asserts that a Status code is OK.
74  */
75 #define ASSERT_OK(EXPRESSION) ASSERT_EQUALS(::mongo::Status::OK(), (EXPRESSION))
76 
77 /**
78  * Asserts that a status code is anything but OK.
79  */
80 #define ASSERT_NOT_OK(EXPRESSION) ASSERT_NOT_EQUALS(::mongo::Status::OK(), (EXPRESSION))
81 
82 /*
83  * Binary comparison assertions.
84  */
85 #define ASSERT_EQUALS(a, b) ASSERT_EQ(a, b)
86 #define ASSERT_NOT_EQUALS(a, b) ASSERT_NE(a, b)
87 #define ASSERT_LESS_THAN(a, b) ASSERT_LT(a, b)
88 #define ASSERT_NOT_LESS_THAN(a, b) ASSERT_GTE(a, b)
89 #define ASSERT_GREATER_THAN(a, b) ASSERT_GT(a, b)
90 #define ASSERT_NOT_GREATER_THAN(a, b) ASSERT_LTE(a, b)
91 #define ASSERT_LESS_THAN_OR_EQUALS(a, b) ASSERT_LTE(a, b)
92 #define ASSERT_GREATER_THAN_OR_EQUALS(a, b) ASSERT_GTE(a, b)
93 
94 #define ASSERT_EQ(a, b) _ASSERT_COMPARISON(EQ, a, b)
95 #define ASSERT_NE(a, b) _ASSERT_COMPARISON(NE, a, b)
96 #define ASSERT_LT(a, b) _ASSERT_COMPARISON(LT, a, b)
97 #define ASSERT_LTE(a, b) _ASSERT_COMPARISON(LTE, a, b)
98 #define ASSERT_GT(a, b) _ASSERT_COMPARISON(GT, a, b)
99 #define ASSERT_GTE(a, b) _ASSERT_COMPARISON(GTE, a, b)
100 
101 /**
102  * Binary comparison utility macro.  Do not use directly.
103  */
104 #define _ASSERT_COMPARISON(COMPARISON, a, b)                                                       \
105     if (::mongo::unittest::ComparisonAssertion_##COMPARISON ca =                                   \
106             ::mongo::unittest::ComparisonAssertion_##COMPARISON(__FILE__, __LINE__, #a, #b, a, b)) \
107     ca.failure().stream()
108 
109 /**
110  * Approximate equality assertion. Useful for comparisons on limited precision floating point
111  * values.
112  */
113 #define ASSERT_APPROX_EQUAL(a, b, ABSOLUTE_ERR) ASSERT_LTE(std::abs((a) - (b)), ABSOLUTE_ERR)
114 
115 /**
116  * Verify that the evaluation of "EXPRESSION" throws an exception of type EXCEPTION_TYPE.
117  *
118  * If "EXPRESSION" throws no exception, or one that is neither of type "EXCEPTION_TYPE" nor
119  * of a subtype of "EXCEPTION_TYPE", the test is considered a failure and further evaluation
120  * halts.
121  */
122 #define ASSERT_THROWS(STATEMENT, EXCEPTION_TYPE) \
123     ASSERT_THROWS_WITH_CHECK(STATEMENT, EXCEPTION_TYPE, ([](const EXCEPTION_TYPE&) {}))
124 
125 /**
126  * Behaves like ASSERT_THROWS, above, but also fails if calling what() on the thrown exception
127  * does not return a string equal to EXPECTED_WHAT.
128  */
129 #define ASSERT_THROWS_WHAT(STATEMENT, EXCEPTION_TYPE, EXPECTED_WHAT)                     \
130     ASSERT_THROWS_WITH_CHECK(STATEMENT, EXCEPTION_TYPE, ([&](const EXCEPTION_TYPE& ex) { \
131                                  ASSERT_EQ(::mongo::StringData(ex.what()),               \
132                                            ::mongo::StringData(EXPECTED_WHAT));          \
133                              }))
134 
135 /**
136  * Behaves like ASSERT_THROWS, above, but also fails if calling getCode() on the thrown exception
137  * does not return an error code equal to EXPECTED_CODE.
138  */
139 #define ASSERT_THROWS_CODE(STATEMENT, EXCEPTION_TYPE, EXPECTED_CODE)                     \
140     ASSERT_THROWS_WITH_CHECK(STATEMENT, EXCEPTION_TYPE, ([&](const EXCEPTION_TYPE& ex) { \
141                                  ASSERT_EQ(ex.toStatus().code(), EXPECTED_CODE);         \
142                              }))
143 
144 /**
145  * Behaves like ASSERT_THROWS, above, but also fails if calling getCode() on the thrown exception
146  * does not return an error code equal to EXPECTED_CODE or if calling what() on the thrown exception
147  * does not return a string equal to EXPECTED_WHAT.
148  */
149 #define ASSERT_THROWS_CODE_AND_WHAT(STATEMENT, EXCEPTION_TYPE, EXPECTED_CODE, EXPECTED_WHAT) \
150     ASSERT_THROWS_WITH_CHECK(STATEMENT, EXCEPTION_TYPE, ([&](const EXCEPTION_TYPE& ex) {     \
151                                  ASSERT_EQ(ex.toStatus().code(), EXPECTED_CODE);             \
152                                  ASSERT_EQ(::mongo::StringData(ex.what()),                   \
153                                            ::mongo::StringData(EXPECTED_WHAT));              \
154                              }))
155 
156 /**
157  * Behaves like ASSERT_THROWS, above, but also calls CHECK(caughtException) which may contain
158  * additional assertions.
159  */
160 #define ASSERT_THROWS_WITH_CHECK(STATEMENT, EXCEPTION_TYPE, CHECK)             \
161     do {                                                                       \
162         try {                                                                  \
163             STATEMENT;                                                         \
164             FAIL("Expected statement " #STATEMENT " to throw " #EXCEPTION_TYPE \
165                  " but it threw nothing.");                                    \
166         } catch (const EXCEPTION_TYPE& ex) {                                   \
167             CHECK(ex);                                                         \
168         }                                                                      \
169     } while (false)
170 
171 #define ASSERT_STRING_CONTAINS(BIG_STRING, CONTAINS)                                            \
172     do {                                                                                        \
173         std::string myString(BIG_STRING);                                                       \
174         std::string myContains(CONTAINS);                                                       \
175         if (myString.find(myContains) == std::string::npos) {                                   \
176             ::mongoutils::str::stream err;                                                      \
177             err << "Expected to find " #CONTAINS " (" << myContains << ") in " #BIG_STRING " (" \
178                 << myString << ")";                                                             \
179             ::mongo::unittest::TestAssertionFailure(__FILE__, __LINE__, err).stream();          \
180         }                                                                                       \
181     } while (false)
182 
183 /**
184  * Construct a single test, named "TEST_NAME" within the test case "CASE_NAME".
185  *
186  * Usage:
187  *
188  * TEST(MyModuleTests, TestThatFooFailsOnErrors) {
189  *     ASSERT_EQUALS(error_success, foo(invalidValue));
190  * }
191  */
192 #define TEST(CASE_NAME, TEST_NAME)                                                          \
193     class _TEST_TYPE_NAME(CASE_NAME, TEST_NAME) : public ::mongo::unittest::Test {          \
194     private:                                                                                \
195         virtual void _doTest();                                                             \
196                                                                                             \
197         static const RegistrationAgent<_TEST_TYPE_NAME(CASE_NAME, TEST_NAME)> _agent;       \
198     };                                                                                      \
199     const ::mongo::unittest::Test::RegistrationAgent<_TEST_TYPE_NAME(CASE_NAME, TEST_NAME)> \
200         _TEST_TYPE_NAME(CASE_NAME, TEST_NAME)::_agent(#CASE_NAME, #TEST_NAME);              \
201     void _TEST_TYPE_NAME(CASE_NAME, TEST_NAME)::_doTest()
202 
203 /**
204  * Construct a single test named TEST_NAME that has access to a common class (a "fixture")
205  * named "FIXTURE_NAME".
206  *
207  * Usage:
208  *
209  * class FixtureClass : public mongo::unittest::Test {
210  * protected:
211  *   int myVar;
212  *   void setUp() { myVar = 10; }
213  * };
214  *
215  * TEST(FixtureClass, TestThatUsesFixture) {
216  *     ASSERT_EQUALS(10, myVar);
217  * }
218  */
219 #define TEST_F(FIXTURE_NAME, TEST_NAME)                                                        \
220     class _TEST_TYPE_NAME(FIXTURE_NAME, TEST_NAME) : public FIXTURE_NAME {                     \
221     private:                                                                                   \
222         virtual void _doTest();                                                                \
223                                                                                                \
224         static const RegistrationAgent<_TEST_TYPE_NAME(FIXTURE_NAME, TEST_NAME)> _agent;       \
225     };                                                                                         \
226     const ::mongo::unittest::Test::RegistrationAgent<_TEST_TYPE_NAME(FIXTURE_NAME, TEST_NAME)> \
227         _TEST_TYPE_NAME(FIXTURE_NAME, TEST_NAME)::_agent(#FIXTURE_NAME, #TEST_NAME);           \
228     void _TEST_TYPE_NAME(FIXTURE_NAME, TEST_NAME)::_doTest()
229 
230 /**
231  * Macro to construct a type name for a test, from its "CASE_NAME" and "TEST_NAME".
232  * Do not use directly in test code.
233  */
234 #define _TEST_TYPE_NAME(CASE_NAME, TEST_NAME) UnitTest__##CASE_NAME##__##TEST_NAME
235 
236 namespace mongo {
237 
238 namespace unittest {
239 
240 class Result;
241 
242 /**
243  * Gets a LogstreamBuilder for logging to the unittest log domain, which may have
244  * different target from the global log domain.
245  */
246 mongo::logger::LogstreamBuilder log();
247 
248 /**
249  * Type representing the function composing a test.
250  */
251 typedef stdx::function<void(void)> TestFunction;
252 
253 /**
254  * Container holding a test function and its name.  Suites
255  * contain lists of these.
256  */
257 class TestHolder {
258     MONGO_DISALLOW_COPYING(TestHolder);
259 
260 public:
TestHolder(const std::string & name,const TestFunction & fn)261     TestHolder(const std::string& name, const TestFunction& fn) : _name(name), _fn(fn) {}
262 
~TestHolder()263     ~TestHolder() {}
run()264     void run() const {
265         _fn();
266     }
getName()267     std::string getName() const {
268         return _name;
269     }
270 
271 private:
272     std::string _name;
273     TestFunction _fn;
274 };
275 
276 /**
277  * Base type for unit test fixtures.  Also, the default fixture type used
278  * by the TEST() macro.
279  */
280 class Test {
281     MONGO_DISALLOW_COPYING(Test);
282 
283 public:
284     Test();
285     virtual ~Test();
286 
287     void run();
288 
289 protected:
290     /**
291      * Registration agent for adding tests to suites, used by TEST macro.
292      */
293     template <typename T>
294     class RegistrationAgent {
295         MONGO_DISALLOW_COPYING(RegistrationAgent);
296 
297     public:
298         RegistrationAgent(const std::string& suiteName, const std::string& testName);
299         std::string getSuiteName() const;
300         std::string getTestName() const;
301 
302     private:
303         const std::string _suiteName;
304         const std::string _testName;
305     };
306 
307     /**
308      * This exception class is used to exercise the testing framework itself. If a test
309      * case throws it, the framework would not consider it an error.
310      */
311     class FixtureExceptionForTesting : public std::exception {};
312 
313     /**
314      * Starts capturing messages logged by code under test.
315      *
316      * Log messages will still also go to their default destination; this
317      * code simply adds an additional sink for log messages.
318      *
319      * Clears any previously captured log lines.
320      */
321     void startCapturingLogMessages();
322 
323     /**
324      * Stops capturing log messages logged by code under test.
325      */
326     void stopCapturingLogMessages();
327 
328     /**
329      * Gets a vector of strings, one log line per string, captured since
330      * the last call to startCapturingLogMessages() in this test.
331      */
getCapturedLogMessages()332     const std::vector<std::string>& getCapturedLogMessages() const {
333         return _capturedLogMessages;
334     }
335 
336     /**
337      * Returns the number of collected log lines containing "needle".
338      */
339     int64_t countLogLinesContaining(const std::string& needle);
340 
341     /**
342      * Prints the captured log lines.
343      */
344     void printCapturedLogLines() const;
345 
346 private:
347     /**
348      * Called on the test object before running the test.
349      */
350     virtual void setUp();
351 
352     /**
353      * Called on the test object after running the test.
354      */
355     virtual void tearDown();
356 
357     /**
358      * The test itself.
359      */
360     virtual void _doTest() = 0;
361 
362     bool _isCapturingLogMessages;
363     std::vector<std::string> _capturedLogMessages;
364     logger::MessageLogDomain::AppenderHandle _captureAppenderHandle;
365     logger::MessageLogDomain::AppenderAutoPtr _captureAppender;
366 };
367 
368 /**
369  * Representation of a collection of tests.
370  *
371  * One suite is constructed for each "CASE_NAME" when using the TEST macro.
372  * Additionally, tests that are part of dbtests are manually assigned to suites
373  * by the programmer by overriding setupTests() in a subclass of Suite.  This
374  * approach is deprecated.
375  */
376 class Suite {
377     MONGO_DISALLOW_COPYING(Suite);
378 
379 public:
380     Suite(const std::string& name);
381     virtual ~Suite();
382 
383     template <class T>
add()384     void add() {
385         add<T>(demangleName(typeid(T)));
386     }
387 
388     template <class T, typename A>
add(const A & a)389     void add(const A& a) {
390         add(demangleName(typeid(T)), stdx::bind(&Suite::runTestObjectWithArg<T, A>, a));
391     }
392 
393     template <class T>
add(const std::string & name)394     void add(const std::string& name) {
395         add(name, &Suite::runTestObject<T>);
396     }
397 
398     void add(const std::string& name, const TestFunction& testFn);
399 
400     Result* run(const std::string& filter, int runsPerTest);
401 
402     static int run(const std::vector<std::string>& suites,
403                    const std::string& filter,
404                    int runsPerTest);
405 
406     /**
407      * Get a suite with the given name, creating it if necessary.
408      *
409      * The implementation of this function must be safe to call during the global static
410      * initialization block before main() executes.
411      */
412     static Suite* getSuite(const std::string& name);
413 
414 protected:
415     virtual void setupTests();
416 
417 private:
418     // TODO(C++11): Make this hold unique_ptrs.
419     typedef std::vector<std::shared_ptr<TestHolder>> TestHolderList;
420 
421     template <typename T>
runTestObject()422     static void runTestObject() {
423         T testObj;
424         testObj.run();
425     }
426 
427     template <typename T, typename A>
runTestObjectWithArg(const A & a)428     static void runTestObjectWithArg(const A& a) {
429         T testObj(a);
430         testObj.run();
431     }
432 
433     std::string _name;
434     TestHolderList _tests;
435     bool _ran;
436 
437     void registerSuite(const std::string& name, Suite* s);
438 };
439 
440 // A type that makes it easy to declare a self registering suite for old style test
441 // declarations. Suites are self registering so this is *not* a memory leak.
442 template <typename T>
443 struct SuiteInstance {
SuiteInstanceSuiteInstance444     SuiteInstance() {
445         new T;
446     }
447 
448     template <typename U>
SuiteInstanceSuiteInstance449     SuiteInstance(const U& u) {
450         new T(u);
451     }
452 };
453 
454 /**
455  * Exception thrown when a test assertion fails.
456  *
457  * Typically thrown by helpers in the TestAssertion class and its ilk, below.
458  *
459  * NOTE(schwerin): This intentionally does _not_ extend std::exception, so that code under
460  * test that (foolishly?) catches std::exception won't swallow test failures.  Doesn't
461  * protect you from code that foolishly catches ..., but you do what you can.
462  */
463 class TestAssertionFailureException {
464 public:
465     TestAssertionFailureException(const std::string& theFile,
466                                   unsigned theLine,
467                                   const std::string& theMessage);
468 
getFile()469     const std::string& getFile() const {
470         return _file;
471     }
getLine()472     unsigned getLine() const {
473         return _line;
474     }
getMessage()475     const std::string& getMessage() const {
476         return _message;
477     }
setMessage(const std::string & message)478     void setMessage(const std::string& message) {
479         _message = message;
480     }
481 
what()482     const std::string& what() const {
483         return getMessage();
484     }
485 
486     std::string toString() const;
487 
488 private:
489     std::string _file;
490     unsigned _line;
491     std::string _message;
492 };
493 
494 class TestAssertionFailure {
495 public:
496     TestAssertionFailure(const std::string& file, unsigned line, const std::string& message);
497     TestAssertionFailure(const TestAssertionFailure& other);
498     ~TestAssertionFailure() noexcept(false);
499 
500     TestAssertionFailure& operator=(const TestAssertionFailure& other);
501 
502     std::ostream& stream();
503 
504 private:
505     TestAssertionFailureException _exception;
506     std::ostringstream _stream;
507     bool _enabled;
508 };
509 
510 #define DECLARE_COMPARISON_ASSERTION(NAME, OPERATOR)                                          \
511     class ComparisonAssertion_##NAME {                                                        \
512         typedef void (ComparisonAssertion_##NAME::*bool_type)() const;                        \
513                                                                                               \
514     public:                                                                                   \
515         template <typename A, typename B>                                                     \
516         ComparisonAssertion_##NAME(const std::string& theFile,                                \
517                                    unsigned theLine,                                          \
518                                    StringData aExpression,                                    \
519                                    StringData bExpression,                                    \
520                                    const A& a,                                                \
521                                    const B& b) {                                              \
522             if (a OPERATOR b) {                                                               \
523                 return;                                                                       \
524             }                                                                                 \
525             std::ostringstream os;                                                            \
526             os << "Expected " << aExpression << " " #OPERATOR " " << bExpression << " (" << a \
527                << " " #OPERATOR " " << b << ")";                                              \
528             _assertion.reset(new TestAssertionFailure(theFile, theLine, os.str()));           \
529         }                                                                                     \
530         operator bool_type() const {                                                          \
531             return _assertion.get() ? &ComparisonAssertion_##NAME::comparison_failed : NULL;  \
532         }                                                                                     \
533         TestAssertionFailure failure() {                                                      \
534             return *_assertion;                                                               \
535         }                                                                                     \
536                                                                                               \
537     private:                                                                                  \
538         void comparison_failed() const {}                                                     \
539         std::shared_ptr<TestAssertionFailure> _assertion;                                     \
540     }
541 
542 DECLARE_COMPARISON_ASSERTION(EQ, ==);
543 DECLARE_COMPARISON_ASSERTION(NE, !=);
544 DECLARE_COMPARISON_ASSERTION(LT, <);
545 DECLARE_COMPARISON_ASSERTION(LTE, <=);
546 DECLARE_COMPARISON_ASSERTION(GT, >);
547 DECLARE_COMPARISON_ASSERTION(GTE, >=);
548 #undef DECLARE_COMPARISON_ASSERTION
549 
550 /**
551  * Get the value out of a StatusWith<T>, or throw an exception if it is not OK.
552  */
553 template <typename T>
assertGet(const StatusWith<T> & swt)554 const T& assertGet(const StatusWith<T>& swt) {
555     ASSERT_OK(swt.getStatus());
556     return swt.getValue();
557 }
558 
559 template <typename T>
assertGet(StatusWith<T> && swt)560 T assertGet(StatusWith<T>&& swt) {
561     ASSERT_OK(swt.getStatus());
562     return std::move(swt.getValue());
563 }
564 
565 /**
566  * Return a list of suite names.
567  */
568 std::vector<std::string> getAllSuiteNames();
569 
570 
alwaysTrue()571 inline bool alwaysTrue() {
572     return true;
573 }
574 
575 }  // namespace unittest
576 }  // namespace mongo
577 
578 #include "mongo/unittest/unittest-inl.h"
579