TeraFoodDecimalEntryTests.swift (6559B)
1 import Foundation 2 @testable import TeraApp 3 import XCTest 4 5 final class TeraFoodDecimalEntryTests: XCTestCase { 6 func testExactLocaleTranslationNeverRoundsOrInfersUnits() { 7 for (locale, raw, expected) in [ 8 ("fr_FR", "0004,500", "4.5"), ("de_DE", "0,000000000000000000000000001", "0.000000000000000000000000001"), 9 ("en_US", "12345678901234567890.12345678", "12345678901234567890.12345678"), 10 ("en_US", "000.000", "0"), ("ar_EG", "٤٫٥٠", "4.5"), ("fa_IR", "۱۲٫۵۰", "12.5"), 11 ("fr_FR", "4.5", "4.5"), ("en_US", "9.9900", "9.99"), 12 ] { 13 XCTAssertEqual(TeraFoodDecimalEntry.canonicalOrRaw(raw, locale: Locale(identifier: locale)), expected, raw) 14 } 15 } 16 17 func testIncompleteOrAmbiguousEntriesStayUnchangedForSharedValidation() { 18 for raw in ["", "-", "1,", ",5", "1.000,5", "1,000.5", "1,2,3", "1 000", "1\u{202F}000", "1e3", "+1", " 1 ", "⅕", "²"] { 19 XCTAssertEqual(TeraFoodDecimalEntry.canonicalOrRaw(raw, locale: Locale(identifier: "fr_FR")), raw) 20 } 21 XCTAssertNil(TeraFoodDecimalEntry.canonicalOrRaw(nil, locale: Locale(identifier: "en_US"))) 22 XCTAssertEqual(TeraFoodDecimalEntry.canonicalOrRaw("1,5", locale: Locale(identifier: "en_US")), "1,5") 23 } 24 25 func testOnlyFoodAmountsAreTranslatedAndContractFieldsArePreserved() { 26 var form = TeraAddForm.empty(.createFoodAvailability) 27 form.priceAmount = "4,50" 28 form.quantity = "0002,00" 29 form.unit = "bag" 30 form.currency = "ZZZ" 31 form.foodStatus = "sold" 32 var expected = form 33 expected.priceAmount = "4.5" 34 expected.quantity = "2" 35 XCTAssertEqual(TeraFoodDecimalEntry.form(form, locale: Locale(identifier: "fr_FR")), expected) 36 form.commandType = .createUpdate 37 XCTAssertEqual(TeraFoodDecimalEntry.form(form, locale: Locale(identifier: "fr_FR")), form) 38 } 39 } 40 41 extension TeraAddStoreTests { 42 @MainActor 43 func testAutomaticRevisionPreservationKeepsRawEntryAndItsRetryInterlock() async throws { 44 let backend = AddBackend() 45 let client = try await Self.startedClient(backend) 46 let store = TeraAddStore(runtimeClient: client, initialType: .createFoodAvailability) 47 await store.configure(snapshot: backend.snapshot()) 48 await store.start() 49 configure(store, type: .createFoodAvailability) 50 let original = try await backend.saveAddIntent(input: TeraAddRuntimeInput(form: store.form, media: []), 51 existingDraftID: nil, expectedRevision: nil) 52 await store.retractAndRevise(Self.card(localOperationID: original.id)) 53 store.updateForm(\.priceAmount, "4.50") 54 await backend.failNextRevisionReceipt() 55 store.newDraft(type: .createUpdate) 56 await TeraScopeFixtures.eventually { !store.protection.isWorking } 57 XCTAssertTrue(store.protection.failed) 58 XCTAssertTrue(store.revisionPreparation.isCaptured) 59 XCTAssertEqual(store.form.priceAmount, "4.50") 60 store.protection.retry() 61 await TeraScopeFixtures.eventually { !store.protection.isWorking } 62 XCTAssertFalse(store.protection.failed) 63 XCTAssertEqual(store.form.commandType, .createUpdate) 64 let retained = await backend.values 65 XCTAssertEqual(retained.values.first(where: \.isRevision)?.form?.priceAmount, "4.50") 66 let count = await backend.revisionPlanCount() 67 XCTAssertEqual(count, 1) 68 store.stop() 69 _ = try await client.stop() 70 } 71 72 @MainActor 73 func testFoodRevisionSaveTranslatesOnceAndLostReceiptRetainsExactAmounts() async throws { 74 let backend = AddBackend() 75 let client = try await Self.startedClient(backend) 76 let store = TeraAddStore(runtimeClient: client, initialType: .createFoodAvailability) 77 await store.configure(snapshot: backend.snapshot()) 78 await store.start() 79 configure(store, type: .createFoodAvailability) 80 let original = try await backend.saveAddIntent(input: TeraAddRuntimeInput(form: store.form, media: []), 81 existingDraftID: nil, expectedRevision: nil) 82 await store.retractAndRevise(Self.card(localOperationID: original.id)) 83 store.updateForm(\.priceAmount, "4,50") 84 store.updateForm(\.quantity, "002,00") 85 await backend.failNextRevisionReceipt() 86 await store.save(locale: Locale(identifier: "fr_FR")) 87 XCTAssertTrue(store.revisionPreparation.isCaptured) 88 XCTAssertEqual(store.form.priceAmount, "4.5") 89 XCTAssertEqual(store.form.quantity, "2") 90 store.updateForm(\.priceAmount, "9,00") 91 await store.save(locale: Locale(identifier: "en_US")) 92 XCTAssertTrue(store.activeDraft?.isRevision == true) 93 XCTAssertEqual(store.activeDraft?.form?.priceAmount, "4.5") 94 XCTAssertEqual(store.activeDraft?.form?.quantity, "2") 95 let count = await backend.revisionPlanCount() 96 XCTAssertEqual(count, 1) 97 store.stop() 98 _ = try await client.stop() 99 } 100 101 @MainActor 102 func testFoodDraftStaysRawUntilNewSubmitAndRetryRetainsCapturedAmounts() async throws { 103 let backend = AddBackend() 104 let client = try await Self.startedClient(backend) 105 let store = TeraAddStore(runtimeClient: client, initialType: .createFoodAvailability) 106 await store.configure(snapshot: backend.snapshot()) 107 await store.start() 108 configure(store, type: .createFoodAvailability) 109 store.updateForm(\.priceAmount, "4,50") 110 store.updateForm(\.quantity, "002,00") 111 await store.save() 112 XCTAssertEqual(store.savedComposer?.form.priceAmount, "4,50") 113 XCTAssertEqual(store.form.quantity, "002,00") 114 await store.submit(locale: Locale(identifier: "fr_FR")) 115 let captured = try XCTUnwrap(store.submissions.status?.captured) 116 XCTAssertEqual(captured.form.priceAmount, "4.5") 117 XCTAssertEqual(captured.form.quantity, "2") 118 XCTAssertEqual(captured.form.editingValue, store.form) 119 store.updateForm(\.priceAmount, "9,00") 120 await store.submit(locale: Locale(identifier: "en_US")) 121 XCTAssertEqual(store.submissions.status?.captured, captured) 122 XCTAssertEqual(store.form.priceAmount, "9,00") 123 store.newDraft(type: .createFoodAvailability) 124 await TeraScopeFixtures.eventually { !store.protection.isWorking } 125 configure(store, type: .createFoodAvailability) 126 store.updateForm(\.priceAmount, "4,50") 127 store.updateForm(\.quantity, "002,00") 128 await store.submit(locale: Locale(identifier: "fr_FR")) 129 let next = try XCTUnwrap(store.submissions.status?.captured) 130 XCTAssertNotEqual(next.id, captured.id) 131 XCTAssertNotEqual(next.form.identifier, captured.form.identifier) 132 XCTAssertEqual(next.form.priceAmount, captured.form.priceAmount) 133 store.stop() 134 _ = try await client.stop() 135 } 136 }