// // CanonPTPCommandsTests.swift // suixinkanTests // import XCTest @testable import suixinkan /// Canon PTP 命令与事件解析测试。 final class CanonPTPCommandsTests: XCTestCase { /// 测试 SetRemoteMode 命令包 opcode。 func testBuildSetRemoteModeCommand() { let data = PTPHelper.buildCommand( code: CanonPTPCommand.eosSetRemoteMode, transactionID: 1, parameters: [1] ) XCTAssertEqual(data.count, 16) XCTAssertEqual(data[6], 0x14) XCTAssertEqual(data[7], 0x91) } /// 测试 ObjectAddedEx (0xC181) 事件解析。 func testParseObjectAddedExEvent() { var blob = Data() let recordSize: UInt32 = 8 + 40 blob.append(contentsOf: withUnsafeBytes(of: recordSize.littleEndian) { Data($0) }) blob.append(contentsOf: withUnsafeBytes(of: CanonPTPCommand.eosObjectAddedEx.littleEndian) { Data($0) }) blob.append(contentsOf: withUnsafeBytes(of: UInt32(0x1234).littleEndian) { Data($0) }) // handle blob.append(contentsOf: withUnsafeBytes(of: UInt32(0x00010001).littleEndian) { Data($0) }) // storage blob.append(contentsOf: withUnsafeBytes(of: UInt32(0x3801).littleEndian) { Data($0) }) // ofc blob.append(contentsOf: withUnsafeBytes(of: UInt32(0).littleEndian) { Data($0) }) // flags blob.append(contentsOf: withUnsafeBytes(of: UInt32(0).littleEndian) { Data($0) }) // parent blob.append(contentsOf: withUnsafeBytes(of: UInt32(0).littleEndian) { Data($0) }) // reserved blob.append(contentsOf: withUnsafeBytes(of: UInt32(1024).littleEndian) { Data($0) }) // size blob.append(contentsOf: withUnsafeBytes(of: UInt32(0).littleEndian) { Data($0) }) // reserved let filename = "IMG_0001.JPG" blob.append(filename.data(using: .ascii)!) blob.append(0) let events = CanonEosEventParser.parse(blob) XCTAssertEqual(events.count, 1) guard case .objectAdded(let added) = events[0] else { return XCTFail("expected objectAdded") } XCTAssertEqual(added.objectHandle, 0x1234) XCTAssertEqual(added.filename, "IMG_0001.JPG") XCTAssertEqual(added.size, 1024) } /// 测试 ObjectAddedEx2 (0xC1A7) 大文件 size 解析。 func testParseObjectAddedEx2Event() { var blob = Data() let recordSize: UInt32 = 8 + 48 blob.append(contentsOf: withUnsafeBytes(of: recordSize.littleEndian) { Data($0) }) blob.append(contentsOf: withUnsafeBytes(of: CanonPTPCommand.eosObjectAddedEx2.littleEndian) { Data($0) }) blob.append(contentsOf: withUnsafeBytes(of: UInt32(0x5678).littleEndian) { Data($0) }) blob.append(contentsOf: withUnsafeBytes(of: UInt32(0x00010001).littleEndian) { Data($0) }) blob.append(contentsOf: withUnsafeBytes(of: UInt32(0x3801).littleEndian) { Data($0) }) blob.append(contentsOf: withUnsafeBytes(of: UInt32(0).littleEndian) { Data($0) }) blob.append(contentsOf: withUnsafeBytes(of: UInt32(0).littleEndian) { Data($0) }) blob.append(contentsOf: withUnsafeBytes(of: UInt32(512).littleEndian) { Data($0) }) // sizeLow blob.append(contentsOf: withUnsafeBytes(of: UInt32(1).littleEndian) { Data($0) }) // sizeHigh blob.append(contentsOf: withUnsafeBytes(of: UInt32(0).littleEndian) { Data($0) }) blob.append(contentsOf: withUnsafeBytes(of: UInt32(0).littleEndian) { Data($0) }) blob.append("LARGE.JPG".data(using: .ascii)!) blob.append(0) let events = CanonEosEventParser.parse(blob) XCTAssertEqual(events.count, 1) guard case .objectAdded(let added) = events[0] else { return XCTFail("expected objectAdded") } XCTAssertEqual(added.objectHandle, 0x5678) XCTAssertEqual(added.size, 512 | (1 << 32)) } /// 测试支持的文件名扩展名过滤。 func testSupportedFilenameExtensions() { XCTAssertTrue(CanonPTPHelper.isSupportedFilename("photo.JPG")) XCTAssertTrue(CanonPTPHelper.isSupportedFilename("photo.cr2")) XCTAssertFalse(CanonPTPHelper.isSupportedFilename("photo.tif")) } }