import XCTest import Foundation #if canImport(FoundationNetworking) import FoundationNetworking #endif @testable import ForgeSim final class ArriSimTests: XCTestCase { var sim: ArriSimulator! override func setUp() async throws { sim = ArriSimulator() try await sim.start(port: 0) // ephemeral } override func tearDown() async throws { try await sim.stop() sim = nil } func get(_ path: String) async throws -> (Int, Data) { let port = await sim.boundPort! let url = URL(string: "http://127.0.0.1:\(port)\(path)")! let (data, resp) = try await URLSession.shared.data(from: url) return ((resp as! HTTPURLResponse).statusCode, data) } func put(_ path: String, body: Data) async throws -> (Int, Data) { let port = await sim.boundPort! var req = URLRequest(url: URL(string: "http://127.0.0.1:\(port)\(path)")!) req.httpMethod = "PUT" req.httpBody = body let (data, resp) = try await URLSession.shared.data(for: req) return ((resp as! HTTPURLResponse).statusCode, data) } // System info endpoint serves model + serial JSON. func testSystemInfo() async throws { let (status, data) = try await get("/api/v1/system/info") XCTAssertEqual(status, 200) let obj = try JSONSerialization.jsonObject(with: data) as? [String: Any] XCTAssertEqual(obj?["model"] as? String, "ALEXA 35") XCTAssertNotNil(obj?["serialNumber"]) } // Rec state reflects scripted changes. func testRecStateScriptable() async throws { var (_, data) = try await get("/api/v1/recording/status") var obj = try JSONSerialization.jsonObject(with: data) as? [String: Any] XCTAssertEqual(obj?["recording"] as? Bool, false) await sim.setRecording(true, clipName: "A001C003_250710_R1CD") (_, data) = try await get("/api/v1/recording/status") obj = try JSONSerialization.jsonObject(with: data) as? [String: Any] XCTAssertEqual(obj?["recording"] as? Bool, true) XCTAssertEqual(obj?["clipName"] as? String, "A001C003_250710_R1CD") } // Metadata endpoint. func testMetadata() async throws { await sim.setMetadata(ei: 1280, wb: 3200, tint: -2, fps: 25, timecode: "10:20:30:12") let (status, data) = try await get("/api/v1/camera/metadata") XCTAssertEqual(status, 200) let obj = try JSONSerialization.jsonObject(with: data) as? [String: Any] XCTAssertEqual(obj?["exposureIndex"] as? Int, 1280) XCTAssertEqual(obj?["whiteBalance"] as? Int, 3200) XCTAssertEqual(obj?["tint"] as? Int, -2) XCTAssertEqual(obj?["timecode"] as? String, "10:20:30:12") } // Look upload stored and retrievable. func testLookUploadStored() async throws { let payload = try JSONSerialization.data(withJSONObject: [ "name": "shot42", "cdl": ["slope": [1.1, 1.0, 0.9], "offset": [0, 0, 0], "power": [1, 1, 1], "saturation": 1.2], "lut3dSize": 2, "lut3dTable": Array(repeating: 0.5, count: 24), ]) let (status, _) = try await put("/api/v1/look/current", body: payload) XCTAssertEqual(status, 200) let stored = await sim.uploadedLooks XCTAssertEqual(stored.count, 1) let storedObj = try JSONSerialization.jsonObject(with: stored[0]) as? [String: Any] XCTAssertEqual(storedObj?["name"] as? String, "shot42") // Retrievable over HTTP too. let (gs, gd) = try await get("/api/v1/look/current") XCTAssertEqual(gs, 200) let obj = try JSONSerialization.jsonObject(with: gd) as? [String: Any] XCTAssertEqual(obj?["name"] as? String, "shot42") } // Malformed look rejected 400. func testMalformedLookRejected() async throws { let (status, _) = try await put("/api/v1/look/current", body: Data("not json".utf8)) XCTAssertEqual(status, 400) } // Unknown path 404. func testUnknownPath404() async throws { let (status, _) = try await get("/api/v1/warp/drive") XCTAssertEqual(status, 404) } }