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, NegHysteresis_BehavesAsExpected) 156 { 157 158 // This test verifies Negative hysteresis behaves as expected by 159 // crossing the setpoint and noticing readings don't change until past the 160 // hysteresis value 161 162 ZoneMock z; 163 164 std::vector<std::string> inputs = {"fleeting0"}; 165 double setpoint = 10.0; 166 ec::pidinfo initial; 167 initial.negativeHysteresis = 4.0; 168 169 std::unique_ptr<PIDController> p = ThermalController::createThermalPid( 170 &z, "therm1", inputs, setpoint, initial, ThermalType::margin); 171 EXPECT_FALSE(p == nullptr); 172 173 EXPECT_CALL(z, getCachedValue(StrEq("fleeting0"))) 174 .Times(3) 175 .WillOnce(Return(12.0)) 176 .WillOnce(Return(9.0)) 177 .WillOnce(Return(7.0)); 178 179 EXPECT_CALL(z, addSetPoint(_, "therm1")).Times(3); 180 181 std::vector<double> lastReadings = {12.0, 12.0, 7.0}; 182 for (auto& reading : lastReadings) 183 { 184 p->process(); 185 EXPECT_EQ(p->getLastInput(), reading); 186 } 187 } 188 189 TEST(ThermalControllerTest, PosHysteresis_BehavesAsExpected) 190 { 191 // This test verifies Positive hysteresis behaves as expected by 192 // crossing the setpoint and noticing readings don't change until past the 193 // hysteresis value 194 195 ZoneMock z; 196 197 std::vector<std::string> inputs = {"fleeting0"}; 198 double setpoint = 10.0; 199 ec::pidinfo initial; 200 initial.positiveHysteresis = 5.0; 201 202 std::unique_ptr<PIDController> p = ThermalController::createThermalPid( 203 &z, "therm1", inputs, setpoint, initial, ThermalType::margin); 204 EXPECT_FALSE(p == nullptr); 205 206 EXPECT_CALL(z, getCachedValue(StrEq("fleeting0"))) 207 .Times(3) 208 .WillOnce(Return(8.0)) 209 .WillOnce(Return(13.0)) 210 .WillOnce(Return(14.0)); 211 212 EXPECT_CALL(z, addSetPoint(_, "therm1")).Times(3); 213 214 std::vector<double> lastReadings = {8.0, 8.0, 14.0}; 215 for (auto& reading : lastReadings) 216 { 217 p->process(); 218 EXPECT_EQ(p->getLastInput(), reading); 219 } 220 } 221 222 } // namespace 223 } // namespace pid_control 224