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 fn supports_cov(&self) -> bool {
238 true
239 }
240}
241
242pub struct LifeSafetyZoneObject {
252 oid: ObjectIdentifier,
253 name: String,
254 description: String,
255 present_value: u32,
257 mode: u32,
259 silenced: u32,
261 operation_expected: u32,
263 zone_members: Vec<ObjectIdentifier>,
265 event_state: u32,
267 status_flags: StatusFlags,
268 out_of_service: bool,
269 reliability: u32,
271}
272
273impl LifeSafetyZoneObject {
274 pub fn new(instance: u32, name: impl Into<String>) -> Result<Self, Error> {
279 let oid = ObjectIdentifier::new(ObjectType::LIFE_SAFETY_ZONE, instance)?;
280 Ok(Self {
281 oid,
282 name: name.into(),
283 description: String::new(),
284 present_value: 0, mode: 0, silenced: 0, operation_expected: 0, zone_members: Vec::new(),
289 event_state: 0, status_flags: StatusFlags::empty(),
291 out_of_service: false,
292 reliability: 0,
293 })
294 }
295
296 pub fn set_present_value(&mut self, state: u32) {
298 self.present_value = state;
299 }
300
301 pub fn set_mode(&mut self, mode: u32) {
303 self.mode = mode;
304 }
305
306 pub fn set_description(&mut self, desc: impl Into<String>) {
308 self.description = desc.into();
309 }
310
311 pub fn add_zone_member(&mut self, point_oid: ObjectIdentifier) {
313 self.zone_members.push(point_oid);
314 }
315}
316
317impl BACnetObject for LifeSafetyZoneObject {
318 fn object_identifier(&self) -> ObjectIdentifier {
319 self.oid
320 }
321
322 fn object_name(&self) -> &str {
323 &self.name
324 }
325
326 fn read_property(
327 &self,
328 property: PropertyIdentifier,
329 array_index: Option<u32>,
330 ) -> Result<PropertyValue, Error> {
331 if let Some(result) = read_common_properties!(self, property, array_index) {
332 return result;
333 }
334 match property {
335 p if p == PropertyIdentifier::OBJECT_TYPE => Ok(PropertyValue::Enumerated(
336 ObjectType::LIFE_SAFETY_ZONE.to_raw(),
337 )),
338 p if p == PropertyIdentifier::PRESENT_VALUE => {
339 Ok(PropertyValue::Enumerated(self.present_value))
340 }
341 p if p == PropertyIdentifier::MODE => Ok(PropertyValue::Enumerated(self.mode)),
342 p if p == PropertyIdentifier::SILENCED => Ok(PropertyValue::Enumerated(self.silenced)),
343 p if p == PropertyIdentifier::OPERATION_EXPECTED => {
344 Ok(PropertyValue::Enumerated(self.operation_expected))
345 }
346 p if p == PropertyIdentifier::ZONE_MEMBERS => Ok(PropertyValue::List(
347 self.zone_members
348 .iter()
349 .map(|oid| PropertyValue::ObjectIdentifier(*oid))
350 .collect(),
351 )),
352 p if p == PropertyIdentifier::EVENT_STATE => {
353 Ok(PropertyValue::Enumerated(self.event_state))
354 }
355 _ => Err(common::unknown_property_error()),
356 }
357 }
358
359 fn write_property(
360 &mut self,
361 property: PropertyIdentifier,
362 _array_index: Option<u32>,
363 value: PropertyValue,
364 _priority: Option<u8>,
365 ) -> Result<(), Error> {
366 if property == PropertyIdentifier::PRESENT_VALUE {
368 return Err(common::write_access_denied_error());
369 }
370 if property == PropertyIdentifier::MODE {
371 if let PropertyValue::Enumerated(v) = value {
372 self.mode = v;
373 return Ok(());
374 }
375 return Err(common::invalid_data_type_error());
376 }
377 if property == PropertyIdentifier::SILENCED {
378 if let PropertyValue::Enumerated(v) = value {
379 self.silenced = v;
380 return Ok(());
381 }
382 return Err(common::invalid_data_type_error());
383 }
384 if property == PropertyIdentifier::OPERATION_EXPECTED {
385 if let PropertyValue::Enumerated(v) = value {
386 self.operation_expected = v;
387 return Ok(());
388 }
389 return Err(common::invalid_data_type_error());
390 }
391 if let Some(result) =
392 common::write_out_of_service(&mut self.out_of_service, property, &value)
393 {
394 return result;
395 }
396 if let Some(result) = common::write_description(&mut self.description, property, &value) {
397 return result;
398 }
399 Err(common::write_access_denied_error())
400 }
401
402 fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
403 static PROPS: &[PropertyIdentifier] = &[
404 PropertyIdentifier::OBJECT_IDENTIFIER,
405 PropertyIdentifier::OBJECT_NAME,
406 PropertyIdentifier::OBJECT_TYPE,
407 PropertyIdentifier::DESCRIPTION,
408 PropertyIdentifier::PRESENT_VALUE,
409 PropertyIdentifier::MODE,
410 PropertyIdentifier::SILENCED,
411 PropertyIdentifier::OPERATION_EXPECTED,
412 PropertyIdentifier::ZONE_MEMBERS,
413 PropertyIdentifier::EVENT_STATE,
414 PropertyIdentifier::STATUS_FLAGS,
415 PropertyIdentifier::OUT_OF_SERVICE,
416 PropertyIdentifier::RELIABILITY,
417 ];
418 Cow::Borrowed(PROPS)
419 }
420
421 fn supports_cov(&self) -> bool {
422 true
423 }
424}
425
426#[cfg(test)]
431mod tests {
432 use super::*;
433 use bacnet_types::enums::{LifeSafetyMode, LifeSafetyState, ObjectType};
434
435 #[test]
440 fn point_object_type() {
441 let pt = LifeSafetyPointObject::new(1, "LSP-1").unwrap();
442 assert_eq!(
443 pt.object_identifier().object_type(),
444 ObjectType::LIFE_SAFETY_POINT
445 );
446 assert_eq!(pt.object_identifier().instance_number(), 1);
447 assert_eq!(pt.object_name(), "LSP-1");
448 }
449
450 #[test]
451 fn point_read_present_value_default() {
452 let pt = LifeSafetyPointObject::new(1, "LSP-1").unwrap();
453 let val = pt
454 .read_property(PropertyIdentifier::PRESENT_VALUE, None)
455 .unwrap();
456 assert_eq!(
457 val,
458 PropertyValue::Enumerated(LifeSafetyState::QUIET.to_raw())
459 );
460 }
461
462 #[test]
463 fn point_set_and_read_present_value() {
464 let mut pt = LifeSafetyPointObject::new(1, "LSP-1").unwrap();
465 pt.set_present_value(LifeSafetyState::ALARM.to_raw());
466 let val = pt
467 .read_property(PropertyIdentifier::PRESENT_VALUE, None)
468 .unwrap();
469 assert_eq!(
470 val,
471 PropertyValue::Enumerated(LifeSafetyState::ALARM.to_raw())
472 );
473 }
474
475 #[test]
476 fn point_present_value_write_denied() {
477 let mut pt = LifeSafetyPointObject::new(1, "LSP-1").unwrap();
478 let result = pt.write_property(
479 PropertyIdentifier::PRESENT_VALUE,
480 None,
481 PropertyValue::Enumerated(2),
482 None,
483 );
484 assert!(result.is_err());
485 }
486
487 #[test]
488 fn point_read_mode_default() {
489 let pt = LifeSafetyPointObject::new(1, "LSP-1").unwrap();
490 let val = pt.read_property(PropertyIdentifier::MODE, None).unwrap();
491 assert_eq!(val, PropertyValue::Enumerated(LifeSafetyMode::OFF.to_raw()));
492 }
493
494 #[test]
495 fn point_set_mode() {
496 let mut pt = LifeSafetyPointObject::new(1, "LSP-1").unwrap();
497 pt.set_mode(LifeSafetyMode::ON.to_raw());
498 let val = pt.read_property(PropertyIdentifier::MODE, None).unwrap();
499 assert_eq!(val, PropertyValue::Enumerated(LifeSafetyMode::ON.to_raw()));
500 }
501
502 #[test]
503 fn point_write_mode() {
504 let mut pt = LifeSafetyPointObject::new(1, "LSP-1").unwrap();
505 pt.write_property(
506 PropertyIdentifier::MODE,
507 None,
508 PropertyValue::Enumerated(LifeSafetyMode::ARMED.to_raw()),
509 None,
510 )
511 .unwrap();
512 let val = pt.read_property(PropertyIdentifier::MODE, None).unwrap();
513 assert_eq!(
514 val,
515 PropertyValue::Enumerated(LifeSafetyMode::ARMED.to_raw())
516 );
517 }
518
519 #[test]
520 fn point_read_silenced_default() {
521 let pt = LifeSafetyPointObject::new(1, "LSP-1").unwrap();
522 let val = pt
523 .read_property(PropertyIdentifier::SILENCED, None)
524 .unwrap();
525 assert_eq!(val, PropertyValue::Enumerated(0)); }
527
528 #[test]
529 fn point_read_tracking_value() {
530 let mut pt = LifeSafetyPointObject::new(1, "LSP-1").unwrap();
531 pt.set_tracking_value(LifeSafetyState::PRE_ALARM.to_raw());
532 let val = pt
533 .read_property(PropertyIdentifier::TRACKING_VALUE, None)
534 .unwrap();
535 assert_eq!(
536 val,
537 PropertyValue::Enumerated(LifeSafetyState::PRE_ALARM.to_raw())
538 );
539 }
540
541 #[test]
542 fn point_read_direct_reading() {
543 let mut pt = LifeSafetyPointObject::new(1, "LSP-1").unwrap();
544 pt.set_direct_reading(42.5);
545 let val = pt
546 .read_property(PropertyIdentifier::DIRECT_READING, None)
547 .unwrap();
548 assert_eq!(val, PropertyValue::Real(42.5));
549 }
550
551 #[test]
552 fn point_read_maintenance_required() {
553 let pt = LifeSafetyPointObject::new(1, "LSP-1").unwrap();
554 let val = pt
555 .read_property(PropertyIdentifier::MAINTENANCE_REQUIRED, None)
556 .unwrap();
557 assert_eq!(val, PropertyValue::Boolean(false));
558 }
559
560 #[test]
561 fn point_add_member_and_read() {
562 let mut pt = LifeSafetyPointObject::new(1, "LSP-1").unwrap();
563 let zone1 = ObjectIdentifier::new(ObjectType::LIFE_SAFETY_ZONE, 1).unwrap();
564 let zone2 = ObjectIdentifier::new(ObjectType::LIFE_SAFETY_ZONE, 2).unwrap();
565 pt.add_member(zone1);
566 pt.add_member(zone2);
567
568 let val = pt
569 .read_property(PropertyIdentifier::MEMBER_OF, None)
570 .unwrap();
571 assert_eq!(
572 val,
573 PropertyValue::List(vec![
574 PropertyValue::ObjectIdentifier(zone1),
575 PropertyValue::ObjectIdentifier(zone2),
576 ])
577 );
578 }
579
580 #[test]
581 fn point_member_of_empty() {
582 let pt = LifeSafetyPointObject::new(1, "LSP-1").unwrap();
583 let val = pt
584 .read_property(PropertyIdentifier::MEMBER_OF, None)
585 .unwrap();
586 assert_eq!(val, PropertyValue::List(vec![]));
587 }
588
589 #[test]
590 fn point_read_event_state_default() {
591 let pt = LifeSafetyPointObject::new(1, "LSP-1").unwrap();
592 let val = pt
593 .read_property(PropertyIdentifier::EVENT_STATE, None)
594 .unwrap();
595 assert_eq!(val, PropertyValue::Enumerated(0)); }
597
598 #[test]
599 fn point_read_object_type() {
600 let pt = LifeSafetyPointObject::new(1, "LSP-1").unwrap();
601 let val = pt
602 .read_property(PropertyIdentifier::OBJECT_TYPE, None)
603 .unwrap();
604 assert_eq!(
605 val,
606 PropertyValue::Enumerated(ObjectType::LIFE_SAFETY_POINT.to_raw())
607 );
608 }
609
610 #[test]
611 fn point_property_list() {
612 let pt = LifeSafetyPointObject::new(1, "LSP-1").unwrap();
613 let props = pt.property_list();
614 assert!(props.contains(&PropertyIdentifier::PRESENT_VALUE));
615 assert!(props.contains(&PropertyIdentifier::MODE));
616 assert!(props.contains(&PropertyIdentifier::SILENCED));
617 assert!(props.contains(&PropertyIdentifier::OPERATION_EXPECTED));
618 assert!(props.contains(&PropertyIdentifier::TRACKING_VALUE));
619 assert!(props.contains(&PropertyIdentifier::MEMBER_OF));
620 assert!(props.contains(&PropertyIdentifier::DIRECT_READING));
621 assert!(props.contains(&PropertyIdentifier::MAINTENANCE_REQUIRED));
622 assert!(props.contains(&PropertyIdentifier::EVENT_STATE));
623 assert!(props.contains(&PropertyIdentifier::STATUS_FLAGS));
624 assert!(props.contains(&PropertyIdentifier::OUT_OF_SERVICE));
625 assert!(props.contains(&PropertyIdentifier::RELIABILITY));
626 }
627
628 #[test]
629 fn point_write_mode_wrong_type() {
630 let mut pt = LifeSafetyPointObject::new(1, "LSP-1").unwrap();
631 let result = pt.write_property(
632 PropertyIdentifier::MODE,
633 None,
634 PropertyValue::Real(1.0),
635 None,
636 );
637 assert!(result.is_err());
638 }
639
640 #[test]
645 fn zone_object_type() {
646 let z = LifeSafetyZoneObject::new(1, "LSZ-1").unwrap();
647 assert_eq!(
648 z.object_identifier().object_type(),
649 ObjectType::LIFE_SAFETY_ZONE
650 );
651 assert_eq!(z.object_identifier().instance_number(), 1);
652 assert_eq!(z.object_name(), "LSZ-1");
653 }
654
655 #[test]
656 fn zone_read_present_value_default() {
657 let z = LifeSafetyZoneObject::new(1, "LSZ-1").unwrap();
658 let val = z
659 .read_property(PropertyIdentifier::PRESENT_VALUE, None)
660 .unwrap();
661 assert_eq!(
662 val,
663 PropertyValue::Enumerated(LifeSafetyState::QUIET.to_raw())
664 );
665 }
666
667 #[test]
668 fn zone_set_and_read_present_value() {
669 let mut z = LifeSafetyZoneObject::new(1, "LSZ-1").unwrap();
670 z.set_present_value(LifeSafetyState::ALARM.to_raw());
671 let val = z
672 .read_property(PropertyIdentifier::PRESENT_VALUE, None)
673 .unwrap();
674 assert_eq!(
675 val,
676 PropertyValue::Enumerated(LifeSafetyState::ALARM.to_raw())
677 );
678 }
679
680 #[test]
681 fn zone_present_value_write_denied() {
682 let mut z = LifeSafetyZoneObject::new(1, "LSZ-1").unwrap();
683 let result = z.write_property(
684 PropertyIdentifier::PRESENT_VALUE,
685 None,
686 PropertyValue::Enumerated(2),
687 None,
688 );
689 assert!(result.is_err());
690 }
691
692 #[test]
693 fn zone_read_mode_default() {
694 let z = LifeSafetyZoneObject::new(1, "LSZ-1").unwrap();
695 let val = z.read_property(PropertyIdentifier::MODE, None).unwrap();
696 assert_eq!(val, PropertyValue::Enumerated(LifeSafetyMode::OFF.to_raw()));
697 }
698
699 #[test]
700 fn zone_set_mode() {
701 let mut z = LifeSafetyZoneObject::new(1, "LSZ-1").unwrap();
702 z.set_mode(LifeSafetyMode::ARMED.to_raw());
703 let val = z.read_property(PropertyIdentifier::MODE, None).unwrap();
704 assert_eq!(
705 val,
706 PropertyValue::Enumerated(LifeSafetyMode::ARMED.to_raw())
707 );
708 }
709
710 #[test]
711 fn zone_add_zone_member_and_read() {
712 let mut z = LifeSafetyZoneObject::new(1, "LSZ-1").unwrap();
713 let pt1 = ObjectIdentifier::new(ObjectType::LIFE_SAFETY_POINT, 1).unwrap();
714 let pt2 = ObjectIdentifier::new(ObjectType::LIFE_SAFETY_POINT, 2).unwrap();
715 let pt3 = ObjectIdentifier::new(ObjectType::LIFE_SAFETY_POINT, 3).unwrap();
716 z.add_zone_member(pt1);
717 z.add_zone_member(pt2);
718 z.add_zone_member(pt3);
719
720 let val = z
721 .read_property(PropertyIdentifier::ZONE_MEMBERS, None)
722 .unwrap();
723 assert_eq!(
724 val,
725 PropertyValue::List(vec![
726 PropertyValue::ObjectIdentifier(pt1),
727 PropertyValue::ObjectIdentifier(pt2),
728 PropertyValue::ObjectIdentifier(pt3),
729 ])
730 );
731 }
732
733 #[test]
734 fn zone_members_empty() {
735 let z = LifeSafetyZoneObject::new(1, "LSZ-1").unwrap();
736 let val = z
737 .read_property(PropertyIdentifier::ZONE_MEMBERS, None)
738 .unwrap();
739 assert_eq!(val, PropertyValue::List(vec![]));
740 }
741
742 #[test]
743 fn zone_read_event_state_default() {
744 let z = LifeSafetyZoneObject::new(1, "LSZ-1").unwrap();
745 let val = z
746 .read_property(PropertyIdentifier::EVENT_STATE, None)
747 .unwrap();
748 assert_eq!(val, PropertyValue::Enumerated(0)); }
750
751 #[test]
752 fn zone_read_object_type() {
753 let z = LifeSafetyZoneObject::new(1, "LSZ-1").unwrap();
754 let val = z
755 .read_property(PropertyIdentifier::OBJECT_TYPE, None)
756 .unwrap();
757 assert_eq!(
758 val,
759 PropertyValue::Enumerated(ObjectType::LIFE_SAFETY_ZONE.to_raw())
760 );
761 }
762
763 #[test]
764 fn zone_property_list() {
765 let z = LifeSafetyZoneObject::new(1, "LSZ-1").unwrap();
766 let props = z.property_list();
767 assert!(props.contains(&PropertyIdentifier::PRESENT_VALUE));
768 assert!(props.contains(&PropertyIdentifier::MODE));
769 assert!(props.contains(&PropertyIdentifier::SILENCED));
770 assert!(props.contains(&PropertyIdentifier::OPERATION_EXPECTED));
771 assert!(props.contains(&PropertyIdentifier::ZONE_MEMBERS));
772 assert!(props.contains(&PropertyIdentifier::EVENT_STATE));
773 assert!(props.contains(&PropertyIdentifier::STATUS_FLAGS));
774 assert!(props.contains(&PropertyIdentifier::OUT_OF_SERVICE));
775 assert!(props.contains(&PropertyIdentifier::RELIABILITY));
776 }
777
778 #[test]
779 fn zone_write_mode() {
780 let mut z = LifeSafetyZoneObject::new(1, "LSZ-1").unwrap();
781 z.write_property(
782 PropertyIdentifier::MODE,
783 None,
784 PropertyValue::Enumerated(LifeSafetyMode::ON.to_raw()),
785 None,
786 )
787 .unwrap();
788 let val = z.read_property(PropertyIdentifier::MODE, None).unwrap();
789 assert_eq!(val, PropertyValue::Enumerated(LifeSafetyMode::ON.to_raw()));
790 }
791
792 #[test]
793 fn zone_write_out_of_service() {
794 let mut z = LifeSafetyZoneObject::new(1, "LSZ-1").unwrap();
795 z.write_property(
796 PropertyIdentifier::OUT_OF_SERVICE,
797 None,
798 PropertyValue::Boolean(true),
799 None,
800 )
801 .unwrap();
802 let val = z
803 .read_property(PropertyIdentifier::OUT_OF_SERVICE, None)
804 .unwrap();
805 assert_eq!(val, PropertyValue::Boolean(true));
806 }
807
808 #[test]
809 fn zone_write_unknown_property_denied() {
810 let mut z = LifeSafetyZoneObject::new(1, "LSZ-1").unwrap();
811 let result = z.write_property(
812 PropertyIdentifier::TRACKING_VALUE,
813 None,
814 PropertyValue::Enumerated(0),
815 None,
816 );
817 assert!(result.is_err());
818 }
819}