Files
suixinkan_ios_new/suixinkanTests/CameraTethering/CanonPTPCommandsTests.swift
汉秋 90d135b5ac 完善 OTG 相机有线传图:支持 Sony/Canon 自动识别,页面 detach 保持会话以便再次进入复连。
引入进程级 CameraTetheringSession 与共享 USB Browser;离开传图页仅取消 UI 回调,App 终止时再完整 shutdown 释放 PTP 与 Browser 资源。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-01 15:45:35 +08:00

86 lines
4.1 KiB
Swift

//
// 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"))
}
}