Skip to content

fix(extract-rust): inline test fns (#[test]/#[tokio::test]) are not marked is_test — leak into graph/agent context #855

Description

@moofone

Summary

Inline Rust test functions — #[test], #[tokio::test], #[async_std::test], #[actix_rt::test], and #[cfg(test)] mod tests { … } bodies — that live inside a regular source file (e.g. src/lib.rs) are not detected as tests. They are indexed as ordinary Function nodes with is_test = false, so they are not filtered by the is_test != 1 clause in store.c and leak into graph queries / agent context, polluting it with test code.

Root cause

Test detection is file-path-based only:

  • cbm_is_test_file(rel_path, lang) (internal/cbm/helpers.c:292) marks a file/module as a test only by path. For Rust it is return has_suffix(base, "_test.rs") || has_prefix(base, "test_"); (with the code comment "Rust tests are typically mod tests inside the file, but test files too"). A file like src/lib.rs is therefore never a test file, regardless of its contents.
  • CBMDefinition.is_test (internal/cbm/cbm.h:213) is the per-function flag. It is read by src/pipeline/pass_definitions.c and src/pipeline/pass_parallel.c (emitted into node properties) but is never assigned in the extraction layer — the only is_test write is mod.is_test = ctx->result->is_test_file; (internal/cbm/extract_defs.c:6316), which is module/file-level. So def->is_test stays at its zero-initialized default (false).

Because functions are never marked, the store.c filter (json_extract(properties, '$.is_test') != 1) only ever drops whole test-files, never inline test functions.

Repro

Index any repo containing, in a non-test-named file:

// src/lib.rs
pub fn real_fn() {}

#[cfg(test)]
mod tests {
    #[tokio::test]
    async fn something_works() {}
}

cbm cli --json search_graph '{"project":"…","name_pattern":"something_works"}' returns something_works as a Function with is_test absent/false — i.e. it is not filtered and appears alongside real_fn in graph context.

Proposed fix (Rust-scoped)

In the Rust function-extraction path in internal/cbm/extract_defs.c, scan each function's attribute_item / meta_item children for test macros and set def->is_test = true. Initial attribute set:

  • bare #[test]
  • #[tokio::test] (the case that surfaced this — async tests)
  • #[async_std::test]
  • #[actix_rt::test]
  • #[test_case::case] (optionally)

Plus a regression test in tests/test_extraction.c asserting a Rust snippet with #[tokio::test] async fn … yields def->is_test == true. make -f Makefile.cbm test + scripts/lint.sh clean.

Scope

Rust only in the follow-up PR. Rust is a high-value first target because inline #[cfg(test)] mod tests { … } is idiomatic, so these unmarked test functions leak into the graph for any typical Rust crate — not an edge case. Go / Python / JS / Java / C# can follow in separate PRs per the one-issue-per-PR guidance.

Ask

Status: PR #857 implements this (Rust-scoped, with a regression test; scripts/test.sh green, red→green verified). Feedback on the attribute set and the extraction-hook point welcome there or here — happy to adjust. (Filed for alignment first; went ahead since it's a focused correctness fix.)


Citations verified against main at 37c00d1.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions