diff --git a/Cargo.lock b/Cargo.lock index d5d4e5f..9b448df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -182,6 +182,12 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + [[package]] name = "libc" version = "0.2.158" @@ -270,6 +276,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + [[package]] name = "serde" version = "1.0.210" @@ -290,6 +302,18 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + [[package]] name = "strsim" version = "0.11.1" @@ -353,6 +377,7 @@ dependencies = [ "assert_cmd", "clap", "hex", + "serde_json", "tempfile", "thiserror", ] diff --git a/Cargo.toml b/Cargo.toml index 6fa6f0f..d3783c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] clap = { version = "4.5.17", features = ["derive"] } hex = "0.4" +serde_json = "1.0.128" thiserror = "1.0.64" [dev-dependencies] diff --git a/project-words.txt b/project-words.txt index 9c285ac..dd94996 100644 --- a/project-words.txt +++ b/project-words.txt @@ -13,6 +13,7 @@ fooe fooi llee llleee +ñandú spame spamee tempdir diff --git a/src/parsers/mod.rs b/src/parsers/mod.rs index a81edf6..8ab6ed6 100644 --- a/src/parsers/mod.rs +++ b/src/parsers/mod.rs @@ -411,10 +411,31 @@ mod tests { assert_eq!(to_json(b"1:9"), r#""9""#.to_string()); } - /* todo: - - String containing special chars like : `"`, `\`, '\\' - - String containing JSON - */ + mod should_escape_json { + use crate::parsers::tests::{to_bencode, to_json}; + + #[test] + fn containing_a_double_quote() { + assert_eq!(to_json("1:\"".as_bytes()), r#""\"""#.to_string()); + } + + #[test] + fn containing_backslashes() { + assert_eq!(to_json("1:\\".as_bytes()), r#""\\""#.to_string()); + } + + #[test] + fn containing_control_characters() { + assert_eq!(to_json("1:\n".as_bytes()), r#""\n""#.to_string()); + assert_eq!(to_json("1:\r".as_bytes()), r#""\r""#.to_string()); + assert_eq!(to_json("1:\t".as_bytes()), r#""\t""#.to_string()); + } + + #[test] + fn containing_unicode_characters() { + assert_eq!(to_json(&to_bencode("ñandú")), r#""ñandú""#.to_string()); + } + } mod it_should_fail_parsing_when { use crate::parsers::{error::Error, tests::parse}; @@ -735,6 +756,12 @@ mod tests { output } + /// Helper to convert a string into a bencoded string. + fn to_bencode(value: &str) -> Vec { + let bencoded_str = format!("{}:{}", value.len(), value); + bencoded_str.as_bytes().to_vec() + } + /// Wrapper to easily use the parser in tests fn parse(input_buffer: &[u8]) -> Result { let mut output = String::new(); diff --git a/src/parsers/string.rs b/src/parsers/string.rs index d6c263d..17c587c 100644 --- a/src/parsers/string.rs +++ b/src/parsers/string.rs @@ -75,11 +75,10 @@ impl StringParser { self.parsed_value.clone() } - /// It adds the double quotes to the string it's the JSON delimiter for - /// string values. + /// It serializes the parsed value into JSON. #[must_use] fn json(&self) -> String { - format!("\"{}\"", self.parsed_value()) + serde_json::to_string(&self.parsed_value()).unwrap() } } @@ -184,11 +183,7 @@ impl Value { fn parse(&mut self, reader: &mut ByteReader) -> Result<(), Error> { for _i in 1..=self.length { - let byte = Self::next_byte(reader)?; - - self.add_byte(byte); - - // todo: escape '"' and '\\' with '\\'; + self.add_byte(Self::next_byte(reader)?); } Ok(())