Make use of the custom sub-address separator

This commit is contained in:
Rodolphe Bréard 2023-07-16 12:28:48 +02:00
parent 01220e6001
commit 071b3b5b76
4 changed files with 56 additions and 43 deletions

View file

@ -11,16 +11,14 @@ pub struct CodedAddress {
domain: Option<String>,
}
impl FromStr for CodedAddress {
type Err = Error;
fn from_str(s: &str) -> Result<Self> {
impl CodedAddress {
pub fn parse(s: &str, separator: char) -> Result<Self> {
let (local_part, domain) = split_local_part(s);
ensure!(!local_part.is_empty(), "{s}: local part cannot be empty");
if let Some(dom) = &domain {
ensure!(!dom.is_empty(), "{s}: domain cannot be empty");
}
let parts: Vec<&str> = local_part.split(crate::DEFAULT_SEPARATOR).collect();
let parts: Vec<&str> = local_part.split(separator).collect();
let local_part = parts[0].to_string();
ensure!(!local_part.is_empty(), "{s}: local part cannot be empty");
let sub_addr = if parts.len() >= 2 {
@ -120,17 +118,17 @@ mod tests {
#[test]
fn parse_coded_addr_empty_email() {
assert!(CodedAddress::from_str("").is_err());
assert!(CodedAddress::parse("", '+').is_err());
}
#[test]
fn parse_coded_addr_empty_local() {
assert!(CodedAddress::from_str("@example.com").is_err());
assert!(CodedAddress::parse("@example.com", '+').is_err());
}
#[test]
fn parse_coded_addr_empty_domain() {
assert!(CodedAddress::from_str("derp@").is_err());
assert!(CodedAddress::parse("derp@", '+').is_err());
}
#[test]
@ -151,7 +149,7 @@ mod tests {
#[test]
fn parse_valid_coded_addr_with_domain() {
let addr_str = "a+test+orsxg5a@example.org";
let addr = CodedAddress::from_str(addr_str);
let addr = CodedAddress::parse(addr_str, '+');
assert!(addr.is_ok(), "unable to parse {addr_str}: {addr:?}");
let addr = addr.unwrap();
assert_eq!(addr.local_part, "a");
@ -163,7 +161,7 @@ mod tests {
#[test]
fn parse_valid_coded_addr_without_domain() {
let addr_str = "local.part+test+orsxg5a";
let addr = CodedAddress::from_str(addr_str);
let addr = CodedAddress::parse(addr_str, '+');
assert!(addr.is_ok(), "unable to parse {addr_str}: {addr:?}");
let addr = addr.unwrap();
assert_eq!(addr.local_part, "local.part");
@ -172,10 +170,22 @@ mod tests {
assert!(addr.domain.is_none());
}
#[test]
fn parse_valid_coded_addr_alt_sep() {
let addr_str = "local-part.test.orsxg5a@example.org";
let addr = CodedAddress::parse(addr_str, '.');
assert!(addr.is_ok(), "unable to parse {addr_str}: {addr:?}");
let addr = addr.unwrap();
assert_eq!(addr.local_part, "local-part");
assert_eq!(addr.sub_addr, Some("test".to_string()));
assert_eq!(addr.code, b"test");
assert_eq!(addr.domain, Some("example.org".to_string()));
}
#[test]
fn parse_valid_coded_addr_without_sub_addr() {
let addr_str = "local.part@example.org";
let addr = CodedAddress::from_str(addr_str);
let addr = CodedAddress::parse(addr_str, '+');
assert!(addr.is_ok(), "unable to parse {addr_str}: {addr:?}");
let addr = addr.unwrap();
assert_eq!(addr.local_part, "local.part");
@ -232,29 +242,29 @@ mod tests {
#[test]
fn cmp_coded_addr_with_domain_eq() {
let addr_1 = CodedAddress::from_str("test+test+orsxg5a@example.org").unwrap();
let addr_2 = CodedAddress::from_str("test+test+orsxg5a@example.org").unwrap();
let addr_1 = CodedAddress::parse("test+test+orsxg5a@example.org", '+').unwrap();
let addr_2 = CodedAddress::parse("test+test+orsxg5a@example.org", '+').unwrap();
assert_eq!(addr_1, addr_2);
}
#[test]
fn cmp_coded_addr_without_domain_eq() {
let addr_1 = CodedAddress::from_str("test+test+orsxg5a").unwrap();
let addr_2 = CodedAddress::from_str("test+test+orsxg5a").unwrap();
let addr_1 = CodedAddress::parse("test+test+orsxg5a", '+').unwrap();
let addr_2 = CodedAddress::parse("test+test+orsxg5a", '+').unwrap();
assert_eq!(addr_1, addr_2);
}
#[test]
fn cmp_coded_addr_with_domain_ne() {
let addr_1 = CodedAddress::from_str("test+test+orsxg5a@example.org").unwrap();
let addr_2 = CodedAddress::from_str("test2+test+orsxg5a@example.org").unwrap();
let addr_1 = CodedAddress::parse("test+test+orsxg5a@example.org", '+').unwrap();
let addr_2 = CodedAddress::parse("test2+test+orsxg5a@example.org", '+').unwrap();
assert_ne!(addr_1, addr_2);
}
#[test]
fn cmp_coded_addr_without_domain_ne() {
let addr_1 = CodedAddress::from_str("test+test+orsxg5a").unwrap();
let addr_2 = CodedAddress::from_str("test2+test+orsxg5a").unwrap();
let addr_1 = CodedAddress::parse("test+test+orsxg5a", '+').unwrap();
let addr_2 = CodedAddress::parse("test2+test+orsxg5a", '+').unwrap();
assert_ne!(addr_1, addr_2);
}
@ -289,35 +299,35 @@ mod tests {
#[test]
fn cmp_addr_types_with_domain_eq() {
let addr_1 = KeyedAddress::from_str("test@example.org:3d74YQqk").unwrap();
let addr_2 = CodedAddress::from_str("test+test+orsxg5a@example.org").unwrap();
let addr_2 = CodedAddress::parse("test+test+orsxg5a@example.org", '+').unwrap();
assert_eq!(addr_1, addr_2);
}
#[test]
fn cmp_addr_types_without_domain_eq() {
let addr_1 = KeyedAddress::from_str("test:3d74YQqk").unwrap();
let addr_2 = CodedAddress::from_str("test+test+orsxg5a").unwrap();
let addr_2 = CodedAddress::parse("test+test+orsxg5a", '+').unwrap();
assert_eq!(addr_1, addr_2);
}
#[test]
fn cmp_addr_types_without_sub_addr() {
let addr_1 = KeyedAddress::from_str("test@example.org:3d74YQqk").unwrap();
let addr_2 = CodedAddress::from_str("test@example.org").unwrap();
let addr_2 = CodedAddress::parse("test@example.org", '+').unwrap();
assert_eq!(addr_1, addr_2);
}
#[test]
fn cmp_addr_types_with_domain_ne() {
let addr_1 = KeyedAddress::from_str("test@example.org:3d74YQqk").unwrap();
let addr_2 = CodedAddress::from_str("test+test+orsxg5a@example.com").unwrap();
let addr_2 = CodedAddress::parse("test+test+orsxg5a@example.com", '+').unwrap();
assert_ne!(addr_1, addr_2);
}
#[test]
fn cmp_addr_types_without_domain_ne() {
let addr_1 = KeyedAddress::from_str("test:3d74YQqk").unwrap();
let addr_2 = CodedAddress::from_str("test2+test+orsxg5a").unwrap();
let addr_2 = CodedAddress::parse("test2+test+orsxg5a", '+').unwrap();
assert_ne!(addr_1, addr_2);
}
}

View file

@ -37,4 +37,8 @@ impl Config {
}
Ok(addr_set)
}
pub fn get_separator(&self) -> char {
self.separator
}
}

View file

@ -1,6 +1,5 @@
use crate::address::CodedAddress;
use anyhow::{anyhow, ensure, Result};
use std::str::FromStr;
macro_rules! next_param {
($it: ident) => {
@ -25,7 +24,7 @@ impl Input {
}
}
pub fn parse_input(input: &str) -> Result<Input> {
pub fn parse_input(input: &str, separator: char) -> Result<Input> {
let mut params_it = input.split(crate::PARAM_SEPARATOR);
let stream = next_param!(params_it)?;
ensure!(stream == "filter", "{stream}: invalid stream");
@ -42,7 +41,7 @@ pub fn parse_input(input: &str) -> Result<Input> {
let token = next_param!(params_it)?.to_string();
ensure!(!token.is_empty(), "empty token");
let address = next_param!(params_it)?.trim_end();
let address = CodedAddress::from_str(address)?;
let address = CodedAddress::parse(address, separator)?;
Ok(Input {
session_id,
token,
@ -57,7 +56,7 @@ mod tests {
#[test]
fn test_valid_input() {
let input = "filter|0.5|1576146008.006099|smtp-in|rcpt-to|7641df9771b4ed00|1ef1c203cc576e5d|derp@example.com";
let res = parse_input(input);
let res = parse_input(input, '+');
assert!(res.is_ok());
let inp = res.unwrap();
assert_eq!(inp.session_id, "7641df9771b4ed00");
@ -66,83 +65,83 @@ mod tests {
#[test]
fn test_empty_input() {
assert!(parse_input("").is_err());
assert!(parse_input("", '+').is_err());
}
#[test]
fn test_empty_stream() {
let input = "|0.5|1576146008.006099|smtp-in|rcpt-to|7641df9771b4ed00|1ef1c203cc576e5d|derp@example.com";
assert!(parse_input(input).is_err());
assert!(parse_input(input, '+').is_err());
}
#[test]
fn test_invalid_stream() {
let input = "invalid|0.5|1576146008.006099|smtp-in|rcpt-to|7641df9771b4ed00|1ef1c203cc576e5d|derp@example.com";
assert!(parse_input(input).is_err());
assert!(parse_input(input, '+').is_err());
}
#[test]
fn test_empty_version() {
let input = "filter||1576146008.006099|smtp-in|rcpt-to|7641df9771b4ed00|1ef1c203cc576e5d|derp@example.com";
assert!(parse_input(input).is_err());
assert!(parse_input(input, '+').is_err());
}
#[test]
fn test_empty_timestamp() {
let input =
"filter|0.5||smtp-in|rcpt-to|7641df9771b4ed00|1ef1c203cc576e5d|derp@example.com";
assert!(parse_input(input).is_err());
assert!(parse_input(input, '+').is_err());
}
#[test]
fn test_empty_subsystem() {
let input = "filter|0.5|1576146008.006099||rcpt-to|7641df9771b4ed00|1ef1c203cc576e5d|derp@example.com";
assert!(parse_input(input).is_err());
assert!(parse_input(input, '+').is_err());
}
#[test]
fn test_invalid_subsystem() {
let input = "filter|0.5|1576146008.006099|invalid|rcpt-to|7641df9771b4ed00|1ef1c203cc576e5d|derp@example.com";
assert!(parse_input(input).is_err());
assert!(parse_input(input, '+').is_err());
}
#[test]
fn test_empty_phase() {
let input = "filter|0.5|1576146008.006099|smtp-in||7641df9771b4ed00|1ef1c203cc576e5d|derp@example.com";
assert!(parse_input(input).is_err());
assert!(parse_input(input, '+').is_err());
}
#[test]
fn test_invalid_phase() {
let input = "filter|0.5|1576146008.006099|smtp-in|invalid|7641df9771b4ed00|1ef1c203cc576e5d|derp@example.com";
assert!(parse_input(input).is_err());
assert!(parse_input(input, '+').is_err());
}
#[test]
fn test_empty_id() {
let input =
"filter|0.5|1576146008.006099|smtp-in|rcpt-to||1ef1c203cc576e5d|derp@example.com";
assert!(parse_input(input).is_err());
assert!(parse_input(input, '+').is_err());
}
#[test]
fn test_empty_token() {
let input =
"filter|0.5|1576146008.006099|smtp-in|rcpt-to|7641df9771b4ed00||derp@example.com";
assert!(parse_input(input).is_err());
assert!(parse_input(input, '+').is_err());
}
#[test]
fn test_empty_data() {
let input =
"filter|0.5|1576146008.006099|smtp-in|rcpt-to|7641df9771b4ed00|1ef1c203cc576e5d|";
assert!(parse_input(input).is_err());
assert!(parse_input(input, '+').is_err());
}
#[test]
fn test_missing_data() {
let input =
"filter|0.5|1576146008.006099|smtp-in|rcpt-to|7641df9771b4ed00|1ef1c203cc576e5d";
assert!(parse_input(input).is_err());
assert!(parse_input(input, '+').is_err());
}
}

View file

@ -35,7 +35,7 @@ pub fn start_service() -> Result<()> {
if buffer.is_empty() {
continue;
}
match parse_input(&buffer) {
match parse_input(&buffer, cfg.get_separator()) {
Ok(input) => {
if allow_email(&input, &addresses) {
input.answer(ANSWER_OK);
@ -71,7 +71,7 @@ mod tests {
fn run_test_with_addr(address: &str) -> bool {
// Preparing the input
let input_str = format!("filter|0.5|1576146008.006099|smtp-in|rcpt-to|7641df9771b4ed00|1ef1c203cc576e5d|{address}");
let input = parse_input(&input_str);
let input = parse_input(&input_str, '+');
assert!(input.is_ok());
let input = input.unwrap();