Path: blob/master/Help/guide/tutorial/Step10/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_CONCAT_(a, b) a##b52#define SIMPLETEST_CONCAT(a, b) SIMPLETEST_CONCAT_(a, b)5354#define TEST(name_literal) \55static void SIMPLETEST_CONCAT(_simpletest_fn_, __LINE__)(); \56static ::SimpleTest::Registrar SIMPLETEST_CONCAT(_simpletest_reg_, \57__LINE__)( \58name_literal, &SIMPLETEST_CONCAT(_simpletest_fn_, __LINE__)); \59static void SIMPLETEST_CONCAT(_simpletest_fn_, __LINE__)()6061// Minimal assertion62#define REQUIRE(expr) \63do { \64if (!(expr)) \65throw ::SimpleTest::failure{ __FILE__, __LINE__, #expr }; \66} while (0)6768int main(int argc, char** argv)69{70using namespace ::SimpleTest;7172std::string_view arg1 =73(argc >= 2) ? std::string_view{ argv[1] } : std::string_view{};7475if (arg1 == "--list") {76bool first = true;77for (auto const& [name, _] : registry()) {78if (!first)79std::printf(",");80std::printf("%.*s", int(name.size()), name.data());81first = false;82}83std::printf("\n");84return 0;85}8687if (arg1 == "--test") {88if (argc < 3) {89std::printf("usage: %s [--list] [--test <name>]\n", argv[0]);90return 2;91}9293#ifdef SIMPLETEST_CONFIG94std::printf("SimpleTest built with config: %s\n", SIMPLETEST_CONFIG);95#endif9697std::string_view name{ argv[2] };98auto it = registry().find(name);99if (it == registry().end()) {100std::printf("[ NOTFOUND ] %s\n", argv[2]);101return 2;102}103104int failed = 0;105std::printf("[ RUN ] %.*s\n", int(it->first.size()),106it->first.data());107try {108it->second();109std::printf("[ OK] %.*s\n", int(it->first.size()),110it->first.data());111} catch (failure const& f) {112std::printf("[ FAILED ] %.*s at %s:%d : %s\n", int(it->first.size()),113it->first.data(), f.file, f.line, f.expr);114failed = 1;115} catch (...) {116std::printf("[ FAILED ] %.*s : unknown exception\n",117int(it->first.size()), it->first.data());118failed = 1;119}120return failed;121}122123if (argc > 1) {124std::printf("usage: %s [--list] [--test <name>]\n", argv[0]);125return 2;126}127128#ifdef SIMPLETEST_CONFIG129std::printf("SimpleTest built with config: %s\n", SIMPLETEST_CONFIG);130#endif131132// Default: run all tests.133int failed = 0;134for (auto const& [name, func] : all()) {135std::printf("[ RUN ] %.*s\n", int(name.size()), name.data());136try {137func();138std::printf("[ OK ] %.*s\n", int(name.size()), name.data());139} catch (failure const& f) {140std::printf("[ FAILED ] %.*s at %s:%d : %s\n", int(name.size()),141name.data(), f.file, f.line, f.expr);142failed = 1;143} catch (...) {144std::printf("[ FAILED ] %.*s : unknown exception\n", int(name.size()),145name.data());146failed = 1;147}148}149return failed;150}151152153