File: SimpleTest.h

package info (click to toggle)
cmake 4.2.1-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 152,348 kB
  • sloc: ansic: 403,894; cpp: 303,807; sh: 4,097; python: 3,582; yacc: 3,106; lex: 1,279; f90: 538; asm: 471; lisp: 375; cs: 270; java: 266; fortran: 239; objc: 215; perl: 213; xml: 198; makefile: 108; javascript: 83; pascal: 63; tcl: 55; php: 25; ruby: 22
file content (155 lines) | stat: -rw-r--r-- 4,266 bytes parent folder | download | duplicates (2)
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
#pragma once

#include <cstdio>
#include <map>
#include <string_view>

namespace SimpleTest {

using TestFunc = void (*)();

using Registry = std::map<std::string_view, TestFunc, std::less<>>;
inline Registry g_registry;

inline Registry& registry()
{
  return g_registry;
}

struct failure
{
  char const* file;
  int line;
  char const* expr;
};

struct Registrar
{
  template <std::size_t N>
  Registrar(char const (&name)[N], TestFunc f)
  {
    auto [it, inserted] =
      registry().emplace(std::string_view{ name, N ? (N - 1) : 0 }, f);
    if (!inserted) {
      std::printf("[  WARN    ] duplicate test name: %.*s\n",
                  int(it->first.size()), it->first.data());
    }
  }
};

inline Registry const& all()
{
  return registry();
}
inline TestFunc find(std::string_view name)
{
  auto it = registry().find(name);
  return it == registry().end() ? nullptr : it->second;
}

}

#define SIMPLETEST_STRINGIFY(a) #a
#define SIMPLETEST_XSTRINGIFY(a) SIMPLETEST_STRINGIFY(a)
#define SIMPLETEST_CONCAT_(a, b) a##b
#define SIMPLETEST_CONCAT(a, b) SIMPLETEST_CONCAT_(a, b)

#define TEST(name_literal)                                                    \
  static void SIMPLETEST_CONCAT(_simpletest_fn_, __LINE__)();                 \
  static ::SimpleTest::Registrar SIMPLETEST_CONCAT(_simpletest_reg_,          \
                                                   __LINE__)(                 \
    name_literal, &SIMPLETEST_CONCAT(_simpletest_fn_, __LINE__));             \
  static void SIMPLETEST_CONCAT(_simpletest_fn_, __LINE__)()

// Minimal assertion
#define REQUIRE(expr)                                                         \
  do {                                                                        \
    if (!(expr))                                                              \
      throw ::SimpleTest::failure{ __FILE__, __LINE__, #expr };               \
  } while (0)

int main(int argc, char** argv)
{
  using namespace ::SimpleTest;

  std::string_view arg1 =
    (argc >= 2) ? std::string_view{ argv[1] } : std::string_view{};

  if (arg1 == "--list") {
    bool first = true;
    for (auto const& [name, _] : registry()) {
      if (!first)
        std::printf(",");
      std::printf("%.*s", int(name.size()), name.data());
      first = false;
    }
    std::printf("\n");
    return 0;
  }

  if (arg1 == "--test") {
    if (argc < 3) {
      std::printf("usage: %s [--list] [--test <name>]\n", argv[0]);
      return 2;
    }

#ifdef SIMPLETEST_CONFIG
    std::printf("SimpleTest built with config: " SIMPLETEST_XSTRINGIFY(
      SIMPLETEST_CONFIG) "\n");
#endif

    std::string_view name{ argv[2] };
    auto it = registry().find(name);
    if (it == registry().end()) {
      std::printf("[ NOTFOUND ] %s\n", argv[2]);
      return 2;
    }

    int failed = 0;
    std::printf("[ RUN      ] %.*s\n", int(it->first.size()),
                it->first.data());
    try {
      it->second();
      std::printf("[       OK] %.*s\n", int(it->first.size()),
                  it->first.data());
    } catch (failure const& f) {
      std::printf("[  FAILED  ] %.*s at %s:%d : %s\n", int(it->first.size()),
                  it->first.data(), f.file, f.line, f.expr);
      failed = 1;
    } catch (...) {
      std::printf("[  FAILED  ] %.*s : unknown exception\n",
                  int(it->first.size()), it->first.data());
      failed = 1;
    }
    return failed;
  }

  if (argc > 1) {
    std::printf("usage: %s [--list] [--test <name>]\n", argv[0]);
    return 2;
  }

#ifdef SIMPLETEST_CONFIG
  std::printf("SimpleTest built with config: " SIMPLETEST_XSTRINGIFY(
    SIMPLETEST_CONFIG) "\n");
#endif

  // Default: run all tests.
  int failed = 0;
  for (auto const& [name, func] : all()) {
    std::printf("[ RUN      ] %.*s\n", int(name.size()), name.data());
    try {
      func();
      std::printf("[       OK ] %.*s\n", int(name.size()), name.data());
    } catch (failure const& f) {
      std::printf("[  FAILED  ] %.*s at %s:%d : %s\n", int(name.size()),
                  name.data(), f.file, f.line, f.expr);
      failed = 1;
    } catch (...) {
      std::printf("[  FAILED  ] %.*s : unknown exception\n", int(name.size()),
                  name.data());
      failed = 1;
    }
  }
  return failed;
}