// tests/test_motor.cpp #include "vendor/catch_amalgamated.hpp" #include "Motor.h" // Bring Approx into local scope using Catch::Approx; TEST_CASE("Motor basic behavior", "[motor]") { Motor testMotor("TestMotor", 0.05, 50.0); // 50 grams propellant, 50 Ns impulse SECTION("Motor should not be ignited at start") { REQUIRE(testMotor.isBurnedOut() == false); REQUIRE(testMotor.getCurrentThrust() == Approx(0.0)); } SECTION("Motor thrust curve points can be added") { testMotor.addThrustDataPoint(0.0, 0.0); testMotor.addThrustDataPoint(0.5, 100.0); testMotor.addThrustDataPoint(1.0, 0.0); testMotor.ignite(); testMotor.update(0.25); // halfway to 0.5 seconds // Should interpolate between 0 and 100 N REQUIRE(testMotor.getCurrentThrust() > 0.0); REQUIRE(testMotor.isBurnedOut() == false); } SECTION("Motor ignition starts thrust production") { testMotor.addThrustDataPoint(0.0, 0.0); testMotor.addThrustDataPoint(0.1, 50.0); testMotor.addThrustDataPoint(1.5, 50.0); testMotor.addThrustDataPoint(1.6, 0.0); testMotor.ignite(); testMotor.update(0.1); // 100ms REQUIRE(testMotor.getCurrentThrust() > 0.0); REQUIRE(testMotor.isBurnedOut() == false); } SECTION("Motor burns out after thrust curve ends") { testMotor.addThrustDataPoint(0.0, 0.0); testMotor.addThrustDataPoint(0.5, 50.0); testMotor.addThrustDataPoint(1.0, 0.0); testMotor.ignite(); testMotor.update(2.0); // 2 seconds, way past end REQUIRE(testMotor.isBurnedOut() == true); REQUIRE(testMotor.getCurrentThrust() == Approx(0.0)); } SECTION("Remaining propellant decreases over time") { testMotor.addThrustDataPoint(0.0, 0.0); testMotor.addThrustDataPoint(0.5, 100.0); testMotor.addThrustDataPoint(1.0, 0.0); testMotor.ignite(); double initialMass = testMotor.getRemainingPropellantMass(); testMotor.update(0.5); // Burn for 0.5 seconds double remainingMass = testMotor.getRemainingPropellantMass(); REQUIRE(remainingMass < initialMass); REQUIRE(remainingMass >= 0.0); } }