relay-knowledge 1.1.14

Graph-database-based knowledge graph project.
Documentation
// Direct tests for reference-target identity resolution.

use crate::domain::{RepositoryCodeRange, RepositoryCodeReferenceRecord};

use super::*;

#[test]
fn same_path_overloads_remain_ambiguous_even_when_one_contains_call_line() {
    let mut symbols = vec![
        symbol("sym-int", "src/overload.cpp", "run"),
        symbol("sym-double", "src/overload.cpp", "run"),
    ];
    symbols[0].line_range = RepositoryCodeRange { start: 1, end: 3 };
    symbols[1].line_range = RepositoryCodeRange { start: 5, end: 5 };
    let mut references = vec![reference("ref-call", "src/overload.cpp", "run")];
    references[0].line_range = RepositoryCodeRange { start: 2, end: 2 };

    resolve_reference_targets(&symbols, &mut references);

    assert_eq!(references[0].target_symbol_snapshot_id, None);
    assert_eq!(references[0].resolution_state, "ambiguous");
}

#[test]
fn call_resolution_prefers_implementation_over_header_declaration() {
    let mut symbols = vec![
        symbol("header-declaration", "include/rk_bridge.h", "rk_c_decode"),
        symbol("source-definition", "src/c_entry.c", "rk_c_decode"),
    ];
    symbols[0].kind = "function_declaration".to_owned();
    let mut references = vec![reference("cpp-call", "src/cpp_bridge.cpp", "rk_c_decode")];

    resolve_reference_targets(&symbols, &mut references);

    assert_eq!(
        references[0].target_symbol_snapshot_id.as_deref(),
        Some("source-definition")
    );
    assert_eq!(references[0].target_hint.as_deref(), Some("rk_c_decode"));
    assert_eq!(references[0].resolution_state, "resolved");
}

#[test]
fn call_resolution_follows_cgo_and_ffi_aliases_to_c_symbols() {
    let symbols = vec![symbol("c-definition", "src/c_entry.c", "rk_c_decode")];
    let mut references = vec![
        reference("go-cgo-call", "bridge/go_bridge.go", "C.rk_c_decode"),
        reference(
            "rust-ffi-call",
            "crates/rust_bridge/src/lib.rs",
            "ffi::rk_c_decode",
        ),
    ];

    resolve_reference_targets(&symbols, &mut references);

    assert!(references.iter().all(|reference| {
        reference.target_symbol_snapshot_id.as_deref() == Some("c-definition")
            && reference.resolution_state == "resolved"
    }));
    assert_eq!(references[0].target_hint.as_deref(), Some("C.rk_c_decode"));
    assert_eq!(
        references[1].target_hint.as_deref(),
        Some("ffi::rk_c_decode")
    );
}

#[test]
fn call_resolution_does_not_leaf_alias_ordinary_namespaced_calls() {
    let symbols = vec![symbol("plain-connect", "src/socket.c", "connect")];
    let mut references = vec![
        reference(
            "rust-module-call",
            "crates/app/src/lib.rs",
            "module::connect",
        ),
        reference(
            "rust-module-sys-call",
            "crates/app/src/lib.rs",
            "module::sys::connect",
        ),
        reference("rust-c-member-call", "crates/app/src/lib.rs", "C.connect"),
        reference("go-object-c-call", "bridge/go_bridge.go", "obj.C.connect"),
    ];

    resolve_reference_targets(&symbols, &mut references);

    assert!(references.iter().all(|reference| {
        reference.target_symbol_snapshot_id.is_none() && reference.resolution_state == "unresolved"
    }));
    assert_eq!(
        references[0].target_hint.as_deref(),
        Some("module::connect")
    );
    assert_eq!(
        references[1].target_hint.as_deref(),
        Some("module::sys::connect")
    );
    assert_eq!(references[2].target_hint.as_deref(), Some("C.connect"));
    assert_eq!(references[3].target_hint.as_deref(), Some("obj.C.connect"));
}

#[test]
fn call_resolution_ignores_unique_non_callable_leaf_targets() {
    let mut symbols = vec![symbol("constant-connect", "src/constants.rs", "connect")];
    symbols[0].kind = "constant".to_owned();
    let mut references = vec![reference("ffi-connect", "src/lib.rs", "ffi::connect")];

    resolve_reference_targets(&symbols, &mut references);

    assert_eq!(references[0].target_symbol_snapshot_id, None);
    assert_eq!(references[0].target_hint.as_deref(), Some("ffi::connect"));
    assert_eq!(references[0].resolution_state, "unresolved");
}

#[test]
fn dependency_references_can_resolve_to_module_symbols() {
    let mut symbols = vec![symbol("go-module", "libs/lib/go.mod", "example.com/lib")];
    symbols[0].kind = "module".to_owned();
    let mut references = vec![reference("go-require", "go.mod", "example.com/lib")];
    references[0].kind = "dependency".to_owned();

    resolve_reference_targets(&symbols, &mut references);

    assert_eq!(
        references[0].target_symbol_snapshot_id.as_deref(),
        Some("go-module")
    );
    assert_eq!(references[0].resolution_state, "resolved");
}

