1 #include "pid/ec/pid.hpp"
2 #include "pid/thermalcontroller.hpp"
3 #include "test/zone_mock.hpp"
4 
5 #include <string>
6 #include <vector>
7 
8 #include <gmock/gmock.h>
9 #include <gtest/gtest.h>
10 
11 using ::testing::_;
12 using ::testing::Return;
13 using ::testing::StrEq;
14 
15 TEST(ThermalControllerTest, BoringFactoryTest)
16 {
17     // Verifies building a ThermalPIDController with the factory works as
18     // expected in the boring (uninteresting) case.
19 
20     ZoneMock z;
21 
22     std::vector<std::string> inputs = {"fleeting0"};
23     double setpoint = 10.0;
24     ec::pidinfo initial;
25 
26     std::unique_ptr<PIDController> p = ThermalController::createThermalPid(
27         &z, "therm1", inputs, setpoint, initial, ThermalType::margin);
28     // Success
29     EXPECT_FALSE(p == nullptr);
30 }
31 
32 TEST(ThermalControllerTest, VerifyFactoryFailsWithZeroInputs)
33 {
34     // A thermal controller needs at least one input.
35 
36     ZoneMock z;
37 
38     std::vector<std::string> inputs = {};
39     double setpoint = 10.0;
40     ec::pidinfo initial;
41     std::unique_ptr<PIDController> p;
42     EXPECT_THROW(
43         {
44             p = ThermalController::createThermalPid(
45                 &z, "therm1", inputs, setpoint, initial, ThermalType::margin);
46         },
47         std::exception);
48     EXPECT_TRUE(p == nullptr);
49 }
50 
51 TEST(ThermalControllerTest, InputProc_BehavesAsExpected)
52 {
53     // This test just verifies inputProc behaves as expected.
54 
55     ZoneMock z;
56 
57     std::vector<std::string> inputs = {"fleeting0"};
58     double setpoint = 10.0;
59     ec::pidinfo initial;
60 
61     std::unique_ptr<PIDController> p = ThermalController::createThermalPid(
62         &z, "therm1", inputs, setpoint, initial, ThermalType::margin);
63     EXPECT_FALSE(p == nullptr);
64 
65     EXPECT_CALL(z, getCachedValue(StrEq("fleeting0"))).WillOnce(Return(5.0));
66 
67     EXPECT_EQ(5.0, p->inputProc());
68 }
69 
70 TEST(ThermalControllerTest, SetPtProc_BehavesAsExpected)
71 {
72     // This test just verifies inputProc behaves as expected.
73 
74     ZoneMock z;
75 
76     std::vector<std::string> inputs = {"fleeting0"};
77     double setpoint = 10.0;
78     ec::pidinfo initial;
79 
80     std::unique_ptr<PIDController> p = ThermalController::createThermalPid(
81         &z, "therm1", inputs, setpoint, initial, ThermalType::margin);
82     EXPECT_FALSE(p == nullptr);
83 
84     EXPECT_EQ(setpoint, p->setptProc());
85 }
86 
87 TEST(ThermalControllerTest, OutputProc_BehavesAsExpected)
88 {
89     // This test just verifies outputProc behaves as expected.
90 
91     ZoneMock z;
92 
93     std::vector<std::string> inputs = {"fleeting0"};
94     double setpoint = 10.0;
95     ec::pidinfo initial;
96 
97     std::unique_ptr<PIDController> p = ThermalController::createThermalPid(
98         &z, "therm1", inputs, setpoint, initial, ThermalType::margin);
99     EXPECT_FALSE(p == nullptr);
100 
101     double value = 90.0;
102     EXPECT_CALL(z, addRPMSetPoint(value));
103 
104     p->outputProc(value);
105 }
106 
107 TEST(ThermalControllerTest, InputProc_MultipleInputsAbsolute)
108 {
109     // This test verifies inputProc behaves as expected with multiple absolute
110     // inputs.
111 
112     ZoneMock z;
113 
114     std::vector<std::string> inputs = {"fleeting0", "fleeting1"};
115     double setpoint = 10.0;
116     ec::pidinfo initial;
117 
118     std::unique_ptr<PIDController> p = ThermalController::createThermalPid(
119         &z, "therm1", inputs, setpoint, initial, ThermalType::absolute);
120     EXPECT_FALSE(p == nullptr);
121 
122     EXPECT_CALL(z, getCachedValue(StrEq("fleeting0"))).WillOnce(Return(5.0));
123     EXPECT_CALL(z, getCachedValue(StrEq("fleeting1"))).WillOnce(Return(10.0));
124 
125     EXPECT_EQ(10.0, p->inputProc());
126 }
127 
128 TEST(ThermalControllerTest, InputProc_MultipleInputsMargin)
129 {
130     // This test verifies inputProc behaves as expected with multiple margin
131     // inputs.
132 
133     ZoneMock z;
134 
135     std::vector<std::string> inputs = {"fleeting0", "fleeting1"};
136     double setpoint = 10.0;
137     ec::pidinfo initial;
138 
139     std::unique_ptr<PIDController> p = ThermalController::createThermalPid(
140         &z, "therm1", inputs, setpoint, initial, ThermalType::margin);
141     EXPECT_FALSE(p == nullptr);
142 
143     EXPECT_CALL(z, getCachedValue(StrEq("fleeting0"))).WillOnce(Return(5.0));
144     EXPECT_CALL(z, getCachedValue(StrEq("fleeting1"))).WillOnce(Return(10.0));
145 
146     EXPECT_EQ(5.0, p->inputProc());
147 }
148 
149 TEST(ThermalControllerTest, NegHysteresis_BehavesAsExpected)
150 {
151 
152     // This test verifies Negative hysteresis behaves as expected by
153     // crossing the setpoint and noticing readings don't change until past the
154     // hysteresis value
155 
156     ZoneMock z;
157 
158     std::vector<std::string> inputs = {"fleeting0"};
159     double setpoint = 10.0;
160     ec::pidinfo initial;
161     initial.negativeHysteresis = 4.0;
162 
163     std::unique_ptr<PIDController> p = ThermalController::createThermalPid(
164         &z, "therm1", inputs, setpoint, initial, ThermalType::margin);
165     EXPECT_FALSE(p == nullptr);
166 
167     EXPECT_CALL(z, getCachedValue(StrEq("fleeting0")))
168         .Times(3)
169         .WillOnce(Return(12.0))
170         .WillOnce(Return(9.0))
171         .WillOnce(Return(7.0));
172 
173     EXPECT_CALL(z, addRPMSetPoint(_)).Times(3);
174 
175     std::vector<double> lastReadings = {12.0, 12.0, 7.0};
176     for (auto& reading : lastReadings)
177     {
178         p->process();
179         EXPECT_EQ(p->getLastInput(), reading);
180     }
181 }
182 
183 TEST(ThermalControllerTest, PosHysteresis_BehavesAsExpected)
184 {
185     // This test verifies Positive hysteresis behaves as expected by
186     // crossing the setpoint and noticing readings don't change until past the
187     // hysteresis value
188 
189     ZoneMock z;
190 
191     std::vector<std::string> inputs = {"fleeting0"};
192     double setpoint = 10.0;
193     ec::pidinfo initial;
194     initial.positiveHysteresis = 5.0;
195 
196     std::unique_ptr<PIDController> p = ThermalController::createThermalPid(
197         &z, "therm1", inputs, setpoint, initial, ThermalType::margin);
198     EXPECT_FALSE(p == nullptr);
199 
200     EXPECT_CALL(z, getCachedValue(StrEq("fleeting0")))
201         .Times(3)
202         .WillOnce(Return(8.0))
203         .WillOnce(Return(13.0))
204         .WillOnce(Return(14.0));
205 
206     EXPECT_CALL(z, addRPMSetPoint(_)).Times(3);
207 
208     std::vector<double> lastReadings = {8.0, 8.0, 14.0};
209     for (auto& reading : lastReadings)
210     {
211         p->process();
212         EXPECT_EQ(p->getLastInput(), reading);
213     }
214 }