PageRenderTime 276ms CodeModel.GetById 100ms app.highlight 77ms RepoModel.GetById 94ms app.codeStats 0ms

/mordor/test/test.h

http://github.com/mozy/mordor
C Header | 377 lines | 312 code | 52 blank | 13 comment | 12 complexity | da3a6968ce85e43d62bc5b16d0c7f083 MD5 | raw file
  1#ifndef __TEST_H__
  2#define __TEST_H__
  3// Copyright (c) 2009 - Mozy, Inc.
  4
  5#include <map>
  6#include <sstream>
  7#include <typeinfo>
  8#include <vector>
  9
 10#include "mordor/assert.h"
 11
 12namespace Mordor {
 13namespace Test {
 14
 15class TestInstance;
 16
 17typedef void (*TestDg)();
 18typedef std::pair<TestDg, std::map<std::string, TestDg> > TestSuite;
 19typedef std::map<std::string, TestSuite> TestSuites;
 20
 21/// Create an invariant that is run before and after every test in TestSuite
 22#define MORDOR_SUITE_INVARIANT(TestSuite)                                       \
 23    static void _ ## TestSuite ## _invariant();                                 \
 24    namespace {                                                                 \
 25    static struct register__ ## TestSuite ## _invariant_struct {                \
 26        register__ ## TestSuite ## _invariant_struct() {                        \
 27            ::Mordor::Test::registerSuiteInvariant(#TestSuite,                  \
 28                &_ ## TestSuite ## _invariant);                                 \
 29        }                                                                       \
 30} g__ ## TestSuite ## _invariant_registration;                                  \
 31    }                                                                           \
 32    static void _ ## TestSuite ## _invariant()
 33
 34/// Create a unit test that is part of TestSuite
 35#define MORDOR_UNITTEST(TestSuite, TestName)                                    \
 36    static void TestSuite ## _ ## TestName();                                   \
 37    namespace {                                                                 \
 38    static struct register_ ## TestSuite ## _ ## TestName ## _struct {          \
 39        register_ ## TestSuite ## _ ## TestName ## _struct() {                  \
 40            ::Mordor::Test::registerTest(#TestSuite, #TestName,                 \
 41                & TestSuite ## _ ## TestName );                                 \
 42        }                                                                       \
 43} g_ ## TestSuite ## _ ## TestName ## _registration;                            \
 44    }                                                                           \
 45    static void TestSuite ## _ ## TestName()
 46
 47/// Create a unit test that is part of TestSuite, and runs as a member function
 48/// of Fixture
 49#define MORDOR_UNITTEST_FIXTURE(Fixture, TestSuite, TestName)                   \
 50    class TestSuite ## _ ## TestName ## Helper : public Fixture                 \
 51    {                                                                           \
 52    public:                                                                     \
 53        void run();                                                             \
 54    };                                                                          \
 55    MORDOR_UNITTEST(TestSuite, TestName)                                        \
 56    {                                                                           \
 57        TestSuite ## _ ## TestName ## Helper helper;                            \
 58        helper.run();                                                           \
 59    }                                                                           \
 60    void TestSuite ## _ ## TestName ## Helper::run()
 61
 62// Public interface
 63class TestListener
 64{
 65public:
 66    virtual ~TestListener() {}
 67
 68    virtual void testStarted(const std::string &suite,
 69        const std::string &test) = 0;
 70    virtual void testComplete(const std::string &suite,
 71        const std::string &test) = 0;
 72    virtual void testSkipped(const std::string &suite,
 73        const std::string &test) = 0;
 74    virtual void testAsserted(const std::string &suite,
 75        const std::string &test, const Assertion &assertion) = 0;
 76    virtual void testException(const std::string &suite,
 77        const std::string &test) = 0;
 78    virtual void testsComplete() = 0;
 79};
 80
 81// Internal functions
 82void registerTest(const std::string &suite, const std::string &testName,
 83                  TestDg test);
 84void registerSuiteInvariant(const std::string &suite, TestDg invariant);
 85
 86// Public functions
 87TestSuites &allTests();
 88TestSuites testsForArguments(int argc, char **argv);
 89bool runTests();
 90bool runTests(const TestSuites &suites);
 91bool runTests(TestListener &listener);
 92bool runTests(const TestSuites &suites,
 93              TestListener &listener);
 94
 95struct TestSkippedException {};
 96
 97// Serialization for assertion reporting
 98template <class T>
 99struct serializer
