#pragma once #include #include #include #include #include "Platform.h" #include "Runner.h" #include "Support/Compare.h" #include "Support/FileSystem.h" #include "Support/FixedString.h" #include "cpptrace/cpptrace.hpp" #include "llvm/ADT/FunctionExtras.h" #include "llvm/ADT/StringMap.h" namespace clice::testing { template struct TestSuiteDef { private: TestState state = TestState::Passed; public: using Self = Derived; void failure() { state = TestState::Failed; } void pass() { state = TestState::Passed; } void skip() { state = TestState::Skipped; } constexpr inline static auto& test_cases() { static std::vector instance; return instance; } constexpr inline static auto suites() { return std::move(test_cases()); } template inline static bool _register_suites = [] { Runner2::instance().add_suite(TestName.data(), &suites); return true; }(); template inline static bool _register_test_case = [] { auto run_test = +[] -> TestState { Derived test; if constexpr(requires { test.setup(); }) { test.setup(); } (test.*test_body)(); if constexpr(requires { test.teardown(); }) { test.teardown(); } return test.state; }; test_cases().emplace_back(case_name.data(), path.data(), line, attrs, run_test); return true; }(); }; inline void print_trace(cpptrace::stacktrace& trace, std::source_location location) { auto& frames = trace.frames; auto it = std::ranges::find_if(frames, [&](cpptrace::stacktrace_frame& frame) { return frame.filename != location.file_name(); }); frames.erase(it, frames.end()); trace.print(); } #define TEST_SUITE(name) struct name##TEST : TestSuiteDef<#name, name##TEST> #define TEST_CASE(name, ...) \ void _register_##name() { \ constexpr auto file_name = std::source_location::current().file_name(); \ constexpr auto file_len = std::string_view(file_name).size(); \ (void)_register_suites<>; \ (void)_register_test_case<#name, \ &Self::test_##name, \ fixed_string(file_name), \ std::source_location::current().line() __VA_OPT__(, ) \ __VA_ARGS__>; \ } \ void test_##name() #define CLICE_CHECK_IMPL(condition, return_action) \ do { \ if(condition) [[unlikely]] { \ auto trace = cpptrace::generate_trace(); \ clice::testing::print_trace(trace, std::source_location::current()); \ failure(); \ return_action; \ } \ } while(0) #define EXPECT_TRUE(expr) CLICE_CHECK_IMPL(!(expr), (void)0) #define EXPECT_FALSE(expr) CLICE_CHECK_IMPL((expr), (void)0) #define EXPECT_EQ(lhs, rhs) CLICE_CHECK_IMPL((lhs) != (rhs), (void)0) #define EXPECT_NE(lhs, rhs) CLICE_CHECK_IMPL((lhs) == (rhs), (void)0) #define ASSERT_TRUE(expr) CLICE_CHECK_IMPL(!(expr), return) #define ASSERT_FALSE(expr) CLICE_CHECK_IMPL((expr), return) #define ASSERT_EQ(lhs, rhs) CLICE_CHECK_IMPL((lhs) != (rhs), return) #define ASSERT_NE(lhs, rhs) CLICE_CHECK_IMPL((lhs) == (rhs), return) #define CO_ASSERT_TRUE(expr) CLICE_CHECK_IMPL(!(expr), co_return) #define CO_ASSERT_FALSE(expr) CLICE_CHECK_IMPL((expr), co_return) #define CO_ASSERT_EQ(lhs, rhs) CLICE_CHECK_IMPL((lhs) != (rhs), co_return) #define CO_ASSERT_NE(lhs, rhs) CLICE_CHECK_IMPL((lhs) == (rhs), co_return) } // namespace clice::testing