Home | History | Annotate | Download | only in test_lib_json
      1 // Copyright 2007-2010 Baptiste Lepilleur
      2 // Distributed under MIT license, or public domain if desired and
      3 // recognized in your jurisdiction.
      4 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
      5 
      6 #ifndef JSONTEST_H_INCLUDED
      7 #define JSONTEST_H_INCLUDED
      8 
      9 #include <json/config.h>
     10 #include <json/value.h>
     11 #include <json/writer.h>
     12 #include <stdio.h>
     13 #include <deque>
     14 #include <sstream>
     15 #include <string>
     16 
     17 // //////////////////////////////////////////////////////////////////
     18 // //////////////////////////////////////////////////////////////////
     19 // Mini Unit Testing framework
     20 // //////////////////////////////////////////////////////////////////
     21 // //////////////////////////////////////////////////////////////////
     22 
     23 /** \brief Unit testing framework.
     24  * \warning: all assertions are non-aborting, test case execution will continue
     25  *           even if an assertion namespace.
     26  *           This constraint is for portability: the framework needs to compile
     27  *           on Visual Studio 6 and must not require exception usage.
     28  */
     29 namespace JsonTest {
     30 
     31 class Failure {
     32 public:
     33   const char* file_;
     34   unsigned int line_;
     35   std::string expr_;
     36   std::string message_;
     37   unsigned int nestingLevel_;
     38 };
     39 
     40 /// Context used to create the assertion callstack on failure.
     41 /// Must be a POD to allow inline initialisation without stepping
     42 /// into the debugger.
     43 struct PredicateContext {
     44   typedef unsigned int Id;
     45   Id id_;
     46   const char* file_;
     47   unsigned int line_;
     48   const char* expr_;
     49   PredicateContext* next_;
     50   /// Related Failure, set when the PredicateContext is converted
     51   /// into a Failure.
     52   Failure* failure_;
     53 };
     54 
     55 class TestResult {
     56 public:
     57   TestResult();
     58 
     59   /// \internal Implementation detail for assertion macros
     60   /// Not encapsulated to prevent step into when debugging failed assertions
     61   /// Incremented by one on assertion predicate entry, decreased by one
     62   /// by addPredicateContext().
     63   PredicateContext::Id predicateId_;
     64 
     65   /// \internal Implementation detail for predicate macros
     66   PredicateContext* predicateStackTail_;
     67 
     68   void setTestName(const std::string& name);
     69 
     70   /// Adds an assertion failure.
     71   TestResult&
     72   addFailure(const char* file, unsigned int line, const char* expr = 0);
     73 
     74   /// Removes the last PredicateContext added to the predicate stack
     75   /// chained list.
     76   /// Next messages will be targed at the PredicateContext that was removed.
     77   TestResult& popPredicateContext();
     78 
     79   bool failed() const;
     80 
     81   void printFailure(bool printTestName) const;
     82 
     83   // Generic operator that will work with anything ostream can deal with.
     84   template <typename T> TestResult& operator<<(const T& value) {
     85     std::ostringstream oss;
     86     oss.precision(16);
     87     oss.setf(std::ios_base::floatfield);
     88     oss << value;
     89     return addToLastFailure(oss.str());
     90   }
     91 
     92   // Specialized versions.
     93   TestResult& operator<<(bool value);
     94   // std:ostream does not support 64bits integers on all STL implementation
     95   TestResult& operator<<(Json::Int64 value);
     96   TestResult& operator<<(Json::UInt64 value);
     97 
     98 private:
     99   TestResult& addToLastFailure(const std::string& message);
    100   unsigned int getAssertionNestingLevel() const;
    101   /// Adds a failure or a predicate context
    102   void addFailureInfo(const char* file,
    103                       unsigned int line,
    104                       const char* expr,
    105                       unsigned int nestingLevel);
    106   static std::string indentText(const std::string& text,
    107                                 const std::string& indent);
    108 
    109   typedef std::deque<Failure> Failures;
    110   Failures failures_;
    111   std::string name_;
    112   PredicateContext rootPredicateNode_;
    113   PredicateContext::Id lastUsedPredicateId_;
    114   /// Failure which is the target of the messages added using operator <<
    115   Failure* messageTarget_;
    116 };
    117 
    118 class TestCase {
    119 public:
    120   TestCase();
    121 
    122   virtual ~TestCase();
    123 
    124   void run(TestResult& result);
    125 
    126   virtual const char* testName() const = 0;
    127 
    128 protected:
    129   TestResult* result_;
    130 
    131 private:
    132   virtual void runTestCase() = 0;
    133 };
    134 
    135 /// Function pointer type for TestCase factory
    136 typedef TestCase* (*TestCaseFactory)();
    137 
    138 class Runner {
    139 public:
    140   Runner();
    141 
    142   /// Adds a test to the suite
    143   Runner& add(TestCaseFactory factory);
    144 
    145   /// Runs test as specified on the command-line
    146   /// If no command-line arguments are provided, run all tests.
    147   /// If --list-tests is provided, then print the list of all test cases
    148   /// If --test <testname> is provided, then run test testname.
    149   int runCommandLine(int argc, const char* argv[]) const;
    150 
    151   /// Runs all the test cases
    152   bool runAllTest(bool printSummary) const;
    153 
    154   /// Returns the number of test case in the suite
    155   unsigned int testCount() const;
    156 
    157   /// Returns the name of the test case at the specified index
    158   std::string testNameAt(unsigned int index) const;
    159 
    160   /// Runs the test case at the specified index using the specified TestResult
    161   void runTestAt(unsigned int index, TestResult& result) const;
    162 
    163   static void printUsage(const char* appName);
    164 
    165 private: // prevents copy construction and assignment
    166   Runner(const Runner& other);
    167   Runner& operator=(const Runner& other);
    168 
    169 private:
    170   void listTests() const;
    171   bool testIndex(const std::string& testName, unsigned int& index) const;
    172   static void preventDialogOnCrash();
    173 
    174 private:
    175   typedef std::deque<TestCaseFactory> Factories;
    176   Factories tests_;
    177 };
    178 
    179 template <typename T, typename U>
    180 TestResult& checkEqual(TestResult& result,
    181                        const T& expected,
    182                        const U& actual,
    183                        const char* file,
    184                        unsigned int line,
    185                        const char* expr) {
    186   if (static_cast<U>(expected) != actual) {
    187     result.addFailure(file, line, expr);
    188     result << "Expected: " << static_cast<U>(expected) << "\n";
    189     result << "Actual  : " << actual;
    190   }
    191   return result;
    192 }
    193 
    194 TestResult& checkStringEqual(TestResult& result,
    195                              const std::string& expected,
    196                              const std::string& actual,
    197                              const char* file,
    198                              unsigned int line,
    199                              const char* expr);
    200 
    201 } // namespace JsonTest
    202 
    203 /// \brief Asserts that the given expression is true.
    204 /// JSONTEST_ASSERT( x == y ) << "x=" << x << ", y=" << y;
    205 /// JSONTEST_ASSERT( x == y );
    206 #define JSONTEST_ASSERT(expr)                                                  \
    207   if (expr) {                                                                  \
    208   } else                                                                       \
    209   result_->addFailure(__FILE__, __LINE__, #expr)
    210 
    211 /// \brief Asserts that the given predicate is true.
    212 /// The predicate may do other assertions and be a member function of the
    213 /// fixture.
    214 #define JSONTEST_ASSERT_PRED(expr)                                             \
    215   {                                                                            \
    216     JsonTest::PredicateContext _minitest_Context = {                           \
    217       result_->predicateId_, __FILE__, __LINE__, #expr                         \
    218     };                                                                         \
    219     result_->predicateStackTail_->next_ = &_minitest_Context;                  \
    220     result_->predicateId_ += 1;                                                \
    221     result_->predicateStackTail_ = &_minitest_Context;                         \
    222     (expr);                                                                    \
    223     result_->popPredicateContext();                                            \
    224   }
    225 
    226 /// \brief Asserts that two values are equals.
    227 #define JSONTEST_ASSERT_EQUAL(expected, actual)                                \
    228   JsonTest::checkEqual(*result_,                                               \
    229                        expected,                                               \
    230                        actual,                                                 \
    231                        __FILE__,                                               \
    232                        __LINE__,                                               \
    233                        #expected " == " #actual)
    234 
    235 /// \brief Asserts that two values are equals.
    236 #define JSONTEST_ASSERT_STRING_EQUAL(expected, actual)                         \
    237   JsonTest::checkStringEqual(*result_,                                         \
    238                              std::string(expected),                            \
    239                              std::string(actual),                              \
    240                              __FILE__,                                         \
    241                              __LINE__,                                         \
    242                              #expected " == " #actual)
    243 
    244 /// \brief Asserts that a given expression throws an exception
    245 #define JSONTEST_ASSERT_THROWS(expr)                                           \
    246   {                                                                            \
    247     bool _threw = false;                                                       \
    248     try {                                                                      \
    249       expr;                                                                    \
    250     }                                                                          \
    251     catch (...) {                                                              \
    252       _threw = true;                                                           \
    253     }                                                                          \
    254     if (!_threw)                                                               \
    255       result_->addFailure(                                                     \
    256           __FILE__, __LINE__, "expected exception thrown: " #expr);            \
    257   }
    258 
    259 /// \brief Begin a fixture test case.
    260 #define JSONTEST_FIXTURE(FixtureType, name)                                    \
    261   class Test##FixtureType##name : public FixtureType {                         \
    262   public:                                                                      \
    263     static JsonTest::TestCase* factory() {                                     \
    264       return new Test##FixtureType##name();                                    \
    265     }                                                                          \
    266                                                                                \
    267   public: /* overidden from TestCase */                                        \
    268     virtual const char* testName() const { return #FixtureType "/" #name; }    \
    269     virtual void runTestCase();                                                \
    270   };                                                                           \
    271                                                                                \
    272   void Test##FixtureType##name::runTestCase()
    273 
    274 #define JSONTEST_FIXTURE_FACTORY(FixtureType, name)                            \
    275   &Test##FixtureType##name::factory
    276 
    277 #define JSONTEST_REGISTER_FIXTURE(runner, FixtureType, name)                   \
    278   (runner).add(JSONTEST_FIXTURE_FACTORY(FixtureType, name))
    279 
    280 #endif // ifndef JSONTEST_H_INCLUDED
    281