use std::process::Command;
use std::path::Path;
const CLI_BINARY: &str = "websearch";
fn run_cli_command(args: &[&str]) -> (String, String, bool) {
let output = Command::new("cargo")
.args(&["run", "--bin", CLI_BINARY, "--"])
.args(args)
.output()
.expect("Failed to execute CLI command");
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
let stderr = String::from_utf8_lossy(&output.stderr).to_string();
let success = output.status.success();
(stdout, stderr, success)
}
fn cli_binary_exists() -> bool {
let build_output = Command::new("cargo")
.args(&["build", "--bin", CLI_BINARY])
.output()
.expect("Failed to build CLI binary");
build_output.status.success()
}
#[test]
fn test_cli_binary_builds() {
assert!(cli_binary_exists(), "CLI binary should build successfully");
}
#[test]
fn test_cli_help() {
let (stdout, _stderr, success) = run_cli_command(&["--help"]);
assert!(success, "Help command should succeed");
assert!(stdout.contains("Multi-provider web search CLI"));
assert!(stdout.contains("multi"));
assert!(stdout.contains("providers"));
assert!(stdout.contains("--provider"));
assert!(stdout.contains("--max-results"));
}
#[test]
fn test_cli_version() {
let (stdout, _stderr, success) = run_cli_command(&["--version"]);
assert!(success, "Version command should succeed");
assert!(stdout.contains("websearch"));
}
#[test]
fn test_providers_command() {
let (stdout, _stderr, success) = run_cli_command(&["providers"]);
assert!(success, "Providers command should succeed");
assert!(stdout.contains("Available Search Providers"));
assert!(stdout.contains("Google"));
assert!(stdout.contains("Tavily"));
assert!(stdout.contains("DuckDuckGo"));
assert!(stdout.contains("ArXiv"));
assert!(stdout.contains("✅") || stdout.contains("❌"));
}
#[test]
fn test_default_search_with_provider() {
let (stdout, _stderr, success) = run_cli_command(&["--help"]);
assert!(success, "Default search help should succeed");
assert!(stdout.contains("--provider"));
assert!(stdout.contains("--max-results"));
assert!(stdout.contains("--format"));
assert!(stdout.contains("arxiv") || stdout.contains("duckduckgo"));
}
#[test]
fn test_multi_search_help() {
let (stdout, _stderr, success) = run_cli_command(&["multi", "--help"]);
assert!(success, "Multi search help should succeed");
assert!(stdout.contains("Search using multiple providers"));
assert!(stdout.contains("--strategy"));
assert!(stdout.contains("--providers"));
}
#[test]
fn test_arxiv_search_flags() {
let (stdout, _stderr, success) = run_cli_command(&["--help"]);
assert!(success, "Help should show ArXiv options");
assert!(stdout.contains("--arxiv-ids"));
assert!(stdout.contains("--sort-by"));
assert!(stdout.contains("--sort-order"));
assert!(stdout.contains("arxiv"));
}
#[test]
fn test_invalid_provider() {
let (stdout, stderr, success) = run_cli_command(&[
"test query",
"--provider",
"invalid"
]);
assert!(!success, "Invalid provider should fail");
assert!(stderr.contains("invalid") || stdout.contains("invalid"));
}
#[test]
fn test_missing_api_key_error() {
let (stdout, stderr, success) = run_cli_command(&[
"test query",
"--provider",
"google",
"--max-results",
"1"
]);
assert!(!success, "Google without API key should fail");
let error_output = format!("{}{}", stdout, stderr);
assert!(
error_output.contains("GOOGLE_API_KEY") ||
error_output.contains("environment variable") ||
error_output.contains("API key") ||
error_output.contains("NotPresent") ||
error_output.contains("Error")
);
}
#[test]
fn test_duckduckgo_search_dry_run() {
let (stdout, stderr, success) = run_cli_command(&[
"rust programming",
"--provider",
"duckduckgo",
"--max-results",
"1",
"--format",
"simple"
]);
if success {
assert!(stdout.len() > 0, "Should return some results");
assert!(stdout.contains("1."), "Should have numbered results");
} else {
println!("DuckDuckGo search failed (network issue): {}{}", stdout, stderr);
}
}
#[test]
fn test_output_formats() {
let formats = ["simple", "table", "json"];
for format in &formats {
let help_output = run_cli_command(&["--help"]);
assert!(help_output.0.contains(format), "Format {} should be in help", format);
}
}
#[test]
fn test_multi_search_strategies() {
let strategies = ["aggregate", "failover", "load-balance"];
for strategy in &strategies {
let (stdout, _stderr, success) = run_cli_command(&[
"multi",
"--help"
]);
assert!(stdout.contains("strategy") || stdout.contains(strategy),
"Strategy {} should be mentioned in help", strategy);
}
}
#[test]
fn test_arxiv_paper_search() {
let (stdout, stderr, success) = run_cli_command(&[
"",
"--provider",
"arxiv",
"--arxiv-ids",
"2301.00001", "--max-results",
"1",
"--format",
"simple"
]);
if !success {
let error_output = format!("{}{}", stdout, stderr);
assert!(
error_output.contains("ArXiv") ||
error_output.contains("arxiv") ||
error_output.contains("search")
);
}
}
#[test]
fn test_debug_flag() {
let (stdout, stderr, success) = run_cli_command(&[
"test",
"--provider",
"duckduckgo",
"--debug",
"--max-results",
"1"
]);
let combined_output = format!("{}{}", stdout, stderr);
if success {
println!("Debug output: {}", combined_output);
}
}
#[test]
fn test_max_results_parameter() {
let (stdout, _stderr, success) = run_cli_command(&[
"--help"
]);
assert!(success);
assert!(stdout.contains("max-results") || stdout.contains("max_results"));
}
#[test]
fn test_json_output_format() {
let (stdout, stderr, success) = run_cli_command(&[
"providers" ]);
assert!(success, "Providers command should always work");
assert!(stdout.contains("Google") || stdout.contains("DuckDuckGo"));
}
#[test]
fn test_empty_query_handling() {
let (stdout, stderr, success) = run_cli_command(&[
"", "--provider",
"duckduckgo"
]);
if !success {
let error_output = format!("{}{}", stdout, stderr);
assert!(
error_output.contains("query") ||
error_output.contains("empty") ||
error_output.contains("required")
);
}
}
#[test]
fn test_cli_comprehensive_flag_validation() {
let test_cases = vec![
(vec!["test", "--provider", "google"], false), (vec!["test", "--provider", "tavily"], false), (vec!["test", "--provider", "duckduckgo"], true), (vec!["multi", "test", "--strategy", "aggregate"], true), (vec!["providers"], true), ];
for (args, should_succeed) in test_cases {
let (stdout, stderr, success) = run_cli_command(&args);
let combined = format!("{}{}", stdout, stderr);
if should_succeed {
assert!(success || combined.contains("DuckDuckGo") || combined.contains("Available"),
"Command {:?} should succeed or show meaningful output", args);
} else {
assert!(
combined.contains("API") ||
combined.contains("key") ||
combined.contains("environment") ||
success, "Command {:?} should fail due to API keys, not invalid syntax", args
);
}
}
}