extends GdUnitTestSuite ## NEO-72: `InventoryClient` GET parse + failure signals. const InventoryClient := preload("res://scripts/inventory_client.gd") var _inventory_capture: Dictionary = {} func _capture_inventory(snapshot: Dictionary) -> void: _inventory_capture = snapshot class MockHttpTransport: extends Node signal request_completed( result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray ) var last_url: String = "" var response_code: int = 200 var body_json: String = "" func request( url: String, _custom_headers: PackedStringArray = PackedStringArray(), _method: HTTPClient.Method = HTTPClient.METHOD_GET, _request_data: String = "" ) -> Error: last_url = url request_completed.emit( HTTPRequest.RESULT_SUCCESS, response_code, PackedStringArray(), body_json.to_utf8_buffer() ) return OK static func _empty_inventory_json() -> String: var bag_parts: PackedStringArray = PackedStringArray() for i in range(24): bag_parts.append('{"slotIndex":%d,"quantity":0}' % i) var bag: String = ", ".join(bag_parts) return ( ( '{"schemaVersion":1,"playerId":"dev-local-1","bagSlots":[%s],' + '"equipmentSlots":[{"slotIndex":0,"quantity":0}]}' ) % bag ) func _make_client(transport: Node) -> Node: var c: Node = InventoryClient.new() c.set("injected_http", transport) auto_free(transport) auto_free(c) add_child(c) return c func test_parse_inventory_json_empty_grid() -> void: # Arrange var json := _empty_inventory_json() # Act var snapshot: Variant = InventoryClient.parse_inventory_json(json) # Assert assert_that(snapshot is Dictionary).is_true() var bag: Variant = (snapshot as Dictionary).get("bagSlots", null) assert_that(bag is Array).is_true() assert_that((bag as Array).size()).is_equal(24) func test_request_sync_emits_inventory_received() -> void: # Arrange _inventory_capture = {} var transport := MockHttpTransport.new() transport.body_json = _empty_inventory_json() var c := _make_client(transport) c.connect("inventory_received", Callable(self, "_capture_inventory")) monitor_signals(c) # Act c.call("request_sync_from_server") # Assert await assert_signal(c).is_emitted("inventory_received", any()) assert_that(_inventory_capture.has("bagSlots")).is_true() assert_that((_inventory_capture["bagSlots"] as Array).size()).is_equal(24) assert_that((_inventory_capture["equipmentSlots"] as Array).size()).is_equal(1) assert_that(transport.last_url).contains("/inventory") func test_http_404_emits_inventory_sync_failed() -> void: # Arrange var transport := MockHttpTransport.new() transport.response_code = 404 var c := _make_client(transport) monitor_signals(c) # Act c.call("request_sync_from_server") # Assert await assert_signal(c).is_emitted("inventory_sync_failed", "HTTP 404 (player unknown)") func test_malformed_json_emits_inventory_sync_failed() -> void: # Arrange var transport := MockHttpTransport.new() transport.body_json = "[]" var c := _make_client(transport) monitor_signals(c) # Act c.call("request_sync_from_server") # Assert await assert_signal(c).is_emitted("inventory_sync_failed", any())