From 96b3293023a4e3f2b5d9f4e11b3f49a9a31f889d Mon Sep 17 00:00:00 2001 From: Jonny Date: Sun, 7 Sep 2025 22:50:38 +0100 Subject: [PATCH] Add tests to make sure batteries aren't renewing liveness on bogus CAN frames --- test/CMakeLists.txt | 1 + test/battery/still_alive_tests.cpp | 81 ++++++++++++++++++++++++++++++ test/tests.cpp | 2 + 3 files changed, 84 insertions(+) create mode 100644 test/battery/still_alive_tests.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 307339a1..91bcbd9d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -70,6 +70,7 @@ add_executable(tests tests.cpp safety_tests.cpp battery/NissanLeafTest.cpp + battery/still_alive_tests.cpp can_log_based/canlog_safety_tests.cpp utils/utils.cpp ../Software/src/communication/can/obd.cpp diff --git a/test/battery/still_alive_tests.cpp b/test/battery/still_alive_tests.cpp new file mode 100644 index 00000000..beed0dd2 --- /dev/null +++ b/test/battery/still_alive_tests.cpp @@ -0,0 +1,81 @@ +#include + +#include "../utils/utils.h" + +#include "../../Software/src/battery/BATTERIES.h" +#include "../../Software/src/devboard/utils/events.h" + +class BatteryTestFixture : public testing::Test { + public: + BatteryTestFixture(BatteryType type) : type(type) {} + // Optional: + // static void SetUpTestSuite() { ... } + // static void TearDownTestSuite() { ... } + + void SetUp() override { + // Reset the datalayer and events before each test + datalayer = DataLayer(); + reset_all_events(); + if (battery) { + delete battery; + battery = nullptr; + } + init_hal(); + + user_selected_battery_type = type; + setup_battery(); + } + + void TearDown() override { + if (battery) { + delete battery; + battery = nullptr; + } + } + + private: + BatteryType type; +}; + +// Check that the parsed logs correctly trigger an overvoltage event. +class StillAliveTimeoutTest : public BatteryTestFixture { + public: + explicit StillAliveTimeoutTest(BatteryType type) : BatteryTestFixture(type) {} + void TestBody() override { + // check if battery is a CanBattery subclass + auto* battery = dynamic_cast(::battery); + if (battery == nullptr) { + GTEST_SKIP() << "Battery is not a CanBattery subclass"; + } + + // Set the still-alive counter to 0 (ie, not alive) + datalayer.battery.status.CAN_battery_still_alive = 0; + + // A random fake CAN frame + CAN_frame frame = { + .ID = 0x7ff, + .data = {.u8 = {0x00, 0x64, 0x00, 0x64, 0x0F, 0xA0, 0x27, 0x10}}, + }; + for (int i = 0; i < 50; i++) { + battery->handle_incoming_can_frame(frame); + } + + // Check it's still not alive (ie, the CAN frame handling didn't renew the counter) + EXPECT_EQ(datalayer.battery.status.CAN_battery_still_alive, 0); + } +}; + +void RegisterStillAliveTests() { + for (int i = 2; i < 42; i++) { + if ((BatteryType)i == BatteryType::TestFake) { + continue; + } + if ((BatteryType)i == BatteryType::DalyBms) { + continue; + } + + std::string test_name = ("TestStillAliveTimeout" + snake_case_to_camel_case(name_for_battery_type((BatteryType)i))); + testing::RegisterTest("StillAliveTests", test_name.c_str(), nullptr, nullptr, __FILE__, __LINE__, + [=]() -> BatteryTestFixture* { return new StillAliveTimeoutTest((BatteryType)i); }); + } +} diff --git a/test/tests.cpp b/test/tests.cpp index 4eeff7bf..82863941 100644 --- a/test/tests.cpp +++ b/test/tests.cpp @@ -6,10 +6,12 @@ #include "../Software/src/devboard/utils/events.h" void RegisterCanLogTests(void); +void RegisterStillAliveTests(void); int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); RegisterCanLogTests(); + RegisterStillAliveTests(); return RUN_ALL_TESTS(); }