jamie@264
|
1 /*
|
jamie@264
|
2 * CATCH v1.0 build 53 (master branch)
|
jamie@264
|
3 * Generated: 2014-08-20 08:08:19.533804
|
jamie@264
|
4 * ----------------------------------------------------------
|
jamie@264
|
5 * This file has been merged from multiple headers. Please don't edit it directly
|
jamie@264
|
6 * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved.
|
jamie@264
|
7 *
|
jamie@264
|
8 * Distributed under the Boost Software License, Version 1.0. (See accompanying
|
jamie@264
|
9 * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
jamie@264
|
10 */
|
jamie@264
|
11 #ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
|
jamie@264
|
12 #define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
|
jamie@264
|
13
|
jamie@264
|
14 #define TWOBLUECUBES_CATCH_HPP_INCLUDED
|
jamie@264
|
15
|
jamie@264
|
16 // #included from: internal/catch_suppress_warnings.h
|
jamie@264
|
17
|
jamie@264
|
18 #define TWOBLUECUBES_CATCH_SUPPRESS_WARNINGS_H_INCLUDED
|
jamie@264
|
19
|
jamie@264
|
20 #ifdef __clang__
|
jamie@264
|
21 #pragma clang diagnostic ignored "-Wglobal-constructors"
|
jamie@264
|
22 #pragma clang diagnostic ignored "-Wvariadic-macros"
|
jamie@264
|
23 #pragma clang diagnostic ignored "-Wc99-extensions"
|
jamie@264
|
24 #pragma clang diagnostic ignored "-Wunused-variable"
|
jamie@264
|
25 #pragma clang diagnostic push
|
jamie@264
|
26 #pragma clang diagnostic ignored "-Wpadded"
|
jamie@264
|
27 #pragma clang diagnostic ignored "-Wc++98-compat"
|
jamie@264
|
28 #pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
|
jamie@264
|
29 #elif defined __GNUC__
|
jamie@264
|
30 #pragma GCC diagnostic ignored "-Wvariadic-macros"
|
jamie@264
|
31 #pragma GCC diagnostic ignored "-Wunused-variable"
|
jamie@264
|
32 #pragma GCC diagnostic push
|
jamie@264
|
33 #pragma GCC diagnostic ignored "-Wpadded"
|
jamie@264
|
34 #endif
|
jamie@264
|
35
|
jamie@264
|
36 #ifdef CATCH_CONFIG_MAIN
|
jamie@264
|
37 # define CATCH_CONFIG_RUNNER
|
jamie@264
|
38 #endif
|
jamie@264
|
39
|
jamie@264
|
40 #ifdef CATCH_CONFIG_RUNNER
|
jamie@264
|
41 # ifndef CLARA_CONFIG_MAIN
|
jamie@264
|
42 # define CLARA_CONFIG_MAIN_NOT_DEFINED
|
jamie@264
|
43 # define CLARA_CONFIG_MAIN
|
jamie@264
|
44 # endif
|
jamie@264
|
45 #endif
|
jamie@264
|
46
|
jamie@264
|
47 // #included from: internal/catch_notimplemented_exception.h
|
jamie@264
|
48 #define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED
|
jamie@264
|
49
|
jamie@264
|
50 // #included from: catch_common.h
|
jamie@264
|
51 #define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED
|
jamie@264
|
52
|
jamie@264
|
53 #define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line
|
jamie@264
|
54 #define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line )
|
jamie@264
|
55 #define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ )
|
jamie@264
|
56
|
jamie@264
|
57 #define INTERNAL_CATCH_STRINGIFY2( expr ) #expr
|
jamie@264
|
58 #define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr )
|
jamie@264
|
59
|
jamie@264
|
60 #include <sstream>
|
jamie@264
|
61 #include <stdexcept>
|
jamie@264
|
62 #include <algorithm>
|
jamie@264
|
63
|
jamie@264
|
64 // #included from: catch_compiler_capabilities.h
|
jamie@264
|
65 #define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
|
jamie@264
|
66
|
jamie@264
|
67 // Much of the following code is based on Boost (1.53)
|
jamie@264
|
68
|
jamie@264
|
69 #ifdef __clang__
|
jamie@264
|
70
|
jamie@264
|
71 # if __has_feature(cxx_nullptr)
|
jamie@264
|
72 # define CATCH_CONFIG_CPP11_NULLPTR
|
jamie@264
|
73 # endif
|
jamie@264
|
74
|
jamie@264
|
75 # if __has_feature(cxx_noexcept)
|
jamie@264
|
76 # define CATCH_CONFIG_CPP11_NOEXCEPT
|
jamie@264
|
77 # endif
|
jamie@264
|
78
|
jamie@264
|
79 #endif // __clang__
|
jamie@264
|
80
|
jamie@264
|
81 ////////////////////////////////////////////////////////////////////////////////
|
jamie@264
|
82 // Borland
|
jamie@264
|
83 #ifdef __BORLANDC__
|
jamie@264
|
84
|
jamie@264
|
85 #if (__BORLANDC__ > 0x582 )
|
jamie@264
|
86 //#define CATCH_CONFIG_SFINAE // Not confirmed
|
jamie@264
|
87 #endif
|
jamie@264
|
88
|
jamie@264
|
89 #endif // __BORLANDC__
|
jamie@264
|
90
|
jamie@264
|
91 ////////////////////////////////////////////////////////////////////////////////
|
jamie@264
|
92 // EDG
|
jamie@264
|
93 #ifdef __EDG_VERSION__
|
jamie@264
|
94
|
jamie@264
|
95 #if (__EDG_VERSION__ > 238 )
|
jamie@264
|
96 //#define CATCH_CONFIG_SFINAE // Not confirmed
|
jamie@264
|
97 #endif
|
jamie@264
|
98
|
jamie@264
|
99 #endif // __EDG_VERSION__
|
jamie@264
|
100
|
jamie@264
|
101 ////////////////////////////////////////////////////////////////////////////////
|
jamie@264
|
102 // Digital Mars
|
jamie@264
|
103 #ifdef __DMC__
|
jamie@264
|
104
|
jamie@264
|
105 #if (__DMC__ > 0x840 )
|
jamie@264
|
106 //#define CATCH_CONFIG_SFINAE // Not confirmed
|
jamie@264
|
107 #endif
|
jamie@264
|
108
|
jamie@264
|
109 #endif // __DMC__
|
jamie@264
|
110
|
jamie@264
|
111 ////////////////////////////////////////////////////////////////////////////////
|
jamie@264
|
112 // GCC
|
jamie@264
|
113 #ifdef __GNUC__
|
jamie@264
|
114
|
jamie@264
|
115 #if __GNUC__ < 3
|
jamie@264
|
116
|
jamie@264
|
117 #if (__GNUC_MINOR__ >= 96 )
|
jamie@264
|
118 //#define CATCH_CONFIG_SFINAE
|
jamie@264
|
119 #endif
|
jamie@264
|
120
|
jamie@264
|
121 #elif __GNUC__ >= 3
|
jamie@264
|
122
|
jamie@264
|
123 // #define CATCH_CONFIG_SFINAE // Taking this out completely for now
|
jamie@264
|
124
|
jamie@264
|
125 #endif // __GNUC__ < 3
|
jamie@264
|
126
|
jamie@264
|
127 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) )
|
jamie@264
|
128
|
jamie@264
|
129 #define CATCH_CONFIG_CPP11_NULLPTR
|
jamie@264
|
130 #endif
|
jamie@264
|
131
|
jamie@264
|
132 #endif // __GNUC__
|
jamie@264
|
133
|
jamie@264
|
134 ////////////////////////////////////////////////////////////////////////////////
|
jamie@264
|
135 // Visual C++
|
jamie@264
|
136 #ifdef _MSC_VER
|
jamie@264
|
137
|
jamie@264
|
138 #if (_MSC_VER >= 1310 ) // (VC++ 7.0+)
|
jamie@264
|
139 //#define CATCH_CONFIG_SFINAE // Not confirmed
|
jamie@264
|
140 #endif
|
jamie@264
|
141
|
jamie@264
|
142 #endif // _MSC_VER
|
jamie@264
|
143
|
jamie@264
|
144 // Use variadic macros if the compiler supports them
|
jamie@264
|
145 #if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \
|
jamie@264
|
146 ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \
|
jamie@264
|
147 ( defined __GNUC__ && __GNUC__ >= 3 ) || \
|
jamie@264
|
148 ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L )
|
jamie@264
|
149
|
jamie@264
|
150 #ifndef CATCH_CONFIG_NO_VARIADIC_MACROS
|
jamie@264
|
151 #define CATCH_CONFIG_VARIADIC_MACROS
|
jamie@264
|
152 #endif
|
jamie@264
|
153
|
jamie@264
|
154 #endif
|
jamie@264
|
155
|
jamie@264
|
156 ////////////////////////////////////////////////////////////////////////////////
|
jamie@264
|
157 // C++ language feature support
|
jamie@264
|
158
|
jamie@264
|
159 // detect language version:
|
jamie@264
|
160 #if (__cplusplus == 201103L)
|
jamie@264
|
161 # define CATCH_CPP11
|
jamie@264
|
162 # define CATCH_CPP11_OR_GREATER
|
jamie@264
|
163 #elif (__cplusplus >= 201103L)
|
jamie@264
|
164 # define CATCH_CPP11_OR_GREATER
|
jamie@264
|
165 #endif
|
jamie@264
|
166
|
jamie@264
|
167 // noexcept support:
|
jamie@264
|
168 #if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT)
|
jamie@264
|
169 # define CATCH_NOEXCEPT noexcept
|
jamie@264
|
170 # define CATCH_NOEXCEPT_IS(x) noexcept(x)
|
jamie@264
|
171 #else
|
jamie@264
|
172 # define CATCH_NOEXCEPT throw()
|
jamie@264
|
173 # define CATCH_NOEXCEPT_IS(x)
|
jamie@264
|
174 #endif
|
jamie@264
|
175
|
jamie@264
|
176 namespace Catch {
|
jamie@264
|
177
|
jamie@264
|
178 class NonCopyable {
|
jamie@264
|
179 NonCopyable( NonCopyable const& );
|
jamie@264
|
180 void operator = ( NonCopyable const& );
|
jamie@264
|
181 protected:
|
jamie@264
|
182 NonCopyable() {}
|
jamie@264
|
183 virtual ~NonCopyable();
|
jamie@264
|
184 };
|
jamie@264
|
185
|
jamie@264
|
186 class SafeBool {
|
jamie@264
|
187 public:
|
jamie@264
|
188 typedef void (SafeBool::*type)() const;
|
jamie@264
|
189
|
jamie@264
|
190 static type makeSafe( bool value ) {
|
jamie@264
|
191 return value ? &SafeBool::trueValue : 0;
|
jamie@264
|
192 }
|
jamie@264
|
193 private:
|
jamie@264
|
194 void trueValue() const {}
|
jamie@264
|
195 };
|
jamie@264
|
196
|
jamie@264
|
197 template<typename ContainerT>
|
jamie@264
|
198 inline void deleteAll( ContainerT& container ) {
|
jamie@264
|
199 typename ContainerT::const_iterator it = container.begin();
|
jamie@264
|
200 typename ContainerT::const_iterator itEnd = container.end();
|
jamie@264
|
201 for(; it != itEnd; ++it )
|
jamie@264
|
202 delete *it;
|
jamie@264
|
203 }
|
jamie@264
|
204 template<typename AssociativeContainerT>
|
jamie@264
|
205 inline void deleteAllValues( AssociativeContainerT& container ) {
|
jamie@264
|
206 typename AssociativeContainerT::const_iterator it = container.begin();
|
jamie@264
|
207 typename AssociativeContainerT::const_iterator itEnd = container.end();
|
jamie@264
|
208 for(; it != itEnd; ++it )
|
jamie@264
|
209 delete it->second;
|
jamie@264
|
210 }
|
jamie@264
|
211
|
jamie@264
|
212 bool startsWith( std::string const& s, std::string const& prefix );
|
jamie@264
|
213 bool endsWith( std::string const& s, std::string const& suffix );
|
jamie@264
|
214 bool contains( std::string const& s, std::string const& infix );
|
jamie@264
|
215 void toLowerInPlace( std::string& s );
|
jamie@264
|
216 std::string toLower( std::string const& s );
|
jamie@264
|
217 std::string trim( std::string const& str );
|
jamie@264
|
218
|
jamie@264
|
219 struct pluralise {
|
jamie@264
|
220 pluralise( std::size_t count, std::string const& label );
|
jamie@264
|
221
|
jamie@264
|
222 friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser );
|
jamie@264
|
223
|
jamie@264
|
224 std::size_t m_count;
|
jamie@264
|
225 std::string m_label;
|
jamie@264
|
226 };
|
jamie@264
|
227
|
jamie@264
|
228 struct SourceLineInfo {
|
jamie@264
|
229
|
jamie@264
|
230 SourceLineInfo();
|
jamie@264
|
231 SourceLineInfo( char const* _file, std::size_t _line );
|
jamie@264
|
232 SourceLineInfo( SourceLineInfo const& other );
|
jamie@264
|
233 # ifdef CATCH_CPP11_OR_GREATER
|
jamie@264
|
234 SourceLineInfo( SourceLineInfo && ) = default;
|
jamie@264
|
235 SourceLineInfo& operator = ( SourceLineInfo const& ) = default;
|
jamie@264
|
236 SourceLineInfo& operator = ( SourceLineInfo && ) = default;
|
jamie@264
|
237 # endif
|
jamie@264
|
238 bool empty() const;
|
jamie@264
|
239 bool operator == ( SourceLineInfo const& other ) const;
|
jamie@264
|
240
|
jamie@264
|
241 std::string file;
|
jamie@264
|
242 std::size_t line;
|
jamie@264
|
243 };
|
jamie@264
|
244
|
jamie@264
|
245 std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info );
|
jamie@264
|
246
|
jamie@264
|
247 // This is just here to avoid compiler warnings with macro constants and boolean literals
|
jamie@264
|
248 inline bool isTrue( bool value ){ return value; }
|
jamie@264
|
249 inline bool alwaysTrue() { return true; }
|
jamie@264
|
250 inline bool alwaysFalse() { return false; }
|
jamie@264
|
251
|
jamie@264
|
252 void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo );
|
jamie@264
|
253
|
jamie@264
|
254 // Use this in variadic streaming macros to allow
|
jamie@264
|
255 // >> +StreamEndStop
|
jamie@264
|
256 // as well as
|
jamie@264
|
257 // >> stuff +StreamEndStop
|
jamie@264
|
258 struct StreamEndStop {
|
jamie@264
|
259 std::string operator+() {
|
jamie@264
|
260 return std::string();
|
jamie@264
|
261 }
|
jamie@264
|
262 };
|
jamie@264
|
263 template<typename T>
|
jamie@264
|
264 T const& operator + ( T const& value, StreamEndStop ) {
|
jamie@264
|
265 return value;
|
jamie@264
|
266 }
|
jamie@264
|
267 }
|
jamie@264
|
268
|
jamie@264
|
269 #define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) )
|
jamie@264
|
270 #define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO );
|
jamie@264
|
271
|
jamie@264
|
272 #include <ostream>
|
jamie@264
|
273
|
jamie@264
|
274 namespace Catch {
|
jamie@264
|
275
|
jamie@264
|
276 class NotImplementedException : public std::exception
|
jamie@264
|
277 {
|
jamie@264
|
278 public:
|
jamie@264
|
279 NotImplementedException( SourceLineInfo const& lineInfo );
|
jamie@264
|
280 NotImplementedException( NotImplementedException const& ) {}
|
jamie@264
|
281
|
jamie@264
|
282 virtual ~NotImplementedException() CATCH_NOEXCEPT {}
|
jamie@264
|
283
|
jamie@264
|
284 virtual const char* what() const CATCH_NOEXCEPT;
|
jamie@264
|
285
|
jamie@264
|
286 private:
|
jamie@264
|
287 std::string m_what;
|
jamie@264
|
288 SourceLineInfo m_lineInfo;
|
jamie@264
|
289 };
|
jamie@264
|
290
|
jamie@264
|
291 } // end namespace Catch
|
jamie@264
|
292
|
jamie@264
|
293 ///////////////////////////////////////////////////////////////////////////////
|
jamie@264
|
294 #define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO )
|
jamie@264
|
295
|
jamie@264
|
296 // #included from: internal/catch_context.h
|
jamie@264
|
297 #define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED
|
jamie@264
|
298
|
jamie@264
|
299 // #included from: catch_interfaces_generators.h
|
jamie@264
|
300 #define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED
|
jamie@264
|
301
|
jamie@264
|
302 #include <string>
|
jamie@264
|
303
|
jamie@264
|
304 namespace Catch {
|
jamie@264
|
305
|
jamie@264
|
306 struct IGeneratorInfo {
|
jamie@264
|
307 virtual ~IGeneratorInfo();
|
jamie@264
|
308 virtual bool moveNext() = 0;
|
jamie@264
|
309 virtual std::size_t getCurrentIndex() const = 0;
|
jamie@264
|
310 };
|
jamie@264
|
311
|
jamie@264
|
312 struct IGeneratorsForTest {
|
jamie@264
|
313 virtual ~IGeneratorsForTest();
|
jamie@264
|
314
|
jamie@264
|
315 virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0;
|
jamie@264
|
316 virtual bool moveNext() = 0;
|
jamie@264
|
317 };
|
jamie@264
|
318
|
jamie@264
|
319 IGeneratorsForTest* createGeneratorsForTest();
|
jamie@264
|
320
|
jamie@264
|
321 } // end namespace Catch
|
jamie@264
|
322
|
jamie@264
|
323 // #included from: catch_ptr.hpp
|
jamie@264
|
324 #define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED
|
jamie@264
|
325
|
jamie@264
|
326 #ifdef __clang__
|
jamie@264
|
327 #pragma clang diagnostic push
|
jamie@264
|
328 #pragma clang diagnostic ignored "-Wpadded"
|
jamie@264
|
329 #endif
|
jamie@264
|
330
|
jamie@264
|
331 namespace Catch {
|
jamie@264
|
332
|
jamie@264
|
333 // An intrusive reference counting smart pointer.
|
jamie@264
|
334 // T must implement addRef() and release() methods
|
jamie@264
|
335 // typically implementing the IShared interface
|
jamie@264
|
336 template<typename T>
|
jamie@264
|
337 class Ptr {
|
jamie@264
|
338 public:
|
jamie@264
|
339 Ptr() : m_p( NULL ){}
|
jamie@264
|
340 Ptr( T* p ) : m_p( p ){
|
jamie@264
|
341 if( m_p )
|
jamie@264
|
342 m_p->addRef();
|
jamie@264
|
343 }
|
jamie@264
|
344 Ptr( Ptr const& other ) : m_p( other.m_p ){
|
jamie@264
|
345 if( m_p )
|
jamie@264
|
346 m_p->addRef();
|
jamie@264
|
347 }
|
jamie@264
|
348 ~Ptr(){
|
jamie@264
|
349 if( m_p )
|
jamie@264
|
350 m_p->release();
|
jamie@264
|
351 }
|
jamie@264
|
352 void reset() {
|
jamie@264
|
353 if( m_p )
|
jamie@264
|
354 m_p->release();
|
jamie@264
|
355 m_p = NULL;
|
jamie@264
|
356 }
|
jamie@264
|
357 Ptr& operator = ( T* p ){
|
jamie@264
|
358 Ptr temp( p );
|
jamie@264
|
359 swap( temp );
|
jamie@264
|
360 return *this;
|
jamie@264
|
361 }
|
jamie@264
|
362 Ptr& operator = ( Ptr const& other ){
|
jamie@264
|
363 Ptr temp( other );
|
jamie@264
|
364 swap( temp );
|
jamie@264
|
365 return *this;
|
jamie@264
|
366 }
|
jamie@264
|
367 void swap( Ptr& other ) { std::swap( m_p, other.m_p ); }
|
jamie@264
|
368 T* get() { return m_p; }
|
jamie@264
|
369 const T* get() const{ return m_p; }
|
jamie@264
|
370 T& operator*() const { return *m_p; }
|
jamie@264
|
371 T* operator->() const { return m_p; }
|
jamie@264
|
372 bool operator !() const { return m_p == NULL; }
|
jamie@264
|
373 operator SafeBool::type() const { return SafeBool::makeSafe( m_p != NULL ); }
|
jamie@264
|
374
|
jamie@264
|
375 private:
|
jamie@264
|
376 T* m_p;
|
jamie@264
|
377 };
|
jamie@264
|
378
|
jamie@264
|
379 struct IShared : NonCopyable {
|
jamie@264
|
380 virtual ~IShared();
|
jamie@264
|
381 virtual void addRef() const = 0;
|
jamie@264
|
382 virtual void release() const = 0;
|
jamie@264
|
383 };
|
jamie@264
|
384
|
jamie@264
|
385 template<typename T = IShared>
|
jamie@264
|
386 struct SharedImpl : T {
|
jamie@264
|
387
|
jamie@264
|
388 SharedImpl() : m_rc( 0 ){}
|
jamie@264
|
389
|
jamie@264
|
390 virtual void addRef() const {
|
jamie@264
|
391 ++m_rc;
|
jamie@264
|
392 }
|
jamie@264
|
393 virtual void release() const {
|
jamie@264
|
394 if( --m_rc == 0 )
|
jamie@264
|
395 delete this;
|
jamie@264
|
396 }
|
jamie@264
|
397
|
jamie@264
|
398 mutable unsigned int m_rc;
|
jamie@264
|
399 };
|
jamie@264
|
400
|
jamie@264
|
401 } // end namespace Catch
|
jamie@264
|
402
|
jamie@264
|
403 #ifdef __clang__
|
jamie@264
|
404 #pragma clang diagnostic pop
|
jamie@264
|
405 #endif
|
jamie@264
|
406
|
jamie@264
|
407 #include <memory>
|
jamie@264
|
408 #include <vector>
|
jamie@264
|
409 #include <stdlib.h>
|
jamie@264
|
410
|
jamie@264
|
411 namespace Catch {
|
jamie@264
|
412
|
jamie@264
|
413 class TestCase;
|
jamie@264
|
414 class Stream;
|
jamie@264
|
415 struct IResultCapture;
|
jamie@264
|
416 struct IRunner;
|
jamie@264
|
417 struct IGeneratorsForTest;
|
jamie@264
|
418 struct IConfig;
|
jamie@264
|
419
|
jamie@264
|
420 struct IContext
|
jamie@264
|
421 {
|
jamie@264
|
422 virtual ~IContext();
|
jamie@264
|
423
|
jamie@264
|
424 virtual IResultCapture* getResultCapture() = 0;
|
jamie@264
|
425 virtual IRunner* getRunner() = 0;
|
jamie@264
|
426 virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0;
|
jamie@264
|
427 virtual bool advanceGeneratorsForCurrentTest() = 0;
|
jamie@264
|
428 virtual Ptr<IConfig const> getConfig() const = 0;
|
jamie@264
|
429 };
|
jamie@264
|
430
|
jamie@264
|
431 struct IMutableContext : IContext
|
jamie@264
|
432 {
|
jamie@264
|
433 virtual ~IMutableContext();
|
jamie@264
|
434 virtual void setResultCapture( IResultCapture* resultCapture ) = 0;
|
jamie@264
|
435 virtual void setRunner( IRunner* runner ) = 0;
|
jamie@264
|
436 virtual void setConfig( Ptr<IConfig const> const& config ) = 0;
|
jamie@264
|
437 };
|
jamie@264
|
438
|
jamie@264
|
439 IContext& getCurrentContext();
|
jamie@264
|
440 IMutableContext& getCurrentMutableContext();
|
jamie@264
|
441 void cleanUpContext();
|
jamie@264
|
442 Stream createStream( std::string const& streamName );
|
jamie@264
|
443
|
jamie@264
|
444 }
|
jamie@264
|
445
|
jamie@264
|
446 // #included from: internal/catch_test_registry.hpp
|
jamie@264
|
447 #define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED
|
jamie@264
|
448
|
jamie@264
|
449 // #included from: catch_interfaces_testcase.h
|
jamie@264
|
450 #define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED
|
jamie@264
|
451
|
jamie@264
|
452 #include <vector>
|
jamie@264
|
453
|
jamie@264
|
454 namespace Catch {
|
jamie@264
|
455
|
jamie@264
|
456 class TestSpec;
|
jamie@264
|
457
|
jamie@264
|
458 struct ITestCase : IShared {
|
jamie@264
|
459 virtual void invoke () const = 0;
|
jamie@264
|
460 protected:
|
jamie@264
|
461 virtual ~ITestCase();
|
jamie@264
|
462 };
|
jamie@264
|
463
|
jamie@264
|
464 class TestCase;
|
jamie@264
|
465 struct IConfig;
|
jamie@264
|
466
|
jamie@264
|
467 struct ITestCaseRegistry {
|
jamie@264
|
468 virtual ~ITestCaseRegistry();
|
jamie@264
|
469 virtual std::vector<TestCase> const& getAllTests() const = 0;
|
jamie@264
|
470 virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector<TestCase>& matchingTestCases ) const = 0;
|
jamie@264
|
471
|
jamie@264
|
472 };
|
jamie@264
|
473 }
|
jamie@264
|
474
|
jamie@264
|
475 namespace Catch {
|
jamie@264
|
476
|
jamie@264
|
477 template<typename C>
|
jamie@264
|
478 class MethodTestCase : public SharedImpl<ITestCase> {
|
jamie@264
|
479
|
jamie@264
|
480 public:
|
jamie@264
|
481 MethodTestCase( void (C::*method)() ) : m_method( method ) {}
|
jamie@264
|
482
|
jamie@264
|
483 virtual void invoke() const {
|
jamie@264
|
484 C obj;
|
jamie@264
|
485 (obj.*m_method)();
|
jamie@264
|
486 }
|
jamie@264
|
487
|
jamie@264
|
488 private:
|
jamie@264
|
489 virtual ~MethodTestCase() {}
|
jamie@264
|
490
|
jamie@264
|
491 void (C::*m_method)();
|
jamie@264
|
492 };
|
jamie@264
|
493
|
jamie@264
|
494 typedef void(*TestFunction)();
|
jamie@264
|
495
|
jamie@264
|
496 struct NameAndDesc {
|
jamie@264
|
497 NameAndDesc( const char* _name = "", const char* _description= "" )
|
jamie@264
|
498 : name( _name ), description( _description )
|
jamie@264
|
499 {}
|
jamie@264
|
500
|
jamie@264
|
501 const char* name;
|
jamie@264
|
502 const char* description;
|
jamie@264
|
503 };
|
jamie@264
|
504
|
jamie@264
|
505 struct AutoReg {
|
jamie@264
|
506
|
jamie@264
|
507 AutoReg( TestFunction function,
|
jamie@264
|
508 SourceLineInfo const& lineInfo,
|
jamie@264
|
509 NameAndDesc const& nameAndDesc );
|
jamie@264
|
510
|
jamie@264
|
511 template<typename C>
|
jamie@264
|
512 AutoReg( void (C::*method)(),
|
jamie@264
|
513 char const* className,
|
jamie@264
|
514 NameAndDesc const& nameAndDesc,
|
jamie@264
|
515 SourceLineInfo const& lineInfo ) {
|
jamie@264
|
516 registerTestCase( new MethodTestCase<C>( method ),
|
jamie@264
|
517 className,
|
jamie@264
|
518 nameAndDesc,
|
jamie@264
|
519 lineInfo );
|
jamie@264
|
520 }
|
jamie@264
|
521
|
jamie@264
|
522 void registerTestCase( ITestCase* testCase,
|
jamie@264
|
523 char const* className,
|
jamie@264
|
524 NameAndDesc const& nameAndDesc,
|
jamie@264
|
525 SourceLineInfo const& lineInfo );
|
jamie@264
|
526
|
jamie@264
|
527 ~AutoReg();
|
jamie@264
|
528
|
jamie@264
|
529 private:
|
jamie@264
|
530 AutoReg( AutoReg const& );
|
jamie@264
|
531 void operator= ( AutoReg const& );
|
jamie@264
|
532 };
|
jamie@264
|
533
|
jamie@264
|
534 } // end namespace Catch
|
jamie@264
|
535
|
jamie@264
|
536 #ifdef CATCH_CONFIG_VARIADIC_MACROS
|
jamie@264
|
537 ///////////////////////////////////////////////////////////////////////////////
|
jamie@264
|
538 #define INTERNAL_CATCH_TESTCASE( ... ) \
|
jamie@264
|
539 static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \
|
jamie@264
|
540 namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\
|
jamie@264
|
541 static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )()
|
jamie@264
|
542
|
jamie@264
|
543 ///////////////////////////////////////////////////////////////////////////////
|
jamie@264
|
544 #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
|
jamie@264
|
545 namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); }
|
jamie@264
|
546
|
jamie@264
|
547 ///////////////////////////////////////////////////////////////////////////////
|
jamie@264
|
548 #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... )\
|
jamie@264
|
549 namespace{ \
|
jamie@264
|
550 struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \
|
jamie@264
|
551 void test(); \
|
jamie@264
|
552 }; \
|
jamie@264
|
553 Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \
|
jamie@264
|
554 } \
|
jamie@264
|
555 void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test()
|
jamie@264
|
556
|
jamie@264
|
557 #else
|
jamie@264
|
558 ///////////////////////////////////////////////////////////////////////////////
|
jamie@264
|
559 #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \
|
jamie@264
|
560 static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \
|
jamie@264
|
561 namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\
|
jamie@264
|
562 static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )()
|
jamie@264
|
563
|
jamie@264
|
564 ///////////////////////////////////////////////////////////////////////////////
|
jamie@264
|
565 #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \
|
jamie@264
|
566 namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); }
|
jamie@264
|
567
|
jamie@264
|
568 ///////////////////////////////////////////////////////////////////////////////
|
jamie@264
|
569 #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\
|
jamie@264
|
570 namespace{ \
|
jamie@264
|
571 struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \
|
jamie@264
|
572 void test(); \
|
jamie@264
|
573 }; \
|
jamie@264
|
574 Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \
|
jamie@264
|
575 } \
|
jamie@264
|
576 void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test()
|
jamie@264
|
577
|
jamie@264
|
578 #endif
|
jamie@264
|
579
|
jamie@264
|
580 // #included from: internal/catch_capture.hpp
|
jamie@264
|
581 #define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
|
jamie@264
|
582
|
jamie@264
|
583 // #included from: catch_result_builder.h
|
jamie@264
|
584 #define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED
|
jamie@264
|
585
|
jamie@264
|
586 // #included from: catch_result_type.h
|
jamie@264
|
587 #define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED
|
jamie@264
|
588
|
jamie@264
|
589 namespace Catch {
|
jamie@264
|
590
|
jamie@264
|
591 // ResultWas::OfType enum
|
jamie@264
|
592 struct ResultWas { enum OfType {
|
jamie@264
|
593 Unknown = -1,
|
jamie@264
|
594 Ok = 0,
|
jamie@264
|
595 Info = 1,
|
jamie@264
|
596 Warning = 2,
|
jamie@264
|
597
|
jamie@264
|
598 FailureBit = 0x10,
|
jamie@264
|
599
|
jamie@264
|
600 ExpressionFailed = FailureBit | 1,
|
jamie@264
|
601 ExplicitFailure = FailureBit | 2,
|
jamie@264
|
602
|
jamie@264
|
603 Exception = 0x100 | FailureBit,
|
jamie@264
|
604
|
jamie@264
|
605 ThrewException = Exception | 1,
|
jamie@264
|
606 DidntThrowException = Exception | 2
|
jamie@264
|
607
|
jamie@264
|
608 }; };
|
jamie@264
|
609
|
jamie@264
|
610 inline bool isOk( ResultWas::OfType resultType ) {
|
jamie@264
|
611 return ( resultType & ResultWas::FailureBit ) == 0;
|
jamie@264
|
612 }
|
jamie@264
|
613 inline bool isJustInfo( int flags ) {
|
jamie@264
|
614 return flags == ResultWas::Info;
|
jamie@264
|
615 }
|
jamie@264
|
616
|
jamie@264
|
617 // ResultDisposition::Flags enum
|
jamie@264
|
618 struct ResultDisposition { enum Flags {
|
jamie@264
|
619 Normal = 0x00,
|
jamie@264
|
620
|
jamie@264
|
621 ContinueOnFailure = 0x01, // Failures fail test, but execution continues
|
jamie@264
|
622 FalseTest = 0x02, // Prefix expression with !
|
jamie@264
|
623 SuppressFail = 0x04 // Failures are reported but do not fail the test
|
jamie@264
|
624 }; };
|
jamie@264
|
625
|
jamie@264
|
626 inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) {
|
jamie@264
|
627 return static_cast<ResultDisposition::Flags>( static_cast<int>( lhs ) | static_cast<int>( rhs ) );
|
jamie@264
|
628 }
|
jamie@264
|
629
|
jamie@264
|
630 inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; }
|
jamie@264
|
631 inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; }
|
jamie@264
|
632 inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; }
|
jamie@264
|
633
|
jamie@264
|
634 } // end namespace Catch
|
jamie@264
|
635
|
jamie@264
|
636 // #included from: catch_assertionresult.h
|
jamie@264
|
637 #define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED
|
jamie@264
|
638
|
jamie@264
|
639 #include <string>
|
jamie@264
|
640
|
jamie@264
|
641 namespace Catch {
|
jamie@264
|
642
|
jamie@264
|
643 struct AssertionInfo
|
jamie@264
|
644 {
|
jamie@264
|
645 AssertionInfo() {}
|
jamie@264
|
646 AssertionInfo( std::string const& _macroName,
|
jamie@264
|
647 SourceLineInfo const& _lineInfo,
|
jamie@264
|
648 std::string const& _capturedExpression,
|
jamie@264
|
649 ResultDisposition::Flags _resultDisposition );
|
jamie@264
|
650
|
jamie@264
|
651 std::string macroName;
|
jamie@264
|
652 SourceLineInfo lineInfo;
|
jamie@264
|
653 std::string capturedExpression;
|
jamie@264
|
654 ResultDisposition::Flags resultDisposition;
|
jamie@264
|
655 };
|
jamie@264
|
656
|
jamie@264
|
657 struct AssertionResultData
|
jamie@264
|
658 {
|
jamie@264
|
659 AssertionResultData() : resultType( ResultWas::Unknown ) {}
|
jamie@264
|
660
|
jamie@264
|
661 std::string reconstructedExpression;
|
jamie@264
|
662 std::string message;
|
jamie@264
|
663 ResultWas::OfType resultType;
|
jamie@264
|
664 };
|
jamie@264
|
665
|
jamie@264
|
666 class AssertionResult {
|
jamie@264
|
667 public:
|
jamie@264
|
668 AssertionResult();
|
jamie@264
|
669 AssertionResult( AssertionInfo const& info, AssertionResultData const& data );
|
jamie@264
|
670 ~AssertionResult();
|
jamie@264
|
671 # ifdef CATCH_CPP11_OR_GREATER
|
jamie@264
|
672 AssertionResult( AssertionResult const& ) = default;
|
jamie@264
|
673 AssertionResult( AssertionResult && ) = default;
|
jamie@264
|
674 AssertionResult& operator = ( AssertionResult const& ) = default;
|
jamie@264
|
675 AssertionResult& operator = ( AssertionResult && ) = default;
|
jamie@264
|
676 # endif
|
jamie@264
|
677
|
jamie@264
|
678 bool isOk() const;
|
jamie@264
|
679 bool succeeded() const;
|
jamie@264
|
680 ResultWas::OfType getResultType() const;
|
jamie@264
|
681 bool hasExpression() const;
|
jamie@264
|
682 bool hasMessage() const;
|
jamie@264
|
683 std::string getExpression() const;
|
jamie@264
|
684 std::string getExpressionInMacro() const;
|
jamie@264
|
685 bool hasExpandedExpression() const;
|
jamie@264
|
686 std::string getExpandedExpression() const;
|
jamie@264
|
687 std::string getMessage() const;
|
jamie@264
|
688 SourceLineInfo getSourceInfo() const;
|
jamie@264
|
689 std::string getTestMacroName() const;
|
jamie@264
|
690
|
jamie@264
|
691 protected:
|
jamie@264
|
692 AssertionInfo m_info;
|
jamie@264
|
693 AssertionResultData m_resultData;
|
jamie@264
|
694 };
|
jamie@264
|
695
|
jamie@264
|
696 } // end namespace Catch
|
jamie@264
|
697
|
jamie@264
|
698 namespace Catch {
|
jamie@264
|
699
|
jamie@264
|
700 struct TestFailureException{};
|
jamie@264
|
701
|
jamie@264
|
702 template<typename T> class ExpressionLhs;
|
jamie@264
|
703
|
jamie@264
|
704 struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison;
|
jamie@264
|
705
|
jamie@264
|
706 struct CopyableStream {
|
jamie@264
|
707 CopyableStream() {}
|
jamie@264
|
708 CopyableStream( CopyableStream const& other ) {
|
jamie@264
|
709 oss << other.oss.str();
|
jamie@264
|
710 }
|
jamie@264
|
711 CopyableStream& operator=( CopyableStream const& other ) {
|
jamie@264
|
712 oss.str("");
|
jamie@264
|
713 oss << other.oss.str();
|
jamie@264
|
714 return *this;
|
jamie@264
|
715 }
|
jamie@264
|
716 std::ostringstream oss;
|
jamie@264
|
717 };
|
jamie@264
|
718
|
jamie@264
|
719 class ResultBuilder {
|
jamie@264
|
720 public:
|
jamie@264
|
721 ResultBuilder( char const* macroName,
|
jamie@264
|
722 SourceLineInfo const& lineInfo,
|
jamie@264
|
723 char const* capturedExpression,
|
jamie@264
|
724 ResultDisposition::Flags resultDisposition );
|
jamie@264
|
725
|
jamie@264
|
726 template<typename T>
|
jamie@264
|
727 ExpressionLhs<T const&> operator->* ( T const& operand );
|
jamie@264
|
728 ExpressionLhs<bool> operator->* ( bool value );
|
jamie@264
|
729
|
jamie@264
|
730 template<typename T>
|
jamie@264
|
731 ResultBuilder& operator << ( T const& value ) {
|
jamie@264
|
732 m_stream.oss << value;
|
jamie@264
|
733 return *this;
|
jamie@264
|
734 }
|
jamie@264
|
735
|
jamie@264
|
736 template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& );
|
jamie@264
|
737 template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& );
|
jamie@264
|
738
|
jamie@264
|
739 ResultBuilder& setResultType( ResultWas::OfType result );
|
jamie@264
|
740 ResultBuilder& setResultType( bool result );
|
jamie@264
|
741 ResultBuilder& setLhs( std::string const& lhs );
|
jamie@264
|
742 ResultBuilder& setRhs( std::string const& rhs );
|
jamie@264
|
743 ResultBuilder& setOp( std::string const& op );
|
jamie@264
|
744
|
jamie@264
|
745 void endExpression();
|
jamie@264
|
746
|
jamie@264
|
747 std::string reconstructExpression() const;
|
jamie@264
|
748 AssertionResult build() const;
|
jamie@264
|
749
|
jamie@264
|
750 void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal );
|
jamie@264
|
751 void captureResult( ResultWas::OfType resultType );
|
jamie@264
|
752 void captureExpression();
|
jamie@264
|
753 void react();
|
jamie@264
|
754 bool shouldDebugBreak() const;
|
jamie@264
|
755 bool allowThrows() const;
|
jamie@264
|
756
|
jamie@264
|
757 private:
|
jamie@264
|
758 AssertionInfo m_assertionInfo;
|
jamie@264
|
759 AssertionResultData m_data;
|
jamie@264
|
760 struct ExprComponents {
|
jamie@264
|
761 ExprComponents() : testFalse( false ) {}
|
jamie@264
|
762 bool testFalse;
|
jamie@264
|
763 std::string lhs, rhs, op;
|
jamie@264
|
764 } m_exprComponents;
|
jamie@264
|
765 CopyableStream m_stream;
|
jamie@264
|
766
|
jamie@264
|
767 bool m_shouldDebugBreak;
|
jamie@264
|
768 bool m_shouldThrow;
|
jamie@264
|
769 };
|
jamie@264
|
770
|
jamie@264
|
771 } // namespace Catch
|
jamie@264
|
772
|
jamie@264
|
773 // Include after due to circular dependency:
|
jamie@264
|
774 // #included from: catch_expression_lhs.hpp
|
jamie@264
|
775 #define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED
|
jamie@264
|
776
|
jamie@264
|
777 // #included from: catch_evaluate.hpp
|
jamie@264
|
778 #define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED
|
jamie@264
|
779
|
jamie@264
|
780 #ifdef _MSC_VER
|
jamie@264
|
781 #pragma warning(push)
|
jamie@264
|
782 #pragma warning(disable:4389) // '==' : signed/unsigned mismatch
|
jamie@264
|
783 #endif
|
jamie@264
|
784
|
jamie@264
|
785 #include <cstddef>
|
jamie@264
|
786
|
jamie@264
|
787 namespace Catch {
|
jamie@264
|
788 namespace Internal {
|
jamie@264
|
789
|
jamie@264
|
790 enum Operator {
|
jamie@264
|
791 IsEqualTo,
|
jamie@264
|
792 IsNotEqualTo,
|
jamie@264
|
793 IsLessThan,
|
jamie@264
|
794 IsGreaterThan,
|
jamie@264
|
795 IsLessThanOrEqualTo,
|
jamie@264
|
796 IsGreaterThanOrEqualTo
|
jamie@264
|
797 };
|
jamie@264
|
798
|
jamie@264
|
799 template<Operator Op> struct OperatorTraits { static const char* getName(){ return "*error*"; } };
|
jamie@264
|
800 template<> struct OperatorTraits<IsEqualTo> { static const char* getName(){ return "=="; } };
|
jamie@264
|
801 template<> struct OperatorTraits<IsNotEqualTo> { static const char* getName(){ return "!="; } };
|
jamie@264
|
802 template<> struct OperatorTraits<IsLessThan> { static const char* getName(){ return "<"; } };
|
jamie@264
|
803 template<> struct OperatorTraits<IsGreaterThan> { static const char* getName(){ return ">"; } };
|
jamie@264
|
804 template<> struct OperatorTraits<IsLessThanOrEqualTo> { static const char* getName(){ return "<="; } };
|
jamie@264
|
805 template<> struct OperatorTraits<IsGreaterThanOrEqualTo>{ static const char* getName(){ return ">="; } };
|
jamie@264
|
806
|
jamie@264
|
807 template<typename T>
|
jamie@264
|
808 inline T& opCast(T const& t) { return const_cast<T&>(t); }
|
jamie@264
|
809
|
jamie@264
|
810 // nullptr_t support based on pull request #154 from Konstantin Baumann
|
jamie@264
|
811 #ifdef CATCH_CONFIG_CPP11_NULLPTR
|
jamie@264
|
812 inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; }
|
jamie@264
|
813 #endif // CATCH_CONFIG_CPP11_NULLPTR
|
jamie@264
|
814
|
jamie@264
|
815 // So the compare overloads can be operator agnostic we convey the operator as a template
|
jamie@264
|
816 // enum, which is used to specialise an Evaluator for doing the comparison.
|
jamie@264
|
817 template<typename T1, typename T2, Operator Op>
|
jamie@264
|
818 class Evaluator{};
|
jamie@264
|
819
|
jamie@264
|
820 template<typename T1, typename T2>
|
jamie@264
|
821 struct Evaluator<T1, T2, IsEqualTo> {
|
jamie@264
|
822 static bool evaluate( T1 const& lhs, T2 const& rhs) {
|
jamie@264
|
823 return opCast( lhs ) == opCast( rhs );
|
jamie@264
|
824 }
|
jamie@264
|
825 };
|
jamie@264
|
826 template<typename T1, typename T2>
|
jamie@264
|
827 struct Evaluator<T1, T2, IsNotEqualTo> {
|
jamie@264
|
828 static bool evaluate( T1 const& lhs, T2 const& rhs ) {
|
jamie@264
|
829 return opCast( lhs ) != opCast( rhs );
|
jamie@264
|
830 }
|
jamie@264
|
831 };
|
jamie@264
|
832 template<typename T1, typename T2>
|
jamie@264
|
833 struct Evaluator<T1, T2, IsLessThan> {
|
jamie@264
|
834 static bool evaluate( T1 const& lhs, T2 const& rhs ) {
|
jamie@264
|
835 return opCast( lhs ) < opCast( rhs );
|
jamie@264
|
836 }
|
jamie@264
|
837 };
|
jamie@264
|
838 template<typename T1, typename T2>
|
jamie@264
|
839 struct Evaluator<T1, T2, IsGreaterThan> {
|
jamie@264
|
840 static bool evaluate( T1 const& lhs, T2 const& rhs ) {
|
jamie@264
|
841 return opCast( lhs ) > opCast( rhs );
|
jamie@264
|
842 }
|
jamie@264
|
843 };
|
jamie@264
|
844 template<typename T1, typename T2>
|
jamie@264
|
845 struct Evaluator<T1, T2, IsGreaterThanOrEqualTo> {
|
jamie@264
|
846 static bool evaluate( T1 const& lhs, T2 const& rhs ) {
|
jamie@264
|
847 return opCast( lhs ) >= opCast( rhs );
|
jamie@264
|
848 }
|
jamie@264
|
849 };
|
jamie@264
|
850 template<typename T1, typename T2>
|
jamie@264
|
851 struct Evaluator<T1, T2, IsLessThanOrEqualTo> {
|
jamie@264
|
852 static bool evaluate( T1 const& lhs, T2 const& rhs ) {
|
jamie@264
|
853 return opCast( lhs ) <= opCast( rhs );
|
jamie@264
|
854 }
|
jamie@264
|
855 };
|
jamie@264
|
856
|
jamie@264
|
857 template<Operator Op, typename T1, typename T2>
|
jamie@264
|
858 bool applyEvaluator( T1 const& lhs, T2 const& rhs ) {
|
jamie@264
|
859 return Evaluator<T1, T2, Op>::evaluate( lhs, rhs );
|
jamie@264
|
860 }
|
jamie@264
|
861
|
jamie@264
|
862 // This level of indirection allows us to specialise for integer types
|
jamie@264
|
863 // to avoid signed/ unsigned warnings
|
jamie@264
|
864
|
jamie@264
|
865 // "base" overload
|
jamie@264
|
866 template<Operator Op, typename T1, typename T2>
|
jamie@264
|
867 bool compare( T1 const& lhs, T2 const& rhs ) {
|
jamie@264
|
868 return Evaluator<T1, T2, Op>::evaluate( lhs, rhs );
|
jamie@264
|
869 }
|
jamie@264
|
870
|
jamie@264
|
871 // unsigned X to int
|
jamie@264
|
872 template<Operator Op> bool compare( unsigned int lhs, int rhs ) {
|
jamie@264
|
873 return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
|
jamie@264
|
874 }
|
jamie@264
|
875 template<Operator Op> bool compare( unsigned long lhs, int rhs ) {
|
jamie@264
|
876 return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
|
jamie@264
|
877 }
|
jamie@264
|
878 template<Operator Op> bool compare( unsigned char lhs, int rhs ) {
|
jamie@264
|
879 return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
|
jamie@264
|
880 }
|
jamie@264
|
881
|
jamie@264
|
882 // unsigned X to long
|
jamie@264
|
883 template<Operator Op> bool compare( unsigned int lhs, long rhs ) {
|
jamie@264
|
884 return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
|
jamie@264
|
885 }
|
jamie@264
|
886 template<Operator Op> bool compare( unsigned long lhs, long rhs ) {
|
jamie@264
|
887 return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
|
jamie@264
|
888 }
|
jamie@264
|
889 template<Operator Op> bool compare( unsigned char lhs, long rhs ) {
|
jamie@264
|
890 return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
|
jamie@264
|
891 }
|
jamie@264
|
892
|
jamie@264
|
893 // int to unsigned X
|
jamie@264
|
894 template<Operator Op> bool compare( int lhs, unsigned int rhs ) {
|
jamie@264
|
895 return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
|
jamie@264
|
896 }
|
jamie@264
|
897 template<Operator Op> bool compare( int lhs, unsigned long rhs ) {
|
jamie@264
|
898 return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
|
jamie@264
|
899 }
|
jamie@264
|
900 template<Operator Op> bool compare( int lhs, unsigned char rhs ) {
|
jamie@264
|
901 return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
|
jamie@264
|
902 }
|
jamie@264
|
903
|
jamie@264
|
904 // long to unsigned X
|
jamie@264
|
905 template<Operator Op> bool compare( long lhs, unsigned int rhs ) {
|
jamie@264
|
906 return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
|
jamie@264
|
907 }
|
jamie@264
|
908 template<Operator Op> bool compare( long lhs, unsigned long rhs ) {
|
jamie@264
|
909 return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
|
jamie@264
|
910 }
|
jamie@264
|
911 template<Operator Op> bool compare( long lhs, unsigned char rhs ) {
|
jamie@264
|
912 return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
|
jamie@264
|
913 }
|
jamie@264
|
914
|
jamie@264
|
915 // pointer to long (when comparing against NULL)
|
jamie@264
|
916 template<Operator Op, typename T> bool compare( long lhs, T* rhs ) {
|
jamie@264
|
917 return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
|
jamie@264
|
918 }
|
jamie@264
|
919 template<Operator Op, typename T> bool compare( T* lhs, long rhs ) {
|
jamie@264
|
920 return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
|
jamie@264
|
921 }
|
jamie@264
|
922
|
jamie@264
|
923 // pointer to int (when comparing against NULL)
|
jamie@264
|
924 template<Operator Op, typename T> bool compare( int lhs, T* rhs ) {
|
jamie@264
|
925 return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
|
jamie@264
|
926 }
|
jamie@264
|
927 template<Operator Op, typename T> bool compare( T* lhs, int rhs ) {
|
jamie@264
|
928 return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
|
jamie@264
|
929 }
|
jamie@264
|
930
|
jamie@264
|
931 #ifdef CATCH_CONFIG_CPP11_NULLPTR
|
jamie@264
|
932 // pointer to nullptr_t (when comparing against nullptr)
|
jamie@264
|
933 template<Operator Op, typename T> bool compare( std::nullptr_t, T* rhs ) {
|
jamie@264
|
934 return Evaluator<T*, T*, Op>::evaluate( NULL, rhs );
|
jamie@264
|
935 }
|
jamie@264
|
936 template<Operator Op, typename T> bool compare( T* lhs, std::nullptr_t ) {
|
jamie@264
|
937 return Evaluator<T*, T*, Op>::evaluate( lhs, NULL );
|
jamie@264
|
938 }
|
jamie@264
|
939 #endif // CATCH_CONFIG_CPP11_NULLPTR
|
jamie@264
|
940
|
jamie@264
|
941 } // end of namespace Internal
|
jamie@264
|
942 } // end of namespace Catch
|
jamie@264
|
943
|
jamie@264
|
944 #ifdef _MSC_VER
|
jamie@264
|
945 #pragma warning(pop)
|
jamie@264
|
946 #endif
|
jamie@264
|
947
|
jamie@264
|
948 // #included from: catch_tostring.h
|
jamie@264
|
949 #define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED
|
jamie@264
|
950
|
jamie@264
|
951 // #included from: catch_sfinae.hpp
|
jamie@264
|
952 #define TWOBLUECUBES_CATCH_SFINAE_HPP_INCLUDED
|
jamie@264
|
953
|
jamie@264
|
954 // Try to detect if the current compiler supports SFINAE
|
jamie@264
|
955
|
jamie@264
|
956 namespace Catch {
|
jamie@264
|
957
|
jamie@264
|
958 struct TrueType {
|
jamie@264
|
959 static const bool value = true;
|
jamie@264
|
960 typedef void Enable;
|
jamie@264
|
961 char sizer[1];
|
jamie@264
|
962 };
|
jamie@264
|
963 struct FalseType {
|
jamie@264
|
964 static const bool value = false;
|
jamie@264
|
965 typedef void Disable;
|
jamie@264
|
966 char sizer[2];
|
jamie@264
|
967 };
|
jamie@264
|
968
|
jamie@264
|
969 #ifdef CATCH_CONFIG_SFINAE
|
jamie@264
|
970
|
jamie@264
|
971 template<bool> struct NotABooleanExpression;
|
jamie@264
|
972
|
jamie@264
|
973 template<bool c> struct If : NotABooleanExpression<c> {};
|
jamie@264
|
974 template<> struct If<true> : TrueType {};
|
jamie@264
|
975 template<> struct If<false> : FalseType {};
|
jamie@264
|
976
|
jamie@264
|
977 template<int size> struct SizedIf;
|
jamie@264
|
978 template<> struct SizedIf<sizeof(TrueType)> : TrueType {};
|
jamie@264
|
979 template<> struct SizedIf<sizeof(FalseType)> : FalseType {};
|
jamie@264
|
980
|
jamie@264
|
981 #endif // CATCH_CONFIG_SFINAE
|
jamie@264
|
982
|
jamie@264
|
983 } // end namespace Catch
|
jamie@264
|
984
|
jamie@264
|
985 #include <sstream>
|
jamie@264
|
986 #include <iomanip>
|
jamie@264
|
987 #include <limits>
|
jamie@264
|
988 #include <vector>
|
jamie@264
|
989 #include <cstddef>
|
jamie@264
|
990
|
jamie@264
|
991 #ifdef __OBJC__
|
jamie@264
|
992 // #included from: catch_objc_arc.hpp
|
jamie@264
|
993 #define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED
|
jamie@264
|
994
|
jamie@264
|
995 #import <Foundation/Foundation.h>
|
jamie@264
|
996
|
jamie@264
|
997 #ifdef __has_feature
|
jamie@264
|
998 #define CATCH_ARC_ENABLED __has_feature(objc_arc)
|
jamie@264
|
999 #else
|
jamie@264
|
1000 #define CATCH_ARC_ENABLED 0
|
jamie@264
|
1001 #endif
|
jamie@264
|
1002
|
jamie@264
|
1003 void arcSafeRelease( NSObject* obj );
|
jamie@264
|
1004 id performOptionalSelector( id obj, SEL sel );
|
jamie@264
|
1005
|
jamie@264
|
1006 #if !CATCH_ARC_ENABLED
|
jamie@264
|
1007 inline void arcSafeRelease( NSObject* obj ) {
|
jamie@264
|
1008 [obj release];
|
jamie@264
|
1009 }
|
jamie@264
|
1010 inline id performOptionalSelector( id obj, SEL sel ) {
|
jamie@264
|
1011 if( [obj respondsToSelector: sel] )
|
jamie@264
|
1012 return [obj performSelector: sel];
|
jamie@264
|
1013 return nil;
|
jamie@264
|
1014 }
|
jamie@264
|
1015 #define CATCH_UNSAFE_UNRETAINED
|
jamie@264
|
1016 #define CATCH_ARC_STRONG
|
jamie@264
|
1017 #else
|
jamie@264
|
1018 inline void arcSafeRelease( NSObject* ){}
|
jamie@264
|
1019 inline id performOptionalSelector( id obj, SEL sel ) {
|
jamie@264
|
1020 #ifdef __clang__
|
jamie@264
|
1021 #pragma clang diagnostic push
|
jamie@264
|
1022 #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
|
jamie@264
|
1023 #endif
|
jamie@264
|
1024 if( [obj respondsToSelector: sel] )
|
jamie@264
|
1025 return [obj performSelector: sel];
|
jamie@264
|
1026 #ifdef __clang__
|
jamie@264
|
1027 #pragma clang diagnostic pop
|
jamie@264
|
1028 #endif
|
jamie@264
|
1029 return nil;
|
jamie@264
|
1030 }
|
jamie@264
|
1031 #define CATCH_UNSAFE_UNRETAINED __unsafe_unretained
|
jamie@264
|
1032 #define CATCH_ARC_STRONG __strong
|
jamie@264
|
1033 #endif
|
jamie@264
|
1034
|
jamie@264
|
1035 #endif
|
jamie@264
|
1036
|
jamie@264
|
1037 namespace Catch {
|
jamie@264
|
1038 namespace Detail {
|
jamie@264
|
1039
|
jamie@264
|
1040 // SFINAE is currently disabled by default for all compilers.
|
jamie@264
|
1041 // If the non SFINAE version of IsStreamInsertable is ambiguous for you
|
jamie@264
|
1042 // and your compiler supports SFINAE, try #defining CATCH_CONFIG_SFINAE
|
jamie@264
|
1043 #ifdef CATCH_CONFIG_SFINAE
|
jamie@264
|
1044
|
jamie@264
|
1045 template<typename T>
|
jamie@264
|
1046 class IsStreamInsertableHelper {
|
jamie@264
|
1047 template<int N> struct TrueIfSizeable : TrueType {};
|
jamie@264
|
1048
|
jamie@264
|
1049 template<typename T2>
|
jamie@264
|
1050 static TrueIfSizeable<sizeof((*(std::ostream*)0) << *((T2 const*)0))> dummy(T2*);
|
jamie@264
|
1051 static FalseType dummy(...);
|
jamie@264
|
1052
|
jamie@264
|
1053 public:
|
jamie@264
|
1054 typedef SizedIf<sizeof(dummy((T*)0))> type;
|
jamie@264
|
1055 };
|
jamie@264
|
1056
|
jamie@264
|
1057 template<typename T>
|
jamie@264
|
1058 struct IsStreamInsertable : IsStreamInsertableHelper<T>::type {};
|
jamie@264
|
1059
|
jamie@264
|
1060 #else
|
jamie@264
|
1061
|
jamie@264
|
1062 struct BorgType {
|
jamie@264
|
1063 template<typename T> BorgType( T const& );
|
jamie@264
|
1064 };
|
jamie@264
|
1065
|
jamie@264
|
1066 TrueType& testStreamable( std::ostream& );
|
jamie@264
|
1067 FalseType testStreamable( FalseType );
|
jamie@264
|
1068
|
jamie@264
|
1069 FalseType operator<<( std::ostream const&, BorgType const& );
|
jamie@264
|
1070
|
jamie@264
|
1071 template<typename T>
|
jamie@264
|
1072 struct IsStreamInsertable {
|
jamie@264
|
1073 static std::ostream &s;
|
jamie@264
|
1074 static T const&t;
|
jamie@264
|
1075 enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) };
|
jamie@264
|
1076 };
|
jamie@264
|
1077
|
jamie@264
|
1078 #endif
|
jamie@264
|
1079
|
jamie@264
|
1080 template<bool C>
|
jamie@264
|
1081 struct StringMakerBase {
|
jamie@264
|
1082 template<typename T>
|
jamie@264
|
1083 static std::string convert( T const& ) { return "{?}"; }
|
jamie@264
|
1084 };
|
jamie@264
|
1085
|
jamie@264
|
1086 template<>
|
jamie@264
|
1087 struct StringMakerBase<true> {
|
jamie@264
|
1088 template<typename T>
|
jamie@264
|
1089 static std::string convert( T const& _value ) {
|
jamie@264
|
1090 std::ostringstream oss;
|
jamie@264
|
1091 oss << _value;
|
jamie@264
|
1092 return oss.str();
|
jamie@264
|
1093 }
|
jamie@264
|
1094 };
|
jamie@264
|
1095
|
jamie@264
|
1096 std::string rawMemoryToString( const void *object, std::size_t size );
|
jamie@264
|
1097
|
jamie@264
|
1098 template<typename T>
|
jamie@264
|
1099 inline std::string rawMemoryToString( const T& object ) {
|
jamie@264
|
1100 return rawMemoryToString( &object, sizeof(object) );
|
jamie@264
|
1101 }
|
jamie@264
|
1102
|
jamie@264
|
1103 } // end namespace Detail
|
jamie@264
|
1104
|
jamie@264
|
1105 template<typename T>
|
jamie@264
|
1106 std::string toString( T const& value );
|
jamie@264
|
1107
|
jamie@264
|
1108 template<typename T>
|
jamie@264
|
1109 struct StringMaker :
|
jamie@264
|
1110 Detail::StringMakerBase<Detail::IsStreamInsertable<T>::value> {};
|
jamie@264
|
1111
|
jamie@264
|
1112 template<typename T>
|
jamie@264
|
1113 struct StringMaker<T*> {
|
jamie@264
|
1114 template<typename U>
|
jamie@264
|
1115 static std::string convert( U* p ) {
|
jamie@264
|
1116 if( !p )
|
jamie@264
|
1117 return INTERNAL_CATCH_STRINGIFY( NULL );
|
jamie@264
|
1118 else
|
jamie@264
|
1119 return Detail::rawMemoryToString( p );
|
jamie@264
|
1120 }
|
jamie@264
|
1121 };
|
jamie@264
|
1122
|
jamie@264
|
1123 template<typename R, typename C>
|
jamie@264
|
1124 struct StringMaker<R C::*> {
|
jamie@264
|
1125 static std::string convert( R C::* p ) {
|
jamie@264
|
1126 if( !p )
|
jamie@264
|
1127 return INTERNAL_CATCH_STRINGIFY( NULL );
|
jamie@264
|
1128 else
|
jamie@264
|
1129 return Detail::rawMemoryToString( p );
|
jamie@264
|
1130 }
|
jamie@264
|
1131 };
|
jamie@264
|
1132
|
jamie@264
|
1133 namespace Detail {
|
jamie@264
|
1134 template<typename InputIterator>
|
jamie@264
|
1135 std::string rangeToString( InputIterator first, InputIterator last );
|
jamie@264
|
1136 }
|
jamie@264
|
1137
|
jamie@264
|
1138 template<typename T, typename Allocator>
|
jamie@264
|
1139 struct StringMaker<std::vector<T, Allocator> > {
|
jamie@264
|
1140 static std::string convert( std::vector<T,Allocator> const& v ) {
|
jamie@264
|
1141 return Detail::rangeToString( v.begin(), v.end() );
|
jamie@264
|
1142 }
|
jamie@264
|
1143 };
|
jamie@264
|
1144
|
jamie@264
|
1145 namespace Detail {
|
jamie@264
|
1146 template<typename T>
|
jamie@264
|
1147 std::string makeString( T const& value ) {
|
jamie@264
|
1148 return StringMaker<T>::convert( value );
|
jamie@264
|
1149 }
|
jamie@264
|
1150 } // end namespace Detail
|
jamie@264
|
1151
|
jamie@264
|
1152 /// \brief converts any type to a string
|
jamie@264
|
1153 ///
|
jamie@264
|
1154 /// The default template forwards on to ostringstream - except when an
|
jamie@264
|
1155 /// ostringstream overload does not exist - in which case it attempts to detect
|
jamie@264
|
1156 /// that and writes {?}.
|
jamie@264
|
1157 /// Overload (not specialise) this template for custom typs that you don't want
|
jamie@264
|
1158 /// to provide an ostream overload for.
|
jamie@264
|
1159 template<typename T>
|
jamie@264
|
1160 std::string toString( T const& value ) {
|
jamie@264
|
1161 return StringMaker<T>::convert( value );
|
jamie@264
|
1162 }
|
jamie@264
|
1163
|
jamie@264
|
1164 // Built in overloads
|
jamie@264
|
1165
|
jamie@264
|
1166 std::string toString( std::string const& value );
|
jamie@264
|
1167 std::string toString( std::wstring const& value );
|
jamie@264
|
1168 std::string toString( const char* const value );
|
jamie@264
|
1169 std::string toString( char* const value );
|
jamie@264
|
1170 std::string toString( const wchar_t* const value );
|
jamie@264
|
1171 std::string toString( wchar_t* const value );
|
jamie@264
|
1172 std::string toString( int value );
|
jamie@264
|
1173 std::string toString( unsigned long value );
|
jamie@264
|
1174 std::string toString( unsigned int value );
|
jamie@264
|
1175 std::string toString( const double value );
|
jamie@264
|
1176 std::string toString( const float value );
|
jamie@264
|
1177 std::string toString( bool value );
|
jamie@264
|
1178 std::string toString( char value );
|
jamie@264
|
1179 std::string toString( signed char value );
|
jamie@264
|
1180 std::string toString( unsigned char value );
|
jamie@264
|
1181
|
jamie@264
|
1182 #ifdef CATCH_CONFIG_CPP11_NULLPTR
|
jamie@264
|
1183 std::string toString( std::nullptr_t );
|
jamie@264
|
1184 #endif
|
jamie@264
|
1185
|
jamie@264
|
1186 #ifdef __OBJC__
|
jamie@264
|
1187 std::string toString( NSString const * const& nsstring );
|
jamie@264
|
1188 std::string toString( NSString * CATCH_ARC_STRONG const& nsstring );
|
jamie@264
|
1189 std::string toString( NSObject* const& nsObject );
|
jamie@264
|
1190 #endif
|
jamie@264
|
1191
|
jamie@264
|
1192 namespace Detail {
|
jamie@264
|
1193 template<typename InputIterator>
|
jamie@264
|
1194 std::string rangeToString( InputIterator first, InputIterator last ) {
|
jamie@264
|
1195 std::ostringstream oss;
|
jamie@264
|
1196 oss << "{ ";
|
jamie@264
|
1197 if( first != last ) {
|
jamie@264
|
1198 oss << toString( *first );
|
jamie@264
|
1199 for( ++first ; first != last ; ++first ) {
|
jamie@264
|
1200 oss << ", " << toString( *first );
|
jamie@264
|
1201 }
|
jamie@264
|
1202 }
|
jamie@264
|
1203 oss << " }";
|
jamie@264
|
1204 return oss.str();
|
jamie@264
|
1205 }
|
jamie@264
|
1206 }
|
jamie@264
|
1207
|
jamie@264
|
1208 } // end namespace Catch
|
jamie@264
|
1209
|
jamie@264
|
1210 namespace Catch {
|
jamie@264
|
1211
|
jamie@264
|
1212 // Wraps the LHS of an expression and captures the operator and RHS (if any) -
|
jamie@264
|
1213 // wrapping them all in a ResultBuilder object
|
jamie@264
|
1214 template<typename T>
|
jamie@264
|
1215 class ExpressionLhs {
|
jamie@264
|
1216 ExpressionLhs& operator = ( ExpressionLhs const& );
|
jamie@264
|
1217 # ifdef CATCH_CPP11_OR_GREATER
|
jamie@264
|
1218 ExpressionLhs& operator = ( ExpressionLhs && ) = delete;
|
jamie@264
|
1219 # endif
|
jamie@264
|
1220
|
jamie@264
|
1221 public:
|
jamie@264
|
1222 ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {}
|
jamie@264
|
1223 # ifdef CATCH_CPP11_OR_GREATER
|
jamie@264
|
1224 ExpressionLhs( ExpressionLhs const& ) = default;
|
jamie@264
|
1225 ExpressionLhs( ExpressionLhs && ) = default;
|
jamie@264
|
1226 # endif
|
jamie@264
|
1227
|
jamie@264
|
1228 template<typename RhsT>
|
jamie@264
|
1229 ResultBuilder& operator == ( RhsT const& rhs ) {
|
jamie@264
|
1230 return captureExpression<Internal::IsEqualTo>( rhs );
|
jamie@264
|
1231 }
|
jamie@264
|
1232
|
jamie@264
|
1233 template<typename RhsT>
|
jamie@264
|
1234 ResultBuilder& operator != ( RhsT const& rhs ) {
|
jamie@264
|
1235 return captureExpression<Internal::IsNotEqualTo>( rhs );
|
jamie@264
|
1236 }
|
jamie@264
|
1237
|
jamie@264
|
1238 template<typename RhsT>
|
jamie@264
|
1239 ResultBuilder& operator < ( RhsT const& rhs ) {
|
jamie@264
|
1240 return captureExpression<Internal::IsLessThan>( rhs );
|
jamie@264
|
1241 }
|
jamie@264
|
1242
|
jamie@264
|
1243 template<typename RhsT>
|
jamie@264
|
1244 ResultBuilder& operator > ( RhsT const& rhs ) {
|
jamie@264
|
1245 return captureExpression<Internal::IsGreaterThan>( rhs );
|
jamie@264
|
1246 }
|
jamie@264
|
1247
|
jamie@264
|
1248 template<typename RhsT>
|
jamie@264
|
1249 ResultBuilder& operator <= ( RhsT const& rhs ) {
|
jamie@264
|
1250 return captureExpression<Internal::IsLessThanOrEqualTo>( rhs );
|
jamie@264
|
1251 }
|
jamie@264
|
1252
|
jamie@264
|
1253 template<typename RhsT>
|
jamie@264
|
1254 ResultBuilder& operator >= ( RhsT const& rhs ) {
|
jamie@264
|
1255 return captureExpression<Internal::IsGreaterThanOrEqualTo>( rhs );
|
jamie@264
|
1256 }
|
jamie@264
|
1257
|
jamie@264
|
1258 ResultBuilder& operator == ( bool rhs ) {
|
jamie@264
|
1259 return captureExpression<Internal::IsEqualTo>( rhs );
|
jamie@264
|
1260 }
|
jamie@264
|
1261
|
jamie@264
|
1262 ResultBuilder& operator != ( bool rhs ) {
|
jamie@264
|
1263 return captureExpression<Internal::IsNotEqualTo>( rhs );
|
jamie@264
|
1264 }
|
jamie@264
|
1265
|
jamie@264
|
1266 void endExpression() {
|
jamie@264
|
1267 bool value = m_lhs ? true : false;
|
jamie@264
|
1268 m_rb
|
jamie@264
|
1269 .setLhs( Catch::toString( value ) )
|
jamie@264
|
1270 .setResultType( value )
|
jamie@264
|
1271 .endExpression();
|
jamie@264
|
1272 }
|
jamie@264
|
1273
|
jamie@264
|
1274 // Only simple binary expressions are allowed on the LHS.
|
jamie@264
|
1275 // If more complex compositions are required then place the sub expression in parentheses
|
jamie@264
|
1276 template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( RhsT const& );
|
jamie@264
|
1277 template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( RhsT const& );
|
jamie@264
|
1278 template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( RhsT const& );
|
jamie@264
|
1279 template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( RhsT const& );
|
jamie@264
|
1280 template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& );
|
jamie@264
|
1281 template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& );
|
jamie@264
|
1282
|
jamie@264
|
1283 private:
|
jamie@264
|
1284 template<Internal::Operator Op, typename RhsT>
|
jamie@264
|
1285 ResultBuilder& captureExpression( RhsT const& rhs ) {
|
jamie@264
|
1286 return m_rb
|
jamie@264
|
1287 .setResultType( Internal::compare<Op>( m_lhs, rhs ) )
|
jamie@264
|
1288 .setLhs( Catch::toString( m_lhs ) )
|
jamie@264
|
1289 .setRhs( Catch::toString( rhs ) )
|
jamie@264
|
1290 .setOp( Internal::OperatorTraits<Op>::getName() );
|
jamie@264
|
1291 }
|
jamie@264
|
1292
|
jamie@264
|
1293 private:
|
jamie@264
|
1294 ResultBuilder& m_rb;
|
jamie@264
|
1295 T m_lhs;
|
jamie@264
|
1296 };
|
jamie@264
|
1297
|
jamie@264
|
1298 } // end namespace Catch
|
jamie@264
|
1299
|
jamie@264
|
1300
|
jamie@264
|
1301 namespace Catch {
|
jamie@264
|
1302
|
jamie@264
|
1303 template<typename T>
|
jamie@264
|
1304 inline ExpressionLhs<T const&> ResultBuilder::operator->* ( T const& operand ) {
|
jamie@264
|
1305 return ExpressionLhs<T const&>( *this, operand );
|
jamie@264
|
1306 }
|
jamie@264
|
1307
|
jamie@264
|
1308 inline ExpressionLhs<bool> ResultBuilder::operator->* ( bool value ) {
|
jamie@264
|
1309 return ExpressionLhs<bool>( *this, value );
|
jamie@264
|
1310 }
|
jamie@264
|
1311
|
jamie@264
|
1312 } // namespace Catch
|
jamie@264
|
1313
|
jamie@264
|
1314 // #included from: catch_message.h
|
jamie@264
|
1315 #define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED
|
jamie@264
|
1316
|
jamie@264
|
1317 #include <string>
|
jamie@264
|
1318
|
jamie@264
|
1319 namespace Catch {
|
jamie@264
|
1320
|
jamie@264
|
1321 struct MessageInfo {
|
jamie@264
|
1322 MessageInfo( std::string const& _macroName,
|
jamie@264
|
1323 SourceLineInfo const& _lineInfo,
|
jamie@264
|
1324 ResultWas::OfType _type );
|
jamie@264
|
1325
|
jamie@264
|
1326 std::string macroName;
|
jamie@264
|
1327 SourceLineInfo lineInfo;
|
jamie@264
|
1328 ResultWas::OfType type;
|
jamie@264
|
1329 std::string message;
|
jamie@264
|
1330 unsigned int sequence;
|
jamie@264
|
1331
|
jamie@264
|
1332 bool operator == ( MessageInfo const& other ) const {
|
jamie@264
|
1333 return sequence == other.sequence;
|
jamie@264
|
1334 }
|
jamie@264
|
1335 bool operator < ( MessageInfo const& other ) const {
|
jamie@264
|
1336 return sequence < other.sequence;
|
jamie@264
|
1337 }
|
jamie@264
|
1338 private:
|
jamie@264
|
1339 static unsigned int globalCount;
|
jamie@264
|
1340 };
|
jamie@264
|
1341
|
jamie@264
|
1342 struct MessageBuilder {
|
jamie@264
|
1343 MessageBuilder( std::string const& macroName,
|
jamie@264
|
1344 SourceLineInfo const& lineInfo,
|
jamie@264
|
1345 ResultWas::OfType type )
|
jamie@264
|
1346 : m_info( macroName, lineInfo, type )
|
jamie@264
|
1347 {}
|
jamie@264
|
1348
|
jamie@264
|
1349 template<typename T>
|
jamie@264
|
1350 MessageBuilder& operator << ( T const& value ) {
|
jamie@264
|
1351 m_stream << value;
|
jamie@264
|
1352 return *this;
|
jamie@264
|
1353 }
|
jamie@264
|
1354
|
jamie@264
|
1355 MessageInfo m_info;
|
jamie@264
|
1356 std::ostringstream m_stream;
|
jamie@264
|
1357 };
|
jamie@264
|
1358
|
jamie@264
|
1359 class ScopedMessage {
|
jamie@264
|
1360 public:
|
jamie@264
|
1361 ScopedMessage( MessageBuilder const& builder );
|
jamie@264
|
1362 ScopedMessage( ScopedMessage const& other );
|
jamie@264
|
1363 ~ScopedMessage();
|
jamie@264
|
1364
|
jamie@264
|
1365 MessageInfo m_info;
|
jamie@264
|
1366 };
|
jamie@264
|
1367
|
jamie@264
|
1368 } // end namespace Catch
|
jamie@264
|
1369
|
jamie@264
|
1370 // #included from: catch_interfaces_capture.h
|
jamie@264
|
1371 #define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED
|
jamie@264
|
1372
|
jamie@264
|
1373 #include <string>
|
jamie@264
|
1374
|
jamie@264
|
1375 namespace Catch {
|
jamie@264
|
1376
|
jamie@264
|
1377 class TestCase;
|
jamie@264
|
1378 class AssertionResult;
|
jamie@264
|
1379 struct AssertionInfo;
|
jamie@264
|
1380 struct SectionInfo;
|
jamie@264
|
1381 struct MessageInfo;
|
jamie@264
|
1382 class ScopedMessageBuilder;
|
jamie@264
|
1383 struct Counts;
|
jamie@264
|
1384
|
jamie@264
|
1385 struct IResultCapture {
|
jamie@264
|
1386
|
jamie@264
|
1387 virtual ~IResultCapture();
|
jamie@264
|
1388
|
jamie@264
|
1389 virtual void assertionEnded( AssertionResult const& result ) = 0;
|
jamie@264
|
1390 virtual bool sectionStarted( SectionInfo const& sectionInfo,
|
jamie@264
|
1391 Counts& assertions ) = 0;
|
jamie@264
|
1392 virtual void sectionEnded( SectionInfo const& name, Counts const& assertions, double _durationInSeconds ) = 0;
|
jamie@264
|
1393 virtual void pushScopedMessage( MessageInfo const& message ) = 0;
|
jamie@264
|
1394 virtual void popScopedMessage( MessageInfo const& message ) = 0;
|
jamie@264
|
1395
|
jamie@264
|
1396 virtual std::string getCurrentTestName() const = 0;
|
jamie@264
|
1397 virtual const AssertionResult* getLastResult() const = 0;
|
jamie@264
|
1398 };
|
jamie@264
|
1399
|
jamie@264
|
1400 IResultCapture& getResultCapture();
|
jamie@264
|
1401 }
|
jamie@264
|
1402
|
jamie@264
|
1403 // #included from: catch_debugger.h
|
jamie@264
|
1404 #define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED
|
jamie@264
|
1405
|
jamie@264
|
1406 // #included from: catch_platform.h
|
jamie@264
|
1407 #define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED
|
jamie@264
|
1408
|
jamie@264
|
1409 #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
|
jamie@264
|
1410 #define CATCH_PLATFORM_MAC
|
jamie@264
|
1411 #elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
|
jamie@264
|
1412 #define CATCH_PLATFORM_IPHONE
|
jamie@264
|
1413 #elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
|
jamie@264
|
1414 #define CATCH_PLATFORM_WINDOWS
|
jamie@264
|
1415 #endif
|
jamie@264
|
1416
|
jamie@264
|
1417 #include <string>
|
jamie@264
|
1418
|
jamie@264
|
1419 namespace Catch{
|
jamie@264
|
1420
|
jamie@264
|
1421 bool isDebuggerActive();
|
jamie@264
|
1422 void writeToDebugConsole( std::string const& text );
|
jamie@264
|
1423 }
|
jamie@264
|
1424
|
jamie@264
|
1425 #ifdef CATCH_PLATFORM_MAC
|
jamie@264
|
1426
|
jamie@264
|
1427 // The following code snippet based on:
|
jamie@264
|
1428 // http://cocoawithlove.com/2008/03/break-into-debugger.html
|
jamie@264
|
1429 #ifdef DEBUG
|
jamie@264
|
1430 #if defined(__ppc64__) || defined(__ppc__)
|
jamie@264
|
1431 #define CATCH_BREAK_INTO_DEBUGGER() \
|
jamie@264
|
1432 if( Catch::isDebuggerActive() ) { \
|
jamie@264
|
1433 __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
|
jamie@264
|
1434 : : : "memory","r0","r3","r4" ); \
|
jamie@264
|
1435 }
|
jamie@264
|
1436 #else
|
jamie@264
|
1437 #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );}
|
jamie@264
|
1438 #endif
|
jamie@264
|
1439 #endif
|
jamie@264
|
1440
|
jamie@264
|
1441 #elif defined(_MSC_VER)
|
jamie@264
|
1442 #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { __debugbreak(); }
|
jamie@264
|
1443 #elif defined(__MINGW32__)
|
jamie@264
|
1444 extern "C" __declspec(dllimport) void __stdcall DebugBreak();
|
jamie@264
|
1445 #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { DebugBreak(); }
|
jamie@264
|
1446 #endif
|
jamie@264
|
1447
|
jamie@264
|
1448 #ifndef CATCH_BREAK_INTO_DEBUGGER
|
jamie@264
|
1449 #define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue();
|
jamie@264
|
1450 #endif
|
jamie@264
|
1451
|
jamie@264
|
1452 // #included from: catch_interfaces_runner.h
|
jamie@264
|
1453 #define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED
|
jamie@264
|
1454
|
jamie@264
|
1455 namespace Catch {
|
jamie@264
|
1456 class TestCase;
|
jamie@264
|
1457
|
jamie@264
|
1458 struct IRunner {
|
jamie@264
|
1459 virtual ~IRunner();
|
jamie@264
|
1460 virtual bool aborting() const = 0;
|
jamie@264
|
1461 };
|
jamie@264
|
1462 }
|
jamie@264
|
1463
|
jamie@264
|
1464 ///////////////////////////////////////////////////////////////////////////////
|
jamie@264
|
1465 // In the event of a failure works out if the debugger needs to be invoked
|
jamie@264
|
1466 // and/or an exception thrown and takes appropriate action.
|
jamie@264
|
1467 // This needs to be done as a macro so the debugger will stop in the user
|
jamie@264
|
1468 // source code rather than in Catch library code
|
jamie@264
|
1469 #define INTERNAL_CATCH_REACT( resultBuilder ) \
|
jamie@264
|
1470 if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \
|
jamie@264
|
1471 resultBuilder.react();
|
jamie@264
|
1472
|
jamie@264
|
1473 ///////////////////////////////////////////////////////////////////////////////
|
jamie@264
|
1474 #define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \
|
jamie@264
|
1475 do { \
|
jamie@264
|
1476 Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
|
jamie@264
|
1477 try { \
|
jamie@264
|
1478 ( __catchResult->*expr ).endExpression(); \
|
jamie@264
|
1479 } \
|
jamie@264
|
1480 catch( ... ) { \
|
jamie@264
|
1481 __catchResult.useActiveException( Catch::ResultDisposition::Normal ); \
|
jamie@264
|
1482 } \
|
jamie@264
|
1483 INTERNAL_CATCH_REACT( __catchResult ) \
|
jamie@264
|
1484 } while( Catch::isTrue( false && (expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look
|
jamie@264
|
1485
|
jamie@264
|
1486 ///////////////////////////////////////////////////////////////////////////////
|
jamie@264
|
1487 #define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \
|
jamie@264
|
1488 INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \
|
jamie@264
|
1489 if( Catch::getResultCapture().getLastResult()->succeeded() )
|
jamie@264
|
1490
|
jamie@264
|
1491 ///////////////////////////////////////////////////////////////////////////////
|
jamie@264
|
1492 #define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \
|
jamie@264
|
1493 INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \
|
jamie@264
|
1494 if( !Catch::getResultCapture().getLastResult()->succeeded() )
|
jamie@264
|
1495
|
jamie@264
|
1496 ///////////////////////////////////////////////////////////////////////////////
|
jamie@264
|
1497 #define INTERNAL_CATCH_NO_THROW( expr, resultDisposition, macroName ) \
|
jamie@264
|
1498 do { \
|
jamie@264
|
1499 Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
|
jamie@264
|
1500 try { \
|
jamie@264
|
1501 expr; \
|
jamie@264
|
1502 __catchResult.captureResult( Catch::ResultWas::Ok ); \
|
jamie@264
|
1503 } \
|
jamie@264
|
1504 catch( ... ) { \
|
jamie@264
|
1505 __catchResult.useActiveException( resultDisposition ); \
|
jamie@264
|
1506 } \
|
jamie@264
|
1507 INTERNAL_CATCH_REACT( __catchResult ) \
|
jamie@264
|
1508 } while( Catch::alwaysFalse() )
|
jamie@264
|
1509
|
jamie@264
|
1510 ///////////////////////////////////////////////////////////////////////////////
|
jamie@264
|
1511 #define INTERNAL_CATCH_THROWS( expr, resultDisposition, macroName ) \
|
jamie@264
|
1512 do { \
|
jamie@264
|
1513 Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
|
jamie@264
|
1514 if( __catchResult.allowThrows() ) \
|
jamie@264
|
1515 try { \
|
jamie@264
|
1516 expr; \
|
jamie@264
|
1517 __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
|
jamie@264
|
1518 } \
|
jamie@264
|
1519 catch( ... ) { \
|
jamie@264
|
1520 __catchResult.captureResult( Catch::ResultWas::Ok ); \
|
jamie@264
|
1521 } \
|
jamie@264
|
1522 else \
|
jamie@264
|
1523 __catchResult.captureResult( Catch::ResultWas::Ok ); \
|
jamie@264
|
1524 INTERNAL_CATCH_REACT( __catchResult ) \
|
jamie@264
|
1525 } while( Catch::alwaysFalse() )
|
jamie@264
|
1526
|
jamie@264
|
1527 ///////////////////////////////////////////////////////////////////////////////
|
jamie@264
|
1528 #define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \
|
jamie@264
|
1529 do { \
|
jamie@264
|
1530 Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
|
jamie@264
|
1531 if( __catchResult.allowThrows() ) \
|
jamie@264
|
1532 try { \
|
jamie@264
|
1533 expr; \
|
jamie@264
|
1534 __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
|
jamie@264
|
1535 } \
|
jamie@264
|
1536 catch( exceptionType ) { \
|
jamie@264
|
1537 __catchResult.captureResult( Catch::ResultWas::Ok ); \
|
jamie@264
|
1538 } \
|
jamie@264
|
1539 catch( ... ) { \
|
jamie@264
|
1540 __catchResult.useActiveException( resultDisposition ); \
|
jamie@264
|
1541 } \
|
jamie@264
|
1542 else \
|
jamie@264
|
1543 __catchResult.captureResult( Catch::ResultWas::Ok ); \
|
jamie@264
|
1544 INTERNAL_CATCH_REACT( __catchResult ) \
|
jamie@264
|
1545 } while( Catch::alwaysFalse() )
|
jamie@264
|
1546
|
jamie@264
|
1547 ///////////////////////////////////////////////////////////////////////////////
|
jamie@264
|
1548 #ifdef CATCH_CONFIG_VARIADIC_MACROS
|
jamie@264
|
1549 #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, ... ) \
|
jamie@264
|
1550 do { \
|
jamie@264
|
1551 Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
|
jamie@264
|
1552 __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \
|
jamie@264
|
1553 __catchResult.captureResult( messageType ); \
|
jamie@264
|
1554 INTERNAL_CATCH_REACT( __catchResult ) \
|
jamie@264
|
1555 } while( Catch::alwaysFalse() )
|
jamie@264
|
1556 #else
|
jamie@264
|
1557 #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, log ) \
|
jamie@264
|
1558 do { \
|
jamie@264
|
1559 Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
|
jamie@264
|
1560 __catchResult << log + ::Catch::StreamEndStop(); \
|
jamie@264
|
1561 __catchResult.captureResult( messageType ); \
|
jamie@264
|
1562 INTERNAL_CATCH_REACT( __catchResult ) \
|
jamie@264
|
1563 } while( Catch::alwaysFalse() )
|
jamie@264
|
1564 #endif
|
jamie@264
|
1565
|
jamie@264
|
1566 ///////////////////////////////////////////////////////////////////////////////
|
jamie@264
|
1567 #define INTERNAL_CATCH_INFO( log, macroName ) \
|
jamie@264
|
1568 Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log;
|
jamie@264
|
1569
|
jamie@264
|
1570 ///////////////////////////////////////////////////////////////////////////////
|
jamie@264
|
1571 #define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \
|
jamie@264
|
1572 do { \
|
jamie@264
|
1573 Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg " " #matcher, resultDisposition ); \
|
jamie@264
|
1574 try { \
|
jamie@264
|
1575 std::string matcherAsString = ::Catch::Matchers::matcher.toString(); \
|
jamie@264
|
1576 __catchResult \
|
jamie@264
|
1577 .setLhs( Catch::toString( arg ) ) \
|
jamie@264
|
1578 .setRhs( matcherAsString == "{?}" ? #matcher : matcherAsString ) \
|
jamie@264
|
1579 .setOp( "matches" ) \
|
jamie@264
|
1580 .setResultType( ::Catch::Matchers::matcher.match( arg ) ); \
|
jamie@264
|
1581 __catchResult.captureExpression(); \
|
jamie@264
|
1582 } catch( ... ) { \
|
jamie@264
|
1583 __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \
|
jamie@264
|
1584 } \
|
jamie@264
|
1585 INTERNAL_CATCH_REACT( __catchResult ) \
|
jamie@264
|
1586 } while( Catch::alwaysFalse() )
|
jamie@264
|
1587
|
jamie@264
|
1588 // #included from: internal/catch_section.h
|
jamie@264
|
1589 #define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED
|
jamie@264
|
1590
|
jamie@264
|
1591 // #included from: catch_section_info.h
|
jamie@264
|
1592 #define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED
|
jamie@264
|
1593
|
jamie@264
|
1594 namespace Catch {
|
jamie@264
|
1595
|
jamie@264
|
1596 struct SectionInfo {
|
jamie@264
|
1597 SectionInfo
|
jamie@264
|
1598 ( SourceLineInfo const& _lineInfo,
|
jamie@264
|
1599 std::string const& _name,
|
jamie@264
|
1600 std::string const& _description = std::string() );
|
jamie@264
|
1601
|
jamie@264
|
1602 std::string name;
|
jamie@264
|
1603 std::string description;
|
jamie@264
|
1604 SourceLineInfo lineInfo;
|
jamie@264
|
1605 };
|
jamie@264
|
1606
|
jamie@264
|
1607 } // end namespace Catch
|
jamie@264
|
1608
|
jamie@264
|
1609 // #included from: catch_totals.hpp
|
jamie@264
|
1610 #define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED
|
jamie@264
|
1611
|
jamie@264
|
1612 #include <cstddef>
|
jamie@264
|
1613
|
jamie@264
|
1614 namespace Catch {
|
jamie@264
|
1615
|
jamie@264
|
1616 struct Counts {
|
jamie@264
|
1617 Counts() : passed( 0 ), failed( 0 ), failedButOk( 0 ) {}
|
jamie@264
|
1618
|
jamie@264
|
1619 Counts operator - ( Counts const& other ) const {
|
jamie@264
|
1620 Counts diff;
|
jamie@264
|
1621 diff.passed = passed - other.passed;
|
jamie@264
|
1622 diff.failed = failed - other.failed;
|
jamie@264
|
1623 diff.failedButOk = failedButOk - other.failedButOk;
|
jamie@264
|
1624 return diff;
|
jamie@264
|
1625 }
|
jamie@264
|
1626 Counts& operator += ( Counts const& other ) {
|
jamie@264
|
1627 passed += other.passed;
|
jamie@264
|
1628 failed += other.failed;
|
jamie@264
|
1629 failedButOk += other.failedButOk;
|
jamie@264
|
1630 return *this;
|
jamie@264
|
1631 }
|
jamie@264
|
1632
|
jamie@264
|
1633 std::size_t total() const {
|
jamie@264
|
1634 return passed + failed + failedButOk;
|
jamie@264
|
1635 }
|
jamie@264
|
1636 bool allPassed() const {
|
jamie@264
|
1637 return failed == 0 && failedButOk == 0;
|
jamie@264
|
1638 }
|
jamie@264
|
1639
|
jamie@264
|
1640 std::size_t passed;
|
jamie@264
|
1641 std::size_t failed;
|
jamie@264
|
1642 std::size_t failedButOk;
|
jamie@264
|
1643 };
|
jamie@264
|
1644
|
jamie@264
|
1645 struct Totals {
|
jamie@264
|
1646
|
jamie@264
|
1647 Totals operator - ( Totals const& other ) const {
|
jamie@264
|
1648 Totals diff;
|
jamie@264
|
1649 diff.assertions = assertions - other.assertions;
|
jamie@264
|
1650 diff.testCases = testCases - other.testCases;
|
jamie@264
|
1651 return diff;
|
jamie@264
|
1652 }
|
jamie@264
|
1653
|
jamie@264
|
1654 Totals delta( Totals const& prevTotals ) const {
|
jamie@264
|
1655 Totals diff = *this - prevTotals;
|
jamie@264
|
1656 if( diff.assertions.failed > 0 )
|
jamie@264
|
1657 ++diff.testCases.failed;
|
jamie@264
|
1658 else if( diff.assertions.failedButOk > 0 )
|
jamie@264
|
1659 ++diff.testCases.failedButOk;
|
jamie@264
|
1660 else
|
jamie@264
|
1661 ++diff.testCases.passed;
|
jamie@264
|
1662 return diff;
|
jamie@264
|
1663 }
|
jamie@264
|
1664
|
jamie@264
|
1665 Totals& operator += ( Totals const& other ) {
|
jamie@264
|
1666 assertions += other.assertions;
|
jamie@264
|
1667 testCases += other.testCases;
|
jamie@264
|
1668 return *this;
|
jamie@264
|
1669 }
|
jamie@264
|
1670
|
jamie@264
|
1671 Counts assertions;
|
jamie@264
|
1672 Counts testCases;
|
jamie@264
|
1673 };
|
jamie@264
|
1674 }
|
jamie@264
|
1675
|
jamie@264
|
1676 // #included from: catch_timer.h
|
jamie@264
|
1677 #define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED
|
jamie@264
|
1678
|
jamie@264
|
1679 #ifdef CATCH_PLATFORM_WINDOWS
|
jamie@264
|
1680 typedef unsigned long long uint64_t;
|
jamie@264
|
1681 #else
|
jamie@264
|
1682 #include <stdint.h>
|
jamie@264
|
1683 #endif
|
jamie@264
|
1684
|
jamie@264
|
1685 namespace Catch {
|
jamie@264
|
1686
|
jamie@264
|
1687 class Timer {
|
jamie@264
|
1688 public:
|
jamie@264
|
1689 Timer() : m_ticks( 0 ) {}
|
jamie@264
|
1690 void start();
|
jamie@264
|
1691 unsigned int getElapsedNanoseconds() const;
|
jamie@264
|
1692 unsigned int getElapsedMilliseconds() const;
|
jamie@264
|
1693 double getElapsedSeconds() const;
|
jamie@264
|
1694
|
jamie@264
|
1695 private:
|
jamie@264
|
1696 uint64_t m_ticks;
|
jamie@264
|
1697 };
|
jamie@264
|
1698
|
jamie@264
|
1699 } // namespace Catch
|
jamie@264
|
1700
|
jamie@264
|
1701 #include <string>
|
jamie@264
|
1702
|
jamie@264
|
1703 namespace Catch {
|
jamie@264
|
1704
|
jamie@264
|
1705 class Section {
|
jamie@264
|
1706 public:
|
jamie@264
|
1707 Section( SectionInfo const& info );
|
jamie@264
|
1708 ~Section();
|
jamie@264
|
1709
|
jamie@264
|
1710 // This indicates whether the section should be executed or not
|
jamie@264
|
1711 operator bool() const;
|
jamie@264
|
1712
|
jamie@264
|
1713 private:
|
jamie@264
|
1714 #ifdef CATCH_CPP11_OR_GREATER
|
jamie@264
|
1715 Section( Section const& ) = delete;
|
jamie@264
|
1716 Section( Section && ) = delete;
|
jamie@264
|
1717 Section& operator = ( Section const& ) = delete;
|
jamie@264
|
1718 Section& operator = ( Section && ) = delete;
|
jamie@264
|
1719 #else
|
jamie@264
|
1720 Section( Section const& info );
|
jamie@264
|
1721 Section& operator = ( Section const& );
|
jamie@264
|
1722 #endif
|
jamie@264
|
1723 SectionInfo m_info;
|
jamie@264
|
1724
|
jamie@264
|
1725 std::string m_name;
|
jamie@264
|
1726 Counts m_assertions;
|
jamie@264
|
1727 bool m_sectionIncluded;
|
jamie@264
|
1728 Timer m_timer;
|
jamie@264
|
1729 };
|
jamie@264
|
1730
|
jamie@264
|
1731 } // end namespace Catch
|
jamie@264
|
1732
|
jamie@264
|
1733 #ifdef CATCH_CONFIG_VARIADIC_MACROS
|
jamie@264
|
1734 #define INTERNAL_CATCH_SECTION( ... ) \
|
jamie@264
|
1735 if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) )
|
jamie@264
|
1736 #else
|
jamie@264
|
1737 #define INTERNAL_CATCH_SECTION( name, desc ) \
|
jamie@264
|
1738 if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) )
|
jamie@264
|
1739 #endif
|
jamie@264
|
1740
|
jamie@264
|
1741 // #included from: internal/catch_generators.hpp
|
jamie@264
|
1742 #define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
|
jamie@264
|
1743
|
jamie@264
|
1744 #include <iterator>
|
jamie@264
|
1745 #include <vector>
|
jamie@264
|
1746 #include <string>
|
jamie@264
|
1747 #include <stdlib.h>
|
jamie@264
|
1748
|
jamie@264
|
1749 namespace Catch {
|
jamie@264
|
1750
|
jamie@264
|
1751 template<typename T>
|
jamie@264
|
1752 struct IGenerator {
|
jamie@264
|
1753 virtual ~IGenerator() {}
|
jamie@264
|
1754 virtual T getValue( std::size_t index ) const = 0;
|
jamie@264
|
1755 virtual std::size_t size () const = 0;
|
jamie@264
|
1756 };
|
jamie@264
|
1757
|
jamie@264
|
1758 template<typename T>
|
jamie@264
|
1759 class BetweenGenerator : public IGenerator<T> {
|
jamie@264
|
1760 public:
|
jamie@264
|
1761 BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){}
|
jamie@264
|
1762
|
jamie@264
|
1763 virtual T getValue( std::size_t index ) const {
|
jamie@264
|
1764 return m_from+static_cast<int>( index );
|
jamie@264
|
1765 }
|
jamie@264
|
1766
|
jamie@264
|
1767 virtual std::size_t size() const {
|
jamie@264
|
1768 return static_cast<std::size_t>( 1+m_to-m_from );
|
jamie@264
|
1769 }
|
jamie@264
|
1770
|
jamie@264
|
1771 private:
|
jamie@264
|
1772
|
jamie@264
|
1773 T m_from;
|
jamie@264
|
1774 T m_to;
|
jamie@264
|
1775 };
|
jamie@264
|
1776
|
jamie@264
|
1777 template<typename T>
|
jamie@264
|
1778 class ValuesGenerator : public IGenerator<T> {
|
jamie@264
|
1779 public:
|
jamie@264
|
1780 ValuesGenerator(){}
|
jamie@264
|
1781
|
jamie@264
|
1782 void add( T value ) {
|
jamie@264
|
1783 m_values.push_back( value );
|
jamie@264
|
1784 }
|
jamie@264
|
1785
|
jamie@264
|
1786 virtual T getValue( std::size_t index ) const {
|
jamie@264
|
1787 return m_values[index];
|
jamie@264
|
1788 }
|
jamie@264
|
1789
|
jamie@264
|
1790 virtual std::size_t size() const {
|
jamie@264
|
1791 return m_values.size();
|
jamie@264
|
1792 }
|
jamie@264
|
1793
|
jamie@264
|
1794 private:
|
jamie@264
|
1795 std::vector<T> m_values;
|
jamie@264
|
1796 };
|
jamie@264
|
1797
|
jamie@264
|
1798 template<typename T>
|
jamie@264
|
1799 class CompositeGenerator {
|
jamie@264
|
1800 public:
|
jamie@264
|
1801 CompositeGenerator() : m_totalSize( 0 ) {}
|
jamie@264
|
1802
|
jamie@264
|
1803 // *** Move semantics, similar to auto_ptr ***
|
jamie@264
|
1804 CompositeGenerator( CompositeGenerator& other )
|
jamie@264
|
1805 : m_fileInfo( other.m_fileInfo ),
|
jamie@264
|
1806 m_totalSize( 0 )
|
jamie@264
|
1807 {
|
jamie@264
|
1808 move( other );
|
jamie@264
|
1809 }
|
jamie@264
|
1810
|
jamie@264
|
1811 CompositeGenerator& setFileInfo( const char* fileInfo ) {
|
jamie@264
|
1812 m_fileInfo = fileInfo;
|
jamie@264
|
1813 return *this;
|
jamie@264
|
1814 }
|
jamie@264
|
1815
|
jamie@264
|
1816 ~CompositeGenerator() {
|
jamie@264
|
1817 deleteAll( m_composed );
|
jamie@264
|
1818 }
|
jamie@264
|
1819
|
jamie@264
|
1820 operator T () const {
|
jamie@264
|
1821 size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize );
|
jamie@264
|
1822
|
jamie@264
|
1823 typename std::vector<const IGenerator<T>*>::const_iterator it = m_composed.begin();
|
jamie@264
|
1824 typename std::vector<const IGenerator<T>*>::const_iterator itEnd = m_composed.end();
|
jamie@264
|
1825 for( size_t index = 0; it != itEnd; ++it )
|
jamie@264
|
1826 {
|
jamie@264
|
1827 const IGenerator<T>* generator = *it;
|
jamie@264
|
1828 if( overallIndex >= index && overallIndex < index + generator->size() )
|
jamie@264
|
1829 {
|
jamie@264
|
1830 return generator->getValue( overallIndex-index );
|
jamie@264
|
1831 }
|
jamie@264
|
1832 index += generator->size();
|
jamie@264
|
1833 }
|
jamie@264
|
1834 CATCH_INTERNAL_ERROR( "Indexed past end of generated range" );
|
jamie@264
|
1835 return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so
|
jamie@264
|
1836 }
|
jamie@264
|
1837
|
jamie@264
|
1838 void add( const IGenerator<T>* generator ) {
|
jamie@264
|
1839 m_totalSize += generator->size();
|
jamie@264
|
1840 m_composed.push_back( generator );
|
jamie@264
|
1841 }
|
jamie@264
|
1842
|
jamie@264
|
1843 CompositeGenerator& then( CompositeGenerator& other ) {
|
jamie@264
|
1844 move( other );
|
jamie@264
|
1845 return *this;
|
jamie@264
|
1846 }
|
jamie@264
|
1847
|
jamie@264
|
1848 CompositeGenerator& then( T value ) {
|
jamie@264
|
1849 ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
|
jamie@264
|
1850 valuesGen->add( value );
|
jamie@264
|
1851 add( valuesGen );
|
jamie@264
|
1852 return *this;
|
jamie@264
|
1853 }
|
jamie@264
|
1854
|
jamie@264
|
1855 private:
|
jamie@264
|
1856
|
jamie@264
|
1857 void move( CompositeGenerator& other ) {
|
jamie@264
|
1858 std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) );
|
jamie@264
|
1859 m_totalSize += other.m_totalSize;
|
jamie@264
|
1860 other.m_composed.clear();
|
jamie@264
|
1861 }
|
jamie@264
|
1862
|
jamie@264
|
1863 std::vector<const IGenerator<T>*> m_composed;
|
jamie@264
|
1864 std::string m_fileInfo;
|
jamie@264
|
1865 size_t m_totalSize;
|
jamie@264
|
1866 };
|
jamie@264
|
1867
|
jamie@264
|
1868 namespace Generators
|
jamie@264
|
1869 {
|
jamie@264
|
1870 template<typename T>
|
jamie@264
|
1871 CompositeGenerator<T> between( T from, T to ) {
|
jamie@264
|
1872 CompositeGenerator<T> generators;
|
jamie@264
|
1873 generators.add( new BetweenGenerator<T>( from, to ) );
|
jamie@264
|
1874 return generators;
|
jamie@264
|
1875 }
|
jamie@264
|
1876
|
jamie@264
|
1877 template<typename T>
|
jamie@264
|
1878 CompositeGenerator<T> values( T val1, T val2 ) {
|
jamie@264
|
1879 CompositeGenerator<T> generators;
|
jamie@264
|
1880 ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
|
jamie@264
|
1881 valuesGen->add( val1 );
|
jamie@264
|
1882 valuesGen->add( val2 );
|
jamie@264
|
1883 generators.add( valuesGen );
|
jamie@264
|
1884 return generators;
|
jamie@264
|
1885 }
|
jamie@264
|
1886
|
jamie@264
|
1887 template<typename T>
|
jamie@264
|
1888 CompositeGenerator<T> values( T val1, T val2, T val3 ){
|
jamie@264
|
1889 CompositeGenerator<T> generators;
|
jamie@264
|
1890 ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
|
jamie@264
|
1891 valuesGen->add( val1 );
|
jamie@264
|
1892 valuesGen->add( val2 );
|
jamie@264
|
1893 valuesGen->add( val3 );
|
jamie@264
|
1894 generators.add( valuesGen );
|
jamie@264
|
1895 return generators;
|
jamie@264
|
1896 }
|
jamie@264
|
1897
|
jamie@264
|
1898 template<typename T>
|
jamie@264
|
1899 CompositeGenerator<T> values( T val1, T val2, T val3, T val4 ) {
|
jamie@264
|
1900 CompositeGenerator<T> generators;
|
jamie@264
|
1901 ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
|
jamie@264
|
1902 valuesGen->add( val1 );
|
jamie@264
|
1903 valuesGen->add( val2 );
|
jamie@264
|
1904 valuesGen->add( val3 );
|
jamie@264
|
1905 valuesGen->add( val4 );
|
jamie@264
|
1906 generators.add( valuesGen );
|
jamie@264
|
1907 return generators;
|
jamie@264
|
1908 }
|
jamie@264
|
1909
|
jamie@264
|
1910 } // end namespace Generators
|
jamie@264
|
1911
|
jamie@264
|
1912 using namespace Generators;
|
jamie@264
|
1913
|
jamie@264
|
1914 } // end namespace Catch
|
jamie@264
|
1915
|
jamie@264
|
1916 #define INTERNAL_CATCH_LINESTR2( line ) #line
|
jamie@264
|
1917 #define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line )
|
jamie@264
|
1918
|
jamie@264
|
1919 #define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" )
|
jamie@264
|
1920
|
jamie@264
|
1921 // #included from: internal/catch_interfaces_exception.h
|
jamie@264
|
1922 #define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED
|
jamie@264
|
1923
|
jamie@264
|
1924 #include <string>
|
jamie@264
|
1925 // #included from: catch_interfaces_registry_hub.h
|
jamie@264
|
1926 #define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED
|
jamie@264
|
1927
|
jamie@264
|
1928 #include <string>
|
jamie@264
|
1929
|
jamie@264
|
1930 namespace Catch {
|
jamie@264
|
1931
|
jamie@264
|
1932 class TestCase;
|
jamie@264
|
1933 struct ITestCaseRegistry;
|
jamie@264
|
1934 struct IExceptionTranslatorRegistry;
|
jamie@264
|
1935 struct IExceptionTranslator;
|
jamie@264
|
1936 struct IReporterRegistry;
|
jamie@264
|
1937 struct IReporterFactory;
|
jamie@264
|
1938
|
jamie@264
|
1939 struct IRegistryHub {
|
jamie@264
|
1940 virtual ~IRegistryHub();
|
jamie@264
|
1941
|
jamie@264
|
1942 virtual IReporterRegistry const& getReporterRegistry() const = 0;
|
jamie@264
|
1943 virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
|
jamie@264
|
1944 virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0;
|
jamie@264
|
1945 };
|
jamie@264
|
1946
|
jamie@264
|
1947 struct IMutableRegistryHub {
|
jamie@264
|
1948 virtual ~IMutableRegistryHub();
|
jamie@264
|
1949 virtual void registerReporter( std::string const& name, IReporterFactory* factory ) = 0;
|
jamie@264
|
1950 virtual void registerTest( TestCase const& testInfo ) = 0;
|
jamie@264
|
1951 virtual void registerTranslator( const IExceptionTranslator* translator ) = 0;
|
jamie@264
|
1952 };
|
jamie@264
|
1953
|
jamie@264
|
1954 IRegistryHub& getRegistryHub();
|
jamie@264
|
1955 IMutableRegistryHub& getMutableRegistryHub();
|
jamie@264
|
1956 void cleanUp();
|
jamie@264
|
1957 std::string translateActiveException();
|
jamie@264
|
1958
|
jamie@264
|
1959 }
|
jamie@264
|
1960
|
jamie@264
|
1961
|
jamie@264
|
1962 namespace Catch {
|
jamie@264
|
1963
|
jamie@264
|
1964 typedef std::string(*exceptionTranslateFunction)();
|
jamie@264
|
1965
|
jamie@264
|
1966 struct IExceptionTranslator {
|
jamie@264
|
1967 virtual ~IExceptionTranslator();
|
jamie@264
|
1968 virtual std::string translate() const = 0;
|
jamie@264
|
1969 };
|
jamie@264
|
1970
|
jamie@264
|
1971 struct IExceptionTranslatorRegistry {
|
jamie@264
|
1972 virtual ~IExceptionTranslatorRegistry();
|
jamie@264
|
1973
|
jamie@264
|
1974 virtual std::string translateActiveException() const = 0;
|
jamie@264
|
1975 };
|
jamie@264
|
1976
|
jamie@264
|
1977 class ExceptionTranslatorRegistrar {
|
jamie@264
|
1978 template<typename T>
|
jamie@264
|
1979 class ExceptionTranslator : public IExceptionTranslator {
|
jamie@264
|
1980 public:
|
jamie@264
|
1981
|
jamie@264
|
1982 ExceptionTranslator( std::string(*translateFunction)( T& ) )
|
jamie@264
|
1983 : m_translateFunction( translateFunction )
|
jamie@264
|
1984 {}
|
jamie@264
|
1985
|
jamie@264
|
1986 virtual std::string translate() const {
|
jamie@264
|
1987 try {
|
jamie@264
|
1988 throw;
|
jamie@264
|
1989 }
|
jamie@264
|
1990 catch( T& ex ) {
|
jamie@264
|
1991 return m_translateFunction( ex );
|
jamie@264
|
1992 }
|
jamie@264
|
1993 }
|
jamie@264
|
1994
|
jamie@264
|
1995 protected:
|
jamie@264
|
1996 std::string(*m_translateFunction)( T& );
|
jamie@264
|
1997 };
|
jamie@264
|
1998
|
jamie@264
|
1999 public:
|
jamie@264
|
2000 template<typename T>
|
jamie@264
|
2001 ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) {
|
jamie@264
|
2002 getMutableRegistryHub().registerTranslator
|
jamie@264
|
2003 ( new ExceptionTranslator<T>( translateFunction ) );
|
jamie@264
|
2004 }
|
jamie@264
|
2005 };
|
jamie@264
|
2006 }
|
jamie@264
|
2007
|
jamie@264
|
2008 ///////////////////////////////////////////////////////////////////////////////
|
jamie@264
|
2009 #define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \
|
jamie@264
|
2010 static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \
|
jamie@264
|
2011 namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\
|
jamie@264
|
2012 static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature )
|
jamie@264
|
2013
|
jamie@264
|
2014 // #included from: internal/catch_approx.hpp
|
jamie@264
|
2015 #define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED
|
jamie@264
|
2016
|
jamie@264
|
2017 #include <cmath>
|
jamie@264
|
2018 #include <limits>
|
jamie@264
|
2019
|
jamie@264
|
2020 namespace Catch {
|
jamie@264
|
2021 namespace Detail {
|
jamie@264
|
2022
|
jamie@264
|
2023 class Approx {
|
jamie@264
|
2024 public:
|
jamie@264
|
2025 explicit Approx ( double value )
|
jamie@264
|
2026 : m_epsilon( std::numeric_limits<float>::epsilon()*100 ),
|
jamie@264
|
2027 m_scale( 1.0 ),
|
jamie@264
|
2028 m_value( value )
|
jamie@264
|
2029 {}
|
jamie@264
|
2030
|
jamie@264
|
2031 Approx( Approx const& other )
|
jamie@264
|
2032 : m_epsilon( other.m_epsilon ),
|
jamie@264
|
2033 m_scale( other.m_scale ),
|
jamie@264
|
2034 m_value( other.m_value )
|
jamie@264
|
2035 {}
|
jamie@264
|
2036
|
jamie@264
|
2037 static Approx custom() {
|
jamie@264
|
2038 return Approx( 0 );
|
jamie@264
|
2039 }
|
jamie@264
|
2040
|
jamie@264
|
2041 Approx operator()( double value ) {
|
jamie@264
|
2042 Approx approx( value );
|
jamie@264
|
2043 approx.epsilon( m_epsilon );
|
jamie@264
|
2044 approx.scale( m_scale );
|
jamie@264
|
2045 return approx;
|
jamie@264
|
2046 }
|
jamie@264
|
2047
|
jamie@264
|
2048 friend bool operator == ( double lhs, Approx const& rhs ) {
|
jamie@264
|
2049 // Thanks to Richard Harris for his help refining this formula
|
jamie@264
|
2050 return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) );
|
jamie@264
|
2051 }
|
jamie@264
|
2052
|
jamie@264
|
2053 friend bool operator == ( Approx const& lhs, double rhs ) {
|
jamie@264
|
2054 return operator==( rhs, lhs );
|
jamie@264
|
2055 }
|
jamie@264
|
2056
|
jamie@264
|
2057 friend bool operator != ( double lhs, Approx const& rhs ) {
|
jamie@264
|
2058 return !operator==( lhs, rhs );
|
jamie@264
|
2059 }
|
jamie@264
|
2060
|
jamie@264
|
2061 friend bool operator != ( Approx const& lhs, double rhs ) {
|
jamie@264
|
2062 return !operator==( rhs, lhs );
|
jamie@264
|
2063 }
|
jamie@264
|
2064
|
jamie@264
|
2065 Approx& epsilon( double newEpsilon ) {
|
jamie@264
|
2066 m_epsilon = newEpsilon;
|
jamie@264
|
2067 return *this;
|
jamie@264
|
2068 }
|
jamie@264
|
2069
|
jamie@264
|
2070 Approx& scale( double newScale ) {
|
jamie@264
|
2071 m_scale = newScale;
|
jamie@264
|
2072 return *this;
|
jamie@264
|
2073 }
|
jamie@264
|
2074
|
jamie@264
|
2075 std::string toString() const {
|
jamie@264
|
2076 std::ostringstream oss;
|
jamie@264
|
2077 oss << "Approx( " << Catch::toString( m_value ) << " )";
|
jamie@264
|
2078 return oss.str();
|
jamie@264
|
2079 }
|
jamie@264
|
2080
|
jamie@264
|
2081 private:
|
jamie@264
|
2082 double m_epsilon;
|
jamie@264
|
2083 double m_scale;
|
jamie@264
|
2084 double m_value;
|
jamie@264
|
2085 };
|
jamie@264
|
2086 }
|
jamie@264
|
2087
|
jamie@264
|
2088 template<>
|
jamie@264
|
2089 inline std::string toString<Detail::Approx>( Detail::Approx const& value ) {
|
jamie@264
|
2090 return value.toString();
|
jamie@264
|
2091 }
|
jamie@264
|
2092
|
jamie@264
|
2093 } // end namespace Catch
|
jamie@264
|
2094
|
jamie@264
|
2095 // #included from: internal/catch_matchers.hpp
|
jamie@264
|
2096 #define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED
|
jamie@264
|
2097
|
jamie@264
|
2098 namespace Catch {
|
jamie@264
|
2099 namespace Matchers {
|
jamie@264
|
2100 namespace Impl {
|
jamie@264
|
2101
|
jamie@264
|
2102 template<typename ExpressionT>
|
jamie@264
|
2103 struct Matcher : SharedImpl<IShared>
|
jamie@264
|
2104 {
|
jamie@264
|
2105 typedef ExpressionT ExpressionType;
|
jamie@264
|
2106
|
jamie@264
|
2107 virtual ~Matcher() {}
|
jamie@264
|
2108 virtual Ptr<Matcher> clone() const = 0;
|
jamie@264
|
2109 virtual bool match( ExpressionT const& expr ) const = 0;
|
jamie@264
|
2110 virtual std::string toString() const = 0;
|
jamie@264
|
2111 };
|
jamie@264
|
2112
|
jamie@264
|
2113 template<typename DerivedT, typename ExpressionT>
|
jamie@264
|
2114 struct MatcherImpl : Matcher<ExpressionT> {
|
jamie@264
|
2115
|
jamie@264
|
2116 virtual Ptr<Matcher<ExpressionT> > clone() const {
|
jamie@264
|
2117 return Ptr<Matcher<ExpressionT> >( new DerivedT( static_cast<DerivedT const&>( *this ) ) );
|
jamie@264
|
2118 }
|
jamie@264
|
2119 };
|
jamie@264
|
2120
|
jamie@264
|
2121 namespace Generic {
|
jamie@264
|
2122
|
jamie@264
|
2123 template<typename ExpressionT>
|
jamie@264
|
2124 class AllOf : public MatcherImpl<AllOf<ExpressionT>, ExpressionT> {
|
jamie@264
|
2125 public:
|
jamie@264
|
2126
|
jamie@264
|
2127 AllOf() {}
|
jamie@264
|
2128 AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {}
|
jamie@264
|
2129
|
jamie@264
|
2130 AllOf& add( Matcher<ExpressionT> const& matcher ) {
|
jamie@264
|
2131 m_matchers.push_back( matcher.clone() );
|
jamie@264
|
2132 return *this;
|
jamie@264
|
2133 }
|
jamie@264
|
2134 virtual bool match( ExpressionT const& expr ) const
|
jamie@264
|
2135 {
|
jamie@264
|
2136 for( std::size_t i = 0; i < m_matchers.size(); ++i )
|
jamie@264
|
2137 if( !m_matchers[i]->match( expr ) )
|
jamie@264
|
2138 return false;
|
jamie@264
|
2139 return true;
|
jamie@264
|
2140 }
|
jamie@264
|
2141 virtual std::string toString() const {
|
jamie@264
|
2142 std::ostringstream oss;
|
jamie@264
|
2143 oss << "( ";
|
jamie@264
|
2144 for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
|
jamie@264
|
2145 if( i != 0 )
|
jamie@264
|
2146 oss << " and ";
|
jamie@264
|
2147 oss << m_matchers[i]->toString();
|
jamie@264
|
2148 }
|
jamie@264
|
2149 oss << " )";
|
jamie@264
|
2150 return oss.str();
|
jamie@264
|
2151 }
|
jamie@264
|
2152
|
jamie@264
|
2153 private:
|
jamie@264
|
2154 std::vector<Ptr<Matcher<ExpressionT> > > m_matchers;
|
jamie@264
|
2155 };
|
jamie@264
|
2156
|
jamie@264
|
2157 template<typename ExpressionT>
|
jamie@264
|
2158 class AnyOf : public MatcherImpl<AnyOf<ExpressionT>, ExpressionT> {
|
jamie@264
|
2159 public:
|
jamie@264
|
2160
|
jamie@264
|
2161 AnyOf() {}
|
jamie@264
|
2162 AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {}
|
jamie@264
|
2163
|
jamie@264
|
2164 AnyOf& add( Matcher<ExpressionT> const& matcher ) {
|
jamie@264
|
2165 m_matchers.push_back( matcher.clone() );
|
jamie@264
|
2166 return *this;
|
jamie@264
|
2167 }
|
jamie@264
|
2168 virtual bool match( ExpressionT const& expr ) const
|
jamie@264
|
2169 {
|
jamie@264
|
2170 for( std::size_t i = 0; i < m_matchers.size(); ++i )
|
jamie@264
|
2171 if( m_matchers[i]->match( expr ) )
|
jamie@264
|
2172 return true;
|
jamie@264
|
2173 return false;
|
jamie@264
|
2174 }
|
jamie@264
|
2175 virtual std::string toString() const {
|
jamie@264
|
2176 std::ostringstream oss;
|
jamie@264
|
2177 oss << "( ";
|
jamie@264
|
2178 for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
|
jamie@264
|
2179 if( i != 0 )
|
jamie@264
|
2180 oss << " or ";
|
jamie@264
|
2181 oss << m_matchers[i]->toString();
|
jamie@264
|
2182 }
|
jamie@264
|
2183 oss << " )";
|
jamie@264
|
2184 return oss.str();
|
jamie@264
|
2185 }
|
jamie@264
|
2186
|
jamie@264
|
2187 private:
|
jamie@264
|
2188 std::vector<Ptr<Matcher<ExpressionT> > > m_matchers;
|
jamie@264
|
2189 };
|
jamie@264
|
2190
|
jamie@264
|
2191 }
|
jamie@264
|
2192
|
jamie@264
|
2193 namespace StdString {
|
jamie@264
|
2194
|
jamie@264
|
2195 inline std::string makeString( std::string const& str ) { return str; }
|
jamie@264
|
2196 inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); }
|
jamie@264
|
2197
|
jamie@264
|
2198 struct Equals : MatcherImpl<Equals, std::string> {
|
jamie@264
|
2199 Equals( std::string const& str ) : m_str( str ){}
|
jamie@264
|
2200 Equals( Equals const& other ) : m_str( other.m_str ){}
|
jamie@264
|
2201
|
jamie@264
|
2202 virtual ~Equals();
|
jamie@264
|
2203
|
jamie@264
|
2204 virtual bool match( std::string const& expr ) const {
|
jamie@264
|
2205 return m_str == expr;
|
jamie@264
|
2206 }
|
jamie@264
|
2207 virtual std::string toString() const {
|
jamie@264
|
2208 return "equals: \"" + m_str + "\"";
|
jamie@264
|
2209 }
|
jamie@264
|
2210
|
jamie@264
|
2211 std::string m_str;
|
jamie@264
|
2212 };
|
jamie@264
|
2213
|
jamie@264
|
2214 struct Contains : MatcherImpl<Contains, std::string> {
|
jamie@264
|
2215 Contains( std::string const& substr ) : m_substr( substr ){}
|
jamie@264
|
2216 Contains( Contains const& other ) : m_substr( other.m_substr ){}
|
jamie@264
|
2217
|
jamie@264
|
2218 virtual ~Contains();
|
jamie@264
|
2219
|
jamie@264
|
2220 virtual bool match( std::string const& expr ) const {
|
jamie@264
|
2221 return expr.find( m_substr ) != std::string::npos;
|
jamie@264
|
2222 }
|
jamie@264
|
2223 virtual std::string toString() const {
|
jamie@264
|
2224 return "contains: \"" + m_substr + "\"";
|
jamie@264
|
2225 }
|
jamie@264
|
2226
|
jamie@264
|
2227 std::string m_substr;
|
jamie@264
|
2228 };
|
jamie@264
|
2229
|
jamie@264
|
2230 struct StartsWith : MatcherImpl<StartsWith, std::string> {
|
jamie@264
|
2231 StartsWith( std::string const& substr ) : m_substr( substr ){}
|
jamie@264
|
2232 StartsWith( StartsWith const& other ) : m_substr( other.m_substr ){}
|
jamie@264
|
2233
|
jamie@264
|
2234 virtual ~StartsWith();
|
jamie@264
|
2235
|
jamie@264
|
2236 virtual bool match( std::string const& expr ) const {
|
jamie@264
|
2237 return expr.find( m_substr ) == 0;
|
jamie@264
|
2238 }
|
jamie@264
|
2239 virtual std::string toString() const {
|
jamie@264
|
2240 return "starts with: \"" + m_substr + "\"";
|
jamie@264
|
2241 }
|
jamie@264
|
2242
|
jamie@264
|
2243 std::string m_substr;
|
jamie@264
|
2244 };
|
jamie@264
|
2245
|
jamie@264
|
2246 struct EndsWith : MatcherImpl<EndsWith, std::string> {
|
jamie@264
|
2247 EndsWith( std::string const& substr ) : m_substr( substr ){}
|
jamie@264
|
2248 EndsWith( EndsWith const& other ) : m_substr( other.m_substr ){}
|
jamie@264
|
2249
|
jamie@264
|
2250 virtual ~EndsWith();
|
jamie@264
|
2251
|
jamie@264
|
2252 virtual bool match( std::string const& expr ) const {
|
jamie@264
|
2253 return expr.find( m_substr ) == expr.size() - m_substr.size();
|
jamie@264
|
2254 }
|
jamie@264
|
2255 virtual std::string toString() const {
|
jamie@264
|
2256 return "ends with: \"" + m_substr + "\"";
|
jamie@264
|
2257 }
|
jamie@264
|
2258
|
jamie@264
|
2259 std::string m_substr;
|
jamie@264
|
2260 };
|
jamie@264
|
2261 } // namespace StdString
|
jamie@264
|
2262 } // namespace Impl
|
jamie@264
|
2263
|
jamie@264
|
2264 // The following functions create the actual matcher objects.
|
jamie@264
|
2265 // This allows the types to be inferred
|
jamie@264
|
2266 template<typename ExpressionT>
|
jamie@264
|
2267 inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1,
|
jamie@264
|
2268 Impl::Matcher<ExpressionT> const& m2 ) {
|
jamie@264
|
2269 return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 );
|
jamie@264
|
2270 }
|
jamie@264
|
2271 template<typename ExpressionT>
|
jamie@264
|
2272 inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1,
|
jamie@264
|
2273 Impl::Matcher<ExpressionT> const& m2,
|
jamie@264
|
2274 Impl::Matcher<ExpressionT> const& m3 ) {
|
jamie@264
|
2275 return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 );
|
jamie@264
|
2276 }
|
jamie@264
|
2277 template<typename ExpressionT>
|
jamie@264
|
2278 inline Impl::Generic::AnyOf<ExpressionT> AnyOf( Impl::Matcher<ExpressionT> const& m1,
|
jamie@264
|
2279 Impl::Matcher<ExpressionT> const& m2 ) {
|
jamie@264
|
2280 return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 );
|
jamie@264
|
2281 }
|
jamie@264
|
2282 template<typename ExpressionT>
|
jamie@264
|
2283 inline Impl::Generic::AnyOf<ExpressionT> AnyOf( Impl::Matcher<ExpressionT> const& m1,
|
jamie@264
|
2284 Impl::Matcher<ExpressionT> const& m2,
|
jamie@264
|
2285 Impl::Matcher<ExpressionT> const& m3 ) {
|
jamie@264
|
2286 return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 );
|
jamie@264
|
2287 }
|
jamie@264
|
2288
|
jamie@264
|
2289 inline Impl::StdString::Equals Equals( std::string const& str ) {
|
jamie@264
|
2290 return Impl::StdString::Equals( str );
|
jamie@264
|
2291 }
|
jamie@264
|
2292 inline Impl::StdString::Equals Equals( const char* str ) {
|
jamie@264
|
2293 return Impl::StdString::Equals( Impl::StdString::makeString( str ) );
|
jamie@264
|
2294 }
|
jamie@264
|
2295 inline Impl::StdString::Contains Contains( std::string const& substr ) {
|
jamie@264
|
2296 return Impl::StdString::Contains( substr );
|
jamie@264
|
2297 }
|
jamie@264
|
2298 inline Impl::StdString::Contains Contains( const char* substr ) {
|
jamie@264
|
2299 return Impl::StdString::Contains( Impl::StdString::makeString( substr ) );
|
jamie@264
|
2300 }
|
jamie@264
|
2301 inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) {
|
jamie@264
|
2302 return Impl::StdString::StartsWith( substr );
|
jamie@264
|
2303 }
|
jamie@264
|
2304 inline Impl::StdString::StartsWith StartsWith( const char* substr ) {
|
jamie@264
|
2305 return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) );
|
jamie@264
|
2306 }
|
jamie@264
|
2307 inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) {
|
jamie@264
|
2308 return Impl::StdString::EndsWith( substr );
|
jamie@264
|
2309 }
|
jamie@264
|
2310 inline Impl::StdString::EndsWith EndsWith( const char* substr ) {
|
jamie@264
|
2311 return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) );
|
jamie@264
|
2312 }
|
jamie@264
|
2313
|
jamie@264
|
2314 } // namespace Matchers
|
jamie@264
|
2315
|
jamie@264
|
2316 using namespace Matchers;
|
jamie@264
|
2317
|
jamie@264
|
2318 } // namespace Catch
|
jamie@264
|
2319
|
jamie@264
|
2320 // #included from: internal/catch_interfaces_tag_alias_registry.h
|
jamie@264
|
2321 #define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED
|
jamie@264
|
2322
|
jamie@264
|
2323 // #included from: catch_tag_alias.h
|
jamie@264
|
2324 #define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED
|
jamie@264
|
2325
|
jamie@264
|
2326 #include <string>
|
jamie@264
|
2327
|
jamie@264
|
2328 namespace Catch {
|
jamie@264
|
2329
|
jamie@264
|
2330 struct TagAlias {
|
jamie@264
|
2331 TagAlias( std::string _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {}
|
jamie@264
|
2332
|
jamie@264
|
2333 std::string tag;
|
jamie@264
|
2334 SourceLineInfo lineInfo;
|
jamie@264
|
2335 };
|
jamie@264
|
2336
|
jamie@264
|
2337 struct RegistrarForTagAliases {
|
jamie@264
|
2338 RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo );
|
jamie@264
|
2339 };
|
jamie@264
|
2340
|
jamie@264
|
2341 } // end namespace Catch
|
jamie@264
|
2342
|
jamie@264
|
2343 #define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); }
|
jamie@264
|
2344 // #included from: catch_option.hpp
|
jamie@264
|
2345 #define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED
|
jamie@264
|
2346
|
jamie@264
|
2347 namespace Catch {
|
jamie@264
|
2348
|
jamie@264
|
2349 // An optional type
|
jamie@264
|
2350 template<typename T>
|
jamie@264
|
2351 class Option {
|
jamie@264
|
2352 public:
|
jamie@264
|
2353 Option() : nullableValue( NULL ) {}
|
jamie@264
|
2354 Option( T const& _value )
|
jamie@264
|
2355 : nullableValue( new( storage ) T( _value ) )
|
jamie@264
|
2356 {}
|
jamie@264
|
2357 Option( Option const& _other )
|
jamie@264
|
2358 : nullableValue( _other ? new( storage ) T( *_other ) : NULL )
|
jamie@264
|
2359 {}
|
jamie@264
|
2360
|
jamie@264
|
2361 ~Option() {
|
jamie@264
|
2362 reset();
|
jamie@264
|
2363 }
|
jamie@264
|
2364
|
jamie@264
|
2365 Option& operator= ( Option const& _other ) {
|
jamie@264
|
2366 if( &_other != this ) {
|
jamie@264
|
2367 reset();
|
jamie@264
|
2368 if( _other )
|
jamie@264
|
2369 nullableValue = new( storage ) T( *_other );
|
jamie@264
|
2370 }
|
jamie@264
|
2371 return *this;
|
jamie@264
|
2372 }
|
jamie@264
|
2373 Option& operator = ( T const& _value ) {
|
jamie@264
|
2374 reset();
|
jamie@264
|
2375 nullableValue = new( storage ) T( _value );
|
jamie@264
|
2376 return *this;
|
jamie@264
|
2377 }
|
jamie@264
|
2378
|
jamie@264
|
2379 void reset() {
|
jamie@264
|
2380 if( nullableValue )
|
jamie@264
|
2381 nullableValue->~T();
|
jamie@264
|
2382 nullableValue = NULL;
|
jamie@264
|
2383 }
|
jamie@264
|
2384
|
jamie@264
|
2385 T& operator*() { return *nullableValue; }
|
jamie@264
|
2386 T const& operator*() const { return *nullableValue; }
|
jamie@264
|
2387 T* operator->() { return nullableValue; }
|
jamie@264
|
2388 const T* operator->() const { return nullableValue; }
|
jamie@264
|
2389
|
jamie@264
|
2390 T valueOr( T const& defaultValue ) const {
|
jamie@264
|
2391 return nullableValue ? *nullableValue : defaultValue;
|
jamie@264
|
2392 }
|
jamie@264
|
2393
|
jamie@264
|
2394 bool some() const { return nullableValue != NULL; }
|
jamie@264
|
2395 bool none() const { return nullableValue == NULL; }
|
jamie@264
|
2396
|
jamie@264
|
2397 bool operator !() const { return nullableValue == NULL; }
|
jamie@264
|
2398 operator SafeBool::type() const {
|
jamie@264
|
2399 return SafeBool::makeSafe( some() );
|
jamie@264
|
2400 }
|
jamie@264
|
2401
|
jamie@264
|
2402 private:
|
jamie@264
|
2403 T* nullableValue;
|
jamie@264
|
2404 char storage[sizeof(T)];
|
jamie@264
|
2405 };
|
jamie@264
|
2406
|
jamie@264
|
2407 } // end namespace Catch
|
jamie@264
|
2408
|
jamie@264
|
2409 namespace Catch {
|
jamie@264
|
2410
|
jamie@264
|
2411 struct ITagAliasRegistry {
|
jamie@264
|
2412 virtual ~ITagAliasRegistry();
|
jamie@264
|
2413 virtual Option<TagAlias> find( std::string const& alias ) const = 0;
|
jamie@264
|
2414 virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0;
|
jamie@264
|
2415
|
jamie@264
|
2416 static ITagAliasRegistry const& get();
|
jamie@264
|
2417 };
|
jamie@264
|
2418
|
jamie@264
|
2419 } // end namespace Catch
|
jamie@264
|
2420
|
jamie@264
|
2421 // These files are included here so the single_include script doesn't put them
|
jamie@264
|
2422 // in the conditionally compiled sections
|
jamie@264
|
2423 // #included from: internal/catch_test_case_info.h
|
jamie@264
|
2424 #define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED
|
jamie@264
|
2425
|
jamie@264
|
2426 #include <string>
|
jamie@264
|
2427 #include <set>
|
jamie@264
|
2428
|
jamie@264
|
2429 #ifdef __clang__
|
jamie@264
|
2430 #pragma clang diagnostic push
|
jamie@264
|
2431 #pragma clang diagnostic ignored "-Wpadded"
|
jamie@264
|
2432 #endif
|
jamie@264
|
2433
|
jamie@264
|
2434 namespace Catch {
|
jamie@264
|
2435
|
jamie@264
|
2436 struct ITestCase;
|
jamie@264
|
2437
|
jamie@264
|
2438 struct TestCaseInfo {
|
jamie@264
|
2439 enum SpecialProperties{
|
jamie@264
|
2440 None = 0,
|
jamie@264
|
2441 IsHidden = 1 << 1,
|
jamie@264
|
2442 ShouldFail = 1 << 2,
|
jamie@264
|
2443 MayFail = 1 << 3,
|
jamie@264
|
2444 Throws = 1 << 4
|
jamie@264
|
2445 };
|
jamie@264
|
2446
|
jamie@264
|
2447 TestCaseInfo( std::string const& _name,
|
jamie@264
|
2448 std::string const& _className,
|
jamie@264
|
2449 std::string const& _description,
|
jamie@264
|
2450 std::set<std::string> const& _tags,
|
jamie@264
|
2451 SourceLineInfo const& _lineInfo );
|
jamie@264
|
2452
|
jamie@264
|
2453 TestCaseInfo( TestCaseInfo const& other );
|
jamie@264
|
2454
|
jamie@264
|
2455 bool isHidden() const;
|
jamie@264
|
2456 bool throws() const;
|
jamie@264
|
2457 bool okToFail() const;
|
jamie@264
|
2458 bool expectedToFail() const;
|
jamie@264
|
2459
|
jamie@264
|
2460 std::string name;
|
jamie@264
|
2461 std::string className;
|
jamie@264
|
2462 std::string description;
|
jamie@264
|
2463 std::set<std::string> tags;
|
jamie@264
|
2464 std::set<std::string> lcaseTags;
|
jamie@264
|
2465 std::string tagsAsString;
|
jamie@264
|
2466 SourceLineInfo lineInfo;
|
jamie@264
|
2467 SpecialProperties properties;
|
jamie@264
|
2468 };
|
jamie@264
|
2469
|
jamie@264
|
2470 class TestCase : public TestCaseInfo {
|
jamie@264
|
2471 public:
|
jamie@264
|
2472
|
jamie@264
|
2473 TestCase( ITestCase* testCase, TestCaseInfo const& info );
|
jamie@264
|
2474 TestCase( TestCase const& other );
|
jamie@264
|
2475
|
jamie@264
|
2476 TestCase withName( std::string const& _newName ) const;
|
jamie@264
|
2477
|
jamie@264
|
2478 void invoke() const;
|
jamie@264
|
2479
|
jamie@264
|
2480 TestCaseInfo const& getTestCaseInfo() const;
|
jamie@264
|
2481
|
jamie@264
|
2482 void swap( TestCase& other );
|
jamie@264
|
2483 bool operator == ( TestCase const& other ) const;
|
jamie@264
|
2484 bool operator < ( TestCase const& other ) const;
|
jamie@264
|
2485 TestCase& operator = ( TestCase const& other );
|
jamie@264
|
2486
|
jamie@264
|
2487 private:
|
jamie@264
|
2488 Ptr<ITestCase> test;
|
jamie@264
|
2489 };
|
jamie@264
|
2490
|
jamie@264
|
2491 TestCase makeTestCase( ITestCase* testCase,
|
jamie@264
|
2492 std::string const& className,
|
jamie@264
|
2493 std::string const& name,
|
jamie@264
|
2494 std::string const& description,
|
jamie@264
|
2495 SourceLineInfo const& lineInfo );
|
jamie@264
|
2496 }
|
jamie@264
|
2497
|
jamie@264
|
2498 #ifdef __clang__
|
jamie@264
|
2499 #pragma clang diagnostic pop
|
jamie@264
|
2500 #endif
|
jamie@264
|
2501
|
jamie@264
|
2502
|
jamie@264
|
2503 #ifdef __OBJC__
|
jamie@264
|
2504 // #included from: internal/catch_objc.hpp
|
jamie@264
|
2505 #define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED
|
jamie@264
|
2506
|
jamie@264
|
2507 #import <objc/runtime.h>
|
jamie@264
|
2508
|
jamie@264
|
2509 #include <string>
|
jamie@264
|
2510
|
jamie@264
|
2511 // NB. Any general catch headers included here must be included
|
jamie@264
|
2512 // in catch.hpp first to make sure they are included by the single
|
jamie@264
|
2513 // header for non obj-usage
|
jamie@264
|
2514
|
jamie@264
|
2515 ///////////////////////////////////////////////////////////////////////////////
|
jamie@264
|
2516 // This protocol is really only here for (self) documenting purposes, since
|
jamie@264
|
2517 // all its methods are optional.
|
jamie@264
|
2518 @protocol OcFixture
|
jamie@264
|
2519
|
jamie@264
|
2520 @optional
|
jamie@264
|
2521
|
jamie@264
|
2522 -(void) setUp;
|
jamie@264
|
2523 -(void) tearDown;
|
jamie@264
|
2524
|
jamie@264
|
2525 @end
|
jamie@264
|
2526
|
jamie@264
|
2527 namespace Catch {
|
jamie@264
|
2528
|
jamie@264
|
2529 class OcMethod : public SharedImpl<ITestCase> {
|
jamie@264
|
2530
|
jamie@264
|
2531 public:
|
jamie@264
|
2532 OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {}
|
jamie@264
|
2533
|
jamie@264
|
2534 virtual void invoke() const {
|
jamie@264
|
2535 id obj = [[m_cls alloc] init];
|
jamie@264
|
2536
|
jamie@264
|
2537 performOptionalSelector( obj, @selector(setUp) );
|
jamie@264
|
2538 performOptionalSelector( obj, m_sel );
|
jamie@264
|
2539 performOptionalSelector( obj, @selector(tearDown) );
|
jamie@264
|
2540
|
jamie@264
|
2541 arcSafeRelease( obj );
|
jamie@264
|
2542 }
|
jamie@264
|
2543 private:
|
jamie@264
|
2544 virtual ~OcMethod() {}
|
jamie@264
|
2545
|
jamie@264
|
2546 Class m_cls;
|
jamie@264
|
2547 SEL m_sel;
|
jamie@264
|
2548 };
|
jamie@264
|
2549
|
jamie@264
|
2550 namespace Detail{
|
jamie@264
|
2551
|
jamie@264
|
2552 inline std::string getAnnotation( Class cls,
|
jamie@264
|
2553 std::string const& annotationName,
|
jamie@264
|
2554 std::string const& testCaseName ) {
|
jamie@264
|
2555 NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()];
|
jamie@264
|
2556 SEL sel = NSSelectorFromString( selStr );
|
jamie@264
|
2557 arcSafeRelease( selStr );
|
jamie@264
|
2558 id value = performOptionalSelector( cls, sel );
|
jamie@264
|
2559 if( value )
|
jamie@264
|
2560 return [(NSString*)value UTF8String];
|
jamie@264
|
2561 return "";
|
jamie@264
|
2562 }
|
jamie@264
|
2563 }
|
jamie@264
|
2564
|
jamie@264
|
2565 inline size_t registerTestMethods() {
|
jamie@264
|
2566 size_t noTestMethods = 0;
|
jamie@264
|
2567 int noClasses = objc_getClassList( NULL, 0 );
|
jamie@264
|
2568
|
jamie@264
|
2569 Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses);
|
jamie@264
|
2570 objc_getClassList( classes, noClasses );
|
jamie@264
|
2571
|
jamie@264
|
2572 for( int c = 0; c < noClasses; c++ ) {
|
jamie@264
|
2573 Class cls = classes[c];
|
jamie@264
|
2574 {
|
jamie@264
|
2575 u_int count;
|
jamie@264
|
2576 Method* methods = class_copyMethodList( cls, &count );
|
jamie@264
|
2577 for( u_int m = 0; m < count ; m++ ) {
|
jamie@264
|
2578 SEL selector = method_getName(methods[m]);
|
jamie@264
|
2579 std::string methodName = sel_getName(selector);
|
jamie@264
|
2580 if( startsWith( methodName, "Catch_TestCase_" ) ) {
|
jamie@264
|
2581 std::string testCaseName = methodName.substr( 15 );
|
jamie@264
|
2582 std::string name = Detail::getAnnotation( cls, "Name", testCaseName );
|
jamie@264
|
2583 std::string desc = Detail::getAnnotation( cls, "Description", testCaseName );
|
jamie@264
|
2584 const char* className = class_getName( cls );
|
jamie@264
|
2585
|
jamie@264
|
2586 getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) );
|
jamie@264
|
2587 noTestMethods++;
|
jamie@264
|
2588 }
|
jamie@264
|
2589 }
|
jamie@264
|
2590 free(methods);
|
jamie@264
|
2591 }
|
jamie@264
|
2592 }
|
jamie@264
|
2593 return noTestMethods;
|
jamie@264
|
2594 }
|
jamie@264
|
2595
|
jamie@264
|
2596 namespace Matchers {
|
jamie@264
|
2597 namespace Impl {
|
jamie@264
|
2598 namespace NSStringMatchers {
|
jamie@264
|
2599
|
jamie@264
|
2600 template<typename MatcherT>
|
jamie@264
|
2601 struct StringHolder : MatcherImpl<MatcherT, NSString*>{
|
jamie@264
|
2602 StringHolder( NSString* substr ) : m_substr( [substr copy] ){}
|
jamie@264
|
2603 StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){}
|
jamie@264
|
2604 StringHolder() {
|
jamie@264
|
2605 arcSafeRelease( m_substr );
|
jamie@264
|
2606 }
|
jamie@264
|
2607
|
jamie@264
|
2608 NSString* m_substr;
|
jamie@264
|
2609 };
|
jamie@264
|
2610
|
jamie@264
|
2611 struct Equals : StringHolder<Equals> {
|
jamie@264
|
2612 Equals( NSString* substr ) : StringHolder( substr ){}
|
jamie@264
|
2613
|
jamie@264
|
2614 virtual bool match( ExpressionType const& str ) const {
|
jamie@264
|
2615 return (str != nil || m_substr == nil ) &&
|
jamie@264
|
2616 [str isEqualToString:m_substr];
|
jamie@264
|
2617 }
|
jamie@264
|
2618
|
jamie@264
|
2619 virtual std::string toString() const {
|
jamie@264
|
2620 return "equals string: " + Catch::toString( m_substr );
|
jamie@264
|
2621 }
|
jamie@264
|
2622 };
|
jamie@264
|
2623
|
jamie@264
|
2624 struct Contains : StringHolder<Contains> {
|
jamie@264
|
2625 Contains( NSString* substr ) : StringHolder( substr ){}
|
jamie@264
|
2626
|
jamie@264
|
2627 virtual bool match( ExpressionType const& str ) const {
|
jamie@264
|
2628 return (str != nil || m_substr == nil ) &&
|
jamie@264
|
2629 [str rangeOfString:m_substr].location != NSNotFound;
|
jamie@264
|
2630 }
|
jamie@264
|
2631
|
jamie@264
|
2632 virtual std::string toString() const {
|
jamie@264
|
2633 return "contains string: " + Catch::toString( m_substr );
|
jamie@264
|
2634 }
|
jamie@264
|
2635 };
|
jamie@264
|
2636
|
jamie@264
|
2637 struct StartsWith : StringHolder<StartsWith> {
|
jamie@264
|
2638 StartsWith( NSString* substr ) : StringHolder( substr ){}
|
jamie@264
|
2639
|
jamie@264
|
2640 virtual bool match( ExpressionType const& str ) const {
|
jamie@264
|
2641 return (str != nil || m_substr == nil ) &&
|
jamie@264
|
2642 [str rangeOfString:m_substr].location == 0;
|
jamie@264
|
2643 }
|
jamie@264
|
2644
|
jamie@264
|
2645 virtual std::string toString() const {
|
jamie@264
|
2646 return "starts with: " + Catch::toString( m_substr );
|
jamie@264
|
2647 }
|
jamie@264
|
2648 };
|
jamie@264
|
2649 struct EndsWith : StringHolder<EndsWith> {
|
jamie@264
|
2650 EndsWith( NSString* substr ) : StringHolder( substr ){}
|
jamie@264
|
2651
|
jamie@264
|
2652 virtual bool match( ExpressionType const& str ) const {
|
jamie@264
|
2653 return (str != nil || m_substr == nil ) &&
|
jamie@264
|
2654 [str rangeOfString:m_substr].location == [str length] - [m_substr length];
|
jamie@264
|
2655 }
|
jamie@264
|
2656
|
jamie@264
|
2657 virtual std::string toString() const {
|
jamie@264
|
2658 return "ends with: " + Catch::toString( m_substr );
|
jamie@264
|
2659 }
|
jamie@264
|
2660 };
|
jamie@264
|
2661
|
jamie@264
|
2662 } // namespace NSStringMatchers
|
jamie@264
|
2663 } // namespace Impl
|
jamie@264
|
2664
|
jamie@264
|
2665 inline Impl::NSStringMatchers::Equals
|
jamie@264
|
2666 Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); }
|
jamie@264
|
2667
|
jamie@264
|
2668 inline Impl::NSStringMatchers::Contains
|
jamie@264
|
2669 Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); }
|
jamie@264
|
2670
|
jamie@264
|
2671 inline Impl::NSStringMatchers::StartsWith
|
jamie@264
|
2672 StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); }
|
jamie@264
|
2673
|
jamie@264
|
2674 inline Impl::NSStringMatchers::EndsWith
|
jamie@264
|
2675 EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); }
|
jamie@264
|
2676
|
jamie@264
|
2677 } // namespace Matchers
|
jamie@264
|
2678
|
jamie@264
|
2679 using namespace Matchers;
|
jamie@264
|
2680
|
jamie@264
|
2681 } // namespace Catch
|
jamie@264
|
2682
|
jamie@264
|
2683 ///////////////////////////////////////////////////////////////////////////////
|
jamie@264
|
2684 #define OC_TEST_CASE( name, desc )\
|
jamie@264
|
2685 +(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \
|
jamie@264
|
2686 {\
|
jamie@264
|
2687 return @ name; \
|
jamie@264
|
2688 }\
|
jamie@264
|
2689 +(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \
|
jamie@264
|
2690 { \
|
jamie@264
|
2691 return @ desc; \
|
jamie@264
|
2692 } \
|
jamie@264
|
2693 -(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test )
|
jamie@264
|
2694
|
jamie@264
|
2695 #endif
|
jamie@264
|
2696
|
jamie@264
|
2697 #ifdef CATCH_CONFIG_RUNNER
|
jamie@264
|
2698 // #included from: internal/catch_impl.hpp
|
jamie@264
|
2699 #define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED
|
jamie@264
|
2700
|
jamie@264
|
2701 // Collect all the implementation files together here
|
jamie@264
|
2702 // These are the equivalent of what would usually be cpp files
|
jamie@264
|
2703
|
jamie@264
|
2704 #ifdef __clang__
|
jamie@264
|
2705 #pragma clang diagnostic push
|
jamie@264
|
2706 #pragma clang diagnostic ignored "-Wweak-vtables"
|
jamie@264
|
2707 #endif
|
jamie@264
|
2708
|
jamie@264
|
2709 // #included from: catch_runner.hpp
|
jamie@264
|
2710 #define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED
|
jamie@264
|
2711
|
jamie@264
|
2712 // #included from: internal/catch_commandline.hpp
|
jamie@264
|
2713 #define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED
|
jamie@264
|
2714
|
jamie@264
|
2715 // #included from: catch_config.hpp
|
jamie@264
|
2716 #define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED
|
jamie@264
|
2717
|
jamie@264
|
2718 // #included from: catch_test_spec_parser.hpp
|
jamie@264
|
2719 #define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED
|
jamie@264
|
2720
|
jamie@264
|
2721 #ifdef __clang__
|
jamie@264
|
2722 #pragma clang diagnostic push
|
jamie@264
|
2723 #pragma clang diagnostic ignored "-Wpadded"
|
jamie@264
|
2724 #endif
|
jamie@264
|
2725
|
jamie@264
|
2726 // #included from: catch_test_spec.hpp
|
jamie@264
|
2727 #define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED
|
jamie@264
|
2728
|
jamie@264
|
2729 #ifdef __clang__
|
jamie@264
|
2730 #pragma clang diagnostic push
|
jamie@264
|
2731 #pragma clang diagnostic ignored "-Wpadded"
|
jamie@264
|
2732 #endif
|
jamie@264
|
2733
|
jamie@264
|
2734 #include <string>
|
jamie@264
|
2735 #include <vector>
|
jamie@264
|
2736
|
jamie@264
|
2737 namespace Catch {
|
jamie@264
|
2738
|
jamie@264
|
2739 class TestSpec {
|
jamie@264
|
2740 struct Pattern : SharedImpl<> {
|
jamie@264
|
2741 virtual ~Pattern();
|
jamie@264
|
2742 virtual bool matches( TestCaseInfo const& testCase ) const = 0;
|
jamie@264
|
2743 };
|
jamie@264
|
2744 class NamePattern : public Pattern {
|
jamie@264
|
2745 enum WildcardPosition {
|
jamie@264
|
2746 NoWildcard = 0,
|
jamie@264
|
2747 WildcardAtStart = 1,
|
jamie@264
|
2748 WildcardAtEnd = 2,
|
jamie@264
|
2749 WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd
|
jamie@264
|
2750 };
|
jamie@264
|
2751
|
jamie@264
|
2752 public:
|
jamie@264
|
2753 NamePattern( std::string const& name ) : m_name( toLower( name ) ), m_wildcard( NoWildcard ) {
|
jamie@264
|
2754 if( startsWith( m_name, "*" ) ) {
|
jamie@264
|
2755 m_name = m_name.substr( 1 );
|
jamie@264
|
2756 m_wildcard = WildcardAtStart;
|
jamie@264
|
2757 }
|
jamie@264
|
2758 if( endsWith( m_name, "*" ) ) {
|
jamie@264
|
2759 m_name = m_name.substr( 0, m_name.size()-1 );
|
jamie@264
|
2760 m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd );
|
jamie@264
|
2761 }
|
jamie@264
|
2762 }
|
jamie@264
|
2763 virtual ~NamePattern();
|
jamie@264
|
2764 virtual bool matches( TestCaseInfo const& testCase ) const {
|
jamie@264
|
2765 switch( m_wildcard ) {
|
jamie@264
|
2766 case NoWildcard:
|
jamie@264
|
2767 return m_name == toLower( testCase.name );
|
jamie@264
|
2768 case WildcardAtStart:
|
jamie@264
|
2769 return endsWith( toLower( testCase.name ), m_name );
|
jamie@264
|
2770 case WildcardAtEnd:
|
jamie@264
|
2771 return startsWith( toLower( testCase.name ), m_name );
|
jamie@264
|
2772 case WildcardAtBothEnds:
|
jamie@264
|
2773 return contains( toLower( testCase.name ), m_name );
|
jamie@264
|
2774 }
|
jamie@264
|
2775
|
jamie@264
|
2776 #ifdef __clang__
|
jamie@264
|
2777 #pragma clang diagnostic push
|
jamie@264
|
2778 #pragma clang diagnostic ignored "-Wunreachable-code"
|
jamie@264
|
2779 #endif
|
jamie@264
|
2780 throw std::logic_error( "Unknown enum" );
|
jamie@264
|
2781 #ifdef __clang__
|
jamie@264
|
2782 #pragma clang diagnostic pop
|
jamie@264
|
2783 #endif
|
jamie@264
|
2784 }
|
jamie@264
|
2785 private:
|
jamie@264
|
2786 std::string m_name;
|
jamie@264
|
2787 WildcardPosition m_wildcard;
|
jamie@264
|
2788 };
|
jamie@264
|
2789 class TagPattern : public Pattern {
|
jamie@264
|
2790 public:
|
jamie@264
|
2791 TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {}
|
jamie@264
|
2792 virtual ~TagPattern();
|
jamie@264
|
2793 virtual bool matches( TestCaseInfo const& testCase ) const {
|
jamie@264
|
2794 return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end();
|
jamie@264
|
2795 }
|
jamie@264
|
2796 private:
|
jamie@264
|
2797 std::string m_tag;
|
jamie@264
|
2798 };
|
jamie@264
|
2799 class ExcludedPattern : public Pattern {
|
jamie@264
|
2800 public:
|
jamie@264
|
2801 ExcludedPattern( Ptr<Pattern> const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {}
|
jamie@264
|
2802 virtual ~ExcludedPattern();
|
jamie@264
|
2803 virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); }
|
jamie@264
|
2804 private:
|
jamie@264
|
2805 Ptr<Pattern> m_underlyingPattern;
|
jamie@264
|
2806 };
|
jamie@264
|
2807
|
jamie@264
|
2808 struct Filter {
|
jamie@264
|
2809 std::vector<Ptr<Pattern> > m_patterns;
|
jamie@264
|
2810
|
jamie@264
|
2811 bool matches( TestCaseInfo const& testCase ) const {
|
jamie@264
|
2812 // All patterns in a filter must match for the filter to be a match
|
jamie@264
|
2813 for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it )
|
jamie@264
|
2814 if( !(*it)->matches( testCase ) )
|
jamie@264
|
2815 return false;
|
jamie@264
|
2816 return true;
|
jamie@264
|
2817 }
|
jamie@264
|
2818 };
|
jamie@264
|
2819
|
jamie@264
|
2820 public:
|
jamie@264
|
2821 bool hasFilters() const {
|
jamie@264
|
2822 return !m_filters.empty();
|
jamie@264
|
2823 }
|
jamie@264
|
2824 bool matches( TestCaseInfo const& testCase ) const {
|
jamie@264
|
2825 // A TestSpec matches if any filter matches
|
jamie@264
|
2826 for( std::vector<Filter>::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it )
|
jamie@264
|
2827 if( it->matches( testCase ) )
|
jamie@264
|
2828 return true;
|
jamie@264
|
2829 return false;
|
jamie@264
|
2830 }
|
jamie@264
|
2831
|
jamie@264
|
2832 private:
|
jamie@264
|
2833 std::vector<Filter> m_filters;
|
jamie@264
|
2834
|
jamie@264
|
2835 friend class TestSpecParser;
|
jamie@264
|
2836 };
|
jamie@264
|
2837 }
|
jamie@264
|
2838
|
jamie@264
|
2839 #ifdef __clang__
|
jamie@264
|
2840 #pragma clang diagnostic pop
|
jamie@264
|
2841 #endif
|
jamie@264
|
2842
|
jamie@264
|
2843 namespace Catch {
|
jamie@264
|
2844
|
jamie@264
|
2845 class TestSpecParser {
|
jamie@264
|
2846 enum Mode{ None, Name, QuotedName, Tag };
|
jamie@264
|
2847 Mode m_mode;
|
jamie@264
|
2848 bool m_exclusion;
|
jamie@264
|
2849 std::size_t m_start, m_pos;
|
jamie@264
|
2850 std::string m_arg;
|
jamie@264
|
2851 TestSpec::Filter m_currentFilter;
|
jamie@264
|
2852 TestSpec m_testSpec;
|
jamie@264
|
2853 ITagAliasRegistry const* m_tagAliases;
|
jamie@264
|
2854
|
jamie@264
|
2855 public:
|
jamie@264
|
2856 TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {}
|
jamie@264
|
2857
|
jamie@264
|
2858 TestSpecParser& parse( std::string const& arg ) {
|
jamie@264
|
2859 m_mode = None;
|
jamie@264
|
2860 m_exclusion = false;
|
jamie@264
|
2861 m_start = std::string::npos;
|
jamie@264
|
2862 m_arg = m_tagAliases->expandAliases( arg );
|
jamie@264
|
2863 for( m_pos = 0; m_pos < m_arg.size(); ++m_pos )
|
jamie@264
|
2864 visitChar( m_arg[m_pos] );
|
jamie@264
|
2865 if( m_mode == Name )
|
jamie@264
|
2866 addPattern<TestSpec::NamePattern>();
|
jamie@264
|
2867 return *this;
|
jamie@264
|
2868 }
|
jamie@264
|
2869 TestSpec testSpec() {
|
jamie@264
|
2870 addFilter();
|
jamie@264
|
2871 return m_testSpec;
|
jamie@264
|
2872 }
|
jamie@264
|
2873 private:
|
jamie@264
|
2874 void visitChar( char c ) {
|
jamie@264
|
2875 if( m_mode == None ) {
|
jamie@264
|
2876 switch( c ) {
|
jamie@264
|
2877 case ' ': return;
|
jamie@264
|
2878 case '~': m_exclusion = true; return;
|
jamie@264
|
2879 case '[': return startNewMode( Tag, ++m_pos );
|
jamie@264
|
2880 case '"': return startNewMode( QuotedName, ++m_pos );
|
jamie@264
|
2881 default: startNewMode( Name, m_pos ); break;
|
jamie@264
|
2882 }
|
jamie@264
|
2883 }
|
jamie@264
|
2884 if( m_mode == Name ) {
|
jamie@264
|
2885 if( c == ',' ) {
|
jamie@264
|
2886 addPattern<TestSpec::NamePattern>();
|
jamie@264
|
2887 addFilter();
|
jamie@264
|
2888 }
|
jamie@264
|
2889 else if( c == '[' ) {
|
jamie@264
|
2890 if( subString() == "exclude:" )
|
jamie@264
|
2891 m_exclusion = true;
|
jamie@264
|
2892 else
|
jamie@264
|
2893 addPattern<TestSpec::NamePattern>();
|
jamie@264
|
2894 startNewMode( Tag, ++m_pos );
|
jamie@264
|
2895 }
|
jamie@264
|
2896 }
|
jamie@264
|
2897 else if( m_mode == QuotedName && c == '"' )
|
jamie@264
|
2898 addPattern<TestSpec::NamePattern>();
|
jamie@264
|
2899 else if( m_mode == Tag && c == ']' )
|
jamie@264
|
2900 addPattern<TestSpec::TagPattern>();
|
jamie@264
|
2901 }
|
jamie@264
|
2902 void startNewMode( Mode mode, std::size_t start ) {
|
jamie@264
|
2903 m_mode = mode;
|
jamie@264
|
2904 m_start = start;
|
jamie@264
|
2905 }
|
jamie@264
|
2906 std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); }
|
jamie@264
|
2907 template<typename T>
|
jamie@264
|
2908 void addPattern() {
|
jamie@264
|
2909 std::string token = subString();
|
jamie@264
|
2910 if( startsWith( token, "exclude:" ) ) {
|
jamie@264
|
2911 m_exclusion = true;
|
jamie@264
|
2912 token = token.substr( 8 );
|
jamie@264
|
2913 }
|
jamie@264
|
2914 if( !token.empty() ) {
|
jamie@264
|
2915 Ptr<TestSpec::Pattern> pattern = new T( token );
|
jamie@264
|
2916 if( m_exclusion )
|
jamie@264
|
2917 pattern = new TestSpec::ExcludedPattern( pattern );
|
jamie@264
|
2918 m_currentFilter.m_patterns.push_back( pattern );
|
jamie@264
|
2919 }
|
jamie@264
|
2920 m_exclusion = false;
|
jamie@264
|
2921 m_mode = None;
|
jamie@264
|
2922 }
|
jamie@264
|
2923 void addFilter() {
|
jamie@264
|
2924 if( !m_currentFilter.m_patterns.empty() ) {
|
jamie@264
|
2925 m_testSpec.m_filters.push_back( m_currentFilter );
|
jamie@264
|
2926 m_currentFilter = TestSpec::Filter();
|
jamie@264
|
2927 }
|
jamie@264
|
2928 }
|
jamie@264
|
2929 };
|
jamie@264
|
2930 inline TestSpec parseTestSpec( std::string const& arg ) {
|
jamie@264
|
2931 return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec();
|
jamie@264
|
2932 }
|
jamie@264
|
2933
|
jamie@264
|
2934 } // namespace Catch
|
jamie@264
|
2935
|
jamie@264
|
2936 #ifdef __clang__
|
jamie@264
|
2937 #pragma clang diagnostic pop
|
jamie@264
|
2938 #endif
|
jamie@264
|
2939
|
jamie@264
|
2940 // #included from: catch_interfaces_config.h
|
jamie@264
|
2941 #define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED
|
jamie@264
|
2942
|
jamie@264
|
2943 #include <iostream>
|
jamie@264
|
2944 #include <string>
|
jamie@264
|
2945 #include <vector>
|
jamie@264
|
2946
|
jamie@264
|
2947 namespace Catch {
|
jamie@264
|
2948
|
jamie@264
|
2949 struct Verbosity { enum Level {
|
jamie@264
|
2950 NoOutput = 0,
|
jamie@264
|
2951 Quiet,
|
jamie@264
|
2952 Normal
|
jamie@264
|
2953 }; };
|
jamie@264
|
2954
|
jamie@264
|
2955 struct WarnAbout { enum What {
|
jamie@264
|
2956 Nothing = 0x00,
|
jamie@264
|
2957 NoAssertions = 0x01
|
jamie@264
|
2958 }; };
|
jamie@264
|
2959
|
jamie@264
|
2960 struct ShowDurations { enum OrNot {
|
jamie@264
|
2961 DefaultForReporter,
|
jamie@264
|
2962 Always,
|
jamie@264
|
2963 Never
|
jamie@264
|
2964 }; };
|
jamie@264
|
2965
|
jamie@264
|
2966 class TestSpec;
|
jamie@264
|
2967
|
jamie@264
|
2968 struct IConfig : IShared {
|
jamie@264
|
2969
|
jamie@264
|
2970 virtual ~IConfig();
|
jamie@264
|
2971
|
jamie@264
|
2972 virtual bool allowThrows() const = 0;
|
jamie@264
|
2973 virtual std::ostream& stream() const = 0;
|
jamie@264
|
2974 virtual std::string name() const = 0;
|
jamie@264
|
2975 virtual bool includeSuccessfulResults() const = 0;
|
jamie@264
|
2976 virtual bool shouldDebugBreak() const = 0;
|
jamie@264
|
2977 virtual bool warnAboutMissingAssertions() const = 0;
|
jamie@264
|
2978 virtual int abortAfter() const = 0;
|
jamie@264
|
2979 virtual bool showInvisibles() const = 0;
|
jamie@264
|
2980 virtual ShowDurations::OrNot showDurations() const = 0;
|
jamie@264
|
2981 virtual TestSpec const& testSpec() const = 0;
|
jamie@264
|
2982 };
|
jamie@264
|
2983 }
|
jamie@264
|
2984
|
jamie@264
|
2985 // #included from: catch_stream.h
|
jamie@264
|
2986 #define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
|
jamie@264
|
2987
|
jamie@264
|
2988 #include <streambuf>
|
jamie@264
|
2989
|
jamie@264
|
2990 #ifdef __clang__
|
jamie@264
|
2991 #pragma clang diagnostic ignored "-Wpadded"
|
jamie@264
|
2992 #endif
|
jamie@264
|
2993
|
jamie@264
|
2994 namespace Catch {
|
jamie@264
|
2995
|
jamie@264
|
2996 class Stream {
|
jamie@264
|
2997 public:
|
jamie@264
|
2998 Stream();
|
jamie@264
|
2999 Stream( std::streambuf* _streamBuf, bool _isOwned );
|
jamie@264
|
3000 void release();
|
jamie@264
|
3001
|
jamie@264
|
3002 std::streambuf* streamBuf;
|
jamie@264
|
3003
|
jamie@264
|
3004 private:
|
jamie@264
|
3005 bool isOwned;
|
jamie@264
|
3006 };
|
jamie@264
|
3007 }
|
jamie@264
|
3008
|
jamie@264
|
3009 #include <memory>
|
jamie@264
|
3010 #include <vector>
|
jamie@264
|
3011 #include <string>
|
jamie@264
|
3012 #include <iostream>
|
jamie@264
|
3013
|
jamie@264
|
3014 #ifndef CATCH_CONFIG_CONSOLE_WIDTH
|
jamie@264
|
3015 #define CATCH_CONFIG_CONSOLE_WIDTH 80
|
jamie@264
|
3016 #endif
|
jamie@264
|
3017
|
jamie@264
|
3018 namespace Catch {
|
jamie@264
|
3019
|
jamie@264
|
3020 struct ConfigData {
|
jamie@264
|
3021
|
jamie@264
|
3022 ConfigData()
|
jamie@264
|
3023 : listTests( false ),
|
jamie@264
|
3024 listTags( false ),
|
jamie@264
|
3025 listReporters( false ),
|
jamie@264
|
3026 listTestNamesOnly( false ),
|
jamie@264
|
3027 showSuccessfulTests( false ),
|
jamie@264
|
3028 shouldDebugBreak( false ),
|
jamie@264
|
3029 noThrow( false ),
|
jamie@264
|
3030 showHelp( false ),
|
jamie@264
|
3031 showInvisibles( false ),
|
jamie@264
|
3032 abortAfter( -1 ),
|
jamie@264
|
3033 verbosity( Verbosity::Normal ),
|
jamie@264
|
3034 warnings( WarnAbout::Nothing ),
|
jamie@264
|
3035 showDurations( ShowDurations::DefaultForReporter )
|
jamie@264
|
3036 {}
|
jamie@264
|
3037
|
jamie@264
|
3038 bool listTests;
|
jamie@264
|
3039 bool listTags;
|
jamie@264
|
3040 bool listReporters;
|
jamie@264
|
3041 bool listTestNamesOnly;
|
jamie@264
|
3042
|
jamie@264
|
3043 bool showSuccessfulTests;
|
jamie@264
|
3044 bool shouldDebugBreak;
|
jamie@264
|
3045 bool noThrow;
|
jamie@264
|
3046 bool showHelp;
|
jamie@264
|
3047 bool showInvisibles;
|
jamie@264
|
3048
|
jamie@264
|
3049 int abortAfter;
|
jamie@264
|
3050
|
jamie@264
|
3051 Verbosity::Level verbosity;
|
jamie@264
|
3052 WarnAbout::What warnings;
|
jamie@264
|
3053 ShowDurations::OrNot showDurations;
|
jamie@264
|
3054
|
jamie@264
|
3055 std::string reporterName;
|
jamie@264
|
3056 std::string outputFilename;
|
jamie@264
|
3057 std::string name;
|
jamie@264
|
3058 std::string processName;
|
jamie@264
|
3059
|
jamie@264
|
3060 std::vector<std::string> testsOrTags;
|
jamie@264
|
3061 };
|
jamie@264
|
3062
|
jamie@264
|
3063 class Config : public SharedImpl<IConfig> {
|
jamie@264
|
3064 private:
|
jamie@264
|
3065 Config( Config const& other );
|
jamie@264
|
3066 Config& operator = ( Config const& other );
|
jamie@264
|
3067 virtual void dummy();
|
jamie@264
|
3068 public:
|
jamie@264
|
3069
|
jamie@264
|
3070 Config()
|
jamie@264
|
3071 : m_os( std::cout.rdbuf() )
|
jamie@264
|
3072 {}
|
jamie@264
|
3073
|
jamie@264
|
3074 Config( ConfigData const& data )
|
jamie@264
|
3075 : m_data( data ),
|
jamie@264
|
3076 m_os( std::cout.rdbuf() )
|
jamie@264
|
3077 {
|
jamie@264
|
3078 if( !data.testsOrTags.empty() ) {
|
jamie@264
|
3079 TestSpecParser parser( ITagAliasRegistry::get() );
|
jamie@264
|
3080 for( std::size_t i = 0; i < data.testsOrTags.size(); ++i )
|
jamie@264
|
3081 parser.parse( data.testsOrTags[i] );
|
jamie@264
|
3082 m_testSpec = parser.testSpec();
|
jamie@264
|
3083 }
|
jamie@264
|
3084 }
|
jamie@264
|
3085
|
jamie@264
|
3086 virtual ~Config() {
|
jamie@264
|
3087 m_os.rdbuf( std::cout.rdbuf() );
|
jamie@264
|
3088 m_stream.release();
|
jamie@264
|
3089 }
|
jamie@264
|
3090
|
jamie@264
|
3091 void setFilename( std::string const& filename ) {
|
jamie@264
|
3092 m_data.outputFilename = filename;
|
jamie@264
|
3093 }
|
jamie@264
|
3094
|
jamie@264
|
3095 std::string const& getFilename() const {
|
jamie@264
|
3096 return m_data.outputFilename ;
|
jamie@264
|
3097 }
|
jamie@264
|
3098
|
jamie@264
|
3099 bool listTests() const { return m_data.listTests; }
|
jamie@264
|
3100 bool listTestNamesOnly() const { return m_data.listTestNamesOnly; }
|
jamie@264
|
3101 bool listTags() const { return m_data.listTags; }
|
jamie@264
|
3102 bool listReporters() const { return m_data.listReporters; }
|
jamie@264
|
3103
|
jamie@264
|
3104 std::string getProcessName() const { return m_data.processName; }
|
jamie@264
|
3105
|
jamie@264
|
3106 bool shouldDebugBreak() const { return m_data.shouldDebugBreak; }
|
jamie@264
|
3107
|
jamie@264
|
3108 void setStreamBuf( std::streambuf* buf ) {
|
jamie@264
|
3109 m_os.rdbuf( buf ? buf : std::cout.rdbuf() );
|
jamie@264
|
3110 }
|
jamie@264
|
3111
|
jamie@264
|
3112 void useStream( std::string const& streamName ) {
|
jamie@264
|
3113 Stream stream = createStream( streamName );
|
jamie@264
|
3114 setStreamBuf( stream.streamBuf );
|
jamie@264
|
3115 m_stream.release();
|
jamie@264
|
3116 m_stream = stream;
|
jamie@264
|
3117 }
|
jamie@264
|
3118
|
jamie@264
|
3119 std::string getReporterName() const { return m_data.reporterName; }
|
jamie@264
|
3120
|
jamie@264
|
3121 int abortAfter() const { return m_data.abortAfter; }
|
jamie@264
|
3122
|
jamie@264
|
3123 TestSpec const& testSpec() const { return m_testSpec; }
|
jamie@264
|
3124
|
jamie@264
|
3125 bool showHelp() const { return m_data.showHelp; }
|
jamie@264
|
3126 bool showInvisibles() const { return m_data.showInvisibles; }
|
jamie@264
|
3127
|
jamie@264
|
3128 // IConfig interface
|
jamie@264
|
3129 virtual bool allowThrows() const { return !m_data.noThrow; }
|
jamie@264
|
3130 virtual std::ostream& stream() const { return m_os; }
|
jamie@264
|
3131 virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; }
|
jamie@264
|
3132 virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; }
|
jamie@264
|
3133 virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; }
|
jamie@264
|
3134 virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; }
|
jamie@264
|
3135
|
jamie@264
|
3136 private:
|
jamie@264
|
3137 ConfigData m_data;
|
jamie@264
|
3138
|
jamie@264
|
3139 Stream m_stream;
|
jamie@264
|
3140 mutable std::ostream m_os;
|
jamie@264
|
3141 TestSpec m_testSpec;
|
jamie@264
|
3142 };
|
jamie@264
|
3143
|
jamie@264
|
3144 } // end namespace Catch
|
jamie@264
|
3145
|
jamie@264
|
3146 // #included from: catch_clara.h
|
jamie@264
|
3147 #define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED
|
jamie@264
|
3148
|
jamie@264
|
3149 // Use Catch's value for console width (store Clara's off to the side, if present)
|
jamie@264
|
3150 #ifdef CLARA_CONFIG_CONSOLE_WIDTH
|
jamie@264
|
3151 #define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH
|
jamie@264
|
3152 #undef CLARA_CONFIG_CONSOLE_WIDTH
|
jamie@264
|
3153 #endif
|
jamie@264
|
3154 #define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH
|
jamie@264
|
3155
|
jamie@264
|
3156 // Declare Clara inside the Catch namespace
|
jamie@264
|
3157 #define STITCH_CLARA_OPEN_NAMESPACE namespace Catch {
|
jamie@264
|
3158 // #included from: ../external/clara.h
|
jamie@264
|
3159
|
jamie@264
|
3160 // Only use header guard if we are not using an outer namespace
|
jamie@264
|
3161 #if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE)
|
jamie@264
|
3162
|
jamie@264
|
3163 #ifndef STITCH_CLARA_OPEN_NAMESPACE
|
jamie@264
|
3164 #define TWOBLUECUBES_CLARA_H_INCLUDED
|
jamie@264
|
3165 #define STITCH_CLARA_OPEN_NAMESPACE
|
jamie@264
|
3166 #define STITCH_CLARA_CLOSE_NAMESPACE
|
jamie@264
|
3167 #else
|
jamie@264
|
3168 #define STITCH_CLARA_CLOSE_NAMESPACE }
|
jamie@264
|
3169 #endif
|
jamie@264
|
3170
|
jamie@264
|
3171 #define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE
|
jamie@264
|
3172
|
jamie@264
|
3173 // ----------- #included from tbc_text_format.h -----------
|
jamie@264
|
3174
|
jamie@264
|
3175 // Only use header guard if we are not using an outer namespace
|
jamie@264
|
3176 #if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE)
|
jamie@264
|
3177 #ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
|
jamie@264
|
3178 #define TBC_TEXT_FORMAT_H_INCLUDED
|
jamie@264
|
3179 #endif
|
jamie@264
|
3180
|
jamie@264
|
3181 #include <string>
|
jamie@264
|
3182 #include <vector>
|
jamie@264
|
3183 #include <sstream>
|
jamie@264
|
3184
|
jamie@264
|
3185 // Use optional outer namespace
|
jamie@264
|
3186 #ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
|
jamie@264
|
3187 namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE {
|
jamie@264
|
3188 #endif
|
jamie@264
|
3189
|
jamie@264
|
3190 namespace Tbc {
|
jamie@264
|
3191
|
jamie@264
|
3192 #ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH
|
jamie@264
|
3193 const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH;
|
jamie@264
|
3194 #else
|
jamie@264
|
3195 const unsigned int consoleWidth = 80;
|
jamie@264
|
3196 #endif
|
jamie@264
|
3197
|
jamie@264
|
3198 struct TextAttributes {
|
jamie@264
|
3199 TextAttributes()
|
jamie@264
|
3200 : initialIndent( std::string::npos ),
|
jamie@264
|
3201 indent( 0 ),
|
jamie@264
|
3202 width( consoleWidth-1 ),
|
jamie@264
|
3203 tabChar( '\t' )
|
jamie@264
|
3204 {}
|
jamie@264
|
3205
|
jamie@264
|
3206 TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; }
|
jamie@264
|
3207 TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; }
|
jamie@264
|
3208 TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; }
|
jamie@264
|
3209 TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; }
|
jamie@264
|
3210
|
jamie@264
|
3211 std::size_t initialIndent; // indent of first line, or npos
|
jamie@264
|
3212 std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos
|
jamie@264
|
3213 std::size_t width; // maximum width of text, including indent. Longer text will wrap
|
jamie@264
|
3214 char tabChar; // If this char is seen the indent is changed to current pos
|
jamie@264
|
3215 };
|
jamie@264
|
3216
|
jamie@264
|
3217 class Text {
|
jamie@264
|
3218 public:
|
jamie@264
|
3219 Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() )
|
jamie@264
|
3220 : attr( _attr )
|
jamie@264
|
3221 {
|
jamie@264
|
3222 std::string wrappableChars = " [({.,/|\\-";
|
jamie@264
|
3223 std::size_t indent = _attr.initialIndent != std::string::npos
|
jamie@264
|
3224 ? _attr.initialIndent
|
jamie@264
|
3225 : _attr.indent;
|
jamie@264
|
3226 std::string remainder = _str;
|
jamie@264
|
3227
|
jamie@264
|
3228 while( !remainder.empty() ) {
|
jamie@264
|
3229 if( lines.size() >= 1000 ) {
|
jamie@264
|
3230 lines.push_back( "... message truncated due to excessive size" );
|
jamie@264
|
3231 return;
|
jamie@264
|
3232 }
|
jamie@264
|
3233 std::size_t tabPos = std::string::npos;
|
jamie@264
|
3234 std::size_t width = (std::min)( remainder.size(), _attr.width - indent );
|
jamie@264
|
3235 std::size_t pos = remainder.find_first_of( '\n' );
|
jamie@264
|
3236 if( pos <= width ) {
|
jamie@264
|
3237 width = pos;
|
jamie@264
|
3238 }
|
jamie@264
|
3239 pos = remainder.find_last_of( _attr.tabChar, width );
|
jamie@264
|
3240 if( pos != std::string::npos ) {
|
jamie@264
|
3241 tabPos = pos;
|
jamie@264
|
3242 if( remainder[width] == '\n' )
|
jamie@264
|
3243 width--;
|
jamie@264
|
3244 remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 );
|
jamie@264
|
3245 }
|
jamie@264
|
3246
|
jamie@264
|
3247 if( width == remainder.size() ) {
|
jamie@264
|
3248 spliceLine( indent, remainder, width );
|
jamie@264
|
3249 }
|
jamie@264
|
3250 else if( remainder[width] == '\n' ) {
|
jamie@264
|
3251 spliceLine( indent, remainder, width );
|
jamie@264
|
3252 if( width <= 1 || remainder.size() != 1 )
|
jamie@264
|
3253 remainder = remainder.substr( 1 );
|
jamie@264
|
3254 indent = _attr.indent;
|
jamie@264
|
3255 }
|
jamie@264
|
3256 else {
|
jamie@264
|
3257 pos = remainder.find_last_of( wrappableChars, width );
|
jamie@264
|
3258 if( pos != std::string::npos && pos > 0 ) {
|
jamie@264
|
3259 spliceLine( indent, remainder, pos );
|
jamie@264
|
3260 if( remainder[0] == ' ' )
|
jamie@264
|
3261 remainder = remainder.substr( 1 );
|
jamie@264
|
3262 }
|
jamie@264
|
3263 else {
|
jamie@264
|
3264 spliceLine( indent, remainder, width-1 );
|
jamie@264
|
3265 lines.back() += "-";
|
jamie@264
|
3266 }
|
jamie@264
|
3267 if( lines.size() == 1 )
|
jamie@264
|
3268 indent = _attr.indent;
|
jamie@264
|
3269 if( tabPos != std::string::npos )
|
jamie@264
|
3270 indent += tabPos;
|
jamie@264
|
3271 }
|
jamie@264
|
3272 }
|
jamie@264
|
3273 }
|
jamie@264
|
3274
|
jamie@264
|
3275 void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) {
|
jamie@264
|
3276 lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) );
|
jamie@264
|
3277 _remainder = _remainder.substr( _pos );
|
jamie@264
|
3278 }
|
jamie@264
|
3279
|
jamie@264
|
3280 typedef std::vector<std::string>::const_iterator const_iterator;
|
jamie@264
|
3281
|
jamie@264
|
3282 const_iterator begin() const { return lines.begin(); }
|
jamie@264
|
3283 const_iterator end() const { return lines.end(); }
|
jamie@264
|
3284 std::string const& last() const { return lines.back(); }
|
jamie@264
|
3285 std::size_t size() const { return lines.size(); }
|
jamie@264
|
3286 std::string const& operator[]( std::size_t _index ) const { return lines[_index]; }
|
jamie@264
|
3287 std::string toString() const {
|
jamie@264
|
3288 std::ostringstream oss;
|
jamie@264
|
3289 oss << *this;
|
jamie@264
|
3290 return oss.str();
|
jamie@264
|
3291 }
|
jamie@264
|
3292
|
jamie@264
|
3293 inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) {
|
jamie@264
|
3294 for( Text::const_iterator it = _text.begin(), itEnd = _text.end();
|
jamie@264
|
3295 it != itEnd; ++it ) {
|
jamie@264
|
3296 if( it != _text.begin() )
|
jamie@264
|
3297 _stream << "\n";
|
jamie@264
|
3298 _stream << *it;
|
jamie@264
|
3299 }
|
jamie@264
|
3300 return _stream;
|
jamie@264
|
3301 }
|
jamie@264
|
3302
|
jamie@264
|
3303 private:
|
jamie@264
|
3304 std::string str;
|
jamie@264
|
3305 TextAttributes attr;
|
jamie@264
|
3306 std::vector<std::string> lines;
|
jamie@264
|
3307 };
|
jamie@264
|
3308
|
jamie@264
|
3309 } // end namespace Tbc
|
jamie@264
|
3310
|
jamie@264
|
3311 #ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
|
jamie@264
|
3312 } // end outer namespace
|
jamie@264
|
3313 #endif
|
jamie@264
|
3314
|
jamie@264
|
3315 #endif // TBC_TEXT_FORMAT_H_INCLUDED
|
jamie@264
|
3316
|
jamie@264
|
3317 // ----------- end of #include from tbc_text_format.h -----------
|
jamie@264
|
3318 // ........... back in /Users/philnash/Dev/OSS/Clara/srcs/clara.h
|
jamie@264
|
3319
|
jamie@264
|
3320 #undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE
|
jamie@264
|
3321
|
jamie@264
|
3322 #include <map>
|
jamie@264
|
3323 #include <algorithm>
|
jamie@264
|
3324 #include <stdexcept>
|
jamie@264
|
3325 #include <memory>
|
jamie@264
|
3326
|
jamie@264
|
3327 // Use optional outer namespace
|
jamie@264
|
3328 #ifdef STITCH_CLARA_OPEN_NAMESPACE
|
jamie@264
|
3329 STITCH_CLARA_OPEN_NAMESPACE
|
jamie@264
|
3330 #endif
|
jamie@264
|
3331
|
jamie@264
|
3332 namespace Clara {
|
jamie@264
|
3333
|
jamie@264
|
3334 struct UnpositionalTag {};
|
jamie@264
|
3335
|
jamie@264
|
3336 extern UnpositionalTag _;
|
jamie@264
|
3337
|
jamie@264
|
3338 #ifdef CLARA_CONFIG_MAIN
|
jamie@264
|
3339 UnpositionalTag _;
|
jamie@264
|
3340 #endif
|
jamie@264
|
3341
|
jamie@264
|
3342 namespace Detail {
|
jamie@264
|
3343
|
jamie@264
|
3344 #ifdef CLARA_CONSOLE_WIDTH
|
jamie@264
|
3345 const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH;
|
jamie@264
|
3346 #else
|
jamie@264
|
3347 const unsigned int consoleWidth = 80;
|
jamie@264
|
3348 #endif
|
jamie@264
|
3349
|
jamie@264
|
3350 using namespace Tbc;
|
jamie@264
|
3351
|
jamie@264
|
3352 inline bool startsWith( std::string const& str, std::string const& prefix ) {
|
jamie@264
|
3353 return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix;
|
jamie@264
|
3354 }
|
jamie@264
|
3355
|
jamie@264
|
3356 template<typename T> struct RemoveConstRef{ typedef T type; };
|
jamie@264
|
3357 template<typename T> struct RemoveConstRef<T&>{ typedef T type; };
|
jamie@264
|
3358 template<typename T> struct RemoveConstRef<T const&>{ typedef T type; };
|
jamie@264
|
3359 template<typename T> struct RemoveConstRef<T const>{ typedef T type; };
|
jamie@264
|
3360
|
jamie@264
|
3361 template<typename T> struct IsBool { static const bool value = false; };
|
jamie@264
|
3362 template<> struct IsBool<bool> { static const bool value = true; };
|
jamie@264
|
3363
|
jamie@264
|
3364 template<typename T>
|
jamie@264
|
3365 void convertInto( std::string const& _source, T& _dest ) {
|
jamie@264
|
3366 std::stringstream ss;
|
jamie@264
|
3367 ss << _source;
|
jamie@264
|
3368 ss >> _dest;
|
jamie@264
|
3369 if( ss.fail() )
|
jamie@264
|
3370 throw std::runtime_error( "Unable to convert " + _source + " to destination type" );
|
jamie@264
|
3371 }
|
jamie@264
|
3372 inline void convertInto( std::string const& _source, std::string& _dest ) {
|
jamie@264
|
3373 _dest = _source;
|
jamie@264
|
3374 }
|
jamie@264
|
3375 inline void convertInto( std::string const& _source, bool& _dest ) {
|
jamie@264
|
3376 std::string sourceLC = _source;
|
jamie@264
|
3377 std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), ::tolower );
|
jamie@264
|
3378 if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" )
|
jamie@264
|
3379 _dest = true;
|
jamie@264
|
3380 else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" )
|
jamie@264
|
3381 _dest = false;
|
jamie@264
|
3382 else
|
jamie@264
|
3383 throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" );
|
jamie@264
|
3384 }
|
jamie@264
|
3385 inline void convertInto( bool _source, bool& _dest ) {
|
jamie@264
|
3386 _dest = _source;
|
jamie@264
|
3387 }
|
jamie@264
|
3388 template<typename T>
|
jamie@264
|
3389 inline void convertInto( bool, T& ) {
|
jamie@264
|
3390 throw std::runtime_error( "Invalid conversion" );
|
jamie@264
|
3391 }
|
jamie@264
|
3392
|
jamie@264
|
3393 template<typename ConfigT>
|
jamie@264
|
3394 struct IArgFunction {
|
jamie@264
|
3395 virtual ~IArgFunction() {}
|
jamie@264
|
3396 # ifdef CATCH_CPP11_OR_GREATER
|
jamie@264
|
3397 IArgFunction() = default;
|
jamie@264
|
3398 IArgFunction( IArgFunction const& ) = default;
|
jamie@264
|
3399 # endif
|
jamie@264
|
3400 virtual void set( ConfigT& config, std::string const& value ) const = 0;
|
jamie@264
|
3401 virtual void setFlag( ConfigT& config ) const = 0;
|
jamie@264
|
3402 virtual bool takesArg() const = 0;
|
jamie@264
|
3403 virtual IArgFunction* clone() const = 0;
|
jamie@264
|
3404 };
|
jamie@264
|
3405
|
jamie@264
|
3406 template<typename ConfigT>
|
jamie@264
|
3407 class BoundArgFunction {
|
jamie@264
|
3408 public:
|
jamie@264
|
3409 BoundArgFunction() : functionObj( NULL ) {}
|
jamie@264
|
3410 BoundArgFunction( IArgFunction<ConfigT>* _functionObj ) : functionObj( _functionObj ) {}
|
jamie@264
|
3411 BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : NULL ) {}
|
jamie@264
|
3412 BoundArgFunction& operator = ( BoundArgFunction const& other ) {
|
jamie@264
|
3413 IArgFunction<ConfigT>* newFunctionObj = other.functionObj ? other.functionObj->clone() : NULL;
|
jamie@264
|
3414 delete functionObj;
|
jamie@264
|
3415 functionObj = newFunctionObj;
|
jamie@264
|
3416 return *this;
|
jamie@264
|
3417 }
|
jamie@264
|
3418 ~BoundArgFunction() { delete functionObj; }
|
jamie@264
|
3419
|
jamie@264
|
3420 void set( ConfigT& config, std::string const& value ) const {
|
jamie@264
|
3421 functionObj->set( config, value );
|
jamie@264
|
3422 }
|
jamie@264
|
3423 void setFlag( ConfigT& config ) const {
|
jamie@264
|
3424 functionObj->setFlag( config );
|
jamie@264
|
3425 }
|
jamie@264
|
3426 bool takesArg() const { return functionObj->takesArg(); }
|
jamie@264
|
3427
|
jamie@264
|
3428 bool isSet() const {
|
jamie@264
|
3429 return functionObj != NULL;
|
jamie@264
|
3430 }
|
jamie@264
|
3431 private:
|
jamie@264
|
3432 IArgFunction<ConfigT>* functionObj;
|
jamie@264
|
3433 };
|
jamie@264
|
3434
|
jamie@264
|
3435 template<typename C>
|
jamie@264
|
3436 struct NullBinder : IArgFunction<C>{
|
jamie@264
|
3437 virtual void set( C&, std::string const& ) const {}
|
jamie@264
|
3438 virtual void setFlag( C& ) const {}
|
jamie@264
|
3439 virtual bool takesArg() const { return true; }
|
jamie@264
|
3440 virtual IArgFunction<C>* clone() const { return new NullBinder( *this ); }
|
jamie@264
|
3441 };
|
jamie@264
|
3442
|
jamie@264
|
3443 template<typename C, typename M>
|
jamie@264
|
3444 struct BoundDataMember : IArgFunction<C>{
|
jamie@264
|
3445 BoundDataMember( M C::* _member ) : member( _member ) {}
|
jamie@264
|
3446 virtual void set( C& p, std::string const& stringValue ) const {
|
jamie@264
|
3447 convertInto( stringValue, p.*member );
|
jamie@264
|
3448 }
|
jamie@264
|
3449 virtual void setFlag( C& p ) const {
|
jamie@264
|
3450 convertInto( true, p.*member );
|
jamie@264
|
3451 }
|
jamie@264
|
3452 virtual bool takesArg() const { return !IsBool<M>::value; }
|
jamie@264
|
3453 virtual IArgFunction<C>* clone() const { return new BoundDataMember( *this ); }
|
jamie@264
|
3454 M C::* member;
|
jamie@264
|
3455 };
|
jamie@264
|
3456 template<typename C, typename M>
|
jamie@264
|
3457 struct BoundUnaryMethod : IArgFunction<C>{
|
jamie@264
|
3458 BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {}
|
jamie@264
|
3459 virtual void set( C& p, std::string const& stringValue ) const {
|
jamie@264
|
3460 typename RemoveConstRef<M>::type value;
|
jamie@264
|
3461 convertInto( stringValue, value );
|
jamie@264
|
3462 (p.*member)( value );
|
jamie@264
|
3463 }
|
jamie@264
|
3464 virtual void setFlag( C& p ) const {
|
jamie@264
|
3465 typename RemoveConstRef<M>::type value;
|
jamie@264
|
3466 convertInto( true, value );
|
jamie@264
|
3467 (p.*member)( value );
|
jamie@264
|
3468 }
|
jamie@264
|
3469 virtual bool takesArg() const { return !IsBool<M>::value; }
|
jamie@264
|
3470 virtual IArgFunction<C>* clone() const { return new BoundUnaryMethod( *this ); }
|
jamie@264
|
3471 void (C::*member)( M );
|
jamie@264
|
3472 };
|
jamie@264
|
3473 template<typename C>
|
jamie@264
|
3474 struct BoundNullaryMethod : IArgFunction<C>{
|
jamie@264
|
3475 BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {}
|
jamie@264
|
3476 virtual void set( C& p, std::string const& stringValue ) const {
|
jamie@264
|
3477 bool value;
|
jamie@264
|
3478 convertInto( stringValue, value );
|
jamie@264
|
3479 if( value )
|
jamie@264
|
3480 (p.*member)();
|
jamie@264
|
3481 }
|
jamie@264
|
3482 virtual void setFlag( C& p ) const {
|
jamie@264
|
3483 (p.*member)();
|
jamie@264
|
3484 }
|
jamie@264
|
3485 virtual bool takesArg() const { return false; }
|
jamie@264
|
3486 virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod( *this ); }
|
jamie@264
|
3487 void (C::*member)();
|
jamie@264
|
3488 };
|
jamie@264
|
3489
|
jamie@264
|
3490 template<typename C>
|
jamie@264
|
3491 struct BoundUnaryFunction : IArgFunction<C>{
|
jamie@264
|
3492 BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {}
|
jamie@264
|
3493 virtual void set( C& obj, std::string const& stringValue ) const {
|
jamie@264
|
3494 bool value;
|
jamie@264
|
3495 convertInto( stringValue, value );
|
jamie@264
|
3496 if( value )
|
jamie@264
|
3497 function( obj );
|
jamie@264
|
3498 }
|
jamie@264
|
3499 virtual void setFlag( C& p ) const {
|
jamie@264
|
3500 function( p );
|
jamie@264
|
3501 }
|
jamie@264
|
3502 virtual bool takesArg() const { return false; }
|
jamie@264
|
3503 virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction( *this ); }
|
jamie@264
|
3504 void (*function)( C& );
|
jamie@264
|
3505 };
|
jamie@264
|
3506
|
jamie@264
|
3507 template<typename C, typename T>
|
jamie@264
|
3508 struct BoundBinaryFunction : IArgFunction<C>{
|
jamie@264
|
3509 BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {}
|
jamie@264
|
3510 virtual void set( C& obj, std::string const& stringValue ) const {
|
jamie@264
|
3511 typename RemoveConstRef<T>::type value;
|
jamie@264
|
3512 convertInto( stringValue, value );
|
jamie@264
|
3513 function( obj, value );
|
jamie@264
|
3514 }
|
jamie@264
|
3515 virtual void setFlag( C& obj ) const {
|
jamie@264
|
3516 typename RemoveConstRef<T>::type value;
|
jamie@264
|
3517 convertInto( true, value );
|
jamie@264
|
3518 function( obj, value );
|
jamie@264
|
3519 }
|
jamie@264
|
3520 virtual bool takesArg() const { return !IsBool<T>::value; }
|
jamie@264
|
3521 virtual IArgFunction<C>* clone() const { return new BoundBinaryFunction( *this ); }
|
jamie@264
|
3522 void (*function)( C&, T );
|
jamie@264
|
3523 };
|
jamie@264
|
3524
|
jamie@264
|
3525 } // namespace Detail
|
jamie@264
|
3526
|
jamie@264
|
3527 struct Parser {
|
jamie@264
|
3528 Parser() : separators( " \t=:" ) {}
|
jamie@264
|
3529
|
jamie@264
|
3530 struct Token {
|
jamie@264
|
3531 enum Type { Positional, ShortOpt, LongOpt };
|
jamie@264
|
3532 Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {}
|
jamie@264
|
3533 Type type;
|
jamie@264
|
3534 std::string data;
|
jamie@264
|
3535 };
|
jamie@264
|
3536
|
jamie@264
|
3537 void parseIntoTokens( int argc, char const * const * argv, std::vector<Parser::Token>& tokens ) const {
|
jamie@264
|
3538 const std::string doubleDash = "--";
|
jamie@264
|
3539 for( int i = 1; i < argc && argv[i] != doubleDash; ++i )
|
jamie@264
|
3540 parseIntoTokens( argv[i] , tokens);
|
jamie@264
|
3541 }
|
jamie@264
|
3542 void parseIntoTokens( std::string arg, std::vector<Parser::Token>& tokens ) const {
|
jamie@264
|
3543 while( !arg.empty() ) {
|
jamie@264
|
3544 Parser::Token token( Parser::Token::Positional, arg );
|
jamie@264
|
3545 arg = "";
|
jamie@264
|
3546 if( token.data[0] == '-' ) {
|
jamie@264
|
3547 if( token.data.size() > 1 && token.data[1] == '-' ) {
|
jamie@264
|
3548 token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) );
|
jamie@264
|
3549 }
|
jamie@264
|
3550 else {
|
jamie@264
|
3551 token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) );
|
jamie@264
|
3552 if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) {
|
jamie@264
|
3553 arg = "-" + token.data.substr( 1 );
|
jamie@264
|
3554 token.data = token.data.substr( 0, 1 );
|
jamie@264
|
3555 }
|
jamie@264
|
3556 }
|
jamie@264
|
3557 }
|
jamie@264
|
3558 if( token.type != Parser::Token::Positional ) {
|
jamie@264
|
3559 std::size_t pos = token.data.find_first_of( separators );
|
jamie@264
|
3560 if( pos != std::string::npos ) {
|
jamie@264
|
3561 arg = token.data.substr( pos+1 );
|
jamie@264
|
3562 token.data = token.data.substr( 0, pos );
|
jamie@264
|
3563 }
|
jamie@264
|
3564 }
|
jamie@264
|
3565 tokens.push_back( token );
|
jamie@264
|
3566 }
|
jamie@264
|
3567 }
|
jamie@264
|
3568 std::string separators;
|
jamie@264
|
3569 };
|
jamie@264
|
3570
|
jamie@264
|
3571 template<typename ConfigT>
|
jamie@264
|
3572 struct CommonArgProperties {
|
jamie@264
|
3573 CommonArgProperties() {}
|
jamie@264
|
3574 CommonArgProperties( Detail::BoundArgFunction<ConfigT> const& _boundField ) : boundField( _boundField ) {}
|
jamie@264
|
3575
|
jamie@264
|
3576 Detail::BoundArgFunction<ConfigT> boundField;
|
jamie@264
|
3577 std::string description;
|
jamie@264
|
3578 std::string detail;
|
jamie@264
|
3579 std::string placeholder; // Only value if boundField takes an arg
|
jamie@264
|
3580
|
jamie@264
|
3581 bool takesArg() const {
|
jamie@264
|
3582 return !placeholder.empty();
|
jamie@264
|
3583 }
|
jamie@264
|
3584 void validate() const {
|
jamie@264
|
3585 if( !boundField.isSet() )
|
jamie@264
|
3586 throw std::logic_error( "option not bound" );
|
jamie@264
|
3587 }
|
jamie@264
|
3588 };
|
jamie@264
|
3589 struct OptionArgProperties {
|
jamie@264
|
3590 std::vector<std::string> shortNames;
|
jamie@264
|
3591 std::string longName;
|
jamie@264
|
3592
|
jamie@264
|
3593 bool hasShortName( std::string const& shortName ) const {
|
jamie@264
|
3594 return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end();
|
jamie@264
|
3595 }
|
jamie@264
|
3596 bool hasLongName( std::string const& _longName ) const {
|
jamie@264
|
3597 return _longName == longName;
|
jamie@264
|
3598 }
|
jamie@264
|
3599 };
|
jamie@264
|
3600 struct PositionalArgProperties {
|
jamie@264
|
3601 PositionalArgProperties() : position( -1 ) {}
|
jamie@264
|
3602 int position; // -1 means non-positional (floating)
|
jamie@264
|
3603
|
jamie@264
|
3604 bool isFixedPositional() const {
|
jamie@264
|
3605 return position != -1;
|
jamie@264
|
3606 }
|
jamie@264
|
3607 };
|
jamie@264
|
3608
|
jamie@264
|
3609 template<typename ConfigT>
|
jamie@264
|
3610 class CommandLine {
|
jamie@264
|
3611
|
jamie@264
|
3612 struct Arg : CommonArgProperties<ConfigT>, OptionArgProperties, PositionalArgProperties {
|
jamie@264
|
3613 Arg() {}
|
jamie@264
|
3614 Arg( Detail::BoundArgFunction<ConfigT> const& _boundField ) : CommonArgProperties<ConfigT>( _boundField ) {}
|
jamie@264
|
3615
|
jamie@264
|
3616 using CommonArgProperties<ConfigT>::placeholder; // !TBD
|
jamie@264
|
3617
|
jamie@264
|
3618 std::string dbgName() const {
|
jamie@264
|
3619 if( !longName.empty() )
|
jamie@264
|
3620 return "--" + longName;
|
jamie@264
|
3621 if( !shortNames.empty() )
|
jamie@264
|
3622 return "-" + shortNames[0];
|
jamie@264
|
3623 return "positional args";
|
jamie@264
|
3624 }
|
jamie@264
|
3625 std::string commands() const {
|
jamie@264
|
3626 std::ostringstream oss;
|
jamie@264
|
3627 bool first = true;
|
jamie@264
|
3628 std::vector<std::string>::const_iterator it = shortNames.begin(), itEnd = shortNames.end();
|
jamie@264
|
3629 for(; it != itEnd; ++it ) {
|
jamie@264
|
3630 if( first )
|
jamie@264
|
3631 first = false;
|
jamie@264
|
3632 else
|
jamie@264
|
3633 oss << ", ";
|
jamie@264
|
3634 oss << "-" << *it;
|
jamie@264
|
3635 }
|
jamie@264
|
3636 if( !longName.empty() ) {
|
jamie@264
|
3637 if( !first )
|
jamie@264
|
3638 oss << ", ";
|
jamie@264
|
3639 oss << "--" << longName;
|
jamie@264
|
3640 }
|
jamie@264
|
3641 if( !placeholder.empty() )
|
jamie@264
|
3642 oss << " <" << placeholder << ">";
|
jamie@264
|
3643 return oss.str();
|
jamie@264
|
3644 }
|
jamie@264
|
3645 };
|
jamie@264
|
3646
|
jamie@264
|
3647 // NOTE: std::auto_ptr is deprecated in c++11/c++0x
|
jamie@264
|
3648 #if defined(__cplusplus) && __cplusplus > 199711L
|
jamie@264
|
3649 typedef std::unique_ptr<Arg> ArgAutoPtr;
|
jamie@264
|
3650 #else
|
jamie@264
|
3651 typedef std::auto_ptr<Arg> ArgAutoPtr;
|
jamie@264
|
3652 #endif
|
jamie@264
|
3653
|
jamie@264
|
3654 friend void addOptName( Arg& arg, std::string const& optName )
|
jamie@264
|
3655 {
|
jamie@264
|
3656 if( optName.empty() )
|
jamie@264
|
3657 return;
|
jamie@264
|
3658 if( Detail::startsWith( optName, "--" ) ) {
|
jamie@264
|
3659 if( !arg.longName.empty() )
|
jamie@264
|
3660 throw std::logic_error( "Only one long opt may be specified. '"
|
jamie@264
|
3661 + arg.longName
|
jamie@264
|
3662 + "' already specified, now attempting to add '"
|
jamie@264
|
3663 + optName + "'" );
|
jamie@264
|
3664 arg.longName = optName.substr( 2 );
|
jamie@264
|
3665 }
|
jamie@264
|
3666 else if( Detail::startsWith( optName, "-" ) )
|
jamie@264
|
3667 arg.shortNames.push_back( optName.substr( 1 ) );
|
jamie@264
|
3668 else
|
jamie@264
|
3669 throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" );
|
jamie@264
|
3670 }
|
jamie@264
|
3671 friend void setPositionalArg( Arg& arg, int position )
|
jamie@264
|
3672 {
|
jamie@264
|
3673 arg.position = position;
|
jamie@264
|
3674 }
|
jamie@264
|
3675
|
jamie@264
|
3676 class ArgBuilder {
|
jamie@264
|
3677 public:
|
jamie@264
|
3678 ArgBuilder( Arg* arg ) : m_arg( arg ) {}
|
jamie@264
|
3679
|
jamie@264
|
3680 // Bind a non-boolean data member (requires placeholder string)
|
jamie@264
|
3681 template<typename C, typename M>
|
jamie@264
|
3682 void bind( M C::* field, std::string const& placeholder ) {
|
jamie@264
|
3683 m_arg->boundField = new Detail::BoundDataMember<C,M>( field );
|
jamie@264
|
3684 m_arg->placeholder = placeholder;
|
jamie@264
|
3685 }
|
jamie@264
|
3686 // Bind a boolean data member (no placeholder required)
|
jamie@264
|
3687 template<typename C>
|
jamie@264
|
3688 void bind( bool C::* field ) {
|
jamie@264
|
3689 m_arg->boundField = new Detail::BoundDataMember<C,bool>( field );
|
jamie@264
|
3690 }
|
jamie@264
|
3691
|
jamie@264
|
3692 // Bind a method taking a single, non-boolean argument (requires a placeholder string)
|
jamie@264
|
3693 template<typename C, typename M>
|
jamie@264
|
3694 void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) {
|
jamie@264
|
3695 m_arg->boundField = new Detail::BoundUnaryMethod<C,M>( unaryMethod );
|
jamie@264
|
3696 m_arg->placeholder = placeholder;
|
jamie@264
|
3697 }
|
jamie@264
|
3698
|
jamie@264
|
3699 // Bind a method taking a single, boolean argument (no placeholder string required)
|
jamie@264
|
3700 template<typename C>
|
jamie@264
|
3701 void bind( void (C::* unaryMethod)( bool ) ) {
|
jamie@264
|
3702 m_arg->boundField = new Detail::BoundUnaryMethod<C,bool>( unaryMethod );
|
jamie@264
|
3703 }
|
jamie@264
|
3704
|
jamie@264
|
3705 // Bind a method that takes no arguments (will be called if opt is present)
|
jamie@264
|
3706 template<typename C>
|
jamie@264
|
3707 void bind( void (C::* nullaryMethod)() ) {
|
jamie@264
|
3708 m_arg->boundField = new Detail::BoundNullaryMethod<C>( nullaryMethod );
|
jamie@264
|
3709 }
|
jamie@264
|
3710
|
jamie@264
|
3711 // Bind a free function taking a single argument - the object to operate on (no placeholder string required)
|
jamie@264
|
3712 template<typename C>
|
jamie@264
|
3713 void bind( void (* unaryFunction)( C& ) ) {
|
jamie@264
|
3714 m_arg->boundField = new Detail::BoundUnaryFunction<C>( unaryFunction );
|
jamie@264
|
3715 }
|
jamie@264
|
3716
|
jamie@264
|
3717 // Bind a free function taking a single argument - the object to operate on (requires a placeholder string)
|
jamie@264
|
3718 template<typename C, typename T>
|
jamie@264
|
3719 void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) {
|
jamie@264
|
3720 m_arg->boundField = new Detail::BoundBinaryFunction<C, T>( binaryFunction );
|
jamie@264
|
3721 m_arg->placeholder = placeholder;
|
jamie@264
|
3722 }
|
jamie@264
|
3723
|
jamie@264
|
3724 ArgBuilder& describe( std::string const& description ) {
|
jamie@264
|
3725 m_arg->description = description;
|
jamie@264
|
3726 return *this;
|
jamie@264
|
3727 }
|
jamie@264
|
3728 ArgBuilder& detail( std::string const& detail ) {
|
jamie@264
|
3729 m_arg->detail = detail;
|
jamie@264
|
3730 return *this;
|
jamie@264
|
3731 }
|
jamie@264
|
3732
|
jamie@264
|
3733 protected:
|
jamie@264
|
3734 Arg* m_arg;
|
jamie@264
|
3735 };
|
jamie@264
|
3736
|
jamie@264
|
3737 class OptBuilder : public ArgBuilder {
|
jamie@264
|
3738 public:
|
jamie@264
|
3739 OptBuilder( Arg* arg ) : ArgBuilder( arg ) {}
|
jamie@264
|
3740 OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {}
|
jamie@264
|
3741
|
jamie@264
|
3742 OptBuilder& operator[]( std::string const& optName ) {
|
jamie@264
|
3743 addOptName( *ArgBuilder::m_arg, optName );
|
jamie@264
|
3744 return *this;
|
jamie@264
|
3745 }
|
jamie@264
|
3746 };
|
jamie@264
|
3747
|
jamie@264
|
3748 public:
|
jamie@264
|
3749
|
jamie@264
|
3750 CommandLine()
|
jamie@264
|
3751 : m_boundProcessName( new Detail::NullBinder<ConfigT>() ),
|
jamie@264
|
3752 m_highestSpecifiedArgPosition( 0 ),
|
jamie@264
|
3753 m_throwOnUnrecognisedTokens( false )
|
jamie@264
|
3754 {}
|
jamie@264
|
3755 CommandLine( CommandLine const& other )
|
jamie@264
|
3756 : m_boundProcessName( other.m_boundProcessName ),
|
jamie@264
|
3757 m_options ( other.m_options ),
|
jamie@264
|
3758 m_positionalArgs( other.m_positionalArgs ),
|
jamie@264
|
3759 m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ),
|
jamie@264
|
3760 m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens )
|
jamie@264
|
3761 {
|
jamie@264
|
3762 if( other.m_floatingArg.get() )
|
jamie@264
|
3763 m_floatingArg = ArgAutoPtr( new Arg( *other.m_floatingArg ) );
|
jamie@264
|
3764 }
|
jamie@264
|
3765
|
jamie@264
|
3766 CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) {
|
jamie@264
|
3767 m_throwOnUnrecognisedTokens = shouldThrow;
|
jamie@264
|
3768 return *this;
|
jamie@264
|
3769 }
|
jamie@264
|
3770
|
jamie@264
|
3771 OptBuilder operator[]( std::string const& optName ) {
|
jamie@264
|
3772 m_options.push_back( Arg() );
|
jamie@264
|
3773 addOptName( m_options.back(), optName );
|
jamie@264
|
3774 OptBuilder builder( &m_options.back() );
|
jamie@264
|
3775 return builder;
|
jamie@264
|
3776 }
|
jamie@264
|
3777
|
jamie@264
|
3778 ArgBuilder operator[]( int position ) {
|
jamie@264
|
3779 m_positionalArgs.insert( std::make_pair( position, Arg() ) );
|
jamie@264
|
3780 if( position > m_highestSpecifiedArgPosition )
|
jamie@264
|
3781 m_highestSpecifiedArgPosition = position;
|
jamie@264
|
3782 setPositionalArg( m_positionalArgs[position], position );
|
jamie@264
|
3783 ArgBuilder builder( &m_positionalArgs[position] );
|
jamie@264
|
3784 return builder;
|
jamie@264
|
3785 }
|
jamie@264
|
3786
|
jamie@264
|
3787 // Invoke this with the _ instance
|
jamie@264
|
3788 ArgBuilder operator[]( UnpositionalTag ) {
|
jamie@264
|
3789 if( m_floatingArg.get() )
|
jamie@264
|
3790 throw std::logic_error( "Only one unpositional argument can be added" );
|
jamie@264
|
3791 m_floatingArg = ArgAutoPtr( new Arg() );
|
jamie@264
|
3792 ArgBuilder builder( m_floatingArg.get() );
|
jamie@264
|
3793 return builder;
|
jamie@264
|
3794 }
|
jamie@264
|
3795
|
jamie@264
|
3796 template<typename C, typename M>
|
jamie@264
|
3797 void bindProcessName( M C::* field ) {
|
jamie@264
|
3798 m_boundProcessName = new Detail::BoundDataMember<C,M>( field );
|
jamie@264
|
3799 }
|
jamie@264
|
3800 template<typename C, typename M>
|
jamie@264
|
3801 void bindProcessName( void (C::*_unaryMethod)( M ) ) {
|
jamie@264
|
3802 m_boundProcessName = new Detail::BoundUnaryMethod<C,M>( _unaryMethod );
|
jamie@264
|
3803 }
|
jamie@264
|
3804
|
jamie@264
|
3805 void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const {
|
jamie@264
|
3806 typename std::vector<Arg>::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it;
|
jamie@264
|
3807 std::size_t maxWidth = 0;
|
jamie@264
|
3808 for( it = itBegin; it != itEnd; ++it )
|
jamie@264
|
3809 maxWidth = (std::max)( maxWidth, it->commands().size() );
|
jamie@264
|
3810
|
jamie@264
|
3811 for( it = itBegin; it != itEnd; ++it ) {
|
jamie@264
|
3812 Detail::Text usage( it->commands(), Detail::TextAttributes()
|
jamie@264
|
3813 .setWidth( maxWidth+indent )
|
jamie@264
|
3814 .setIndent( indent ) );
|
jamie@264
|
3815 Detail::Text desc( it->description, Detail::TextAttributes()
|
jamie@264
|
3816 .setWidth( width - maxWidth - 3 ) );
|
jamie@264
|
3817
|
jamie@264
|
3818 for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) {
|
jamie@264
|
3819 std::string usageCol = i < usage.size() ? usage[i] : "";
|
jamie@264
|
3820 os << usageCol;
|
jamie@264
|
3821
|
jamie@264
|
3822 if( i < desc.size() && !desc[i].empty() )
|
jamie@264
|
3823 os << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' )
|
jamie@264
|
3824 << desc[i];
|
jamie@264
|
3825 os << "\n";
|
jamie@264
|
3826 }
|
jamie@264
|
3827 }
|
jamie@264
|
3828 }
|
jamie@264
|
3829 std::string optUsage() const {
|
jamie@264
|
3830 std::ostringstream oss;
|
jamie@264
|
3831 optUsage( oss );
|
jamie@264
|
3832 return oss.str();
|
jamie@264
|
3833 }
|
jamie@264
|
3834
|
jamie@264
|
3835 void argSynopsis( std::ostream& os ) const {
|
jamie@264
|
3836 for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) {
|
jamie@264
|
3837 if( i > 1 )
|
jamie@264
|
3838 os << " ";
|
jamie@264
|
3839 typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find( i );
|
jamie@264
|
3840 if( it != m_positionalArgs.end() )
|
jamie@264
|
3841 os << "<" << it->second.placeholder << ">";
|
jamie@264
|
3842 else if( m_floatingArg.get() )
|
jamie@264
|
3843 os << "<" << m_floatingArg->placeholder << ">";
|
jamie@264
|
3844 else
|
jamie@264
|
3845 throw std::logic_error( "non consecutive positional arguments with no floating args" );
|
jamie@264
|
3846 }
|
jamie@264
|
3847 // !TBD No indication of mandatory args
|
jamie@264
|
3848 if( m_floatingArg.get() ) {
|
jamie@264
|
3849 if( m_highestSpecifiedArgPosition > 1 )
|
jamie@264
|
3850 os << " ";
|
jamie@264
|
3851 os << "[<" << m_floatingArg->placeholder << "> ...]";
|
jamie@264
|
3852 }
|
jamie@264
|
3853 }
|
jamie@264
|
3854 std::string argSynopsis() const {
|
jamie@264
|
3855 std::ostringstream oss;
|
jamie@264
|
3856 argSynopsis( oss );
|
jamie@264
|
3857 return oss.str();
|
jamie@264
|
3858 }
|
jamie@264
|
3859
|
jamie@264
|
3860 void usage( std::ostream& os, std::string const& procName ) const {
|
jamie@264
|
3861 validate();
|
jamie@264
|
3862 os << "usage:\n " << procName << " ";
|
jamie@264
|
3863 argSynopsis( os );
|
jamie@264
|
3864 if( !m_options.empty() ) {
|
jamie@264
|
3865 os << " [options]\n\nwhere options are: \n";
|
jamie@264
|
3866 optUsage( os, 2 );
|
jamie@264
|
3867 }
|
jamie@264
|
3868 os << "\n";
|
jamie@264
|
3869 }
|
jamie@264
|
3870 std::string usage( std::string const& procName ) const {
|
jamie@264
|
3871 std::ostringstream oss;
|
jamie@264
|
3872 usage( oss, procName );
|
jamie@264
|
3873 return oss.str();
|
jamie@264
|
3874 }
|
jamie@264
|
3875
|
jamie@264
|
3876 ConfigT parse( int argc, char const * const * argv ) const {
|
jamie@264
|
3877 ConfigT config;
|
jamie@264
|
3878 parseInto( argc, argv, config );
|
jamie@264
|
3879 return config;
|
jamie@264
|
3880 }
|
jamie@264
|
3881
|
jamie@264
|
3882 std::vector<Parser::Token> parseInto( int argc, char const * const * argv, ConfigT& config ) const {
|
jamie@264
|
3883 std::string processName = argv[0];
|
jamie@264
|
3884 std::size_t lastSlash = processName.find_last_of( "/\\" );
|
jamie@264
|
3885 if( lastSlash != std::string::npos )
|
jamie@264
|
3886 processName = processName.substr( lastSlash+1 );
|
jamie@264
|
3887 m_boundProcessName.set( config, processName );
|
jamie@264
|
3888 std::vector<Parser::Token> tokens;
|
jamie@264
|
3889 Parser parser;
|
jamie@264
|
3890 parser.parseIntoTokens( argc, argv, tokens );
|
jamie@264
|
3891 return populate( tokens, config );
|
jamie@264
|
3892 }
|
jamie@264
|
3893
|
jamie@264
|
3894 std::vector<Parser::Token> populate( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
|
jamie@264
|
3895 validate();
|
jamie@264
|
3896 std::vector<Parser::Token> unusedTokens = populateOptions( tokens, config );
|
jamie@264
|
3897 unusedTokens = populateFixedArgs( unusedTokens, config );
|
jamie@264
|
3898 unusedTokens = populateFloatingArgs( unusedTokens, config );
|
jamie@264
|
3899 return unusedTokens;
|
jamie@264
|
3900 }
|
jamie@264
|
3901
|
jamie@264
|
3902 std::vector<Parser::Token> populateOptions( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
|
jamie@264
|
3903 std::vector<Parser::Token> unusedTokens;
|
jamie@264
|
3904 std::vector<std::string> errors;
|
jamie@264
|
3905 for( std::size_t i = 0; i < tokens.size(); ++i ) {
|
jamie@264
|
3906 Parser::Token const& token = tokens[i];
|
jamie@264
|
3907 typename std::vector<Arg>::const_iterator it = m_options.begin(), itEnd = m_options.end();
|
jamie@264
|
3908 for(; it != itEnd; ++it ) {
|
jamie@264
|
3909 Arg const& arg = *it;
|
jamie@264
|
3910
|
jamie@264
|
3911 try {
|
jamie@264
|
3912 if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) ||
|
jamie@264
|
3913 ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) {
|
jamie@264
|
3914 if( arg.takesArg() ) {
|
jamie@264
|
3915 if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional )
|
jamie@264
|
3916 errors.push_back( "Expected argument to option: " + token.data );
|
jamie@264
|
3917 else
|
jamie@264
|
3918 arg.boundField.set( config, tokens[++i].data );
|
jamie@264
|
3919 }
|
jamie@264
|
3920 else {
|
jamie@264
|
3921 arg.boundField.setFlag( config );
|
jamie@264
|
3922 }
|
jamie@264
|
3923 break;
|
jamie@264
|
3924 }
|
jamie@264
|
3925 }
|
jamie@264
|
3926 catch( std::exception& ex ) {
|
jamie@264
|
3927 errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" );
|
jamie@264
|
3928 }
|
jamie@264
|
3929 }
|
jamie@264
|
3930 if( it == itEnd ) {
|
jamie@264
|
3931 if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens )
|
jamie@264
|
3932 unusedTokens.push_back( token );
|
jamie@264
|
3933 else if( m_throwOnUnrecognisedTokens )
|
jamie@264
|
3934 errors.push_back( "unrecognised option: " + token.data );
|
jamie@264
|
3935 }
|
jamie@264
|
3936 }
|
jamie@264
|
3937 if( !errors.empty() ) {
|
jamie@264
|
3938 std::ostringstream oss;
|
jamie@264
|
3939 for( std::vector<std::string>::const_iterator it = errors.begin(), itEnd = errors.end();
|
jamie@264
|
3940 it != itEnd;
|
jamie@264
|
3941 ++it ) {
|
jamie@264
|
3942 if( it != errors.begin() )
|
jamie@264
|
3943 oss << "\n";
|
jamie@264
|
3944 oss << *it;
|
jamie@264
|
3945 }
|
jamie@264
|
3946 throw std::runtime_error( oss.str() );
|
jamie@264
|
3947 }
|
jamie@264
|
3948 return unusedTokens;
|
jamie@264
|
3949 }
|
jamie@264
|
3950 std::vector<Parser::Token> populateFixedArgs( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
|
jamie@264
|
3951 std::vector<Parser::Token> unusedTokens;
|
jamie@264
|
3952 int position = 1;
|
jamie@264
|
3953 for( std::size_t i = 0; i < tokens.size(); ++i ) {
|
jamie@264
|
3954 Parser::Token const& token = tokens[i];
|
jamie@264
|
3955 typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find( position );
|
jamie@264
|
3956 if( it != m_positionalArgs.end() )
|
jamie@264
|
3957 it->second.boundField.set( config, token.data );
|
jamie@264
|
3958 else
|
jamie@264
|
3959 unusedTokens.push_back( token );
|
jamie@264
|
3960 if( token.type == Parser::Token::Positional )
|
jamie@264
|
3961 position++;
|
jamie@264
|
3962 }
|
jamie@264
|
3963 return unusedTokens;
|
jamie@264
|
3964 }
|
jamie@264
|
3965 std::vector<Parser::Token> populateFloatingArgs( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
|
jamie@264
|
3966 if( !m_floatingArg.get() )
|
jamie@264
|
3967 return tokens;
|
jamie@264
|
3968 std::vector<Parser::Token> unusedTokens;
|
jamie@264
|
3969 for( std::size_t i = 0; i < tokens.size(); ++i ) {
|
jamie@264
|
3970 Parser::Token const& token = tokens[i];
|
jamie@264
|
3971 if( token.type == Parser::Token::Positional )
|
jamie@264
|
3972 m_floatingArg->boundField.set( config, token.data );
|
jamie@264
|
3973 else
|
jamie@264
|
3974 unusedTokens.push_back( token );
|
jamie@264
|
3975 }
|
jamie@264
|
3976 return unusedTokens;
|
jamie@264
|
3977 }
|
jamie@264
|
3978
|
jamie@264
|
3979 void validate() const
|
jamie@264
|
3980 {
|
jamie@264
|
3981 if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() )
|
jamie@264
|
3982 throw std::logic_error( "No options or arguments specified" );
|
jamie@264
|
3983
|
jamie@264
|
3984 for( typename std::vector<Arg>::const_iterator it = m_options.begin(),
|
jamie@264
|
3985 itEnd = m_options.end();
|
jamie@264
|
3986 it != itEnd; ++it )
|
jamie@264
|
3987 it->validate();
|
jamie@264
|
3988 }
|
jamie@264
|
3989
|
jamie@264
|
3990 private:
|
jamie@264
|
3991 Detail::BoundArgFunction<ConfigT> m_boundProcessName;
|
jamie@264
|
3992 std::vector<Arg> m_options;
|
jamie@264
|
3993 std::map<int, Arg> m_positionalArgs;
|
jamie@264
|
3994 ArgAutoPtr m_floatingArg;
|
jamie@264
|
3995 int m_highestSpecifiedArgPosition;
|
jamie@264
|
3996 bool m_throwOnUnrecognisedTokens;
|
jamie@264
|
3997 };
|
jamie@264
|
3998
|
jamie@264
|
3999 } // end namespace Clara
|
jamie@264
|
4000
|
jamie@264
|
4001 STITCH_CLARA_CLOSE_NAMESPACE
|
jamie@264
|
4002 #undef STITCH_CLARA_OPEN_NAMESPACE
|
jamie@264
|
4003 #undef STITCH_CLARA_CLOSE_NAMESPACE
|
jamie@264
|
4004
|
jamie@264
|
4005 #endif // TWOBLUECUBES_CLARA_H_INCLUDED
|
jamie@264
|
4006 #undef STITCH_CLARA_OPEN_NAMESPACE
|
jamie@264
|
4007
|
jamie@264
|
4008 // Restore Clara's value for console width, if present
|
jamie@264
|
4009 #ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
|
jamie@264
|
4010 #define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
|
jamie@264
|
4011 #undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
|
jamie@264
|
4012 #endif
|
jamie@264
|
4013
|
jamie@264
|
4014 #include <fstream>
|
jamie@264
|
4015
|
jamie@264
|
4016 namespace Catch {
|
jamie@264
|
4017
|
jamie@264
|
4018 inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; }
|
jamie@264
|
4019 inline void abortAfterX( ConfigData& config, int x ) {
|
jamie@264
|
4020 if( x < 1 )
|
jamie@264
|
4021 throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" );
|
jamie@264
|
4022 config.abortAfter = x;
|
jamie@264
|
4023 }
|
jamie@264
|
4024 inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); }
|
jamie@264
|
4025
|
jamie@264
|
4026 inline void addWarning( ConfigData& config, std::string const& _warning ) {
|
jamie@264
|
4027 if( _warning == "NoAssertions" )
|
jamie@264
|
4028 config.warnings = static_cast<WarnAbout::What>( config.warnings | WarnAbout::NoAssertions );
|
jamie@264
|
4029 else
|
jamie@264
|
4030 throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" );
|
jamie@264
|
4031
|
jamie@264
|
4032 }
|
jamie@264
|
4033 inline void setVerbosity( ConfigData& config, int level ) {
|
jamie@264
|
4034 // !TBD: accept strings?
|
jamie@264
|
4035 config.verbosity = static_cast<Verbosity::Level>( level );
|
jamie@264
|
4036 }
|
jamie@264
|
4037 inline void setShowDurations( ConfigData& config, bool _showDurations ) {
|
jamie@264
|
4038 config.showDurations = _showDurations
|
jamie@264
|
4039 ? ShowDurations::Always
|
jamie@264
|
4040 : ShowDurations::Never;
|
jamie@264
|
4041 }
|
jamie@264
|
4042 inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) {
|
jamie@264
|
4043 std::ifstream f( _filename.c_str() );
|
jamie@264
|
4044 if( !f.is_open() )
|
jamie@264
|
4045 throw std::domain_error( "Unable to load input file: " + _filename );
|
jamie@264
|
4046
|
jamie@264
|
4047 std::string line;
|
jamie@264
|
4048 while( std::getline( f, line ) ) {
|
jamie@264
|
4049 line = trim(line);
|
jamie@264
|
4050 if( !line.empty() && !startsWith( line, "#" ) )
|
jamie@264
|
4051 addTestOrTags( config, "\"" + line + "\"," );
|
jamie@264
|
4052 }
|
jamie@264
|
4053 }
|
jamie@264
|
4054
|
jamie@264
|
4055 inline Clara::CommandLine<ConfigData> makeCommandLineParser() {
|
jamie@264
|
4056
|
jamie@264
|
4057 using namespace Clara;
|
jamie@264
|
4058 CommandLine<ConfigData> cli;
|
jamie@264
|
4059
|
jamie@264
|
4060 cli.bindProcessName( &ConfigData::processName );
|
jamie@264
|
4061
|
jamie@264
|
4062 cli["-?"]["-h"]["--help"]
|
jamie@264
|
4063 .describe( "display usage information" )
|
jamie@264
|
4064 .bind( &ConfigData::showHelp );
|
jamie@264
|
4065
|
jamie@264
|
4066 cli["-l"]["--list-tests"]
|
jamie@264
|
4067 .describe( "list all/matching test cases" )
|
jamie@264
|
4068 .bind( &ConfigData::listTests );
|
jamie@264
|
4069
|
jamie@264
|
4070 cli["-t"]["--list-tags"]
|
jamie@264
|
4071 .describe( "list all/matching tags" )
|
jamie@264
|
4072 .bind( &ConfigData::listTags );
|
jamie@264
|
4073
|
jamie@264
|
4074 cli["-s"]["--success"]
|
jamie@264
|
4075 .describe( "include successful tests in output" )
|
jamie@264
|
4076 .bind( &ConfigData::showSuccessfulTests );
|
jamie@264
|
4077
|
jamie@264
|
4078 cli["-b"]["--break"]
|
jamie@264
|
4079 .describe( "break into debugger on failure" )
|
jamie@264
|
4080 .bind( &ConfigData::shouldDebugBreak );
|
jamie@264
|
4081
|
jamie@264
|
4082 cli["-e"]["--nothrow"]
|
jamie@264
|
4083 .describe( "skip exception tests" )
|
jamie@264
|
4084 .bind( &ConfigData::noThrow );
|
jamie@264
|
4085
|
jamie@264
|
4086 cli["-i"]["--invisibles"]
|
jamie@264
|
4087 .describe( "show invisibles (tabs, newlines)" )
|
jamie@264
|
4088 .bind( &ConfigData::showInvisibles );
|
jamie@264
|
4089
|
jamie@264
|
4090 cli["-o"]["--out"]
|
jamie@264
|
4091 .describe( "output filename" )
|
jamie@264
|
4092 .bind( &ConfigData::outputFilename, "filename" );
|
jamie@264
|
4093
|
jamie@264
|
4094 cli["-r"]["--reporter"]
|
jamie@264
|
4095 // .placeholder( "name[:filename]" )
|
jamie@264
|
4096 .describe( "reporter to use (defaults to console)" )
|
jamie@264
|
4097 .bind( &ConfigData::reporterName, "name" );
|
jamie@264
|
4098
|
jamie@264
|
4099 cli["-n"]["--name"]
|
jamie@264
|
4100 .describe( "suite name" )
|
jamie@264
|
4101 .bind( &ConfigData::name, "name" );
|
jamie@264
|
4102
|
jamie@264
|
4103 cli["-a"]["--abort"]
|
jamie@264
|
4104 .describe( "abort at first failure" )
|
jamie@264
|
4105 .bind( &abortAfterFirst );
|
jamie@264
|
4106
|
jamie@264
|
4107 cli["-x"]["--abortx"]
|
jamie@264
|
4108 .describe( "abort after x failures" )
|
jamie@264
|
4109 .bind( &abortAfterX, "no. failures" );
|
jamie@264
|
4110
|
jamie@264
|
4111 cli["-w"]["--warn"]
|
jamie@264
|
4112 .describe( "enable warnings" )
|
jamie@264
|
4113 .bind( &addWarning, "warning name" );
|
jamie@264
|
4114
|
jamie@264
|
4115 // - needs updating if reinstated
|
jamie@264
|
4116 // cli.into( &setVerbosity )
|
jamie@264
|
4117 // .describe( "level of verbosity (0=no output)" )
|
jamie@264
|
4118 // .shortOpt( "v")
|
jamie@264
|
4119 // .longOpt( "verbosity" )
|
jamie@264
|
4120 // .placeholder( "level" );
|
jamie@264
|
4121
|
jamie@264
|
4122 cli[_]
|
jamie@264
|
4123 .describe( "which test or tests to use" )
|
jamie@264
|
4124 .bind( &addTestOrTags, "test name, pattern or tags" );
|
jamie@264
|
4125
|
jamie@264
|
4126 cli["-d"]["--durations"]
|
jamie@264
|
4127 .describe( "show test durations" )
|
jamie@264
|
4128 .bind( &setShowDurations, "yes/no" );
|
jamie@264
|
4129
|
jamie@264
|
4130 cli["-f"]["--input-file"]
|
jamie@264
|
4131 .describe( "load test names to run from a file" )
|
jamie@264
|
4132 .bind( &loadTestNamesFromFile, "filename" );
|
jamie@264
|
4133
|
jamie@264
|
4134 // Less common commands which don't have a short form
|
jamie@264
|
4135 cli["--list-test-names-only"]
|
jamie@264
|
4136 .describe( "list all/matching test cases names only" )
|
jamie@264
|
4137 .bind( &ConfigData::listTestNamesOnly );
|
jamie@264
|
4138
|
jamie@264
|
4139 cli["--list-reporters"]
|
jamie@264
|
4140 .describe( "list all reporters" )
|
jamie@264
|
4141 .bind( &ConfigData::listReporters );
|
jamie@264
|
4142
|
jamie@264
|
4143 return cli;
|
jamie@264
|
4144 }
|
jamie@264
|
4145
|
jamie@264
|
4146 } // end namespace Catch
|
jamie@264
|
4147
|
jamie@264
|
4148 // #included from: internal/catch_list.hpp
|
jamie@264
|
4149 #define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED
|
jamie@264
|
4150
|
jamie@264
|
4151 // #included from: catch_text.h
|
jamie@264
|
4152 #define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED
|
jamie@264
|
4153
|
jamie@264
|
4154 #define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH
|
jamie@264
|
4155
|
jamie@264
|
4156 #define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch
|
jamie@264
|
4157 // #included from: ../external/tbc_text_format.h
|
jamie@264
|
4158 // Only use header guard if we are not using an outer namespace
|
jamie@264
|
4159 #ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
|
jamie@264
|
4160 # ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED
|
jamie@264
|
4161 # ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
|
jamie@264
|
4162 # define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
|
jamie@264
|
4163 # endif
|
jamie@264
|
4164 # else
|
jamie@264
|
4165 # define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED
|
jamie@264
|
4166 # endif
|
jamie@264
|
4167 #endif
|
jamie@264
|
4168 #ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
|
jamie@264
|
4169 #include <string>
|
jamie@264
|
4170 #include <vector>
|
jamie@264
|
4171 #include <sstream>
|
jamie@264
|
4172
|
jamie@264
|
4173 // Use optional outer namespace
|
jamie@264
|
4174 #ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
|
jamie@264
|
4175 namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE {
|
jamie@264
|
4176 #endif
|
jamie@264
|
4177
|
jamie@264
|
4178 namespace Tbc {
|
jamie@264
|
4179
|
jamie@264
|
4180 #ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH
|
jamie@264
|
4181 const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH;
|
jamie@264
|
4182 #else
|
jamie@264
|
4183 const unsigned int consoleWidth = 80;
|
jamie@264
|
4184 #endif
|
jamie@264
|
4185
|
jamie@264
|
4186 struct TextAttributes {
|
jamie@264
|
4187 TextAttributes()
|
jamie@264
|
4188 : initialIndent( std::string::npos ),
|
jamie@264
|
4189 indent( 0 ),
|
jamie@264
|
4190 width( consoleWidth-1 ),
|
jamie@264
|
4191 tabChar( '\t' )
|
jamie@264
|
4192 {}
|
jamie@264
|
4193
|
jamie@264
|
4194 TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; }
|
jamie@264
|
4195 TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; }
|
jamie@264
|
4196 TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; }
|
jamie@264
|
4197 TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; }
|
jamie@264
|
4198
|
jamie@264
|
4199 std::size_t initialIndent; // indent of first line, or npos
|
jamie@264
|
4200 std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos
|
jamie@264
|
4201 std::size_t width; // maximum width of text, including indent. Longer text will wrap
|
jamie@264
|
4202 char tabChar; // If this char is seen the indent is changed to current pos
|
jamie@264
|
4203 };
|
jamie@264
|
4204
|
jamie@264
|
4205 class Text {
|
jamie@264
|
4206 public:
|
jamie@264
|
4207 Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() )
|
jamie@264
|
4208 : attr( _attr )
|
jamie@264
|
4209 {
|
jamie@264
|
4210 std::string wrappableChars = " [({.,/|\\-";
|
jamie@264
|
4211 std::size_t indent = _attr.initialIndent != std::string::npos
|
jamie@264
|
4212 ? _attr.initialIndent
|
jamie@264
|
4213 : _attr.indent;
|
jamie@264
|
4214 std::string remainder = _str;
|
jamie@264
|
4215
|
jamie@264
|
4216 while( !remainder.empty() ) {
|
jamie@264
|
4217 if( lines.size() >= 1000 ) {
|
jamie@264
|
4218 lines.push_back( "... message truncated due to excessive size" );
|
jamie@264
|
4219 return;
|
jamie@264
|
4220 }
|
jamie@264
|
4221 std::size_t tabPos = std::string::npos;
|
jamie@264
|
4222 std::size_t width = (std::min)( remainder.size(), _attr.width - indent );
|
jamie@264
|
4223 std::size_t pos = remainder.find_first_of( '\n' );
|
jamie@264
|
4224 if( pos <= width ) {
|
jamie@264
|
4225 width = pos;
|
jamie@264
|
4226 }
|
jamie@264
|
4227 pos = remainder.find_last_of( _attr.tabChar, width );
|
jamie@264
|
4228 if( pos != std::string::npos ) {
|
jamie@264
|
4229 tabPos = pos;
|
jamie@264
|
4230 if( remainder[width] == '\n' )
|
jamie@264
|
4231 width--;
|
jamie@264
|
4232 remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 );
|
jamie@264
|
4233 }
|
jamie@264
|
4234
|
jamie@264
|
4235 if( width == remainder.size() ) {
|
jamie@264
|
4236 spliceLine( indent, remainder, width );
|
jamie@264
|
4237 }
|
jamie@264
|
4238 else if( remainder[width] == '\n' ) {
|
jamie@264
|
4239 spliceLine( indent, remainder, width );
|
jamie@264
|
4240 if( width <= 1 || remainder.size() != 1 )
|
jamie@264
|
4241 remainder = remainder.substr( 1 );
|
jamie@264
|
4242 indent = _attr.indent;
|
jamie@264
|
4243 }
|
jamie@264
|
4244 else {
|
jamie@264
|
4245 pos = remainder.find_last_of( wrappableChars, width );
|
jamie@264
|
4246 if( pos != std::string::npos && pos > 0 ) {
|
jamie@264
|
4247 spliceLine( indent, remainder, pos );
|
jamie@264
|
4248 if( remainder[0] == ' ' )
|
jamie@264
|
4249 remainder = remainder.substr( 1 );
|
jamie@264
|
4250 }
|
jamie@264
|
4251 else {
|
jamie@264
|
4252 spliceLine( indent, remainder, width-1 );
|
jamie@264
|
4253 lines.back() += "-";
|
jamie@264
|
4254 }
|
jamie@264
|
4255 if( lines.size() == 1 )
|
jamie@264
|
4256 indent = _attr.indent;
|
jamie@264
|
4257 if( tabPos != std::string::npos )
|
jamie@264
|
4258 indent += tabPos;
|
jamie@264
|
4259 }
|
jamie@264
|
4260 }
|
jamie@264
|
4261 }
|
jamie@264
|
4262
|
jamie@264
|
4263 void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) {
|
jamie@264
|
4264 lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) );
|
jamie@264
|
4265 _remainder = _remainder.substr( _pos );
|
jamie@264
|
4266 }
|
jamie@264
|
4267
|
jamie@264
|
4268 typedef std::vector<std::string>::const_iterator const_iterator;
|
jamie@264
|
4269
|
jamie@264
|
4270 const_iterator begin() const { return lines.begin(); }
|
jamie@264
|
4271 const_iterator end() const { return lines.end(); }
|
jamie@264
|
4272 std::string const& last() const { return lines.back(); }
|
jamie@264
|
4273 std::size_t size() const { return lines.size(); }
|
jamie@264
|
4274 std::string const& operator[]( std::size_t _index ) const { return lines[_index]; }
|
jamie@264
|
4275 std::string toString() const {
|
jamie@264
|
4276 std::ostringstream oss;
|
jamie@264
|
4277 oss << *this;
|
jamie@264
|
4278 return oss.str();
|
jamie@264
|
4279 }
|
jamie@264
|
4280
|
jamie@264
|
4281 inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) {
|
jamie@264
|
4282 for( Text::const_iterator it = _text.begin(), itEnd = _text.end();
|
jamie@264
|
4283 it != itEnd; ++it ) {
|
jamie@264
|
4284 if( it != _text.begin() )
|
jamie@264
|
4285 _stream << "\n";
|
jamie@264
|
4286 _stream << *it;
|
jamie@264
|
4287 }
|
jamie@264
|
4288 return _stream;
|
jamie@264
|
4289 }
|
jamie@264
|
4290
|
jamie@264
|
4291 private:
|
jamie@264
|
4292 std::string str;
|
jamie@264
|
4293 TextAttributes attr;
|
jamie@264
|
4294 std::vector<std::string> lines;
|
jamie@264
|
4295 };
|
jamie@264
|
4296
|
jamie@264
|
4297 } // end namespace Tbc
|
jamie@264
|
4298
|
jamie@264
|
4299 #ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
|
jamie@264
|
4300 } // end outer namespace
|
jamie@264
|
4301 #endif
|
jamie@264
|
4302
|
jamie@264
|
4303 #endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
|
jamie@264
|
4304 #undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
|
jamie@264
|
4305
|
jamie@264
|
4306 namespace Catch {
|
jamie@264
|
4307 using Tbc::Text;
|
jamie@264
|
4308 using Tbc::TextAttributes;
|
jamie@264
|
4309 }
|
jamie@264
|
4310
|
jamie@264
|
4311 // #included from: catch_console_colour.hpp
|
jamie@264
|
4312 #define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED
|
jamie@264
|
4313
|
jamie@264
|
4314 namespace Catch {
|
jamie@264
|
4315
|
jamie@264
|
4316 namespace Detail {
|
jamie@264
|
4317 struct IColourImpl;
|
jamie@264
|
4318 }
|
jamie@264
|
4319
|
jamie@264
|
4320 struct Colour {
|
jamie@264
|
4321 enum Code {
|
jamie@264
|
4322 None = 0,
|
jamie@264
|
4323
|
jamie@264
|
4324 White,
|
jamie@264
|
4325 Red,
|
jamie@264
|
4326 Green,
|
jamie@264
|
4327 Blue,
|
jamie@264
|
4328 Cyan,
|
jamie@264
|
4329 Yellow,
|
jamie@264
|
4330 Grey,
|
jamie@264
|
4331
|
jamie@264
|
4332 Bright = 0x10,
|
jamie@264
|
4333
|
jamie@264
|
4334 BrightRed = Bright | Red,
|
jamie@264
|
4335 BrightGreen = Bright | Green,
|
jamie@264
|
4336 LightGrey = Bright | Grey,
|
jamie@264
|
4337 BrightWhite = Bright | White,
|
jamie@264
|
4338
|
jamie@264
|
4339 // By intention
|
jamie@264
|
4340 FileName = LightGrey,
|
jamie@264
|
4341 Warning = Yellow,
|
jamie@264
|
4342 ResultError = BrightRed,
|
jamie@264
|
4343 ResultSuccess = BrightGreen,
|
jamie@264
|
4344 ResultExpectedFailure = Warning,
|
jamie@264
|
4345
|
jamie@264
|
4346 Error = BrightRed,
|
jamie@264
|
4347 Success = Green,
|
jamie@264
|
4348
|
jamie@264
|
4349 OriginalExpression = Cyan,
|
jamie@264
|
4350 ReconstructedExpression = Yellow,
|
jamie@264
|
4351
|
jamie@264
|
4352 SecondaryText = LightGrey,
|
jamie@264
|
4353 Headers = White
|
jamie@264
|
4354 };
|
jamie@264
|
4355
|
jamie@264
|
4356 // Use constructed object for RAII guard
|
jamie@264
|
4357 Colour( Code _colourCode );
|
jamie@264
|
4358 Colour( Colour const& other );
|
jamie@264
|
4359 ~Colour();
|
jamie@264
|
4360
|
jamie@264
|
4361 // Use static method for one-shot changes
|
jamie@264
|
4362 static void use( Code _colourCode );
|
jamie@264
|
4363
|
jamie@264
|
4364 private:
|
jamie@264
|
4365 static Detail::IColourImpl* impl();
|
jamie@264
|
4366 bool m_moved;
|
jamie@264
|
4367 };
|
jamie@264
|
4368
|
jamie@264
|
4369 inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; }
|
jamie@264
|
4370
|
jamie@264
|
4371 } // end namespace Catch
|
jamie@264
|
4372
|
jamie@264
|
4373 // #included from: catch_interfaces_reporter.h
|
jamie@264
|
4374 #define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED
|
jamie@264
|
4375
|
jamie@264
|
4376 #include <string>
|
jamie@264
|
4377 #include <ostream>
|
jamie@264
|
4378 #include <map>
|
jamie@264
|
4379 #include <assert.h>
|
jamie@264
|
4380
|
jamie@264
|
4381 namespace Catch
|
jamie@264
|
4382 {
|
jamie@264
|
4383 struct ReporterConfig {
|
jamie@264
|
4384 explicit ReporterConfig( Ptr<IConfig> const& _fullConfig )
|
jamie@264
|
4385 : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {}
|
jamie@264
|
4386
|
jamie@264
|
4387 ReporterConfig( Ptr<IConfig> const& _fullConfig, std::ostream& _stream )
|
jamie@264
|
4388 : m_stream( &_stream ), m_fullConfig( _fullConfig ) {}
|
jamie@264
|
4389
|
jamie@264
|
4390 std::ostream& stream() const { return *m_stream; }
|
jamie@264
|
4391 Ptr<IConfig> fullConfig() const { return m_fullConfig; }
|
jamie@264
|
4392
|
jamie@264
|
4393 private:
|
jamie@264
|
4394 std::ostream* m_stream;
|
jamie@264
|
4395 Ptr<IConfig> m_fullConfig;
|
jamie@264
|
4396 };
|
jamie@264
|
4397
|
jamie@264
|
4398 struct ReporterPreferences {
|
jamie@264
|
4399 ReporterPreferences()
|
jamie@264
|
4400 : shouldRedirectStdOut( false )
|
jamie@264
|
4401 {}
|
jamie@264
|
4402
|
jamie@264
|
4403 bool shouldRedirectStdOut;
|
jamie@264
|
4404 };
|
jamie@264
|
4405
|
jamie@264
|
4406 template<typename T>
|
jamie@264
|
4407 struct LazyStat : Option<T> {
|
jamie@264
|
4408 LazyStat() : used( false ) {}
|
jamie@264
|
4409 LazyStat& operator=( T const& _value ) {
|
jamie@264
|
4410 Option<T>::operator=( _value );
|
jamie@264
|
4411 used = false;
|
jamie@264
|
4412 return *this;
|
jamie@264
|
4413 }
|
jamie@264
|
4414 void reset() {
|
jamie@264
|
4415 Option<T>::reset();
|
jamie@264
|
4416 used = false;
|
jamie@264
|
4417 }
|
jamie@264
|
4418 bool used;
|
jamie@264
|
4419 };
|
jamie@264
|
4420
|
jamie@264
|
4421 struct TestRunInfo {
|
jamie@264
|
4422 TestRunInfo( std::string const& _name ) : name( _name ) {}
|
jamie@264
|
4423 std::string name;
|
jamie@264
|
4424 };
|
jamie@264
|
4425 struct GroupInfo {
|
jamie@264
|
4426 GroupInfo( std::string const& _name,
|
jamie@264
|
4427 std::size_t _groupIndex,
|
jamie@264
|
4428 std::size_t _groupsCount )
|
jamie@264
|
4429 : name( _name ),
|
jamie@264
|
4430 groupIndex( _groupIndex ),
|
jamie@264
|
4431 groupsCounts( _groupsCount )
|
jamie@264
|
4432 {}
|
jamie@264
|
4433
|
jamie@264
|
4434 std::string name;
|
jamie@264
|
4435 std::size_t groupIndex;
|
jamie@264
|
4436 std::size_t groupsCounts;
|
jamie@264
|
4437 };
|
jamie@264
|
4438
|
jamie@264
|
4439 struct AssertionStats {
|
jamie@264
|
4440 AssertionStats( AssertionResult const& _assertionResult,
|
jamie@264
|
4441 std::vector<MessageInfo> const& _infoMessages,
|
jamie@264
|
4442 Totals const& _totals )
|
jamie@264
|
4443 : assertionResult( _assertionResult ),
|
jamie@264
|
4444 infoMessages( _infoMessages ),
|
jamie@264
|
4445 totals( _totals )
|
jamie@264
|
4446 {
|
jamie@264
|
4447 if( assertionResult.hasMessage() ) {
|
jamie@264
|
4448 // Copy message into messages list.
|
jamie@264
|
4449 // !TBD This should have been done earlier, somewhere
|
jamie@264
|
4450 MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() );
|
jamie@264
|
4451 builder << assertionResult.getMessage();
|
jamie@264
|
4452 builder.m_info.message = builder.m_stream.str();
|
jamie@264
|
4453
|
jamie@264
|
4454 infoMessages.push_back( builder.m_info );
|
jamie@264
|
4455 }
|
jamie@264
|
4456 }
|
jamie@264
|
4457 virtual ~AssertionStats();
|
jamie@264
|
4458
|
jamie@264
|
4459 # ifdef CATCH_CPP11_OR_GREATER
|
jamie@264
|
4460 AssertionStats( AssertionStats const& ) = default;
|
jamie@264
|
4461 AssertionStats( AssertionStats && ) = default;
|
jamie@264
|
4462 AssertionStats& operator = ( AssertionStats const& ) = default;
|
jamie@264
|
4463 AssertionStats& operator = ( AssertionStats && ) = default;
|
jamie@264
|
4464 # endif
|
jamie@264
|
4465
|
jamie@264
|
4466 AssertionResult assertionResult;
|
jamie@264
|
4467 std::vector<MessageInfo> infoMessages;
|
jamie@264
|
4468 Totals totals;
|
jamie@264
|
4469 };
|
jamie@264
|
4470
|
jamie@264
|
4471 struct SectionStats {
|
jamie@264
|
4472 SectionStats( SectionInfo const& _sectionInfo,
|
jamie@264
|
4473 Counts const& _assertions,
|
jamie@264
|
4474 double _durationInSeconds,
|
jamie@264
|
4475 bool _missingAssertions )
|
jamie@264
|
4476 : sectionInfo( _sectionInfo ),
|
jamie@264
|
4477 assertions( _assertions ),
|
jamie@264
|
4478 durationInSeconds( _durationInSeconds ),
|
jamie@264
|
4479 missingAssertions( _missingAssertions )
|
jamie@264
|
4480 {}
|
jamie@264
|
4481 virtual ~SectionStats();
|
jamie@264
|
4482 # ifdef CATCH_CPP11_OR_GREATER
|
jamie@264
|
4483 SectionStats( SectionStats const& ) = default;
|
jamie@264
|
4484 SectionStats( SectionStats && ) = default;
|
jamie@264
|
4485 SectionStats& operator = ( SectionStats const& ) = default;
|
jamie@264
|
4486 SectionStats& operator = ( SectionStats && ) = default;
|
jamie@264
|
4487 # endif
|
jamie@264
|
4488
|
jamie@264
|
4489 SectionInfo sectionInfo;
|
jamie@264
|
4490 Counts assertions;
|
jamie@264
|
4491 double durationInSeconds;
|
jamie@264
|
4492 bool missingAssertions;
|
jamie@264
|
4493 };
|
jamie@264
|
4494
|
jamie@264
|
4495 struct TestCaseStats {
|
jamie@264
|
4496 TestCaseStats( TestCaseInfo const& _testInfo,
|
jamie@264
|
4497 Totals const& _totals,
|
jamie@264
|
4498 std::string const& _stdOut,
|
jamie@264
|
4499 std::string const& _stdErr,
|
jamie@264
|
4500 bool _aborting )
|
jamie@264
|
4501 : testInfo( _testInfo ),
|
jamie@264
|
4502 totals( _totals ),
|
jamie@264
|
4503 stdOut( _stdOut ),
|
jamie@264
|
4504 stdErr( _stdErr ),
|
jamie@264
|
4505 aborting( _aborting )
|
jamie@264
|
4506 {}
|
jamie@264
|
4507 virtual ~TestCaseStats();
|
jamie@264
|
4508
|
jamie@264
|
4509 # ifdef CATCH_CPP11_OR_GREATER
|
jamie@264
|
4510 TestCaseStats( TestCaseStats const& ) = default;
|
jamie@264
|
4511 TestCaseStats( TestCaseStats && ) = default;
|
jamie@264
|
4512 TestCaseStats& operator = ( TestCaseStats const& ) = default;
|
jamie@264
|
4513 TestCaseStats& operator = ( TestCaseStats && ) = default;
|
jamie@264
|
4514 # endif
|
jamie@264
|
4515
|
jamie@264
|
4516 TestCaseInfo testInfo;
|
jamie@264
|
4517 Totals totals;
|
jamie@264
|
4518 std::string stdOut;
|
jamie@264
|
4519 std::string stdErr;
|
jamie@264
|
4520 bool aborting;
|
jamie@264
|
4521 };
|
jamie@264
|
4522
|
jamie@264
|
4523 struct TestGroupStats {
|
jamie@264
|
4524 TestGroupStats( GroupInfo const& _groupInfo,
|
jamie@264
|
4525 Totals const& _totals,
|
jamie@264
|
4526 bool _aborting )
|
jamie@264
|
4527 : groupInfo( _groupInfo ),
|
jamie@264
|
4528 totals( _totals ),
|
jamie@264
|
4529 aborting( _aborting )
|
jamie@264
|
4530 {}
|
jamie@264
|
4531 TestGroupStats( GroupInfo const& _groupInfo )
|
jamie@264
|
4532 : groupInfo( _groupInfo ),
|
jamie@264
|
4533 aborting( false )
|
jamie@264
|
4534 {}
|
jamie@264
|
4535 virtual ~TestGroupStats();
|
jamie@264
|
4536
|
jamie@264
|
4537 # ifdef CATCH_CPP11_OR_GREATER
|
jamie@264
|
4538 TestGroupStats( TestGroupStats const& ) = default;
|
jamie@264
|
4539 TestGroupStats( TestGroupStats && ) = default;
|
jamie@264
|
4540 TestGroupStats& operator = ( TestGroupStats const& ) = default;
|
jamie@264
|
4541 TestGroupStats& operator = ( TestGroupStats && ) = default;
|
jamie@264
|
4542 # endif
|
jamie@264
|
4543
|
jamie@264
|
4544 GroupInfo groupInfo;
|
jamie@264
|
4545 Totals totals;
|
jamie@264
|
4546 bool aborting;
|
jamie@264
|
4547 };
|
jamie@264
|
4548
|
jamie@264
|
4549 struct TestRunStats {
|
jamie@264
|
4550 TestRunStats( TestRunInfo const& _runInfo,
|
jamie@264
|
4551 Totals const& _totals,
|
jamie@264
|
4552 bool _aborting )
|
jamie@264
|
4553 : runInfo( _runInfo ),
|
jamie@264
|
4554 totals( _totals ),
|
jamie@264
|
4555 aborting( _aborting )
|
jamie@264
|
4556 {}
|
jamie@264
|
4557 virtual ~TestRunStats();
|
jamie@264
|
4558
|
jamie@264
|
4559 # ifndef CATCH_CPP11_OR_GREATER
|
jamie@264
|
4560 TestRunStats( TestRunStats const& _other )
|
jamie@264
|
4561 : runInfo( _other.runInfo ),
|
jamie@264
|
4562 totals( _other.totals ),
|
jamie@264
|
4563 aborting( _other.aborting )
|
jamie@264
|
4564 {}
|
jamie@264
|
4565 # else
|
jamie@264
|
4566 TestRunStats( TestRunStats const& ) = default;
|
jamie@264
|
4567 TestRunStats( TestRunStats && ) = default;
|
jamie@264
|
4568 TestRunStats& operator = ( TestRunStats const& ) = default;
|
jamie@264
|
4569 TestRunStats& operator = ( TestRunStats && ) = default;
|
jamie@264
|
4570 # endif
|
jamie@264
|
4571
|
jamie@264
|
4572 TestRunInfo runInfo;
|
jamie@264
|
4573 Totals totals;
|
jamie@264
|
4574 bool aborting;
|
jamie@264
|
4575 };
|
jamie@264
|
4576
|
jamie@264
|
4577 struct IStreamingReporter : IShared {
|
jamie@264
|
4578 virtual ~IStreamingReporter();
|
jamie@264
|
4579
|
jamie@264
|
4580 // Implementing class must also provide the following static method:
|
jamie@264
|
4581 // static std::string getDescription();
|
jamie@264
|
4582
|
jamie@264
|
4583 virtual ReporterPreferences getPreferences() const = 0;
|
jamie@264
|
4584
|
jamie@264
|
4585 virtual void noMatchingTestCases( std::string const& spec ) = 0;
|
jamie@264
|
4586
|
jamie@264
|
4587 virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0;
|
jamie@264
|
4588 virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0;
|
jamie@264
|
4589
|
jamie@264
|
4590 virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0;
|
jamie@264
|
4591 virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0;
|
jamie@264
|
4592
|
jamie@264
|
4593 virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0;
|
jamie@264
|
4594
|
jamie@264
|
4595 virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0;
|
jamie@264
|
4596 virtual void sectionEnded( SectionStats const& sectionStats ) = 0;
|
jamie@264
|
4597 virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0;
|
jamie@264
|
4598 virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0;
|
jamie@264
|
4599 virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;
|
jamie@264
|
4600 };
|
jamie@264
|
4601
|
jamie@264
|
4602 struct IReporterFactory {
|
jamie@264
|
4603 virtual ~IReporterFactory();
|
jamie@264
|
4604 virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0;
|
jamie@264
|
4605 virtual std::string getDescription() const = 0;
|
jamie@264
|
4606 };
|
jamie@264
|
4607
|
jamie@264
|
4608 struct IReporterRegistry {
|
jamie@264
|
4609 typedef std::map<std::string, IReporterFactory*> FactoryMap;
|
jamie@264
|
4610
|
jamie@264
|
4611 virtual ~IReporterRegistry();
|
jamie@264
|
4612 virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig> const& config ) const = 0;
|
jamie@264
|
4613 virtual FactoryMap const& getFactories() const = 0;
|
jamie@264
|
4614 };
|
jamie@264
|
4615
|
jamie@264
|
4616 }
|
jamie@264
|
4617
|
jamie@264
|
4618 #include <limits>
|
jamie@264
|
4619 #include <algorithm>
|
jamie@264
|
4620
|
jamie@264
|
4621 namespace Catch {
|
jamie@264
|
4622
|
jamie@264
|
4623 inline std::size_t listTests( Config const& config ) {
|
jamie@264
|
4624
|
jamie@264
|
4625 TestSpec testSpec = config.testSpec();
|
jamie@264
|
4626 if( config.testSpec().hasFilters() )
|
jamie@264
|
4627 std::cout << "Matching test cases:\n";
|
jamie@264
|
4628 else {
|
jamie@264
|
4629 std::cout << "All available test cases:\n";
|
jamie@264
|
4630 testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
|
jamie@264
|
4631 }
|
jamie@264
|
4632
|
jamie@264
|
4633 std::size_t matchedTests = 0;
|
jamie@264
|
4634 TextAttributes nameAttr, tagsAttr;
|
jamie@264
|
4635 nameAttr.setInitialIndent( 2 ).setIndent( 4 );
|
jamie@264
|
4636 tagsAttr.setIndent( 6 );
|
jamie@264
|
4637
|
jamie@264
|
4638 std::vector<TestCase> matchedTestCases;
|
jamie@264
|
4639 getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases );
|
jamie@264
|
4640 for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
|
jamie@264
|
4641 it != itEnd;
|
jamie@264
|
4642 ++it ) {
|
jamie@264
|
4643 matchedTests++;
|
jamie@264
|
4644 TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
|
jamie@264
|
4645 Colour::Code colour = testCaseInfo.isHidden()
|
jamie@264
|
4646 ? Colour::SecondaryText
|
jamie@264
|
4647 : Colour::None;
|
jamie@264
|
4648 Colour colourGuard( colour );
|
jamie@264
|
4649
|
jamie@264
|
4650 std::cout << Text( testCaseInfo.name, nameAttr ) << std::endl;
|
jamie@264
|
4651 if( !testCaseInfo.tags.empty() )
|
jamie@264
|
4652 std::cout << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl;
|
jamie@264
|
4653 }
|
jamie@264
|
4654
|
jamie@264
|
4655 if( !config.testSpec().hasFilters() )
|
jamie@264
|
4656 std::cout << pluralise( matchedTests, "test case" ) << "\n" << std::endl;
|
jamie@264
|
4657 else
|
jamie@264
|
4658 std::cout << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl;
|
jamie@264
|
4659 return matchedTests;
|
jamie@264
|
4660 }
|
jamie@264
|
4661
|
jamie@264
|
4662 inline std::size_t listTestsNamesOnly( Config const& config ) {
|
jamie@264
|
4663 TestSpec testSpec = config.testSpec();
|
jamie@264
|
4664 if( !config.testSpec().hasFilters() )
|
jamie@264
|
4665 testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
|
jamie@264
|
4666 std::size_t matchedTests = 0;
|
jamie@264
|
4667 std::vector<TestCase> matchedTestCases;
|
jamie@264
|
4668 getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases );
|
jamie@264
|
4669 for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
|
jamie@264
|
4670 it != itEnd;
|
jamie@264
|
4671 ++it ) {
|
jamie@264
|
4672 matchedTests++;
|
jamie@264
|
4673 TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
|
jamie@264
|
4674 std::cout << testCaseInfo.name << std::endl;
|
jamie@264
|
4675 }
|
jamie@264
|
4676 return matchedTests;
|
jamie@264
|
4677 }
|
jamie@264
|
4678
|
jamie@264
|
4679 struct TagInfo {
|
jamie@264
|
4680 TagInfo() : count ( 0 ) {}
|
jamie@264
|
4681 void add( std::string const& spelling ) {
|
jamie@264
|
4682 ++count;
|
jamie@264
|
4683 spellings.insert( spelling );
|
jamie@264
|
4684 }
|
jamie@264
|
4685 std::string all() const {
|
jamie@264
|
4686 std::string out;
|
jamie@264
|
4687 for( std::set<std::string>::const_iterator it = spellings.begin(), itEnd = spellings.end();
|
jamie@264
|
4688 it != itEnd;
|
jamie@264
|
4689 ++it )
|
jamie@264
|
4690 out += "[" + *it + "]";
|
jamie@264
|
4691 return out;
|
jamie@264
|
4692 }
|
jamie@264
|
4693 std::set<std::string> spellings;
|
jamie@264
|
4694 std::size_t count;
|
jamie@264
|
4695 };
|
jamie@264
|
4696
|
jamie@264
|
4697 inline std::size_t listTags( Config const& config ) {
|
jamie@264
|
4698 TestSpec testSpec = config.testSpec();
|
jamie@264
|
4699 if( config.testSpec().hasFilters() )
|
jamie@264
|
4700 std::cout << "Tags for matching test cases:\n";
|
jamie@264
|
4701 else {
|
jamie@264
|
4702 std::cout << "All available tags:\n";
|
jamie@264
|
4703 testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
|
jamie@264
|
4704 }
|
jamie@264
|
4705
|
jamie@264
|
4706 std::map<std::string, TagInfo> tagCounts;
|
jamie@264
|
4707
|
jamie@264
|
4708 std::vector<TestCase> matchedTestCases;
|
jamie@264
|
4709 getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases );
|
jamie@264
|
4710 for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
|
jamie@264
|
4711 it != itEnd;
|
jamie@264
|
4712 ++it ) {
|
jamie@264
|
4713 for( std::set<std::string>::const_iterator tagIt = it->getTestCaseInfo().tags.begin(),
|
jamie@264
|
4714 tagItEnd = it->getTestCaseInfo().tags.end();
|
jamie@264
|
4715 tagIt != tagItEnd;
|
jamie@264
|
4716 ++tagIt ) {
|
jamie@264
|
4717 std::string tagName = *tagIt;
|
jamie@264
|
4718 std::string lcaseTagName = toLower( tagName );
|
jamie@264
|
4719 std::map<std::string, TagInfo>::iterator countIt = tagCounts.find( lcaseTagName );
|
jamie@264
|
4720 if( countIt == tagCounts.end() )
|
jamie@264
|
4721 countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first;
|
jamie@264
|
4722 countIt->second.add( tagName );
|
jamie@264
|
4723 }
|
jamie@264
|
4724 }
|
jamie@264
|
4725
|
jamie@264
|
4726 for( std::map<std::string, TagInfo>::const_iterator countIt = tagCounts.begin(),
|
jamie@264
|
4727 countItEnd = tagCounts.end();
|
jamie@264
|
4728 countIt != countItEnd;
|
jamie@264
|
4729 ++countIt ) {
|
jamie@264
|
4730 std::ostringstream oss;
|
jamie@264
|
4731 oss << " " << std::setw(2) << countIt->second.count << " ";
|
jamie@264
|
4732 Text wrapper( countIt->second.all(), TextAttributes()
|
jamie@264
|
4733 .setInitialIndent( 0 )
|
jamie@264
|
4734 .setIndent( oss.str().size() )
|
jamie@264
|
4735 .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) );
|
jamie@264
|
4736 std::cout << oss.str() << wrapper << "\n";
|
jamie@264
|
4737 }
|
jamie@264
|
4738 std::cout << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl;
|
jamie@264
|
4739 return tagCounts.size();
|
jamie@264
|
4740 }
|
jamie@264
|
4741
|
jamie@264
|
4742 inline std::size_t listReporters( Config const& /*config*/ ) {
|
jamie@264
|
4743 std::cout << "Available reports:\n";
|
jamie@264
|
4744 IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
|
jamie@264
|
4745 IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it;
|
jamie@264
|
4746 std::size_t maxNameLen = 0;
|
jamie@264
|
4747 for(it = itBegin; it != itEnd; ++it )
|
jamie@264
|
4748 maxNameLen = (std::max)( maxNameLen, it->first.size() );
|
jamie@264
|
4749
|
jamie@264
|
4750 for(it = itBegin; it != itEnd; ++it ) {
|
jamie@264
|
4751 Text wrapper( it->second->getDescription(), TextAttributes()
|
jamie@264
|
4752 .setInitialIndent( 0 )
|
jamie@264
|
4753 .setIndent( 7+maxNameLen )
|
jamie@264
|
4754 .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) );
|
jamie@264
|
4755 std::cout << " "
|
jamie@264
|
4756 << it->first
|
jamie@264
|
4757 << ":"
|
jamie@264
|
4758 << std::string( maxNameLen - it->first.size() + 2, ' ' )
|
jamie@264
|
4759 << wrapper << "\n";
|
jamie@264
|
4760 }
|
jamie@264
|
4761 std::cout << std::endl;
|
jamie@264
|
4762 return factories.size();
|
jamie@264
|
4763 }
|
jamie@264
|
4764
|
jamie@264
|
4765 inline Option<std::size_t> list( Config const& config ) {
|
jamie@264
|
4766 Option<std::size_t> listedCount;
|
jamie@264
|
4767 if( config.listTests() )
|
jamie@264
|
4768 listedCount = listedCount.valueOr(0) + listTests( config );
|
jamie@264
|
4769 if( config.listTestNamesOnly() )
|
jamie@264
|
4770 listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config );
|
jamie@264
|
4771 if( config.listTags() )
|
jamie@264
|
4772 listedCount = listedCount.valueOr(0) + listTags( config );
|
jamie@264
|
4773 if( config.listReporters() )
|
jamie@264
|
4774 listedCount = listedCount.valueOr(0) + listReporters( config );
|
jamie@264
|
4775 return listedCount;
|
jamie@264
|
4776 }
|
jamie@264
|
4777
|
jamie@264
|
4778 } // end namespace Catch
|
jamie@264
|
4779
|
jamie@264
|
4780 // #included from: internal/catch_runner_impl.hpp
|
jamie@264
|
4781 #define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED
|
jamie@264
|
4782
|
jamie@264
|
4783 // #included from: catch_test_case_tracker.hpp
|
jamie@264
|
4784 #define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
|
jamie@264
|
4785
|
jamie@264
|
4786 #include <map>
|
jamie@264
|
4787 #include <string>
|
jamie@264
|
4788 #include <assert.h>
|
jamie@264
|
4789
|
jamie@264
|
4790 namespace Catch {
|
jamie@264
|
4791 namespace SectionTracking {
|
jamie@264
|
4792
|
jamie@264
|
4793 class TrackedSection {
|
jamie@264
|
4794
|
jamie@264
|
4795 typedef std::map<std::string, TrackedSection> TrackedSections;
|
jamie@264
|
4796
|
jamie@264
|
4797 public:
|
jamie@264
|
4798 enum RunState {
|
jamie@264
|
4799 NotStarted,
|
jamie@264
|
4800 Executing,
|
jamie@264
|
4801 ExecutingChildren,
|
jamie@264
|
4802 Completed
|
jamie@264
|
4803 };
|
jamie@264
|
4804
|
jamie@264
|
4805 TrackedSection( std::string const& name, TrackedSection* parent )
|
jamie@264
|
4806 : m_name( name ), m_runState( NotStarted ), m_parent( parent )
|
jamie@264
|
4807 {}
|
jamie@264
|
4808
|
jamie@264
|
4809 RunState runState() const { return m_runState; }
|
jamie@264
|
4810
|
jamie@264
|
4811 TrackedSection* findChild( std::string const& childName ) {
|
jamie@264
|
4812 TrackedSections::iterator it = m_children.find( childName );
|
jamie@264
|
4813 return it != m_children.end()
|
jamie@264
|
4814 ? &it->second
|
jamie@264
|
4815 : NULL;
|
jamie@264
|
4816 }
|
jamie@264
|
4817 TrackedSection* acquireChild( std::string const& childName ) {
|
jamie@264
|
4818 if( TrackedSection* child = findChild( childName ) )
|
jamie@264
|
4819 return child;
|
jamie@264
|
4820 m_children.insert( std::make_pair( childName, TrackedSection( childName, this ) ) );
|
jamie@264
|
4821 return findChild( childName );
|
jamie@264
|
4822 }
|
jamie@264
|
4823 void enter() {
|
jamie@264
|
4824 if( m_runState == NotStarted )
|
jamie@264
|
4825 m_runState = Executing;
|
jamie@264
|
4826 }
|
jamie@264
|
4827 void leave() {
|
jamie@264
|
4828 for( TrackedSections::const_iterator it = m_children.begin(), itEnd = m_children.end();
|
jamie@264
|
4829 it != itEnd;
|
jamie@264
|
4830 ++it )
|
jamie@264
|
4831 if( it->second.runState() != Completed ) {
|
jamie@264
|
4832 m_runState = ExecutingChildren;
|
jamie@264
|
4833 return;
|
jamie@264
|
4834 }
|
jamie@264
|
4835 m_runState = Completed;
|
jamie@264
|
4836 }
|
jamie@264
|
4837 TrackedSection* getParent() {
|
jamie@264
|
4838 return m_parent;
|
jamie@264
|
4839 }
|
jamie@264
|
4840 bool hasChildren() const {
|
jamie@264
|
4841 return !m_children.empty();
|
jamie@264
|
4842 }
|
jamie@264
|
4843
|
jamie@264
|
4844 private:
|
jamie@264
|
4845 std::string m_name;
|
jamie@264
|
4846 RunState m_runState;
|
jamie@264
|
4847 TrackedSections m_children;
|
jamie@264
|
4848 TrackedSection* m_parent;
|
jamie@264
|
4849
|
jamie@264
|
4850 };
|
jamie@264
|
4851
|
jamie@264
|
4852 class TestCaseTracker {
|
jamie@264
|
4853 public:
|
jamie@264
|
4854 TestCaseTracker( std::string const& testCaseName )
|
jamie@264
|
4855 : m_testCase( testCaseName, NULL ),
|
jamie@264
|
4856 m_currentSection( &m_testCase ),
|
jamie@264
|
4857 m_completedASectionThisRun( false )
|
jamie@264
|
4858 {}
|
jamie@264
|
4859
|
jamie@264
|
4860 bool enterSection( std::string const& name ) {
|
jamie@264
|
4861 TrackedSection* child = m_currentSection->acquireChild( name );
|
jamie@264
|
4862 if( m_completedASectionThisRun || child->runState() == TrackedSection::Completed )
|
jamie@264
|
4863 return false;
|
jamie@264
|
4864
|
jamie@264
|
4865 m_currentSection = child;
|
jamie@264
|
4866 m_currentSection->enter();
|
jamie@264
|
4867 return true;
|
jamie@264
|
4868 }
|
jamie@264
|
4869 void leaveSection() {
|
jamie@264
|
4870 m_currentSection->leave();
|
jamie@264
|
4871 m_currentSection = m_currentSection->getParent();
|
jamie@264
|
4872 assert( m_currentSection != NULL );
|
jamie@264
|
4873 m_completedASectionThisRun = true;
|
jamie@264
|
4874 }
|
jamie@264
|
4875
|
jamie@264
|
4876 bool currentSectionHasChildren() const {
|
jamie@264
|
4877 return m_currentSection->hasChildren();
|
jamie@264
|
4878 }
|
jamie@264
|
4879 bool isCompleted() const {
|
jamie@264
|
4880 return m_testCase.runState() == TrackedSection::Completed;
|
jamie@264
|
4881 }
|
jamie@264
|
4882
|
jamie@264
|
4883 class Guard {
|
jamie@264
|
4884 public:
|
jamie@264
|
4885 Guard( TestCaseTracker& tracker ) : m_tracker( tracker ) {
|
jamie@264
|
4886 m_tracker.enterTestCase();
|
jamie@264
|
4887 }
|
jamie@264
|
4888 ~Guard() {
|
jamie@264
|
4889 m_tracker.leaveTestCase();
|
jamie@264
|
4890 }
|
jamie@264
|
4891 private:
|
jamie@264
|
4892 Guard( Guard const& );
|
jamie@264
|
4893 void operator = ( Guard const& );
|
jamie@264
|
4894 TestCaseTracker& m_tracker;
|
jamie@264
|
4895 };
|
jamie@264
|
4896
|
jamie@264
|
4897 private:
|
jamie@264
|
4898 void enterTestCase() {
|
jamie@264
|
4899 m_currentSection = &m_testCase;
|
jamie@264
|
4900 m_completedASectionThisRun = false;
|
jamie@264
|
4901 m_testCase.enter();
|
jamie@264
|
4902 }
|
jamie@264
|
4903 void leaveTestCase() {
|
jamie@264
|
4904 m_testCase.leave();
|
jamie@264
|
4905 }
|
jamie@264
|
4906
|
jamie@264
|
4907 TrackedSection m_testCase;
|
jamie@264
|
4908 TrackedSection* m_currentSection;
|
jamie@264
|
4909 bool m_completedASectionThisRun;
|
jamie@264
|
4910 };
|
jamie@264
|
4911
|
jamie@264
|
4912 } // namespace SectionTracking
|
jamie@264
|
4913
|
jamie@264
|
4914 using SectionTracking::TestCaseTracker;
|
jamie@264
|
4915
|
jamie@264
|
4916 } // namespace Catch
|
jamie@264
|
4917
|
jamie@264
|
4918 #include <set>
|
jamie@264
|
4919 #include <string>
|
jamie@264
|
4920
|
jamie@264
|
4921 namespace Catch {
|
jamie@264
|
4922
|
jamie@264
|
4923 class StreamRedirect {
|
jamie@264
|
4924
|
jamie@264
|
4925 public:
|
jamie@264
|
4926 StreamRedirect( std::ostream& stream, std::string& targetString )
|
jamie@264
|
4927 : m_stream( stream ),
|
jamie@264
|
4928 m_prevBuf( stream.rdbuf() ),
|
jamie@264
|
4929 m_targetString( targetString )
|
jamie@264
|
4930 {
|
jamie@264
|
4931 stream.rdbuf( m_oss.rdbuf() );
|
jamie@264
|
4932 }
|
jamie@264
|
4933
|
jamie@264
|
4934 ~StreamRedirect() {
|
jamie@264
|
4935 m_targetString += m_oss.str();
|
jamie@264
|
4936 m_stream.rdbuf( m_prevBuf );
|
jamie@264
|
4937 }
|
jamie@264
|
4938
|
jamie@264
|
4939 private:
|
jamie@264
|
4940 std::ostream& m_stream;
|
jamie@264
|
4941 std::streambuf* m_prevBuf;
|
jamie@264
|
4942 std::ostringstream m_oss;
|
jamie@264
|
4943 std::string& m_targetString;
|
jamie@264
|
4944 };
|
jamie@264
|
4945
|
jamie@264
|
4946 ///////////////////////////////////////////////////////////////////////////
|
jamie@264
|
4947
|
jamie@264
|
4948 class RunContext : public IResultCapture, public IRunner {
|
jamie@264
|
4949
|
jamie@264
|
4950 RunContext( RunContext const& );
|
jamie@264
|
4951 void operator =( RunContext const& );
|
jamie@264
|
4952
|
jamie@264
|
4953 public:
|
jamie@264
|
4954
|
jamie@264
|
4955 explicit RunContext( Ptr<IConfig const> const& config, Ptr<IStreamingReporter> const& reporter )
|
jamie@264
|
4956 : m_runInfo( config->name() ),
|
jamie@264
|
4957 m_context( getCurrentMutableContext() ),
|
jamie@264
|
4958 m_activeTestCase( NULL ),
|
jamie@264
|
4959 m_config( config ),
|
jamie@264
|
4960 m_reporter( reporter ),
|
jamie@264
|
4961 m_prevRunner( m_context.getRunner() ),
|
jamie@264
|
4962 m_prevResultCapture( m_context.getResultCapture() ),
|
jamie@264
|
4963 m_prevConfig( m_context.getConfig() )
|
jamie@264
|
4964 {
|
jamie@264
|
4965 m_context.setRunner( this );
|
jamie@264
|
4966 m_context.setConfig( m_config );
|
jamie@264
|
4967 m_context.setResultCapture( this );
|
jamie@264
|
4968 m_reporter->testRunStarting( m_runInfo );
|
jamie@264
|
4969 }
|
jamie@264
|
4970
|
jamie@264
|
4971 virtual ~RunContext() {
|
jamie@264
|
4972 m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) );
|
jamie@264
|
4973 m_context.setRunner( m_prevRunner );
|
jamie@264
|
4974 m_context.setConfig( NULL );
|
jamie@264
|
4975 m_context.setResultCapture( m_prevResultCapture );
|
jamie@264
|
4976 m_context.setConfig( m_prevConfig );
|
jamie@264
|
4977 }
|
jamie@264
|
4978
|
jamie@264
|
4979 void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) {
|
jamie@264
|
4980 m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) );
|
jamie@264
|
4981 }
|
jamie@264
|
4982 void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) {
|
jamie@264
|
4983 m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) );
|
jamie@264
|
4984 }
|
jamie@264
|
4985
|
jamie@264
|
4986 Totals runTest( TestCase const& testCase ) {
|
jamie@264
|
4987 Totals prevTotals = m_totals;
|
jamie@264
|
4988
|
jamie@264
|
4989 std::string redirectedCout;
|
jamie@264
|
4990 std::string redirectedCerr;
|
jamie@264
|
4991
|
jamie@264
|
4992 TestCaseInfo testInfo = testCase.getTestCaseInfo();
|
jamie@264
|
4993
|
jamie@264
|
4994 m_reporter->testCaseStarting( testInfo );
|
jamie@264
|
4995
|
jamie@264
|
4996 m_activeTestCase = &testCase;
|
jamie@264
|
4997 m_testCaseTracker = TestCaseTracker( testInfo.name );
|
jamie@264
|
4998
|
jamie@264
|
4999 do {
|
jamie@264
|
5000 do {
|
jamie@264
|
5001 runCurrentTest( redirectedCout, redirectedCerr );
|
jamie@264
|
5002 }
|
jamie@264
|
5003 while( !m_testCaseTracker->isCompleted() && !aborting() );
|
jamie@264
|
5004 }
|
jamie@264
|
5005 while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() );
|
jamie@264
|
5006
|
jamie@264
|
5007 Totals deltaTotals = m_totals.delta( prevTotals );
|
jamie@264
|
5008 m_totals.testCases += deltaTotals.testCases;
|
jamie@264
|
5009 m_reporter->testCaseEnded( TestCaseStats( testInfo,
|
jamie@264
|
5010 deltaTotals,
|
jamie@264
|
5011 redirectedCout,
|
jamie@264
|
5012 redirectedCerr,
|
jamie@264
|
5013 aborting() ) );
|
jamie@264
|
5014
|
jamie@264
|
5015 m_activeTestCase = NULL;
|
jamie@264
|
5016 m_testCaseTracker.reset();
|
jamie@264
|
5017
|
jamie@264
|
5018 return deltaTotals;
|
jamie@264
|
5019 }
|
jamie@264
|
5020
|
jamie@264
|
5021 Ptr<IConfig const> config() const {
|
jamie@264
|
5022 return m_config;
|
jamie@264
|
5023 }
|
jamie@264
|
5024
|
jamie@264
|
5025 private: // IResultCapture
|
jamie@264
|
5026
|
jamie@264
|
5027 virtual void assertionEnded( AssertionResult const& result ) {
|
jamie@264
|
5028 if( result.getResultType() == ResultWas::Ok ) {
|
jamie@264
|
5029 m_totals.assertions.passed++;
|
jamie@264
|
5030 }
|
jamie@264
|
5031 else if( !result.isOk() ) {
|
jamie@264
|
5032 m_totals.assertions.failed++;
|
jamie@264
|
5033 }
|
jamie@264
|
5034
|
jamie@264
|
5035 if( m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) ) )
|
jamie@264
|
5036 m_messages.clear();
|
jamie@264
|
5037
|
jamie@264
|
5038 // Reset working state
|
jamie@264
|
5039 m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition );
|
jamie@264
|
5040 m_lastResult = result;
|
jamie@264
|
5041 }
|
jamie@264
|
5042
|
jamie@264
|
5043 virtual bool sectionStarted (
|
jamie@264
|
5044 SectionInfo const& sectionInfo,
|
jamie@264
|
5045 Counts& assertions
|
jamie@264
|
5046 )
|
jamie@264
|
5047 {
|
jamie@264
|
5048 std::ostringstream oss;
|
jamie@264
|
5049 oss << sectionInfo.name << "@" << sectionInfo.lineInfo;
|
jamie@264
|
5050
|
jamie@264
|
5051 if( !m_testCaseTracker->enterSection( oss.str() ) )
|
jamie@264
|
5052 return false;
|
jamie@264
|
5053
|
jamie@264
|
5054 m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
|
jamie@264
|
5055
|
jamie@264
|
5056 m_reporter->sectionStarting( sectionInfo );
|
jamie@264
|
5057
|
jamie@264
|
5058 assertions = m_totals.assertions;
|
jamie@264
|
5059
|
jamie@264
|
5060 return true;
|
jamie@264
|
5061 }
|
jamie@264
|
5062 bool testForMissingAssertions( Counts& assertions ) {
|
jamie@264
|
5063 if( assertions.total() != 0 ||
|
jamie@264
|
5064 !m_config->warnAboutMissingAssertions() ||
|
jamie@264
|
5065 m_testCaseTracker->currentSectionHasChildren() )
|
jamie@264
|
5066 return false;
|
jamie@264
|
5067 m_totals.assertions.failed++;
|
jamie@264
|
5068 assertions.failed++;
|
jamie@264
|
5069 return true;
|
jamie@264
|
5070 }
|
jamie@264
|
5071
|
jamie@264
|
5072 virtual void sectionEnded( SectionInfo const& info, Counts const& prevAssertions, double _durationInSeconds ) {
|
jamie@264
|
5073 if( std::uncaught_exception() ) {
|
jamie@264
|
5074 m_unfinishedSections.push_back( UnfinishedSections( info, prevAssertions, _durationInSeconds ) );
|
jamie@264
|
5075 return;
|
jamie@264
|
5076 }
|
jamie@264
|
5077
|
jamie@264
|
5078 Counts assertions = m_totals.assertions - prevAssertions;
|
jamie@264
|
5079 bool missingAssertions = testForMissingAssertions( assertions );
|
jamie@264
|
5080
|
jamie@264
|
5081 m_testCaseTracker->leaveSection();
|
jamie@264
|
5082
|
jamie@264
|
5083 m_reporter->sectionEnded( SectionStats( info, assertions, _durationInSeconds, missingAssertions ) );
|
jamie@264
|
5084 m_messages.clear();
|
jamie@264
|
5085 }
|
jamie@264
|
5086
|
jamie@264
|
5087 virtual void pushScopedMessage( MessageInfo const& message ) {
|
jamie@264
|
5088 m_messages.push_back( message );
|
jamie@264
|
5089 }
|
jamie@264
|
5090
|
jamie@264
|
5091 virtual void popScopedMessage( MessageInfo const& message ) {
|
jamie@264
|
5092 m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() );
|
jamie@264
|
5093 }
|
jamie@264
|
5094
|
jamie@264
|
5095 virtual std::string getCurrentTestName() const {
|
jamie@264
|
5096 return m_activeTestCase
|
jamie@264
|
5097 ? m_activeTestCase->getTestCaseInfo().name
|
jamie@264
|
5098 : "";
|
jamie@264
|
5099 }
|
jamie@264
|
5100
|
jamie@264
|
5101 virtual const AssertionResult* getLastResult() const {
|
jamie@264
|
5102 return &m_lastResult;
|
jamie@264
|
5103 }
|
jamie@264
|
5104
|
jamie@264
|
5105 public:
|
jamie@264
|
5106 // !TBD We need to do this another way!
|
jamie@264
|
5107 bool aborting() const {
|
jamie@264
|
5108 return m_totals.assertions.failed == static_cast<std::size_t>( m_config->abortAfter() );
|
jamie@264
|
5109 }
|
jamie@264
|
5110
|
jamie@264
|
5111 private:
|
jamie@264
|
5112
|
jamie@264
|
5113 void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) {
|
jamie@264
|
5114 TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
|
jamie@264
|
5115 SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description );
|
jamie@264
|
5116 m_reporter->sectionStarting( testCaseSection );
|
jamie@264
|
5117 Counts prevAssertions = m_totals.assertions;
|
jamie@264
|
5118 double duration = 0;
|
jamie@264
|
5119 try {
|
jamie@264
|
5120 m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal );
|
jamie@264
|
5121 TestCaseTracker::Guard guard( *m_testCaseTracker );
|
jamie@264
|
5122
|
jamie@264
|
5123 Timer timer;
|
jamie@264
|
5124 timer.start();
|
jamie@264
|
5125 if( m_reporter->getPreferences().shouldRedirectStdOut ) {
|
jamie@264
|
5126 StreamRedirect coutRedir( std::cout, redirectedCout );
|
jamie@264
|
5127 StreamRedirect cerrRedir( std::cerr, redirectedCerr );
|
jamie@264
|
5128 m_activeTestCase->invoke();
|
jamie@264
|
5129 }
|
jamie@264
|
5130 else {
|
jamie@264
|
5131 m_activeTestCase->invoke();
|
jamie@264
|
5132 }
|
jamie@264
|
5133 duration = timer.getElapsedSeconds();
|
jamie@264
|
5134 }
|
jamie@264
|
5135 catch( TestFailureException& ) {
|
jamie@264
|
5136 // This just means the test was aborted due to failure
|
jamie@264
|
5137 }
|
jamie@264
|
5138 catch(...) {
|
jamie@264
|
5139 ResultBuilder exResult( m_lastAssertionInfo.macroName.c_str(),
|
jamie@264
|
5140 m_lastAssertionInfo.lineInfo,
|
jamie@264
|
5141 m_lastAssertionInfo.capturedExpression.c_str(),
|
jamie@264
|
5142 m_lastAssertionInfo.resultDisposition );
|
jamie@264
|
5143 exResult.useActiveException();
|
jamie@264
|
5144 }
|
jamie@264
|
5145 // If sections ended prematurely due to an exception we stored their
|
jamie@264
|
5146 // infos here so we can tear them down outside the unwind process.
|
jamie@264
|
5147 for( std::vector<UnfinishedSections>::const_reverse_iterator it = m_unfinishedSections.rbegin(),
|
jamie@264
|
5148 itEnd = m_unfinishedSections.rend();
|
jamie@264
|
5149 it != itEnd;
|
jamie@264
|
5150 ++it )
|
jamie@264
|
5151 sectionEnded( it->info, it->prevAssertions, it->durationInSeconds );
|
jamie@264
|
5152 m_unfinishedSections.clear();
|
jamie@264
|
5153 m_messages.clear();
|
jamie@264
|
5154
|
jamie@264
|
5155 Counts assertions = m_totals.assertions - prevAssertions;
|
jamie@264
|
5156 bool missingAssertions = testForMissingAssertions( assertions );
|
jamie@264
|
5157
|
jamie@264
|
5158 if( testCaseInfo.okToFail() ) {
|
jamie@264
|
5159 std::swap( assertions.failedButOk, assertions.failed );
|
jamie@264
|
5160 m_totals.assertions.failed -= assertions.failedButOk;
|
jamie@264
|
5161 m_totals.assertions.failedButOk += assertions.failedButOk;
|
jamie@264
|
5162 }
|
jamie@264
|
5163
|
jamie@264
|
5164 SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions );
|
jamie@264
|
5165 m_reporter->sectionEnded( testCaseSectionStats );
|
jamie@264
|
5166 }
|
jamie@264
|
5167
|
jamie@264
|
5168 private:
|
jamie@264
|
5169 struct UnfinishedSections {
|
jamie@264
|
5170 UnfinishedSections( SectionInfo const& _info, Counts const& _prevAssertions, double _durationInSeconds )
|
jamie@264
|
5171 : info( _info ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds )
|
jamie@264
|
5172 {}
|
jamie@264
|
5173
|
jamie@264
|
5174 SectionInfo info;
|
jamie@264
|
5175 Counts prevAssertions;
|
jamie@264
|
5176 double durationInSeconds;
|
jamie@264
|
5177 };
|
jamie@264
|
5178
|
jamie@264
|
5179 TestRunInfo m_runInfo;
|
jamie@264
|
5180 IMutableContext& m_context;
|
jamie@264
|
5181 TestCase const* m_activeTestCase;
|
jamie@264
|
5182 Option<TestCaseTracker> m_testCaseTracker;
|
jamie@264
|
5183 AssertionResult m_lastResult;
|
jamie@264
|
5184
|
jamie@264
|
5185 Ptr<IConfig const> m_config;
|
jamie@264
|
5186 Totals m_totals;
|
jamie@264
|
5187 Ptr<IStreamingReporter> m_reporter;
|
jamie@264
|
5188 std::vector<MessageInfo> m_messages;
|
jamie@264
|
5189 IRunner* m_prevRunner;
|
jamie@264
|
5190 IResultCapture* m_prevResultCapture;
|
jamie@264
|
5191 Ptr<IConfig const> m_prevConfig;
|
jamie@264
|
5192 AssertionInfo m_lastAssertionInfo;
|
jamie@264
|
5193 std::vector<UnfinishedSections> m_unfinishedSections;
|
jamie@264
|
5194 };
|
jamie@264
|
5195
|
jamie@264
|
5196 IResultCapture& getResultCapture() {
|
jamie@264
|
5197 if( IResultCapture* capture = getCurrentContext().getResultCapture() )
|
jamie@264
|
5198 return *capture;
|
jamie@264
|
5199 else
|
jamie@264
|
5200 throw std::logic_error( "No result capture instance" );
|
jamie@264
|
5201 }
|
jamie@264
|
5202
|
jamie@264
|
5203 } // end namespace Catch
|
jamie@264
|
5204
|
jamie@264
|
5205 // #included from: internal/catch_version.h
|
jamie@264
|
5206 #define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED
|
jamie@264
|
5207
|
jamie@264
|
5208 namespace Catch {
|
jamie@264
|
5209
|
jamie@264
|
5210 // Versioning information
|
jamie@264
|
5211 struct Version {
|
jamie@264
|
5212 Version( unsigned int _majorVersion,
|
jamie@264
|
5213 unsigned int _minorVersion,
|
jamie@264
|
5214 unsigned int _buildNumber,
|
jamie@264
|
5215 char const* const _branchName )
|
jamie@264
|
5216 : majorVersion( _majorVersion ),
|
jamie@264
|
5217 minorVersion( _minorVersion ),
|
jamie@264
|
5218 buildNumber( _buildNumber ),
|
jamie@264
|
5219 branchName( _branchName )
|
jamie@264
|
5220 {}
|
jamie@264
|
5221
|
jamie@264
|
5222 unsigned int const majorVersion;
|
jamie@264
|
5223 unsigned int const minorVersion;
|
jamie@264
|
5224 unsigned int const buildNumber;
|
jamie@264
|
5225 char const* const branchName;
|
jamie@264
|
5226
|
jamie@264
|
5227 private:
|
jamie@264
|
5228 void operator=( Version const& );
|
jamie@264
|
5229 };
|
jamie@264
|
5230
|
jamie@264
|
5231 extern Version libraryVersion;
|
jamie@264
|
5232 }
|
jamie@264
|
5233
|
jamie@264
|
5234 #include <fstream>
|
jamie@264
|
5235 #include <stdlib.h>
|
jamie@264
|
5236 #include <limits>
|
jamie@264
|
5237
|
jamie@264
|
5238 namespace Catch {
|
jamie@264
|
5239
|
jamie@264
|
5240 class Runner {
|
jamie@264
|
5241
|
jamie@264
|
5242 public:
|
jamie@264
|
5243 Runner( Ptr<Config> const& config )
|
jamie@264
|
5244 : m_config( config )
|
jamie@264
|
5245 {
|
jamie@264
|
5246 openStream();
|
jamie@264
|
5247 makeReporter();
|
jamie@264
|
5248 }
|
jamie@264
|
5249
|
jamie@264
|
5250 Totals runTests() {
|
jamie@264
|
5251
|
jamie@264
|
5252 RunContext context( m_config.get(), m_reporter );
|
jamie@264
|
5253
|
jamie@264
|
5254 Totals totals;
|
jamie@264
|
5255
|
jamie@264
|
5256 context.testGroupStarting( "", 1, 1 ); // deprecated?
|
jamie@264
|
5257
|
jamie@264
|
5258 TestSpec testSpec = m_config->testSpec();
|
jamie@264
|
5259 if( !testSpec.hasFilters() )
|
jamie@264
|
5260 testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests
|
jamie@264
|
5261
|
jamie@264
|
5262 std::vector<TestCase> testCases;
|
jamie@264
|
5263 getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, testCases );
|
jamie@264
|
5264
|
jamie@264
|
5265 int testsRunForGroup = 0;
|
jamie@264
|
5266 for( std::vector<TestCase>::const_iterator it = testCases.begin(), itEnd = testCases.end();
|
jamie@264
|
5267 it != itEnd;
|
jamie@264
|
5268 ++it ) {
|
jamie@264
|
5269 testsRunForGroup++;
|
jamie@264
|
5270 if( m_testsAlreadyRun.find( *it ) == m_testsAlreadyRun.end() ) {
|
jamie@264
|
5271
|
jamie@264
|
5272 if( context.aborting() )
|
jamie@264
|
5273 break;
|
jamie@264
|
5274
|
jamie@264
|
5275 totals += context.runTest( *it );
|
jamie@264
|
5276 m_testsAlreadyRun.insert( *it );
|
jamie@264
|
5277 }
|
jamie@264
|
5278 }
|
jamie@264
|
5279 context.testGroupEnded( "", totals, 1, 1 );
|
jamie@264
|
5280 return totals;
|
jamie@264
|
5281 }
|
jamie@264
|
5282
|
jamie@264
|
5283 private:
|
jamie@264
|
5284 void openStream() {
|
jamie@264
|
5285 // Open output file, if specified
|
jamie@264
|
5286 if( !m_config->getFilename().empty() ) {
|
jamie@264
|
5287 m_ofs.open( m_config->getFilename().c_str() );
|
jamie@264
|
5288 if( m_ofs.fail() ) {
|
jamie@264
|
5289 std::ostringstream oss;
|
jamie@264
|
5290 oss << "Unable to open file: '" << m_config->getFilename() << "'";
|
jamie@264
|
5291 throw std::domain_error( oss.str() );
|
jamie@264
|
5292 }
|
jamie@264
|
5293 m_config->setStreamBuf( m_ofs.rdbuf() );
|
jamie@264
|
5294 }
|
jamie@264
|
5295 }
|
jamie@264
|
5296 void makeReporter() {
|
jamie@264
|
5297 std::string reporterName = m_config->getReporterName().empty()
|
jamie@264
|
5298 ? "console"
|
jamie@264
|
5299 : m_config->getReporterName();
|
jamie@264
|
5300
|
jamie@264
|
5301 m_reporter = getRegistryHub().getReporterRegistry().create( reporterName, m_config.get() );
|
jamie@264
|
5302 if( !m_reporter ) {
|
jamie@264
|
5303 std::ostringstream oss;
|
jamie@264
|
5304 oss << "No reporter registered with name: '" << reporterName << "'";
|
jamie@264
|
5305 throw std::domain_error( oss.str() );
|
jamie@264
|
5306 }
|
jamie@264
|
5307 }
|
jamie@264
|
5308
|
jamie@264
|
5309 private:
|
jamie@264
|
5310 Ptr<Config> m_config;
|
jamie@264
|
5311 std::ofstream m_ofs;
|
jamie@264
|
5312 Ptr<IStreamingReporter> m_reporter;
|
jamie@264
|
5313 std::set<TestCase> m_testsAlreadyRun;
|
jamie@264
|
5314 };
|
jamie@264
|
5315
|
jamie@264
|
5316 class Session {
|
jamie@264
|
5317 static bool alreadyInstantiated;
|
jamie@264
|
5318
|
jamie@264
|
5319 public:
|
jamie@264
|
5320
|
jamie@264
|
5321 struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; };
|
jamie@264
|
5322
|
jamie@264
|
5323 Session()
|
jamie@264
|
5324 : m_cli( makeCommandLineParser() ) {
|
jamie@264
|
5325 if( alreadyInstantiated ) {
|
jamie@264
|
5326 std::string msg = "Only one instance of Catch::Session can ever be used";
|
jamie@264
|
5327 std::cerr << msg << std::endl;
|
jamie@264
|
5328 throw std::logic_error( msg );
|
jamie@264
|
5329 }
|
jamie@264
|
5330 alreadyInstantiated = true;
|
jamie@264
|
5331 }
|
jamie@264
|
5332 ~Session() {
|
jamie@264
|
5333 Catch::cleanUp();
|
jamie@264
|
5334 }
|
jamie@264
|
5335
|
jamie@264
|
5336 void showHelp( std::string const& processName ) {
|
jamie@264
|
5337 std::cout << "\nCatch v" << libraryVersion.majorVersion << "."
|
jamie@264
|
5338 << libraryVersion.minorVersion << " build "
|
jamie@264
|
5339 << libraryVersion.buildNumber;
|
jamie@264
|
5340 if( libraryVersion.branchName != std::string( "master" ) )
|
jamie@264
|
5341 std::cout << " (" << libraryVersion.branchName << " branch)";
|
jamie@264
|
5342 std::cout << "\n";
|
jamie@264
|
5343
|
jamie@264
|
5344 m_cli.usage( std::cout, processName );
|
jamie@264
|
5345 std::cout << "For more detail usage please see the project docs\n" << std::endl;
|
jamie@264
|
5346 }
|
jamie@264
|
5347
|
jamie@264
|
5348 int applyCommandLine( int argc, char* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) {
|
jamie@264
|
5349 try {
|
jamie@264
|
5350 m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail );
|
jamie@264
|
5351 m_unusedTokens = m_cli.parseInto( argc, argv, m_configData );
|
jamie@264
|
5352 if( m_configData.showHelp )
|
jamie@264
|
5353 showHelp( m_configData.processName );
|
jamie@264
|
5354 m_config.reset();
|
jamie@264
|
5355 }
|
jamie@264
|
5356 catch( std::exception& ex ) {
|
jamie@264
|
5357 {
|
jamie@264
|
5358 Colour colourGuard( Colour::Red );
|
jamie@264
|
5359 std::cerr << "\nError(s) in input:\n"
|
jamie@264
|
5360 << Text( ex.what(), TextAttributes().setIndent(2) )
|
jamie@264
|
5361 << "\n\n";
|
jamie@264
|
5362 }
|
jamie@264
|
5363 m_cli.usage( std::cout, m_configData.processName );
|
jamie@264
|
5364 return (std::numeric_limits<int>::max)();
|
jamie@264
|
5365 }
|
jamie@264
|
5366 return 0;
|
jamie@264
|
5367 }
|
jamie@264
|
5368
|
jamie@264
|
5369 void useConfigData( ConfigData const& _configData ) {
|
jamie@264
|
5370 m_configData = _configData;
|
jamie@264
|
5371 m_config.reset();
|
jamie@264
|
5372 }
|
jamie@264
|
5373
|
jamie@264
|
5374 int run( int argc, char* const argv[] ) {
|
jamie@264
|
5375
|
jamie@264
|
5376 int returnCode = applyCommandLine( argc, argv );
|
jamie@264
|
5377 if( returnCode == 0 )
|
jamie@264
|
5378 returnCode = run();
|
jamie@264
|
5379 return returnCode;
|
jamie@264
|
5380 }
|
jamie@264
|
5381
|
jamie@264
|
5382 int run() {
|
jamie@264
|
5383 if( m_configData.showHelp )
|
jamie@264
|
5384 return 0;
|
jamie@264
|
5385
|
jamie@264
|
5386 try
|
jamie@264
|
5387 {
|
jamie@264
|
5388 config(); // Force config to be constructed
|
jamie@264
|
5389 Runner runner( m_config );
|
jamie@264
|
5390
|
jamie@264
|
5391 // Handle list request
|
jamie@264
|
5392 if( Option<std::size_t> listed = list( config() ) )
|
jamie@264
|
5393 return static_cast<int>( *listed );
|
jamie@264
|
5394
|
jamie@264
|
5395 return static_cast<int>( runner.runTests().assertions.failed );
|
jamie@264
|
5396 }
|
jamie@264
|
5397 catch( std::exception& ex ) {
|
jamie@264
|
5398 std::cerr << ex.what() << std::endl;
|
jamie@264
|
5399 return (std::numeric_limits<int>::max)();
|
jamie@264
|
5400 }
|
jamie@264
|
5401 }
|
jamie@264
|
5402
|
jamie@264
|
5403 Clara::CommandLine<ConfigData> const& cli() const {
|
jamie@264
|
5404 return m_cli;
|
jamie@264
|
5405 }
|
jamie@264
|
5406 std::vector<Clara::Parser::Token> const& unusedTokens() const {
|
jamie@264
|
5407 return m_unusedTokens;
|
jamie@264
|
5408 }
|
jamie@264
|
5409 ConfigData& configData() {
|
jamie@264
|
5410 return m_configData;
|
jamie@264
|
5411 }
|
jamie@264
|
5412 Config& config() {
|
jamie@264
|
5413 if( !m_config )
|
jamie@264
|
5414 m_config = new Config( m_configData );
|
jamie@264
|
5415 return *m_config;
|
jamie@264
|
5416 }
|
jamie@264
|
5417
|
jamie@264
|
5418 private:
|
jamie@264
|
5419 Clara::CommandLine<ConfigData> m_cli;
|
jamie@264
|
5420 std::vector<Clara::Parser::Token> m_unusedTokens;
|
jamie@264
|
5421 ConfigData m_configData;
|
jamie@264
|
5422 Ptr<Config> m_config;
|
jamie@264
|
5423 };
|
jamie@264
|
5424
|
jamie@264
|
5425 bool Session::alreadyInstantiated = false;
|
jamie@264
|
5426
|
jamie@264
|
5427 } // end namespace Catch
|
jamie@264
|
5428
|
jamie@264
|
5429 // #included from: catch_registry_hub.hpp
|
jamie@264
|
5430 #define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED
|
jamie@264
|
5431
|
jamie@264
|
5432 // #included from: catch_test_case_registry_impl.hpp
|
jamie@264
|
5433 #define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED
|
jamie@264
|
5434
|
jamie@264
|
5435 #include <vector>
|
jamie@264
|
5436 #include <set>
|
jamie@264
|
5437 #include <sstream>
|
jamie@264
|
5438 #include <iostream>
|
jamie@264
|
5439
|
jamie@264
|
5440 namespace Catch {
|
jamie@264
|
5441
|
jamie@264
|
5442 class TestRegistry : public ITestCaseRegistry {
|
jamie@264
|
5443 public:
|
jamie@264
|
5444 TestRegistry() : m_unnamedCount( 0 ) {}
|
jamie@264
|
5445 virtual ~TestRegistry();
|
jamie@264
|
5446
|
jamie@264
|
5447 virtual void registerTest( TestCase const& testCase ) {
|
jamie@264
|
5448 std::string name = testCase.getTestCaseInfo().name;
|
jamie@264
|
5449 if( name == "" ) {
|
jamie@264
|
5450 std::ostringstream oss;
|
jamie@264
|
5451 oss << "Anonymous test case " << ++m_unnamedCount;
|
jamie@264
|
5452 return registerTest( testCase.withName( oss.str() ) );
|
jamie@264
|
5453 }
|
jamie@264
|
5454
|
jamie@264
|
5455 if( m_functions.find( testCase ) == m_functions.end() ) {
|
jamie@264
|
5456 m_functions.insert( testCase );
|
jamie@264
|
5457 m_functionsInOrder.push_back( testCase );
|
jamie@264
|
5458 if( !testCase.isHidden() )
|
jamie@264
|
5459 m_nonHiddenFunctions.push_back( testCase );
|
jamie@264
|
5460 }
|
jamie@264
|
5461 else {
|
jamie@264
|
5462 TestCase const& prev = *m_functions.find( testCase );
|
jamie@264
|
5463 {
|
jamie@264
|
5464 Colour colourGuard( Colour::Red );
|
jamie@264
|
5465 std::cerr << "error: TEST_CASE( \"" << name << "\" ) already defined.\n"
|
jamie@264
|
5466 << "\tFirst seen at " << prev.getTestCaseInfo().lineInfo << "\n"
|
jamie@264
|
5467 << "\tRedefined at " << testCase.getTestCaseInfo().lineInfo << std::endl;
|
jamie@264
|
5468 }
|
jamie@264
|
5469 exit(1);
|
jamie@264
|
5470 }
|
jamie@264
|
5471 }
|
jamie@264
|
5472
|
jamie@264
|
5473 virtual std::vector<TestCase> const& getAllTests() const {
|
jamie@264
|
5474 return m_functionsInOrder;
|
jamie@264
|
5475 }
|
jamie@264
|
5476
|
jamie@264
|
5477 virtual std::vector<TestCase> const& getAllNonHiddenTests() const {
|
jamie@264
|
5478 return m_nonHiddenFunctions;
|
jamie@264
|
5479 }
|
jamie@264
|
5480
|
jamie@264
|
5481 virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector<TestCase>& matchingTestCases ) const {
|
jamie@264
|
5482 for( std::vector<TestCase>::const_iterator it = m_functionsInOrder.begin(),
|
jamie@264
|
5483 itEnd = m_functionsInOrder.end();
|
jamie@264
|
5484 it != itEnd;
|
jamie@264
|
5485 ++it ) {
|
jamie@264
|
5486 if( testSpec.matches( *it ) && ( config.allowThrows() || !it->throws() ) )
|
jamie@264
|
5487 matchingTestCases.push_back( *it );
|
jamie@264
|
5488 }
|
jamie@264
|
5489 }
|
jamie@264
|
5490
|
jamie@264
|
5491 private:
|
jamie@264
|
5492
|
jamie@264
|
5493 std::set<TestCase> m_functions;
|
jamie@264
|
5494 std::vector<TestCase> m_functionsInOrder;
|
jamie@264
|
5495 std::vector<TestCase> m_nonHiddenFunctions;
|
jamie@264
|
5496 size_t m_unnamedCount;
|
jamie@264
|
5497 };
|
jamie@264
|
5498
|
jamie@264
|
5499 ///////////////////////////////////////////////////////////////////////////
|
jamie@264
|
5500
|
jamie@264
|
5501 class FreeFunctionTestCase : public SharedImpl<ITestCase> {
|
jamie@264
|
5502 public:
|
jamie@264
|
5503
|
jamie@264
|
5504 FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {}
|
jamie@264
|
5505
|
jamie@264
|
5506 virtual void invoke() const {
|
jamie@264
|
5507 m_fun();
|
jamie@264
|
5508 }
|
jamie@264
|
5509
|
jamie@264
|
5510 private:
|
jamie@264
|
5511 virtual ~FreeFunctionTestCase();
|
jamie@264
|
5512
|
jamie@264
|
5513 TestFunction m_fun;
|
jamie@264
|
5514 };
|
jamie@264
|
5515
|
jamie@264
|
5516 inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) {
|
jamie@264
|
5517 std::string className = classOrQualifiedMethodName;
|
jamie@264
|
5518 if( startsWith( className, "&" ) )
|
jamie@264
|
5519 {
|
jamie@264
|
5520 std::size_t lastColons = className.rfind( "::" );
|
jamie@264
|
5521 std::size_t penultimateColons = className.rfind( "::", lastColons-1 );
|
jamie@264
|
5522 if( penultimateColons == std::string::npos )
|
jamie@264
|
5523 penultimateColons = 1;
|
jamie@264
|
5524 className = className.substr( penultimateColons, lastColons-penultimateColons );
|
jamie@264
|
5525 }
|
jamie@264
|
5526 return className;
|
jamie@264
|
5527 }
|
jamie@264
|
5528
|
jamie@264
|
5529 ///////////////////////////////////////////////////////////////////////////
|
jamie@264
|
5530
|
jamie@264
|
5531 AutoReg::AutoReg( TestFunction function,
|
jamie@264
|
5532 SourceLineInfo const& lineInfo,
|
jamie@264
|
5533 NameAndDesc const& nameAndDesc ) {
|
jamie@264
|
5534 registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo );
|
jamie@264
|
5535 }
|
jamie@264
|
5536
|
jamie@264
|
5537 AutoReg::~AutoReg() {}
|
jamie@264
|
5538
|
jamie@264
|
5539 void AutoReg::registerTestCase( ITestCase* testCase,
|
jamie@264
|
5540 char const* classOrQualifiedMethodName,
|
jamie@264
|
5541 NameAndDesc const& nameAndDesc,
|
jamie@264
|
5542 SourceLineInfo const& lineInfo ) {
|
jamie@264
|
5543
|
jamie@264
|
5544 getMutableRegistryHub().registerTest
|
jamie@264
|
5545 ( makeTestCase( testCase,
|
jamie@264
|
5546 extractClassName( classOrQualifiedMethodName ),
|
jamie@264
|
5547 nameAndDesc.name,
|
jamie@264
|
5548 nameAndDesc.description,
|
jamie@264
|
5549 lineInfo ) );
|
jamie@264
|
5550 }
|
jamie@264
|
5551
|
jamie@264
|
5552 } // end namespace Catch
|
jamie@264
|
5553
|
jamie@264
|
5554 // #included from: catch_reporter_registry.hpp
|
jamie@264
|
5555 #define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED
|
jamie@264
|
5556
|
jamie@264
|
5557 #include <map>
|
jamie@264
|
5558
|
jamie@264
|
5559 namespace Catch {
|
jamie@264
|
5560
|
jamie@264
|
5561 class ReporterRegistry : public IReporterRegistry {
|
jamie@264
|
5562
|
jamie@264
|
5563 public:
|
jamie@264
|
5564
|
jamie@264
|
5565 virtual ~ReporterRegistry() {
|
jamie@264
|
5566 deleteAllValues( m_factories );
|
jamie@264
|
5567 }
|
jamie@264
|
5568
|
jamie@264
|
5569 virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig> const& config ) const {
|
jamie@264
|
5570 FactoryMap::const_iterator it = m_factories.find( name );
|
jamie@264
|
5571 if( it == m_factories.end() )
|
jamie@264
|
5572 return NULL;
|
jamie@264
|
5573 return it->second->create( ReporterConfig( config ) );
|
jamie@264
|
5574 }
|
jamie@264
|
5575
|
jamie@264
|
5576 void registerReporter( std::string const& name, IReporterFactory* factory ) {
|
jamie@264
|
5577 m_factories.insert( std::make_pair( name, factory ) );
|
jamie@264
|
5578 }
|
jamie@264
|
5579
|
jamie@264
|
5580 FactoryMap const& getFactories() const {
|
jamie@264
|
5581 return m_factories;
|
jamie@264
|
5582 }
|
jamie@264
|
5583
|
jamie@264
|
5584 private:
|
jamie@264
|
5585 FactoryMap m_factories;
|
jamie@264
|
5586 };
|
jamie@264
|
5587 }
|
jamie@264
|
5588
|
jamie@264
|
5589 // #included from: catch_exception_translator_registry.hpp
|
jamie@264
|
5590 #define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
|
jamie@264
|
5591
|
jamie@264
|
5592 #ifdef __OBJC__
|
jamie@264
|
5593 #import "Foundation/Foundation.h"
|
jamie@264
|
5594 #endif
|
jamie@264
|
5595
|
jamie@264
|
5596 namespace Catch {
|
jamie@264
|
5597
|
jamie@264
|
5598 class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry {
|
jamie@264
|
5599 public:
|
jamie@264
|
5600 ~ExceptionTranslatorRegistry() {
|
jamie@264
|
5601 deleteAll( m_translators );
|
jamie@264
|
5602 }
|
jamie@264
|
5603
|
jamie@264
|
5604 virtual void registerTranslator( const IExceptionTranslator* translator ) {
|
jamie@264
|
5605 m_translators.push_back( translator );
|
jamie@264
|
5606 }
|
jamie@264
|
5607
|
jamie@264
|
5608 virtual std::string translateActiveException() const {
|
jamie@264
|
5609 try {
|
jamie@264
|
5610 #ifdef __OBJC__
|
jamie@264
|
5611 // In Objective-C try objective-c exceptions first
|
jamie@264
|
5612 @try {
|
jamie@264
|
5613 throw;
|
jamie@264
|
5614 }
|
jamie@264
|
5615 @catch (NSException *exception) {
|
jamie@264
|
5616 return toString( [exception description] );
|
jamie@264
|
5617 }
|
jamie@264
|
5618 #else
|
jamie@264
|
5619 throw;
|
jamie@264
|
5620 #endif
|
jamie@264
|
5621 }
|
jamie@264
|
5622 catch( TestFailureException& ) {
|
jamie@264
|
5623 throw;
|
jamie@264
|
5624 }
|
jamie@264
|
5625 catch( std::exception& ex ) {
|
jamie@264
|
5626 return ex.what();
|
jamie@264
|
5627 }
|
jamie@264
|
5628 catch( std::string& msg ) {
|
jamie@264
|
5629 return msg;
|
jamie@264
|
5630 }
|
jamie@264
|
5631 catch( const char* msg ) {
|
jamie@264
|
5632 return msg;
|
jamie@264
|
5633 }
|
jamie@264
|
5634 catch(...) {
|
jamie@264
|
5635 return tryTranslators( m_translators.begin() );
|
jamie@264
|
5636 }
|
jamie@264
|
5637 }
|
jamie@264
|
5638
|
jamie@264
|
5639 std::string tryTranslators( std::vector<const IExceptionTranslator*>::const_iterator it ) const {
|
jamie@264
|
5640 if( it == m_translators.end() )
|
jamie@264
|
5641 return "Unknown exception";
|
jamie@264
|
5642
|
jamie@264
|
5643 try {
|
jamie@264
|
5644 return (*it)->translate();
|
jamie@264
|
5645 }
|
jamie@264
|
5646 catch(...) {
|
jamie@264
|
5647 return tryTranslators( it+1 );
|
jamie@264
|
5648 }
|
jamie@264
|
5649 }
|
jamie@264
|
5650
|
jamie@264
|
5651 private:
|
jamie@264
|
5652 std::vector<const IExceptionTranslator*> m_translators;
|
jamie@264
|
5653 };
|
jamie@264
|
5654 }
|
jamie@264
|
5655
|
jamie@264
|
5656 namespace Catch {
|
jamie@264
|
5657
|
jamie@264
|
5658 namespace {
|
jamie@264
|
5659
|
jamie@264
|
5660 class RegistryHub : public IRegistryHub, public IMutableRegistryHub {
|
jamie@264
|
5661
|
jamie@264
|
5662 RegistryHub( RegistryHub const& );
|
jamie@264
|
5663 void operator=( RegistryHub const& );
|
jamie@264
|
5664
|
jamie@264
|
5665 public: // IRegistryHub
|
jamie@264
|
5666 RegistryHub() {
|
jamie@264
|
5667 }
|
jamie@264
|
5668 virtual IReporterRegistry const& getReporterRegistry() const {
|
jamie@264
|
5669 return m_reporterRegistry;
|
jamie@264
|
5670 }
|
jamie@264
|
5671 virtual ITestCaseRegistry const& getTestCaseRegistry() const {
|
jamie@264
|
5672 return m_testCaseRegistry;
|
jamie@264
|
5673 }
|
jamie@264
|
5674 virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() {
|
jamie@264
|
5675 return m_exceptionTranslatorRegistry;
|
jamie@264
|
5676 }
|
jamie@264
|
5677
|
jamie@264
|
5678 public: // IMutableRegistryHub
|
jamie@264
|
5679 virtual void registerReporter( std::string const& name, IReporterFactory* factory ) {
|
jamie@264
|
5680 m_reporterRegistry.registerReporter( name, factory );
|
jamie@264
|
5681 }
|
jamie@264
|
5682 virtual void registerTest( TestCase const& testInfo ) {
|
jamie@264
|
5683 m_testCaseRegistry.registerTest( testInfo );
|
jamie@264
|
5684 }
|
jamie@264
|
5685 virtual void registerTranslator( const IExceptionTranslator* translator ) {
|
jamie@264
|
5686 m_exceptionTranslatorRegistry.registerTranslator( translator );
|
jamie@264
|
5687 }
|
jamie@264
|
5688
|
jamie@264
|
5689 private:
|
jamie@264
|
5690 TestRegistry m_testCaseRegistry;
|
jamie@264
|
5691 ReporterRegistry m_reporterRegistry;
|
jamie@264
|
5692 ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
|
jamie@264
|
5693 };
|
jamie@264
|
5694
|
jamie@264
|
5695 // Single, global, instance
|
jamie@264
|
5696 inline RegistryHub*& getTheRegistryHub() {
|
jamie@264
|
5697 static RegistryHub* theRegistryHub = NULL;
|
jamie@264
|
5698 if( !theRegistryHub )
|
jamie@264
|
5699 theRegistryHub = new RegistryHub();
|
jamie@264
|
5700 return theRegistryHub;
|
jamie@264
|
5701 }
|
jamie@264
|
5702 }
|
jamie@264
|
5703
|
jamie@264
|
5704 IRegistryHub& getRegistryHub() {
|
jamie@264
|
5705 return *getTheRegistryHub();
|
jamie@264
|
5706 }
|
jamie@264
|
5707 IMutableRegistryHub& getMutableRegistryHub() {
|
jamie@264
|
5708 return *getTheRegistryHub();
|
jamie@264
|
5709 }
|
jamie@264
|
5710 void cleanUp() {
|
jamie@264
|
5711 delete getTheRegistryHub();
|
jamie@264
|
5712 getTheRegistryHub() = NULL;
|
jamie@264
|
5713 cleanUpContext();
|
jamie@264
|
5714 }
|
jamie@264
|
5715 std::string translateActiveException() {
|
jamie@264
|
5716 return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();
|
jamie@264
|
5717 }
|
jamie@264
|
5718
|
jamie@264
|
5719 } // end namespace Catch
|
jamie@264
|
5720
|
jamie@264
|
5721 // #included from: catch_notimplemented_exception.hpp
|
jamie@264
|
5722 #define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED
|
jamie@264
|
5723
|
jamie@264
|
5724 #include <ostream>
|
jamie@264
|
5725
|
jamie@264
|
5726 namespace Catch {
|
jamie@264
|
5727
|
jamie@264
|
5728 NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo )
|
jamie@264
|
5729 : m_lineInfo( lineInfo ) {
|
jamie@264
|
5730 std::ostringstream oss;
|
jamie@264
|
5731 oss << lineInfo << ": function ";
|
jamie@264
|
5732 oss << "not implemented";
|
jamie@264
|
5733 m_what = oss.str();
|
jamie@264
|
5734 }
|
jamie@264
|
5735
|
jamie@264
|
5736 const char* NotImplementedException::what() const CATCH_NOEXCEPT {
|
jamie@264
|
5737 return m_what.c_str();
|
jamie@264
|
5738 }
|
jamie@264
|
5739
|
jamie@264
|
5740 } // end namespace Catch
|
jamie@264
|
5741
|
jamie@264
|
5742 // #included from: catch_context_impl.hpp
|
jamie@264
|
5743 #define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED
|
jamie@264
|
5744
|
jamie@264
|
5745 // #included from: catch_stream.hpp
|
jamie@264
|
5746 #define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED
|
jamie@264
|
5747
|
jamie@264
|
5748 // #included from: catch_streambuf.h
|
jamie@264
|
5749 #define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED
|
jamie@264
|
5750
|
jamie@264
|
5751 #include <streambuf>
|
jamie@264
|
5752
|
jamie@264
|
5753 namespace Catch {
|
jamie@264
|
5754
|
jamie@264
|
5755 class StreamBufBase : public std::streambuf {
|
jamie@264
|
5756 public:
|
jamie@264
|
5757 virtual ~StreamBufBase() CATCH_NOEXCEPT;
|
jamie@264
|
5758 };
|
jamie@264
|
5759 }
|
jamie@264
|
5760
|
jamie@264
|
5761 #include <stdexcept>
|
jamie@264
|
5762 #include <cstdio>
|
jamie@264
|
5763
|
jamie@264
|
5764 namespace Catch {
|
jamie@264
|
5765
|
jamie@264
|
5766 template<typename WriterF, size_t bufferSize=256>
|
jamie@264
|
5767 class StreamBufImpl : public StreamBufBase {
|
jamie@264
|
5768 char data[bufferSize];
|
jamie@264
|
5769 WriterF m_writer;
|
jamie@264
|
5770
|
jamie@264
|
5771 public:
|
jamie@264
|
5772 StreamBufImpl() {
|
jamie@264
|
5773 setp( data, data + sizeof(data) );
|
jamie@264
|
5774 }
|
jamie@264
|
5775
|
jamie@264
|
5776 ~StreamBufImpl() CATCH_NOEXCEPT {
|
jamie@264
|
5777 sync();
|
jamie@264
|
5778 }
|
jamie@264
|
5779
|
jamie@264
|
5780 private:
|
jamie@264
|
5781 int overflow( int c ) {
|
jamie@264
|
5782 sync();
|
jamie@264
|
5783
|
jamie@264
|
5784 if( c != EOF ) {
|
jamie@264
|
5785 if( pbase() == epptr() )
|
jamie@264
|
5786 m_writer( std::string( 1, static_cast<char>( c ) ) );
|
jamie@264
|
5787 else
|
jamie@264
|
5788 sputc( static_cast<char>( c ) );
|
jamie@264
|
5789 }
|
jamie@264
|
5790 return 0;
|
jamie@264
|
5791 }
|
jamie@264
|
5792
|
jamie@264
|
5793 int sync() {
|
jamie@264
|
5794 if( pbase() != pptr() ) {
|
jamie@264
|
5795 m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) );
|
jamie@264
|
5796 setp( pbase(), epptr() );
|
jamie@264
|
5797 }
|
jamie@264
|
5798 return 0;
|
jamie@264
|
5799 }
|
jamie@264
|
5800 };
|
jamie@264
|
5801
|
jamie@264
|
5802 ///////////////////////////////////////////////////////////////////////////
|
jamie@264
|
5803
|
jamie@264
|
5804 struct OutputDebugWriter {
|
jamie@264
|
5805
|
jamie@264
|
5806 void operator()( std::string const&str ) {
|
jamie@264
|
5807 writeToDebugConsole( str );
|
jamie@264
|
5808 }
|
jamie@264
|
5809 };
|
jamie@264
|
5810
|
jamie@264
|
5811 Stream::Stream()
|
jamie@264
|
5812 : streamBuf( NULL ), isOwned( false )
|
jamie@264
|
5813 {}
|
jamie@264
|
5814
|
jamie@264
|
5815 Stream::Stream( std::streambuf* _streamBuf, bool _isOwned )
|
jamie@264
|
5816 : streamBuf( _streamBuf ), isOwned( _isOwned )
|
jamie@264
|
5817 {}
|
jamie@264
|
5818
|
jamie@264
|
5819 void Stream::release() {
|
jamie@264
|
5820 if( isOwned ) {
|
jamie@264
|
5821 delete streamBuf;
|
jamie@264
|
5822 streamBuf = NULL;
|
jamie@264
|
5823 isOwned = false;
|
jamie@264
|
5824 }
|
jamie@264
|
5825 }
|
jamie@264
|
5826 }
|
jamie@264
|
5827
|
jamie@264
|
5828 namespace Catch {
|
jamie@264
|
5829
|
jamie@264
|
5830 class Context : public IMutableContext {
|
jamie@264
|
5831
|
jamie@264
|
5832 Context() : m_config( NULL ), m_runner( NULL ), m_resultCapture( NULL ) {}
|
jamie@264
|
5833 Context( Context const& );
|
jamie@264
|
5834 void operator=( Context const& );
|
jamie@264
|
5835
|
jamie@264
|
5836 public: // IContext
|
jamie@264
|
5837 virtual IResultCapture* getResultCapture() {
|
jamie@264
|
5838 return m_resultCapture;
|
jamie@264
|
5839 }
|
jamie@264
|
5840 virtual IRunner* getRunner() {
|
jamie@264
|
5841 return m_runner;
|
jamie@264
|
5842 }
|
jamie@264
|
5843 virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) {
|
jamie@264
|
5844 return getGeneratorsForCurrentTest()
|
jamie@264
|
5845 .getGeneratorInfo( fileInfo, totalSize )
|
jamie@264
|
5846 .getCurrentIndex();
|
jamie@264
|
5847 }
|
jamie@264
|
5848 virtual bool advanceGeneratorsForCurrentTest() {
|
jamie@264
|
5849 IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
|
jamie@264
|
5850 return generators && generators->moveNext();
|
jamie@264
|
5851 }
|
jamie@264
|
5852
|
jamie@264
|
5853 virtual Ptr<IConfig const> getConfig() const {
|
jamie@264
|
5854 return m_config;
|
jamie@264
|
5855 }
|
jamie@264
|
5856
|
jamie@264
|
5857 public: // IMutableContext
|
jamie@264
|
5858 virtual void setResultCapture( IResultCapture* resultCapture ) {
|
jamie@264
|
5859 m_resultCapture = resultCapture;
|
jamie@264
|
5860 }
|
jamie@264
|
5861 virtual void setRunner( IRunner* runner ) {
|
jamie@264
|
5862 m_runner = runner;
|
jamie@264
|
5863 }
|
jamie@264
|
5864 virtual void setConfig( Ptr<IConfig const> const& config ) {
|
jamie@264
|
5865 m_config = config;
|
jamie@264
|
5866 }
|
jamie@264
|
5867
|
jamie@264
|
5868 friend IMutableContext& getCurrentMutableContext();
|
jamie@264
|
5869
|
jamie@264
|
5870 private:
|
jamie@264
|
5871 IGeneratorsForTest* findGeneratorsForCurrentTest() {
|
jamie@264
|
5872 std::string testName = getResultCapture()->getCurrentTestName();
|
jamie@264
|
5873
|
jamie@264
|
5874 std::map<std::string, IGeneratorsForTest*>::const_iterator it =
|
jamie@264
|
5875 m_generatorsByTestName.find( testName );
|
jamie@264
|
5876 return it != m_generatorsByTestName.end()
|
jamie@264
|
5877 ? it->second
|
jamie@264
|
5878 : NULL;
|
jamie@264
|
5879 }
|
jamie@264
|
5880
|
jamie@264
|
5881 IGeneratorsForTest& getGeneratorsForCurrentTest() {
|
jamie@264
|
5882 IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
|
jamie@264
|
5883 if( !generators ) {
|
jamie@264
|
5884 std::string testName = getResultCapture()->getCurrentTestName();
|
jamie@264
|
5885 generators = createGeneratorsForTest();
|
jamie@264
|
5886 m_generatorsByTestName.insert( std::make_pair( testName, generators ) );
|
jamie@264
|
5887 }
|
jamie@264
|
5888 return *generators;
|
jamie@264
|
5889 }
|
jamie@264
|
5890
|
jamie@264
|
5891 private:
|
jamie@264
|
5892 Ptr<IConfig const> m_config;
|
jamie@264
|
5893 IRunner* m_runner;
|
jamie@264
|
5894 IResultCapture* m_resultCapture;
|
jamie@264
|
5895 std::map<std::string, IGeneratorsForTest*> m_generatorsByTestName;
|
jamie@264
|
5896 };
|
jamie@264
|
5897
|
jamie@264
|
5898 namespace {
|
jamie@264
|
5899 Context* currentContext = NULL;
|
jamie@264
|
5900 }
|
jamie@264
|
5901 IMutableContext& getCurrentMutableContext() {
|
jamie@264
|
5902 if( !currentContext )
|
jamie@264
|
5903 currentContext = new Context();
|
jamie@264
|
5904 return *currentContext;
|
jamie@264
|
5905 }
|
jamie@264
|
5906 IContext& getCurrentContext() {
|
jamie@264
|
5907 return getCurrentMutableContext();
|
jamie@264
|
5908 }
|
jamie@264
|
5909
|
jamie@264
|
5910 Stream createStream( std::string const& streamName ) {
|
jamie@264
|
5911 if( streamName == "stdout" ) return Stream( std::cout.rdbuf(), false );
|
jamie@264
|
5912 if( streamName == "stderr" ) return Stream( std::cerr.rdbuf(), false );
|
jamie@264
|
5913 if( streamName == "debug" ) return Stream( new StreamBufImpl<OutputDebugWriter>, true );
|
jamie@264
|
5914
|
jamie@264
|
5915 throw std::domain_error( "Unknown stream: " + streamName );
|
jamie@264
|
5916 }
|
jamie@264
|
5917
|
jamie@264
|
5918 void cleanUpContext() {
|
jamie@264
|
5919 delete currentContext;
|
jamie@264
|
5920 currentContext = NULL;
|
jamie@264
|
5921 }
|
jamie@264
|
5922 }
|
jamie@264
|
5923
|
jamie@264
|
5924 // #included from: catch_console_colour_impl.hpp
|
jamie@264
|
5925 #define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED
|
jamie@264
|
5926
|
jamie@264
|
5927 namespace Catch { namespace Detail {
|
jamie@264
|
5928 struct IColourImpl {
|
jamie@264
|
5929 virtual ~IColourImpl() {}
|
jamie@264
|
5930 virtual void use( Colour::Code _colourCode ) = 0;
|
jamie@264
|
5931 };
|
jamie@264
|
5932 }}
|
jamie@264
|
5933
|
jamie@264
|
5934 #if defined ( CATCH_PLATFORM_WINDOWS ) /////////////////////////////////////////
|
jamie@264
|
5935
|
jamie@264
|
5936 #ifndef NOMINMAX
|
jamie@264
|
5937 #define NOMINMAX
|
jamie@264
|
5938 #endif
|
jamie@264
|
5939
|
jamie@264
|
5940 #ifdef __AFXDLL
|
jamie@264
|
5941 #include <AfxWin.h>
|
jamie@264
|
5942 #else
|
jamie@264
|
5943 #include <windows.h>
|
jamie@264
|
5944 #endif
|
jamie@264
|
5945
|
jamie@264
|
5946 namespace Catch {
|
jamie@264
|
5947 namespace {
|
jamie@264
|
5948
|
jamie@264
|
5949 class Win32ColourImpl : public Detail::IColourImpl {
|
jamie@264
|
5950 public:
|
jamie@264
|
5951 Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) )
|
jamie@264
|
5952 {
|
jamie@264
|
5953 CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
|
jamie@264
|
5954 GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo );
|
jamie@264
|
5955 originalAttributes = csbiInfo.wAttributes;
|
jamie@264
|
5956 }
|
jamie@264
|
5957
|
jamie@264
|
5958 virtual void use( Colour::Code _colourCode ) {
|
jamie@264
|
5959 switch( _colourCode ) {
|
jamie@264
|
5960 case Colour::None: return setTextAttribute( originalAttributes );
|
jamie@264
|
5961 case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
|
jamie@264
|
5962 case Colour::Red: return setTextAttribute( FOREGROUND_RED );
|
jamie@264
|
5963 case Colour::Green: return setTextAttribute( FOREGROUND_GREEN );
|
jamie@264
|
5964 case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE );
|
jamie@264
|
5965 case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN );
|
jamie@264
|
5966 case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN );
|
jamie@264
|
5967 case Colour::Grey: return setTextAttribute( 0 );
|
jamie@264
|
5968
|
jamie@264
|
5969 case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY );
|
jamie@264
|
5970 case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED );
|
jamie@264
|
5971 case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN );
|
jamie@264
|
5972 case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
|
jamie@264
|
5973
|
jamie@264
|
5974 case Colour::Bright: throw std::logic_error( "not a colour" );
|
jamie@264
|
5975 }
|
jamie@264
|
5976 }
|
jamie@264
|
5977
|
jamie@264
|
5978 private:
|
jamie@264
|
5979 void setTextAttribute( WORD _textAttribute ) {
|
jamie@264
|
5980 SetConsoleTextAttribute( stdoutHandle, _textAttribute );
|
jamie@264
|
5981 }
|
jamie@264
|
5982 HANDLE stdoutHandle;
|
jamie@264
|
5983 WORD originalAttributes;
|
jamie@264
|
5984 };
|
jamie@264
|
5985
|
jamie@264
|
5986 inline bool shouldUseColourForPlatform() {
|
jamie@264
|
5987 return true;
|
jamie@264
|
5988 }
|
jamie@264
|
5989
|
jamie@264
|
5990 static Detail::IColourImpl* platformColourInstance() {
|
jamie@264
|
5991 static Win32ColourImpl s_instance;
|
jamie@264
|
5992 return &s_instance;
|
jamie@264
|
5993 }
|
jamie@264
|
5994
|
jamie@264
|
5995 } // end anon namespace
|
jamie@264
|
5996 } // end namespace Catch
|
jamie@264
|
5997
|
jamie@264
|
5998 #else // Not Windows - assumed to be POSIX compatible //////////////////////////
|
jamie@264
|
5999
|
jamie@264
|
6000 #include <unistd.h>
|
jamie@264
|
6001
|
jamie@264
|
6002 namespace Catch {
|
jamie@264
|
6003 namespace {
|
jamie@264
|
6004
|
jamie@264
|
6005 // use POSIX/ ANSI console terminal codes
|
jamie@264
|
6006 // Thanks to Adam Strzelecki for original contribution
|
jamie@264
|
6007 // (http://github.com/nanoant)
|
jamie@264
|
6008 // https://github.com/philsquared/Catch/pull/131
|
jamie@264
|
6009 class PosixColourImpl : public Detail::IColourImpl {
|
jamie@264
|
6010 public:
|
jamie@264
|
6011 virtual void use( Colour::Code _colourCode ) {
|
jamie@264
|
6012 switch( _colourCode ) {
|
jamie@264
|
6013 case Colour::None:
|
jamie@264
|
6014 case Colour::White: return setColour( "[0m" );
|
jamie@264
|
6015 case Colour::Red: return setColour( "[0;31m" );
|
jamie@264
|
6016 case Colour::Green: return setColour( "[0;32m" );
|
jamie@264
|
6017 case Colour::Blue: return setColour( "[0:34m" );
|
jamie@264
|
6018 case Colour::Cyan: return setColour( "[0;36m" );
|
jamie@264
|
6019 case Colour::Yellow: return setColour( "[0;33m" );
|
jamie@264
|
6020 case Colour::Grey: return setColour( "[1;30m" );
|
jamie@264
|
6021
|
jamie@264
|
6022 case Colour::LightGrey: return setColour( "[0;37m" );
|
jamie@264
|
6023 case Colour::BrightRed: return setColour( "[1;31m" );
|
jamie@264
|
6024 case Colour::BrightGreen: return setColour( "[1;32m" );
|
jamie@264
|
6025 case Colour::BrightWhite: return setColour( "[1;37m" );
|
jamie@264
|
6026
|
jamie@264
|
6027 case Colour::Bright: throw std::logic_error( "not a colour" );
|
jamie@264
|
6028 }
|
jamie@264
|
6029 }
|
jamie@264
|
6030 private:
|
jamie@264
|
6031 void setColour( const char* _escapeCode ) {
|
jamie@264
|
6032 std::cout << '\033' << _escapeCode;
|
jamie@264
|
6033 }
|
jamie@264
|
6034 };
|
jamie@264
|
6035
|
jamie@264
|
6036 inline bool shouldUseColourForPlatform() {
|
jamie@264
|
6037 return isatty(STDOUT_FILENO);
|
jamie@264
|
6038 }
|
jamie@264
|
6039
|
jamie@264
|
6040 static Detail::IColourImpl* platformColourInstance() {
|
jamie@264
|
6041 static PosixColourImpl s_instance;
|
jamie@264
|
6042 return &s_instance;
|
jamie@264
|
6043 }
|
jamie@264
|
6044
|
jamie@264
|
6045 } // end anon namespace
|
jamie@264
|
6046 } // end namespace Catch
|
jamie@264
|
6047
|
jamie@264
|
6048 #endif // not Windows
|
jamie@264
|
6049
|
jamie@264
|
6050 namespace Catch {
|
jamie@264
|
6051
|
jamie@264
|
6052 namespace {
|
jamie@264
|
6053 struct NoColourImpl : Detail::IColourImpl {
|
jamie@264
|
6054 void use( Colour::Code ) {}
|
jamie@264
|
6055
|
jamie@264
|
6056 static IColourImpl* instance() {
|
jamie@264
|
6057 static NoColourImpl s_instance;
|
jamie@264
|
6058 return &s_instance;
|
jamie@264
|
6059 }
|
jamie@264
|
6060 };
|
jamie@264
|
6061 static bool shouldUseColour() {
|
jamie@264
|
6062 return shouldUseColourForPlatform() && !isDebuggerActive();
|
jamie@264
|
6063 }
|
jamie@264
|
6064 }
|
jamie@264
|
6065
|
jamie@264
|
6066 Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); }
|
jamie@264
|
6067 Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast<Colour&>( _other ).m_moved = true; }
|
jamie@264
|
6068 Colour::~Colour(){ if( !m_moved ) use( None ); }
|
jamie@264
|
6069 void Colour::use( Code _colourCode ) {
|
jamie@264
|
6070 impl()->use( _colourCode );
|
jamie@264
|
6071 }
|
jamie@264
|
6072
|
jamie@264
|
6073 Detail::IColourImpl* Colour::impl() {
|
jamie@264
|
6074 return shouldUseColour()
|
jamie@264
|
6075 ? platformColourInstance()
|
jamie@264
|
6076 : NoColourImpl::instance();
|
jamie@264
|
6077 }
|
jamie@264
|
6078
|
jamie@264
|
6079 } // end namespace Catch
|
jamie@264
|
6080
|
jamie@264
|
6081 // #included from: catch_generators_impl.hpp
|
jamie@264
|
6082 #define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED
|
jamie@264
|
6083
|
jamie@264
|
6084 #include <vector>
|
jamie@264
|
6085 #include <string>
|
jamie@264
|
6086 #include <map>
|
jamie@264
|
6087
|
jamie@264
|
6088 namespace Catch {
|
jamie@264
|
6089
|
jamie@264
|
6090 struct GeneratorInfo : IGeneratorInfo {
|
jamie@264
|
6091
|
jamie@264
|
6092 GeneratorInfo( std::size_t size )
|
jamie@264
|
6093 : m_size( size ),
|
jamie@264
|
6094 m_currentIndex( 0 )
|
jamie@264
|
6095 {}
|
jamie@264
|
6096
|
jamie@264
|
6097 bool moveNext() {
|
jamie@264
|
6098 if( ++m_currentIndex == m_size ) {
|
jamie@264
|
6099 m_currentIndex = 0;
|
jamie@264
|
6100 return false;
|
jamie@264
|
6101 }
|
jamie@264
|
6102 return true;
|
jamie@264
|
6103 }
|
jamie@264
|
6104
|
jamie@264
|
6105 std::size_t getCurrentIndex() const {
|
jamie@264
|
6106 return m_currentIndex;
|
jamie@264
|
6107 }
|
jamie@264
|
6108
|
jamie@264
|
6109 std::size_t m_size;
|
jamie@264
|
6110 std::size_t m_currentIndex;
|
jamie@264
|
6111 };
|
jamie@264
|
6112
|
jamie@264
|
6113 ///////////////////////////////////////////////////////////////////////////
|
jamie@264
|
6114
|
jamie@264
|
6115 class GeneratorsForTest : public IGeneratorsForTest {
|
jamie@264
|
6116
|
jamie@264
|
6117 public:
|
jamie@264
|
6118 ~GeneratorsForTest() {
|
jamie@264
|
6119 deleteAll( m_generatorsInOrder );
|
jamie@264
|
6120 }
|
jamie@264
|
6121
|
jamie@264
|
6122 IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) {
|
jamie@264
|
6123 std::map<std::string, IGeneratorInfo*>::const_iterator it = m_generatorsByName.find( fileInfo );
|
jamie@264
|
6124 if( it == m_generatorsByName.end() ) {
|
jamie@264
|
6125 IGeneratorInfo* info = new GeneratorInfo( size );
|
jamie@264
|
6126 m_generatorsByName.insert( std::make_pair( fileInfo, info ) );
|
jamie@264
|
6127 m_generatorsInOrder.push_back( info );
|
jamie@264
|
6128 return *info;
|
jamie@264
|
6129 }
|
jamie@264
|
6130 return *it->second;
|
jamie@264
|
6131 }
|
jamie@264
|
6132
|
jamie@264
|
6133 bool moveNext() {
|
jamie@264
|
6134 std::vector<IGeneratorInfo*>::const_iterator it = m_generatorsInOrder.begin();
|
jamie@264
|
6135 std::vector<IGeneratorInfo*>::const_iterator itEnd = m_generatorsInOrder.end();
|
jamie@264
|
6136 for(; it != itEnd; ++it ) {
|
jamie@264
|
6137 if( (*it)->moveNext() )
|
jamie@264
|
6138 return true;
|
jamie@264
|
6139 }
|
jamie@264
|
6140 return false;
|
jamie@264
|
6141 }
|
jamie@264
|
6142
|
jamie@264
|
6143 private:
|
jamie@264
|
6144 std::map<std::string, IGeneratorInfo*> m_generatorsByName;
|
jamie@264
|
6145 std::vector<IGeneratorInfo*> m_generatorsInOrder;
|
jamie@264
|
6146 };
|
jamie@264
|
6147
|
jamie@264
|
6148 IGeneratorsForTest* createGeneratorsForTest()
|
jamie@264
|
6149 {
|
jamie@264
|
6150 return new GeneratorsForTest();
|
jamie@264
|
6151 }
|
jamie@264
|
6152
|
jamie@264
|
6153 } // end namespace Catch
|
jamie@264
|
6154
|
jamie@264
|
6155 // #included from: catch_assertionresult.hpp
|
jamie@264
|
6156 #define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED
|
jamie@264
|
6157
|
jamie@264
|
6158 namespace Catch {
|
jamie@264
|
6159
|
jamie@264
|
6160 AssertionInfo::AssertionInfo( std::string const& _macroName,
|
jamie@264
|
6161 SourceLineInfo const& _lineInfo,
|
jamie@264
|
6162 std::string const& _capturedExpression,
|
jamie@264
|
6163 ResultDisposition::Flags _resultDisposition )
|
jamie@264
|
6164 : macroName( _macroName ),
|
jamie@264
|
6165 lineInfo( _lineInfo ),
|
jamie@264
|
6166 capturedExpression( _capturedExpression ),
|
jamie@264
|
6167 resultDisposition( _resultDisposition )
|
jamie@264
|
6168 {}
|
jamie@264
|
6169
|
jamie@264
|
6170 AssertionResult::AssertionResult() {}
|
jamie@264
|
6171
|
jamie@264
|
6172 AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data )
|
jamie@264
|
6173 : m_info( info ),
|
jamie@264
|
6174 m_resultData( data )
|
jamie@264
|
6175 {}
|
jamie@264
|
6176
|
jamie@264
|
6177 AssertionResult::~AssertionResult() {}
|
jamie@264
|
6178
|
jamie@264
|
6179 // Result was a success
|
jamie@264
|
6180 bool AssertionResult::succeeded() const {
|
jamie@264
|
6181 return Catch::isOk( m_resultData.resultType );
|
jamie@264
|
6182 }
|
jamie@264
|
6183
|
jamie@264
|
6184 // Result was a success, or failure is suppressed
|
jamie@264
|
6185 bool AssertionResult::isOk() const {
|
jamie@264
|
6186 return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition );
|
jamie@264
|
6187 }
|
jamie@264
|
6188
|
jamie@264
|
6189 ResultWas::OfType AssertionResult::getResultType() const {
|
jamie@264
|
6190 return m_resultData.resultType;
|
jamie@264
|
6191 }
|
jamie@264
|
6192
|
jamie@264
|
6193 bool AssertionResult::hasExpression() const {
|
jamie@264
|
6194 return !m_info.capturedExpression.empty();
|
jamie@264
|
6195 }
|
jamie@264
|
6196
|
jamie@264
|
6197 bool AssertionResult::hasMessage() const {
|
jamie@264
|
6198 return !m_resultData.message.empty();
|
jamie@264
|
6199 }
|
jamie@264
|
6200
|
jamie@264
|
6201 std::string AssertionResult::getExpression() const {
|
jamie@264
|
6202 if( isFalseTest( m_info.resultDisposition ) )
|
jamie@264
|
6203 return "!" + m_info.capturedExpression;
|
jamie@264
|
6204 else
|
jamie@264
|
6205 return m_info.capturedExpression;
|
jamie@264
|
6206 }
|
jamie@264
|
6207 std::string AssertionResult::getExpressionInMacro() const {
|
jamie@264
|
6208 if( m_info.macroName.empty() )
|
jamie@264
|
6209 return m_info.capturedExpression;
|
jamie@264
|
6210 else
|
jamie@264
|
6211 return m_info.macroName + "( " + m_info.capturedExpression + " )";
|
jamie@264
|
6212 }
|
jamie@264
|
6213
|
jamie@264
|
6214 bool AssertionResult::hasExpandedExpression() const {
|
jamie@264
|
6215 return hasExpression() && getExpandedExpression() != getExpression();
|
jamie@264
|
6216 }
|
jamie@264
|
6217
|
jamie@264
|
6218 std::string AssertionResult::getExpandedExpression() const {
|
jamie@264
|
6219 return m_resultData.reconstructedExpression;
|
jamie@264
|
6220 }
|
jamie@264
|
6221
|
jamie@264
|
6222 std::string AssertionResult::getMessage() const {
|
jamie@264
|
6223 return m_resultData.message;
|
jamie@264
|
6224 }
|
jamie@264
|
6225 SourceLineInfo AssertionResult::getSourceInfo() const {
|
jamie@264
|
6226 return m_info.lineInfo;
|
jamie@264
|
6227 }
|
jamie@264
|
6228
|
jamie@264
|
6229 std::string AssertionResult::getTestMacroName() const {
|
jamie@264
|
6230 return m_info.macroName;
|
jamie@264
|
6231 }
|
jamie@264
|
6232
|
jamie@264
|
6233 } // end namespace Catch
|
jamie@264
|
6234
|
jamie@264
|
6235 // #included from: catch_test_case_info.hpp
|
jamie@264
|
6236 #define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED
|
jamie@264
|
6237
|
jamie@264
|
6238 namespace Catch {
|
jamie@264
|
6239
|
jamie@264
|
6240 inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) {
|
jamie@264
|
6241 if( tag == "." ||
|
jamie@264
|
6242 tag == "hide" ||
|
jamie@264
|
6243 tag == "!hide" )
|
jamie@264
|
6244 return TestCaseInfo::IsHidden;
|
jamie@264
|
6245 else if( tag == "!throws" )
|
jamie@264
|
6246 return TestCaseInfo::Throws;
|
jamie@264
|
6247 else if( tag == "!shouldfail" )
|
jamie@264
|
6248 return TestCaseInfo::ShouldFail;
|
jamie@264
|
6249 else if( tag == "!mayfail" )
|
jamie@264
|
6250 return TestCaseInfo::MayFail;
|
jamie@264
|
6251 else
|
jamie@264
|
6252 return TestCaseInfo::None;
|
jamie@264
|
6253 }
|
jamie@264
|
6254 inline bool isReservedTag( std::string const& tag ) {
|
jamie@264
|
6255 return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !isalnum( tag[0] );
|
jamie@264
|
6256 }
|
jamie@264
|
6257 inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) {
|
jamie@264
|
6258 if( isReservedTag( tag ) ) {
|
jamie@264
|
6259 {
|
jamie@264
|
6260 Colour colourGuard( Colour::Red );
|
jamie@264
|
6261 std::cerr
|
jamie@264
|
6262 << "Tag name [" << tag << "] not allowed.\n"
|
jamie@264
|
6263 << "Tag names starting with non alpha-numeric characters are reserved\n";
|
jamie@264
|
6264 }
|
jamie@264
|
6265 {
|
jamie@264
|
6266 Colour colourGuard( Colour::FileName );
|
jamie@264
|
6267 std::cerr << _lineInfo << std::endl;
|
jamie@264
|
6268 }
|
jamie@264
|
6269 exit(1);
|
jamie@264
|
6270 }
|
jamie@264
|
6271 }
|
jamie@264
|
6272
|
jamie@264
|
6273 TestCase makeTestCase( ITestCase* _testCase,
|
jamie@264
|
6274 std::string const& _className,
|
jamie@264
|
6275 std::string const& _name,
|
jamie@264
|
6276 std::string const& _descOrTags,
|
jamie@264
|
6277 SourceLineInfo const& _lineInfo )
|
jamie@264
|
6278 {
|
jamie@264
|
6279 bool isHidden( startsWith( _name, "./" ) ); // Legacy support
|
jamie@264
|
6280
|
jamie@264
|
6281 // Parse out tags
|
jamie@264
|
6282 std::set<std::string> tags;
|
jamie@264
|
6283 std::string desc, tag;
|
jamie@264
|
6284 bool inTag = false;
|
jamie@264
|
6285 for( std::size_t i = 0; i < _descOrTags.size(); ++i ) {
|
jamie@264
|
6286 char c = _descOrTags[i];
|
jamie@264
|
6287 if( !inTag ) {
|
jamie@264
|
6288 if( c == '[' )
|
jamie@264
|
6289 inTag = true;
|
jamie@264
|
6290 else
|
jamie@264
|
6291 desc += c;
|
jamie@264
|
6292 }
|
jamie@264
|
6293 else {
|
jamie@264
|
6294 if( c == ']' ) {
|
jamie@264
|
6295 enforceNotReservedTag( tag, _lineInfo );
|
jamie@264
|
6296
|
jamie@264
|
6297 inTag = false;
|
jamie@264
|
6298 if( tag == "hide" || tag == "." )
|
jamie@264
|
6299 isHidden = true;
|
jamie@264
|
6300 else
|
jamie@264
|
6301 tags.insert( tag );
|
jamie@264
|
6302 tag.clear();
|
jamie@264
|
6303 }
|
jamie@264
|
6304 else
|
jamie@264
|
6305 tag += c;
|
jamie@264
|
6306 }
|
jamie@264
|
6307 }
|
jamie@264
|
6308 if( isHidden ) {
|
jamie@264
|
6309 tags.insert( "hide" );
|
jamie@264
|
6310 tags.insert( "." );
|
jamie@264
|
6311 }
|
jamie@264
|
6312
|
jamie@264
|
6313 TestCaseInfo info( _name, _className, desc, tags, _lineInfo );
|
jamie@264
|
6314 return TestCase( _testCase, info );
|
jamie@264
|
6315 }
|
jamie@264
|
6316
|
jamie@264
|
6317 TestCaseInfo::TestCaseInfo( std::string const& _name,
|
jamie@264
|
6318 std::string const& _className,
|
jamie@264
|
6319 std::string const& _description,
|
jamie@264
|
6320 std::set<std::string> const& _tags,
|
jamie@264
|
6321 SourceLineInfo const& _lineInfo )
|
jamie@264
|
6322 : name( _name ),
|
jamie@264
|
6323 className( _className ),
|
jamie@264
|
6324 description( _description ),
|
jamie@264
|
6325 tags( _tags ),
|
jamie@264
|
6326 lineInfo( _lineInfo ),
|
jamie@264
|
6327 properties( None )
|
jamie@264
|
6328 {
|
jamie@264
|
6329 std::ostringstream oss;
|
jamie@264
|
6330 for( std::set<std::string>::const_iterator it = _tags.begin(), itEnd = _tags.end(); it != itEnd; ++it ) {
|
jamie@264
|
6331 oss << "[" << *it << "]";
|
jamie@264
|
6332 std::string lcaseTag = toLower( *it );
|
jamie@264
|
6333 properties = static_cast<SpecialProperties>( properties | parseSpecialTag( lcaseTag ) );
|
jamie@264
|
6334 lcaseTags.insert( lcaseTag );
|
jamie@264
|
6335 }
|
jamie@264
|
6336 tagsAsString = oss.str();
|
jamie@264
|
6337 }
|
jamie@264
|
6338
|
jamie@264
|
6339 TestCaseInfo::TestCaseInfo( TestCaseInfo const& other )
|
jamie@264
|
6340 : name( other.name ),
|
jamie@264
|
6341 className( other.className ),
|
jamie@264
|
6342 description( other.description ),
|
jamie@264
|
6343 tags( other.tags ),
|
jamie@264
|
6344 lcaseTags( other.lcaseTags ),
|
jamie@264
|
6345 tagsAsString( other.tagsAsString ),
|
jamie@264
|
6346 lineInfo( other.lineInfo ),
|
jamie@264
|
6347 properties( other.properties )
|
jamie@264
|
6348 {}
|
jamie@264
|
6349
|
jamie@264
|
6350 bool TestCaseInfo::isHidden() const {
|
jamie@264
|
6351 return ( properties & IsHidden ) != 0;
|
jamie@264
|
6352 }
|
jamie@264
|
6353 bool TestCaseInfo::throws() const {
|
jamie@264
|
6354 return ( properties & Throws ) != 0;
|
jamie@264
|
6355 }
|
jamie@264
|
6356 bool TestCaseInfo::okToFail() const {
|
jamie@264
|
6357 return ( properties & (ShouldFail | MayFail ) ) != 0;
|
jamie@264
|
6358 }
|
jamie@264
|
6359 bool TestCaseInfo::expectedToFail() const {
|
jamie@264
|
6360 return ( properties & (ShouldFail ) ) != 0;
|
jamie@264
|
6361 }
|
jamie@264
|
6362
|
jamie@264
|
6363 TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {}
|
jamie@264
|
6364
|
jamie@264
|
6365 TestCase::TestCase( TestCase const& other )
|
jamie@264
|
6366 : TestCaseInfo( other ),
|
jamie@264
|
6367 test( other.test )
|
jamie@264
|
6368 {}
|
jamie@264
|
6369
|
jamie@264
|
6370 TestCase TestCase::withName( std::string const& _newName ) const {
|
jamie@264
|
6371 TestCase other( *this );
|
jamie@264
|
6372 other.name = _newName;
|
jamie@264
|
6373 return other;
|
jamie@264
|
6374 }
|
jamie@264
|
6375
|
jamie@264
|
6376 void TestCase::swap( TestCase& other ) {
|
jamie@264
|
6377 test.swap( other.test );
|
jamie@264
|
6378 name.swap( other.name );
|
jamie@264
|
6379 className.swap( other.className );
|
jamie@264
|
6380 description.swap( other.description );
|
jamie@264
|
6381 tags.swap( other.tags );
|
jamie@264
|
6382 lcaseTags.swap( other.lcaseTags );
|
jamie@264
|
6383 tagsAsString.swap( other.tagsAsString );
|
jamie@264
|
6384 std::swap( TestCaseInfo::properties, static_cast<TestCaseInfo&>( other ).properties );
|
jamie@264
|
6385 std::swap( lineInfo, other.lineInfo );
|
jamie@264
|
6386 }
|
jamie@264
|
6387
|
jamie@264
|
6388 void TestCase::invoke() const {
|
jamie@264
|
6389 test->invoke();
|
jamie@264
|
6390 }
|
jamie@264
|
6391
|
jamie@264
|
6392 bool TestCase::operator == ( TestCase const& other ) const {
|
jamie@264
|
6393 return test.get() == other.test.get() &&
|
jamie@264
|
6394 name == other.name &&
|
jamie@264
|
6395 className == other.className;
|
jamie@264
|
6396 }
|
jamie@264
|
6397
|
jamie@264
|
6398 bool TestCase::operator < ( TestCase const& other ) const {
|
jamie@264
|
6399 return name < other.name;
|
jamie@264
|
6400 }
|
jamie@264
|
6401 TestCase& TestCase::operator = ( TestCase const& other ) {
|
jamie@264
|
6402 TestCase temp( other );
|
jamie@264
|
6403 swap( temp );
|
jamie@264
|
6404 return *this;
|
jamie@264
|
6405 }
|
jamie@264
|
6406
|
jamie@264
|
6407 TestCaseInfo const& TestCase::getTestCaseInfo() const
|
jamie@264
|
6408 {
|
jamie@264
|
6409 return *this;
|
jamie@264
|
6410 }
|
jamie@264
|
6411
|
jamie@264
|
6412 } // end namespace Catch
|
jamie@264
|
6413
|
jamie@264
|
6414 // #included from: catch_version.hpp
|
jamie@264
|
6415 #define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED
|
jamie@264
|
6416
|
jamie@264
|
6417 namespace Catch {
|
jamie@264
|
6418
|
jamie@264
|
6419 // These numbers are maintained by a script
|
jamie@264
|
6420 Version libraryVersion( 1, 0, 53, "master" );
|
jamie@264
|
6421 }
|
jamie@264
|
6422
|
jamie@264
|
6423 // #included from: catch_message.hpp
|
jamie@264
|
6424 #define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED
|
jamie@264
|
6425
|
jamie@264
|
6426 namespace Catch {
|
jamie@264
|
6427
|
jamie@264
|
6428 MessageInfo::MessageInfo( std::string const& _macroName,
|
jamie@264
|
6429 SourceLineInfo const& _lineInfo,
|
jamie@264
|
6430 ResultWas::OfType _type )
|
jamie@264
|
6431 : macroName( _macroName ),
|
jamie@264
|
6432 lineInfo( _lineInfo ),
|
jamie@264
|
6433 type( _type ),
|
jamie@264
|
6434 sequence( ++globalCount )
|
jamie@264
|
6435 {}
|
jamie@264
|
6436
|
jamie@264
|
6437 // This may need protecting if threading support is added
|
jamie@264
|
6438 unsigned int MessageInfo::globalCount = 0;
|
jamie@264
|
6439
|
jamie@264
|
6440 ////////////////////////////////////////////////////////////////////////////
|
jamie@264
|
6441
|
jamie@264
|
6442 ScopedMessage::ScopedMessage( MessageBuilder const& builder )
|
jamie@264
|
6443 : m_info( builder.m_info )
|
jamie@264
|
6444 {
|
jamie@264
|
6445 m_info.message = builder.m_stream.str();
|
jamie@264
|
6446 getResultCapture().pushScopedMessage( m_info );
|
jamie@264
|
6447 }
|
jamie@264
|
6448 ScopedMessage::ScopedMessage( ScopedMessage const& other )
|
jamie@264
|
6449 : m_info( other.m_info )
|
jamie@264
|
6450 {}
|
jamie@264
|
6451
|
jamie@264
|
6452 ScopedMessage::~ScopedMessage() {
|
jamie@264
|
6453 getResultCapture().popScopedMessage( m_info );
|
jamie@264
|
6454 }
|
jamie@264
|
6455
|
jamie@264
|
6456 } // end namespace Catch
|
jamie@264
|
6457
|
jamie@264
|
6458 // #included from: catch_legacy_reporter_adapter.hpp
|
jamie@264
|
6459 #define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED
|
jamie@264
|
6460
|
jamie@264
|
6461 // #included from: catch_legacy_reporter_adapter.h
|
jamie@264
|
6462 #define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED
|
jamie@264
|
6463
|
jamie@264
|
6464 namespace Catch
|
jamie@264
|
6465 {
|
jamie@264
|
6466 // Deprecated
|
jamie@264
|
6467 struct IReporter : IShared {
|
jamie@264
|
6468 virtual ~IReporter();
|
jamie@264
|
6469
|
jamie@264
|
6470 virtual bool shouldRedirectStdout() const = 0;
|
jamie@264
|
6471
|
jamie@264
|
6472 virtual void StartTesting() = 0;
|
jamie@264
|
6473 virtual void EndTesting( Totals const& totals ) = 0;
|
jamie@264
|
6474 virtual void StartGroup( std::string const& groupName ) = 0;
|
jamie@264
|
6475 virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0;
|
jamie@264
|
6476 virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0;
|
jamie@264
|
6477 virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0;
|
jamie@264
|
6478 virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0;
|
jamie@264
|
6479 virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0;
|
jamie@264
|
6480 virtual void NoAssertionsInSection( std::string const& sectionName ) = 0;
|
jamie@264
|
6481 virtual void NoAssertionsInTestCase( std::string const& testName ) = 0;
|
jamie@264
|
6482 virtual void Aborted() = 0;
|
jamie@264
|
6483 virtual void Result( AssertionResult const& result ) = 0;
|
jamie@264
|
6484 };
|
jamie@264
|
6485
|
jamie@264
|
6486 class LegacyReporterAdapter : public SharedImpl<IStreamingReporter>
|
jamie@264
|
6487 {
|
jamie@264
|
6488 public:
|
jamie@264
|
6489 LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter );
|
jamie@264
|
6490 virtual ~LegacyReporterAdapter();
|
jamie@264
|
6491
|
jamie@264
|
6492 virtual ReporterPreferences getPreferences() const;
|
jamie@264
|
6493 virtual void noMatchingTestCases( std::string const& );
|
jamie@264
|
6494 virtual void testRunStarting( TestRunInfo const& );
|
jamie@264
|
6495 virtual void testGroupStarting( GroupInfo const& groupInfo );
|
jamie@264
|
6496 virtual void testCaseStarting( TestCaseInfo const& testInfo );
|
jamie@264
|
6497 virtual void sectionStarting( SectionInfo const& sectionInfo );
|
jamie@264
|
6498 virtual void assertionStarting( AssertionInfo const& );
|
jamie@264
|
6499 virtual bool assertionEnded( AssertionStats const& assertionStats );
|
jamie@264
|
6500 virtual void sectionEnded( SectionStats const& sectionStats );
|
jamie@264
|
6501 virtual void testCaseEnded( TestCaseStats const& testCaseStats );
|
jamie@264
|
6502 virtual void testGroupEnded( TestGroupStats const& testGroupStats );
|
jamie@264
|
6503 virtual void testRunEnded( TestRunStats const& testRunStats );
|
jamie@264
|
6504
|
jamie@264
|
6505 private:
|
jamie@264
|
6506 Ptr<IReporter> m_legacyReporter;
|
jamie@264
|
6507 };
|
jamie@264
|
6508 }
|
jamie@264
|
6509
|
jamie@264
|
6510 namespace Catch
|
jamie@264
|
6511 {
|
jamie@264
|
6512 LegacyReporterAdapter::LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter )
|
jamie@264
|
6513 : m_legacyReporter( legacyReporter )
|
jamie@264
|
6514 {}
|
jamie@264
|
6515 LegacyReporterAdapter::~LegacyReporterAdapter() {}
|
jamie@264
|
6516
|
jamie@264
|
6517 ReporterPreferences LegacyReporterAdapter::getPreferences() const {
|
jamie@264
|
6518 ReporterPreferences prefs;
|
jamie@264
|
6519 prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout();
|
jamie@264
|
6520 return prefs;
|
jamie@264
|
6521 }
|
jamie@264
|
6522
|
jamie@264
|
6523 void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {}
|
jamie@264
|
6524 void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) {
|
jamie@264
|
6525 m_legacyReporter->StartTesting();
|
jamie@264
|
6526 }
|
jamie@264
|
6527 void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) {
|
jamie@264
|
6528 m_legacyReporter->StartGroup( groupInfo.name );
|
jamie@264
|
6529 }
|
jamie@264
|
6530 void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) {
|
jamie@264
|
6531 m_legacyReporter->StartTestCase( testInfo );
|
jamie@264
|
6532 }
|
jamie@264
|
6533 void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) {
|
jamie@264
|
6534 m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description );
|
jamie@264
|
6535 }
|
jamie@264
|
6536 void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) {
|
jamie@264
|
6537 // Not on legacy interface
|
jamie@264
|
6538 }
|
jamie@264
|
6539
|
jamie@264
|
6540 bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) {
|
jamie@264
|
6541 if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) {
|
jamie@264
|
6542 for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end();
|
jamie@264
|
6543 it != itEnd;
|
jamie@264
|
6544 ++it ) {
|
jamie@264
|
6545 if( it->type == ResultWas::Info ) {
|
jamie@264
|
6546 ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal );
|
jamie@264
|
6547 rb << it->message;
|
jamie@264
|
6548 rb.setResultType( ResultWas::Info );
|
jamie@264
|
6549 AssertionResult result = rb.build();
|
jamie@264
|
6550 m_legacyReporter->Result( result );
|
jamie@264
|
6551 }
|
jamie@264
|
6552 }
|
jamie@264
|
6553 }
|
jamie@264
|
6554 m_legacyReporter->Result( assertionStats.assertionResult );
|
jamie@264
|
6555 return true;
|
jamie@264
|
6556 }
|
jamie@264
|
6557 void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) {
|
jamie@264
|
6558 if( sectionStats.missingAssertions )
|
jamie@264
|
6559 m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name );
|
jamie@264
|
6560 m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions );
|
jamie@264
|
6561 }
|
jamie@264
|
6562 void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) {
|
jamie@264
|
6563 m_legacyReporter->EndTestCase
|
jamie@264
|
6564 ( testCaseStats.testInfo,
|
jamie@264
|
6565 testCaseStats.totals,
|
jamie@264
|
6566 testCaseStats.stdOut,
|
jamie@264
|
6567 testCaseStats.stdErr );
|
jamie@264
|
6568 }
|
jamie@264
|
6569 void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) {
|
jamie@264
|
6570 if( testGroupStats.aborting )
|
jamie@264
|
6571 m_legacyReporter->Aborted();
|
jamie@264
|
6572 m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals );
|
jamie@264
|
6573 }
|
jamie@264
|
6574 void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) {
|
jamie@264
|
6575 m_legacyReporter->EndTesting( testRunStats.totals );
|
jamie@264
|
6576 }
|
jamie@264
|
6577 }
|
jamie@264
|
6578
|
jamie@264
|
6579 // #included from: catch_timer.hpp
|
jamie@264
|
6580
|
jamie@264
|
6581 #ifdef __clang__
|
jamie@264
|
6582 #pragma clang diagnostic push
|
jamie@264
|
6583 #pragma clang diagnostic ignored "-Wc++11-long-long"
|
jamie@264
|
6584 #endif
|
jamie@264
|
6585
|
jamie@264
|
6586 #ifdef CATCH_PLATFORM_WINDOWS
|
jamie@264
|
6587 #include <windows.h>
|
jamie@264
|
6588 #else
|
jamie@264
|
6589 #include <sys/time.h>
|
jamie@264
|
6590 #endif
|
jamie@264
|
6591
|
jamie@264
|
6592 namespace Catch {
|
jamie@264
|
6593
|
jamie@264
|
6594 namespace {
|
jamie@264
|
6595 #ifdef CATCH_PLATFORM_WINDOWS
|
jamie@264
|
6596 uint64_t getCurrentTicks() {
|
jamie@264
|
6597 static uint64_t hz=0, hzo=0;
|
jamie@264
|
6598 if (!hz) {
|
jamie@264
|
6599 QueryPerformanceFrequency((LARGE_INTEGER*)&hz);
|
jamie@264
|
6600 QueryPerformanceCounter((LARGE_INTEGER*)&hzo);
|
jamie@264
|
6601 }
|
jamie@264
|
6602 uint64_t t;
|
jamie@264
|
6603 QueryPerformanceCounter((LARGE_INTEGER*)&t);
|
jamie@264
|
6604 return ((t-hzo)*1000000)/hz;
|
jamie@264
|
6605 }
|
jamie@264
|
6606 #else
|
jamie@264
|
6607 uint64_t getCurrentTicks() {
|
jamie@264
|
6608 timeval t;
|
jamie@264
|
6609 gettimeofday(&t,NULL);
|
jamie@264
|
6610 return static_cast<uint64_t>( t.tv_sec ) * 1000000ull + static_cast<uint64_t>( t.tv_usec );
|
jamie@264
|
6611 }
|
jamie@264
|
6612 #endif
|
jamie@264
|
6613 }
|
jamie@264
|
6614
|
jamie@264
|
6615 void Timer::start() {
|
jamie@264
|
6616 m_ticks = getCurrentTicks();
|
jamie@264
|
6617 }
|
jamie@264
|
6618 unsigned int Timer::getElapsedNanoseconds() const {
|
jamie@264
|
6619 return static_cast<unsigned int>(getCurrentTicks() - m_ticks);
|
jamie@264
|
6620 }
|
jamie@264
|
6621 unsigned int Timer::getElapsedMilliseconds() const {
|
jamie@264
|
6622 return static_cast<unsigned int>((getCurrentTicks() - m_ticks)/1000);
|
jamie@264
|
6623 }
|
jamie@264
|
6624 double Timer::getElapsedSeconds() const {
|
jamie@264
|
6625 return (getCurrentTicks() - m_ticks)/1000000.0;
|
jamie@264
|
6626 }
|
jamie@264
|
6627
|
jamie@264
|
6628 } // namespace Catch
|
jamie@264
|
6629
|
jamie@264
|
6630 #ifdef __clang__
|
jamie@264
|
6631 #pragma clang diagnostic pop
|
jamie@264
|
6632 #endif
|
jamie@264
|
6633 // #included from: catch_common.hpp
|
jamie@264
|
6634 #define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED
|
jamie@264
|
6635
|
jamie@264
|
6636 namespace Catch {
|
jamie@264
|
6637
|
jamie@264
|
6638 bool startsWith( std::string const& s, std::string const& prefix ) {
|
jamie@264
|
6639 return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix;
|
jamie@264
|
6640 }
|
jamie@264
|
6641 bool endsWith( std::string const& s, std::string const& suffix ) {
|
jamie@264
|
6642 return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix;
|
jamie@264
|
6643 }
|
jamie@264
|
6644 bool contains( std::string const& s, std::string const& infix ) {
|
jamie@264
|
6645 return s.find( infix ) != std::string::npos;
|
jamie@264
|
6646 }
|
jamie@264
|
6647 void toLowerInPlace( std::string& s ) {
|
jamie@264
|
6648 std::transform( s.begin(), s.end(), s.begin(), ::tolower );
|
jamie@264
|
6649 }
|
jamie@264
|
6650 std::string toLower( std::string const& s ) {
|
jamie@264
|
6651 std::string lc = s;
|
jamie@264
|
6652 toLowerInPlace( lc );
|
jamie@264
|
6653 return lc;
|
jamie@264
|
6654 }
|
jamie@264
|
6655 std::string trim( std::string const& str ) {
|
jamie@264
|
6656 static char const* whitespaceChars = "\n\r\t ";
|
jamie@264
|
6657 std::string::size_type start = str.find_first_not_of( whitespaceChars );
|
jamie@264
|
6658 std::string::size_type end = str.find_last_not_of( whitespaceChars );
|
jamie@264
|
6659
|
jamie@264
|
6660 return start != std::string::npos ? str.substr( start, 1+end-start ) : "";
|
jamie@264
|
6661 }
|
jamie@264
|
6662
|
jamie@264
|
6663 pluralise::pluralise( std::size_t count, std::string const& label )
|
jamie@264
|
6664 : m_count( count ),
|
jamie@264
|
6665 m_label( label )
|
jamie@264
|
6666 {}
|
jamie@264
|
6667
|
jamie@264
|
6668 std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) {
|
jamie@264
|
6669 os << pluraliser.m_count << " " << pluraliser.m_label;
|
jamie@264
|
6670 if( pluraliser.m_count != 1 )
|
jamie@264
|
6671 os << "s";
|
jamie@264
|
6672 return os;
|
jamie@264
|
6673 }
|
jamie@264
|
6674
|
jamie@264
|
6675 SourceLineInfo::SourceLineInfo() : line( 0 ){}
|
jamie@264
|
6676 SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line )
|
jamie@264
|
6677 : file( _file ),
|
jamie@264
|
6678 line( _line )
|
jamie@264
|
6679 {}
|
jamie@264
|
6680 SourceLineInfo::SourceLineInfo( SourceLineInfo const& other )
|
jamie@264
|
6681 : file( other.file ),
|
jamie@264
|
6682 line( other.line )
|
jamie@264
|
6683 {}
|
jamie@264
|
6684 bool SourceLineInfo::empty() const {
|
jamie@264
|
6685 return file.empty();
|
jamie@264
|
6686 }
|
jamie@264
|
6687 bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const {
|
jamie@264
|
6688 return line == other.line && file == other.file;
|
jamie@264
|
6689 }
|
jamie@264
|
6690
|
jamie@264
|
6691 std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
|
jamie@264
|
6692 #ifndef __GNUG__
|
jamie@264
|
6693 os << info.file << "(" << info.line << ")";
|
jamie@264
|
6694 #else
|
jamie@264
|
6695 os << info.file << ":" << info.line;
|
jamie@264
|
6696 #endif
|
jamie@264
|
6697 return os;
|
jamie@264
|
6698 }
|
jamie@264
|
6699
|
jamie@264
|
6700 void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) {
|
jamie@264
|
6701 std::ostringstream oss;
|
jamie@264
|
6702 oss << locationInfo << ": Internal Catch error: '" << message << "'";
|
jamie@264
|
6703 if( alwaysTrue() )
|
jamie@264
|
6704 throw std::logic_error( oss.str() );
|
jamie@264
|
6705 }
|
jamie@264
|
6706 }
|
jamie@264
|
6707
|
jamie@264
|
6708 // #included from: catch_section.hpp
|
jamie@264
|
6709 #define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED
|
jamie@264
|
6710
|
jamie@264
|
6711 namespace Catch {
|
jamie@264
|
6712
|
jamie@264
|
6713 SectionInfo::SectionInfo
|
jamie@264
|
6714 ( SourceLineInfo const& _lineInfo,
|
jamie@264
|
6715 std::string const& _name,
|
jamie@264
|
6716 std::string const& _description )
|
jamie@264
|
6717 : name( _name ),
|
jamie@264
|
6718 description( _description ),
|
jamie@264
|
6719 lineInfo( _lineInfo )
|
jamie@264
|
6720 {}
|
jamie@264
|
6721
|
jamie@264
|
6722 Section::Section( SectionInfo const& info )
|
jamie@264
|
6723 : m_info( info ),
|
jamie@264
|
6724 m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) )
|
jamie@264
|
6725 {
|
jamie@264
|
6726 m_timer.start();
|
jamie@264
|
6727 }
|
jamie@264
|
6728
|
jamie@264
|
6729 Section::~Section() {
|
jamie@264
|
6730 if( m_sectionIncluded )
|
jamie@264
|
6731 getResultCapture().sectionEnded( m_info, m_assertions, m_timer.getElapsedSeconds() );
|
jamie@264
|
6732 }
|
jamie@264
|
6733
|
jamie@264
|
6734 // This indicates whether the section should be executed or not
|
jamie@264
|
6735 Section::operator bool() const {
|
jamie@264
|
6736 return m_sectionIncluded;
|
jamie@264
|
6737 }
|
jamie@264
|
6738
|
jamie@264
|
6739 } // end namespace Catch
|
jamie@264
|
6740
|
jamie@264
|
6741 // #included from: catch_debugger.hpp
|
jamie@264
|
6742 #define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED
|
jamie@264
|
6743
|
jamie@264
|
6744 #include <iostream>
|
jamie@264
|
6745
|
jamie@264
|
6746 #ifdef CATCH_PLATFORM_MAC
|
jamie@264
|
6747
|
jamie@264
|
6748 #include <assert.h>
|
jamie@264
|
6749 #include <stdbool.h>
|
jamie@264
|
6750 #include <sys/types.h>
|
jamie@264
|
6751 #include <unistd.h>
|
jamie@264
|
6752 #include <sys/sysctl.h>
|
jamie@264
|
6753
|
jamie@264
|
6754 namespace Catch{
|
jamie@264
|
6755
|
jamie@264
|
6756 // The following function is taken directly from the following technical note:
|
jamie@264
|
6757 // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html
|
jamie@264
|
6758
|
jamie@264
|
6759 // Returns true if the current process is being debugged (either
|
jamie@264
|
6760 // running under the debugger or has a debugger attached post facto).
|
jamie@264
|
6761 bool isDebuggerActive(){
|
jamie@264
|
6762
|
jamie@264
|
6763 int mib[4];
|
jamie@264
|
6764 struct kinfo_proc info;
|
jamie@264
|
6765 size_t size;
|
jamie@264
|
6766
|
jamie@264
|
6767 // Initialize the flags so that, if sysctl fails for some bizarre
|
jamie@264
|
6768 // reason, we get a predictable result.
|
jamie@264
|
6769
|
jamie@264
|
6770 info.kp_proc.p_flag = 0;
|
jamie@264
|
6771
|
jamie@264
|
6772 // Initialize mib, which tells sysctl the info we want, in this case
|
jamie@264
|
6773 // we're looking for information about a specific process ID.
|
jamie@264
|
6774
|
jamie@264
|
6775 mib[0] = CTL_KERN;
|
jamie@264
|
6776 mib[1] = KERN_PROC;
|
jamie@264
|
6777 mib[2] = KERN_PROC_PID;
|
jamie@264
|
6778 mib[3] = getpid();
|
jamie@264
|
6779
|
jamie@264
|
6780 // Call sysctl.
|
jamie@264
|
6781
|
jamie@264
|
6782 size = sizeof(info);
|
jamie@264
|
6783 if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0) != 0 ) {
|
jamie@264
|
6784 std::cerr << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl;
|
jamie@264
|
6785 return false;
|
jamie@264
|
6786 }
|
jamie@264
|
6787
|
jamie@264
|
6788 // We're being debugged if the P_TRACED flag is set.
|
jamie@264
|
6789
|
jamie@264
|
6790 return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
|
jamie@264
|
6791 }
|
jamie@264
|
6792 } // namespace Catch
|
jamie@264
|
6793
|
jamie@264
|
6794 #elif defined(_MSC_VER)
|
jamie@264
|
6795 extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
|
jamie@264
|
6796 namespace Catch {
|
jamie@264
|
6797 bool isDebuggerActive() {
|
jamie@264
|
6798 return IsDebuggerPresent() != 0;
|
jamie@264
|
6799 }
|
jamie@264
|
6800 }
|
jamie@264
|
6801 #elif defined(__MINGW32__)
|
jamie@264
|
6802 extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
|
jamie@264
|
6803 namespace Catch {
|
jamie@264
|
6804 bool isDebuggerActive() {
|
jamie@264
|
6805 return IsDebuggerPresent() != 0;
|
jamie@264
|
6806 }
|
jamie@264
|
6807 }
|
jamie@264
|
6808 #else
|
jamie@264
|
6809 namespace Catch {
|
jamie@264
|
6810 inline bool isDebuggerActive() { return false; }
|
jamie@264
|
6811 }
|
jamie@264
|
6812 #endif // Platform
|
jamie@264
|
6813
|
jamie@264
|
6814 #ifdef CATCH_PLATFORM_WINDOWS
|
jamie@264
|
6815 extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* );
|
jamie@264
|
6816 namespace Catch {
|
jamie@264
|
6817 void writeToDebugConsole( std::string const& text ) {
|
jamie@264
|
6818 ::OutputDebugStringA( text.c_str() );
|
jamie@264
|
6819 }
|
jamie@264
|
6820 }
|
jamie@264
|
6821 #else
|
jamie@264
|
6822 namespace Catch {
|
jamie@264
|
6823 void writeToDebugConsole( std::string const& text ) {
|
jamie@264
|
6824 // !TBD: Need a version for Mac/ XCode and other IDEs
|
jamie@264
|
6825 std::cout << text;
|
jamie@264
|
6826 }
|
jamie@264
|
6827 }
|
jamie@264
|
6828 #endif // Platform
|
jamie@264
|
6829
|
jamie@264
|
6830 // #included from: catch_tostring.hpp
|
jamie@264
|
6831 #define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED
|
jamie@264
|
6832
|
jamie@264
|
6833 namespace Catch {
|
jamie@264
|
6834
|
jamie@264
|
6835 namespace Detail {
|
jamie@264
|
6836
|
jamie@264
|
6837 namespace {
|
jamie@264
|
6838 struct Endianness {
|
jamie@264
|
6839 enum Arch { Big, Little };
|
jamie@264
|
6840
|
jamie@264
|
6841 static Arch which() {
|
jamie@264
|
6842 union _{
|
jamie@264
|
6843 int asInt;
|
jamie@264
|
6844 char asChar[sizeof (int)];
|
jamie@264
|
6845 } u;
|
jamie@264
|
6846
|
jamie@264
|
6847 u.asInt = 1;
|
jamie@264
|
6848 return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little;
|
jamie@264
|
6849 }
|
jamie@264
|
6850 };
|
jamie@264
|
6851 }
|
jamie@264
|
6852
|
jamie@264
|
6853 std::string rawMemoryToString( const void *object, std::size_t size )
|
jamie@264
|
6854 {
|
jamie@264
|
6855 // Reverse order for little endian architectures
|
jamie@264
|
6856 int i = 0, end = static_cast<int>( size ), inc = 1;
|
jamie@264
|
6857 if( Endianness::which() == Endianness::Little ) {
|
jamie@264
|
6858 i = end-1;
|
jamie@264
|
6859 end = inc = -1;
|
jamie@264
|
6860 }
|
jamie@264
|
6861
|
jamie@264
|
6862 unsigned char const *bytes = static_cast<unsigned char const *>(object);
|
jamie@264
|
6863 std::ostringstream os;
|
jamie@264
|
6864 os << "0x" << std::setfill('0') << std::hex;
|
jamie@264
|
6865 for( ; i != end; i += inc )
|
jamie@264
|
6866 os << std::setw(2) << static_cast<unsigned>(bytes[i]);
|
jamie@264
|
6867 return os.str();
|
jamie@264
|
6868 }
|
jamie@264
|
6869 }
|
jamie@264
|
6870
|
jamie@264
|
6871 std::string toString( std::string const& value ) {
|
jamie@264
|
6872 std::string s = value;
|
jamie@264
|
6873 if( getCurrentContext().getConfig()->showInvisibles() ) {
|
jamie@264
|
6874 for(size_t i = 0; i < s.size(); ++i ) {
|
jamie@264
|
6875 std::string subs;
|
jamie@264
|
6876 switch( s[i] ) {
|
jamie@264
|
6877 case '\n': subs = "\\n"; break;
|
jamie@264
|
6878 case '\t': subs = "\\t"; break;
|
jamie@264
|
6879 default: break;
|
jamie@264
|
6880 }
|
jamie@264
|
6881 if( !subs.empty() ) {
|
jamie@264
|
6882 s = s.substr( 0, i ) + subs + s.substr( i+1 );
|
jamie@264
|
6883 ++i;
|
jamie@264
|
6884 }
|
jamie@264
|
6885 }
|
jamie@264
|
6886 }
|
jamie@264
|
6887 return "\"" + s + "\"";
|
jamie@264
|
6888 }
|
jamie@264
|
6889 std::string toString( std::wstring const& value ) {
|
jamie@264
|
6890
|
jamie@264
|
6891 std::string s;
|
jamie@264
|
6892 s.reserve( value.size() );
|
jamie@264
|
6893 for(size_t i = 0; i < value.size(); ++i )
|
jamie@264
|
6894 s += value[i] <= 0xff ? static_cast<char>( value[i] ) : '?';
|
jamie@264
|
6895 return toString( s );
|
jamie@264
|
6896 }
|
jamie@264
|
6897
|
jamie@264
|
6898 std::string toString( const char* const value ) {
|
jamie@264
|
6899 return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" );
|
jamie@264
|
6900 }
|
jamie@264
|
6901
|
jamie@264
|
6902 std::string toString( char* const value ) {
|
jamie@264
|
6903 return Catch::toString( static_cast<const char*>( value ) );
|
jamie@264
|
6904 }
|
jamie@264
|
6905
|
jamie@264
|
6906 std::string toString( const wchar_t* const value )
|
jamie@264
|
6907 {
|
jamie@264
|
6908 return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" );
|
jamie@264
|
6909 }
|
jamie@264
|
6910
|
jamie@264
|
6911 std::string toString( wchar_t* const value )
|
jamie@264
|
6912 {
|
jamie@264
|
6913 return Catch::toString( static_cast<const wchar_t*>( value ) );
|
jamie@264
|
6914 }
|
jamie@264
|
6915
|
jamie@264
|
6916 std::string toString( int value ) {
|
jamie@264
|
6917 std::ostringstream oss;
|
jamie@264
|
6918 oss << value;
|
jamie@264
|
6919 return oss.str();
|
jamie@264
|
6920 }
|
jamie@264
|
6921
|
jamie@264
|
6922 std::string toString( unsigned long value ) {
|
jamie@264
|
6923 std::ostringstream oss;
|
jamie@264
|
6924 if( value > 8192 )
|
jamie@264
|
6925 oss << "0x" << std::hex << value;
|
jamie@264
|
6926 else
|
jamie@264
|
6927 oss << value;
|
jamie@264
|
6928 return oss.str();
|
jamie@264
|
6929 }
|
jamie@264
|
6930
|
jamie@264
|
6931 std::string toString( unsigned int value ) {
|
jamie@264
|
6932 return toString( static_cast<unsigned long>( value ) );
|
jamie@264
|
6933 }
|
jamie@264
|
6934
|
jamie@264
|
6935 template<typename T>
|
jamie@264
|
6936 std::string fpToString( T value, int precision ) {
|
jamie@264
|
6937 std::ostringstream oss;
|
jamie@264
|
6938 oss << std::setprecision( precision )
|
jamie@264
|
6939 << std::fixed
|
jamie@264
|
6940 << value;
|
jamie@264
|
6941 std::string d = oss.str();
|
jamie@264
|
6942 std::size_t i = d.find_last_not_of( '0' );
|
jamie@264
|
6943 if( i != std::string::npos && i != d.size()-1 ) {
|
jamie@264
|
6944 if( d[i] == '.' )
|
jamie@264
|
6945 i++;
|
jamie@264
|
6946 d = d.substr( 0, i+1 );
|
jamie@264
|
6947 }
|
jamie@264
|
6948 return d;
|
jamie@264
|
6949 }
|
jamie@264
|
6950
|
jamie@264
|
6951 std::string toString( const double value ) {
|
jamie@264
|
6952 return fpToString( value, 10 );
|
jamie@264
|
6953 }
|
jamie@264
|
6954 std::string toString( const float value ) {
|
jamie@264
|
6955 return fpToString( value, 5 ) + "f";
|
jamie@264
|
6956 }
|
jamie@264
|
6957
|
jamie@264
|
6958 std::string toString( bool value ) {
|
jamie@264
|
6959 return value ? "true" : "false";
|
jamie@264
|
6960 }
|
jamie@264
|
6961
|
jamie@264
|
6962 std::string toString( char value ) {
|
jamie@264
|
6963 return value < ' '
|
jamie@264
|
6964 ? toString( static_cast<unsigned int>( value ) )
|
jamie@264
|
6965 : Detail::makeString( value );
|
jamie@264
|
6966 }
|
jamie@264
|
6967
|
jamie@264
|
6968 std::string toString( signed char value ) {
|
jamie@264
|
6969 return toString( static_cast<char>( value ) );
|
jamie@264
|
6970 }
|
jamie@264
|
6971
|
jamie@264
|
6972 std::string toString( unsigned char value ) {
|
jamie@264
|
6973 return toString( static_cast<char>( value ) );
|
jamie@264
|
6974 }
|
jamie@264
|
6975
|
jamie@264
|
6976 #ifdef CATCH_CONFIG_CPP11_NULLPTR
|
jamie@264
|
6977 std::string toString( std::nullptr_t ) {
|
jamie@264
|
6978 return "nullptr";
|
jamie@264
|
6979 }
|
jamie@264
|
6980 #endif
|
jamie@264
|
6981
|
jamie@264
|
6982 #ifdef __OBJC__
|
jamie@264
|
6983 std::string toString( NSString const * const& nsstring ) {
|
jamie@264
|
6984 if( !nsstring )
|
jamie@264
|
6985 return "nil";
|
jamie@264
|
6986 return "@" + toString([nsstring UTF8String]);
|
jamie@264
|
6987 }
|
jamie@264
|
6988 std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) {
|
jamie@264
|
6989 if( !nsstring )
|
jamie@264
|
6990 return "nil";
|
jamie@264
|
6991 return "@" + toString([nsstring UTF8String]);
|
jamie@264
|
6992 }
|
jamie@264
|
6993 std::string toString( NSObject* const& nsObject ) {
|
jamie@264
|
6994 return toString( [nsObject description] );
|
jamie@264
|
6995 }
|
jamie@264
|
6996 #endif
|
jamie@264
|
6997
|
jamie@264
|
6998 } // end namespace Catch
|
jamie@264
|
6999
|
jamie@264
|
7000 // #included from: catch_result_builder.hpp
|
jamie@264
|
7001 #define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED
|
jamie@264
|
7002
|
jamie@264
|
7003 namespace Catch {
|
jamie@264
|
7004
|
jamie@264
|
7005 ResultBuilder::ResultBuilder( char const* macroName,
|
jamie@264
|
7006 SourceLineInfo const& lineInfo,
|
jamie@264
|
7007 char const* capturedExpression,
|
jamie@264
|
7008 ResultDisposition::Flags resultDisposition )
|
jamie@264
|
7009 : m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition ),
|
jamie@264
|
7010 m_shouldDebugBreak( false ),
|
jamie@264
|
7011 m_shouldThrow( false )
|
jamie@264
|
7012 {}
|
jamie@264
|
7013
|
jamie@264
|
7014 ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) {
|
jamie@264
|
7015 m_data.resultType = result;
|
jamie@264
|
7016 return *this;
|
jamie@264
|
7017 }
|
jamie@264
|
7018 ResultBuilder& ResultBuilder::setResultType( bool result ) {
|
jamie@264
|
7019 m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed;
|
jamie@264
|
7020 return *this;
|
jamie@264
|
7021 }
|
jamie@264
|
7022 ResultBuilder& ResultBuilder::setLhs( std::string const& lhs ) {
|
jamie@264
|
7023 m_exprComponents.lhs = lhs;
|
jamie@264
|
7024 return *this;
|
jamie@264
|
7025 }
|
jamie@264
|
7026 ResultBuilder& ResultBuilder::setRhs( std::string const& rhs ) {
|
jamie@264
|
7027 m_exprComponents.rhs = rhs;
|
jamie@264
|
7028 return *this;
|
jamie@264
|
7029 }
|
jamie@264
|
7030 ResultBuilder& ResultBuilder::setOp( std::string const& op ) {
|
jamie@264
|
7031 m_exprComponents.op = op;
|
jamie@264
|
7032 return *this;
|
jamie@264
|
7033 }
|
jamie@264
|
7034
|
jamie@264
|
7035 void ResultBuilder::endExpression() {
|
jamie@264
|
7036 m_exprComponents.testFalse = isFalseTest( m_assertionInfo.resultDisposition );
|
jamie@264
|
7037 captureExpression();
|
jamie@264
|
7038 }
|
jamie@264
|
7039
|
jamie@264
|
7040 void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) {
|
jamie@264
|
7041 m_assertionInfo.resultDisposition = resultDisposition;
|
jamie@264
|
7042 m_stream.oss << Catch::translateActiveException();
|
jamie@264
|
7043 captureResult( ResultWas::ThrewException );
|
jamie@264
|
7044 }
|
jamie@264
|
7045
|
jamie@264
|
7046 void ResultBuilder::captureResult( ResultWas::OfType resultType ) {
|
jamie@264
|
7047 setResultType( resultType );
|
jamie@264
|
7048 captureExpression();
|
jamie@264
|
7049 }
|
jamie@264
|
7050
|
jamie@264
|
7051 void ResultBuilder::captureExpression() {
|
jamie@264
|
7052 AssertionResult result = build();
|
jamie@264
|
7053 getResultCapture().assertionEnded( result );
|
jamie@264
|
7054
|
jamie@264
|
7055 if( !result.isOk() ) {
|
jamie@264
|
7056 if( getCurrentContext().getConfig()->shouldDebugBreak() )
|
jamie@264
|
7057 m_shouldDebugBreak = true;
|
jamie@264
|
7058 if( getCurrentContext().getRunner()->aborting() || m_assertionInfo.resultDisposition == ResultDisposition::Normal )
|
jamie@264
|
7059 m_shouldThrow = true;
|
jamie@264
|
7060 }
|
jamie@264
|
7061 }
|
jamie@264
|
7062 void ResultBuilder::react() {
|
jamie@264
|
7063 if( m_shouldThrow )
|
jamie@264
|
7064 throw Catch::TestFailureException();
|
jamie@264
|
7065 }
|
jamie@264
|
7066
|
jamie@264
|
7067 bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; }
|
jamie@264
|
7068 bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); }
|
jamie@264
|
7069
|
jamie@264
|
7070 AssertionResult ResultBuilder::build() const
|
jamie@264
|
7071 {
|
jamie@264
|
7072 assert( m_data.resultType != ResultWas::Unknown );
|
jamie@264
|
7073
|
jamie@264
|
7074 AssertionResultData data = m_data;
|
jamie@264
|
7075
|
jamie@264
|
7076 // Flip bool results if testFalse is set
|
jamie@264
|
7077 if( m_exprComponents.testFalse ) {
|
jamie@264
|
7078 if( data.resultType == ResultWas::Ok )
|
jamie@264
|
7079 data.resultType = ResultWas::ExpressionFailed;
|
jamie@264
|
7080 else if( data.resultType == ResultWas::ExpressionFailed )
|
jamie@264
|
7081 data.resultType = ResultWas::Ok;
|
jamie@264
|
7082 }
|
jamie@264
|
7083
|
jamie@264
|
7084 data.message = m_stream.oss.str();
|
jamie@264
|
7085 data.reconstructedExpression = reconstructExpression();
|
jamie@264
|
7086 if( m_exprComponents.testFalse ) {
|
jamie@264
|
7087 if( m_exprComponents.op == "" )
|
jamie@264
|
7088 data.reconstructedExpression = "!" + data.reconstructedExpression;
|
jamie@264
|
7089 else
|
jamie@264
|
7090 data.reconstructedExpression = "!(" + data.reconstructedExpression + ")";
|
jamie@264
|
7091 }
|
jamie@264
|
7092 return AssertionResult( m_assertionInfo, data );
|
jamie@264
|
7093 }
|
jamie@264
|
7094 std::string ResultBuilder::reconstructExpression() const {
|
jamie@264
|
7095 if( m_exprComponents.op == "" )
|
jamie@264
|
7096 return m_exprComponents.lhs.empty() ? m_assertionInfo.capturedExpression : m_exprComponents.op + m_exprComponents.lhs;
|
jamie@264
|
7097 else if( m_exprComponents.op == "matches" )
|
jamie@264
|
7098 return m_exprComponents.lhs + " " + m_exprComponents.rhs;
|
jamie@264
|
7099 else if( m_exprComponents.op != "!" ) {
|
jamie@264
|
7100 if( m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 &&
|
jamie@264
|
7101 m_exprComponents.lhs.find("\n") == std::string::npos &&
|
jamie@264
|
7102 m_exprComponents.rhs.find("\n") == std::string::npos )
|
jamie@264
|
7103 return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs;
|
jamie@264
|
7104 else
|
jamie@264
|
7105 return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs;
|
jamie@264
|
7106 }
|
jamie@264
|
7107 else
|
jamie@264
|
7108 return "{can't expand - use " + m_assertionInfo.macroName + "_FALSE( " + m_assertionInfo.capturedExpression.substr(1) + " ) instead of " + m_assertionInfo.macroName + "( " + m_assertionInfo.capturedExpression + " ) for better diagnostics}";
|
jamie@264
|
7109 }
|
jamie@264
|
7110
|
jamie@264
|
7111 } // end namespace Catch
|
jamie@264
|
7112
|
jamie@264
|
7113 // #included from: catch_tag_alias_registry.hpp
|
jamie@264
|
7114 #define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED
|
jamie@264
|
7115
|
jamie@264
|
7116 // #included from: catch_tag_alias_registry.h
|
jamie@264
|
7117 #define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED
|
jamie@264
|
7118
|
jamie@264
|
7119 #include <map>
|
jamie@264
|
7120
|
jamie@264
|
7121 namespace Catch {
|
jamie@264
|
7122
|
jamie@264
|
7123 class TagAliasRegistry : public ITagAliasRegistry {
|
jamie@264
|
7124 public:
|
jamie@264
|
7125 virtual ~TagAliasRegistry();
|
jamie@264
|
7126 virtual Option<TagAlias> find( std::string const& alias ) const;
|
jamie@264
|
7127 virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const;
|
jamie@264
|
7128 void add( char const* alias, char const* tag, SourceLineInfo const& lineInfo );
|
jamie@264
|
7129 static TagAliasRegistry& get();
|
jamie@264
|
7130
|
jamie@264
|
7131 private:
|
jamie@264
|
7132 std::map<std::string, TagAlias> m_registry;
|
jamie@264
|
7133 };
|
jamie@264
|
7134
|
jamie@264
|
7135 } // end namespace Catch
|
jamie@264
|
7136
|
jamie@264
|
7137 #include <map>
|
jamie@264
|
7138 #include <iostream>
|
jamie@264
|
7139
|
jamie@264
|
7140 namespace Catch {
|
jamie@264
|
7141
|
jamie@264
|
7142 TagAliasRegistry::~TagAliasRegistry() {}
|
jamie@264
|
7143
|
jamie@264
|
7144 Option<TagAlias> TagAliasRegistry::find( std::string const& alias ) const {
|
jamie@264
|
7145 std::map<std::string, TagAlias>::const_iterator it = m_registry.find( alias );
|
jamie@264
|
7146 if( it != m_registry.end() )
|
jamie@264
|
7147 return it->second;
|
jamie@264
|
7148 else
|
jamie@264
|
7149 return Option<TagAlias>();
|
jamie@264
|
7150 }
|
jamie@264
|
7151
|
jamie@264
|
7152 std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const {
|
jamie@264
|
7153 std::string expandedTestSpec = unexpandedTestSpec;
|
jamie@264
|
7154 for( std::map<std::string, TagAlias>::const_iterator it = m_registry.begin(), itEnd = m_registry.end();
|
jamie@264
|
7155 it != itEnd;
|
jamie@264
|
7156 ++it ) {
|
jamie@264
|
7157 std::size_t pos = expandedTestSpec.find( it->first );
|
jamie@264
|
7158 if( pos != std::string::npos ) {
|
jamie@264
|
7159 expandedTestSpec = expandedTestSpec.substr( 0, pos ) +
|
jamie@264
|
7160 it->second.tag +
|
jamie@264
|
7161 expandedTestSpec.substr( pos + it->first.size() );
|
jamie@264
|
7162 }
|
jamie@264
|
7163 }
|
jamie@264
|
7164 return expandedTestSpec;
|
jamie@264
|
7165 }
|
jamie@264
|
7166
|
jamie@264
|
7167 void TagAliasRegistry::add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) {
|
jamie@264
|
7168
|
jamie@264
|
7169 if( !startsWith( alias, "[@" ) || !endsWith( alias, "]" ) ) {
|
jamie@264
|
7170 std::ostringstream oss;
|
jamie@264
|
7171 oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << lineInfo;
|
jamie@264
|
7172 throw std::domain_error( oss.str().c_str() );
|
jamie@264
|
7173 }
|
jamie@264
|
7174 if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) {
|
jamie@264
|
7175 std::ostringstream oss;
|
jamie@264
|
7176 oss << "error: tag alias, \"" << alias << "\" already registered.\n"
|
jamie@264
|
7177 << "\tFirst seen at " << find(alias)->lineInfo << "\n"
|
jamie@264
|
7178 << "\tRedefined at " << lineInfo;
|
jamie@264
|
7179 throw std::domain_error( oss.str().c_str() );
|
jamie@264
|
7180 }
|
jamie@264
|
7181 }
|
jamie@264
|
7182
|
jamie@264
|
7183 TagAliasRegistry& TagAliasRegistry::get() {
|
jamie@264
|
7184 static TagAliasRegistry instance;
|
jamie@264
|
7185 return instance;
|
jamie@264
|
7186
|
jamie@264
|
7187 }
|
jamie@264
|
7188
|
jamie@264
|
7189 ITagAliasRegistry::~ITagAliasRegistry() {}
|
jamie@264
|
7190 ITagAliasRegistry const& ITagAliasRegistry::get() { return TagAliasRegistry::get(); }
|
jamie@264
|
7191
|
jamie@264
|
7192 RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) {
|
jamie@264
|
7193 try {
|
jamie@264
|
7194 TagAliasRegistry::get().add( alias, tag, lineInfo );
|
jamie@264
|
7195 }
|
jamie@264
|
7196 catch( std::exception& ex ) {
|
jamie@264
|
7197 Colour colourGuard( Colour::Red );
|
jamie@264
|
7198 std::cerr << ex.what() << std::endl;
|
jamie@264
|
7199 exit(1);
|
jamie@264
|
7200 }
|
jamie@264
|
7201 }
|
jamie@264
|
7202
|
jamie@264
|
7203 } // end namespace Catch
|
jamie@264
|
7204
|
jamie@264
|
7205 // #included from: ../reporters/catch_reporter_xml.hpp
|
jamie@264
|
7206 #define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED
|
jamie@264
|
7207
|
jamie@264
|
7208 // #included from: catch_reporter_bases.hpp
|
jamie@264
|
7209 #define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED
|
jamie@264
|
7210
|
jamie@264
|
7211 namespace Catch {
|
jamie@264
|
7212
|
jamie@264
|
7213 struct StreamingReporterBase : SharedImpl<IStreamingReporter> {
|
jamie@264
|
7214
|
jamie@264
|
7215 StreamingReporterBase( ReporterConfig const& _config )
|
jamie@264
|
7216 : m_config( _config.fullConfig() ),
|
jamie@264
|
7217 stream( _config.stream() )
|
jamie@264
|
7218 {}
|
jamie@264
|
7219
|
jamie@264
|
7220 virtual ~StreamingReporterBase();
|
jamie@264
|
7221
|
jamie@264
|
7222 virtual void noMatchingTestCases( std::string const& ) {}
|
jamie@264
|
7223
|
jamie@264
|
7224 virtual void testRunStarting( TestRunInfo const& _testRunInfo ) {
|
jamie@264
|
7225 currentTestRunInfo = _testRunInfo;
|
jamie@264
|
7226 }
|
jamie@264
|
7227 virtual void testGroupStarting( GroupInfo const& _groupInfo ) {
|
jamie@264
|
7228 currentGroupInfo = _groupInfo;
|
jamie@264
|
7229 }
|
jamie@264
|
7230
|
jamie@264
|
7231 virtual void testCaseStarting( TestCaseInfo const& _testInfo ) {
|
jamie@264
|
7232 currentTestCaseInfo = _testInfo;
|
jamie@264
|
7233 }
|
jamie@264
|
7234 virtual void sectionStarting( SectionInfo const& _sectionInfo ) {
|
jamie@264
|
7235 m_sectionStack.push_back( _sectionInfo );
|
jamie@264
|
7236 }
|
jamie@264
|
7237
|
jamie@264
|
7238 virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) {
|
jamie@264
|
7239 m_sectionStack.pop_back();
|
jamie@264
|
7240 }
|
jamie@264
|
7241 virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) {
|
jamie@264
|
7242 currentTestCaseInfo.reset();
|
jamie@264
|
7243 assert( m_sectionStack.empty() );
|
jamie@264
|
7244 }
|
jamie@264
|
7245 virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) {
|
jamie@264
|
7246 currentGroupInfo.reset();
|
jamie@264
|
7247 }
|
jamie@264
|
7248 virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) {
|
jamie@264
|
7249 currentTestCaseInfo.reset();
|
jamie@264
|
7250 currentGroupInfo.reset();
|
jamie@264
|
7251 currentTestRunInfo.reset();
|
jamie@264
|
7252 }
|
jamie@264
|
7253
|
jamie@264
|
7254 Ptr<IConfig> m_config;
|
jamie@264
|
7255 std::ostream& stream;
|
jamie@264
|
7256
|
jamie@264
|
7257 LazyStat<TestRunInfo> currentTestRunInfo;
|
jamie@264
|
7258 LazyStat<GroupInfo> currentGroupInfo;
|
jamie@264
|
7259 LazyStat<TestCaseInfo> currentTestCaseInfo;
|
jamie@264
|
7260
|
jamie@264
|
7261 std::vector<SectionInfo> m_sectionStack;
|
jamie@264
|
7262 };
|
jamie@264
|
7263
|
jamie@264
|
7264 struct CumulativeReporterBase : SharedImpl<IStreamingReporter> {
|
jamie@264
|
7265 template<typename T, typename ChildNodeT>
|
jamie@264
|
7266 struct Node : SharedImpl<> {
|
jamie@264
|
7267 explicit Node( T const& _value ) : value( _value ) {}
|
jamie@264
|
7268 virtual ~Node() {}
|
jamie@264
|
7269
|
jamie@264
|
7270 typedef std::vector<Ptr<ChildNodeT> > ChildNodes;
|
jamie@264
|
7271 T value;
|
jamie@264
|
7272 ChildNodes children;
|
jamie@264
|
7273 };
|
jamie@264
|
7274 struct SectionNode : SharedImpl<> {
|
jamie@264
|
7275 explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {}
|
jamie@264
|
7276 virtual ~SectionNode();
|
jamie@264
|
7277
|
jamie@264
|
7278 bool operator == ( SectionNode const& other ) const {
|
jamie@264
|
7279 return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo;
|
jamie@264
|
7280 }
|
jamie@264
|
7281 bool operator == ( Ptr<SectionNode> const& other ) const {
|
jamie@264
|
7282 return operator==( *other );
|
jamie@264
|
7283 }
|
jamie@264
|
7284
|
jamie@264
|
7285 SectionStats stats;
|
jamie@264
|
7286 typedef std::vector<Ptr<SectionNode> > ChildSections;
|
jamie@264
|
7287 typedef std::vector<AssertionStats> Assertions;
|
jamie@264
|
7288 ChildSections childSections;
|
jamie@264
|
7289 Assertions assertions;
|
jamie@264
|
7290 std::string stdOut;
|
jamie@264
|
7291 std::string stdErr;
|
jamie@264
|
7292 };
|
jamie@264
|
7293
|
jamie@264
|
7294 struct BySectionInfo {
|
jamie@264
|
7295 BySectionInfo( SectionInfo const& other ) : m_other( other ) {}
|
jamie@264
|
7296 BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {}
|
jamie@264
|
7297 bool operator() ( Ptr<SectionNode> const& node ) const {
|
jamie@264
|
7298 return node->stats.sectionInfo.lineInfo == m_other.lineInfo;
|
jamie@264
|
7299 }
|
jamie@264
|
7300 private:
|
jamie@264
|
7301 void operator=( BySectionInfo const& );
|
jamie@264
|
7302 SectionInfo const& m_other;
|
jamie@264
|
7303 };
|
jamie@264
|
7304
|
jamie@264
|
7305 typedef Node<TestCaseStats, SectionNode> TestCaseNode;
|
jamie@264
|
7306 typedef Node<TestGroupStats, TestCaseNode> TestGroupNode;
|
jamie@264
|
7307 typedef Node<TestRunStats, TestGroupNode> TestRunNode;
|
jamie@264
|
7308
|
jamie@264
|
7309 CumulativeReporterBase( ReporterConfig const& _config )
|
jamie@264
|
7310 : m_config( _config.fullConfig() ),
|
jamie@264
|
7311 stream( _config.stream() )
|
jamie@264
|
7312 {}
|
jamie@264
|
7313 ~CumulativeReporterBase();
|
jamie@264
|
7314
|
jamie@264
|
7315 virtual void testRunStarting( TestRunInfo const& ) {}
|
jamie@264
|
7316 virtual void testGroupStarting( GroupInfo const& ) {}
|
jamie@264
|
7317
|
jamie@264
|
7318 virtual void testCaseStarting( TestCaseInfo const& ) {}
|
jamie@264
|
7319
|
jamie@264
|
7320 virtual void sectionStarting( SectionInfo const& sectionInfo ) {
|
jamie@264
|
7321 SectionStats incompleteStats( sectionInfo, Counts(), 0, false );
|
jamie@264
|
7322 Ptr<SectionNode> node;
|
jamie@264
|
7323 if( m_sectionStack.empty() ) {
|
jamie@264
|
7324 if( !m_rootSection )
|
jamie@264
|
7325 m_rootSection = new SectionNode( incompleteStats );
|
jamie@264
|
7326 node = m_rootSection;
|
jamie@264
|
7327 }
|
jamie@264
|
7328 else {
|
jamie@264
|
7329 SectionNode& parentNode = *m_sectionStack.back();
|
jamie@264
|
7330 SectionNode::ChildSections::const_iterator it =
|
jamie@264
|
7331 std::find_if( parentNode.childSections.begin(),
|
jamie@264
|
7332 parentNode.childSections.end(),
|
jamie@264
|
7333 BySectionInfo( sectionInfo ) );
|
jamie@264
|
7334 if( it == parentNode.childSections.end() ) {
|
jamie@264
|
7335 node = new SectionNode( incompleteStats );
|
jamie@264
|
7336 parentNode.childSections.push_back( node );
|
jamie@264
|
7337 }
|
jamie@264
|
7338 else
|
jamie@264
|
7339 node = *it;
|
jamie@264
|
7340 }
|
jamie@264
|
7341 m_sectionStack.push_back( node );
|
jamie@264
|
7342 m_deepestSection = node;
|
jamie@264
|
7343 }
|
jamie@264
|
7344
|
jamie@264
|
7345 virtual void assertionStarting( AssertionInfo const& ) {}
|
jamie@264
|
7346
|
jamie@264
|
7347 virtual bool assertionEnded( AssertionStats const& assertionStats ) {
|
jamie@264
|
7348 assert( !m_sectionStack.empty() );
|
jamie@264
|
7349 SectionNode& sectionNode = *m_sectionStack.back();
|
jamie@264
|
7350 sectionNode.assertions.push_back( assertionStats );
|
jamie@264
|
7351 return true;
|
jamie@264
|
7352 }
|
jamie@264
|
7353 virtual void sectionEnded( SectionStats const& sectionStats ) {
|
jamie@264
|
7354 assert( !m_sectionStack.empty() );
|
jamie@264
|
7355 SectionNode& node = *m_sectionStack.back();
|
jamie@264
|
7356 node.stats = sectionStats;
|
jamie@264
|
7357 m_sectionStack.pop_back();
|
jamie@264
|
7358 }
|
jamie@264
|
7359 virtual void testCaseEnded( TestCaseStats const& testCaseStats ) {
|
jamie@264
|
7360 Ptr<TestCaseNode> node = new TestCaseNode( testCaseStats );
|
jamie@264
|
7361 assert( m_sectionStack.size() == 0 );
|
jamie@264
|
7362 node->children.push_back( m_rootSection );
|
jamie@264
|
7363 m_testCases.push_back( node );
|
jamie@264
|
7364 m_rootSection.reset();
|
jamie@264
|
7365
|
jamie@264
|
7366 assert( m_deepestSection );
|
jamie@264
|
7367 m_deepestSection->stdOut = testCaseStats.stdOut;
|
jamie@264
|
7368 m_deepestSection->stdErr = testCaseStats.stdErr;
|
jamie@264
|
7369 }
|
jamie@264
|
7370 virtual void testGroupEnded( TestGroupStats const& testGroupStats ) {
|
jamie@264
|
7371 Ptr<TestGroupNode> node = new TestGroupNode( testGroupStats );
|
jamie@264
|
7372 node->children.swap( m_testCases );
|
jamie@264
|
7373 m_testGroups.push_back( node );
|
jamie@264
|
7374 }
|
jamie@264
|
7375 virtual void testRunEnded( TestRunStats const& testRunStats ) {
|
jamie@264
|
7376 Ptr<TestRunNode> node = new TestRunNode( testRunStats );
|
jamie@264
|
7377 node->children.swap( m_testGroups );
|
jamie@264
|
7378 m_testRuns.push_back( node );
|
jamie@264
|
7379 testRunEndedCumulative();
|
jamie@264
|
7380 }
|
jamie@264
|
7381 virtual void testRunEndedCumulative() = 0;
|
jamie@264
|
7382
|
jamie@264
|
7383 Ptr<IConfig> m_config;
|
jamie@264
|
7384 std::ostream& stream;
|
jamie@264
|
7385 std::vector<AssertionStats> m_assertions;
|
jamie@264
|
7386 std::vector<std::vector<Ptr<SectionNode> > > m_sections;
|
jamie@264
|
7387 std::vector<Ptr<TestCaseNode> > m_testCases;
|
jamie@264
|
7388 std::vector<Ptr<TestGroupNode> > m_testGroups;
|
jamie@264
|
7389
|
jamie@264
|
7390 std::vector<Ptr<TestRunNode> > m_testRuns;
|
jamie@264
|
7391
|
jamie@264
|
7392 Ptr<SectionNode> m_rootSection;
|
jamie@264
|
7393 Ptr<SectionNode> m_deepestSection;
|
jamie@264
|
7394 std::vector<Ptr<SectionNode> > m_sectionStack;
|
jamie@264
|
7395
|
jamie@264
|
7396 };
|
jamie@264
|
7397
|
jamie@264
|
7398 } // end namespace Catch
|
jamie@264
|
7399
|
jamie@264
|
7400 // #included from: ../internal/catch_reporter_registrars.hpp
|
jamie@264
|
7401 #define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED
|
jamie@264
|
7402
|
jamie@264
|
7403 namespace Catch {
|
jamie@264
|
7404
|
jamie@264
|
7405 template<typename T>
|
jamie@264
|
7406 class LegacyReporterRegistrar {
|
jamie@264
|
7407
|
jamie@264
|
7408 class ReporterFactory : public IReporterFactory {
|
jamie@264
|
7409 virtual IStreamingReporter* create( ReporterConfig const& config ) const {
|
jamie@264
|
7410 return new LegacyReporterAdapter( new T( config ) );
|
jamie@264
|
7411 }
|
jamie@264
|
7412
|
jamie@264
|
7413 virtual std::string getDescription() const {
|
jamie@264
|
7414 return T::getDescription();
|
jamie@264
|
7415 }
|
jamie@264
|
7416 };
|
jamie@264
|
7417
|
jamie@264
|
7418 public:
|
jamie@264
|
7419
|
jamie@264
|
7420 LegacyReporterRegistrar( std::string const& name ) {
|
jamie@264
|
7421 getMutableRegistryHub().registerReporter( name, new ReporterFactory() );
|
jamie@264
|
7422 }
|
jamie@264
|
7423 };
|
jamie@264
|
7424
|
jamie@264
|
7425 template<typename T>
|
jamie@264
|
7426 class ReporterRegistrar {
|
jamie@264
|
7427
|
jamie@264
|
7428 class ReporterFactory : public IReporterFactory {
|
jamie@264
|
7429
|
jamie@264
|
7430 // *** Please Note ***:
|
jamie@264
|
7431 // - If you end up here looking at a compiler error because it's trying to register
|
jamie@264
|
7432 // your custom reporter class be aware that the native reporter interface has changed
|
jamie@264
|
7433 // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via
|
jamie@264
|
7434 // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter.
|
jamie@264
|
7435 // However please consider updating to the new interface as the old one is now
|
jamie@264
|
7436 // deprecated and will probably be removed quite soon!
|
jamie@264
|
7437 // Please contact me via github if you have any questions at all about this.
|
jamie@264
|
7438 // In fact, ideally, please contact me anyway to let me know you've hit this - as I have
|
jamie@264
|
7439 // no idea who is actually using custom reporters at all (possibly no-one!).
|
jamie@264
|
7440 // The new interface is designed to minimise exposure to interface changes in the future.
|
jamie@264
|
7441 virtual IStreamingReporter* create( ReporterConfig const& config ) const {
|
jamie@264
|
7442 return new T( config );
|
jamie@264
|
7443 }
|
jamie@264
|
7444
|
jamie@264
|
7445 virtual std::string getDescription() const {
|
jamie@264
|
7446 return T::getDescription();
|
jamie@264
|
7447 }
|
jamie@264
|
7448 };
|
jamie@264
|
7449
|
jamie@264
|
7450 public:
|
jamie@264
|
7451
|
jamie@264
|
7452 ReporterRegistrar( std::string const& name ) {
|
jamie@264
|
7453 getMutableRegistryHub().registerReporter( name, new ReporterFactory() );
|
jamie@264
|
7454 }
|
jamie@264
|
7455 };
|
jamie@264
|
7456 }
|
jamie@264
|
7457
|
jamie@264
|
7458 #define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \
|
jamie@264
|
7459 namespace{ Catch::LegacyReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); }
|
jamie@264
|
7460 #define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \
|
jamie@264
|
7461 namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); }
|
jamie@264
|
7462
|
jamie@264
|
7463 // #included from: ../internal/catch_xmlwriter.hpp
|
jamie@264
|
7464 #define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED
|
jamie@264
|
7465
|
jamie@264
|
7466 #include <sstream>
|
jamie@264
|
7467 #include <iostream>
|
jamie@264
|
7468 #include <string>
|
jamie@264
|
7469 #include <vector>
|
jamie@264
|
7470
|
jamie@264
|
7471 namespace Catch {
|
jamie@264
|
7472
|
jamie@264
|
7473 class XmlWriter {
|
jamie@264
|
7474 public:
|
jamie@264
|
7475
|
jamie@264
|
7476 class ScopedElement {
|
jamie@264
|
7477 public:
|
jamie@264
|
7478 ScopedElement( XmlWriter* writer )
|
jamie@264
|
7479 : m_writer( writer )
|
jamie@264
|
7480 {}
|
jamie@264
|
7481
|
jamie@264
|
7482 ScopedElement( ScopedElement const& other )
|
jamie@264
|
7483 : m_writer( other.m_writer ){
|
jamie@264
|
7484 other.m_writer = NULL;
|
jamie@264
|
7485 }
|
jamie@264
|
7486
|
jamie@264
|
7487 ~ScopedElement() {
|
jamie@264
|
7488 if( m_writer )
|
jamie@264
|
7489 m_writer->endElement();
|
jamie@264
|
7490 }
|
jamie@264
|
7491
|
jamie@264
|
7492 ScopedElement& writeText( std::string const& text, bool indent = true ) {
|
jamie@264
|
7493 m_writer->writeText( text, indent );
|
jamie@264
|
7494 return *this;
|
jamie@264
|
7495 }
|
jamie@264
|
7496
|
jamie@264
|
7497 template<typename T>
|
jamie@264
|
7498 ScopedElement& writeAttribute( std::string const& name, T const& attribute ) {
|
jamie@264
|
7499 m_writer->writeAttribute( name, attribute );
|
jamie@264
|
7500 return *this;
|
jamie@264
|
7501 }
|
jamie@264
|
7502
|
jamie@264
|
7503 private:
|
jamie@264
|
7504 mutable XmlWriter* m_writer;
|
jamie@264
|
7505 };
|
jamie@264
|
7506
|
jamie@264
|
7507 XmlWriter()
|
jamie@264
|
7508 : m_tagIsOpen( false ),
|
jamie@264
|
7509 m_needsNewline( false ),
|
jamie@264
|
7510 m_os( &std::cout )
|
jamie@264
|
7511 {}
|
jamie@264
|
7512
|
jamie@264
|
7513 XmlWriter( std::ostream& os )
|
jamie@264
|
7514 : m_tagIsOpen( false ),
|
jamie@264
|
7515 m_needsNewline( false ),
|
jamie@264
|
7516 m_os( &os )
|
jamie@264
|
7517 {}
|
jamie@264
|
7518
|
jamie@264
|
7519 ~XmlWriter() {
|
jamie@264
|
7520 while( !m_tags.empty() )
|
jamie@264
|
7521 endElement();
|
jamie@264
|
7522 }
|
jamie@264
|
7523
|
jamie@264
|
7524 //# ifndef CATCH_CPP11_OR_GREATER
|
jamie@264
|
7525 // XmlWriter& operator = ( XmlWriter const& other ) {
|
jamie@264
|
7526 // XmlWriter temp( other );
|
jamie@264
|
7527 // swap( temp );
|
jamie@264
|
7528 // return *this;
|
jamie@264
|
7529 // }
|
jamie@264
|
7530 //# else
|
jamie@264
|
7531 // XmlWriter( XmlWriter const& ) = default;
|
jamie@264
|
7532 // XmlWriter( XmlWriter && ) = default;
|
jamie@264
|
7533 // XmlWriter& operator = ( XmlWriter const& ) = default;
|
jamie@264
|
7534 // XmlWriter& operator = ( XmlWriter && ) = default;
|
jamie@264
|
7535 //# endif
|
jamie@264
|
7536 //
|
jamie@264
|
7537 // void swap( XmlWriter& other ) {
|
jamie@264
|
7538 // std::swap( m_tagIsOpen, other.m_tagIsOpen );
|
jamie@264
|
7539 // std::swap( m_needsNewline, other.m_needsNewline );
|
jamie@264
|
7540 // std::swap( m_tags, other.m_tags );
|
jamie@264
|
7541 // std::swap( m_indent, other.m_indent );
|
jamie@264
|
7542 // std::swap( m_os, other.m_os );
|
jamie@264
|
7543 // }
|
jamie@264
|
7544
|
jamie@264
|
7545 XmlWriter& startElement( std::string const& name ) {
|
jamie@264
|
7546 ensureTagClosed();
|
jamie@264
|
7547 newlineIfNecessary();
|
jamie@264
|
7548 stream() << m_indent << "<" << name;
|
jamie@264
|
7549 m_tags.push_back( name );
|
jamie@264
|
7550 m_indent += " ";
|
jamie@264
|
7551 m_tagIsOpen = true;
|
jamie@264
|
7552 return *this;
|
jamie@264
|
7553 }
|
jamie@264
|
7554
|
jamie@264
|
7555 ScopedElement scopedElement( std::string const& name ) {
|
jamie@264
|
7556 ScopedElement scoped( this );
|
jamie@264
|
7557 startElement( name );
|
jamie@264
|
7558 return scoped;
|
jamie@264
|
7559 }
|
jamie@264
|
7560
|
jamie@264
|
7561 XmlWriter& endElement() {
|
jamie@264
|
7562 newlineIfNecessary();
|
jamie@264
|
7563 m_indent = m_indent.substr( 0, m_indent.size()-2 );
|
jamie@264
|
7564 if( m_tagIsOpen ) {
|
jamie@264
|
7565 stream() << "/>\n";
|
jamie@264
|
7566 m_tagIsOpen = false;
|
jamie@264
|
7567 }
|
jamie@264
|
7568 else {
|
jamie@264
|
7569 stream() << m_indent << "</" << m_tags.back() << ">\n";
|
jamie@264
|
7570 }
|
jamie@264
|
7571 m_tags.pop_back();
|
jamie@264
|
7572 return *this;
|
jamie@264
|
7573 }
|
jamie@264
|
7574
|
jamie@264
|
7575 XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) {
|
jamie@264
|
7576 if( !name.empty() && !attribute.empty() ) {
|
jamie@264
|
7577 stream() << " " << name << "=\"";
|
jamie@264
|
7578 writeEncodedText( attribute );
|
jamie@264
|
7579 stream() << "\"";
|
jamie@264
|
7580 }
|
jamie@264
|
7581 return *this;
|
jamie@264
|
7582 }
|
jamie@264
|
7583
|
jamie@264
|
7584 XmlWriter& writeAttribute( std::string const& name, bool attribute ) {
|
jamie@264
|
7585 stream() << " " << name << "=\"" << ( attribute ? "true" : "false" ) << "\"";
|
jamie@264
|
7586 return *this;
|
jamie@264
|
7587 }
|
jamie@264
|
7588
|
jamie@264
|
7589 template<typename T>
|
jamie@264
|
7590 XmlWriter& writeAttribute( std::string const& name, T const& attribute ) {
|
jamie@264
|
7591 if( !name.empty() )
|
jamie@264
|
7592 stream() << " " << name << "=\"" << attribute << "\"";
|
jamie@264
|
7593 return *this;
|
jamie@264
|
7594 }
|
jamie@264
|
7595
|
jamie@264
|
7596 XmlWriter& writeText( std::string const& text, bool indent = true ) {
|
jamie@264
|
7597 if( !text.empty() ){
|
jamie@264
|
7598 bool tagWasOpen = m_tagIsOpen;
|
jamie@264
|
7599 ensureTagClosed();
|
jamie@264
|
7600 if( tagWasOpen && indent )
|
jamie@264
|
7601 stream() << m_indent;
|
jamie@264
|
7602 writeEncodedText( text );
|
jamie@264
|
7603 m_needsNewline = true;
|
jamie@264
|
7604 }
|
jamie@264
|
7605 return *this;
|
jamie@264
|
7606 }
|
jamie@264
|
7607
|
jamie@264
|
7608 XmlWriter& writeComment( std::string const& text ) {
|
jamie@264
|
7609 ensureTagClosed();
|
jamie@264
|
7610 stream() << m_indent << "<!--" << text << "-->";
|
jamie@264
|
7611 m_needsNewline = true;
|
jamie@264
|
7612 return *this;
|
jamie@264
|
7613 }
|
jamie@264
|
7614
|
jamie@264
|
7615 XmlWriter& writeBlankLine() {
|
jamie@264
|
7616 ensureTagClosed();
|
jamie@264
|
7617 stream() << "\n";
|
jamie@264
|
7618 return *this;
|
jamie@264
|
7619 }
|
jamie@264
|
7620
|
jamie@264
|
7621 void setStream( std::ostream& os ) {
|
jamie@264
|
7622 m_os = &os;
|
jamie@264
|
7623 }
|
jamie@264
|
7624
|
jamie@264
|
7625 private:
|
jamie@264
|
7626 XmlWriter( XmlWriter const& );
|
jamie@264
|
7627 void operator=( XmlWriter const& );
|
jamie@264
|
7628
|
jamie@264
|
7629 std::ostream& stream() {
|
jamie@264
|
7630 return *m_os;
|
jamie@264
|
7631 }
|
jamie@264
|
7632
|
jamie@264
|
7633 void ensureTagClosed() {
|
jamie@264
|
7634 if( m_tagIsOpen ) {
|
jamie@264
|
7635 stream() << ">\n";
|
jamie@264
|
7636 m_tagIsOpen = false;
|
jamie@264
|
7637 }
|
jamie@264
|
7638 }
|
jamie@264
|
7639
|
jamie@264
|
7640 void newlineIfNecessary() {
|
jamie@264
|
7641 if( m_needsNewline ) {
|
jamie@264
|
7642 stream() << "\n";
|
jamie@264
|
7643 m_needsNewline = false;
|
jamie@264
|
7644 }
|
jamie@264
|
7645 }
|
jamie@264
|
7646
|
jamie@264
|
7647 void writeEncodedText( std::string const& text ) {
|
jamie@264
|
7648 static const char* charsToEncode = "<&\"";
|
jamie@264
|
7649 std::string mtext = text;
|
jamie@264
|
7650 std::string::size_type pos = mtext.find_first_of( charsToEncode );
|
jamie@264
|
7651 while( pos != std::string::npos ) {
|
jamie@264
|
7652 stream() << mtext.substr( 0, pos );
|
jamie@264
|
7653
|
jamie@264
|
7654 switch( mtext[pos] ) {
|
jamie@264
|
7655 case '<':
|
jamie@264
|
7656 stream() << "<";
|
jamie@264
|
7657 break;
|
jamie@264
|
7658 case '&':
|
jamie@264
|
7659 stream() << "&";
|
jamie@264
|
7660 break;
|
jamie@264
|
7661 case '\"':
|
jamie@264
|
7662 stream() << """;
|
jamie@264
|
7663 break;
|
jamie@264
|
7664 }
|
jamie@264
|
7665 mtext = mtext.substr( pos+1 );
|
jamie@264
|
7666 pos = mtext.find_first_of( charsToEncode );
|
jamie@264
|
7667 }
|
jamie@264
|
7668 stream() << mtext;
|
jamie@264
|
7669 }
|
jamie@264
|
7670
|
jamie@264
|
7671 bool m_tagIsOpen;
|
jamie@264
|
7672 bool m_needsNewline;
|
jamie@264
|
7673 std::vector<std::string> m_tags;
|
jamie@264
|
7674 std::string m_indent;
|
jamie@264
|
7675 std::ostream* m_os;
|
jamie@264
|
7676 };
|
jamie@264
|
7677
|
jamie@264
|
7678 }
|
jamie@264
|
7679 namespace Catch {
|
jamie@264
|
7680 class XmlReporter : public SharedImpl<IReporter> {
|
jamie@264
|
7681 public:
|
jamie@264
|
7682 XmlReporter( ReporterConfig const& config ) : m_config( config ), m_sectionDepth( 0 ) {}
|
jamie@264
|
7683
|
jamie@264
|
7684 static std::string getDescription() {
|
jamie@264
|
7685 return "Reports test results as an XML document";
|
jamie@264
|
7686 }
|
jamie@264
|
7687 virtual ~XmlReporter();
|
jamie@264
|
7688
|
jamie@264
|
7689 private: // IReporter
|
jamie@264
|
7690
|
jamie@264
|
7691 virtual bool shouldRedirectStdout() const {
|
jamie@264
|
7692 return true;
|
jamie@264
|
7693 }
|
jamie@264
|
7694
|
jamie@264
|
7695 virtual void StartTesting() {
|
jamie@264
|
7696 m_xml.setStream( m_config.stream() );
|
jamie@264
|
7697 m_xml.startElement( "Catch" );
|
jamie@264
|
7698 if( !m_config.fullConfig()->name().empty() )
|
jamie@264
|
7699 m_xml.writeAttribute( "name", m_config.fullConfig()->name() );
|
jamie@264
|
7700 }
|
jamie@264
|
7701
|
jamie@264
|
7702 virtual void EndTesting( const Totals& totals ) {
|
jamie@264
|
7703 m_xml.scopedElement( "OverallResults" )
|
jamie@264
|
7704 .writeAttribute( "successes", totals.assertions.passed )
|
jamie@264
|
7705 .writeAttribute( "failures", totals.assertions.failed )
|
jamie@264
|
7706 .writeAttribute( "expectedFailures", totals.assertions.failedButOk );
|
jamie@264
|
7707 m_xml.endElement();
|
jamie@264
|
7708 }
|
jamie@264
|
7709
|
jamie@264
|
7710 virtual void StartGroup( const std::string& groupName ) {
|
jamie@264
|
7711 m_xml.startElement( "Group" )
|
jamie@264
|
7712 .writeAttribute( "name", groupName );
|
jamie@264
|
7713 }
|
jamie@264
|
7714
|
jamie@264
|
7715 virtual void EndGroup( const std::string&, const Totals& totals ) {
|
jamie@264
|
7716 m_xml.scopedElement( "OverallResults" )
|
jamie@264
|
7717 .writeAttribute( "successes", totals.assertions.passed )
|
jamie@264
|
7718 .writeAttribute( "failures", totals.assertions.failed )
|
jamie@264
|
7719 .writeAttribute( "expectedFailures", totals.assertions.failedButOk );
|
jamie@264
|
7720 m_xml.endElement();
|
jamie@264
|
7721 }
|
jamie@264
|
7722
|
jamie@264
|
7723 virtual void StartSection( const std::string& sectionName, const std::string& description ) {
|
jamie@264
|
7724 if( m_sectionDepth++ > 0 ) {
|
jamie@264
|
7725 m_xml.startElement( "Section" )
|
jamie@264
|
7726 .writeAttribute( "name", trim( sectionName ) )
|
jamie@264
|
7727 .writeAttribute( "description", description );
|
jamie@264
|
7728 }
|
jamie@264
|
7729 }
|
jamie@264
|
7730 virtual void NoAssertionsInSection( const std::string& ) {}
|
jamie@264
|
7731 virtual void NoAssertionsInTestCase( const std::string& ) {}
|
jamie@264
|
7732
|
jamie@264
|
7733 virtual void EndSection( const std::string& /*sectionName*/, const Counts& assertions ) {
|
jamie@264
|
7734 if( --m_sectionDepth > 0 ) {
|
jamie@264
|
7735 m_xml.scopedElement( "OverallResults" )
|
jamie@264
|
7736 .writeAttribute( "successes", assertions.passed )
|
jamie@264
|
7737 .writeAttribute( "failures", assertions.failed )
|
jamie@264
|
7738 .writeAttribute( "expectedFailures", assertions.failedButOk );
|
jamie@264
|
7739 m_xml.endElement();
|
jamie@264
|
7740 }
|
jamie@264
|
7741 }
|
jamie@264
|
7742
|
jamie@264
|
7743 virtual void StartTestCase( const Catch::TestCaseInfo& testInfo ) {
|
jamie@264
|
7744 m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) );
|
jamie@264
|
7745 m_currentTestSuccess = true;
|
jamie@264
|
7746 }
|
jamie@264
|
7747
|
jamie@264
|
7748 virtual void Result( const Catch::AssertionResult& assertionResult ) {
|
jamie@264
|
7749 if( !m_config.fullConfig()->includeSuccessfulResults() && assertionResult.getResultType() == ResultWas::Ok )
|
jamie@264
|
7750 return;
|
jamie@264
|
7751
|
jamie@264
|
7752 if( assertionResult.hasExpression() ) {
|
jamie@264
|
7753 m_xml.startElement( "Expression" )
|
jamie@264
|
7754 .writeAttribute( "success", assertionResult.succeeded() )
|
jamie@264
|
7755 .writeAttribute( "filename", assertionResult.getSourceInfo().file )
|
jamie@264
|
7756 .writeAttribute( "line", assertionResult.getSourceInfo().line );
|
jamie@264
|
7757
|
jamie@264
|
7758 m_xml.scopedElement( "Original" )
|
jamie@264
|
7759 .writeText( assertionResult.getExpression() );
|
jamie@264
|
7760 m_xml.scopedElement( "Expanded" )
|
jamie@264
|
7761 .writeText( assertionResult.getExpandedExpression() );
|
jamie@264
|
7762 m_currentTestSuccess &= assertionResult.succeeded();
|
jamie@264
|
7763 }
|
jamie@264
|
7764
|
jamie@264
|
7765 switch( assertionResult.getResultType() ) {
|
jamie@264
|
7766 case ResultWas::ThrewException:
|
jamie@264
|
7767 m_xml.scopedElement( "Exception" )
|
jamie@264
|
7768 .writeAttribute( "filename", assertionResult.getSourceInfo().file )
|
jamie@264
|
7769 .writeAttribute( "line", assertionResult.getSourceInfo().line )
|
jamie@264
|
7770 .writeText( assertionResult.getMessage() );
|
jamie@264
|
7771 m_currentTestSuccess = false;
|
jamie@264
|
7772 break;
|
jamie@264
|
7773 case ResultWas::Info:
|
jamie@264
|
7774 m_xml.scopedElement( "Info" )
|
jamie@264
|
7775 .writeText( assertionResult.getMessage() );
|
jamie@264
|
7776 break;
|
jamie@264
|
7777 case ResultWas::Warning:
|
jamie@264
|
7778 m_xml.scopedElement( "Warning" )
|
jamie@264
|
7779 .writeText( assertionResult.getMessage() );
|
jamie@264
|
7780 break;
|
jamie@264
|
7781 case ResultWas::ExplicitFailure:
|
jamie@264
|
7782 m_xml.scopedElement( "Failure" )
|
jamie@264
|
7783 .writeText( assertionResult.getMessage() );
|
jamie@264
|
7784 m_currentTestSuccess = false;
|
jamie@264
|
7785 break;
|
jamie@264
|
7786 case ResultWas::Unknown:
|
jamie@264
|
7787 case ResultWas::Ok:
|
jamie@264
|
7788 case ResultWas::FailureBit:
|
jamie@264
|
7789 case ResultWas::ExpressionFailed:
|
jamie@264
|
7790 case ResultWas::Exception:
|
jamie@264
|
7791 case ResultWas::DidntThrowException:
|
jamie@264
|
7792 break;
|
jamie@264
|
7793 }
|
jamie@264
|
7794 if( assertionResult.hasExpression() )
|
jamie@264
|
7795 m_xml.endElement();
|
jamie@264
|
7796 }
|
jamie@264
|
7797
|
jamie@264
|
7798 virtual void Aborted() {
|
jamie@264
|
7799 // !TBD
|
jamie@264
|
7800 }
|
jamie@264
|
7801
|
jamie@264
|
7802 virtual void EndTestCase( const Catch::TestCaseInfo&, const Totals&, const std::string&, const std::string& ) {
|
jamie@264
|
7803 m_xml.scopedElement( "OverallResult" ).writeAttribute( "success", m_currentTestSuccess );
|
jamie@264
|
7804 m_xml.endElement();
|
jamie@264
|
7805 }
|
jamie@264
|
7806
|
jamie@264
|
7807 private:
|
jamie@264
|
7808 ReporterConfig m_config;
|
jamie@264
|
7809 bool m_currentTestSuccess;
|
jamie@264
|
7810 XmlWriter m_xml;
|
jamie@264
|
7811 int m_sectionDepth;
|
jamie@264
|
7812 };
|
jamie@264
|
7813
|
jamie@264
|
7814 } // end namespace Catch
|
jamie@264
|
7815
|
jamie@264
|
7816 // #included from: ../reporters/catch_reporter_junit.hpp
|
jamie@264
|
7817 #define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED
|
jamie@264
|
7818
|
jamie@264
|
7819 #include <assert.h>
|
jamie@264
|
7820
|
jamie@264
|
7821 namespace Catch {
|
jamie@264
|
7822
|
jamie@264
|
7823 class JunitReporter : public CumulativeReporterBase {
|
jamie@264
|
7824 public:
|
jamie@264
|
7825 JunitReporter( ReporterConfig const& _config )
|
jamie@264
|
7826 : CumulativeReporterBase( _config ),
|
jamie@264
|
7827 xml( _config.stream() )
|
jamie@264
|
7828 {}
|
jamie@264
|
7829
|
jamie@264
|
7830 ~JunitReporter();
|
jamie@264
|
7831
|
jamie@264
|
7832 static std::string getDescription() {
|
jamie@264
|
7833 return "Reports test results in an XML format that looks like Ant's junitreport target";
|
jamie@264
|
7834 }
|
jamie@264
|
7835
|
jamie@264
|
7836 virtual void noMatchingTestCases( std::string const& /*spec*/ ) {}
|
jamie@264
|
7837
|
jamie@264
|
7838 virtual ReporterPreferences getPreferences() const {
|
jamie@264
|
7839 ReporterPreferences prefs;
|
jamie@264
|
7840 prefs.shouldRedirectStdOut = true;
|
jamie@264
|
7841 return prefs;
|
jamie@264
|
7842 }
|
jamie@264
|
7843
|
jamie@264
|
7844 virtual void testRunStarting( TestRunInfo const& runInfo ) {
|
jamie@264
|
7845 CumulativeReporterBase::testRunStarting( runInfo );
|
jamie@264
|
7846 xml.startElement( "testsuites" );
|
jamie@264
|
7847 }
|
jamie@264
|
7848
|
jamie@264
|
7849 virtual void testGroupStarting( GroupInfo const& groupInfo ) {
|
jamie@264
|
7850 suiteTimer.start();
|
jamie@264
|
7851 stdOutForSuite.str("");
|
jamie@264
|
7852 stdErrForSuite.str("");
|
jamie@264
|
7853 unexpectedExceptions = 0;
|
jamie@264
|
7854 CumulativeReporterBase::testGroupStarting( groupInfo );
|
jamie@264
|
7855 }
|
jamie@264
|
7856
|
jamie@264
|
7857 virtual bool assertionEnded( AssertionStats const& assertionStats ) {
|
jamie@264
|
7858 if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException )
|
jamie@264
|
7859 unexpectedExceptions++;
|
jamie@264
|
7860 return CumulativeReporterBase::assertionEnded( assertionStats );
|
jamie@264
|
7861 }
|
jamie@264
|
7862
|
jamie@264
|
7863 virtual void testCaseEnded( TestCaseStats const& testCaseStats ) {
|
jamie@264
|
7864 stdOutForSuite << testCaseStats.stdOut;
|
jamie@264
|
7865 stdErrForSuite << testCaseStats.stdErr;
|
jamie@264
|
7866 CumulativeReporterBase::testCaseEnded( testCaseStats );
|
jamie@264
|
7867 }
|
jamie@264
|
7868
|
jamie@264
|
7869 virtual void testGroupEnded( TestGroupStats const& testGroupStats ) {
|
jamie@264
|
7870 double suiteTime = suiteTimer.getElapsedSeconds();
|
jamie@264
|
7871 CumulativeReporterBase::testGroupEnded( testGroupStats );
|
jamie@264
|
7872 writeGroup( *m_testGroups.back(), suiteTime );
|
jamie@264
|
7873 }
|
jamie@264
|
7874
|
jamie@264
|
7875 virtual void testRunEndedCumulative() {
|
jamie@264
|
7876 xml.endElement();
|
jamie@264
|
7877 }
|
jamie@264
|
7878
|
jamie@264
|
7879 void writeGroup( TestGroupNode const& groupNode, double suiteTime ) {
|
jamie@264
|
7880 XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" );
|
jamie@264
|
7881 TestGroupStats const& stats = groupNode.value;
|
jamie@264
|
7882 xml.writeAttribute( "name", stats.groupInfo.name );
|
jamie@264
|
7883 xml.writeAttribute( "errors", unexpectedExceptions );
|
jamie@264
|
7884 xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions );
|
jamie@264
|
7885 xml.writeAttribute( "tests", stats.totals.assertions.total() );
|
jamie@264
|
7886 xml.writeAttribute( "hostname", "tbd" ); // !TBD
|
jamie@264
|
7887 if( m_config->showDurations() == ShowDurations::Never )
|
jamie@264
|
7888 xml.writeAttribute( "time", "" );
|
jamie@264
|
7889 else
|
jamie@264
|
7890 xml.writeAttribute( "time", suiteTime );
|
jamie@264
|
7891 xml.writeAttribute( "timestamp", "tbd" ); // !TBD
|
jamie@264
|
7892
|
jamie@264
|
7893 // Write test cases
|
jamie@264
|
7894 for( TestGroupNode::ChildNodes::const_iterator
|
jamie@264
|
7895 it = groupNode.children.begin(), itEnd = groupNode.children.end();
|
jamie@264
|
7896 it != itEnd;
|
jamie@264
|
7897 ++it )
|
jamie@264
|
7898 writeTestCase( **it );
|
jamie@264
|
7899
|
jamie@264
|
7900 xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false );
|
jamie@264
|
7901 xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false );
|
jamie@264
|
7902 }
|
jamie@264
|
7903
|
jamie@264
|
7904 void writeTestCase( TestCaseNode const& testCaseNode ) {
|
jamie@264
|
7905 TestCaseStats const& stats = testCaseNode.value;
|
jamie@264
|
7906
|
jamie@264
|
7907 // All test cases have exactly one section - which represents the
|
jamie@264
|
7908 // test case itself. That section may have 0-n nested sections
|
jamie@264
|
7909 assert( testCaseNode.children.size() == 1 );
|
jamie@264
|
7910 SectionNode const& rootSection = *testCaseNode.children.front();
|
jamie@264
|
7911
|
jamie@264
|
7912 std::string className = stats.testInfo.className;
|
jamie@264
|
7913
|
jamie@264
|
7914 if( className.empty() ) {
|
jamie@264
|
7915 if( rootSection.childSections.empty() )
|
jamie@264
|
7916 className = "global";
|
jamie@264
|
7917 }
|
jamie@264
|
7918 writeSection( className, "", rootSection );
|
jamie@264
|
7919 }
|
jamie@264
|
7920
|
jamie@264
|
7921 void writeSection( std::string const& className,
|
jamie@264
|
7922 std::string const& rootName,
|
jamie@264
|
7923 SectionNode const& sectionNode ) {
|
jamie@264
|
7924 std::string name = trim( sectionNode.stats.sectionInfo.name );
|
jamie@264
|
7925 if( !rootName.empty() )
|
jamie@264
|
7926 name = rootName + "/" + name;
|
jamie@264
|
7927
|
jamie@264
|
7928 if( !sectionNode.assertions.empty() ||
|
jamie@264
|
7929 !sectionNode.stdOut.empty() ||
|
jamie@264
|
7930 !sectionNode.stdErr.empty() ) {
|
jamie@264
|
7931 XmlWriter::ScopedElement e = xml.scopedElement( "testcase" );
|
jamie@264
|
7932 if( className.empty() ) {
|
jamie@264
|
7933 xml.writeAttribute( "classname", name );
|
jamie@264
|
7934 xml.writeAttribute( "name", "root" );
|
jamie@264
|
7935 }
|
jamie@264
|
7936 else {
|
jamie@264
|
7937 xml.writeAttribute( "classname", className );
|
jamie@264
|
7938 xml.writeAttribute( "name", name );
|
jamie@264
|
7939 }
|
jamie@264
|
7940 xml.writeAttribute( "time", toString( sectionNode.stats.durationInSeconds ) );
|
jamie@264
|
7941
|
jamie@264
|
7942 writeAssertions( sectionNode );
|
jamie@264
|
7943
|
jamie@264
|
7944 if( !sectionNode.stdOut.empty() )
|
jamie@264
|
7945 xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false );
|
jamie@264
|
7946 if( !sectionNode.stdErr.empty() )
|
jamie@264
|
7947 xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false );
|
jamie@264
|
7948 }
|
jamie@264
|
7949 for( SectionNode::ChildSections::const_iterator
|
jamie@264
|
7950 it = sectionNode.childSections.begin(),
|
jamie@264
|
7951 itEnd = sectionNode.childSections.end();
|
jamie@264
|
7952 it != itEnd;
|
jamie@264
|
7953 ++it )
|
jamie@264
|
7954 if( className.empty() )
|
jamie@264
|
7955 writeSection( name, "", **it );
|
jamie@264
|
7956 else
|
jamie@264
|
7957 writeSection( className, name, **it );
|
jamie@264
|
7958 }
|
jamie@264
|
7959
|
jamie@264
|
7960 void writeAssertions( SectionNode const& sectionNode ) {
|
jamie@264
|
7961 for( SectionNode::Assertions::const_iterator
|
jamie@264
|
7962 it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end();
|
jamie@264
|
7963 it != itEnd;
|
jamie@264
|
7964 ++it )
|
jamie@264
|
7965 writeAssertion( *it );
|
jamie@264
|
7966 }
|
jamie@264
|
7967 void writeAssertion( AssertionStats const& stats ) {
|
jamie@264
|
7968 AssertionResult const& result = stats.assertionResult;
|
jamie@264
|
7969 if( !result.isOk() ) {
|
jamie@264
|
7970 std::string elementName;
|
jamie@264
|
7971 switch( result.getResultType() ) {
|
jamie@264
|
7972 case ResultWas::ThrewException:
|
jamie@264
|
7973 elementName = "error";
|
jamie@264
|
7974 break;
|
jamie@264
|
7975 case ResultWas::ExplicitFailure:
|
jamie@264
|
7976 elementName = "failure";
|
jamie@264
|
7977 break;
|
jamie@264
|
7978 case ResultWas::ExpressionFailed:
|
jamie@264
|
7979 elementName = "failure";
|
jamie@264
|
7980 break;
|
jamie@264
|
7981 case ResultWas::DidntThrowException:
|
jamie@264
|
7982 elementName = "failure";
|
jamie@264
|
7983 break;
|
jamie@264
|
7984
|
jamie@264
|
7985 // We should never see these here:
|
jamie@264
|
7986 case ResultWas::Info:
|
jamie@264
|
7987 case ResultWas::Warning:
|
jamie@264
|
7988 case ResultWas::Ok:
|
jamie@264
|
7989 case ResultWas::Unknown:
|
jamie@264
|
7990 case ResultWas::FailureBit:
|
jamie@264
|
7991 case ResultWas::Exception:
|
jamie@264
|
7992 elementName = "internalError";
|
jamie@264
|
7993 break;
|
jamie@264
|
7994 }
|
jamie@264
|
7995
|
jamie@264
|
7996 XmlWriter::ScopedElement e = xml.scopedElement( elementName );
|
jamie@264
|
7997
|
jamie@264
|
7998 xml.writeAttribute( "message", result.getExpandedExpression() );
|
jamie@264
|
7999 xml.writeAttribute( "type", result.getTestMacroName() );
|
jamie@264
|
8000
|
jamie@264
|
8001 std::ostringstream oss;
|
jamie@264
|
8002 if( !result.getMessage().empty() )
|
jamie@264
|
8003 oss << result.getMessage() << "\n";
|
jamie@264
|
8004 for( std::vector<MessageInfo>::const_iterator
|
jamie@264
|
8005 it = stats.infoMessages.begin(),
|
jamie@264
|
8006 itEnd = stats.infoMessages.end();
|
jamie@264
|
8007 it != itEnd;
|
jamie@264
|
8008 ++it )
|
jamie@264
|
8009 if( it->type == ResultWas::Info )
|
jamie@264
|
8010 oss << it->message << "\n";
|
jamie@264
|
8011
|
jamie@264
|
8012 oss << "at " << result.getSourceInfo();
|
jamie@264
|
8013 xml.writeText( oss.str(), false );
|
jamie@264
|
8014 }
|
jamie@264
|
8015 }
|
jamie@264
|
8016
|
jamie@264
|
8017 XmlWriter xml;
|
jamie@264
|
8018 Timer suiteTimer;
|
jamie@264
|
8019 std::ostringstream stdOutForSuite;
|
jamie@264
|
8020 std::ostringstream stdErrForSuite;
|
jamie@264
|
8021 unsigned int unexpectedExceptions;
|
jamie@264
|
8022 };
|
jamie@264
|
8023
|
jamie@264
|
8024 INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter )
|
jamie@264
|
8025
|
jamie@264
|
8026 } // end namespace Catch
|
jamie@264
|
8027
|
jamie@264
|
8028 // #included from: ../reporters/catch_reporter_console.hpp
|
jamie@264
|
8029 #define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED
|
jamie@264
|
8030
|
jamie@264
|
8031 #include <cstring>
|
jamie@264
|
8032
|
jamie@264
|
8033 namespace Catch {
|
jamie@264
|
8034
|
jamie@264
|
8035 struct ConsoleReporter : StreamingReporterBase {
|
jamie@264
|
8036 ConsoleReporter( ReporterConfig const& _config )
|
jamie@264
|
8037 : StreamingReporterBase( _config ),
|
jamie@264
|
8038 m_headerPrinted( false )
|
jamie@264
|
8039 {}
|
jamie@264
|
8040
|
jamie@264
|
8041 virtual ~ConsoleReporter();
|
jamie@264
|
8042 static std::string getDescription() {
|
jamie@264
|
8043 return "Reports test results as plain lines of text";
|
jamie@264
|
8044 }
|
jamie@264
|
8045 virtual ReporterPreferences getPreferences() const {
|
jamie@264
|
8046 ReporterPreferences prefs;
|
jamie@264
|
8047 prefs.shouldRedirectStdOut = false;
|
jamie@264
|
8048 return prefs;
|
jamie@264
|
8049 }
|
jamie@264
|
8050
|
jamie@264
|
8051 virtual void noMatchingTestCases( std::string const& spec ) {
|
jamie@264
|
8052 stream << "No test cases matched '" << spec << "'" << std::endl;
|
jamie@264
|
8053 }
|
jamie@264
|
8054
|
jamie@264
|
8055 virtual void assertionStarting( AssertionInfo const& ) {
|
jamie@264
|
8056 }
|
jamie@264
|
8057
|
jamie@264
|
8058 virtual bool assertionEnded( AssertionStats const& _assertionStats ) {
|
jamie@264
|
8059 AssertionResult const& result = _assertionStats.assertionResult;
|
jamie@264
|
8060
|
jamie@264
|
8061 bool printInfoMessages = true;
|
jamie@264
|
8062
|
jamie@264
|
8063 // Drop out if result was successful and we're not printing those
|
jamie@264
|
8064 if( !m_config->includeSuccessfulResults() && result.isOk() ) {
|
jamie@264
|
8065 if( result.getResultType() != ResultWas::Warning )
|
jamie@264
|
8066 return false;
|
jamie@264
|
8067 printInfoMessages = false;
|
jamie@264
|
8068 }
|
jamie@264
|
8069
|
jamie@264
|
8070 lazyPrint();
|
jamie@264
|
8071
|
jamie@264
|
8072 AssertionPrinter printer( stream, _assertionStats, printInfoMessages );
|
jamie@264
|
8073 printer.print();
|
jamie@264
|
8074 stream << std::endl;
|
jamie@264
|
8075 return true;
|
jamie@264
|
8076 }
|
jamie@264
|
8077
|
jamie@264
|
8078 virtual void sectionStarting( SectionInfo const& _sectionInfo ) {
|
jamie@264
|
8079 m_headerPrinted = false;
|
jamie@264
|
8080 StreamingReporterBase::sectionStarting( _sectionInfo );
|
jamie@264
|
8081 }
|
jamie@264
|
8082 virtual void sectionEnded( SectionStats const& _sectionStats ) {
|
jamie@264
|
8083 if( _sectionStats.missingAssertions ) {
|
jamie@264
|
8084 lazyPrint();
|
jamie@264
|
8085 Colour colour( Colour::ResultError );
|
jamie@264
|
8086 if( m_sectionStack.size() > 1 )
|
jamie@264
|
8087 stream << "\nNo assertions in section";
|
jamie@264
|
8088 else
|
jamie@264
|
8089 stream << "\nNo assertions in test case";
|
jamie@264
|
8090 stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl;
|
jamie@264
|
8091 }
|
jamie@264
|
8092 if( m_headerPrinted ) {
|
jamie@264
|
8093 if( m_config->showDurations() == ShowDurations::Always )
|
jamie@264
|
8094 stream << "Completed in " << _sectionStats.durationInSeconds << "s" << std::endl;
|
jamie@264
|
8095 m_headerPrinted = false;
|
jamie@264
|
8096 }
|
jamie@264
|
8097 else {
|
jamie@264
|
8098 if( m_config->showDurations() == ShowDurations::Always )
|
jamie@264
|
8099 stream << _sectionStats.sectionInfo.name << " completed in " << _sectionStats.durationInSeconds << "s" << std::endl;
|
jamie@264
|
8100 }
|
jamie@264
|
8101 StreamingReporterBase::sectionEnded( _sectionStats );
|
jamie@264
|
8102 }
|
jamie@264
|
8103
|
jamie@264
|
8104 virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) {
|
jamie@264
|
8105 StreamingReporterBase::testCaseEnded( _testCaseStats );
|
jamie@264
|
8106 m_headerPrinted = false;
|
jamie@264
|
8107 }
|
jamie@264
|
8108 virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) {
|
jamie@264
|
8109 if( currentGroupInfo.used ) {
|
jamie@264
|
8110 printSummaryDivider();
|
jamie@264
|
8111 stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n";
|
jamie@264
|
8112 printTotals( _testGroupStats.totals );
|
jamie@264
|
8113 stream << "\n" << std::endl;
|
jamie@264
|
8114 }
|
jamie@264
|
8115 StreamingReporterBase::testGroupEnded( _testGroupStats );
|
jamie@264
|
8116 }
|
jamie@264
|
8117 virtual void testRunEnded( TestRunStats const& _testRunStats ) {
|
jamie@264
|
8118 printTotalsDivider( _testRunStats.totals );
|
jamie@264
|
8119 printTotals( _testRunStats.totals );
|
jamie@264
|
8120 stream << std::endl;
|
jamie@264
|
8121 StreamingReporterBase::testRunEnded( _testRunStats );
|
jamie@264
|
8122 }
|
jamie@264
|
8123
|
jamie@264
|
8124 private:
|
jamie@264
|
8125
|
jamie@264
|
8126 class AssertionPrinter {
|
jamie@264
|
8127 void operator= ( AssertionPrinter const& );
|
jamie@264
|
8128 public:
|
jamie@264
|
8129 AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages )
|
jamie@264
|
8130 : stream( _stream ),
|
jamie@264
|
8131 stats( _stats ),
|
jamie@264
|
8132 result( _stats.assertionResult ),
|
jamie@264
|
8133 colour( Colour::None ),
|
jamie@264
|
8134 message( result.getMessage() ),
|
jamie@264
|
8135 messages( _stats.infoMessages ),
|
jamie@264
|
8136 printInfoMessages( _printInfoMessages )
|
jamie@264
|
8137 {
|
jamie@264
|
8138 switch( result.getResultType() ) {
|
jamie@264
|
8139 case ResultWas::Ok:
|
jamie@264
|
8140 colour = Colour::Success;
|
jamie@264
|
8141 passOrFail = "PASSED";
|
jamie@264
|
8142 //if( result.hasMessage() )
|
jamie@264
|
8143 if( _stats.infoMessages.size() == 1 )
|
jamie@264
|
8144 messageLabel = "with message";
|
jamie@264
|
8145 if( _stats.infoMessages.size() > 1 )
|
jamie@264
|
8146 messageLabel = "with messages";
|
jamie@264
|
8147 break;
|
jamie@264
|
8148 case ResultWas::ExpressionFailed:
|
jamie@264
|
8149 if( result.isOk() ) {
|
jamie@264
|
8150 colour = Colour::Success;
|
jamie@264
|
8151 passOrFail = "FAILED - but was ok";
|
jamie@264
|
8152 }
|
jamie@264
|
8153 else {
|
jamie@264
|
8154 colour = Colour::Error;
|
jamie@264
|
8155 passOrFail = "FAILED";
|
jamie@264
|
8156 }
|
jamie@264
|
8157 if( _stats.infoMessages.size() == 1 )
|
jamie@264
|
8158 messageLabel = "with message";
|
jamie@264
|
8159 if( _stats.infoMessages.size() > 1 )
|
jamie@264
|
8160 messageLabel = "with messages";
|
jamie@264
|
8161 break;
|
jamie@264
|
8162 case ResultWas::ThrewException:
|
jamie@264
|
8163 colour = Colour::Error;
|
jamie@264
|
8164 passOrFail = "FAILED";
|
jamie@264
|
8165 messageLabel = "due to unexpected exception with message";
|
jamie@264
|
8166 break;
|
jamie@264
|
8167 case ResultWas::DidntThrowException:
|
jamie@264
|
8168 colour = Colour::Error;
|
jamie@264
|
8169 passOrFail = "FAILED";
|
jamie@264
|
8170 messageLabel = "because no exception was thrown where one was expected";
|
jamie@264
|
8171 break;
|
jamie@264
|
8172 case ResultWas::Info:
|
jamie@264
|
8173 messageLabel = "info";
|
jamie@264
|
8174 break;
|
jamie@264
|
8175 case ResultWas::Warning:
|
jamie@264
|
8176 messageLabel = "warning";
|
jamie@264
|
8177 break;
|
jamie@264
|
8178 case ResultWas::ExplicitFailure:
|
jamie@264
|
8179 passOrFail = "FAILED";
|
jamie@264
|
8180 colour = Colour::Error;
|
jamie@264
|
8181 if( _stats.infoMessages.size() == 1 )
|
jamie@264
|
8182 messageLabel = "explicitly with message";
|
jamie@264
|
8183 if( _stats.infoMessages.size() > 1 )
|
jamie@264
|
8184 messageLabel = "explicitly with messages";
|
jamie@264
|
8185 break;
|
jamie@264
|
8186 // These cases are here to prevent compiler warnings
|
jamie@264
|
8187 case ResultWas::Unknown:
|
jamie@264
|
8188 case ResultWas::FailureBit:
|
jamie@264
|
8189 case ResultWas::Exception:
|
jamie@264
|
8190 passOrFail = "** internal error **";
|
jamie@264
|
8191 colour = Colour::Error;
|
jamie@264
|
8192 break;
|
jamie@264
|
8193 }
|
jamie@264
|
8194 }
|
jamie@264
|
8195
|
jamie@264
|
8196 void print() const {
|
jamie@264
|
8197 printSourceInfo();
|
jamie@264
|
8198 if( stats.totals.assertions.total() > 0 ) {
|
jamie@264
|
8199 if( result.isOk() )
|
jamie@264
|
8200 stream << "\n";
|
jamie@264
|
8201 printResultType();
|
jamie@264
|
8202 printOriginalExpression();
|
jamie@264
|
8203 printReconstructedExpression();
|
jamie@264
|
8204 }
|
jamie@264
|
8205 else {
|
jamie@264
|
8206 stream << "\n";
|
jamie@264
|
8207 }
|
jamie@264
|
8208 printMessage();
|
jamie@264
|
8209 }
|
jamie@264
|
8210
|
jamie@264
|
8211 private:
|
jamie@264
|
8212 void printResultType() const {
|
jamie@264
|
8213 if( !passOrFail.empty() ) {
|
jamie@264
|
8214 Colour colourGuard( colour );
|
jamie@264
|
8215 stream << passOrFail << ":\n";
|
jamie@264
|
8216 }
|
jamie@264
|
8217 }
|
jamie@264
|
8218 void printOriginalExpression() const {
|
jamie@264
|
8219 if( result.hasExpression() ) {
|
jamie@264
|
8220 Colour colourGuard( Colour::OriginalExpression );
|
jamie@264
|
8221 stream << " ";
|
jamie@264
|
8222 stream << result.getExpressionInMacro();
|
jamie@264
|
8223 stream << "\n";
|
jamie@264
|
8224 }
|
jamie@264
|
8225 }
|
jamie@264
|
8226 void printReconstructedExpression() const {
|
jamie@264
|
8227 if( result.hasExpandedExpression() ) {
|
jamie@264
|
8228 stream << "with expansion:\n";
|
jamie@264
|
8229 Colour colourGuard( Colour::ReconstructedExpression );
|
jamie@264
|
8230 stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << "\n";
|
jamie@264
|
8231 }
|
jamie@264
|
8232 }
|
jamie@264
|
8233 void printMessage() const {
|
jamie@264
|
8234 if( !messageLabel.empty() )
|
jamie@264
|
8235 stream << messageLabel << ":" << "\n";
|
jamie@264
|
8236 for( std::vector<MessageInfo>::const_iterator it = messages.begin(), itEnd = messages.end();
|
jamie@264
|
8237 it != itEnd;
|
jamie@264
|
8238 ++it ) {
|
jamie@264
|
8239 // If this assertion is a warning ignore any INFO messages
|
jamie@264
|
8240 if( printInfoMessages || it->type != ResultWas::Info )
|
jamie@264
|
8241 stream << Text( it->message, TextAttributes().setIndent(2) ) << "\n";
|
jamie@264
|
8242 }
|
jamie@264
|
8243 }
|
jamie@264
|
8244 void printSourceInfo() const {
|
jamie@264
|
8245 Colour colourGuard( Colour::FileName );
|
jamie@264
|
8246 stream << result.getSourceInfo() << ": ";
|
jamie@264
|
8247 }
|
jamie@264
|
8248
|
jamie@264
|
8249 std::ostream& stream;
|
jamie@264
|
8250 AssertionStats const& stats;
|
jamie@264
|
8251 AssertionResult const& result;
|
jamie@264
|
8252 Colour::Code colour;
|
jamie@264
|
8253 std::string passOrFail;
|
jamie@264
|
8254 std::string messageLabel;
|
jamie@264
|
8255 std::string message;
|
jamie@264
|
8256 std::vector<MessageInfo> messages;
|
jamie@264
|
8257 bool printInfoMessages;
|
jamie@264
|
8258 };
|
jamie@264
|
8259
|
jamie@264
|
8260 void lazyPrint() {
|
jamie@264
|
8261
|
jamie@264
|
8262 if( !currentTestRunInfo.used )
|
jamie@264
|
8263 lazyPrintRunInfo();
|
jamie@264
|
8264 if( !currentGroupInfo.used )
|
jamie@264
|
8265 lazyPrintGroupInfo();
|
jamie@264
|
8266
|
jamie@264
|
8267 if( !m_headerPrinted ) {
|
jamie@264
|
8268 printTestCaseAndSectionHeader();
|
jamie@264
|
8269 m_headerPrinted = true;
|
jamie@264
|
8270 }
|
jamie@264
|
8271 }
|
jamie@264
|
8272 void lazyPrintRunInfo() {
|
jamie@264
|
8273 stream << "\n" << getLineOfChars<'~'>() << "\n";
|
jamie@264
|
8274 Colour colour( Colour::SecondaryText );
|
jamie@264
|
8275 stream << currentTestRunInfo->name
|
jamie@264
|
8276 << " is a Catch v" << libraryVersion.majorVersion << "."
|
jamie@264
|
8277 << libraryVersion.minorVersion << " b"
|
jamie@264
|
8278 << libraryVersion.buildNumber;
|
jamie@264
|
8279 if( libraryVersion.branchName != std::string( "master" ) )
|
jamie@264
|
8280 stream << " (" << libraryVersion.branchName << ")";
|
jamie@264
|
8281 stream << " host application.\n"
|
jamie@264
|
8282 << "Run with -? for options\n\n";
|
jamie@264
|
8283
|
jamie@264
|
8284 currentTestRunInfo.used = true;
|
jamie@264
|
8285 }
|
jamie@264
|
8286 void lazyPrintGroupInfo() {
|
jamie@264
|
8287 if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) {
|
jamie@264
|
8288 printClosedHeader( "Group: " + currentGroupInfo->name );
|
jamie@264
|
8289 currentGroupInfo.used = true;
|
jamie@264
|
8290 }
|
jamie@264
|
8291 }
|
jamie@264
|
8292 void printTestCaseAndSectionHeader() {
|
jamie@264
|
8293 assert( !m_sectionStack.empty() );
|
jamie@264
|
8294 printOpenHeader( currentTestCaseInfo->name );
|
jamie@264
|
8295
|
jamie@264
|
8296 if( m_sectionStack.size() > 1 ) {
|
jamie@264
|
8297 Colour colourGuard( Colour::Headers );
|
jamie@264
|
8298
|
jamie@264
|
8299 std::vector<SectionInfo>::const_iterator
|
jamie@264
|
8300 it = m_sectionStack.begin()+1, // Skip first section (test case)
|
jamie@264
|
8301 itEnd = m_sectionStack.end();
|
jamie@264
|
8302 for( ; it != itEnd; ++it )
|
jamie@264
|
8303 printHeaderString( it->name, 2 );
|
jamie@264
|
8304 }
|
jamie@264
|
8305
|
jamie@264
|
8306 SourceLineInfo lineInfo = m_sectionStack.front().lineInfo;
|
jamie@264
|
8307
|
jamie@264
|
8308 if( !lineInfo.empty() ){
|
jamie@264
|
8309 stream << getLineOfChars<'-'>() << "\n";
|
jamie@264
|
8310 Colour colourGuard( Colour::FileName );
|
jamie@264
|
8311 stream << lineInfo << "\n";
|
jamie@264
|
8312 }
|
jamie@264
|
8313 stream << getLineOfChars<'.'>() << "\n" << std::endl;
|
jamie@264
|
8314 }
|
jamie@264
|
8315
|
jamie@264
|
8316 void printClosedHeader( std::string const& _name ) {
|
jamie@264
|
8317 printOpenHeader( _name );
|
jamie@264
|
8318 stream << getLineOfChars<'.'>() << "\n";
|
jamie@264
|
8319 }
|
jamie@264
|
8320 void printOpenHeader( std::string const& _name ) {
|
jamie@264
|
8321 stream << getLineOfChars<'-'>() << "\n";
|
jamie@264
|
8322 {
|
jamie@264
|
8323 Colour colourGuard( Colour::Headers );
|
jamie@264
|
8324 printHeaderString( _name );
|
jamie@264
|
8325 }
|
jamie@264
|
8326 }
|
jamie@264
|
8327
|
jamie@264
|
8328 // if string has a : in first line will set indent to follow it on
|
jamie@264
|
8329 // subsequent lines
|
jamie@264
|
8330 void printHeaderString( std::string const& _string, std::size_t indent = 0 ) {
|
jamie@264
|
8331 std::size_t i = _string.find( ": " );
|
jamie@264
|
8332 if( i != std::string::npos )
|
jamie@264
|
8333 i+=2;
|
jamie@264
|
8334 else
|
jamie@264
|
8335 i = 0;
|
jamie@264
|
8336 stream << Text( _string, TextAttributes()
|
jamie@264
|
8337 .setIndent( indent+i)
|
jamie@264
|
8338 .setInitialIndent( indent ) ) << "\n";
|
jamie@264
|
8339 }
|
jamie@264
|
8340
|
jamie@264
|
8341 struct SummaryColumn {
|
jamie@264
|
8342
|
jamie@264
|
8343 SummaryColumn( std::string const& _label, Colour::Code _colour )
|
jamie@264
|
8344 : label( _label ),
|
jamie@264
|
8345 colour( _colour )
|
jamie@264
|
8346 {}
|
jamie@264
|
8347 SummaryColumn addRow( std::size_t count ) {
|
jamie@264
|
8348 std::ostringstream oss;
|
jamie@264
|
8349 oss << count;
|
jamie@264
|
8350 std::string row = oss.str();
|
jamie@264
|
8351 for( std::vector<std::string>::iterator it = rows.begin(); it != rows.end(); ++it ) {
|
jamie@264
|
8352 while( it->size() < row.size() )
|
jamie@264
|
8353 *it = " " + *it;
|
jamie@264
|
8354 while( it->size() > row.size() )
|
jamie@264
|
8355 row = " " + row;
|
jamie@264
|
8356 }
|
jamie@264
|
8357 rows.push_back( row );
|
jamie@264
|
8358 return *this;
|
jamie@264
|
8359 }
|
jamie@264
|
8360
|
jamie@264
|
8361 std::string label;
|
jamie@264
|
8362 Colour::Code colour;
|
jamie@264
|
8363 std::vector<std::string> rows;
|
jamie@264
|
8364
|
jamie@264
|
8365 };
|
jamie@264
|
8366
|
jamie@264
|
8367 void printTotals( Totals const& totals ) {
|
jamie@264
|
8368 if( totals.testCases.total() == 0 ) {
|
jamie@264
|
8369 stream << Colour( Colour::Warning ) << "No tests ran\n";
|
jamie@264
|
8370 }
|
jamie@264
|
8371 else if( totals.assertions.total() > 0 && totals.assertions.allPassed() ) {
|
jamie@264
|
8372 stream << Colour( Colour::ResultSuccess ) << "All tests passed";
|
jamie@264
|
8373 stream << " ("
|
jamie@264
|
8374 << pluralise( totals.assertions.passed, "assertion" ) << " in "
|
jamie@264
|
8375 << pluralise( totals.testCases.passed, "test case" ) << ")"
|
jamie@264
|
8376 << "\n";
|
jamie@264
|
8377 }
|
jamie@264
|
8378 else {
|
jamie@264
|
8379
|
jamie@264
|
8380 std::vector<SummaryColumn> columns;
|
jamie@264
|
8381 columns.push_back( SummaryColumn( "", Colour::None )
|
jamie@264
|
8382 .addRow( totals.testCases.total() )
|
jamie@264
|
8383 .addRow( totals.assertions.total() ) );
|
jamie@264
|
8384 columns.push_back( SummaryColumn( "passed", Colour::Success )
|
jamie@264
|
8385 .addRow( totals.testCases.passed )
|
jamie@264
|
8386 .addRow( totals.assertions.passed ) );
|
jamie@264
|
8387 columns.push_back( SummaryColumn( "failed", Colour::ResultError )
|
jamie@264
|
8388 .addRow( totals.testCases.failed )
|
jamie@264
|
8389 .addRow( totals.assertions.failed ) );
|
jamie@264
|
8390 columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure )
|
jamie@264
|
8391 .addRow( totals.testCases.failedButOk )
|
jamie@264
|
8392 .addRow( totals.assertions.failedButOk ) );
|
jamie@264
|
8393
|
jamie@264
|
8394 printSummaryRow( "test cases", columns, 0 );
|
jamie@264
|
8395 printSummaryRow( "assertions", columns, 1 );
|
jamie@264
|
8396 }
|
jamie@264
|
8397 }
|
jamie@264
|
8398 void printSummaryRow( std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row ) {
|
jamie@264
|
8399 for( std::vector<SummaryColumn>::const_iterator it = cols.begin(); it != cols.end(); ++it ) {
|
jamie@264
|
8400 std::string value = it->rows[row];
|
jamie@264
|
8401 if( it->label.empty() ) {
|
jamie@264
|
8402 stream << label << ": ";
|
jamie@264
|
8403 if( value != "0" )
|
jamie@264
|
8404 stream << value;
|
jamie@264
|
8405 else
|
jamie@264
|
8406 stream << Colour( Colour::Warning ) << "- none -";
|
jamie@264
|
8407 }
|
jamie@264
|
8408 else if( value != "0" ) {
|
jamie@264
|
8409 stream << Colour( Colour::LightGrey ) << " | ";
|
jamie@264
|
8410 stream << Colour( it->colour )
|
jamie@264
|
8411 << value << " " << it->label;
|
jamie@264
|
8412 }
|
jamie@264
|
8413 }
|
jamie@264
|
8414 stream << "\n";
|
jamie@264
|
8415 }
|
jamie@264
|
8416
|
jamie@264
|
8417 static std::size_t makeRatio( std::size_t number, std::size_t total ) {
|
jamie@264
|
8418 std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0;
|
jamie@264
|
8419 return ( ratio == 0 && number > 0 ) ? 1 : ratio;
|
jamie@264
|
8420 }
|
jamie@264
|
8421 static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) {
|
jamie@264
|
8422 if( i > j && i > k )
|
jamie@264
|
8423 return i;
|
jamie@264
|
8424 else if( j > k )
|
jamie@264
|
8425 return j;
|
jamie@264
|
8426 else
|
jamie@264
|
8427 return k;
|
jamie@264
|
8428 }
|
jamie@264
|
8429
|
jamie@264
|
8430 void printTotalsDivider( Totals const& totals ) {
|
jamie@264
|
8431 if( totals.testCases.total() > 0 ) {
|
jamie@264
|
8432 std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() );
|
jamie@264
|
8433 std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() );
|
jamie@264
|
8434 std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() );
|
jamie@264
|
8435 while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 )
|
jamie@264
|
8436 findMax( failedRatio, failedButOkRatio, passedRatio )++;
|
jamie@264
|
8437 while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 )
|
jamie@264
|
8438 findMax( failedRatio, failedButOkRatio, passedRatio )--;
|
jamie@264
|
8439
|
jamie@264
|
8440 stream << Colour( Colour::Error ) << std::string( failedRatio, '=' );
|
jamie@264
|
8441 stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' );
|
jamie@264
|
8442 if( totals.testCases.allPassed() )
|
jamie@264
|
8443 stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' );
|
jamie@264
|
8444 else
|
jamie@264
|
8445 stream << Colour( Colour::Success ) << std::string( passedRatio, '=' );
|
jamie@264
|
8446 }
|
jamie@264
|
8447 else {
|
jamie@264
|
8448 stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' );
|
jamie@264
|
8449 }
|
jamie@264
|
8450 stream << "\n";
|
jamie@264
|
8451 }
|
jamie@264
|
8452 void printSummaryDivider() {
|
jamie@264
|
8453 stream << getLineOfChars<'-'>() << "\n";
|
jamie@264
|
8454 }
|
jamie@264
|
8455 template<char C>
|
jamie@264
|
8456 static char const* getLineOfChars() {
|
jamie@264
|
8457 static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0};
|
jamie@264
|
8458 if( !*line ) {
|
jamie@264
|
8459 memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 );
|
jamie@264
|
8460 line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0;
|
jamie@264
|
8461 }
|
jamie@264
|
8462 return line;
|
jamie@264
|
8463 }
|
jamie@264
|
8464
|
jamie@264
|
8465 private:
|
jamie@264
|
8466 bool m_headerPrinted;
|
jamie@264
|
8467 };
|
jamie@264
|
8468
|
jamie@264
|
8469 INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter )
|
jamie@264
|
8470
|
jamie@264
|
8471 } // end namespace Catch
|
jamie@264
|
8472
|
jamie@264
|
8473 // #included from: ../reporters/catch_reporter_compact.hpp
|
jamie@264
|
8474 #define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED
|
jamie@264
|
8475
|
jamie@264
|
8476 namespace Catch {
|
jamie@264
|
8477
|
jamie@264
|
8478 struct CompactReporter : StreamingReporterBase {
|
jamie@264
|
8479
|
jamie@264
|
8480 CompactReporter( ReporterConfig const& _config )
|
jamie@264
|
8481 : StreamingReporterBase( _config )
|
jamie@264
|
8482 {}
|
jamie@264
|
8483
|
jamie@264
|
8484 virtual ~CompactReporter();
|
jamie@264
|
8485
|
jamie@264
|
8486 static std::string getDescription() {
|
jamie@264
|
8487 return "Reports test results on a single line, suitable for IDEs";
|
jamie@264
|
8488 }
|
jamie@264
|
8489
|
jamie@264
|
8490 virtual ReporterPreferences getPreferences() const {
|
jamie@264
|
8491 ReporterPreferences prefs;
|
jamie@264
|
8492 prefs.shouldRedirectStdOut = false;
|
jamie@264
|
8493 return prefs;
|
jamie@264
|
8494 }
|
jamie@264
|
8495
|
jamie@264
|
8496 virtual void noMatchingTestCases( std::string const& spec ) {
|
jamie@264
|
8497 stream << "No test cases matched '" << spec << "'" << std::endl;
|
jamie@264
|
8498 }
|
jamie@264
|
8499
|
jamie@264
|
8500 virtual void assertionStarting( AssertionInfo const& ) {
|
jamie@264
|
8501 }
|
jamie@264
|
8502
|
jamie@264
|
8503 virtual bool assertionEnded( AssertionStats const& _assertionStats ) {
|
jamie@264
|
8504 AssertionResult const& result = _assertionStats.assertionResult;
|
jamie@264
|
8505
|
jamie@264
|
8506 bool printInfoMessages = true;
|
jamie@264
|
8507
|
jamie@264
|
8508 // Drop out if result was successful and we're not printing those
|
jamie@264
|
8509 if( !m_config->includeSuccessfulResults() && result.isOk() ) {
|
jamie@264
|
8510 if( result.getResultType() != ResultWas::Warning )
|
jamie@264
|
8511 return false;
|
jamie@264
|
8512 printInfoMessages = false;
|
jamie@264
|
8513 }
|
jamie@264
|
8514
|
jamie@264
|
8515 AssertionPrinter printer( stream, _assertionStats, printInfoMessages );
|
jamie@264
|
8516 printer.print();
|
jamie@264
|
8517
|
jamie@264
|
8518 stream << std::endl;
|
jamie@264
|
8519 return true;
|
jamie@264
|
8520 }
|
jamie@264
|
8521
|
jamie@264
|
8522 virtual void testRunEnded( TestRunStats const& _testRunStats ) {
|
jamie@264
|
8523 printTotals( _testRunStats.totals );
|
jamie@264
|
8524 stream << "\n" << std::endl;
|
jamie@264
|
8525 StreamingReporterBase::testRunEnded( _testRunStats );
|
jamie@264
|
8526 }
|
jamie@264
|
8527
|
jamie@264
|
8528 private:
|
jamie@264
|
8529 class AssertionPrinter {
|
jamie@264
|
8530 void operator= ( AssertionPrinter const& );
|
jamie@264
|
8531 public:
|
jamie@264
|
8532 AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages )
|
jamie@264
|
8533 : stream( _stream )
|
jamie@264
|
8534 , stats( _stats )
|
jamie@264
|
8535 , result( _stats.assertionResult )
|
jamie@264
|
8536 , messages( _stats.infoMessages )
|
jamie@264
|
8537 , itMessage( _stats.infoMessages.begin() )
|
jamie@264
|
8538 , printInfoMessages( _printInfoMessages )
|
jamie@264
|
8539 {}
|
jamie@264
|
8540
|
jamie@264
|
8541 void print() {
|
jamie@264
|
8542 printSourceInfo();
|
jamie@264
|
8543
|
jamie@264
|
8544 itMessage = messages.begin();
|
jamie@264
|
8545
|
jamie@264
|
8546 switch( result.getResultType() ) {
|
jamie@264
|
8547 case ResultWas::Ok:
|
jamie@264
|
8548 printResultType( Colour::ResultSuccess, passedString() );
|
jamie@264
|
8549 printOriginalExpression();
|
jamie@264
|
8550 printReconstructedExpression();
|
jamie@264
|
8551 if ( ! result.hasExpression() )
|
jamie@264
|
8552 printRemainingMessages( Colour::None );
|
jamie@264
|
8553 else
|
jamie@264
|
8554 printRemainingMessages();
|
jamie@264
|
8555 break;
|
jamie@264
|
8556 case ResultWas::ExpressionFailed:
|
jamie@264
|
8557 if( result.isOk() )
|
jamie@264
|
8558 printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) );
|
jamie@264
|
8559 else
|
jamie@264
|
8560 printResultType( Colour::Error, failedString() );
|
jamie@264
|
8561 printOriginalExpression();
|
jamie@264
|
8562 printReconstructedExpression();
|
jamie@264
|
8563 printRemainingMessages();
|
jamie@264
|
8564 break;
|
jamie@264
|
8565 case ResultWas::ThrewException:
|
jamie@264
|
8566 printResultType( Colour::Error, failedString() );
|
jamie@264
|
8567 printIssue( "unexpected exception with message:" );
|
jamie@264
|
8568 printMessage();
|
jamie@264
|
8569 printExpressionWas();
|
jamie@264
|
8570 printRemainingMessages();
|
jamie@264
|
8571 break;
|
jamie@264
|
8572 case ResultWas::DidntThrowException:
|
jamie@264
|
8573 printResultType( Colour::Error, failedString() );
|
jamie@264
|
8574 printIssue( "expected exception, got none" );
|
jamie@264
|
8575 printExpressionWas();
|
jamie@264
|
8576 printRemainingMessages();
|
jamie@264
|
8577 break;
|
jamie@264
|
8578 case ResultWas::Info:
|
jamie@264
|
8579 printResultType( Colour::None, "info" );
|
jamie@264
|
8580 printMessage();
|
jamie@264
|
8581 printRemainingMessages();
|
jamie@264
|
8582 break;
|
jamie@264
|
8583 case ResultWas::Warning:
|
jamie@264
|
8584 printResultType( Colour::None, "warning" );
|
jamie@264
|
8585 printMessage();
|
jamie@264
|
8586 printRemainingMessages();
|
jamie@264
|
8587 break;
|
jamie@264
|
8588 case ResultWas::ExplicitFailure:
|
jamie@264
|
8589 printResultType( Colour::Error, failedString() );
|
jamie@264
|
8590 printIssue( "explicitly" );
|
jamie@264
|
8591 printRemainingMessages( Colour::None );
|
jamie@264
|
8592 break;
|
jamie@264
|
8593 // These cases are here to prevent compiler warnings
|
jamie@264
|
8594 case ResultWas::Unknown:
|
jamie@264
|
8595 case ResultWas::FailureBit:
|
jamie@264
|
8596 case ResultWas::Exception:
|
jamie@264
|
8597 printResultType( Colour::Error, "** internal error **" );
|
jamie@264
|
8598 break;
|
jamie@264
|
8599 }
|
jamie@264
|
8600 }
|
jamie@264
|
8601
|
jamie@264
|
8602 private:
|
jamie@264
|
8603 // Colour::LightGrey
|
jamie@264
|
8604
|
jamie@264
|
8605 static Colour::Code dimColour() { return Colour::FileName; }
|
jamie@264
|
8606
|
jamie@264
|
8607 #ifdef CATCH_PLATFORM_MAC
|
jamie@264
|
8608 static const char* failedString() { return "FAILED"; }
|
jamie@264
|
8609 static const char* passedString() { return "PASSED"; }
|
jamie@264
|
8610 #else
|
jamie@264
|
8611 static const char* failedString() { return "failed"; }
|
jamie@264
|
8612 static const char* passedString() { return "passed"; }
|
jamie@264
|
8613 #endif
|
jamie@264
|
8614
|
jamie@264
|
8615 void printSourceInfo() const {
|
jamie@264
|
8616 Colour colourGuard( Colour::FileName );
|
jamie@264
|
8617 stream << result.getSourceInfo() << ":";
|
jamie@264
|
8618 }
|
jamie@264
|
8619
|
jamie@264
|
8620 void printResultType( Colour::Code colour, std::string passOrFail ) const {
|
jamie@264
|
8621 if( !passOrFail.empty() ) {
|
jamie@264
|
8622 {
|
jamie@264
|
8623 Colour colourGuard( colour );
|
jamie@264
|
8624 stream << " " << passOrFail;
|
jamie@264
|
8625 }
|
jamie@264
|
8626 stream << ":";
|
jamie@264
|
8627 }
|
jamie@264
|
8628 }
|
jamie@264
|
8629
|
jamie@264
|
8630 void printIssue( std::string issue ) const {
|
jamie@264
|
8631 stream << " " << issue;
|
jamie@264
|
8632 }
|
jamie@264
|
8633
|
jamie@264
|
8634 void printExpressionWas() {
|
jamie@264
|
8635 if( result.hasExpression() ) {
|
jamie@264
|
8636 stream << ";";
|
jamie@264
|
8637 {
|
jamie@264
|
8638 Colour colour( dimColour() );
|
jamie@264
|
8639 stream << " expression was:";
|
jamie@264
|
8640 }
|
jamie@264
|
8641 printOriginalExpression();
|
jamie@264
|
8642 }
|
jamie@264
|
8643 }
|
jamie@264
|
8644
|
jamie@264
|
8645 void printOriginalExpression() const {
|
jamie@264
|
8646 if( result.hasExpression() ) {
|
jamie@264
|
8647 stream << " " << result.getExpression();
|
jamie@264
|
8648 }
|
jamie@264
|
8649 }
|
jamie@264
|
8650
|
jamie@264
|
8651 void printReconstructedExpression() const {
|
jamie@264
|
8652 if( result.hasExpandedExpression() ) {
|
jamie@264
|
8653 {
|
jamie@264
|
8654 Colour colour( dimColour() );
|
jamie@264
|
8655 stream << " for: ";
|
jamie@264
|
8656 }
|
jamie@264
|
8657 stream << result.getExpandedExpression();
|
jamie@264
|
8658 }
|
jamie@264
|
8659 }
|
jamie@264
|
8660
|
jamie@264
|
8661 void printMessage() {
|
jamie@264
|
8662 if ( itMessage != messages.end() ) {
|
jamie@264
|
8663 stream << " '" << itMessage->message << "'";
|
jamie@264
|
8664 ++itMessage;
|
jamie@264
|
8665 }
|
jamie@264
|
8666 }
|
jamie@264
|
8667
|
jamie@264
|
8668 void printRemainingMessages( Colour::Code colour = dimColour() ) {
|
jamie@264
|
8669 if ( itMessage == messages.end() )
|
jamie@264
|
8670 return;
|
jamie@264
|
8671
|
jamie@264
|
8672 // using messages.end() directly yields compilation error:
|
jamie@264
|
8673 std::vector<MessageInfo>::const_iterator itEnd = messages.end();
|
jamie@264
|
8674 const std::size_t N = static_cast<std::size_t>( std::distance( itMessage, itEnd ) );
|
jamie@264
|
8675
|
jamie@264
|
8676 {
|
jamie@264
|
8677 Colour colourGuard( colour );
|
jamie@264
|
8678 stream << " with " << pluralise( N, "message" ) << ":";
|
jamie@264
|
8679 }
|
jamie@264
|
8680
|
jamie@264
|
8681 for(; itMessage != itEnd; ) {
|
jamie@264
|
8682 // If this assertion is a warning ignore any INFO messages
|
jamie@264
|
8683 if( printInfoMessages || itMessage->type != ResultWas::Info ) {
|
jamie@264
|
8684 stream << " '" << itMessage->message << "'";
|
jamie@264
|
8685 if ( ++itMessage != itEnd ) {
|
jamie@264
|
8686 Colour colourGuard( dimColour() );
|
jamie@264
|
8687 stream << " and";
|
jamie@264
|
8688 }
|
jamie@264
|
8689 }
|
jamie@264
|
8690 }
|
jamie@264
|
8691 }
|
jamie@264
|
8692
|
jamie@264
|
8693 private:
|
jamie@264
|
8694 std::ostream& stream;
|
jamie@264
|
8695 AssertionStats const& stats;
|
jamie@264
|
8696 AssertionResult const& result;
|
jamie@264
|
8697 std::vector<MessageInfo> messages;
|
jamie@264
|
8698 std::vector<MessageInfo>::const_iterator itMessage;
|
jamie@264
|
8699 bool printInfoMessages;
|
jamie@264
|
8700 };
|
jamie@264
|
8701
|
jamie@264
|
8702 // Colour, message variants:
|
jamie@264
|
8703 // - white: No tests ran.
|
jamie@264
|
8704 // - red: Failed [both/all] N test cases, failed [both/all] M assertions.
|
jamie@264
|
8705 // - white: Passed [both/all] N test cases (no assertions).
|
jamie@264
|
8706 // - red: Failed N tests cases, failed M assertions.
|
jamie@264
|
8707 // - green: Passed [both/all] N tests cases with M assertions.
|
jamie@264
|
8708
|
jamie@264
|
8709 std::string bothOrAll( std::size_t count ) const {
|
jamie@264
|
8710 return count == 1 ? "" : count == 2 ? "both " : "all " ;
|
jamie@264
|
8711 }
|
jamie@264
|
8712
|
jamie@264
|
8713 void printTotals( const Totals& totals ) const {
|
jamie@264
|
8714 if( totals.testCases.total() == 0 ) {
|
jamie@264
|
8715 stream << "No tests ran.";
|
jamie@264
|
8716 }
|
jamie@264
|
8717 else if( totals.testCases.failed == totals.testCases.total() ) {
|
jamie@264
|
8718 Colour colour( Colour::ResultError );
|
jamie@264
|
8719 const std::string qualify_assertions_failed =
|
jamie@264
|
8720 totals.assertions.failed == totals.assertions.total() ?
|
jamie@264
|
8721 bothOrAll( totals.assertions.failed ) : "";
|
jamie@264
|
8722 stream <<
|
jamie@264
|
8723 "Failed " << bothOrAll( totals.testCases.failed )
|
jamie@264
|
8724 << pluralise( totals.testCases.failed, "test case" ) << ", "
|
jamie@264
|
8725 "failed " << qualify_assertions_failed <<
|
jamie@264
|
8726 pluralise( totals.assertions.failed, "assertion" ) << ".";
|
jamie@264
|
8727 }
|
jamie@264
|
8728 else if( totals.assertions.total() == 0 ) {
|
jamie@264
|
8729 stream <<
|
jamie@264
|
8730 "Passed " << bothOrAll( totals.testCases.total() )
|
jamie@264
|
8731 << pluralise( totals.testCases.total(), "test case" )
|
jamie@264
|
8732 << " (no assertions).";
|
jamie@264
|
8733 }
|
jamie@264
|
8734 else if( totals.assertions.failed ) {
|
jamie@264
|
8735 Colour colour( Colour::ResultError );
|
jamie@264
|
8736 stream <<
|
jamie@264
|
8737 "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", "
|
jamie@264
|
8738 "failed " << pluralise( totals.assertions.failed, "assertion" ) << ".";
|
jamie@264
|
8739 }
|
jamie@264
|
8740 else {
|
jamie@264
|
8741 Colour colour( Colour::ResultSuccess );
|
jamie@264
|
8742 stream <<
|
jamie@264
|
8743 "Passed " << bothOrAll( totals.testCases.passed )
|
jamie@264
|
8744 << pluralise( totals.testCases.passed, "test case" ) <<
|
jamie@264
|
8745 " with " << pluralise( totals.assertions.passed, "assertion" ) << ".";
|
jamie@264
|
8746 }
|
jamie@264
|
8747 }
|
jamie@264
|
8748 };
|
jamie@264
|
8749
|
jamie@264
|
8750 INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter )
|
jamie@264
|
8751
|
jamie@264
|
8752 } // end namespace Catch
|
jamie@264
|
8753
|
jamie@264
|
8754 namespace Catch {
|
jamie@264
|
8755 NonCopyable::~NonCopyable() {}
|
jamie@264
|
8756 IShared::~IShared() {}
|
jamie@264
|
8757 StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {}
|
jamie@264
|
8758 IContext::~IContext() {}
|
jamie@264
|
8759 IResultCapture::~IResultCapture() {}
|
jamie@264
|
8760 ITestCase::~ITestCase() {}
|
jamie@264
|
8761 ITestCaseRegistry::~ITestCaseRegistry() {}
|
jamie@264
|
8762 IRegistryHub::~IRegistryHub() {}
|
jamie@264
|
8763 IMutableRegistryHub::~IMutableRegistryHub() {}
|
jamie@264
|
8764 IExceptionTranslator::~IExceptionTranslator() {}
|
jamie@264
|
8765 IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {}
|
jamie@264
|
8766 IReporter::~IReporter() {}
|
jamie@264
|
8767 IReporterFactory::~IReporterFactory() {}
|
jamie@264
|
8768 IReporterRegistry::~IReporterRegistry() {}
|
jamie@264
|
8769 IStreamingReporter::~IStreamingReporter() {}
|
jamie@264
|
8770 AssertionStats::~AssertionStats() {}
|
jamie@264
|
8771 SectionStats::~SectionStats() {}
|
jamie@264
|
8772 TestCaseStats::~TestCaseStats() {}
|
jamie@264
|
8773 TestGroupStats::~TestGroupStats() {}
|
jamie@264
|
8774 TestRunStats::~TestRunStats() {}
|
jamie@264
|
8775 CumulativeReporterBase::SectionNode::~SectionNode() {}
|
jamie@264
|
8776 CumulativeReporterBase::~CumulativeReporterBase() {}
|
jamie@264
|
8777
|
jamie@264
|
8778 StreamingReporterBase::~StreamingReporterBase() {}
|
jamie@264
|
8779 ConsoleReporter::~ConsoleReporter() {}
|
jamie@264
|
8780 CompactReporter::~CompactReporter() {}
|
jamie@264
|
8781 IRunner::~IRunner() {}
|
jamie@264
|
8782 IMutableContext::~IMutableContext() {}
|
jamie@264
|
8783 IConfig::~IConfig() {}
|
jamie@264
|
8784 XmlReporter::~XmlReporter() {}
|
jamie@264
|
8785 JunitReporter::~JunitReporter() {}
|
jamie@264
|
8786 TestRegistry::~TestRegistry() {}
|
jamie@264
|
8787 FreeFunctionTestCase::~FreeFunctionTestCase() {}
|
jamie@264
|
8788 IGeneratorInfo::~IGeneratorInfo() {}
|
jamie@264
|
8789 IGeneratorsForTest::~IGeneratorsForTest() {}
|
jamie@264
|
8790 TestSpec::Pattern::~Pattern() {}
|
jamie@264
|
8791 TestSpec::NamePattern::~NamePattern() {}
|
jamie@264
|
8792 TestSpec::TagPattern::~TagPattern() {}
|
jamie@264
|
8793 TestSpec::ExcludedPattern::~ExcludedPattern() {}
|
jamie@264
|
8794
|
jamie@264
|
8795 Matchers::Impl::StdString::Equals::~Equals() {}
|
jamie@264
|
8796 Matchers::Impl::StdString::Contains::~Contains() {}
|
jamie@264
|
8797 Matchers::Impl::StdString::StartsWith::~StartsWith() {}
|
jamie@264
|
8798 Matchers::Impl::StdString::EndsWith::~EndsWith() {}
|
jamie@264
|
8799
|
jamie@264
|
8800 void Config::dummy() {}
|
jamie@264
|
8801
|
jamie@264
|
8802 INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( "xml", XmlReporter )
|
jamie@264
|
8803 }
|
jamie@264
|
8804
|
jamie@264
|
8805 #ifdef __clang__
|
jamie@264
|
8806 #pragma clang diagnostic pop
|
jamie@264
|
8807 #endif
|
jamie@264
|
8808
|
jamie@264
|
8809 #endif
|
jamie@264
|
8810
|
jamie@264
|
8811 #ifdef CATCH_CONFIG_MAIN
|
jamie@264
|
8812 // #included from: internal/catch_default_main.hpp
|
jamie@264
|
8813 #define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED
|
jamie@264
|
8814
|
jamie@264
|
8815 #ifndef __OBJC__
|
jamie@264
|
8816
|
jamie@264
|
8817 // Standard C/C++ main entry point
|
jamie@264
|
8818 int main (int argc, char * const argv[]) {
|
jamie@264
|
8819 return Catch::Session().run( argc, argv );
|
jamie@264
|
8820 }
|
jamie@264
|
8821
|
jamie@264
|
8822 #else // __OBJC__
|
jamie@264
|
8823
|
jamie@264
|
8824 // Objective-C entry point
|
jamie@264
|
8825 int main (int argc, char * const argv[]) {
|
jamie@264
|
8826 #if !CATCH_ARC_ENABLED
|
jamie@264
|
8827 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
|
jamie@264
|
8828 #endif
|
jamie@264
|
8829
|
jamie@264
|
8830 Catch::registerTestMethods();
|
jamie@264
|
8831 int result = Catch::Session().run( argc, (char* const*)argv );
|
jamie@264
|
8832
|
jamie@264
|
8833 #if !CATCH_ARC_ENABLED
|
jamie@264
|
8834 [pool drain];
|
jamie@264
|
8835 #endif
|
jamie@264
|
8836
|
jamie@264
|
8837 return result;
|
jamie@264
|
8838 }
|
jamie@264
|
8839
|
jamie@264
|
8840 #endif // __OBJC__
|
jamie@264
|
8841
|
jamie@264
|
8842 #endif
|
jamie@264
|
8843
|
jamie@264
|
8844 #ifdef CLARA_CONFIG_MAIN_NOT_DEFINED
|
jamie@264
|
8845 # undef CLARA_CONFIG_MAIN
|
jamie@264
|
8846 #endif
|
jamie@264
|
8847
|
jamie@264
|
8848 //////
|
jamie@264
|
8849
|
jamie@264
|
8850 // If this config identifier is defined then all CATCH macros are prefixed with CATCH_
|
jamie@264
|
8851 #ifdef CATCH_CONFIG_PREFIX_ALL
|
jamie@264
|
8852
|
jamie@264
|
8853 #define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" )
|
jamie@264
|
8854 #define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" )
|
jamie@264
|
8855
|
jamie@264
|
8856 #define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS" )
|
jamie@264
|
8857 #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" )
|
jamie@264
|
8858 #define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" )
|
jamie@264
|
8859
|
jamie@264
|
8860 #define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" )
|
jamie@264
|
8861 #define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CATCH_CHECK_FALSE" )
|
jamie@264
|
8862 #define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_IF" )
|
jamie@264
|
8863 #define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE" )
|
jamie@264
|
8864 #define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL" )
|
jamie@264
|
8865
|
jamie@264
|
8866 #define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" )
|
jamie@264
|
8867 #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" )
|
jamie@264
|
8868 #define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" )
|
jamie@264
|
8869
|
jamie@264
|
8870 #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" )
|
jamie@264
|
8871 #define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT" )
|
jamie@264
|
8872
|
jamie@264
|
8873 #define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" )
|
jamie@264
|
8874 #define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "CATCH_WARN", msg )
|
jamie@264
|
8875 #define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" )
|
jamie@264
|
8876 #define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" )
|
jamie@264
|
8877 #define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" )
|
jamie@264
|
8878
|
jamie@264
|
8879 #ifdef CATCH_CONFIG_VARIADIC_MACROS
|
jamie@264
|
8880 #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
|
jamie@264
|
8881 #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
jamie@264
|
8882 #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
|
jamie@264
|
8883 #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
|
jamie@264
|
8884 #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ )
|
jamie@264
|
8885 #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ )
|
jamie@264
|
8886 #else
|
jamie@264
|
8887 #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
|
jamie@264
|
8888 #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description )
|
jamie@264
|
8889 #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description )
|
jamie@264
|
8890 #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
|
jamie@264
|
8891 #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg )
|
jamie@264
|
8892 #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg )
|
jamie@264
|
8893 #endif
|
jamie@264
|
8894 #define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" )
|
jamie@264
|
8895
|
jamie@264
|
8896 #define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType )
|
jamie@264
|
8897 #define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType )
|
jamie@264
|
8898
|
jamie@264
|
8899 #define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr )
|
jamie@264
|
8900
|
jamie@264
|
8901 // "BDD-style" convenience wrappers
|
jamie@264
|
8902 #ifdef CATCH_CONFIG_VARIADIC_MACROS
|
jamie@264
|
8903 #define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ )
|
jamie@264
|
8904 #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
|
jamie@264
|
8905 #else
|
jamie@264
|
8906 #define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags )
|
jamie@264
|
8907 #define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags )
|
jamie@264
|
8908 #endif
|
jamie@264
|
8909 #define CATCH_GIVEN( desc ) CATCH_SECTION( "Given: " desc, "" )
|
jamie@264
|
8910 #define CATCH_WHEN( desc ) CATCH_SECTION( " When: " desc, "" )
|
jamie@264
|
8911 #define CATCH_AND_WHEN( desc ) CATCH_SECTION( " And: " desc, "" )
|
jamie@264
|
8912 #define CATCH_THEN( desc ) CATCH_SECTION( " Then: " desc, "" )
|
jamie@264
|
8913 #define CATCH_AND_THEN( desc ) CATCH_SECTION( " And: " desc, "" )
|
jamie@264
|
8914
|
jamie@264
|
8915 // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
|
jamie@264
|
8916 #else
|
jamie@264
|
8917
|
jamie@264
|
8918 #define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" )
|
jamie@264
|
8919 #define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE" )
|
jamie@264
|
8920
|
jamie@264
|
8921 #define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "REQUIRE_THROWS" )
|
jamie@264
|
8922 #define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" )
|
jamie@264
|
8923 #define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" )
|
jamie@264
|
8924
|
jamie@264
|
8925 #define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" )
|
jamie@264
|
8926 #define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CHECK_FALSE" )
|
jamie@264
|
8927 #define CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_IF" )
|
jamie@264
|
8928 #define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" )
|
jamie@264
|
8929 #define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" )
|
jamie@264
|
8930
|
jamie@264
|
8931 #define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS" )
|
jamie@264
|
8932 #define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" )
|
jamie@264
|
8933 #define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" )
|
jamie@264
|
8934
|
jamie@264
|
8935 #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" )
|
jamie@264
|
8936 #define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "REQUIRE_THAT" )
|
jamie@264
|
8937
|
jamie@264
|
8938 #define INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" )
|
jamie@264
|
8939 #define WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "WARN", msg )
|
jamie@264
|
8940 #define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" )
|
jamie@264
|
8941 #define CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" )
|
jamie@264
|
8942 #define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" )
|
jamie@264
|
8943
|
jamie@264
|
8944 #ifdef CATCH_CONFIG_VARIADIC_MACROS
|
jamie@264
|
8945 #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
|
jamie@264
|
8946 #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
jamie@264
|
8947 #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
|
jamie@264
|
8948 #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
|
jamie@264
|
8949 #define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ )
|
jamie@264
|
8950 #define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ )
|
jamie@264
|
8951 #else
|
jamie@264
|
8952 #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
|
jamie@264
|
8953 #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description )
|
jamie@264
|
8954 #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description )
|
jamie@264
|
8955 #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
|
jamie@264
|
8956 #define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg )
|
jamie@264
|
8957 #define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg )
|
jamie@264
|
8958 #endif
|
jamie@264
|
8959 #define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" )
|
jamie@264
|
8960
|
jamie@264
|
8961 #define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType )
|
jamie@264
|
8962 #define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType )
|
jamie@264
|
8963
|
jamie@264
|
8964 #define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr )
|
jamie@264
|
8965
|
jamie@264
|
8966 #endif
|
jamie@264
|
8967
|
jamie@264
|
8968 #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature )
|
jamie@264
|
8969
|
jamie@264
|
8970 // "BDD-style" convenience wrappers
|
jamie@264
|
8971 #ifdef CATCH_CONFIG_VARIADIC_MACROS
|
jamie@264
|
8972 #define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ )
|
jamie@264
|
8973 #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
|
jamie@264
|
8974 #else
|
jamie@264
|
8975 #define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags )
|
jamie@264
|
8976 #define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags )
|
jamie@264
|
8977 #endif
|
jamie@264
|
8978 #define GIVEN( desc ) SECTION( " Given: " desc, "" )
|
jamie@264
|
8979 #define WHEN( desc ) SECTION( " When: " desc, "" )
|
jamie@264
|
8980 #define AND_WHEN( desc ) SECTION( "And when: " desc, "" )
|
jamie@264
|
8981 #define THEN( desc ) SECTION( " Then: " desc, "" )
|
jamie@264
|
8982 #define AND_THEN( desc ) SECTION( " And: " desc, "" )
|
jamie@264
|
8983
|
jamie@264
|
8984 using Catch::Detail::Approx;
|
jamie@264
|
8985
|
jamie@264
|
8986 // #included from: internal/catch_reenable_warnings.h
|
jamie@264
|
8987
|
jamie@264
|
8988 #define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED
|
jamie@264
|
8989
|
jamie@264
|
8990 #ifdef __clang__
|
jamie@264
|
8991 #pragma clang diagnostic pop
|
jamie@264
|
8992 #elif defined __GNUC__
|
jamie@264
|
8993 #pragma GCC diagnostic pop
|
jamie@264
|
8994 #endif
|
jamie@264
|
8995
|
jamie@264
|
8996 #endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
|
jamie@264
|
8997
|