将本地存储与上传编排下沉到 Features/TravelAlbum,删除 USB/PTP 相关代码与测试。 Co-authored-by: Cursor <cursoragent@cursor.com>
545 lines
23 KiB
Swift
545 lines
23 KiB
Swift
//
|
||
// WiredCameraTransferViewModelTests.swift
|
||
// suixinkanTests
|
||
//
|
||
// Created by Codex on 2026/6/30.
|
||
//
|
||
|
||
import XCTest
|
||
import UIKit
|
||
@testable import suixinkan
|
||
|
||
@MainActor
|
||
/// 有线传图 ViewModel 测试。
|
||
final class WiredCameraTransferViewModelTests: XCTestCase {
|
||
/// 测试 start 被取消时会 detach UI 回调。
|
||
func testStartCancellationDetachesFromUI() async {
|
||
let context = WiredTransferContext(
|
||
albumId: 6603,
|
||
albumName: "测试相册",
|
||
phone: "",
|
||
orderNumber: ""
|
||
)
|
||
let viewModel = WiredCameraTransferViewModel(context: context)
|
||
let account = AccountContext()
|
||
account.applyLogin(profile: AccountProfile(userId: "101", displayName: "测试"))
|
||
|
||
let startTask = Task {
|
||
await viewModel.start(
|
||
api: MockTravelAlbumAPIForWiredTransfer(),
|
||
ossService: WiredTransferMockOSSUploadService(),
|
||
scenicID: 1,
|
||
accountContext: account
|
||
)
|
||
}
|
||
|
||
try? await Task.sleep(nanoseconds: 100_000_000)
|
||
startTask.cancel()
|
||
try? await Task.sleep(nanoseconds: 200_000_000)
|
||
|
||
XCTAssertEqual(viewModel.connectionState, .disconnected)
|
||
}
|
||
|
||
/// 测试批量上传按钮三态流转。
|
||
func testBatchUploadButtonThreeStateFlow() async {
|
||
let viewModel = makeViewModelWithPendingPhotos()
|
||
let api = MockTravelAlbumAPIForWiredTransfer()
|
||
let oss = WiredTransferMockOSSUploadService()
|
||
|
||
XCTAssertFalse(viewModel.selectUploadMode)
|
||
await viewModel.onBatchUploadButtonClick(api: api, ossService: oss, scenicID: 1)
|
||
XCTAssertTrue(viewModel.selectUploadMode)
|
||
XCTAssertTrue(viewModel.selectedPhotoIDs.isEmpty)
|
||
|
||
viewModel.togglePhotoSelection(id: "pending-1")
|
||
XCTAssertEqual(viewModel.selectedPhotoIDs, ["pending-1"])
|
||
|
||
await viewModel.onBatchUploadButtonClick(api: api, ossService: oss, scenicID: 1)
|
||
XCTAssertFalse(viewModel.selectUploadMode)
|
||
XCTAssertTrue(viewModel.selectedPhotoIDs.isEmpty)
|
||
}
|
||
|
||
/// 测试全选 pending 与取消全选。
|
||
func testToggleSelectAllPendingInVisible() {
|
||
let viewModel = makeViewModelWithPendingPhotos()
|
||
viewModel.selectUploadMode = true
|
||
|
||
viewModel.toggleSelectAllPendingInVisible()
|
||
XCTAssertEqual(viewModel.selectedPhotoIDs, ["pending-1", "pending-2"])
|
||
|
||
viewModel.toggleSelectAllPendingInVisible()
|
||
XCTAssertTrue(viewModel.selectedPhotoIDs.isEmpty)
|
||
}
|
||
|
||
/// 测试指定上传今日拍摄筛选。
|
||
func testUploadAllTodayCapturedFiltersByDate() async {
|
||
let formatter = DateFormatter()
|
||
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
|
||
formatter.locale = Locale(identifier: "zh_CN")
|
||
let today = formatter.string(from: Date())
|
||
|
||
let viewModel = WiredCameraTransferViewModel(
|
||
context: WiredTransferContext(albumId: 1, albumName: "相册", phone: "", orderNumber: "")
|
||
)
|
||
viewModel.replacePhotos([
|
||
makePendingPhoto(id: "today", capturedAt: today),
|
||
makePendingPhoto(id: "old", capturedAt: "2020-01-01 09:00:00"),
|
||
])
|
||
|
||
await viewModel.onSpecifyUploadOptionSelected(
|
||
WiredCameraTransferViewModel.specifyUploadTodayCaptured,
|
||
api: MockTravelAlbumAPIForWiredTransfer(),
|
||
ossService: WiredTransferMockOSSUploadService(),
|
||
scenicID: 1
|
||
)
|
||
XCTAssertNil(viewModel.errorMessage)
|
||
}
|
||
|
||
/// 测试拍后传输模式下重传会从持久化记录恢复上传。
|
||
func testRetryPhotoInPostShootModeUploadsPersistedFile() async throws {
|
||
let context = WiredTransferContext(
|
||
albumId: 1,
|
||
albumName: "测试相册",
|
||
phone: "",
|
||
orderNumber: ""
|
||
)
|
||
let account = AccountContext()
|
||
account.applyLogin(profile: AccountProfile(userId: "101", displayName: "测试"))
|
||
|
||
let scope = downloadScope(account: account, albumID: context.albumId)
|
||
let fileURL = CameraDownloadStorage.uniqueLocalURL(for: "retry_failed.JPG", scope: scope)
|
||
try Data(repeating: 0xCD, count: 32).write(to: fileURL)
|
||
defer { CameraDownloadStorage.removeScopeDirectory(for: scope) }
|
||
|
||
let photoID = "persist_failed_001"
|
||
let record = WiredTransferPhotoRecord(
|
||
id: photoID,
|
||
sourceId: photoID,
|
||
fileName: "retry_failed.JPG",
|
||
localPath: CameraDownloadStorage.relativePath(for: fileURL),
|
||
thumbnailPath: "",
|
||
capturedAt: "2026-05-20 12:05:18",
|
||
fileSizeBytes: 32,
|
||
status: WiredTransferUploadStatus.failed.rawValue,
|
||
progress: 0,
|
||
errorMessage: "upload failed",
|
||
albumId: 1,
|
||
userId: "101",
|
||
remoteURL: "",
|
||
updatedAt: Date().timeIntervalSince1970
|
||
)
|
||
let store = WiredTransferPhotoStore(
|
||
accountPrefixProvider: { account.accountCachePrefix ?? "guest_" },
|
||
userIDProvider: { "101" }
|
||
)
|
||
store.save(albumID: 1, records: [record])
|
||
|
||
let viewModel = WiredCameraTransferViewModel(context: context)
|
||
viewModel.transferModeOption = WiredCameraTransferViewModel.modePostShootTransfer
|
||
|
||
let api = MockTravelAlbumAPIForWiredTransfer()
|
||
let oss = WiredTransferMockOSSUploadService()
|
||
await viewModel.start(api: api, ossService: oss, scenicID: 1, accountContext: account)
|
||
|
||
XCTAssertEqual(viewModel.photos.first?.id, photoID)
|
||
XCTAssertEqual(viewModel.photos.first?.status, .failed)
|
||
|
||
await viewModel.retryPhoto(id: photoID, api: api, ossService: oss, scenicID: 1)
|
||
try await Task.sleep(nanoseconds: 500_000_000)
|
||
|
||
XCTAssertEqual(viewModel.photos.first?.status, .uploaded)
|
||
}
|
||
|
||
/// 测试指定上传“所有未上传”会恢复本地持久化照片并全部上传。
|
||
func testBatchUploadAllUploadsPersistedPendingFiles() async throws {
|
||
let albumID = 7711
|
||
let userID = "batch-persist-user"
|
||
let account = AccountContext()
|
||
account.applyLogin(profile: AccountProfile(userId: userID, displayName: "测试"))
|
||
|
||
let fileURLs = try (1 ... 5).map { index in
|
||
let scope = downloadScope(account: account, albumID: albumID)
|
||
let url = CameraDownloadStorage.uniqueLocalURL(for: "batch_persist_\(index).JPG", scope: scope)
|
||
try Data(repeating: UInt8(0xA0 + index), count: 32).write(to: url)
|
||
return url
|
||
}
|
||
defer {
|
||
CameraDownloadStorage.removeScopeDirectory(for: downloadScope(account: account, albumID: albumID))
|
||
}
|
||
|
||
let records = fileURLs.enumerated().map { offset, url in
|
||
let index = offset + 1
|
||
return makePhotoRecord(
|
||
id: "batch_persist_\(index)",
|
||
fileName: "batch_persist_\(index).JPG",
|
||
localPath: CameraDownloadStorage.relativePath(for: url),
|
||
albumID: albumID,
|
||
userID: userID
|
||
)
|
||
}
|
||
let store = WiredTransferPhotoStore(
|
||
accountPrefixProvider: { account.accountCachePrefix ?? "guest_" },
|
||
userIDProvider: { userID }
|
||
)
|
||
store.save(albumID: albumID, records: records)
|
||
|
||
let viewModel = WiredCameraTransferViewModel(
|
||
context: WiredTransferContext(albumId: albumID, albumName: "批量上传", phone: "", orderNumber: "")
|
||
)
|
||
let oss = WiredTransferMockOSSUploadService()
|
||
oss.uploadDelayNanoseconds = 150_000_000
|
||
await viewModel.start(
|
||
api: MockTravelAlbumAPIForWiredTransfer(),
|
||
ossService: oss,
|
||
scenicID: 1,
|
||
accountContext: account
|
||
)
|
||
|
||
XCTAssertEqual(viewModel.photos.filter(\.isNotUploaded).count, 5)
|
||
|
||
await viewModel.batchUploadAll(
|
||
api: MockTravelAlbumAPIForWiredTransfer(),
|
||
ossService: oss,
|
||
scenicID: 1
|
||
)
|
||
|
||
XCTAssertEqual(Set(oss.uploadedFileNames), Set((1 ... 5).map { "batch_persist_\($0).JPG" }))
|
||
XCTAssertGreaterThan(oss.maxActiveUploads, 1)
|
||
XCTAssertLessThanOrEqual(oss.maxActiveUploads, 3)
|
||
XCTAssertTrue(viewModel.photos.allSatisfy { $0.status == .uploaded })
|
||
}
|
||
|
||
/// 测试切换传输模式后会按账号缓存选项。
|
||
func testSelectTransferModePersistsOption() async {
|
||
let account = makeTransferModeTestAccount()
|
||
let store = makeTransferModeTestStore(account: account)
|
||
let viewModel = WiredCameraTransferViewModel(
|
||
context: WiredTransferContext(albumId: 1, albumName: "相册", phone: "", orderNumber: "")
|
||
)
|
||
await viewModel.start(
|
||
api: MockTravelAlbumAPIForWiredTransfer(),
|
||
ossService: WiredTransferMockOSSUploadService(),
|
||
scenicID: 1,
|
||
accountContext: account
|
||
)
|
||
|
||
viewModel.selectTransferMode(
|
||
WiredCameraTransferViewModel.modePostShootTransfer,
|
||
api: MockTravelAlbumAPIForWiredTransfer(),
|
||
ossService: WiredTransferMockOSSUploadService(),
|
||
scenicID: 1
|
||
)
|
||
|
||
XCTAssertEqual(store.loadTransferModeOption(), WiredCameraTransferViewModel.modePostShootTransfer)
|
||
}
|
||
|
||
/// 测试进入页面时会恢复缓存的传输模式。
|
||
func testStartRestoresCachedTransferModeOption() async {
|
||
let account = makeTransferModeTestAccount()
|
||
let store = makeTransferModeTestStore(account: account)
|
||
store.saveTransferModeOption(WiredCameraTransferViewModel.modePostShootTransfer)
|
||
|
||
let viewModel = WiredCameraTransferViewModel(
|
||
context: WiredTransferContext(albumId: 1, albumName: "相册", phone: "", orderNumber: "")
|
||
)
|
||
await viewModel.start(
|
||
api: MockTravelAlbumAPIForWiredTransfer(),
|
||
ossService: WiredTransferMockOSSUploadService(),
|
||
scenicID: 1,
|
||
accountContext: account
|
||
)
|
||
|
||
XCTAssertEqual(viewModel.transferModeOption, WiredCameraTransferViewModel.modePostShootTransfer)
|
||
}
|
||
|
||
/// 测试旧记录没有缩略图时列表先占位,但仍保留原图预览能力。
|
||
func testLegacyRecordWithoutThumbnailKeepsPreviewURL() async throws {
|
||
let albumID = 6602
|
||
let account = AccountContext()
|
||
account.applyLogin(profile: AccountProfile(userId: "legacy-user", displayName: "测试"))
|
||
let scope = downloadScope(account: account, albumID: albumID)
|
||
let fileURL = CameraDownloadStorage.uniqueLocalURL(for: "legacy_only.JPG", scope: scope)
|
||
try makeJPEGData().write(to: fileURL)
|
||
defer { CameraDownloadStorage.removeScopeDirectory(for: scope) }
|
||
|
||
let record = WiredTransferPhotoRecord(
|
||
id: "legacy_photo_001",
|
||
sourceId: "legacy_photo_001",
|
||
fileName: "legacy_only.JPG",
|
||
localPath: CameraDownloadStorage.relativePath(for: fileURL),
|
||
thumbnailPath: "",
|
||
capturedAt: "2026-05-20 12:05:18",
|
||
fileSizeBytes: 128,
|
||
status: WiredTransferUploadStatus.pending.rawValue,
|
||
progress: 0,
|
||
errorMessage: nil,
|
||
albumId: albumID,
|
||
userId: "legacy-user",
|
||
remoteURL: "",
|
||
updatedAt: Date().timeIntervalSince1970
|
||
)
|
||
let store = WiredTransferPhotoStore(
|
||
accountPrefixProvider: { account.accountCachePrefix ?? "guest_" },
|
||
userIDProvider: { "legacy-user" }
|
||
)
|
||
store.save(albumID: albumID, records: [record])
|
||
|
||
let viewModel = WiredCameraTransferViewModel(
|
||
context: WiredTransferContext(albumId: albumID, albumName: "旧记录", phone: "", orderNumber: "")
|
||
)
|
||
await viewModel.start(
|
||
api: MockTravelAlbumAPIForWiredTransfer(),
|
||
ossService: WiredTransferMockOSSUploadService(),
|
||
scenicID: 1,
|
||
accountContext: account
|
||
)
|
||
|
||
let photo = try XCTUnwrap(viewModel.photos.first)
|
||
XCTAssertEqual(photo.thumbnailURL, "")
|
||
XCTAssertFalse(photo.previewURL.isEmpty)
|
||
}
|
||
|
||
/// 测试清空相册时只删除当前账号当前相册的物理目录。
|
||
func testClearAlbumRemovesOnlyCurrentAlbumScopedDirectory() throws {
|
||
let userID = "clear-scope-user"
|
||
let account = AccountContext()
|
||
account.applyLogin(profile: AccountProfile(userId: userID, displayName: "测试"), accountType: "store")
|
||
let albumID = 8801
|
||
let otherAlbumID = 8802
|
||
let scope = downloadScope(account: account, albumID: albumID)
|
||
let otherScope = downloadScope(account: account, albumID: otherAlbumID)
|
||
let scopeDirectoryPath = CameraDownloadStorage.scopeDirectory(for: scope).path
|
||
let otherScopeDirectoryPath = CameraDownloadStorage.scopeDirectory(for: otherScope).path
|
||
defer {
|
||
CameraDownloadStorage.removeScopeDirectory(for: scope)
|
||
CameraDownloadStorage.removeScopeDirectory(for: otherScope)
|
||
}
|
||
|
||
let storeURL = CameraDownloadStorage.uniqueLocalURL(for: "store_photo.JPG", scope: scope)
|
||
let otherURL = CameraDownloadStorage.uniqueLocalURL(for: "other_photo.JPG", scope: otherScope)
|
||
try makeJPEGData().write(to: storeURL)
|
||
try makeJPEGData().write(to: otherURL)
|
||
|
||
let store = WiredTransferPhotoStore(
|
||
accountPrefixProvider: { account.accountCachePrefix ?? "guest_" },
|
||
userIDProvider: { userID }
|
||
)
|
||
store.save(albumID: albumID, records: [
|
||
makePhotoRecord(
|
||
id: "store_photo",
|
||
fileName: "store_photo.JPG",
|
||
localPath: CameraDownloadStorage.relativePath(for: storeURL),
|
||
albumID: albumID,
|
||
userID: userID
|
||
)
|
||
])
|
||
store.clearAlbum(albumID: albumID)
|
||
|
||
XCTAssertFalse(FileManager.default.fileExists(atPath: scopeDirectoryPath))
|
||
XCTAssertTrue(FileManager.default.fileExists(atPath: otherScopeDirectoryPath))
|
||
}
|
||
|
||
/// 测试同手机号不同账号类型的本地记录与物理目录隔离。
|
||
func testSameUserIDDifferentAccountTypesAreIsolated() throws {
|
||
let userID = "same-user-id"
|
||
let albumID = 9901
|
||
|
||
let storeAccount = AccountContext()
|
||
storeAccount.applyLogin(profile: AccountProfile(userId: userID, displayName: "门店"), accountType: "store")
|
||
let photographerAccount = AccountContext()
|
||
photographerAccount.applyLogin(profile: AccountProfile(userId: userID, displayName: "摄影师"), accountType: "photographer")
|
||
|
||
let storeScope = downloadScope(account: storeAccount, albumID: albumID)
|
||
let photographerScope = downloadScope(account: photographerAccount, albumID: albumID)
|
||
defer {
|
||
CameraDownloadStorage.removeScopeDirectory(for: storeScope)
|
||
CameraDownloadStorage.removeScopeDirectory(for: photographerScope)
|
||
}
|
||
|
||
let storeURL = CameraDownloadStorage.uniqueLocalURL(for: "store_photo.JPG", scope: storeScope)
|
||
let photographerURL = CameraDownloadStorage.uniqueLocalURL(for: "photographer_photo.JPG", scope: photographerScope)
|
||
try makeJPEGData().write(to: storeURL)
|
||
try makeJPEGData().write(to: photographerURL)
|
||
|
||
let storeStore = WiredTransferPhotoStore(
|
||
accountPrefixProvider: { storeAccount.accountCachePrefix ?? "guest_" },
|
||
userIDProvider: { userID }
|
||
)
|
||
let photographerStore = WiredTransferPhotoStore(
|
||
accountPrefixProvider: { photographerAccount.accountCachePrefix ?? "guest_" },
|
||
userIDProvider: { userID }
|
||
)
|
||
storeStore.save(albumID: albumID, records: [
|
||
makePhotoRecord(
|
||
id: "store_photo",
|
||
fileName: "store_photo.JPG",
|
||
localPath: CameraDownloadStorage.relativePath(for: storeURL),
|
||
albumID: albumID,
|
||
userID: userID
|
||
)
|
||
])
|
||
photographerStore.save(albumID: albumID, records: [
|
||
makePhotoRecord(
|
||
id: "photographer_photo",
|
||
fileName: "photographer_photo.JPG",
|
||
localPath: CameraDownloadStorage.relativePath(for: photographerURL),
|
||
albumID: albumID,
|
||
userID: userID
|
||
)
|
||
])
|
||
|
||
XCTAssertEqual(storeStore.load(albumID: albumID).map(\.id), ["store_photo"])
|
||
XCTAssertEqual(photographerStore.load(albumID: albumID).map(\.id), ["photographer_photo"])
|
||
XCTAssertNotEqual(
|
||
CameraDownloadStorage.scopeDirectory(for: storeScope).path,
|
||
CameraDownloadStorage.scopeDirectory(for: photographerScope).path
|
||
)
|
||
}
|
||
|
||
private func makeViewModelWithPendingPhotos() -> WiredCameraTransferViewModel {
|
||
let viewModel = WiredCameraTransferViewModel(
|
||
context: WiredTransferContext(albumId: 1, albumName: "相册", phone: "", orderNumber: "")
|
||
)
|
||
viewModel.replacePhotos([
|
||
makePendingPhoto(id: "pending-1", capturedAt: "2026-05-20 12:05:18"),
|
||
makePendingPhoto(id: "pending-2", capturedAt: "2026-05-20 12:18:06"),
|
||
WiredTransferPhotoItem(
|
||
id: "uploaded-1",
|
||
fileName: "uploaded.JPG",
|
||
thumbnailURL: "",
|
||
previewURL: "",
|
||
capturedAt: "2026-05-20 12:20:00",
|
||
fileSizeText: "1 MB",
|
||
status: .uploaded
|
||
),
|
||
])
|
||
return viewModel
|
||
}
|
||
|
||
private func makePendingPhoto(id: String, capturedAt: String) -> WiredTransferPhotoItem {
|
||
WiredTransferPhotoItem(
|
||
id: id,
|
||
fileName: "\(id).JPG",
|
||
thumbnailURL: "",
|
||
capturedAt: capturedAt,
|
||
fileSizeText: "1 MB",
|
||
status: .pending
|
||
)
|
||
}
|
||
|
||
private func makePhotoRecord(
|
||
id: String,
|
||
fileName: String,
|
||
localPath: String,
|
||
albumID: Int,
|
||
userID: String,
|
||
status: WiredTransferUploadStatus = .pending
|
||
) -> WiredTransferPhotoRecord {
|
||
WiredTransferPhotoRecord(
|
||
id: id,
|
||
sourceId: id,
|
||
fileName: fileName,
|
||
localPath: localPath,
|
||
thumbnailPath: "",
|
||
capturedAt: "2026-05-20 12:05:18",
|
||
fileSizeBytes: 32,
|
||
status: status.rawValue,
|
||
progress: 0,
|
||
errorMessage: nil,
|
||
albumId: albumID,
|
||
userId: userID,
|
||
remoteURL: "",
|
||
updatedAt: Date().timeIntervalSince1970
|
||
)
|
||
}
|
||
|
||
private func makeJPEGData() -> Data {
|
||
let renderer = UIGraphicsImageRenderer(size: CGSize(width: 8, height: 8))
|
||
return renderer.jpegData(withCompressionQuality: 0.9) { context in
|
||
UIColor.systemBlue.setFill()
|
||
context.fill(CGRect(x: 0, y: 0, width: 8, height: 8))
|
||
}
|
||
}
|
||
|
||
private func downloadScope(account: AccountContext, albumID: Int) -> CameraDownloadStorage.Scope {
|
||
CameraDownloadStorage.Scope(accountKey: account.accountCachePrefix ?? "guest_", albumID: albumID)
|
||
}
|
||
}
|
||
|
||
@MainActor
|
||
private final class MockTravelAlbumAPIForWiredTransfer: TravelAlbumServing {
|
||
func availableOrders() async throws -> [TravelAlbumAvailableOrder] { [] }
|
||
func createAlbum(_ request: TravelAlbumCreateRequest) async throws -> TravelAlbumCreateResponse {
|
||
TravelAlbumCreateResponse(id: 1)
|
||
}
|
||
func albumList(page: Int, pageSize: Int) async throws -> ListPayload<TravelAlbumItem> {
|
||
ListPayload(total: 0, list: [])
|
||
}
|
||
func albumInfo(id: Int) async throws -> TravelAlbumItem { throw APIError.emptyData }
|
||
func editAlbum(_ request: TravelAlbumEditRequest) async throws {}
|
||
func deleteAlbum(_ request: TravelAlbumDeleteRequest) async throws {}
|
||
func materialList(
|
||
userEquityTravelId: Int,
|
||
page: Int,
|
||
pageSize: Int,
|
||
orderBy: Int,
|
||
isPurchased: Int?
|
||
) async throws -> ListPayload<TravelAlbumMaterial> {
|
||
ListPayload(total: 0, list: [])
|
||
}
|
||
func uploadMaterial(_ request: TravelAlbumUploadMaterialRequest) async throws -> TravelAlbumMaterial {
|
||
let data = Data(
|
||
#"{"code":100000,"msg":"success","data":{"id":"11","user_equity_travel_id":"8","status":"1","order_number":"","user_id":"100","file_name":"DSC_001.JPG","file_type":"2","file_url":"https://cdn/a.jpg","file_size":"2048","cover_url":"","is_purchased":"0","created_at":"2026","updated_at":"2026"}}"#.utf8
|
||
)
|
||
let envelope = try JSONDecoder().decode(APIEnvelope<TravelAlbumMaterial>.self, from: data)
|
||
return try XCTUnwrap(envelope.data)
|
||
}
|
||
func deleteMaterial(_ request: TravelAlbumDeleteMaterialRequest) async throws {}
|
||
func mpCode(id: Int) async throws -> TravelAlbumMpCodeResponse {
|
||
TravelAlbumMpCodeResponse(mpCodeOssURL: "")
|
||
}
|
||
}
|
||
|
||
@MainActor
|
||
private final class WiredTransferMockOSSUploadService: OSSUploadServing {
|
||
private(set) var uploadedFileNames: [String] = []
|
||
var uploadDelayNanoseconds: UInt64 = 0
|
||
private(set) var activeUploads = 0
|
||
private(set) var maxActiveUploads = 0
|
||
|
||
func uploadUserAvatar(data: Data, fileName: String, scenicId: Int, onProgress: @escaping (Int) -> Void) async throws -> String { "" }
|
||
func uploadRealNameImage(data: Data, fileName: String, scenicId: Int, onProgress: @escaping (Int) -> Void) async throws -> String { "" }
|
||
func uploadCloudFile(data: Data, fileName: String, fileType: Int, scenicId: Int, onProgress: @escaping (Int) -> Void) async throws -> String { "" }
|
||
func uploadAlbumFile(data: Data, fileName: String, fileType: Int, scenicId: Int, onProgress: @escaping (Int) -> Void) async throws -> String {
|
||
activeUploads += 1
|
||
maxActiveUploads = max(maxActiveUploads, activeUploads)
|
||
if uploadDelayNanoseconds > 0 {
|
||
try await Task.sleep(nanoseconds: uploadDelayNanoseconds)
|
||
}
|
||
activeUploads -= 1
|
||
uploadedFileNames.append(fileName)
|
||
onProgress(100)
|
||
return "https://cdn/mock/\(fileName)"
|
||
}
|
||
func uploadTaskFile(data: Data, fileName: String, fileType: Int, scenicId: Int, onProgress: @escaping (Int) -> Void) async throws -> String { "" }
|
||
func uploadProjectImage(data: Data, fileName: String, scenicId: Int, onProgress: @escaping (Int) -> Void) async throws -> String { "" }
|
||
func uploadPunchPointImage(data: Data, fileName: String, scenicId: Int, onProgress: @escaping (Int) -> Void) async throws -> String { "" }
|
||
func uploadScenicApplicationImage(data: Data, fileName: String, scenicId: Int, onProgress: @escaping (Int) -> Void) async throws -> String { "" }
|
||
func uploadBankCardImage(data: Data, fileName: String, scenicId: Int, onProgress: @escaping (Int) -> Void) async throws -> String { "" }
|
||
}
|
||
|
||
@MainActor
|
||
private func makeTransferModeTestAccount() -> AccountContext {
|
||
let account = AccountContext()
|
||
account.applyLogin(profile: AccountProfile(userId: "transfer-mode-user", displayName: "测试"))
|
||
return account
|
||
}
|
||
|
||
@MainActor
|
||
private func makeTransferModeTestStore(account: AccountContext) -> WiredTransferPhotoStore {
|
||
WiredTransferPhotoStore(
|
||
accountPrefixProvider: { account.accountCachePrefix ?? "guest_" },
|
||
userIDProvider: { account.profile?.userId ?? "" }
|
||
)
|
||
}
|