File indexing completed on 2025-01-18 09:12:57
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <boost/test/unit_test.hpp>
0010
0011 #include "Acts/Utilities/FiniteStateMachine.hpp"
0012
0013 #include <iostream>
0014 #include <optional>
0015 #include <stdexcept>
0016
0017 namespace Acts::Test {
0018
0019 namespace states {
0020 struct Disconnected {};
0021
0022 struct Connecting {};
0023 struct Pinging {};
0024 struct Connected {};
0025 }
0026
0027 namespace events {
0028 struct Connect {};
0029 struct Established {};
0030 struct Timeout {};
0031 struct Ping {};
0032 struct Pong {};
0033 struct Disconnect {};
0034 }
0035
0036 struct fsm : FiniteStateMachine<fsm, states::Disconnected, states::Connecting,
0037 states::Pinging, states::Connected> {
0038 fsm() : fsm_base(states::Disconnected{}) {}
0039
0040 event_return on_event(const states::Disconnected& ,
0041 const events::Connect& ) {
0042 return states::Connecting{};
0043 }
0044
0045 event_return on_event(const states::Connecting& ,
0046 const events::Established& ) {
0047 return states::Connected{};
0048 }
0049
0050 event_return on_event(const states::Connected& ,
0051 const events::Ping& ) {
0052 std::cout << "ping!" << std::endl;
0053 setState(states::Pinging{});
0054 return process_event(events::Pong{});
0055 }
0056
0057 event_return on_event(const states::Pinging& ,
0058 const events::Pong& ) {
0059 std::cout << "pong!" << std::endl;
0060 return states::Connected{};
0061 }
0062
0063 event_return on_event(const states::Connected& ,
0064 const events::Timeout& ) {
0065 return states::Connecting{};
0066 }
0067
0068 event_return on_event(const states::Connected& ,
0069 const events::Disconnect& ) {
0070 return states::Disconnected{};
0071 }
0072
0073 template <typename State, typename Event>
0074 event_return on_event(const State& ,
0075 const Event& ) const {
0076 return Terminated{};
0077 }
0078
0079 template <typename State, typename... Args>
0080 void on_enter(const State& , Args&&... ) {}
0081
0082 template <typename State, typename... Args>
0083 void on_exit(const State& , Args&&... ) {}
0084
0085 template <typename... Args>
0086 void on_process(Args&&... ) {}
0087 };
0088
0089 BOOST_AUTO_TEST_SUITE(Utilities)
0090
0091 BOOST_AUTO_TEST_CASE(Transitions) {
0092 fsm sm{};
0093 BOOST_CHECK(sm.is(states::Disconnected{}));
0094 sm.dispatch(events::Connect{});
0095 BOOST_CHECK(sm.is(states::Connecting{}));
0096 sm.dispatch(events::Established{});
0097 BOOST_CHECK(sm.is(states::Connected{}));
0098 sm.dispatch(events::Ping{});
0099 sm.dispatch(events::Ping{});
0100 sm.dispatch(events::Ping{});
0101 sm.dispatch(events::Ping{});
0102 BOOST_CHECK(sm.is(states::Connected{}));
0103 sm.dispatch(events::Timeout{});
0104 BOOST_CHECK(sm.is(states::Connecting{}));
0105 sm.dispatch(events::Established{});
0106 BOOST_CHECK(sm.is(states::Connected{}));
0107 sm.dispatch(events::Disconnect{});
0108 BOOST_CHECK(sm.is(states::Disconnected{}));
0109 }
0110
0111 BOOST_AUTO_TEST_CASE(Terminted) {
0112 fsm sm{};
0113 BOOST_CHECK(sm.is(states::Disconnected{}));
0114
0115 sm.dispatch(events::Disconnect{});
0116 BOOST_CHECK(sm.terminated());
0117 }
0118
0119 struct fsm2
0120 : FiniteStateMachine<fsm2, states::Disconnected, states::Connected> {
0121 fsm2() : fsm_base(states::Disconnected{}) {}
0122
0123 event_return on_event(const states::Disconnected& ,
0124 const events::Connect& , double f) {
0125 std::cout << "f: " << f << std::endl;
0126 return states::Connected{};
0127 }
0128
0129 event_return on_event(const states::Connected& ,
0130 const events::Disconnect& ) {
0131 std::cout << "disconnect!" << std::endl;
0132 return states::Disconnected{};
0133 }
0134
0135 template <typename State, typename Event, typename... Args>
0136 event_return on_event(const State& , const Event& ,
0137 Args&&... ) const {
0138 return Terminated{};
0139 }
0140
0141 template <typename... Args>
0142 void on_enter(const Terminated& , Args&&... ) {
0143 throw std::runtime_error("FSM terminated!");
0144 }
0145
0146 template <typename State, typename... Args>
0147 void on_enter(const State& , Args&&... ) {}
0148
0149 template <typename State, typename... Args>
0150 void on_exit(const State& , Args&&... ) {}
0151 template <typename... Args>
0152 void on_process(Args&&... ) {}
0153 };
0154
0155 BOOST_AUTO_TEST_CASE(Arguments) {
0156 fsm2 sm{};
0157 BOOST_CHECK(sm.is(states::Disconnected{}));
0158
0159 sm.dispatch(events::Connect{}, 42.);
0160 BOOST_CHECK(sm.is(states::Connected{}));
0161 sm.dispatch(events::Disconnect{});
0162 BOOST_CHECK(sm.is(states::Disconnected{}));
0163 sm.dispatch(events::Connect{}, -1.);
0164
0165
0166 BOOST_REQUIRE_THROW(sm.dispatch(events::Disconnect{}, 9), std::runtime_error);
0167 BOOST_CHECK(sm.terminated());
0168
0169
0170
0171 BOOST_REQUIRE_THROW(sm.dispatch(events::Connect{}), std::runtime_error);
0172
0173 BOOST_CHECK(sm.terminated());
0174
0175
0176 sm.setState(states::Disconnected{});
0177 BOOST_CHECK(sm.is(states::Disconnected{}));
0178 sm.dispatch(events::Connect{}, -1.);
0179 BOOST_CHECK(sm.is(states::Connected{}));
0180 }
0181
0182 struct S1 {};
0183 struct S2 {};
0184 struct S3 {};
0185
0186 struct E1 {};
0187 struct E2 {};
0188 struct E3 {};
0189
0190 struct fsm3 : FiniteStateMachine<fsm3, S1, S2, S3> {
0191 bool on_exit_called = false;
0192 bool on_enter_called = false;
0193 bool on_process_called = false;
0194 void reset() {
0195 on_exit_called = false;
0196 on_enter_called = false;
0197 on_process_called = false;
0198 }
0199
0200
0201 event_return on_event(const S1& , const E1& ) {
0202 return S2{};
0203 }
0204
0205
0206
0207 event_return on_event(const S2& , const E1& ) {
0208 return S2{};
0209 }
0210
0211
0212
0213 event_return on_event(const S2& , const E2& ) {
0214 return std::nullopt;
0215
0216 }
0217
0218
0219
0220 event_return on_event(const S2& , const E3& ) {
0221 return S3{};
0222 }
0223
0224
0225
0226 template <typename State, typename Event, typename... Args>
0227 event_return on_event(const State& , const Event& ,
0228 Args&&... ) const {
0229 return Terminated{};
0230 }
0231
0232 template <typename State, typename... Args>
0233 void on_enter(const State& , Args&&... ) {
0234 on_enter_called = true;
0235 }
0236
0237 template <typename State, typename... Args>
0238 void on_exit(const State& , Args&&... ) {
0239 on_exit_called = true;
0240 }
0241
0242 template <typename... Args>
0243 void on_process(Args&&... ) {
0244 on_process_called = true;
0245 }
0246 };
0247
0248 BOOST_AUTO_TEST_CASE(InternalTransitions) {
0249 fsm3 sm;
0250 BOOST_CHECK(sm.is(S1{}));
0251
0252 sm.dispatch(E1{});
0253 BOOST_CHECK(sm.is(S2{}));
0254 BOOST_CHECK(sm.on_exit_called);
0255 BOOST_CHECK(sm.on_enter_called);
0256 BOOST_CHECK(sm.on_process_called);
0257
0258 sm.reset();
0259
0260 sm.dispatch(E1{});
0261
0262 BOOST_CHECK(sm.is(S2{}));
0263
0264 BOOST_CHECK(sm.on_exit_called);
0265 BOOST_CHECK(sm.on_enter_called);
0266 BOOST_CHECK(sm.on_process_called);
0267 sm.reset();
0268
0269 sm.dispatch(E2{});
0270
0271 BOOST_CHECK(sm.is(S2{}));
0272
0273 BOOST_CHECK(!sm.on_exit_called);
0274 BOOST_CHECK(!sm.on_enter_called);
0275 BOOST_CHECK(sm.on_process_called);
0276 sm.reset();
0277
0278 sm.dispatch(E3{});
0279 BOOST_CHECK(sm.is(S3{}));
0280
0281 BOOST_CHECK(sm.on_exit_called);
0282 BOOST_CHECK(sm.on_enter_called);
0283 BOOST_CHECK(sm.on_process_called);
0284
0285 sm.setState(S1{});
0286 sm.reset();
0287 BOOST_CHECK(sm.is(S1{}));
0288
0289 sm.dispatch(E3{});
0290
0291 BOOST_CHECK(sm.terminated());
0292
0293 BOOST_CHECK(sm.on_exit_called);
0294 BOOST_CHECK(sm.on_enter_called);
0295 BOOST_CHECK(sm.on_process_called);
0296 }
0297
0298 BOOST_AUTO_TEST_SUITE_END()
0299
0300 }