khive-runtime 0.10.0

Composable Service API: entity/note CRUD, graph traversal, hybrid search, curation.
Documentation
use super::*;

#[test]
fn static_sql_keeps_named_route_guard_class_and_occurrences() {
    let route = *ROUTE_INVENTORY
        .iter()
        .find(|route| route.id == "gtd.transition.statement")
        .unwrap();
    let path = "khive-pack-gtd/src/handlers.rs";
    let sql = "UPDATE notes SET properties=?1 WHERE id=?2";
    let assets =
        StaticSqlSources::from([("khive-pack-gtd/sql/fixture.sql".into(), format!("{sql}\n"))]);
    let inline = format!("fn gtd_transition_statement() {{ reject_reserved_secret_gate_property(properties); call({sql:?}); }}");
    let original = scan_source_population(&[(path.into(), inline)]).unwrap();
    for loader in [
        "khive_runtime::sql!(\"fixture\")",
        "include_str!(\"../sql/fixture.sql\")",
    ] {
        let source = format!("fn gtd_transition_statement() {{ reject_reserved_secret_gate_property(properties); call({loader}); }}");
        let population =
            scan_source_population_with_sql(&[(path.into(), source.clone())], &assets).unwrap();
        let before = &original.properties[0];
        let after = &population.properties[0];
        assert_eq!(
            (
                &after.key,
                after.target,
                after.route_class,
                &after.class,
                after.write_count,
                &after.calls
            ),
            (
                &before.key,
                before.target,
                before.route_class,
                &before.class,
                before.write_count,
                &before.calls
            )
        );
        assert!(check_inventory(&population.properties, &[route], 0).is_ok());
        let unchecked = source.replace("reject_reserved_secret_gate_property(properties);", "");
        let population =
            scan_source_population_with_sql(&[(path.into(), unchecked)], &assets).unwrap();
        assert!(check_inventory(&population.properties, &[route], 0).is_err());
        let doubled = source.replace(
            &format!("call({loader});"),
            &format!("call({loader}); call({loader});"),
        );
        let population =
            scan_source_population_with_sql(&[(path.into(), doubled)], &assets).unwrap();
        assert_eq!(population.properties[0].write_count, 2);
        assert!(check_inventory(&population.properties, &[route], 0).is_err());
    }
}

#[test]
fn static_sql_refuses_shadowed_loaders_without_poisoning_sibling_scopes() {
    let assets = StaticSqlSources::from([(
        "sample/sql/query.sql".into(),
        "UPDATE notes SET properties='{}'".into(),
    )]);
    for source in [
        "mod khive_runtime {} fn writer() { khive_runtime::sql!(\"query\"); }",
        "fn writer() { use other as khive_runtime; khive_runtime::sql!(\"query\"); }",
        "fn writer() { use unknown::*; khive_runtime::sql!(\"query\"); }",
        "macro_rules! include_str { () => {}; } fn writer() { include_str!(\"../sql/query.sql\"); }",
    ] {
        assert!(scan_source_population_with_sql(&[("sample/src/lib.rs".into(), source.into())], &assets).is_err(), "{source}");
    }
    let sources = vec![
        (
            "sample/src/lib.rs".into(),
            "mod unrelated; mod writer;".into(),
        ),
        ("sample/src/unrelated.rs".into(), "use unknown::*;".into()),
        (
            "sample/src/writer.rs".into(),
            "fn writer() { khive_runtime::sql!(\"query\"); }".into(),
        ),
    ];
    assert_eq!(
        scan_source_population_with_sql(&sources, &assets)
            .unwrap()
            .properties
            .len(),
        1
    );
    let sources = vec![
        (
            "sample/src/lib.rs".into(),
            "macro_rules! include_str { () => {}; } mod writer;".into(),
        ),
        (
            "sample/src/writer.rs".into(),
            "fn writer() { include_str!(\"../sql/query.sql\"); }".into(),
        ),
    ];
    assert!(scan_source_population_with_sql(&sources, &assets).is_err());
}

