use tempfile::TempDir;
use tokio::fs;
use std::process::Command;
#[tokio::test]
async fn test_fail_fast_parallel_processing() {
let temp_dir = TempDir::new().unwrap();
let root_path = temp_dir.path();
let good_files = [
("good1-0.txt", "This is a good file. It has proper sentences."),
("good2-0.txt", "Another good file. More sentences here."),
];
for (filename, content) in &good_files {
let file_path = root_path.join(filename);
fs::write(&file_path, content).await.unwrap();
}
let bad_file_path = root_path.join("bad1-0.txt");
fs::write(&bad_file_path, "This file will have permission issues").await.unwrap();
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let mut perms = fs::metadata(&bad_file_path).await.unwrap().permissions();
perms.set_mode(0o000); fs::set_permissions(&bad_file_path, perms).await.unwrap();
}
let additional_files = [
("good3-0.txt", "Third good file. Should not be processed in fail-fast mode."),
("good4-0.txt", "Fourth good file. Should not be processed in fail-fast mode."),
];
for (filename, content) in &additional_files {
let file_path = root_path.join(filename);
fs::write(&file_path, content).await.unwrap();
}
let output = Command::new("cargo")
.args(["run", "--bin", "seams", "--", "--fail-fast", root_path.to_str().unwrap()])
.current_dir(env!("CARGO_MANIFEST_DIR"))
.output()
.unwrap();
let stderr = String::from_utf8_lossy(&output.stderr);
let stdout = String::from_utf8_lossy(&output.stdout);
println!("STDOUT: {stdout}");
println!("STDERR: {stderr}");
println!("Exit status: {}", output.status);
assert!(
stdout.contains("Processing error") || stdout.contains("Permission denied") ||
stderr.contains("Permission denied") || stderr.contains("Access is denied"),
"Should log permission/processing error. STDOUT: {stdout}, STDERR: {stderr}"
);
let good1_aux = root_path.join("good1-0_seams2.txt");
let good2_aux = root_path.join("good2-0_seams2.txt");
let good3_aux = root_path.join("good3-0_seams2.txt");
let good4_aux = root_path.join("good4-0_seams2.txt");
let bad_aux = root_path.join("bad1-0_seams2.txt");
assert!(!bad_aux.exists(), "Bad file should not have been processed successfully");
let good_files_processed = [&good1_aux, &good2_aux, &good3_aux, &good4_aux]
.iter()
.filter(|path| path.exists())
.count();
println!("Good files processed: {good_files_processed}/4");
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let mut perms = fs::metadata(&bad_file_path).await.unwrap().permissions();
perms.set_mode(0o644); fs::set_permissions(&bad_file_path, perms).await.unwrap();
}
}
#[tokio::test]
async fn test_fail_fast_utf8_error() {
let temp_dir = TempDir::new().unwrap();
let root_path = temp_dir.path();
let bad_file = root_path.join("bad_utf8-0.txt");
let invalid_utf8 = vec![0xFF, 0xFE, 0xFD]; fs::write(&bad_file, invalid_utf8).await.unwrap();
for i in 1..=3 {
let good_file = root_path.join(format!("good{i}-0.txt"));
fs::write(&good_file, "This is a valid UTF-8 file. It has sentences.").await.unwrap();
}
let output = Command::new("cargo")
.args(["run", "--bin", "seams", "--", "--fail-fast", root_path.to_str().unwrap()])
.current_dir(env!("CARGO_MANIFEST_DIR"))
.output()
.unwrap();
let stderr = String::from_utf8_lossy(&output.stderr);
println!("Command output: {stderr}");
}
#[tokio::test]
async fn test_without_fail_fast_continues() {
let temp_dir = TempDir::new().unwrap();
let root_path = temp_dir.path();
let good_files = ["good1-0.txt", "good2-0.txt", "good3-0.txt"];
for filename in &good_files {
let file_path = root_path.join(filename);
fs::write(&file_path, "This is a good file. It has proper sentences.").await.unwrap();
}
let bad_file = root_path.join("bad-0.txt");
fs::write(&bad_file, "This will have permission issues").await.unwrap();
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let mut perms = fs::metadata(&bad_file).await.unwrap().permissions();
perms.set_mode(0o000); fs::set_permissions(&bad_file, perms).await.unwrap();
}
let output = Command::new("cargo")
.args(["run", "--bin", "seams", "--", root_path.to_str().unwrap()])
.current_dir(env!("CARGO_MANIFEST_DIR"))
.output()
.unwrap();
assert!(output.status.success(), "Command should succeed without --fail-fast");
for filename in &good_files {
let aux_file = root_path.join(filename.replace("-0.txt", "-0_seams2.txt"));
assert!(aux_file.exists(), "Aux file should exist for {filename}");
}
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let mut perms = fs::metadata(&bad_file).await.unwrap().permissions();
perms.set_mode(0o644); fs::set_permissions(&bad_file, perms).await.unwrap();
}
}
#[tokio::test]
async fn test_fail_fast_sentence_detection_error() {
let temp_dir = TempDir::new().unwrap();
let root_path = temp_dir.path();
let test_files = [
("good1-0.txt", "This is a good file. It has proper sentences."),
("good2-0.txt", "Another good file. More sentences here."),
("good3-0.txt", "Third good file. Should not be processed in fail-fast mode."),
("good4-0.txt", "Fourth good file. Should not be processed in fail-fast mode."),
("good5-0.txt", "Fifth good file. Should not be processed in fail-fast mode."),
];
for (filename, content) in &test_files {
let file_path = root_path.join(filename);
fs::write(&file_path, content).await.unwrap();
}
let output = Command::new("cargo")
.args(["run", "--bin", "seams", "--", "--fail-fast", root_path.to_str().unwrap()])
.current_dir(env!("CARGO_MANIFEST_DIR"))
.output()
.unwrap();
assert!(output.status.success(), "Command should succeed with valid files");
for (filename, _) in &test_files {
let aux_file = root_path.join(filename.replace("-0.txt", "-0_seams2.txt"));
assert!(aux_file.exists(), "Aux file should exist for {filename}");
}
}