1use std::path::Path;
2
3use crate::error::{HashError, HashResult};
4
5pub fn calculate_checksum<P: AsRef<Path>>(file_path: P) -> HashResult<String> {
32 let file_path = file_path.as_ref();
33 let mut hasher = blake3::Hasher::new();
34 hasher.update_mmap(file_path).map_err(|err| {
35 HashError::ReadFailed {
36 path: file_path.to_path_buf(),
37 source: err,
38 }
39 })?;
40 Ok(hasher.finalize().to_hex().to_string())
41}
42
43pub fn verify_checksum<P: AsRef<Path>>(file_path: P, expected: &str) -> HashResult<bool> {
70 let file_path = file_path.as_ref();
71 let actual = calculate_checksum(file_path)?;
72 Ok(actual.eq_ignore_ascii_case(expected))
73}
74
75#[cfg(test)]
76mod tests {
77 use std::io::Write;
78
79 use tempfile::NamedTempFile;
80
81 use super::{calculate_checksum, verify_checksum};
82
83 #[test]
84 fn test_calculate_checksum() {
85 let mut file = NamedTempFile::new().unwrap();
86 file.write_all(b"hello world\n").unwrap();
87 let path = file.path();
88
89 let checksum = calculate_checksum(path).unwrap();
90 assert_eq!(
91 checksum,
92 "dc5a4edb8240b018124052c330270696f96771a63b45250a5c17d3000e823355"
93 );
94 }
95
96 #[test]
97 fn test_verify_checksum_valid() {
98 let mut file = NamedTempFile::new().unwrap();
99 file.write_all(b"hello world\n").unwrap();
100 let path = file.path();
101
102 let result = verify_checksum(
103 path,
104 "dc5a4edb8240b018124052c330270696f96771a63b45250a5c17d3000e823355",
105 )
106 .unwrap();
107 assert!(result);
108 }
109
110 #[test]
111 fn test_verify_checksum_invalid() {
112 let mut file = NamedTempFile::new().unwrap();
113 file.write_all(b"hello world").unwrap();
114 let path = file.path();
115
116 let result = verify_checksum(path, "invalid-checksum").unwrap();
117 assert!(!result);
118 }
119
120 #[test]
121 fn test_calculate_checksum_file_not_found() {
122 let result = calculate_checksum("/path/to/nonexistent/file");
123 assert!(result.is_err());
124 }
125
126 #[test]
127 fn test_verify_checksum_file_not_found() {
128 let result = verify_checksum("/path/to/nonexistent/file", "any-checksum");
129 assert!(result.is_err());
130 }
131
132 #[test]
133 fn test_calculate_checksum_on_directory() {
134 let dir = tempfile::tempdir().unwrap();
135 let result = calculate_checksum(dir.path());
136 assert!(result.is_err());
137 }
138}