Introduce travel album entry with Sony PTP tethering pipeline, profile space settings page, home routing updates, Launch Screen storyboard, and related tests/docs. Co-authored-by: Cursor <cursoragent@cursor.com>
71 lines
2.1 KiB
Swift
71 lines
2.1 KiB
Swift
//
|
||
// CameraTransferPipelineTests.swift
|
||
// suixinkanTests
|
||
//
|
||
// Created by Codex on 2026/6/29.
|
||
//
|
||
|
||
import XCTest
|
||
@testable import suixinkan
|
||
|
||
@MainActor
|
||
/// 相机传输管道测试,使用 Mock 相机与上传 Sink。
|
||
final class CameraTransferPipelineTests: XCTestCase {
|
||
/// 测试新照片下载后触发上传 Sink。
|
||
func testNewAssetTriggersUploadSink() async {
|
||
let camera = MockCameraService()
|
||
let sink = MockUploadSink()
|
||
let pipeline = CameraTransferPipeline(cameraService: camera)
|
||
pipeline.configure(uploadSink: sink, uploadEnabled: true)
|
||
|
||
let asset = CameraAsset(id: "ptp_1", filename: "DSC_001.JPG", fileSize: 1024)
|
||
let tempURL = FileManager.default.temporaryDirectory.appendingPathComponent("DSC_001.JPG")
|
||
try? Data(repeating: 0xFF, count: 8).write(to: tempURL)
|
||
|
||
camera.onNewAsset?(asset)
|
||
try? await Task.sleep(nanoseconds: 300_000_000)
|
||
|
||
XCTAssertEqual(sink.uploadCount, 1)
|
||
try? FileManager.default.removeItem(at: tempURL)
|
||
}
|
||
}
|
||
|
||
@MainActor
|
||
private final class MockCameraService: CameraServiceProtocol {
|
||
let brand: CameraBrand = .sony
|
||
var connectionState: CameraConnectionState = .connected(deviceName: "Mock")
|
||
var onConnectionStateChange: ((CameraConnectionState) -> Void)?
|
||
var onNewAsset: ((CameraAsset) -> Void)?
|
||
|
||
func connect() async {}
|
||
func disconnect() async {}
|
||
|
||
func listAssets() async throws -> [CameraAsset] {
|
||
[]
|
||
}
|
||
|
||
func downloadAsset(_ asset: CameraAsset) async throws -> URL {
|
||
let url = FileManager.default.temporaryDirectory.appendingPathComponent(asset.filename)
|
||
if !FileManager.default.fileExists(atPath: url.path) {
|
||
try Data(repeating: 0xFF, count: 8).write(to: url)
|
||
}
|
||
return url
|
||
}
|
||
}
|
||
|
||
@MainActor
|
||
private final class MockUploadSink: CameraAssetUploadSink {
|
||
var uploadCount = 0
|
||
|
||
func upload(
|
||
localURL: URL,
|
||
fileName: String,
|
||
fileType: Int,
|
||
progress: @escaping @Sendable (Int) -> Void
|
||
) async throws -> String {
|
||
uploadCount += 1
|
||
progress(100)
|
||
return "https://cdn/mock/\(fileName)"
|
||
}
|
||
}
|