caldir_core/event/
x_property.rs1use icalendar::Property;
2
3#[derive(Debug, Clone, Eq)]
4pub struct XProperty {
5 pub name: String,
6 pub value: String,
7 pub params: Vec<(String, String)>,
8}
9
10impl PartialEq for XProperty {
13 fn eq(&self, other: &Self) -> bool {
14 self.name == other.name && self.value == other.value
15 }
16}
17
18impl XProperty {
19 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
20 XProperty {
21 name: name.into(),
22 value: value.into(),
23 params: Vec::new(),
24 }
25 }
26}
27
28impl From<&XProperty> for Property {
29 fn from(value: &XProperty) -> Self {
30 let mut prop = Property::new(&value.name, &value.value);
31 for (k, v) in &value.params {
32 prop.add_parameter(k, v);
33 }
34 prop.done()
35 }
36}
37
38impl From<&Property> for XProperty {
39 fn from(value: &Property) -> Self {
40 let params = value
41 .params()
42 .values()
43 .map(|p| (p.key().to_string(), p.value().to_string()))
44 .collect();
45 XProperty {
46 name: value.key().to_string(),
47 value: value.value().to_string(),
48 params,
49 }
50 }
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56
57 #[test]
58 fn parses_name_and_value() {
59 let prop = Property::new("X-HOOLI-EVENT-ID", "abc123").done();
60
61 let x = XProperty::from(&prop);
62
63 assert_eq!(x.name, "X-HOOLI-EVENT-ID");
64 assert_eq!(x.value, "abc123");
65 assert!(x.params.is_empty());
66 }
67
68 #[test]
69 fn parses_params() {
70 let mut prop = Property::new("X-ALT-DESC", "<html>...</html>");
71 prop.add_parameter("FMTTYPE", "text/html");
72
73 let x = XProperty::from(&prop.done());
74
75 assert_eq!(
76 x.params,
77 vec![("FMTTYPE".to_string(), "text/html".to_string())]
78 );
79 }
80
81 #[test]
82 fn writes_name_and_value() {
83 let x = XProperty::new("X-HOOLI-EVENT-ID", "abc123");
84
85 let prop = Property::from(&x);
86
87 assert_eq!(prop.key(), "X-HOOLI-EVENT-ID");
88 assert_eq!(prop.value(), "abc123");
89 assert!(prop.params().is_empty());
90 }
91
92 #[test]
93 fn writes_params() {
94 let x = XProperty {
95 name: "X-ALT-DESC".to_string(),
96 value: "<html>...</html>".to_string(),
97 params: vec![("FMTTYPE".to_string(), "text/html".to_string())],
98 };
99
100 let prop = Property::from(&x);
101
102 assert_eq!(
103 prop.params().get("FMTTYPE").map(|p| p.value()),
104 Some("text/html")
105 );
106 }
107
108 #[test]
109 fn eq_ignores_param_drift() {
110 let bare = XProperty::new("X-APPLE-STRUCTURED-LOCATION", "geo:51.47,-0.45");
111 let with_params = XProperty {
112 name: "X-APPLE-STRUCTURED-LOCATION".to_string(),
113 value: "geo:51.47,-0.45".to_string(),
114 params: vec![
115 ("VALUE".to_string(), "URI".to_string()),
116 ("X-TITLE".to_string(), "London Heathrow".to_string()),
117 ],
118 };
119
120 assert_eq!(bare, with_params);
121 }
122
123 #[test]
124 fn eq_distinguishes_value_changes() {
125 let a = XProperty::new("X-APPLE-STRUCTURED-LOCATION", "geo:51.47,-0.45");
126 let b = XProperty::new("X-APPLE-STRUCTURED-LOCATION", "geo:1.0,2.0");
127
128 assert_ne!(a, b);
129 }
130}