use std::collections::BTreeSet; use std::fs; use std::process::Command; use std::process::Stdio; use log::info; #[derive(Default, Clone, Debug)] struct CollectedFiles { files: BTreeSet, folders: BTreeSet, symlinks: BTreeSet, } static CZKAWKA_PATH: state::InitCell = state::InitCell::new(); static COLLECTED_FILES: state::InitCell = state::InitCell::new(); const ATTEMPTS: u32 = 10; const PRINT_MESSAGES_CZKAWKA: bool = true; // App runs - ./ci_tester PATH_TO_CZKAWKA fn main() { handsome_logger::init().unwrap(); let args: Vec = std::env::args().collect(); let path_to_czkawka = args[1].clone(); CZKAWKA_PATH.set(path_to_czkawka); remove_test_dir(); run_with_good_status(&["ls"], false); unzip_files(); let all_files = collect_all_files_and_dirs("TestFiles").unwrap(); COLLECTED_FILES.set(all_files); remove_test_dir(); for _ in 0..ATTEMPTS { test_empty_files(); test_smallest_files(); test_biggest_files(); test_empty_folders(); test_temporary_files(); test_symlinks_files(); test_remove_duplicates_one_oldest(); test_remove_duplicates_one_newest(); test_remove_duplicates_all_expect_newest(); test_remove_duplicates_all_expect_oldest(); test_remove_same_music_tags_one_oldest(); test_remove_same_music_tags_one_newest(); test_remove_same_music_tags_all_expect_oldest(); test_remove_same_music_tags_all_expect_newest(); test_remove_same_music_content_one_oldest(); test_remove_same_music_content_all_expect_oldest(); test_remove_same_music_content_one_newest(); test_remove_same_music_content_all_expect_newest(); test_remove_videos_one_oldest(); test_remove_videos_one_newest(); test_remove_videos_all_expect_oldest(); test_remove_videos_all_expect_newest(); } println!("Completed checking"); } fn test_remove_videos_one_oldest() { info!("test_remove_videos_one_oldest"); run_test(&["video", "-d", "TestFiles", "-D", "OO"], vec!["Videos/V3.webm"], vec![], vec![]); } fn test_remove_videos_one_newest() { info!("test_remove_videos_one_newest"); run_test(&["video", "-d", "TestFiles", "-D", "ON"], vec!["Videos/V5.mp4"], vec![], vec![]); } fn test_remove_videos_all_expect_oldest() { info!("test_remove_videos_all_expect_oldest"); run_test( &["video", "-d", "TestFiles", "-D", "AEO"], vec!["Videos/V1.mp4", "Videos/V2.mp4", "Videos/V5.mp4"], vec![], vec![], ); } fn test_remove_videos_all_expect_newest() { info!("test_remove_videos_all_expect_newest"); run_test( &["video", "-d", "TestFiles", "-D", "AEN"], vec!["Videos/V1.mp4", "Videos/V2.mp4", "Videos/V3.webm"], vec![], vec![], ); } fn test_remove_same_music_content_one_newest() { info!("test_remove_same_music_content_one_newest"); run_test( &["music", "-d", "TestFiles", "-s", "CONTENT", "-l", "2.0", "-D", "ON"], vec!["Music/M2.mp3"], vec![], vec![], ); } fn test_remove_same_music_content_all_expect_newest() { info!("test_remove_same_music_content_all_expect_newest"); run_test( &["music", "-d", "TestFiles", "-s", "CONTENT", "-l", "2.0", "-D", "AEN"], vec!["Music/M1.mp3", "Music/M3.flac", "Music/M5.mp3"], vec![], vec![], ); } fn test_remove_same_music_content_all_expect_oldest() { info!("test_remove_same_music_content_all_expect_oldest"); run_test( &["music", "-d", "TestFiles", "-s", "CONTENT", "-l", "2.0", "-D", "AEO"], vec!["Music/M1.mp3", "Music/M2.mp3", "Music/M3.flac"], vec![], vec![], ); } fn test_remove_same_music_content_one_oldest() { info!("test_remove_same_music_content_one_oldest"); run_test( &["music", "-d", "TestFiles", "-s", "CONTENT", "-l", "2.0", "-D", "OO"], vec!["Music/M5.mp3"], vec![], vec![], ); } fn test_remove_same_music_tags_one_oldest() { info!("test_remove_same_music_one_oldest"); run_test(&["music", "-d", "TestFiles", "-D", "OO"], vec!["Music/M5.mp3"], vec![], vec![]); } fn test_remove_same_music_tags_one_newest() { info!("test_remove_same_music_one_newest"); run_test(&["music", "-d", "TestFiles", "-D", "ON"], vec!["Music/M2.mp3"], vec![], vec![]); } fn test_remove_same_music_tags_all_expect_oldest() { info!("test_remove_same_music_all_expect_oldest"); run_test( &["music", "-d", "TestFiles", "-D", "AEO"], vec!["Music/M1.mp3", "Music/M2.mp3", "Music/M3.flac"], vec![], vec![], ); } fn test_remove_same_music_tags_all_expect_newest() { info!("test_remove_same_music_all_expect_newest"); run_test( &["music", "-d", "TestFiles", "-D", "AEN"], vec!["Music/M1.mp3", "Music/M3.flac", "Music/M5.mp3"], vec![], vec![], ); } fn test_remove_duplicates_all_expect_oldest() { info!("test_remove_duplicates_all_expect_oldest"); run_test( &["dup", "-d", "TestFiles", "-D", "AEO"], vec!["Images/A1.jpg", "Images/A5.jpg", "Music/M1.mp3", "Music/M2.mp3", "Videos/V1.mp4", "Videos/V5.mp4"], vec![], vec![], ); } fn test_remove_duplicates_all_expect_newest() { info!("test_remove_duplicates_all_expect_newest"); run_test( &["dup", "-d", "TestFiles", "-D", "AEN"], vec!["Images/A2.jpg", "Images/A5.jpg", "Music/M1.mp3", "Music/M5.mp3", "Videos/V1.mp4", "Videos/V2.mp4"], vec![], vec![], ); } fn test_remove_duplicates_one_newest() { info!("test_remove_duplicates_one_newest"); run_test( &["dup", "-d", "TestFiles", "-D", "ON"], vec!["Images/A1.jpg", "Music/M2.mp3", "Videos/V5.mp4"], vec![], vec![], ); } fn test_remove_duplicates_one_oldest() { info!("test_remove_duplicates_one_oldest"); run_test( &["dup", "-d", "TestFiles", "-D", "OO"], vec!["Images/A2.jpg", "Music/M5.mp3", "Videos/V2.mp4"], vec![], vec![], ); } fn test_symlinks_files() { info!("test_symlinks_files"); run_test(&["symlinks", "-d", "TestFiles", "-D"], vec![], vec![], vec!["Symlinks/EmptyFiles"]); } fn test_temporary_files() { info!("test_temporary_files"); run_test(&["temp", "-d", "TestFiles", "-D"], vec!["Temporary/Boczze.cache"], vec![], vec![]); } fn test_empty_folders() { info!("test_empty_folders"); run_test( &["empty-folders", "-d", "TestFiles", "-D"], vec![], vec!["EmptyFolders/One", "EmptyFolders/Two", "EmptyFolders/Two/TwoInside"], vec![], ); } fn test_biggest_files() { info!("test_biggest_files"); run_test( &["big", "-d", "TestFiles", "-n", "6", "-D"], vec!["Music/M3.flac", "Music/M4.mp3", "Videos/V2.mp4", "Videos/V3.webm", "Videos/V1.mp4", "Videos/V5.mp4"], vec![], vec![], ); } fn test_smallest_files() { info!("test_smallest_files"); run_test( &["big", "-d", "TestFiles", "-J", "-n", "5", "-D"], vec!["Broken/Br.jpg", "Broken/Br.mp3", "Broken/Br.pdf", "Broken/Br.zip", "EmptyFolders/ThreeButNot/KEKEKE"], vec![], vec![], ); } fn test_empty_files() { info!("test_empty_files"); run_test(&["empty-files", "-d", "TestFiles", "-D"], vec!["EmptyFile"], vec![], vec![]); } //////////////////////////////////// //////////////////////////////////// /////////HELPER FUNCTIONS/////////// //////////////////////////////////// //////////////////////////////////// fn run_test(arguments: &[&str], expected_files_differences: Vec<&'static str>, expected_folders_differences: Vec<&'static str>, expected_symlinks_differences: Vec<&'static str>) { unzip_files(); // Add path_to_czkawka to arguments let mut all_arguments = vec![]; all_arguments.push(CZKAWKA_PATH.get().as_str()); all_arguments.extend_from_slice(arguments); run_with_good_status(&all_arguments, PRINT_MESSAGES_CZKAWKA); file_folder_diffs( COLLECTED_FILES.get(), expected_files_differences, expected_folders_differences, expected_symlinks_differences, ); remove_test_dir(); } fn unzip_files() { run_with_good_status(&["unzip", "-X", "TestFiles.zip", "-d", "TestFiles"], false); } fn remove_test_dir() { let _ = fs::remove_dir_all("TestFiles"); } fn run_with_good_status(str_command: &[&str], print_messages: bool) { let mut command = Command::new(str_command[0]); let mut com = command.args(&str_command[1..]); if !print_messages { com = com.stderr(Stdio::piped()).stdout(Stdio::piped()); } let status = com.spawn().expect("failed to execute process").wait().unwrap(); assert!(status.success()); } fn file_folder_diffs( all_files: &CollectedFiles, mut expected_files_differences: Vec<&'static str>, mut expected_folders_differences: Vec<&'static str>, mut expected_symlinks_differences: Vec<&'static str>, ) { let current_files = collect_all_files_and_dirs("TestFiles").unwrap(); let mut diff_files = all_files .files .difference(¤t_files.files) .map(|e| e.strip_prefix("TestFiles/").unwrap().to_string()) .collect::>(); let mut diff_folders = all_files .folders .difference(¤t_files.folders) .map(|e| e.strip_prefix("TestFiles/").unwrap().to_string()) .collect::>(); let mut diff_symlinks = all_files .symlinks .difference(¤t_files.symlinks) .map(|e| e.strip_prefix("TestFiles/").unwrap().to_string()) .collect::>(); expected_symlinks_differences.sort(); expected_folders_differences.sort(); expected_files_differences.sort(); diff_files.sort(); diff_folders.sort(); diff_symlinks.sort(); assert_eq!(diff_files, expected_files_differences); assert_eq!(diff_folders, expected_folders_differences); assert_eq!(diff_symlinks, expected_symlinks_differences); } fn collect_all_files_and_dirs(dir: &str) -> std::io::Result { let mut files = BTreeSet::new(); let mut folders = BTreeSet::new(); let mut symlinks = BTreeSet::new(); let mut folders_to_check = vec![dir.to_string()]; while !folders_to_check.is_empty() { let folder = folders_to_check.pop().unwrap(); let rd = fs::read_dir(folder)?; for entry in rd { let entry = entry?; let file_type = entry.file_type()?; let path_str = entry.path().to_string_lossy().to_string(); if file_type.is_dir() { folders.insert(path_str.clone()); folders_to_check.push(path_str); } else if file_type.is_symlink() { symlinks.insert(path_str); } else if file_type.is_file() { files.insert(path_str); } else { panic!("Unknown type of file {path_str:?}"); } } } folders.remove(dir); // println!("Found {} files, {} folders and {} symlinks", files.len(), folders.len(), symlinks.len()); Ok(CollectedFiles { files, folders, symlinks }) }