diff --git a/src/file/checked.rs b/src/file/checked.rs index accef63..b7118d6 100644 --- a/src/file/checked.rs +++ b/src/file/checked.rs @@ -112,3 +112,83 @@ impl FileTrait for Checked { super::check_hash(&self.path, self.size, self.hash.as_deref(), on_progress) } } + +#[cfg(test)] +mod tests { + use tempfile::TempDir; + + use crate::{ + create_file, + file::tests::{CASES, HASHES}, + }; + + use super::*; + + #[test] + fn new_on_existing_file_works() { + for (content, size) in CASES { + let file = create_file(content); + let path = file + .path() + .canonicalize() + .expect("the file should have a canonical path"); + + let chk = Checked::new(file.path()).expect("creating `Checked` should succeed"); + assert_eq!(chk.path, path); + assert_eq!(chk.size, size); + assert!(chk.hash.is_none()); + } + } + + #[test] + fn new_on_dir_errors() { + let tempdir = TempDir::new().expect("creating temp dir"); + let fs_root = PathBuf::from("/"); + + let dirs = [tempdir.path(), fs_root.as_path()]; + + for p in dirs { + let err = Checked::new(p).expect_err("creating `Checked` should fail"); + assert_eq!(err.kind(), io::ErrorKind::InvalidInput); + #[cfg(target_os = "linux")] + assert_eq!(err.to_string(), "Not a regular file"); + } + } + + #[test] + fn new_on_nex_errors() { + let tempdir = TempDir::new().expect("creating temp dir"); + let nex_paths = [0, 1, 2, 3, 4].map(|i| tempdir.path().join(format!("nex_{i}.ext"))); + + for p in nex_paths { + let err = Checked::new(p).expect_err("creating `Checked` should fail"); + assert_eq!(err.kind(), io::ErrorKind::NotFound); + #[cfg(target_os = "linux")] + assert_eq!(err.to_string(), "No such file or directory (os error 2)"); + } + } + + #[test] + fn hashing_works() { + for (&(content, _), hash) in CASES.iter().zip(HASHES) { + let file = create_file(content); + let mut chk = Checked::new(file.path()).expect("creating `Checked` should succeed"); + + chk.hash(drop).expect("hashing should succeed"); + assert_eq!(chk.hash, Some(hash.to_string())); + } + } + + #[test] + fn hashing_again_errors() { + for (content, _) in CASES { + let file = create_file(content); + let mut chk = Checked::new(file.path()).expect("creating `Checked` should succeed"); + + chk.hash(drop).expect("hashing should succeed"); + let err = chk.hash(drop).expect_err("hashing twice should fail"); + + assert!(err.is_mismatch("unhashed file", chk.path.display().to_string())); + } + } +} diff --git a/src/file/mod.rs b/src/file/mod.rs index f61845a..b8dd45b 100644 --- a/src/file/mod.rs +++ b/src/file/mod.rs @@ -124,20 +124,11 @@ pub trait FileTrait { #[cfg(test)] mod tests { - use std::io::Write; - - use tempfile::NamedTempFile; + use crate::create_file; use super::*; - /// Helper to create a temp file from `data` - fn create_file(data: &[u8]) -> NamedTempFile { - let mut tmp = NamedTempFile::new().expect("creating temp file"); - tmp.write_all(data).expect("writing to tempfile"); - tmp - } - - static CASES: [(&[u8], u64); 8] = [ + pub static CASES: [(&[u8], u64); 8] = [ (b"The quick brown fox jumps over the lazy dog", 43), // common pangram (b"hello world", 11), // simple greeting (b"", 0), // empty slice @@ -148,7 +139,7 @@ mod tests { (b"foo\0bar\0baz", 11), // embedded nulls ]; - static HASHES: [&str; 8] = [ + pub static HASHES: [&str; 8] = [ "qK3Uvd39k+SHfSdG5igXsRY2Sh+nvBSNlQkLxzM7NnP4JAHPeqLkyx7NkCluPxTLVBP47Xe+cwRbE5FM3NapGA", // common pangram "Ahzth5kpbOylV4MquUGlC0oR+DR4zxQfUfkz9lOrn7zAWgN83b7QbjCb8zSULE5YzfGkbiN5EczX/Pl4fLx/0A", // simple greeting "eGoC90IBWQPGxv2FJVLScpEvR0DhWEdhiobiF/cfVBnSXhAxr+5YUxOJZESTTrBLkDpoWxRIt1XVb3Aa/pvizg", // empty slice @@ -162,8 +153,9 @@ mod tests { #[test] fn compute_hash_as_expected() { for (&(content, size), expected_hash) in CASES.iter().zip(HASHES) { - // to capture progress updates from `compute_hash` let file = create_file(content); + + // to capture progress updates from `compute_hash` let mut read_total = 0; let callback = |n| read_total += n; diff --git a/src/lib.rs b/src/lib.rs index 4e979e7..2efbcd5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,7 +15,6 @@ pub use cli::Cli; pub use error::{Error, Parameter, Result}; #[cfg(test)] -#[inline] pub fn check_trait(expected: &E, actual: &A, tr: &'static str, ty: &'static str) where E: std::fmt::Debug + PartialEq, @@ -26,3 +25,13 @@ where "`impl {tr} for {ty}` expected: {expected:?}, actual: {actual:?}", ); } + +/// Helper to create a temp file from `data` +#[cfg(test)] +fn create_file(data: &[u8]) -> tempfile::NamedTempFile { + use std::io::Write; + + let mut tmp = tempfile::NamedTempFile::new().expect("creating temp file"); + tmp.write_all(data).expect("writing to tempfile"); + tmp +}