#include #include "fgc/mock/MockCameraSource.h" #include "fgc/ui/UiSnapshot.h" using namespace fgc; TEST_CASE("axisStateLabel maps every state") { CHECK(std::string(axisStateLabel(AxisState::Boot)) == "BOOT"); CHECK(std::string(axisStateLabel(AxisState::Reset)) == "RESET"); CHECK(std::string(axisStateLabel(AxisState::Homing)) == "HOMING"); CHECK(std::string(axisStateLabel(AxisState::Ready)) == "READY"); CHECK(std::string(axisStateLabel(AxisState::Error)) == "ERROR"); CHECK(std::string(axisStateLabel(AxisState::Unknown)) == "----"); } TEST_CASE("axisStateColor signals health") { CHECK(axisStateColor(AxisState::Ready) == UiColor::Green); CHECK(axisStateColor(AxisState::Homing) == UiColor::Yellow); CHECK(axisStateColor(AxisState::Error) == UiColor::Red); CHECK(axisStateColor(AxisState::Boot) == UiColor::Dim); CHECK(axisStateColor(AxisState::Reset) == UiColor::Dim); CHECK(axisStateColor(AxisState::Unknown) == UiColor::Default); } TEST_CASE("formatDegrees: one decimal, sign preserved, degree sign appended") { CHECK(formatDegrees(12.34) == "12.3\xC2\xB0"); CHECK(formatDegrees(-4.0) == "-4.0\xC2\xB0"); CHECK(formatDegrees(0.0) == "0.0\xC2\xB0"); } TEST_CASE("formatTimeAgo: buckets and the never case") { CHECK(formatTimeAgo(10'000, 0) == "\xE2\x80\x94"); // never CHECK(formatTimeAgo(10'000, 7'000) == "3s ago"); // seconds CHECK(formatTimeAgo(200'000, 10'000) == "3m ago"); // minutes CHECK(formatTimeAgo(10'000'000, 1'000'000) == "2h ago"); // hours CHECK(formatTimeAgo(5'000, 9'000) == "0s ago"); // future clamps to 0 } TEST_CASE("MockCameraSource::deviceInfo reports identity, dims, streaming, frame count") { MockCameraSource cam(1, 320, 240); cam.start(); auto info = cam.deviceInfo(); REQUIRE(info.size() == 1); CHECK(info[0].model == "MockCamera"); CHECK(info[0].streaming == true); CHECK(info[0].width == 320); CHECK(info[0].height == 240); CHECK(info[0].frames_delivered == 0); int got = 0; cam.setFrameCallback([&](const Frame&) { ++got; }); cam.trigger(); CHECK(got == 1); CHECK(cam.deviceInfo()[0].frames_delivered == 1); cam.stop(); CHECK(cam.deviceInfo()[0].streaming == false); } TEST_CASE("pendingSensorsView: grouped by sensor, all absent until drivers land") { SensorsView v = pendingSensorsView(); CHECK_FALSE(v.imu.present); CHECK_FALSE(v.env.present); CHECK_FALSE(v.imu.title.empty()); CHECK_FALSE(v.env.title.empty()); CHECK(v.imu.fields.size() >= 3); // roll/pitch/yaw (+ device temp) CHECK(v.env.fields.size() >= 2); // ambient temp + humidity for (const auto* g : {&v.imu, &v.env}) { for (const auto& f : g->fields) { CHECK_FALSE(f.present); CHECK_FALSE(f.label.empty()); } } }