File: TestLib.h

package info (click to toggle)
snap-aligner 1.0.0%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 4,988 kB
  • sloc: cpp: 36,500; ansic: 5,239; python: 227; makefile: 85; sh: 28
file content (152 lines) | stat: -rw-r--r-- 4,881 bytes parent folder | download | duplicates (6)
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);