mirror of
https://github.com/ETLCPP/etl.git
synced 2026-10-28 18:07:10 +08:00
Merge branch 'pull-request/#1199-Added-support-for-transitions-on-state-enter-for-HFSM' into development
This commit is contained in:
commit
85678586c4
@ -160,18 +160,6 @@ namespace etl
|
||||
}
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
/// Exception for forbidden state changes.
|
||||
//***************************************************************************
|
||||
class fsm_state_composite_state_change_forbidden : public etl::fsm_exception
|
||||
{
|
||||
public:
|
||||
fsm_state_composite_state_change_forbidden(string_type file_name_, numeric_type line_number_)
|
||||
: etl::fsm_exception(ETL_ERROR_TEXT("fsm:change in composite state forbidden", ETL_FSM_FILE_ID"E"), file_name_, line_number_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
/// Exception for message received but not started.
|
||||
//***************************************************************************
|
||||
@ -330,7 +318,6 @@ namespace etl
|
||||
|
||||
if (p_default_child == ETL_NULLPTR)
|
||||
{
|
||||
p_active_child = &state;
|
||||
p_default_child = &state;
|
||||
}
|
||||
}
|
||||
@ -481,7 +468,7 @@ namespace etl
|
||||
virtual void start(bool call_on_enter_state = true)
|
||||
{
|
||||
// Can only be started once.
|
||||
if (p_state == ETL_NULLPTR)
|
||||
if (!is_started())
|
||||
{
|
||||
p_state = state_list[0];
|
||||
ETL_ASSERT(p_state != ETL_NULLPTR, ETL_ERROR(etl::fsm_null_state_exception));
|
||||
@ -589,7 +576,7 @@ namespace etl
|
||||
//*******************************************
|
||||
virtual void reset(bool call_on_exit_state = false)
|
||||
{
|
||||
if ((p_state != ETL_NULLPTR) && call_on_exit_state)
|
||||
if (is_started() && call_on_exit_state)
|
||||
{
|
||||
p_state->on_exit_state();
|
||||
}
|
||||
@ -636,6 +623,12 @@ namespace etl
|
||||
//*******************************************
|
||||
virtual etl::fsm_state_id_t process_state_change(etl::fsm_state_id_t next_state_id)
|
||||
{
|
||||
if (is_self_transition(next_state_id))
|
||||
{
|
||||
p_state->on_exit_state();
|
||||
next_state_id = p_state->on_enter_state();
|
||||
}
|
||||
|
||||
if (have_changed_state(next_state_id))
|
||||
{
|
||||
ETL_ASSERT_OR_RETURN_VALUE(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception), p_state->get_state_id());
|
||||
@ -655,11 +648,6 @@ namespace etl
|
||||
}
|
||||
} while (p_next_state != p_state); // Have we changed state again?
|
||||
}
|
||||
else if (is_self_transition(next_state_id))
|
||||
{
|
||||
p_state->on_exit_state();
|
||||
p_state->on_enter_state();
|
||||
}
|
||||
|
||||
return p_state->get_state_id();
|
||||
}
|
||||
|
||||
@ -60,18 +60,33 @@ namespace etl
|
||||
void start(bool call_on_enter_state = true) ETL_OVERRIDE
|
||||
{
|
||||
// Can only be started once.
|
||||
if (p_state == ETL_NULLPTR)
|
||||
if (!is_started())
|
||||
{
|
||||
p_state = state_list[0];
|
||||
ETL_ASSERT(p_state != ETL_NULLPTR, ETL_ERROR(etl::fsm_null_state_exception));
|
||||
etl::ifsm_state* p_first_state = state_list[0];
|
||||
ETL_ASSERT(p_first_state != ETL_NULLPTR, ETL_ERROR(etl::fsm_null_state_exception));
|
||||
p_state = p_first_state;
|
||||
|
||||
if (call_on_enter_state)
|
||||
{
|
||||
etl::fsm_state_id_t next_state = do_enters(ETL_NULLPTR, p_state, true);
|
||||
|
||||
if (next_state != ifsm_state::No_State_Change)
|
||||
do_enters_result result = do_enters(ETL_NULLPTR, p_first_state, true);
|
||||
|
||||
if (result.active_state_id != ifsm_state::No_State_Change)
|
||||
{
|
||||
p_state = state_list[next_state];
|
||||
// If the active_state_id is not No_State_Change, it means that an on_enter changed the target state.
|
||||
// Set the state pointer as the active state to use it as the new origin for the transition to the
|
||||
// updated target state.
|
||||
ETL_ASSERT(result.active_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception));
|
||||
p_state = state_list[result.active_state_id];
|
||||
|
||||
process_state_change(result.next_state_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (have_changed_state(result.next_state_id))
|
||||
{
|
||||
ETL_ASSERT(result.next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception));
|
||||
p_state = state_list[result.next_state_id];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -83,7 +98,7 @@ namespace etl
|
||||
//*******************************************
|
||||
virtual void reset(bool call_on_exit_state = false) ETL_OVERRIDE
|
||||
{
|
||||
if ((p_state != ETL_NULLPTR) && call_on_exit_state)
|
||||
if (is_started() && call_on_exit_state)
|
||||
{
|
||||
do_exits(ETL_NULLPTR, p_state);
|
||||
}
|
||||
@ -151,10 +166,21 @@ namespace etl
|
||||
return s;
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
/// Result of a "do_enters()" call
|
||||
//*******************************************
|
||||
struct do_enters_result
|
||||
{
|
||||
// State which is presently being targeted as the next state
|
||||
etl::fsm_state_id_t next_state_id;
|
||||
// State which was active when the on_enter triggered a state change
|
||||
etl::fsm_state_id_t active_state_id;
|
||||
};
|
||||
|
||||
//*******************************************
|
||||
/// Entering the state.
|
||||
//*******************************************
|
||||
static etl::fsm_state_id_t do_enters(const etl::ifsm_state* p_root, etl::ifsm_state* p_target, bool activate_default_children)
|
||||
static do_enters_result do_enters(const etl::ifsm_state* p_root, etl::ifsm_state* p_target, bool activate_default_children)
|
||||
{
|
||||
ETL_ASSERT(p_target != ETL_NULLPTR, ETL_ERROR(etl::fsm_null_state_exception));
|
||||
|
||||
@ -163,8 +189,14 @@ namespace etl
|
||||
{
|
||||
if (p_target->p_parent != p_root)
|
||||
{
|
||||
// The parent we're calling shouldn't activate its defaults, or this state will be deactivated.
|
||||
do_enters(p_root, p_target->p_parent, false);
|
||||
// The parent we're calling shouldn't activate its defaults, or this state will be deactivated
|
||||
do_enters_result result = do_enters(p_root, p_target->p_parent, false);
|
||||
|
||||
// Short circuit the do enters if the parent state decided that a different state should be entered
|
||||
if (result.active_state_id != ifsm_state::No_State_Change)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Set us as our parent's active child
|
||||
@ -172,9 +204,14 @@ namespace etl
|
||||
}
|
||||
|
||||
etl::fsm_state_id_t next_state = p_target->on_enter_state();
|
||||
ETL_ASSERT(ifsm_state::No_State_Change == next_state, ETL_ERROR(etl::fsm_state_composite_state_change_forbidden));
|
||||
|
||||
// Short circuit the activation of any child states if the target state changed
|
||||
if (next_state != ifsm_state::No_State_Change)
|
||||
{
|
||||
return {next_state, p_target->get_state_id()};
|
||||
}
|
||||
|
||||
// Activate default child if we need to activate any initial states in an active composite state.
|
||||
// Activate default child if we need to activate any initial states in an active composite state
|
||||
if (activate_default_children)
|
||||
{
|
||||
while (p_target->p_default_child != ETL_NULLPTR)
|
||||
@ -182,13 +219,19 @@ namespace etl
|
||||
p_target = p_target->p_default_child;
|
||||
p_target->p_parent->p_active_child = p_target;
|
||||
next_state = p_target->on_enter_state();
|
||||
ETL_ASSERT(ifsm_state::No_State_Change == next_state, ETL_ERROR(etl::fsm_state_composite_state_change_forbidden));
|
||||
|
||||
// Short circuit the activation of any child states if the target state changed
|
||||
if (next_state != ifsm_state::No_State_Change)
|
||||
{
|
||||
return {next_state, p_target->get_state_id()};
|
||||
}
|
||||
}
|
||||
|
||||
next_state = p_target->get_state_id();
|
||||
}
|
||||
|
||||
return next_state;
|
||||
// Wrapping No_State_Change in a static_cast gets rid of the "undefined reference" error when compiling on C++11
|
||||
return {next_state, static_cast<fsm_state_id_t>(ifsm_state::No_State_Change)};
|
||||
}
|
||||
|
||||
//*******************************************
|
||||
@ -217,7 +260,13 @@ namespace etl
|
||||
//*******************************************
|
||||
etl::fsm_state_id_t process_state_change(etl::fsm_state_id_t next_state_id) ETL_OVERRIDE
|
||||
{
|
||||
if (have_changed_state(next_state_id))
|
||||
if (is_self_transition(next_state_id))
|
||||
{
|
||||
p_state->on_exit_state();
|
||||
next_state_id = p_state->on_enter_state();
|
||||
}
|
||||
|
||||
while (have_changed_state(next_state_id))
|
||||
{
|
||||
ETL_ASSERT_OR_RETURN_VALUE(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception), p_state->get_state_id());
|
||||
|
||||
@ -225,17 +274,34 @@ namespace etl
|
||||
etl::ifsm_state* p_root = common_ancestor(p_state, p_next_state);
|
||||
|
||||
do_exits(p_root, p_state);
|
||||
next_state_id = do_enters(p_root, p_next_state, true);
|
||||
|
||||
ETL_ASSERT_OR_RETURN_VALUE(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception), p_state->get_state_id());
|
||||
p_state = state_list[next_state_id];
|
||||
}
|
||||
else if (is_self_transition(next_state_id))
|
||||
{
|
||||
p_state->on_exit_state();
|
||||
p_state->on_enter_state();
|
||||
}
|
||||
do_enters_result result = do_enters(p_root, p_next_state, true);
|
||||
next_state_id = result.next_state_id;
|
||||
|
||||
if (result.active_state_id != ifsm_state::No_State_Change)
|
||||
{
|
||||
// If the active_state_id is not No_State_Change, it means that an on_enter changed the target state.
|
||||
// Set the state pointer as the active state to use it as the new origin for the transition to the
|
||||
// updated target state.
|
||||
ETL_ASSERT(result.active_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception));
|
||||
p_state = state_list[result.active_state_id];
|
||||
ETL_ASSERT(result.next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception));
|
||||
p_next_state = state_list[result.next_state_id];
|
||||
}
|
||||
else if (result.next_state_id != ifsm_state::No_State_Change)
|
||||
{
|
||||
// If the next state is different, means that default children were activated.
|
||||
// Assign both p_state and p_next_state to get out of the loop.
|
||||
ETL_ASSERT(result.next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception));
|
||||
p_state = state_list[result.next_state_id];
|
||||
p_next_state = state_list[result.next_state_id];
|
||||
}
|
||||
else
|
||||
{
|
||||
p_state = p_next_state;
|
||||
}
|
||||
}
|
||||
|
||||
return p_state->get_state_id();
|
||||
}
|
||||
};
|
||||
|
||||
@ -194,6 +194,7 @@ add_executable(etl_tests
|
||||
test_hash.cpp
|
||||
test_hfsm.cpp
|
||||
test_hfsm_recurse_to_inner_state_on_start.cpp
|
||||
test_hfsm_transition_on_enter.cpp
|
||||
test_histogram.cpp
|
||||
test_index_of_type.cpp
|
||||
test_indirect_vector.cpp
|
||||
|
||||
363
test/test_hfsm_transition_on_enter.cpp
Normal file
363
test/test_hfsm_transition_on_enter.cpp
Normal file
@ -0,0 +1,363 @@
|
||||
/******************************************************************************
|
||||
The MIT License(MIT)
|
||||
|
||||
Embedded Template Library.
|
||||
https://github.com/ETLCPP/etl
|
||||
https://www.etlcpp.com
|
||||
|
||||
Copyright(c) 2021
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include "unit_test_framework.h"
|
||||
|
||||
#include "etl/hfsm.h"
|
||||
#include "etl/string.h"
|
||||
#include <array>
|
||||
|
||||
// entry && mode=RxEventDeviation
|
||||
// ┌─────────────────────────────────────────────────────┐
|
||||
// │ │
|
||||
// * ┌────────▼─────────────┐ ToS6Event │
|
||||
// │ │ │ ┌────────────────────┐ │
|
||||
// │ │ s3 │ │ │ │
|
||||
// │ │ ┌─────────────────┐ │ │ ┌────────┼────────────┴──────────────┐
|
||||
// │ │ │ s2* │ │ │ │ s4 │ │
|
||||
// │ │ │ ┌────┐ ┌────┐ │ │ │ │ ┌────┴─────────────────────────┐ │
|
||||
// │ │ │ │ s1*│ │ s6 ◄─┼─┼─────┘ │ │ s5* │ │
|
||||
// │ │ │ │ │ │ │ │ │ entry && mode= │ ├──────────────────────────────┤ │
|
||||
// │ │ │ │ │ │ │ │ │ StartDeviation │ │ToS6Event && RxEventDuringTr./│ │
|
||||
// └──────┼──► │ │ │ │ ├─┼─────────────────┼───► receive(ToS5Event)** │ │
|
||||
// │ │ │ │ │ │ │ │ │ └─▲────────────────────────────┘ │
|
||||
// │ │ └┬───┘ └────┘ │ │ │ │ │
|
||||
// │ │ │ │ │ └─────┼──▲───────────────────────────┘
|
||||
// │ └──┼──────────────┘ │ │ │
|
||||
// │ │ │ │ │
|
||||
// └─────┼─┬──────────────┘ │ │
|
||||
// │ │ ToS5Event │ │
|
||||
// │ └──────────────────────────────────────┘ │
|
||||
// │ │
|
||||
// │ entry && mode=StartDeviationDefaultChild │
|
||||
// └───────────────────────────────────────────┘
|
||||
//
|
||||
// * indicates default state
|
||||
// ** Tests an exception for recursive receives
|
||||
// Diagram created with asciiflow.com
|
||||
|
||||
namespace
|
||||
{
|
||||
class StateList;
|
||||
|
||||
enum class Events : uint8_t
|
||||
{
|
||||
ToS5,
|
||||
ToS6
|
||||
};
|
||||
|
||||
class ToS5Event : public etl::message<static_cast<uint8_t>(Events::ToS5)>
|
||||
{
|
||||
};
|
||||
|
||||
class ToS6Event : public etl::message<static_cast<uint8_t>(Events::ToS6)>
|
||||
{
|
||||
};
|
||||
|
||||
class EntryTestSM : public etl::hfsm
|
||||
{
|
||||
public:
|
||||
EntryTestSM();
|
||||
|
||||
etl::string<30> test_data;
|
||||
enum RunMode
|
||||
{
|
||||
Normal,
|
||||
StartDeviation,
|
||||
RxEventDeviation,
|
||||
StartDeviationDefaultChild,
|
||||
RxEventDuringTransition
|
||||
};
|
||||
RunMode runMode = Normal;
|
||||
|
||||
enum hfsmStates : uint8_t
|
||||
{
|
||||
S2,
|
||||
S3,
|
||||
S1,
|
||||
S4,
|
||||
S5,
|
||||
S6,
|
||||
Number_Of_States
|
||||
};
|
||||
|
||||
private:
|
||||
std::unique_ptr<StateList> m_state_list;
|
||||
};
|
||||
|
||||
class S1 : public etl::fsm_state<EntryTestSM, S1, EntryTestSM::S1>
|
||||
{
|
||||
public:
|
||||
etl::fsm_state_id_t on_enter_state() override
|
||||
{
|
||||
get_fsm_context().test_data += "E1";
|
||||
return (get_fsm_context().runMode == EntryTestSM::StartDeviationDefaultChild)
|
||||
? static_cast<uint8_t>(EntryTestSM::S4) : No_State_Change;
|
||||
}
|
||||
|
||||
static etl::fsm_state_id_t on_event_unknown(const etl::imessage&)
|
||||
{
|
||||
return No_State_Change;
|
||||
}
|
||||
|
||||
void on_exit_state() override
|
||||
{
|
||||
get_fsm_context().test_data += "X1";
|
||||
}
|
||||
};
|
||||
|
||||
class S2 : public etl::fsm_state<EntryTestSM, S2, EntryTestSM::S2>
|
||||
{
|
||||
public:
|
||||
etl::fsm_state_id_t on_enter_state() override
|
||||
{
|
||||
get_fsm_context().test_data += "E2";
|
||||
return (get_fsm_context().runMode == EntryTestSM::StartDeviation)
|
||||
? static_cast<uint8_t>(EntryTestSM::S5) : No_State_Change;
|
||||
}
|
||||
|
||||
static etl::fsm_state_id_t on_event_unknown(const etl::imessage&)
|
||||
{
|
||||
return No_State_Change;
|
||||
}
|
||||
|
||||
void on_exit_state() override
|
||||
{
|
||||
get_fsm_context().test_data += "X2";
|
||||
}
|
||||
};
|
||||
|
||||
class S3 : public etl::fsm_state<EntryTestSM, S3, EntryTestSM::S3, ToS5Event>
|
||||
{
|
||||
public:
|
||||
etl::fsm_state_id_t on_enter_state() override
|
||||
{
|
||||
if(get_fsm_context().runMode == EntryTestSM::RxEventDuringTransition)
|
||||
{
|
||||
get_fsm_context().receive(ToS5Event{});
|
||||
}
|
||||
get_fsm_context().test_data += "E3";
|
||||
return No_State_Change;
|
||||
}
|
||||
|
||||
static etl::fsm_state_id_t on_event(ToS5Event const& /*event*/)
|
||||
{
|
||||
return EntryTestSM::S5;
|
||||
}
|
||||
|
||||
static etl::fsm_state_id_t on_event_unknown(const etl::imessage&)
|
||||
{
|
||||
return No_State_Change;
|
||||
}
|
||||
|
||||
void on_exit_state() override
|
||||
{
|
||||
get_fsm_context().test_data += "X3";
|
||||
}
|
||||
};
|
||||
|
||||
class S4 : public etl::fsm_state<EntryTestSM, S4, EntryTestSM::S4>
|
||||
{
|
||||
public:
|
||||
etl::fsm_state_id_t on_enter_state() override
|
||||
{
|
||||
get_fsm_context().test_data += "E4";
|
||||
return (get_fsm_context().runMode == EntryTestSM::RxEventDeviation)
|
||||
? static_cast<uint8_t>(EntryTestSM::S3) : No_State_Change;
|
||||
}
|
||||
|
||||
static etl::fsm_state_id_t on_event_unknown(const etl::imessage&)
|
||||
{
|
||||
return No_State_Change;
|
||||
}
|
||||
|
||||
void on_exit_state() override
|
||||
{
|
||||
get_fsm_context().test_data += "X4";
|
||||
}
|
||||
};
|
||||
|
||||
class S5 : public etl::fsm_state<EntryTestSM, S5, EntryTestSM::S5, ToS6Event>
|
||||
{
|
||||
public:
|
||||
etl::fsm_state_id_t on_enter_state() override
|
||||
{
|
||||
get_fsm_context().test_data += "E5";
|
||||
return No_State_Change;
|
||||
}
|
||||
|
||||
etl::fsm_state_id_t on_event(ToS6Event const& /*event*/)
|
||||
{
|
||||
if (get_fsm_context().runMode == EntryTestSM::RxEventDuringTransition)
|
||||
{
|
||||
get_fsm_context().receive(ToS5Event{});
|
||||
}
|
||||
return EntryTestSM::S6;
|
||||
}
|
||||
|
||||
static etl::fsm_state_id_t on_event_unknown(const etl::imessage&)
|
||||
{
|
||||
return No_State_Change;
|
||||
}
|
||||
|
||||
void on_exit_state() override
|
||||
{
|
||||
get_fsm_context().test_data += "X5";
|
||||
}
|
||||
};
|
||||
|
||||
class S6 : public etl::fsm_state<EntryTestSM, S6, EntryTestSM::S6>
|
||||
{
|
||||
public:
|
||||
etl::fsm_state_id_t on_enter_state() override
|
||||
{
|
||||
get_fsm_context().test_data += "E6";
|
||||
return No_State_Change;
|
||||
}
|
||||
|
||||
static etl::fsm_state_id_t on_event_unknown(const etl::imessage&)
|
||||
{
|
||||
return No_State_Change;
|
||||
}
|
||||
|
||||
void on_exit_state() override
|
||||
{
|
||||
get_fsm_context().test_data += "X6";
|
||||
}
|
||||
};
|
||||
|
||||
class StateList
|
||||
{
|
||||
public:
|
||||
StateList()
|
||||
{
|
||||
m_s3.add_child_state(m_s2);
|
||||
m_s2.add_child_state(m_s1);
|
||||
m_s2.add_child_state(m_s6);
|
||||
|
||||
m_s4.add_child_state(m_s5);
|
||||
}
|
||||
|
||||
std::array<etl::ifsm_state*, static_cast<uint8_t>(EntryTestSM::Number_Of_States)> stateList = {
|
||||
&m_s2, &m_s3, &m_s1, &m_s4, &m_s5, &m_s6};
|
||||
|
||||
private:
|
||||
// The states.
|
||||
S1 m_s1;
|
||||
S2 m_s2;
|
||||
S3 m_s3;
|
||||
S4 m_s4;
|
||||
S5 m_s5;
|
||||
S6 m_s6;
|
||||
};
|
||||
|
||||
EntryTestSM::EntryTestSM()
|
||||
: hfsm(0), m_state_list(new StateList{})
|
||||
{
|
||||
set_states(m_state_list->stateList.data(), m_state_list->stateList.size());
|
||||
}
|
||||
|
||||
SUITE(test_hfsm_transition_on_enter)
|
||||
{
|
||||
//*************************************************************************
|
||||
TEST(start_regular)
|
||||
{
|
||||
EntryTestSM sm;
|
||||
sm.start(true);
|
||||
CHECK_EQUAL("E3E2E1", sm.test_data.c_str());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(start_deviation)
|
||||
{
|
||||
// Checks default child wanting to go to another state
|
||||
EntryTestSM sm;
|
||||
sm.runMode = EntryTestSM::StartDeviation;
|
||||
sm.start(true);
|
||||
CHECK_EQUAL("E3E2X2X3E4E5", sm.test_data.c_str());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(start_deviation_with_default_child_activation)
|
||||
{
|
||||
// Checks default child wanting to go to another state
|
||||
EntryTestSM sm;
|
||||
sm.runMode = EntryTestSM::StartDeviationDefaultChild;
|
||||
sm.start(true);
|
||||
CHECK_EQUAL("E3E2E1X1X2X3E4E5", sm.test_data.c_str());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(receive_event_normal)
|
||||
{
|
||||
EntryTestSM sm;
|
||||
sm.start(true);
|
||||
sm.test_data.clear();
|
||||
sm.receive(ToS5Event{});
|
||||
CHECK_EQUAL("X1X2X3E4E5", sm.test_data.c_str());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(receive_event_with_deviation)
|
||||
{
|
||||
// Test utilizes default child state entry
|
||||
EntryTestSM sm;
|
||||
sm.start(true);
|
||||
sm.test_data.clear();
|
||||
sm.runMode = EntryTestSM::RxEventDeviation;
|
||||
sm.receive(ToS5Event{});
|
||||
CHECK_EQUAL("X1X2X3E4X4E3E2E1", sm.test_data.c_str());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(go_to_non_default_state_and_back)
|
||||
{
|
||||
EntryTestSM sm;
|
||||
// Skip enters so test data doesn't need to be cleared
|
||||
sm.start(false);
|
||||
sm.receive(ToS5Event{});
|
||||
sm.test_data.clear();
|
||||
sm.receive(ToS6Event{});
|
||||
CHECK_EQUAL("X5X4E3E2E6", sm.test_data.c_str());
|
||||
sm.test_data.clear();
|
||||
sm.receive(ToS5Event{});
|
||||
CHECK_EQUAL("X6X2X3E4E5", sm.test_data.c_str());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(reset_exits)
|
||||
{
|
||||
EntryTestSM sm;
|
||||
sm.start(true);
|
||||
sm.test_data.clear();
|
||||
sm.reset(true);
|
||||
CHECK_EQUAL("X1X2X3", sm.test_data.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@ -10282,6 +10282,7 @@
|
||||
<ClCompile Include="..\test_expected.cpp" />
|
||||
<ClCompile Include="..\test_function_traits.cpp" />
|
||||
<ClCompile Include="..\test_hfsm_recurse_to_inner_state_on_start.cpp" />
|
||||
<ClCompile Include="..\test_hfsm_transition_on_enter.cpp" />
|
||||
<ClCompile Include="..\test_index_of_type.cpp" />
|
||||
<ClCompile Include="..\test_intrusive_links.cpp" />
|
||||
<ClCompile Include="..\test_macros.cpp" />
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user