#![cfg(feature = "test-helpers")]
use std::process::Command;
use seams::incremental::{create_complete_aux_file, generate_aux_file_path};
mod integration;
use integration::TestFixture;
#[tokio::test]
async fn test_skip_complete_aux_files() {
let fixture = TestFixture::new();
let source_content = "This is a test sentence. This is another sentence.";
let source_path = fixture.create_gutenberg_file("test-0.txt", source_content);
let output1 = Command::new("cargo")
.args(["run", "--bin", "seams", "--", fixture.root_path.to_str().unwrap()])
.output()
.expect("Failed to run first command");
assert!(output1.status.success(), "First run failed: {}", String::from_utf8_lossy(&output1.stderr));
assert!(generate_aux_file_path(&source_path).exists(), "Aux file should exist after first run");
let restart_log_path = fixture.root_path.join(".seams_restart.json");
assert!(restart_log_path.exists(), "Restart log should exist after first run");
let aux_content = std::fs::read_to_string(generate_aux_file_path(&source_path)).expect("Should be able to read aux file");
let restart_log_content = std::fs::read_to_string(&restart_log_path).expect("Should be able to read restart log");
let output2 = Command::new("cargo")
.args(["run", "--bin", "seams", "--", fixture.root_path.to_str().unwrap()])
.output()
.expect("Failed to run second command");
assert!(output2.status.success(), "Second run failed: {}", String::from_utf8_lossy(&output2.stderr));
let stdout2 = String::from_utf8_lossy(&output2.stdout);
assert!(stdout2.contains("Skipped (complete aux files): 1 files"),
"Second run should report 1 skipped file, stdout: {stdout2}");
let aux_content_after = std::fs::read_to_string(generate_aux_file_path(&source_path)).expect("Should be able to read aux file after second run");
assert_eq!(aux_content, aux_content_after, "Aux file content should be unchanged");
let restart_log_content_after = std::fs::read_to_string(&restart_log_path).expect("Restart log should still exist after second run");
assert_eq!(restart_log_content, restart_log_content_after, "Restart log content should be unchanged");
}
#[tokio::test]
async fn test_process_aux_files_missing_from_cache() {
let fixture = TestFixture::new();
let source_content = "This is a test sentence. This is another sentence.";
let source_path = fixture.create_gutenberg_file("test-0.txt", source_content);
let aux_content = "0\t32\tThis is a test sentence.\n";
create_complete_aux_file(&source_path, aux_content).expect("Failed to create aux file");
assert!(generate_aux_file_path(&source_path).exists(), "Aux file should exist");
let restart_log_path = fixture.root_path.join(".seams_restart.json");
assert!(!restart_log_path.exists(), "Restart log should not exist initially");
let output = tokio::time::timeout(
std::time::Duration::from_secs(30),
tokio::process::Command::new("cargo")
.args(["run", "--bin", "seams", "--", fixture.root_path.to_str().unwrap()])
.output()
)
.await
.expect("Command timed out after 30 seconds")
.expect("Failed to run command");
assert!(output.status.success(), "Run failed: {}", String::from_utf8_lossy(&output.stderr));
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(stdout.contains("Successfully processed: 1 files"),
"Should report 1 processed file, stdout: {stdout}");
assert!(restart_log_path.exists(), "Restart log should exist after processing");
let final_aux_content = std::fs::read_to_string(generate_aux_file_path(&source_path)).expect("Should be able to read aux file");
let lines: Vec<&str> = final_aux_content.lines().collect();
assert!(lines.len() >= 2, "Complete aux file should have multiple sentences");
assert!(final_aux_content.ends_with('\n'), "Complete aux file should end with newline");
}
#[tokio::test]
async fn test_overwrite_all_flag() {
let fixture = TestFixture::new();
let source_content = "This is a test sentence. This is another sentence.";
let source_path = fixture.create_gutenberg_file("test-0.txt", source_content);
let output1 = Command::new("cargo")
.args(["run", "--bin", "seams", "--", fixture.root_path.to_str().unwrap()])
.output()
.expect("Failed to run first command");
assert!(output1.status.success(), "First run failed: {}", String::from_utf8_lossy(&output1.stderr));
assert!(generate_aux_file_path(&source_path).exists(), "Aux file should exist after first run");
let output2 = Command::new("cargo")
.args(["run", "--bin", "seams", "--", "--overwrite-all", fixture.root_path.to_str().unwrap()])
.output()
.expect("Failed to run second command");
assert!(output2.status.success(), "Second run failed: {}", String::from_utf8_lossy(&output2.stderr));
let stdout2 = String::from_utf8_lossy(&output2.stdout);
assert!(stdout2.contains("Successfully processed: 1 files"),
"Second run with --overwrite-all should report 1 processed file, stdout: {stdout2}");
assert!(!stdout2.contains("Skipped"),
"Second run with --overwrite-all should not report any skipped files, stdout: {stdout2}");
}
#[tokio::test]
async fn test_deleted_aux_files_regenerated() {
let fixture = TestFixture::new();
let source_content = "This is a test sentence.";
let source_path = fixture.create_gutenberg_file("test-0.txt", source_content);
let output1 = Command::new("cargo")
.args(["run", "--bin", "seams", "--", fixture.root_path.to_str().unwrap()])
.output()
.expect("Failed to run first command");
assert!(output1.status.success(), "First run failed: {}", String::from_utf8_lossy(&output1.stderr));
assert!(generate_aux_file_path(&source_path).exists(), "Aux file should exist after first run");
let restart_log_path = fixture.root_path.join(".seams_restart.json");
assert!(restart_log_path.exists(), "Restart log should exist after first run");
let aux_path = fixture.generate_aux_file_path(&source_path);
std::fs::remove_file(&aux_path).expect("Failed to delete aux file");
assert!(!generate_aux_file_path(&source_path).exists(), "Aux file should be deleted");
let output2 = Command::new("cargo")
.args(["run", "--bin", "seams", "--", fixture.root_path.to_str().unwrap()])
.output()
.expect("Failed to run second command");
assert!(output2.status.success(), "Second run failed: {}", String::from_utf8_lossy(&output2.stderr));
let stdout2 = String::from_utf8_lossy(&output2.stdout);
assert!(stdout2.contains("Successfully processed: 1 files"),
"Should report 1 processed file when aux file is missing, stdout: {stdout2}");
assert!(generate_aux_file_path(&source_path).exists(), "Aux file should be regenerated");
let aux_content = std::fs::read_to_string(generate_aux_file_path(&source_path)).expect("Should be able to read regenerated aux file");
assert!(!aux_content.is_empty(), "Regenerated aux file should have content");
assert!(aux_content.ends_with('\n'), "Regenerated aux file should end with newline");
}
#[tokio::test]
async fn test_mixed_incremental_states() {
let fixture = TestFixture::new();
let content1 = "First file sentence.";
let content2 = "Second file sentence.";
let content3 = "Third file sentence.";
let path1 = fixture.create_gutenberg_file("file1-0.txt", content1);
let path2 = fixture.create_gutenberg_file("file2-0.txt", content2);
let path3 = fixture.create_gutenberg_file("file3-0.txt", content3);
let output1 = Command::new("cargo")
.args(["run", "--bin", "seams", "--", fixture.root_path.to_str().unwrap()])
.output()
.expect("Failed to run first command");
assert!(output1.status.success(), "First run failed: {}", String::from_utf8_lossy(&output1.stderr));
assert!(generate_aux_file_path(&path1).exists(), "File1 aux should exist after first run");
assert!(generate_aux_file_path(&path2).exists(), "File2 aux should exist after first run");
assert!(generate_aux_file_path(&path3).exists(), "File3 aux should exist after first run");
let restart_log_path = fixture.root_path.join(".seams_restart.json");
assert!(restart_log_path.exists(), "Restart log should exist after first run");
let aux3_path = fixture.generate_aux_file_path(&path3);
std::fs::remove_file(&aux3_path).expect("Failed to delete file3 aux");
let output2 = Command::new("cargo")
.args(["run", "--bin", "seams", "--", fixture.root_path.to_str().unwrap()])
.output()
.expect("Failed to run second command");
assert!(output2.status.success(), "Second run failed: {}", String::from_utf8_lossy(&output2.stderr));
let stdout2 = String::from_utf8_lossy(&output2.stdout);
assert!(stdout2.contains("Successfully processed: 1 files"),
"Should report 1 processed file (file3), stdout: {stdout2}");
assert!(stdout2.contains("Skipped (complete aux files): 2 files"),
"Should report 2 skipped files (file1 and file2), stdout: {stdout2}");
assert!(generate_aux_file_path(&path1).exists(), "File1 aux should still exist");
assert!(generate_aux_file_path(&path2).exists(), "File2 aux should still exist");
assert!(generate_aux_file_path(&path3).exists(), "File3 aux should be regenerated");
let aux1 = std::fs::read_to_string(generate_aux_file_path(&path1)).expect("Should read file1 aux");
let aux2 = std::fs::read_to_string(generate_aux_file_path(&path2)).expect("Should read file2 aux");
let aux3 = std::fs::read_to_string(generate_aux_file_path(&path3)).expect("Should read file3 aux");
assert!(aux1.ends_with('\n'), "File1 aux should end with newline");
assert!(aux2.ends_with('\n'), "File2 aux should end with newline");
assert!(aux3.ends_with('\n'), "File3 aux should end with newline");
assert!(aux2.contains("Second file sentence"), "File2 aux should contain original content");
}