From 8e3472a0cc7d7ddf58afcbe961289a50420583a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABlle=20Huisman?= Date: Fri, 5 Dec 2025 19:52:10 +0100 Subject: [PATCH] feat: add validation tests --- packages/fortifier/src/validations/email.rs | 111 +++- packages/fortifier/src/validations/length.rs | 570 +++++++++++++++++-- packages/fortifier/src/validations/url.rs | 148 ++++- 3 files changed, 733 insertions(+), 96 deletions(-) diff --git a/packages/fortifier/src/validations/email.rs b/packages/fortifier/src/validations/email.rs index 14988c2..3c14203 100644 --- a/packages/fortifier/src/validations/email.rs +++ b/packages/fortifier/src/validations/email.rs @@ -6,7 +6,7 @@ use std::{ }; /// Email validation error. -#[derive(Debug)] +#[derive(Debug, Eq, PartialEq)] pub enum EmailError { /// Invalid email address. Invalid, @@ -33,26 +33,6 @@ pub trait ValidateEmail { } } -macro_rules! validate_type_with_deref { - ($type:ty) => { - impl ValidateEmail for $type - where - T: ValidateEmail, - { - fn email(&self) -> Option> { - T::email(self) - } - } - }; -} - -validate_type_with_deref!(&T); -validate_type_with_deref!(Arc); -validate_type_with_deref!(Box); -validate_type_with_deref!(Rc); -validate_type_with_deref!(Ref<'_, T>); -validate_type_with_deref!(RefMut<'_, T>); - impl ValidateEmail for str { fn email(&self) -> Option> { Some(self.into()) @@ -89,3 +69,92 @@ where } } } + +macro_rules! validate_with_deref { + ($type:ty) => { + impl ValidateEmail for $type + where + T: ValidateEmail, + { + fn email(&self) -> Option> { + T::email(self) + } + } + }; +} + +validate_with_deref!(&T); +validate_with_deref!(Arc); +validate_with_deref!(Box); +validate_with_deref!(Rc); +validate_with_deref!(Ref<'_, T>); +validate_with_deref!(RefMut<'_, T>); + +#[cfg(test)] +mod tests { + use std::{borrow::Cow, cell::RefCell, rc::Rc, sync::Arc}; + + use super::{EmailError, ValidateEmail}; + + #[test] + fn ok() { + assert_eq!((*"admin@localhost").validate_email(), Ok(())); + assert_eq!("admin@localhost".validate_email(), Ok(())); + assert_eq!("admin@localhost".to_owned().validate_email(), Ok(())); + assert_eq!( + Cow::::Borrowed("admin@localhost").validate_email(), + Ok(()) + ); + assert_eq!( + Cow::::Owned("admin@localhost".to_owned()).validate_email(), + Ok(()) + ); + + assert_eq!(None::<&str>.validate_email(), Ok(())); + assert_eq!(Some("admin@localhost").validate_email(), Ok(())); + + assert_eq!((&"admin@localhost").validate_email(), Ok(())); + #[expect(unused_allocation)] + { + assert_eq!(Box::new("admin@localhost").validate_email(), Ok(())); + } + assert_eq!(Arc::new("admin@localhost").validate_email(), Ok(())); + assert_eq!(Rc::new("admin@localhost").validate_email(), Ok(())); + + let cell = RefCell::new("admin@localhost"); + assert_eq!(cell.borrow().validate_email(), Ok(())); + assert_eq!(cell.borrow_mut().validate_email(), Ok(())); + } + + #[test] + fn invalid_error() { + assert_eq!((*"admin").validate_email(), Err(EmailError::Invalid)); + assert_eq!("admin".validate_email(), Err(EmailError::Invalid)); + assert_eq!( + "admin".to_owned().validate_email(), + Err(EmailError::Invalid) + ); + assert_eq!( + Cow::::Borrowed("admin").validate_email(), + Err(EmailError::Invalid) + ); + assert_eq!( + Cow::::Owned("admin".to_owned()).validate_email(), + Err(EmailError::Invalid) + ); + + assert_eq!(Some("admin").validate_email(), Err(EmailError::Invalid)); + + assert_eq!((&"admin").validate_email(), Err(EmailError::Invalid)); + #[expect(unused_allocation)] + { + assert_eq!(Box::new("admin").validate_email(), Err(EmailError::Invalid)); + } + assert_eq!(Arc::new("admin").validate_email(), Err(EmailError::Invalid)); + assert_eq!(Rc::new("admin").validate_email(), Err(EmailError::Invalid)); + + let cell = RefCell::new("admin"); + assert_eq!(cell.borrow().validate_email(), Err(EmailError::Invalid)); + assert_eq!(cell.borrow_mut().validate_email(), Err(EmailError::Invalid)); + } +} diff --git a/packages/fortifier/src/validations/length.rs b/packages/fortifier/src/validations/length.rs index a860472..88e5bf4 100644 --- a/packages/fortifier/src/validations/length.rs +++ b/packages/fortifier/src/validations/length.rs @@ -10,7 +10,7 @@ use std::{ use indexmap::{IndexMap, IndexSet}; /// Length validation error. -#[derive(Debug)] +#[derive(Debug, Eq, PartialEq)] pub enum LengthError { /// Length is not equal to the required length. Equal { @@ -79,27 +79,7 @@ where } } -macro_rules! validate_type_with_deref { - ($type:ty) => { - impl ValidateLength for $type - where - T: ValidateLength, - { - fn length(&self) -> Option { - T::length(self) - } - } - }; -} - -validate_type_with_deref!(&T); -validate_type_with_deref!(Arc); -validate_type_with_deref!(Box); -validate_type_with_deref!(Rc); -validate_type_with_deref!(Ref<'_, T>); -validate_type_with_deref!(RefMut<'_, T>); - -macro_rules! validate_type_with_chars { +macro_rules! validate_with_chars { ($type:ty) => { impl ValidateLength for $type { fn length(&self) -> Option { @@ -109,13 +89,19 @@ macro_rules! validate_type_with_chars { }; } -validate_type_with_chars!(str); -validate_type_with_chars!(&str); -validate_type_with_chars!(String); +validate_with_chars!(str); +validate_with_chars!(&str); +validate_with_chars!(String); -macro_rules! validate_type_with_len { +impl ValidateLength for [T; N] { + fn length(&self) -> Option { + Some(N) + } +} + +macro_rules! validate_with_len { ($type:ty) => { - validate_type_with_len!($type,); + validate_with_len!($type,); }; ($type:ty, $( $generic:ident ),*$( , )*) => { impl<$( $generic ),*> ValidateLength for $type { @@ -126,33 +112,24 @@ macro_rules! validate_type_with_len { }; } -validate_type_with_len!([T], T); -validate_type_with_len!(BTreeSet, T); -validate_type_with_len!(BTreeMap, K, V); -validate_type_with_len!(HashSet, T, S); -validate_type_with_len!(HashMap, K, V, S); -validate_type_with_len!(Vec, T); -validate_type_with_len!(VecDeque, T); +validate_with_len!([T], T); +validate_with_len!(BTreeSet, T); +validate_with_len!(BTreeMap, K, V); +validate_with_len!(HashSet, T, S); +validate_with_len!(HashMap, K, V, S); +validate_with_len!(Vec, T); +validate_with_len!(VecDeque, T); #[cfg(feature = "indexmap")] -validate_type_with_len!(IndexSet, T); +validate_with_len!(IndexSet, T); #[cfg(feature = "indexmap")] -validate_type_with_len!(IndexMap, K, V); - -impl ValidateLength for Cow<'_, T> -where - T: ToOwned + ?Sized, - for<'a> &'a T: ValidateLength, -{ - fn length(&self) -> Option { - self.as_ref().length() - } -} +validate_with_len!(IndexMap, K, V); -impl ValidateLength for Option +impl ValidateLength for Option where - T: ValidateLength, + L: PartialEq + PartialOrd, + T: ValidateLength, { - fn length(&self) -> Option { + fn length(&self) -> Option { if let Some(s) = self { T::length(s) } else { @@ -161,8 +138,497 @@ where } } -impl ValidateLength for [T; N] { - fn length(&self) -> Option { - Some(N) +macro_rules! validate_with_deref { + ($type:ty) => { + impl ValidateLength for $type + where + L: PartialEq + PartialOrd, + T: ValidateLength, + { + fn length(&self) -> Option { + T::length(self) + } + } + }; +} + +validate_with_deref!(&T); +validate_with_deref!(Arc); +validate_with_deref!(Box); +validate_with_deref!(Rc); +validate_with_deref!(Ref<'_, T>); +validate_with_deref!(RefMut<'_, T>); + +impl ValidateLength for Cow<'_, T> +where + L: PartialEq + PartialOrd, + T: ToOwned + ?Sized, + for<'a> &'a T: ValidateLength, +{ + fn length(&self) -> Option { + self.as_ref().length() + } +} + +#[cfg(test)] +mod tests { + use std::{ + borrow::Cow, + cell::RefCell, + collections::{BTreeMap, BTreeSet, HashMap, HashSet, VecDeque}, + rc::Rc, + sync::Arc, + }; + + #[cfg(feature = "indexmap")] + use indexmap::{IndexMap, IndexSet}; + + use super::{LengthError, ValidateLength}; + + #[test] + fn ok() { + assert_eq!((*"a").validate_length(Some(1), None, None), Ok(())); + assert_eq!("a".validate_length(Some(1), None, None), Ok(())); + assert_eq!("a".to_owned().validate_length(Some(1), None, None), Ok(())); + assert_eq!( + Cow::::Borrowed("a").validate_length(Some(1), None, None), + Ok(()) + ); + assert_eq!( + Cow::::Owned("a".to_owned()).validate_length(Some(1), None, None), + Ok(()) + ); + + assert_eq!(None::<&str>.validate_length(Some(1), None, None), Ok(())); + assert_eq!(Some("a").validate_length(Some(1), None, None), Ok(())); + + assert_eq!([""; 1].validate_length(Some(1), None, None), Ok(())); + assert_eq!([""].validate_length(Some(1), None, None), Ok(())); + assert_eq!( + BTreeSet::from([""]).validate_length(Some(1), None, None), + Ok(()) + ); + assert_eq!( + BTreeMap::from([("", "")]).validate_length(Some(1), None, None), + Ok(()) + ); + assert_eq!( + HashSet::from([""]).validate_length(Some(1), None, None), + Ok(()) + ); + assert_eq!( + HashMap::from([("", "")]).validate_length(Some(1), None, None), + Ok(()) + ); + assert_eq!(vec![""].validate_length(Some(1), None, None), Ok(())); + assert_eq!( + VecDeque::from([""]).validate_length(Some(1), None, None), + Ok(()) + ); + + #[cfg(feature = "indexmap")] + { + assert_eq!( + IndexSet::from([""]).validate_length(Some(1), None, None), + Ok(()) + ); + assert_eq!( + IndexMap::from([("", "")]).validate_length(Some(1), None, None), + Ok(()) + ); + } + + assert_eq!((&"a").validate_length(Some(1), None, None), Ok(())); + #[expect(unused_allocation)] + { + assert_eq!(Box::new("a").validate_length(Some(1), None, None), Ok(())); + } + assert_eq!(Arc::new("a").validate_length(Some(1), None, None), Ok(())); + assert_eq!(Rc::new("a").validate_length(Some(1), None, None), Ok(())); + + let cell = RefCell::new("a"); + assert_eq!(cell.borrow().validate_length(Some(1), None, None), Ok(())); + assert_eq!( + cell.borrow_mut().validate_length(Some(1), None, None), + Ok(()) + ); + } + + #[test] + fn equal_error() { + assert_eq!( + (*"a").validate_length(Some(2), None, None), + Err(LengthError::Equal { + equal: 2, + length: 1 + }) + ); + assert_eq!( + "a".validate_length(Some(2), None, None), + Err(LengthError::Equal { + equal: 2, + length: 1 + }) + ); + assert_eq!( + "a".to_owned().validate_length(Some(2), None, None), + Err(LengthError::Equal { + equal: 2, + length: 1 + }) + ); + assert_eq!( + Cow::::Borrowed("a").validate_length(Some(2), None, None), + Err(LengthError::Equal { + equal: 2, + length: 1 + }) + ); + assert_eq!( + Cow::::Owned("a".to_owned()).validate_length(Some(2), None, None), + Err(LengthError::Equal { + equal: 2, + length: 1 + }) + ); + + assert_eq!( + Some("a").validate_length(Some(2), None, None), + Err(LengthError::Equal { + equal: 2, + length: 1 + }) + ); + + assert_eq!( + [""; 1].validate_length(Some(2), None, None), + Err(LengthError::Equal { + equal: 2, + length: 1 + }) + ); + assert_eq!( + [""].validate_length(Some(2), None, None), + Err(LengthError::Equal { + equal: 2, + length: 1 + }) + ); + assert_eq!( + BTreeSet::from([""]).validate_length(Some(2), None, None), + Err(LengthError::Equal { + equal: 2, + length: 1 + }) + ); + assert_eq!( + BTreeMap::from([("", "")]).validate_length(Some(2), None, None), + Err(LengthError::Equal { + equal: 2, + length: 1 + }) + ); + assert_eq!( + HashSet::from([""]).validate_length(Some(2), None, None), + Err(LengthError::Equal { + equal: 2, + length: 1 + }) + ); + assert_eq!( + HashMap::from([("", "")]).validate_length(Some(2), None, None), + Err(LengthError::Equal { + equal: 2, + length: 1 + }) + ); + assert_eq!( + vec![""].validate_length(Some(2), None, None), + Err(LengthError::Equal { + equal: 2, + length: 1 + }) + ); + assert_eq!( + VecDeque::from([""]).validate_length(Some(2), None, None), + Err(LengthError::Equal { + equal: 2, + length: 1 + }) + ); + + #[cfg(feature = "indexmap")] + { + assert_eq!( + IndexSet::from([""]).validate_length(Some(2), None, None), + Err(LengthError::Equal { + equal: 2, + length: 1 + }) + ); + assert_eq!( + IndexMap::from([("", "")]).validate_length(Some(2), None, None), + Err(LengthError::Equal { + equal: 2, + length: 1 + }) + ); + } + + assert_eq!( + (&"a").validate_length(Some(2), None, None), + Err(LengthError::Equal { + equal: 2, + length: 1 + }) + ); + #[expect(unused_allocation)] + { + assert_eq!( + Box::new("a").validate_length(Some(2), None, None), + Err(LengthError::Equal { + equal: 2, + length: 1 + }) + ); + } + assert_eq!( + Arc::new("a").validate_length(Some(2), None, None), + Err(LengthError::Equal { + equal: 2, + length: 1 + }) + ); + assert_eq!( + Rc::new("a").validate_length(Some(2), None, None), + Err(LengthError::Equal { + equal: 2, + length: 1 + }) + ); + + let cell = RefCell::new("a"); + assert_eq!( + cell.borrow().validate_length(Some(2), None, None), + Err(LengthError::Equal { + equal: 2, + length: 1 + }) + ); + assert_eq!( + cell.borrow_mut().validate_length(Some(2), None, None), + Err(LengthError::Equal { + equal: 2, + length: 1 + }) + ); + } + + #[test] + fn min_error() { + assert_eq!( + (*"a").validate_length(None, Some(3), None), + Err(LengthError::Min { min: 3, length: 1 }) + ); + assert_eq!( + "a".validate_length(None, Some(3), None), + Err(LengthError::Min { min: 3, length: 1 }) + ); + assert_eq!( + "a".to_owned().validate_length(None, Some(3), None), + Err(LengthError::Min { min: 3, length: 1 }) + ); + assert_eq!( + Cow::::Borrowed("a").validate_length(None, Some(3), None), + Err(LengthError::Min { min: 3, length: 1 }) + ); + assert_eq!( + Cow::::Owned("a".to_owned()).validate_length(None, Some(3), None), + Err(LengthError::Min { min: 3, length: 1 }) + ); + + assert_eq!( + Some("a").validate_length(None, Some(3), None), + Err(LengthError::Min { min: 3, length: 1 }) + ); + + assert_eq!( + [""; 1].validate_length(None, Some(3), None), + Err(LengthError::Min { min: 3, length: 1 }) + ); + assert_eq!( + [""].validate_length(None, Some(3), None), + Err(LengthError::Min { min: 3, length: 1 }) + ); + assert_eq!( + BTreeSet::from([""]).validate_length(None, Some(3), None), + Err(LengthError::Min { min: 3, length: 1 }) + ); + assert_eq!( + BTreeMap::from([("", "")]).validate_length(None, Some(3), None), + Err(LengthError::Min { min: 3, length: 1 }) + ); + assert_eq!( + HashSet::from([""]).validate_length(None, Some(3), None), + Err(LengthError::Min { min: 3, length: 1 }) + ); + assert_eq!( + HashMap::from([("", "")]).validate_length(None, Some(3), None), + Err(LengthError::Min { min: 3, length: 1 }) + ); + assert_eq!( + vec![""].validate_length(None, Some(3), None), + Err(LengthError::Min { min: 3, length: 1 }) + ); + assert_eq!( + VecDeque::from([""]).validate_length(None, Some(3), None), + Err(LengthError::Min { min: 3, length: 1 }) + ); + + #[cfg(feature = "indexmap")] + { + assert_eq!( + IndexSet::from([""]).validate_length(None, Some(3), None), + Err(LengthError::Min { min: 3, length: 1 }) + ); + assert_eq!( + IndexMap::from([("", "")]).validate_length(None, Some(3), None), + Err(LengthError::Min { min: 3, length: 1 }) + ); + } + + assert_eq!( + (&"a").validate_length(None, Some(3), None), + Err(LengthError::Min { min: 3, length: 1 }) + ); + #[expect(unused_allocation)] + { + assert_eq!( + Box::new("a").validate_length(None, Some(3), None), + Err(LengthError::Min { min: 3, length: 1 }) + ); + } + assert_eq!( + Arc::new("a").validate_length(None, Some(3), None), + Err(LengthError::Min { min: 3, length: 1 }) + ); + assert_eq!( + Rc::new("a").validate_length(None, Some(3), None), + Err(LengthError::Min { min: 3, length: 1 }) + ); + + let cell = RefCell::new("a"); + assert_eq!( + cell.borrow().validate_length(None, Some(3), None), + Err(LengthError::Min { min: 3, length: 1 }) + ); + assert_eq!( + cell.borrow_mut().validate_length(None, Some(3), None), + Err(LengthError::Min { min: 3, length: 1 }) + ); + } + + #[test] + fn max_error() { + assert_eq!( + (*"a").validate_length(None, None, Some(0)), + Err(LengthError::Max { max: 0, length: 1 }) + ); + assert_eq!( + "a".validate_length(None, None, Some(0)), + Err(LengthError::Max { max: 0, length: 1 }) + ); + assert_eq!( + "a".to_owned().validate_length(None, None, Some(0)), + Err(LengthError::Max { max: 0, length: 1 }) + ); + assert_eq!( + Cow::::Borrowed("a").validate_length(None, None, Some(0)), + Err(LengthError::Max { max: 0, length: 1 }) + ); + assert_eq!( + Cow::::Owned("a".to_owned()).validate_length(None, None, Some(0)), + Err(LengthError::Max { max: 0, length: 1 }) + ); + + assert_eq!( + Some("a").validate_length(None, None, Some(0)), + Err(LengthError::Max { max: 0, length: 1 }) + ); + + assert_eq!( + [""; 1].validate_length(None, None, Some(0)), + Err(LengthError::Max { max: 0, length: 1 }) + ); + assert_eq!( + [""].validate_length(None, None, Some(0)), + Err(LengthError::Max { max: 0, length: 1 }) + ); + assert_eq!( + BTreeSet::from([""]).validate_length(None, None, Some(0)), + Err(LengthError::Max { max: 0, length: 1 }) + ); + assert_eq!( + BTreeMap::from([("", "")]).validate_length(None, None, Some(0)), + Err(LengthError::Max { max: 0, length: 1 }) + ); + assert_eq!( + HashSet::from([""]).validate_length(None, None, Some(0)), + Err(LengthError::Max { max: 0, length: 1 }) + ); + assert_eq!( + HashMap::from([("", "")]).validate_length(None, None, Some(0)), + Err(LengthError::Max { max: 0, length: 1 }) + ); + assert_eq!( + vec![""].validate_length(None, None, Some(0)), + Err(LengthError::Max { max: 0, length: 1 }) + ); + assert_eq!( + VecDeque::from([""]).validate_length(None, None, Some(0)), + Err(LengthError::Max { max: 0, length: 1 }) + ); + + #[cfg(feature = "indexmap")] + { + assert_eq!( + IndexSet::from([""]).validate_length(None, None, Some(0)), + Err(LengthError::Max { max: 0, length: 1 }) + ); + assert_eq!( + IndexMap::from([("", "")]).validate_length(None, None, Some(0)), + Err(LengthError::Max { max: 0, length: 1 }) + ); + } + + assert_eq!( + (&"a").validate_length(None, None, Some(0)), + Err(LengthError::Max { max: 0, length: 1 }) + ); + #[expect(unused_allocation)] + { + assert_eq!( + Box::new("a").validate_length(None, None, Some(0)), + Err(LengthError::Max { max: 0, length: 1 }) + ); + } + assert_eq!( + Arc::new("a").validate_length(None, None, Some(0)), + Err(LengthError::Max { max: 0, length: 1 }) + ); + assert_eq!( + Rc::new("a").validate_length(None, None, Some(0)), + Err(LengthError::Max { max: 0, length: 1 }) + ); + + let cell = RefCell::new("a"); + assert_eq!( + cell.borrow().validate_length(None, None, Some(0)), + Err(LengthError::Max { max: 0, length: 1 }) + ); + assert_eq!( + cell.borrow_mut().validate_length(None, None, Some(0)), + Err(LengthError::Max { max: 0, length: 1 }) + ); } } diff --git a/packages/fortifier/src/validations/url.rs b/packages/fortifier/src/validations/url.rs index 05db33c..3b4e081 100644 --- a/packages/fortifier/src/validations/url.rs +++ b/packages/fortifier/src/validations/url.rs @@ -8,9 +8,9 @@ use std::{ use url::{ParseError, Url}; /// URL validation error. -#[derive(Debug)] +#[derive(Debug, Eq, PartialEq)] pub enum UrlError { - /// Invalid URL. + /// Parse error. Parse(ParseError), } @@ -31,26 +31,6 @@ pub trait ValidateUrl { } } -macro_rules! validate_type_with_deref { - ($type:ty) => { - impl ValidateUrl for $type - where - T: ValidateUrl, - { - fn url(&self) -> Option> { - T::url(self) - } - } - }; -} - -validate_type_with_deref!(&T); -validate_type_with_deref!(Arc); -validate_type_with_deref!(Box); -validate_type_with_deref!(Rc); -validate_type_with_deref!(Ref<'_, T>); -validate_type_with_deref!(RefMut<'_, T>); - impl ValidateUrl for str { fn url(&self) -> Option> { Some(self.into()) @@ -80,6 +60,128 @@ where T: ValidateUrl, { fn url(&self) -> Option> { - if let Some(s) = self { T::url(s) } else { None } + if let Some(url) = self { + T::url(url) + } else { + None + } + } +} + +macro_rules! validate_with_deref { + ($type:ty) => { + impl ValidateUrl for $type + where + T: ValidateUrl, + { + fn url(&self) -> Option> { + T::url(self) + } + } + }; +} + +validate_with_deref!(&T); +validate_with_deref!(Arc); +validate_with_deref!(Box); +validate_with_deref!(Rc); +validate_with_deref!(Ref<'_, T>); +validate_with_deref!(RefMut<'_, T>); + +#[cfg(test)] +mod tests { + use std::{borrow::Cow, cell::RefCell, rc::Rc, sync::Arc}; + + use url::ParseError; + + use super::{UrlError, ValidateUrl}; + + #[test] + fn ok() { + assert_eq!((*"http://localhost").validate_url(), Ok(())); + assert_eq!("http://localhost".validate_url(), Ok(())); + assert_eq!("http://localhost".to_owned().validate_url(), Ok(())); + assert_eq!( + Cow::::Borrowed("http://localhost").validate_url(), + Ok(()) + ); + assert_eq!( + Cow::::Owned("http://localhost".to_owned()).validate_url(), + Ok(()) + ); + + assert_eq!(None::<&str>.validate_url(), Ok(())); + assert_eq!(Some("http://localhost").validate_url(), Ok(())); + + assert_eq!((&"http://localhost").validate_url(), Ok(())); + #[expect(unused_allocation)] + { + assert_eq!(Box::new("http://localhost").validate_url(), Ok(())); + } + assert_eq!(Arc::new("http://localhost").validate_url(), Ok(())); + assert_eq!(Rc::new("http://localhost").validate_url(), Ok(())); + + let cell = RefCell::new("http://localhost"); + assert_eq!(cell.borrow().validate_url(), Ok(())); + assert_eq!(cell.borrow_mut().validate_url(), Ok(())); + } + + #[test] + fn parse_error() { + assert_eq!( + (*"http://").validate_url(), + Err(UrlError::Parse(ParseError::EmptyHost)) + ); + assert_eq!( + "http://".validate_url(), + Err(UrlError::Parse(ParseError::EmptyHost)) + ); + assert_eq!( + "http://".to_owned().validate_url(), + Err(UrlError::Parse(ParseError::EmptyHost)) + ); + assert_eq!( + Cow::::Borrowed("http://").validate_url(), + Err(UrlError::Parse(ParseError::EmptyHost)) + ); + assert_eq!( + Cow::::Owned("http://".to_owned()).validate_url(), + Err(UrlError::Parse(ParseError::EmptyHost)) + ); + + assert_eq!( + Some("http://").validate_url(), + Err(UrlError::Parse(ParseError::EmptyHost)) + ); + + assert_eq!( + (&"http://").validate_url(), + Err(UrlError::Parse(ParseError::EmptyHost)) + ); + #[expect(unused_allocation)] + { + assert_eq!( + Box::new("http://").validate_url(), + Err(UrlError::Parse(ParseError::EmptyHost)) + ); + } + assert_eq!( + Arc::new("http://").validate_url(), + Err(UrlError::Parse(ParseError::EmptyHost)) + ); + assert_eq!( + Rc::new("http://").validate_url(), + Err(UrlError::Parse(ParseError::EmptyHost)) + ); + + let cell = RefCell::new("http://"); + assert_eq!( + cell.borrow().validate_url(), + Err(UrlError::Parse(ParseError::EmptyHost)) + ); + assert_eq!( + cell.borrow_mut().validate_url(), + Err(UrlError::Parse(ParseError::EmptyHost)) + ); } }