mirror of
https://github.com/Kitware/CMake.git
synced 2025-10-25 04:25:29 +08:00
This is a full re-write of the CMake Tutorial for CMake 3.23, both the functionality it provides, as well as the modern workflows that developers use when interfacing with CMake. Issue: #22663, #23086, #23799, #26053, #26105, #26153, #26914
156 lines
4.2 KiB
C++
156 lines
4.2 KiB
C++
#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;
|
|
}
|