From 6001224339b44f2bc7f5b89b94c97718a9bd5d6f Mon Sep 17 00:00:00 2001 From: Ethan Henderson Date: Tue, 2 Aug 2022 02:17:11 +0100 Subject: [PATCH] Fix bug with line endings --- src/lib.rs | 48 ++++++++++++++++++++++++++++++++++++------------ src/line.rs | 4 ++++ 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2f0b355..7daea19 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,7 +35,7 @@ //! You can parse IRC messages using the provided `parse` function. //! //! ``` -//! let msg = "@id=123;name=rick :nick!user@host.tmi.twitch.tv PRIVMSG #rickastley :Never gonna give you up!"; +//! let msg = "@id=123;name=rick :nick!user@host.tmi.twitch.tv PRIVMSG #rickastley :Never gonna give you up!\r\n"; //! match ircparser::parse(msg) { //! Ok(mut x) => { //! let line = x.pop_front().unwrap(); @@ -81,6 +81,7 @@ impl ParseError { /// /// assert_eq!(e.details, "err".to_string()) /// ``` + /// pub fn new(details: &str) -> Self { Self { details: details.into(), @@ -112,11 +113,12 @@ fn find_index(text: &str, char: char, start: usize) -> Option { /// will be a separate element in the return value. /// /// # Returns -/// - [`VecDeque`] - A [`VecDeque`] of all parsed [`Line`]s. +/// - [`VecDeque`] - A [`VecDeque`] of all parsed [`Line`]s. This +/// will be empty if no valid lines were passed and no errors occur. /// /// # Example /// ``` -/// let msg = "@id=123;name=rick :nick!user@host.tmi.twitch.tv PRIVMSG #rickastley :Never gonna give you up!"; +/// let msg = "@id=123;name=rick :nick!user@host.tmi.twitch.tv PRIVMSG #rickastley :Never gonna give you up!\r\n"; /// /// match ircparser::parse(msg) { /// Ok(mut x) => { @@ -141,12 +143,16 @@ fn find_index(text: &str, char: char, start: usize) -> Option { /// The behaviour of this function changed in v0.2.0. It can now accept /// multiple lines at once, but as a consequence, now returns a /// [`VecDeque`] of [`Line`] objects instead of a single [`Line`]. +/// pub fn parse(text: &str) -> ParseResult> { let mut parsed_lines: VecDeque = VecDeque::new(); - for line in text.replace('\r', "").split('\n') { + for line in text.split("\r\n") { if line.is_empty() { - return Err(ParseError::new("line length cannot be 0")); + // If the line length is 0, we can assume the previous line + // ended in \r\n, and that this line doesn't need to be + // processed. + continue; } let mut idx = 0; @@ -202,9 +208,11 @@ mod test_lib { #[test] fn test_single_partial() { - let msg = "PRIVMSG #rickastley :Never gonna give you up!"; + let msg = "PRIVMSG #rickastley :Never gonna give you up!\r\n"; + match parse(msg) { Ok(mut x) => { + assert_eq!(x.len(), 1); let line = x.pop_front().unwrap(); assert_eq!(line.tags, HashMap::new()); @@ -214,16 +222,17 @@ mod test_lib { } Err(e) => { println!("A parsing error occured: {e}"); - return; + assert!(false); } } } #[test] fn test_single_full() { - let msg = "@id=123;name=rick :nick!user@host.tmi.twitch.tv PRIVMSG #rickastley :Never gonna give you up!"; + let msg = "@id=123;name=rick :nick!user@host.tmi.twitch.tv PRIVMSG #rickastley :Never gonna give you up!\r\n"; match parse(msg) { Ok(mut x) => { + assert_eq!(x.len(), 1); let line = x.pop_front().unwrap(); assert_eq!( @@ -249,9 +258,11 @@ mod test_lib { #[test] fn test_readme_example() { - let msg = "@id=123;name=rick :nick!user@host.tmi.twitch.tv PRIVMSG #rickastley :Never gonna give you up!"; + let msg = "@id=123;name=rick :nick!user@host.tmi.twitch.tv PRIVMSG #rickastley :Never gonna give you up!\r\n"; match parse(msg) { Ok(mut x) => { + println!("{x:?}"); + assert_eq!(x.len(), 1); let line = x.pop_front().unwrap(); assert_eq!(&line.tags["id"], "123"); @@ -264,14 +275,27 @@ mod test_lib { } Err(e) => { println!("A parsing error occured: {e}"); - return; + assert!(false); + } + }; + } + + #[test] + fn test_empty() { + match parse("") { + Ok(x) => { + assert_eq!(x.len(), 0); + } + Err(e) => { + println!("A parsing error occured: {e}"); + assert!(false); } }; } #[test] fn test_multiline() { - let msg = "@id=123 PRIVMSG #rickastley :Never gonna give you up!\n@id=456 PRIVMSG #rickastley :Never gonna let you down!"; + let msg = "@id=123 PRIVMSG #rickastley :Never gonna give you up!\r\n@id=456 PRIVMSG #rickastley :Never gonna let you down!\r\n"; match parse(msg) { Ok(mut x) => { assert_eq!(x.len(), 2); @@ -287,7 +311,7 @@ mod test_lib { } Err(e) => { println!("A parsing error occured: {e}"); - return; + assert!(false); } } } diff --git a/src/line.rs b/src/line.rs index 7e102a7..41be2cd 100644 --- a/src/line.rs +++ b/src/line.rs @@ -36,11 +36,14 @@ pub struct Line { /// This line's tags. This will be an empty hashmap if there are /// none. pub tags: HashMap, + /// This line's source (including the nick, user, and host). This is /// optional, and will be [`None`] if not provided. pub source: Option, + /// This line's command. pub command: String, + /// Any parameters passed to the command. This will be an empty /// vector if there are none. pub params: Vec, @@ -78,6 +81,7 @@ impl Line { /// assert_eq!(line.command, "PRIVMSG"); /// assert_eq!(line.params[0], "#rickastley"); /// ``` + /// pub fn new( tags: HashMap, source: Option,