123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- #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_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: %s\n", SIMPLETEST_CONFIG);
- #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: %s\n", SIMPLETEST_CONFIG);
- #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;
- }
|