use super::*;
use std::path::{Path, PathBuf};
#[test]
fn test_pipeline_context_creation() {
let input = PathBuf::from("/input");
let output = PathBuf::from("/output");
let ctx = PipelineContext::new(input.clone(), output.clone());
assert_eq!(ctx.input_path, input);
assert_eq!(ctx.output_path, output);
assert!(ctx.primary_language.is_none());
assert!(ctx.file_mappings.is_empty());
assert!(ctx.optimizations.is_empty());
assert!(ctx.validation_results.is_empty());
assert!(ctx.metadata.is_empty());
}
#[test]
fn test_pipeline_context_with_language() {
let mut ctx = PipelineContext::new(PathBuf::from("/input"), PathBuf::from("/output"));
ctx.primary_language = Some(crate::types::Language::Python);
assert_eq!(ctx.primary_language, Some(crate::types::Language::Python));
}
#[test]
fn test_pipeline_context_file_mappings() {
let mut ctx = PipelineContext::new(PathBuf::from("/input"), PathBuf::from("/output"));
ctx.file_mappings.push((PathBuf::from("/input/main.py"), PathBuf::from("/output/src/main.rs")));
assert_eq!(ctx.file_mappings.len(), 1);
assert_eq!(ctx.file_mappings[0].0, PathBuf::from("/input/main.py"));
assert_eq!(ctx.file_mappings[0].1, PathBuf::from("/output/src/main.rs"));
}
#[test]
fn test_pipeline_context_optimizations() {
let mut ctx = PipelineContext::new(PathBuf::from("/input"), PathBuf::from("/output"));
ctx.optimizations.push("SIMD enabled".to_string());
ctx.optimizations.push("GPU dispatch enabled".to_string());
assert_eq!(ctx.optimizations.len(), 2);
assert_eq!(ctx.optimizations[0], "SIMD enabled");
assert_eq!(ctx.optimizations[1], "GPU dispatch enabled");
}
#[test]
fn test_pipeline_context_validation_results() {
let mut ctx = PipelineContext::new(PathBuf::from("/input"), PathBuf::from("/output"));
ctx.validation_results.push(ValidationResult {
stage: "Analysis".to_string(),
passed: true,
message: "Language detected".to_string(),
details: None,
});
assert_eq!(ctx.validation_results.len(), 1);
assert!(ctx.validation_results[0].passed);
assert_eq!(ctx.validation_results[0].stage, "Analysis");
}
#[test]
fn test_pipeline_context_metadata() {
let mut ctx = PipelineContext::new(PathBuf::from("/input"), PathBuf::from("/output"));
ctx.metadata.insert("total_files".to_string(), serde_json::json!(42));
ctx.metadata.insert("language".to_string(), serde_json::json!("Python"));
assert_eq!(ctx.metadata.len(), 2);
assert_eq!(ctx.metadata.get("total_files").unwrap(), &serde_json::json!(42));
assert_eq!(ctx.metadata.get("language").unwrap(), &serde_json::json!("Python"));
}
#[test]
fn test_pipeline_context_output() {
let mut ctx = PipelineContext::new(PathBuf::from("/input"), PathBuf::from("/output"));
ctx.file_mappings.push((PathBuf::from("/input/main.py"), PathBuf::from("/output/main.rs")));
ctx.optimizations.push("SIMD".to_string());
ctx.validation_results.push(ValidationResult {
stage: "Test".to_string(),
passed: true,
message: "OK".to_string(),
details: None,
});
let output = ctx.output();
assert_eq!(output.output_path, PathBuf::from("/output"));
assert_eq!(output.file_mappings.len(), 1);
assert_eq!(output.optimizations.len(), 1);
assert!(output.validation_passed);
}
#[test]
fn test_pipeline_context_output_validation_failed() {
let mut ctx = PipelineContext::new(PathBuf::from("/input"), PathBuf::from("/output"));
ctx.validation_results.push(ValidationResult {
stage: "Stage1".to_string(),
passed: true,
message: "OK".to_string(),
details: None,
});
ctx.validation_results.push(ValidationResult {
stage: "Stage2".to_string(),
passed: false,
message: "Failed".to_string(),
details: None,
});
let output = ctx.output();
assert!(!output.validation_passed);
}
#[test]
fn test_validation_result_passed() {
let result = ValidationResult {
stage: "TestStage".to_string(),
passed: true,
message: "All checks passed".to_string(),
details: None,
};
assert_eq!(result.stage, "TestStage");
assert!(result.passed);
assert_eq!(result.message, "All checks passed");
assert!(result.details.is_none());
}
#[test]
fn test_validation_result_failed() {
let result = ValidationResult {
stage: "TestStage".to_string(),
passed: false,
message: "Check failed".to_string(),
details: Some(serde_json::json!({"error": "details here"})),
};
assert_eq!(result.stage, "TestStage");
assert!(!result.passed);
assert_eq!(result.message, "Check failed");
assert!(result.details.is_some());
}
#[test]
fn test_validation_result_with_details() {
let details = serde_json::json!({
"errors": ["error1", "error2"],
"warnings": ["warning1"]
});
let result = ValidationResult {
stage: "Analysis".to_string(),
passed: false,
message: "Multiple issues found".to_string(),
details: Some(details.clone()),
};
assert_eq!(result.details, Some(details));
}
#[test]
fn test_validation_strategy_equality() {
assert_eq!(ValidationStrategy::StopOnError, ValidationStrategy::StopOnError);
assert_eq!(ValidationStrategy::ContinueOnError, ValidationStrategy::ContinueOnError);
assert_eq!(ValidationStrategy::None, ValidationStrategy::None);
assert_ne!(ValidationStrategy::StopOnError, ValidationStrategy::ContinueOnError);
assert_ne!(ValidationStrategy::StopOnError, ValidationStrategy::None);
assert_ne!(ValidationStrategy::ContinueOnError, ValidationStrategy::None);
}
struct MockStage {
name: String,
should_fail: bool,
validation_should_pass: bool,
}
impl MockStage {
fn new(name: &str) -> Self {
Self { name: name.to_string(), should_fail: false, validation_should_pass: true }
}
fn with_execution_failure(mut self) -> Self {
self.should_fail = true;
self
}
fn with_validation_failure(mut self) -> Self {
self.validation_should_pass = false;
self
}
}
#[async_trait::async_trait]
impl PipelineStage for MockStage {
fn name(&self) -> &str {
&self.name
}
async fn execute(&self, mut ctx: PipelineContext) -> anyhow::Result<PipelineContext> {
if self.should_fail {
anyhow::bail!("Execution failed for {}", self.name);
}
ctx.metadata.insert(format!("{}_executed", self.name), serde_json::json!(true));
Ok(ctx)
}
fn validate(&self, _ctx: &PipelineContext) -> anyhow::Result<ValidationResult> {
Ok(ValidationResult {
stage: self.name.clone(),
passed: self.validation_should_pass,
message: if self.validation_should_pass {
format!("{} validation passed", self.name)
} else {
format!("{} validation failed", self.name)
},
details: None,
})
}
}
#[tokio::test]
async fn test_pipeline_creation() {
let pipeline = TranspilationPipeline::new(ValidationStrategy::StopOnError);
assert_eq!(pipeline.stages.len(), 0);
assert_eq!(pipeline.validation, ValidationStrategy::StopOnError);
}
#[tokio::test]
async fn test_pipeline_add_stage() {
let pipeline = TranspilationPipeline::new(ValidationStrategy::None)
.add_stage(Box::new(MockStage::new("Stage1")))
.add_stage(Box::new(MockStage::new("Stage2")));
assert_eq!(pipeline.stages.len(), 2);
}
#[tokio::test]
async fn test_pipeline_run_no_stages() {
let pipeline = TranspilationPipeline::new(ValidationStrategy::None);
let input = PathBuf::from("/tmp/input");
let output = PathBuf::from("/tmp/output");
let result = pipeline.run(&input, &output).await;
assert!(result.is_ok());
let pipeline_output = result.unwrap();
assert_eq!(pipeline_output.output_path, output);
assert!(pipeline_output.file_mappings.is_empty());
}
#[tokio::test]
async fn test_pipeline_run_single_stage() {
let pipeline = TranspilationPipeline::new(ValidationStrategy::None)
.add_stage(Box::new(MockStage::new("TestStage")));
let input = PathBuf::from("/tmp/input");
let output = PathBuf::from("/tmp/output");
let result = pipeline.run(&input, &output).await;
assert!(result.is_ok());
let pipeline_output = result.unwrap();
assert_eq!(pipeline_output.output_path, output);
}
#[tokio::test]
async fn test_pipeline_run_multiple_stages() {
let pipeline = TranspilationPipeline::new(ValidationStrategy::None)
.add_stage(Box::new(MockStage::new("Stage1")))
.add_stage(Box::new(MockStage::new("Stage2")))
.add_stage(Box::new(MockStage::new("Stage3")));
let input = PathBuf::from("/tmp/input");
let output = PathBuf::from("/tmp/output");
let result = pipeline.run(&input, &output).await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_pipeline_stage_execution_order() {
let pipeline = TranspilationPipeline::new(ValidationStrategy::None)
.add_stage(Box::new(MockStage::new("First")))
.add_stage(Box::new(MockStage::new("Second")))
.add_stage(Box::new(MockStage::new("Third")));
let input = PathBuf::from("/tmp/input");
let output = PathBuf::from("/tmp/output");
let result = pipeline.run(&input, &output).await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_pipeline_stop_on_error_execution() {
let pipeline = TranspilationPipeline::new(ValidationStrategy::StopOnError)
.add_stage(Box::new(MockStage::new("Stage1")))
.add_stage(Box::new(MockStage::new("Stage2").with_execution_failure()))
.add_stage(Box::new(MockStage::new("Stage3")));
let input = PathBuf::from("/tmp/input");
let output = PathBuf::from("/tmp/output");
let result = pipeline.run(&input, &output).await;
assert!(result.is_err());
let err = result.unwrap_err();
assert!(err.to_string().contains("Stage 'Stage2' failed"));
}
#[tokio::test]
async fn test_pipeline_stop_on_error_validation() {
let pipeline = TranspilationPipeline::new(ValidationStrategy::StopOnError)
.add_stage(Box::new(MockStage::new("Stage1")))
.add_stage(Box::new(MockStage::new("Stage2").with_validation_failure()))
.add_stage(Box::new(MockStage::new("Stage3")));
let input = PathBuf::from("/tmp/input");
let output = PathBuf::from("/tmp/output");
let result = pipeline.run(&input, &output).await;
assert!(result.is_err());
let err = result.unwrap_err();
assert!(err.to_string().contains("Validation failed for stage 'Stage2'"));
}
#[tokio::test]
async fn test_pipeline_continue_on_error_validation() {
let pipeline = TranspilationPipeline::new(ValidationStrategy::ContinueOnError)
.add_stage(Box::new(MockStage::new("Stage1")))
.add_stage(Box::new(MockStage::new("Stage2").with_validation_failure()))
.add_stage(Box::new(MockStage::new("Stage3")));
let input = PathBuf::from("/tmp/input");
let output = PathBuf::from("/tmp/output");
let result = pipeline.run(&input, &output).await;
assert!(result.is_ok());
let pipeline_output = result.unwrap();
assert!(!pipeline_output.validation_passed);
}
#[tokio::test]
async fn test_pipeline_no_validation() {
let pipeline = TranspilationPipeline::new(ValidationStrategy::None)
.add_stage(Box::new(MockStage::new("Stage1").with_validation_failure()))
.add_stage(Box::new(MockStage::new("Stage2").with_validation_failure()));
let input = PathBuf::from("/tmp/input");
let output = PathBuf::from("/tmp/output");
let result = pipeline.run(&input, &output).await;
assert!(result.is_ok());
let pipeline_output = result.unwrap();
assert!(pipeline_output.validation_passed); }
#[test]
fn test_transpilation_stage_creation() {
let stage = TranspilationStage::new(true, true);
assert!(stage.incremental);
assert!(stage.cache);
let _ = &stage.library_analyzer;
}
#[test]
fn test_transpilation_stage_name() {
let stage = TranspilationStage::new(false, false);
assert_eq!(stage.name(), "Transpilation");
}
#[test]
fn test_optimization_stage_creation() {
let stage = OptimizationStage::new(true, true, 1000);
assert!(stage.enable_gpu);
assert!(stage.enable_simd);
assert_eq!(stage.gpu_threshold, 1000);
}
#[test]
fn test_optimization_stage_name() {
let stage = OptimizationStage::new(false, false, 500);
assert_eq!(stage.name(), "Optimization");
}
#[test]
fn test_optimization_stage_analyze_optimizations() {
let stage = OptimizationStage::new(true, true, 1000);
let recommendations = stage.analyze_optimizations();
assert_eq!(recommendations.len(), 3);
assert!(recommendations[0].contains("Element-wise operations"));
assert!(recommendations[1].contains("Vector reductions"));
assert!(recommendations[2].contains("Matrix multiplications"));
}
#[tokio::test]
async fn test_optimization_stage_execute() {
let stage = OptimizationStage::new(true, true, 1000);
let ctx = PipelineContext::new(PathBuf::from("/tmp/input"), PathBuf::from("/tmp/output"));
let result = stage.execute(ctx).await;
assert!(result.is_ok());
let ctx = result.unwrap();
assert!(!ctx.optimizations.is_empty());
assert!(ctx.optimizations.iter().any(|o| o.contains("SIMD")));
assert!(ctx.optimizations.iter().any(|o| o.contains("GPU")));
assert!(ctx.metadata.contains_key("optimizations_applied"));
assert!(ctx.metadata.contains_key("moe_routing_enabled"));
}
#[tokio::test]
async fn test_optimization_stage_simd_only() {
let stage = OptimizationStage::new(false, true, 1000);
let ctx = PipelineContext::new(PathBuf::from("/tmp/input"), PathBuf::from("/tmp/output"));
let result = stage.execute(ctx).await;
assert!(result.is_ok());
let ctx = result.unwrap();
assert!(ctx.optimizations.iter().any(|o| o.contains("SIMD")));
assert!(!ctx.optimizations.iter().any(|o| o.contains("GPU dispatch enabled")));
}
#[tokio::test]
async fn test_optimization_stage_gpu_only() {
let stage = OptimizationStage::new(true, false, 2000);
let ctx = PipelineContext::new(PathBuf::from("/tmp/input"), PathBuf::from("/tmp/output"));
let result = stage.execute(ctx).await;
assert!(result.is_ok());
let ctx = result.unwrap();
assert!(!ctx.optimizations.iter().any(|o| o.contains("SIMD vectorization enabled")));
assert!(ctx.optimizations.iter().any(|o| o.contains("GPU")));
assert!(ctx.optimizations.iter().any(|o| o.contains("2000")));
}
#[test]
fn test_validation_stage_creation() {
let stage = ValidationStage::new(true, true);
assert!(stage.trace_syscalls);
assert!(stage.run_tests);
}
#[test]
fn test_validation_stage_name() {
let stage = ValidationStage::new(false, false);
assert_eq!(stage.name(), "Validation");
}
#[test]
fn test_validation_stage_compare_traces_identical() {
let trace1 =
vec!["open(/file)".to_string(), "read(fd, buf, 100)".to_string(), "close(fd)".to_string()];
let trace2 =
vec!["open(/file)".to_string(), "read(fd, buf, 100)".to_string(), "close(fd)".to_string()];
assert!(ValidationStage::compare_traces(&trace1, &trace2));
}
#[test]
fn test_validation_stage_compare_traces_different_length() {
let trace1 = vec!["open(/file)".to_string(), "close(fd)".to_string()];
let trace2 = vec!["open(/file)".to_string()];
assert!(!ValidationStage::compare_traces(&trace1, &trace2));
}
#[test]
fn test_validation_stage_compare_traces_different_syscalls() {
let trace1 = vec!["open(/file)".to_string(), "read(fd, buf, 100)".to_string()];
let trace2 = vec!["open(/file)".to_string(), "write(fd, buf, 100)".to_string()];
assert!(!ValidationStage::compare_traces(&trace1, &trace2));
}
#[test]
fn test_validation_stage_compare_traces_same_syscall_different_args() {
let trace1 = vec!["open(/file1)".to_string(), "read(fd, buf, 100)".to_string()];
let trace2 = vec!["open(/file2)".to_string(), "read(fd, buf, 200)".to_string()];
assert!(ValidationStage::compare_traces(&trace1, &trace2));
}
#[test]
fn test_build_stage_creation() {
let stage = BuildStage::new(true, Some("x86_64-unknown-linux-gnu".to_string()), false);
assert!(stage.release);
assert_eq!(stage.target, Some("x86_64-unknown-linux-gnu".to_string()));
assert!(!stage.wasm);
}
#[test]
fn test_build_stage_creation_wasm() {
let stage = BuildStage::new(false, None, true);
assert!(!stage.release);
assert!(stage.target.is_none());
assert!(stage.wasm);
}
#[test]
fn test_build_stage_name() {
let stage = BuildStage::new(false, None, false);
assert_eq!(stage.name(), "Build");
}
#[test]
fn test_build_stage_validate_no_build_dir() {
let stage = BuildStage::new(true, None, false);
let ctx = PipelineContext::new(PathBuf::from("/tmp/input"), PathBuf::from("/tmp/nonexistent"));
let result = stage.validate(&ctx);
assert!(result.is_ok());
let validation = result.unwrap();
assert!(!validation.passed);
assert!(validation.message.contains("not found"));
}
#[test]
fn test_analysis_stage_name() {
let stage = AnalysisStage;
assert_eq!(stage.name(), "Analysis");
}
#[test]
fn test_analysis_stage_validate_no_language() {
let stage = AnalysisStage;
let ctx = PipelineContext::new(PathBuf::from("/tmp/input"), PathBuf::from("/tmp/output"));
let result = stage.validate(&ctx);
assert!(result.is_ok());
let validation = result.unwrap();
assert!(!validation.passed);
assert!(validation.message.contains("Could not detect"));
}
#[test]
fn test_analysis_stage_validate_with_language() {
let stage = AnalysisStage;
let mut ctx = PipelineContext::new(PathBuf::from("/tmp/input"), PathBuf::from("/tmp/output"));
ctx.primary_language = Some(crate::types::Language::Python);
let result = stage.validate(&ctx);
assert!(result.is_ok());
let validation = result.unwrap();
assert!(validation.passed);
assert!(validation.message.contains("Language detected"));
}
#[test]
fn test_pipeline_context_serialization() {
let mut ctx = PipelineContext::new(PathBuf::from("/input"), PathBuf::from("/output"));
ctx.primary_language = Some(crate::types::Language::Python);
ctx.file_mappings.push((PathBuf::from("a.py"), PathBuf::from("a.rs")));
ctx.optimizations.push("SIMD".to_string());
let json = serde_json::to_string(&ctx).unwrap();
let deserialized: PipelineContext = serde_json::from_str(&json).unwrap();
assert_eq!(ctx.input_path, deserialized.input_path);
assert_eq!(ctx.output_path, deserialized.output_path);
assert_eq!(ctx.primary_language, deserialized.primary_language);
assert_eq!(ctx.file_mappings.len(), deserialized.file_mappings.len());
assert_eq!(ctx.optimizations.len(), deserialized.optimizations.len());
}
#[test]
fn test_validation_result_serialization() {
let result = ValidationResult {
stage: "Test".to_string(),
passed: true,
message: "OK".to_string(),
details: Some(serde_json::json!({"key": "value"})),
};
let json = serde_json::to_string(&result).unwrap();
let deserialized: ValidationResult = serde_json::from_str(&json).unwrap();
assert_eq!(result.stage, deserialized.stage);
assert_eq!(result.passed, deserialized.passed);
assert_eq!(result.message, deserialized.message);
assert_eq!(result.details, deserialized.details);
}
#[test]
fn test_pipeline_output_serialization() {
let output = PipelineOutput {
output_path: PathBuf::from("/output"),
file_mappings: vec![(PathBuf::from("a"), PathBuf::from("b"))],
optimizations: vec!["opt1".to_string(), "opt2".to_string()],
validation_passed: true,
};
let json = serde_json::to_string(&output).unwrap();
let deserialized: PipelineOutput = serde_json::from_str(&json).unwrap();
assert_eq!(output.output_path, deserialized.output_path);
assert_eq!(output.file_mappings.len(), deserialized.file_mappings.len());
assert_eq!(output.optimizations.len(), deserialized.optimizations.len());
assert_eq!(output.validation_passed, deserialized.validation_passed);
}
#[cfg(feature = "native")]
#[tokio::test]
async fn test_analysis_stage_execute_with_rust_project() {
use tempfile::TempDir;
let temp_dir = TempDir::new().unwrap();
let src_dir = temp_dir.path().join("src");
std::fs::create_dir(&src_dir).unwrap();
std::fs::write(src_dir.join("main.rs"), "fn main() {}").unwrap();
let stage = AnalysisStage;
let ctx = PipelineContext::new(temp_dir.path().to_path_buf(), PathBuf::from("/tmp/output"));
let result = stage.execute(ctx).await;
assert!(result.is_ok());
let ctx = result.unwrap();
assert_eq!(ctx.primary_language, Some(crate::types::Language::Rust));
assert!(ctx.metadata.contains_key("total_files"));
assert!(ctx.metadata.contains_key("total_lines"));
}
#[cfg(feature = "native")]
#[tokio::test]
async fn test_analysis_stage_execute_with_python_project() {
use tempfile::TempDir;
let temp_dir = TempDir::new().unwrap();
std::fs::write(temp_dir.path().join("main.py"), "print('hello')").unwrap();
let stage = AnalysisStage;
let ctx = PipelineContext::new(temp_dir.path().to_path_buf(), PathBuf::from("/tmp/output"));
let result = stage.execute(ctx).await;
assert!(result.is_ok());
let ctx = result.unwrap();
assert_eq!(ctx.primary_language, Some(crate::types::Language::Python));
}
#[cfg(feature = "native")]
#[tokio::test]
async fn test_analysis_stage_execute_empty_directory() {
use tempfile::TempDir;
let temp_dir = TempDir::new().unwrap();
let stage = AnalysisStage;
let ctx = PipelineContext::new(temp_dir.path().to_path_buf(), PathBuf::from("/tmp/output"));
let result = stage.execute(ctx).await;
assert!(result.is_ok());
let ctx = result.unwrap();
assert!(ctx.primary_language.is_none());
}
#[cfg(feature = "native")]
#[tokio::test]
async fn test_transpilation_stage_creates_directories() {
use tempfile::TempDir;
let temp_dir = TempDir::new().unwrap();
let output_dir = temp_dir.path().join("output");
let stage = TranspilationStage::new(false, false);
let mut ctx = PipelineContext::new(temp_dir.path().to_path_buf(), output_dir.clone());
ctx.primary_language = Some(crate::types::Language::Rust);
let _result = stage.execute(ctx).await;
assert!(output_dir.exists());
assert!(output_dir.join("src").exists());
}
#[test]
fn test_transpilation_stage_validate_empty_output() {
use tempfile::TempDir;
let temp_dir = TempDir::new().unwrap();
let output_dir = temp_dir.path().join("output");
std::fs::create_dir_all(output_dir.join("src")).unwrap();
let stage = TranspilationStage::new(false, false);
let ctx = PipelineContext::new(PathBuf::from("/tmp/input"), output_dir.clone());
let result = stage.validate(&ctx);
assert!(result.is_ok());
let validation = result.unwrap();
assert!(!validation.passed);
}
#[test]
fn test_transpilation_stage_validate_with_files() {
use tempfile::TempDir;
let temp_dir = TempDir::new().unwrap();
let output_dir = temp_dir.path().join("output");
std::fs::create_dir_all(output_dir.join("src")).unwrap();
std::fs::write(output_dir.join("src/main.rs"), "fn main() {}").unwrap();
let stage = TranspilationStage::new(false, false);
let ctx = PipelineContext::new(PathBuf::from("/tmp/input"), output_dir.clone());
let result = stage.validate(&ctx);
assert!(result.is_ok());
let validation = result.unwrap();
assert!(validation.passed);
}
#[test]
fn test_build_stage_validate_debug_build() {
use tempfile::TempDir;
let temp_dir = TempDir::new().unwrap();
let output_dir = temp_dir.path().join("output");
std::fs::create_dir_all(output_dir.join("target/debug")).unwrap();
let stage = BuildStage::new(false, None, false);
let ctx = PipelineContext::new(PathBuf::from("/tmp/input"), output_dir.clone());
let result = stage.validate(&ctx);
assert!(result.is_ok());
let validation = result.unwrap();
assert!(validation.passed);
}
#[test]
fn test_build_stage_validate_release_build() {
use tempfile::TempDir;
let temp_dir = TempDir::new().unwrap();
let output_dir = temp_dir.path().join("output");
std::fs::create_dir_all(output_dir.join("target/release")).unwrap();
let stage = BuildStage::new(true, None, false);
let ctx = PipelineContext::new(PathBuf::from("/tmp/input"), output_dir.clone());
let result = stage.validate(&ctx);
assert!(result.is_ok());
let validation = result.unwrap();
assert!(validation.passed);
}
#[tokio::test]
async fn test_validation_stage_execute_no_binaries() {
use tempfile::TempDir;
let temp_dir = TempDir::new().unwrap();
let stage = ValidationStage::new(true, false);
let ctx = PipelineContext::new(temp_dir.path().to_path_buf(), temp_dir.path().join("output"));
let result = stage.execute(ctx).await;
assert!(result.is_ok());
let ctx = result.unwrap();
assert!(ctx.metadata.contains_key("validation_completed"));
}
#[tokio::test]
async fn test_validation_stage_execute_without_tracing() {
let stage = ValidationStage::new(false, false);
let ctx = PipelineContext::new(PathBuf::from("/tmp/input"), PathBuf::from("/tmp/output"));
let result = stage.execute(ctx).await;
assert!(result.is_ok());
let ctx = result.unwrap();
assert_eq!(ctx.metadata.get("validation_completed"), Some(&serde_json::json!(true)));
}
#[test]
fn test_pipeline_context_clone() {
let mut ctx1 = PipelineContext::new(PathBuf::from("/input"), PathBuf::from("/output"));
ctx1.optimizations.push("test".to_string());
let ctx2 = ctx1.clone();
assert_eq!(ctx1.input_path, ctx2.input_path);
assert_eq!(ctx1.output_path, ctx2.output_path);
assert_eq!(ctx1.optimizations.len(), ctx2.optimizations.len());
}
#[test]
fn test_validation_result_clone() {
let result1 = ValidationResult {
stage: "Test".to_string(),
passed: true,
message: "OK".to_string(),
details: None,
};
let result2 = result1.clone();
assert_eq!(result1.stage, result2.stage);
assert_eq!(result1.passed, result2.passed);
}
#[test]
fn test_pipeline_output_clone() {
let output1 = PipelineOutput {
output_path: PathBuf::from("/out"),
file_mappings: vec![],
optimizations: vec!["opt".to_string()],
validation_passed: true,
};
let output2 = output1.clone();
assert_eq!(output1.output_path, output2.output_path);
assert_eq!(output1.validation_passed, output2.validation_passed);
}
#[test]
fn test_optimization_stage_no_gpu_no_simd() {
let stage = OptimizationStage::new(false, false, 500);
let recommendations = stage.analyze_optimizations();
assert!(!recommendations.is_empty());
}
#[test]
fn test_pipeline_context_output_method_extended() {
let mut ctx = PipelineContext::new(PathBuf::from("/input"), PathBuf::from("/output"));
ctx.file_mappings.push((PathBuf::from("a.py"), PathBuf::from("a.rs")));
ctx.optimizations.push("simd".to_string());
ctx.validation_results.push(ValidationResult {
stage: "test".to_string(),
passed: true,
message: "ok".to_string(),
details: None,
});
let output = ctx.output();
assert_eq!(output.output_path, PathBuf::from("/output"));
assert_eq!(output.file_mappings.len(), 1);
assert!(output.validation_passed);
}
#[test]
fn test_pipeline_context_output_fails_validation_extended() {
let mut ctx = PipelineContext::new(PathBuf::from("/input"), PathBuf::from("/output"));
ctx.validation_results.push(ValidationResult {
stage: "test".to_string(),
passed: false,
message: "failed".to_string(),
details: None,
});
let output = ctx.output();
assert!(!output.validation_passed);
}
#[test]
fn test_transpilation_stage_library_analyzer_initialized() {
let stage = TranspilationStage::new(true, true);
let _ = &stage.library_analyzer;
}
#[test]
fn test_optimization_stage_with_different_simd_thresholds_ext() {
let stage_low = OptimizationStage::new(false, true, 100);
let stage_high = OptimizationStage::new(false, true, 10000);
let recs_low = stage_low.analyze_optimizations();
let recs_high = stage_high.analyze_optimizations();
assert!(!recs_low.is_empty());
assert!(!recs_high.is_empty());
}
#[test]
fn test_transpilation_stage_validate_ext() {
let stage = TranspilationStage::new(true, true);
let mut ctx = PipelineContext::new(PathBuf::from("/tmp"), PathBuf::from("/tmp/out"));
let result = stage.validate(&ctx);
assert!(result.is_ok());
ctx.file_mappings.push((PathBuf::from("a.py"), PathBuf::from("a.rs")));
let result = stage.validate(&ctx);
assert!(result.is_ok());
}
#[test]
fn test_pipeline_context_empty_metadata() {
let ctx = PipelineContext::new(PathBuf::from("/in"), PathBuf::from("/out"));
assert!(ctx.metadata.is_empty());
assert!(ctx.file_mappings.is_empty());
assert!(ctx.optimizations.is_empty());
assert!(ctx.validation_results.is_empty());
}
#[test]
fn test_pipeline_context_complex_metadata() {
let mut ctx = PipelineContext::new(PathBuf::from("/in"), PathBuf::from("/out"));
ctx.metadata.insert("array".to_string(), serde_json::json!([1, 2, 3]));
ctx.metadata.insert("nested".to_string(), serde_json::json!({"a": {"b": "c"}}));
ctx.metadata.insert("null".to_string(), serde_json::Value::Null);
ctx.metadata.insert("bool".to_string(), serde_json::json!(true));
assert_eq!(ctx.metadata.len(), 4);
}
#[test]
fn test_validation_result_default_details() {
let result = ValidationResult {
stage: "Test".to_string(),
passed: true,
message: "OK".to_string(),
details: None,
};
assert!(result.details.is_none());
assert!(result.passed);
}
#[test]
fn test_pipeline_output_all_fields() {
let output = PipelineOutput {
output_path: PathBuf::from("/output"),
file_mappings: vec![
(PathBuf::from("a.py"), PathBuf::from("a.rs")),
(PathBuf::from("b.py"), PathBuf::from("b.rs")),
],
optimizations: vec!["opt1".to_string(), "opt2".to_string()],
validation_passed: true,
};
assert_eq!(output.file_mappings.len(), 2);
assert_eq!(output.optimizations.len(), 2);
assert!(output.validation_passed);
}
#[test]
fn test_analysis_stage_name_immutable() {
let stage = AnalysisStage;
let name1 = stage.name();
let name2 = stage.name();
assert_eq!(name1, name2);
}
#[test]
fn test_validation_stage_empty_traces() {
let _stage = ValidationStage::new(true, true);
let trace1: Vec<String> = vec![];
let trace2: Vec<String> = vec![];
assert!(ValidationStage::compare_traces(&trace1, &trace2));
}
#[test]
fn test_optimization_stage_edge_cases() {
let stage = OptimizationStage::new(true, true, 0);
let recommendations = stage.analyze_optimizations();
assert!(!recommendations.is_empty());
let stage_high = OptimizationStage::new(true, true, 10_000_000);
let rec_high = stage_high.analyze_optimizations();
assert!(!rec_high.is_empty());
}
#[test]
fn test_build_stage_all_configurations() {
let stage1 = BuildStage::new(false, None, false);
assert!(!stage1.release);
assert!(stage1.target.is_none());
assert!(!stage1.wasm);
let stage2 = BuildStage::new(true, Some("aarch64-apple-darwin".to_string()), false);
assert!(stage2.release);
assert!(stage2.target.is_some());
let stage3 = BuildStage::new(false, None, true);
assert!(stage3.wasm);
}
#[test]
fn test_transpilation_stage_no_cache() {
let stage = TranspilationStage::new(false, false);
assert!(!stage.incremental);
assert!(!stage.cache);
}
#[test]
fn test_validation_stage_no_tracing() {
let stage = ValidationStage::new(false, false);
assert!(!stage.trace_syscalls);
assert!(!stage.run_tests);
}
#[test]
fn test_trace_binary_nonexistent_cov() {
let result = ValidationStage::trace_binary(Path::new("/nonexistent/binary"));
let _ = result;
}
#[tokio::test]
async fn test_pipeline_stop_on_error_all_pass() {
let pipeline = TranspilationPipeline::new(ValidationStrategy::StopOnError)
.add_stage(Box::new(MockStage::new("Stage1")))
.add_stage(Box::new(MockStage::new("Stage2")))
.add_stage(Box::new(MockStage::new("Stage3")));
let input = PathBuf::from("/tmp/input");
let output = PathBuf::from("/tmp/output");
let result = pipeline.run(&input, &output).await;
assert!(result.is_ok());
let pipeline_output = result.unwrap();
assert!(pipeline_output.validation_passed);
}
#[tokio::test]
async fn test_pipeline_continue_on_error_all_pass() {
let pipeline = TranspilationPipeline::new(ValidationStrategy::ContinueOnError)
.add_stage(Box::new(MockStage::new("Stage1")))
.add_stage(Box::new(MockStage::new("Stage2")));
let input = PathBuf::from("/tmp/input");
let output = PathBuf::from("/tmp/output");
let result = pipeline.run(&input, &output).await;
assert!(result.is_ok());
let pipeline_output = result.unwrap();
assert!(pipeline_output.validation_passed);
}
#[tokio::test]
async fn test_pipeline_continue_on_error_execution_failure() {
let pipeline = TranspilationPipeline::new(ValidationStrategy::ContinueOnError)
.add_stage(Box::new(MockStage::new("Stage1")))
.add_stage(Box::new(MockStage::new("Stage2").with_execution_failure()));
let input = PathBuf::from("/tmp/input");
let output = PathBuf::from("/tmp/output");
let result = pipeline.run(&input, &output).await;
assert!(result.is_err());
let err = result.unwrap_err();
assert!(err.to_string().contains("Stage 'Stage2' failed"));
}
#[tokio::test]
async fn test_pipeline_first_stage_execution_failure() {
let pipeline = TranspilationPipeline::new(ValidationStrategy::StopOnError)
.add_stage(Box::new(MockStage::new("Stage1").with_execution_failure()))
.add_stage(Box::new(MockStage::new("Stage2")));
let input = PathBuf::from("/tmp/input");
let output = PathBuf::from("/tmp/output");
let result = pipeline.run(&input, &output).await;
assert!(result.is_err());
let err = result.unwrap_err();
assert!(err.to_string().contains("Stage 'Stage1' failed"));
}
#[tokio::test]
async fn test_build_stage_execute_no_cargo_toml() {
use tempfile::TempDir;
let temp_dir = TempDir::new().unwrap();
let stage = BuildStage::new(false, None, false);
let ctx = PipelineContext::new(PathBuf::from("/tmp/input"), temp_dir.path().to_path_buf());
let result = stage.execute(ctx).await;
assert!(result.is_err());
let err = result.unwrap_err();
assert!(err.to_string().contains("No Cargo.toml found"));
}
#[cfg(feature = "native")]
#[tokio::test]
async fn test_build_stage_execute_debug_build() {
use tempfile::TempDir;
let temp_dir = TempDir::new().unwrap();
let project_dir = temp_dir.path().join("project");
std::fs::create_dir_all(project_dir.join("src")).unwrap();
std::fs::write(
project_dir.join("Cargo.toml"),
r#"[package]
name = "test-build"
version = "0.1.0"
edition = "2021"
"#,
)
.unwrap();
std::fs::write(project_dir.join("src/main.rs"), "fn main() {}\n").unwrap();
let stage = BuildStage::new(false, None, false);
let ctx = PipelineContext::new(PathBuf::from("/tmp/input"), project_dir.clone());
let result = stage.execute(ctx).await;
assert!(result.is_ok());
let ctx = result.unwrap();
assert_eq!(ctx.metadata.get("build_mode"), Some(&serde_json::json!("debug")));
assert!(!ctx.metadata.contains_key("wasm_build"));
}
#[cfg(feature = "native")]
#[tokio::test]
async fn test_build_stage_execute_release_build() {
use tempfile::TempDir;
let temp_dir = TempDir::new().unwrap();
let project_dir = temp_dir.path().join("project");
std::fs::create_dir_all(project_dir.join("src")).unwrap();
std::fs::write(
project_dir.join("Cargo.toml"),
r#"[package]
name = "test-build"
version = "0.1.0"
edition = "2021"
"#,
)
.unwrap();
std::fs::write(project_dir.join("src/main.rs"), "fn main() {}\n").unwrap();
let stage = BuildStage::new(true, None, false);
let ctx = PipelineContext::new(PathBuf::from("/tmp/input"), project_dir.clone());
let result = stage.execute(ctx).await;
assert!(result.is_ok());
let ctx = result.unwrap();
assert_eq!(ctx.metadata.get("build_mode"), Some(&serde_json::json!("release")));
}
#[cfg(feature = "native")]
#[tokio::test]
async fn test_build_stage_execute_with_target() {
use tempfile::TempDir;
let temp_dir = TempDir::new().unwrap();
let project_dir = temp_dir.path().join("project");
std::fs::create_dir_all(project_dir.join("src")).unwrap();
std::fs::write(
project_dir.join("Cargo.toml"),
r#"[package]
name = "test-build"
version = "0.1.0"
edition = "2021"
"#,
)
.unwrap();
std::fs::write(project_dir.join("src/main.rs"), "fn main() {}\n").unwrap();
let stage = BuildStage::new(false, Some("x86_64-unknown-linux-gnu".to_string()), false);
let ctx = PipelineContext::new(PathBuf::from("/tmp/input"), project_dir.clone());
let result = stage.execute(ctx).await;
assert!(result.is_ok());
}
#[test]
fn test_build_stage_validate_debug_no_dir() {
let stage = BuildStage::new(false, None, false);
let ctx = PipelineContext::new(
PathBuf::from("/tmp/input"),
PathBuf::from("/tmp/nonexistent_dir_for_test"),
);
let result = stage.validate(&ctx);
assert!(result.is_ok());
let validation = result.unwrap();
assert!(!validation.passed);
assert_eq!(validation.message, "Build directory not found");
}
#[test]
fn test_build_stage_validate_release_passing() {
use tempfile::TempDir;
let temp_dir = TempDir::new().unwrap();
std::fs::create_dir_all(temp_dir.path().join("target/release")).unwrap();
let stage = BuildStage::new(true, None, false);
let ctx = PipelineContext::new(PathBuf::from("/tmp/input"), temp_dir.path().to_path_buf());
let result = stage.validate(&ctx);
assert!(result.is_ok());
let validation = result.unwrap();
assert!(validation.passed);
assert_eq!(validation.message, "Build artifacts found");
}
struct DefaultValidateStage;
#[async_trait::async_trait]
impl PipelineStage for DefaultValidateStage {
fn name(&self) -> &str {
"DefaultValidate"
}
async fn execute(&self, ctx: PipelineContext) -> anyhow::Result<PipelineContext> {
Ok(ctx)
}
}
#[test]
fn test_default_validate_method() {
let stage = DefaultValidateStage;
let ctx = PipelineContext::new(PathBuf::from("/input"), PathBuf::from("/output"));
let result = stage.validate(&ctx);
assert!(result.is_ok());
let validation = result.unwrap();
assert_eq!(validation.stage, "DefaultValidate");
assert!(validation.passed);
assert_eq!(validation.message, "No validation configured");
assert!(validation.details.is_none());
}
#[tokio::test]
async fn test_pipeline_run_with_default_validate_stage() {
let pipeline = TranspilationPipeline::new(ValidationStrategy::StopOnError)
.add_stage(Box::new(DefaultValidateStage));
let input = PathBuf::from("/tmp/input");
let output = PathBuf::from("/tmp/output");
let result = pipeline.run(&input, &output).await;
assert!(result.is_ok());
let pipeline_output = result.unwrap();
assert!(pipeline_output.validation_passed);
}
#[test]
fn test_pipeline_context_debug_format() {
let ctx = PipelineContext::new(PathBuf::from("/input"), PathBuf::from("/output"));
let debug_str = format!("{:?}", ctx);
assert!(debug_str.contains("PipelineContext"));
assert!(debug_str.contains("/input"));
assert!(debug_str.contains("/output"));
}
#[test]
fn test_validation_result_debug_format() {
let result = ValidationResult {
stage: "TestStage".to_string(),
passed: true,
message: "OK".to_string(),
details: None,
};
let debug_str = format!("{:?}", result);
assert!(debug_str.contains("ValidationResult"));
assert!(debug_str.contains("TestStage"));
}
#[test]
fn test_pipeline_output_debug_format() {
let output = PipelineOutput {
output_path: PathBuf::from("/out"),
file_mappings: vec![],
optimizations: vec![],
validation_passed: false,
};
let debug_str = format!("{:?}", output);
assert!(debug_str.contains("PipelineOutput"));
assert!(debug_str.contains("false"));
}
#[test]
fn test_validation_strategy_debug_format() {
let strategy = ValidationStrategy::StopOnError;
let debug_str = format!("{:?}", strategy);
assert_eq!(debug_str, "StopOnError");
let strategy2 = ValidationStrategy::ContinueOnError;
let debug_str2 = format!("{:?}", strategy2);
assert_eq!(debug_str2, "ContinueOnError");
let strategy3 = ValidationStrategy::None;
let debug_str3 = format!("{:?}", strategy3);
assert_eq!(debug_str3, "None");
}
#[test]
fn test_validation_strategy_copy_semantics() {
let s1 = ValidationStrategy::StopOnError;
let s2 = s1; assert_eq!(s1, s2); }
#[test]
fn test_pipeline_context_with_all_fields_populated() {
let mut ctx = PipelineContext::new(PathBuf::from("/input"), PathBuf::from("/output"));
ctx.primary_language = Some(crate::types::Language::Python);
ctx.file_mappings.push((PathBuf::from("a.py"), PathBuf::from("a.rs")));
ctx.file_mappings.push((PathBuf::from("b.py"), PathBuf::from("b.rs")));
ctx.optimizations.push("simd".to_string());
ctx.optimizations.push("gpu".to_string());
ctx.validation_results.push(ValidationResult {
stage: "s1".to_string(),
passed: true,
message: "ok".to_string(),
details: Some(serde_json::json!({"info": "details"})),
});
ctx.metadata.insert("key1".to_string(), serde_json::json!("val1"));
let output = ctx.output();
assert_eq!(output.file_mappings.len(), 2);
assert_eq!(output.optimizations.len(), 2);
assert!(output.validation_passed);
}
#[cfg(feature = "native")]
#[tokio::test]
async fn test_build_stage_execute_cargo_build_fails() {
use tempfile::TempDir;
let temp_dir = TempDir::new().unwrap();
let project_dir = temp_dir.path().join("project");
std::fs::create_dir_all(project_dir.join("src")).unwrap();
std::fs::write(
project_dir.join("Cargo.toml"),
r#"[package]
name = "broken-build"
version = "0.1.0"
edition = "2021"
"#,
)
.unwrap();
std::fs::write(project_dir.join("src/main.rs"), "fn main() { this is not valid rust }")
.unwrap();
let stage = BuildStage::new(false, None, false);
let ctx = PipelineContext::new(PathBuf::from("/tmp/input"), project_dir.clone());
let result = stage.execute(ctx).await;
assert!(result.is_err());
let err = result.unwrap_err();
assert!(err.to_string().contains("Cargo build failed"));
}
#[cfg(feature = "native")]
#[tokio::test]
async fn test_build_stage_execute_wasm_flag() {
use tempfile::TempDir;
let temp_dir = TempDir::new().unwrap();
let project_dir = temp_dir.path().join("project");
std::fs::create_dir_all(project_dir.join("src")).unwrap();
std::fs::write(
project_dir.join("Cargo.toml"),
r#"[package]
name = "wasm-test"
version = "0.1.0"
edition = "2021"
"#,
)
.unwrap();
std::fs::write(project_dir.join("src/lib.rs"), "pub fn hello() {}\n").unwrap();
let stage = BuildStage::new(false, None, true);
let ctx = PipelineContext::new(PathBuf::from("/tmp/input"), project_dir.clone());
let result = stage.execute(ctx).await;
if let Ok(ctx) = result {
assert_eq!(ctx.metadata.get("build_mode"), Some(&serde_json::json!("debug")));
assert_eq!(ctx.metadata.get("wasm_build"), Some(&serde_json::json!(true)));
}
}
#[cfg(feature = "native")]
#[tokio::test]
async fn test_pipeline_run_with_tracing_subscriber() {
use tracing_subscriber::fmt;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
let subscriber = tracing_subscriber::registry().with(fmt::layer().with_writer(std::io::sink));
let _guard = subscriber.set_default();
let pipeline = TranspilationPipeline::new(ValidationStrategy::StopOnError)
.add_stage(Box::new(MockStage::new("Analysis")))
.add_stage(Box::new(MockStage::new("Build")));
let input = PathBuf::from("/tmp/input");
let output = PathBuf::from("/tmp/output");
let result = pipeline.run(&input, &output).await;
assert!(result.is_ok());
let pipeline_output = result.unwrap();
assert!(pipeline_output.validation_passed);
}
#[cfg(feature = "native")]
#[tokio::test]
async fn test_pipeline_run_continue_on_error_with_tracing() {
use tracing_subscriber::fmt;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
let subscriber = tracing_subscriber::registry().with(fmt::layer().with_writer(std::io::sink));
let _guard = subscriber.set_default();
let pipeline = TranspilationPipeline::new(ValidationStrategy::ContinueOnError)
.add_stage(Box::new(MockStage::new("Stage1").with_validation_failure()))
.add_stage(Box::new(MockStage::new("Stage2")));
let input = PathBuf::from("/tmp/input");
let output = PathBuf::from("/tmp/output");
let result = pipeline.run(&input, &output).await;
assert!(result.is_ok());
assert!(!result.unwrap().validation_passed);
}
#[cfg(feature = "native")]
#[tokio::test]
async fn test_pipeline_single_stage_with_tracing() {
use tracing_subscriber::fmt;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
let subscriber = tracing_subscriber::registry().with(fmt::layer().with_writer(std::io::sink));
let _guard = subscriber.set_default();
let pipeline = TranspilationPipeline::new(ValidationStrategy::None)
.add_stage(Box::new(MockStage::new("OnlyStage")));
let input = PathBuf::from("/tmp/input");
let output = PathBuf::from("/tmp/output");
let result = pipeline.run(&input, &output).await;
assert!(result.is_ok());
}