relay-knowledge 1.1.10

Graph-database-based knowledge graph project.
Documentation
use super::{
    CodeIndexProgressSummary, CodeIndexResourceBudget, CodeIndexSummary, CodeQueryKind,
    CodeRepositoryReport, CodeRepositorySelector, CodeRepositoryTotals, CodeRetrievalRequest,
    FreshnessPolicy, RepositoryCodeRange, code_snapshot_expected_scope_id, code_snapshot_scope_id,
    code_snapshot_scope_is_fact_versioned,
};

#[test]
fn selector_trims_and_deduplicates_filters() {
    let selector = CodeRepositorySelector::new(
        " repo ",
        " HEAD ",
        vec!["src".to_owned(), " src ".to_owned()],
        vec!["rust".to_owned(), "rust".to_owned()],
    )
    .expect("selector should validate");

    assert_eq!(selector.repository, "repo");
    assert_eq!(selector.ref_selector, "HEAD");
    assert_eq!(selector.path_filters, ["src"]);
    assert_eq!(selector.language_filters, ["rust"]);
}

#[test]
fn snapshot_scope_id_tracks_tree_and_filters() {
    let scope = code_snapshot_scope_id(
        "repo-1",
        "tree-a",
        &["src".to_owned()],
        &["rust".to_owned()],
    );
    let same = code_snapshot_scope_id(
        "repo-1",
        "tree-a",
        &["src".to_owned()],
        &["rust".to_owned()],
    );
    let different_tree = code_snapshot_scope_id(
        "repo-1",
        "tree-b",
        &["src".to_owned()],
        &["rust".to_owned()],
    );

    assert_eq!(scope, same);
    assert_ne!(scope, different_tree);
    assert!(scope.starts_with("git_snapshot:"));
}

#[test]
fn expected_snapshot_scope_id_is_checked_for_unfiltered_repositories() {
    let scope = code_snapshot_scope_id("repo-1", "tree-a", &[], &[]);
    let expected = code_snapshot_expected_scope_id("repo-1", "tree-a", &[], &[])
        .expect("all repository snapshots should carry a fact version");

    assert_eq!(expected, scope);
}

#[test]
fn fact_versioned_snapshot_scope_requires_generated_hash_shape() {
    assert!(code_snapshot_scope_is_fact_versioned(
        "git_snapshot:0123456789abcdef"
    ));
    assert!(!code_snapshot_scope_is_fact_versioned("git_snapshot:test"));
    assert!(!code_snapshot_scope_is_fact_versioned("manual:test"));
}

#[test]
fn retrieval_request_rejects_unbounded_limits() {
    let selector = CodeRepositorySelector::new("repo", "HEAD", Vec::new(), Vec::new())
        .expect("selector should validate");
    let error = CodeRetrievalRequest::new(
        "symbol",
        selector,
        CodeQueryKind::Hybrid,
        51,
        FreshnessPolicy::AllowStale,
    )
    .expect_err("large limit should fail");

    assert_eq!(error.field, "limit");
}

#[test]
fn code_ranges_must_be_ordered() {
    let error = RepositoryCodeRange::new("line_range", 3, 2).expect_err("range should fail");

    assert_eq!(error.field, "line_range");
}

#[test]
fn default_code_index_budget_batches_more_small_files_without_raising_row_or_byte_caps() {
    let budget = CodeIndexResourceBudget::default();

    assert_eq!(budget.max_files_per_batch, 512);
    assert_eq!(
        budget.max_bytes_per_batch,
        CodeIndexResourceBudget::DEFAULT_MAX_BYTES_PER_BATCH
    );
    assert_eq!(
        budget.max_rows_per_batch,
        CodeIndexResourceBudget::DEFAULT_MAX_ROWS_PER_BATCH
    );
}

#[test]
fn generated_count_fields_default_when_deserializing_older_responses() {
    let mut summary_json = serde_json::to_value(CodeIndexSummary {
        repository_id: "repo".to_owned(),
        source_scope: "scope".to_owned(),
        resolved_commit_sha: "commit".to_owned(),
        tree_hash: "tree".to_owned(),
        indexed_file_count: 1,
        changed_path_count: 1,
        skipped_unchanged_count: 0,
        deleted_path_count: 0,
        symbol_count: 2,
        handwritten_symbol_count: 1,
        generated_symbol_count: 1,
        reference_count: 0,
        chunk_count: 0,
        degraded_file_count: 0,
        progress: CodeIndexProgressSummary::default(),
    })
    .expect("summary should serialize");
    let summary_object = summary_json
        .as_object_mut()
        .expect("summary json should be an object");
    summary_object.remove("handwritten_symbol_count");
    summary_object.remove("generated_symbol_count");
    let summary = serde_json::from_value::<CodeIndexSummary>(summary_json)
        .expect("older summary response should deserialize");

    assert_eq!(summary.handwritten_symbol_count, 0);
    assert_eq!(summary.generated_symbol_count, 0);

    let mut totals_json =
        serde_json::to_value(CodeRepositoryTotals::default()).expect("totals should serialize");
    let totals_object = totals_json
        .as_object_mut()
        .expect("totals json should be an object");
    totals_object.remove("handwritten_symbol_count");
    totals_object.remove("generated_symbol_count");
    let totals = serde_json::from_value::<CodeRepositoryTotals>(totals_json)
        .expect("older totals response should deserialize");

    assert_eq!(totals.handwritten_symbol_count, 0);
    assert_eq!(totals.generated_symbol_count, 0);

    let mut report_json = serde_json::to_value(CodeRepositoryReport {
        repository_id: "repo".to_owned(),
        alias: "fixture".to_owned(),
        root_path: "/tmp/repo".to_owned(),
        path_filters: Vec::new(),
        language_filters: Vec::new(),
        resolved_commit_sha: Some("commit".to_owned()),
        tree_hash: Some("tree".to_owned()),
        indexed_file_count: 1,
        symbol_count: 2,
        handwritten_symbol_count: 1,
        generated_symbol_count: 1,
        reference_count: 0,
        chunk_count: 0,
        degraded_file_count: 0,
        resolved_edge_count: 0,
        ambiguous_edge_count: 0,
        unresolved_edge_count: 0,
        degradation_summary: Vec::new(),
        representative_queries: Vec::new(),
        latency_samples: Vec::new(),
        freshness_state: "fresh".to_owned(),
    })
    .expect("report should serialize");
    let report_object = report_json
        .as_object_mut()
        .expect("report json should be an object");
    report_object.remove("handwritten_symbol_count");
    report_object.remove("generated_symbol_count");
    let report = serde_json::from_value::<CodeRepositoryReport>(report_json)
        .expect("older report response should deserialize");

    assert_eq!(report.handwritten_symbol_count, 0);
    assert_eq!(report.generated_symbol_count, 0);
}