use splice::graph::CodeGraph;
use splice::ingest::extract_java_symbols;
use splice::patch::apply_patch_with_validation;
use splice::resolve::resolve_symbol;
use splice::symbol::Language;
use splice::validate::AnalyzerMode;
use tempfile::TempDir;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_java_patch_succeeds_with_all_gates() {
let workspace_dir = TempDir::new().expect("Failed to create temp workspace");
let workspace_path = workspace_dir.path();
let java_path = workspace_path.join("Test.java");
let source = r#"
public class Test {
public int greet() {
return 0;
}
public int farewell() {
return 0;
}
}
"#;
std::fs::write(&java_path, source).expect("Failed to write Test.java");
let graph_db_path = workspace_path.join("graph.db");
let mut code_graph =
CodeGraph::open(&graph_db_path).expect("Failed to open graph database");
let symbols =
extract_java_symbols(&java_path, source.as_bytes()).expect("Failed to parse Test.java");
assert!(
symbols.len() >= 2,
"Expected at least 2 symbols (class + methods)"
);
for symbol in &symbols {
code_graph
.store_symbol_with_file_and_language(
&java_path,
&symbol.name,
symbol.kind.as_str(),
Language::Java,
symbol.byte_start,
symbol.byte_end,
symbol.line_start,
symbol.line_end,
symbol.col_start,
symbol.col_end,
)
.expect("Failed to store symbol");
}
let resolved = resolve_symbol(&code_graph, Some(&java_path), Some("method"), "greet")
.expect("Failed to resolve greet method");
let new_body = r#"
public int greet() {
return 42;
}"#;
let result = apply_patch_with_validation(
&java_path,
resolved.byte_start,
resolved.byte_end,
new_body.trim(),
workspace_path,
Language::Java,
AnalyzerMode::Off,
false, false, );
if result.is_ok() {
let new_content =
std::fs::read_to_string(&java_path).expect("Failed to read patched file");
assert!(
new_content.contains("return 42;"),
"Patched content should be present"
);
} else {
println!("javac not available, skipping full patch validation test");
}
}
#[test]
fn test_java_patch_rejected_on_syntax_gate() {
let workspace_dir = TempDir::new().expect("Failed to create temp workspace");
let workspace_path = workspace_dir.path();
let java_path = workspace_path.join("Test.java");
let source = r#"
public class Test {
public int validMethod() {
return 42;
}
}
"#;
std::fs::write(&java_path, source).expect("Failed to write Test.java");
let graph_db_path = workspace_path.join("graph.db");
let mut code_graph =
CodeGraph::open(&graph_db_path).expect("Failed to open graph database");
let symbols =
extract_java_symbols(&java_path, source.as_bytes()).expect("Failed to parse Test.java");
let method = symbols
.iter()
.find(|s| s.name == "validMethod")
.expect("Should find validMethod");
code_graph
.store_symbol_with_file_and_language(
&java_path,
&method.name,
method.kind.as_str(),
Language::Java,
method.byte_start,
method.byte_end,
method.line_start,
method.line_end,
method.col_start,
method.col_end,
)
.expect("Failed to store symbol");
let resolved = resolve_symbol(&code_graph, Some(&java_path), Some("method"), "validMethod")
.expect("Failed to resolve method");
let replaced_content =
std::fs::read_to_string(&java_path).expect("Failed to read replaced file");
let invalid_patch = r#"
public int validMethod() {
return 42;
"#;
let result = apply_patch_with_validation(
&java_path,
resolved.byte_start,
resolved.byte_end,
invalid_patch.trim(),
workspace_path,
Language::Java,
AnalyzerMode::Off,
false, false, );
assert!(
result.is_err(),
"Patch should fail on syntax error: {:?}",
result
);
let current_content =
std::fs::read_to_string(&java_path).expect("Failed to read current file");
assert_eq!(
replaced_content, current_content,
"File should be unchanged after failed patch (atomic rollback)"
);
}
#[test]
fn test_java_class_patch_succeeds() {
let workspace_dir = TempDir::new().expect("Failed to create temp workspace");
let workspace_path = workspace_dir.path();
let java_path = workspace_path.join("Calculator.java");
let source = r#"
public class Calculator {
public int add(int a, int b) {
return a + b;
}
}
"#;
std::fs::write(&java_path, source).expect("Failed to write Calculator.java");
let graph_db_path = workspace_path.join("graph.db");
let mut code_graph =
CodeGraph::open(&graph_db_path).expect("Failed to open graph database");
let symbols = extract_java_symbols(&java_path, source.as_bytes())
.expect("Failed to parse Calculator.java");
let class = symbols
.iter()
.find(|s| s.kind.as_str() == "class")
.expect("Should find class symbol");
code_graph
.store_symbol_with_file_and_language(
&java_path,
&class.name,
class.kind.as_str(),
Language::Java,
class.byte_start,
class.byte_end,
class.line_start,
class.line_end,
class.col_start,
class.col_end,
)
.expect("Failed to store symbol");
let resolved = resolve_symbol(&code_graph, Some(&java_path), Some("class"), "Calculator")
.expect("Failed to resolve class");
let new_body = r#"
public class Calculator {
public int add(int a, int b) {
return a + b;
}
public int subtract(int a, int b) {
return a - b;
}
}
"#;
let result = apply_patch_with_validation(
&java_path,
resolved.byte_start,
resolved.byte_end,
new_body.trim(),
workspace_path,
Language::Java,
AnalyzerMode::Off,
false, false, );
if result.is_ok() {
let new_content =
std::fs::read_to_string(&java_path).expect("Failed to read patched file");
assert!(
new_content.contains("subtract"),
"Patched content should be present"
);
} else {
println!("javac not available, skipping Java class patch validation");
}
}
}