169 lines
5.7 KiB
Swift
169 lines
5.7 KiB
Swift
|
|
import XCTest
|
||
|
|
import ForgeCamera
|
||
|
|
import ForgeGrade
|
||
|
|
import ForgeColor
|
||
|
|
import ForgeSim
|
||
|
|
@testable import ForgeCameraARRI
|
||
|
|
|
||
|
|
final class ArriDriverTests: XCTestCase {
|
||
|
|
|
||
|
|
var sim: ArriSimulator!
|
||
|
|
|
||
|
|
override func setUp() async throws {
|
||
|
|
sim = ArriSimulator()
|
||
|
|
try await sim.start(port: 0)
|
||
|
|
}
|
||
|
|
|
||
|
|
override func tearDown() async throws {
|
||
|
|
try? await sim.stop()
|
||
|
|
sim = nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func makeDriver(pollInterval: Duration = .milliseconds(20)) async -> ArriDriver {
|
||
|
|
let port = await sim.boundPort!
|
||
|
|
return ArriDriver(host: "127.0.0.1", port: port, pollInterval: pollInterval)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Capabilities: ARRI = native CDL + 33/65 LUTs.
|
||
|
|
func testCapabilities() async {
|
||
|
|
let driver = await makeDriver()
|
||
|
|
XCTAssertEqual(driver.capabilities.vendor, .arri)
|
||
|
|
XCTAssertTrue(driver.capabilities.supportsNativeCDL)
|
||
|
|
XCTAssertTrue(driver.capabilities.lut3dSizes.contains(33))
|
||
|
|
XCTAssertTrue(driver.capabilities.metadataFields.contains(.clipName))
|
||
|
|
}
|
||
|
|
|
||
|
|
// Connect verifies system info and emits connected state.
|
||
|
|
func testConnectEmitsConnected() async throws {
|
||
|
|
let driver = await makeDriver()
|
||
|
|
var iterator = driver.state.makeAsyncIterator()
|
||
|
|
try await driver.connect()
|
||
|
|
var connected = false
|
||
|
|
for _ in 0..<5 {
|
||
|
|
if let s = await iterator.next(), s.connection == .connected {
|
||
|
|
connected = true
|
||
|
|
break
|
||
|
|
}
|
||
|
|
}
|
||
|
|
XCTAssertTrue(connected)
|
||
|
|
await driver.disconnect()
|
||
|
|
}
|
||
|
|
|
||
|
|
// Connect to dead port throws.
|
||
|
|
func testConnectFailsOnDeadPort() async {
|
||
|
|
let driver = ArriDriver(host: "127.0.0.1", port: 1, pollInterval: .milliseconds(20))
|
||
|
|
do {
|
||
|
|
try await driver.connect()
|
||
|
|
XCTFail("expected throw")
|
||
|
|
} catch {}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Poll loop surfaces metadata.
|
||
|
|
func testMetadataPolling() async throws {
|
||
|
|
await sim.setMetadata(ei: 1280, wb: 3200, tint: -2, fps: 25, timecode: "10:20:30:12")
|
||
|
|
let driver = await makeDriver()
|
||
|
|
var iterator = driver.state.makeAsyncIterator()
|
||
|
|
try await driver.connect()
|
||
|
|
|
||
|
|
var got = false
|
||
|
|
for _ in 0..<20 {
|
||
|
|
if let s = await iterator.next(),
|
||
|
|
let md = s.metadata,
|
||
|
|
md.exposureIndex == 1280, md.whiteBalance == 3200 {
|
||
|
|
XCTAssertEqual(md.timecode, "10:20:30:12")
|
||
|
|
got = true
|
||
|
|
break
|
||
|
|
}
|
||
|
|
}
|
||
|
|
XCTAssertTrue(got)
|
||
|
|
await driver.disconnect()
|
||
|
|
}
|
||
|
|
|
||
|
|
// Rec start/stop events with clip name.
|
||
|
|
func testRecStateEvents() async throws {
|
||
|
|
let driver = await makeDriver()
|
||
|
|
var iterator = driver.state.makeAsyncIterator()
|
||
|
|
try await driver.connect()
|
||
|
|
|
||
|
|
await sim.setRecording(true, clipName: "A001C007_250710_R1CD")
|
||
|
|
var sawRec = false
|
||
|
|
for _ in 0..<30 {
|
||
|
|
if let s = await iterator.next(), s.isRecording {
|
||
|
|
XCTAssertEqual(s.clipName, "A001C007_250710_R1CD")
|
||
|
|
sawRec = true
|
||
|
|
break
|
||
|
|
}
|
||
|
|
}
|
||
|
|
XCTAssertTrue(sawRec)
|
||
|
|
|
||
|
|
await sim.setRecording(false)
|
||
|
|
var sawStop = false
|
||
|
|
for _ in 0..<30 {
|
||
|
|
if let s = await iterator.next(), !s.isRecording {
|
||
|
|
sawStop = true
|
||
|
|
break
|
||
|
|
}
|
||
|
|
}
|
||
|
|
XCTAssertTrue(sawStop)
|
||
|
|
await driver.disconnect()
|
||
|
|
}
|
||
|
|
|
||
|
|
// push(look:) uploads CDL + LUT payload sim can parse.
|
||
|
|
func testPushLook() async throws {
|
||
|
|
let driver = await makeDriver()
|
||
|
|
try await driver.connect()
|
||
|
|
|
||
|
|
let cdl = CDL(slope: SIMD3(1.1, 1.0, 0.9), offset: .zero, power: .one, saturation: 1.2)
|
||
|
|
let lut = Lut3D.identity(size: 33)
|
||
|
|
let look = FlattenedLook(cdl: cdl, lut: lut, latticeSize: 33)
|
||
|
|
try await driver.push(look: look)
|
||
|
|
|
||
|
|
let uploads = await sim.uploadedLooks
|
||
|
|
XCTAssertEqual(uploads.count, 1)
|
||
|
|
let obj = try JSONSerialization.jsonObject(with: uploads[0]) as? [String: Any]
|
||
|
|
let cdlObj = obj?["cdl"] as? [String: Any]
|
||
|
|
let slope = cdlObj?["slope"] as? [Double]
|
||
|
|
XCTAssertEqual(slope?[0] ?? 0, 1.1, accuracy: 1e-5)
|
||
|
|
XCTAssertEqual(cdlObj?["saturation"] as? Double ?? 0, 1.2, accuracy: 1e-5)
|
||
|
|
XCTAssertEqual(obj?["lut3dSize"] as? Int, 33)
|
||
|
|
let table = obj?["lut3dTable"] as? [Double]
|
||
|
|
XCTAssertEqual(table?.count, 33 * 33 * 33 * 3)
|
||
|
|
await driver.disconnect()
|
||
|
|
}
|
||
|
|
|
||
|
|
// Unsupported LUT size rejected before hitting the wire.
|
||
|
|
func testUnsupportedLutSizeRejected() async throws {
|
||
|
|
let driver = await makeDriver()
|
||
|
|
try await driver.connect()
|
||
|
|
let look = FlattenedLook(cdl: nil, lut: Lut3D.identity(size: 5), latticeSize: 5)
|
||
|
|
do {
|
||
|
|
try await driver.push(look: look)
|
||
|
|
XCTFail("expected unsupportedLook")
|
||
|
|
} catch let error as CameraError {
|
||
|
|
guard case .unsupportedLook = error else { return XCTFail("wrong error") }
|
||
|
|
}
|
||
|
|
let uploads = await sim.uploadedLooks
|
||
|
|
XCTAssertTrue(uploads.isEmpty)
|
||
|
|
await driver.disconnect()
|
||
|
|
}
|
||
|
|
|
||
|
|
// Reconnect after sim restart.
|
||
|
|
func testReconnectAfterSimRestart() async throws {
|
||
|
|
let port = await sim.boundPort!
|
||
|
|
let driver = ArriDriver(host: "127.0.0.1", port: port, pollInterval: .milliseconds(20))
|
||
|
|
try await driver.connect()
|
||
|
|
await driver.disconnect()
|
||
|
|
|
||
|
|
try await sim.stop()
|
||
|
|
sim = ArriSimulator()
|
||
|
|
try await sim.start(port: port)
|
||
|
|
|
||
|
|
try await driver.connect()
|
||
|
|
let look = FlattenedLook(cdl: nil, lut: Lut3D.identity(size: 33), latticeSize: 33)
|
||
|
|
try await driver.push(look: look)
|
||
|
|
let uploads = await sim.uploadedLooks
|
||
|
|
XCTAssertEqual(uploads.count, 1)
|
||
|
|
await driver.disconnect()
|
||
|
|
}
|
||
|
|
}
|