1use chrono::naive::NaiveDateTime;
6use fidl_fuchsia_bluetooth_map::{Audience, Notification, NotificationType};
7use objects::{Builder, ObexObjectError as Error, Parser};
8use std::collections::HashSet;
9use std::fmt;
10use std::str::FromStr;
11use xml::EventWriter;
12use xml::attribute::OwnedAttribute;
13use xml::reader::{ParserConfig, XmlEvent};
14use xml::writer::{EmitterConfig, XmlEvent as XmlWriteEvent};
15
16use crate::MessageType;
17use crate::packets::{ISO_8601_TIME_FORMAT, bool_to_string, str_to_bool, truncate_string};
18
19const EVENT_ELEM: &str = "event";
39const EVENT_REPORT_ELEM: &str = "MAP-event-report";
40
41const VERSION_ATTR: &str = "version";
42
43const TYPE_ATTR: &str = "type";
44const HANDLE_ATTR: &str = "handle";
45const FOLDER_ATTR: &str = "folder";
46const OLD_FOLDER_ATTR: &str = "old_folder";
47const MSG_TYPE_ATTR: &str = "msg_type";
48
49const DATETIME_ATTR: &str = "datetime";
51const SUBJECT_ATTR: &str = "subject";
52const SENDER_NAME_ATTR: &str = "sender_name";
53const PRIORITY_ATTR: &str = "priority";
54
55#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
59pub enum Type {
60 NewMessage,
61 DeliverySuccess,
62 SendingSuccess,
63 DeliveryFailure,
64 SendingFailure,
65 MessageDeleted,
66 MessageShift,
67 ReadStatusChanged,
68}
69
70impl fmt::Display for Type {
71 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72 let str_value = match self {
73 Type::NewMessage => "NewMessage",
74 Type::DeliverySuccess => "DeliverySuccess",
75 Type::SendingSuccess => "SendingSuccess",
76 Type::DeliveryFailure => "DeliveryFailure",
77 Type::SendingFailure => "SendingFailure",
78 Type::MessageDeleted => "MessageDeleted",
79 Type::MessageShift => "MessageShift",
80 Type::ReadStatusChanged => "ReadStatusChanged",
81 };
82
83 write!(f, "{}", str_value)
84 }
85}
86
87impl FromStr for Type {
88 type Err = Error;
89 fn from_str(src: &str) -> Result<Self, Self::Err> {
90 let val = match src {
91 "NewMessage" => Self::NewMessage,
92 "DeliverySuccess" => Self::DeliverySuccess,
93 "SendingSuccess" => Self::SendingSuccess,
94 "SendingFailure" => Self::DeliveryFailure,
95 "MessageDeleted" => Self::MessageDeleted,
96 "MessageShift" => Self::MessageShift,
97 "ReadStatusChanged" => Self::ReadStatusChanged,
98 v => return Err(Error::invalid_data(v)),
99 };
100 Ok(val)
101 }
102}
103
104impl From<Type> for NotificationType {
105 fn from(value: Type) -> Self {
106 match value {
107 Type::NewMessage => NotificationType::NewMessage,
108 Type::DeliverySuccess => NotificationType::DeliverySuccess,
109 Type::SendingSuccess => NotificationType::SendingSuccess,
110 Type::DeliveryFailure => NotificationType::DeliveryFailure,
111 Type::SendingFailure => NotificationType::SendingFailure,
112 Type::MessageDeleted => NotificationType::MessageDeleted,
113 Type::MessageShift => NotificationType::MessageShift,
114 Type::ReadStatusChanged => NotificationType::ReadStatusChanged,
115 }
116 }
117}
118
119#[derive(Clone, Copy, Debug, PartialEq)]
120pub enum EventReportVersion {
121 V1_0,
122 V1_1,
123}
124
125impl fmt::Display for EventReportVersion {
126 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127 match self {
128 Self::V1_0 => write!(f, "1.0"),
129 Self::V1_1 => write!(f, "1.1"),
130 }
131 }
132}
133
134impl FromStr for EventReportVersion {
135 type Err = Error;
136 fn from_str(src: &str) -> Result<Self, Self::Err> {
137 match src {
138 "1.0" => Ok(Self::V1_0),
139 "1.1" => Ok(Self::V1_1),
140 _v => Err(Error::UnsupportedVersion),
141 }
142 }
143}
144
145#[derive(Clone, Debug, Eq, Hash, PartialEq)]
148pub enum EventAttribute {
149 Type(Type),
151 Handle(u64),
152 Folder(String),
153 OldFolder(String),
154 MessageType(MessageType),
155 Datetime(NaiveDateTime),
157 Subject(String),
158 SenderName(String),
159 Priority(bool),
160}
161
162impl EventAttribute {
163 fn xml_attribute_name(&self) -> &'static str {
164 match self {
165 EventAttribute::Type(_) => TYPE_ATTR,
166 EventAttribute::Handle(_) => HANDLE_ATTR,
167 EventAttribute::Folder(_) => FOLDER_ATTR,
168 EventAttribute::OldFolder(_) => OLD_FOLDER_ATTR,
169 EventAttribute::MessageType(_) => MSG_TYPE_ATTR,
170 EventAttribute::Datetime(_) => DATETIME_ATTR,
171 EventAttribute::Subject(_) => SUBJECT_ATTR,
172 EventAttribute::SenderName(_) => SENDER_NAME_ATTR,
173 EventAttribute::Priority(_) => PRIORITY_ATTR,
174 }
175 }
176
177 fn xml_attribute_value(&self) -> String {
178 match self {
179 EventAttribute::Type(v) => v.to_string(),
180 EventAttribute::Handle(v) => hex::encode(v.to_be_bytes()),
181 EventAttribute::Folder(v) => v.into(),
182 EventAttribute::OldFolder(v) => v.into(),
183 EventAttribute::MessageType(v) => v.to_string(),
184 EventAttribute::Datetime(v) => v.format(ISO_8601_TIME_FORMAT).to_string(),
185 EventAttribute::Subject(v) => v.to_string(),
186 EventAttribute::SenderName(v) => v.to_string(),
187 EventAttribute::Priority(v) => bool_to_string(*v),
188 }
189 }
190
191 fn add_to_notification(&self, notification: &mut Notification) -> Result<(), Error> {
193 match self {
194 EventAttribute::Type(type_) => notification.type_ = Some((*type_).into()),
195 EventAttribute::Handle(h) => notification.message_handle = Some(*h),
196 EventAttribute::Folder(name) => notification.folder = Some(name.clone()),
197 EventAttribute::MessageType(type_) => {
199 notification.message_type = Some((*type_).into());
200 }
201 EventAttribute::Datetime(datetime) => {
202 let timestamp_nanos = datetime
203 .and_utc()
204 .timestamp_nanos_opt()
205 .ok_or_else(|| Error::invalid_data(datetime))?;
206 notification.timestamp = Some(timestamp_nanos);
207 }
208 EventAttribute::Subject(value) => notification.subject = Some(value.to_string()),
209 EventAttribute::SenderName(value) => {
210 notification.sender =
211 Some(Audience { name: Some(value.to_string()), ..Default::default() })
212 }
213 EventAttribute::Priority(value) => notification.priority = Some(*value),
214 _ => {}
215 };
216 Ok(())
217 }
218
219 fn version(&self) -> EventReportVersion {
221 match self {
222 &EventAttribute::Datetime(_)
223 | &EventAttribute::Subject(_)
224 | &EventAttribute::SenderName(_)
225 | &EventAttribute::Priority(_) => EventReportVersion::V1_1,
226 _other => EventReportVersion::V1_0,
227 }
228 }
229
230 fn is_new_message_attribute(&self) -> bool {
234 if self.version() == EventReportVersion::V1_1 {
235 return true;
236 }
237 false
238 }
239
240 fn validate_v1_0(attrs: &Vec<EventAttribute>) -> Result<(), Error> {
242 if let Some(a) = attrs.iter().find(|a| a.version() == EventReportVersion::V1_1) {
244 return Err(Error::invalid_data(a.xml_attribute_name()));
245 }
246 Ok(())
247 }
248}
249
250impl TryFrom<&OwnedAttribute> for EventAttribute {
251 type Error = Error;
252
253 fn try_from(src: &OwnedAttribute) -> Result<Self, Error> {
254 let attr_name = src.name.local_name.as_str();
255 let attribute = match attr_name {
256 TYPE_ATTR => Self::Type(str::parse(src.value.as_str())?),
257 HANDLE_ATTR => {
258 if src.value.len() > 16 {
259 return Err(Error::invalid_data(&src.value));
260 }
261 Self::Handle(u64::from_be_bytes(
262 hex::decode(format!("{:0>16}", src.value.as_str()))
263 .map_err(|e| Error::invalid_data(e))?
264 .as_slice()
265 .try_into()
266 .unwrap(),
267 ))
268 }
269 FOLDER_ATTR => Self::Folder(truncate_string(&src.value, 512)),
271 OLD_FOLDER_ATTR => Self::OldFolder(truncate_string(&src.value, 512)),
272 MSG_TYPE_ATTR => Self::MessageType(str::parse(src.value.as_str())?),
273 DATETIME_ATTR => Self::Datetime(
275 NaiveDateTime::parse_from_str(src.value.as_str(), ISO_8601_TIME_FORMAT)
276 .map_err(|e| Error::invalid_data(e))?,
277 ),
278 SUBJECT_ATTR => Self::Subject(truncate_string(&src.value, 256)),
279 SENDER_NAME_ATTR => Self::SenderName(truncate_string(&src.value, 256)),
280 PRIORITY_ATTR => Self::Priority(str_to_bool(&src.value)?),
281 val => return Err(Error::invalid_data(val)),
282 };
283 Ok(attribute)
284 }
285}
286
287#[derive(Debug, PartialEq)]
291pub struct EventReport {
292 version: EventReportVersion,
293 attrs: Vec<EventAttribute>,
294}
295
296impl EventReport {
297 pub fn v1_0(attrs: Vec<EventAttribute>) -> Result<Self, Error> {
299 EventReport::new(EventReportVersion::V1_0, attrs)
300 }
301
302 pub fn v1_1(attrs: Vec<EventAttribute>) -> Result<Self, Error> {
304 EventReport::new(EventReportVersion::V1_1, attrs)
305 }
306
307 fn new(version: EventReportVersion, attrs: Vec<EventAttribute>) -> Result<Self, Error> {
308 let event_report = EventReport { version, attrs };
309 event_report.validate()?;
310 Ok(event_report)
311 }
312
313 pub fn version(&self) -> EventReportVersion {
314 self.version
315 }
316
317 fn validate(&self) -> Result<(), Error> {
318 let type_ = self
321 .attrs
322 .iter()
323 .find_map(|a| if let EventAttribute::Type(t) = a { Some(t) } else { None })
324 .ok_or_else(|| Error::missing_data(TYPE_ATTR))?;
325
326 if type_ != &Type::MessageShift
328 && self.attrs.iter().any(|a| a.xml_attribute_name() == OLD_FOLDER_ATTR)
329 {
330 return Err(Error::invalid_data(
331 "old_folder attribute is only allowed for MessageShift event",
332 ));
333 }
334 match self.version {
335 EventReportVersion::V1_0 => EventAttribute::validate_v1_0(&self.attrs)?,
336 EventReportVersion::V1_1 => {
337 if type_ == &Type::NewMessage {
339 return Ok(());
340 }
341 if self.attrs.iter().any(|a| a.is_new_message_attribute()) {
344 return Err(Error::invalid_data(
345 "contains attribute only allowed in NewMessage event",
346 ));
347 }
348 }
349 }
350 Ok(())
351 }
352
353 fn check_map_event_report_element(element: XmlEvent) -> Result<EventReportVersion, Error> {
356 let XmlEvent::StartElement { ref name, ref attributes, .. } = element else {
357 return Err(Error::invalid_data(format!("{element:?}")));
358 };
359
360 if name.local_name != EVENT_REPORT_ELEM {
361 return Err(Error::invalid_data(&name.local_name));
362 }
363
364 let version_attr = &attributes
365 .iter()
366 .find(|a| a.name.local_name == VERSION_ATTR)
367 .ok_or_else(|| Error::MissingData(VERSION_ATTR.to_string()))?
368 .value;
369 str::parse(version_attr.as_str())
370 }
371
372 fn write<W: std::io::Write>(&self, writer: &mut EventWriter<W>) -> Result<(), Error> {
373 let mut builder = XmlWriteEvent::start_element(EVENT_ELEM);
374 let attr_pairs: Vec<_> =
375 self.attrs.iter().map(|a| (a.xml_attribute_name(), a.xml_attribute_value())).collect();
376 for a in &attr_pairs {
377 builder = builder.attr(a.0, a.1.as_str());
378 }
379 writer.write(builder)?;
380 Ok(writer.write(XmlWriteEvent::end_element())?)
381 }
382}
383
384impl TryFrom<(XmlEvent, EventReportVersion)> for EventReport {
385 type Error = Error;
386 fn try_from(src: (XmlEvent, EventReportVersion)) -> Result<Self, Error> {
387 let XmlEvent::StartElement { ref name, ref attributes, .. } = src.0 else {
388 return Err(Error::InvalidData(format!("{:?}", src)));
389 };
390 if name.local_name.as_str() != EVENT_ELEM {
391 return Err(Error::invalid_data(&name.local_name));
392 }
393 let mut seen_attrs: HashSet<_> = HashSet::new();
394 let mut attrs = vec![];
395
396 attributes.iter().try_for_each(|a| {
397 let attr = EventAttribute::try_from(a)?;
398 if !seen_attrs.insert(std::mem::discriminant(&attr)) {
399 return Err(Error::DuplicateData(a.name.local_name.to_string()));
400 }
401 attrs.push(attr);
402 Ok(())
403 })?;
404
405 let event_report = EventReport { version: src.1, attrs };
406 let _ = event_report.validate()?;
407 Ok(event_report)
408 }
409}
410
411impl TryFrom<&EventReport> for Notification {
412 type Error = Error;
413 fn try_from(value: &EventReport) -> Result<Self, Error> {
414 let mut notification = Notification::default();
415
416 for a in &value.attrs {
417 let _ = a.add_to_notification(&mut notification)?;
418 }
419 Ok(notification)
420 }
421}
422
423impl Parser for EventReport {
424 type Error = Error;
425
426 fn parse<R: std::io::prelude::Read>(buf: R) -> Result<Self, Self::Error> {
428 let mut reader = ParserConfig::new()
429 .ignore_comments(true)
430 .whitespace_to_characters(true)
431 .cdata_to_characters(true)
432 .trim_whitespace(true)
433 .create_reader(buf);
434
435 match reader.next() {
437 Ok(XmlEvent::StartDocument { .. }) => {}
438 Ok(element) => return Err(Error::InvalidData(format!("{:?}", element))),
439 Err(e) => return Err(Error::ReadXml(e)),
440 };
441
442 let mut xml_event = reader.next()?;
444 while matches!(xml_event, XmlEvent::Doctype { .. } | XmlEvent::Comment(_)) {
445 xml_event = reader.next()?;
446 }
447 let version = EventReport::check_map_event_report_element(xml_event)?;
448
449 let mut xml_event: XmlEvent = reader.next()?;
451 while matches!(xml_event, XmlEvent::Doctype { .. } | XmlEvent::Comment(_)) {
452 xml_event = reader.next()?;
453 }
454 let invalid_elem_err = Err(Error::InvalidData(format!("{:?}", xml_event)));
455 let event_report: EventReport = match xml_event {
456 XmlEvent::StartElement { ref name, .. } => match name.local_name.as_str() {
457 EVENT_ELEM => (xml_event, version).try_into()?,
458 _ => return invalid_elem_err,
459 },
460 _ => return invalid_elem_err,
461 };
462
463 let xml_event = reader.next()?;
465 match xml_event {
466 XmlEvent::EndElement { ref name } => {
467 if name.local_name.as_str() != EVENT_ELEM {
468 return Err(Error::InvalidData(format!("{:?}", xml_event)));
469 }
470 }
471 _ => return Err(Error::InvalidData(format!("{:?}", xml_event))),
472 };
473
474 let xml_event = reader.next()?;
476 match xml_event {
477 XmlEvent::EndElement { ref name } => {
478 if name.local_name.as_str() != EVENT_REPORT_ELEM {
479 return Err(Error::InvalidData(format!("{:?}", xml_event)));
480 }
481 }
482 _ => return Err(Error::InvalidData(format!("{:?}", xml_event))),
483 };
484
485 let xml_event = reader.next()?;
487 match xml_event {
488 XmlEvent::EndDocument { .. } => {}
489 _ => return Err(Error::InvalidData(format!("{:?}", xml_event))),
490 };
491
492 Ok(event_report)
493 }
494}
495
496impl Builder for EventReport {
497 type Error = Error;
498
499 fn mime_type(&self) -> String {
501 "application/xml".to_string()
502 }
503
504 fn build<W: std::io::Write>(&self, buf: W) -> core::result::Result<(), Self::Error> {
505 let _ = self.validate()?;
507
508 let mut w = EmitterConfig::new()
509 .write_document_declaration(true)
510 .perform_indent(true)
511 .create_writer(buf);
512
513 let version = self.version().to_string();
515 let event_report =
516 XmlWriteEvent::start_element(EVENT_REPORT_ELEM).attr(VERSION_ATTR, version.as_str());
517 w.write(event_report)?;
518
519 self.write(&mut w)?;
521
522 Ok(w.write(XmlWriteEvent::end_element())?)
524 }
525}
526
527#[cfg(test)]
528mod tests {
529 use super::*;
530
531 use chrono::{NaiveDate, NaiveTime};
532 use fidl_fuchsia_bluetooth_map as fidl_bt_map;
533
534 use std::fs;
535 use std::io::Cursor;
536
537 #[fuchsia::test]
538 fn event_report() {
539 let _event_report = EventReport::v1_0(vec![
540 EventAttribute::Type(Type::NewMessage),
541 EventAttribute::Handle(0x12345678),
542 EventAttribute::Folder("TELECOM/MSG/INBOX".to_string()),
543 EventAttribute::MessageType(MessageType::SmsCdma),
544 ])
545 .expect("should be created");
546
547 let _event_report = EventReport::v1_1(vec![
548 EventAttribute::Type(Type::NewMessage),
549 EventAttribute::Handle(0x12345678),
550 EventAttribute::Folder("TELECOM/MSG/INBOX".to_string()),
551 EventAttribute::MessageType(MessageType::SmsCdma),
552 EventAttribute::Subject("Hello".to_string()),
553 ])
554 .expect("should be created");
555 }
556
557 #[fuchsia::test]
558 fn event_report_fail() {
559 let _ = EventReport::v1_0(vec![
561 EventAttribute::Type(Type::DeliveryFailure),
562 EventAttribute::Handle(0x12345678),
563 EventAttribute::Folder("TELECOM/MSG/INBOX".to_string()),
564 EventAttribute::OldFolder("TELECOM/MSG/SOME".to_string()),
565 EventAttribute::MessageType(MessageType::SmsCdma),
566 ])
567 .expect_err("should fail");
568
569 let _ = EventReport::v1_1(vec![
571 EventAttribute::Type(Type::DeliveryFailure),
572 EventAttribute::Handle(0x12345678),
573 EventAttribute::Folder("TELECOM/MSG/INBOX".to_string()),
574 EventAttribute::MessageType(MessageType::SmsCdma),
575 EventAttribute::Subject("Hello".to_string()),
576 ])
577 .expect_err("should fail");
578 }
579
580 #[fuchsia::test]
581 fn parse_event_report_v1_0_success() {
582 const V1_0_TEST_FILE: &str = "/pkg/data/sample_event_report_v1_0.xml";
583 let bytes = fs::read(V1_0_TEST_FILE).expect("should be ok");
584 let report = EventReport::parse(Cursor::new(bytes)).expect("should be ok");
585 assert_eq!(report.version(), EventReportVersion::V1_0);
586 assert_eq!(
587 report.attrs,
588 vec![
589 EventAttribute::Type(Type::NewMessage),
590 EventAttribute::Handle(0x12345678),
591 EventAttribute::Folder("TELECOM/MSG/INBOX".to_string()),
592 EventAttribute::MessageType(MessageType::SmsCdma),
593 ]
594 );
595 }
596
597 #[fuchsia::test]
598 fn parse_event_report_v1_1_success() {
599 const V1_1_TEST_FILE: &str = "/pkg/data/sample_event_report_v1_1.xml";
600 let bytes = fs::read(V1_1_TEST_FILE).expect("should be ok");
601 let report = EventReport::parse(Cursor::new(bytes)).expect("should be ok");
602 assert_eq!(report.version(), EventReportVersion::V1_1);
603 assert_eq!(
604 report.attrs,
605 vec![
606 EventAttribute::Type(Type::NewMessage),
607 EventAttribute::Handle(0x12345678),
608 EventAttribute::Folder("TELECOM/MSG/INBOX".to_string()),
609 EventAttribute::MessageType(MessageType::SmsCdma),
610 EventAttribute::Subject("Hello".to_string()),
611 EventAttribute::Datetime(NaiveDateTime::new(
612 NaiveDate::from_ymd_opt(2011, 02, 21).unwrap(),
613 NaiveTime::from_hms_opt(13, 05, 10).unwrap(),
614 )),
615 EventAttribute::SenderName("Jamie".to_string()),
616 EventAttribute::Priority(true),
617 ]
618 );
619 }
620
621 #[fuchsia::test]
622 fn parse_event_report_fail() {
623 let bytes = fs::read("/pkg/data/bad_sample.xml").unwrap();
624 let Error::InvalidData(_) =
625 EventReport::parse(Cursor::new(bytes)).expect_err("should have failed")
626 else {
627 panic!("expected failure due to invalid data");
628 };
629
630 let bytes = fs::read("/pkg/data/sample_event_report_v1_2.xml").unwrap();
631 let Error::UnsupportedVersion =
632 EventReport::parse(Cursor::new(bytes)).expect_err("should have failed")
633 else {
634 panic!("expected failure due to unsupported version");
635 };
636
637 let bytes = fs::read("/pkg/data/bad_sample_event_report_v1_0_1.xml").unwrap();
638 let Error::ReadXml(_) =
639 EventReport::parse(Cursor::new(bytes)).expect_err("should have failed")
640 else {
641 panic!("expected failure due to read xml error");
642 };
643
644 let bytes = fs::read("/pkg/data/bad_sample_event_report_v1_0_2.xml").unwrap();
645 let Error::MissingData(_) =
646 EventReport::parse(Cursor::new(bytes)).expect_err("should have failed")
647 else {
648 panic!("expected failure due to missing data");
649 };
650
651 let bytes = fs::read("/pkg/data/bad_sample_event_report_v1_1.xml").unwrap();
652 let Error::InvalidData(_) =
653 EventReport::parse(Cursor::new(bytes)).expect_err("should have failed")
654 else {
655 panic!("expected failure due to invalid data");
656 };
657 }
658
659 #[fuchsia::test]
660 fn build_event_report_v1_0_success() {
661 let event_report = EventReport {
662 version: EventReportVersion::V1_0,
663 attrs: vec![
664 EventAttribute::Type(Type::NewMessage),
665 EventAttribute::Handle(12345678),
666 EventAttribute::Folder("TELECOM/MSG/INBOX".to_string()),
667 EventAttribute::MessageType(MessageType::SmsCdma),
668 ],
669 };
670
671 let mut buf = Vec::new();
672 let _ = event_report.build(&mut buf).expect("should have succeeded");
673 assert_eq!(
674 event_report,
675 EventReport::parse(Cursor::new(buf)).expect("should be valid xml")
676 );
677 }
678
679 #[fuchsia::test]
680 fn build_event_report_v1_1_success() {
681 let event_report = EventReport {
682 version: EventReportVersion::V1_1,
683 attrs: vec![
684 EventAttribute::Type(Type::NewMessage),
685 EventAttribute::Handle(12345678),
686 EventAttribute::Folder("TELECOM/MSG/INBOX".to_string()),
687 EventAttribute::MessageType(MessageType::SmsCdma),
688 EventAttribute::Subject("Hello".to_string()),
689 EventAttribute::Datetime(NaiveDateTime::new(
690 NaiveDate::from_ymd_opt(2011, 02, 21).unwrap(),
691 NaiveTime::from_hms_opt(13, 05, 10).unwrap(),
692 )),
693 EventAttribute::SenderName("Jamie".to_string()),
694 EventAttribute::Priority(true),
695 ],
696 };
697
698 let mut buf = Vec::new();
699 event_report.build(&mut buf).expect("should have succeeded");
700 assert_eq!(
701 event_report,
702 EventReport::parse(Cursor::new(buf)).expect("should be valid xml")
703 );
704 }
705
706 #[fuchsia::test]
707 fn build_event_report_fail() {
708 let event_report = EventReport {
710 version: EventReportVersion::V1_0,
711 attrs: vec![
712 EventAttribute::Handle(12345678),
713 EventAttribute::Folder("TELECOM/MSG/INBOX".to_string()),
714 EventAttribute::MessageType(MessageType::SmsCdma),
715 ],
716 };
717 let mut buf = Vec::new();
718 let _ = event_report.build(&mut buf).expect_err("should have failed");
719
720 let event_report = EventReport {
722 version: EventReportVersion::V1_1,
723 attrs: vec![
724 EventAttribute::Type(Type::DeliveryFailure),
725 EventAttribute::Handle(12345678),
726 EventAttribute::Folder("TELECOM/MSG/INBOX".to_string()),
727 EventAttribute::MessageType(MessageType::SmsCdma),
728 EventAttribute::Subject("Hello".to_string()),
729 ],
730 };
731 let mut buf = Vec::new();
732 let _ = event_report.build(&mut buf).expect_err("should have failed");
733 }
734
735 #[fuchsia::test]
736 fn notification() {
737 let event_report = EventReport::v1_1(vec![
738 EventAttribute::Type(Type::NewMessage),
739 EventAttribute::Handle(12345678),
740 EventAttribute::Folder("TELECOM/MSG/INBOX".to_string()),
741 EventAttribute::MessageType(MessageType::SmsCdma),
742 EventAttribute::Datetime(NaiveDateTime::new(
743 NaiveDate::from_ymd_opt(2000, 01, 09).unwrap(),
744 NaiveTime::from_hms_opt(01, 09, 19).unwrap(),
745 )),
746 ])
747 .unwrap();
748
749 let notification: Notification = (&event_report).try_into().expect("should succeed");
751 assert_eq!(
752 notification,
753 Notification {
754 type_: Some(NotificationType::NewMessage),
755 message_handle: Some(12345678),
756 folder: Some("TELECOM/MSG/INBOX".to_string()),
757 message_type: Some(fidl_bt_map::MessageType::SMS_CDMA),
758 timestamp: Some(947380159000000000),
759 ..Default::default()
760 }
761 );
762 }
763
764 #[fuchsia::test]
765 fn notification_fail() {
766 let event_report = EventReport::v1_1(vec![
767 EventAttribute::Type(Type::NewMessage),
768 EventAttribute::Handle(12345678),
769 EventAttribute::Folder("TELECOM/MSG/INBOX".to_string()),
770 EventAttribute::MessageType(MessageType::SmsCdma),
771 EventAttribute::Datetime(NaiveDateTime::new(
772 NaiveDate::from_ymd_opt(1500, 02, 21).unwrap(),
774 NaiveTime::from_hms_opt(13, 05, 10).unwrap(),
775 )),
776 ])
777 .unwrap();
778
779 let res: Result<Notification, _> = (&event_report).try_into();
781 let _ = res.expect_err("should have failed");
782 }
783}