use std::path::Path;
#[test]
#[cfg(feature = "geometric")]
fn splice_can_compute_reachable_symbols_on_geo() {
if !Path::new("./code.geo").exists() {
eprintln!("SKIP: No code.geo file available");
return;
}
let mut integration =
splice::graph::magellan_integration::MagellanIntegration::open(Path::new("./code.geo"))
.unwrap();
let symbols = integration
.find_symbol_by_name("reachable_symbols", false)
.unwrap();
if let Some(symbol) = symbols.first() {
let file_path = Path::new(&symbol.file_path);
let reachable = integration.reachable_symbols(file_path, &symbol.name, 2);
assert!(
reachable.is_ok(),
"Should compute reachable symbols without error"
);
let reachable = reachable.unwrap();
eprintln!(
"Symbol '{}' has {} reachable symbols at depth <= 2",
symbol.name,
reachable.len()
);
for r in &reachable {
assert!(
!r.symbol.name.is_empty(),
"Reachable symbol should have a name"
);
assert!(
!r.symbol.file_path.is_empty(),
"Reachable symbol should have a file path"
);
assert!(r.depth > 0 && r.depth <= 2, "Depth should be within range");
}
} else {
eprintln!("SKIP: No 'reachable_symbols' function found to test");
}
}
#[test]
#[cfg(feature = "geometric")]
fn splice_can_compute_reverse_reachable_symbols_on_geo() {
if !Path::new("./code.geo").exists() {
eprintln!("SKIP: No code.geo file available");
return;
}
let mut integration =
splice::graph::magellan_integration::MagellanIntegration::open(Path::new("./code.geo"))
.unwrap();
let symbols = integration
.find_symbol_by_name("reachable_symbols", false)
.unwrap();
if let Some(symbol) = symbols.first() {
let file_path = Path::new(&symbol.file_path);
let callers = integration.reverse_reachable_symbols(file_path, &symbol.name, 2);
assert!(
callers.is_ok(),
"Should compute reverse reachable symbols without error"
);
let callers = callers.unwrap();
eprintln!(
"Symbol '{}' has {} reverse reachable symbols at depth <= 2",
symbol.name,
callers.len()
);
for c in &callers {
assert!(
!c.symbol.name.is_empty(),
"Caller symbol should have a name"
);
assert!(
!c.symbol.file_path.is_empty(),
"Caller symbol should have a file path"
);
assert!(c.depth > 0 && c.depth <= 2, "Depth should be within range");
}
} else {
eprintln!("SKIP: No 'reachable_symbols' function found to test");
}
}
#[test]
#[cfg(feature = "geometric")]
fn splice_can_detect_cycles_on_geo() {
if !Path::new("./code.geo").exists() {
eprintln!("SKIP: No code.geo file available");
return;
}
let mut integration =
splice::graph::magellan_integration::MagellanIntegration::open(Path::new("./code.geo"))
.unwrap();
let cycles = integration.detect_cycles(100);
assert!(cycles.is_ok(), "Should detect cycles without error");
let cycles = cycles.unwrap();
eprintln!("Detected {} cycles in call graph", cycles.len());
for cycle in &cycles {
assert!(!cycle.id.is_empty(), "Cycle should have an ID");
assert!(cycle.size > 0, "Cycle should have at least one member");
assert!(!cycle.members.is_empty(), "Cycle should have members");
for member in &cycle.members {
assert!(!member.name.is_empty(), "Cycle member should have a name");
}
}
}
#[test]
#[cfg(feature = "geometric")]
fn splice_can_detect_dead_symbols_on_geo() {
if !Path::new("./code.geo").exists() {
eprintln!("SKIP: No code.geo file available");
return;
}
let mut integration =
splice::graph::magellan_integration::MagellanIntegration::open(Path::new("./code.geo"))
.unwrap();
let main_symbols = integration.find_symbol_by_name("main", false).unwrap();
if let Some(main_symbol) = main_symbols.first() {
let entry_file = Path::new(&main_symbol.file_path);
let dead = integration.dead_symbols(entry_file, "main", false);
assert!(dead.is_ok(), "Should detect dead symbols without error");
let dead = dead.unwrap();
eprintln!(
"Found {} potentially dead symbols from main entry point",
dead.len()
);
for d in &dead {
assert!(!d.symbol.name.is_empty(), "Dead symbol should have a name");
assert!(
!d.symbol.file_path.is_empty(),
"Dead symbol should have a file path"
);
assert!(!d.reason.is_empty(), "Dead symbol should have a reason");
}
} else {
eprintln!("SKIP: No 'main' function found as entry point");
}
}
#[test]
fn splice_sqlite_backend_still_works_for_batch2() {
use std::io::Write;
use tempfile::NamedTempFile;
let temp_file = NamedTempFile::with_suffix(".db").unwrap();
let integration =
splice::graph::magellan_integration::MagellanIntegration::open(temp_file.path());
match integration {
Ok(mut integ) => {
assert!(!integ.is_geometric(), "Should be SQLite backend");
let temp_path = temp_file.path();
let reachable = integ.reachable_symbols(temp_path, "nonexistent", 2);
match reachable {
Ok(symbols) => {
eprintln!(
"SQLite reachable_symbols returned {} symbols (expected 0 for empty DB)",
symbols.len()
);
}
Err(e) => {
let err_str = format!("{}", e);
assert!(
!err_str.contains("Geometric backend"),
"SQLite should not fail with geometric error: {}",
err_str
);
eprintln!(
"SQLite reachable_symbols error (expected for empty DB): {}",
err_str
);
}
}
let cycles = integ.detect_cycles(100);
match cycles {
Ok(c) => {
eprintln!(
"SQLite detect_cycles returned {} cycles (expected 0 for empty DB)",
c.len()
);
}
Err(e) => {
let err_str = format!("{}", e);
assert!(
!err_str.contains("Geometric backend"),
"SQLite should not fail with geometric error: {}",
err_str
);
eprintln!(
"SQLite detect_cycles error (expected for empty DB): {}",
err_str
);
}
}
}
Err(e) => {
let err_str = format!("{}", e);
assert!(
!err_str.contains("Geometric backend"),
"SQLite backend should not fail with geometric error: {}",
err_str
);
eprintln!("SQLite open error (OK for this test): {}", err_str);
}
}
}