103 Star 575 Fork 242

cpp-master/cpp-tbox

加入 Gitee
与超过 1400万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
state_machine_test.cpp 20.90 KB
一键复制 编辑 原始数据 按行查看 历史
海卫哥 提交于 2023-08-07 23:54 +08:00 . feat(flow,dbus):1.5.8
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719
/*
* .============.
* // M A K E / \
* // C++ DEV / \
* // E A S Y / \/ \
* ++ ----------. \/\ .
* \\ \ \ /\ /
* \\ \ \ /
* \\ \ \ /
* -============'
*
* Copyright (c) 2018 Hevake and contributors, all rights reserved.
*
* This file is part of cpp-tbox (https://github.com/cpp-main/cpp-tbox)
* Use of this source code is governed by MIT license that can be found
* in the LICENSE file in the root of the source tree. All contributing
* project authors may be found in the CONTRIBUTORS.md file in the root
* of the source tree.
*/
#include <gtest/gtest.h>
#include <tbox/base/json.hpp>
#include "state_machine.h"
using namespace std;
namespace tbox {
namespace flow {
using SM = StateMachine;
enum StateId {
STATE_TERM = 0,
STATE_A,
STATE_B,
STATE_C,
STATE_D,
};
enum EventId {
EVENT_ANY = 0,
EVENT_1,
EVENT_2,
EVENT_3,
EVENT_4,
};
//! 测试创建状态
TEST(StateMachine, NewState)
{
SM sm;
EXPECT_TRUE (sm.newState(STATE_A, nullptr, nullptr));
EXPECT_TRUE (sm.newState(STATE_B, nullptr, nullptr));
EXPECT_FALSE(sm.newState(STATE_A, nullptr, nullptr));
}
//! 测试创建事件
TEST(StateMachine, AddRoute)
{
SM sm;
sm.newState(STATE_A, nullptr, nullptr);
sm.newState(STATE_B, nullptr, nullptr);
EXPECT_TRUE (sm.addRoute(STATE_A, EVENT_1, STATE_B, nullptr, nullptr));
EXPECT_FALSE(sm.addRoute(STATE_A, EVENT_1, STATE_C, nullptr, nullptr));
EXPECT_FALSE(sm.addRoute(STATE_C, EVENT_1, STATE_B, nullptr, nullptr));
EXPECT_FALSE(sm.addRoute(STATE_C, EVENT_1, STATE_D, nullptr, nullptr));
}
//! 测试创建两个状态,一个事件由A到B转换,没有守卫与执行函数
TEST(StateMachine, StateWithoutGuardAndAction)
{
SM sm;
sm.newState(STATE_A, nullptr, nullptr);
sm.newState(STATE_B, nullptr, nullptr);
sm.addRoute(STATE_A, EVENT_1, STATE_B, nullptr, nullptr);
sm.setInitState(STATE_A);
sm.start();
EXPECT_EQ(sm.currentState(), STATE_A);
EXPECT_TRUE(sm.run(EVENT_1));
EXPECT_EQ(sm.currentState(), STATE_B);
EXPECT_FALSE(sm.run(EVENT_2));
}
//! 测试创建两个状态,一个事件由A到B转换,有守卫
TEST(StateMachine, RouteWithGuard)
{
SM sm;
sm.newState(STATE_A, nullptr, nullptr);
sm.newState(STATE_B, nullptr, nullptr);
sm.newState(STATE_C, nullptr, nullptr);
bool condition = false;
sm.addRoute(STATE_A, EVENT_1, STATE_B, [&](Event){ return !condition; }, nullptr);
sm.addRoute(STATE_A, EVENT_1, STATE_C, [&](Event){ return condition; }, nullptr);
sm.addRoute(STATE_B, EVENT_2, STATE_A, nullptr, nullptr);
sm.addRoute(STATE_C, EVENT_2, STATE_A, nullptr, nullptr);
sm.setInitState(STATE_A);
sm.start();
EXPECT_EQ(sm.currentState(), STATE_A);
condition = false;
EXPECT_TRUE(sm.run(EVENT_1));
EXPECT_EQ(sm.currentState(), STATE_B);
EXPECT_TRUE(sm.run(EVENT_2));
EXPECT_EQ(sm.currentState(), STATE_A);
condition = true;
EXPECT_TRUE(sm.run(EVENT_1));
EXPECT_EQ(sm.currentState(), STATE_C);
EXPECT_TRUE(sm.run(EVENT_2));
EXPECT_EQ(sm.currentState(), STATE_A);
}
//! 测试创建两个状态,一个事件由A到B转换,有进入与退出动作
TEST(StateMachine, StateWithEnterAndExitAction)
{
SM sm;
int a_enter_counter = 0;
int a_exit_counter = 0;
int b_enter_counter = 0;
int b_exit_counter = 0;
sm.newState(STATE_A, [&](Event){ ++a_enter_counter; }, [&](Event){ ++a_exit_counter; });
sm.newState(STATE_B, [&](Event){ ++b_enter_counter; }, [&](Event){ ++b_exit_counter; });
sm.addRoute(STATE_A, EVENT_1, STATE_B, nullptr, nullptr);
sm.addRoute(STATE_B, EVENT_2, STATE_A, nullptr, nullptr);
sm.setInitState(STATE_A);
EXPECT_EQ(a_enter_counter, 0);
sm.start();
EXPECT_EQ(a_enter_counter, 1);
sm.run(EVENT_1);
EXPECT_EQ(a_exit_counter, 1);
EXPECT_EQ(b_enter_counter, 1);
sm.run(EVENT_2);
EXPECT_EQ(b_exit_counter, 1);
EXPECT_EQ(a_enter_counter, 2);
}
//! 测试创建两个状态,一个事件由A到B转换,事件有转换动作
TEST(StateMachine, EventWithAction)
{
SM sm;
sm.newState(STATE_A, nullptr, nullptr);
sm.newState(STATE_B, nullptr, nullptr);
int count_1 = 0;
int count_2 = 0;
sm.addRoute(STATE_A, EVENT_1, STATE_B, nullptr, [&](Event){ ++count_1; });
sm.addRoute(STATE_B, EVENT_2, STATE_A, nullptr, [&](Event){ ++count_2; });
sm.setInitState(STATE_A);
sm.start();
sm.run(EVENT_1);
EXPECT_EQ(count_1, 1);
sm.run(EVENT_2);
EXPECT_EQ(count_2, 1);
}
TEST(StateMachine, AnyEvent)
{
SM sm;
sm.newState(STATE_A, nullptr, nullptr);
sm.newState(STATE_B, nullptr, nullptr);
sm.addRoute(STATE_A, 0, STATE_B, nullptr, nullptr);
sm.addRoute(STATE_B, 0, STATE_A, nullptr, nullptr);
sm.setInitState(STATE_A);
sm.start();
sm.run(EVENT_1);
EXPECT_EQ(sm.currentState(), STATE_B);
sm.run(EVENT_2);
EXPECT_EQ(sm.currentState(), STATE_A);
sm.run(EVENT_3);
EXPECT_EQ(sm.currentState(), STATE_B);
}
TEST(StateMachine, Restart)
{
SM sm;
int a_enter_counter = 0;
int a_exit_counter = 0;
int b_enter_counter = 0;
int b_exit_counter = 0;
sm.newState(STATE_A, [&](Event){ ++a_enter_counter; }, [&](Event){ ++a_exit_counter; });
sm.newState(STATE_B, [&](Event){ ++b_enter_counter; }, [&](Event){ ++b_exit_counter; });
sm.addRoute(STATE_A, EVENT_1, STATE_B, nullptr, nullptr);
sm.setInitState(STATE_A);
sm.start();
EXPECT_EQ(a_enter_counter, 1);
EXPECT_TRUE(sm.run(EVENT_1));
EXPECT_EQ(a_exit_counter, 1);
EXPECT_EQ(b_enter_counter, 1);
sm.restart();
EXPECT_EQ(b_exit_counter, 1);
EXPECT_EQ(a_enter_counter, 2);
EXPECT_EQ(sm.currentState(), STATE_A);
}
//! 主要测试用 enum class 定义的状态与事件是否能编译过
TEST(StateMachine, EnumClass)
{
SM sm;
enum class StateId { k1 = 1, k2 };
enum class EventId { k1 = 1, k2 };
int enter_counter = 0;
int exit_counter = 0;
sm.newState(StateId::k1, [&](Event){ ++enter_counter; }, [&](Event){ ++exit_counter; });
sm.newState(StateId::k2, nullptr, nullptr);
sm.addRoute(StateId::k1, EventId::k1, StateId::k2, nullptr, nullptr);
sm.addRoute(StateId::k2, EventId::k2, StateId::k1, nullptr, nullptr);
sm.setInitState(StateId::k1);
sm.start();
sm.run(EventId::k1);
sm.run(EventId::k2);
sm.stop();
EXPECT_EQ(enter_counter, 2);
EXPECT_EQ(exit_counter, 2);
}
TEST(StateMachine, SubSM)
{
enum class StateId { kTerm, kInit, k1, k2 };
enum class EventId { kTerm, k1, k2 };
SM sm, sub_sm;
sm.newState(StateId::kInit, nullptr, nullptr);
sm.newState(StateId::k1, nullptr, nullptr);
sm.newState(StateId::k2, nullptr, nullptr);
sm.addRoute(StateId::kInit, EventId::k1, StateId::k1, nullptr, nullptr);
sm.addRoute(StateId::kInit, EventId::k2, StateId::k2, nullptr, nullptr);
sm.addRoute(StateId::k1, EventId::k1, StateId::kTerm, nullptr, nullptr);
sm.addRoute(StateId::k1, EventId::k2, StateId::k2, nullptr, nullptr);
sm.addRoute(StateId::k2, EventId::k1, StateId::k1, nullptr, nullptr);
sm.addRoute(StateId::k2, EventId::k2, StateId::k1, nullptr, nullptr);
sub_sm.newState(StateId::kInit, nullptr, nullptr);
sub_sm.newState(StateId::k1, nullptr, nullptr);
sub_sm.newState(StateId::k2, nullptr, nullptr);
sub_sm.addRoute(StateId::kInit, EventId::k1, StateId::k1, nullptr, nullptr);
sub_sm.addRoute(StateId::kInit, EventId::k2, StateId::k2, nullptr, nullptr);
sub_sm.addRoute(StateId::k1, EventId::k2, StateId::k2, nullptr, nullptr);
sub_sm.addRoute(StateId::k1, EventId::k1, StateId::kTerm, nullptr, nullptr);
sub_sm.addRoute(StateId::k2, EventId::k1, StateId::k1, nullptr, nullptr);
sub_sm.addRoute(StateId::k2, EventId::k2, StateId::kTerm, nullptr, nullptr);
sm.setSubStateMachine(StateId::k1, &sub_sm);
{ //! 直通
sm.start();
EXPECT_EQ(sm.currentState<StateId>(), StateId::kInit);
EXPECT_EQ(sub_sm.currentState(), -1);
EXPECT_TRUE(sm.run(EventId::k1));
EXPECT_EQ(sm.currentState<StateId>(), StateId::k1);
EXPECT_EQ(sub_sm.currentState<StateId>(), StateId::k1);
EXPECT_TRUE(sm.run(EventId::k1));
EXPECT_EQ(sm.currentState<StateId>(), StateId::kTerm);
EXPECT_EQ(sub_sm.currentState(), -1);
EXPECT_TRUE(sm.isTerminated());
sm.stop();
}
{ //! 在子状态机里转了一下
sm.start();
EXPECT_EQ(sm.currentState<StateId>(), StateId::kInit);
EXPECT_EQ(sub_sm.currentState(), -1);
EXPECT_TRUE(sm.run(EventId::k1));
EXPECT_EQ(sm.currentState<StateId>(), StateId::k1);
EXPECT_EQ(sub_sm.currentState<StateId>(), StateId::k1);
EXPECT_TRUE(sm.run(EventId::k2));
EXPECT_EQ(sm.currentState<StateId>(), StateId::k1);
EXPECT_EQ(sub_sm.currentState<StateId>(), StateId::k2);
EXPECT_TRUE(sm.run(EventId::k1));
EXPECT_EQ(sm.currentState<StateId>(), StateId::k1);
EXPECT_EQ(sub_sm.currentState<StateId>(), StateId::k1);
EXPECT_TRUE(sm.run(EventId::k1));
EXPECT_EQ(sm.currentState<StateId>(), StateId::kTerm);
EXPECT_EQ(sub_sm.currentState(), -1);
EXPECT_TRUE(sm.isTerminated());
sm.stop();
}
{ //! 从S2进的S1的子状态机,再出来回到S2,再进去
sm.start();
EXPECT_EQ(sm.currentState<StateId>(), StateId::kInit);
EXPECT_EQ(sub_sm.currentState(), -1);
EXPECT_TRUE(sm.run(EventId::k2));
EXPECT_EQ(sm.currentState<StateId>(), StateId::k2);
EXPECT_EQ(sub_sm.currentState(), -1);
EXPECT_TRUE(sm.run(EventId::k2));
EXPECT_EQ(sm.currentState<StateId>(), StateId::k1);
EXPECT_EQ(sub_sm.currentState<StateId>(), StateId::k2);
EXPECT_TRUE(sm.run(EventId::k2));
EXPECT_EQ(sm.currentState<StateId>(), StateId::k2);
EXPECT_EQ(sub_sm.currentState(), -1);
EXPECT_TRUE(sm.run(EventId::k2));
EXPECT_EQ(sm.currentState<StateId>(), StateId::k1);
EXPECT_EQ(sub_sm.currentState<StateId>(), StateId::k2);
EXPECT_TRUE(sm.run(EventId::k1));
EXPECT_EQ(sm.currentState<StateId>(), StateId::k1);
EXPECT_EQ(sub_sm.currentState<StateId>(), StateId::k1);
EXPECT_TRUE(sm.run(EventId::k1));
EXPECT_EQ(sm.currentState<StateId>(), StateId::kTerm);
EXPECT_EQ(sub_sm.currentState(), -1);
sm.stop();
}
}
TEST(StateMachine, StateChangedCallback)
{
enum class StateId { kTerm, kInit, k1 };
enum class EventId { kAny, k1 };
SM sm;
sm.newState(StateId::kInit, nullptr, nullptr);
sm.newState(StateId::k1, nullptr, nullptr);
sm.addRoute(StateId::kInit, EventId::k1, StateId::k1, nullptr, nullptr);
sm.addRoute(StateId::k1, EventId::k1, StateId::kTerm, nullptr, nullptr);
StateId from, to;
EventId event;
sm.setStateChangedCallback(
[&] (SM::StateID f, SM::StateID t, Event e) {
from = static_cast<StateId>(f);
to = static_cast<StateId>(t);
event = static_cast<EventId>(e.id);
}
);
sm.start();
sm.run(EventId::k1);
EXPECT_EQ(from, StateId::kInit);
EXPECT_EQ(to, StateId::k1);
EXPECT_EQ(event, EventId::k1);
sm.run(EventId::k1);
EXPECT_EQ(from, StateId::k1);
EXPECT_EQ(to, StateId::kTerm);
EXPECT_EQ(event, EventId::k1);
}
//! 测试起始状态有子状态的情况
TEST(StateMachine, InitStateHasSubMachine)
{
enum class StateId { kTerm, kInit };
enum class EventId { kAny, k1 };
SM sm;
SM sub_sm;
int step = 0;
sm.newState(StateId::kInit, [&](Event){ EXPECT_EQ(step, 0); ++step; }, [&](Event){ EXPECT_EQ(step, 6); ++step; });
sm.newState(StateId::kTerm, [&](Event){ EXPECT_EQ(step, 8); ++step; }, [&](Event){ EXPECT_EQ(step, 9); ++step; });
sm.addRoute(StateId::kInit, EventId::k1, StateId::kTerm, nullptr, [&](Event){ EXPECT_EQ(step, 7); ++step; });
sub_sm.newState(StateId::kInit, [&](Event){ EXPECT_EQ(step, 1); ++step; }, [&](Event){ EXPECT_EQ(step, 2); ++step; });
sub_sm.newState(StateId::kTerm, [&](Event){ EXPECT_EQ(step, 4); ++step; }, [&](Event){ EXPECT_EQ(step, 5); ++step; });
sub_sm.addRoute(StateId::kInit, EventId::k1, StateId::kTerm, nullptr, [&](Event){ EXPECT_EQ(step, 3); ++step; });
sm.setSubStateMachine(StateId::kInit, &sub_sm);
#if 0
sm.setStateChangedCallback(
[&] (SM::StateID f, SM::StateID t, EventID e) {
cout << f << "-->" << t << "," << e << endl;
}
);
sub_sm.setStateChangedCallback(
[&] (SM::StateID f, SM::StateID t, EventID e) {
cout << " " << f << "-->" << t << "," << e << endl;
}
);
#endif
sm.start();
sm.run(EventId::k1);
sm.stop();
}
//! 测试各种Action之间的执行顺序
TEST(StateMachine, SubSMActionOrder)
{
enum class StateId { kTerm, kInit, k1};
enum class EventId { kAny, k1 };
SM sm;
SM sub_sm;
int step = 0;
sm.newState(StateId::kInit, [&](Event){ EXPECT_EQ(step, 0); ++step; }, [&](Event){ EXPECT_EQ(step, 1); ++step; });
sm.newState(StateId::k1, [&](Event){ EXPECT_EQ(step, 3); ++step; }, [&](Event){ EXPECT_EQ(step, 9); ++step; });
sm.newState(StateId::kTerm, [&](Event){ EXPECT_EQ(step, 11); ++step; }, [&](Event){ EXPECT_EQ(step, 12); ++step; });
sm.addRoute(StateId::kInit, EventId::k1, StateId::k1, nullptr, [&](Event){ EXPECT_EQ(step, 2); ++step; });
sm.addRoute(StateId::k1, EventId::k1, StateId::kTerm, nullptr, [&](Event){ EXPECT_EQ(step, 10); ++step; });
sub_sm.newState(StateId::kInit, [&](Event){ EXPECT_EQ(step, 4); ++step; }, [&](Event){ EXPECT_EQ(step, 5); ++step; });
sub_sm.newState(StateId::kTerm, [&](Event){ EXPECT_EQ(step, 7); ++step; }, [&](Event){ EXPECT_EQ(step, 8); ++step; });
sub_sm.addRoute(StateId::kInit, EventId::k1, StateId::kTerm, nullptr, [&](Event){ EXPECT_EQ(step, 6); ++step; });
sm.setSubStateMachine(StateId::k1, &sub_sm);
#if 0
sm.setStateChangedCallback(
[&] (SM::StateID f, SM::StateID t, EventID e) {
cout << f << "-->" << t << "," << e << endl;
}
);
sub_sm.setStateChangedCallback(
[&] (SM::StateID f, SM::StateID t, EventID e) {
cout << " " << f << "-->" << t << "," << e << endl;
}
);
#endif
sm.start();
sm.run(EventId::k1);
sm.run(EventId::k1);
sm.stop();
}
TEST(StateMachine, EventExtra)
{
enum class StateId { kTerm, kInit };
SM sm;
int extra_data = 100;
int count = 0;
sm.newState(StateId::kInit,
[&](Event e){
++count;
EXPECT_EQ(e.id, 0);
EXPECT_EQ(e.extra, nullptr);
},
[&](Event e){
++count;
EXPECT_EQ(e.id, 10);
EXPECT_EQ(e.extra, &extra_data);
}
);
sm.newState(StateId::kTerm,
[&](Event e){
++count;
EXPECT_EQ(e.id, 10);
EXPECT_EQ(e.extra, &extra_data);
},
[&](Event e){
++count;
EXPECT_EQ(e.id, 0);
EXPECT_EQ(e.extra, nullptr);
}
);
sm.addRoute(StateId::kInit, 10, StateId::kTerm,
[&](Event e){
++count;
EXPECT_EQ(e.id, 10);
EXPECT_EQ(e.extra, &extra_data);
return true;
},
[&](Event e){
++count;
EXPECT_EQ(e.id, 10);
EXPECT_EQ(e.extra, &extra_data);
}
);
sm.setStateChangedCallback(
[&] (SM::StateID f, SM::StateID t, Event e) {
++count;
EXPECT_EQ(e.id, 10);
EXPECT_EQ(e.extra, &extra_data);
(void)f;
(void)t;
}
);
sm.start();
sm.run(Event(10, &extra_data));
sm.stop();
EXPECT_EQ(count, 7);
}
TEST(StateMachine, InnerEvent) {
enum class StateId { kTerm, k1, k2 };
enum class EventId { kAny, k1 };
SM sm;
bool is_k1_event_run = false;
bool is_k2_event_run = false;
sm.setInitState(StateId::k1);
sm.newState(StateId::k1, nullptr, nullptr);
sm.newState(StateId::k2, nullptr, nullptr);
sm.addEvent(StateId::k1, EventId::k1, [&](Event) { is_k1_event_run = true; return -1; });
sm.addRoute(StateId::k1, EventId::k1, StateId::k2, nullptr, nullptr);
sm.addEvent(StateId::k2, EventId::k1, [&](Event) { is_k2_event_run = true; return -1; });
sm.start();
sm.run(EventId::k1);
EXPECT_TRUE(is_k1_event_run);
EXPECT_FALSE(is_k2_event_run);
EXPECT_EQ(sm.currentState<StateId>(), StateId::k2);
is_k1_event_run = false;
sm.run(EventId::k1);
EXPECT_FALSE(is_k1_event_run);
EXPECT_TRUE(is_k2_event_run);
}
TEST(StateMachine, InnerAnyEvent) {
enum class StateId { kTerm, k1 };
enum class EventId { kAny, k1, k2 };
SM sm;
bool is_k1_event_run = false;
bool is_any_event_run = false;
sm.setInitState(StateId::k1);
sm.newState(StateId::k1, nullptr, nullptr);
sm.addEvent(StateId::k1, EventId::k1, [&](Event) { is_k1_event_run = true; return -1; });
sm.addEvent(StateId::k1, EventId::kAny, [&](Event) { is_any_event_run = true; return -1; });
sm.start();
sm.run(EventId::k1);
EXPECT_TRUE(is_k1_event_run);
EXPECT_FALSE(is_any_event_run);
is_k1_event_run = false;
sm.run(EventId::k2);
EXPECT_FALSE(is_k1_event_run);
EXPECT_TRUE(is_any_event_run);
}
TEST(StateMachine, SwitchStateInEvent) {
SM sm;
sm.newState(STATE_A, nullptr, nullptr);
sm.newState(STATE_B, nullptr, nullptr);
sm.setInitState(STATE_A);
sm.addEvent(STATE_A, EVENT_ANY,
[](Event e) -> SM::StateID {
if (e.id == EVENT_1)
return STATE_B;
if (e.id == EVENT_2)
return STATE_TERM;
return -1;
}
);
sm.addEvent(STATE_B, EVENT_1,
[](Event e) -> SM::StateID { return STATE_A; (void)e; }
);
sm.start();
EXPECT_EQ(sm.currentState(), STATE_A);
EXPECT_TRUE(sm.run(EVENT_1));
EXPECT_EQ(sm.currentState(), STATE_B);
EXPECT_FALSE(sm.run(EVENT_2));
EXPECT_TRUE(sm.run(EVENT_1));
EXPECT_EQ(sm.currentState(), STATE_A);
EXPECT_TRUE(sm.run(EVENT_2));
EXPECT_EQ(sm.currentState(), STATE_TERM);
EXPECT_TRUE(sm.isTerminated());
}
TEST(StateMachine, SetInitState)
{
enum class StateId { kTerm, k1, kInit };
enum class EventId { kAny, k1 };
SM sm;
sm.setInitState(StateId::kInit);
sm.newState(StateId::kInit, nullptr, nullptr);
sm.newState(StateId::k1, nullptr, nullptr);
EXPECT_TRUE(sm.start());
EXPECT_EQ(sm.currentState<StateId>(), StateId::kInit);
}
TEST(StateMachine, SetInitState_Fail)
{
enum class StateId { kTerm, k1, kInit };
enum class EventId { kAny, k1 };
SM sm;
sm.setInitState(StateId::kInit);
sm.newState(StateId::k1, nullptr, nullptr);
EXPECT_FALSE(sm.start());
}
TEST(StateMachine, LastNextState)
{
enum class StateId {
kNone = -1,
kTerm = 0,
kInit,
kA
};
enum class EventId {
kAny,
k1
};
SM sm;
int count = 0;
sm.setInitState(StateId::kInit);
sm.newState(StateId::kInit,
[&] (Event) {
++count;
EXPECT_EQ(sm.currentState<StateId>(), StateId::kInit);
EXPECT_EQ(sm.lastState(), -1);
EXPECT_EQ(sm.nextState(), -1);
},
[&] (Event) {
++count;
EXPECT_EQ(sm.currentState<StateId>(), StateId::kInit);
EXPECT_EQ(sm.lastState(), -1);
EXPECT_EQ(sm.nextState<StateId>(), StateId::kA);
}
);
sm.newState(StateId::kA,
[&] (Event) {
++count;
EXPECT_EQ(sm.currentState<StateId>(), StateId::kA);
EXPECT_EQ(sm.lastState<StateId>(), StateId::kInit);
EXPECT_EQ(sm.nextState(), -1);
},
[&] (Event) {
++count;
EXPECT_EQ(sm.currentState<StateId>(), StateId::kA);
EXPECT_EQ(sm.lastState<StateId>(), StateId::kInit);
EXPECT_EQ(sm.nextState<StateId>(), StateId::kTerm);
}
);
sm.newState(StateId::kTerm,
[&] (Event) {
++count;
EXPECT_EQ(sm.currentState<StateId>(), StateId::kTerm);
EXPECT_EQ(sm.lastState<StateId>(), StateId::kA);
EXPECT_EQ(sm.nextState(), -1);
},
nullptr
);
sm.addRoute(StateId::kInit, EventId::k1, StateId::kA, nullptr,
[&] (Event) {
++count;
EXPECT_EQ(sm.currentState(), -1);
EXPECT_EQ(sm.lastState<StateId>(), StateId::kInit);
EXPECT_EQ(sm.nextState<StateId>(), StateId::kA);
}
);
sm.addRoute(StateId::kA, EventId::k1, StateId::kTerm, nullptr,
[&] (Event) {
++count;
EXPECT_EQ(sm.currentState(), -1);
EXPECT_EQ(sm.lastState<StateId>(), StateId::kA);
EXPECT_EQ(sm.nextState<StateId>(), StateId::kTerm);
}
);
sm.start();
sm.run(EventId::k1);
sm.run(EventId::k1);
EXPECT_EQ(count, 7);
}
}
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C++
1
https://gitee.com/cpp-master/cpp-tbox.git
git@gitee.com:cpp-master/cpp-tbox.git
cpp-master
cpp-tbox
cpp-tbox
master

搜索帮助