From 236a3a213e518378ac4bb312eff3e5d65f6ea184 Mon Sep 17 00:00:00 2001 From: Josh Klar Date: Wed, 1 Mar 2017 23:19:22 -0600 Subject: [PATCH 1/6] Convert LineParsed.value to Option to allow empty descriptions (Google Calendar) --- Cargo.toml | 2 +- src/line/parser.rs | 14 ++++-- src/parser/ical/mod.rs | 2 +- src/parser/mod.rs | 6 ++- src/parser/vcard/mod.rs | 2 +- tests/ressources/ical_input.ics | 13 ++++- tests/ressources/ical_line_parser.res | 68 +++++++++++++++----------- tests/ressources/ical_line_reader.res | 13 ++++- tests/ressources/vcard_line_parser.res | 68 +++++++++++++------------- 9 files changed, 115 insertions(+), 73 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 99268996..cd19f3db 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ical" -version = "0.2.1" +version = "0.3.0" authors = ["Peltoche "] description = "Ical/Vcard parser for Rust" diff --git a/src/line/parser.rs b/src/line/parser.rs index 289c6a6d..c04dd095 100644 --- a/src/line/parser.rs +++ b/src/line/parser.rs @@ -17,7 +17,7 @@ use line::reader::{LineReader, Line}; pub struct LineParsed { pub name: String, pub params: Option)>>, - pub value: String, + pub value: Option, } impl LineParsed { @@ -25,7 +25,7 @@ impl LineParsed { LineParsed { name: String::new(), params: None, - value: String::new(), + value: None, } } } @@ -33,7 +33,7 @@ impl LineParsed { impl fmt::Display for LineParsed { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, - "name: {}\nparams: {:?}\nvalue: {}", + "name: {}\nparams: {:?}\nvalue: {:?}", self.name, self.params, self.value) @@ -68,8 +68,12 @@ impl LineParser { // Parse value property.value = self.parse_value(line.as_str()) - .and_then(|value| Some(value.to_string())) - .ok_or(ParseError::MissingValue)?; + .and_then(|value| { + match value.len() { + 0 => None, + _ => Some(value.to_string()) + } + }); // Parse parameters. property.params = self.parse_parameters(line.as_str())?; diff --git a/src/parser/ical/mod.rs b/src/parser/ical/mod.rs index 6818b63a..1db989a3 100644 --- a/src/parser/ical/mod.rs +++ b/src/parser/ical/mod.rs @@ -28,7 +28,7 @@ impl IcalParser { None => return Ok(None), }; - if line.name != "BEGIN" || line.value != "VCALENDAR" || line.params != None { + if line.name != "BEGIN" || line.value.is_none() || line.value.unwrap() != "VCALENDAR" || line.params != None { return Err(ParseError::MissingHeader); } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 76ad860e..f2197190 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -32,7 +32,11 @@ pub trait Component { match line.name.as_str() { "END" => break, - "BEGIN" => self.add_sub_component(line.value.as_str(), line_parser)?, + "BEGIN" => match line.value { + Some(v) => self.add_sub_component(v.as_str(), line_parser)?, + None => self.add_sub_component("", line_parser)?, + }, + _ => self.add_property(line), }; } diff --git a/src/parser/vcard/mod.rs b/src/parser/vcard/mod.rs index b6efd11c..25466ba3 100644 --- a/src/parser/vcard/mod.rs +++ b/src/parser/vcard/mod.rs @@ -27,7 +27,7 @@ impl VcardParser { None => return Ok(None), }; - if line.name != "BEGIN" || line.value != "VCARD" || line.params != None { + if line.name != "BEGIN" || line.value.is_none() || line.value.unwrap() != "VCARD" || line.params != None { return Err(ParseError::MissingHeader); } diff --git a/tests/ressources/ical_input.ics b/tests/ressources/ical_input.ics index cacbc2ce..9dd3a83b 100644 --- a/tests/ressources/ical_input.ics +++ b/tests/ressources/ical_input.ics @@ -35,4 +35,15 @@ X-BAZ2;PARAM1=VAL1;PARAM2="VAL2:FOO":BAZ;BAR END:VCALENDAR - +BEGIN:VCALENDAR +CALSCALE:GREGORIAN +PRODID:-//Example Inc.//Example Calendar//EN +VERSION:2.0 +BEGIN:VEVENT +DTSTAMP:20080205T191224Z +DTSTART;VALUE=DATE:20081006 +SUMMARY:Missing description value, but includes header +DESCRIPTION: +UID:4088E990AD89CB3DBB484909 +END:VEVENT +END:VCALENDAR diff --git a/tests/ressources/ical_line_parser.res b/tests/ressources/ical_line_parser.res index 87296517..5a03f870 100644 --- a/tests/ressources/ical_line_parser.res +++ b/tests/ressources/ical_line_parser.res @@ -1,28 +1,40 @@ -Ok(LineParsed { name: "BEGIN", params: None, value: "VCALENDAR" }) -Ok(LineParsed { name: "CALSCALE", params: None, value: "GREGORIAN" }) -Ok(LineParsed { name: "PRODID", params: None, value: "-//Example Inc.//Example Calendar//EN" }) -Ok(LineParsed { name: "VERSION", params: None, value: "2.0" }) -Ok(LineParsed { name: "BEGIN", params: None, value: "VEVENT" }) -Ok(LineParsed { name: "DTSTAMP", params: None, value: "20080205T191224Z" }) -Ok(LineParsed { name: "DTSTART", params: Some([("VALUE", ["DATE"])]), value: "20081006" }) -Ok(LineParsed { name: "SUMMARY", params: None, value: "Planning meeting" }) -Ok(LineParsed { name: "UID", params: None, value: "4088E990AD89CB3DBB484909" }) -Ok(LineParsed { name: "BEGIN", params: None, value: "VALARM" }) -Ok(LineParsed { name: "SUMMARY", params: None, value: "escaped\\, comma and\\; semicolon\\nnewline" }) -Ok(LineParsed { name: "END", params: None, value: "VALARM" }) -Ok(LineParsed { name: "END", params: None, value: "VEVENT" }) -Ok(LineParsed { name: "END", params: None, value: "VCALENDAR" }) -Ok(LineParsed { name: "BEGIN", params: None, value: "VCALENDAR" }) -Ok(LineParsed { name: "ATTENDEE", params: Some([("DELEGATED-TO", ["mailto:foo7@bar", "mailto:foo8@bar"]), ("CN", ["Foo, Bar"])]), value: "foo7@bar\",\"mailto:foo8@bar\";CN=\"Foo, Bar\":mailto:foo1@bar" }) -Ok(LineParsed { name: "ATTENDEE", params: Some([("DELEGATED-TO", ["mailto:foo7@bar", "mailto:foo8@bar"]), ("CN", ["Foo; Bar"])]), value: "foo7@bar\",\"mailto:foo8@bar\";CN=\"Foo; Bar\":mailto:foo2@bar" }) -Ok(LineParsed { name: "ATTENDEE", params: Some([("CN", ["Foo, Bar"])]), value: "mailto:foo3@bar" }) -Ok(LineParsed { name: "ATTENDEE", params: Some([("CN", ["Foo; Bar"])]), value: "mailto:foo4@bar" }) -Ok(LineParsed { name: "ATTENDEE", params: Some([("DELEGATED-TO", ["mailto:foo7@bar"]), ("CN", ["Foo, Bar"])]), value: "foo7@bar\";CN=\"Foo, Bar\":mailto:foo5@bar" }) -Ok(LineParsed { name: "ATTENDEE", params: Some([("DELEGATED-TO", ["mailto:foo7@bar"]), ("CN", ["Foo; Bar"])]), value: "foo7@bar\";CN=\"Foo; Bar\":mailto:foo6@bar" }) -Ok(LineParsed { name: "ATTENDEE", params: Some([("ROLE", ["REQ-PARTICIPANT;foo"]), ("DELEGATED-FROM", ["mailto:bar@baz.com"]), ("PARTSTAT", ["ACCEPTED"]), ("RSVP", ["TRUE"])]), value: "bar@baz.com\";PARTSTAT=ACCEPTED;RSVP=TRUE:mailto:foo@bar.com" }) -Ok(LineParsed { name: "X-FOO", params: Some([("PARAM1", ["VAL1"])]), value: "FOO;BAR" }) -Ok(LineParsed { name: "X-FOO2", params: Some([("PARAM1", ["VAL1"]), ("PARAM2", ["VAL2"])]), value: "FOO;BAR" }) -Ok(LineParsed { name: "X-BAR", params: Some([("PARAM1", ["VAL1:FOO"])]), value: "FOO\":BAZ;BAR" }) -Ok(LineParsed { name: "X-BAZ", params: Some([("PARAM1", ["VAL1:FOO"]), ("PARAM2", ["VAL2"])]), value: "FOO\";PARAM2=VAL2:BAZ;BAR" }) -Ok(LineParsed { name: "X-BAZ2", params: Some([("PARAM1", ["VAL1"]), ("PARAM2", ["VAL2:FOO"])]), value: "FOO\":BAZ;BAR" }) -Ok(LineParsed { name: "END", params: None, value: "VCALENDAR" }) +Ok(LineParsed { name: "BEGIN", params: None, value: Some("VCALENDAR") }) +Ok(LineParsed { name: "CALSCALE", params: None, value: Some("GREGORIAN") }) +Ok(LineParsed { name: "PRODID", params: None, value: Some("-//Example Inc.//Example Calendar//EN") }) +Ok(LineParsed { name: "VERSION", params: None, value: Some("2.0") }) +Ok(LineParsed { name: "BEGIN", params: None, value: Some("VEVENT") }) +Ok(LineParsed { name: "DTSTAMP", params: None, value: Some("20080205T191224Z") }) +Ok(LineParsed { name: "DTSTART", params: Some([("VALUE", ["DATE"])]), value: Some("20081006") }) +Ok(LineParsed { name: "SUMMARY", params: None, value: Some("Planning meeting") }) +Ok(LineParsed { name: "UID", params: None, value: Some("4088E990AD89CB3DBB484909") }) +Ok(LineParsed { name: "BEGIN", params: None, value: Some("VALARM") }) +Ok(LineParsed { name: "SUMMARY", params: None, value: Some("escaped\\, comma and\\; semicolon\\nnewline") }) +Ok(LineParsed { name: "END", params: None, value: Some("VALARM") }) +Ok(LineParsed { name: "END", params: None, value: Some("VEVENT") }) +Ok(LineParsed { name: "END", params: None, value: Some("VCALENDAR") }) +Ok(LineParsed { name: "BEGIN", params: None, value: Some("VCALENDAR") }) +Ok(LineParsed { name: "ATTENDEE", params: Some([("DELEGATED-TO", ["mailto:foo7@bar", "mailto:foo8@bar"]), ("CN", ["Foo, Bar"])]), value: Some("foo7@bar\",\"mailto:foo8@bar\";CN=\"Foo, Bar\":mailto:foo1@bar") }) +Ok(LineParsed { name: "ATTENDEE", params: Some([("DELEGATED-TO", ["mailto:foo7@bar", "mailto:foo8@bar"]), ("CN", ["Foo; Bar"])]), value: Some("foo7@bar\",\"mailto:foo8@bar\";CN=\"Foo; Bar\":mailto:foo2@bar") }) +Ok(LineParsed { name: "ATTENDEE", params: Some([("CN", ["Foo, Bar"])]), value: Some("mailto:foo3@bar") }) +Ok(LineParsed { name: "ATTENDEE", params: Some([("CN", ["Foo; Bar"])]), value: Some("mailto:foo4@bar") }) +Ok(LineParsed { name: "ATTENDEE", params: Some([("DELEGATED-TO", ["mailto:foo7@bar"]), ("CN", ["Foo, Bar"])]), value: Some("foo7@bar\";CN=\"Foo, Bar\":mailto:foo5@bar") }) +Ok(LineParsed { name: "ATTENDEE", params: Some([("DELEGATED-TO", ["mailto:foo7@bar"]), ("CN", ["Foo; Bar"])]), value: Some("foo7@bar\";CN=\"Foo; Bar\":mailto:foo6@bar") }) +Ok(LineParsed { name: "ATTENDEE", params: Some([("ROLE", ["REQ-PARTICIPANT;foo"]), ("DELEGATED-FROM", ["mailto:bar@baz.com"]), ("PARTSTAT", ["ACCEPTED"]), ("RSVP", ["TRUE"])]), value: Some("bar@baz.com\";PARTSTAT=ACCEPTED;RSVP=TRUE:mailto:foo@bar.com") }) +Ok(LineParsed { name: "X-FOO", params: Some([("PARAM1", ["VAL1"])]), value: Some("FOO;BAR") }) +Ok(LineParsed { name: "X-FOO2", params: Some([("PARAM1", ["VAL1"]), ("PARAM2", ["VAL2"])]), value: Some("FOO;BAR") }) +Ok(LineParsed { name: "X-BAR", params: Some([("PARAM1", ["VAL1:FOO"])]), value: Some("FOO\":BAZ;BAR") }) +Ok(LineParsed { name: "X-BAZ", params: Some([("PARAM1", ["VAL1:FOO"]), ("PARAM2", ["VAL2"])]), value: Some("FOO\";PARAM2=VAL2:BAZ;BAR") }) +Ok(LineParsed { name: "X-BAZ2", params: Some([("PARAM1", ["VAL1"]), ("PARAM2", ["VAL2:FOO"])]), value: Some("FOO\":BAZ;BAR") }) +Ok(LineParsed { name: "END", params: None, value: Some("VCALENDAR") }) +Ok(LineParsed { name: "BEGIN", params: None, value: Some("VCALENDAR") }) +Ok(LineParsed { name: "CALSCALE", params: None, value: Some("GREGORIAN") }) +Ok(LineParsed { name: "PRODID", params: None, value: Some("-//Example Inc.//Example Calendar//EN") }) +Ok(LineParsed { name: "VERSION", params: None, value: Some("2.0") }) +Ok(LineParsed { name: "BEGIN", params: None, value: Some("VEVENT") }) +Ok(LineParsed { name: "DTSTAMP", params: None, value: Some("20080205T191224Z") }) +Ok(LineParsed { name: "DTSTART", params: Some([("VALUE", ["DATE"])]), value: Some("20081006") }) +Ok(LineParsed { name: "SUMMARY", params: None, value: Some("Missing description value, but includes header") }) +Ok(LineParsed { name: "DESCRIPTION", params: None, value: None }) +Ok(LineParsed { name: "UID", params: None, value: Some("4088E990AD89CB3DBB484909") }) +Ok(LineParsed { name: "END", params: None, value: Some("VEVENT") }) +Ok(LineParsed { name: "END", params: None, value: Some("VCALENDAR") }) diff --git a/tests/ressources/ical_line_reader.res b/tests/ressources/ical_line_reader.res index 968e3ae1..9f1d743e 100644 --- a/tests/ressources/ical_line_reader.res +++ b/tests/ressources/ical_line_reader.res @@ -26,4 +26,15 @@ Line { inner: "X-BAR;PARAM1=\"VAL1:FOO\":BAZ;BAR", number: 32 } Line { inner: "X-BAZ;PARAM1=\"VAL1:FOO\";PARAM2=VAL2:BAZ;BAR", number: 33 } Line { inner: "X-BAZ2;PARAM1=VAL1;PARAM2=\"VAL2:FOO\":BAZ;BAR", number: 34 } Line { inner: "END:VCALENDAR", number: 35 } - +Line { inner: "BEGIN:VCALENDAR", number: 38 } +Line { inner: "CALSCALE:GREGORIAN", number: 39 } +Line { inner: "PRODID:-//Example Inc.//Example Calendar//EN", number: 40 } +Line { inner: "VERSION:2.0", number: 41 } +Line { inner: "BEGIN:VEVENT", number: 42 } +Line { inner: "DTSTAMP:20080205T191224Z", number: 43 } +Line { inner: "DTSTART;VALUE=DATE:20081006", number: 44 } +Line { inner: "SUMMARY:Missing description value, but includes header", number: 45 } +Line { inner: "DESCRIPTION:", number: 46 } +Line { inner: "UID:4088E990AD89CB3DBB484909", number: 47 } +Line { inner: "END:VEVENT", number: 48 } +Line { inner: "END:VCALENDAR", number: 49 } diff --git a/tests/ressources/vcard_line_parser.res b/tests/ressources/vcard_line_parser.res index 90569a22..cbbe44f5 100644 --- a/tests/ressources/vcard_line_parser.res +++ b/tests/ressources/vcard_line_parser.res @@ -1,34 +1,34 @@ -Ok(LineParsed { name: "BEGIN", params: None, value: "VCARD" }) -Ok(LineParsed { name: "VERSION", params: None, value: "4.0" }) -Ok(LineParsed { name: "ADR", params: Some([("TYPE", ["work"])]), value: "pobox;apt;street;city;state;zipcode;country" }) -Ok(LineParsed { name: "ANNIVERSARY", params: None, value: "19960415" }) -Ok(LineParsed { name: "BDAY", params: None, value: "--0203" }) -Ok(LineParsed { name: "CALADRURI", params: None, value: "http://example.com/calendar/jdoe" }) -Ok(LineParsed { name: "CALURI", params: Some([("MEDIATYPE", ["text/calendar"])]), value: "ftp://ftp.example.com/calA.ics" }) -Ok(LineParsed { name: "CLIENTPIDMAP", params: None, value: "1;urn:uuid:3df403f4-5924-4bb7-b077-3c711d9eb34b" }) -Ok(LineParsed { name: "EMAIL", params: Some([("TYPE", ["work"])]), value: "jqpublic@xyz.example.com" }) -Ok(LineParsed { name: "FBURL", params: Some([("MEDIATYPE", ["text/calendar"])]), value: "ftp://example.com/busy/project-a.ifb" }) -Ok(LineParsed { name: "FN", params: None, value: "J. Doe" }) -Ok(LineParsed { name: "GENDER", params: None, value: "M;Fellow" }) -Ok(LineParsed { name: "GEO", params: None, value: "geo:37.386013\\,-122.082932" }) -Ok(LineParsed { name: "IMPP", params: Some([("PREF", ["1"])]), value: "xmpp:alice@example.com" }) -Ok(LineParsed { name: "KEY", params: None, value: "http://www.example.com/keys/jdoe.cer" }) -Ok(LineParsed { name: "KIND", params: None, value: "individual" }) -Ok(LineParsed { name: "LANG", params: Some([("PREF", ["1"])]), value: "fr" }) -Ok(LineParsed { name: "LOGO", params: None, value: "http://www.example.com/pub/logos/abccorp.jpg" }) -Ok(LineParsed { name: "MEMBER", params: None, value: "urn:uuid:03a0e51f-d1aa-4385-8a53-e29025acd8af" }) -Ok(LineParsed { name: "N", params: None, value: "Stevenson;John;Philip,Paul;Dr.;Jr.,M.D.,A.C.P." }) -Ok(LineParsed { name: "NICKNAME", params: Some([("TYPE", ["work"])]), value: "Boss" }) -Ok(LineParsed { name: "NOTE", params: None, value: "This fax number is operational 0800 to 1715 EST\\, Mon-Fri" }) -Ok(LineParsed { name: "ORG", params: None, value: "ABC\\, Inc.;North American Division;Marketing" }) -Ok(LineParsed { name: "PHOTO", params: None, value: "http://www.example.com/pub/photos/jqpublic.gif" }) -Ok(LineParsed { name: "RELATED", params: Some([("TYPE", ["friend"])]), value: "urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6" }) -Ok(LineParsed { name: "REV", params: None, value: "19951031T222710Z" }) -Ok(LineParsed { name: "ROLE", params: None, value: "Project Leader" }) -Ok(LineParsed { name: "SOUND", params: None, value: "CID:JOHNQPUBLIC.part8.19960229T080000.xyzMail@example.com" }) -Ok(LineParsed { name: "SOURCE", params: None, value: "ldap://ldap.example.com/cn=Babs%20Jensen\\,%20o=Babsco\\,%20c=US" }) -Ok(LineParsed { name: "TEL", params: Some([("VALUE", ["uri"]), ("TYPE", ["home"])]), value: "tel:+33-01-23-45-67" }) -Ok(LineParsed { name: "TITLE", params: None, value: "Research Scientist" }) -Ok(LineParsed { name: "TZ", params: Some([("VALUE", ["utc-offset"])]), value: "-0500" }) -Ok(LineParsed { name: "XML", params: None, value: "" }) -Ok(LineParsed { name: "END", params: None, value: "VCARD" }) +Ok(LineParsed { name: "BEGIN", params: None, value: Some("VCARD") }) +Ok(LineParsed { name: "VERSION", params: None, value: Some("4.0") }) +Ok(LineParsed { name: "ADR", params: Some([("TYPE", ["work"])]), value: Some("pobox;apt;street;city;state;zipcode;country") }) +Ok(LineParsed { name: "ANNIVERSARY", params: None, value: Some("19960415") }) +Ok(LineParsed { name: "BDAY", params: None, value: Some("--0203") }) +Ok(LineParsed { name: "CALADRURI", params: None, value: Some("http://example.com/calendar/jdoe") }) +Ok(LineParsed { name: "CALURI", params: Some([("MEDIATYPE", ["text/calendar"])]), value: Some("ftp://ftp.example.com/calA.ics") }) +Ok(LineParsed { name: "CLIENTPIDMAP", params: None, value: Some("1;urn:uuid:3df403f4-5924-4bb7-b077-3c711d9eb34b") }) +Ok(LineParsed { name: "EMAIL", params: Some([("TYPE", ["work"])]), value: Some("jqpublic@xyz.example.com") }) +Ok(LineParsed { name: "FBURL", params: Some([("MEDIATYPE", ["text/calendar"])]), value: Some("ftp://example.com/busy/project-a.ifb") }) +Ok(LineParsed { name: "FN", params: None, value: Some("J. Doe") }) +Ok(LineParsed { name: "GENDER", params: None, value: Some("M;Fellow") }) +Ok(LineParsed { name: "GEO", params: None, value: Some("geo:37.386013\\,-122.082932") }) +Ok(LineParsed { name: "IMPP", params: Some([("PREF", ["1"])]), value: Some("xmpp:alice@example.com") }) +Ok(LineParsed { name: "KEY", params: None, value: Some("http://www.example.com/keys/jdoe.cer") }) +Ok(LineParsed { name: "KIND", params: None, value: Some("individual") }) +Ok(LineParsed { name: "LANG", params: Some([("PREF", ["1"])]), value: Some("fr") }) +Ok(LineParsed { name: "LOGO", params: None, value: Some("http://www.example.com/pub/logos/abccorp.jpg") }) +Ok(LineParsed { name: "MEMBER", params: None, value: Some("urn:uuid:03a0e51f-d1aa-4385-8a53-e29025acd8af") }) +Ok(LineParsed { name: "N", params: None, value: Some("Stevenson;John;Philip,Paul;Dr.;Jr.,M.D.,A.C.P.") }) +Ok(LineParsed { name: "NICKNAME", params: Some([("TYPE", ["work"])]), value: Some("Boss") }) +Ok(LineParsed { name: "NOTE", params: None, value: Some("This fax number is operational 0800 to 1715 EST\\, Mon-Fri") }) +Ok(LineParsed { name: "ORG", params: None, value: Some("ABC\\, Inc.;North American Division;Marketing") }) +Ok(LineParsed { name: "PHOTO", params: None, value: Some("http://www.example.com/pub/photos/jqpublic.gif") }) +Ok(LineParsed { name: "RELATED", params: Some([("TYPE", ["friend"])]), value: Some("urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6") }) +Ok(LineParsed { name: "REV", params: None, value: Some("19951031T222710Z") }) +Ok(LineParsed { name: "ROLE", params: None, value: Some("Project Leader") }) +Ok(LineParsed { name: "SOUND", params: None, value: Some("CID:JOHNQPUBLIC.part8.19960229T080000.xyzMail@example.com") }) +Ok(LineParsed { name: "SOURCE", params: None, value: Some("ldap://ldap.example.com/cn=Babs%20Jensen\\,%20o=Babsco\\,%20c=US") }) +Ok(LineParsed { name: "TEL", params: Some([("VALUE", ["uri"]), ("TYPE", ["home"])]), value: Some("tel:+33-01-23-45-67") }) +Ok(LineParsed { name: "TITLE", params: None, value: Some("Research Scientist") }) +Ok(LineParsed { name: "TZ", params: Some([("VALUE", ["utc-offset"])]), value: Some("-0500") }) +Ok(LineParsed { name: "XML", params: None, value: Some("") }) +Ok(LineParsed { name: "END", params: None, value: Some("VCARD") }) From 1b01e3af6f9363b8dac77d50094cec997e88464e Mon Sep 17 00:00:00 2001 From: Josh Klar Date: Wed, 1 Mar 2017 23:23:39 -0600 Subject: [PATCH 2/6] README Updates --- README.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 577c4023..7743edcc 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# ical-rs 0.2.1 +# ical-rs 0.3.0 =============== [![Build Status](https://travis-ci.org/Peltoche/ical-rs.svg?branch=master)](https://travis-ci.org/Peltoche/ical-rs) @@ -22,7 +22,7 @@ Put this in your `Cargo.toml`: ```toml [dependencies] -ical = "0.2.0" +ical = "0.3.0" ``` @@ -50,7 +50,7 @@ Each component can contains properties (ie: LineParsed) or sub-components. Cargo.toml: ```toml [dependencies.ical] -version = "0.2.*" +version = "0.3.*" default-features = false features = ["ical-parser", "vcard-parser"] ``` @@ -111,7 +111,7 @@ It work for both the Vcard and Ical format. Cargo.toml: ```toml [dependencies.ical] -version = "0.2.*" +version = "0.3.*" default-features = false features = ["line-parser"] ``` @@ -137,9 +137,10 @@ fn main() { Input -> Output: ``` -begin:VCALENDAR Ok(LineParsed { name: "BEGIN", params: None, value: "VCALENDAR" }) -ATTENDEE;cn=FooBar:mailto:foo3@bar -> Ok(LineParsed { name: "ATTENDEE", params: Some([("CN", "FooBar")]), value: "mailto:foo3@bar" }) -END:VCALENDAR Ok(LineParsed { name: "END", params: None, value: "VCALENDAR" }) +begin:VCALENDAR Ok(LineParsed { name: "BEGIN", params: None, value: Some("VCALENDAR") }) +ATTENDEE;cn=FooBar:mailto:foo3@bar -> Ok(LineParsed { name: "ATTENDEE", params: Some([("CN", "FooBar")]), value: Some("mailto:foo3@bar") }) +DESCRIPTION: Ok(LineParsed { name: "DESCRIPTION": params: None, value: None }) +END:VCALENDAR Ok(LineParsed { name: "END", params: None, value: Some("VCALENDAR") }) ``` ### LineReader @@ -153,7 +154,7 @@ It work for both the Vcard and Ical format. Cargo.toml: ```toml [dependencies.ical] -version = "0.2.*" +version = "0.3.*" default-features = false features = ["line-reader"] ``` From f3b852d71cae6f7b77550d29d24584fa687331b9 Mon Sep 17 00:00:00 2001 From: Josh Klar Date: Wed, 1 Mar 2017 23:36:52 -0600 Subject: [PATCH 3/6] Do not allow "BEGIN:" (value-less begin) --- src/parser/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parser/mod.rs b/src/parser/mod.rs index f2197190..556834ae 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -34,7 +34,7 @@ pub trait Component { "END" => break, "BEGIN" => match line.value { Some(v) => self.add_sub_component(v.as_str(), line_parser)?, - None => self.add_sub_component("", line_parser)?, + None => return Err(ParseError::NotComplete), }, _ => self.add_property(line), From b62447be8693f60104579922bf6e98d1b81c020a Mon Sep 17 00:00:00 2001 From: peltoche Date: Sat, 4 Mar 2017 14:29:23 +0100 Subject: [PATCH 4/6] Correct README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7743edcc..4d22c4cf 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ fn main() { let buf = BufReader::new(File::open("/tmp/component.ics") .unwrap()); - let reader = ical::IcalReader::new(buf); + let reader = ical::IcalParser::new(buf); for line in reader { println!("{:?}", line); @@ -132,7 +132,7 @@ fn main() { for line in reader { println!("{:?}", line); } - +} ``` Input -> Output: From 7109ecfe315ca03235415c8b1b843d8295220634 Mon Sep 17 00:00:00 2001 From: peltoche Date: Sat, 4 Mar 2017 15:14:11 +0100 Subject: [PATCH 5/6] Fix bad value detection. --- src/line/parser.rs | 60 ++++++++++++++++----------- tests/ressources/ical_line_parser.res | 16 +++---- 2 files changed, 43 insertions(+), 33 deletions(-) diff --git a/src/line/parser.rs b/src/line/parser.rs index c04dd095..bcbfc2cc 100644 --- a/src/line/parser.rs +++ b/src/line/parser.rs @@ -61,13 +61,24 @@ impl LineParser { fn parse(&self, line: Line) -> Result { let mut property = LineParsed::new(); + let mut content = line.as_str(); + + println!("\n\nstart: {}", content); + // Parse name. - property.name = self.parse_name(line.as_str()) + property.name = self.parse_name(content) .and_then(|name| Some(name.to_string())) .ok_or(ParseError::MissingName)?; + content = content.split_at(property.name.len()).1; + + // Parse parameters. + let res = self.parse_parameters(content)?; + property.params = res.0; + content = res.1; + // Parse value - property.value = self.parse_value(line.as_str()) + property.value = self.parse_value(content) .and_then(|value| { match value.len() { 0 => None, @@ -75,15 +86,12 @@ impl LineParser { } }); - // Parse parameters. - property.params = self.parse_parameters(line.as_str())?; - Ok(property) } /// Return the name from the given `Line`. - fn parse_name<'a>(&self, line: &'a str) -> Option<&'a str> { + fn parse_name<'a>(&self, line: &'a str) -> Option<(&'a str)> { let end_name_index; let param_index = line.find(::PARAM_DELIMITER).unwrap_or(usize::max_value()); @@ -100,34 +108,20 @@ impl LineParser { Some(line.split_at(end_name_index).0) } - - /// Return the value from the given `Line`. - fn parse_value<'a>(&self, line: &'a str) -> Option<&'a str> { - let value_index = match line.find(::VALUE_DELIMITER) { - Some(val) => val + 1, // Jump the VALUE_DELIMITER - None => return None, - }; - - if value_index < line.len() { - Some(line.split_at(value_index).1) - } else { - None - } - } - /// Return the parameters from the given `Line`. - fn parse_parameters(&self, line: &str) -> Result)>>, ParseError> { + fn parse_parameters<'a>(&self, line: &'a str) -> Result<(Option)>>, &'a str), ParseError> { + println!("param line: {}", line); let mut param_list = Vec::new(); let mut params_str; let start_value_index = line.find(::VALUE_DELIMITER).unwrap_or(usize::max_value()); let start_param_index = match line.find(::PARAM_DELIMITER) { Some(val) => val, - None => return Ok(None), // there is no params. + None => return Ok((None, line)), // there is no params. }; if start_value_index < start_param_index { - return Ok(None); + return Ok((None, line)); } // Remove the attribue name. @@ -151,7 +145,23 @@ impl LineParser { }; - Ok(Some((param_list))) + Ok((Some(param_list), params_str)) + } + + + /// Return the value from the given `Line`. + fn parse_value<'a>(&self, line: &'a str) -> Option<&'a str> { + println!("value line: {}", line); + let value_index = match line.find(::VALUE_DELIMITER) { + Some(val) => val + 1, // Jump the VALUE_DELIMITER + None => return None, + }; + + if value_index < line.len() { + Some(line.split_at(value_index).1) + } else { + None + } } } diff --git a/tests/ressources/ical_line_parser.res b/tests/ressources/ical_line_parser.res index 5a03f870..272dd135 100644 --- a/tests/ressources/ical_line_parser.res +++ b/tests/ressources/ical_line_parser.res @@ -13,18 +13,18 @@ Ok(LineParsed { name: "END", params: None, value: Some("VALARM") }) Ok(LineParsed { name: "END", params: None, value: Some("VEVENT") }) Ok(LineParsed { name: "END", params: None, value: Some("VCALENDAR") }) Ok(LineParsed { name: "BEGIN", params: None, value: Some("VCALENDAR") }) -Ok(LineParsed { name: "ATTENDEE", params: Some([("DELEGATED-TO", ["mailto:foo7@bar", "mailto:foo8@bar"]), ("CN", ["Foo, Bar"])]), value: Some("foo7@bar\",\"mailto:foo8@bar\";CN=\"Foo, Bar\":mailto:foo1@bar") }) -Ok(LineParsed { name: "ATTENDEE", params: Some([("DELEGATED-TO", ["mailto:foo7@bar", "mailto:foo8@bar"]), ("CN", ["Foo; Bar"])]), value: Some("foo7@bar\",\"mailto:foo8@bar\";CN=\"Foo; Bar\":mailto:foo2@bar") }) +Ok(LineParsed { name: "ATTENDEE", params: Some([("DELEGATED-TO", ["mailto:foo7@bar", "mailto:foo8@bar"]), ("CN", ["Foo, Bar"])]), value: Some("mailto:foo1@bar") }) +Ok(LineParsed { name: "ATTENDEE", params: Some([("DELEGATED-TO", ["mailto:foo7@bar", "mailto:foo8@bar"]), ("CN", ["Foo; Bar"])]), value: Some("mailto:foo2@bar") }) Ok(LineParsed { name: "ATTENDEE", params: Some([("CN", ["Foo, Bar"])]), value: Some("mailto:foo3@bar") }) Ok(LineParsed { name: "ATTENDEE", params: Some([("CN", ["Foo; Bar"])]), value: Some("mailto:foo4@bar") }) -Ok(LineParsed { name: "ATTENDEE", params: Some([("DELEGATED-TO", ["mailto:foo7@bar"]), ("CN", ["Foo, Bar"])]), value: Some("foo7@bar\";CN=\"Foo, Bar\":mailto:foo5@bar") }) -Ok(LineParsed { name: "ATTENDEE", params: Some([("DELEGATED-TO", ["mailto:foo7@bar"]), ("CN", ["Foo; Bar"])]), value: Some("foo7@bar\";CN=\"Foo; Bar\":mailto:foo6@bar") }) -Ok(LineParsed { name: "ATTENDEE", params: Some([("ROLE", ["REQ-PARTICIPANT;foo"]), ("DELEGATED-FROM", ["mailto:bar@baz.com"]), ("PARTSTAT", ["ACCEPTED"]), ("RSVP", ["TRUE"])]), value: Some("bar@baz.com\";PARTSTAT=ACCEPTED;RSVP=TRUE:mailto:foo@bar.com") }) +Ok(LineParsed { name: "ATTENDEE", params: Some([("DELEGATED-TO", ["mailto:foo7@bar"]), ("CN", ["Foo, Bar"])]), value: Some("mailto:foo5@bar") }) +Ok(LineParsed { name: "ATTENDEE", params: Some([("DELEGATED-TO", ["mailto:foo7@bar"]), ("CN", ["Foo; Bar"])]), value: Some("mailto:foo6@bar") }) +Ok(LineParsed { name: "ATTENDEE", params: Some([("ROLE", ["REQ-PARTICIPANT;foo"]), ("DELEGATED-FROM", ["mailto:bar@baz.com"]), ("PARTSTAT", ["ACCEPTED"]), ("RSVP", ["TRUE"])]), value: Some("mailto:foo@bar.com") }) Ok(LineParsed { name: "X-FOO", params: Some([("PARAM1", ["VAL1"])]), value: Some("FOO;BAR") }) Ok(LineParsed { name: "X-FOO2", params: Some([("PARAM1", ["VAL1"]), ("PARAM2", ["VAL2"])]), value: Some("FOO;BAR") }) -Ok(LineParsed { name: "X-BAR", params: Some([("PARAM1", ["VAL1:FOO"])]), value: Some("FOO\":BAZ;BAR") }) -Ok(LineParsed { name: "X-BAZ", params: Some([("PARAM1", ["VAL1:FOO"]), ("PARAM2", ["VAL2"])]), value: Some("FOO\";PARAM2=VAL2:BAZ;BAR") }) -Ok(LineParsed { name: "X-BAZ2", params: Some([("PARAM1", ["VAL1"]), ("PARAM2", ["VAL2:FOO"])]), value: Some("FOO\":BAZ;BAR") }) +Ok(LineParsed { name: "X-BAR", params: Some([("PARAM1", ["VAL1:FOO"])]), value: Some("BAZ;BAR") }) +Ok(LineParsed { name: "X-BAZ", params: Some([("PARAM1", ["VAL1:FOO"]), ("PARAM2", ["VAL2"])]), value: Some("BAZ;BAR") }) +Ok(LineParsed { name: "X-BAZ2", params: Some([("PARAM1", ["VAL1"]), ("PARAM2", ["VAL2:FOO"])]), value: Some("BAZ;BAR") }) Ok(LineParsed { name: "END", params: None, value: Some("VCALENDAR") }) Ok(LineParsed { name: "BEGIN", params: None, value: Some("VCALENDAR") }) Ok(LineParsed { name: "CALSCALE", params: None, value: Some("GREGORIAN") }) From 0d070ad5b07cd498e7cdec92767a418490251aa4 Mon Sep 17 00:00:00 2001 From: peltoche Date: Sat, 4 Mar 2017 16:47:33 +0100 Subject: [PATCH 6/6] Format code / Add some tests --- src/line/parser.rs | 24 ++++---- src/parser/ical/mod.rs | 4 +- src/parser/mod.rs | 10 ++-- src/parser/vcard/component.rs | 5 +- src/parser/vcard/mod.rs | 3 +- tests/mod.rs | 94 ++++++++++++++++++++++--------- tests/ressources/ical_parser.res | 3 + tests/ressources/vcard_parser.res | 1 + 8 files changed, 95 insertions(+), 49 deletions(-) create mode 100644 tests/ressources/ical_parser.res create mode 100644 tests/ressources/vcard_parser.res diff --git a/src/line/parser.rs b/src/line/parser.rs index bcbfc2cc..e4ee8d64 100644 --- a/src/line/parser.rs +++ b/src/line/parser.rs @@ -63,8 +63,6 @@ impl LineParser { let mut content = line.as_str(); - println!("\n\nstart: {}", content); - // Parse name. property.name = self.parse_name(content) .and_then(|name| Some(name.to_string())) @@ -82,7 +80,7 @@ impl LineParser { .and_then(|value| { match value.len() { 0 => None, - _ => Some(value.to_string()) + _ => Some(value.to_string()), } }); @@ -109,8 +107,10 @@ impl LineParser { } /// Return the parameters from the given `Line`. - fn parse_parameters<'a>(&self, line: &'a str) -> Result<(Option)>>, &'a str), ParseError> { - println!("param line: {}", line); + fn parse_parameters<'a> + (&self, + line: &'a str) + -> Result<(Option)>>, &'a str), ParseError> { let mut param_list = Vec::new(); let mut params_str; @@ -143,7 +143,7 @@ impl LineParser { param_list.push((name.to_uppercase(), values)); - }; + } Ok((Some(param_list), params_str)) } @@ -151,7 +151,6 @@ impl LineParser { /// Return the value from the given `Line`. fn parse_value<'a>(&self, line: &'a str) -> Option<&'a str> { - println!("value line: {}", line); let value_index = match line.find(::VALUE_DELIMITER) { Some(val) => val + 1, // Jump the VALUE_DELIMITER None => return None, @@ -165,15 +164,17 @@ impl LineParser { } } -fn parse_param_value<'a>(mut values: Vec, params_str: &'a str) -> Result<(Vec, &'a str), ParseError> { +fn parse_param_value<'a>(mut values: Vec, + params_str: &'a str) + -> Result<(Vec, &'a str), ParseError> { let new_params_str; if params_str.starts_with('"') { // This is a dquoted value. (NAME:Foo="Bar":value) let mut elements = params_str.splitn(3, '"').skip(1); values.push(elements.next() - .and_then(|value| Some(value.to_string())) - .ok_or(ParseError::InvalidParamFormat)?); + .and_then(|value| Some(value.to_string())) + .ok_or(ParseError::InvalidParamFormat)?); new_params_str = elements.next() .ok_or(ParseError::InvalidParamFormat)?; } else { @@ -198,7 +199,8 @@ fn parse_param_value<'a>(mut values: Vec, params_str: &'a str) -> Result } if new_params_str.starts_with(::PARAM_VALUE_DELIMITER) { - parse_param_value(values, new_params_str.trim_left_matches(::PARAM_VALUE_DELIMITER)) + parse_param_value(values, + new_params_str.trim_left_matches(::PARAM_VALUE_DELIMITER)) } else { Ok((values, new_params_str)) } diff --git a/src/parser/ical/mod.rs b/src/parser/ical/mod.rs index 1db989a3..030157f1 100644 --- a/src/parser/ical/mod.rs +++ b/src/parser/ical/mod.rs @@ -28,7 +28,8 @@ impl IcalParser { None => return Ok(None), }; - if line.name != "BEGIN" || line.value.is_none() || line.value.unwrap() != "VCALENDAR" || line.params != None { + if line.name != "BEGIN" || line.value.is_none() || line.value.unwrap() != "VCALENDAR" || + line.params != None { return Err(ParseError::MissingHeader); } @@ -59,4 +60,3 @@ impl Iterator for IcalParser { Some(result) } } - diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 556834ae..b4b48515 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -32,10 +32,12 @@ pub trait Component { match line.name.as_str() { "END" => break, - "BEGIN" => match line.value { - Some(v) => self.add_sub_component(v.as_str(), line_parser)?, - None => return Err(ParseError::NotComplete), - }, + "BEGIN" => { + match line.value { + Some(v) => self.add_sub_component(v.as_str(), line_parser)?, + None => return Err(ParseError::NotComplete), + } + } _ => self.add_property(line), }; diff --git a/src/parser/vcard/component.rs b/src/parser/vcard/component.rs index 41bb0d0e..56341d67 100644 --- a/src/parser/vcard/component.rs +++ b/src/parser/vcard/component.rs @@ -5,15 +5,14 @@ use std::cell::RefCell; use parser::{Component, ParseError}; use line::parser::{LineParsed, LineParser}; +#[derive(Debug, Clone)] pub struct VcardContact { pub properties: Vec, } impl VcardContact { pub fn new() -> VcardContact { - VcardContact { - properties: Vec::new(), - } + VcardContact { properties: Vec::new() } } } diff --git a/src/parser/vcard/mod.rs b/src/parser/vcard/mod.rs index 25466ba3..257f666f 100644 --- a/src/parser/vcard/mod.rs +++ b/src/parser/vcard/mod.rs @@ -27,7 +27,8 @@ impl VcardParser { None => return Ok(None), }; - if line.name != "BEGIN" || line.value.is_none() || line.value.unwrap() != "VCARD" || line.params != None { + if line.name != "BEGIN" || line.value.is_none() || line.value.unwrap() != "VCARD" || + line.params != None { return Err(ParseError::MissingHeader); } diff --git a/tests/mod.rs b/tests/mod.rs index 9edf312a..98bb9b57 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -1,19 +1,18 @@ #[cfg(feature = "line-parser")] pub mod line_parser { -extern crate ical; + extern crate ical; -use std::io::BufReader; -use std::io::BufRead; -use std::fs::File; + use std::io::BufReader; + use std::io::BufRead; + use std::fs::File; -#[test] + #[test] fn ical() { - let input = BufReader::new(File::open("./tests/ressources/ical_input.ics") - .unwrap()); + let input = BufReader::new(File::open("./tests/ressources/ical_input.ics").unwrap()); - let mut valids = BufReader::new(File::open("./tests/ressources/ical_line_parser.res") - .unwrap()).lines(); + let mut valids = + BufReader::new(File::open("./tests/ressources/ical_line_parser.res").unwrap()).lines(); let reader = ical::LineParser::from_reader(input); @@ -26,13 +25,12 @@ use std::fs::File; } -#[test] + #[test] fn vcard() { - let input = BufReader::new(File::open("./tests/ressources/vcard_input.vcf") - .unwrap()); + let input = BufReader::new(File::open("./tests/ressources/vcard_input.vcf").unwrap()); - let mut valids = BufReader::new(File::open("./tests/ressources/vcard_line_parser.res") - .unwrap()).lines(); + let mut valids = + BufReader::new(File::open("./tests/ressources/vcard_line_parser.res").unwrap()).lines(); let reader = ical::LineParser::from_reader(input); @@ -48,19 +46,18 @@ use std::fs::File; #[cfg(feature = "line-reader")] pub mod line_reader { -extern crate ical; + extern crate ical; -use std::io::BufReader; -use std::io::BufRead; -use std::fs::File; + use std::io::BufReader; + use std::io::BufRead; + use std::fs::File; -#[test] + #[test] fn ical() { - let input = BufReader::new(File::open("./tests/ressources/ical_input.ics") - .unwrap()); + let input = BufReader::new(File::open("./tests/ressources/ical_input.ics").unwrap()); - let mut valids = BufReader::new(File::open("./tests/ressources/ical_line_reader.res") - .unwrap()).lines(); + let mut valids = + BufReader::new(File::open("./tests/ressources/ical_line_reader.res").unwrap()).lines(); let reader = ical::LineReader::new(input); @@ -72,13 +69,12 @@ use std::fs::File; } } -#[test] + #[test] fn vcard() { - let input = BufReader::new(File::open("./tests/ressources/vcard_input.vcf") - .unwrap()); + let input = BufReader::new(File::open("./tests/ressources/vcard_input.vcf").unwrap()); - let mut valids = BufReader::new(File::open("./tests/ressources/vcard_line_reader.res") - .unwrap()).lines(); + let mut valids = + BufReader::new(File::open("./tests/ressources/vcard_line_reader.res").unwrap()).lines(); let reader = ical::LineReader::new(input); @@ -90,3 +86,45 @@ use std::fs::File; } } } + +pub mod parser { + extern crate ical; + + use std::io::BufReader; + use std::io::BufRead; + use std::fs::File; + + #[test] + fn ical() { + let input = BufReader::new(File::open("./tests/ressources/ical_input.ics").unwrap()); + + let mut valids = + BufReader::new(File::open("./tests/ressources/ical_parser.res").unwrap()).lines(); + + + let reader = ical::IcalParser::new(input); + + for calendar in reader { + let output = format!("{:?}", calendar); + + assert_eq!(output, valids.next().unwrap().unwrap()); + } + } + + #[test] + fn vcard() { + let input = BufReader::new(File::open("./tests/ressources/vcard_input.vcf").unwrap()); + + let mut valids = + BufReader::new(File::open("./tests/ressources/vcard_parser.res").unwrap()).lines(); + + + let reader = ical::VcardParser::new(input); + + for contact_book in reader { + let output = format!("{:?}", contact_book); + + assert_eq!(output, valids.next().unwrap().unwrap()); + } + } +} diff --git a/tests/ressources/ical_parser.res b/tests/ressources/ical_parser.res new file mode 100644 index 00000000..12e45758 --- /dev/null +++ b/tests/ressources/ical_parser.res @@ -0,0 +1,3 @@ +Ok(IcalCalendar { properties: [LineParsed { name: "CALSCALE", params: None, value: Some("GREGORIAN") }, LineParsed { name: "PRODID", params: None, value: Some("-//Example Inc.//Example Calendar//EN") }, LineParsed { name: "VERSION", params: None, value: Some("2.0") }], events: [IcalEvent { properties: [LineParsed { name: "DTSTAMP", params: None, value: Some("20080205T191224Z") }, LineParsed { name: "DTSTART", params: Some([("VALUE", ["DATE"])]), value: Some("20081006") }, LineParsed { name: "SUMMARY", params: None, value: Some("Planning meeting") }, LineParsed { name: "UID", params: None, value: Some("4088E990AD89CB3DBB484909") }], alarms: [IcalAlarm { properties: [LineParsed { name: "SUMMARY", params: None, value: Some("escaped\\, comma and\\; semicolon\\nnewline") }] }] }], alarms: [], todos: [], journals: [], free_busys: [], timezones: [] }) +Ok(IcalCalendar { properties: [LineParsed { name: "ATTENDEE", params: Some([("DELEGATED-TO", ["mailto:foo7@bar", "mailto:foo8@bar"]), ("CN", ["Foo, Bar"])]), value: Some("mailto:foo1@bar") }, LineParsed { name: "ATTENDEE", params: Some([("DELEGATED-TO", ["mailto:foo7@bar", "mailto:foo8@bar"]), ("CN", ["Foo; Bar"])]), value: Some("mailto:foo2@bar") }, LineParsed { name: "ATTENDEE", params: Some([("CN", ["Foo, Bar"])]), value: Some("mailto:foo3@bar") }, LineParsed { name: "ATTENDEE", params: Some([("CN", ["Foo; Bar"])]), value: Some("mailto:foo4@bar") }, LineParsed { name: "ATTENDEE", params: Some([("DELEGATED-TO", ["mailto:foo7@bar"]), ("CN", ["Foo, Bar"])]), value: Some("mailto:foo5@bar") }, LineParsed { name: "ATTENDEE", params: Some([("DELEGATED-TO", ["mailto:foo7@bar"]), ("CN", ["Foo; Bar"])]), value: Some("mailto:foo6@bar") }, LineParsed { name: "ATTENDEE", params: Some([("ROLE", ["REQ-PARTICIPANT;foo"]), ("DELEGATED-FROM", ["mailto:bar@baz.com"]), ("PARTSTAT", ["ACCEPTED"]), ("RSVP", ["TRUE"])]), value: Some("mailto:foo@bar.com") }, LineParsed { name: "X-FOO", params: Some([("PARAM1", ["VAL1"])]), value: Some("FOO;BAR") }, LineParsed { name: "X-FOO2", params: Some([("PARAM1", ["VAL1"]), ("PARAM2", ["VAL2"])]), value: Some("FOO;BAR") }, LineParsed { name: "X-BAR", params: Some([("PARAM1", ["VAL1:FOO"])]), value: Some("BAZ;BAR") }, LineParsed { name: "X-BAZ", params: Some([("PARAM1", ["VAL1:FOO"]), ("PARAM2", ["VAL2"])]), value: Some("BAZ;BAR") }, LineParsed { name: "X-BAZ2", params: Some([("PARAM1", ["VAL1"]), ("PARAM2", ["VAL2:FOO"])]), value: Some("BAZ;BAR") }], events: [], alarms: [], todos: [], journals: [], free_busys: [], timezones: [] }) +Ok(IcalCalendar { properties: [LineParsed { name: "CALSCALE", params: None, value: Some("GREGORIAN") }, LineParsed { name: "PRODID", params: None, value: Some("-//Example Inc.//Example Calendar//EN") }, LineParsed { name: "VERSION", params: None, value: Some("2.0") }], events: [IcalEvent { properties: [LineParsed { name: "DTSTAMP", params: None, value: Some("20080205T191224Z") }, LineParsed { name: "DTSTART", params: Some([("VALUE", ["DATE"])]), value: Some("20081006") }, LineParsed { name: "SUMMARY", params: None, value: Some("Missing description value, but includes header") }, LineParsed { name: "DESCRIPTION", params: None, value: None }, LineParsed { name: "UID", params: None, value: Some("4088E990AD89CB3DBB484909") }], alarms: [] }], alarms: [], todos: [], journals: [], free_busys: [], timezones: [] }) diff --git a/tests/ressources/vcard_parser.res b/tests/ressources/vcard_parser.res new file mode 100644 index 00000000..39ca9cb8 --- /dev/null +++ b/tests/ressources/vcard_parser.res @@ -0,0 +1 @@ +Ok(VcardContact { properties: [LineParsed { name: "VERSION", params: None, value: Some("4.0") }, LineParsed { name: "ADR", params: Some([("TYPE", ["work"])]), value: Some("pobox;apt;street;city;state;zipcode;country") }, LineParsed { name: "ANNIVERSARY", params: None, value: Some("19960415") }, LineParsed { name: "BDAY", params: None, value: Some("--0203") }, LineParsed { name: "CALADRURI", params: None, value: Some("http://example.com/calendar/jdoe") }, LineParsed { name: "CALURI", params: Some([("MEDIATYPE", ["text/calendar"])]), value: Some("ftp://ftp.example.com/calA.ics") }, LineParsed { name: "CLIENTPIDMAP", params: None, value: Some("1;urn:uuid:3df403f4-5924-4bb7-b077-3c711d9eb34b") }, LineParsed { name: "EMAIL", params: Some([("TYPE", ["work"])]), value: Some("jqpublic@xyz.example.com") }, LineParsed { name: "FBURL", params: Some([("MEDIATYPE", ["text/calendar"])]), value: Some("ftp://example.com/busy/project-a.ifb") }, LineParsed { name: "FN", params: None, value: Some("J. Doe") }, LineParsed { name: "GENDER", params: None, value: Some("M;Fellow") }, LineParsed { name: "GEO", params: None, value: Some("geo:37.386013\\,-122.082932") }, LineParsed { name: "IMPP", params: Some([("PREF", ["1"])]), value: Some("xmpp:alice@example.com") }, LineParsed { name: "KEY", params: None, value: Some("http://www.example.com/keys/jdoe.cer") }, LineParsed { name: "KIND", params: None, value: Some("individual") }, LineParsed { name: "LANG", params: Some([("PREF", ["1"])]), value: Some("fr") }, LineParsed { name: "LOGO", params: None, value: Some("http://www.example.com/pub/logos/abccorp.jpg") }, LineParsed { name: "MEMBER", params: None, value: Some("urn:uuid:03a0e51f-d1aa-4385-8a53-e29025acd8af") }, LineParsed { name: "N", params: None, value: Some("Stevenson;John;Philip,Paul;Dr.;Jr.,M.D.,A.C.P.") }, LineParsed { name: "NICKNAME", params: Some([("TYPE", ["work"])]), value: Some("Boss") }, LineParsed { name: "NOTE", params: None, value: Some("This fax number is operational 0800 to 1715 EST\\, Mon-Fri") }, LineParsed { name: "ORG", params: None, value: Some("ABC\\, Inc.;North American Division;Marketing") }, LineParsed { name: "PHOTO", params: None, value: Some("http://www.example.com/pub/photos/jqpublic.gif") }, LineParsed { name: "RELATED", params: Some([("TYPE", ["friend"])]), value: Some("urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6") }, LineParsed { name: "REV", params: None, value: Some("19951031T222710Z") }, LineParsed { name: "ROLE", params: None, value: Some("Project Leader") }, LineParsed { name: "SOUND", params: None, value: Some("CID:JOHNQPUBLIC.part8.19960229T080000.xyzMail@example.com") }, LineParsed { name: "SOURCE", params: None, value: Some("ldap://ldap.example.com/cn=Babs%20Jensen\\,%20o=Babsco\\,%20c=US") }, LineParsed { name: "TEL", params: Some([("VALUE", ["uri"]), ("TYPE", ["home"])]), value: Some("tel:+33-01-23-45-67") }, LineParsed { name: "TITLE", params: None, value: Some("Research Scientist") }, LineParsed { name: "TZ", params: Some([("VALUE", ["utc-offset"])]), value: Some("-0500") }, LineParsed { name: "XML", params: None, value: Some("") }] })