mod common;
use assert_cmd::Command;
use common::{add_template, run_in_terminal};
use expectrl::{spawn, Eof};
use quagga::test_utils::temp_dir::TempDir;
use serial_test::serial;
use std::fs;
use std::io::Read;
use std::path::PathBuf;
use std::time::Duration;
#[test]
fn test_main_success_run() {
let td: TempDir = TempDir::new().unwrap();
add_template(&td);
td.mkfile_with_contents("file1.txt", "Hello");
td.mkfile_with_contents("file2.txt", "World!");
let output: String = run_in_terminal(td.path().display().to_string());
let expected_output = r#"Hello
World!
"#;
assert_eq!(output, expected_output);
}
#[test]
fn test_main_with_nonexistent_directory() {
let quagga_bin = assert_cmd::cargo::cargo_bin("quagga");
let non_existent_path = "/path/to/nonexistent/directory";
// Spawn the quagga binary in a PTY with the non-existent directory as an argument
let mut p = spawn(format!("{} {}", quagga_bin.display(), non_existent_path))
.expect("Failed to spawn quagga binary");
// Read the error output from the process
let mut stderr_output = String::new();
p.read_to_string(&mut stderr_output)
.expect("Failed to read stderr from quagga");
assert!(stderr_output.contains("Error"));
p.expect(Eof).expect("Failed to expect EOF");
}
#[test]
fn test_main_with_piped_input() {
let td = TempDir::new().unwrap();
add_template(&td);
let mut cmd = Command::cargo_bin("quagga").unwrap();
cmd.arg(td.path());
let path1 = td.mkfile_with_contents("file1.txt", "Hello");
let path2 = td.mkfile_with_contents("file2.txt", "World!");
td.mkfile_with_contents("ignore.txt", "ignore"); // This file should be ignored since its path is not piped-in
let input = format!("{}\n{}", path1.display(), path2.display());
cmd.write_stdin(input);
let expected_output = r#"Hello
World!
"#;
cmd.assert().success().stdout(expected_output);
}
#[test]
fn test_main_with_piped_input_non_existent_file() {
let non_existent_path = PathBuf::from("/path/to/non/existent/file.txt");
let mut cmd = Command::cargo_bin("quagga").unwrap();
let input = format!("{}", non_existent_path.display());
cmd.write_stdin(input);
let assert = cmd.assert();
assert.failure().stderr(predicates::str::contains(
"Error: Failed to read metadata for file /path/to/non/existent/file.txt",
));
}
#[test]
fn test_main_show_paths() {
let td = TempDir::new().unwrap();
let path1 = td.mkfile("file1.txt");
let path2 = td.mkfile("file2.txt");
let output: String = run_in_terminal(format!("--paths {}", td.path().display()));
let expected = format!("{}\n{}\n", path1.display(), path2.display());
assert_eq!(output, expected);
}
#[test]
fn test_main_file_sizes() {
let td = TempDir::new().unwrap();
let path1 = td.mkfile_with_contents("file1.txt", &"A".repeat(1000));
let path2 = td.mkfile_with_contents("file2.txt", &"B".repeat(2000));
let path3 = td.mkfile_with_contents("file3.txt", &"C".repeat(500));
let output: String = run_in_terminal(format!("--file-sizes {}", td.path().display()));
let expected = format!(
"\
[1.95 KB] {}
[1000 B] {}
[500 B] {}
",
path2.display(),
path1.display(),
path3.display()
);
assert_eq!(output, expected);
}
#[test]
fn test_main_show_tree() {
let td = TempDir::new().unwrap();
td.mkfile("file1.txt");
td.mkfile("file2.txt");
td.mkdir("subdir");
td.mkfile("subdir/file3.txt");
let output: String = run_in_terminal(format!("--tree {}", td.path().display()));
let expected = format!(
r#"{}
├── subdir
│ └── file3.txt
├── file1.txt
└── file2.txt
"#,
td.path().display()
);
assert_eq!(output, expected);
}
#[test]
fn test_main_copy_template() {
let td = TempDir::new().unwrap();
let output: String = run_in_terminal(format!("--copy-template {}", td.path().display()));
let expected = format!(
"Template was copied to '{}'.\n",
td.path().join(".quagga_template").display()
);
assert_eq!(output, expected);
}
#[test]
fn test_main_uses_quagga_template_by_default() {
let td = TempDir::new().unwrap();
// Create a custom .quagga_template in the temporary directory
let custom_template = r#"
Custom Item:
If part pending
"#;
td.mkfile_with_contents(".quagga_template", custom_template);
td.mkfile_with_contents("file1.txt", "Hello");
td.mkfile_with_contents("file2.txt", "World!");
let output: String = run_in_terminal(td.path().display().to_string());
let expected = r#"Custom Header
Custom Item: Hello
Custom Item: World!
Custom Footer
"#;
assert_eq!(output, expected);
}
#[test]
fn test_main_with_contain_option() {
let td: TempDir = TempDir::new().unwrap();
add_template(&td);
// Create files with and without the target content
td.mkfile_with_contents("file_with_keyword.txt", "This file contains the keyword.");
td.mkfile_with_contents("file_without_keyword.txt", "This file does not contain it.");
let output = run_in_terminal(format!("--contain keyword -- {}", td.path().display()));
let expected = r#"This file contains the keyword.
"#;
assert_eq!(output, expected);
}
#[test]
fn test_main_respect_gitignore() {
let td = TempDir::new().unwrap();
add_template(&td);
td.mkfile_with_contents(".gitignore", "ignored.txt");
// Create files that should be included
td.mkfile_with_contents("file1.txt", "file1");
td.mkfile_with_contents("file2.txt", "file2");
// Create a file that should be ignored by .gitignore
td.mkfile_with_contents("ignored.txt", "ignored");
let output = run_in_terminal(td.path().display().to_string());
let expected = r#"file1
file2
"#;
assert_eq!(output, expected);
}
#[test]
fn test_main_no_gitignore() {
let td = TempDir::new().unwrap();
add_template(&td);
td.mkfile_with_contents(".gitignore", "ignored.txt");
td.mkfile_with_contents("file1.txt", "file1");
td.mkfile_with_contents("file2.txt", "file2");
td.mkfile_with_contents("ignored.txt", "ignored");
// Ignore .gitignore
let output = run_in_terminal(format!("--no-gitignore {}", td.path().display()));
let expected = r#"file1
file2
ignored
"#;
assert_eq!(output, expected);
}
#[test]
fn test_main_max_depth() {
let td = TempDir::new().unwrap();
add_template(&td);
td.mkfile_with_contents("file0.txt", "file0");
td.mkdir("dir1");
td.mkfile_with_contents("dir1/file1.txt", "file1");
td.mkdir("dir1/dir2");
td.mkfile_with_contents("dir1/dir2/file2.txt", "file2");
td.mkdir("dir1/dir2/dir3");
td.mkfile_with_contents("dir1/dir2/dir3/file3.txt", "file3");
let output = run_in_terminal(format!("--max-depth 2 {}", td.path().display()));
let expected = r#"file1
file0
"#;
assert_eq!(output, expected);
}
#[test]
fn test_main_max_filesize() {
let td = TempDir::new().unwrap();
add_template(&td);
td.mkfile_with_contents("four_bytes.txt", "1234");
td.mkfile_with_contents("five_bytes.txt", "12345");
let output = run_in_terminal(format!("--max-filesize 4 {}", td.path().display()));
let expected = r#"1234
"#;
assert_eq!(output, expected);
}
#[test]
fn test_main_max_total_size_exceeds_maximum() {
let td = TempDir::new().unwrap();
add_template(&td);
td.mkfile_with_contents("four_bytes.txt", "123456"); // 6 bytes
let output = run_in_terminal(format!("--max-total-size 5 {}", td.path().display()));
assert!(output.contains("exceeds the maximum"));
}
#[test]
fn test_main_split_into_parts() {
let td = TempDir::new().unwrap();
// Create a custom .quagga_template in the temporary directory
let custom_template = r#"
Custom Item:
Wait for more parts please
"#;
td.mkfile_with_contents(".quagga_template", custom_template);
td.mkfile_with_contents("file1.txt", &"Hello".repeat(10));
td.mkfile_with_contents("file2.txt", &"World!".repeat(10));
let output: String = run_in_terminal(format!("--max-part-size 164 {}", td.path().display()));
let expected = r#"Custom Header
== Part start
Custom Item: HelloHelloHelloHelloHelloHelloHelloHelloHelloHello
== Part end
Wait for more parts please
== Part start
Custom Item: World!World!World!World!World!World!World!World!World!World!
== Part end
Custom Footer
"#;
assert_eq!(output, expected);
}
#[test]
fn test_main_output_to_file() {
let td: TempDir = TempDir::new().unwrap();
add_template(&td);
td.mkfile_with_contents("file1.txt", "Hello");
td.mkfile_with_contents("file2.txt", "World!");
let output_path = td.path().join("output.txt");
let output: String = run_in_terminal(format!(
"--output {} {}",
output_path.display(),
td.path().display()
));
assert_eq!(output, "");
let written_content = fs::read_to_string(&output_path).unwrap();
let expected = "Hello
World!";
assert_eq!(written_content, expected);
}
#[test]
fn test_main_output_to_file_multiple_parts() {
let td = TempDir::new().unwrap();
let output_path = td.path().join("output.txt");
// Create a custom .quagga_template in the temporary directory
let custom_template = r#"
Custom Item:
Wait for more parts please
"#;
td.mkfile_with_contents(".quagga_template", custom_template);
td.mkfile_with_contents("file1.txt", &"Hello".repeat(10));
td.mkfile_with_contents("file2.txt", &"World!".repeat(10));
let output: String = run_in_terminal(format!(
"--output {} --max-part-size 164 {}",
output_path.display(),
td.path().display()
));
assert_eq!(output, "");
// Check part one
// --------
let path1 = td.path().join("output.txt.001");
let written_content = fs::read_to_string(&path1).unwrap();
let expected = "Custom Header
== Part start
Custom Item: HelloHelloHelloHelloHelloHelloHelloHelloHelloHello
== Part end
Wait for more parts please";
assert_eq!(written_content, expected);
// Check part two
// --------
let path2 = td.path().join("output.txt.002");
let written_content = fs::read_to_string(&path2).unwrap();
let expected = "== Part start
Custom Item: World!World!World!World!World!World!World!World!World!World!
== Part end
Custom Footer";
assert_eq!(written_content, expected);
}
#[test]
#[serial]
fn test_main_output_to_clipboard_single_part() {
if std::env::var("CI").is_ok() {
println!("Skipping clipboard test in CI environment");
return;
}
let td: TempDir = TempDir::new().unwrap();
add_template(&td);
td.mkfile_with_contents("file.txt", "Hello");
let output: String = run_in_terminal(format!("--clipboard {}", td.path().display()));
assert_eq!(output.trim(), "Output copied to clipboard.");
}
#[test]
#[serial]
fn test_main_output_to_clipboard_multiple_parts() {
if std::env::var("CI").is_ok() {
println!("Skipping clipboard test in CI environment");
return;
}
let td: TempDir = TempDir::new().unwrap();
add_template(&td);
// Create two files with content that will be split into two parts
td.mkfile_with_contents("file1.txt", &"A".repeat(1000));
td.mkfile_with_contents("file2.txt", &"B".repeat(1000));
let quagga_bin = assert_cmd::cargo::cargo_bin("quagga");
let cmd = format!(
"{} --clipboard --max-part-size 2000 {}",
quagga_bin.display(),
td.path().display()
);
let mut p = spawn(cmd).expect("Failed to spawn command");
// Set a timeout for expectations
let timeout = Duration::from_secs(1);
p.set_expect_timeout(Some(timeout));
// Wait for and check the first message
p.expect("Part 1 of 2 copied to clipboard.").unwrap();
p.expect("Press Enter to copy the next part...").unwrap();
p.send_line("").unwrap(); // Press Enter to copy the next part
p.expect("Part 2 of 2 copied to clipboard.").unwrap();
p.expect("We are done.").unwrap();
}
#[test]
fn test_main_size() {
let td = TempDir::new().unwrap();
td.mkfile_with_contents("file1.txt", &"A".repeat(1000));
td.mkfile_with_contents("file2.txt", &"B".repeat(200));
let output = run_in_terminal(format!("--size {}", td.path().display()));
assert_eq!(output.trim(), "1.17 KB");
}