95 lines
4.2 KiB
GDScript
95 lines
4.2 KiB
GDScript
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")
|
|
|
|
seed(12345)
|
|
var weighted_distractors: Array = question.get("choices", []).slice(1)
|
|
var weighted_counts := {"B": 0, "C": 0, "D": 0, "E": 0, "F": 0, "G": 0, "H": 0, "I": 0}
|
|
for _iteration in range(2000):
|
|
var selected: Array = service._select_weighted_distractors(weighted_distractors, {"B": 100}, 1)
|
|
var selected_id := str(selected[0].get("id", ""))
|
|
weighted_counts[selected_id] = int(weighted_counts.get(selected_id, 0)) + 1
|
|
for low_rate_id in ["C", "D", "E", "F", "G", "H", "I"]:
|
|
_assert(weighted_counts["B"] > weighted_counts[low_rate_id], "higher-rate distractors should be preferred")
|
|
|
|
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)
|