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