#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod cli_command_dispatcher_tests {
use crate::cli::{
command_dispatcher::CommandDispatcher,
commands::{Commands, AnalyzeCommands, RefactorCommands},
OutputFormat, ComplexityOutputFormat, ContextFormat, DagType, DemoProtocol,
};
use crate::stateless_server::StatelessTemplateServer;
use std::sync::Arc;
use tempfile::TempDir;
use std::path::PathBuf;
use serde_json::json;
fn create_test_server() -> Arc<StatelessTemplateServer> {
Arc::new(StatelessTemplateServer::new().unwrap())
}
fn create_test_dir_with_rust_file() -> TempDir {
let test_dir = TempDir::new().unwrap();
let src_dir = test_dir.path().join("src");
std::fs::create_dir(&src_dir).unwrap();
std::fs::write(
src_dir.join("lib.rs"),
r#"
pub fn test_function() {
println!("test");
}
pub fn complex_function(x: i32) -> i32 {
if x > 0 {
if x > 10 {
x * 2
} else {
x + 1
}
} else {
0
}
}
"#
).unwrap();
test_dir
}
#[tokio::test]
async fn test_execute_generate_command() {
let server = create_test_server();
let test_dir = TempDir::new().unwrap();
let output_path = test_dir.path().join("test.gitignore");
let command = Commands::Generate {
category: "gitignore".to_string(),
template: "rust/cli".to_string(),
params: vec![("project_name".to_string(), json!("test-project"))],
output: Some(output_path.clone()),
create_dirs: true,
};
let result = CommandDispatcher::execute_command(command, server).await;
assert!(result.is_ok(), "Generate command failed: {:?}", result);
assert!(output_path.exists(), "Output file was not created");
}
#[tokio::test]
async fn test_execute_scaffold_command() {
let server = create_test_server();
let command = Commands::Scaffold {
toolchain: "rust".to_string(),
templates: vec!["gitignore".to_string(), "makefile".to_string()],
params: vec![("project_name".to_string(), json!("test-scaffold"))],
parallel: 1,
};
let result = CommandDispatcher::execute_command(command, server).await;
assert!(result.is_ok(), "Scaffold command failed: {:?}", result);
}
#[tokio::test]
async fn test_execute_list_command() {
let server = create_test_server();
let command = Commands::List {
toolchain: None,
category: None,
format: OutputFormat::Table,
};
let result = CommandDispatcher::execute_command(command, server).await;
assert!(result.is_ok(), "List command failed: {:?}", result);
}
#[tokio::test]
async fn test_execute_search_command() {
let server = create_test_server();
let command = Commands::Search {
query: "rust".to_string(),
toolchain: None,
limit: 10,
};
let result = CommandDispatcher::execute_command(command, server).await;
assert!(result.is_ok(), "Search command failed: {:?}", result);
}
#[tokio::test]
async fn test_execute_validate_command() {
let server = create_test_server();
let command = Commands::Validate {
uri: "rust/cli/gitignore".to_string(),
params: vec![("project_name".to_string(), json!("test"))],
};
let result = CommandDispatcher::execute_command(command, server).await;
assert!(result.is_ok(), "Validate command failed: {:?}", result);
}
#[tokio::test]
async fn test_execute_context_command() {
let server = create_test_server();
let test_dir = create_test_dir_with_rust_file();
let command = Commands::Context {
toolchain: None,
project_path: test_dir.path().to_path_buf(),
output: None,
format: ContextFormat::Markdown,
};
let result = CommandDispatcher::execute_command(command, server).await;
assert!(result.is_ok(), "Context command failed: {:?}", result);
}
#[tokio::test]
async fn test_execute_analyze_complexity_command() {
let test_dir = create_test_dir_with_rust_file();
let analyze_cmd = AnalyzeCommands::Complexity {
project_path: test_dir.path().to_path_buf(),
toolchain: None,
format: ComplexityOutputFormat::Summary,
output: None,
max_cyclomatic: Some(5),
max_cognitive: Some(10),
include: vec![],
watch: false,
top_files: 10,
};
let command = Commands::Analyze(analyze_cmd);
let result = CommandDispatcher::execute_command(command, create_test_server()).await;
assert!(result.is_ok(), "Analyze complexity command failed: {:?}", result);
}
#[tokio::test]
async fn test_execute_analyze_dag_command() {
let test_dir = create_test_dir_with_rust_file();
let analyze_cmd = AnalyzeCommands::Dag {
dag_type: DagType::FullDependency,
project_path: test_dir.path().to_path_buf(),
output: None,
max_depth: Some(10),
filter_external: false,
show_complexity: true,
include_duplicates: false,
include_dead_code: false,
enhanced: false,
};
let command = Commands::Analyze(analyze_cmd);
let result = CommandDispatcher::execute_command(command, create_test_server()).await;
assert!(result.is_ok(), "Analyze DAG command failed: {:?}", result);
}
#[tokio::test]
async fn test_execute_demo_command() {
let test_dir = create_test_dir_with_rust_file();
let command = Commands::Demo {
path: Some(test_dir.path().to_path_buf()),
url: None,
repo: None,
format: OutputFormat::Json,
protocol: DemoProtocol::Cli,
show_api: false,
no_browser: true,
port: Some(3001),
cli: false,
target_nodes: 50,
centrality_threshold: 0.1,
merge_threshold: 3,
debug: false,
debug_output: None,
skip_vendor: true,
no_skip_vendor: false,
max_line_length: Some(80),
};
let result = CommandDispatcher::execute_command(command, create_test_server()).await;
assert!(result.is_ok(), "Demo command failed: {:?}", result);
}
#[tokio::test]
async fn test_execute_refactor_command() {
let test_dir = create_test_dir_with_rust_file();
let refactor_cmd = RefactorCommands::Extract {
project_path: test_dir.path().to_path_buf(),
file_path: test_dir.path().join("src/lib.rs"),
start_line: 1,
end_line: 5,
function_name: "extracted_function".to_string(),
output: None,
};
let command = Commands::Refactor(refactor_cmd);
let result = CommandDispatcher::execute_command(command, create_test_server()).await;
assert!(result.is_ok(), "Refactor command failed: {:?}", result);
}
#[tokio::test]
async fn test_execute_diagnose_command() {
let test_dir = create_test_dir_with_rust_file();
let command = Commands::Diagnose {
args: crate::cli::diagnose::DiagnoseArgs {
path: test_dir.path().to_path_buf(),
output: None,
verbose: false,
check_deps: true,
check_tools: true,
check_config: true,
},
};
let result = CommandDispatcher::execute_command(command, create_test_server()).await;
assert!(result.is_ok(), "Diagnose command failed: {:?}", result);
}
#[tokio::test]
async fn test_command_handler_trait_bounds() {
fn assert_send_sync<T: Send + Sync>() {}
assert_send_sync::<Box<dyn crate::cli::command_dispatcher::CommandHandler>>();
}
#[tokio::test]
async fn test_analyze_command_handler_trait_bounds() {
fn assert_send_sync<T: Send + Sync>() {}
assert_send_sync::<Box<dyn crate::cli::command_dispatcher::AnalyzeCommandHandler>>();
}
#[tokio::test]
async fn test_error_handling_invalid_path() {
let analyze_cmd = AnalyzeCommands::Complexity {
project_path: PathBuf::from("/non/existent/path"),
toolchain: None,
format: ComplexityOutputFormat::Summary,
output: None,
max_cyclomatic: Some(5),
max_cognitive: Some(10),
include: vec![],
watch: false,
top_files: 10,
};
let command = Commands::Analyze(analyze_cmd);
let result = CommandDispatcher::execute_command(command, create_test_server()).await;
assert!(result.is_err(), "Expected error for non-existent path");
}
#[tokio::test]
async fn test_concurrent_command_execution() {
let server = create_test_server();
let mut results = Vec::new();
for _ in 0..3 {
let server_clone = Arc::clone(&server);
let command = Commands::List {
toolchain: None,
category: None,
format: OutputFormat::Json,
};
let result = CommandDispatcher::execute_command(command, server_clone).await;
results.push(result);
}
for result in results {
assert!(result.is_ok(), "Concurrent execution failed");
}
}
}