1
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
import Foundation
|
||||
|
||||
@main
|
||||
struct ExpenseSummaryTests {
|
||||
static func match(_ id: String, category: String, amounts: [String]) -> MatchGroup {
|
||||
var ocr = OCRData()
|
||||
ocr.amounts = amounts
|
||||
let invoice = Material(id: id, name: id, path: "", type: "invoice", size: 0, matched: true,
|
||||
previewPath: "", ocr: ocr, displayAmount: 9999, sortDate: "", issueDate: "")
|
||||
return MatchGroup(id: id, invoices: [invoice], payments: [], category: category,
|
||||
matchType: "manual", score: 100, reasons: [], paymentTotal: 8888, expenseAmount: 7777)
|
||||
}
|
||||
|
||||
static func main() throws {
|
||||
let traffic = (1...6).map { match("traffic-\($0)", category: "交通", amounts: ["100.10"]) }
|
||||
let hotel = match("hotel", category: "住宿", amounts: ["250.20"])
|
||||
let excluded = match("excluded", category: "交通", amounts: ["999"])
|
||||
var workspace = Workspace()
|
||||
workspace.matches = traffic + [hotel, excluded]
|
||||
let selection = MatchedPPTSelection(ids: Set((traffic + [hotel]).map(\.id)))
|
||||
let selected = try selection.exportWorkspace(from: workspace)
|
||||
let rows = ExpenseSummary.rows(for: selected.matches)
|
||||
precondition(rows.count == 2)
|
||||
precondition(rows.map(\.category) == ["交通", "住宿"])
|
||||
precondition(rows[0].groupCount == 6 && rows[0].invoiceCount == 6)
|
||||
precondition(rows[0].amount == Decimal(string: "600.60"))
|
||||
precondition(rows[1].amount == Decimal(string: "250.20"))
|
||||
precondition(workspace.matches.count == 8)
|
||||
var multiple = match("multi", category: "交通", amounts: ["100", "-1,200.30", "5"])
|
||||
multiple.invoices += [hotel.invoices[0]]
|
||||
let combined = ExpenseSummary.rows(for: [multiple])
|
||||
precondition(combined[0].invoiceCount == 2)
|
||||
precondition(combined[0].amount == Decimal(string: "1450.50"))
|
||||
let emptyAmounts = ExpenseSummary.rows(for: [match("empty", category: "", amounts: [])])
|
||||
precondition(emptyAmounts[0].category == "其他" && emptyAmounts[0].amount == .zero)
|
||||
precondition(ExpenseSummary.rows(for: []).isEmpty)
|
||||
let response = try JSONSerialization.data(withJSONObject: ["expenseGrouping": "category-v1", "expenseRowCount": 2])
|
||||
try ExpenseSummary.validateExportResult(response, matches: selected.matches)
|
||||
for result: [String: Any] in [
|
||||
["destination": "/tmp/old-engine.xlsx"],
|
||||
["expenseGrouping": "category-v1", "expenseRowCount": 7],
|
||||
["expenseGrouping": "per-match", "expenseRowCount": 2]
|
||||
] {
|
||||
let data = try JSONSerialization.data(withJSONObject: result)
|
||||
do {
|
||||
try ExpenseSummary.validateExportResult(data, matches: selected.matches)
|
||||
preconditionFailure("Outdated or inconsistent exports must be rejected")
|
||||
} catch {}
|
||||
}
|
||||
print("Selected expense grouping, counts and decimal totals tests passed")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
import Foundation
|
||||
|
||||
final class MemoryPayeeStorage: PayeeStorage {
|
||||
var data: Data?
|
||||
var failRead = false
|
||||
var failWrite = false
|
||||
var failDelete = false
|
||||
|
||||
func read() throws -> Data? {
|
||||
if failRead { throw PayeeFailure(message: "Read failed") }
|
||||
return data
|
||||
}
|
||||
|
||||
func write(_ value: Data) throws {
|
||||
if failWrite { throw PayeeFailure(message: "Write failed") }
|
||||
data = value
|
||||
}
|
||||
|
||||
func delete() throws {
|
||||
if failDelete { throw PayeeFailure(message: "Delete failed") }
|
||||
data = nil
|
||||
}
|
||||
}
|
||||
|
||||
@main
|
||||
struct PayeeProfileTests {
|
||||
@MainActor static func main() throws {
|
||||
let storage = MemoryPayeeStorage()
|
||||
let store = PayeeProfileStore(storage: storage)
|
||||
precondition(store.profile == nil && store.loadError == nil)
|
||||
let empty = try store.exportFields()
|
||||
precondition(empty.isEmpty)
|
||||
precondition((try? PayeeProfile().validated()) == nil)
|
||||
let draft = PayeeProfile(recipient: " 测试收款人 ", bankName: " 测试银行支行 ",
|
||||
accountNumber: " 0012 3456 7890 ", preparer: "")
|
||||
try store.save(draft)
|
||||
precondition(store.profile?.accountNumber == "001234567890")
|
||||
precondition(store.profile?.recipient == "测试收款人")
|
||||
precondition(store.profile?.exportFields["preparer"] == "测试收款人")
|
||||
let restored = PayeeProfileStore(storage: storage)
|
||||
precondition(restored.profile == store.profile)
|
||||
var changed = draft
|
||||
changed.preparer = "测试制单人"
|
||||
try store.save(changed)
|
||||
precondition(store.profile?.exportFields["preparer"] == "测试制单人")
|
||||
let saved = store.profile
|
||||
let savedData = storage.data
|
||||
storage.failWrite = true
|
||||
do {
|
||||
try store.save(draft)
|
||||
preconditionFailure("Failed storage must not report success")
|
||||
} catch {}
|
||||
precondition(store.profile == saved && storage.data == savedData)
|
||||
storage.failWrite = false
|
||||
storage.failDelete = true
|
||||
do {
|
||||
try store.clear()
|
||||
preconditionFailure("Failed delete must retain profile")
|
||||
} catch {}
|
||||
precondition(store.profile == saved)
|
||||
storage.failDelete = false
|
||||
try store.clear()
|
||||
precondition(storage.data == nil && store.profile == nil)
|
||||
try store.save(draft)
|
||||
storage.failRead = true
|
||||
store.reload()
|
||||
precondition(store.profile == nil && store.loadError != nil)
|
||||
precondition((try? store.exportFields()) == nil)
|
||||
precondition((try? store.save(draft)) == nil)
|
||||
storage.failRead = false
|
||||
store.reload()
|
||||
precondition(store.profile != nil && store.loadError == nil)
|
||||
storage.data = Data("corrupt".utf8)
|
||||
store.reload()
|
||||
precondition(store.loadError != nil && store.profile == nil)
|
||||
var invalid = draft
|
||||
invalid.bankName = String(repeating: "行", count: 201)
|
||||
precondition((try? invalid.validated()) == nil)
|
||||
invalid = draft
|
||||
invalid.recipient = "测试\n收款人"
|
||||
precondition((try? invalid.validated()) == nil)
|
||||
print("Payee profile validation, persistence, update, delete and failure tests passed")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user