// Copyright 2024 Christophe Henry // henry UNDERSCORE christophe AT hotmail DOT com // This is an extended version of the state machine available in the boost::mpl library // Distributed under the same license as the original. // Copyright for the original version: // Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed // under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // back-end #include "BackCommon.hpp" //front-end #include #include #include #include #ifndef BOOST_MSM_NONSTANDALONE_TEST #define BOOST_TEST_MODULE throwing_test #endif #include namespace msm = boost::msm; namespace mpl = boost::mpl; using namespace boost::msm::front; namespace { template void print(T t) { std::cout << t << "\n"; } template using Row = boost::msm::front::Row; using None = boost::msm::front::none; // events struct ExceptionRaised {}; // states struct Init : boost::msm::front::state<> { template void on_entry(Event const&, FSM&) { ++entry_counter;} template void on_exit(Event const&, FSM&) { ++exit_counter;} int entry_counter = 0; int exit_counter = 0; }; struct WaitingForException : boost::msm::front::state<> { template void on_entry(Event const&, FSM&) { ++entry_counter; } template void on_exit(Event const&, FSM&) { ++exit_counter;} int entry_counter = 0; int exit_counter = 0; }; struct Intermediate : boost::msm::front::state<> { template void on_entry(Event const&, FSM&) { ++entry_counter;} template void on_exit(Event const&, FSM&) { ++exit_counter;} int entry_counter = 0; int exit_counter = 0; }; struct End : boost::msm::front::terminate_state<> { template void on_entry(Event const&, FSM&) { ++entry_counter;} template void on_exit(Event const&, FSM&) { ++exit_counter;} int entry_counter = 0; int exit_counter = 0; }; // actions struct ThrowingAction { template void operator()(const Event&, StateMachine&, SourceState&, TargetState&) { throw std::runtime_error("foo"); } }; struct ExceptionHandler { template void operator()(const Event&, StateMachine&, SourceState&, TargetState&) { } }; struct MyMachineFrontend : public boost::msm::front::state_machine_def { using initial_state = boost::mpl::vector; using transition_table = boost::mpl::vector< Row, Row >; template void exception_caught(const Event&, StateMachine& machine, std::exception&) { machine.process_event(ExceptionRaised{}); } }; using MyMachines = get_test_machines; BOOST_AUTO_TEST_CASE_TEMPLATE(throwing_test, MyMachine, MyMachines) { MyMachine m; m.start(); BOOST_CHECK_MESSAGE(m.template get_state().entry_counter == 1, "Init entry not called correctly"); BOOST_CHECK_MESSAGE(m.template get_state().exit_counter == 1, "Init exit not called correctly"); BOOST_CHECK_MESSAGE(m.template get_state().entry_counter == 0, "Intermediate entry not called correctly"); BOOST_CHECK_MESSAGE(m.template get_state().exit_counter == 0, "Intermediate exit not called correctly"); BOOST_CHECK_MESSAGE(m.template get_state().entry_counter == 1, "WaitingForException entry not called correctly"); BOOST_CHECK_MESSAGE(m.template get_state().exit_counter == 1, "WaitingForException exit not called correctly"); BOOST_CHECK_MESSAGE(m.template get_state().entry_counter == 1, "End entry not called correctly"); BOOST_CHECK_MESSAGE(m.template get_state().exit_counter == 0, "End exit not called correctly"); BOOST_CHECK_MESSAGE(m.current_state()[0] == 0, "Init should be active"); BOOST_CHECK_MESSAGE(m.current_state()[1] == 3, "End should be active"); } }