field_ios

In-the-field app for Radroots on iOS
git clone https://radroots.dev/git/field_ios.git
Log | Files | Refs | README | LICENSE

TeraCalendarEditingTests.swift (5700B)


      1 import Foundation
      2 @testable import TeraApp
      3 import XCTest
      4 
      5 final class TeraCalendarEditingTests: XCTestCase {
      6   func testCivilComponentsRetainIncompleteInputAndCanonicalizeWithoutDateParsing() throws {
      7     let partial = TeraCivilDateInput(raw: "2024--")
      8     XCTAssertNil(partial.value)
      9     let month = partial.replacing(1, with: "2")
     10     XCTAssertEqual(month, "2024-2-")
     11     let leap = TeraCivilDateInput(raw: month).replacing(2, with: "29")
     12     XCTAssertEqual(leap, "2024-2-29")
     13     XCTAssertEqual(TeraCivilDateInput(raw: leap).canonicalOrRaw, "2024-02-29")
     14     XCTAssertEqual(TeraCivilDateInput(raw: leap).value, try TeraCivilDate(year: 2024, month: 2, day: 29))
     15     XCTAssertNil(TeraCivilDateInput(raw: "2023-02-29").value)
     16     XCTAssertNil(TeraCivilDateInput(raw: "2026-09-05-extra").value)
     17     let arabic = TeraCivilDateInput(raw: "٢٠٢٦-٠٩-").replacing(2, with: "٠٥")
     18     XCTAssertEqual(arabic, "٢٠٢٦-٠٩-٠٥")
     19     XCTAssertEqual(TeraCivilDateInput(raw: arabic).canonicalOrRaw, "2026-09-05")
     20     XCTAssertEqual(TeraCivilDateInput(raw: "2026-09-05").replacing(0, with: "2"), "2-09-05")
     21     XCTAssertNil(TeraCivilDateInput(raw: "--").replacing(0, with: ""))
     22   }
     23 
     24   func testNewFormUsesLocalCivilTodayAndSeparateCheckedInstantDefaults() throws {
     25     let zone = try XCTUnwrap(TimeZone(identifier: "America/Vancouver"))
     26     let form = TeraAddPresentation.newForm(type: .createEvent, identifier: { String(repeating: "a", count: 32) },
     27                                            clock: .fixed(unixSeconds: 1_788_568_200), timeZone: zone)
     28     XCTAssertEqual(form.eventTimezone, "America/Vancouver")
     29     XCTAssertEqual(form.eventStartDate, "2026-09-04")
     30     XCTAssertEqual(form.eventEndDate, "2026-09-05")
     31     XCTAssertEqual(form.eventStartUnixSeconds, 1_788_571_800)
     32     XCTAssertEqual(form.eventEndUnixSeconds, 1_788_575_400)
     33   }
     34 
     35   func testExclusiveNextDayUsesGregorianComponentsAtLeapAndDomainBoundaries() throws {
     36     XCTAssertEqual(try TeraCivilDate(year: 2024, month: 2, day: 28).nextDay?.canonical, "2024-02-29")
     37     XCTAssertEqual(try TeraCivilDate(year: 2024, month: 2, day: 29).nextDay?.canonical, "2024-03-01")
     38     XCTAssertEqual(try TeraCivilDate(year: 1900, month: 2, day: 28).nextDay?.canonical, "1900-03-01")
     39     XCTAssertEqual(try TeraCivilDate(year: 2025, month: 12, day: 31).nextDay?.canonical, "2026-01-01")
     40     XCTAssertNil(try TeraCivilDate(year: 9999, month: 12, day: 31).nextDay)
     41   }
     42 
     43   func testHistoricalSpringGapNeverBecomesANormalizedInstant() throws {
     44     let zone = try XCTUnwrap(TimeZone(identifier: "America/Vancouver"))
     45     let gap = try TeraWallTime(date: TeraCivilDate(year: 2024, month: 3, day: 10), hour: 2, minute: 30)
     46     XCTAssertEqual(gap.instants(in: zone), [])
     47     XCTAssertEqual(TeraWallTime(date: gap.date, hour: 3, minute: 30).instants(in: zone).count, 1)
     48     XCTAssertEqual(TeraWallTime(date: gap.date, hour: 25, minute: 0).instants(in: zone), [])
     49   }
     50 
     51   func testHistoricalOverlapOffersBothExactInstantsWithoutDiscardingSeconds() throws {
     52     let zone = try XCTUnwrap(TimeZone(identifier: "America/Vancouver"))
     53     let wall = try TeraWallTime(date: TeraCivilDate(year: 2024, month: 11, day: 3), hour: 1, minute: 30, second: 17)
     54     let expected: [UInt64] = [1_730_622_617, 1_730_626_217]
     55     XCTAssertEqual(wall.instants(in: zone), expected)
     56     for instant in expected {
     57       XCTAssertEqual(TeraWallTime.from(instant, timeZone: zone)?.instants(in: zone), expected)
     58       let date = try XCTUnwrap(TeraCalendarEditing.pickerInstant(instant))
     59       XCTAssertEqual(TeraCalendarEditing.pickerSeconds(date), instant)
     60     }
     61   }
     62 
     63   func testSkippedLocalDayRemainsAValidCivilDateAndHasNoTimedInstant() throws {
     64     let zone = try XCTUnwrap(TimeZone(identifier: "Pacific/Apia"))
     65     let date = try TeraCivilDate(year: 2011, month: 12, day: 30)
     66     XCTAssertEqual(TeraCivilDateInput(raw: date.canonical).value, date)
     67     XCTAssertEqual(TeraWallTime(date: date, hour: 12, minute: 0).instants(in: zone), [])
     68     XCTAssertEqual(date.nextDay?.canonical, "2011-12-31")
     69   }
     70 
     71   func testUnsupportedUnsignedValuesAndDatesCannotSilentlySeedOrRoundPickers() {
     72     for value: UInt64 in [0, 253_402_300_800, (1 << 53) + 1, .max] {
     73       XCTAssertNil(TeraCalendarEditing.pickerInstant(value))
     74     }
     75     for value in [Double.nan, .infinity, -1, 253_402_300_800] {
     76       XCTAssertNil(TeraCalendarEditing.pickerSeconds(Date(timeIntervalSince1970: value)))
     77     }
     78     var form = TeraAddForm.empty(.createEvent)
     79     TeraCalendarEditing.initialize(&form, now: .max, timeZone: .gmt)
     80     XCTAssertNil(form.eventStartDate)
     81     XCTAssertNil(form.eventEndDate)
     82     XCTAssertNil(form.eventStartUnixSeconds)
     83     XCTAssertNil(form.eventEndUnixSeconds)
     84   }
     85 
     86   @MainActor
     87   func testModeAndZoneChangesPreserveEveryOtherUnsavedField() async throws {
     88     let client = try await TeraScopeFixtures.client(TeraScopeBackend())
     89     let store = TeraAddStore(runtimeClient: client, initialType: .createEvent, clock: .fixed(unixSeconds: 1_788_568_200))
     90     store.updateForm(\.title, "Unsaved harvest")
     91     store.updateForm(\.content, "Unsaved details")
     92     store.updateForm(\.eventStartDate, "2026-09-")
     93     store.updateForm(\.eventEndDate, "2026-09-07")
     94     store.updateForm(\.eventTimezone, "America/Vancouver")
     95     let original = store.form
     96     var expected = original
     97     expected.eventTiming = .allDay
     98     store.updateForm(\.eventTiming, .allDay)
     99     XCTAssertEqual(store.form, expected)
    100     store.updateForm(\.eventTiming, .timed)
    101     XCTAssertEqual(store.form, original)
    102     expected = original
    103     expected.eventTimezone = "Pacific/Kiritimati"
    104     store.updateForm(\.eventTimezone, "Pacific/Kiritimati")
    105     XCTAssertEqual(store.form, expected)
    106     _ = try await client.stop()
    107   }
    108 }