use super::*;
#[test]
fn package_imports_recursive_calls_and_f_strings_retain_call_edges() {
let snapshot = analyze(&[
(
"src/core.py",
"def resolve_target(selector: str) -> str:\n if selector.startswith('#'):\n return resolve_target(selector[1:])\n return selector.strip()\n\ndef resolve_target_path(selector: str) -> str:\n return f\"/{resolve_target(selector)}\"\n",
),
(
"src/caller.py",
"from src.core import resolve_target\n\ndef run(value: str) -> str:\n return resolve_target(value)\n",
),
(
"src/toplevel.py",
"from src.core import resolve_target\n\nDEFAULT_TARGET = resolve_target('#main')\n",
),
]);
let target = snapshot
.nodes
.iter()
.find(|node| {
node.label == "resolve_target"
&& node
.span
.as_ref()
.is_some_and(|span| span.file == "src/core.py")
})
.expect("target declaration");
let mut call_files = snapshot
.edges
.iter()
.filter(|edge| edge.kind == EdgeKind::Calls && edge.target == target.id)
.filter_map(|edge| edge.provenance.span.as_ref().map(|span| span.file.as_str()))
.collect::<Vec<_>>();
call_files.sort_unstable();
assert_eq!(
call_files,
[
"src/caller.py",
"src/core.py",
"src/core.py",
"src/toplevel.py"
],
"every exact Python call must resolve to the exported declaration; edges: {:?}",
snapshot.edges
);
}