use assert_cmd::{cargo_bin, Command};
use std::fs;
use tempfile::TempDir;
fn parse_simple_output(line: &str) -> Option<(String, u32, String)> {
let parts: Vec<&str> = line.split(':').collect();
if parts.len() < 3 {
return None;
}
for i in 1..parts.len() {
if let Ok(line_num) = parts[i].parse::<u32>() {
let file_path = parts[0..i].join(":");
let content = parts[i + 1..].join(":");
return Some((file_path, line_num, content));
}
}
None
}
#[test]
fn test_simple_format_programmatic_parsing() {
let mut cmd = Command::new(cargo_bin!("cs"));
let output = cmd
.arg("add new")
.arg("--simple")
.current_dir("tests/fixtures/rails-app")
.output()
.expect("Failed to execute cs command");
assert!(output.status.success(), "cs command should succeed");
let stdout = String::from_utf8(output.stdout).expect("Output should be valid UTF-8");
let stderr = String::from_utf8(output.stderr).expect("Stderr should be valid UTF-8");
println!(
"DEBUG: Verifying stderr is empty. Current stderr content: {:?}",
stderr
);
assert!(
stderr.trim().is_empty(),
"Stderr should be empty in simple mode, but got:\n{}",
stderr
);
let lines: Vec<&str> = stdout
.lines()
.filter(|line| !line.trim().is_empty())
.collect();
assert!(!lines.is_empty(), "Should have at least one result");
for line in lines {
let result = parse_simple_output(line);
assert!(result.is_some(), "Line should be parseable: {}", line);
let (file_path, _line_num, content) = result.unwrap();
assert!(
!file_path.is_empty(),
"File path should not be empty: {}",
line
);
assert!(
!content.contains("├─>"),
"Content should not contain tree characters: {}",
line
);
assert!(
!content.contains("└─>"),
"Content should not contain tree characters: {}",
line
);
assert!(
!content.contains("\x1b["),
"Content should not contain ANSI codes: {}",
line
);
}
}
#[test]
fn test_error_handling_in_automated_scenarios() {
let temp_dir = TempDir::new().unwrap();
let mut cmd = Command::new(cargo_bin!("cs"));
let output = cmd
.arg("test")
.arg("--simple")
.current_dir(&temp_dir) .output()
.expect("Failed to execute cs command");
assert!(
output.status.success(),
"cs should succeed even in empty directory"
);
let stdout = String::from_utf8(output.stdout).expect("Stdout should be valid UTF-8");
if !stdout.trim().is_empty() {
assert!(
stdout.contains("No matches found"),
"Should either be empty or contain 'No matches found' message"
);
}
let mut cmd = Command::new(cargo_bin!("cs"));
let output = cmd
.arg("")
.arg("--simple")
.current_dir("tests/fixtures/rails-app")
.output()
.expect("Failed to execute cs command");
assert!(
!output.status.success(),
"cs should fail for empty search text"
);
let stderr = String::from_utf8(output.stderr).expect("Stderr should be valid UTF-8");
assert!(
stderr.contains("empty"),
"Should mention empty search text in error"
);
let mut cmd = Command::new(cargo_bin!("cs"));
let output = cmd
.arg("[invalid")
.arg("--regex")
.arg("--simple")
.current_dir("tests/fixtures/rails-app")
.output()
.expect("Failed to execute cs command");
let stderr = String::from_utf8(output.stderr).expect("Stderr should be valid UTF-8");
if !output.status.success() {
assert!(
!stderr.trim().is_empty(),
"Should have error message in stderr for invalid regex"
);
}
}
#[test]
fn test_performance_with_large_codebase() {
let start = std::time::Instant::now();
let mut cmd = Command::new(cargo_bin!("cs"));
let output = cmd
.arg("function")
.arg("--simple")
.current_dir("tests/fixtures")
.output()
.expect("Failed to execute cs command");
let duration = start.elapsed();
assert!(
duration.as_secs() < 30,
"Search should complete within 30 seconds, took {:?}",
duration
);
if output.status.success() {
let stdout = String::from_utf8(output.stdout).expect("Output should be valid UTF-8");
for line in stdout.lines() {
if !line.trim().is_empty() {
assert!(
parse_simple_output(line).is_some(),
"Line should be parseable: {}",
line
);
}
}
}
}
#[test]
fn test_ai_agent_workflow_simulation() {
let mut cmd = Command::new(cargo_bin!("cs"));
let output = cmd
.arg("add new")
.arg("--simple")
.current_dir("tests/fixtures/rails-app")
.output()
.expect("Failed to execute cs command");
assert!(output.status.success(), "Initial search should succeed");
let stdout = String::from_utf8(output.stdout).expect("Output should be valid UTF-8");
let mut parsed_results = Vec::new();
for line in stdout.lines() {
if !line.trim().is_empty() {
if let Some((path, line_num, content)) = parse_simple_output(line) {
parsed_results.push((path, line_num, content));
}
}
}
assert!(
!parsed_results.is_empty(),
"Should parse at least one result"
);
let mut translation_files = 0;
let mut code_files = 0;
for (file_path, _line_num, _content) in &parsed_results {
if file_path.ends_with(".yml") || file_path.ends_with(".yaml") {
translation_files += 1;
} else if file_path.ends_with(".ts")
|| file_path.ends_with(".js")
|| file_path.ends_with(".tsx")
{
code_files += 1;
}
}
assert!(
translation_files > 0 || code_files > 0,
"Should find either translation or code files"
);
if translation_files > 0 {
let mut cmd = Command::new(cargo_bin!("cs"));
let output = cmd
.arg("invoice.labels")
.arg("--simple")
.current_dir("tests/fixtures/rails-app")
.output()
.expect("Failed to execute follow-up search");
assert!(
output.status.success() || output.status.code() == Some(0),
"Follow-up search should not crash"
);
}
}
#[test]
fn test_rg_compatibility_command_line_args() {
let mut cmd = Command::new(cargo_bin!("cs"));
cmd.arg("ADD NEW") .arg("--ignore-case")
.arg("--simple")
.current_dir("tests/fixtures/rails-app")
.assert()
.success();
let mut cmd = Command::new(cargo_bin!("cs"));
cmd.arg("new")
.arg("--word-regexp")
.arg("--simple")
.current_dir("tests/fixtures/rails-app")
.assert()
.success();
let mut cmd = Command::new(cargo_bin!("cs"));
cmd.arg("add.*new")
.arg("--regex")
.arg("--simple")
.current_dir("tests/fixtures/rails-app")
.assert()
.success();
}
#[test]
fn test_output_consistency_across_search_types() {
let temp_dir = TempDir::new().unwrap();
let yaml_dir = temp_dir.path().join("config/locales");
fs::create_dir_all(&yaml_dir).unwrap();
let yaml_file = yaml_dir.join("en.yml");
fs::write(&yaml_file, "en:\n test:\n key: \"test value\"").unwrap();
let code_dir = temp_dir.path().join("src");
fs::create_dir_all(&code_dir).unwrap();
let code_file = code_dir.join("app.ts");
fs::write(
&code_file,
"const message = 'test value';\nconsole.log('test');",
)
.unwrap();
let mut cmd = Command::new(cargo_bin!("cs"));
let translation_output = cmd
.arg("test value")
.arg("--simple")
.current_dir(temp_dir.path())
.output()
.expect("Failed to execute translation search");
let mut cmd = Command::new(cargo_bin!("cs"));
let exact_output = cmd
.arg("test")
.arg("--simple")
.current_dir(temp_dir.path())
.output()
.expect("Failed to execute exact search");
if translation_output.status.success() {
let stdout = String::from_utf8(translation_output.stdout).unwrap();
for line in stdout.lines() {
if !line.trim().is_empty() {
assert!(
parse_simple_output(line).is_some(),
"Translation search line should be parseable: {}",
line
);
}
}
}
if exact_output.status.success() {
let stdout = String::from_utf8(exact_output.stdout).unwrap();
for line in stdout.lines() {
if !line.trim().is_empty() {
assert!(
parse_simple_output(line).is_some(),
"Exact search line should be parseable: {}",
line
);
}
}
}
}
#[test]
fn test_large_output_handling() {
let temp_dir = TempDir::new().unwrap();
let test_file = temp_dir.path().join("large_file.txt");
let mut content = String::new();
for i in 1..=1000 {
content.push_str(&format!("Line {} contains test pattern\n", i));
}
fs::write(&test_file, content).unwrap();
let mut cmd = Command::new(cargo_bin!("cs"));
let output = cmd
.arg("test pattern")
.arg("--simple")
.current_dir(temp_dir.path())
.output()
.expect("Failed to execute search on large file");
if output.status.success() {
let stdout = String::from_utf8(output.stdout).expect("Output should be valid UTF-8");
let lines: Vec<&str> = stdout
.lines()
.filter(|line| !line.trim().is_empty())
.collect();
assert!(lines.len() > 100, "Should find many matches in large file");
for line in lines {
assert!(
parse_simple_output(line).is_some(),
"Large output line should be parseable: {}",
line
);
}
}
}
#[test]
fn test_special_characters_in_ai_workflows() {
let temp_dir = TempDir::new().unwrap();
let test_file = temp_dir.path().join("special.txt");
fs::write(
&test_file,
"Line with spaces and symbols: $var @mention #tag\n\
Unicode content: café naïve résumé 中文 🚀\n\
Shell metacharacters: $(command) `backticks` |pipe| &background&\n\
Quotes and escapes: \"double\" 'single' \\backslash\n",
)
.unwrap();
let test_cases = vec!["$var", "café", "中文", "🚀", "\"double\"", "\\backslash"];
for search_term in test_cases {
let mut cmd = Command::new(cargo_bin!("cs"));
let output = cmd
.arg(search_term)
.arg("--simple")
.current_dir(temp_dir.path())
.output()
.expect("Failed to execute search with special characters");
let stderr = String::from_utf8(output.stderr).unwrap();
if !output.status.success() {
assert!(
!stderr.contains("panic"),
"Should not panic on special characters: {}",
search_term
);
} else {
let stdout = String::from_utf8(output.stdout).unwrap();
for line in stdout.lines() {
if !line.trim().is_empty() {
assert!(
parse_simple_output(line).is_some(),
"Special character search result should be parseable: {}",
line
);
}
}
}
}
}