Skip to content

Commit a5cf09a

Browse files
committed
Add tests for new filter + modules
1 parent aa913d4 commit a5cf09a

File tree

4 files changed

+819
-0
lines changed

4 files changed

+819
-0
lines changed
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
#include <unity.h>
2+
#include <memory>
3+
4+
#include <Filters/DigitalPassthroughFilter.h>
5+
6+
void setUp(void)
7+
{
8+
// Setup for each test
9+
}
10+
11+
void tearDown(void)
12+
{
13+
// Cleanup after each test
14+
}
15+
16+
void DigitalPassthroughFilter_Constructor_CreatesPins()
17+
{
18+
// Arrange
19+
DigitalPassthroughFilter filter;
20+
21+
// Act
22+
auto inputPins = filter.GetInputPins();
23+
auto outputPins = filter.GetOutputPins();
24+
25+
// Assert
26+
TEST_ASSERT_EQUAL(1, inputPins.size());
27+
TEST_ASSERT_EQUAL(1, outputPins.size());
28+
29+
auto inputPin = inputPins[0].lock();
30+
auto outputPin = outputPins[0].lock();
31+
32+
TEST_ASSERT_NOT_NULL(inputPin.get());
33+
TEST_ASSERT_NOT_NULL(outputPin.get());
34+
35+
// Default states
36+
TEST_ASSERT_EQUAL(DigitalValue(false), inputPin->GetStateAs<DigitalValue>());
37+
TEST_ASSERT_EQUAL(DigitalValue(false), outputPin->GetStateAs<DigitalValue>());
38+
}
39+
40+
void DigitalPassthroughFilter_InputChangesOutput()
41+
{
42+
// Arrange
43+
DigitalPassthroughFilter filter;
44+
auto inputPin = filter.GetInputPins()[0].lock();
45+
auto outputPin = filter.GetOutputPins()[0].lock();
46+
47+
// Act: Set input to true
48+
inputPin->SetState(DigitalValue(true));
49+
50+
// Assert: Output should now be true
51+
TEST_ASSERT_EQUAL(DigitalValue(true), outputPin->GetStateAs<DigitalValue>());
52+
53+
// Act: Set input to false
54+
inputPin->SetState(DigitalValue(false));
55+
56+
// Assert: Output should now be false
57+
TEST_ASSERT_EQUAL(DigitalValue(false), outputPin->GetStateAs<DigitalValue>());
58+
}
59+
60+
void DigitalPassthroughFilter_Callback_IsCalled_OnChange()
61+
{
62+
// Arrange
63+
DigitalPassthroughFilter filter;
64+
auto inputPin = filter.GetInputPins()[0].lock();
65+
66+
bool callbackCalled = false;
67+
DigitalValue callbackValue(false);
68+
69+
filter.SetStateCallback(
70+
[&](const DigitalPassthroughFilter&, DigitalValue value)
71+
{
72+
callbackCalled = true;
73+
callbackValue = value;
74+
});
75+
76+
// Act: Change input to true
77+
inputPin->SetState(DigitalValue(true));
78+
79+
// Assert
80+
TEST_ASSERT_TRUE(callbackCalled);
81+
TEST_ASSERT_EQUAL(DigitalValue(true), callbackValue);
82+
}
83+
84+
void DigitalPassthroughFilter_Callback_NotCalled_WhenStateUnchanged()
85+
{
86+
// Arrange
87+
DigitalPassthroughFilter filter;
88+
auto inputPin = filter.GetInputPins()[0].lock();
89+
90+
bool callbackCalled = false;
91+
92+
filter.SetStateCallback(
93+
[&](const DigitalPassthroughFilter&, DigitalValue)
94+
{
95+
callbackCalled = true;
96+
});
97+
98+
// Act: Set input to false (already false)
99+
inputPin->SetState(DigitalValue(false));
100+
101+
// Assert
102+
TEST_ASSERT_FALSE(callbackCalled);
103+
}
104+
105+
void DigitalPassthroughFilter_SetStateCallback_OnlyOnce()
106+
{
107+
// Arrange
108+
DigitalPassthroughFilter filter;
109+
110+
auto first = [&](const DigitalPassthroughFilter&, DigitalValue) {};
111+
auto second = [&](const DigitalPassthroughFilter&, DigitalValue) {};
112+
113+
// Act
114+
bool firstResult = filter.SetStateCallback(first);
115+
bool secondResult = filter.SetStateCallback(second);
116+
117+
// Assert
118+
TEST_ASSERT_TRUE(firstResult);
119+
TEST_ASSERT_FALSE(secondResult);
120+
}
121+
122+
int main()
123+
{
124+
UNITY_BEGIN();
125+
126+
RUN_TEST(DigitalPassthroughFilter_Constructor_CreatesPins);
127+
RUN_TEST(DigitalPassthroughFilter_InputChangesOutput);
128+
RUN_TEST(DigitalPassthroughFilter_Callback_IsCalled_OnChange);
129+
RUN_TEST(DigitalPassthroughFilter_Callback_NotCalled_WhenStateUnchanged);
130+
RUN_TEST(DigitalPassthroughFilter_SetStateCallback_OnlyOnce);
131+
132+
return UNITY_END();
133+
}
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
#include <unity.h>
2+
#include <memory>
3+
4+
#include <Modules/InputModule.h>
5+
#include "../../Mocks/MockBus.h"
6+
7+
void setUp(void)
8+
{
9+
// Setup for each test
10+
}
11+
12+
void tearDown(void)
13+
{
14+
// Cleanup after each test
15+
}
16+
17+
void InputModule_CreateFromInitialData_InitializesCorrectly()
18+
{
19+
// Arrange
20+
MockBus bus;
21+
const uint8_t address = 0x20;
22+
const uint16_t initialData = 0x3000; // 3 inputs
23+
24+
// Act
25+
auto module = InputModule::CreateFromInitialData(bus, address, initialData);
26+
27+
// Assert
28+
auto outputPins = module->GetOutputPins();
29+
TEST_ASSERT_EQUAL(3, outputPins.size());
30+
31+
for (const auto& weakPin : outputPins)
32+
{
33+
auto pin = weakPin.lock();
34+
TEST_ASSERT_NOT_NULL(pin.get());
35+
TEST_ASSERT_EQUAL(DigitalValue(false), pin->GetStateAs<DigitalValue>());
36+
}
37+
}
38+
39+
void InputModule_Process_FirstPoll_ForcesExchange()
40+
{
41+
// Arrange
42+
MockBus bus;
43+
const uint8_t address = 0x20;
44+
const uint8_t numberOfInputs = 4;
45+
46+
ScanResponse response =
47+
{
48+
.Success = true,
49+
.RespondedWithTypeAndData = false
50+
};
51+
bus.QueueResponse(response);
52+
53+
InputModule module(bus, address, numberOfInputs);
54+
55+
// Act
56+
auto result = module.Process();
57+
58+
// Assert
59+
TEST_ASSERT_TRUE(result.Success);
60+
TEST_ASSERT_TRUE(bus.ExchangeCalled);
61+
TEST_ASSERT_TRUE(bus.LastForceDataExchange); // first call forces exchange
62+
TEST_ASSERT_EQUAL(address, bus.LastExchangeAddress);
63+
}
64+
65+
void InputModule_Process_SuccessfulPoll_NoInputsActive()
66+
{
67+
// Arrange
68+
MockBus bus;
69+
const uint8_t address = 0x20;
70+
const uint8_t numberOfInputs = 8;
71+
72+
ScanResponse response =
73+
{
74+
.Success = true,
75+
.RespondedWithTypeAndData = true,
76+
.Data = 0x0000
77+
};
78+
bus.QueueResponse(response);
79+
80+
InputModule module(bus, address, numberOfInputs);
81+
82+
// Act
83+
auto result = module.Process();
84+
85+
// Assert
86+
TEST_ASSERT_TRUE(result.Success);
87+
88+
auto pins = module.GetOutputPins();
89+
for (const auto& weakPin : pins)
90+
TEST_ASSERT_EQUAL(DigitalValue(false), weakPin.lock()->GetStateAs<DigitalValue>());
91+
}
92+
93+
void InputModule_Process_SuccessfulPoll_InputsActive()
94+
{
95+
// Arrange
96+
MockBus bus;
97+
const uint8_t address = 0x20;
98+
const uint8_t numberOfInputs = 8;
99+
100+
// InputMasks8[0] = 0x10 → bit 4
101+
ScanResponse response =
102+
{
103+
.Success = true,
104+
.RespondedWithTypeAndData = true,
105+
.Data = 0x0010
106+
};
107+
bus.QueueResponse(response);
108+
109+
InputModule module(bus, address, numberOfInputs);
110+
111+
// Act
112+
auto result = module.Process();
113+
114+
// Assert
115+
TEST_ASSERT_TRUE(result.Success);
116+
117+
auto pins = module.GetOutputPins();
118+
TEST_ASSERT_EQUAL(DigitalValue(true), pins[0].lock()->GetStateAs<DigitalValue>());
119+
for (size_t i = 1; i < pins.size(); i++)
120+
TEST_ASSERT_EQUAL(DigitalValue(false), pins[i].lock()->GetStateAs<DigitalValue>());
121+
}
122+
123+
void InputModule_Process_SecondPoll_DoesNotForceExchange()
124+
{
125+
// Arrange
126+
MockBus bus;
127+
const uint8_t address = 0x20;
128+
const uint8_t numberOfInputs = 8;
129+
130+
// First response: data
131+
ScanResponse first =
132+
{
133+
.Success = true,
134+
.RespondedWithTypeAndData = true,
135+
.Data = 0x0010
136+
};
137+
bus.QueueResponse(first);
138+
139+
// Second response: no data
140+
ScanResponse second =
141+
{
142+
.Success = true,
143+
.RespondedWithTypeAndData = false
144+
};
145+
bus.QueueResponse(second);
146+
147+
InputModule module(bus, address, numberOfInputs);
148+
149+
// First call forces exchange
150+
auto firstResult = module.Process();
151+
TEST_ASSERT_TRUE(firstResult.Success);
152+
153+
bus.ClearCalls();
154+
155+
// Act – second call should NOT force exchange
156+
auto secondResult = module.Process();
157+
158+
// Assert
159+
TEST_ASSERT_TRUE(secondResult.Success);
160+
TEST_ASSERT_TRUE(bus.ExchangeCalled);
161+
TEST_ASSERT_FALSE(bus.LastForceDataExchange);
162+
}
163+
164+
void InputModule_Process_FailedPoll()
165+
{
166+
// Arrange
167+
MockBus bus;
168+
const uint8_t address = 0x20;
169+
const uint8_t numberOfInputs = 8;
170+
171+
ScanResponse failed =
172+
{
173+
.Success = false
174+
};
175+
bus.QueueResponse(failed);
176+
177+
InputModule module(bus, address, numberOfInputs);
178+
179+
// Act
180+
auto result = module.Process();
181+
182+
// Assert
183+
TEST_ASSERT_FALSE(result.Success);
184+
TEST_ASSERT_TRUE(bus.ExchangeCalled);
185+
TEST_ASSERT_TRUE(bus.LastForceDataExchange); // still forced on first call
186+
}
187+
188+
int main()
189+
{
190+
UNITY_BEGIN();
191+
192+
RUN_TEST(InputModule_CreateFromInitialData_InitializesCorrectly);
193+
RUN_TEST(InputModule_Process_FirstPoll_ForcesExchange);
194+
RUN_TEST(InputModule_Process_SuccessfulPoll_NoInputsActive);
195+
RUN_TEST(InputModule_Process_SuccessfulPoll_InputsActive);
196+
RUN_TEST(InputModule_Process_SecondPoll_DoesNotForceExchange);
197+
RUN_TEST(InputModule_Process_FailedPoll);
198+
199+
return UNITY_END();
200+
}

0 commit comments

Comments
 (0)