1use bacnet_types::enums::{ObjectType, PropertyIdentifier};
5use bacnet_types::error::Error;
6use bacnet_types::primitives::{ObjectIdentifier, PropertyValue, StatusFlags};
7use std::borrow::Cow;
8
9use crate::common::{self, read_common_properties};
10use crate::traits::BACnetObject;
11
12pub struct LifeSafetyPointObject {
22 oid: ObjectIdentifier,
23 name: String,
24 description: String,
25 present_value: u32,
27 mode: u32,
29 silenced: u32,
31 operation_expected: u32,
33 tracking_value: u32,
35 member_of: Vec<ObjectIdentifier>,
37 direct_reading: f32,
39 maintenance_required: bool,
41 event_state: u32,
43 status_flags: StatusFlags,
44 out_of_service: bool,
45 reliability: u32,
47}
48
49impl LifeSafetyPointObject {
50 pub fn new(instance: u32, name: impl Into<String>) -> Result<Self, Error> {
55 let oid = ObjectIdentifier::new(ObjectType::LIFE_SAFETY_POINT, instance)?;
56 Ok(Self {
57 oid,
58 name: name.into(),
59 description: String::new(),
60 present_value: 0, mode: 0, silenced: 0, operation_expected: 0, tracking_value: 0, member_of: Vec::new(),
66 direct_reading: 0.0,
67 maintenance_required: false,
68 event_state: 0, status_flags: StatusFlags::empty(),
70 out_of_service: false,
71 reliability: 0,
72 })
73 }
74
75 pub fn set_present_value(&mut self, state: u32) {
77 self.present_value = state;
78 }
79
80 pub fn set_mode(&mut self, mode: u32) {
82 self.mode = mode;
83 }
84
85 pub fn set_tracking_value(&mut self, state: u32) {
87 self.tracking_value = state;
88 }
89
90 pub fn set_direct_reading(&mut self, value: f32) {
92 self.direct_reading = value;
93 }
94
95 pub fn set_description(&mut self, desc: impl Into<String>) {
97 self.description = desc.into();
98 }
99
100 pub fn add_member(&mut self, zone_oid: ObjectIdentifier) {
102 self.member_of.push(zone_oid);
103 }
104}
105
106impl BACnetObject for LifeSafetyPointObject {
107 fn object_identifier(&self) -> ObjectIdentifier {
108 self.oid
109 }
110
111 fn object_name(&self) -> &str {
112 &self.name
113 }
114
115 fn read_property(
116 &self,
117 property: PropertyIdentifier,
118 array_index: Option<u32>,
119 ) -> Result<PropertyValue, Error> {
120 if let Some(result) = read_common_properties!(self, property, array_index) {
121 return result;
122 }
123 match property {
124 p if p == PropertyIdentifier::OBJECT_TYPE => Ok(PropertyValue::Enumerated(
125 ObjectType::LIFE_SAFETY_POINT.to_raw(),
126 )),
127 p if p == PropertyIdentifier::PRESENT_VALUE => {
128 Ok(PropertyValue::Enumerated(self.present_value))
129 }
130 p if p == PropertyIdentifier::MODE => Ok(PropertyValue::Enumerated(self.mode)),
131 p if p == PropertyIdentifier::SILENCED => Ok(PropertyValue::Enumerated(self.silenced)),
132 p if p == PropertyIdentifier::OPERATION_EXPECTED => {
133 Ok(PropertyValue::Enumerated(self.operation_expected))
134 }
135 p if p == PropertyIdentifier::TRACKING_VALUE => {
136 Ok(PropertyValue::Enumerated(self.tracking_value))
137 }
138 p if p == PropertyIdentifier::MEMBER_OF => Ok(PropertyValue::List(
139 self.member_of
140 .iter()
141 .map(|oid| PropertyValue::ObjectIdentifier(*oid))
142 .collect(),
143 )),
144 p if p == PropertyIdentifier::DIRECT_READING => {
145 Ok(PropertyValue::Real(self.direct_reading))
146 }
147 p if p == PropertyIdentifier::MAINTENANCE_REQUIRED => {
148 Ok(PropertyValue::Boolean(self.maintenance_required))
149 }
150 p if p == PropertyIdentifier::EVENT_STATE => {
151 Ok(PropertyValue::Enumerated(self.event_state))
152 }
153 _ => Err(common::unknown_property_error()),
154 }
155 }
156
157 fn write_property(
158 &mut self,
159 property: PropertyIdentifier,
160 _array_index: Option<u32>,
161 value: PropertyValue,
162 _priority: Option<u8>,
163 ) -> Result<(), Error> {
164 if property == PropertyIdentifier::PRESENT_VALUE {
166 return Err(common::write_access_denied_error());
167 }
168 if property == PropertyIdentifier::MODE {
169 if let PropertyValue::Enumerated(v) = value {
170 self.mode = v;
171 return Ok(());
172 }
173 return Err(common::invalid_data_type_error());
174 }
175 if property == PropertyIdentifier::SILENCED {
176 if let PropertyValue::Enumerated(v) = value {
177 self.silenced = v;
178 return Ok(());
179 }
180 return Err(common::invalid_data_type_error());
181 }
182 if property == PropertyIdentifier::OPERATION_EXPECTED {
183 if let PropertyValue::Enumerated(v) = value {
184 self.operation_expected = v;
185 return Ok(());
186 }
187 return Err(common::invalid_data_type_error());
188 }
189 if property == PropertyIdentifier::DIRECT_READING {
190 if let PropertyValue::Real(v) = value {
191 common::reject_non_finite(v)?;
192 self.direct_reading = v;
193 return Ok(());
194 }
195 return Err(common::invalid_data_type_error());
196 }
197 if property == PropertyIdentifier::MAINTENANCE_REQUIRED {
198 if let PropertyValue::Boolean(v) = value {
199 self.maintenance_required = v;
200 return Ok(());
201 }
202 return Err(common::invalid_data_type_error());
203 }
204 if let Some(result) =
205 common::write_out_of_service(&mut self.out_of_service, property, &value)
206 {
207 return result;
208 }
209 if let Some(result) = common::write_description(&mut self.description, property, &value) {
210 return result;
211 }
212 Err(common::write_access_denied_error())
213 }
214
215 fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
216 static PROPS: &[PropertyIdentifier] = &[
217 PropertyIdentifier::OBJECT_IDENTIFIER,
218 PropertyIdentifier::OBJECT_NAME,
219 PropertyIdentifier::OBJECT_TYPE,
220 PropertyIdentifier::DESCRIPTION,
221 PropertyIdentifier::PRESENT_VALUE,
222 PropertyIdentifier::MODE,
223 PropertyIdentifier::SILENCED,
224 PropertyIdentifier::OPERATION_EXPECTED,
225 PropertyIdentifier::TRACKING_VALUE,
226 PropertyIdentifier::MEMBER_OF,
227 PropertyIdentifier::DIRECT_READING,
228 PropertyIdentifier::MAINTENANCE_REQUIRED,
229 PropertyIdentifier::EVENT_STATE,
230 PropertyIdentifier::STATUS_FLAGS,
231 PropertyIdentifier::OUT_OF_SERVICE,
232 PropertyIdentifier::RELIABILITY,
233 ];
234 Cow::Borrowed(PROPS)
235 }
236}
237
238pub struct LifeSafetyZoneObject {
248 oid: ObjectIdentifier,
249 name: String,
250 description: String,
251 present_value: u32,
253 mode: u32,
255 silenced: u32,
257 operation_expected: u32,
259 zone_members: Vec<ObjectIdentifier>,
261 event_state: u32,
263 status_flags: StatusFlags,
264 out_of_service: bool,
265 reliability: u32,
267}
268
269impl LifeSafetyZoneObject {
270 pub fn new(instance: u32, name: impl Into<String>) -> Result<Self, Error> {
275 let oid = ObjectIdentifier::new(ObjectType::LIFE_SAFETY_ZONE, instance)?;
276 Ok(Self {
277 oid,
278 name: name.into(),
279 description: String::new(),
280 present_value: 0, mode: 0, silenced: 0, operation_expected: 0, zone_members: Vec::new(),
285 event_state: 0, status_flags: StatusFlags::empty(),
287 out_of_service: false,
288 reliability: 0,
289 })
290 }
291
292 pub fn set_present_value(&mut self, state: u32) {
294 self.present_value = state;
295 }
296
297 pub fn set_mode(&mut self, mode: u32) {
299 self.mode = mode;
300 }
301
302 pub fn set_description(&mut self, desc: impl Into<String>) {
304 self.description = desc.into();
305 }
306
307 pub fn add_zone_member(&mut self, point_oid: ObjectIdentifier) {
309 self.zone_members.push(point_oid);
310 }
311}
312
313impl BACnetObject for LifeSafetyZoneObject {
314 fn object_identifier(&self) -> ObjectIdentifier {
315 self.oid
316 }
317
318 fn object_name(&self) -> &str {
319 &self.name
320 }
321
322 fn read_property(
323 &self,
324 property: PropertyIdentifier,
325 array_index: Option<u32>,
326 ) -> Result<PropertyValue, Error> {
327 if let Some(result) = read_common_properties!(self, property, array_index) {
328 return result;
329 }
330 match property {
331 p if p == PropertyIdentifier::OBJECT_TYPE => Ok(PropertyValue::Enumerated(
332 ObjectType::LIFE_SAFETY_ZONE.to_raw(),
333 )),
334 p if p == PropertyIdentifier::PRESENT_VALUE => {
335 Ok(PropertyValue::Enumerated(self.present_value))
336 }
337 p if p == PropertyIdentifier::MODE => Ok(PropertyValue::Enumerated(self.mode)),
338 p if p == PropertyIdentifier::SILENCED => Ok(PropertyValue::Enumerated(self.silenced)),
339 p if p == PropertyIdentifier::OPERATION_EXPECTED => {
340 Ok(PropertyValue::Enumerated(self.operation_expected))
341 }
342 p if p == PropertyIdentifier::ZONE_MEMBERS => Ok(PropertyValue::List(
343 self.zone_members
344 .iter()
345 .map(|oid| PropertyValue::ObjectIdentifier(*oid))
346 .collect(),
347 )),
348 p if p == PropertyIdentifier::EVENT_STATE => {
349 Ok(PropertyValue::Enumerated(self.event_state))
350 }
351 _ => Err(common::unknown_property_error()),
352 }
353 }
354
355 fn write_property(
356 &mut self,
357 property: PropertyIdentifier,
358 _array_index: Option<u32>,
359 value: PropertyValue,
360 _priority: Option<u8>,
361 ) -> Result<(), Error> {
362 if property == PropertyIdentifier::PRESENT_VALUE {
364 return Err(common::write_access_denied_error());
365 }
366 if property == PropertyIdentifier::MODE {
367 if let PropertyValue::Enumerated(v) = value {
368 self.mode = v;
369 return Ok(());
370 }
371 return Err(common::invalid_data_type_error());
372 }
373 if property == PropertyIdentifier::SILENCED {
374 if let PropertyValue::Enumerated(v) = value {
375 self.silenced = v;
376 return Ok(());
377 }
378 return Err(common::invalid_data_type_error());
379 }
380 if property == PropertyIdentifier::OPERATION_EXPECTED {
381 if let PropertyValue::Enumerated(v) = value {
382 self.operation_expected = v;
383 return Ok(());
384 }
385 return Err(common::invalid_data_type_error());
386 }
387 if let Some(result) =
388 common::write_out_of_service(&mut self.out_of_service, property, &value)
389 {
390 return result;
391 }
392 if let Some(result) = common::write_description(&mut self.description, property, &value) {
393 return result;
394 }
395 Err(common::write_access_denied_error())
396 }
397
398 fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
399 static PROPS: &[PropertyIdentifier] = &[
400 PropertyIdentifier::OBJECT_IDENTIFIER,
401 PropertyIdentifier::OBJECT_NAME,
402 PropertyIdentifier::OBJECT_TYPE,
403 PropertyIdentifier::DESCRIPTION,
404 PropertyIdentifier::PRESENT_VALUE,
405 PropertyIdentifier::MODE,
406 PropertyIdentifier::SILENCED,
407 PropertyIdentifier::OPERATION_EXPECTED,
408 PropertyIdentifier::ZONE_MEMBERS,
409 PropertyIdentifier::EVENT_STATE,
410 PropertyIdentifier::STATUS_FLAGS,
411 PropertyIdentifier::OUT_OF_SERVICE,
412 PropertyIdentifier::RELIABILITY,
413 ];
414 Cow::Borrowed(PROPS)
415 }
416}
417
418#[cfg(test)]
423mod tests {
424 use super::*;
425 use bacnet_types::enums::{LifeSafetyMode, LifeSafetyState, ObjectType};
426
427 #[test]
432 fn point_object_type() {
433 let pt = LifeSafetyPointObject::new(1, "LSP-1").unwrap();
434 assert_eq!(
435 pt.object_identifier().object_type(),
436 ObjectType::LIFE_SAFETY_POINT
437 );
438 assert_eq!(pt.object_identifier().instance_number(), 1);
439 assert_eq!(pt.object_name(), "LSP-1");
440 }
441
442 #[test]
443 fn point_read_present_value_default() {
444 let pt = LifeSafetyPointObject::new(1, "LSP-1").unwrap();
445 let val = pt
446 .read_property(PropertyIdentifier::PRESENT_VALUE, None)
447 .unwrap();
448 assert_eq!(
449 val,
450 PropertyValue::Enumerated(LifeSafetyState::QUIET.to_raw())
451 );
452 }
453
454 #[test]
455 fn point_set_and_read_present_value() {
456 let mut pt = LifeSafetyPointObject::new(1, "LSP-1").unwrap();
457 pt.set_present_value(LifeSafetyState::ALARM.to_raw());
458 let val = pt
459 .read_property(PropertyIdentifier::PRESENT_VALUE, None)
460 .unwrap();
461 assert_eq!(
462 val,
463 PropertyValue::Enumerated(LifeSafetyState::ALARM.to_raw())
464 );
465 }
466
467 #[test]
468 fn point_present_value_write_denied() {
469 let mut pt = LifeSafetyPointObject::new(1, "LSP-1").unwrap();
470 let result = pt.write_property(
471 PropertyIdentifier::PRESENT_VALUE,
472 None,
473 PropertyValue::Enumerated(2),
474 None,
475 );
476 assert!(result.is_err());
477 }
478
479 #[test]
480 fn point_read_mode_default() {
481 let pt = LifeSafetyPointObject::new(1, "LSP-1").unwrap();
482 let val = pt.read_property(PropertyIdentifier::MODE, None).unwrap();
483 assert_eq!(val, PropertyValue::Enumerated(LifeSafetyMode::OFF.to_raw()));
484 }
485
486 #[test]
487 fn point_set_mode() {
488 let mut pt = LifeSafetyPointObject::new(1, "LSP-1").unwrap();
489 pt.set_mode(LifeSafetyMode::ON.to_raw());
490 let val = pt.read_property(PropertyIdentifier::MODE, None).unwrap();
491 assert_eq!(val, PropertyValue::Enumerated(LifeSafetyMode::ON.to_raw()));
492 }
493
494 #[test]
495 fn point_write_mode() {
496 let mut pt = LifeSafetyPointObject::new(1, "LSP-1").unwrap();
497 pt.write_property(
498 PropertyIdentifier::MODE,
499 None,
500 PropertyValue::Enumerated(LifeSafetyMode::ARMED.to_raw()),
501 None,
502 )
503 .unwrap();
504 let val = pt.read_property(PropertyIdentifier::MODE, None).unwrap();
505 assert_eq!(
506 val,
507 PropertyValue::Enumerated(LifeSafetyMode::ARMED.to_raw())
508 );
509 }
510
511 #[test]
512 fn point_read_silenced_default() {
513 let pt = LifeSafetyPointObject::new(1, "LSP-1").unwrap();
514 let val = pt
515 .read_property(PropertyIdentifier::SILENCED, None)
516 .unwrap();
517 assert_eq!(val, PropertyValue::Enumerated(0)); }
519
520 #[test]
521 fn point_read_tracking_value() {
522 let mut pt = LifeSafetyPointObject::new(1, "LSP-1").unwrap();
523 pt.set_tracking_value(LifeSafetyState::PRE_ALARM.to_raw());
524 let val = pt
525 .read_property(PropertyIdentifier::TRACKING_VALUE, None)
526 .unwrap();
527 assert_eq!(
528 val,
529 PropertyValue::Enumerated(LifeSafetyState::PRE_ALARM.to_raw())
530 );
531 }
532
533 #[test]
534 fn point_read_direct_reading() {
535 let mut pt = LifeSafetyPointObject::new(1, "LSP-1").unwrap();
536 pt.set_direct_reading(42.5);
537 let val = pt
538 .read_property(PropertyIdentifier::DIRECT_READING, None)
539 .unwrap();
540 assert_eq!(val, PropertyValue::Real(42.5));
541 }
542
543 #[test]
544 fn point_read_maintenance_required() {
545 let pt = LifeSafetyPointObject::new(1, "LSP-1").unwrap();
546 let val = pt
547 .read_property(PropertyIdentifier::MAINTENANCE_REQUIRED, None)
548 .unwrap();
549 assert_eq!(val, PropertyValue::Boolean(false));
550 }
551
552 #[test]
553 fn point_add_member_and_read() {
554 let mut pt = LifeSafetyPointObject::new(1, "LSP-1").unwrap();
555 let zone1 = ObjectIdentifier::new(ObjectType::LIFE_SAFETY_ZONE, 1).unwrap();
556 let zone2 = ObjectIdentifier::new(ObjectType::LIFE_SAFETY_ZONE, 2).unwrap();
557 pt.add_member(zone1);
558 pt.add_member(zone2);
559
560 let val = pt
561 .read_property(PropertyIdentifier::MEMBER_OF, None)
562 .unwrap();
563 assert_eq!(
564 val,
565 PropertyValue::List(vec![
566 PropertyValue::ObjectIdentifier(zone1),
567 PropertyValue::ObjectIdentifier(zone2),
568 ])
569 );
570 }
571
572 #[test]
573 fn point_member_of_empty() {
574 let pt = LifeSafetyPointObject::new(1, "LSP-1").unwrap();
575 let val = pt
576 .read_property(PropertyIdentifier::MEMBER_OF, None)
577 .unwrap();
578 assert_eq!(val, PropertyValue::List(vec![]));
579 }
580
581 #[test]
582 fn point_read_event_state_default() {
583 let pt = LifeSafetyPointObject::new(1, "LSP-1").unwrap();
584 let val = pt
585 .read_property(PropertyIdentifier::EVENT_STATE, None)
586 .unwrap();
587 assert_eq!(val, PropertyValue::Enumerated(0)); }
589
590 #[test]
591 fn point_read_object_type() {
592 let pt = LifeSafetyPointObject::new(1, "LSP-1").unwrap();
593 let val = pt
594 .read_property(PropertyIdentifier::OBJECT_TYPE, None)
595 .unwrap();
596 assert_eq!(
597 val,
598 PropertyValue::Enumerated(ObjectType::LIFE_SAFETY_POINT.to_raw())
599 );
600 }
601
602 #[test]
603 fn point_property_list() {
604 let pt = LifeSafetyPointObject::new(1, "LSP-1").unwrap();
605 let props = pt.property_list();
606 assert!(props.contains(&PropertyIdentifier::PRESENT_VALUE));
607 assert!(props.contains(&PropertyIdentifier::MODE));
608 assert!(props.contains(&PropertyIdentifier::SILENCED));
609 assert!(props.contains(&PropertyIdentifier::OPERATION_EXPECTED));
610 assert!(props.contains(&PropertyIdentifier::TRACKING_VALUE));
611 assert!(props.contains(&PropertyIdentifier::MEMBER_OF));
612 assert!(props.contains(&PropertyIdentifier::DIRECT_READING));
613 assert!(props.contains(&PropertyIdentifier::MAINTENANCE_REQUIRED));
614 assert!(props.contains(&PropertyIdentifier::EVENT_STATE));
615 assert!(props.contains(&PropertyIdentifier::STATUS_FLAGS));
616 assert!(props.contains(&PropertyIdentifier::OUT_OF_SERVICE));
617 assert!(props.contains(&PropertyIdentifier::RELIABILITY));
618 }
619
620 #[test]
621 fn point_write_mode_wrong_type() {
622 let mut pt = LifeSafetyPointObject::new(1, "LSP-1").unwrap();
623 let result = pt.write_property(
624 PropertyIdentifier::MODE,
625 None,
626 PropertyValue::Real(1.0),
627 None,
628 );
629 assert!(result.is_err());
630 }
631
632 #[test]
637 fn zone_object_type() {
638 let z = LifeSafetyZoneObject::new(1, "LSZ-1").unwrap();
639 assert_eq!(
640 z.object_identifier().object_type(),
641 ObjectType::LIFE_SAFETY_ZONE
642 );
643 assert_eq!(z.object_identifier().instance_number(), 1);
644 assert_eq!(z.object_name(), "LSZ-1");
645 }
646
647 #[test]
648 fn zone_read_present_value_default() {
649 let z = LifeSafetyZoneObject::new(1, "LSZ-1").unwrap();
650 let val = z
651 .read_property(PropertyIdentifier::PRESENT_VALUE, None)
652 .unwrap();
653 assert_eq!(
654 val,
655 PropertyValue::Enumerated(LifeSafetyState::QUIET.to_raw())
656 );
657 }
658
659 #[test]
660 fn zone_set_and_read_present_value() {
661 let mut z = LifeSafetyZoneObject::new(1, "LSZ-1").unwrap();
662 z.set_present_value(LifeSafetyState::ALARM.to_raw());
663 let val = z
664 .read_property(PropertyIdentifier::PRESENT_VALUE, None)
665 .unwrap();
666 assert_eq!(
667 val,
668 PropertyValue::Enumerated(LifeSafetyState::ALARM.to_raw())
669 );
670 }
671
672 #[test]
673 fn zone_present_value_write_denied() {
674 let mut z = LifeSafetyZoneObject::new(1, "LSZ-1").unwrap();
675 let result = z.write_property(
676 PropertyIdentifier::PRESENT_VALUE,
677 None,
678 PropertyValue::Enumerated(2),
679 None,
680 );
681 assert!(result.is_err());
682 }
683
684 #[test]
685 fn zone_read_mode_default() {
686 let z = LifeSafetyZoneObject::new(1, "LSZ-1").unwrap();
687 let val = z.read_property(PropertyIdentifier::MODE, None).unwrap();
688 assert_eq!(val, PropertyValue::Enumerated(LifeSafetyMode::OFF.to_raw()));
689 }
690
691 #[test]
692 fn zone_set_mode() {
693 let mut z = LifeSafetyZoneObject::new(1, "LSZ-1").unwrap();
694 z.set_mode(LifeSafetyMode::ARMED.to_raw());
695 let val = z.read_property(PropertyIdentifier::MODE, None).unwrap();
696 assert_eq!(
697 val,
698 PropertyValue::Enumerated(LifeSafetyMode::ARMED.to_raw())
699 );
700 }
701
702 #[test]
703 fn zone_add_zone_member_and_read() {
704 let mut z = LifeSafetyZoneObject::new(1, "LSZ-1").unwrap();
705 let pt1 = ObjectIdentifier::new(ObjectType::LIFE_SAFETY_POINT, 1).unwrap();
706 let pt2 = ObjectIdentifier::new(ObjectType::LIFE_SAFETY_POINT, 2).unwrap();
707 let pt3 = ObjectIdentifier::new(ObjectType::LIFE_SAFETY_POINT, 3).unwrap();
708 z.add_zone_member(pt1);
709 z.add_zone_member(pt2);
710 z.add_zone_member(pt3);
711
712 let val = z
713 .read_property(PropertyIdentifier::ZONE_MEMBERS, None)
714 .unwrap();
715 assert_eq!(
716 val,
717 PropertyValue::List(vec![
718 PropertyValue::ObjectIdentifier(pt1),
719 PropertyValue::ObjectIdentifier(pt2),
720 PropertyValue::ObjectIdentifier(pt3),
721 ])
722 );
723 }
724
725 #[test]
726 fn zone_members_empty() {
727 let z = LifeSafetyZoneObject::new(1, "LSZ-1").unwrap();
728 let val = z
729 .read_property(PropertyIdentifier::ZONE_MEMBERS, None)
730 .unwrap();
731 assert_eq!(val, PropertyValue::List(vec![]));
732 }
733
734 #[test]
735 fn zone_read_event_state_default() {
736 let z = LifeSafetyZoneObject::new(1, "LSZ-1").unwrap();
737 let val = z
738 .read_property(PropertyIdentifier::EVENT_STATE, None)
739 .unwrap();
740 assert_eq!(val, PropertyValue::Enumerated(0)); }
742
743 #[test]
744 fn zone_read_object_type() {
745 let z = LifeSafetyZoneObject::new(1, "LSZ-1").unwrap();
746 let val = z
747 .read_property(PropertyIdentifier::OBJECT_TYPE, None)
748 .unwrap();
749 assert_eq!(
750 val,
751 PropertyValue::Enumerated(ObjectType::LIFE_SAFETY_ZONE.to_raw())
752 );
753 }
754
755 #[test]
756 fn zone_property_list() {
757 let z = LifeSafetyZoneObject::new(1, "LSZ-1").unwrap();
758 let props = z.property_list();
759 assert!(props.contains(&PropertyIdentifier::PRESENT_VALUE));
760 assert!(props.contains(&PropertyIdentifier::MODE));
761 assert!(props.contains(&PropertyIdentifier::SILENCED));
762 assert!(props.contains(&PropertyIdentifier::OPERATION_EXPECTED));
763 assert!(props.contains(&PropertyIdentifier::ZONE_MEMBERS));
764 assert!(props.contains(&PropertyIdentifier::EVENT_STATE));
765 assert!(props.contains(&PropertyIdentifier::STATUS_FLAGS));
766 assert!(props.contains(&PropertyIdentifier::OUT_OF_SERVICE));
767 assert!(props.contains(&PropertyIdentifier::RELIABILITY));
768 }
769
770 #[test]
771 fn zone_write_mode() {
772 let mut z = LifeSafetyZoneObject::new(1, "LSZ-1").unwrap();
773 z.write_property(
774 PropertyIdentifier::MODE,
775 None,
776 PropertyValue::Enumerated(LifeSafetyMode::ON.to_raw()),
777 None,
778 )
779 .unwrap();
780 let val = z.read_property(PropertyIdentifier::MODE, None).unwrap();
781 assert_eq!(val, PropertyValue::Enumerated(LifeSafetyMode::ON.to_raw()));
782 }
783
784 #[test]
785 fn zone_write_out_of_service() {
786 let mut z = LifeSafetyZoneObject::new(1, "LSZ-1").unwrap();
787 z.write_property(
788 PropertyIdentifier::OUT_OF_SERVICE,
789 None,
790 PropertyValue::Boolean(true),
791 None,
792 )
793 .unwrap();
794 let val = z
795 .read_property(PropertyIdentifier::OUT_OF_SERVICE, None)
796 .unwrap();
797 assert_eq!(val, PropertyValue::Boolean(true));
798 }
799
800 #[test]
801 fn zone_write_unknown_property_denied() {
802 let mut z = LifeSafetyZoneObject::new(1, "LSZ-1").unwrap();
803 let result = z.write_property(
804 PropertyIdentifier::TRACKING_VALUE,
805 None,
806 PropertyValue::Enumerated(0),
807 None,
808 );
809 assert!(result.is_err());
810 }
811}