summaryrefslogtreecommitdiffstats
path: root/vespalib/src/vespa/vespalib/testkit/testapp.h
blob: 25e4c060822965fa2bea337e0f4cb244940c3e59 (plain) (blame)
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#pragma once

#include "test_kit.h"

#undef TEST_MASTER
#define TEST_MASTER vespalib::TestApp::master

#define TEST_INIT(name) do { ReportInit(name); TEST_MASTER.init(name); } while(false)
#define TEST_DONE() do { ReportConclusion(); return TEST_MASTER.fini() ? 0 : 1; } while(false)

#define TEST_APPHOOK(app) \
  int main(int argc, char **argv) \
  { \
    app myapp; \
    return myapp.Entry(argc, argv); \
  }
#define TEST_SETUP(test) \
  class test : public vespalib::TestApp \
  { \
    public: int Main(); \
  }; \
  TEST_APPHOOK(test)
#define TEST_SETUP_WITHPROCESSPROXY(test) \
  class test : public vespalib::TestApp \
  { \
    public: \
        int Main(); \
        virtual bool useProcessStarter() const { return true; } \
  }; \
  TEST_APPHOOK(test)

namespace vespalib {

/**
 * @brief TestApp is used to create executable unit tests
 *
 * TestApp is a subclass of FastOS_Application that is tailored to
 * create small executable programs containing unit tests. The idea is
 * that you create a class that subclasses TestApp and use a set of
 * macros to test your code. It is similar to the concept used in
 * cppunit except that your tests become programs rather than library
 * code.
 *
 * Below follows an explanation of all the available macros. Note that
 * while you can also invoke the methods in this class directly, most
 * tests will only need to use macros. Also, some features like
 * grabbing the text making up a boolean expression, the file name and
 * the line number of a statement is only possible with macros.
 *
 * <table>
 * <tr><td><b>TEST_INIT(name)</b></td><td>
 *   Invokes the ReportInit method. <i>name</i> is the name of this
 *   test.
 * </td></tr>
 * <tr><td><b>TEST_GROUP(val)</b></td><td>
 *   Invokes the SetGroupModulo method. <i>val</i> is an integer
 *   defining the number of successful tests that may be logged at
 *   once. If <i>val</i> is 0, all consecutive successful test cases
 *   will be reported at once. If <i>val</i> is 1, all tests will be
 *   reported by separate log messages (this is the default).
 * </td></tr>
 * <tr><td><b>TEST_DEBUG(lhsFile, rhsFile)</b></td><td>
 *   Invokes the OpenDebugFiles method. <i>lhs</i> and <i>rhs</i> are
 *   file names for files where we want the left hand side and right
 *   hand side values to be stored. Diffing these files will simplify
 *   debugging of failed tests.
 * </td></tr>
 * <tr><td><b>TEST_PUSH_STATE(msg)</b></td><td>
 *   Invokes the PushState function. <i>msg</i> is pushed on the
 *   internal state stack together with the current file and line
 *   number. The state stack is dumped when a test fails, unless the
 *   DumpState function is overridden.
 * </td></tr>
 * <tr><td><b>TEST_POP_STATE()</b></td><td>
 *   Invokes the PopState function. The topmost item on the state stack
 *   will be popped. If the state stack is empty, nothing will happen.
 * </td></tr>
 * <tr><td><b>TEST_DO(statement)</b></td><td>
 *   Pushes <i>statement</i> on the state stack, performs
 *   <i>statement</i> and finally pops the state stack. The intended
 *   use is to wrap function calls within TEST_DO in order to produce
 *   something that looks like a stack trace when the state stack is
 *   dumped.
 * </td></tr>
 * <tr><td><b>EXPECT_TRUE(rc)</b></td><td>
 *   Test that <i>rc</i> evaluates to true. <i>rc</i> must be an
 *   expression that can be evaluated as a boolean. This automatically
 *   creates a test case. The macro invokes the ReportTestResult
 *   method.
 * </td></tr>
 * <tr><td><b>ASSERT_TRUE(rc)</b></td><td>
 *   Does the same as EXPECT_TRUE except that the application is
 *   aborted if the test fails. This macro may be used to test that
 *   setup vital to the rest of the tests does not fail.
 * </td></tr>
 * <tr><td><b>EXPECT_EQUAL(a, b)</b></td><td>
 *   Test that <i>a</i> == <i>b</i>.
 * </td></tr>
 * <tr><td><b>EXPECT_NOT_EQUAL(a, b)</b></td><td>
 *   Test that <i>a</i> != <i>b</i>.
 * </td></tr>
 * <tr><td><b>EXPECT_LESS(a, b)</b></td><td>
 *   Test that <i>a</i> &lt; <i>b</i>.
 * </td></tr>
 * <tr><td><b>EXPECT_LESS_EQUAL(a, b)</b></td><td>
 *   Test that <i>a</i> &lt;= <i>b</i>.
 * </td></tr>
 * <tr><td><b>EXPECT_GREATER(a, b)</b></td><td>
 *   Test that <i>a</i> &gt; <i>b</i>.
 * </td></tr>
 * <tr><td><b>EXPECT_GREATER_EQUAL(a, b)</b></td><td>
 *   Test that <i>a</i> &gt;= <i>b</i>.
 * </td></tr>
 * <tr><td><b>TEST_FLUSH()</b></td><td>
 *   Invokes the FlushReport method. This is used to force the logging
 *   of successful test cases that are waiting to be logged due to
 *   grouping (see TEST_GROUP).
 * </td></tr>
 * <tr><td><b>TEST_DONE()</b></td><td>
 *   Invokes the ReportConclusion method and returns 0 if all test
 *   cases passed, 1 otherwise. This should be the last thing in your
 *   Main method.
 * </td></tr>
 * <tr><td><b>TEST_APPHOOK(app)</b></td><td>
 *   Creates the code needed to run the class <i>app</i> that must be
 *   a subclass of FastOS_Application. This will create a canonical
 *   main method launching your fastos application.
 * </td></tr>
 * <tr><td><b>TEST_SETUP(test)</b></td><td>
 *   Does the same as TEST_APPHOOK, but also creates a simple class
 *   named <i>test</i> that is a subclass of TestApp and contains only
 *   the Main method. If you want to add some helper methods to your
 *   test, use TEST_APPHOOK, otherwise use this one.
 * </td></tr>
 * <tr><td><b>TEST_THREADS()</b></td><td>
 *   This macro is used in tests that require thread support. If no
 *   thread support is available (fastos was compiled without
 *   threads), this macro will invoke the ReportNoThreads and call the
 *   TEST_DONE macro to exit the test. If thread support is available
 *   this macro does nothing.
 * </td></tr>
 * </table>
 *
 * Simple test example:
 * <pre>
 * \#include <vespa/log/log.h>
 * LOG_SETUP("true_test");
 * \#include <vespa/fastos/fastos.h>
 * \#include <vespa/vespalib/testkit/testapp.h>
 *
 * TEST_SETUP(Test)
 *
 * int
 * Test::Main()
 * {
 *     TEST_INIT("true_test");
 *     EXPECT_TRUE(true);
 *     TEST_DONE();
 * }
 * </pre>
 **/
class TestApp : public FastOS_Application
{
private:
    std::string _name;

public:
    static TestMaster &master;

    TestApp();
    virtual ~TestApp();

    /**
     * @brief Obtain the name of this test
     *
     * @return test name
     **/
    const char *GetName() { return _name.c_str(); }

    /**
     * @brief Obtain the source directory for the current test
     *
     * @return Path to source directory with trailing /
     */
    static const std::string& GetSourceDirectory();

    /**
     * @brief Report test initialization
     *
     * @param name the name of this test
     **/
    virtual void ReportInit(const char *name);

    /**
     * @brief Report test summary
     *
     * @return true if all test cases passed
     **/
    virtual bool ReportConclusion();
};

} // namespace vespalib