use assert_cmd::prelude::*; use lazy_static::lazy_static; use walkdir::WalkDir; use sha2::{Sha256, Digest}; use std::io; use std::time; use std::fs; use std::path::{Path, PathBuf}; use std::process::Command; lazy_static! { static ref INPUT_DIR: &'static Path = Path::new("test_inputs"); static ref OUTPUT_DIR: &'static Path = Path::new("test_outputs"); } #[test] fn dir2file() { run_testcase("dir2file"); } #[test] fn recursive_tree() { run_testcase("recursive_tree"); } #[test] fn recursive_tree_longnames() { run_testcase("recursive_tree_longnames"); } #[test] fn softlinked() { run_testcase("softlinked"); } #[test] fn hardlinked() { run_testcase("hardlinked"); } fn run_testcase(testcase: &str) { let input_file = INPUT_DIR.join(testcase); let output_result = OUTPUT_DIR.join(testcase); let output_archive = OUTPUT_DIR.join(format!("{}.tar", testcase)); if output_result.exists() { fs::remove_dir_all(&output_result) .expect("Could not clean old result from output directory"); } if output_archive.exists() { fs::remove_file(&output_archive) .expect("Could not clean old archive from output directory"); } assert!(!output_archive.exists()); println!("tar cf {:?} C {:?} {:?}", &output_archive, *INPUT_DIR, testcase); let tar_run = Command::new("tar") .arg("cf") .arg(&output_archive) .arg("-C") .arg(*INPUT_DIR) .arg(testcase) .output() .expect("Failed to run `tar`"); assert!(tar_run.status.success()); assert!(output_archive.exists()); let taro_run = Command::cargo_bin("taro") .unwrap() .current_dir(*OUTPUT_DIR) .arg(format!("{}.tar", testcase)) .assert() .success(); println!("{}", taro_run); assert!(!output_archive.exists()); assert!(output_result.exists()); //Note - this will not detect extra files created by taro that do not exist in the input //directory. WalkDir::new(input_file) .sort_by(|a, b| a.file_name().cmp(b.file_name())) .into_iter() .for_each(|infile| { let infile = infile.unwrap(); let infile_path: PathBuf = infile.path().components().skip(1).collect(); println!("{:?}", infile_path); test_recreated_file(&infile_path); }); } /// Compares a file in the test input directory to its respective file in the test output directory /// to verify that they each have the same properties. /// /// `relpath` should be provided as a relative path from the base of the test input directory. fn test_recreated_file(relpath: &Path) { let input_file = INPUT_DIR.join(relpath); let output_file = OUTPUT_DIR.join(relpath); assert!(input_file.exists()); assert!(output_file.exists()); let input_meta = input_file.metadata().unwrap(); let output_meta = output_file.metadata().unwrap(); assert_eq!(input_meta.file_type(), output_meta.file_type()); assert_eq!(input_meta.len(), output_meta.len()); assert_eq!(input_meta.permissions(), output_meta.permissions()); if !input_meta.file_type().is_dir() { if let Ok(input_mtime) = input_meta.modified() { assert_eq!( input_mtime.duration_since(time::UNIX_EPOCH).unwrap().as_secs(), output_meta.modified().unwrap().duration_since(time::UNIX_EPOCH).unwrap().as_secs() ); } } assert!(same_contents(input_file, output_file)); } /// Compares the contents of both files (if they are readable and have contents) /// and returns whether or not they are the same. fn same_contents(input: PathBuf, output: PathBuf) -> bool { fn file_checksum(path: PathBuf) -> Result, io::Error> { let mut file = fs::File::open(path)?; let mut sha256 = Sha256::new(); io::copy(&mut file, &mut sha256)?; Ok(sha256.result().as_slice().into()) } let input = file_checksum(input); let output = file_checksum(output); input.iter().zip(output.iter()).all(|(i, o)| { i == o }) }