Skip to content
2 changes: 1 addition & 1 deletion src/classes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,5 +126,5 @@ OPTIONS:

Algorithm can be:
CRC32, MD5, SHA1, WHIRLPOOL, BLAKE2S-256, BLAKE2B-512,
SHA2 / SHA2-256 / SHA-256, SHA-224, SHA2-384, SHA2-512,
SHA2 / SHA2-256 / SHA-256, SHA2-224, SHA2-384, SHA2-512,
SHA3 / SHA3-256 (default), SHA3-384, SHA3-512";
23 changes: 16 additions & 7 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::io;
use std::io::BufRead;
use std::str::FromStr;

use anyhow::{anyhow, Result};
use anyhow::{Result, anyhow};

//use crate::hasher::hash_file_crc32;
use blake2::{Blake2b512, Blake2s256};
Expand All @@ -24,7 +24,7 @@ use classes::OutputEncoding;
use hasher::{file_exists, hash_file_encoded};

use crate::classes::{
BasicHash, ConfigSettings, HashAlgorithm, DEFAULT_HASH, GIT_VERSION_SHORT, HELP, VERSION,
BasicHash, ConfigSettings, DEFAULT_HASH, GIT_VERSION_SHORT, HELP, HashAlgorithm, VERSION,
};

mod classes;
Expand Down Expand Up @@ -228,8 +228,17 @@ fn get_paths_matching_glob(config: &ConfigSettings) -> Result<Vec<String>> {
.collect();

// If the glob matched nothing, check if the pattern itself is a valid file
if glob_matches.is_empty() && file_exists(pattern) {
result.push(pattern.clone());
if glob_matches.is_empty() {
if file_exists(pattern) {
result.push(pattern.clone());
} else {
// Check if this looks like a specific file path (not a glob pattern)
// If it doesn't contain glob metacharacters, treat it as a missing file error
if !pattern.contains(&['*', '?', '[', ']']) {
return Err(anyhow::anyhow!("File not found: {}", pattern));
}
// Otherwise it's a glob pattern that matched nothing, which is acceptable
}
} else {
result.extend(glob_matches);
}
Expand Down Expand Up @@ -279,11 +288,11 @@ where
let file_hash = call_hasher(config.algorithm, config.encoding, pathstr);

match file_hash {
Ok(hash) => {
Ok(basic_hash) => {
if config.exclude_fn {
println!("{}", hash.0);
println!("{basic_hash}");
} else {
println!("{} {}", hash.0, pathstr);
println!("{basic_hash} {pathstr}");
}
}

Expand Down
134 changes: 124 additions & 10 deletions src/unit_tests.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,132 @@
#![allow(unused_imports)]
// #![allow(dead_code)]
// #![allow(unused_variables)]

// unit tests are part of the main crate

#[cfg(test)]
use super::*;
use std::str::FromStr;

#[test]
fn test_parse_hash_algorithm_valid() {
assert_eq!(
parse_hash_algorithm(Some("SHA3-256")).unwrap(),
HashAlgorithm::SHA3_256
);
assert_eq!(
parse_hash_algorithm(Some("MD5")).unwrap(),
HashAlgorithm::MD5
);
assert_eq!(
parse_hash_algorithm(Some("CRC32")).unwrap(),
HashAlgorithm::CRC32
);
assert_eq!(
parse_hash_algorithm(Some("WHIRLPOOL")).unwrap(),
HashAlgorithm::Whirlpool
);
}

#[test]
fn test_parse_hash_algorithm_default() {
assert_eq!(parse_hash_algorithm(None).unwrap(), DEFAULT_HASH);
assert_eq!(parse_hash_algorithm(Some("")).unwrap(), DEFAULT_HASH);
}

#[test]
fn test_parse_hash_algorithm_invalid() {
assert!(parse_hash_algorithm(Some("INVALID")).is_err());
}

#[test]
fn test_parse_hash_encoding_valid() {
assert_eq!(
parse_hash_encoding(Some("Hex")).unwrap(),
OutputEncoding::Hex
);
assert_eq!(
parse_hash_encoding(Some("Base64")).unwrap(),
OutputEncoding::Base64
);
assert_eq!(
parse_hash_encoding(Some("Base32")).unwrap(),
OutputEncoding::Base32
);
}

#[test]
fn test_parse_hash_encoding_default() {
assert_eq!(
parse_hash_encoding(None).unwrap(),
OutputEncoding::Unspecified
);
assert_eq!(
parse_hash_encoding(Some("")).unwrap(),
OutputEncoding::Unspecified
);
}

#[test]
fn test_hash_algorithm_from_str() {
assert_eq!(
HashAlgorithm::from_str("sha3-256").unwrap(),
HashAlgorithm::SHA3_256
);
assert_eq!(
HashAlgorithm::from_str("SHA2").unwrap(),
HashAlgorithm::SHA2_256
);
assert_eq!(
HashAlgorithm::from_str("sha1").unwrap(),
HashAlgorithm::SHA1
);
}

#[test]
fn test_config_settings_new() {
let config = ConfigSettings::new(
true, // debug_mode
false, // exclude_fn
false, // single_thread
true, // case_sensitive
HashAlgorithm::SHA3_256,
OutputEncoding::Hex,
Some(100),
);

assert!(config.debug_mode);
assert!(!config.exclude_fn);
assert!(config.case_sensitive);
assert_eq!(config.algorithm, HashAlgorithm::SHA3_256);
assert_eq!(config.encoding, OutputEncoding::Hex);
assert_eq!(config.limit_num, Some(100));
assert!(config.supplied_paths.is_empty());
}

#[test]
fn test_config_settings_set_paths() {
let mut config = ConfigSettings::new(
false,
false,
false,
false,
HashAlgorithm::MD5,
OutputEncoding::Base64,
None,
);

let paths = vec!["file1.txt".to_string(), "file2.txt".to_string()];
config.set_supplied_paths(paths.clone());

assert_eq!(config.supplied_paths, paths);
}

#[test]
fn unit_it_works() {
assert_eq!(2 + 2, 4);
fn test_basic_hash_display() {
let hash = BasicHash("abc123".to_string());
assert_eq!(format!("{hash}"), "abc123");
}

#[test]
fn help_length() {
assert!(HELP.len() > 10);
fn test_help_content() {
assert!(HELP.contains("USAGE:"));
assert!(HELP.contains("FLAGS:"));
assert!(HELP.contains("OPTIONS:"));
assert!(HELP.contains("Algorithm can be:"));
assert!(HELP.len() > 100);
}
Loading