extends RefCounted ## Headless tests for the centralized localization string table. const Strings := preload("res://src/core/strings.gd") func test_strings_lookup() -> bool: var a := TestUtils.check_eq(Strings.lookup("hud.aim_first"), "Aim at someone first.", "known key returns value") var b := TestUtils.check_eq(Strings.lookup("missing.key"), "missing.key", "missing key returns key itself") return a and b func test_strings_format() -> bool: var a := TestUtils.check_eq(Strings.fmt("react.comply", ["Tourist"]), "Tourist complies and steps back.", "reaction formats") var b := TestUtils.check_eq(Strings.fmt("hud.venue_switched", ["The Joke Shop"]), "Venue: The Joke Shop", "venue switch formats") return a and b func test_strings_json_backed_all_resolve() -> bool: ## Every key in the JSON-loaded table must resolve to a value other than ## the key itself (fail-safe would otherwise mask broken entries). for key in Strings.TABLE.keys(): var value: String = Strings.lookup(key) if value == key: return TestUtils.fail("key %s resolves to itself — table entry missing" % key) return true func test_placeholder_count() -> bool: var a := TestUtils.check_eq(Strings.placeholder_count("no args"), 0, "plain text has no placeholders") var b := TestUtils.check_eq(Strings.placeholder_count("%s complies"), 1, "one %s") var c := TestUtils.check_eq(Strings.placeholder_count("%s: \"%s\""), 2, "two %s") var d := TestUtils.check_eq(Strings.placeholder_count("100%% sure"), 0, "%% is an escape, not an argument") var e := TestUtils.check_eq(Strings.placeholder_count("%.0f%% mood"), 1, "float plus percent sign") return a and b and c and d and e func test_fmt_fails_safe_on_arg_mismatch() -> bool: ## A drifting placeholder count must not raise an engine error at runtime. var result: String = Strings.fmt("react.comply", []) var a := TestUtils.check_eq(result, Strings.lookup("react.comply"), "wrong arg count returns the raw template") var extra: String = Strings.fmt("react.comply", ["A", "B"]) var b := TestUtils.check_eq(extra, Strings.lookup("react.comply"), "too many args also fails safe") return a and b func test_table_validates_cleanly() -> bool: var problems: Array = Strings.validate() if not problems.is_empty(): return TestUtils.fail("string table format problems: %s" % str(problems)) return true func test_every_placeholder_key_formats() -> bool: ## Feed each template one dummy arg per placeholder, with a type that matches ## the conversion (%s text, %d int, %f float). Nothing may be left unformatted. var problems: Array[String] = [] for key in Strings.TABLE.keys(): var template: String = str(Strings.TABLE[key]) var specs: Array[String] = _specifiers(template) if specs.is_empty(): continue var args := [] for spec in specs: var conv: String = spec.substr(spec.length() - 1) if conv == "d" or conv == "x" or conv == "X": args.append(7) elif conv == "f": args.append(1.5) else: args.append("x") var out: String = Strings.fmt(key, args) if out == template: problems.append("%s did not format (%s)" % [key, str(specs)]) return TestUtils.check(problems.is_empty(), "all placeholder keys format (problems: %s)" % str(problems)) func _specifiers(template: String) -> Array[String]: var out: Array[String] = [] var i := 0 while i < template.length(): if template[i] != "%": i += 1 continue if i + 1 < template.length() and template[i + 1] == "%": i += 2 continue var j := i + 1 while j < template.length() and template[j] in "0123456789.$": j += 1 if j < template.length(): out.append(template.substr(i, j - i + 1)) j += 1 i = j return out func test_strings_cover_ui_keys() -> bool: ## Every key referenced by the HUD and game manager must exist. var required := [ "hud.controls", "hud.escalation_prefix", "hud.cooldown", "hud.venue_switched", "hud.aim_first", "hud.no_one_nearby", "hud.targeting", "hud.no_wand", "hud.screen_first", "access.granted", "access.denied", "access.policy_satisfied", "access.wrong_grant", "access.wrong_deny", "wand.admitted_prohibited", "wand.denied_false_alarm", "wand.cleared", "wand.refused", "wand.recharge", "radio.address_first", "radio.blocked", "radio.inaccurate", "radio.received", "radio.emergency_dispatched", "responder.arrived", "react.comply", "react.leave", "react.argue", "react.record", "react.ignore", "react.threaten", "react.force_entry", "react.return_later", "react.none", "perception.near", "perception.aware", ] for key in required: if not Strings.TABLE.has(key): return TestUtils.fail("missing string key: %s" % key) return true