diff --git a/src/blobs.rs b/src/blobs.rs index 0c9f057..2199970 100644 --- a/src/blobs.rs +++ b/src/blobs.rs @@ -15,7 +15,7 @@ use crate::error::GolgiError; /// # Example /// /// ```rust -/// use golgi::blobs; +/// use golgi::{blobs, GolgiError}; /// /// fn lookup_blob_path() -> Result<(), GolgiError> { /// let blob_ref = "&JlJHc9yeG1EpZA9fIPGLzUKDH0FeR39Ai57euhKT1G8=.sha256"; @@ -30,12 +30,18 @@ use crate::error::GolgiError; /// } /// ``` pub fn get_blob_path(blob_id: &str) -> Result { - let dot_index = blob_id.rfind('.').ok_or_else(|| { - GolgiError::SigilLink(format!( - "Invalid blob ID; no dot index was found: {}", + // ensure the id starts with the correct sigil link + if !blob_id.starts_with('&') { + return Err(GolgiError::SigilLink(format!( + "incorrect first character, expected '&' sigil: {}", blob_id - )) - })?; + ))); + } + + // find the dot index denoting the start of the algorithm definition tag + let dot_index = blob_id + .rfind('.') + .ok_or_else(|| GolgiError::SigilLink(format!("no dot index was found: {}", blob_id)))?; // obtain the base64 portion (substring) of the blob id let base64_str = &blob_id[1..dot_index]; @@ -82,3 +88,58 @@ pub fn hash_blob(buffer: &[u8]) -> Result<(String, String), GolgiError> { Ok((hex_hash, blob_id)) } + +#[cfg(test)] +mod tests { + use crate::blobs; + + /* HAPPY PATH TESTS */ + + #[test] + fn blob_path() { + let blob_ref = "&JlJHc9yeG1EpZA9fIPGLzUKDH0FeR39Ai57euhKT1G8=.sha256"; + let blob_path = blobs::get_blob_path(blob_ref); + assert!(blob_path.is_ok()); + assert_eq!( + blob_path.unwrap(), + "26/524773dc9e1b5129640f5f20f18bcd42831f415e477f408b9edeba1293d46f" + ); + } + + #[test] + fn hashed_blob() { + // pretend this represents a file which has been written to a buffer + let buffer = vec![7; 128]; + let hash_result = blobs::hash_blob(&buffer); + assert!(hash_result.is_ok()); + let (hex_hash, blob_id) = hash_result.unwrap(); + assert_eq!( + hex_hash, + "4c1398e54d53e925cff04da532f4bbaf15f75b5981fc76c2072dfdc6491a9fb1" + ); + assert_eq!( + blob_id, + "&TBOY5U1T6SXP8E2lMvS7rxX3W1mB/HbCBy39xkkan7E=.sha256" + ); + } + + /* SAD PATH TESTS */ + + #[test] + fn blob_id_without_sigil() { + let blob_ref = "JlJHc9yeG1EpZA9fIPGLzUKDH0FeR39Ai57euhKT1G8=.sha256"; + match blobs::get_blob_path(blob_ref) { + Err(e) => assert_eq!(e.to_string(), "SSB blob ID error: incorrect first character, expected '&' sigil: JlJHc9yeG1EpZA9fIPGLzUKDH0FeR39Ai57euhKT1G8=.sha256"), + _ => panic!(), + } + } + + #[test] + fn blob_id_without_algo() { + let blob_ref = "&JlJHc9yeG1EpZA9fIPGLzUKDH0FeR39Ai57euhKT1G8="; + match blobs::get_blob_path(blob_ref) { + Err(e) => assert_eq!(e.to_string(), "SSB blob ID error: no dot index was found: &JlJHc9yeG1EpZA9fIPGLzUKDH0FeR39Ai57euhKT1G8="), + _ => panic!(), + } + } +} diff --git a/src/error.rs b/src/error.rs index c954bac..d5efe84 100644 --- a/src/error.rs +++ b/src/error.rs @@ -78,7 +78,7 @@ impl std::fmt::Display for GolgiError { // then have the core display msg be: "SSB RPC error: {}", context GolgiError::Rpc(ref err) => write!(f, "SSB RPC failure: {}", err), GolgiError::Sbot(ref err) => write!(f, "Sbot returned an error response: {}", err), - GolgiError::SigilLink(ref context) => write!(f, "SSB sigil-link error: {}", context), + GolgiError::SigilLink(ref context) => write!(f, "SSB blob ID error: {}", context), GolgiError::SerdeJson(_) => write!(f, "Failed to serialize JSON slice"), //GolgiError::WhoAmI(ref err) => write!(f, "{}", err), GolgiError::ContentType(ref err) => write!(