From 5d41970ea7aa22b78026d8ca4d12012cf445507c Mon Sep 17 00:00:00 2001 From: Michael Baumann Date: Wed, 6 Jul 2022 12:25:03 +0200 Subject: [PATCH] [Reproducer] guard incorrectly checked twice --- test/CMakeLists.txt | 7 +- .../reproducer/should_check_guard_once.cpp | 101 ++++++++++++++++++ 2 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 test/integration/reproducer/should_check_guard_once.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 363e6d5..dff1b25 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -57,8 +57,8 @@ target_link_libraries(hsmPerformanceTests PRIVATE hsm::hsm GTest::gtest_main) gtest_discover_tests(hsmPerformanceTests TEST_PREFIX performance.) add_executable( - hsmIntegrationTests - integration/main.cpp + hsmIntegrationTests + integration/main.cpp integration/basic_transitions.cpp integration/direct_transition.cpp integration/entry_exit_actions.cpp @@ -79,13 +79,14 @@ add_executable( integration/amalgamation_header.cpp integration/custom_targets.cpp integration/chain_actions.cpp + integration/reproducer/should_check_guard_once.cpp integration/reproducer/should_execute_anonymous_transition_once.cpp integration/reproducer/should_enter_substate_with_multiple_regions.cpp ) if (UNIX) target_sources( - hsmIntegrationTests + hsmIntegrationTests PRIVATE # Test compilation fails with msvc with: fatal error C1001: Internal compiler error integration/state_data_members.cpp diff --git a/test/integration/reproducer/should_check_guard_once.cpp b/test/integration/reproducer/should_check_guard_once.cpp new file mode 100644 index 0000000..98d0686 --- /dev/null +++ b/test/integration/reproducer/should_check_guard_once.cpp @@ -0,0 +1,101 @@ +#include "hsm/hsm.h" + +#include + +using namespace ::testing; +using namespace boost::hana; + +namespace { + +// States +// -- sub +struct SubStateEntry { }; +struct SubStateIntermediate { }; +struct SubExit1 { }; +struct SubExit2 { }; +// -- main +struct Initial { }; +struct Intermediate { }; +struct Final { }; + +// Events +struct entrySubEvent { }; +struct exitSubEvent1 { }; +struct exitSubEvent2 { }; +struct mainEvent1 { }; + +// Guards +const auto guard = [](auto /*event*/, auto /*source*/, auto /*target*/, auto& dependency) { + dependency.callCount++; + return false; +}; + +struct SubState { + static constexpr auto make_transition_table() + { + using namespace hsm; + + // clang-format off + return transition_table( + * state = state, + state + event = state, + state + event = state + ); + // clang-format on + } +}; + +struct MainState { + static constexpr auto make_transition_table() + { + using namespace hsm; + + // clang-format off + return transition_table( + * state + event = state, + state [ guard ] = state, + state + event = state, + state + event = history, + state = state, + hsm::exit = state, + hsm::exit = state + ); + // clang-format on + } +}; + +} +class GuardCallCountTest : public Test { + protected: + struct Dependency { + explicit Dependency(int callCount) + : callCount(callCount) + { + } + + // Dependency is not copied, assigned, or moved + Dependency(const Dependency&) = delete; + Dependency(Dependency&&) = delete; + Dependency& operator=(const Dependency&) = delete; + Dependency& operator=(Dependency&&) = delete; + + int callCount = 0; + }; + + GuardCallCountTest() + : _dependency(0) + , _fsm { _dependency } + { + } + + Dependency _dependency; + hsm::sm _fsm; +}; + +TEST_F(GuardCallCountTest, should_check_guard_only_once) +{ + _fsm.process_event(mainEvent1 {}); + _fsm.process_event(entrySubEvent {}); + _fsm.process_event(exitSubEvent2 {}); + ASSERT_EQ(_dependency.callCount, 1); +}