catchorg / catchorg/Catch2

Catch2 C++20 module example.

Open
#2,983 0 comments 3 reactions 0 assignees View on GitHub
Dominant language
C++
Stars
21.5k
Forks
3.5k
Avg merge
3d 16h
Merged PRs (30d)
2

Description

```cpp
// src/catch2.session.ixx
module;
#include

export module catch2.session;

export namespace Catch
{
using Catch::Session;
} // namespace Catch

```

```cpp
// src/catch.ixx
module;
#include

export module catch2;
export import catch2.session;
import std;

::Catch::SourceLineInfo lineInfo(std::source_location _location)
{
return ::Catch::SourceLineInfo(_location.file_name(), static_cast(_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(!!(_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 _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:
```cpp
// 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 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
```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("$<$:${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)
````

[Full repo](https://github.com/gwankyun/catch2-module-example.git)

I think Catch2 could consider adding support for modules.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.