Как напрямую достичь любого состояния в машине состояний, написанной с помощью Boost MSM - PullRequest
1 голос
/ 10 января 2020

В настоящее время я использую библиотеку Boost MSM для написания конечного автомата и хочу написать модульные тесты для проверки переходов между его состояниями. Для каждого модульного теста мне нужно писать повторяющиеся строки кода, чтобы достичь состояния, из которого я хочу начать. Поэтому я хотел бы знать, является ли это способом запуска конечного автомата в заданном состоянии вместо начального состояния.

Например, если у меня есть простой конечный автомат, который обычно запускается в StartingState, я хотел бы напрямую связаться с IdleState, чтобы выполнить мой тест:

  • -> StartingState -> IdleState -> ErrorState

1 Ответ

1 голос
/ 12 января 2020

Boost.MSM напрямую не поддерживает желаемую функциональность.

Но вы можете управлять начальным состоянием, используя initial_state внутренний тип и макрос препроцессора.

Допустим, ваше состояние машина определена в 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(); 
}

Демо: https://wandbox.org/permlink/dnLrAZ7fTJhg473q

Ключевым моментом является следующий код:

// Set initial state
using initial_state = TEST_SM1_STATE;

Вы можете установить любое состояние в качестве исходного состояния. Определите начальное состояние перед включением sm1.hpp следующим образом:

#define TEST_SM1_STATE IdleState
#include "sm1.hpp"
...