use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::env;
use std::io;
fn get_binary_path() -> PathBuf {
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
if cfg!(debug_assertions) {
path.push("target/debug/contextify");
} else {
path.push("target/release/contextify");
}
if cfg!(windows) {
path.set_extension("exe");
}
path
}
fn get_test_dir(name: &str) -> PathBuf {
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
path.push("tests");
path.push("data");
path.push(name);
if let Some(parent) = path.parent() {
fs::create_dir_all(parent).expect("Failed to create parent directory");
}
path
}
fn setup_test_directory(test_dir: &Path) -> std::io::Result<()> {
if test_dir.exists() {
fs::remove_dir_all(test_dir)?;
}
fs::create_dir_all(test_dir)?;
fs::write(test_dir.join("file1.rs"), "fn main() {\n println!(\"Hello, world!\");\n}")?;
fs::write(test_dir.join("file2.md"), "# Title\n\nThis is a markdown file.")?;
fs::write(test_dir.join("file3.txt"), "Plain text file.")?;
fs::write(test_dir.join("file4.json"), "{\"key\": \"value\"}")?;
let subdir = test_dir.join("subdir");
fs::create_dir(&subdir)?;
fs::write(subdir.join("subfile1.rs"), "struct Test {\n field: i32\n}")?;
fs::write(subdir.join("subfile2.txt"), "Another text file.")?;
fs::write(test_dir.join(".gitignore"), "*.json\n*.txt\n")?;
let config_dir = test_dir.join("config");
fs::create_dir_all(&config_dir)?;
fs::write(config_dir.join(".blacklist"), "*.json\n")?;
fs::write(config_dir.join(".whitelist"), "*.rs\n*.md\n")?;
Ok(())
}
fn cleanup_test_directory(test_dir: &Path) -> std::io::Result<()> {
if test_dir.exists() {
fs::remove_dir_all(test_dir)?;
}
Ok(())
}
fn check_output_content(output_content: &str, expected_files: &[&str], excluded_files: &[&str]) {
for &file in expected_files {
if output_content.contains(file) {
println!("✓ Expected file {} is PRESENT in output", file);
} else {
println!("✗ Expected file {} is MISSING from output", file);
}
assert!(output_content.contains(file), "Expected file {} is missing from output", file);
}
for &file in excluded_files {
if !output_content.contains(file) {
println!("✓ Excluded file {} is correctly NOT present in output", file);
} else {
println!("✗ Excluded file {} is incorrectly present in output", file);
}
assert!(!output_content.contains(file), "Excluded file {} is incorrectly present in output", file);
}
}
#[test]
fn test_default_run() -> io::Result<()> {
let test_dir = get_test_dir("default_test");
setup_test_directory(&test_dir)?;
let output_file = test_dir.join("output.txt");
let binary = get_binary_path();
let output = Command::new(&binary)
.current_dir(&test_dir)
.arg("--output")
.arg(output_file.file_name().unwrap())
.output()?;
println!("Command stdout: {}", String::from_utf8_lossy(&output.stdout));
assert!(output.status.success());
assert!(output_file.exists());
let output_content = fs::read_to_string(&output_file)?;
let expected_files = ["file1.rs", "file2.md", "subfile1.rs"];
let excluded_files = ["file3.txt", "file4.json", "subfile2.txt"];
check_output_content(&output_content, &expected_files, &excluded_files);
cleanup_test_directory(&test_dir)?;
Ok(())
}
#[test]
fn test_gitignore_flag() -> io::Result<()> {
let test_dir = get_test_dir("gitignore_test");
setup_test_directory(&test_dir)?;
let output_file = test_dir.join("output.txt");
let binary = get_binary_path();
let output = Command::new(&binary)
.current_dir(&test_dir)
.arg("--gitignore")
.arg("--output")
.arg(output_file.file_name().unwrap())
.output()?;
assert!(output.status.success());
assert!(output_file.exists());
let output_content = fs::read_to_string(&output_file)?;
let expected_files = ["file1.rs", "file2.md", "subfile1.rs"];
let excluded_files = ["file3.txt", "file4.json", "subfile2.txt"];
check_output_content(&output_content, &expected_files, &excluded_files);
cleanup_test_directory(&test_dir)?;
Ok(())
}
#[test]
fn test_no_gitignore_flag() -> io::Result<()> {
let test_dir = get_test_dir("no_gitignore_test");
setup_test_directory(&test_dir)?;
let output_file = test_dir.join("output.txt");
let binary = get_binary_path();
let output = Command::new(&binary)
.current_dir(&test_dir)
.arg("--no-gitignore")
.arg("--output")
.arg(output_file.file_name().unwrap())
.output()?;
println!("Command stdout: {}", String::from_utf8_lossy(&output.stdout));
println!("Command stderr: {}", String::from_utf8_lossy(&output.stderr));
assert!(output.status.success());
assert!(output_file.exists());
let output_content = fs::read_to_string(&output_file)?;
let expected_files = ["file1.rs", "file2.md", "file3.txt", "file4.json", "subfile1.rs", "subfile2.txt"];
let excluded_files: [&str; 0] = [];
check_output_content(&output_content, &expected_files, &excluded_files);
cleanup_test_directory(&test_dir)?;
Ok(())
}
#[test]
fn test_blacklist_only() -> io::Result<()> {
let test_dir = get_test_dir("blacklist_only_test");
setup_test_directory(&test_dir)?;
let output_file = test_dir.join("output.txt");
let binary = get_binary_path();
let output = Command::new(&binary)
.current_dir(&test_dir)
.arg("--blacklist")
.arg("--no-gitignore") .arg("--output")
.arg(output_file.file_name().unwrap())
.output()?;
assert!(output.status.success());
assert!(output_file.exists());
let output_content = fs::read_to_string(&output_file)?;
let expected_files = ["file1.rs", "file2.md", "file3.txt", "subfile1.rs", "subfile2.txt"];
let excluded_files = ["file4.json"];
check_output_content(&output_content, &expected_files, &excluded_files);
cleanup_test_directory(&test_dir)?;
Ok(())
}
#[test]
fn test_whitelist_only() -> io::Result<()> {
let test_dir = get_test_dir("whitelist_only_test");
setup_test_directory(&test_dir)?;
let output_file = test_dir.join("output.txt");
let binary = get_binary_path();
let output = Command::new(&binary)
.current_dir(&test_dir)
.arg("--whitelist")
.arg("--no-gitignore") .arg("--output")
.arg(output_file.file_name().unwrap())
.output()?;
assert!(output.status.success());
assert!(output_file.exists());
let output_content = fs::read_to_string(&output_file)?;
let expected_files = ["file1.rs", "file2.md", "subfile1.rs"];
let excluded_files = ["file3.txt", "file4.json", "subfile2.txt"];
check_output_content(&output_content, &expected_files, &excluded_files);
cleanup_test_directory(&test_dir)?;
Ok(())
}
#[test]
fn test_custom_patterns_only() -> io::Result<()> {
let test_dir = get_test_dir("custom_patterns_test");
setup_test_directory(&test_dir)?;
let output_file = test_dir.join("output.txt");
let binary = get_binary_path();
let output = Command::new(&binary)
.current_dir(&test_dir)
.arg("--blacklist-patterns")
.arg("*.txt,subdir")
.arg("--no-gitignore") .arg("--output")
.arg(output_file.file_name().unwrap())
.output()?;
assert!(output.status.success());
assert!(output_file.exists());
let output_content = fs::read_to_string(&output_file)?;
let expected_files = ["file1.rs", "file2.md", "file4.json"];
let excluded_files = ["file3.txt", "subfile1.rs", "subfile2.txt"];
check_output_content(&output_content, &expected_files, &excluded_files);
cleanup_test_directory(&test_dir)?;
Ok(())
}