Commit f39e3fea authored by Dominik Charousset's avatar Dominik Charousset

Fix build on GCC/Linux

parent 7a77a40e
...@@ -30,7 +30,7 @@ IndentCaseLabels: true ...@@ -30,7 +30,7 @@ IndentCaseLabels: true
IndentPPDirectives: AfterHash IndentPPDirectives: AfterHash
IndentWidth: 2 IndentWidth: 2
IndentWrappedFunctionNames: false IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: true KeepEmptyLinesAtTheStartOfBlocks: false
Language: Cpp Language: Cpp
MacroBlockBegin: "^BEGIN_STATE$|CAF_BEGIN_TYPE_ID_BLOCK" MacroBlockBegin: "^BEGIN_STATE$|CAF_BEGIN_TYPE_ID_BLOCK"
MacroBlockEnd: "^END_STATE$|CAF_END_TYPE_ID_BLOCK" MacroBlockEnd: "^END_STATE$|CAF_END_TYPE_ID_BLOCK"
......
...@@ -90,6 +90,7 @@ config = [ ...@@ -90,6 +90,7 @@ config = [
tags: ['docker', 'LeakSanitizer'], tags: ['docker', 'LeakSanitizer'],
builds: ['debug'], builds: ['debug'],
extraBuildFlags: [ extraBuildFlags: [
'BUILD_SHARED_LIBS:BOOL=OFF',
'CAF_LOG_LEVEL:STRING=TRACE', 'CAF_LOG_LEVEL:STRING=TRACE',
'CAF_ENABLE_ROBOT_TESTS:BOOL=ON', 'CAF_ENABLE_ROBOT_TESTS:BOOL=ON',
'CAF_SANITIZERS:STRING=address', 'CAF_SANITIZERS:STRING=address',
...@@ -104,9 +105,9 @@ config = [ ...@@ -104,9 +105,9 @@ config = [
tags: ['docker', 'UBSanitizer'], tags: ['docker', 'UBSanitizer'],
builds: ['debug'], builds: ['debug'],
extraBuildFlags: [ extraBuildFlags: [
'BUILD_SHARED_LIBS:BOOL=OFF',
'CAF_LOG_LEVEL:STRING=TRACE', 'CAF_LOG_LEVEL:STRING=TRACE',
'CAF_ENABLE_ROBOT_TESTS:BOOL=ON', 'CAF_ENABLE_ROBOT_TESTS:BOOL=ON',
'BUILD_SHARED_LIBS:BOOL=OFF',
'CAF_SANITIZERS:STRING=address,undefined', 'CAF_SANITIZERS:STRING=address,undefined',
], ],
extraBuildEnv: [ extraBuildEnv: [
......
...@@ -17,7 +17,9 @@ namespace caf::test { ...@@ -17,7 +17,9 @@ namespace caf::test {
/// structure. /// structure.
class CAF_TEST_EXPORT block { class CAF_TEST_EXPORT block {
public: public:
block(context_ptr ctx, int id, std::string_view description, // Note: the context owns the block. Hence, we can use a raw pointer for
// pointing back to the parent object here.
block(context* ctx, int id, std::string_view description,
const detail::source_location& loc); const detail::source_location& loc);
virtual ~block(); virtual ~block();
...@@ -100,7 +102,7 @@ public: ...@@ -100,7 +102,7 @@ public:
protected: protected:
std::unique_ptr<block>& get_nested_or_construct(int id); std::unique_ptr<block>& get_nested_or_construct(int id);
context_ptr ctx_; context* ctx_;
int id_ = 0; int id_ = 0;
std::string_view description_; std::string_view description_;
bool active_ = false; bool active_ = false;
......
...@@ -16,10 +16,10 @@ ...@@ -16,10 +16,10 @@
namespace caf::test { namespace caf::test {
/// Represents the exeuction context of a test. The context stores all steps of /// Represents the execution context of a test. The context stores all steps of
/// the test and the current execution stack. The context persists across /// the test and the current execution stack. The context persists across
/// multiple runs of the test in order to select one execution path per run. /// multiple runs of the test in order to select one execution path per run.
class CAF_TEST_EXPORT context : public std::enable_shared_from_this<context> { class CAF_TEST_EXPORT context {
public: public:
/// Returns whether the test is still active. A test is active as long as /// Returns whether the test is still active. A test is active as long as
/// no unwinding is in progress. /// no unwinding is in progress.
...@@ -42,9 +42,7 @@ public: ...@@ -42,9 +42,7 @@ public:
/// Checks whether `ptr` has been activated this run, i.e., whether we can /// Checks whether `ptr` has been activated this run, i.e., whether we can
/// find it in `unwind_stack`. /// find it in `unwind_stack`.
bool activated(block* ptr) { bool activated(block* ptr) const noexcept;
return std::find(path.begin(), path.end(), ptr) != path.end();
}
/// Stores the current execution stack for the run. /// Stores the current execution stack for the run.
std::vector<block*> call_stack; std::vector<block*> call_stack;
...@@ -55,7 +53,6 @@ public: ...@@ -55,7 +53,6 @@ public:
/// Stores all steps that we have reached at least once during the run. /// Stores all steps that we have reached at least once during the run.
std::vector<block*> path; std::vector<block*> path;
/// Stores all steps of the test with their run-time ID. /// Stores all steps of the test with their run-time ID.
std::map<int, std::unique_ptr<block>> steps; std::map<int, std::unique_ptr<block>> steps;
...@@ -64,7 +61,7 @@ public: ...@@ -64,7 +61,7 @@ public:
const detail::source_location& loc) { const detail::source_location& loc) {
auto& result = steps[id]; auto& result = steps[id];
if (!result) { if (!result) {
result = std::make_unique<T>(shared_from_this(), id, description, loc); result = std::make_unique<T>(this, id, description, loc);
} }
return static_cast<T*>(result.get()); return static_cast<T*>(result.get());
} }
......
...@@ -87,4 +87,4 @@ private: ...@@ -87,4 +87,4 @@ private:
detail::source_location loc_; detail::source_location loc_;
}; };
} // namespace caf::test } // namespace caf::test
...@@ -18,7 +18,6 @@ namespace caf::test { ...@@ -18,7 +18,6 @@ namespace caf::test {
/// A registry for our factories. /// A registry for our factories.
class registry { class registry {
public: public:
/// Maps test names to factories. Elements are sorted by the order of their /// Maps test names to factories. Elements are sorted by the order of their
/// registration. /// registration.
using tests_map = unordered_flat_map<std::string_view, factory*>; using tests_map = unordered_flat_map<std::string_view, factory*>;
......
...@@ -16,7 +16,7 @@ public: ...@@ -16,7 +16,7 @@ public:
static constexpr block_type type_token = block_type::when; static constexpr block_type type_token = block_type::when;
then* get_then(int id, std::string_view description, then* get_then(int id, std::string_view description,
const detail::source_location& loc) override ; const detail::source_location& loc) override;
and_then* get_and_then(int id, std::string_view description, and_then* get_and_then(int id, std::string_view description,
const detail::source_location& loc) override; const detail::source_location& loc) override;
......
...@@ -7,9 +7,11 @@ ...@@ -7,9 +7,11 @@
#include "caf/test/context.hpp" #include "caf/test/context.hpp"
#include "caf/test/nesting_error.hpp" #include "caf/test/nesting_error.hpp"
#include <algorithm>
namespace caf::test { namespace caf::test {
block::block(context_ptr ctx, int id, std::string_view description, block::block(context* ctx, int id, std::string_view description,
const detail::source_location& loc) const detail::source_location& loc)
: ctx_(ctx), id_(id), description_(description), loc_(loc) { : ctx_(ctx), id_(id), description_(description), loc_(loc) {
// nop // nop
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
#include "caf/test/block.hpp" #include "caf/test/block.hpp"
#include "caf/test/reporter.hpp" #include "caf/test/reporter.hpp"
#include <algorithm>
namespace caf::test { namespace caf::test {
void context::on_enter(block* ptr) { void context::on_enter(block* ptr) {
...@@ -22,6 +24,10 @@ void context::on_leave(block* ptr) { ...@@ -22,6 +24,10 @@ void context::on_leave(block* ptr) {
reporter::instance->end_step(ptr); reporter::instance->end_step(ptr);
} }
bool context::activated(block* ptr) const noexcept {
return std::find(path.begin(), path.end(), ptr) != path.end();
}
bool context::can_run() { bool context::can_run() {
auto pred = [](auto& kvp) { return kvp.second->can_run(); }; auto pred = [](auto& kvp) { return kvp.second->can_run(); };
return !steps.empty() && std::any_of(steps.begin(), steps.end(), pred); return !steps.empty() && std::any_of(steps.begin(), steps.end(), pred);
......
...@@ -39,4 +39,4 @@ scope given::commit() { ...@@ -39,4 +39,4 @@ scope given::commit() {
return scope{this}; return scope{this};
} }
} // namespace caf::test } // namespace caf::test
...@@ -32,9 +32,9 @@ nesting_error::raise_impl(nesting_error::code what, block_type parent, ...@@ -32,9 +32,9 @@ nesting_error::raise_impl(nesting_error::code what, block_type parent,
#ifdef CAF_ENABLE_EXCEPTIONS #ifdef CAF_ENABLE_EXCEPTIONS
throw nesting_error{what, parent, child, loc}; throw nesting_error{what, parent, child, loc};
#else #else
auto msg = nesting_error{code::not_allowed, parent, child}.message(); auto msg = nesting_error{what, parent, child, loc}.message();
fprintf(stderr, "[FATAL] critical error (%s:%d): %s\n", msg.c_str(), fprintf(stderr, "[FATAL] critical error (%s:%d): %s\n", loc.file_name(),
loc.file_name, static_cast<int>(loc.line)); static_cast<int>(loc.line()), msg.c_str());
abort(); abort();
#endif #endif
} }
......
...@@ -34,6 +34,12 @@ namespace { ...@@ -34,6 +34,12 @@ namespace {
/// - $C(cyan text) /// - $C(cyan text)
/// - $0 turns off coloring completely (enter verbatim mode) /// - $0 turns off coloring completely (enter verbatim mode)
struct colorizing_iterator { struct colorizing_iterator {
using difference_type = void;
using value_type = void;
using pointer = void;
using reference = void;
using iterator_category = std::output_iterator_tag;
enum mode_t { enum mode_t {
normal, normal,
read_color, read_color,
...@@ -240,7 +246,7 @@ public: ...@@ -240,7 +246,7 @@ public:
failed_tests_.push_back(current_test_); failed_tests_.push_back(current_test_);
suite_stats_ += test_stats_; suite_stats_ += test_stats_;
current_ctx_.reset(); current_ctx_.reset();
if(live_) if (live_)
std::cout << std::endl; std::cout << std::endl;
} }
...@@ -252,7 +258,7 @@ public: ...@@ -252,7 +258,7 @@ public:
CAF_RAISE_ERROR(std::logic_error, "begin_test was not called"); CAF_RAISE_ERROR(std::logic_error, "begin_test was not called");
format_to(colored(), "$C(Suite): $0{}\n", current_suite_); format_to(colored(), "$C(Suite): $0{}\n", current_suite_);
indent_ = 2; indent_ = 2;
live_= true; live_ = true;
for (auto* frame : current_ctx_->call_stack) for (auto* frame : current_ctx_->call_stack)
begin_step(frame); begin_step(frame);
} }
......
...@@ -22,33 +22,38 @@ namespace caf::test { ...@@ -22,33 +22,38 @@ namespace caf::test {
namespace { namespace {
config_option_set make_option_set() { config_option_set make_option_set() {
config_option_set result; config_option_set result;
config_option_adder{result, "global"} config_option_adder{result, "global"}
.add<bool>("help,h?", "print this help text")
.add<bool>("available-suites,a", "print all available suites") .add<bool>("available-suites,a", "print all available suites")
.add<bool>("help,h?", "print this help text")
.add<bool>("no-colors,n", "disable coloring (ignored on Windows)")
.add<size_t>("max-runtime,r", "set a maximum runtime in seconds")
.add<std::string>("suites,s", "regex for selecting suites")
.add<std::string>("available-tests,A", "print tests for a suite") .add<std::string>("available-tests,A", "print tests for a suite")
.add<std::string>("verbosity,v", "set verbosity level of the reporter"); .add<std::string>("verbosity,v", "set verbosity level of the reporter");
return result; return result;
} }
std::optional<unsigned> parse_log_level(std::string_view x) { std::optional<unsigned> parse_log_level(std::string_view x) {
if (x == "quiet") // Note: the 0-5 aliases are for compatibility with the old unit testing
// framework.
if (x == "quiet" || x == "0")
return CAF_LOG_LEVEL_QUIET; return CAF_LOG_LEVEL_QUIET;
if (x == "error") if (x == "error" || x == "1")
return CAF_LOG_LEVEL_ERROR; return CAF_LOG_LEVEL_ERROR;
if (x == "warning") if (x == "warning" || x == "2")
return CAF_LOG_LEVEL_WARNING; return CAF_LOG_LEVEL_WARNING;
if (x == "info") if (x == "info" || x == "3")
return CAF_LOG_LEVEL_INFO; return CAF_LOG_LEVEL_INFO;
if (x == "debug") if (x == "debug" || x == "4")
return CAF_LOG_LEVEL_DEBUG; return CAF_LOG_LEVEL_DEBUG;
if (x == "trace") if (x == "trace" || x == "5")
return CAF_LOG_LEVEL_TRACE; return CAF_LOG_LEVEL_TRACE;
return {}; return {};
} }
}// } // namespace
runner::runner() : suites_(caf::test::registry::suites()) { runner::runner() : suites_(caf::test::registry::suites()) {
// nop // nop
...@@ -67,6 +72,7 @@ int runner::run(int argc, char** argv) { ...@@ -67,6 +72,7 @@ int runner::run(int argc, char** argv) {
default_reporter->begin_suite(suite_name); default_reporter->begin_suite(suite_name);
for (auto [test_name, factory_instance] : suite) { for (auto [test_name, factory_instance] : suite) {
auto state = std::make_shared<context>(); auto state = std::make_shared<context>();
#ifdef CAF_ENABLE_EXCEPTIONS
try { try {
do { do {
default_reporter->begin_test(state, test_name); default_reporter->begin_test(state, test_name);
...@@ -85,6 +91,15 @@ int runner::run(int argc, char** argv) { ...@@ -85,6 +91,15 @@ int runner::run(int argc, char** argv) {
default_reporter->unhandled_exception("unknown exception type"); default_reporter->unhandled_exception("unknown exception type");
default_reporter->end_test(); default_reporter->end_test();
} }
#else
do {
default_reporter->begin_test(state, test_name);
auto def = factory_instance->make(state);
def->run();
default_reporter->end_test();
state->clear_stacks();
} while (state->can_run());
#endif
} }
default_reporter->end_suite(suite_name); default_reporter->end_suite(suite_name);
} }
...@@ -100,8 +115,8 @@ runner::parse_cli_result runner::parse_cli(int argc, char** argv) { ...@@ -100,8 +115,8 @@ runner::parse_cli_result runner::parse_cli(int argc, char** argv) {
auto res = options.parse(cfg, args_cpy); auto res = options.parse(cfg, args_cpy);
auto err = std::ostream_iterator<char>{std::cerr}; auto err = std::ostream_iterator<char>{std::cerr};
if (res.first != caf::pec::success) { if (res.first != caf::pec::success) {
format_to(err, "error while parsing argument '{}': {}\n\n{}\n", format_to(err, "error while parsing argument '{}': {}\n\n{}\n", *res.second,
*res.second, to_string(res.first), options.help_text()); to_string(res.first), options.help_text());
return {false, true}; return {false, true};
} }
if (get_or(cfg, "help", false)) { if (get_or(cfg, "help", false)) {
......
...@@ -14,35 +14,35 @@ ...@@ -14,35 +14,35 @@
namespace caf::test { namespace caf::test {
block_type scenario::type() const noexcept { block_type scenario::type() const noexcept {
return block_type::scenario; return block_type::scenario;
} }
given* scenario::get_given(int id, std::string_view description, given* scenario::get_given(int id, std::string_view description,
const detail::source_location& loc) { const detail::source_location& loc) {
return get_nested<given>(id, description, loc); return get_nested<given>(id, description, loc);
} }
and_given* scenario::get_and_given(int id, std::string_view description, and_given* scenario::get_and_given(int id, std::string_view description,
const detail::source_location& loc) { const detail::source_location& loc) {
return get_nested<and_given>(id, description, loc); return get_nested<and_given>(id, description, loc);
} }
when* scenario::get_when(int id, std::string_view description, when* scenario::get_when(int id, std::string_view description,
const detail::source_location& loc) { const detail::source_location& loc) {
return get_nested<when>(id, description, loc); return get_nested<when>(id, description, loc);
} }
and_when* scenario::get_and_when(int id, std::string_view description, and_when* scenario::get_and_when(int id, std::string_view description,
const detail::source_location& loc) { const detail::source_location& loc) {
return get_nested<and_when>(id, description, loc); return get_nested<and_when>(id, description, loc);
} }
scope scenario::commit() { scope scenario::commit() {
if (!ctx_->active() || !can_run()) if (!ctx_->active() || !can_run())
return {}; return {};
enter(); enter();
return scope{this}; return scope{this};
} }
} // namespace caf::test } // namespace caf::test
...@@ -44,7 +44,6 @@ SCENARIO("each run starts with fresh local variables") { ...@@ -44,7 +44,6 @@ SCENARIO("each run starts with fresh local variables") {
} }
} }
struct int_fixture { struct int_fixture {
int my_int = 0; int my_int = 0;
}; };
......
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