Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 154 additions & 0 deletions Domain/Tests/ExpenseValidationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -178,4 +178,158 @@ struct ExpenseValidationTests {
// when / then - 에러가 발생하지 않아야 함
try expense.validate()
}

// MARK: - ExpenseInput Validation Tests (TC-037, TC-038)

@Test("TC-037: ExpenseInput - 모든 필드 유효")
func validExpenseInput() throws {
let input = ExpenseInput(
title: "점심 식사",
amount: 50000.0,
currency: "KRW",
expenseDate: Date(),
category: .foodAndDrink,
payerId: "user1",
participantIds: ["user1", "user2", "user3"]
)

// when / then - 에러가 발생하지 않아야 함
try input.validate()
}

@Test("TC-038: ExpenseInput - 금액 검증 우선순위 확인")
func validationPriority_amountFirst() throws {
// Given - 여러 유효하지 않은 필드: 금액 음수, 제목 비어있음, 참가자 없음
let input = ExpenseInput(
title: "",
amount: -1000.0,
currency: "KRW",
expenseDate: Date(),
category: .foodAndDrink,
payerId: "user1",
participantIds: []
)

// When / Then - 금액 검증이 먼저 실행되어 invalidAmount 에러가 발생해야 함
#expect(throws: ExpenseError.invalidAmount(-1000.0)) {
try input.validate()
}
}

@Test("ExpenseInput - 금액이 0인 경우")
func expenseInput_zeroAmount() throws {
let input = ExpenseInput(
title: "테스트",
amount: 0.0,
currency: "KRW",
expenseDate: Date(),
category: .foodAndDrink,
payerId: "user1",
participantIds: ["user1"]
)

#expect(throws: ExpenseError.invalidAmount(0.0)) {
try input.validate()
}
}

@Test("ExpenseInput - 제목이 빈 문자열인 경우")
func expenseInput_emptyTitle() throws {
let input = ExpenseInput(
title: "",
amount: 10000.0,
currency: "KRW",
expenseDate: Date(),
category: .foodAndDrink,
payerId: "user1",
participantIds: ["user1"]
)

#expect(throws: ExpenseError.emptyTitle) {
try input.validate()
}
}

@Test("ExpenseInput - 제목이 공백만 있는 경우")
func expenseInput_whitespaceOnlyTitle() throws {
let input = ExpenseInput(
title: " ",
amount: 10000.0,
currency: "KRW",
expenseDate: Date(),
category: .foodAndDrink,
payerId: "user1",
participantIds: ["user1"]
)

#expect(throws: ExpenseError.emptyTitle) {
try input.validate()
}
}

@Test("ExpenseInput - 참가자가 없는 경우")
func expenseInput_emptyParticipants() throws {
let input = ExpenseInput(
title: "테스트",
amount: 10000.0,
currency: "KRW",
expenseDate: Date(),
category: .foodAndDrink,
payerId: "user1",
participantIds: []
)

#expect(throws: ExpenseError.invalidParticipants) {
try input.validate()
}
}

@Test("ExpenseInput - 지불자가 참가자 목록에 없는 경우")
func expenseInput_payerNotInParticipants() throws {
let input = ExpenseInput(
title: "테스트",
amount: 10000.0,
currency: "KRW",
expenseDate: Date(),
category: .foodAndDrink,
payerId: "user1",
participantIds: ["user2", "user3"]
)

#expect(throws: ExpenseError.payerNotInParticipants) {
try input.validate()
}
}

@Test("ExpenseInput - 최소 유효 금액 (0.01)")
func expenseInput_minimumValidAmount() throws {
let input = ExpenseInput(
title: "최소 금액",
amount: 0.01,
currency: "KRW",
expenseDate: Date(),
category: .other,
payerId: "user1",
participantIds: ["user1"]
)

// 에러가 발생하지 않아야 함
try input.validate()
}

@Test("ExpenseInput - 매우 큰 금액")
func expenseInput_veryLargeAmount() throws {
let input = ExpenseInput(
title: "대용량 금액",
amount: 999_999_999.99,
currency: "KRW",
expenseDate: Date(),
category: .accommodation,
payerId: "user1",
participantIds: ["user1"]
)

// 에러가 발생하지 않아야 함
try input.validate()
}
}
Loading