GCC Code Coverage Report


Directory: ./
File: test/unit-tests/test_exit_gate.cpp
Date: 2025-12-16 19:41:02
Exec Total Coverage
Lines: 92 94 97.9%
Functions: 5 5 100.0%
Branches: 64 126 50.8%

Line Branch Exec Source
1 /**
2 * @file test_exit_gate.cpp
3 * @brief Unit tests for Exit Gate Controller
4 */
5
6 #include "mocks/MockGate.h"
7 #include "mocks/MockEventBus.h"
8 #include "mocks/MockTicketService.h"
9 #include "ExitGateController.h"
10 #include <cassert>
11 #include <cstdio>
12
13 1 void test_exit_full_cycle() {
14
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 printf("Test: Exit Full Cycle (Manual Validation)\n");
15
16
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 MockEventBus eventBus;
17 1 MockGate gate;
18 1 MockTicketService tickets(5);
19
20 // Pre-create one active PAID ticket (ID=1)
21
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 uint32_t id = tickets.getNewTicket();
22
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 assert(id == 1);
23
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 tickets.payTicket(id); // Pay the ticket!
24
25 ExitGateController controller(
26
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 eventBus, gate, tickets, 100, 50);
27
28 // Initial state
29
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(controller.getState() == ExitGateState::Idle);
30
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(!gate.isOpen());
31
32 // Manually validate ticket
33
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 bool validated = controller.validateTicketManually(id);
34
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 assert(validated);
35
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 eventBus.processAllPending();
36
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(controller.getState() == ExitGateState::OpeningBarrier);
37
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(gate.isOpen());
38
39 // Barrier finished opening
40
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 controller.TEST_forceBarrierTimeout();
41
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(controller.getState() == ExitGateState::WaitingForCarToPass);
42
43 // Car passes through
44
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 eventBus.publish(Event(EventType::ExitLightBarrierBlocked)); // blocked -> entering
45
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 eventBus.processAllPending();
46
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(controller.getState() == ExitGateState::CarPassing);
47
48
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 eventBus.publish(Event(EventType::ExitLightBarrierCleared)); // cleared -> car left
49
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 eventBus.processAllPending();
50
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(controller.getState() == ExitGateState::WaitingBeforeClose);
51
52 // Wait 2 seconds before closing
53
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 controller.TEST_forceBarrierTimeout();
54
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(controller.getState() == ExitGateState::ClosingBarrier);
55
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(!gate.isOpen());
56
57 // Barrier finished closing
58
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 controller.TEST_forceBarrierTimeout();
59
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(controller.getState() == ExitGateState::Idle);
60
61
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 printf(" ✓ Exit full cycle with manual validation\n\n");
62 1 }
63
64 1 void test_exit_no_tickets_rejected() {
65
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 printf("Test: Exit No Tickets -> Rejected\n");
66
67
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 MockEventBus eventBus;
68 1 MockGate gate;
69 1 MockTicketService tickets(5);
70
71 ExitGateController controller(
72
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 eventBus, gate, tickets, 100, 10);
73
74 // Try to validate non-existent ticket
75
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 bool validated = controller.validateTicketManually(99);
76
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 assert(!validated); // Should fail
77
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 eventBus.processAllPending();
78
79 // Should return to Idle (rejected)
80
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(controller.getState() == ExitGateState::Idle);
81
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(!gate.isOpen());
82
83
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 printf(" ✓ Rejection without active tickets\n\n");
84 1 }
85
86 1 void test_exit_unpaid_ticket_rejected() {
87
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 printf("Test: Exit rejects unpaid ticket\n");
88
89
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 MockEventBus eventBus;
90 1 MockGate gate;
91 1 MockTicketService tickets(5);
92
93 // Prepare one active ticket (UNPAID)
94
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 uint32_t id = tickets.getNewTicket(); // ID=1
95 1 Ticket ticket;
96
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 bool found = tickets.getTicketInfo(id, ticket);
97
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 assert(found && !ticket.isPaid); // Verify unpaid
98
99 ExitGateController controller(
100
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 eventBus, gate, tickets, 100, 50);
101
102 // Try to validate unpaid ticket
103
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 bool validated = controller.validateTicketManually(id);
104
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 assert(!validated); // Should fail - ticket not paid
105
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 eventBus.processAllPending();
106
107 // Should return to Idle
108
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(controller.getState() == ExitGateState::Idle);
109
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(!gate.isOpen());
110
111 // Ensure no ExitBarrierOpened event
112 1 bool openedEvent = false;
113
2/2
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 1 times.
2 for (const auto& ev : eventBus.history()) {
114
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ev.type == EventType::ExitBarrierOpened) {
115 ✗ openedEvent = true;
116 ✗ break;
117 }
118 }
119
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 assert(!openedEvent && "ExitBarrierOpened should not be published for unpaid ticket");
120
121
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 printf(" ✓ Unpaid ticket rejected\n\n");
122 1 }
123
124 1 void test_exit_light_barrier_in_idle_ignored() {
125
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 printf("Test: Light barrier in Idle state is ignored\n");
126
127
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 MockEventBus eventBus;
128 1 MockGate gate;
129 1 MockTicketService tickets(5);
130
131 // Create a paid ticket
132
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 uint32_t id = tickets.getNewTicket();
133
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 tickets.payTicket(id);
134
135 ExitGateController controller(
136
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 eventBus, gate, tickets, 100, 10);
137
138 // Initial state
139
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(controller.getState() == ExitGateState::Idle);
140
141 // Trigger light barrier in Idle - should be ignored
142
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 eventBus.publish(Event(EventType::ExitLightBarrierBlocked));
143
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 eventBus.processAllPending();
144
145 // Should still be in Idle
146
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(controller.getState() == ExitGateState::Idle);
147
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(!gate.isOpen());
148
149
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 printf(" ✓ Light barrier ignored in Idle state\n\n");
150 1 }
151
152 1 int main() {
153 1 printf("=================================\n");
154 1 printf("Exit Gate Controller Unit Tests\n");
155 1 printf("=================================\n\n");
156
157 1 test_exit_full_cycle();
158 1 test_exit_no_tickets_rejected();
159 1 test_exit_unpaid_ticket_rejected();
160 1 test_exit_light_barrier_in_idle_ignored();
161
162 1 printf("=================================\n");
163 1 printf("All tests passed!\n");
164 1 printf("=================================\n");
165 1 return 0;
166 }
167