extends SceneTree var failures := 0 func _initialize() -> void: var service = load("res://scripts/autoload/block_session_service.gd").new() var question := _question(9) var prepared: Dictionary = service._prepare_question_choices(question.duplicate(true)) _check_presented(prepared) var stable: Dictionary = service._prepare_question_choices(prepared.duplicate(true)) _assert(stable.get("presented_choices", []) == prepared.get("presented_choices", []), "session choices must remain stable") var observed_sets := {} for iteration in range(40): var rerolled: Dictionary = service._prepare_question_choices(question.duplicate(true)) _check_presented(rerolled) var ids := _ids(rerolled.get("presented_choices", [])) ids.sort() observed_sets[",".join(ids)] = true _assert(observed_sets.size() > 1, "future sessions should be able to present different distractors") var legacy: Dictionary = service._prepare_question_choices(_question(5)) _check_presented(legacy) _assert(_ids(legacy.get("presented_choices", [])).size() == 5, "legacy five-choice questions must show all choices") service.session_kind = "block" service.session_initial_seconds = 900.0 service.seconds_remaining = 450.0 _assert(is_equal_approx(service.get_session_timer_ratio(), 0.5), "timed block progress should use the full session duration") service.session_kind = "core" service.core_question_total_elapsed_seconds = 25.0 service.core_question_total_active_since = 0.0 _assert(is_equal_approx(service.get_core_question_total_elapsed_seconds(), 25.0), "core question timer should expose cumulative elapsed time") service._start_core_retry_window() _assert(is_equal_approx(service.get_core_question_total_elapsed_seconds(), 25.0), "wrong-answer retry windows should not reset cumulative question time") service.core_question_total_active_since = 100.0 service.core_question_total_elapsed_seconds = 4.0 service._pause_core_question_total_timer(106.0) _assert(is_equal_approx(service.get_core_question_total_elapsed_seconds(), 10.0), "pausing should preserve accumulated question time") service.core_question_total_elapsed_seconds = 0.0 service.core_question_total_active_since = 0.001 service._freeze_core_question_total_timer() var frozen_elapsed: float = service.get_core_question_total_elapsed_seconds() OS.delay_msec(10) _assert(is_equal_approx(service.get_core_question_total_elapsed_seconds(), frozen_elapsed), "freezing should stop cumulative question time") var resume_now := Time.get_ticks_msec() / 1000.0 service.current_question_started_at = maxf(0.001, resume_now - 5.0) service.current_question_pause_started_at = maxf(0.001, resume_now - 0.001) service.resume_current_question_timer() _assert(service.core_question_total_active_since == 0.0, "a completed core question timer should not restart") service.free() quit(1 if failures > 0 else 0) func _question(count: int) -> Dictionary: var choices: Array = [] for index in range(count): choices.append({"id": String.chr(65 + index), "text": "Choice %d" % index}) return {"choices": choices, "correct_choice_id": "A"} func _check_presented(question: Dictionary) -> void: var ids := _ids(question.get("presented_choices", [])) _assert(ids.size() == 5, "exactly five choices must be presented") _assert(ids.has("A"), "the correct answer must be presented") var unique := {} for id in ids: unique[id] = true _assert(unique.size() == ids.size(), "presented choices must be unique") func _ids(choices: Array) -> Array: var ids: Array = [] for choice in choices: ids.append(str(choice.get("id", ""))) return ids func _assert(condition: bool, message: String) -> void: if condition: return failures += 1 push_error(message)