#![allow(deprecated)]
#![allow(
clippy::field_reassign_with_default,
clippy::assertions_on_constants,
clippy::overly_complex_bool_expr,
clippy::useless_vec
)]
use assert_cmd::Command;
use predicates::prelude::*;
use std::fs;
use std::process::Command as StdCommand;
use tempfile::tempdir;
fn init_test_git_repo(dir: &std::path::Path) {
StdCommand::new("git")
.arg("init")
.current_dir(dir)
.output()
.expect("Failed to init git repo");
StdCommand::new("git")
.args(["config", "user.email", "test@example.com"])
.current_dir(dir)
.output()
.expect("Failed to set git email");
StdCommand::new("git")
.args(["config", "user.name", "Test User"])
.current_dir(dir)
.output()
.expect("Failed to set git name");
fs::write(dir.join(".gitignore"), "").expect("Failed to create .gitignore");
StdCommand::new("git")
.args(["add", ".gitignore"])
.current_dir(dir)
.output()
.expect("Failed to add .gitignore");
StdCommand::new("git")
.args(["commit", "-m", "Initial commit"])
.current_dir(dir)
.output()
.expect("Failed to create initial commit");
}
#[test]
fn test_auth_command_help() {
let mut cmd = Command::cargo_bin("rco").unwrap();
cmd.arg("auth")
.arg("--help")
.assert()
.success()
.stdout(predicate::str::contains(
"Authenticate with Claude using OAuth",
));
}
#[test]
fn test_auth_status_not_authenticated() {
let temp_dir = tempdir().unwrap();
let mut cmd = Command::cargo_bin("rco").unwrap();
cmd.env("HOME", temp_dir.path())
.arg("auth")
.arg("status")
.assert()
.success()
.stdout(predicate::str::contains("Not authenticated"));
}
#[test]
fn test_auth_logout_when_not_logged_in() {
let temp_dir = tempdir().unwrap();
let mut cmd = Command::cargo_bin("rco").unwrap();
cmd.env("HOME", temp_dir.path())
.arg("auth")
.arg("logout")
.assert()
.success()
.stdout(predicate::str::contains("Successfully logged out"));
}
#[test]
fn test_config_commands_comprehensive() {
let temp_dir = tempdir().unwrap();
let home = temp_dir.path();
let test_cases = vec![
("RCO_AI_PROVIDER", "anthropic"),
("RCO_AI_PROVIDER", "openai"),
("RCO_AI_PROVIDER", "openrouter"),
("RCO_AI_PROVIDER", "groq"),
("RCO_AI_PROVIDER", "deepseek"),
("RCO_AI_PROVIDER", "mistral"),
("RCO_AI_PROVIDER", "amazon-bedrock"),
("RCO_AI_PROVIDER", "azure"),
("RCO_AI_PROVIDER", "together"),
("RCO_AI_PROVIDER", "deepinfra"),
("RCO_AI_PROVIDER", "huggingface"),
("RCO_AI_PROVIDER", "github-models"),
("RCO_AI_PROVIDER", "github-copilot"),
("RCO_AI_PROVIDER", "gemini"),
("RCO_AI_PROVIDER", "ollama"),
("RCO_AI_PROVIDER", "fireworks"),
("RCO_AI_PROVIDER", "moonshot"),
("RCO_AI_PROVIDER", "dashscope"),
];
for (key, value) in test_cases {
let mut cmd = Command::cargo_bin("rco").unwrap();
cmd.env("HOME", home)
.arg("config")
.arg("set")
.arg(format!("{}={}", key, value))
.assert()
.success()
.stdout(predicate::str::contains(format!(
"{} set to: {}",
key, value
)));
let mut cmd = Command::cargo_bin("rco").unwrap();
cmd.env("HOME", home)
.arg("config")
.arg("get")
.arg(key)
.assert()
.success()
.stdout(predicate::str::contains(format!("{}: {}", key, value)));
}
}
#[test]
fn test_config_model_settings() {
let temp_dir = tempdir().unwrap();
let home = temp_dir.path();
let model_tests = vec![
("gpt-4o", "openai"),
("claude-3-5-haiku-20241022", "anthropic"),
("llama-3.1-70b-versatile", "groq"),
("deepseek-chat", "deepseek"),
("mistral-large-latest", "mistral"),
("gemini-1.5-pro", "gemini"),
("meta-llama/Llama-3.2-3B-Instruct", "together"),
("kimi-k2", "moonshot"),
("qwen3-coder-32b-instruct", "dashscope"),
];
for (model, provider) in model_tests {
let mut cmd = Command::cargo_bin("rco").unwrap();
cmd.env("HOME", home)
.arg("config")
.arg("set")
.arg(format!("RCO_AI_PROVIDER={}", provider))
.assert()
.success();
let mut cmd = Command::cargo_bin("rco").unwrap();
cmd.env("HOME", home)
.arg("config")
.arg("set")
.arg(format!("RCO_MODEL={}", model))
.assert()
.success()
.stdout(predicate::str::contains(format!(
"RCO_MODEL set to: {}",
model
)));
let mut cmd = Command::cargo_bin("rco").unwrap();
cmd.env("HOME", home)
.arg("config")
.arg("get")
.arg("RCO_MODEL")
.assert()
.success()
.stdout(predicate::str::contains(format!("RCO_MODEL: {}", model)));
}
}
#[test]
fn test_config_boolean_values() {
let temp_dir = tempdir().unwrap();
let home = temp_dir.path();
let boolean_tests = vec![
("RCO_EMOJI", "true"),
("RCO_EMOJI", "false"),
("RCO_GITPUSH", "true"),
("RCO_GITPUSH", "false"),
("RCO_DESCRIPTION_CAPITALIZE", "true"),
("RCO_DESCRIPTION_CAPITALIZE", "false"),
];
for (key, value) in boolean_tests {
let mut cmd = Command::cargo_bin("rco").unwrap();
cmd.env("HOME", home)
.arg("config")
.arg("set")
.arg(format!("{}={}", key, value))
.assert()
.success()
.stdout(predicate::str::contains(format!(
"{} set to: {}",
key, value
)));
}
}
#[test]
fn test_config_numeric_values() {
let temp_dir = tempdir().unwrap();
let home = temp_dir.path();
let numeric_tests = vec![
("RCO_TOKENS_MAX_INPUT", "8192"),
("RCO_TOKENS_MAX_OUTPUT", "1000"),
("RCO_DESCRIPTION_MAX_LENGTH", "72"),
];
for (key, value) in numeric_tests {
let mut cmd = Command::cargo_bin("rco").unwrap();
cmd.env("HOME", home)
.arg("config")
.arg("set")
.arg(format!("{}={}", key, value))
.assert()
.success()
.stdout(predicate::str::contains(format!(
"{} set to: {}",
key, value
)));
}
}
#[test]
fn test_config_api_urls() {
let temp_dir = tempdir().unwrap();
let home = temp_dir.path();
let url_tests = vec![
("https://api.openai.com/v1", "openai"),
("https://api.anthropic.com", "anthropic"),
("https://openrouter.ai/api/v1", "openrouter"),
("https://api.groq.com/openai/v1", "groq"),
("https://api.deepseek.com", "deepseek"),
("https://api.mistral.ai/v1", "mistral"),
("https://api.together.xyz/v1", "together"),
("https://api.deepinfra.com/v1/openai", "deepinfra"),
("https://api-inference.huggingface.co/v1", "huggingface"),
("https://models.inference.ai.azure.com", "github-models"),
("https://generativelanguage.googleapis.com/v1beta", "gemini"),
("http://localhost:11434", "ollama"),
("https://api.fireworks.ai/inference/v1", "fireworks"),
("https://api.moonshot.cn/v1", "moonshot"),
(
"https://dashscope.aliyuncs.com/compatible-mode/v1",
"dashscope",
),
];
for (url, provider) in url_tests {
let mut cmd = Command::cargo_bin("rco").unwrap();
cmd.env("HOME", home)
.arg("config")
.arg("set")
.arg(format!("RCO_AI_PROVIDER={}", provider))
.assert()
.success();
let mut cmd = Command::cargo_bin("rco").unwrap();
cmd.env("HOME", home)
.arg("config")
.arg("set")
.arg(format!("RCO_API_URL={}", url))
.assert()
.success()
.stdout(predicate::str::contains(format!(
"RCO_API_URL set to: {}",
url
)));
}
}
#[test]
fn test_config_invalid_values() {
let temp_dir = tempdir().unwrap();
let home = temp_dir.path();
let invalid_tests = vec![
("RCO_EMOJI", "not_a_boolean"),
("RCO_TOKENS_MAX_INPUT", "not_a_number"),
("RCO_TOKENS_MAX_OUTPUT", "negative_number"),
("INVALID_KEY", "any_value"),
];
for (key, value) in invalid_tests {
let mut cmd = Command::cargo_bin("rco").unwrap();
cmd.env("HOME", home)
.arg("config")
.arg("set")
.arg(format!("{}={}", key, value))
.assert()
.success()
.stderr(predicate::str::contains(format!("Failed to set {}", key)));
}
}
#[test]
fn test_config_status() {
let temp_dir = tempdir().unwrap();
let home = temp_dir.path();
let mut cmd = Command::cargo_bin("rco").unwrap();
cmd.env("HOME", home)
.arg("config")
.arg("status")
.assert()
.success()
.stdout(predicate::str::contains("Secure Storage Status"))
.stdout(predicate::str::contains("No API key configured"));
let mut cmd = Command::cargo_bin("rco").unwrap();
cmd.env("HOME", home)
.arg("config")
.arg("set")
.arg("RCO_AI_PROVIDER=openai")
.assert()
.success();
let mut cmd = Command::cargo_bin("rco").unwrap();
cmd.env("HOME", home)
.arg("config")
.arg("status")
.assert()
.success()
.stdout(predicate::str::contains("AI Provider: openai"));
}
#[test]
fn test_config_reset() {
let temp_dir = tempdir().unwrap();
let home = temp_dir.path();
let mut cmd = Command::cargo_bin("rco").unwrap();
cmd.env("HOME", home)
.arg("config")
.arg("set")
.arg("RCO_EMOJI=true")
.arg("RCO_GITPUSH=true")
.assert()
.success();
let mut cmd = Command::cargo_bin("rco").unwrap();
cmd.env("HOME", home)
.arg("config")
.arg("reset")
.arg("RCO_EMOJI")
.assert()
.success()
.stdout(predicate::str::contains("Reset keys: RCO_EMOJI"));
let mut cmd = Command::cargo_bin("rco").unwrap();
cmd.env("HOME", home)
.arg("config")
.arg("get")
.arg("RCO_EMOJI")
.assert()
.success()
.stdout(predicate::str::contains("RCO_EMOJI: false"));
let mut cmd = Command::cargo_bin("rco").unwrap();
cmd.env("HOME", home)
.arg("config")
.arg("reset")
.arg("--all")
.assert()
.success()
.stdout(predicate::str::contains(
"All configuration reset to defaults",
));
}
#[test]
fn test_main_command_options() {
let temp_dir = tempdir().unwrap();
init_test_git_repo(temp_dir.path());
let mut cmd = Command::cargo_bin("rco").unwrap();
cmd.current_dir(temp_dir.path())
.arg("--help")
.assert()
.success()
.stdout(predicate::str::contains("Rusty Commit"))
.stdout(predicate::str::contains("--fgm"))
.stdout(predicate::str::contains("--context"))
.stdout(predicate::str::contains("--yes"));
let mut cmd = Command::cargo_bin("rco").unwrap();
cmd.current_dir(temp_dir.path())
.arg("--version")
.assert()
.success()
.stdout(predicate::str::contains("rco "));
}
#[test]
fn test_hook_commands() {
let temp_dir = tempdir().unwrap();
init_test_git_repo(temp_dir.path());
let mut cmd = Command::cargo_bin("rco").unwrap();
cmd.current_dir(temp_dir.path())
.arg("hook")
.arg("--help")
.assert()
.success()
.stdout(predicate::str::contains("Setup git hooks"));
}
#[test]
fn test_commitlint_commands() {
let temp_dir = tempdir().unwrap();
init_test_git_repo(temp_dir.path());
let mut cmd = Command::cargo_bin("rco").unwrap();
cmd.current_dir(temp_dir.path())
.arg("commitlint")
.arg("--help")
.assert()
.success()
.stdout(predicate::str::contains(
"Generate commitlint configuration",
));
}
#[test]
fn test_error_handling_no_git_repo() {
let temp_dir = tempdir().unwrap();
let mut cmd = Command::cargo_bin("rco").unwrap();
cmd.current_dir(temp_dir.path())
.env("HOME", temp_dir.path())
.assert()
.failure(); }
#[test]
fn test_error_handling_no_api_key() {
let temp_dir = tempdir().unwrap();
init_test_git_repo(temp_dir.path());
fs::write(temp_dir.path().join("test.txt"), "test content").unwrap();
StdCommand::new("git")
.args(["add", "test.txt"])
.current_dir(temp_dir.path())
.output()
.unwrap();
let mut cmd = Command::cargo_bin("rco").unwrap();
cmd.current_dir(temp_dir.path())
.env("HOME", temp_dir.path())
.assert()
.failure() .stderr(predicate::str::contains("API key").or(predicate::str::contains("authentication")));
}
#[test]
fn test_multiple_provider_configurations() {
let temp_dir = tempdir().unwrap();
let home = temp_dir.path();
let providers = vec![
("openai", "gpt-4o-mini"),
("anthropic", "claude-3-5-haiku-20241022"),
("groq", "llama-3.1-70b-versatile"),
("openrouter", "openai/gpt-4o-mini"),
];
for (provider, model) in providers {
let mut cmd = Command::cargo_bin("rco").unwrap();
cmd.env("HOME", home)
.arg("config")
.arg("set")
.arg(format!("RCO_AI_PROVIDER={}", provider))
.assert()
.success();
let mut cmd = Command::cargo_bin("rco").unwrap();
cmd.env("HOME", home)
.arg("config")
.arg("set")
.arg(format!("RCO_MODEL={}", model))
.assert()
.success();
let mut cmd = Command::cargo_bin("rco").unwrap();
cmd.env("HOME", home)
.arg("config")
.arg("get")
.arg("RCO_AI_PROVIDER")
.assert()
.success()
.stdout(predicate::str::contains(format!(
"RCO_AI_PROVIDER: {}",
provider
)));
let mut cmd = Command::cargo_bin("rco").unwrap();
cmd.env("HOME", home)
.arg("config")
.arg("get")
.arg("RCO_MODEL")
.assert()
.success()
.stdout(predicate::str::contains(format!("RCO_MODEL: {}", model)));
}
}