简体   繁体   中英

How to reach directly any state in a state-machine written with Boost MSM

I am currently using the Boost MSM library to write a state machine and I want to write unit tests to check transitions between its states. For each unit test, I need to write repetitive lines of code to reach the state from which I want to start. Therefore I would like to know if their is a way to start the state machine in a given state instead of the starting state.

For example if I have a simple state machine like this that usually starts at StartingState, I would like to reach directly IdleState to do my test :

  • --> StartingState --> IdleState --> ErrorState

Boost.MSM doesn't directly support the functionality that you want.

But you can control the initial state using initial_state inner type and preprocessor macro.

Let's say your state machine is defined in sm1.hpp .

sm1.hpp

#include <iostream>
#include <boost/msm/back/state_machine.hpp>

#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/functor_row.hpp>

namespace msm = boost::msm;
namespace msmf = boost::msm::front;
namespace mpl = boost::mpl;

// ----- Events
struct Event1 {};

// Test helper code
#if !defined(TEST_SM1_STATE)
#define TEST_SM1_STATE StartingState
#endif //!defined(TEST_SM1_STATE)

// ----- State machine
struct Sm1_:msmf::state_machine_def<Sm1_> {
    // States
    struct StartingState:msmf::state<> {
        // Entry action
        template <class Event,class Fsm>
        void on_entry(Event const&, Fsm&) {
            std::cout << "StartingState::on_entry()" << std::endl;
        }
    };
    struct IdleState:msmf::state<> {
        // Entry action
        template <class Event,class Fsm>
        void on_entry(Event const&, Fsm&) {
            std::cout << "IdleState::on_entry()" << std::endl;
        }
    };
    struct ErrorState:msmf::state<> {
        // Entry action
        template <class Event,class Fsm>
        void on_entry(Event const&, Fsm&) {
            std::cout << "ErrorState::on_entry()" << std::endl;
        }
    };

    // Set initial state
    using initial_state = TEST_SM1_STATE;

    // Transition table
    struct transition_table:mpl::vector<
        //          Start          Event   Next        Action      Guard
        msmf::Row < StartingState, Event1, IdleState,  msmf::none, msmf::none >,
        msmf::Row < IdleState,     Event1, ErrorState, msmf::none, msmf::none >
    > {};
};

// Pick a back-end
typedef msm::back::state_machine<Sm1_> Sm1;

test.cpp

#define TEST_SM1_STATE IdleState
#include "sm1.hpp"

int main() {
    Sm1 sm1;
    sm1.start(); 
}

Demo: https://wandbox.org/permlink/dnLrAZ7fTJhg473q

The key point is the following code:

// Set initial state
using initial_state = TEST_SM1_STATE;

You can set any state as the initial state. Define initial state before including sm1.hpp like as follows:

#define TEST_SM1_STATE IdleState
#include "sm1.hpp"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM