1 #include "dbus_environment.hpp"
2 #include "helpers.hpp"
3 #include "mocks/clock_mock.hpp"
4 #include "mocks/sensor_mock.hpp"
5 #include "mocks/trigger_action_mock.hpp"
6 #include "on_change_threshold.hpp"
7 #include "utils/conv_container.hpp"
8 
9 #include <gmock/gmock.h>
10 
11 using namespace testing;
12 using namespace std::chrono_literals;
13 
14 class TestOnChangeThreshold : public Test
15 {
16   public:
17     std::vector<std::shared_ptr<SensorMock>> sensorMocks = {
18         std::make_shared<NiceMock<SensorMock>>(),
19         std::make_shared<NiceMock<SensorMock>>()};
20     std::vector<std::string> sensorNames = {"Sensor1", "Sensor2"};
21     std::unique_ptr<TriggerActionMock> actionMockPtr =
22         std::make_unique<StrictMock<TriggerActionMock>>();
23     TriggerActionMock& actionMock = *actionMockPtr;
24     std::shared_ptr<OnChangeThreshold> sut;
25     std::string triggerId = "MyTrigger";
26     std::unique_ptr<NiceMock<ClockMock>> clockMockPtr =
27         std::make_unique<NiceMock<ClockMock>>();
28 
SetUp()29     void SetUp() override
30     {
31         std::vector<std::unique_ptr<interfaces::TriggerAction>> actions;
32         actions.push_back(std::move(actionMockPtr));
33 
34         for (size_t idx = 0; idx < sensorMocks.size(); idx++)
35         {
36             ON_CALL(*sensorMocks.at(idx), getName())
37                 .WillByDefault(Return(sensorNames[idx]));
38         }
39 
40         sut = std::make_shared<OnChangeThreshold>(
41             triggerId,
42             utils::convContainer<std::shared_ptr<interfaces::Sensor>>(
43                 sensorMocks),
44             std::move(actions), std::move(clockMockPtr));
45     }
46 };
47 
TEST_F(TestOnChangeThreshold,initializeThresholdExpectAllSensorsAreRegistered)48 TEST_F(TestOnChangeThreshold, initializeThresholdExpectAllSensorsAreRegistered)
49 {
50     for (auto& sensor : sensorMocks)
51     {
52         EXPECT_CALL(*sensor,
53                     registerForUpdates(Truly([sut = sut.get()](const auto& x) {
54             return x.lock().get() == sut;
55         })));
56     }
57 
58     sut->initialize();
59 }
60 
TEST_F(TestOnChangeThreshold,thresholdIsNotInitializeExpectNoActionCommit)61 TEST_F(TestOnChangeThreshold, thresholdIsNotInitializeExpectNoActionCommit)
62 {
63     EXPECT_CALL(actionMock, commit(_, _, _, _, _)).Times(0);
64 }
65 
TEST_F(TestOnChangeThreshold,getLabeledParamsReturnsCorrectly)66 TEST_F(TestOnChangeThreshold, getLabeledParamsReturnsCorrectly)
67 {
68     LabeledThresholdParam expected = std::monostate();
69     EXPECT_EQ(sut->getThresholdParam(), expected);
70 }
71 
TEST_F(TestOnChangeThreshold,firstReadingDoesNoActionCommit)72 TEST_F(TestOnChangeThreshold, firstReadingDoesNoActionCommit)
73 {
74     EXPECT_CALL(actionMock, commit(_, _, _, _, _)).Times(0);
75 
76     sut->initialize();
77     sut->sensorUpdated(*sensorMocks.front(), 0ms, 42);
78 }
79 
80 struct OnChangeParams
81 {
82     using UpdateParams = std::tuple<size_t, double>;
83     using ExpectedParams = std::tuple<size_t, double>;
84 
UpdatesOnChangeParams85     OnChangeParams& Updates(std::vector<UpdateParams> val)
86     {
87         updates = std::move(val);
88         return *this;
89     }
90 
ExpectedOnChangeParams91     OnChangeParams& Expected(std::vector<ExpectedParams> val)
92     {
93         expected = std::move(val);
94         return *this;
95     }
96 
PrintTo(const OnChangeParams & o,std::ostream * os)97     friend void PrintTo(const OnChangeParams& o, std::ostream* os)
98     {
99         *os << "{ Updates: [ ";
100         for (const auto& [index, value] : o.updates)
101         {
102             *os << "{ SensorIndex: " << index << ", Value: " << value << " }, ";
103         }
104         *os << " ] Expected: [ ";
105         for (const auto& [index, value] : o.expected)
106         {
107             *os << "{ SensorIndex: " << index << ", Value: " << value << " }, ";
108         }
109         *os << " ] }";
110     }
111 
112     std::vector<UpdateParams> updates;
113     std::vector<ExpectedParams> expected;
114 };
115 
116 class TestOnChangeThresholdUpdates :
117     public TestOnChangeThreshold,
118     public WithParamInterface<OnChangeParams>
119 {};
120 
121 INSTANTIATE_TEST_SUITE_P(
122     _, TestOnChangeThresholdUpdates,
123     Values(OnChangeParams().Updates({{0, 80.0}}).Expected({{0, 80.0}}),
124            OnChangeParams()
125                .Updates({{0, 80.0}, {1, 81.0}})
126                .Expected({{0, 80.0}, {1, 81.0}}),
127            OnChangeParams()
128                .Updates({{0, 80.0}, {0, 90.0}})
129                .Expected({{0, 80.0}, {0, 90.0}}),
130            OnChangeParams()
131                .Updates({{0, 80.0}, {1, 90.0}, {0, 90.0}})
132                .Expected({{0, 80.0}, {1, 90.0}, {0, 90.0}}),
133            OnChangeParams()
134                .Updates({{0, 80.0}, {1, 80.0}, {1, 90.0}, {0, 90.0}})
135                .Expected({{0, 80.0}, {1, 80.0}, {1, 90.0}, {0, 90.0}})));
136 
TEST_P(TestOnChangeThresholdUpdates,senorsIsUpdatedMultipleTimes)137 TEST_P(TestOnChangeThresholdUpdates, senorsIsUpdatedMultipleTimes)
138 {
139     InSequence seq;
140     for (const auto& [index, value] : GetParam().expected)
141     {
142         EXPECT_CALL(actionMock,
143                     commit(triggerId, Eq(std::nullopt), sensorNames[index], _,
144                            TriggerValue(value)));
145     }
146 
147     sut->initialize();
148 
149     // First reading will be skipped
150     sut->sensorUpdated(*sensorMocks.front(), 0ms, 42);
151 
152     for (const auto& [index, value] : GetParam().updates)
153     {
154         sut->sensorUpdated(*sensorMocks[index], 42ms, value);
155     }
156 }
157