#[test]
fn call_resolution_continues_to_leaf_after_scoped_ambiguity() {
    let mut symbols = vec![
        symbol("ffi-declaration-a", "src/bindings_a.rs", "ffi::rk_c_decode"),
        symbol("ffi-declaration-b", "src/bindings_b.rs", "ffi::rk_c_decode"),
        symbol("c-definition", "src/c_entry.c", "rk_c_decode"),
    ];
    symbols[0].kind = "function_declaration".to_owned();
    symbols[1].kind = "function_declaration".to_owned();
    let mut references = vec![reference("ffi-call", "src/lib.rs", "ffi::rk_c_decode")];

    resolve_reference_targets(&symbols, &mut references);

    assert_eq!(
        references[0].target_symbol_snapshot_id.as_deref(),
        Some("c-definition")
    );
    assert_eq!(
        references[0].target_hint.as_deref(),
        Some("ffi::rk_c_decode")
    );
    assert_eq!(references[0].resolution_state, "resolved");
}

#[test]
fn call_resolution_prefers_leaf_definition_over_unique_scoped_declaration() {
    let mut symbols = vec![
        symbol("ffi-declaration", "src/bindings.rs", "ffi::rk_c_decode"),
        symbol("c-definition", "src/c_entry.c", "rk_c_decode"),
    ];
    symbols[0].kind = "function_declaration".to_owned();
    let mut references = vec![reference("ffi-call", "src/lib.rs", "ffi::rk_c_decode")];

    resolve_reference_targets(&symbols, &mut references);

    assert_eq!(
        references[0].target_symbol_snapshot_id.as_deref(),
        Some("c-definition")
    );
    assert_eq!(
        references[0].target_hint.as_deref(),
        Some("ffi::rk_c_decode")
    );
    assert_eq!(references[0].resolution_state, "resolved");
}

#[test]
fn call_resolution_treats_signature_only_functions_as_declarations() {
    let mut symbols = vec![
        symbol("ffi-declaration", "src/bindings.rs", "ffi::rk_c_decode"),
        symbol("c-definition", "src/c_entry.c", "rk_c_decode"),
    ];
    symbols[0].signature = "fn rk_c_decode(input: *const u8);".to_owned();
    let mut references = vec![reference("ffi-call", "src/lib.rs", "ffi::rk_c_decode")];

    resolve_reference_targets(&symbols, &mut references);

    assert_eq!(
        references[0].target_symbol_snapshot_id.as_deref(),
        Some("c-definition")
    );
    assert_eq!(
        references[0].target_hint.as_deref(),
        Some("ffi::rk_c_decode")
    );
    assert_eq!(references[0].resolution_state, "resolved");
}

#[test]
fn call_resolution_defers_ambiguous_declaration_until_leaf_fallback() {
    let mut symbols = vec![
        symbol("ffi-declaration", "src/bindings.rs", "ffi::rk_c_decode"),
        symbol("ffi-constant", "src/constants.rs", "ffi::rk_c_decode"),
        symbol("c-definition", "src/c_entry.c", "rk_c_decode"),
    ];
    symbols[0].kind = "function_declaration".to_owned();
    symbols[1].kind = "constant".to_owned();
    let mut references = vec![reference("ffi-call", "src/lib.rs", "ffi::rk_c_decode")];

    resolve_reference_targets(&symbols, &mut references);

    assert_eq!(
        references[0].target_symbol_snapshot_id.as_deref(),
        Some("c-definition")
    );
    assert_eq!(
        references[0].target_hint.as_deref(),
        Some("ffi::rk_c_decode")
    );
    assert_eq!(references[0].resolution_state, "resolved");
}

fn symbol(id: &str, path: &str, name: &str) -> RepositoryCodeSymbolRecord {
    RepositoryCodeSymbolRecord {
        repository_id: "repo".to_owned(),
        source_scope: "git_snapshot:test".to_owned(),
        symbol_snapshot_id: id.to_owned(),
        canonical_symbol_id: format!("repo://repo/{}::{name}", path.replace('/', "::")),
        file_id: format!("file-{id}"),
        path: path.to_owned(),
        language_id: "cpp".to_owned(),
        name: name.to_owned(),
        qualified_name: format!("{}::{name}", path.replace('/', "::")),
        kind: "function".to_owned(),
        signature: format!("void {name}()"),
        doc_comment: None,
        byte_range: RepositoryCodeRange { start: 0, end: 8 },
        line_range: RepositoryCodeRange { start: 1, end: 1 },
        symbol_role: None,
    }
}

fn reference(id: &str, path: &str, name: &str) -> RepositoryCodeReferenceRecord {
    RepositoryCodeReferenceRecord {
        repository_id: "repo".to_owned(),
        source_scope: "git_snapshot:test".to_owned(),
        reference_id: id.to_owned(),
        file_id: format!("file-{id}"),
        path: path.to_owned(),
        name: name.to_owned(),
        kind: "call".to_owned(),
        target_symbol_snapshot_id: None,
        target_hint: Some(name.to_owned()),
        resolution_state: "unresolved".to_owned(),
        confidence_basis_points: 2_500,
        confidence_tier: "ambiguous".to_owned(),
        byte_range: RepositoryCodeRange { start: 0, end: 8 },
        line_range: RepositoryCodeRange { start: 1, end: 1 },
    }
}