commit e5761180533e6479015c3c91d70bc525a9f3aab2
parent f6c1afd07c60a04f1bfea18501940a9d24ebfdc5
Author: triesap <tyson@radroots.org>
Date: Tue, 11 Aug 2026 04:26:00 +0000
test: type the integration wire contract
- verify integration compatibility through production expectations
- export lifecycle and session as generated UniFFI enums
- map every bridge state exhaustively without string fallbacks
- preserve integration coverage and release bridge isolation
Diffstat:
3 files changed, 43 insertions(+), 26 deletions(-)
diff --git a/app/desktop/src/integrationTest/kotlin/org/harvestcircle/integration/NativeRuntimeIntegrationTest.kt b/app/desktop/src/integrationTest/kotlin/org/harvestcircle/integration/NativeRuntimeIntegrationTest.kt
@@ -7,6 +7,7 @@ import org.harvestcircle.application.RequestContext
import org.harvestcircle.application.SecretKeyInput
import org.harvestcircle.application.SessionLifecycle
import org.harvestcircle.application.SnapshotRevision
+import org.harvestcircle.application.verifyNativeCompatibility
import org.harvestcircle.ffi.compatibilityDescriptor
import org.harvestcircle.testbridge.ffi.HarvestCircleTestBridge
import org.harvestcircle.testbridge.ffi.TestBridgeException
@@ -81,10 +82,7 @@ class NativeRuntimeIntegrationTest {
val dataRoot = Files.createTempDirectory("harvestcircle-native-integration-")
try {
TestBridgeHarvestCircleRuntime.open(dataRoot.toString()).use { runtime ->
- assertEquals(
- "c7a84960e53cd9df35d676bab28294eb048a8b86c766d81cded2635b64a7f3d6",
- compatibilityDescriptor().contractHash,
- )
+ verifyNativeCompatibility(compatibilityDescriptor())
val initial = runtime.bootstrap()
assertTrue(initial.revision.value > 0UL)
assertTrue(initial.identities.isEmpty())
diff --git a/app/desktop/src/integrationTest/kotlin/org/harvestcircle/integration/TestBridgeHarvestCircleRuntime.kt b/app/desktop/src/integrationTest/kotlin/org/harvestcircle/integration/TestBridgeHarvestCircleRuntime.kt
@@ -42,6 +42,8 @@ import org.harvestcircle.testbridge.ffi.HarvestCircleTestBridge
import org.harvestcircle.testbridge.ffi.TestBridgeException
import org.harvestcircle.testbridge.ffi.TestGeneratedRecoveryRequest
import org.harvestcircle.testbridge.ffi.TestIdentity
+import org.harvestcircle.testbridge.ffi.TestLifecycle
+import org.harvestcircle.testbridge.ffi.TestSession
import org.harvestcircle.testbridge.ffi.TestSnapshot
internal class TestBridgeHarvestCircleRuntime private constructor(
@@ -247,11 +249,11 @@ private fun TestSnapshot.toApplicationSnapshot(): ApplicationSnapshot {
val selected = selectedPublicKeyHex?.let(IdentityId::fromPublicKeyHex)
val mappedSession =
when (session) {
- "signed_out" -> SessionLifecycle.SignedOut
- "activating" -> SessionLifecycle.Activating
- "active" -> SessionLifecycle.Active
- "signing_out" -> SessionLifecycle.SigningOut
- else -> SessionLifecycle.Failed
+ TestSession.SIGNED_OUT -> SessionLifecycle.SignedOut
+ TestSession.ACTIVATING -> SessionLifecycle.Activating
+ TestSession.ACTIVE -> SessionLifecycle.Active
+ TestSession.SIGNING_OUT -> SessionLifecycle.SigningOut
+ TestSession.FAILED -> SessionLifecycle.Failed
}
val activeIdentity =
if (mappedSession == SessionLifecycle.Active) {
@@ -269,10 +271,10 @@ private fun TestSnapshot.toApplicationSnapshot(): ApplicationSnapshot {
revision = SnapshotRevision(revision),
lifecycle =
when (lifecycle) {
- "ready" -> ApplicationLifecycle.Ready
- "closed" -> ApplicationLifecycle.Closed
- "fatal" -> ApplicationLifecycle.Fatal
- else -> ApplicationLifecycle.Opening
+ TestLifecycle.BOOTING -> ApplicationLifecycle.Opening
+ TestLifecycle.READY -> ApplicationLifecycle.Ready
+ TestLifecycle.FATAL -> ApplicationLifecycle.Fatal
+ TestLifecycle.CLOSED -> ApplicationLifecycle.Closed
},
lifecycleProblem = null,
configuredRelays = emptyList(),
diff --git a/core/crates/harvestcircle_test_bridge/src/lib.rs b/core/crates/harvestcircle_test_bridge/src/lib.rs
@@ -38,13 +38,30 @@ pub struct TestIdentity {
pub display_label: String,
}
+#[derive(Clone, Copy, Debug, Eq, PartialEq, uniffi::Enum)]
+pub enum TestLifecycle {
+ Booting,
+ Ready,
+ Fatal,
+ Closed,
+}
+
+#[derive(Clone, Copy, Debug, Eq, PartialEq, uniffi::Enum)]
+pub enum TestSession {
+ SignedOut,
+ Activating,
+ Active,
+ SigningOut,
+ Failed,
+}
+
#[derive(Clone, Debug, Eq, PartialEq, uniffi::Record)]
pub struct TestSnapshot {
pub revision: u64,
- pub lifecycle: String,
+ pub lifecycle: TestLifecycle,
pub identities: Vec<TestIdentity>,
pub selected_public_key_hex: Option<String>,
- pub session: String,
+ pub session: TestSession,
pub profile_display_name: Option<String>,
}
@@ -378,7 +395,7 @@ impl HarvestCircleTestBridge {
let _ = self.stop_observer();
self.close_actor()?;
Ok(TestSnapshot {
- lifecycle: "closed".to_owned(),
+ lifecycle: TestLifecycle::Closed,
..snapshot
})
}
@@ -462,16 +479,16 @@ fn to_identity(identity: &harvestcircle_domain::NostrIdentity) -> TestIdentity {
fn to_snapshot(snapshot: AppSnapshot) -> TestSnapshot {
let lifecycle = match snapshot.lifecycle() {
- AppLifecycle::Booting => "booting",
- AppLifecycle::Ready => "ready",
- AppLifecycle::Fatal(_) => "fatal",
+ AppLifecycle::Booting => TestLifecycle::Booting,
+ AppLifecycle::Ready => TestLifecycle::Ready,
+ AppLifecycle::Fatal(_) => TestLifecycle::Fatal,
};
let session = match snapshot.session() {
- SessionState::SignedOut => "signed_out",
- SessionState::Activating(_) => "activating",
- SessionState::Active => "active",
- SessionState::SigningOut => "signing_out",
- SessionState::Failed(_) => "failed",
+ SessionState::SignedOut => TestSession::SignedOut,
+ SessionState::Activating(_) => TestSession::Activating,
+ SessionState::Active => TestSession::Active,
+ SessionState::SigningOut => TestSession::SigningOut,
+ SessionState::Failed(_) => TestSession::Failed,
};
let profile_display_name = snapshot
.active_identity()
@@ -480,10 +497,10 @@ fn to_snapshot(snapshot: AppSnapshot) -> TestSnapshot {
.map(ToOwned::to_owned);
TestSnapshot {
revision: snapshot.revision().value(),
- lifecycle: lifecycle.to_owned(),
+ lifecycle,
identities: snapshot.identities().iter().map(to_identity).collect(),
selected_public_key_hex: snapshot.selected_identity().map(PublicKey::to_hex),
- session: session.to_owned(),
+ session,
profile_display_name,
}
}