GCC Code Coverage Report


Directory: ./
File: test/unit-tests/test_entry_gate.cpp
Date: 2025-12-16 19:41:02
Exec Total Coverage
Lines: 94 94 100.0%
Functions: 5 5 100.0%
Branches: 62 124 50.0%

Line Branch Exec Source
1 /**
2 * @file test_entry_gate.cpp
3 * @brief Unit tests for Entry Gate Controller
4 *
5 * Example tests demonstrating the testability of the system
6 * using mock implementations.
7 */
8
9 #include "mocks/MockGpioInput.h"
10 #include "mocks/MockGate.h"
11 #include "mocks/MockEventBus.h"
12 #include "mocks/MockTicketService.h"
13 #include "EntryGateController.h"
14 #include <cassert>
15 #include <cstdio>
16
17 /**
18 * @brief Test complete entry cycle
19 *
20 * Scenario:
21 * 1. Button pressed
22 * 2. Capacity available
23 * 3. Ticket issued
24 * 4. Barrier opens
25 * 5. Car passes through
26 * 6. Barrier closes
27 */
28 1 void test_entry_full_cycle() {
29
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 printf("Test: Entry Full Cycle\n");
30
31 // Setup
32
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 MockEventBus eventBus;
33 1 MockGpioInput button;
34 1 MockGate gate;
35 1 MockTicketService tickets(5); // Capacity: 5
36
37 EntryGateController controller(
38
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 eventBus, button, gate, tickets, 100);
39
40 // Initial state
41
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(controller.getState() == EntryGateState::Idle);
42
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(!gate.isOpen()); // Gate closed
43
44 // Step 1: Button press -> publish event directly to bus
45
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 eventBus.publish(Event(EventType::EntryButtonPressed));
46
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 eventBus.processAllPending();
47
48 // Should transition through states and end up opening barrier
49
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(controller.getState() == EntryGateState::OpeningBarrier);
50
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(gate.isOpen()); // Gate opening
51
52 // Step 2: Simulate barrier opened (timeout)
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() == EntryGateState::WaitingForCar);
55
56 // Step 3: Car blocks light barrier
57
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 eventBus.publish(Event(EventType::EntryLightBarrierBlocked));
58
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 eventBus.processAllPending();
59
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(controller.getState() == EntryGateState::CarPassing);
60
61 // Step 4: Car clears light barrier -> should wait before closing
62
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 eventBus.publish(Event(EventType::EntryLightBarrierCleared));
63
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 eventBus.processAllPending();
64
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(controller.getState() == EntryGateState::WaitingBeforeClose);
65
66 // Step 5: Simulate 2-second wait timeout
67
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 controller.TEST_forceBarrierTimeout();
68
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(controller.getState() == EntryGateState::ClosingBarrier);
69
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(!gate.isOpen()); // Gate closing
70
71 // Step 6: Simulate barrier closed (timeout)
72
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 controller.TEST_forceBarrierTimeout();
73
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(controller.getState() == EntryGateState::Idle);
74
75
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 printf(" ✓ Button press handled\n");
76
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 printf(" ✓ Barrier opening\n");
77
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 printf(" ✓ Test passed!\n\n");
78 1 }
79
80 /**
81 * @brief Test entry when parking is full
82 *
83 * Scenario:
84 * 1. Fill parking to capacity
85 * 2. Button pressed
86 * 3. Capacity check fails
87 * 4. Remain in Idle state
88 * 5. No ticket issued
89 */
90 1 void test_entry_parking_full() {
91
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 printf("Test: Entry Parking Full\n");
92
93 // Setup
94
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 MockEventBus eventBus;
95 1 MockGpioInput button;
96 1 MockGate gate;
97 1 MockTicketService tickets(2); // Capacity: 2
98
99 // Fill parking
100
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 (void) tickets.getNewTicket();
101
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 (void) tickets.getNewTicket();
102
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(tickets.getActiveTicketCount() == 2);
103
104 EntryGateController controller(
105
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 eventBus, button, gate, tickets, 100);
106
107 // Initial state
108
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(controller.getState() == EntryGateState::Idle);
109
110 // Try to enter when full
111
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 eventBus.publish(Event(EventType::EntryButtonPressed));
112
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 eventBus.processAllPending();
113 // Ensure that the state remains Idle
114
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(controller.getState() == EntryGateState::Idle);
115
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(!gate.isOpen()); // Gate still closed
116
117 // Should remain idle
118
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(controller.getState() == EntryGateState::Idle);
119
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(!gate.isOpen()); // Gate still closed
120
121
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 printf(" ✓ Parking full detected\n");
122
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 printf(" ✓ Entry denied\n");
123
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 printf(" ✓ Test passed!\n\n");
124 1 }
125
126 /**
127 * @brief Test car passing through barrier
128 */
129 1 void test_entry_car_passing() {
130
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 printf("Test: Entry Car Passing\n");
131
132
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 MockEventBus eventBus;
133 1 MockGpioInput button;
134 1 MockGate gate;
135 1 MockTicketService tickets(5);
136
137 EntryGateController controller(
138
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 eventBus, button, gate, tickets, 100);
139
140 // Simulate reaching WaitingForCar state via button press and barrier timeout
141
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 eventBus.publish(Event(EventType::EntryButtonPressed));
142
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 eventBus.processAllPending();
143
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(controller.getState() == EntryGateState::OpeningBarrier);
144
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 controller.TEST_forceBarrierTimeout();
145
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(controller.getState() == EntryGateState::WaitingForCar);
146
147
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 printf(" ✓ Car detection logic ready\n");
148
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 printf(" ✓ Test passed!\n\n");
149 1 }
150
151 /**
152 * @brief Test: Multiple button presses while not Idle are ignored
153 */
154 1 void test_entry_ignore_repeated_press() {
155
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 printf("Test: Entry ignores repeated button press\n");
156
157
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 MockEventBus eventBus;
158 1 MockGpioInput button;
159 1 MockGate gate;
160 1 MockTicketService tickets(5);
161
162 EntryGateController controller(
163
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 eventBus, button, gate, tickets, 100);
164
165 // First press -> starts entry flow
166
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 eventBus.publish(Event(EventType::EntryButtonPressed));
167
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 eventBus.processAllPending();
168
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(controller.getState() == EntryGateState::OpeningBarrier);
169
170 // Press again while not Idle -> should be ignored
171
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 eventBus.publish(Event(EventType::EntryButtonPressed));
172
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 eventBus.processAllPending();
173
174 // Only one active ticket should exist
175
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(tickets.getActiveTicketCount() == 1);
176 // Still opening barrier, state unchanged
177
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(controller.getState() == EntryGateState::OpeningBarrier);
178
179
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 printf(" ✓ Duplicate press ignored\n\n");
180 1 }
181
182 /**
183 * @brief Run all tests
184 */
185 1 int main() {
186 1 printf("=================================\n");
187 1 printf("Entry Gate Controller Unit Tests\n");
188 1 printf("=================================\n\n");
189
190 1 test_entry_full_cycle();
191 1 test_entry_parking_full();
192 1 test_entry_car_passing();
193 1 test_entry_ignore_repeated_press();
194
195 1 printf("=================================\n");
196 1 printf("All tests passed!\n");
197 1 printf("=================================\n");
198
199 1 return 0;
200 }
201