hoodie / icalendar-rs

📆 icalendar library, in Rust of course - for fun
Apache License 2.0
126 stars 34 forks source link

Inconsistent newline encoding & decoding? #87

Open d-e-s-o opened 10 months ago

d-e-s-o commented 10 months ago

I am not sure if the following is expected behavior:

--- tests/reserialize.rs
+++ tests/reserialize.rs
@@ -1,5 +1,8 @@
 #![cfg(feature = "parser")]
-use icalendar::parser::unfold;
+
+use std::str::FromStr as _;
+
+use icalendar::{parser::unfold, Calendar, CalendarComponent, Component, Todo};
 use pretty_assertions::assert_eq;

 const SAMPLE: &str = "\
@@ -50,3 +53,21 @@ fn reserialization() {
     println!("{}", reserialized);
     assert_eq!(SAMPLE, reserialized);
 }
+
+#[test]
+fn reserialization_multi_line_description() {
+    let desc = "multi-\nline\ndescription";
+    let mut todo = Todo::new();
+    todo.summary("summary");
+    todo.description(desc);
+    let calendar = Calendar::from([todo]);
+
+    let serialized = calendar.to_string();
+    let deserialized = Calendar::from_str(&serialized).unwrap();
+    let deserialized_todo = match deserialized.components.as_slice() {
+      [CalendarComponent::Todo(todo)] => todo,
+      _ => unreachable!(),
+    };
+    let deserialized_desc = deserialized_todo.get_description().unwrap();
+    assert_eq!(deserialized_desc, desc);
+}

This test fails:

running 1 test
thread 'reserialization_multi_line_description' panicked at tests/reserialize.rs:72:5:
assertion failed: `(left == right)`

Diff < left / right > :
<multi-\nline\ndescription
>multi-
>line
>description

note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
test reserialization_multi_line_description ... FAILED

It seems as if newlines are encoded to \\n (correct) but then never decoded back to \n in this scenario. I'd expect that at the level of a Todo object, I as the user shouldn't have to deal with such encoding matters -- it should all happen transparently. So I am wondering: Is this behavior intended?

d-e-s-o commented 10 months ago

The following patch seems to fix the test:

--- src/parser/utils.rs
+++ src/parser/utils.rs
@@ -81,6 +81,7 @@ pub fn line_separated<'a, O, E: ParseError<&'a str>, F: Parser<&'a str, O, E>>(
 /// ```
 pub fn unfold(input: &str) -> String {
     input
+        .replace("\\n", "\n")
         .split("\r\n ")
         .flat_map(|l| l.split("\n "))
         .flat_map(|l| l.split("\r\n "))

though I am not convinced that it is doing truly the correct thing at the right point in time (one indication being that it causes the folding_consistency test to fail).