app

Local-first trade for farms and co-ops
git clone https://radroots.dev/git/app.git
Log | Files | Refs | README | LICENSE

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:
Mapp/desktop/src/integrationTest/kotlin/org/harvestcircle/integration/NativeRuntimeIntegrationTest.kt | 6++----
Mapp/desktop/src/integrationTest/kotlin/org/harvestcircle/integration/TestBridgeHarvestCircleRuntime.kt | 20+++++++++++---------
Mcore/crates/harvestcircle_test_bridge/src/lib.rs | 43++++++++++++++++++++++++++++++-------------
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, } }