#[test]
fn static_sql_keeps_backend_and_test_exclusions_and_fixed_key_classes() {
    let assets = StaticSqlSources::from([
        ("sample/sql/query.sql".into(), "UPDATE notes SET properties=json_set(properties,'$.channel_slug',?1,'$.quarantine_content_ref',?2)".into()),
        ("khive-db/sql/query.sql".into(), "INSERT INTO notes (properties) VALUES (?1)".into()),
    ]);
    let sources = vec![
        ("sample/src/lib.rs".into(), "#[cfg(test)] mod hidden { fn writer() { khive_runtime::sql!(\"missing\"); } } fn writer() { let _ = vec![khive_runtime::sql!(\"query\")]; }".into()),
        ("khive-db/src/lib.rs".into(), "const QUERY: &str = include_str!(\"../sql/query.sql\");".into()),
    ];
    let population = scan_source_population_with_sql(&sources, &assets).unwrap();
    assert_eq!(population.properties.len(), 1);
    assert_eq!(population.properties[0].write_count, 1);
    assert_eq!(
        population.properties[0].route_class,
        RouteClass::Application
    );
    assert_eq!(
        population.properties[0].class,
        DetectedClass::FixedKeySet(BTreeSet::from([
            "$.channel_slug".into(),
            "$.quarantine_content_ref".into()
        ]))
    );
}

#[test]
fn static_sql_distinguishes_module_item_scope_from_textual_macro_scope() {
    let assets = StaticSqlSources::from([(
        "sample/sql/query.sql".into(),
        "UPDATE notes SET properties='{}'".into(),
    )]);
    let writer = "fn writer() { khive_runtime::sql!(\"query\"); }";
    for parent in [
        "use other as khive_runtime; mod child;",
        "mod unrelated { use unknown::*; } mod child;",
    ] {
        let sources = vec![
            ("sample/src/lib.rs".into(), parent.into()),
            ("sample/src/child.rs".into(), writer.into()),
        ];
        assert_eq!(
            scan_source_population_with_sql(&sources, &assets)
                .unwrap()
                .properties
                .len(),
            1
        );
    }
    let included = "fn writer() { include_str!(\"../sql/query.sql\"); }";
    for (parent, accepted) in [
        ("mod child; macro_rules! include_str { () => {}; }", true),
        ("macro_rules! include_str { () => {}; } mod child;", false),
    ] {
        let sources = vec![
            ("sample/src/lib.rs".into(), parent.into()),
            ("sample/src/child.rs".into(), included.into()),
        ];
        assert_eq!(
            scan_source_population_with_sql(&sources, &assets).is_ok(),
            accepted,
            "{parent}"
        );
    }
    for (source, accepted) in [
        ("fn writer() { include_str!(\"../sql/query.sql\"); } macro_rules! include_str { () => {}; }", true),
        ("macro_rules! include_str { () => {}; } fn writer() { include_str!(\"../sql/query.sql\"); }", false),
        ("use other as khive_runtime; mod child { fn writer() { khive_runtime::sql!(\"query\"); } }", true),
        ("#![no_implicit_prelude] fn writer() { khive_runtime::sql!(\"query\"); }", false),
        ("extern crate other as khive_runtime; mod child { fn writer() { khive_runtime::sql!(\"query\"); } }", false),
        ("extern crate self as khive_runtime; mod child { fn writer() { khive_runtime::sql!(\"query\"); } }", false),
        ("use other as khive_runtime; fn writer() { ::khive_runtime::sql!(\"query\"); }", true),
    ] {
        assert_eq!(scan_source_population_with_sql(&[("sample/src/lib.rs".into(), source.into())], &assets).is_ok(), accepted, "{source}");
    }
    let sources = vec![
        (
            "sample/src/lib.rs".into(),
            "use other as khive_runtime; include!(\"included.rs\");".into(),
        ),
        ("sample/src/included.rs".into(), writer.into()),
    ];
    assert!(scan_source_population_with_sql(&sources, &assets).is_err());
}

