Add TravelAlbum, ProfileSpace, and wired camera transfer modules.
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>
This commit is contained in:
124
suixinkanTests/TravelAlbum/TravelAlbumViewModelTests.swift
Normal file
124
suixinkanTests/TravelAlbum/TravelAlbumViewModelTests.swift
Normal file
@ -0,0 +1,124 @@
|
||||
//
|
||||
// TravelAlbumViewModelTests.swift
|
||||
// suixinkanTests
|
||||
//
|
||||
// Created by Codex on 2026/6/29.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import suixinkan
|
||||
|
||||
@MainActor
|
||||
/// 旅拍相册 ViewModel 测试。
|
||||
final class TravelAlbumViewModelTests: XCTestCase {
|
||||
/// 测试先拍再买模式缺少单价时创建失败。
|
||||
func testCreatePreShootRequiresSinglePrice() async {
|
||||
let viewModel = TravelAlbumEntryViewModel()
|
||||
let api = MockTravelAlbumAPI()
|
||||
|
||||
let success = await viewModel.confirmCreateTask(
|
||||
api: api,
|
||||
mode: TravelAlbumEntryViewModel.modePreShoot,
|
||||
freeCount: "3",
|
||||
singlePrice: "",
|
||||
packagePrice: "99",
|
||||
order: nil,
|
||||
scenicSelected: true
|
||||
)
|
||||
|
||||
XCTAssertFalse(success)
|
||||
XCTAssertEqual(viewModel.errorMessage, "请输入单张照片价格")
|
||||
XCTAssertEqual(api.createCallCount, 0)
|
||||
}
|
||||
|
||||
/// 测试买了再拍模式缺少订单时创建失败。
|
||||
func testCreatePreOrderRequiresOrder() async {
|
||||
let viewModel = TravelAlbumEntryViewModel()
|
||||
let api = MockTravelAlbumAPI()
|
||||
|
||||
let success = await viewModel.confirmCreateTask(
|
||||
api: api,
|
||||
mode: TravelAlbumEntryViewModel.modePreOrder,
|
||||
freeCount: "",
|
||||
singlePrice: "",
|
||||
packagePrice: "",
|
||||
order: nil,
|
||||
scenicSelected: true
|
||||
)
|
||||
|
||||
XCTAssertFalse(success)
|
||||
XCTAssertEqual(viewModel.errorMessage, "请选择绑定订单")
|
||||
}
|
||||
|
||||
/// 测试创建成功后刷新列表。
|
||||
func testCreateSuccessReloadsList() async {
|
||||
let viewModel = TravelAlbumEntryViewModel()
|
||||
let api = MockTravelAlbumAPI()
|
||||
|
||||
let success = await viewModel.confirmCreateTask(
|
||||
api: api,
|
||||
mode: TravelAlbumEntryViewModel.modePreShoot,
|
||||
freeCount: "3",
|
||||
singlePrice: "9.9",
|
||||
packagePrice: "99",
|
||||
order: nil,
|
||||
scenicSelected: true
|
||||
)
|
||||
|
||||
XCTAssertTrue(success)
|
||||
XCTAssertEqual(api.createCallCount, 1)
|
||||
XCTAssertEqual(api.listCallCount, 1)
|
||||
}
|
||||
|
||||
/// 测试相册名称按日期递增。
|
||||
func testBuildTodayAlbumNameIncrementsSuffix() {
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateFormat = "yyyy-MM-dd"
|
||||
let today = formatter.string(from: Date())
|
||||
|
||||
let name = TravelAlbumEntryViewModel.buildTodayAlbumName(
|
||||
existingNames: ["\(today)-001", "\(today)-002", "2026-06-28-001"]
|
||||
)
|
||||
XCTAssertTrue(name.hasSuffix("003"))
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private final class MockTravelAlbumAPI: TravelAlbumServing {
|
||||
var createCallCount = 0
|
||||
var listCallCount = 0
|
||||
|
||||
func availableOrders() async throws -> [TravelAlbumAvailableOrder] { [] }
|
||||
|
||||
func createAlbum(_ request: TravelAlbumCreateRequest) async throws -> TravelAlbumCreateResponse {
|
||||
createCallCount += 1
|
||||
return TravelAlbumCreateResponse(id: 9)
|
||||
}
|
||||
|
||||
func albumList(page: Int, pageSize: Int) async throws -> ListPayload<TravelAlbumItem> {
|
||||
listCallCount += 1
|
||||
return 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) async throws -> ListPayload<TravelAlbumMaterial> {
|
||||
ListPayload(total: 0, list: [])
|
||||
}
|
||||
|
||||
func uploadMaterial(_ request: TravelAlbumUploadMaterialRequest) async throws -> TravelAlbumMaterial {
|
||||
throw APIError.emptyData
|
||||
}
|
||||
|
||||
func deleteMaterial(_ request: TravelAlbumDeleteMaterialRequest) async throws {}
|
||||
|
||||
func mpCode(id: Int) async throws -> TravelAlbumMpCodeResponse {
|
||||
TravelAlbumMpCodeResponse(mpCodeOssURL: "")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user