Path: blob/master/Help/guide/tutorial/Step11/SimpleTest/SimpleTest.h
5022 views
#pragma once12#include <cstdio>3#include <map>4#include <string_view>56namespace SimpleTest {78using TestFunc = void (*)();910using Registry = std::map<std::string_view, TestFunc, std::less<>>;11inline Registry g_registry;1213inline Registry& registry()14{15return g_registry;16}1718struct failure19{20char const* file;21int line;22char const* expr;23};2425struct Registrar26{27template <std::size_t N>28Registrar(char const (&name)[N], TestFunc f)29{30auto [it, inserted] =31registry().emplace(std::string_view{ name, N ? (N - 1) : 0 }, f);32if (!inserted) {33std::printf("[ WARN ] duplicate test name: %.*s\n",34int(it->first.size()), it->first.data());35}36}37};3839inline Registry const& all()40{41return registry();42}43inline TestFunc find(std::string_view name)44{45auto it = registry().find(name);46return it == registry().end() ? nullptr : it->second;47}4849}5051#define SIMPLETEST_STRINGIFY(a) #a52#define SIMPLETEST_XSTRINGIFY(a) SIMPLETEST_STRINGIFY(a)53#define SIMPLETEST_CONCAT_(a, b) a##b54#define SIMPLETEST_CONCAT(a, b) SIMPLETEST_CONCAT_(a, b)5556#define TEST(name_literal) \57static void SIMPLETEST_CONCAT(_simpletest_fn_, __LINE__)(); \58static ::SimpleTest::Registrar SIMPLETEST_CONCAT(_simpletest_reg_, \59__LINE__)( \60name_literal, &SIMPLETEST_CONCAT(_simpletest_fn_, __LINE__)); \61static void SIMPLETEST_CONCAT(_simpletest_fn_, __LINE__)()6263// Minimal assertion64#define REQUIRE(expr) \65do { \66if (!(expr)) \67throw ::SimpleTest::failure{ __FILE__, __LINE__, #expr }; \68} while (0)6970int main(int argc, char** argv)71{72using namespace ::SimpleTest;7374std::string_view arg1 =75(argc >= 2) ? std::string_view{ argv[1] } : std::string_view{};7677if (arg1 == "--list") {78bool first = true;79for (auto const& [name, _] : registry()) {80if (!first)81std::printf(",");82std::printf("%.*s", int(name.size()), name.data());83first = false;84}85std::printf("\n");86return 0;87}8889if (arg1 == "--test") {90if (argc < 3) {91std::printf("usage: %s [--list] [--test <name>]\n", argv[0]);92return 2;93}9495#ifdef SIMPLETEST_CONFIG96std::printf("SimpleTest built with config: " SIMPLETEST_XSTRINGIFY(97SIMPLETEST_CONFIG) "\n");98#endif99100std::string_view name{ argv[2] };101auto it = registry().find(name);102if (it == registry().end()) {103std::printf("[ NOTFOUND ] %s\n", argv[2]);104return 2;105}106107int failed = 0;108std::printf("[ RUN ] %.*s\n", int(it->first.size()),109it->first.data());110try {111it->second();112std::printf("[ OK] %.*s\n", int(it->first.size()),113it->first.data());114} catch (failure const& f) {115std::printf("[ FAILED ] %.*s at %s:%d : %s\n", int(it->first.size()),116it->first.data(), f.file, f.line, f.expr);117failed = 1;118} catch (...) {119std::printf("[ FAILED ] %.*s : unknown exception\n",120int(it->first.size()), it->first.data());121failed = 1;122}123return failed;124}125126if (argc > 1) {127std::printf("usage: %s [--list] [--test <name>]\n", argv[0]);128return 2;129}130131#ifdef SIMPLETEST_CONFIG132std::printf("SimpleTest built with config: " SIMPLETEST_XSTRINGIFY(133SIMPLETEST_CONFIG) "\n");134#endif135136// Default: run all tests.137int failed = 0;138for (auto const& [name, func] : all()) {139std::printf("[ RUN ] %.*s\n", int(name.size()), name.data());140try {141func();142std::printf("[ OK ] %.*s\n", int(name.size()), name.data());143} catch (failure const& f) {144std::printf("[ FAILED ] %.*s at %s:%d : %s\n", int(name.size()),145name.data(), f.file, f.line, f.expr);146failed = 1;147} catch (...) {148std::printf("[ FAILED ] %.*s : unknown exception\n", int(name.size()),149name.data());150failed = 1;151}152}153return failed;154}155156157