# test_hair_dye_parity.gd —— 40250 发型染色与漂白系统 1:1 回归测试套件 extends SceneTree const HairDyeSystem = preload("res://hair_dye_system.gd") var _passed := 0 var _failed := 0 func _assert(cond: bool, msg: String) -> void: if cond: _passed += 1 print(" [PASS] %s" % msg) else: _failed += 1 printerr(" [FAIL] %s" % msg) func _init() -> void: print("\n=== Running test_hair_dye_parity (Direction 3: Hair Dye System 1:1) ===") _test_hair_dyeing_and_color_mapping() _test_level_cooldown_restriction() _test_bleach_clears_cooldown_and_resets() _test_costume_hair_rejection() _test_serialization() _finish() func _test_hair_dyeing_and_color_mapping() -> void: print("\n--- Test 1: Hair Dyeing & Color Mapping (40250 1:1) ---") var sys := HairDyeSystem.new() _assert(sys.current_hair_color == 0, "Default hair color is 0 (Default)") var inv: Array = [ {"vnum": HairDyeSystem.VNUM_BLONDE_DYE, "name": "染发剂(金)", "count": 1} ] var dye_sig := {"fired": false, "cid": 0, "cname": ""} sys.hair_dyed.connect(func(cid: int, cn: String): dye_sig["fired"] = true dye_sig["cid"] = cid dye_sig["cname"] = cn ) # Dye Blonde at Lv 30 var res_dye = sys.dye_hair(inv, 0, 30) _assert(res_dye["ok"] == true, "Dyeing succeeded") _assert(sys.current_hair_color == 2, "Color is 2 (Blonde)") _assert(sys.last_dye_level == 30, "Last dye level recorded as 30") _assert(inv[0] == null, "Dye consumed from slot 0") _assert(dye_sig["fired"] == true, "hair_dyed signal emitted") _assert(dye_sig["cid"] == 2, "Reported color ID 2") func _test_level_cooldown_restriction() -> void: print("\n--- Test 2: Level Interval Cooldown Rule (last_dye_level + 3 <= Level) ---") var sys := HairDyeSystem.new() sys.current_hair_color = 2 sys.last_dye_level = 30 # Dyed at Lv 30 var inv: Array = [ {"vnum": HairDyeSystem.VNUM_RED_DYE, "name": "染发剂(红)", "count": 2} ] # 1. Attempt at Lv 31 (< 33) -> rejected var res_31 = sys.dye_hair(inv, 0, 31) _assert(res_31["ok"] == false, "Rejected at Lv 31 (< 33)") _assert(res_31["reason"] == "LEVEL_COOLDOWN_ACTIVE", "Reason is LEVEL_COOLDOWN_ACTIVE") _assert(res_31["req_level"] == 33, "Required level is 33") # 2. Attempt at Lv 32 (< 33) -> rejected var res_32 = sys.dye_hair(inv, 0, 32) _assert(res_32["ok"] == false, "Rejected at Lv 32 (< 33)") # 3. Attempt at Lv 33 (>= 33) -> success! var res_33 = sys.dye_hair(inv, 0, 33) _assert(res_33["ok"] == true, "Succeeded at Lv 33 (30 + 3)") _assert(sys.current_hair_color == 3, "Color is now 3 (Red)") _assert(sys.last_dye_level == 33, "New last_dye_level is 33") func _test_bleach_clears_cooldown_and_resets() -> void: print("\n--- Test 3: Bleach (70201) Bypasses Cooldown & Resets Color ---") var sys := HairDyeSystem.new() sys.current_hair_color = 3 # Red sys.last_dye_level = 33 # Normally requires Lv 36 for next dye var inv: Array = [ {"vnum": HairDyeSystem.VNUM_BLEACH, "name": "漂白水", "count": 1}, {"vnum": HairDyeSystem.VNUM_WHITE_DYE, "name": "染发剂(白)", "count": 1} ] var bleach_sig := {"fired": false} sys.hair_bleached.connect(func(): bleach_sig["fired"] = true ) # Use Bleach at Lv 33 (same level) -> succeeds unconditionally var res_bleach = sys.dye_hair(inv, 0, 33) _assert(res_bleach["ok"] == true, "Bleach used successfully at same level") _assert(sys.current_hair_color == 0, "Color reset to 0 (Default)") _assert(sys.last_dye_level == 0, "Cooldown level reset to 0") _assert(bleach_sig["fired"] == true, "hair_bleached signal emitted") # Immediately dye White at Lv 33 without cooldown! var res_white = sys.dye_hair(inv, 1, 33) _assert(res_white["ok"] == true, "White dye used immediately after bleach") _assert(sys.current_hair_color == 1, "Color is now 1 (White)") func _test_costume_hair_rejection() -> void: print("\n--- Test 4: Costume Hair (PART_HAIR >= 1001) Rejection ---") var sys := HairDyeSystem.new() sys.current_hair_style_id = 1005 # Equipped costume hair var inv: Array = [ {"vnum": HairDyeSystem.VNUM_BLACK_DYE, "name": "染发剂(黑)", "count": 1} ] var res_costume = sys.dye_hair(inv, 0, 50) _assert(res_costume["ok"] == false, "Costume hair dyeing rejected") _assert(res_costume["reason"] == "CANNOT_DYE_COSTUME_HAIR", "Reason is CANNOT_DYE_COSTUME_HAIR") _assert(inv[0] != null, "Dye not consumed") func _test_serialization() -> void: print("\n--- Test 5: Serialization & Restoration ---") var sys1 := HairDyeSystem.new() sys1.current_hair_color = 4 # Brown sys1.last_dye_level = 65 sys1.current_hair_style_id = 0 var data = sys1.serialize() var sys2 := HairDyeSystem.new() sys2.deserialize(data) _assert(sys2.current_hair_color == 4, "Restored color 4 (Brown)") _assert(sys2.last_dye_level == 65, "Restored last dye level 65") func _finish() -> void: print("\n=======================================================") print("Hair Dye System Parity Tests: %d Passed, %d Failed" % [_passed, _failed]) print("=======================================================\n") if _failed > 0: quit(1) else: quit(0)