#include #include #include #include "core/GravityManager.h" TEST_CASE("GravityManager basic ms calculation", "[gravity]") { GravityManager g; g.setGlobalMultiplier(1.0); double ms0 = g.getMsForLevel(0); REQUIRE(ms0 > 0); double ms29 = g.getMsForLevel(29); REQUIRE(ms29 >= 1.0); } // Additional tests TEST_CASE("frames_to_ms_exact", "[gravity][exact]") { // Reuse the reference constants (must match GravityManager implementation) constexpr double NES_FPS = 60.0988; constexpr double FRAME_MS = 1000.0 / NES_FPS; constexpr int FRAMES_TABLE[30] = { 48, 43, 38, 33, 28, 23, 18, 13, 8, 6, 5, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 }; GravityManager g; g.setGlobalMultiplier(1.0); for (int lvl = 0; lvl <= 29; ++lvl) { double expected = static_cast(FRAMES_TABLE[lvl]) * FRAME_MS * 1.0; double actual = g.getMsForLevel(lvl); // GravityManager clamps to minimum 1.0ms; expected for these levels is >> 1.0 except possibly level 29 if (expected < 1.0) expected = 1.0; if (!(actual == Catch::Approx(expected).epsilon(1e-6))) { std::cerr << "DEBUG: lvl=" << lvl << ", levelMultiplier=" << g.getLevelMultiplier(lvl) << ", FRAMES_TABLE[lvl]=" << FRAMES_TABLE[lvl] << ", actual=" << actual << ", expected=" << expected << std::endl; } REQUIRE(actual == Catch::Approx(expected).epsilon(1e-6)); REQUIRE(g.getFpsForLevel(lvl) == Catch::Approx(1000.0 / actual).epsilon(1e-6)); } } TEST_CASE("multiplier_effects", "[gravity][multiplier]") { GravityManager g; g.setGlobalMultiplier(1.0); double base = g.getMsForLevel(5); // level 5 baseline g.setLevelMultiplier(5, 2.0); double doubled = g.getMsForLevel(5); REQUIRE(doubled == Catch::Approx(base * 2.0).epsilon(1e-6)); // global multiplier scales all levels g.setGlobalMultiplier(0.5); double afterGlobal = g.getMsForLevel(5); REQUIRE(afterGlobal == Catch::Approx(doubled * 0.5).epsilon(1e-6)); } TEST_CASE("clamping_and_edges", "[gravity][clamp]") { GravityManager g; // global multiplier clamped to [0.01,100.0] g.setGlobalMultiplier(0.0001); REQUIRE(g.getGlobalMultiplier() == Catch::Approx(0.01).epsilon(1e-12)); g.setGlobalMultiplier(500.0); REQUIRE(g.getGlobalMultiplier() == Catch::Approx(100.0).epsilon(1e-12)); // per-level multiplier clamps g.setLevelMultiplier(100, 200.0); REQUIRE(g.getLevelMultiplier(100) == Catch::Approx(100.0).epsilon(1e-12)); // negative level queries map to level 0 REQUIRE(g.getLevelMultiplier(-5) == Catch::Approx(g.getLevelMultiplier(0)).epsilon(1e-12)); } TEST_CASE("min_ms_enforced", "[gravity][min]") { GravityManager g; // Force very small multipliers then ensure minimum 1.0ms enforced g.setLevelMultiplier(29, 0.01); g.setGlobalMultiplier(0.01); double ms29 = g.getMsForLevel(29); REQUIRE(ms29 >= 1.0); REQUIRE(ms29 == Catch::Approx(1.0).epsilon(1e-12)); }