diff --git a/client/tests/unit/test_round_trip.gd b/client/tests/unit/test_round_trip.gd new file mode 100644 index 0000000..3fb1e3c --- /dev/null +++ b/client/tests/unit/test_round_trip.gd @@ -0,0 +1,39 @@ +extends "res://addons/gut/test.gd" + +const NewGame = preload("res://scripts/newgame/new_game.gd") +const ContentDB = preload("res://scripts/content/content_db.gd") +const CanonLog = preload("res://scripts/canon_log/canon_log.gd") + + +func _built_log(): + var world = ContentDB.new() + world.load_from(ContentDB.default_content_root()) + var rng := RandomNumberGenerator.new() + rng.seed = 3 + var origin: Dictionary = ContentDB.load_json(ContentDB.origin_path("deserter")) + var res := NewGame.construct(origin, world, {"name": "Aldric", "class_id": "priest"}, rng) + assert_true(res["ok"], str(res["errors"])) + return res["log"] + + +func test_to_from_dict_is_identity(): + var log = _built_log() + var d1: Dictionary = log.to_dict() + var log2 = CanonLog.from_dict(d1) + assert_not_null(log2) + assert_eq(log2.to_dict(), d1) + + +func test_constructed_log_satisfies_contract_invariants(): + var d: Dictionary = _built_log().to_dict() + assert_eq(d["schema_version"], 1) + assert_true(d["recent_events"].size() <= 5) + assert_eq(d["player"].keys().size(), 3) # exactly name/class_id/luck_descriptor + assert_false("luck" in d["player"]) # ยง7: no numeric luck + assert_true(d["player"]["class_id"] in ["sellsword", "assassin", "priest"]) + for m in d["party"]: + assert_true(m["disposition"] >= -100 and m["disposition"] <= 100) + for q in d["active_quests"]: + assert_true(q["status"] in ["active", "complete", "failed"]) + for h in d["humiliations"]: + assert_true(h["weight"] >= 1 and h["weight"] <= 10)