import XCTest import Foundation @testable import ForgeCameraARRI final class CAPProtocolTests: XCTestCase { // Frame encode: length includes 7-byte header, big-endian fields. func testEncodeFrame() { let frame = CAP.Frame( msgType: CAP.MsgType.command.rawValue, msgId: 0x1234, cmdCode: CAP.Command.live.rawValue, payload: Data([0xAA, 0xBB])) let data = CAP.encode(frame) XCTAssertEqual([UInt8](data), [ 0x00, 0x09, // length 9 = 7 + 2 0x01, // COMMAND 0x12, 0x34, // msgId 0x00, 0x80, // Live 0xAA, 0xBB, ]) } // Round trip. func testDecodeRoundTrip() throws { let frame = CAP.Frame(msgType: 0x02, msgId: 7, cmdCode: 0x0000, payload: Data([1, 2, 3])) var buf = CAP.encode(frame) let decoded = try XCTUnwrap(CAP.decodeFirst(&buf)) XCTAssertEqual(decoded, frame) XCTAssertTrue(buf.isEmpty) } // Partial frame buffers. func testPartialFrame() throws { let full = CAP.encode(CAP.Frame(msgType: 0x01, msgId: 1, cmdCode: 0x0080)) var buf = Data(full.prefix(4)) XCTAssertNil(try CAP.decodeFirst(&buf)) buf.append(full.suffix(from: 4)) XCTAssertNotNil(try CAP.decodeFirst(&buf)) } // Two frames in one buffer. func testTwoFrames() throws { var buf = CAP.encode(CAP.Frame(msgType: 0x01, msgId: 1, cmdCode: 0x0080)) buf.append(CAP.encode(CAP.Frame(msgType: 0x01, msgId: 2, cmdCode: 0x0090))) let f1 = try XCTUnwrap(CAP.decodeFirst(&buf)) let f2 = try XCTUnwrap(CAP.decodeFirst(&buf)) XCTAssertEqual(f1.msgId, 1) XCTAssertEqual(f2.msgId, 2) } // Bogus length rejected. func testShortLengthRejected() { var buf = Data([0x00, 0x03, 0x01]) XCTAssertThrowsError(try CAP.decodeFirst(&buf)) } // CAP string encoding. func testStringCodec() { var data = Data() CAP.putString("Forge", into: &data) XCTAssertEqual([UInt8](data.prefix(2)), [0x00, 0x05]) let read = CAP.readString(data, at: 0) XCTAssertEqual(read?.value, "Forge") XCTAssertEqual(read?.consumed, 7) } // BCD timecode. func testTimecodeBCD() { // 12:34:56:23 -> BCD 0x12345623 XCTAssertEqual(CAP.decodeTimecodeBCD(0x12345623), "12:34:56:23") XCTAssertEqual(CAP.encodeTimecodeBCD("12:34:56:23"), 0x12345623) XCTAssertEqual(CAP.decodeTimecodeBCD(CAP.encodeTimecodeBCD("09:59:00:01")!), "09:59:00:01") } // CDL blob: 10 F32 big-endian, 40 bytes. func testCDLBlob() { let blob = CAP.encodeCDLBlob( slope: (1.1, 1.0, 0.9), offset: (0.01, 0.0, -0.01), power: (0.95, 1.0, 1.05), saturation: 1.2) XCTAssertEqual(blob.count, 40) let values = CAP.decodeCDLBlob(blob)! XCTAssertEqual(values[0], 1.1, accuracy: 1e-6) XCTAssertEqual(values[2], 0.9, accuracy: 1e-6) XCTAssertEqual(values[5], -0.01, accuracy: 1e-6) XCTAssertEqual(values[9], 1.2, accuracy: 1e-6) } // Camera state bitfield. func testCameraStateBits() { let bits = CAP.CameraStateBits(rawValue: 0x0005) XCTAssertTrue(bits.contains(.recording)) XCTAssertTrue(bits.contains(.standbyReady)) XCTAssertFalse(bits.contains(.playback)) } // U32/F32 round trip. func testNumericCodecs() { var data = Data() CAP.putU32(0xDEADBEEF, into: &data) CAP.putF32(3.14159, into: &data) XCTAssertEqual(CAP.readU32(data, at: 0), 0xDEADBEEF) XCTAssertEqual(CAP.readF32(data, at: 4) ?? 0, 3.14159, accuracy: 1e-5) } }