Files
2022-10-26 12:25:11 +08:00

231 lines
6.2 KiB
C++

#ifndef TEST_H
#define TEST_H
// Test is a base class for all tests. It provides a command interface for
// running tests (run) as well as a data member for recording the name of
// the test.
//
// Tests are constructed using the TEST macro. TEST creates a subclass of
// Test and static instance of that subclass. If you look at the constructor
// for the Test class, you'll notice that it registers the created object
// with a global TestRegistry. These features combine to make test creation
// particularly easy.
#include <vector>
#include <string>
#include <math.h>
class TestSetup
{
public:
virtual void setup() = 0;
virtual void teardown() = 0;
};
class TestResult;
class Test : public TestSetup
{
public:
Test (const std::string& testName);
virtual void run (TestResult& result);
virtual void runTest (TestResult& result) = 0;
protected:
std::string name;
};
#define TEST(name,classUnderTest)\
class classUnderTest##name##Test : public Test\
{ \
public: \
classUnderTest##name##Test () : Test (#name "Test") {} \
void setup() {}; \
void teardown() {}; \
void runTest (TestResult& result_); \
} classUnderTest##name##Instance; \
void classUnderTest##name##Test::runTest (TestResult& result_) \
#define TESTWITHSETUP(name,classUnderTest)\
class classUnderTest##name##Test : public Test, name##Setup\
{ \
public: \
classUnderTest##name##Test () : Test (#name "Test") {} \
void setup() {name##Setup::setup();} \
void teardown() {name##Setup::teardown();} \
void runTest (TestResult& result_); \
} classUnderTest##name##Instance; \
void classUnderTest##name##Test::runTest (TestResult& result_) \
// Here is a collection of testing macros that can be used in the
// bodies of tests. CHECK tests a boolean expression and records
// a failure if the expression evaluates to false. CHECK_LONGS_EQUAL
// and CHECK_DOUBLES_EQUAL compare longs and doubles respectively.
//
// To make this an industrial strength test harness, you should
// add equals macros for various low level types as you develop them.
// If, for instance, you have a daterange class, the ability to compare
// them directly and print out their values in the test output is
// invaluable.
#ifndef DONT_CATCH_EXCEPTIONS
#define CHECK(condition) \
try { \
if (!(condition)) \
result_.addFailure (Failure (#condition, name, __FILE__, __LINE__)); \
} catch(...) { \
result_.addFailure (Failure ("Unhandled exception", name, __FILE__, __LINE__)); \
}
#define CHECK_LONGS_EQUAL(expected,actual)\
{\
try { \
long _expected = (expected);\
long _actual = (actual);\
if (_expected != _actual) {\
char message [80];\
sprintf (message, "expected %ld but was: %ld", _expected, _actual);\
result_.addFailure (Failure (message, name, __FILE__, __LINE__));\
}\
} catch(...) { \
result_.addFailure (Failure ("Unhandled exception", name, __FILE__, __LINE__)); \
}\
}
#define CHECK_DOUBLES_EQUAL(expected,actual)\
{\
try { \
double _expected = (expected);\
double _actual = (actual);\
if (fabs ((_expected)-(_actual)) > 0.001) {\
char message [80];\
sprintf (message, "expected %lf but was: %lf", (_expected), (_actual));\
result_.addFailure (Failure (message, name, __FILE__, __LINE__));\
}\
} catch(...) { \
result_.addFailure (Failure ("Unhandled exception", name, __FILE__, __LINE__)); \
}\
}
#define CHECK_POINTS_EQUAL(expected,actual)\
{\
try { \
Point3d _expected = (expected); \
Point3d _actual = (actual); \
if (!_actual.Equals(_expected)) { \
char message [256];\
sprintf (message, "expected point (%f, %f, %f) but was: (%f, %f, %f)", \
_expected.x, _expected.y, _expected.z,\
_actual.x, _actual.y, _actual.z); \
result_.addFailure (Failure (message, name, __FILE__, __LINE__));\
}\
} catch(...) { \
result_.addFailure (Failure ("Unhandled exception", name, __FILE__, __LINE__)); \
}\
}
#define CHECK_STRINGS_EQUAL(expected,actual)\
{\
try { \
std::string _expected(expected);\
std::string _actual(actual);\
if (_expected != _actual) {\
std::string msg = std::string("expected '") + _expected + \
std::string("' but was: '") + _actual + "'"; \
result_.addFailure (Failure (msg.c_str(), name, __FILE__, __LINE__));\
}\
} catch(...) { \
result_.addFailure (Failure ("Unhandled exception", name, __FILE__, __LINE__)); \
}\
}
#else
#define CHECK(condition) \
if (!(condition)) \
result_.addFailure (Failure (#condition, name, __FILE__, __LINE__));
#define CHECK_LONGS_EQUAL(expected,actual)\
{\
long _expected = (expected);\
long _actual = (actual);\
if (_expected != _actual) {\
char message [80];\
sprintf (message, "expected %ld but was: %ld", _expected, _actual);\
result_.addFailure (Failure (message, name, __FILE__, __LINE__));\
}\
}
#define CHECK_DOUBLES_EQUAL(expected,actual)\
{\
double _expected = (expected);\
double _actual = (actual);\
if (fabs ((_expected)-(_actual)) > 0.001) {\
char message [80];\
sprintf (message, "expected %lf but was: %lf", (_expected), (_actual));\
result_.addFailure (Failure (message, name, __FILE__, __LINE__));\
}\
}
#define CHECK_POINTS_EQUAL(expected,actual)\
{\
Point3d _expected = (expected); \
Point3d _actual = (actual); \
if (!_actual.Equals(_expected)) { \
char message [256];\
sprintf (message, "expected point (%f, %f, %f) but was: (%f, %f, %f)", \
_expected.x, _expected.y, _expected.z,\
_actual.x, _actual.y, _actual.z); \
result_.addFailure (Failure (message, name, __FILE__, __LINE__));\
}\
}
#define CHECK_STRINGS_EQUAL(expected,actual)\
{\
std::string _expected(expected);\
std::string _actual(actual);\
if (_expected != _actual) {\
std::string msg = std::string("expected '") + _expected + \
std::string("' but was: '") + _actual + "'"; \
result_.addFailure (Failure (msg.c_str(), name, __FILE__, __LINE__));\
}\
}
#endif // DONT_CATCH_EXCEPTIONS
#endif