commit ab5e35352d9ab684a1ecfbd03cda1b2f9683f1b4
parent 6ed849e562b2ed7f6da36fc36c79e4daadb8b78d
Author: triesap <tyson@radroots.org>
Date: Sun, 14 Jun 2026 02:37:50 -0700
test: expose document interchange probe
- add a UI-test-only document interchange probe for export import and share contracts
- surface probe results through hidden accessibility state
- include the probe source in the generated Xcode project
Diffstat:
4 files changed, 133 insertions(+), 0 deletions(-)
diff --git a/Radroots.xcodeproj/project.pbxproj b/Radroots.xcodeproj/project.pbxproj
@@ -47,6 +47,7 @@
DCE468F668A3C346E716B04C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CCF0F7B3C57D8D770F178329 /* Assets.xcassets */; };
E1EDAEE6B182025ACAF754A6 /* RadrootsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15DBA726450712D6DE88E951 /* RadrootsProvider.swift */; };
E3864E34D67BAD0744B93180 /* Bundle+Build.swift in Sources */ = {isa = PBXBuildFile; fileRef = 138AA7BAA021EE13E829390B /* Bundle+Build.swift */; };
+ E432FD39ECC8F03764EEED81 /* FieldDocumentInterchangeUITestProbe.swift in Sources */ = {isa = PBXBuildFile; fileRef = EF05B944D348DAA4EF28B463 /* FieldDocumentInterchangeUITestProbe.swift */; };
EB7C19F62D7DAB9C044D53AA /* PostDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3C0EFACAD213A69C12D5064 /* PostDetailView.swift */; };
F32EFF00A8A852F76657FEE1 /* PostCreateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA8AAF0C0F1723860A8481E0 /* PostCreateView.swift */; };
F3E40E5A76B4EA19AC7603D2 /* RadrootsKit in Frameworks */ = {isa = PBXBuildFile; productRef = 2DAD90EBF8EB00ACDD7611CD /* RadrootsKit */; };
@@ -101,6 +102,7 @@
E4F2BDC19EF9435162BFF5EC /* FieldDocumentInterchange.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FieldDocumentInterchange.swift; sourceTree = "<group>"; };
E7F9BFC3C8CE2F86FB7DB74B /* DebugDump.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugDump.swift; sourceTree = "<group>"; };
E883FDB7004A210C9D7BE27A /* FieldRuntimeService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FieldRuntimeService.swift; sourceTree = "<group>"; };
+ EF05B944D348DAA4EF28B463 /* FieldDocumentInterchangeUITestProbe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FieldDocumentInterchangeUITestProbe.swift; sourceTree = "<group>"; };
F21554DA87EEC1E5C5F38365 /* PostFeedViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostFeedViewModel.swift; sourceTree = "<group>"; };
F3C0EFACAD213A69C12D5064 /* PostDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostDetailView.swift; sourceTree = "<group>"; };
F4C7DE4207398DE242519F9C /* CopyButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CopyButton.swift; sourceTree = "<group>"; };
@@ -180,6 +182,7 @@
children = (
A71EFADBC7D54AF5B9314773 /* BuildConfig.swift */,
E4F2BDC19EF9435162BFF5EC /* FieldDocumentInterchange.swift */,
+ EF05B944D348DAA4EF28B463 /* FieldDocumentInterchangeUITestProbe.swift */,
491D57E540BAB04F24619737 /* FieldFileAccessUITestProbe.swift */,
CA942715DB13FFD494FD35A0 /* FieldIdentityPublicMetadataStore.swift */,
9EB0A2CFCBBFA9D204C6992B /* FieldLocalState.swift */,
@@ -410,6 +413,7 @@
D3834AF9A4E1327B7DA557F3 /* CopyRow.swift in Sources */,
4025E63F6603011431B8A0E1 /* DebugDump.swift in Sources */,
3FC570AC038C3DC575E5A3E7 /* FieldDocumentInterchange.swift in Sources */,
+ E432FD39ECC8F03764EEED81 /* FieldDocumentInterchangeUITestProbe.swift in Sources */,
7E650F6DA30931E310F842E2 /* FieldFileAccessUITestProbe.swift in Sources */,
D4CFDE54747B6D6957977025 /* FieldIdentityPublicMetadataStore.swift in Sources */,
6E15D30653861F26AC45B501 /* FieldLocalState.swift in Sources */,
diff --git a/Radroots/App/AppEntry.swift b/Radroots/App/AppEntry.swift
@@ -36,6 +36,13 @@ public struct AppEntry<Main: View>: View {
.accessibilityIdentifier("field_ios.file_access.probe")
.accessibilityValue(probeValue)
}
+ if let probeValue = appState.documentInterchangeProbeValue {
+ Color.clear
+ .frame(width: 1, height: 1)
+ .accessibilityElement()
+ .accessibilityIdentifier("field_ios.document_interchange.probe")
+ .accessibilityValue(probeValue)
+ }
}
}
}
diff --git a/Radroots/App/AppState.swift b/Radroots/App/AppState.swift
@@ -42,6 +42,7 @@ public final class AppState: ObservableObject {
@Published public private(set) var relayLight: RelayLight = .red
@Published public private(set) var relayLastError: String?
@Published public private(set) var fileAccessProbeValue: String?
+ @Published public private(set) var documentInterchangeProbeValue: String?
public var canShowAppContent: Bool {
bootstrapPhase == .ready && runtimeIdentityReady && !isLocked
@@ -121,6 +122,7 @@ public final class AppState: ObservableObject {
resetLocalStateRequested: resetLocalStateRequested,
identityResetObserved: false
)
+ try refreshDocumentInterchangeProbe(bundleIdentifier: appBundleIdentifier)
bootstrapPhase = .ready
} catch {
statusTask?.cancel()
@@ -484,6 +486,17 @@ public final class AppState: ObservableObject {
}
}
+ private func refreshDocumentInterchangeProbe(bundleIdentifier: String) throws {
+ documentInterchangeProbeValue = try FieldDocumentInterchangeUITestProbe.startupValue(
+ bundleIdentifier: bundleIdentifier,
+ infoJSONString: infoJSONString,
+ relays: RelaySettings.relays(),
+ connectedCount: relayConnectedCount,
+ connectingCount: relayConnectingCount,
+ lastError: relayLastError
+ )
+ }
+
private func setLocked(_ value: Bool) {
isLocked = value
UserDefaults.standard.set(value, forKey: lockKey)
diff --git a/Radroots/Runtime/FieldDocumentInterchangeUITestProbe.swift b/Radroots/Runtime/FieldDocumentInterchangeUITestProbe.swift
@@ -0,0 +1,109 @@
+import Foundation
+import RadrootsKit
+
+enum FieldDocumentInterchangeUITestProbe {
+ private static let enabledKey = "RADROOTS_FIELD_IOS_UI_TEST_DOCUMENT_INTERCHANGE_PROBE"
+ private static let importFixture = RadrootsFileReference(
+ scope: .temporary,
+ relativePath: "ui_tests/document_interchange/relay_import.json"
+ )
+ private static let invalidImportFixture = RadrootsFileReference(
+ scope: .temporary,
+ relativePath: "ui_tests/document_interchange/invalid_relay_import.json"
+ )
+
+ static var isRequested: Bool {
+ ProcessInfo.processInfo.environment[enabledKey] == "true"
+ }
+
+ static func startupValue(
+ bundleIdentifier: String,
+ infoJSONString: String,
+ relays: [String],
+ connectedCount: UInt32,
+ connectingCount: UInt32,
+ lastError: String?
+ ) throws -> String? {
+ guard isRequested else {
+ return nil
+ }
+ let interchange = try FieldDocumentInterchange(bundleIdentifier: bundleIdentifier)
+ let fileAccess = try FieldLocalState.fileAccess(bundleIdentifier: bundleIdentifier)
+ let diagnosticsExport = try interchange.prepareDiagnosticsExport(
+ infoJSONString: infoJSONString,
+ relays: relays,
+ connectedCount: connectedCount,
+ connectingCount: connectingCount,
+ lastError: lastError
+ )
+ let diagnosticsFileExists = FileManager.default.fileExists(atPath: diagnosticsExport.fileURL.path)
+ try fileAccess.releasePreparedExport(diagnosticsExport)
+ let diagnosticsReleaseRemovedFile = !FileManager.default.fileExists(atPath: diagnosticsExport.fileURL.path)
+ let relayExport = try interchange.prepareRelayConfigExport(relays: relays)
+ let relayExportFileExists = FileManager.default.fileExists(atPath: relayExport.fileURL.path)
+ try fileAccess.releasePreparedExport(relayExport)
+ try fileAccess.write(
+ .inline(relayImportFixtureData()),
+ to: importFixture
+ )
+ let importedRelays = try interchange.importedRelayConfig(from: importFixture)
+ try fileAccess.write(
+ .inline(invalidRelayImportFixtureData()),
+ to: invalidImportFixture
+ )
+ let rejectedInvalidImport = invalidImportWasRejected(interchange)
+ let shareRequest = try interchange.publicPostShareRequest(content: " public field update ")
+ let shareTextTrimmed = shareRequest.items == [.text("public field update")]
+ return [
+ "diagnostics_filename=\(diagnosticsExport.suggestedFilename)",
+ "diagnostics_media_type=\(diagnosticsExport.mediaType ?? "")",
+ "diagnostics_file_exists=\(diagnosticsFileExists)",
+ "diagnostics_release_removed_file=\(diagnosticsReleaseRemovedFile)",
+ "relay_export_filename=\(relayExport.suggestedFilename)",
+ "relay_export_media_type=\(relayExport.mediaType ?? "")",
+ "relay_export_file_exists=\(relayExportFileExists)",
+ "relay_import_count=\(importedRelays.count)",
+ "relay_import_contains_production=\(importedRelays.contains("wss://radroots.org"))",
+ "relay_import_rejected_invalid=\(rejectedInvalidImport)",
+ "share_subject=\(shareRequest.subject ?? "")",
+ "share_text_trimmed=\(shareTextTrimmed)"
+ ].joined(separator: ";")
+ }
+
+ private static func invalidImportWasRejected(_ interchange: FieldDocumentInterchange) -> Bool {
+ do {
+ _ = try interchange.importedRelayConfig(from: invalidImportFixture)
+ return false
+ } catch {
+ return true
+ }
+ }
+
+ private static func relayImportFixtureData() -> Data {
+ Data(
+ """
+ {
+ "format": "radroots_field_ios_relay_config_v1",
+ "relays": [
+ "wss://radroots.org",
+ "ws://127.0.0.1:8080",
+ "wss://radroots.org"
+ ]
+ }
+ """.utf8
+ )
+ }
+
+ private static func invalidRelayImportFixtureData() -> Data {
+ Data(
+ """
+ {
+ "format": "radroots_field_ios_relay_config_v1",
+ "relays": [
+ "https://radroots.org"
+ ]
+ }
+ """.utf8
+ )
+ }
+}