episodic 0.2.3

Reusable Observational Memory core models and pure transforms.
Documentation
use super::*;

#[test]
fn build_scope_key_requires_identifier_by_scope() {
    assert_eq!(
        build_scope_key(OmScope::Session, Some("s1"), None, None).expect("session key"),
        "session:s1"
    );
    assert_eq!(
        build_scope_key(OmScope::Thread, None, Some("t1"), None).expect("thread key"),
        "thread:t1"
    );
    assert_eq!(
        build_scope_key(OmScope::Resource, None, None, Some("r1")).expect("resource key"),
        "resource:r1"
    );
    assert_eq!(
        build_scope_key(OmScope::Session, None, None, None).expect_err("must fail"),
        OmTransformError::MissingScopeIdentifier("session_id")
    );
}

#[test]
fn build_scope_key_trims_identifiers_and_ignores_unrelated_ids() {
    assert_eq!(
        build_scope_key(
            OmScope::Session,
            Some("  s-main  "),
            Some("t-ignored"),
            Some("r-ignored"),
        )
        .expect("session key"),
        "session:s-main"
    );
    assert_eq!(
        build_scope_key(
            OmScope::Thread,
            Some("s-ignored"),
            Some("  t-main  "),
            Some("r-ignored"),
        )
        .expect("thread key"),
        "thread:t-main"
    );
    assert_eq!(
        build_scope_key(
            OmScope::Resource,
            Some("s-ignored"),
            Some("t-ignored"),
            Some("  r-main  "),
        )
        .expect("resource key"),
        "resource:r-main"
    );
}

#[test]
fn build_scope_key_rejects_missing_identifier_for_each_scope() {
    assert_eq!(
        build_scope_key(OmScope::Session, Some("   "), Some("t1"), Some("r1"))
            .expect_err("must fail"),
        OmTransformError::MissingScopeIdentifier("session_id")
    );
    assert_eq!(
        build_scope_key(OmScope::Thread, Some("s1"), None, Some("r1")).expect_err("must fail"),
        OmTransformError::MissingScopeIdentifier("thread_id")
    );
    assert_eq!(
        build_scope_key(OmScope::Thread, Some("s1"), Some("   "), Some("r1"))
            .expect_err("must fail"),
        OmTransformError::MissingScopeIdentifier("thread_id")
    );
    assert_eq!(
        build_scope_key(OmScope::Resource, Some("s1"), Some("t1"), None).expect_err("must fail"),
        OmTransformError::MissingScopeIdentifier("resource_id")
    );
}

#[test]
fn canonical_thread_ref_resource_scope_prefers_source_thread_then_session() {
    let resolved = resolve_canonical_thread_ref(
        OmScope::Resource,
        "resource:docs/om.md",
        Some("thread-source"),
        Some("session-source"),
        Some("thread-current"),
        Some("session-current"),
        None,
    );
    assert_eq!(resolved.canonical_thread_id, "thread:thread-source");
    assert_eq!(resolved.origin_thread_id.as_deref(), Some("thread-source"));
    assert_eq!(
        resolved.origin_session_id.as_deref(),
        Some("session-source")
    );
    assert_eq!(resolved.resource_id.as_deref(), Some("docs/om.md"));
}

#[test]
fn canonical_thread_ref_falls_back_to_session_and_scope_key_identifiers() {
    let session_scope = resolve_canonical_thread_ref(
        OmScope::Session,
        "session:s-scope",
        None,
        None,
        None,
        Some("s-current"),
        None,
    );
    assert_eq!(session_scope.canonical_thread_id, "session:s-current");

    let thread_scope = resolve_canonical_thread_ref(
        OmScope::Thread,
        "thread:t-scope",
        None,
        None,
        None,
        None,
        None,
    );
    assert_eq!(thread_scope.canonical_thread_id, "thread:t-scope");

    let resource_scope = resolve_canonical_thread_ref(
        OmScope::Resource,
        "resource:r-scope",
        None,
        None,
        None,
        None,
        None,
    );
    assert_eq!(resource_scope.canonical_thread_id, "resource:r-scope");
}

#[test]
fn canonical_thread_ref_is_deterministic_for_same_input() {
    let first = resolve_canonical_thread_ref(
        OmScope::Resource,
        "  resource:r-main  ",
        Some(" t-main "),
        Some(" s-main "),
        None,
        None,
        None,
    );
    let second = resolve_canonical_thread_ref(
        OmScope::Resource,
        "  resource:r-main  ",
        Some(" t-main "),
        Some(" s-main "),
        None,
        None,
        None,
    );
    assert_eq!(first, second);
    assert_eq!(first.scope_key, "resource:r-main");
    assert_eq!(first.canonical_thread_id, "thread:t-main");
}