use std::env; use std::fs; use std::path::PathBuf; use tempfile::TempDir; use chrono::{NaiveDate, Datelike}; use sermon_converter::VideoConverter; #[tokio::test] async fn test_sermon_converter_creation() { let temp_output = TempDir::new().unwrap(); // Test that we can create a new converter let converter = VideoConverter::new(temp_output.path().to_path_buf()); // Test that it was created successfully (converter doesn't expose output_path directly) // We'll test this indirectly through other methods assert!(true); // Basic smoke test } #[tokio::test] async fn test_date_extraction_from_sermon_filename() { let temp_output = TempDir::new().unwrap(); let converter = VideoConverter::new(temp_output.path().to_path_buf()); // Test valid sermon filename format let filename = "God's Love and Mercy - Pastor John Smith (December 25th 2024).mp4"; let result = converter.extract_date_from_filename(filename).await; assert!(result.is_ok()); let date = result.unwrap(); assert_eq!(date.year(), 2024); assert_eq!(date.month(), 12); assert_eq!(date.day(), 25); // Test different date formats let test_cases = vec![ ("Title - Speaker (January 1st 2024).mp4", (2024, 1, 1)), ("Title - Speaker (February 29th 2024).mp4", (2024, 2, 29)), // Leap year ("Title - Speaker (March 3rd 2023).mp4", (2023, 3, 3)), ("Title - Speaker (April 22nd 2025).mp4", (2025, 4, 22)), ("Title - Speaker (May 11th 2024).mp4", (2024, 5, 11)), ("Title - Speaker (June 30th 2024).mp4", (2024, 6, 30)), ("Title - Speaker (July 4th 2024).mp4", (2024, 7, 4)), ("Title - Speaker (August 15th 2024).mp4", (2024, 8, 15)), ("Title - Speaker (September 22nd 2024).mp4", (2024, 9, 22)), ("Title - Speaker (October 31st 2024).mp4", (2024, 10, 31)), ("Title - Speaker (November 11th 2024).mp4", (2024, 11, 11)), ]; for (filename, (expected_year, expected_month, expected_day)) in test_cases { let result = converter.extract_date_from_filename(filename).await; assert!(result.is_ok(), "Failed to parse filename: {}", filename); let date = result.unwrap(); assert_eq!(date.year(), expected_year, "Wrong year for: {}", filename); assert_eq!(date.month(), expected_month, "Wrong month for: {}", filename); assert_eq!(date.day(), expected_day, "Wrong day for: {}", filename); } } #[tokio::test] async fn test_invalid_sermon_filenames() { let temp_output = TempDir::new().unwrap(); let converter = VideoConverter::new(temp_output.path().to_path_buf()); let invalid_cases = vec![ "no-date-info.mp4", "Title - Speaker.mp4", "Title - Speaker (Invalid Date).mp4", "Title - Speaker (February 30th 2024).mp4", // Invalid date "Title - Speaker (13th Month 2024).mp4", "No separator here 2024.mp4", ]; for filename in invalid_cases { let result = converter.extract_date_from_filename(filename).await; assert!(result.is_err(), "Should fail to parse invalid filename: {}", filename); } } #[tokio::test] async fn test_title_and_speaker_extraction() { let temp_output = TempDir::new().unwrap(); let converter = VideoConverter::new(temp_output.path().to_path_buf()); let test_cases = vec![ ( "The Power of Prayer - Dr. Sarah Johnson (December 25th 2024).mp4", ("The Power of Prayer", "Dr. Sarah Johnson") ), ( "Faith in Difficult Times - Pastor Michael Brown (January 1st 2024).mp4", ("Faith in Difficult Times", "Pastor Michael Brown") ), ( "God's Amazing Grace - Elder Mary Wilson (March 15th 2024).mp4", ("God's Amazing Grace", "Elder Mary Wilson") ), ]; for (filename, (expected_title, expected_speaker)) in test_cases { let result = converter.extract_title_and_speaker(filename).await; assert!(result.is_ok(), "Failed to extract title and speaker from: {}", filename); let (title, speaker) = result.unwrap(); assert_eq!(title, expected_title); assert_eq!(speaker, expected_speaker); } } #[tokio::test] async fn test_invalid_title_speaker_formats() { let temp_output = TempDir::new().unwrap(); let converter = VideoConverter::new(temp_output.path().to_path_buf()); let invalid_cases = vec![ "No dash separators here (December 25th 2024).mp4", // No dash separator ]; for filename in invalid_cases { let result = converter.extract_title_and_speaker(filename).await; assert!(result.is_err(), "Should fail to parse invalid format: {}", filename); } } #[tokio::test] async fn test_environment_variable_integration() { // Test with custom environment variables env::set_var("SHOW_TITLE", "Custom Sermon Series"); env::set_var("CREATE_NFO_FILES", "true"); env::set_var("PRESERVE_ORIGINAL_FILES", "false"); env::set_var("AUDIO_CODEC", "libopus"); env::set_var("AUDIO_BITRATE", "128k"); let temp_output = TempDir::new().unwrap(); let converter = VideoConverter::new(temp_output.path().to_path_buf()); // Test that the converter was created with custom configuration // (We test this indirectly since the config is internal) assert!(true); // Smoke test that creation succeeded // Clean up env::remove_var("SHOW_TITLE"); env::remove_var("CREATE_NFO_FILES"); env::remove_var("PRESERVE_ORIGINAL_FILES"); env::remove_var("AUDIO_CODEC"); env::remove_var("AUDIO_BITRATE"); } #[tokio::test] async fn test_directory_structure_creation() { let temp_output = TempDir::new().unwrap(); let converter = VideoConverter::new(temp_output.path().to_path_buf()); let test_cases = vec![ ("Title - Speaker (January 15th 2024).mp4", "2024", "01-January"), ("Title - Speaker (December 31st 2024).mp4", "2024", "12-December"), ("Title - Speaker (July 4th 2023).mp4", "2023", "07-July"), ]; for (filename, expected_year, expected_month) in test_cases { let date = converter.extract_date_from_filename(filename).await.unwrap(); // The directory structure should match what the converter expects let year_dir = temp_output.path().join(expected_year); let month_dir = year_dir.join(expected_month); // Create the directory structure as the converter would fs::create_dir_all(&month_dir).unwrap(); // Verify structure exists assert!(year_dir.exists()); assert!(month_dir.exists()); // Test that output file would go in the right place let output_file = month_dir.join(filename); assert!(!output_file.exists()); // Shouldn't exist initially } } #[tokio::test] async fn test_syncthing_temp_file_rejection() { let temp_output = TempDir::new().unwrap(); let temp_input = TempDir::new().unwrap(); let converter = VideoConverter::new(temp_output.path().to_path_buf()); // Create a syncthing temp file let syncthing_file = temp_input.path().join("test.syncthing.tmp.mp4"); fs::write(&syncthing_file, "temporary content").unwrap(); // Process file should reject syncthing files let result = converter.process_file(syncthing_file).await; assert!(result.is_err()); assert!(result.unwrap_err().to_string().contains("Syncthing")); } #[tokio::test] async fn test_non_mp4_file_rejection() { let temp_output = TempDir::new().unwrap(); let temp_input = TempDir::new().unwrap(); let converter = VideoConverter::new(temp_output.path().to_path_buf()); // Create a non-MP4 file let avi_file = temp_input.path().join("Title - Speaker (December 25th 2024).avi"); fs::write(&avi_file, "avi content").unwrap(); // Process file should reject non-MP4 files let result = converter.process_file(avi_file).await; assert!(result.is_err()); assert!(result.unwrap_err().to_string().contains("non-MP4")); } #[tokio::test] async fn test_missing_file_handling() { let temp_output = TempDir::new().unwrap(); let converter = VideoConverter::new(temp_output.path().to_path_buf()); // Try to process a file that doesn't exist let missing_file = PathBuf::from("/nonexistent/path/Title - Speaker (December 25th 2024).mp4"); let result = converter.process_file(missing_file).await; assert!(result.is_err()); assert!(result.unwrap_err().to_string().contains("no longer exists")); }