Open
Description
// src/catch2.session.ixx
module;
#include <catch2/catch_session.hpp>
export module catch2.session;
export namespace Catch
{
using Catch::Session;
} // namespace Catch
// src/catch.ixx
module;
#include <catch2/catch_test_macros.hpp>
export module catch2;
export import catch2.session;
import std;
::Catch::SourceLineInfo lineInfo(std::source_location _location)
{
return ::Catch::SourceLineInfo(_location.file_name(), static_cast<std::size_t>(_location.line()));
}
void test(
bool _expression, std::string _message, Catch::StringRef _macroName,
Catch::ResultDisposition::Flags _resultDisposition, std::source_location _location = std::source_location::current()
)
{
do
{
Catch::AssertionHandler catchAssertionHandler(
_macroName, lineInfo(_location), Catch::StringRef(_message), _resultDisposition
);
try
{
catchAssertionHandler.handleExpr(Catch::Decomposer() <= _expression);
}
catch (...)
{
(catchAssertionHandler).handleUnexpectedInflightException();
}
catchAssertionHandler.complete();
} while ((void)0, (false) && static_cast<const bool&>(!!(_expression)));
}
export namespace Catch
{
void require(
bool _expression, std::string _message = "", std::source_location _location = std::source_location::current()
)
{
test(_expression, _message, "REQUIRE"_catch_sr, Catch::ResultDisposition::Normal, _location);
}
void check(
bool _expression, std::string _message = "", std::source_location _location = std::source_location::current()
)
{
test(_expression, _message, "CHECK"_catch_sr, Catch::ResultDisposition::ContinueOnFailure, _location);
}
void test_case(
std::string _name, std::string _tags, void (*_fn)(),
std::source_location _location = std::source_location::current()
)
{
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
const Catch::AutoReg autoRegistrar(
Catch::makeTestInvoker(_fn), lineInfo(_location), Catch::StringRef(), Catch::NameAndTags{_name, _tags}
);
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
}
void session(
std::string _message, std::function<void()> _fn,
std::source_location _location = std::source_location::current()
)
{
if (Catch::Section const& catch_internal_Section = Catch::Section(lineInfo(_location), _message))
{
_fn();
}
}
} // namespace Catch
example:
// src/main.cpp
import std;
import catch2;
#ifndef CATCH_STRING
# define CATCH_STRING(_str) #_str
#endif // !CATCH_STRING
#ifndef CATCH_EXPRESSION
# define CATCH_EXPRESSION(_expression) _expression, CATCH_STRING(_expression)
#endif // !CATCH_EXPRESSION
#ifndef REQUIRE
# define REQUIRE(_expression) Catch::require(CATCH_EXPRESSION(_expression))
#endif // !REQUIRE
#ifndef CHECK
# define CHECK(_expression) Catch::check(CATCH_EXPRESSION(_expression))
#endif // !CHECK
unsigned int Factorial(unsigned int number)
{
return number <= 1 ? number : Factorial(number - 1) * number;
}
void factorials_are_computed()
{
REQUIRE(Factorial(1) == 1);
REQUIRE(Factorial(2) == 2);
REQUIRE(Factorial(3) == 6);
REQUIRE(Factorial(10) == 3628800);
}
void vectors_can_be_sized_and_resized()
{
using Catch::session;
// This setup will be done 4 times in total, once for each section
std::vector<int> v(5);
REQUIRE(v.size() == 5);
REQUIRE(v.capacity() >= 5);
session(
"resizing bigger changes size and capacity",
[&]
{
v.resize(10);
REQUIRE(v.size() == 10);
REQUIRE(v.capacity() >= 10);
}
);
session(
"resizing smaller changes size but not capacity",
[&]
{
v.resize(0);
REQUIRE(v.size() == 0);
REQUIRE(v.capacity() >= 5);
}
);
session(
"reserving bigger changes capacity but not size",
[&]
{
v.reserve(10);
REQUIRE(v.size() == 5);
REQUIRE(v.capacity() >= 10);
}
);
session(
"reserving smaller does not change size or capacity",
[&]
{
v.reserve(0);
REQUIRE(v.size() == 5);
REQUIRE(v.capacity() >= 5);
}
);
}
int main(int _argc, char* _argv[])
{
using Catch::test_case;
test_case("Factorials are computed", "[factorial]", &factorials_are_computed);
test_case("vectors can be sized and resized", "[vector]", &vectors_can_be_sized_and_resized);
{
test_case(
"base", "[lambda]",
[]
{
using namespace std::literals::string_literals;
REQUIRE(1 + 2 == 3);
REQUIRE("123"s + "456"s == "123456"s);
}
);
}
test_case(
"without macro", "[lambda]",
[]
{
Catch::require(1 + 2 == 3, "1 + 2 == 3");
Catch::check(false, "false");
}
);
auto result = Catch::Session().run(_argc, _argv);
return result;
}
CMake
# CMakeLists.txt
cmake_minimum_required(VERSION 3.28...4.0)
project(catch2-module-example)
find_package(Catch2 CONFIG REQUIRED)
set(msvc_options)
list(APPEND msvc_options "/W4" "/MP")
list(APPEND msvc_options "/experimental:module")
list(APPEND msvc_options "/utf-8")
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:${msvc_options}>")
add_library(catch2_module)
target_sources(catch2_module
PRIVATE FILE_SET CXX_MODULES FILES
src/catch2.ixx
src/catch2.session.ixx)
target_include_directories(catch2_module PUBLIC include)
target_link_libraries(catch2_module PUBLIC Catch2::Catch2)
target_compile_features(catch2_module PRIVATE cxx_std_23)
add_executable(main)
target_sources(main
PRIVATE
src/main.cpp
)
target_link_libraries(main PRIVATE catch2_module)
target_compile_features(main PRIVATE cxx_std_23)
I think Catch2 could consider adding support for modules.
Metadata
Metadata
Assignees
Labels
No labels