use std::collections::HashSet;
use controlled_option::ControlledOption;
use stack_graphs::arena::Handle;
use stack_graphs::graph::StackGraph;
use stack_graphs::partial::PartialPath;
use stack_graphs::partial::PartialPaths;
use stack_graphs::paths::Paths;
use stack_graphs::paths::ScopedSymbol;
use stack_graphs::paths::SymbolStack;
use stack_graphs::stitching::Database;
use stack_graphs::stitching::SymbolStackKey;
use crate::test_graphs;
fn check_root_partial_paths(
graph: &mut StackGraph,
file: &str,
precondition: &[&str],
expected_partial_paths: &[&str],
) {
let file = graph.get_file_unchecked(file);
let mut paths = Paths::new();
let mut partials = PartialPaths::new();
let mut database = Database::new();
partials.find_all_partial_paths_in_file(graph, file, |graph, partials, path| {
if !path.is_complete_as_possible(graph) {
return;
}
if !path.is_productive(partials) {
return;
}
database.add_partial_path(graph, partials, path);
});
let mut symbol_stack = SymbolStack::empty();
for symbol in precondition.iter().rev() {
let symbol = graph.add_symbol(symbol);
let scoped_symbol = ScopedSymbol {
symbol,
scopes: ControlledOption::none(),
};
symbol_stack.push_front(&mut paths, scoped_symbol);
}
let mut results = Vec::<Handle<PartialPath>>::new();
let key = SymbolStackKey::from_symbol_stack(&mut paths, &mut database, symbol_stack);
database.find_candidate_partial_paths_from_root(graph, &mut partials, key, &mut results);
let actual_partial_paths = results
.into_iter()
.map(|path| database[path].display(graph, &mut partials).to_string())
.collect::<HashSet<_>>();
let expected_partial_paths = expected_partial_paths
.iter()
.map(|s| s.to_string())
.collect::<HashSet<_>>();
assert_eq!(actual_partial_paths, expected_partial_paths);
}
#[test]
fn class_field_through_function_parameter() {
let mut graph = test_graphs::class_field_through_function_parameter::new();
check_root_partial_paths(
&mut graph,
"main.py",
&["__main__", ".", "baz"],
&[
"<__main__.,%1> ($1) [root] -> [root] <a.,%1> ($1)",
"<__main__.,%1> ($1) [root] -> [root] <b.,%1> ($1)",
"<__main__,%1> ($1) [root] -> [main.py(0) definition __main__] <%1> ($1)",
],
);
check_root_partial_paths(
&mut graph,
"a.py",
&["a", ".", "baz"],
&["<a,%1> ($1) [root] -> [a.py(0) definition a] <%1> ($1)"],
);
check_root_partial_paths(
&mut graph,
"b.py",
&["b", ".", "baz"],
&["<b,%1> ($1) [root] -> [b.py(0) definition b] <%1> ($1)"],
);
}
#[test]
fn cyclic_imports_python() {
let mut graph = test_graphs::cyclic_imports_python::new();
check_root_partial_paths(
&mut graph,
"main.py",
&["__main__", ".", "baz"],
&[
"<__main__,%1> ($1) [root] -> [main.py(0) definition __main__] <%1> ($1)",
"<__main__.,%1> ($1) [root] -> [root] <a.,%1> ($1)",
],
);
check_root_partial_paths(
&mut graph,
"a.py",
&["a", ".", "baz"],
&[
"<a,%1> ($1) [root] -> [a.py(0) definition a] <%1> ($1)",
"<a.,%1> ($1) [root] -> [root] <b.,%1> ($1)",
],
);
check_root_partial_paths(
&mut graph,
"b.py",
&["b", ".", "baz"],
&[
"<b,%1> ($1) [root] -> [b.py(0) definition b] <%1> ($1)",
"<b.,%1> ($1) [root] -> [root] <a.,%1> ($1)",
],
);
}
#[test]
fn cyclic_imports_rust() {
let mut graph = test_graphs::cyclic_imports_rust::new();
check_root_partial_paths(
&mut graph,
"test.rs",
&[],
&[],
);
}
#[test]
fn sequenced_import_star() {
let mut graph = test_graphs::sequenced_import_star::new();
check_root_partial_paths(
&mut graph,
"main.py",
&["__main__", ".", "baz"],
&[
"<__main__,%1> ($1) [root] -> [main.py(0) definition __main__] <%1> ($1)",
"<__main__.,%1> ($1) [root] -> [root] <a.,%1> ($1)",
],
);
check_root_partial_paths(
&mut graph,
"a.py",
&["a", ".", "baz"],
&[
"<a,%1> ($1) [root] -> [a.py(0) definition a] <%1> ($1)",
"<a.,%1> ($1) [root] -> [root] <b.,%1> ($1)",
],
);
check_root_partial_paths(
&mut graph,
"b.py",
&["b", ".", "baz"],
&["<b,%1> ($1) [root] -> [b.py(0) definition b] <%1> ($1)"],
);
}