use anyhow::Result;
use depyler_core::{debug::DebugConfig, debug::DebugLevel, DepylerPipeline};
use std::path::{Path, PathBuf};
#[derive(Debug, Clone, Default)]
pub struct TranspileConfig {
pub verify: bool,
pub gen_tests: bool,
pub debug: bool,
pub source_map: bool,
pub trace: bool,
pub explain: bool,
pub audit_trail: bool,
pub auto_fix: bool,
pub async_mode: bool,
pub suggest_fixes: bool,
pub fix_confidence: f64,
pub oracle: bool,
pub max_retries: usize,
pub llm_fallback: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AutoFixStrategy {
None,
Synchronous,
Async,
SuggestOnly,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ConfidenceLevel {
High,
Low,
Unknown,
}
#[derive(Debug, Clone)]
pub struct OracleConfig {
pub enabled: bool,
pub threshold: f64,
pub max_retries: usize,
pub llm_fallback: bool,
}
#[derive(Debug, Clone)]
pub struct OutputPaths {
pub main_output: PathBuf,
pub autofix_output: Option<PathBuf>,
pub test_output: Option<PathBuf>,
pub cargo_toml: Option<PathBuf>,
pub source_map: Option<PathBuf>,
}
#[derive(Debug, Clone)]
pub struct TranspileResult {
pub rust_code: String,
pub source_size: usize,
pub output_size: usize,
pub parse_time_ms: u64,
pub transpile_time_ms: u64,
pub verification_passed: Option<bool>,
pub fixes_applied: usize,
}
pub fn create_pipeline(config: &TranspileConfig) -> DepylerPipeline {
let mut pipeline = DepylerPipeline::new();
if config.verify {
pipeline = pipeline.with_verification();
}
if config.debug || config.source_map {
let debug_config = DebugConfig {
debug_level: if config.debug {
DebugLevel::Full
} else {
DebugLevel::Basic
},
generate_source_map: config.source_map,
preserve_symbols: true,
debug_prints: config.debug,
breakpoints: config.debug,
};
pipeline = pipeline.with_debug(debug_config);
}
pipeline
}
pub fn transpile_source(python_source: &str, config: &TranspileConfig) -> Result<TranspileResult> {
let source_size = python_source.len();
let parse_start = std::time::Instant::now();
let pipeline = create_pipeline(config);
let parse_time_ms = parse_start.elapsed().as_millis() as u64;
let transpile_start = std::time::Instant::now();
let rust_code = pipeline.transpile(python_source)?;
let transpile_time_ms = transpile_start.elapsed().as_millis() as u64;
let output_size = rust_code.len();
Ok(TranspileResult {
rust_code,
source_size,
output_size,
parse_time_ms,
transpile_time_ms,
verification_passed: None,
fixes_applied: 0,
})
}
pub fn format_trace_phase(phase: u8, name: &str, details: &[(&str, &str)]) -> String {
let mut output = format!("Phase {}: {}\n", phase, name);
for (key, value) in details {
output.push_str(&format!(" - {}: {}\n", key, value));
}
output
}
pub fn calculate_metrics(result: &TranspileResult) -> TranspileMetrics {
let compression_ratio = if result.source_size > 0 {
result.output_size as f64 / result.source_size as f64
} else {
0.0
};
let total_time_ms = result.parse_time_ms + result.transpile_time_ms;
let throughput = if total_time_ms > 0 {
(result.source_size as f64 / 1024.0) / (total_time_ms as f64 / 1000.0)
} else {
0.0
};
TranspileMetrics {
compression_ratio,
total_time_ms,
throughput_kb_per_sec: throughput,
}
}
#[derive(Debug, Clone)]
pub struct TranspileMetrics {
pub compression_ratio: f64,
pub total_time_ms: u64,
pub throughput_kb_per_sec: f64,
}
pub fn determine_autofix_strategy(config: &TranspileConfig) -> AutoFixStrategy {
if config.suggest_fixes && !config.auto_fix {
AutoFixStrategy::SuggestOnly
} else if config.async_mode && config.auto_fix {
AutoFixStrategy::Async
} else if config.auto_fix {
AutoFixStrategy::Synchronous
} else {
AutoFixStrategy::None
}
}
pub fn evaluate_confidence(confidence: f64, threshold: f64) -> ConfidenceLevel {
if confidence.is_nan() || threshold.is_nan() {
ConfidenceLevel::Unknown
} else if confidence >= threshold {
ConfidenceLevel::High
} else {
ConfidenceLevel::Low
}
}
pub fn build_oracle_config(config: &TranspileConfig) -> OracleConfig {
OracleConfig {
enabled: config.oracle,
threshold: config.fix_confidence,
max_retries: config.max_retries,
llm_fallback: config.llm_fallback,
}
}
pub fn compute_output_path(input: &Path, output: Option<&Path>) -> PathBuf {
match output {
Some(path) => path.to_path_buf(),
None => {
let mut path = input.to_path_buf();
path.set_extension("rs");
path
}
}
}
pub fn compute_output_paths(
input: &Path,
output: Option<&Path>,
config: &TranspileConfig,
has_dependencies: bool,
) -> OutputPaths {
let main_output = compute_output_path(input, output);
let autofix_output = if config.auto_fix && config.async_mode {
let stem = main_output
.file_stem()
.unwrap_or_default()
.to_string_lossy();
let mut p = main_output.clone();
p.set_file_name(format!("{}.autofix.rs", stem));
Some(p)
} else {
None
};
let test_output = if config.gen_tests {
Some(main_output.with_extension("test.rs"))
} else {
None
};
let cargo_toml = if has_dependencies {
let mut p = main_output.clone();
p.set_file_name("Cargo.toml");
Some(p)
} else {
None
};
let source_map = if config.source_map {
let mut p = main_output.clone();
let name = p.file_name().unwrap_or_default().to_string_lossy();
p.set_file_name(format!("{}.sourcemap.json", name));
Some(p)
} else {
None
};
OutputPaths {
main_output,
autofix_output,
test_output,
cargo_toml,
source_map,
}
}
pub fn extract_package_name(output_path: &Path) -> String {
output_path
.file_stem()
.and_then(|s| s.to_str())
.unwrap_or("transpiled_package")
.to_string()
}
pub fn extract_source_file_name(output_path: &Path) -> String {
output_path
.file_name()
.and_then(|s| s.to_str())
.unwrap_or("main.rs")
.to_string()
}
pub fn format_init_trace(config: &TranspileConfig) -> Vec<(String, String)> {
vec![
(
"Verification".to_string(),
if config.verify { "enabled" } else { "disabled" }.to_string(),
),
(
"Debug mode".to_string(),
if config.debug { "enabled" } else { "disabled" }.to_string(),
),
(
"Source map".to_string(),
if config.source_map {
"enabled"
} else {
"disabled"
}
.to_string(),
),
(
"Audit trail".to_string(),
if config.audit_trail {
"enabled (HashChainCollector)"
} else {
"disabled"
}
.to_string(),
),
]
}
pub fn format_parse_trace(source_size: usize, parse_time_ms: u64) -> Vec<(String, String)> {
vec![
("Input size".to_string(), format!("{} bytes", source_size)),
("Parse time".to_string(), format!("{:.2}ms", parse_time_ms)),
]
}
pub fn format_codegen_trace(
output_size: usize,
dependencies_count: usize,
) -> Vec<(String, String)> {
vec![
(
"Generated Rust code".to_string(),
format!("{} bytes", output_size),
),
(
"Dependencies detected".to_string(),
format!("{}", dependencies_count),
),
("Generation".to_string(), "complete".to_string()),
]
}
pub fn format_oracle_trace(
oracle_config: &OracleConfig,
pattern_path: Option<&Path>,
) -> Vec<(String, String)> {
let mut details = vec![
(
"Threshold".to_string(),
format!("{:.0}%", oracle_config.threshold * 100.0),
),
(
"Max retries".to_string(),
format!("{}", oracle_config.max_retries),
),
(
"LLM fallback".to_string(),
if oracle_config.llm_fallback {
"enabled"
} else {
"disabled"
}
.to_string(),
),
];
if let Some(path) = pattern_path {
details.insert(0, ("Pattern file".to_string(), path.display().to_string()));
}
details
}
#[allow(clippy::too_many_arguments)]
pub fn format_summary(
input_path: &Path,
output_path: &Path,
source_size: usize,
output_size: usize,
parse_time_ms: u64,
total_time_ms: u64,
dependencies_count: usize,
verified: bool,
) -> Vec<String> {
let throughput = if parse_time_ms > 0 {
(source_size as f64 / 1024.0) / (parse_time_ms as f64 / 1000.0)
} else {
0.0
};
let mut lines = vec![
format!(
"📄 Source: {} ({} bytes)",
input_path.display(),
source_size
),
format!(
"📝 Output: {} ({} bytes)",
output_path.display(),
output_size
),
];
if dependencies_count > 0 {
let mut cargo_path = output_path.to_path_buf();
cargo_path.set_file_name("Cargo.toml");
lines.push(format!(
"📦 Cargo.toml: {} ({} dependencies)",
cargo_path.display(),
dependencies_count
));
}
lines.push(format!("⏱️ Parse time: {:.2}ms", parse_time_ms));
lines.push(format!("📊 Throughput: {:.1} KB/s", throughput));
lines.push(format!("⏱️ Total time: {:.2}ms", total_time_ms));
if verified {
lines.push("✓ Properties Verified".to_string());
}
lines
}
pub fn validate_confidence_threshold(threshold: f64) -> Result<f64, &'static str> {
if threshold.is_nan() {
Err("Confidence threshold cannot be NaN")
} else if threshold < 0.0 {
Err("Confidence threshold cannot be negative")
} else if threshold > 1.0 {
Err("Confidence threshold cannot exceed 1.0")
} else {
Ok(threshold)
}
}
pub fn validate_max_retries(max_retries: usize) -> Result<usize, &'static str> {
if max_retries == 0 {
Err("Max retries must be at least 1")
} else if max_retries > 100 {
Err("Max retries cannot exceed 100")
} else {
Ok(max_retries)
}
}
pub fn requires_oracle(config: &TranspileConfig) -> bool {
config.oracle || config.auto_fix || config.suggest_fixes
}
pub fn determine_debug_level(config: &TranspileConfig) -> DebugLevel {
if config.debug {
DebugLevel::Full
} else if config.source_map {
DebugLevel::Basic
} else {
DebugLevel::None
}
}
pub fn format_explanation() -> Vec<String> {
vec![
"Transformation Decisions:".to_string(),
" 1. Python AST -> HIR: Converted Python constructs to type-safe HIR".to_string(),
" 2. HIR -> Rust: Generated idiomatic Rust code with:".to_string(),
" - Type inference for local variables".to_string(),
" - Ownership and borrowing semantics".to_string(),
" - Memory safety guarantees".to_string(),
" 3. Module mapping: Applied Python->Rust standard library mappings".to_string(),
]
}
pub fn format_ml_result(
strategy: &str,
confidence: f64,
is_auto_fix: bool,
threshold: f64,
) -> String {
let confidence_pct = confidence * 100.0;
let is_high = confidence >= threshold;
if is_auto_fix && is_high {
format!("🔧 Auto-fix applied with {:.2}% confidence", confidence_pct)
} else if is_high {
format!(
"✓ High confidence ({:.2}%) - auto-fix would apply",
confidence_pct
)
} else {
format!(
"⚠ Low confidence ({:.2}%) - manual review recommended [strategy: {}]",
confidence_pct, strategy
)
}
}
pub fn should_use_result(confidence: f64, threshold: f64) -> bool {
!confidence.is_nan() && !threshold.is_nan() && confidence >= threshold
}
#[cfg(test)]
mod tests {
use super::*;
use std::path::Path;
#[test]
fn test_transpile_config_default() {
let config = TranspileConfig::default();
assert!(!config.verify);
assert!(!config.debug);
assert!(!config.trace);
assert!(!config.async_mode);
assert_eq!(config.fix_confidence, 0.0);
assert_eq!(config.max_retries, 0);
}
#[test]
fn test_transpile_config_all_enabled() {
let config = TranspileConfig {
verify: true,
gen_tests: true,
debug: true,
source_map: true,
trace: true,
explain: true,
audit_trail: true,
auto_fix: true,
async_mode: true,
suggest_fixes: true,
fix_confidence: 0.8,
oracle: true,
max_retries: 5,
llm_fallback: true,
};
assert!(config.verify);
assert!(config.async_mode);
assert_eq!(config.fix_confidence, 0.8);
}
#[test]
fn test_autofix_strategy_none() {
let config = TranspileConfig::default();
assert_eq!(determine_autofix_strategy(&config), AutoFixStrategy::None);
}
#[test]
fn test_autofix_strategy_synchronous() {
let config = TranspileConfig {
auto_fix: true,
..Default::default()
};
assert_eq!(
determine_autofix_strategy(&config),
AutoFixStrategy::Synchronous
);
}
#[test]
fn test_autofix_strategy_async() {
let config = TranspileConfig {
auto_fix: true,
async_mode: true,
..Default::default()
};
assert_eq!(determine_autofix_strategy(&config), AutoFixStrategy::Async);
}
#[test]
fn test_autofix_strategy_suggest_only() {
let config = TranspileConfig {
suggest_fixes: true,
..Default::default()
};
assert_eq!(
determine_autofix_strategy(&config),
AutoFixStrategy::SuggestOnly
);
}
#[test]
fn test_autofix_strategy_autofix_overrides_suggest() {
let config = TranspileConfig {
auto_fix: true,
suggest_fixes: true,
..Default::default()
};
assert_eq!(
determine_autofix_strategy(&config),
AutoFixStrategy::Synchronous
);
}
#[test]
fn test_evaluate_confidence_high() {
assert_eq!(evaluate_confidence(0.9, 0.8), ConfidenceLevel::High);
assert_eq!(evaluate_confidence(0.8, 0.8), ConfidenceLevel::High);
assert_eq!(evaluate_confidence(1.0, 0.5), ConfidenceLevel::High);
}
#[test]
fn test_evaluate_confidence_low() {
assert_eq!(evaluate_confidence(0.5, 0.8), ConfidenceLevel::Low);
assert_eq!(evaluate_confidence(0.0, 0.1), ConfidenceLevel::Low);
assert_eq!(evaluate_confidence(0.79, 0.8), ConfidenceLevel::Low);
}
#[test]
fn test_evaluate_confidence_unknown_nan() {
assert_eq!(evaluate_confidence(f64::NAN, 0.8), ConfidenceLevel::Unknown);
assert_eq!(evaluate_confidence(0.9, f64::NAN), ConfidenceLevel::Unknown);
assert_eq!(
evaluate_confidence(f64::NAN, f64::NAN),
ConfidenceLevel::Unknown
);
}
#[test]
fn test_build_oracle_config() {
let config = TranspileConfig {
oracle: true,
fix_confidence: 0.75,
max_retries: 3,
llm_fallback: true,
..Default::default()
};
let oracle_config = build_oracle_config(&config);
assert!(oracle_config.enabled);
assert_eq!(oracle_config.threshold, 0.75);
assert_eq!(oracle_config.max_retries, 3);
assert!(oracle_config.llm_fallback);
}
#[test]
fn test_build_oracle_config_disabled() {
let config = TranspileConfig::default();
let oracle_config = build_oracle_config(&config);
assert!(!oracle_config.enabled);
assert_eq!(oracle_config.threshold, 0.0);
assert!(!oracle_config.llm_fallback);
}
#[test]
fn test_compute_output_path_with_explicit() {
let input = Path::new("/src/test.py");
let output = Path::new("/out/result.rs");
let result = compute_output_path(input, Some(output));
assert_eq!(result, PathBuf::from("/out/result.rs"));
}
#[test]
fn test_compute_output_path_auto() {
let input = Path::new("/src/test.py");
let result = compute_output_path(input, None);
assert_eq!(result, PathBuf::from("/src/test.rs"));
}
#[test]
fn test_compute_output_path_no_extension() {
let input = Path::new("/src/myfile");
let result = compute_output_path(input, None);
assert_eq!(result, PathBuf::from("/src/myfile.rs"));
}
#[test]
fn test_compute_output_paths_minimal() {
let input = Path::new("/src/test.py");
let config = TranspileConfig::default();
let paths = compute_output_paths(input, None, &config, false);
assert_eq!(paths.main_output, PathBuf::from("/src/test.rs"));
assert!(paths.autofix_output.is_none());
assert!(paths.test_output.is_none());
assert!(paths.cargo_toml.is_none());
assert!(paths.source_map.is_none());
}
#[test]
fn test_compute_output_paths_with_tests() {
let input = Path::new("/src/test.py");
let config = TranspileConfig {
gen_tests: true,
..Default::default()
};
let paths = compute_output_paths(input, None, &config, false);
assert_eq!(paths.test_output, Some(PathBuf::from("/src/test.test.rs")));
}
#[test]
fn test_compute_output_paths_with_dependencies() {
let input = Path::new("/src/test.py");
let config = TranspileConfig::default();
let paths = compute_output_paths(input, None, &config, true);
assert_eq!(paths.cargo_toml, Some(PathBuf::from("/src/Cargo.toml")));
}
#[test]
fn test_compute_output_paths_with_source_map() {
let input = Path::new("/src/test.py");
let config = TranspileConfig {
source_map: true,
..Default::default()
};
let paths = compute_output_paths(input, None, &config, false);
assert_eq!(
paths.source_map,
Some(PathBuf::from("/src/test.rs.sourcemap.json"))
);
}
#[test]
fn test_compute_output_paths_with_async_autofix() {
let input = Path::new("/src/test.py");
let config = TranspileConfig {
auto_fix: true,
async_mode: true,
..Default::default()
};
let paths = compute_output_paths(input, None, &config, false);
assert_eq!(
paths.autofix_output,
Some(PathBuf::from("/src/test.autofix.rs"))
);
}
#[test]
fn test_compute_output_paths_all_options() {
let input = Path::new("/src/example.py");
let output = Path::new("/out/result.rs");
let config = TranspileConfig {
gen_tests: true,
source_map: true,
auto_fix: true,
async_mode: true,
..Default::default()
};
let paths = compute_output_paths(input, Some(output), &config, true);
assert_eq!(paths.main_output, PathBuf::from("/out/result.rs"));
assert!(paths.autofix_output.is_some());
assert!(paths.test_output.is_some());
assert!(paths.cargo_toml.is_some());
assert!(paths.source_map.is_some());
}
#[test]
fn test_extract_package_name() {
assert_eq!(
extract_package_name(Path::new("/src/my_project.rs")),
"my_project"
);
assert_eq!(extract_package_name(Path::new("example.rs")), "example");
assert_eq!(
extract_package_name(Path::new("/a/b/c/test_module.rs")),
"test_module"
);
}
#[test]
fn test_extract_package_name_no_stem() {
assert_eq!(extract_package_name(Path::new("/")), "transpiled_package");
assert_eq!(extract_package_name(Path::new("")), "transpiled_package");
}
#[test]
fn test_extract_source_file_name() {
assert_eq!(
extract_source_file_name(Path::new("/src/main.rs")),
"main.rs"
);
assert_eq!(extract_source_file_name(Path::new("lib.rs")), "lib.rs");
}
#[test]
fn test_extract_source_file_name_no_name() {
assert_eq!(extract_source_file_name(Path::new("/")), "main.rs");
}
#[test]
fn test_format_init_trace_default() {
let config = TranspileConfig::default();
let trace = format_init_trace(&config);
assert_eq!(trace.len(), 4);
assert_eq!(trace[0].1, "disabled");
assert_eq!(trace[1].1, "disabled");
}
#[test]
fn test_format_init_trace_enabled() {
let config = TranspileConfig {
verify: true,
debug: true,
source_map: true,
audit_trail: true,
..Default::default()
};
let trace = format_init_trace(&config);
assert_eq!(trace[0].1, "enabled");
assert_eq!(trace[1].1, "enabled");
assert_eq!(trace[2].1, "enabled");
assert!(trace[3].1.contains("HashChainCollector"));
}
#[test]
fn test_format_parse_trace() {
let trace = format_parse_trace(1024, 15);
assert_eq!(trace.len(), 2);
assert_eq!(trace[0].0, "Input size");
assert!(trace[0].1.contains("1024"));
assert!(trace[1].1.contains("15"));
}
#[test]
fn test_format_codegen_trace() {
let trace = format_codegen_trace(2048, 5);
assert_eq!(trace.len(), 3);
assert!(trace[0].1.contains("2048"));
assert!(trace[1].1.contains("5"));
assert_eq!(trace[2].1, "complete");
}
#[test]
fn test_format_oracle_trace_without_pattern() {
let oracle_config = OracleConfig {
enabled: true,
threshold: 0.75,
max_retries: 3,
llm_fallback: false,
};
let trace = format_oracle_trace(&oracle_config, None);
assert_eq!(trace.len(), 3);
assert!(trace[0].1.contains("75%"));
assert!(trace[1].1.contains("3"));
assert_eq!(trace[2].1, "disabled");
}
#[test]
fn test_format_oracle_trace_with_pattern() {
let oracle_config = OracleConfig {
enabled: true,
threshold: 0.8,
max_retries: 5,
llm_fallback: true,
};
let pattern = Path::new("/patterns/oracle.json");
let trace = format_oracle_trace(&oracle_config, Some(pattern));
assert_eq!(trace.len(), 4);
assert!(trace[0].1.contains("oracle.json"));
}
#[test]
fn test_format_summary_basic() {
let summary = format_summary(
Path::new("/src/test.py"),
Path::new("/out/test.rs"),
1000,
800,
10,
100,
0,
false,
);
assert!(summary.len() >= 4);
assert!(summary[0].contains("test.py"));
assert!(summary[1].contains("test.rs"));
assert!(summary.iter().any(|s| s.contains("Parse time")));
}
#[test]
fn test_format_summary_with_dependencies() {
let summary = format_summary(
Path::new("input.py"),
Path::new("output.rs"),
500,
400,
5,
50,
3,
false,
);
assert!(summary.iter().any(|s| s.contains("Cargo.toml")));
assert!(summary.iter().any(|s| s.contains("3 dependencies")));
}
#[test]
fn test_format_summary_verified() {
let summary = format_summary(
Path::new("in.py"),
Path::new("out.rs"),
100,
80,
2,
20,
0,
true,
);
assert!(summary.iter().any(|s| s.contains("Verified")));
}
#[test]
fn test_format_summary_zero_parse_time() {
let summary = format_summary(
Path::new("in.py"),
Path::new("out.rs"),
100,
80,
0,
10,
0,
false,
);
assert!(summary.iter().any(|s| s.contains("0.0 KB/s")));
}
#[test]
fn test_validate_confidence_threshold_valid() {
assert_eq!(validate_confidence_threshold(0.0), Ok(0.0));
assert_eq!(validate_confidence_threshold(0.5), Ok(0.5));
assert_eq!(validate_confidence_threshold(1.0), Ok(1.0));
}
#[test]
fn test_validate_confidence_threshold_negative() {
assert!(validate_confidence_threshold(-0.1).is_err());
}
#[test]
fn test_validate_confidence_threshold_too_high() {
assert!(validate_confidence_threshold(1.1).is_err());
}
#[test]
fn test_validate_confidence_threshold_nan() {
assert!(validate_confidence_threshold(f64::NAN).is_err());
}
#[test]
fn test_validate_max_retries_valid() {
assert_eq!(validate_max_retries(1), Ok(1));
assert_eq!(validate_max_retries(50), Ok(50));
assert_eq!(validate_max_retries(100), Ok(100));
}
#[test]
fn test_validate_max_retries_zero() {
assert!(validate_max_retries(0).is_err());
}
#[test]
fn test_validate_max_retries_too_high() {
assert!(validate_max_retries(101).is_err());
}
#[test]
fn test_requires_oracle_disabled() {
let config = TranspileConfig::default();
assert!(!requires_oracle(&config));
}
#[test]
fn test_requires_oracle_oracle_flag() {
let config = TranspileConfig {
oracle: true,
..Default::default()
};
assert!(requires_oracle(&config));
}
#[test]
fn test_requires_oracle_auto_fix() {
let config = TranspileConfig {
auto_fix: true,
..Default::default()
};
assert!(requires_oracle(&config));
}
#[test]
fn test_requires_oracle_suggest_fixes() {
let config = TranspileConfig {
suggest_fixes: true,
..Default::default()
};
assert!(requires_oracle(&config));
}
#[test]
fn test_determine_debug_level_none() {
let config = TranspileConfig::default();
assert_eq!(determine_debug_level(&config), DebugLevel::None);
}
#[test]
fn test_determine_debug_level_basic() {
let config = TranspileConfig {
source_map: true,
..Default::default()
};
assert_eq!(determine_debug_level(&config), DebugLevel::Basic);
}
#[test]
fn test_determine_debug_level_full() {
let config = TranspileConfig {
debug: true,
..Default::default()
};
assert_eq!(determine_debug_level(&config), DebugLevel::Full);
}
#[test]
fn test_determine_debug_level_debug_overrides_source_map() {
let config = TranspileConfig {
debug: true,
source_map: true,
..Default::default()
};
assert_eq!(determine_debug_level(&config), DebugLevel::Full);
}
#[test]
fn test_format_explanation() {
let exp = format_explanation();
assert!(exp.len() >= 5);
assert!(exp[0].contains("Transformation"));
assert!(exp.iter().any(|s| s.contains("HIR")));
assert!(exp.iter().any(|s| s.contains("Rust")));
}
#[test]
fn test_format_ml_result_autofix_high() {
let msg = format_ml_result("ast", 0.9, true, 0.8);
assert!(msg.contains("Auto-fix applied"));
assert!(msg.contains("90.00%"));
}
#[test]
fn test_format_ml_result_high_no_autofix() {
let msg = format_ml_result("ml", 0.85, false, 0.8);
assert!(msg.contains("High confidence"));
assert!(msg.contains("would apply"));
}
#[test]
fn test_format_ml_result_low() {
let msg = format_ml_result("fallback", 0.5, false, 0.8);
assert!(msg.contains("Low confidence"));
assert!(msg.contains("manual review"));
assert!(msg.contains("fallback"));
}
#[test]
fn test_format_ml_result_boundary() {
let msg = format_ml_result("exact", 0.8, false, 0.8);
assert!(msg.contains("High confidence"));
}
#[test]
fn test_should_use_result_high() {
assert!(should_use_result(0.9, 0.8));
assert!(should_use_result(0.8, 0.8));
assert!(should_use_result(1.0, 0.0));
}
#[test]
fn test_should_use_result_low() {
assert!(!should_use_result(0.5, 0.8));
assert!(!should_use_result(0.0, 0.1));
}
#[test]
fn test_should_use_result_nan() {
assert!(!should_use_result(f64::NAN, 0.8));
assert!(!should_use_result(0.9, f64::NAN));
}
#[test]
fn test_create_pipeline_basic() {
let config = TranspileConfig::default();
let _pipeline = create_pipeline(&config);
}
#[test]
fn test_create_pipeline_with_verify() {
let config = TranspileConfig {
verify: true,
..Default::default()
};
let _pipeline = create_pipeline(&config);
}
#[test]
fn test_create_pipeline_with_debug() {
let config = TranspileConfig {
debug: true,
..Default::default()
};
let _pipeline = create_pipeline(&config);
}
#[test]
fn test_create_pipeline_with_source_map() {
let config = TranspileConfig {
source_map: true,
..Default::default()
};
let _pipeline = create_pipeline(&config);
}
#[test]
fn test_create_pipeline_all_options() {
let config = TranspileConfig {
verify: true,
debug: true,
source_map: true,
..Default::default()
};
let _pipeline = create_pipeline(&config);
}
#[test]
fn test_transpile_simple() {
let config = TranspileConfig::default();
let source = "def add(a: int, b: int) -> int:\n return a + b\n";
let result = transpile_source(source, &config).unwrap();
assert!(result.rust_code.contains("fn add"));
assert_eq!(result.source_size, source.len());
assert!(result.output_size > 0);
}
#[test]
fn test_transpile_with_verify() {
let config = TranspileConfig {
verify: true,
..Default::default()
};
let source = "x: int = 42\n";
let result = transpile_source(source, &config).unwrap();
assert!(!result.rust_code.is_empty());
}
#[test]
fn test_transpile_empty_source() {
let config = TranspileConfig::default();
let result = transpile_source("", &config);
let _ = result;
}
#[test]
fn test_format_trace_phase() {
let trace = format_trace_phase(
1,
"Parsing",
&[("Input size", "1024 bytes"), ("Parser", "RustPython")],
);
assert!(trace.contains("Phase 1: Parsing"));
assert!(trace.contains("Input size: 1024 bytes"));
assert!(trace.contains("Parser: RustPython"));
}
#[test]
fn test_format_trace_phase_empty_details() {
let trace = format_trace_phase(2, "Generation", &[]);
assert!(trace.contains("Phase 2: Generation"));
assert!(!trace.contains(" - "));
}
#[test]
fn test_calculate_metrics() {
let result = TranspileResult {
rust_code: "fn test() {}".to_string(),
source_size: 1000,
output_size: 500,
parse_time_ms: 10,
transpile_time_ms: 90,
verification_passed: None,
fixes_applied: 0,
};
let metrics = calculate_metrics(&result);
assert!((metrics.compression_ratio - 0.5).abs() < 0.01);
assert_eq!(metrics.total_time_ms, 100);
assert!(metrics.throughput_kb_per_sec > 0.0);
}
#[test]
fn test_calculate_metrics_empty_source() {
let result = TranspileResult {
rust_code: String::new(),
source_size: 0,
output_size: 0,
parse_time_ms: 0,
transpile_time_ms: 0,
verification_passed: None,
fixes_applied: 0,
};
let metrics = calculate_metrics(&result);
assert_eq!(metrics.compression_ratio, 0.0);
assert_eq!(metrics.throughput_kb_per_sec, 0.0);
}
#[test]
fn test_calculate_metrics_expansion() {
let result = TranspileResult {
rust_code: "// expanded".to_string(),
source_size: 100,
output_size: 300,
parse_time_ms: 5,
transpile_time_ms: 5,
verification_passed: Some(true),
fixes_applied: 0,
};
let metrics = calculate_metrics(&result);
assert!((metrics.compression_ratio - 3.0).abs() < 0.01);
}
#[test]
fn test_transpile_result_fields() {
let result = TranspileResult {
rust_code: "// test".to_string(),
source_size: 100,
output_size: 7,
parse_time_ms: 5,
transpile_time_ms: 15,
verification_passed: Some(true),
fixes_applied: 2,
};
assert_eq!(result.source_size, 100);
assert_eq!(result.fixes_applied, 2);
assert_eq!(result.verification_passed, Some(true));
}
#[test]
fn test_transpile_result_verification_none() {
let result = TranspileResult {
rust_code: String::new(),
source_size: 0,
output_size: 0,
parse_time_ms: 0,
transpile_time_ms: 0,
verification_passed: None,
fixes_applied: 0,
};
assert!(result.verification_passed.is_none());
}
#[test]
fn test_transpile_result_verification_false() {
let result = TranspileResult {
rust_code: "bad".to_string(),
source_size: 10,
output_size: 3,
parse_time_ms: 1,
transpile_time_ms: 1,
verification_passed: Some(false),
fixes_applied: 0,
};
assert_eq!(result.verification_passed, Some(false));
}
#[test]
fn test_autofix_strategy_eq() {
assert_eq!(AutoFixStrategy::None, AutoFixStrategy::None);
assert_ne!(AutoFixStrategy::None, AutoFixStrategy::Async);
}
#[test]
fn test_autofix_strategy_clone() {
let strategy = AutoFixStrategy::Synchronous;
let cloned = strategy;
assert_eq!(strategy, cloned);
}
#[test]
fn test_confidence_level_eq() {
assert_eq!(ConfidenceLevel::High, ConfidenceLevel::High);
assert_ne!(ConfidenceLevel::High, ConfidenceLevel::Low);
}
#[test]
fn test_output_paths_clone() {
let paths = OutputPaths {
main_output: PathBuf::from("/test.rs"),
autofix_output: Some(PathBuf::from("/test.autofix.rs")),
test_output: None,
cargo_toml: None,
source_map: None,
};
let cloned = paths.clone();
assert_eq!(paths.main_output, cloned.main_output);
assert_eq!(paths.autofix_output, cloned.autofix_output);
}
}