mod common;
use common::sqry_bin;
use assert_cmd::Command;
use predicates::prelude::*;
use std::fs;
use tempfile::TempDir;
use sqry_core::graph::unified::persistence::{GraphStorage, Manifest};
use sqry_core::test_support::verbosity;
use std::sync::Once;
static INIT: Once = Once::new();
fn init_logging() {
INIT.call_once(|| {
verbosity::init(env!("CARGO_PKG_NAME"));
});
}
fn create_rust_fixture(dir: &std::path::Path) {
let rust_code = r"
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
pub fn multiply(x: i32, y: i32) -> i32 {
x * y
}
pub struct Calculator {
value: i32,
}
impl Calculator {
pub fn new() -> Self {
Self { value: 0 }
}
pub fn compute(&self) -> i32 {
add(self.value, multiply(2, 3))
}
}
";
fs::write(dir.join("lib.rs"), rust_code).unwrap();
}
#[test]
fn test_graph_mode_always_enabled() {
init_logging();
log::info!("Testing that graph mode is always enabled");
let tmp_dir = TempDir::new().unwrap();
create_rust_fixture(tmp_dir.path());
let path = sqry_bin();
let mut cmd = Command::new(path);
cmd.arg("index").arg(tmp_dir.path()).assert().success();
let path2 = sqry_bin();
let mut query_cmd = Command::new(path2);
query_cmd
.arg("query")
.arg("kind:function")
.arg(tmp_dir.path())
.assert()
.success()
.stdout(predicate::str::contains("add"));
log::info!("✓ Graph mode is always enabled");
}
#[test]
fn test_deprecated_env_var_is_ignored() {
init_logging();
log::info!("Testing that SQRY_USE_GRAPH does not break indexing");
let tmp_dir = TempDir::new().unwrap();
create_rust_fixture(tmp_dir.path());
let path = sqry_bin();
let mut cmd = Command::new(path);
cmd.env("SQRY_USE_GRAPH", "1")
.arg("index")
.arg(tmp_dir.path())
.assert()
.success();
log::info!("✓ Deprecated env var ignored (index still succeeds)");
}
#[test]
fn test_graph_mode_multi_language() {
init_logging();
log::info!("Testing graph mode with multiple languages");
let tmp_dir = TempDir::new().unwrap();
create_rust_fixture(tmp_dir.path());
let js_code = r"
class ShoppingCart {
constructor() {
this.items = [];
}
addItem(item) {
this.items.push(item);
}
getTotal() {
return this.items.reduce((sum, item) => sum + item.price, 0);
}
}
export { ShoppingCart };
";
fs::write(tmp_dir.path().join("cart.js"), js_code).unwrap();
let py_code = r"
def calculate_total(items):
return sum(item['price'] for item in items)
class Cart:
def __init__(self):
self.items = []
def add_item(self, item):
self.items.append(item)
";
fs::write(tmp_dir.path().join("cart.py"), py_code).unwrap();
let path = sqry_bin();
let mut cmd = Command::new(path);
cmd.arg("index").arg(tmp_dir.path()).assert().success();
let languages = vec![
("Rust", "add"),
("JavaScript", "ShoppingCart"),
("Python", "Cart"),
];
for (lang, symbol) in languages {
let path_lang = sqry_bin();
let mut query_cmd = Command::new(path_lang);
query_cmd
.arg("query")
.arg(format!("name:{symbol}"))
.arg(tmp_dir.path())
.assert()
.success()
.stdout(predicate::str::contains(symbol));
log::info!(" ✓ {lang} symbols indexed correctly");
}
log::info!("✓ Multi-language graph mode indexing successful");
}
#[test]
fn test_graph_mode_update_command() {
init_logging();
log::info!("Testing graph mode with 'update' command");
let tmp_dir = TempDir::new().unwrap();
create_rust_fixture(tmp_dir.path());
let path = sqry_bin();
let mut cmd = Command::new(path);
cmd.arg("index").arg(tmp_dir.path()).assert().success();
let graph_storage = GraphStorage::new(tmp_dir.path());
let manifest_path = graph_storage.manifest_path();
assert!(
manifest_path.exists(),
"Graph manifest should exist after index"
);
let manifest_before =
Manifest::load(manifest_path).expect("Failed to load graph manifest after index");
let new_code = r"
pub fn subtract(a: i32, b: i32) -> i32 {
a - b
}
";
fs::write(tmp_dir.path().join("math.rs"), new_code).unwrap();
let path2 = sqry_bin();
let mut update_cmd = Command::new(path2);
update_cmd
.arg("update")
.arg(tmp_dir.path())
.assert()
.success();
let manifest_after =
Manifest::load(manifest_path).expect("Failed to load graph manifest after update");
assert_ne!(
manifest_before.snapshot_sha256, manifest_after.snapshot_sha256,
"Graph snapshot checksum should change after update"
);
assert_ne!(
manifest_before.built_at, manifest_after.built_at,
"Graph manifest timestamp should change after update"
);
let path3 = sqry_bin();
let mut query_cmd = Command::new(path3);
query_cmd
.arg("query")
.arg("name:subtract")
.arg(tmp_dir.path())
.assert()
.success()
.stdout(predicate::str::contains("subtract"));
log::info!("✓ Graph mode update command successful");
}
#[test]
fn test_graph_mode_large_fixture() {
init_logging();
log::info!("Testing graph mode with larger fixture (20 files)");
let tmp_dir = TempDir::new().unwrap();
for i in 0..20 {
let code = format!(
r"
pub fn func_{i}_a() -> i32 {{
{i}
}}
pub fn func_{i}_b() -> i32 {{
func_{i}_a() + 1
}}
pub struct Struct{i} {{
pub value: i32,
}}
"
);
fs::write(tmp_dir.path().join(format!("file_{i}.rs")), code).unwrap();
}
let path = sqry_bin();
let mut cmd = Command::new(path);
cmd.arg("index").arg(tmp_dir.path()).assert().success();
let path2 = sqry_bin();
let mut query_cmd = Command::new(path2);
query_cmd
.arg("query")
.arg("kind:function")
.arg(tmp_dir.path())
.assert()
.success();
log::info!("✓ Large fixture (20 files) indexed successfully with graph mode");
}
#[test]
fn test_graph_mode_with_incremental() {
init_logging();
log::info!("Testing graph mode with incremental indexing");
let tmp_dir = TempDir::new().unwrap();
create_rust_fixture(tmp_dir.path());
let config_content = r"
enable_incremental = true
";
fs::write(tmp_dir.path().join(".sqry-config.toml"), config_content).unwrap();
let path = sqry_bin();
let mut cmd = Command::new(path);
cmd.current_dir(tmp_dir.path())
.arg("index")
.arg(".")
.assert()
.success();
let modified_code = r#"
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
pub fn new_function() -> String {
"Hello".to_string()
}
"#;
fs::write(tmp_dir.path().join("lib.rs"), modified_code).unwrap();
let path2 = sqry_bin();
let mut update_cmd = Command::new(path2);
update_cmd
.current_dir(tmp_dir.path())
.arg("update")
.arg(".")
.assert()
.success();
let path3 = sqry_bin();
let mut query_cmd = Command::new(path3);
query_cmd
.current_dir(tmp_dir.path())
.arg("query")
.arg("name:new_function")
.arg(".")
.assert()
.success()
.stdout(predicate::str::contains("new_function"));
log::info!("✓ Graph mode with incremental indexing successful");
}