Add Host struct with tests; Add Request struct (unfinished);
This commit is contained in:
parent
62eeb9d627
commit
30f78990b1
4 changed files with 192 additions and 0 deletions
166
src/host.rs
Normal file
166
src/host.rs
Normal file
|
@ -0,0 +1,166 @@
|
|||
use std::{fmt, str::FromStr};
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
pub struct Host {
|
||||
pub subdomain: Option<String>,
|
||||
pub domain: String,
|
||||
pub tld: String,
|
||||
}
|
||||
|
||||
impl fmt::Display for Host {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if let Some(ref sub) = self.subdomain {
|
||||
write!(f, "{sub}.{}.{}", self.domain, self.tld)
|
||||
} else {
|
||||
write!(f, "{}.{}", self.domain, self.tld)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum ParseHostError {
|
||||
MissingSeparator,
|
||||
EmptyDomain,
|
||||
EmptyTld,
|
||||
EmptySubdomain,
|
||||
IllegalWhitespace,
|
||||
}
|
||||
|
||||
impl fmt::Display for ParseHostError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{self:?}")
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for ParseHostError {}
|
||||
|
||||
impl FromStr for Host {
|
||||
type Err = ParseHostError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
if s.contains(|x: char| x.is_whitespace()) {
|
||||
return Err(ParseHostError::IllegalWhitespace);
|
||||
}
|
||||
if let Some((domain, tld)) = s.rsplit_once('.') {
|
||||
if domain.is_empty() {
|
||||
Err(ParseHostError::EmptyDomain)
|
||||
} else if tld.is_empty() {
|
||||
Err(ParseHostError::EmptyTld)
|
||||
} else if let Some((subdomain, domain)) = domain.rsplit_once('.') {
|
||||
if subdomain.is_empty() {
|
||||
Err(ParseHostError::EmptySubdomain)
|
||||
} else if domain.is_empty() {
|
||||
Err(ParseHostError::EmptyDomain)
|
||||
} else {
|
||||
Ok(Host {
|
||||
subdomain: Some(subdomain.to_string()),
|
||||
domain: domain.to_string(),
|
||||
tld: tld.to_string()
|
||||
})
|
||||
}
|
||||
} else {
|
||||
Ok(Host {
|
||||
subdomain: None,
|
||||
domain: domain.to_string(),
|
||||
tld: tld.to_string(),
|
||||
})
|
||||
}
|
||||
} else {
|
||||
Err(ParseHostError::MissingSeparator)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn parse_missing_separator() {
|
||||
assert_eq!(
|
||||
"exampledotcom".parse::<Host>(),
|
||||
Err(ParseHostError::MissingSeparator)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_empty_tld() {
|
||||
assert_eq!(
|
||||
"example.".parse::<Host>(),
|
||||
Err(ParseHostError::EmptyTld)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_empty_domain() {
|
||||
assert_eq!(
|
||||
".com".parse::<Host>(),
|
||||
Err(ParseHostError::EmptyDomain)
|
||||
);
|
||||
assert_eq!(
|
||||
"example..com".parse::<Host>(),
|
||||
Err(ParseHostError::EmptyDomain)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_empty_subdomain() {
|
||||
assert_eq!(
|
||||
".example.com".parse::<Host>(),
|
||||
Err(ParseHostError::EmptySubdomain)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_illegal_whitespace() {
|
||||
assert_eq!(
|
||||
"exam\tple.com".parse::<Host>(),
|
||||
Err(ParseHostError::IllegalWhitespace)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_host() {
|
||||
assert!("example.com".parse::<Host>().is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_host_with_subdomain() {
|
||||
let host: Host = "mail.example.com".parse().unwrap();
|
||||
assert_eq!(
|
||||
host.subdomain,
|
||||
Some(String::from("mail"))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_complex_subdomain() {
|
||||
let host: Host = "mail.sender.example.com".parse().unwrap();
|
||||
assert_eq!(
|
||||
host.subdomain,
|
||||
Some(String::from("mail.sender"))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fmt() {
|
||||
let host = Host {
|
||||
subdomain: None,
|
||||
domain: String::from("example"),
|
||||
tld: String::from("com")
|
||||
};
|
||||
let host_str = host.to_string();
|
||||
assert_eq!(host_str.as_str(), "example.com");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fmt_with_subdomain() {
|
||||
let host = Host {
|
||||
subdomain: Some(String::from("mail")),
|
||||
domain: String::from("example"),
|
||||
tld: String::from("com")
|
||||
};
|
||||
let host_str = host.to_string();
|
||||
assert_eq!(host_str.as_str(), "mail.example.com");
|
||||
}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
pub mod host;
|
||||
pub mod request;
|
||||
pub mod response;
|
||||
pub mod status;
|
||||
|
||||
|
|
15
src/request.rs
Normal file
15
src/request.rs
Normal file
|
@ -0,0 +1,15 @@
|
|||
use crate::host::{Host, ParseHostError};
|
||||
use std::{fmt, str::FromStr};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Request {
|
||||
user: String,
|
||||
host: Host,
|
||||
message: String,
|
||||
}
|
||||
|
||||
impl fmt::Display for Request {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "misfin://{}@{} {}\r\n", self.user, self.host, self.message)
|
||||
}
|
||||
}
|
|
@ -92,5 +92,14 @@ mod tests {
|
|||
let response = "20 message delivered\n".parse::<Response>();
|
||||
assert_eq!(response, Err(ParseResponseError::Malformed));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_badint() {
|
||||
let response = "twenty message deliverred\r\n".parse::<Response>();
|
||||
match response {
|
||||
Err(ParseResponseError::ParseInt(_)) => {},
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue