1// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file. See the AUTHORS file for names of contributors.
4
5#ifndef STORAGE_LEVELDB_UTIL_TESTHARNESS_H_
6#define STORAGE_LEVELDB_UTIL_TESTHARNESS_H_
7
8#include <stdio.h>
9#include <stdlib.h>
10#include <sstream>
11#include "leveldb/env.h"
12#include "leveldb/slice.h"
13#include "util/random.h"
14
15namespace leveldb {
16namespace test {
17
18// Run some of the tests registered by the TEST() macro.  If the
19// environment variable "LEVELDB_TESTS" is not set, runs all tests.
20// Otherwise, runs only the tests whose name contains the value of
21// "LEVELDB_TESTS" as a substring.  E.g., suppose the tests are:
22//    TEST(Foo, Hello) { ... }
23//    TEST(Foo, World) { ... }
24// LEVELDB_TESTS=Hello will run the first test
25// LEVELDB_TESTS=o     will run both tests
26// LEVELDB_TESTS=Junk  will run no tests
27//
28// Returns 0 if all tests pass.
29// Dies or returns a non-zero value if some test fails.
30extern int RunAllTests();
31
32// Return the directory to use for temporary storage.
33extern std::string TmpDir();
34
35// Return a randomization seed for this run.  Typically returns the
36// same number on repeated invocations of this binary, but automated
37// runs may be able to vary the seed.
38extern int RandomSeed();
39
40// An instance of Tester is allocated to hold temporary state during
41// the execution of an assertion.
42class Tester {
43 private:
44  bool ok_;
45  const char* fname_;
46  int line_;
47  std::stringstream ss_;
48
49 public:
50  Tester(const char* f, int l)
51      : ok_(true), fname_(f), line_(l) {
52  }
53
54  ~Tester() {
55    if (!ok_) {
56      fprintf(stderr, "%s:%d:%s\n", fname_, line_, ss_.str().c_str());
57      exit(1);
58    }
59  }
60
61  Tester& Is(bool b, const char* msg) {
62    if (!b) {
63      ss_ << " Assertion failure " << msg;
64      ok_ = false;
65    }
66    return *this;
67  }
68
69  Tester& IsOk(const Status& s) {
70    if (!s.ok()) {
71      ss_ << " " << s.ToString();
72      ok_ = false;
73    }
74    return *this;
75  }
76
77#define BINARY_OP(name,op)                              \
78  template <class X, class Y>                           \
79  Tester& name(const X& x, const Y& y) {                \
80    if (! (x op y)) {                                   \
81      ss_ << " failed: " << x << (" " #op " ") << y;    \
82      ok_ = false;                                      \
83    }                                                   \
84    return *this;                                       \
85  }
86
87  BINARY_OP(IsEq, ==)
88  BINARY_OP(IsNe, !=)
89  BINARY_OP(IsGe, >=)
90  BINARY_OP(IsGt, >)
91  BINARY_OP(IsLe, <=)
92  BINARY_OP(IsLt, <)
93#undef BINARY_OP
94
95  // Attach the specified value to the error message if an error has occurred
96  template <class V>
97  Tester& operator<<(const V& value) {
98    if (!ok_) {
99      ss_ << " " << value;
100    }
101    return *this;
102  }
103};
104
105#define ASSERT_TRUE(c) ::leveldb::test::Tester(__FILE__, __LINE__).Is((c), #c)
106#define ASSERT_OK(s) ::leveldb::test::Tester(__FILE__, __LINE__).IsOk((s))
107#define ASSERT_EQ(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsEq((a),(b))
108#define ASSERT_NE(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsNe((a),(b))
109#define ASSERT_GE(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsGe((a),(b))
110#define ASSERT_GT(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsGt((a),(b))
111#define ASSERT_LE(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsLe((a),(b))
112#define ASSERT_LT(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsLt((a),(b))
113
114#define TCONCAT(a,b) TCONCAT1(a,b)
115#define TCONCAT1(a,b) a##b
116
117#define TEST(base,name)                                                 \
118class TCONCAT(_Test_,name) : public base {                              \
119 public:                                                                \
120  void _Run();                                                          \
121  static void _RunIt() {                                                \
122    TCONCAT(_Test_,name) t;                                             \
123    t._Run();                                                           \
124  }                                                                     \
125};                                                                      \
126bool TCONCAT(_Test_ignored_,name) =                                     \
127  ::leveldb::test::RegisterTest(#base, #name, &TCONCAT(_Test_,name)::_RunIt); \
128void TCONCAT(_Test_,name)::_Run()
129
130// Register the specified test.  Typically not used directly, but
131// invoked via the macro expansion of TEST.
132extern bool RegisterTest(const char* base, const char* name, void (*func)());
133
134
135}  // namespace test
136}  // namespace leveldb
137
138#endif  // STORAGE_LEVELDB_UTIL_TESTHARNESS_H_
139