100{
101    serializer(const T &t) : m_t(t) {}
102
103    std::ostream &serialize(std::ostream &os)
104    {
105        return os << m_t;
106    }
107
108    const T& m_t;
109};
110
111template <class T>
112std::ostream &operator <<(std::ostream &os, serializer<T> t)
113{
114    return t.serialize(os);
115}
116
117template <class T>
118struct type_serializer
119{
120    std::ostream &serialize(std::ostream &os)
121    {
122        return os << typeid(T).name();
123    }
124};
125
126#define MORDOR_NO_SERIALIZE_BARE(type)                                          \
127struct serializer<type> : public ::Mordor::Test::type_serializer<type>          \
128{                                                                               \
129    serializer(const type &t) {}                                                \
130};
131
132#define MORDOR_NO_SERIALIZE(type)                                               \
133template <>                                                                     \
134MORDOR_NO_SERIALIZE_BARE(type)
135
136template <class T>
137MORDOR_NO_SERIALIZE_BARE(std::vector<T>)
138
139// Assertion macros
140#define MORDOR_TEST_ASSERT(expr)                                                \
141    if (!(expr)) ::Mordor::Test::assertion(__FILE__, __LINE__,                  \
142        BOOST_CURRENT_FUNCTION, #expr)
143
144#define MORDOR_TEST_ASSERT_EQUAL(lhs, rhs)                                      \
145    ::Mordor::Test::assertEqual(__FILE__, __LINE__, BOOST_CURRENT_FUNCTION,     \
146        lhs, rhs, #lhs, #rhs)
147
148#define MORDOR_TEST_ASSERT_NOT_EQUAL(lhs, rhs)                                  \
149    ::Mordor::Test::assertNotEqual(__FILE__, __LINE__, BOOST_CURRENT_FUNCTION,  \
150        lhs, rhs, #lhs, #rhs)
151
152#define MORDOR_TEST_ASSERT_LESS_THAN(lhs, rhs)                                  \
153    ::Mordor::Test::assertLessThan(__FILE__, __LINE__, BOOST_CURRENT_FUNCTION,  \
154        lhs, rhs, #lhs, #rhs)
155
156#define MORDOR_TEST_ASSERT_LESS_THAN_OR_EQUAL(lhs, rhs)                         \
157    ::Mordor::Test::assertLessThanOrEqual(__FILE__, __LINE__,                   \
158        BOOST_CURRENT_FUNCTION, lhs, rhs, #lhs, #rhs)
159
160#define MORDOR_TEST_ASSERT_GREATER_THAN(lhs, rhs)                               \
161    ::Mordor::Test::assertGreaterThan(__FILE__, __LINE__,                       \
162        BOOST_CURRENT_FUNCTION, lhs, rhs, #lhs, #rhs)
163
164#define MORDOR_TEST_ASSERT_GREATER_THAN_OR_EQUAL(lhs, rhs)                      \
165    ::Mordor::Test::assertGreaterThanOrEqual(__FILE__, __LINE__,                \
166        BOOST_CURRENT_FUNCTION, lhs, rhs, #lhs, #rhs)
167
168#define MORDOR_TEST_ASSERT_ABOUT_EQUAL(lhs, rhs, variance)                      \
169    ::Mordor::Test::assertAboutEqual(__FILE__, __LINE__, BOOST_CURRENT_FUNCTION,\
170        lhs, rhs, #lhs, #rhs, variance)
171
172#define MORDOR_TEST_ASSERT_EXCEPTION(code, exception)                           \
173    try {                                                                       \
174        code;                                                                   \
175        ::Mordor::Test::assertion(__FILE__, __LINE__, BOOST_CURRENT_FUNCTION,   \
176            "Expected " + std::string(typeid(exception).name()) +               \
177            " from " #code);                                                    \
178    } catch (exception &) {                                                     \
179    }
180
181#define MORDOR_TEST_ASSERT_ANY_EXCEPTION(code)                                  \
182    try {                                                                       \
183        code;                                                                   \
184        ::Mordor::Test::assertion(__FILE__, __LINE__, BOOST_CURRENT_FUNCTION,   \
185            "Expected an exception from " #code);                               \
186    } catch (...) {                                                             \
187    }
188
189#define MORDOR_TEST_ASSERT_ASSERTED(code)                                       \
190    {                                                                           \
191        bool __selfAsserted = false;                                            \
192        try {                                                                   \
193            code;                                                               \
194            __selfAsserted = true;                                              \
195            ::Mordor::Test::assertion(__FILE__, __LINE__,                       \
196                BOOST_CURRENT_FUNCTION, "Expected Assertion from " #code);      \
197    } catch (::Mordor::Assertion &) {                                           \
198            if (__selfAsserted)                                                 \
199                throw;                                                          \
200        }                                                                       \
201    }
202
203/// Asserts on destruction if it was alive for longer than us microseconds
204struct TimeConstraint
205{
206    TimeConstraint(unsigned long long us);
207    ~TimeConstraint();
208
209private:
210    unsigned long long m_end;
211};
212
213/// Assert on destruction if it was alive for shorter than us microseconds
214struct TakesAtLeast
215{
216    TakesAtLeast(unsigned long long us);
217    ~TakesAtLeast();
218private:
219    unsigned long long m_until;
220};
221
222// Assertion internal functions
223void assertion(const char *file, int line, const char *function,
224               const std::string &expr);
225
226template <class T, class U>
227void assertComparison(const char *file, int line, const char *function,
228    T lhs, U rhs, const char *lhsExpr, const char *rhsExpr,
229    const char *op)
230{
231    std::ostringstream os;
232    serializer<T> t(lhs);
233    serializer<U> u(rhs);
234    os << lhsExpr << " " << op << " " << rhsExpr
235        << "\n" << t << " " << op << " " << u;
236    assertion(file, line, function, os.str());
237}
238
239template <class T, class U>
240void assertEqual(const char *file, int line, const char *function,
241    T lhs, U rhs, const char *lhsExpr, const char *rhsExpr)
242{
243    if (!(lhs == rhs)) {
244        assertComparison(file, line, function, lhs, rhs, lhsExpr, rhsExpr,
245            "==");
246    }
247}
248
249template <>
250void assertEqual<const char *, const char *>(const char *file,
251    int line,  const char *function, const char *lhs, const char *rhs,
252    const char *lhsExpr, const char *rhsExpr);
253#ifdef WINDOWS
254template <>
255void assertEqual<const wchar_t *, const wchar_t *>(const char *file,
256    int line,  const char *function, const wchar_t *lhs, const wchar_t *rhs,
257    const char *lhsExpr, const char *rhsExpr);
258#endif
259
260template <class T, class U>
261void assertNotEqual(const char *file, int line, const char *function,
262    T lhs, U rhs, const char *lhsExpr, const char *rhsExpr)
263{
264    if (!(lhs != rhs)) {
265        assertComparison(file, line, function, lhs, rhs, lhsExpr, rhsExpr,
266            "!=");
267    }
268}
269
270template <>
271void assertNotEqual<const char *, const char *>(const char *file,
272    int line, const char *function, const char *lhs, const char *rhs,
273    const char *lhsExpr, const char *rhsExpr);
274#ifdef WINDOWS
275template <>
276void assertNotEqual<const wchar_t *, const wchar_t *>(const char *file,
277    int line, const char *function, const wchar_t *lhs, const wchar_t *rhs,
278    const char *lhsExpr, const char *rhsExpr);
279#endif
280
281template <class T, class U>
282void assertLessThan(const char *file, int line, const char *function,
283    T lhs, U rhs, const char *lhsExpr, const char *rhsExpr)
284{
285    if (!(lhs < rhs)) {
286        assertComparison(file, line, function, lhs, rhs, lhsExpr, rhsExpr,
287            "<");
288    }
289}
290
291template <>
292void assertLessThan<const char *, const char *>(const char *file,
293    int line, const char *function, const char *lhs, const char *rhs,
294    const char *lhsExpr, const char *rhsExpr);
295#ifdef WINDOWS
296template <>
297void assertLessThan<const wchar_t *, const wchar_t *>(const char *file,
298    int line, const char *function, const wchar_t *lhs, const wchar_t *rhs,
299    const char *lhsExpr, const char *rhsExpr);
300#endif
301
302template <class T, class U>
303void assertLessThanOrEqual(const char *file, int line, const char *function,
304    T lhs, U rhs, const char *lhsExpr, const char *rhsExpr)
305{
306    if (!(lhs <= rhs)) {
307        assertComparison(file, line, function, lhs, rhs, lhsExpr, rhsExpr,
308            "<=");
309    }
310}
311
312template <>
313void assertLessThanOrEqual<const char *, const char *>(const char *file,
314    int line, const char *function, const char *lhs, const char *rhs,
315    const char *lhsExpr, const char *rhsExpr);
316#ifdef WINDOWS
317template <>
318void assertLessThanOrEqual<const wchar_t *, const wchar_t *>(const char *file,
319    int line, const char *function, const wchar_t *lhs, const wchar_t *rhs,
320    const char *lhsExpr, const char *rhsExpr);
321#endif
322
323template <class T, class U>
324void assertGreaterThan(const char *file, int line, const char *function,
325    T lhs, U rhs, const char *lhsExpr, const char *rhsExpr)
326{
327    if (!(lhs > rhs)) {
328        assertComparison(file, line, function, lhs, rhs, lhsExpr, rhsExpr,
329            ">");
330    }
331}
332
333template <>
334void assertGreaterThan<const char *, const char *>(const char *file,
335    int line, const char *function, const char *lhs, const char *rhs,
336    const char *lhsExpr, const char *rhsExpr);
337#ifdef WINDOWS
338template <>
339void assertGreaterThan<const wchar_t *, const wchar_t *>(const char *file,
340    int line, const char *function, const wchar_t *lhs, const wchar_t *rhs,
341    const char *lhsExpr, const char *rhsExpr);
342#endif
343
344template <class T, class U>
345void assertGreaterThanOrEqual(const char *file, int line, const char *function,
346    T lhs, U rhs, const char *lhsExpr, const char *rhsExpr)
347{
348    if (!(lhs >= rhs)) {
349        assertComparison(file, line, function, lhs, rhs, lhsExpr, rhsExpr,
350            ">=");
351    }
352}
353
354template <>
355void assertGreaterThanOrEqual<const char *, const char *>(const char *file,
356    int line, const char *function, const char *lhs, const char *rhs,
357    const char *lhsExpr, const char *rhsExpr);
358#ifdef WINDOWS
359template <>
360void assertGreaterThanOrEqual<const wchar_t *, const wchar_t *>(const char *file,
361    int line, const char *function, const wchar_t *lhs, const wchar_t *rhs,
362    const char *lhsExpr, const char *rhsExpr);
363#endif
364
365template <class T, class U, class V>
366void assertAboutEqual(const char *file, int line, const char *function,
367    T lhs, U rhs, const char *lhsExpr, const char *rhsExpr, V variance)
368{
369    if (!(lhs - variance <= rhs && lhs + variance >= rhs)) {
370        assertComparison(file, line, function, lhs, rhs, lhsExpr, rhsExpr,
371            "~==");
372    }
373}
374
375}}
376
377#endif