From 62eeb9d627d03f1d38c41f78dfe30f2dcb78a7d5 Mon Sep 17 00:00:00 2001 From: Nathan Fisher Date: Mon, 22 May 2023 01:29:03 -0400 Subject: [PATCH] Add Response struct and tests --- src/lib.rs | 15 +------- src/response.rs | 96 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 14 deletions(-) create mode 100644 src/response.rs diff --git a/src/lib.rs b/src/lib.rs index 84c439a..8280fc7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,16 +1,3 @@ +pub mod response; pub mod status; -pub fn add(left: usize, right: usize) -> usize { - left + right -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); - } -} diff --git a/src/response.rs b/src/response.rs new file mode 100644 index 0000000..a4bd42f --- /dev/null +++ b/src/response.rs @@ -0,0 +1,96 @@ +use std::{fmt, str::FromStr, num::ParseIntError}; + +use crate::status::{Status, StatusError}; + +#[derive(Clone, Debug, PartialEq)] +pub struct Response { + pub status: Status, + pub meta: String, +} + +impl fmt::Display for Response { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{} {}\r\n", u8::from(self.status.clone()), self.meta) + } +} + +#[derive(Clone, Debug, PartialEq)] +pub enum ParseResponseError { + TooLong, + ParseInt(ParseIntError), + StatusError, + Malformed, +} + +impl fmt::Display for ParseResponseError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::TooLong => write!(f, "ParseResponseError: too long"), + Self::ParseInt(e) => write!(f, "ParseResponseError: {e}"), + Self::StatusError => write!(f, "ParseResponseError: Invalid Status"), + Self::Malformed => write!(f, "ParseResponseError: Malformed"), + } + } +} + +impl std::error::Error for ParseResponseError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Self::ParseInt(e) => Some(e), + _ => None, + } + } +} + +impl From for ParseResponseError { + fn from(value: ParseIntError) -> Self { + Self::ParseInt(value) + } +} + +impl From for ParseResponseError { + fn from(_value: StatusError) -> Self { + Self::StatusError + } +} + +impl FromStr for Response { + type Err = ParseResponseError; + + fn from_str(s: &str) -> Result { + if s.len() > 2048 { + return Err(ParseResponseError::TooLong); + } + if !s.ends_with("\r\n") { + return Err(ParseResponseError::Malformed); + } + let Some((status, meta)) = s.split_once(' ') else { + return Err(ParseResponseError::Malformed); + }; + let status: u8 = status.parse()?; + let status: Status = status.try_into()?; + Ok(Self { + status, + meta: meta.trim_end().to_string(), + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parse_success() { + let response: Response = "20 message delivered\r\n".parse().unwrap(); + assert_eq!(response.status, Status::Success); + assert_eq!(response.meta.as_str(), "message delivered"); + } + + #[test] + fn parse_badend() { + let response = "20 message delivered\n".parse::(); + assert_eq!(response, Err(ParseResponseError::Malformed)); + } +} +