// // PunchPointAPITests.swift // suixinkanTests // import XCTest @testable import suixinkan /// 打卡点管理 API 路径、参数与请求体测试。 @MainActor final class PunchPointAPITests: XCTestCase { func testListAndInfoUseAndroidPathsAndQueries() async throws { let session = MockURLSession(responses: [ envelopeJSON(#"{"total":0,"list":[]}"#), envelopeJSON(#"{"id":18,"name":"观景台"}"#), ]) let api = PunchPointAPI(client: APIClient(environment: .testing, session: session)) _ = try await api.list(scenicAreaId: "9", status: 2, page: 3, pageSize: 10) _ = try await api.info(id: 18) XCTAssertEqual(session.requests[0].httpMethod, "GET") XCTAssertEqual(session.requests[0].url?.path, "/api/yf-handset-app/photog/scenic-spot/list") let listQuery = URLComponents(url: try XCTUnwrap(session.requests[0].url), resolvingAgainstBaseURL: false)?.queryItems XCTAssertEqual(listQuery?.first { $0.name == "scenic_area_id" }?.value, "9") XCTAssertEqual(listQuery?.first { $0.name == "status" }?.value, "2") XCTAssertEqual(listQuery?.first { $0.name == "page" }?.value, "3") XCTAssertEqual(listQuery?.first { $0.name == "page_size" }?.value, "10") XCTAssertEqual(session.requests[1].httpMethod, "GET") XCTAssertEqual(session.requests[1].url?.path, "/api/yf-handset-app/photog/scenic-spot/info") let infoQuery = URLComponents(url: try XCTUnwrap(session.requests[1].url), resolvingAgainstBaseURL: false)?.queryItems XCTAssertEqual(infoQuery?.first { $0.name == "id" }?.value, "18") } func testAddEditAndDeleteEncodeAndroidBodies() async throws { let session = MockURLSession(responses: [envelopeJSON("{}"), envelopeJSON("{}"), envelopeJSON("{}")]) let api = PunchPointAPI(client: APIClient(environment: .testing, session: session)) let addRequest = PunchPointSaveRequest( scenicAreaId: "7", name: "山顶打卡点", description: "日出位置", region: PunchPointSaveRegion(lot: 120.12, lat: 30.23, address: "山顶平台"), scenicSpotString: "山顶平台", guideImages: ["https://cdn/a.jpg"] ) let editRequest = PunchPointSaveRequest( id: 88, scenicAreaId: "7", name: "山顶打卡点2", description: nil, region: PunchPointSaveRegion(lot: 121.12, lat: 31.23, address: "新平台"), scenicSpotString: "新平台", guideImages: ["https://cdn/b.jpg"] ) try await api.add(addRequest) try await api.edit(editRequest) try await api.delete(id: 88) XCTAssertEqual(session.requests[0].url?.path, "/api/yf-handset-app/photog/scenic-spot/add") let addBody = try bodyJSON(session.requests[0]) XCTAssertNil(addBody["id"]) XCTAssertEqual(addBody["scenic_area_id"] as? String, "7") XCTAssertEqual(addBody["name"] as? String, "山顶打卡点") XCTAssertEqual(addBody["scenic_spot_str"] as? String, "山顶平台") XCTAssertEqual(addBody["guide_imgs"] as? [String], ["https://cdn/a.jpg"]) let addRegion = try XCTUnwrap(addBody["region"] as? [String: Any]) XCTAssertEqual(addRegion["lot"] as? Double, 120.12) XCTAssertEqual(addRegion["lat"] as? Double, 30.23) XCTAssertEqual(addRegion["address"] as? String, "山顶平台") XCTAssertEqual(session.requests[1].url?.path, "/api/yf-handset-app/photog/scenic-spot/edit") let editBody = try bodyJSON(session.requests[1]) XCTAssertEqual(editBody["id"] as? Int, 88) XCTAssertEqual(editBody["name"] as? String, "山顶打卡点2") XCTAssertNil(editBody["description"]) XCTAssertEqual(session.requests[2].url?.path, "/api/yf-handset-app/photog/scenic-spot/delete") let deleteBody = try bodyJSON(session.requests[2]) XCTAssertEqual(deleteBody["id"] as? Int, 88) } private func envelopeJSON(_ dataJSON: String) -> Data { """ {"code":100000,"msg":"success","data":\(dataJSON)} """.data(using: .utf8)! } private func bodyJSON(_ request: URLRequest) throws -> [String: Any] { try XCTUnwrap(JSONSerialization.jsonObject(with: try XCTUnwrap(request.httpBody)) as? [String: Any]) } }