amethystate 0.9.1

Type-safe reactive persistence for Rust GUI apps
Documentation
use amethystate::observability;
use amethystate::{StoreBuilder, amethystate};
use amethystate_core::test_utils::unique_path;
use tracing_test::traced_test;

#[amethystate(prefix = "obs")]
pub struct ObsState {
    #[amestate(default = 8080u16)]
    pub port: u16,

    #[amestate(default = "localhost".to_string())]
    pub host: String,
}

#[test]
fn instance_registered_on_new() {
    let path = unique_path("obs_instance_reg");
    let store = StoreBuilder::new(&path).build().unwrap();
    let _state = ObsState::new_with(&store).unwrap();

    let port_meta = observability::resolve_field("obs.port")
        .expect("obs.port must be in schema registry after construction");

    assert!(
        port_meta.struct_type_name.contains("ObsState"),
        "struct_type_name should contain 'ObsState', got: {}",
        port_meta.struct_type_name
    );
}

#[test]
fn fields_registered_in_schema_registry() {
    let path = unique_path("obs_schema_reg");
    let store = StoreBuilder::new(&path).build().unwrap();
    let _state = ObsState::new_with(&store).unwrap();

    let port_meta =
        observability::resolve_field("obs.port").expect("obs.port must be in schema registry");
    assert_eq!(port_meta.field_name.as_ref(), "port");
    assert!(
        port_meta.struct_type_name.contains("ObsState"),
        "struct_type_name should reference ObsState, got: {}",
        port_meta.struct_type_name
    );
    assert!(
        port_meta.value_type_name.contains("u16"),
        "value_type_name should be u16, got: {}",
        port_meta.value_type_name
    );

    let host_meta =
        observability::resolve_field("obs.host").expect("obs.host must be in schema registry");
    assert_eq!(host_meta.field_name.as_ref(), "host");
    assert!(host_meta.value_type_name.contains("String"));
}

#[test]
#[traced_test]
fn field_set_emits_trace() {
    let path = unique_path("obs_write_trace");
    let store = StoreBuilder::new(&path).build().unwrap();
    let state = ObsState::new_with(&store).unwrap();

    state.port().set(9090).unwrap();

    assert!(logs_contain("field write"), "expected 'field write' trace");
    assert!(
        logs_contain("obs.port"),
        "expected path 'obs.port' in trace"
    );
}

#[test]
#[traced_test]
fn field_set_trace_contains_source_name() {
    let path = unique_path("obs_source_name");
    let store = StoreBuilder::new(&path).build().unwrap();
    let state = ObsState::new_with(&store).unwrap();

    state.host().set("example.com".to_string()).unwrap();

    assert!(
        logs_contain("ObsState"),
        "expected struct name 'ObsState' in write trace"
    );
}

#[test]
#[traced_test]
fn subscription_fire_emits_trace_with_location() {
    let path = unique_path("obs_sub_trace");
    let store = StoreBuilder::new(&path).build().unwrap();
    let state = ObsState::new_with(&store).unwrap();

    let _sub = state.port().subscribe(|_| {});
    state.port().set(1234).unwrap();

    assert!(
        logs_contain("signal emit"),
        "expected 'signal emit' trace on subscription fire"
    );
    assert!(
        logs_contain("observability_tracing.rs"),
        "expected call-site file name in subscription trace"
    );
}

#[test]
#[traced_test]
fn named_subscription_appears_in_trace() {
    let path = unique_path("obs_named_sub");
    let store = StoreBuilder::new(&path).build().unwrap();
    let state = ObsState::new_with(&store).unwrap();

    let _sub = state.port().subscribe(|_| {}).named("PortWatcher");
    state.port().set(5555).unwrap();

    assert!(
        logs_contain("PortWatcher"),
        "expected named subscription label 'PortWatcher' in trace"
    );
}

#[test]
#[traced_test]
fn forked_write_traces_with_source() {
    let path = unique_path("obs_fork_trace");
    let store = StoreBuilder::new(&path).build().unwrap();
    let state = ObsState::new_with(&store).unwrap();
    let fork = state.fork();

    fork.port().set(7777).unwrap();

    assert!(
        logs_contain("field write"),
        "expected trace from fork write"
    );
    assert!(logs_contain("obs.port"));
}