use super::*;
use proptest::prelude::*;
use std::sync::Arc;
use tempfile::TempDir;
mod property_tests {
use proptest::prelude::*;
proptest! {
#[test]
fn basic_property_stability(_input in ".*") {
prop_assert!(true);
}
#[test]
fn module_consistency_check(_x in 0u32..1000) {
prop_assert!(_x < 1001);
}
}
}
mod coverage_tests {
use super::*;
use proptest::prelude::*;
use tempfile::TempDir;
fn create_temp_project() -> TempDir {
let dir = TempDir::new().unwrap();
let src_dir = dir.path().join("src");
std::fs::create_dir_all(&src_dir).unwrap();
let rust_file = src_dir.join("main.rs");
std::fs::write(&rust_file, "fn main() { println!(\"Hello\"); }").unwrap();
let ts_file = src_dir.join("index.ts");
std::fs::write(&ts_file, "export const hello = () => console.log('hi');").unwrap();
dir
}
fn create_temp_checkpoint() -> (TempDir, PathBuf) {
let dir = TempDir::new().unwrap();
let checkpoint_file = dir.path().join("checkpoint.json");
let checkpoint_data = serde_json::json!({
"current": "Analyze",
"targets": ["src/main.rs", "src/lib.rs"],
"current_target_index": 1,
"config": {
"target_complexity": 20,
"parallel_workers": 4
}
});
std::fs::write(
&checkpoint_file,
serde_json::to_string_pretty(&checkpoint_data).unwrap(),
)
.unwrap();
(dir, checkpoint_file)
}
fn create_temp_config_json() -> (TempDir, PathBuf) {
let dir = TempDir::new().unwrap();
let config_file = dir.path().join("refactor.json");
let config_data = serde_json::json!({
"rules": {
"target_complexity": 15,
"max_function_lines": 40,
"remove_satd": false
},
"parallel_workers": 8,
"memory_limit_mb": 1024,
"batch_size": 20,
"priority_expression": "complexity * defect_probability",
"auto_commit_template": "refactor: fix {files} files"
});
std::fs::write(
&config_file,
serde_json::to_string_pretty(&config_data).unwrap(),
)
.unwrap();
(dir, config_file)
}
#[test]
fn test_refactor_serve_params_creation() {
let params = RefactorServeParams {
mode: RefactorMode::Batch,
config: Some(PathBuf::from("/tmp/config.json")),
project: PathBuf::from("/tmp/project"),
parallel: 4,
memory_limit: 512,
batch_size: 10,
priority: Some("complexity".to_string()),
checkpoint_dir: Some(PathBuf::from("/tmp/checkpoints")),
resume: false,
auto_commit: Some("refactor: {files} files".to_string()),
max_runtime: Some(3600),
};
assert_eq!(params.parallel, 4);
assert_eq!(params.memory_limit, 512);
assert_eq!(params.batch_size, 10);
assert!(!params.resume);
}
#[test]
fn test_refactor_serve_params_defaults() {
let params = RefactorServeParams {
mode: RefactorMode::Interactive,
config: None,
project: PathBuf::from("."),
parallel: 1,
memory_limit: 256,
batch_size: 5,
priority: None,
checkpoint_dir: None,
resume: true,
auto_commit: None,
max_runtime: None,
};
assert!(params.config.is_none());
assert!(params.priority.is_none());
assert!(params.checkpoint_dir.is_none());
assert!(params.resume);
assert!(params.auto_commit.is_none());
assert!(params.max_runtime.is_none());
}
#[test]
fn test_extract_refactor_params_full() {
let params = RefactorServeParams {
mode: RefactorMode::Batch,
config: Some(PathBuf::from("/config.json")),
project: PathBuf::from("/project"),
parallel: 8,
memory_limit: 1024,
batch_size: 20,
priority: Some("high".to_string()),
checkpoint_dir: Some(PathBuf::from("/checkpoints")),
resume: true,
auto_commit: Some("commit template".to_string()),
max_runtime: Some(7200),
};
let extracted = extract_refactor_params(params);
assert_eq!(extracted.parallel, 8);
assert_eq!(extracted.memory_limit, 1024);
assert_eq!(extracted.batch_size, 20);
assert!(extracted.resume);
assert_eq!(extracted.priority, Some("high".to_string()));
assert_eq!(extracted.max_runtime, Some(7200));
}
#[test]
fn test_extract_refactor_params_minimal() {
let params = RefactorServeParams {
mode: RefactorMode::Interactive,
config: None,
project: PathBuf::from("."),
parallel: 1,
memory_limit: 128,
batch_size: 1,
priority: None,
checkpoint_dir: None,
resume: false,
auto_commit: None,
max_runtime: None,
};
let extracted = extract_refactor_params(params);
assert_eq!(extracted.parallel, 1);
assert_eq!(extracted.memory_limit, 128);
assert!(extracted.config.is_none());
assert!(!extracted.resume);
}
#[test]
fn test_log_refactor_server_startup_batch() {
let params = ExtractedRefactorParams {
mode: RefactorMode::Batch,
config: None,
project: PathBuf::from("/test/project"),
parallel: 4,
memory_limit: 512,
batch_size: 10,
priority: None,
checkpoint_dir: None,
resume: false,
auto_commit: None,
max_runtime: None,
};
log_refactor_server_startup(¶ms);
}
#[test]
fn test_log_refactor_server_startup_interactive() {
let params = ExtractedRefactorParams {
mode: RefactorMode::Interactive,
config: Some(PathBuf::from("config.json")),
project: PathBuf::from("./my-project"),
parallel: 2,
memory_limit: 256,
batch_size: 5,
priority: Some("defect_probability".to_string()),
checkpoint_dir: Some(PathBuf::from("/tmp/cp")),
resume: true,
auto_commit: Some("template".to_string()),
max_runtime: Some(1800),
};
log_refactor_server_startup(¶ms);
}
#[test]
fn test_apply_command_line_overrides_all() {
let mut config = RefactorConfig::default();
let params = ExtractedRefactorParams {
mode: RefactorMode::Batch,
config: None,
project: PathBuf::from("."),
parallel: 16,
memory_limit: 2048,
batch_size: 50,
priority: Some("complexity * churn".to_string()),
checkpoint_dir: None,
resume: false,
auto_commit: Some("refactor: {refactors} changes".to_string()),
max_runtime: None,
};
apply_command_line_overrides(&mut config, ¶ms);
assert_eq!(config.parallel_workers, 16);
assert_eq!(config.memory_limit_mb, 2048);
assert_eq!(config.batch_size, 50);
assert_eq!(
config.priority_expression,
Some("complexity * churn".to_string())
);
assert_eq!(
config.auto_commit_template,
Some("refactor: {refactors} changes".to_string())
);
}
#[test]
fn test_apply_command_line_overrides_none() {
let mut config = RefactorConfig::default();
let original_parallel = config.parallel_workers;
let original_memory = config.memory_limit_mb;
let original_batch = config.batch_size;
let params = ExtractedRefactorParams {
mode: RefactorMode::Interactive,
config: None,
project: PathBuf::from("."),
parallel: original_parallel,
memory_limit: original_memory,
batch_size: original_batch,
priority: None,
checkpoint_dir: None,
resume: false,
auto_commit: None,
max_runtime: None,
};
apply_command_line_overrides(&mut config, ¶ms);
assert!(config.priority_expression.is_none());
assert!(config.auto_commit_template.is_none());
}
#[tokio::test]
async fn test_setup_checkpoint_directory_default() {
let temp_dir = TempDir::new().unwrap();
let project_path = temp_dir.path().to_path_buf();
let params = ExtractedRefactorParams {
mode: RefactorMode::Batch,
config: None,
project: project_path.clone(),
parallel: 4,
memory_limit: 512,
batch_size: 10,
priority: None,
checkpoint_dir: None,
resume: false,
auto_commit: None,
max_runtime: None,
};
let result = setup_checkpoint_directory(¶ms).await;
assert!(result.is_ok());
let checkpoint_path = result.unwrap();
assert_eq!(checkpoint_path, project_path.join(".refactor_checkpoints"));
assert!(checkpoint_path.exists());
}
#[tokio::test]
async fn test_setup_checkpoint_directory_custom() {
let temp_dir = TempDir::new().unwrap();
let custom_checkpoint = temp_dir.path().join("custom_checkpoints");
let params = ExtractedRefactorParams {
mode: RefactorMode::Batch,
config: None,
project: PathBuf::from("/tmp/project"),
parallel: 4,
memory_limit: 512,
batch_size: 10,
priority: None,
checkpoint_dir: Some(custom_checkpoint.clone()),
resume: false,
auto_commit: None,
max_runtime: None,
};
let result = setup_checkpoint_directory(¶ms).await;
assert!(result.is_ok());
assert_eq!(result.unwrap(), custom_checkpoint);
}
#[tokio::test]
async fn test_setup_checkpoint_directory_resume() {
let temp_dir = TempDir::new().unwrap();
let checkpoint_dir = temp_dir.path().join("existing_checkpoints");
std::fs::create_dir_all(&checkpoint_dir).unwrap();
let params = ExtractedRefactorParams {
mode: RefactorMode::Batch,
config: None,
project: PathBuf::from("/tmp/project"),
parallel: 4,
memory_limit: 512,
batch_size: 10,
priority: None,
checkpoint_dir: Some(checkpoint_dir.clone()),
resume: true, auto_commit: None,
max_runtime: None,
};
let result = setup_checkpoint_directory(¶ms).await;
assert!(result.is_ok());
assert_eq!(result.unwrap(), checkpoint_dir);
}
#[test]
fn test_setup_cache_and_ast_engine_normal() {
let result = setup_cache_and_ast_engine(512);
assert!(result.is_ok());
let (cache, ast_engine) = result.unwrap();
assert!(Arc::strong_count(&cache) >= 1);
assert!(Arc::strong_count(&ast_engine) >= 1);
}
#[test]
fn test_setup_cache_and_ast_engine_small_memory() {
let result = setup_cache_and_ast_engine(64);
assert!(result.is_ok());
}
#[test]
fn test_setup_cache_and_ast_engine_large_memory() {
let result = setup_cache_and_ast_engine(4096);
assert!(result.is_ok());
}
#[test]
fn test_create_engine_mode_batch() {
let checkpoint_path = PathBuf::from("/tmp/checkpoints");
let params = ExtractedRefactorParams {
mode: RefactorMode::Batch,
config: None,
project: PathBuf::from("."),
parallel: 4,
memory_limit: 512,
batch_size: 10,
priority: None,
checkpoint_dir: None,
resume: false,
auto_commit: None,
max_runtime: None,
};
let mode = create_engine_mode(¶ms, &checkpoint_path);
match mode {
EngineMode::Batch {
checkpoint_dir,
resume,
parallel_workers,
} => {
assert_eq!(checkpoint_dir, checkpoint_path);
assert!(!resume);
assert_eq!(parallel_workers, 4);
}
_ => panic!("Expected Batch mode"),
}
}
#[test]
fn test_create_engine_mode_batch_with_resume() {
let checkpoint_path = PathBuf::from("/tmp/checkpoints");
let params = ExtractedRefactorParams {
mode: RefactorMode::Batch,
config: None,
project: PathBuf::from("."),
parallel: 8,
memory_limit: 512,
batch_size: 10,
priority: None,
checkpoint_dir: None,
resume: true,
auto_commit: None,
max_runtime: None,
};
let mode = create_engine_mode(¶ms, &checkpoint_path);
match mode {
EngineMode::Batch {
resume,
parallel_workers,
..
} => {
assert!(resume);
assert_eq!(parallel_workers, 8);
}
_ => panic!("Expected Batch mode"),
}
}
#[test]
fn test_create_engine_mode_interactive() {
let checkpoint_path = PathBuf::from("/tmp/checkpoints");
let params = ExtractedRefactorParams {
mode: RefactorMode::Interactive,
config: None,
project: PathBuf::from("."),
parallel: 4,
memory_limit: 512,
batch_size: 10,
priority: None,
checkpoint_dir: None,
resume: false,
auto_commit: None,
max_runtime: None,
};
let mode = create_engine_mode(¶ms, &checkpoint_path);
match mode {
EngineMode::Interactive {
checkpoint_file,
explain_level,
} => {
assert_eq!(
checkpoint_file,
checkpoint_path.join("interactive_state.json")
);
assert!(matches!(
explain_level,
crate::services::refactor_engine::ExplainLevel::Detailed
));
}
_ => panic!("Expected Interactive mode"),
}
}
#[test]
fn test_validate_checkpoint_file_exists() {
let (_dir, checkpoint) = create_temp_checkpoint();
let result = validate_checkpoint_file(&checkpoint);
assert!(result.is_ok());
}
#[test]
fn test_validate_checkpoint_file_not_exists() {
let result = validate_checkpoint_file(Path::new("/nonexistent/checkpoint.json"));
assert!(result.is_err());
let err_msg = result.unwrap_err().to_string();
assert!(err_msg.contains("Checkpoint file not found"));
}
#[tokio::test]
async fn test_read_checkpoint_data_success() {
let (_dir, checkpoint) = create_temp_checkpoint();
let result = read_checkpoint_data(&checkpoint).await;
assert!(result.is_ok());
let data = result.unwrap();
assert!(data.contains("current"));
assert!(data.contains("targets"));
}
#[tokio::test]
async fn test_read_checkpoint_data_not_found() {
let result = read_checkpoint_data(&PathBuf::from("/nonexistent/file.json")).await;
assert!(result.is_err());
}
#[test]
fn test_format_as_json_valid() {
let checkpoint_data = r#"{"current": "Analyze", "targets": ["a.rs", "b.rs"]}"#;
let result = format_as_json(checkpoint_data);
assert!(result.is_ok());
}
#[test]
fn test_format_as_json_invalid() {
let checkpoint_data = "not valid json";
let result = format_as_json(checkpoint_data);
assert!(result.is_err());
}
#[test]
fn test_format_as_table_valid() {
let checkpoint_data = r#"{
"current": "Analyze",
"targets": ["a.rs", "b.rs"],
"current_target_index": 1
}"#;
let result = format_as_table(checkpoint_data);
assert!(result.is_ok());
}
#[test]
fn test_format_as_table_minimal() {
let checkpoint_data = r#"{}"#;
let result = format_as_table(checkpoint_data);
assert!(result.is_ok());
}
#[test]
fn test_format_as_table_invalid_json() {
let checkpoint_data = "invalid";
let result = format_as_table(checkpoint_data);
assert!(result.is_err());
}
#[test]
fn test_format_as_summary_valid() {
let checkpoint_data = r#"{
"current": "Plan",
"targets": ["x.rs", "y.rs", "z.rs"]
}"#;
let checkpoint_path = PathBuf::from("/tmp/checkpoint.json");
let result = format_as_summary(checkpoint_data, &checkpoint_path);
assert!(result.is_ok());
}
#[test]
fn test_format_as_summary_empty() {
let checkpoint_data = r#"{}"#;
let checkpoint_path = PathBuf::from("/tmp/cp.json");
let result = format_as_summary(checkpoint_data, &checkpoint_path);
assert!(result.is_ok());
}
#[test]
fn test_format_refactor_status_json() {
let checkpoint_data = r#"{"status": "ok"}"#;
let checkpoint = PathBuf::from("/tmp/test.json");
let result =
format_refactor_status(checkpoint_data, RefactorOutputFormat::Json, &checkpoint);
assert!(result.is_ok());
}
#[test]
fn test_format_refactor_status_table() {
let checkpoint_data = r#"{"current": "Test", "targets": []}"#;
let checkpoint = PathBuf::from("/tmp/test.json");
let result =
format_refactor_status(checkpoint_data, RefactorOutputFormat::Table, &checkpoint);
assert!(result.is_ok());
}
#[test]
fn test_format_refactor_status_summary() {
let checkpoint_data = r#"{"current": "Complete"}"#;
let checkpoint = PathBuf::from("/tmp/test.json");
let result =
format_refactor_status(checkpoint_data, RefactorOutputFormat::Summary, &checkpoint);
assert!(result.is_ok());
}
#[test]
fn test_print_table_header() {
print_table_header();
}
#[test]
fn test_print_table_footer() {
print_table_footer();
}
#[test]
fn test_print_table_data_full() {
let state: serde_json::Value = serde_json::json!({
"current": "Analyze",
"targets": ["a.rs", "b.rs", "c.rs"],
"current_target_index": 2
});
print_table_data(&state);
}
#[test]
fn test_print_table_data_partial() {
let state: serde_json::Value = serde_json::json!({
"current": "Test"
});
print_table_data(&state);
}
#[test]
fn test_print_table_data_empty() {
let state: serde_json::Value = serde_json::json!({});
print_table_data(&state);
}
#[test]
fn test_print_refactor_summary_normal() {
let summary = Summary {
files_processed: 10,
refactors_applied: 5,
complexity_reduction: 15.5,
satd_removed: 3,
total_time: Duration::from_secs(120),
};
print_refactor_summary(&summary);
}
#[test]
fn test_print_refactor_summary_zero() {
let summary = Summary::default();
print_refactor_summary(&summary);
}
#[test]
fn test_print_refactor_summary_large() {
let summary = Summary {
files_processed: 1000,
refactors_applied: 500,
complexity_reduction: 75.25,
satd_removed: 250,
total_time: Duration::from_secs(3600),
};
print_refactor_summary(&summary);
}
#[tokio::test]
async fn test_handle_auto_commit_no_template() {
let config = RefactorConfig::default();
let summary = Summary {
files_processed: 5,
refactors_applied: 3,
complexity_reduction: 10.0,
satd_removed: 1,
total_time: Duration::from_secs(60),
};
let result = handle_auto_commit(&config, &summary).await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_handle_auto_commit_with_template_no_refactors() {
let mut config = RefactorConfig::default();
config.auto_commit_template = Some("refactor: {files} files changed".to_string());
let summary = Summary {
files_processed: 5,
refactors_applied: 0, complexity_reduction: 0.0,
satd_removed: 0,
total_time: Duration::from_secs(30),
};
let result = handle_auto_commit(&config, &summary).await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_handle_refactor_status_json() {
let (_dir, checkpoint) = create_temp_checkpoint();
let result = handle_refactor_status(checkpoint, RefactorOutputFormat::Json).await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_handle_refactor_status_table() {
let (_dir, checkpoint) = create_temp_checkpoint();
let result = handle_refactor_status(checkpoint, RefactorOutputFormat::Table).await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_handle_refactor_status_summary() {
let (_dir, checkpoint) = create_temp_checkpoint();
let result = handle_refactor_status(checkpoint, RefactorOutputFormat::Summary).await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_handle_refactor_status_not_found() {
let result = handle_refactor_status(
PathBuf::from("/nonexistent/checkpoint.json"),
RefactorOutputFormat::Json,
)
.await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_handle_refactor_resume_valid() {
let (_dir, checkpoint) = create_temp_checkpoint();
let result = handle_refactor_resume(checkpoint, 10, None).await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_handle_refactor_resume_with_explain() {
let (_dir, checkpoint) = create_temp_checkpoint();
let result = handle_refactor_resume(checkpoint, 5, Some(ExplainLevel::Verbose)).await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_handle_refactor_resume_not_found() {
let result = handle_refactor_resume(
PathBuf::from("/nonexistent/checkpoint.json"),
10,
Some(ExplainLevel::Brief),
)
.await;
assert!(result.is_err());
let err_msg = result.unwrap_err().to_string();
assert!(err_msg.contains("Checkpoint file not found"));
}
#[tokio::test]
async fn test_load_refactor_config() {
let temp_dir = TempDir::new().unwrap();
let config_path = temp_dir.path().join("config.toml");
std::fs::write(&config_path, "# empty config").unwrap();
let result = load_refactor_config(&config_path).await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_load_refactor_config_json_full() {
let (_dir, config_path) = create_temp_config_json();
let result = load_refactor_config_json(&config_path).await;
assert!(result.is_ok());
let config = result.unwrap();
assert_eq!(config.target_complexity, 15);
assert_eq!(config.max_function_lines, 40);
assert!(!config.remove_satd);
assert_eq!(config.parallel_workers, 8);
assert_eq!(config.memory_limit_mb, 1024);
assert_eq!(config.batch_size, 20);
assert_eq!(
config.priority_expression,
Some("complexity * defect_probability".to_string())
);
assert_eq!(
config.auto_commit_template,
Some("refactor: fix {files} files".to_string())
);
}
#[tokio::test]
async fn test_load_refactor_config_json_minimal() {
let temp_dir = TempDir::new().unwrap();
let config_path = temp_dir.path().join("minimal.json");
std::fs::write(&config_path, "{}").unwrap();
let result = load_refactor_config_json(&config_path).await;
assert!(result.is_ok());
let config = result.unwrap();
assert_eq!(config.target_complexity, 20); }
#[tokio::test]
async fn test_load_refactor_config_json_invalid() {
let temp_dir = TempDir::new().unwrap();
let config_path = temp_dir.path().join("invalid.json");
std::fs::write(&config_path, "not json").unwrap();
let result = load_refactor_config_json(&config_path).await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_load_refactor_config_json_not_found() {
let result = load_refactor_config_json(Path::new("/nonexistent/config.json")).await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_sort_targets_by_priority() {
let targets = vec![
PathBuf::from("a.rs"),
PathBuf::from("b.rs"),
PathBuf::from("c.rs"),
];
let result = sort_targets_by_priority(targets.clone(), "complexity").await;
assert!(result.is_ok());
let sorted = result.unwrap();
assert_eq!(sorted.len(), 3);
assert_eq!(sorted[0], PathBuf::from("c.rs"));
assert_eq!(sorted[2], PathBuf::from("a.rs"));
}
#[tokio::test]
async fn test_sort_targets_by_priority_empty() {
let targets: Vec<PathBuf> = vec![];
let result = sort_targets_by_priority(targets, "any").await;
assert!(result.is_ok());
assert!(result.unwrap().is_empty());
}
#[tokio::test]
async fn test_discover_refactor_targets() {
let temp_dir = create_temp_project();
let result = discover_refactor_targets(&temp_dir.path().to_path_buf()).await;
assert!(result.is_ok());
let targets = result.unwrap();
assert!(!targets.is_empty());
let extensions: Vec<_> = targets
.iter()
.filter_map(|p| p.extension().map(|e| e.to_string_lossy().to_string()))
.collect();
assert!(extensions.contains(&"rs".to_string()));
assert!(extensions.contains(&"ts".to_string()));
}
#[tokio::test]
async fn test_discover_refactor_targets_empty_dir() {
let temp_dir = TempDir::new().unwrap();
let result = discover_refactor_targets(&temp_dir.path().to_path_buf()).await;
assert!(result.is_ok());
assert!(result.unwrap().is_empty());
}
#[tokio::test]
async fn test_discover_refactor_targets_various_extensions() {
let temp_dir = TempDir::new().unwrap();
let src = temp_dir.path().join("src");
std::fs::create_dir_all(&src).unwrap();
std::fs::write(src.join("app.rs"), "fn main() {}").unwrap();
std::fs::write(src.join("index.ts"), "export {};").unwrap();
std::fs::write(src.join("component.tsx"), "export default () => null;").unwrap();
std::fs::write(src.join("util.js"), "module.exports = {};").unwrap();
std::fs::write(src.join("helper.jsx"), "export default () => null;").unwrap();
std::fs::write(src.join("main.py"), "print('hi')").unwrap();
std::fs::write(src.join("readme.md"), "# Readme").unwrap();
let result = discover_refactor_targets(&temp_dir.path().to_path_buf()).await;
assert!(result.is_ok());
let targets = result.unwrap();
assert_eq!(targets.len(), 6); }
#[test]
fn test_explain_level_from_brief() {
let level: crate::services::refactor_engine::ExplainLevel = ExplainLevel::Brief.into();
assert!(matches!(
level,
crate::services::refactor_engine::ExplainLevel::Brief
));
}
#[test]
fn test_explain_level_from_detailed() {
let level: crate::services::refactor_engine::ExplainLevel = ExplainLevel::Detailed.into();
assert!(matches!(
level,
crate::services::refactor_engine::ExplainLevel::Detailed
));
}
#[test]
fn test_explain_level_from_verbose() {
let level: crate::services::refactor_engine::ExplainLevel = ExplainLevel::Verbose.into();
assert!(matches!(
level,
crate::services::refactor_engine::ExplainLevel::Verbose
));
}
#[tokio::test]
async fn test_load_base_configuration_with_file() {
let (_dir, config_path) = create_temp_config_json();
let params = ExtractedRefactorParams {
mode: RefactorMode::Batch,
config: Some(config_path),
project: PathBuf::from("."),
parallel: 4,
memory_limit: 512,
batch_size: 10,
priority: None,
checkpoint_dir: None,
resume: false,
auto_commit: None,
max_runtime: None,
};
let result = load_base_configuration(¶ms).await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_load_base_configuration_default() {
let params = ExtractedRefactorParams {
mode: RefactorMode::Batch,
config: None,
project: PathBuf::from("."),
parallel: 4,
memory_limit: 512,
batch_size: 10,
priority: None,
checkpoint_dir: None,
resume: false,
auto_commit: None,
max_runtime: None,
};
let result = load_base_configuration(¶ms).await;
assert!(result.is_ok());
let config = result.unwrap();
assert_eq!(config.target_complexity, 20); }
#[tokio::test]
async fn test_setup_refactor_configuration_with_overrides() {
let (_dir, config_path) = create_temp_config_json();
let params = ExtractedRefactorParams {
mode: RefactorMode::Batch,
config: Some(config_path),
project: PathBuf::from("."),
parallel: 32, memory_limit: 4096, batch_size: 100, priority: Some("high_priority".to_string()), checkpoint_dir: None,
resume: false,
auto_commit: Some("custom template".to_string()), max_runtime: None,
};
let result = setup_refactor_configuration(¶ms).await;
assert!(result.is_ok());
let config = result.unwrap();
assert_eq!(config.parallel_workers, 32);
assert_eq!(config.memory_limit_mb, 4096);
assert_eq!(config.batch_size, 100);
assert_eq!(
config.priority_expression,
Some("high_priority".to_string())
);
assert_eq!(
config.auto_commit_template,
Some("custom template".to_string())
);
}
#[tokio::test]
async fn test_discover_and_prioritize_targets_no_priority() {
let temp_dir = create_temp_project();
let params = ExtractedRefactorParams {
mode: RefactorMode::Batch,
config: None,
project: temp_dir.path().to_path_buf(),
parallel: 4,
memory_limit: 512,
batch_size: 10,
priority: None,
checkpoint_dir: None,
resume: false,
auto_commit: None,
max_runtime: None,
};
let config = RefactorConfig::default();
let result = discover_and_prioritize_targets(¶ms, &config).await;
assert!(result.is_ok());
assert!(!result.unwrap().is_empty());
}
#[tokio::test]
async fn test_discover_and_prioritize_targets_with_priority() {
let temp_dir = create_temp_project();
let params = ExtractedRefactorParams {
mode: RefactorMode::Batch,
config: None,
project: temp_dir.path().to_path_buf(),
parallel: 4,
memory_limit: 512,
batch_size: 10,
priority: None,
checkpoint_dir: None,
resume: false,
auto_commit: None,
max_runtime: None,
};
let mut config = RefactorConfig::default();
config.priority_expression = Some("complexity".to_string());
let result = discover_and_prioritize_targets(¶ms, &config).await;
assert!(result.is_ok());
}
proptest! {
#[test]
fn prop_extract_params_preserves_values(
parallel in 1usize..100,
memory_limit in 64usize..8192,
batch_size in 1usize..100,
max_runtime in proptest::option::of(1u64..86400)
) {
let params = RefactorServeParams {
mode: RefactorMode::Batch,
config: None,
project: PathBuf::from("."),
parallel,
memory_limit,
batch_size,
priority: None,
checkpoint_dir: None,
resume: false,
auto_commit: None,
max_runtime,
};
let extracted = extract_refactor_params(params);
prop_assert_eq!(extracted.parallel, parallel);
prop_assert_eq!(extracted.memory_limit, memory_limit);
prop_assert_eq!(extracted.batch_size, batch_size);
prop_assert_eq!(extracted.max_runtime, max_runtime);
}
#[test]
fn prop_apply_overrides_sets_config_values(
parallel in 1usize..100,
memory_limit in 64usize..8192,
batch_size in 1usize..100
) {
let mut config = RefactorConfig::default();
let params = ExtractedRefactorParams {
mode: RefactorMode::Batch,
config: None,
project: PathBuf::from("."),
parallel,
memory_limit,
batch_size,
priority: None,
checkpoint_dir: None,
resume: false,
auto_commit: None,
max_runtime: None,
};
apply_command_line_overrides(&mut config, ¶ms);
prop_assert_eq!(config.parallel_workers, parallel);
prop_assert_eq!(config.memory_limit_mb, memory_limit);
prop_assert_eq!(config.batch_size, batch_size);
}
#[test]
fn prop_cache_and_ast_engine_handles_various_memory_limits(memory_limit in 32usize..16384) {
let result = setup_cache_and_ast_engine(memory_limit);
prop_assert!(result.is_ok());
}
#[test]
fn prop_sort_targets_preserves_count(count in 0usize..20) {
let rt = tokio::runtime::Runtime::new().unwrap();
let targets: Vec<PathBuf> = (0..count).map(|i| PathBuf::from(format!("file{i}.rs"))).collect();
let original_count = targets.len();
let result = rt.block_on(sort_targets_by_priority(targets, "any"));
prop_assert!(result.is_ok());
prop_assert_eq!(result.unwrap().len(), original_count);
}
#[test]
fn prop_json_format_roundtrip(
current in "[A-Za-z]+",
target_count in 0usize..10
) {
let targets: Vec<String> = (0..target_count).map(|i| format!("file{i}.rs")).collect();
let json = serde_json::json!({
"current": current,
"targets": targets
});
let checkpoint_data = serde_json::to_string(&json).unwrap();
let result = format_as_json(&checkpoint_data);
prop_assert!(result.is_ok());
}
#[test]
fn prop_table_format_handles_various_states(
has_current in proptest::bool::ANY,
has_targets in proptest::bool::ANY,
has_index in proptest::bool::ANY
) {
let mut json = serde_json::Map::new();
if has_current {
json.insert("current".to_string(), serde_json::json!("Test"));
}
if has_targets {
json.insert("targets".to_string(), serde_json::json!(["a.rs"]));
}
if has_index {
json.insert("current_target_index".to_string(), serde_json::json!(0));
}
let checkpoint_data = serde_json::to_string(&json).unwrap();
let result = format_as_table(&checkpoint_data);
prop_assert!(result.is_ok());
}
}
#[test]
fn test_engine_mode_batch_zero_parallel() {
let checkpoint_path = PathBuf::from("/tmp/cp");
let params = ExtractedRefactorParams {
mode: RefactorMode::Batch,
config: None,
project: PathBuf::from("."),
parallel: 0, memory_limit: 512,
batch_size: 10,
priority: None,
checkpoint_dir: None,
resume: false,
auto_commit: None,
max_runtime: None,
};
let mode = create_engine_mode(¶ms, &checkpoint_path);
match mode {
EngineMode::Batch {
parallel_workers, ..
} => {
assert_eq!(parallel_workers, 0);
}
_ => panic!("Expected Batch mode"),
}
}
#[test]
fn test_print_table_data_with_long_current_state() {
let state: serde_json::Value = serde_json::json!({
"current": "ThisIsAVeryLongStateNameThatExceedsThirtyTwoCharacters",
"targets": [],
"current_target_index": 0
});
print_table_data(&state);
}
#[tokio::test]
async fn test_load_config_json_partial_rules() {
let temp_dir = TempDir::new().unwrap();
let config_path = temp_dir.path().join("partial.json");
let config_data = serde_json::json!({
"rules": {
"target_complexity": 25
}
});
std::fs::write(&config_path, serde_json::to_string(&config_data).unwrap()).unwrap();
let result = load_refactor_config_json(&config_path).await;
assert!(result.is_ok());
let config = result.unwrap();
assert_eq!(config.target_complexity, 25);
assert_eq!(config.max_function_lines, 50);
assert!(config.remove_satd); }
#[test]
fn test_format_as_summary_with_empty_targets_array() {
let checkpoint_data = r#"{
"current": "Plan",
"targets": []
}"#;
let checkpoint_path = PathBuf::from("/tmp/cp.json");
let result = format_as_summary(checkpoint_data, &checkpoint_path);
assert!(result.is_ok());
}
#[test]
fn test_format_as_table_targets_not_array() {
let checkpoint_data = r#"{
"targets": "not_an_array"
}"#;
let result = format_as_table(checkpoint_data);
assert!(result.is_ok());
}
#[test]
fn test_format_as_table_index_not_number() {
let checkpoint_data = r#"{
"current_target_index": "not_a_number"
}"#;
let result = format_as_table(checkpoint_data);
assert!(result.is_ok());
}
}