/** * Copyright (c) 2026 Dominic Masters * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #include "dusktest.h" #include // Mocks static uint64_t SDL_GETTICKS_TICKS = 0; static bool_t SDL_GETTICKS_CALLED = false; uint64_t SDL_GetTicks64(void) { SDL_GETTICKS_CALLED = true; return SDL_GETTICKS_TICKS; } // Mocked includes #include "util/memory.h" #include "time/time.h" // Tests static void test_timeInit(void **state) { (void)state; // Fill time with garbage memorySet(&TIME, 0xFF, sizeof(TIME)); // Init timeInit(); // Inital struct is set. assert_float_equal(TIME.time, TIME_STEP, 0.0001f); assert_float_equal(TIME.delta, TIME_STEP, 0.0001f); assert_float_equal(TIME.dynamicTime, TIME_STEP, 0.0001f); assert_float_equal(TIME.dynamicDelta, TIME_STEP, 0.0001f); assert_false(TIME.dynamicUpdate); } static void test_timeUpdate(void **state) { (void)state; // Init first timeInit(); // First time update, calls SDL_GetTicks SDL_GETTICKS_TICKS = 14; // Simulate 15ms elapsed (just barely not one step) SDL_GETTICKS_CALLED = false; timeUpdate(); assert_true(SDL_GETTICKS_CALLED); assert_true(TIME.dynamicUpdate); assert_float_equal(TIME.dynamicDelta, 0.014f, 0.0001f); assert_float_equal(TIME.dynamicTime, TIME_STEP + TIME.dynamicDelta, 0.0001f); assert_float_equal(TIME.delta, TIME_STEP, 0.0001f); // Not changed assert_float_equal(TIME.time, TIME_STEP, 0.0001f); // Not changed // Simulate total 16ms elapsed (2ms more) SDL_GETTICKS_TICKS = 16; SDL_GETTICKS_CALLED = false; timeUpdate(); assert_true(SDL_GETTICKS_CALLED); assert_false(TIME.dynamicUpdate); assert_float_equal(TIME.dynamicDelta, 0.002f, 0.0001f); assert_float_equal(TIME.dynamicTime, TIME_STEP * 2, 0.0001f); assert_float_equal(TIME.delta, TIME_STEP, 0.0001f); assert_float_equal(TIME.time, TIME_STEP * 2, 0.0001f); // Stepped once // Second test, half step (16 + 8) SDL_GETTICKS_TICKS = 24; SDL_GETTICKS_CALLED = false; timeUpdate(); assert_true(SDL_GETTICKS_CALLED); assert_true(TIME.dynamicUpdate); assert_float_equal(TIME.dynamicDelta, 0.008f, 0.0001f); assert_float_equal(TIME.dynamicTime, TIME_STEP + 0.024f, 0.0001f); assert_float_equal(TIME.delta, TIME_STEP, 0.0001f); assert_float_equal(TIME.time, TIME_STEP * 2, 0.0001f);// Unchanged. // Third test, another half step, leading to non dynamic update SDL_GETTICKS_TICKS = 32; SDL_GETTICKS_CALLED = false; timeUpdate(); assert_true(SDL_GETTICKS_CALLED); assert_false(TIME.dynamicUpdate); assert_float_equal(TIME.dynamicDelta, 0.008f, 0.0001f); assert_float_equal(TIME.dynamicTime, TIME_STEP + 0.032f, 0.0001f); assert_float_equal(TIME.delta, TIME_STEP, 0.0001f); assert_float_equal(TIME.time, TIME_STEP * 3, 0.0001f); // Fourth test, large jump, should only step once SDL_GETTICKS_TICKS = 100; // Simulate 100ms elapsed SDL_GETTICKS_CALLED = false; timeUpdate(); assert_true(SDL_GETTICKS_CALLED); assert_false(TIME.dynamicUpdate); assert_float_equal(TIME.dynamicDelta, 0.068f, 0.0001f); assert_float_equal(TIME.dynamicTime, TIME_STEP + 0.100f, 0.0001f); assert_float_equal(TIME.delta, TIME_STEP, 0.0001f); assert_float_equal(TIME.time, TIME_STEP * 4, 0.0001f); // Fifth test, despite a small time passing the game should be trying to catch // and running extra ticks SDL_GETTICKS_TICKS = 104; // Simulate 4ms elapsed SDL_GETTICKS_CALLED = false; timeUpdate(); assert_true(SDL_GETTICKS_CALLED); assert_false(TIME.dynamicUpdate); assert_float_equal(TIME.dynamicDelta, 0.004f, 0.0001f); assert_float_equal(TIME.dynamicTime, TIME_STEP + 0.104f, 0.0001f); assert_float_equal(TIME.delta, TIME_STEP, 0.0001f); assert_float_equal(TIME.time, TIME_STEP * 5, 0.0001f); } int main(int argc, char **argv) { const struct CMUnitTest tests[] = { cmocka_unit_test(test_timeInit), cmocka_unit_test(test_timeUpdate), }; return cmocka_run_group_tests(tests, NULL, NULL); }