Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions tests/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,14 @@ fn test_pack_symbol_includes_reference_sites() {

let out = stdout(&run_ok(
&dir,
&["pack", "--symbol", "Widget", "--format", "json", "--dry-run"],
&[
"pack",
"--symbol",
"Widget",
"--format",
"json",
"--dry-run",
],
));
assert!(
out.contains("src/handlers/app.rs"),
Expand All @@ -449,7 +456,10 @@ fn test_pack_symbol_includes_reference_sites() {

// status --json exposes the new edge count, > 0 here.
let status = stdout(&run_ok(&dir, &["status", "--json"]));
assert!(status.contains("\"referenceEdges\""), "status has referenceEdges: {status}");
assert!(
status.contains("\"referenceEdges\""),
"status has referenceEdges: {status}"
);
assert!(
status.contains("\"referenceLanguages\""),
"status names covered languages: {status}"
Expand Down
18 changes: 10 additions & 8 deletions tests/ladybug_smoke.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,19 +107,21 @@ fn ladybug_reference_edge_roundtrips() {
exported: true,
};
// Target (declared) and referrer (the enclosing decl that uses it).
store.upsert_symbol(mk("sym:a.cs#class#Employee#1", "Employee", "a.cs")).unwrap();
store.upsert_symbol(mk("sym:b.cs#class#Attendance#1", "Attendance", "b.cs")).unwrap();
store
.upsert_symbol(mk("sym:a.cs#class#Employee#1", "Employee", "a.cs"))
.unwrap();
store
.upsert_symbol(mk("sym:b.cs#class#Attendance#1", "Attendance", "b.cs"))
.unwrap();
store
.link_symbol_references("sym:b.cs#class#Attendance#1", "sym:a.cs#class#Employee#1")
.expect("link references");

// The referrer file must come back via symbol_references on the target name.
let refs = store.symbol_references("Employee").expect("symbol_references");
assert_eq!(
refs.len(),
1,
"exactly one referrer expected, got {refs:?}"
);
let refs = store
.symbol_references("Employee")
.expect("symbol_references");
assert_eq!(refs.len(), 1, "exactly one referrer expected, got {refs:?}");
assert_eq!(refs[0].path, "b.cs");
assert_eq!(store.stats().unwrap().reference_edges, 1);

Expand Down
83 changes: 72 additions & 11 deletions tests/unit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1000,7 +1000,11 @@ fn index_creates_reference_edges_csharp() {
let tmp = std::env::temp_dir().join(format!("synapse-ref-cs-{}", std::process::id()));
let _ = std::fs::remove_dir_all(&tmp);
std::fs::create_dir_all(&tmp).unwrap();
std::fs::write(tmp.join("Event.cs"), "namespace N { public record UserRegistered(int Id); }").unwrap();
std::fs::write(
tmp.join("Event.cs"),
"namespace N { public record UserRegistered(int Id); }",
)
.unwrap();
std::fs::write(
tmp.join("Handler.cs"),
"namespace N { class Handler { void On() { var e = new UserRegistered(1); } } }",
Expand All @@ -1009,7 +1013,16 @@ fn index_creates_reference_edges_csharp() {

let repo = Repo { root: tmp.clone() };
let store = MemoryGraphStore::new();
index_repo(&repo, &SynapseConfig::default(), &store, true, false, "2026-06-01T00:00:00+00:00", None).unwrap();
index_repo(
&repo,
&SynapseConfig::default(),
&store,
true,
false,
"2026-06-01T00:00:00+00:00",
None,
)
.unwrap();

let refs = store.symbol_references("UserRegistered").unwrap();
assert!(
Expand All @@ -1019,7 +1032,9 @@ fn index_creates_reference_edges_csharp() {
// And it must surface through the consumer path that pack/related use.
let related = store.related_to_symbol("UserRegistered", 1).unwrap();
assert!(
related.iter().any(|r| r.path == "Handler.cs" && r.depth == 1),
related
.iter()
.any(|r| r.path == "Handler.cs" && r.depth == 1),
"related_to_symbol must include the caller at depth 1: {related:?}"
);

Expand All @@ -1035,12 +1050,25 @@ fn index_creates_reference_edges_rust() {
let tmp = std::env::temp_dir().join(format!("synapse-ref-rs-{}", std::process::id()));
let _ = std::fs::remove_dir_all(&tmp);
std::fs::create_dir_all(&tmp).unwrap();
std::fs::write(tmp.join("widget.rs"), "pub struct Widget; impl Widget { pub fn new() -> Widget { Widget } }").unwrap();
std::fs::write(
tmp.join("widget.rs"),
"pub struct Widget; impl Widget { pub fn new() -> Widget { Widget } }",
)
.unwrap();
std::fs::write(tmp.join("app.rs"), "fn run() { let _w = Widget::new(); }").unwrap();

let repo = Repo { root: tmp.clone() };
let store = MemoryGraphStore::new();
index_repo(&repo, &SynapseConfig::default(), &store, true, false, "2026-06-01T00:00:00+00:00", None).unwrap();
index_repo(
&repo,
&SynapseConfig::default(),
&store,
true,
false,
"2026-06-01T00:00:00+00:00",
None,
)
.unwrap();

let refs = store.symbol_references("Widget").unwrap();
assert!(
Expand All @@ -1061,11 +1089,24 @@ fn index_creates_reference_edges_ts() {
let _ = std::fs::remove_dir_all(&tmp);
std::fs::create_dir_all(&tmp).unwrap();
std::fs::write(tmp.join("widget.ts"), "export class Widget {}").unwrap();
std::fs::write(tmp.join("app.ts"), "import { Widget } from './widget';\nfunction make() { return new Widget(); }").unwrap();
std::fs::write(
tmp.join("app.ts"),
"import { Widget } from './widget';\nfunction make() { return new Widget(); }",
)
.unwrap();

let repo = Repo { root: tmp.clone() };
let store = MemoryGraphStore::new();
index_repo(&repo, &SynapseConfig::default(), &store, true, false, "2026-06-01T00:00:00+00:00", None).unwrap();
index_repo(
&repo,
&SynapseConfig::default(),
&store,
true,
false,
"2026-06-01T00:00:00+00:00",
None,
)
.unwrap();

let refs = store.symbol_references("Widget").unwrap();
assert!(
Expand Down Expand Up @@ -1100,7 +1141,16 @@ fn reference_ambiguous_name_links_all_candidates() {

let repo = Repo { root: tmp.clone() };
let store = MemoryGraphStore::new();
index_repo(&repo, &SynapseConfig::default(), &store, true, false, "2026-06-01T00:00:00+00:00", None).unwrap();
index_repo(
&repo,
&SynapseConfig::default(),
&store,
true,
false,
"2026-06-01T00:00:00+00:00",
None,
)
.unwrap();

let refs = store.symbol_references("Foo").unwrap();
// Both declarations live in their own files; the caller references the name
Expand Down Expand Up @@ -1135,11 +1185,23 @@ fn reference_local_variable_creates_no_edge() {

let repo = Repo { root: tmp.clone() };
let store = MemoryGraphStore::new();
index_repo(&repo, &SynapseConfig::default(), &store, true, false, "2026-06-01T00:00:00+00:00", None).unwrap();
index_repo(
&repo,
&SynapseConfig::default(),
&store,
true,
false,
"2026-06-01T00:00:00+00:00",
None,
)
.unwrap();

// `total` is never declared as a symbol, so it must resolve to no edge.
let refs = store.symbol_references("total").unwrap();
assert!(refs.is_empty(), "local `total` must not be a reference target: {refs:?}");
assert!(
refs.is_empty(),
"local `total` must not be a reference target: {refs:?}"
);

let _ = std::fs::remove_dir_all(&tmp);
}
Expand Down Expand Up @@ -1217,4 +1279,3 @@ fn explore_docker_args_in_memory_skips_mount() {
// READ_ONLY is unsupported with in-memory, so it must not be set.
assert!(!joined.contains("READ_ONLY"));
}

Loading