Commit aba625e2 authored by Dominik Charousset's avatar Dominik Charousset

Use the Canonical Project Structure for caf_test

For the Canonical Project Structure, see
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1204r0.html.

With the new structure, we drop the `src` sub-directory and place the
source files next to the header files. Further, we place the unit test
next to the source file with `.test.cpp` suffix.

Instead of assembling all unit tests into a single large binary and then
have `ctest` pick suites individually, we simply create one binary per
unit test now. This makes the entire CMake setup much easier.

This also frees up the `test` folder (that we will probably rename to
`tests`) for module tests.
parent 0556808c
...@@ -336,11 +336,25 @@ function(caf_add_component name) ...@@ -336,11 +336,25 @@ function(caf_add_component name)
set(pub_lib_target "libcaf_${name}") set(pub_lib_target "libcaf_${name}")
set(obj_lib_target "libcaf_${name}_obj") set(obj_lib_target "libcaf_${name}_obj")
set(targets ${pub_lib_target} ${obj_lib_target}) set(targets ${pub_lib_target} ${obj_lib_target})
add_library(${obj_lib_target} OBJECT add_library(${obj_lib_target} OBJECT ${CAF_ADD_COMPONENT_HEADERS})
${CAF_ADD_COMPONENT_HEADERS} ${CAF_ADD_COMPONENT_SOURCES})
set_property(TARGET ${obj_lib_target} PROPERTY POSITION_INDEPENDENT_CODE ON) set_property(TARGET ${obj_lib_target} PROPERTY POSITION_INDEPENDENT_CODE ON)
caf_target_link_libraries(${obj_lib_target} caf_target_link_libraries(${obj_lib_target}
${CAF_ADD_COMPONENT_DEPENDENCIES}) ${CAF_ADD_COMPONENT_DEPENDENCIES})
foreach(source_file ${CAF_ADD_COMPONENT_SOURCES})
get_filename_component(ext ${source_file} EXT)
if(ext STREQUAL ".cpp")
target_sources(${obj_lib_target} PRIVATE ${source_file})
elseif(ext STREQUAL ".test.cpp" AND CAF_ENABLE_TESTING)
get_filename_component(test_name ${source_file} NAME_WE)
get_filename_component(test_path ${source_file} DIRECTORY)
string(REPLACE "/" "-" test_name "${test_path}/${test_name}-test")
add_executable("${test_name}" ${source_file}
$<TARGET_OBJECTS:${obj_lib_target}>)
target_link_libraries(${test_name} PRIVATE libcaf_test
${CAF_ADD_COMPONENT_DEPENDENCIES})
add_test(NAME ${test_name} COMMAND ${test_name})
endif()
endforeach()
if(NOT TARGET ${pub_lib_target}) if(NOT TARGET ${pub_lib_target})
add_library(${pub_lib_target} add_library(${pub_lib_target}
"${PROJECT_SOURCE_DIR}/cmake/dummy.cpp" "${PROJECT_SOURCE_DIR}/cmake/dummy.cpp"
......
...@@ -16,27 +16,23 @@ caf_add_component( ...@@ -16,27 +16,23 @@ caf_add_component(
HEADERS HEADERS
${CAF_TEST_HEADERS} ${CAF_TEST_HEADERS}
SOURCES SOURCES
src/test/and_given.cpp caf/test/and_given.cpp
src/test/and_then.cpp caf/test/and_then.cpp
src/test/and_when.cpp caf/test/and_when.cpp
src/test/block.cpp caf/test/block.cpp
src/test/context.cpp caf/test/context.cpp
src/test/factory.cpp caf/test/factory.cpp
src/test/given.cpp caf/test/given.cpp
src/test/nesting_error.cpp caf/test/nesting_error.cpp
src/test/registry.cpp caf/test/registry.cpp
src/test/reporter.cpp caf/test/reporter.cpp
src/test/runnable.cpp caf/test/runnable.cpp
src/test/runner.cpp caf/test/runner.cpp
src/test/scenario.cpp caf/test/scenario.cpp
src/test/scope.cpp caf/test/scenario.test.cpp
src/test/section.cpp caf/test/scope.cpp
src/test/test.cpp caf/test/section.cpp
src/test/then.cpp caf/test/test.cpp
src/test/when.cpp caf/test/test.test.cpp
TEST_SOURCES caf/test/then.cpp
test/test-test.cpp caf/test/when.cpp)
TEST_SUITES
test.block_type
test.scenario
test.test)
...@@ -5,11 +5,10 @@ ...@@ -5,11 +5,10 @@
#include "caf/test/block_type.hpp" #include "caf/test/block_type.hpp"
#include "caf/test/test.hpp" #include "caf/test/test.hpp"
#include "caf/test/caf_test_main.hpp"
using caf::test::block_type; using caf::test::block_type;
SUITE("caf.test.block_type") {
TEST("is_extension checks whether a block type needs a predecessor") { TEST("is_extension checks whether a block type needs a predecessor") {
using caf::test::is_extension; using caf::test::is_extension;
SECTION("is_extension is true for all AND_* types and BUT") { SECTION("is_extension is true for all AND_* types and BUT") {
...@@ -28,4 +27,4 @@ TEST("is_extension checks whether a block type needs a predecessor") { ...@@ -28,4 +27,4 @@ TEST("is_extension checks whether a block type needs a predecessor") {
} }
} }
} // SUITE("caf.test.block_type") CAF_TEST_MAIN()
...@@ -36,6 +36,7 @@ public: ...@@ -36,6 +36,7 @@ public:
static suites_map suites(); static suites_map suites();
/// Adds a new test factory to the suite `suite_name`.
template <class TestImpl> template <class TestImpl>
static ptrdiff_t add(std::string_view suite_name, static ptrdiff_t add(std::string_view suite_name,
std::string_view description, block_type type) { std::string_view description, block_type type) {
...@@ -49,6 +50,12 @@ public: ...@@ -49,6 +50,12 @@ public:
return instance().add(new impl(suite_name, description, type)); return instance().add(new impl(suite_name, description, type));
} }
/// Adds a new test factory to the "anonymous" suite named `$`.
template <class TestImpl>
static ptrdiff_t add(unit_t, std::string_view description, block_type type) {
return add<TestImpl>("$", description, type);
}
private: private:
ptrdiff_t add(factory* new_factory); ptrdiff_t add(factory* new_factory);
......
...@@ -220,7 +220,7 @@ public: ...@@ -220,7 +220,7 @@ public:
" $B(Time): $Y({1:.3f}s)\n" " $B(Time): $Y({1:.3f}s)\n"
" $B(Checks): ${2}({3} / {4})\n" " $B(Checks): ${2}({3} / {4})\n"
" $B(Status): ${2}({5})\n", " $B(Status): ${2}({5})\n",
name, // {0} name != "$" ? name : "(default suite)", // {0}
duration_cast<fractional_seconds>(elapsed).count(), // {1} duration_cast<fractional_seconds>(elapsed).count(), // {1}
suite_stats_.failed > 0 ? 'R' : 'G', // {2} suite_stats_.failed > 0 ? 'R' : 'G', // {2}
suite_stats_.passed, // {3} suite_stats_.passed, // {3}
...@@ -256,8 +256,12 @@ public: ...@@ -256,8 +256,12 @@ public:
using detail::format_to; using detail::format_to;
if (current_ctx_ == nullptr) if (current_ctx_ == nullptr)
CAF_RAISE_ERROR(std::logic_error, "begin_test was not called"); CAF_RAISE_ERROR(std::logic_error, "begin_test was not called");
if (current_suite_ != "$") {
format_to(colored(), "$C(Suite): $0{}\n", current_suite_); format_to(colored(), "$C(Suite): $0{}\n", current_suite_);
indent_ = 2; indent_ = 2;
} else {
indent_ = 0;
}
live_ = true; live_ = true;
for (auto* frame : current_ctx_->call_stack) for (auto* frame : current_ctx_->call_stack)
begin_step(frame); begin_step(frame);
......
...@@ -88,9 +88,6 @@ public: ...@@ -88,9 +88,6 @@ public:
using super::super; \ using super::super; \
void do_run() override; \ void do_run() override; \
static ptrdiff_t register_id; \ static ptrdiff_t register_id; \
using caf_test_suite_name_t = std::decay_t<decltype(caf_test_suite_name)>; \
static_assert(!std::is_same_v<caf::unit_t, caf_test_suite_name_t>, \
"SCENARIO must be nested in a SUITE block"); \
}; \ }; \
ptrdiff_t CAF_PP_UNIFYN(scenario_)::register_id \ ptrdiff_t CAF_PP_UNIFYN(scenario_)::register_id \
= caf::test::registry::add<CAF_PP_UNIFYN(scenario_)>( \ = caf::test::registry::add<CAF_PP_UNIFYN(scenario_)>( \
......
...@@ -5,11 +5,10 @@ ...@@ -5,11 +5,10 @@
#include "caf/test/scenario.hpp" #include "caf/test/scenario.hpp"
#include "caf/config.hpp" #include "caf/config.hpp"
#include "caf/test/caf_test_main.hpp"
#include "caf/test/nesting_error.hpp" #include "caf/test/nesting_error.hpp"
#include "caf/test/test.hpp" #include "caf/test/test.hpp"
SUITE("caf.test.scenario") {
#ifdef CAF_ENABLE_EXCEPTIONS #ifdef CAF_ENABLE_EXCEPTIONS
SCENARIO("a scenario may not contain a section") { SCENARIO("a scenario may not contain a section") {
auto entered_section = false; auto entered_section = false;
...@@ -138,4 +137,4 @@ SCENARIO("scenario-1") { ...@@ -138,4 +137,4 @@ SCENARIO("scenario-1") {
} }
} }
} // SUITE("caf.test.scenario") CAF_TEST_MAIN()
...@@ -24,9 +24,6 @@ struct caf_test_case_auto_fixture {}; ...@@ -24,9 +24,6 @@ struct caf_test_case_auto_fixture {};
#define WITH_FIXTURE(name) \ #define WITH_FIXTURE(name) \
namespace CAF_PP_UNIFYN(caf_fixture_) { \ namespace CAF_PP_UNIFYN(caf_fixture_) { \
static_assert( \
!std::is_same_v<std::decay_t<decltype(caf_test_suite_name)>, caf::unit_t>, \
"WITH_FIXTURE must be placed into a SUITE scope"); \
using caf_test_case_auto_fixture = name; \ using caf_test_case_auto_fixture = name; \
} \ } \
namespace CAF_PP_UNIFYN(caf_fixture_) namespace CAF_PP_UNIFYN(caf_fixture_)
...@@ -45,9 +45,6 @@ public: ...@@ -45,9 +45,6 @@ public:
using super::super; \ using super::super; \
void do_run() override; \ void do_run() override; \
static ptrdiff_t register_id; \ static ptrdiff_t register_id; \
using caf_test_suite_name_t = std::decay_t<decltype(caf_test_suite_name)>; \
static_assert(!std::is_same_v<caf::unit_t, caf_test_suite_name_t>, \
"TEST must be nested in a SUITE block"); \
}; \ }; \
ptrdiff_t CAF_PP_UNIFYN(test_)::register_id \ ptrdiff_t CAF_PP_UNIFYN(test_)::register_id \
= caf::test::registry::add<CAF_PP_UNIFYN(test_)>( \ = caf::test::registry::add<CAF_PP_UNIFYN(test_)>( \
......
...@@ -3,9 +3,9 @@ ...@@ -3,9 +3,9 @@
#include "caf/test/test.hpp" #include "caf/test/test.hpp"
using caf::test::block_type; #include "caf/test/caf_test_main.hpp"
SUITE("caf.test.test") { using caf::test::block_type;
TEST("tests can contain checks") { TEST("tests can contain checks") {
auto* rep = caf::test::reporter::instance; auto* rep = caf::test::reporter::instance;
...@@ -57,4 +57,4 @@ TEST("each run starts with a fresh fixture") { ...@@ -57,4 +57,4 @@ TEST("each run starts with a fresh fixture") {
} // WITH_FIXTURE(int_fixture) } // WITH_FIXTURE(int_fixture)
} // SUITE("caf.test.test") CAF_TEST_MAIN()
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#include "caf/test/caf_test_main.hpp"
CAF_TEST_MAIN()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment