#![cfg(feature = "external-tools-cfg")]
use std::io::Write;
use tempfile::NamedTempFile;
#[test]
fn test_clang_detection() {
if !magellan::graph::external_tools::tool_detector::is_tool_available("clang") {
return;
}
let version = magellan::graph::external_tools::tool_detector::check_clang_version();
assert!(version.is_ok());
}
#[test]
fn test_javac_detection() {
if !magellan::graph::external_tools::tool_detector::is_tool_available("javac") {
return;
}
let version = magellan::graph::external_tools::tool_detector::check_javac_version();
assert!(version.is_ok());
}
#[test]
fn test_cpp_cfg_extraction_simple() {
if !magellan::graph::external_tools::tool_detector::is_tool_available("clang") {
return;
}
let source = r#"
int test_if_else(int x) {
if (x > 0) {
return x * 2;
} else {
return x + 1;
}
}
"#;
let mut temp_file = NamedTempFile::with_suffix(".c").unwrap();
temp_file.write_all(source.as_bytes()).unwrap();
let source_path = temp_file.path();
let result = magellan::graph::external_tools::c_cpp::extract_cfg_from_cpp(source_path);
assert!(
result.is_ok(),
"CFG extraction should succeed for valid C code"
);
let cfg = result.unwrap();
assert!(!cfg.blocks.is_empty(), "CFG should have at least one block");
assert!(!cfg.edges.is_empty(), "CFG should have at least one edge");
}
#[test]
fn test_cpp_cfg_extraction_complex() {
if !magellan::graph::external_tools::tool_detector::is_tool_available("clang") {
return;
}
let source = r#"
int test_switch(int x) {
switch (x) {
case 1:
return 10;
case 2:
return 20;
default:
return 0;
}
}
"#;
let mut temp_file = NamedTempFile::with_suffix(".c").unwrap();
temp_file.write_all(source.as_bytes()).unwrap();
let source_path = temp_file.path();
let result = magellan::graph::external_tools::c_cpp::extract_cfg_from_cpp(source_path);
assert!(result.is_ok());
let cfg = result.unwrap();
assert!(!cfg.blocks.is_empty());
}
#[test]
fn test_cpp_cfg_extraction() {
if !magellan::graph::external_tools::tool_detector::is_tool_available("clang") {
return;
}
let source = r#"
extern "C" int cpp_function(int x) {
if (x > 0) {
return x * 2;
}
return x;
}
"#;
let mut temp_file = NamedTempFile::with_suffix(".cpp").unwrap();
temp_file.write_all(source.as_bytes()).unwrap();
let source_path = temp_file.path();
let result = magellan::graph::external_tools::c_cpp::extract_cfg_from_cpp(source_path);
assert!(result.is_ok());
let cfg = result.unwrap();
assert!(!cfg.blocks.is_empty());
}
#[test]
fn test_java_cfg_extraction() {
if !magellan::graph::external_tools::tool_detector::is_tool_available("javac") {
return;
}
let source = r#"
public class TestCFG {
public static int testIfElse(int x) {
if (x > 0) {
return x * 2;
} else {
return x + 1;
}
}
public static int testSwitch(int x) {
switch (x) {
case 1:
return 10;
case 2:
return 20;
default:
return 0;
}
}
}
"#;
let mut temp_file = NamedTempFile::with_suffix(".java").unwrap();
temp_file.write_all(source.as_bytes()).unwrap();
let source_path = temp_file.path();
let result = magellan::graph::external_tools::java::extract_cfg_from_java(source_path);
assert!(
result.is_ok(),
"CFG extraction should succeed for valid Java code"
);
let cfg = result.unwrap();
assert!(!cfg.blocks.is_empty(), "CFG should have at least one block");
assert!(!cfg.edges.is_empty(), "CFG should have at least one edge");
}
#[test]
fn test_graceful_fallback_clang_missing() {
let source = r#"
int test_func(int x) {
return x + 1;
}
"#;
let mut temp_file = NamedTempFile::with_suffix(".c").unwrap();
temp_file.write_all(source.as_bytes()).unwrap();
let source_path = temp_file.path();
let _ = magellan::graph::external_tools::c_cpp::extract_cfg_from_cpp(source_path);
}
#[test]
fn test_graceful_fallback_javac_missing() {
let source = r#"
public class TestFunc {
public static int test(int x) {
return x + 1;
}
}
"#;
let mut temp_file = NamedTempFile::with_suffix(".java").unwrap();
temp_file.write_all(source.as_bytes()).unwrap();
let source_path = temp_file.path();
let _ = magellan::graph::external_tools::java::extract_cfg_from_java(source_path);
}
#[test]
fn test_cpp_function_extraction() {
if !magellan::graph::external_tools::tool_detector::is_tool_available("clang") {
return;
}
let source = r#"
int foo(int x) {
return x + 1;
}
int bar(int x) {
return x * 2;
}
"#;
let mut temp_file = NamedTempFile::with_suffix(".c").unwrap();
temp_file.write_all(source.as_bytes()).unwrap();
let source_path = temp_file.path();
let result =
magellan::graph::external_tools::c_cpp::extract_cfg_for_function(source_path, "foo");
assert!(result.is_ok());
let cfg = result.unwrap();
assert!(!cfg.blocks.is_empty());
}
#[test]
fn test_java_method_extraction() {
if !magellan::graph::external_tools::tool_detector::is_tool_available("javac") {
return;
}
let source = r#"
public class TestMethods {
public static int methodA(int x) {
return x + 1;
}
public static int methodB(int x) {
return x * 2;
}
}
"#;
let mut temp_file = NamedTempFile::with_suffix(".java").unwrap();
temp_file.write_all(source.as_bytes()).unwrap();
let source_path = temp_file.path();
let result =
magellan::graph::external_tools::java::extract_cfg_for_method(source_path, "methodA");
assert!(result.is_ok());
let cfg = result.unwrap();
assert!(!cfg.blocks.is_empty());
}
#[test]
fn test_cpp_invalid_code() {
if !magellan::graph::external_tools::tool_detector::is_tool_available("clang") {
return;
}
let source = r#"
int broken_func(int x {
// Missing closing parenthesis
return x;
}
"#;
let mut temp_file = NamedTempFile::with_suffix(".c").unwrap();
temp_file.write_all(source.as_bytes()).unwrap();
let source_path = temp_file.path();
let result = magellan::graph::external_tools::c_cpp::extract_cfg_from_cpp(source_path);
assert!(result.is_err());
}
#[test]
fn test_java_invalid_code() {
if !magellan::graph::external_tools::tool_detector::is_tool_available("javac") {
return;
}
let source = r#"
public class Broken {
public static void broken( {
// Missing closing parenthesis
}
}
"#;
let mut temp_file = NamedTempFile::with_suffix(".java").unwrap();
temp_file.write_all(source.as_bytes()).unwrap();
let source_path = temp_file.path();
let result = magellan::graph::external_tools::java::extract_cfg_from_java(source_path);
assert!(result.is_err());
}
#[test]
fn test_tool_detector_error_messages() {
let result = magellan::graph::external_tools::tool_detector::find_clang();
let _ = (result.is_ok(), result);
let clang_instructions =
magellan::graph::external_tools::tool_detector::get_clang_install_instructions();
assert!(!clang_instructions.is_empty());
let javac_instructions =
magellan::graph::external_tools::tool_detector::get_javac_install_instructions();
assert!(!javac_instructions.is_empty());
}
#[test]
fn test_cross_platform_detection() {
#[cfg(unix)]
{
let name = magellan::graph::external_tools::tool_detector::get_executable_name("clang");
assert_eq!(name, "clang");
}
#[cfg(windows)]
{
let name = magellan::graph::external_tools::tool_detector::get_executable_name("clang");
assert_eq!(name, "clang.exe");
}
let _ = magellan::graph::external_tools::tool_detector::is_tool_available("nonexistent_tool");
}