# test_player_trade_exchange_parity.gd —— 40250 面对面交易与防调包双向锁定系统回归测试 extends SceneTree const SystemClass = preload("res://player_trade_exchange_system.gd") var _passed: int = 0 var _failed: int = 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_player_trade_exchange_parity (Batch 26 Direction 3) ===") _test_trade_session_initialization() _test_untradeable_items_rejection() _test_anti_swap_lock_reset_security() _test_gold_offer_validation() _test_successful_atomic_exchange() _test_insufficient_space_rejection() _test_cancel_trade() print("\n=== Result: %d Passed, %d Failed ===" % [_passed, _failed]) if _failed == 0: print("ALL TESTS PASSED!\n") else: printerr("SOME TESTS FAILED!\n") quit(0 if _failed == 0 else 1) func _create_player(id: int, name: String, gold: int, inv_size: int = 10) -> Dictionary: var inv: Array = [] for i in range(inv_size): inv.append(null) return { "id": id, "name": name, "gold": gold, "inv": inv } func _test_trade_session_initialization() -> void: print("\n--- Test 1: Trade Session Initialization & Distance ---") var trade = SystemClass.new() var p1 = _create_player(101, "Alice", 500000) var p2 = _create_player(102, "Bob", 300000) # 1. Reject distance > 1000 var r_dist = trade.start_exchange(p1, p2, 1200.0) _assert(r_dist["error_code"] == "TOO_FAR", "Reject trade if distance > 1000") # 2. Reject self trade var r_self = trade.start_exchange(p1, p1, 100.0) _assert(r_self["error_code"] == "CANNOT_TRADE_SELF", "Reject trade with self") # 3. Successful start var r_ok = trade.start_exchange(p1, p2, 100.0) _assert(r_ok["success"] == true, "Trade session opened successfully") _assert(trade.is_active == true, "Trade is active") func _test_untradeable_items_rejection() -> void: print("\n--- Test 2: Untradeable Items Rejection ---") var trade = SystemClass.new() var p1 = _create_player(101, "Alice", 500000) var p2 = _create_player(102, "Bob", 300000) p1["inv"][0] = { "vnum": 1, "name": "Normal Item", "anti_give": false, "is_soulbound": false } p1["inv"][1] = { "vnum": 2, "name": "Bound Item", "anti_give": false, "is_soulbound": true } p1["inv"][2] = { "vnum": 3, "name": "Anti-Give Item", "anti_give": true, "is_soulbound": false } p1["inv"][3] = { "vnum": 4, "name": "Equipped Item", "is_equipped": true } trade.start_exchange(p1, p2) # Soulbound rejected var r_bound = trade.add_item(101, 1, 0) _assert(r_bound["error_code"] == "ITEM_UNTRADEABLE", "Soulbound item rejected from trade") # Anti-give rejected var r_antigive = trade.add_item(101, 2, 0) _assert(r_antigive["error_code"] == "ITEM_UNTRADEABLE", "Anti-give flag item rejected from trade") # Equipped rejected var r_equip = trade.add_item(101, 3, 0) _assert(r_equip["error_code"] == "ITEM_UNTRADEABLE", "Equipped item rejected from trade") # Normal item accepted var r_norm = trade.add_item(101, 0, 0) _assert(r_norm["success"] == true, "Tradeable item successfully added to slot 0") func _test_anti_swap_lock_reset_security() -> void: print("\n--- Test 3: 40250 Anti-Swap Security (Lock Reset on Modification) ---") var trade = SystemClass.new() var p1 = _create_player(101, "Alice", 500000) var p2 = _create_player(102, "Bob", 300000) p1["inv"][0] = { "vnum": 10, "name": "Sword" } p2["inv"][0] = { "vnum": 20, "name": "Shield" } p2["inv"][1] = { "vnum": 30, "name": "Dagger" } trade.start_exchange(p1, p2) trade.add_item(101, 0, 0) trade.add_item(102, 0, 0) # Alice locks ready trade.set_ready(101, true) _assert(trade.side_a.is_ready == true, "Alice locked ready") # Bob attempts to add another item (or swap item) trade.add_item(102, 1, 1) _assert(trade.side_a.is_ready == false, "Alice's ready lock instantly revoked on Bob item add") _assert(trade.side_b.is_ready == false, "Bob's ready lock also reset") # Alice locks ready again trade.set_ready(101, true) _assert(trade.side_a.is_ready == true, "Alice locked ready again") # Bob modifies gold trade.set_gold(102, 10000) _assert(trade.side_a.is_ready == false, "Alice's ready lock instantly revoked on Bob gold change") # Alice locks ready again trade.set_ready(101, true) # Bob removes item trade.remove_item(102, 1) _assert(trade.side_a.is_ready == false, "Alice's ready lock instantly revoked on Bob item remove") func _test_gold_offer_validation() -> void: print("\n--- Test 4: Gold Offer Validation ---") var trade = SystemClass.new() var p1 = _create_player(101, "Alice", 100000) var p2 = _create_player(102, "Bob", 50000) trade.start_exchange(p1, p2) # Reject offer exceeding gold var r_fail = trade.set_gold(101, 150000) _assert(r_fail["error_code"] == "INSUFFICIENT_GOLD", "Reject gold offer exceeding owned gold") # Accept valid offer var r_ok = trade.set_gold(101, 80000) _assert(r_ok["success"] == true, "Valid gold offer accepted") _assert(trade.side_a.offered_gold == 80000, "Alice offered 80,000 gold") func _test_successful_atomic_exchange() -> void: print("\n--- Test 5: Successful Atomic Trade Execution ---") var trade = SystemClass.new() var p1 = _create_player(101, "Alice", 500000, 5) var p2 = _create_player(102, "Bob", 200000, 5) p1["inv"][0] = { "vnum": 101, "name": "Dragon Sword+9" } p2["inv"][0] = { "vnum": 202, "name": "Black Steel Armor+9" } trade.start_exchange(p1, p2) # Alice puts Dragon Sword and 100,000 gold trade.add_item(101, 0, 0) trade.set_gold(101, 100000) # Bob puts Black Steel Armor and 40,000 gold trade.add_item(102, 0, 0) trade.set_gold(102, 40000) # Both confirm var r_ready_a = trade.set_ready(101, true) _assert(r_ready_a["trade_completed"] == false, "Trade not completed after only Alice ready") var r_ready_b = trade.set_ready(102, true) _assert(r_ready_b["trade_completed"] == true, "Trade atomically completed when both ready") _assert(trade.is_active == false, "Trade session closed") # Check Gold: # Alice: 500,000 - 100,000 + 40,000 = 440,000 _assert(p1["gold"] == 440000, "Alice gold correctly calculated (440,000)") # Bob: 200,000 - 40,000 + 100,000 = 260,000 _assert(p2["gold"] == 260000, "Bob gold correctly calculated (260,000)") # Check Items: # Alice now has Black Steel Armor var alice_has_armor := false for it in p1["inv"]: if it != null and it.get("vnum") == 202: alice_has_armor = true _assert(alice_has_armor == true, "Alice received Bob's Black Steel Armor") # Bob now has Dragon Sword var bob_has_sword := false for it in p2["inv"]: if it != null and it.get("vnum") == 101: bob_has_sword = true _assert(bob_has_sword == true, "Bob received Alice's Dragon Sword") func _test_insufficient_space_rejection() -> void: print("\n--- Test 6: CheckSpace Rejection (Inventory Full) ---") var trade = SystemClass.new() # Bob's inventory has only 1 slot, and it is full with an item he is NOT trading var p1 = _create_player(101, "Alice", 500000, 5) var p2 = _create_player(102, "Bob", 200000, 1) p1["inv"][0] = { "vnum": 101, "name": "Item A" } p2["inv"][0] = { "vnum": 999, "name": "Untraded Item (Full)" } # Not trading this trade.start_exchange(p1, p2) trade.add_item(101, 0, 0) # Alice offers Item A trade.set_ready(101, true) var res = trade.set_ready(102, true) _assert(res["trade_completed"] == false, "Trade aborted due to space check") _assert(res["error_code"] == "PLAYER_B_INSUFFICIENT_SPACE", "Detected Bob has insufficient inventory space") func _test_cancel_trade() -> void: print("\n--- Test 7: Trade Cancellation ---") var trade = SystemClass.new() var p1 = _create_player(101, "Alice", 500000, 5) var p2 = _create_player(102, "Bob", 200000, 5) trade.start_exchange(p1, p2) _assert(trade.is_active == true, "Trade started") trade.cancel_trade() _assert(trade.is_active == false, "Trade canceled and inactive")