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