From 3fd114e5b76f04bc7794485ff8338bd12a9ffef7 Mon Sep 17 00:00:00 2001 From: apolisskyi Date: Sat, 26 Aug 2023 22:05:42 +0300 Subject: [PATCH] fsm:attempt to have state hooks list traverse --- .gitignore | 1 + src/active-object/active_object_impl.h | 5 +- test/active-object/active_object.test.c | 92 ++----------------- test/fsm/fsm.test.c | 73 +--------------- test/integration/fsm_active_object.test.c | 102 +--------------------- 5 files changed, 14 insertions(+), 259 deletions(-) diff --git a/.gitignore b/.gitignore index 53b72be..45e82d8 100755 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # IDE .idea +.vscode # Compiled build diff --git a/src/active-object/active_object_impl.h b/src/active-object/active_object_impl.h index d05842e..c780080 100755 --- a/src/active-object/active_object_impl.h +++ b/src/active-object/active_object_impl.h @@ -4,6 +4,7 @@ #include "./active_object.h" #include "../queue/queue_impl.h" +//Generate Unit tests for this macro on Unity framework #define ACTIVE_OBJECT_IMPLEMENTATION(ACTIVE_OBJECT_T, EVENT_T, STATE_T, FIELDS_T, maxQueueCapacity) \ QUEUE_IMPLEMENTATION(EVENT_T, maxQueueCapacity); \ \ @@ -32,8 +33,8 @@ \ EVENT_T e = QUEUE_##EVENT_T##_Dequeue(&self->queue); \ STATE_T nextState = eventHandlerCb(self, e); \ - void* ctx = e->payload ? e->payload : NULL; \ - transitionToNextStateCb(self, nextState, ctx); \ + /* TODO implement passing ctx from event */\ + transitionToNextStateCb(self, nextState, NULL); \ } #endif //ACTIVE_OBJECT_IMPL_H diff --git a/test/active-object/active_object.test.c b/test/active-object/active_object.test.c index 46b189b..468ccdc 100755 --- a/test/active-object/active_object.test.c +++ b/test/active-object/active_object.test.c @@ -2,100 +2,20 @@ #include "../../src/active-object/active_object.h" #include "../../src/active-object/active_object_impl.h" -// Define the types for our test -typedef enum { - TEST_EVENT_A, - TEST_EVENT_B -} TestEvent; - -typedef enum { - TEST_STATE_IDLE, - TEST_STATE_RUNNING, - TEST_STATE_PAUSED -} TestState; - -typedef struct { - int value; -} TestFields; - -DECLARE_ACTIVE_OBJECT(TestActiveObject, TestEvent, TestState, TestFields, 5); -ACTIVE_OBJECT_IMPLEMENTATION(TestActiveObject, TestEvent, TestState, TestFields, 5); - -TestState handleEvent(TestActiveObject *self, TestEvent e) { - switch(e) { - case TEST_EVENT_A: return TEST_STATE_RUNNING; - case TEST_EVENT_B: return TEST_STATE_PAUSED; - default: return self->state; // No change in state - } -} - -bool transitionToState(TestActiveObject *self, TestState nextState) { - return TestActiveObject_basicTransitionToNextState(self, nextState); -} - -void handleEmptyQueue(TestActiveObject *self) { - // For this test, do nothing when the queue is empty. -} - void setUp(void) { - // Called before each test case + // This is run before EACH test } void tearDown(void) { - // Called after each test case + // This is run after EACH test } -void test_constructor(void) { - TestActiveObject obj; - TestFields fields = { .value = 10 }; - TestActiveObject_Ctor(&obj, 1, TEST_STATE_IDLE, fields); - TEST_ASSERT_EQUAL(1, obj.id); - TEST_ASSERT_EQUAL(TEST_STATE_IDLE, obj.state); - TEST_ASSERT_EQUAL(10, obj.fields.value); - TEST_ASSERT_EQUAL(0, QUEUE_TestEvent_GetSize(&obj.queue)); -} -void test_dispatchAndProcessQueue(void) { - TestActiveObject obj; - TestFields fields = { .value = 10 }; - TestActiveObject_Ctor(&obj, 1, TEST_STATE_IDLE, fields); - - // Dispatch TEST_EVENT_A and process it - TestActiveObject_Dispatch(&obj, TEST_EVENT_A); - TestActiveObject_ProcessQueue(&obj, handleEvent, transitionToState); - - TEST_ASSERT_EQUAL(TEST_STATE_RUNNING, obj.state); - - // Dispatch TEST_EVENT_B and process it - TestActiveObject_Dispatch(&obj, TEST_EVENT_B); - TestActiveObject_ProcessQueue(&obj, handleEvent, transitionToState); - - TEST_ASSERT_EQUAL(TEST_STATE_PAUSED, obj.state); -} - -void test_hasEmptyQueue(void) { - TestActiveObject obj; - TestFields fields = { .value = 10 }; - TestActiveObject_Ctor(&obj, 1, TEST_STATE_IDLE, fields); - - // Initially the queue should be empty - TEST_ASSERT_TRUE(TestActiveObject_HasEmptyQueue(&obj)); - - // Add an item to the queue and check again - TestActiveObject_Dispatch(&obj, TEST_EVENT_A); - TEST_ASSERT_FALSE(TestActiveObject_HasEmptyQueue(&obj)); - - // Process the queue, it should become empty again - TestActiveObject_ProcessQueue(&obj, handleEvent, transitionToState); - TEST_ASSERT_TRUE(TestActiveObject_HasEmptyQueue(&obj)); -} +int main(void) +{ + // UNITY_BEGIN(); -int main(void) { - UNITY_BEGIN(); - RUN_TEST(test_constructor); - RUN_TEST(test_dispatchAndProcessQueue); - RUN_TEST(test_hasEmptyQueue); - UNITY_END(); + // return UNITY_END(); return 0; } diff --git a/test/fsm/fsm.test.c b/test/fsm/fsm.test.c index ec38743..e122bbf 100755 --- a/test/fsm/fsm.test.c +++ b/test/fsm/fsm.test.c @@ -2,83 +2,14 @@ #include "../../src/fsm/fsm.h" #include "../../src/fsm/fsm_impl.h" -typedef struct { - int sig; -} MockEvent; - -enum { - MOCK_EVENT_A_SIG, - MOCK_EVENT_B_SIG, - MOCK_EVENT_C_SIG -}; - -typedef enum { - MOCK_STATE_IDLE, - MOCK_STATE_RUNNING, - MOCK_STATE_PAUSED -} MockState; - -typedef struct { - int value; - MockState state; -} MockActiveObject; - -DECLARE_FSM(MockActiveObject, MockEvent, MockState, 3, 3); -FSM_IMPLEMENTATION(MockActiveObject, MockEvent, MockState, 3, 3); - -// Mock state handlers -MockState mock_idle_handler(MockActiveObject *const ao, MockEvent event) { - return MOCK_STATE_RUNNING; -} - -MockState mock_running_handler(MockActiveObject *const ao, MockEvent event) { - return MOCK_STATE_PAUSED; -} - -MockState mock_paused_handler(MockActiveObject *const ao, MockEvent event) { - return MOCK_STATE_IDLE; -} - void setUp(void) { - // Called before each test case + // This is run before EACH test } void tearDown(void) { - // Called after each test case -} - -void test_fsm_process_event_to_next_state(void) { - MockActiveObject ao = { .value = 10 }; - - // Declare and initialize transition table - MockEvent_HANDLE_F transitionTable[3][3]; - transitionTable[MOCK_STATE_IDLE][MOCK_EVENT_A_SIG] = mock_idle_handler; - transitionTable[MOCK_STATE_RUNNING][MOCK_EVENT_B_SIG] = mock_running_handler; - transitionTable[MOCK_STATE_PAUSED][MOCK_EVENT_C_SIG] = mock_paused_handler; - - // Process MOCK_EVENT_A_SIG while in MOCK_STATE_IDLE -> should transition to MOCK_STATE_RUNNING - ao.state = MOCK_STATE_IDLE; - MockEvent e = { .sig = MOCK_EVENT_A_SIG }; - MockState nextState = MockActiveObject_FSM_ProcessEventToNextState(&ao, e, transitionTable, NULL); - TEST_ASSERT_EQUAL(MOCK_STATE_RUNNING, nextState); - - // Process MOCK_EVENT_B_SIG while in MOCK_STATE_RUNNING -> should transition to MOCK_STATE_PAUSED - ao.state = MOCK_STATE_RUNNING; - e.sig = MOCK_EVENT_B_SIG; - nextState = MockActiveObject_FSM_ProcessEventToNextState(&ao, e, transitionTable, NULL); - TEST_ASSERT_EQUAL(MOCK_STATE_PAUSED, nextState); - - // Process MOCK_EVENT_C_SIG while in MOCK_STATE_PAUSED -> should transition to MOCK_STATE_IDLE - ao.state = MOCK_STATE_PAUSED; - e.sig = MOCK_EVENT_C_SIG; - nextState = MockActiveObject_FSM_ProcessEventToNextState(&ao, e, transitionTable, NULL); - TEST_ASSERT_EQUAL(MOCK_STATE_IDLE, nextState); + // This is run after EACH test } int main(void) { - UNITY_BEGIN(); - RUN_TEST(test_fsm_process_event_to_next_state); - UNITY_END(); - return 0; } diff --git a/test/integration/fsm_active_object.test.c b/test/integration/fsm_active_object.test.c index a644cd2..df8fbb4 100755 --- a/test/integration/fsm_active_object.test.c +++ b/test/integration/fsm_active_object.test.c @@ -4,114 +4,16 @@ #include "../../src/fsm/fsm.h" #include "../../src/fsm/fsm_impl.h" -#define QUEUE_CAPACITY 5 -#define EVENTS_MAX 3 -#define STATES_MAX 3 - -typedef enum { - MOCK_EVENT_A_SIG, - MOCK_EVENT_B_SIG, - MOCK_EVENT_C_SIG -} MockEventSignal; - -typedef struct { - MockEventSignal sig; -} MockEvent; - -typedef enum { - MOCK_STATE_IDLE, - MOCK_STATE_RUNNING, - MOCK_STATE_PAUSED -} MockState; - -typedef struct { - int value; -} MockFields; - -DECLARE_ACTIVE_OBJECT(MockActiveObject, MockEvent, MockState, MockFields, QUEUE_CAPACITY); -ACTIVE_OBJECT_IMPLEMENTATION(MockActiveObject, MockEvent, MockState, MockFields, QUEUE_CAPACITY); -DECLARE_FSM(MockActiveObject, MockEvent, MockState, EVENTS_MAX, STATES_MAX); -FSM_IMPLEMENTATION(MockActiveObject, MockEvent, MockState, EVENTS_MAX, STATES_MAX); - -// Mock state handlers (FSM) -MockState mock_idle_handler(MockActiveObject *const ao, MockEvent event) { - return MOCK_STATE_RUNNING; -} - -MockState mock_running_handler(MockActiveObject *const ao, MockEvent event) { - return MOCK_STATE_PAUSED; -} - -MockState mock_paused_handler(MockActiveObject *const ao, MockEvent event) { - return MOCK_STATE_IDLE; -} - -MockEvent_HANDLE_F stateTransitionTable[STATES_MAX][EVENTS_MAX] = { - [MOCK_STATE_IDLE] = { - [MOCK_EVENT_A_SIG] = mock_idle_handler, - [MOCK_EVENT_B_SIG] = NULL, - [MOCK_EVENT_C_SIG] = NULL - }, - [MOCK_STATE_RUNNING] = { - [MOCK_EVENT_A_SIG] = NULL, - [MOCK_EVENT_B_SIG] = mock_running_handler, - [MOCK_EVENT_C_SIG] = NULL - }, - [MOCK_STATE_PAUSED] = { - [MOCK_EVENT_A_SIG] = NULL, - [MOCK_EVENT_B_SIG] = NULL, - [MOCK_EVENT_C_SIG] = mock_paused_handler - } -}; - void setUp(void) { - // Called before each test case + // This is run before EACH test } void tearDown(void) { - // Called after each test case + // This is run after EACH test } -void integration_test_active_object_with_fsm_and_queue(void) { - MockActiveObject ao; - MockFields fields = { .value = 10 }; - - // Initialization - MockActiveObject_Ctor(&ao, 1, MOCK_STATE_IDLE, fields); - TEST_ASSERT_EQUAL(1, ao.id); - TEST_ASSERT_EQUAL(MOCK_STATE_IDLE, ao.state); - TEST_ASSERT_EQUAL(10, ao.fields.value); - TEST_ASSERT_EQUAL(0, QUEUE_MockEvent_GetSize(&ao.queue)); - - // Dispatching and processing an event - MockEvent e1 = { .sig = MOCK_EVENT_A_SIG }; - MockActiveObject_Dispatch(&ao, e1); - TEST_ASSERT_EQUAL(1, QUEUE_MockEvent_GetSize(&ao.queue)); - - // Process Event with FSM - MockState nextState = MockActiveObject_FSM_ProcessEventToNextState(&ao, e1, stateTransitionTable, NULL); - TEST_ASSERT_EQUAL(MOCK_STATE_RUNNING, nextState); - ao.state = nextState; // Update the actual state of the active object - - // Dispatching and processing a second event - MockEvent e2 = { .sig = MOCK_EVENT_B_SIG }; - MockActiveObject_Dispatch(&ao, e2); - nextState = MockActiveObject_FSM_ProcessEventToNextState(&ao, e2, stateTransitionTable, NULL); - TEST_ASSERT_EQUAL(MOCK_STATE_PAUSED, nextState); - ao.state = nextState; // Update the actual state of the active object - - // Dispatching and processing a third event - MockEvent e3 = { .sig = MOCK_EVENT_C_SIG }; - MockActiveObject_Dispatch(&ao, e3); - nextState = MockActiveObject_FSM_ProcessEventToNextState(&ao, e3, stateTransitionTable, NULL); - TEST_ASSERT_EQUAL(MOCK_STATE_IDLE, nextState); - ao.state = nextState; // Update the actual state of the active object -} int main(void) { - UNITY_BEGIN(); - RUN_TEST(integration_test_active_object_with_fsm_and_queue); - UNITY_END(); return 0; }