field_ios

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

TeraCalendarTimingTests.swift (5237B)


      1 import Foundation
      2 @testable import TeraApp
      3 import TeraKitBindings
      4 import XCTest
      5 
      6 final class TeraCalendarTimingTests: XCTestCase {
      7   func testGeneratedNativeBuffersPreserveCivilDatesAndExclusiveEnds() throws {
      8     let values: [FfiCalendarTiming] = [
      9       .dateBased(start: FfiCivilDate(year: 1, month: 1, day: 1), endExclusive: nil),
     10       .dateBased(start: FfiCivilDate(year: 2024, month: 2, day: 29), endExclusive: FfiCivilDate(year: 2024, month: 3, day: 1)),
     11       .dateBased(start: FfiCivilDate(year: 2026, month: 9, day: 5), endExclusive: FfiCivilDate(year: 2026, month: 9, day: 7)),
     12       .dateBased(start: FfiCivilDate(year: 9999, month: 12, day: 31), endExclusive: nil),
     13     ]
     14     for value in values {
     15       let restored = try FfiConverterTypeFfiCalendarTiming_lift(FfiConverterTypeFfiCalendarTiming_lower(value))
     16       XCTAssertEqual(restored, value)
     17       guard case let .dateBased(start, end) = restored,
     18             case let .dateBased(nativeStart, nativeEnd) = try restored.appValue()
     19       else { return XCTFail("The generated boundary must retain civil timing.") }
     20       XCTAssertEqual(nativeStart.year, start.year)
     21       XCTAssertEqual(nativeStart.month, start.month)
     22       XCTAssertEqual(nativeStart.day, start.day)
     23       XCTAssertEqual(nativeEnd?.year, end?.year)
     24       XCTAssertEqual(nativeEnd?.month, end?.month)
     25       XCTAssertEqual(nativeEnd?.day, end?.day)
     26     }
     27   }
     28 
     29   func testGeneratedNativeBuffersKeepUnsignedInstantsAndBothZonesWithoutRounding() throws {
     30     for start: UInt64 in [0, (1 << 53) + 1, .max - 1, .max] {
     31       let end = start == .max ? nil : start + 1
     32       for zones in [false, true] {
     33         let value = FfiCalendarTiming.timeBased(
     34           startUnixS: start, endExclusiveUnixS: end,
     35           startTzid: zones ? "America/Vancouver" : nil, endTzid: zones ? "Europe/Paris" : nil
     36         )
     37         let restored = try FfiConverterTypeFfiCalendarTiming_lift(FfiConverterTypeFfiCalendarTiming_lower(value))
     38         XCTAssertEqual(restored, value)
     39         guard case let .timeBased(actualStart, actualEnd, startZone, endZone) = try restored.appValue() else {
     40           return XCTFail("The generated boundary must retain timed values.")
     41         }
     42         XCTAssertEqual(actualStart, start)
     43         XCTAssertEqual(actualEnd, end)
     44         XCTAssertEqual(startZone, zones ? "America/Vancouver" : nil)
     45         XCTAssertEqual(endZone, zones ? "Europe/Paris" : nil)
     46       }
     47     }
     48     XCTAssertNotNil(TeraCalendarTiming.presentationInstant(0))
     49     XCTAssertNotNil(TeraCalendarTiming.presentationInstant(253_402_300_799))
     50     XCTAssertNil(TeraCalendarTiming.presentationInstant(253_402_300_800))
     51     XCTAssertNil(TeraCalendarTiming.presentationInstant(.max))
     52   }
     53 
     54   func testUnsupportedGeneratedDiscriminantsAndTruncatedPayloadsThrow() {
     55     for bytes: [UInt8] in [[0, 0, 0, 99], [0, 0, 0, 1], []] {
     56       var input = (data: Data(bytes), offset: 0)
     57       XCTAssertThrowsError(try FfiConverterTypeFfiCalendarTiming.read(from: &input))
     58     }
     59   }
     60 
     61   func testMalformedNativeTimingAndUnsupportedCardSchemasFailThroughTypedRecovery() throws {
     62     let date = FfiCivilDate(year: 2026, month: 9, day: 5)
     63     let invalid: [FfiCalendarTiming] = [
     64       .dateBased(start: FfiCivilDate(year: 0, month: 1, day: 1), endExclusive: nil),
     65       .dateBased(start: FfiCivilDate(year: 2023, month: 2, day: 29), endExclusive: nil),
     66       .dateBased(start: FfiCivilDate(year: 2024, month: 13, day: 1), endExclusive: nil),
     67       .dateBased(start: date, endExclusive: date),
     68       .timeBased(startUnixS: 2, endExclusiveUnixS: 1, startTzid: nil, endTzid: nil),
     69       .timeBased(startUnixS: 1, endExclusiveUnixS: nil, startTzid: "Mars/Olympus", endTzid: nil),
     70     ]
     71     for timing in invalid {
     72       XCTAssertThrowsError(try timing.appValue()) { error in
     73         XCTAssertEqual(error as? TeraRuntimeFailure, TeraCalendarTiming.unsupported)
     74       }
     75     }
     76     let timing = FfiCalendarTiming.dateBased(start: date, endExclusive: nil)
     77     for version: UInt16 in [0, 1, .max] {
     78       XCTAssertThrowsError(try card(schema: version, timing: timing).appValue())
     79     }
     80     XCTAssertThrowsError(try card(schema: 2, timing: nil).appValue())
     81     let valid = card(schema: 2, timing: timing)
     82     let restored = try FfiConverterTypeFfiTodayCardRecord_lift(FfiConverterTypeFfiTodayCardRecord_lower(valid))
     83     XCTAssertEqual(restored, valid)
     84     XCTAssertEqual(try restored.appValue().calendarTiming, try timing.appValue())
     85   }
     86 
     87   private func card(schema: UInt16, timing: FfiCalendarTiming?) -> FfiTodayCardRecord {
     88     FfiTodayCardRecord(
     89       schemaVersion: schema, cardId: "synthetic-card", cardType: .event, sourceEventId: "synthetic-event",
     90       sourceAddress: nil, authorPublicKey: "synthetic-author", contractId: "synthetic-calendar",
     91       title: "Harvest day", content: "Synthetic calendar", authoredAtUnixS: 1, effectiveAtUnixS: 1,
     92       calendarTiming: timing, location: nil, priceAmount: nil, priceCurrency: nil, priceUnit: nil,
     93       quantity: nil, foodSummary: nil, foodPublishedAtUnixS: nil, foodStatus: nil, contextRank: 1,
     94       inclusionReason: "local", media: [], lifecycle: .active, rankDigest: nil, authorProfile: nil,
     95       thread: [], localSourceDraftId: nil, localOperationId: nil, localOperationState: nil
     96     )
     97   }
     98 }