use uuid::Uuid; use crate::{ Result, sharry::{AliasID, FileID, ShareID, Uri}, }; const VALID_URI: &str = "scheme://valid.uri"; const VALID_ALIAS: &str = "valid-alias"; const VALID_SHARE: &str = "valid-share"; const VALID_FILE: &str = "valid-file"; fn make_invalid(valid: &str) -> String { let invalid = valid.replace("valid", "invalid"); assert_ne!(invalid, valid); invalid } fn make_valid(valid: &str) -> String { let invalid = make_invalid(valid); let valid = { let id = Uuid::now_v1(&[4, 8, 15, 16, 23, 42]); valid.replace("valid", &id.to_string()) }; assert_ne!(valid, invalid); valid } pub trait CheckID { fn check(self) -> Result<()>; } impl CheckID for (&Uri, &AliasID) { fn check(self) -> Result<()> { if self.0.to_string() == make_invalid(VALID_URI) { Err(self.0.into()) } else if self.1.as_ref() == make_invalid(VALID_ALIAS) { Err(self.1.into()) } else { Ok(()) } } } impl CheckID for &ShareID { fn check(self) -> Result<()> { if self.to_string() == make_invalid(VALID_SHARE) { Err(self.into()) } else { Ok(()) } } } impl CheckID for (&ShareID, &FileID) { fn check(self) -> Result<()> { self.0.check()?; if self.1.to_string() == make_invalid(VALID_FILE) { Err(self.1.into()) } else { Ok(()) } } } impl From for Uri { fn from(value: bool) -> Self { if value { Self::from(make_valid(VALID_URI)) } else { Self::from(make_invalid(VALID_URI)) } } } impl From for AliasID { fn from(value: bool) -> Self { if value { Self::from(make_valid(VALID_ALIAS)) } else { Self::from(make_invalid(VALID_ALIAS)) } } } impl From for ShareID { fn from(value: bool) -> Self { if value { Self::from(make_valid(VALID_SHARE)) } else { Self::from(make_invalid(VALID_SHARE)) } } } impl From for FileID { fn from(value: bool) -> Self { if value { Self::new_test(make_valid(VALID_FILE)) } else { Self::new_test(make_invalid(VALID_FILE)) } } } #[cfg(test)] mod tests { use crate::Parameter; use super::*; #[test] fn true_makes_valids() { let uri = Uri::from(true); let alias_id = AliasID::from(true); let share_id = ShareID::from(true); let file_id = FileID::from(true); assert!((&uri, &alias_id).check().is_ok()); assert!(share_id.check().is_ok()); assert!((&share_id, &file_id).check().is_ok()); } #[test] fn default_is_valid() { let uri = Uri::default(); let alias_id = AliasID::from(true); // no `impl Default` let share_id = ShareID::default(); let file_id = FileID::default(); assert!((&uri, &alias_id).check().is_ok()); assert!(share_id.check().is_ok()); assert!((&share_id, &file_id).check().is_ok()); } #[test] fn false_makes_invalids() { fn test_check(value: impl CheckID, callback: impl FnOnce(&Parameter) -> bool) { let check = value.check().unwrap_err(); let p = check.get_invalid_param().unwrap(); assert!(callback(p)); } // valid ids let uri = Uri::from(true); let alias_id = AliasID::from(true); let share_id = ShareID::from(true); let file_id = FileID::from(true); // invalid ids let uri_i = Uri::from(false); let alias_id_i = AliasID::from(false); let share_id_i = ShareID::from(false); let file_id_i = FileID::from(false); // param checks let is_uri_i = |p: &Parameter| matches!(p, Parameter::Uri(_)); let is_alias_id_i = |p: &Parameter| matches!(p, Parameter::AliasID(_)); let is_share_id_i = |p: &Parameter| matches!(p, Parameter::ShareID(_)); let is_file_id_i = |p: &Parameter| matches!(p, Parameter::FileID(_)); // uri + alias test_check((&uri_i, &alias_id_i), is_uri_i); test_check((&uri_i, &alias_id), is_uri_i); test_check((&uri, &alias_id_i), is_alias_id_i); // share test_check(&share_id_i, is_share_id_i); // share + file test_check((&share_id_i, &file_id_i), is_share_id_i); test_check((&share_id_i, &file_id), is_share_id_i); test_check((&share_id, &file_id_i), is_file_id_i); } }