# test_target_board_parity.gd —— 40250 目标信息板 TargetBoard 1:1 回归测试套件 # 运行方式: # /opt/homebrew/bin/godot --headless --path metin2-client/project --script test_target_board_parity.gd extends SceneTree const TargetUI = preload("res://ui/target_ui.gd") const NetPlay = preload("res://net_play.gd") class MockClient extends Node: var cleared_target_count := 0 func clear_target() -> void: cleared_target_count += 1 func get_entity(vid: int) -> Dictionary: if vid == 1001: return {"vid": 1001, "name": "兽人首领", "level": 50, "grade": 4, "kind": 2, "dead": false} if vid == 1002: return {"vid": 1002, "name": "狂暴野狼", "level": 12, "grade": 0, "kind": 2, "dead": false} return {} 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_target_board_parity (Direction 1: TargetBoard 1:1) ===") _test_board_sizing_and_naming() _test_hp_gauge_and_closing() _test_net_play_integration() _finish() func _test_board_sizing_and_naming() -> void: print("\n--- Test 1: Sizing & Name/Grade Prefix (uitarget.py:301) ---") var client := MockClient.new() get_root().add_child(client) var target_ui := TargetUI.new() get_root().add_child(target_ui) target_ui.setup(client, get_root()) _assert(target_ui.is_open() == false, "Target board initially hidden") # Open Boss target (Lv 50, Grade 4 = 5阶首领) target_ui.open(1001, "兽人首领", 50, 4, false) _assert(target_ui.is_open() == true, "Target board opened") _assert(target_ui.get_target_name() == "[Lv. 50] (5阶首领) 兽人首领", "Name prefix formatted correctly with Lv and Grade") # Verify dynamic width formula: 200 + 7 * len("[Lv. 50] (5阶首领) 兽人首领") # len is 19 chars -> 200 + 7 * 19 = 333 var expected_w := 200.0 + 7.0 * float("[Lv. 50] (5阶首领) 兽人首领".length()) _assert(target_ui._board.size.x == expected_w, "Board width auto-sizes to %.1f (200 + 7*len)" % expected_w) target_ui.queue_free() client.queue_free() func _test_hp_gauge_and_closing() -> void: print("\n--- Test 2: HP Gauge 130px & Close Button (ClearTarget) ---") var client := MockClient.new() get_root().add_child(client) var target_ui := TargetUI.new() get_root().add_child(target_ui) target_ui.setup(client, get_root()) target_ui.open(1002, "野狼", 12, 0, false) target_ui.set_hp(60) _assert(target_ui.get_hp_percentage() == 60, "HP set to 60%") # Gauge width = 130.0 * 0.6 = 78.0 _assert(absf(target_ui._hp_gauge_fill.size.x - 78.0) < 0.01, "HP fill width is 78px (130 * 0.6)") _assert(target_ui._hp_text.text == "60%", "HP text displays '60%'") # Close button click target_ui._on_close_button_pressed() _assert(target_ui.is_open() == false, "Target board closed after clicking close button") _assert(client.cleared_target_count == 1, "client.clear_target() called upon close") target_ui.queue_free() client.queue_free() func _test_net_play_integration() -> void: print("\n--- Test 3: NetPlay _on_target_info Dispatching ---") var client := MockClient.new() get_root().add_child(client) var net_play := NetPlay.new() get_root().add_child(net_play) net_play.client = client var target_ui := TargetUI.new() get_root().add_child(target_ui) target_ui.setup(client, get_root()) net_play.target_ui = target_ui # Simulate RecvTargetPacket for vid 1001 with 85% HP net_play._on_target_info(1001, 85) _assert(target_ui.is_open() == true, "NetPlay _on_target_info opened target_ui") _assert(target_ui.get_target_vid() == 1001, "Target VID is 1001") _assert(target_ui.get_hp_percentage() == 85, "Target HP percentage is 85%") # Clear target net_play._clear_target() _assert(target_ui.is_open() == false, "NetPlay _clear_target closed target_ui") target_ui.queue_free() net_play.queue_free() client.queue_free() func _finish() -> void: print("\n=== SUMMARY: %d passed, %d failed ===" % [_passed, _failed]) if _failed == 0: print("ALL TESTS PASSED!\n") quit(0) else: printerr("SOME TESTS FAILED!\n") quit(1)