diff options
author | Hendrik Sollich <hoodie@users.noreply.github.com> | 2019-03-08 14:20:05 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-03-08 14:20:05 +0100 |
commit | c024d5000ebe375836c8c73cf5e05b2ed9df6b10 (patch) | |
tree | 5ac9372007163d8f4a6def66ce031bfbaa129bae | |
parent | 95df4e92cccc4c7cc52a03cf0ef81824251b9c05 (diff) | |
parent | 3387ec4bd0cab2b6d888b663fbd88c5cdc00ba95 (diff) |
Merge pull request #8 from strohel/feature/deterministic-to-string
Make Component serialization deterministic, add integration tests
-rw-r--r-- | src/components.rs | 21 | ||||
-rw-r--r-- | tests/calendar.rs | 41 |
2 files changed, 53 insertions, 9 deletions
diff --git a/src/components.rs b/src/components.rs index 7139e4b..b4efb91 100644 --- a/src/components.rs +++ b/src/components.rs @@ -4,7 +4,7 @@ use uuid::Uuid; // use std::io; use std::fmt; use std::mem; -use std::collections::HashMap; +use std::collections::BTreeMap; use crate::properties::*; @@ -18,7 +18,7 @@ pub struct Todo { inner: InnerComponent } #[derive(Debug, Default)] struct InnerComponent{ - properties: HashMap<String,Property>, + properties: BTreeMap<String, Property>, multi_properties: Vec<Property> } @@ -27,7 +27,7 @@ impl InnerComponent { /// copies over everything pub fn done(&mut self) -> Self { InnerComponent{ - properties: mem::replace(&mut self.properties, HashMap::new()), + properties: mem::replace(&mut self.properties, BTreeMap::new()), multi_properties: mem::replace(&mut self.multi_properties, Vec::new()), } } @@ -116,8 +116,8 @@ pub trait Component { /// These are used in the `BEGIN` and `END` line of the component. fn component_kind() -> &'static str; - /// Allows access to the inner properties HashMap. - fn properties(&self) -> &HashMap<String,Property>; + /// Allows access to the inner properties map. + fn properties(&self) -> &BTreeMap<String,Property>; /// Read-only access to `multi_properties` fn multi_properties(&self) -> &Vec<Property> ; @@ -127,14 +127,17 @@ pub trait Component { fn fmt_write<W: fmt::Write>(&self, out: &mut W) -> Result<(), fmt::Error> { write_crlf!(out, "BEGIN:{}", Self::component_kind())?; - let now = Local::now().format("%Y%m%dT%H%M%S"); - write_crlf!(out, "DTSTAMP:{}", now)?; + + if !self.properties().contains_key("DTSTAMP") { + let now = Local::now().format("%Y%m%dT%H%M%S"); + write_crlf!(out, "DTSTAMP:{}", now)?; + } for property in self.properties().values() { property.fmt_write(out)?; } - if !self.properties().keys().any(|key| key == "UID") { + if !self.properties().contains_key("UID") { write_crlf!(out, "UID:{}", Uuid::new_v4())?; } @@ -287,7 +290,7 @@ macro_rules! component_impl { fn component_kind() -> &'static str { $kind } /// Read-only access to `properties` - fn properties(&self) -> &HashMap<String, Property> { + fn properties(&self) -> &BTreeMap<String, Property> { &self.inner.properties } diff --git a/tests/calendar.rs b/tests/calendar.rs new file mode 100644 index 0000000..785bec5 --- /dev/null +++ b/tests/calendar.rs @@ -0,0 +1,41 @@ +use chrono::prelude::*; +use icalendar::{Calendar, Class, Component, Event, EventStatus}; + +const EXPECTED_CAL_CONTENT: &str = "\ +BEGIN:VCALENDAR\r +VERSION:2.0\r +PRODID:ICALENDAR-RS\r +CALSCALE:GREGORIAN\r +BEGIN:VEVENT\r +CLASS:CONFIDENTIAL\r +DESCRIPTION:Description\r +DTEND:20140709T091011\r +DTSTAMP:20190307T181159\r +DTSTART:20140708T091011\r +LOCATION:Somewhere\r +PRIORITY:10\r +STATUS:TENTATIVE\r +SUMMARY:summary\r +UID:euid\r +END:VEVENT\r +END:VCALENDAR\r +"; + +#[test] +fn test_calendar_to_string() { + let mut calendar = Calendar::new(); + let event = Event::new() + .status(EventStatus::Tentative) + .starts(Local.ymd(2014, 7, 8).and_hms(9, 10, 11)) + .ends(Local.ymd(2014, 7, 9).and_hms(9, 10, 11)) + .priority(11) // converted to 10 + .summary("summary") + .description("Description") + .location("Somewhere") + .uid("euid") + .class(Class::Confidential) + .add_property("DTSTAMP", "20190307T181159") + .done(); + calendar.push(event); + assert_eq!(calendar.to_string(), EXPECTED_CAL_CONTENT); +} |