Skip to content

Commit

Permalink
fsm:attempt to have state hooks list traverse
Browse files Browse the repository at this point in the history
  • Loading branch information
polesskiy-dev committed Aug 26, 2023
1 parent 596a0bd commit 3fd114e
Show file tree
Hide file tree
Showing 5 changed files with 14 additions and 259 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# IDE
.idea
.vscode

# Compiled
build
Expand Down
5 changes: 3 additions & 2 deletions src/active-object/active_object_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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); \
\
Expand Down Expand Up @@ -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
92 changes: 6 additions & 86 deletions test/active-object/active_object.test.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
73 changes: 2 additions & 71 deletions test/fsm/fsm.test.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
102 changes: 2 additions & 100 deletions test/integration/fsm_active_object.test.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

0 comments on commit 3fd114e

Please sign in to comment.