# system_test.ludic - the runner: init, reset, save and load in the order added, tick phase by # phase, each system its own save section, and a missing section is a reset import "ludic.base" program SystemTest { numbers float state SystemTestState { trail: string = "" apples: int = 0 hours: float = 0.0 } function draw_tick(system_test_st: mut SystemTestState, t: Tick) -> void { system_test_st.trail = system_test_st.trail + "d" } function think_tick(system_test_st: mut SystemTestState, t: Tick) -> void { system_test_st.trail = system_test_st.trail + "t" } function input_tick(system_test_st: mut SystemTestState, t: Tick) -> void { system_test_st.trail = system_test_st.trail + "i" } function commit_tick(system_test_st: mut SystemTestState, t: Tick) -> void { system_test_st.trail = system_test_st.trail + "c" } function apples_init(system_test_st: mut SystemTestState) -> void { system_test_st.trail = system_test_st.trail + "A" } function apples_reset(system_test_st: mut SystemTestState) -> void { system_test_st.apples = 0 } function apples_tick(system_test_st: mut SystemTestState, t: Tick) -> void { system_test_st.apples += 1 } function apples_save(system_test_st: SystemTestState) -> Val { let v = Value.object() sv_put_int(v, "n", system_test_st.apples) return v } function apples_load(system_test_st: mut SystemTestState, v: Val, version: int) -> void { system_test_st.apples = sv_int(v, "n", 0) * version } function clock_reset(system_test_st: mut SystemTestState) -> void { system_test_st.hours = 6.0 } function clock_tick(system_test_st: mut SystemTestState, t: Tick) -> void { system_test_st.hours = system_test_st.hours + t.hours } function clock_save(system_test_st: SystemTestState) -> Val { let v = Value.object() sv_put_float(v, "h", system_test_st.hours) return v } function clock_load(system_test_st: mut SystemTestState, v: Val, version: int) -> void { system_test_st.hours = sv_float(v, "h", 6.0) } function sys(key: string, phase: int, tick: fn(Tick) -> void) -> System { let s = system_new(key, phase) s.tick = tick return s } function setup(base_st: mut BaseState, system_test_st: mut SystemTestState) -> void { core_clear(base_st) system_test_st.trail = "" core_add(base_st, sys("draw", PH_PRESENT, fn draw_tick)) core_add(base_st, sys("think", PH_SIMULATE, fn think_tick)) let a = sys("apples", PH_SIMULATE, fn apples_tick) a.init = fn apples_init a.reset = fn apples_reset a.save = fn apples_save a.load = fn apples_load a.version = 2 core_add(base_st, a) core_add(base_st, sys("input", PH_INPUT, fn input_tick)) core_add(base_st, sys("commit", PH_COMMIT, fn commit_tick)) let c = sys("clock", PH_SIMULATE, fn clock_tick) c.reset = fn clock_reset c.save = fn clock_save c.load = fn clock_load core_add(base_st, c) } test "tick runs phase by phase, in the order added within a phase" (base_st: mut BaseState, system_test_st: mut SystemTestState) { setup(base_st, system_test_st) core_tick_all(base_st, tick_new(1.0 / 60.0, 0, 0.0)) expect(system_test_st.trail == "itcd") expect_eq(system_test_st.apples, 1) } test "init and reset run in the order added and skip a null verb" (base_st: mut BaseState, system_test_st: mut SystemTestState) { setup(base_st, system_test_st) core_init_all(base_st) expect(system_test_st.trail == "A") system_test_st.apples = 9 core_reset_all(base_st) expect_eq(system_test_st.apples, 0) expect(system_test_st.hours == 6.0) expect_eq(core_count(base_st), 6) } test "save writes each system under its key with its version, and load reads it back" (base_st: mut BaseState, system_test_st: mut SystemTestState) { setup(base_st, system_test_st) core_reset_all(base_st) system_test_st.apples = 4 core_tick_all(base_st, tick_new(0.016, 1, 0.5)) let root = core_save_all(base_st) expect_eq(Value.count(root), 2) expect_eq(load_section(root, "apples").version, 2) expect_eq(load_section(root, "clock").version, 1) let text = save_encode(root) core_reset_all(base_st) core_load_all(base_st, save_decode(text)) expect_eq(system_test_st.apples, 10) expect(system_test_st.hours == 6.5) } test "a system with no section in the save is reset" (base_st: mut BaseState, system_test_st: mut SystemTestState) { setup(base_st, system_test_st) system_test_st.apples = 3 system_test_st.hours = 11.0 let root = save_tree() let v = Value.object() sv_put_float(v, "h", 20.25) save_section(root, "clock", 1, v) core_load_all(base_st, root) expect_eq(system_test_st.apples, 0) expect(system_test_st.hours == 20.25) } }