#[test]
fn static_sql_loader_guard_ignores_quoted_spelling_but_refuses_opaque_calls() {
    let assets = StaticSqlSources::from([(
        "sample/sql/query.sql".into(),
        "UPDATE notes SET properties='{}'".into(),
    )]);
    let harmless = "fn writer() { format!(\"khive_runtime :: sql !\"); format!(\"include_str ! (query.sql)\"); }";
    assert!(scan_source_population_with_sql(
        &[("sample/src/lib.rs".into(), harmless.into())],
        &assets
    )
    .unwrap()
    .properties
    .is_empty());
    for source in [
        "fn writer() { format!(\"{}\", khive_runtime::sql!(\"query\")); }",
        "fn writer() { opaque! { label => include_str!(\"../sql/query.sql\") } }",
    ] {
        assert!(scan_source_population_with_sql(
            &[("sample/src/lib.rs".into(), source.into())],
            &assets
        )
        .is_err());
    }
}

#[test]
fn static_sql_macro_scope_follows_inline_path_attributes() {
    for (outer, child_path) in [
        ("macro_rules! include_str { () => {}; } mod nested { #[path=\"leaf.rs\"] mod leaf; }", "sample/src/outer/nested/leaf.rs"),
        ("macro_rules! include_str { () => {}; } #[path=\"custom_dir\"] mod nested { #[path=\"leaf.rs\"] mod leaf; }", "sample/src/custom_dir/leaf.rs"),
    ] {
        let sources = vec![
            ("sample/src/lib.rs".into(), "mod outer;".into()),
            ("sample/src/outer.rs".into(), outer.into()),
            (child_path.into(), "const SQL: &str = include_str!(\"query.sql\");".into()),
        ];
        let asset = format!("{}/query.sql", Path::new(child_path).parent().unwrap().display());
        let assets = StaticSqlSources::from([(asset, "UPDATE notes SET properties='{}'".into())]);
        assert!(scan_source_population_with_sql(&sources, &assets).is_err(), "{child_path}");
        let mut unshadowed = sources.clone();
        unshadowed[1].1 = outer.replace("macro_rules! include_str { () => {}; }", "");
        assert_eq!(scan_source_population_with_sql(&unshadowed, &assets).unwrap().properties.len(), 1);
    }
}

#[test]
fn static_sql_refuses_guarded_assets_that_no_followed_loader_reaches() {
    let path = "sample/sql/query.sql";
    let assets = StaticSqlSources::from([(
        path.into(),
        "UPDATE notes SET properties=?1 WHERE id=?2\n".into(),
    )]);
    let followed = "fn writer() { reject_reserved_secret_gate_property(properties); \
                    call(khive_runtime::sql!(\"query\")); }";
    let population =
        scan_source_population_with_sql(&[("sample/src/lib.rs".into(), followed.into())], &assets)
            .unwrap();
    assert!(population.resolved_sql.contains(path));
    assert!(check_sql_asset_reach(&assets, &population.resolved_sql).is_ok());
    for source in [
        "use crate::sql::sql; fn writer() { call(sql!(\"query\")); }",
        "fn writer() { call(include_bytes!(\"../sql/query.sql\")); }",
        "fn writer() { call(include_str!(concat!(\"../sql/query.\", \"sql\"))); }",
        "fn writer() {}",
    ] {
        let population = scan_source_population_with_sql(
            &[("sample/src/lib.rs".into(), source.into())],
            &assets,
        )
        .unwrap();
        assert!(population.properties.is_empty(), "{source}");
        let failure = check_sql_asset_reach(&assets, &population.resolved_sql).unwrap_err();
        assert!(failure.contains(path), "{source}: {failure}");
    }
    let read_only = StaticSqlSources::from([(
        path.into(),
        "SELECT properties FROM notes WHERE id=?1".into(),
    )]);
    assert!(check_sql_asset_reach(&read_only, &BTreeSet::new()).is_ok());
}