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