use std::path::Path;
use sqry_core::graph::unified::build::{BuildConfig, build_unified_graph};
use sqry_core::graph::unified::concurrent::CodeGraph;
use sqry_core::plugin::PluginManager;
use sqry_lang_rust::RustPlugin;
fn create_rust_plugin_manager() -> PluginManager {
let mut manager = PluginManager::new();
manager.register_builtin(Box::new(RustPlugin::default()));
manager
}
fn cli_basic_fixtures() -> std::path::PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR"))
.parent()
.expect("sqry-core should have a parent directory")
.join("test-fixtures/cli-basic")
}
#[derive(Debug, PartialEq, Eq)]
struct GraphSnapshot {
node_count: usize,
edge_count: usize,
node_names: Vec<(String, String)>,
edge_triples: Vec<(String, String, String)>,
}
fn build_with_threads(threads: usize) -> GraphSnapshot {
let plugins = create_rust_plugin_manager();
let config = BuildConfig {
num_threads: Some(threads),
..BuildConfig::default()
};
let graph = build_unified_graph(&cli_basic_fixtures(), &plugins, &config)
.expect("graph build should succeed");
snapshot(&graph)
}
fn snapshot(graph: &CodeGraph) -> GraphSnapshot {
let strings = graph.strings();
let nodes = graph.nodes();
let edges = graph.edges();
let mut node_names: Vec<(String, String)> = nodes
.iter()
.map(|(_id, entry)| {
let name = strings
.resolve(entry.name)
.map_or_else(|| "<unresolved>".to_string(), |s| s.to_string());
let kind = format!("{:?}", entry.kind);
(name, kind)
})
.collect();
node_names.sort();
let mut edge_triples: Vec<(String, String, String)> = Vec::new();
for (src_id, src_entry) in nodes.iter() {
let src_name = strings
.resolve(src_entry.name)
.map_or_else(|| format!("node#{}", src_id.index()), |s| s.to_string());
for edge_ref in edges.edges_from(src_id) {
let tgt_name = nodes
.get(edge_ref.target)
.and_then(|e| strings.resolve(e.name))
.map_or_else(
|| format!("node#{}", edge_ref.target.index()),
|s| s.to_string(),
);
let kind = format!("{:?}", edge_ref.kind);
edge_triples.push((src_name.clone(), tgt_name, kind));
}
}
edge_triples.sort();
GraphSnapshot {
node_count: graph.node_count(),
edge_count: graph.edge_count(),
node_names,
edge_triples,
}
}
#[test]
fn serial_and_parallel_builds_produce_same_content() {
let serial = build_with_threads(1);
let parallel = build_with_threads(4);
assert!(
serial.node_count > 0,
"serial build should produce at least one node"
);
assert!(
serial.edge_count > 0,
"serial build should produce at least one edge"
);
assert_eq!(
serial, parallel,
"serial vs parallel(4) graph content differs"
);
}
#[test]
fn repeated_parallel_builds_are_stable() {
let first = build_with_threads(4);
let second = build_with_threads(4);
let third = build_with_threads(4);
assert_eq!(first, second, "parallel builds 1 and 2 differ");
assert_eq!(second, third, "parallel builds 2 and 3 differ");
}
#[test]
fn varying_thread_counts_agree() {
let baseline = build_with_threads(1);
for threads in [2, 3, 4, 8] {
let result = build_with_threads(threads);
assert_eq!(
baseline, result,
"thread count {threads} produced different graph content vs serial baseline"
);
}
}