TeraBindingPortabilityTests.swift (3540B)
1 @testable import TeraApp 2 import TeraKitBindings 3 import XCTest 4 5 final class TeraBindingPortabilityTests: XCTestCase { 6 func testActualCallbacksPreserveUnsignedContextBoundariesAndScope() async throws { 7 let fixture = try MediaOwnershipFixture() 8 defer { fixture.remove() } 9 let runtime = try await fixture.runtime() 10 let pair = AsyncStream.makeStream(of: TeraRuntimeChange.self, bufferingPolicy: .bufferingNewest(8)) 11 let observer = TeraGeneratedRuntimeObserver(continuation: pair.continuation) 12 let handle = try runtime.subscribeChanges(observer: observer) 13 defer { handle.unsubscribe(); observer.finish() } 14 let initial = try await next(pair.stream) 15 XCTAssertEqual(initial.kind, .initial) 16 XCTAssertEqual(initial.epoch.count, 32) 17 for (index, generation) in [UInt64(0), UInt64(1), UInt64(Int64.max) + 1, UInt64.max].enumerated() { 18 let context = context(generation: generation) 19 _ = try await runtime.phase1RefreshToday(context: context, nowUnixS: 1_800_000_000, update: .incremental) 20 let changed = try await next(pair.stream) 21 XCTAssertEqual(changed.scope.publicKey, initial.scope.publicKey) 22 XCTAssertEqual(changed.scope.sourceGeneration, initial.scope.sourceGeneration) 23 XCTAssertEqual(changed.scope.context?.id, context.id) 24 XCTAssertEqual(changed.scope.context?.generation, generation) 25 XCTAssertEqual(changed.epoch, initial.epoch) 26 XCTAssertEqual(changed.revision.rawValue, UInt64(index + 1)) 27 } 28 _ = try await runtime.shutdown() 29 } 30 31 func testInvalidContextErrorsCrossTheGeneratedBoundaryWithoutAnInvalidation() async throws { 32 let fixture = try MediaOwnershipFixture() 33 defer { fixture.remove() } 34 let runtime = try await fixture.runtime() 35 let pair = AsyncStream.makeStream(of: TeraRuntimeChange.self, bufferingPolicy: .bufferingNewest(8)) 36 let observer = TeraGeneratedRuntimeObserver(continuation: pair.continuation) 37 let handle = try runtime.subscribeChanges(observer: observer) 38 defer { handle.unsubscribe(); observer.finish() } 39 _ = try await next(pair.stream) 40 var unsupported = context(generation: 1) 41 unsupported.schemaVersion = .max 42 var invalid = context(generation: 1) 43 invalid.id = "" 44 for (context, code) in [(invalid, "invalid_local_network"), (unsupported, "unsupported_schema_version")] { 45 do { 46 _ = try await runtime.phase1RefreshToday(context: context, nowUnixS: 1_800_000_000, update: .incremental) 47 XCTFail("Invalid context must not be admitted") 48 } catch let TeraAppError.Failure(report) { 49 XCTAssertEqual(report.code, code) 50 } 51 } 52 try await runtime.configurePublicRelays(writableRelays: ["wss://write.example"]) 53 let changed = try await next(pair.stream) 54 XCTAssertEqual(changed.kind, .relay) 55 _ = try await runtime.shutdown() 56 } 57 58 private func context(generation: UInt64) -> FfiLocalNetworkRecord { 59 FfiLocalNetworkRecord(schemaVersion: 1, id: "nearby", label: "Nearby", relayUrls: ["wss://relay.example"], locality: nil, followedAuthors: [], generation: generation) 60 } 61 62 private func next(_ stream: AsyncStream<TeraRuntimeChange>) async throws -> TeraRuntimeChange { 63 let value = await withTaskGroup(of: TeraRuntimeChange?.self) { group in 64 group.addTask { await stream.first { _ in true } } 65 group.addTask { try? await Task.sleep(for: .seconds(5)); return nil } 66 defer { group.cancelAll() } 67 return await group.next() ?? nil 68 } 69 return try XCTUnwrap(value, "Native callback deadline") 70 } 71 }