diff --git a/.github/workflows/modules.yml b/.github/workflows/modules.yml new file mode 100644 index 0000000..fdc831e --- /dev/null +++ b/.github/workflows/modules.yml @@ -0,0 +1,55 @@ +name: Build & Test with modules + +on: + push: + branches: + - main + pull_request: + branches: + - main + workflow_dispatch: + release: + types: [published] + +jobs: + build: + name: ${{ matrix.runs_on }}-${{ matrix.compiler }}-${{ matrix.configure_preset }} + runs-on: ${{ matrix.runs_on }} + strategy: + fail-fast: false + matrix: + include: + - runs_on: windows-2025-vs2026 + compiler: msvc-14.50 + configure_preset: "x64-vs" + build_preset: "x64-vs-build" + test_preset : "x64-vs-test" + # To be uncommented once GitHub Actions add GCC 15 or 16 with Ubuntu 26 + # - runs_on: ubuntu-latest + # compiler: gcc-15 + # configure_preset: "linux-debug" + # build_preset: "linux-debug-build" + # test_preset : "linux-debug-test" + # - runs_on: ubuntu-latest + # compiler: clang-18 + # cc: clang + # cxx: clang++ + # configure_preset: "linux-debug" + # build_preset: "linux-debug-build" + # test_preset : "linux-debug-test" + steps: + + - uses: actions/checkout@v6 + + - uses: lukka/get-cmake@latest + + - name: "Build & Test" + uses: lukka/run-cmake@v10 + env: + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + with: + configurePreset: ${{ matrix.configure_preset }} + configurePresetAdditionalArgs: "['-DUT_ENABLE_MODULES=ON']" + buildPreset: ${{ matrix.build_preset }} + testPreset: ${{ matrix.test_preset }} diff --git a/.gitignore b/.gitignore index efe9691..e72a180 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ build* +out/ compile_commands.json .vscode .cache .DS_Store +.vs diff --git a/CMakeLists.txt b/CMakeLists.txt index ec7cfcd..d8cb519 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,40 +1,76 @@ -cmake_minimum_required(VERSION 3.24) +cmake_minimum_required(VERSION 3.31) # Raise to 4.3 on availability global release and availability in CI/CD + +set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "d0edc3af-4c50-42ea-a356-e2862fe7a444") # Should be removed after 4.3 is released include(cmake/prelude.cmake) project( - ut - VERSION 1.1.0 - LANGUAGES CXX + ut + VERSION 1.2.0 + LANGUAGES CXX ) include(cmake/project-is-top-level.cmake) include(cmake/variables.cmake) -add_library(${PROJECT_NAME}_${PROJECT_NAME} INTERFACE) +option(UT_ENABLE_MODULES "Enable modules with import std" OFF) +option(UT_COMPILE_TIME "Enable compile time features" OFF) + +if(UT_ENABLE_MODULES) + if(NOT CMAKE_GENERATOR MATCHES "Visual Studio") ## Support should be added with 4.4, todo: check when available + set(CMAKE_CXX_MODULE_STD 1) + endif() +endif() + +if(UT_ENABLE_MODULES) + add_library(${PROJECT_NAME}_${PROJECT_NAME} STATIC) + set(UT_LIB_TYPE PUBLIC) +else() + add_library(${PROJECT_NAME}_${PROJECT_NAME} INTERFACE) + set(UT_LIB_TYPE INTERFACE) +endif() add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}_${PROJECT_NAME}) -if (MSVC) - string(REGEX MATCH "\/cl(.exe)?$" matched_cl ${CMAKE_CXX_COMPILER}) - if (matched_cl) - # for a C++ standards compliant preprocessor, not needed for clang-cl - target_compile_options(${PROJECT_NAME}_${PROJECT_NAME} INTERFACE "/Zc:preprocessor" /GL /permissive- /Zc:lambda) - target_link_options(${PROJECT_NAME}_${PROJECT_NAME} INTERFACE /LTCG /INCREMENTAL:NO) - endif() +if(PROJECT_IS_TOP_LEVEL) + include(cmake/dev-mode.cmake) +endif() + +target_compile_features(${PROJECT_NAME}_${PROJECT_NAME} ${UT_LIB_TYPE} cxx_std_23) + +if(UT_ENABLE_MODULES) + target_sources(${PROJECT_NAME}_${PROJECT_NAME} + PUBLIC + FILE_SET modules TYPE CXX_MODULES + BASE_DIRS "${PROJECT_SOURCE_DIR}/modules" + FILES + "${PROJECT_SOURCE_DIR}/modules/ut.ixx" + ) + + target_compile_definitions(${PROJECT_NAME}_${PROJECT_NAME} PRIVATE UT_ENABLE_MODULES) +endif() + +if(UT_COMPILE_TIME) + target_compile_definitions(${PROJECT_NAME}_${PROJECT_NAME} ${UT_LIB_TYPE} UT_COMPILE_TIME) +endif() + +if(MSVC) + string(REGEX MATCH "\/cl(.exe)?$" matched_cl ${CMAKE_CXX_COMPILER}) + if(matched_cl) + # for a C++ standards compliant preprocessor, not needed for clang-cl + target_compile_options(${PROJECT_NAME}_${PROJECT_NAME} INTERFACE "/Zc:preprocessor" /GL /permissive- /Zc:lambda) + target_link_options(${PROJECT_NAME}_${PROJECT_NAME} INTERFACE /LTCG /INCREMENTAL:NO) + endif() endif() set_property(TARGET ${PROJECT_NAME}_${PROJECT_NAME} PROPERTY EXPORT_NAME ${PROJECT_NAME}) -target_compile_features(${PROJECT_NAME}_${PROJECT_NAME} INTERFACE cxx_std_23) target_include_directories( - ${PROJECT_NAME}_${PROJECT_NAME} ${warning_guard} - INTERFACE "$" + ${PROJECT_NAME}_${PROJECT_NAME} ${warning_guard} + INTERFACE + "$" + "$" ) if(NOT CMAKE_SKIP_INSTALL_RULES) include(cmake/install-rules.cmake) endif() - -if (PROJECT_IS_TOP_LEVEL) - include(cmake/dev-mode.cmake) -endif() \ No newline at end of file diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 0000000..cbae41f --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,132 @@ +{ + "version": 9, + "cmakeMinimumRequired": { + "major": 3, + "minor": 31, + "patch": 0 + }, + "configurePresets": [ + { + "name": "windows-base", + "hidden": true, + "generator": "Ninja", + "binaryDir": "${sourceDir}/out/build/${presetName}", + "installDir": "${sourceDir}/out/install/${presetName}", + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + }, + { + "name": "x64", + "displayName": "x64", + "description": "Target Windows (64-bit) with the Visual Studio development environment.", + "inherits": "windows-base", + "architecture": { + "value": "x64", + "strategy": "external" + } + }, + { + "name": "windows-base-preview", + "description": "Base preset for MSVC v14.51", + "hidden": true, + "generator": "Ninja", + "binaryDir": "${sourceDir}/out/build/${presetName}", + "installDir": "${sourceDir}/out/install/${presetName}", + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + }, + "toolset": { + "value": "v145,host=x64,version=14.51" + } + }, + { + "name": "x64-preview", + "displayName": "x64 Debug (MSVC v14.51 Preview)", + "inherits": "windows-base-preview", + "architecture": { + "value": "x64", + "strategy": "external" + } + }, + { + "name": "windows-vs-base", + "hidden": true, + "generator": "Visual Studio 18 2026", + "binaryDir": "${sourceDir}/out/build/${presetName}", + "installDir": "${sourceDir}/out/install/${presetName}", + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + }, + { + "name": "x64-vs", + "displayName": "x64 (VS generator)", + "inherits": "windows-vs-base", + "architecture": "x64" + }, + { + "name": "linux-debug", + "displayName": "Linux Debug", + "generator": "Ninja", + "binaryDir": "${sourceDir}/out/build/${presetName}", + "installDir": "${sourceDir}/out/install/${presetName}", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + }, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Linux" + } + } + ], + "buildPresets": [ + { + "name": "x64-build", + "configurePreset": "x64" + }, + { + "name": "x64-vs-build", + "configurePreset": "x64-vs", + "configuration": "Debug" + }, + { + "name": "x64-preview-build", + "configurePreset": "x64-preview" + }, + { + "name": "linux-debug-build", + "configurePreset": "linux-debug" + } + ], + "testPresets": [ + { + "name": "x64-test", + "configurePreset": "x64" + }, + + { + "name": "x64-vs-test", + "configurePreset": "x64-vs", + "configuration": "Debug", + "output": { + "outputOnFailure": true + } + }, + { + "name": "x64-preview-test", + "configurePreset": "x64-preview" + }, + { + "name": "linux-debug-test", + "configurePreset": "linux-debug" + } + ] +} diff --git a/README.md b/README.md index 7ff30b4..35e5d3f 100644 --- a/README.md +++ b/README.md @@ -12,12 +12,28 @@ A simple and fast compiling unit test library. ### Features -- Single header +#### Single header -To enable compile time testing you must define the macro: `UT_COMPILE_TIME` +To enable compile time testing, set the option `UT_COMPILE_TIME` to ON. For example: +```cmake +set(UT_COMPILE_TIME ON) +``` Runtime testing is always enabled. +#### Modules support + +The library supports C++ 20/23 modules. To enable, set the option `UT_ENABLE_MODULES` to ON. For example: +```cmake +set (UT_ENABLE_MODULES ON) +``` +You can then import the library: +```cpp +import ut; +``` + +Please note that modules integration requires compiler and build tools that support `import std`. + ### Running Specific Tests Use the `UT_RUN` environment variable to run specific tests by name: @@ -33,6 +49,7 @@ UT_RUN="[test1,test2,test3]" ./my_tests ### Requirements - C++23 +- CMake 3.31 ## Example diff --git a/cmake/dev-mode.cmake b/cmake/dev-mode.cmake index 8bc7345..292596d 100644 --- a/cmake/dev-mode.cmake +++ b/cmake/dev-mode.cmake @@ -78,3 +78,9 @@ set_tests_properties(ut_run_no_match PROPERTIES ENVIRONMENT "UT_RUN=nonexistent" PASS_REGULAR_EXPRESSION "tests: 0 \\(0 passed" ) + +if (UT_ENABLE_MODULES) + add_executable(ut_module_consumer_tests "${PROJECT_SOURCE_DIR}/tests/ut_module_consumer_tests.cpp") + target_link_libraries(ut_module_consumer_tests PRIVATE ${PROJECT_NAME}::${PROJECT_NAME}) + add_test(NAME ut_module_consumer_import COMMAND ut_module_consumer_tests) +endif() diff --git a/cmake/install-config.cmake b/cmake/install-config.cmake index e9af6c2..e6b051b 100644 --- a/cmake/install-config.cmake +++ b/cmake/install-config.cmake @@ -1 +1 @@ -include("${CMAKE_CURRENT_LIST_DIR}/${PROJECT_NAME}Targets.cmake") \ No newline at end of file +include("${CMAKE_CURRENT_LIST_DIR}/utTargets.cmake") diff --git a/cmake/install-rules.cmake b/cmake/install-rules.cmake index 261fa29..e3ef951 100644 --- a/cmake/install-rules.cmake +++ b/cmake/install-rules.cmake @@ -1,7 +1,3 @@ -if(PROJECT_IS_TOP_LEVEL) - set(CMAKE_INSTALL_INCLUDEDIR include/${PROJECT_NAME} CACHE PATH "") -endif() - # Project is configured with no languages, so tell GNUInstallDirs the lib dir set(CMAKE_INSTALL_LIBDIR lib CACHE PATH "") @@ -17,11 +13,21 @@ install( COMPONENT ${PROJECT_NAME}_Development ) -install( - TARGETS ${PROJECT_NAME}_${PROJECT_NAME} - EXPORT ${PROJECT_NAME}Targets - INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" -) +if(UT_ENABLE_MODULES) + install( + TARGETS ${PROJECT_NAME}_${PROJECT_NAME} + EXPORT ${PROJECT_NAME}Targets + FILE_SET modules DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" + CXX_MODULES_BMI DESTINATION "" # BMIs are not portable; suppress installation + COMPONENT ${PROJECT_NAME}_Development + ) +else() + install( + TARGETS ${PROJECT_NAME}_${PROJECT_NAME} + EXPORT ${PROJECT_NAME}Targets + COMPONENT ${PROJECT_NAME}_Development + ) +endif() write_basic_package_version_file( "${package}ConfigVersion.cmake" @@ -53,6 +59,7 @@ install( EXPORT ${PROJECT_NAME}Targets NAMESPACE ${PROJECT_NAME}:: DESTINATION "${zb8_INSTALL_CMAKEDIR}" + CXX_MODULES_DIRECTORY modules COMPONENT ${PROJECT_NAME}_Development ) diff --git a/include/ut/ut.hpp b/include/ut/ut.hpp index 9b6b258..10af7f9 100644 --- a/include/ut/ut.hpp +++ b/include/ut/ut.hpp @@ -333,8 +333,7 @@ namespace ut return log{eval{test_passed, loc}.passed}; } -#if __cplusplus >= 202300L - // if we have C++23 +#if __cpp_multidimensional_subscript >= 202211L && !defined(_MSC_VER) template requires std::convertible_to constexpr auto operator[](T&& test_passed, diff --git a/modules/ut.ixx b/modules/ut.ixx new file mode 100644 index 0000000..9b68004 --- /dev/null +++ b/modules/ut.ixx @@ -0,0 +1,409 @@ +// Refactored from: +// Copyright (c) 2024 Kris Jusiak (kris at jusiak dot net) +// Distributed under the Boost Software License, Version 1.0. +// (See http://www.boost.org/LICENSE_1_0.txt) +// +// UT: A simple C++23 unit testing library with compile-time and run-time support. +// +// Running specific tests: +// Set the UT_RUN environment variable to run only specific tests by name. +// Single test: UT_RUN="my test" ./my_tests +// Multiple tests: UT_RUN="[test1,test2,test3]" ./my_tests +// If UT_RUN is not set, all tests run (default behavior). +export module ut; + +import std; + +namespace ut +{ + namespace detail + { + constexpr bool fatal = true; + + template + constexpr auto is_mutable_lambda_v = false; + template + constexpr auto is_mutable_lambda_v = true; + template + constexpr auto is_mutable_lambda_v = false; + template + constexpr auto has_capture_lambda_v = sizeof(Fn) > 1ul; + + template + struct identity + { + using type = T; + }; + } + + export template + struct fixed_string + { + constexpr fixed_string(const char (&str)[Size]) + { + for (std::size_t i = 0; i < Size; ++i) { + storage[i] = str[i]; + } + } + [[nodiscard]] constexpr auto operator[](const auto i) const { return storage[i]; } + [[nodiscard]] constexpr auto data() const { return storage; } + [[nodiscard]] static constexpr auto size() { return Size - 1; } + [[nodiscard]] constexpr operator std::string_view() const { return {storage, Size - 1}; } + constexpr friend auto operator<<(auto& os, const fixed_string& fs) -> decltype(auto) + { + return os << std::string_view{fs.storage, fs.size()}; + } + char storage[Size]{}; + }; + + namespace events + { + enum class mode { run_time, compile_time }; + template + struct test_begin + { + std::string_view file_name{}; + std::uint_least32_t line{}; + std::string_view name{}; + }; + template + struct test_end + { + std::string_view file_name{}; + std::uint_least32_t line{}; + std::string_view name{}; + enum { FAILED, PASSED, COMPILE_TIME } result{}; + }; + struct assertion + { + bool passed{}; + std::string_view file_name{}; + std::uint_least32_t line{}; + }; + struct fatal + {}; + template + struct log + { + const Msg& msg; + bool result{}; + }; + struct summary + { + enum { FAILED, PASSED, COMPILE_TIME }; + std::size_t asserts[2]{}; /* FAILED, PASSED */ + std::size_t tests[3]{}; /* FAILED, PASSED, COMPILE_TIME */ + }; + } // namespace events + + template + struct outputter + { + template + constexpr auto on(const events::test_begin&) + {} + constexpr auto on(const events::test_begin& event) { current_test = event; } + template + constexpr auto on(const events::test_end&) + {} + constexpr auto on(const events::assertion& event) + { + if (not event.passed && not std::is_constant_evaluated()) { + if (initial_new_line == '\n') { + os << initial_new_line; + } + else { + initial_new_line = '\n'; + } + os << "FAILED \"" << current_test.name << "\" "; + const auto n = event.file_name.size(); + const auto start = n <= 32 ? 0 : n - 32; + if (start > 0) { + os << "..."; + } + os << event.file_name.substr(start, n) << ":" << event.line << '\n'; + } + } + constexpr auto on(const events::fatal&) {} + template + constexpr auto on(const events::log& event) + { + if (!std::is_constant_evaluated() && !event.result) { + os << ' ' << event.msg; + } + } + constexpr auto on(const events::summary& event) + { + using namespace events; + if (!std::is_constant_evaluated()) { + if (event.asserts[summary::FAILED] || event.tests[summary::FAILED]) { + os << "\nFAILED\n"; + } + else { + os << "\nPASSED\n"; + } + os << "tests: " << (event.tests[summary::PASSED] + event.tests[summary::FAILED]) << " (" + << event.tests[summary::PASSED] << " passed, " << event.tests[summary::FAILED] << " failed, " + << event.tests[summary::COMPILE_TIME] << " compile-time)\n" + << "asserts: " << (event.asserts[summary::PASSED] + event.asserts[summary::FAILED]) << " (" + << event.asserts[summary::PASSED] << " passed, " << event.asserts[summary::FAILED] << " failed)\n"; + } + } + + OStream& os; + events::test_begin current_test{}; + char initial_new_line{}; + }; + + template + struct reporter + { + constexpr auto on(const events::test_begin& event) + { + asserts_failed[current++] = summary.asserts[events::summary::FAILED]; + outputter.on(event); + } + constexpr auto on(const events::test_end& event) + { + const auto result = summary.asserts[events::summary::FAILED] == asserts_failed[--current]; + ++summary.tests[result]; + events::test_end te{event}; + te.result = static_cast(result); + outputter.on(te); + } + constexpr auto on(const events::test_begin&) + { + ++summary.tests[events::summary::COMPILE_TIME]; + } + constexpr auto on(const events::test_end&) {} + constexpr auto on(const events::assertion& event) + { + if (event.passed) { + ++summary.asserts[events::summary::PASSED]; + } + else { + ++summary.asserts[events::summary::FAILED]; + } + outputter.on(event); + } + constexpr auto on(const events::fatal& event) + { + ++summary.tests[events::summary::FAILED]; + outputter.on(event); + outputter.on(summary); + std::exit(1); + } + + ~reporter() + { // non constexpr + outputter.on(summary); + if (summary.asserts[events::summary::FAILED]) { + std::exit(1); + } + } + + Outputter& outputter; + events::summary summary{}; + std::size_t asserts_failed[MaxDepth]{}; + std::size_t current{}; + }; + + template + struct runner + { + template + constexpr auto on(Test test, const std::string_view file_name, std::uint_least32_t line, const std::string_view name) + -> bool + { + if (std::is_constant_evaluated()) { + if constexpr (requires { requires detail::is_mutable_lambda_v; }) { + return false; + } + else { + test(); + return true; + } + } + else { + static const std::string_view filter = []() -> std::string_view { + if (const char* env = std::getenv("UT_RUN")) return env; + return {}; + }(); + + auto matches_filter = [](std::string_view test_name, std::string_view f) { + if (f.empty()) return true; + + // Array format: [test1,test2,test3] + if (f.starts_with('[') && f.ends_with(']')) { + auto content = f.substr(1, f.size() - 2); + std::size_t pos = 0; + while (pos < content.size()) { + auto comma = content.find(',', pos); + auto token = + (comma == std::string_view::npos) ? content.substr(pos) : content.substr(pos, comma - pos); + if (token == test_name) return true; + if (comma == std::string_view::npos) break; + pos = comma + 1; + } + return false; + } + + // Single test name + return test_name == f; + }; + + if (!matches_filter(name, filter)) { + return false; + } + +#if defined(UT_COMPILE_TIME) + if constexpr (!requires { requires detail::is_mutable_lambda_v; } && + !detail::has_capture_lambda_v) { + reporter.on(events::test_begin{file_name, line, name}); + static_assert((test(), "[FAILED]")); + reporter.on(events::test_end{file_name, line, name}); + } +#endif + + reporter.on(events::test_begin{file_name, line, name}); + test(); + reporter.on(events::test_end{file_name, line, name}); + } + return true; + } + + Reporter& reporter; + }; +} + +namespace ut +{ + struct cfg_t + { + struct stream_t + { + friend constexpr decltype(auto) operator<<([[maybe_unused]] auto& os, [[maybe_unused]] const auto& t) + { + static_assert(requires { std::clog << t; }); + return (std::clog << t); + } + } stream; + ut::outputter outputter{stream}; + ut::reporter reporter{outputter}; + ut::runner runner{reporter}; + }; + + export extern cfg_t cfg; + cfg_t cfg{}; + + struct expect_fn final + { + template + struct eval final + { + template + requires std::convertible_to + constexpr eval(T&& test_passed, auto&& loc) : passed(static_cast(test_passed)) + { + if (std::is_constant_evaluated()) { + if (not passed) { + std::abort(); + } + } + else { + cfg.reporter.on(events::assertion{passed, loc.file_name(), loc.line()}); + if (not passed) { + if constexpr (Fatal) { + cfg.reporter.on(events::fatal{}); + } + } + } + } + bool passed{}; + }; + + template + requires std::convertible_to + constexpr auto operator()(T&& test_passed, + const std::source_location& loc = std::source_location::current()) const + { + return log{eval{test_passed, loc}.passed}; + } + + template + requires std::convertible_to + constexpr auto operator[](T&& test_passed, + const std::source_location& loc = std::source_location::current()) const + { + return log{eval{test_passed, loc}.passed}; + } + + private: + struct log final + { + bool passed{}; + + template + constexpr const auto& operator<<(const Msg& msg) const + { + cfg.outputter.on(events::log{msg, passed}); + return *this; + } + }; + }; + + export inline constexpr expect_fn expect{}; + + export struct suite final + { + suite(auto&& tests) { tests(); } + }; + + namespace detail + { + export template + struct test final + { + constexpr auto operator=(auto test) const + { + const auto& loc = std::source_location::current(); + return cfg.runner.on(test, loc.file_name(), loc.line(), Name); + } + }; + + export struct runtime_test final + { + std::string_view name{}; + + constexpr auto operator=(auto test) const + { + const auto& loc = std::source_location::current(); + return cfg.runner.on(test, loc.file_name(), loc.line(), name); + } + }; + } + + export constexpr auto test(const std::string_view name) { return detail::runtime_test{name}; } + + export template + [[nodiscard]] constexpr auto operator""_test() + { + return detail::test{}; + } + +#if __cpp_exceptions + export template + constexpr auto throws(Callable&& c, Args&&... args) + { + try { + std::forward(c)(std::forward(args)...); + } + catch (...) { + return true; + } + return false; + } +#endif +} + +export using ut::operator""_test; diff --git a/src/main.cpp b/src/main.cpp index c2821ea..accc61c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,12 +1,15 @@ -#define UT_COMPILE_TIME +#ifndef UT_ENABLE_MODULES +#include +#include #include "ut/ut.hpp" +#else +import ut; +import std; +#endif using namespace ut; -#include -#include - suite tests = [] { "double"_test = [] { double v = 42.1; diff --git a/tests/ut_module_consumer_tests.cpp b/tests/ut_module_consumer_tests.cpp new file mode 100644 index 0000000..662ef0e --- /dev/null +++ b/tests/ut_module_consumer_tests.cpp @@ -0,0 +1,16 @@ +import ut; + +using namespace ut; + +suite filter_tests = [] { + "alpha"_test = [] { expect(true); }; + + "beta"_test = [] { expect(true); }; + + "gamma"_test = [] { expect(true); }; + + test("delta test") = [] { expect(true); }; + + test("epsilon test") = [] { expect(true); }; +}; +int main() {} diff --git a/tests/ut_run_tests.cpp b/tests/ut_run_tests.cpp index ecdf5ba..1e1ef4c 100644 --- a/tests/ut_run_tests.cpp +++ b/tests/ut_run_tests.cpp @@ -1,7 +1,10 @@ // Tests for UT_RUN environment variable filtering feature // This file is used by CTest to verify the UT_RUN functionality - +#ifndef UT_ENABLE_MODULES #include "ut/ut.hpp" +#else +import ut; +#endif using namespace ut;