1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
#pragma once
/**
* A tiny unit testing library in the spirit of Google Test.
*
* To inplement a standalone test, write:
*
* TEST("description") { body }
*
* For fixture-based tests, define a struct Fixture with the fields you want
* available (all public) and any setup and teardown code, then use TEST_F:
*
* struct MyFixture {
* int field1;
* MyFixture() {} // Optional setup code
* ~MyFixture() {} // Optional teardown code
* }
*
* TEST_F(MyFixture, "description") { body }
*
* TEST_F(MyFixture, "description 2") { another body }
*
* In the body of a test, you can use the following macros and assertions:
*
* ASSERT(expression)
* ASSERT_M(expression, message)
* ASSERT_EQ(expected, actualValue)
* ASSERT_NE(expected, actualValue)
* ASSERT_STREQ(expected, actualValue) (for C strings)
* ASSERT_STRNE(expected, actualValue)
* ASSERT_NEAR(expected, actualValue) (for floats/doubles)
* FAIL(message)
*/
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
namespace test {
struct TestCase;
typedef void (*FunctionPtr)();
struct TestCase {
TestCase(const char *fixture_, const char *name_, FunctionPtr func_)
: fixture(fixture_), name(name_), func(func_) {
getCases().push_back(this);
}
void run() { func(); };
const char *fixture;
const char *name;
FunctionPtr func;
static std::vector<TestCase*>& getCases() {
static std::vector<TestCase*> cases;
return cases;
};
};
struct TestFailedException {
TestFailedException(const char *file_, int line_, const std::string& message_)
: file(file_), line(line_), message(message_) {}
const char *file;
int line;
std::string message;
};
int runAllTests(char *filter);
}
#define CONCAT1( x, y ) x ## y
#define CONCAT2( x, y ) CONCAT1( x, y ) /* To escape weird macro expansion rules */
#define TEST_FUNC(line) CONCAT2(_test_func_, line)
#define TEST_CASE(line) CONCAT2(_test_case_, line)
#define TEST_CLASS(line) CONCAT2(_test_class_, line)
#define TEST(name) \
static void TEST_FUNC(__LINE__) (); \
static test::TestCase TEST_CASE(__LINE__) (__FILE__, name, &TEST_FUNC(__LINE__)); \
static void TEST_FUNC(__LINE__) () /* body follows */
#define TEST_F(fixture, name) \
namespace { struct TEST_CLASS(__LINE__) : public fixture { void _run(); }; } \
static void TEST_FUNC(__LINE__) () { TEST_CLASS(__LINE__) cls; cls._run(); } \
static test::TestCase TEST_CASE(__LINE__) (#fixture, name, &TEST_FUNC(__LINE__)); \
void TEST_CLASS(__LINE__)::_run() /* body follows */
#define ASSERT(expr) \
if (!(expr)) { \
std::ostringstream oss; \
oss << "assertion failed: " #expr; \
throw test::TestFailedException(__FILE__, __LINE__, oss.str()); \
}
#define ASSERT_M(expr, message) \
if (!(expr)) { \
std::ostringstream oss; \
oss << "assertion failed: " << message; \
throw test::TestFailedException(__FILE__, __LINE__, oss.str()); \
}
#define ASSERT_EQ(expected, actual) \
if (!((expected) == (actual))) { \
std::ostringstream oss; \
oss << #actual << " was " << (actual) << ", expected " << (expected); \
throw test::TestFailedException(__FILE__, __LINE__, oss.str()); \
}
#define ASSERT_EQ_M(expected, actual, message) \
if (!((expected) == (actual))) { \
std::ostringstream oss; \
oss << #actual << " was " << (actual) << ", expected " << (expected) << ": " << (message); \
throw test::TestFailedException(__FILE__, __LINE__, oss.str()); \
}
#define ASSERT_NE(expected, actual) \
if (!((expected) != (actual))) { \
std::ostringstream oss; \
oss << #actual << " was " << (expected); \
throw test::TestFailedException(__FILE__, __LINE__, oss.str()); \
}
#define ASSERT_STREQ(expected, actual) \
if (strcmp((expected), (actual)) != 0) { \
std::ostringstream oss; \
oss << #actual << " was \"" << (actual) << "\", expected \"" << (expected) << "\""; \
throw test::TestFailedException(__FILE__, __LINE__, oss.str()); \
}
#define ASSERT_STRNE(expected, actual) \
if (strcmp((expected), (actual)) == 0) { \
std::ostringstream oss; \
oss << #actual << " was \"" << (expected) << "\""; \
throw test::TestFailedException(__FILE__, __LINE__, oss.str()); \
}
#define ASSERT_NEAR(expected, actual) \
if ((expected) < 0.99 * (actual) || (expected) > 1.01 * (actual)) { \
std::ostringstream oss; \
oss << #actual << " was " << (actual) << ", expected near " << (expected); \
throw test::TestFailedException(__FILE__, __LINE__, oss.str()); \
}
#define FAIL(message) \
throw test::TestFailedException(__FILE__, __LINE__, message);
|