sl@0: /*
sl@0:  * Copyright (c) 2003, 2004
sl@0:  * Zdenek Nemec
sl@0:  *
sl@0:  * This material is provided "as is", with absolutely no warranty expressed
sl@0:  * or implied. Any use is at your own risk.
sl@0:  *
sl@0:  * Permission to use or copy this software for any purpose is hereby granted
sl@0:  * without fee, provided the above notices are retained on all copies.
sl@0:  * Permission to modify the code and to distribute modified code is granted,
sl@0:  * provided the above notices are retained, and a notice that the code was
sl@0:  * modified is included with the above copyright notice.
sl@0:  *
sl@0:  */
sl@0: 
sl@0: /* $Id: cppunit_mini.h 2490 2006-06-27 19:49:26Z dums $ */
sl@0: 
sl@0: #ifndef _CPPUNITMPFR_H_
sl@0: #define _CPPUNITMPFR_H_
sl@0: 
sl@0: #define CPPUNIT_NS CppUnitMini
sl@0: 
sl@0: #include <string.h>
sl@0: 
sl@0: namespace CPPUNIT_NS
sl@0: {
sl@0:   class Reporter {
sl@0:   public:
sl@0:     virtual ~Reporter() {}
sl@0:     virtual void error(const char * /*macroName*/, const char * /*in_macro*/, const char * /*in_file*/, int /*in_line*/) {}
sl@0:     virtual void failure(const char * /*macroName*/, const char * /*in_macro*/, const char * /*in_file*/, int /*in_line*/) {}
sl@0:     virtual void message( const char * /*msg*/ ) {}
sl@0:     virtual void progress( const char * /*in_className*/, const char * /*in_testName*/, bool /*ignored*/) {}
sl@0:     virtual void end() {}
sl@0:     virtual void printSummary() {}
sl@0:     void setFirstStep(const bool in_firstStep) {m_firstStep = in_firstStep;}
sl@0:     const bool firstStep() { return m_firstStep; }
sl@0:   private:
sl@0:     bool m_firstStep;
sl@0:   };
sl@0: 
sl@0:   class TestFixture {
sl@0:   public:
sl@0:     virtual ~TestFixture() {}
sl@0: 
sl@0:     //! \brief Set up context before running a test.
sl@0:     virtual void setUp() {}
sl@0: 
sl@0:     //! Clean up after the test run.
sl@0:     virtual void tearDown() {}
sl@0:   };
sl@0: 
sl@0:   class TestCase : public TestFixture {
sl@0:   public:
sl@0:     TestCase() { m_failed = false; registerTestCase(this); }
sl@0: 
sl@0:     static int run(Reporter *in_reporter = 0, const char *in_testName = "", bool invert = false);
sl@0:     int numErrors() { return m_numErrors; }
sl@0:     static void registerTestCase(TestCase *in_testCase);
sl@0: 
sl@0:     virtual void myRun(const char * /*in_name*/, bool /*invert*/ = false) {}
sl@0: 
sl@0:     virtual void failure(const char *in_macroName, const char *in_macro, const char *in_file, int in_line) {
sl@0:       m_failed = true;
sl@0:       if (m_reporter) {
sl@0:         m_reporter->failure(in_macroName, in_macro, in_file, in_line);
sl@0:       }
sl@0:     }
sl@0: 
sl@0:     virtual void error(const char *in_macroName, const char *in_macro, const char *in_file, int in_line) {
sl@0:       ++m_numErrors;
sl@0:       if (m_reporter) {
sl@0:         m_reporter->error(in_macroName, in_macro, in_file, in_line);
sl@0:       }
sl@0:     }
sl@0: 
sl@0:     static void message(const char *msg) {
sl@0:       if (m_reporter) {
sl@0:         m_reporter->message(msg);
sl@0:       }
sl@0:     }
sl@0: 
sl@0:     bool equalDoubles(double in_expected, double in_real, double in_maxErr) {
sl@0:       double diff = in_expected - in_real;
sl@0:       if (diff < 0.) {
sl@0:         diff = -diff;
sl@0:       }
sl@0:       return diff < in_maxErr;
sl@0:     }
sl@0: 
sl@0:     virtual void progress(const char *in_className, const char *in_functionName, bool ignored) {
sl@0:       ++m_numTests;
sl@0:       if (m_reporter) {
sl@0:         m_reporter->progress(in_className, in_functionName, ignored);
sl@0:       }
sl@0:     }
sl@0: 
sl@0:     bool shouldRunThis(const char *in_desiredTest, const char *in_className, const char *in_functionName, bool invert = false) {
sl@0:       if ((in_desiredTest) && (in_desiredTest[0] != '\0')) {
sl@0:         const char *ptr = strstr(in_desiredTest, "::");
sl@0:         if (ptr) {
sl@0:           bool decision = (strncmp(in_desiredTest, in_className, strlen(in_className)) == 0) &&
sl@0:                           (strncmp(ptr + 2, in_functionName, strlen(in_functionName)) == 0);
sl@0:           return invert ? !decision : decision;
sl@0:         }
sl@0:         bool decision = strcmp(in_desiredTest, in_className) == 0;
sl@0:         return invert ? !decision : decision;
sl@0:       }
sl@0:       return true;
sl@0:     }
sl@0: 
sl@0:     void tearDown() {
sl@0:       if (m_failed)
sl@0:         ++m_numErrors;
sl@0:       m_reporter->end();
sl@0:     }
sl@0: 
sl@0:   protected:
sl@0:     static int m_numErrors;
sl@0:     static int m_numTests;
sl@0: 
sl@0:   private:
sl@0:     static TestCase *m_root;
sl@0:     TestCase *m_next;
sl@0:     bool m_failed;
sl@0: 
sl@0:     static Reporter *m_reporter;
sl@0:   };
sl@0: }
sl@0: 
sl@0: #if !defined (CPPUNIT_MINI_HIDE_UNUSED_VARIABLE)
sl@0: #  if defined (_MSC_VER)
sl@0: #    define CPPUNIT_MINI_HIDE_UNUSED_VARIABLE(v) (v);
sl@0: #  else
sl@0: #    define CPPUNIT_MINI_HIDE_UNUSED_VARIABLE(v)
sl@0: #  endif
sl@0: #endif
sl@0: 
sl@0: #define CPPUNIT_TEST_SUITE(X) \
sl@0:   typedef CPPUNIT_NS::TestCase Base; \
sl@0:   virtual void myRun(const char *in_name, bool invert = false) { \
sl@0:     char *className = #X; CPPUNIT_MINI_HIDE_UNUSED_VARIABLE(className) \
sl@0:     bool ignoring = false; CPPUNIT_MINI_HIDE_UNUSED_VARIABLE(ignoring)
sl@0: 
sl@0: #if defined CPPUNIT_MINI_USE_EXCEPTIONS
sl@0: #  define CPPUNIT_TEST(X) \
sl@0:   if (shouldRunThis(in_name, className, #X, invert)) { \
sl@0:     setUp(); \
sl@0:     progress(className, #X, ignoring); \
sl@0:     if (!ignoring) { \
sl@0:       try { \
sl@0:         X(); \
sl@0:       } \
sl@0:       catch(...) { \
sl@0:         Base::error("Test Failed: An Exception was thrown.", #X, __FILE__, __LINE__); \
sl@0:       } \
sl@0:     } \
sl@0:     tearDown(); \
sl@0:   }
sl@0: #else
sl@0: #  define CPPUNIT_TEST(X) \
sl@0:   if (shouldRunThis(in_name, className, #X, invert)) { \
sl@0:     setUp(); \
sl@0:     progress(className, #X, ignoring); \
sl@0:     if (!ignoring) \
sl@0:       X(); \
sl@0:     tearDown(); \
sl@0:   }
sl@0: #endif
sl@0: 
sl@0: #  define CPPUNIT_IGNORE \
sl@0:   ignoring = true
sl@0: 
sl@0: #  define CPPUNIT_STOP_IGNORE \
sl@0:   ignoring = false
sl@0: 
sl@0: #define CPPUNIT_TEST_EXCEPTION(X, Y) \
sl@0:   if (shouldRunThis(in_name, className, #X, invert)) { \
sl@0:     progress(className, #X, ignoring); \
sl@0:   }
sl@0: 
sl@0: #define CPPUNIT_TEST_SUITE_END() }
sl@0: 
sl@0: #define CPPUNIT_TEST_SUITE_REGISTRATION(X) static X local
sl@0: 
sl@0: #define CPPUNIT_CHECK(X) \
sl@0:   if (!(X)) { \
sl@0:     Base::failure("CPPUNIT_CHECK", #X, __FILE__, __LINE__); \
sl@0:   }
sl@0: 
sl@0: #define CPPUNIT_ASSERT(X) \
sl@0:   if (!(X)) { \
sl@0:     Base::error("CPPUNIT_ASSERT", #X, __FILE__, __LINE__); \
sl@0:     return; \
sl@0:   }
sl@0: 
sl@0: #define CPPUNIT_ASSERT_EQUAL(X, Y) \
sl@0:   if ((X) != (Y)) { \
sl@0:     Base::error("CPPUNIT_ASSERT_EQUAL", #X","#Y, __FILE__, __LINE__); \
sl@0:     return; \
sl@0:   }
sl@0: 
sl@0: #define CPPUNIT_ASSERT_DOUBLES_EQUAL(X, Y, Z) \
sl@0:   if (!equalDoubles((X), (Y), (Z))) { \
sl@0:     Base::error("CPPUNIT_ASSERT_DOUBLES_EQUAL", #X","#Y","#Z, __FILE__, __LINE__); \
sl@0:     return; \
sl@0:   }
sl@0: 
sl@0: #define CPPUNIT_MESSAGE(m) CPPUNIT_NS::TestCase::message(m)
sl@0: 
sl@0: #endif