Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:12:57

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
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 }  // namespace states
0026 
0027 namespace events {
0028 struct Connect {};
0029 struct Established {};
0030 struct Timeout {};
0031 struct Ping {};
0032 struct Pong {};
0033 struct Disconnect {};
0034 }  // namespace events
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& /*unused*/,
0041                         const events::Connect& /*unused*/) {
0042     return states::Connecting{};
0043   }
0044 
0045   event_return on_event(const states::Connecting& /*unused*/,
0046                         const events::Established& /*unused*/) {
0047     return states::Connected{};
0048   }
0049 
0050   event_return on_event(const states::Connected& /*unused*/,
0051                         const events::Ping& /*unused*/) {
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& /*unused*/,
0058                         const events::Pong& /*unused*/) {
0059     std::cout << "pong!" << std::endl;
0060     return states::Connected{};
0061   }
0062 
0063   event_return on_event(const states::Connected& /*unused*/,
0064                         const events::Timeout& /*unused*/) {
0065     return states::Connecting{};
0066   }
0067 
0068   event_return on_event(const states::Connected& /*unused*/,
0069                         const events::Disconnect& /*unused*/) {
0070     return states::Disconnected{};
0071   }
0072 
0073   template <typename State, typename Event>
0074   event_return on_event(const State& /*unused*/,
0075                         const Event& /*unused*/) const {
0076     return Terminated{};
0077   }
0078 
0079   template <typename State, typename... Args>
0080   void on_enter(const State& /*unused*/, Args&&... /*unused*/) {}
0081 
0082   template <typename State, typename... Args>
0083   void on_exit(const State& /*unused*/, Args&&... /*unused*/) {}
0084 
0085   template <typename... Args>
0086   void on_process(Args&&... /*unused*/) {}
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& /*unused*/,
0124                         const events::Connect& /*unused*/, double f) {
0125     std::cout << "f: " << f << std::endl;
0126     return states::Connected{};
0127   }
0128 
0129   event_return on_event(const states::Connected& /*unused*/,
0130                         const events::Disconnect& /*unused*/) {
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& /*unused*/, const Event& /*unused*/,
0137                         Args&&... /*unused*/) const {
0138     return Terminated{};
0139   }
0140 
0141   template <typename... Args>
0142   void on_enter(const Terminated& /*unused*/, Args&&... /*unused*/) {
0143     throw std::runtime_error("FSM terminated!");
0144   }
0145 
0146   template <typename State, typename... Args>
0147   void on_enter(const State& /*unused*/, Args&&... /*unused*/) {}
0148 
0149   template <typename State, typename... Args>
0150   void on_exit(const State& /*unused*/, Args&&... /*unused*/) {}
0151   template <typename... Args>
0152   void on_process(Args&&... /*unused*/) {}
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   // call disconnect, but disconnect does not accept this call signature
0166   BOOST_REQUIRE_THROW(sm.dispatch(events::Disconnect{}, 9), std::runtime_error);
0167   BOOST_CHECK(sm.terminated());
0168 
0169   // cannot dispatch on terminated (in this specific configuration, in
0170   // general terminated is just another state).
0171   BOOST_REQUIRE_THROW(sm.dispatch(events::Connect{}), std::runtime_error);
0172   // still in terminated
0173   BOOST_CHECK(sm.terminated());
0174 
0175   // we can reset the state though!
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   // S1 + E1 = S2
0201   event_return on_event(const S1& /*unused*/, const E1& /*unused*/) {
0202     return S2{};
0203   }
0204 
0205   // S2 + E1 = S2
0206   // external transition to self
0207   event_return on_event(const S2& /*unused*/, const E1& /*unused*/) {
0208     return S2{};
0209   }
0210 
0211   // S2 + E2
0212   // internal transition
0213   event_return on_event(const S2& /*unused*/, const E2& /*unused*/) {
0214     return std::nullopt;
0215     // return S2{};
0216   }
0217 
0218   // S2 + E3 = S3
0219   // external transition
0220   event_return on_event(const S2& /*unused*/, const E3& /*unused*/) {
0221     return S3{};
0222   }
0223 
0224   // catchers
0225 
0226   template <typename State, typename Event, typename... Args>
0227   event_return on_event(const State& /*unused*/, const Event& /*unused*/,
0228                         Args&&... /*unused*/) const {
0229     return Terminated{};
0230   }
0231 
0232   template <typename State, typename... Args>
0233   void on_enter(const State& /*unused*/, Args&&... /*unused*/) {
0234     on_enter_called = true;
0235   }
0236 
0237   template <typename State, typename... Args>
0238   void on_exit(const State& /*unused*/, Args&&... /*unused*/) {
0239     on_exit_called = true;
0240   }
0241 
0242   template <typename... Args>
0243   void on_process(Args&&... /*unused*/) {
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   // still in S2
0262   BOOST_CHECK(sm.is(S2{}));
0263   // on_enter / exit should have been called
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   // still in S2
0271   BOOST_CHECK(sm.is(S2{}));
0272   // on_enter / exit should NOT have been called
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   // on_enter / exit should have been called
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   // dispatch invalid event
0289   sm.dispatch(E3{});
0290   // should be terminated now
0291   BOOST_CHECK(sm.terminated());
0292   // hooks should have fired
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 }  // namespace Acts::Test