70 lines
1.9 KiB
Rust
70 lines
1.9 KiB
Rust
use unicode_segmentation::UnicodeSegmentation;
|
|
|
|
#[derive(Debug)]
|
|
pub struct SubscriberName(String);
|
|
|
|
impl SubscriberName {
|
|
pub fn parse(s: String) -> Result<Self, String> {
|
|
let is_empty_or_whitespace = s.trim().is_empty();
|
|
let is_too_long = s.graphemes(true).count() > 256;
|
|
let forbidden_characters = ['/', '(', ')', '"', '<', '>', '\\', '{', '}'];
|
|
let contains_forbidden_characters = s.chars().any(|g| forbidden_characters.contains(&g));
|
|
|
|
if is_empty_or_whitespace || is_too_long || contains_forbidden_characters {
|
|
Err(format!("{} is not a valid subscriber name.", s))
|
|
} else {
|
|
Ok(Self(s))
|
|
}
|
|
}
|
|
}
|
|
|
|
impl AsRef<str> for SubscriberName {
|
|
fn as_ref(&self) -> &str {
|
|
self.0.as_str()
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate::domain::SubscriberName;
|
|
use claims::{assert_err, assert_ok};
|
|
|
|
#[test]
|
|
fn a_256_grapheme_long_name_is_valid() {
|
|
let name = "ê".repeat(256);
|
|
assert_ok!(SubscriberName::parse(name));
|
|
}
|
|
|
|
#[test]
|
|
fn a_name_longer_than_256_graphemes_is_rejected() {
|
|
let name = "ê".repeat(257);
|
|
assert_err!(SubscriberName::parse(name));
|
|
}
|
|
|
|
#[test]
|
|
fn a_whitespace_only_name_is_rejected() {
|
|
let name = "\n \t ".to_string();
|
|
assert_err!(SubscriberName::parse(name));
|
|
}
|
|
|
|
#[test]
|
|
fn empty_string_is_rejected() {
|
|
let name = "".to_string();
|
|
assert_err!(SubscriberName::parse(name));
|
|
}
|
|
|
|
#[test]
|
|
fn a_name_containing_invalid_character_is_rejected() {
|
|
for name in ['/', '(', ')', '"', '<', '>', '\\', '{', '}'] {
|
|
let name = name.to_string();
|
|
assert_err!(SubscriberName::parse(name));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn a_valid_name_is_parsed_successfully() {
|
|
let name = "Alphonse".to_string();
|
|
assert_ok!(SubscriberName::parse(name));
|
|
}
|
|
}
|