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::event::{ChangeOfStateDetector, EventStateChange};
11use crate::traits::BACnetObject;
12
13pub struct MultiStateInputObject {
22 oid: ObjectIdentifier,
23 name: String,
24 description: String,
25 present_value: u32,
26 number_of_states: u32,
27 out_of_service: bool,
28 status_flags: StatusFlags,
29 reliability: u32,
31 state_text: Vec<String>,
32 alarm_values: Vec<u32>,
34 fault_values: Vec<u32>,
36 event_detector: ChangeOfStateDetector,
38}
39
40impl MultiStateInputObject {
41 pub fn new(
42 instance: u32,
43 name: impl Into<String>,
44 number_of_states: u32,
45 ) -> Result<Self, Error> {
46 let oid = ObjectIdentifier::new(ObjectType::MULTI_STATE_INPUT, instance)?;
47 Ok(Self {
48 oid,
49 name: name.into(),
50 description: String::new(),
51 present_value: 1,
52 number_of_states,
53 out_of_service: false,
54 status_flags: StatusFlags::empty(),
55 reliability: 0,
56 state_text: (1..=number_of_states)
57 .map(|i| format!("State {i}"))
58 .collect(),
59 alarm_values: Vec::new(),
60 fault_values: Vec::new(),
61 event_detector: ChangeOfStateDetector::default(),
62 })
63 }
64
65 pub fn set_alarm_values(&mut self, values: Vec<u32>) {
67 self.alarm_values = values.clone();
68 self.event_detector.alarm_values = values;
69 }
70
71 pub fn set_fault_values(&mut self, values: Vec<u32>) {
73 self.fault_values = values;
74 }
75
76 pub fn set_present_value(&mut self, value: u32) {
78 self.present_value = value;
79 }
80
81 pub fn set_description(&mut self, desc: impl Into<String>) {
83 self.description = desc.into();
84 }
85}
86
87impl BACnetObject for MultiStateInputObject {
88 fn object_identifier(&self) -> ObjectIdentifier {
89 self.oid
90 }
91
92 fn object_name(&self) -> &str {
93 &self.name
94 }
95
96 fn supports_cov(&self) -> bool {
97 true
98 }
99
100 fn evaluate_intrinsic_reporting(&mut self) -> Option<EventStateChange> {
101 self.event_detector.evaluate(self.present_value)
102 }
103
104 fn read_property(
105 &self,
106 property: PropertyIdentifier,
107 array_index: Option<u32>,
108 ) -> Result<PropertyValue, Error> {
109 if let Some(result) = read_common_properties!(self, property, array_index) {
110 return result;
111 }
112 match property {
113 p if p == PropertyIdentifier::OBJECT_TYPE => Ok(PropertyValue::Enumerated(
114 ObjectType::MULTI_STATE_INPUT.to_raw(),
115 )),
116 p if p == PropertyIdentifier::PRESENT_VALUE => {
117 Ok(PropertyValue::Unsigned(self.present_value as u64))
118 }
119 p if p == PropertyIdentifier::EVENT_STATE => Ok(PropertyValue::Enumerated(
120 self.event_detector.event_state.to_raw(),
121 )),
122 p if p == PropertyIdentifier::NUMBER_OF_STATES => {
123 Ok(PropertyValue::Unsigned(self.number_of_states as u64))
124 }
125 p if p == PropertyIdentifier::STATE_TEXT => match array_index {
126 None => Ok(PropertyValue::List(
127 self.state_text
128 .iter()
129 .map(|s| PropertyValue::CharacterString(s.clone()))
130 .collect(),
131 )),
132 Some(0) => Ok(PropertyValue::Unsigned(self.state_text.len() as u64)),
133 Some(idx) if idx >= 1 && (idx as usize) <= self.state_text.len() => Ok(
134 PropertyValue::CharacterString(self.state_text[(idx - 1) as usize].clone()),
135 ),
136 _ => Err(common::invalid_array_index_error()),
137 },
138 p if p == PropertyIdentifier::ALARM_VALUES => Ok(PropertyValue::List(
139 self.alarm_values
140 .iter()
141 .map(|v| PropertyValue::Unsigned(*v as u64))
142 .collect(),
143 )),
144 p if p == PropertyIdentifier::FAULT_VALUES => Ok(PropertyValue::List(
145 self.fault_values
146 .iter()
147 .map(|v| PropertyValue::Unsigned(*v as u64))
148 .collect(),
149 )),
150 p if p == PropertyIdentifier::EVENT_ENABLE => Ok(PropertyValue::BitString {
151 unused_bits: 5,
152 data: vec![self.event_detector.event_enable << 5],
153 }),
154 p if p == PropertyIdentifier::ACKED_TRANSITIONS => Ok(PropertyValue::BitString {
155 unused_bits: 5,
156 data: vec![self.event_detector.acked_transitions << 5],
157 }),
158 p if p == PropertyIdentifier::NOTIFICATION_CLASS => Ok(PropertyValue::Unsigned(
159 self.event_detector.notification_class as u64,
160 )),
161 _ => Err(common::unknown_property_error()),
162 }
163 }
164
165 fn write_property(
166 &mut self,
167 property: PropertyIdentifier,
168 array_index: Option<u32>,
169 value: PropertyValue,
170 _priority: Option<u8>,
171 ) -> Result<(), Error> {
172 if property == PropertyIdentifier::PRESENT_VALUE {
173 if !self.out_of_service {
174 return Err(common::write_access_denied_error());
175 }
176 if let PropertyValue::Unsigned(v) = value {
177 if v < 1 || v > self.number_of_states as u64 {
178 return Err(common::value_out_of_range_error());
179 }
180 self.present_value = v as u32;
181 return Ok(());
182 }
183 return Err(common::invalid_data_type_error());
184 }
185 if property == PropertyIdentifier::STATE_TEXT {
186 match array_index {
187 Some(idx) if idx >= 1 && (idx as usize) <= self.state_text.len() => {
188 if let PropertyValue::CharacterString(s) = value {
189 self.state_text[(idx - 1) as usize] = s;
190 return Ok(());
191 }
192 return Err(common::invalid_data_type_error());
193 }
194 None => return Err(common::write_access_denied_error()),
195 _ => return Err(common::invalid_array_index_error()),
196 }
197 }
198 if let Some(result) =
199 common::write_out_of_service(&mut self.out_of_service, property, &value)
200 {
201 return result;
202 }
203 if let Some(result) = common::write_object_name(&mut self.name, property, &value) {
204 return result;
205 }
206 if let Some(result) = common::write_description(&mut self.description, property, &value) {
207 return result;
208 }
209 Err(common::write_access_denied_error())
210 }
211
212 fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
213 static PROPS: &[PropertyIdentifier] = &[
214 PropertyIdentifier::OBJECT_IDENTIFIER,
215 PropertyIdentifier::OBJECT_NAME,
216 PropertyIdentifier::DESCRIPTION,
217 PropertyIdentifier::OBJECT_TYPE,
218 PropertyIdentifier::PRESENT_VALUE,
219 PropertyIdentifier::STATUS_FLAGS,
220 PropertyIdentifier::EVENT_STATE,
221 PropertyIdentifier::OUT_OF_SERVICE,
222 PropertyIdentifier::NUMBER_OF_STATES,
223 PropertyIdentifier::RELIABILITY,
224 PropertyIdentifier::STATE_TEXT,
225 PropertyIdentifier::ALARM_VALUES,
226 PropertyIdentifier::FAULT_VALUES,
227 ];
228 Cow::Borrowed(PROPS)
229 }
230}
231
232pub struct MultiStateOutputObject {
241 oid: ObjectIdentifier,
242 name: String,
243 description: String,
244 present_value: u32,
245 number_of_states: u32,
246 out_of_service: bool,
247 status_flags: StatusFlags,
248 priority_array: [Option<u32>; 16],
249 relinquish_default: u32,
250 reliability: u32,
252 state_text: Vec<String>,
253 alarm_values: Vec<u32>,
254 fault_values: Vec<u32>,
255 event_detector: ChangeOfStateDetector,
257}
258
259impl MultiStateOutputObject {
260 pub fn new(
261 instance: u32,
262 name: impl Into<String>,
263 number_of_states: u32,
264 ) -> Result<Self, Error> {
265 let oid = ObjectIdentifier::new(ObjectType::MULTI_STATE_OUTPUT, instance)?;
266 Ok(Self {
267 oid,
268 name: name.into(),
269 description: String::new(),
270 present_value: 1,
271 number_of_states,
272 out_of_service: false,
273 status_flags: StatusFlags::empty(),
274 priority_array: [None; 16],
275 relinquish_default: 1,
276 reliability: 0,
277 state_text: (1..=number_of_states)
278 .map(|i| format!("State {i}"))
279 .collect(),
280 alarm_values: Vec::new(),
281 fault_values: Vec::new(),
282 event_detector: ChangeOfStateDetector::default(),
283 })
284 }
285
286 pub fn set_description(&mut self, desc: impl Into<String>) {
288 self.description = desc.into();
289 }
290
291 fn recalculate_present_value(&mut self) {
292 self.present_value =
293 common::recalculate_from_priority_array(&self.priority_array, self.relinquish_default);
294 }
295}
296
297impl BACnetObject for MultiStateOutputObject {
298 fn object_identifier(&self) -> ObjectIdentifier {
299 self.oid
300 }
301
302 fn object_name(&self) -> &str {
303 &self.name
304 }
305
306 fn supports_cov(&self) -> bool {
307 true
308 }
309
310 fn evaluate_intrinsic_reporting(&mut self) -> Option<EventStateChange> {
311 self.event_detector.evaluate(self.present_value)
312 }
313
314 fn read_property(
315 &self,
316 property: PropertyIdentifier,
317 array_index: Option<u32>,
318 ) -> Result<PropertyValue, Error> {
319 if let Some(result) = read_common_properties!(self, property, array_index) {
320 return result;
321 }
322 match property {
323 p if p == PropertyIdentifier::OBJECT_TYPE => Ok(PropertyValue::Enumerated(
324 ObjectType::MULTI_STATE_OUTPUT.to_raw(),
325 )),
326 p if p == PropertyIdentifier::PRESENT_VALUE => {
327 Ok(PropertyValue::Unsigned(self.present_value as u64))
328 }
329 p if p == PropertyIdentifier::EVENT_STATE => Ok(PropertyValue::Enumerated(
330 self.event_detector.event_state.to_raw(),
331 )),
332 p if p == PropertyIdentifier::NUMBER_OF_STATES => {
333 Ok(PropertyValue::Unsigned(self.number_of_states as u64))
334 }
335 p if p == PropertyIdentifier::PRIORITY_ARRAY => {
336 common::read_priority_array!(self, array_index, |v: u32| PropertyValue::Unsigned(
337 v as u64
338 ))
339 }
340 p if p == PropertyIdentifier::RELINQUISH_DEFAULT => {
341 Ok(PropertyValue::Unsigned(self.relinquish_default as u64))
342 }
343 p if p == PropertyIdentifier::CURRENT_COMMAND_PRIORITY => {
344 Ok(common::current_command_priority(&self.priority_array))
345 }
346 p if p == PropertyIdentifier::STATE_TEXT => match array_index {
347 None => Ok(PropertyValue::List(
348 self.state_text
349 .iter()
350 .map(|s| PropertyValue::CharacterString(s.clone()))
351 .collect(),
352 )),
353 Some(0) => Ok(PropertyValue::Unsigned(self.state_text.len() as u64)),
354 Some(idx) if idx >= 1 && (idx as usize) <= self.state_text.len() => Ok(
355 PropertyValue::CharacterString(self.state_text[(idx - 1) as usize].clone()),
356 ),
357 _ => Err(common::invalid_array_index_error()),
358 },
359 p if p == PropertyIdentifier::ALARM_VALUES => Ok(PropertyValue::List(
360 self.alarm_values
361 .iter()
362 .map(|v| PropertyValue::Unsigned(*v as u64))
363 .collect(),
364 )),
365 p if p == PropertyIdentifier::FAULT_VALUES => Ok(PropertyValue::List(
366 self.fault_values
367 .iter()
368 .map(|v| PropertyValue::Unsigned(*v as u64))
369 .collect(),
370 )),
371 p if p == PropertyIdentifier::EVENT_ENABLE => Ok(PropertyValue::BitString {
372 unused_bits: 5,
373 data: vec![self.event_detector.event_enable << 5],
374 }),
375 p if p == PropertyIdentifier::ACKED_TRANSITIONS => Ok(PropertyValue::BitString {
376 unused_bits: 5,
377 data: vec![self.event_detector.acked_transitions << 5],
378 }),
379 p if p == PropertyIdentifier::NOTIFICATION_CLASS => Ok(PropertyValue::Unsigned(
380 self.event_detector.notification_class as u64,
381 )),
382 _ => Err(common::unknown_property_error()),
383 }
384 }
385
386 fn write_property(
387 &mut self,
388 property: PropertyIdentifier,
389 array_index: Option<u32>,
390 value: PropertyValue,
391 priority: Option<u8>,
392 ) -> Result<(), Error> {
393 {
394 let num_states = self.number_of_states;
395 common::write_priority_array_direct!(self, property, array_index, value, |v| {
396 if let PropertyValue::Unsigned(u) = v {
397 if u < 1 || u > num_states as u64 {
398 Err(common::value_out_of_range_error())
399 } else {
400 Ok(u as u32)
401 }
402 } else {
403 Err(common::invalid_data_type_error())
404 }
405 });
406 }
407 if property == PropertyIdentifier::PRESENT_VALUE {
408 let num_states = self.number_of_states;
409 return common::write_priority_array!(self, value, priority, |v| {
410 if let PropertyValue::Unsigned(u) = v {
411 if u < 1 || u > num_states as u64 {
412 Err(common::value_out_of_range_error())
413 } else {
414 Ok(u as u32)
415 }
416 } else {
417 Err(common::invalid_data_type_error())
418 }
419 });
420 }
421 if property == PropertyIdentifier::STATE_TEXT {
422 match array_index {
423 Some(idx) if idx >= 1 && (idx as usize) <= self.state_text.len() => {
424 if let PropertyValue::CharacterString(s) = value {
425 self.state_text[(idx - 1) as usize] = s;
426 return Ok(());
427 }
428 return Err(common::invalid_data_type_error());
429 }
430 None => return Err(common::write_access_denied_error()),
431 _ => return Err(common::invalid_array_index_error()),
432 }
433 }
434 if let Some(result) =
435 common::write_out_of_service(&mut self.out_of_service, property, &value)
436 {
437 return result;
438 }
439 if let Some(result) = common::write_object_name(&mut self.name, property, &value) {
440 return result;
441 }
442 if let Some(result) = common::write_description(&mut self.description, property, &value) {
443 return result;
444 }
445 Err(common::write_access_denied_error())
446 }
447
448 fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
449 static PROPS: &[PropertyIdentifier] = &[
450 PropertyIdentifier::OBJECT_IDENTIFIER,
451 PropertyIdentifier::OBJECT_NAME,
452 PropertyIdentifier::DESCRIPTION,
453 PropertyIdentifier::OBJECT_TYPE,
454 PropertyIdentifier::PRESENT_VALUE,
455 PropertyIdentifier::STATUS_FLAGS,
456 PropertyIdentifier::EVENT_STATE,
457 PropertyIdentifier::OUT_OF_SERVICE,
458 PropertyIdentifier::NUMBER_OF_STATES,
459 PropertyIdentifier::PRIORITY_ARRAY,
460 PropertyIdentifier::RELINQUISH_DEFAULT,
461 PropertyIdentifier::CURRENT_COMMAND_PRIORITY,
462 PropertyIdentifier::RELIABILITY,
463 PropertyIdentifier::STATE_TEXT,
464 PropertyIdentifier::ALARM_VALUES,
465 PropertyIdentifier::FAULT_VALUES,
466 ];
467 Cow::Borrowed(PROPS)
468 }
469}
470
471pub struct MultiStateValueObject {
480 oid: ObjectIdentifier,
481 name: String,
482 description: String,
483 present_value: u32,
484 number_of_states: u32,
485 out_of_service: bool,
486 status_flags: StatusFlags,
487 priority_array: [Option<u32>; 16],
488 relinquish_default: u32,
489 reliability: u32,
491 state_text: Vec<String>,
492 alarm_values: Vec<u32>,
493 fault_values: Vec<u32>,
494 event_detector: ChangeOfStateDetector,
496}
497
498impl MultiStateValueObject {
499 pub fn new(
500 instance: u32,
501 name: impl Into<String>,
502 number_of_states: u32,
503 ) -> Result<Self, Error> {
504 let oid = ObjectIdentifier::new(ObjectType::MULTI_STATE_VALUE, instance)?;
505 Ok(Self {
506 oid,
507 name: name.into(),
508 description: String::new(),
509 present_value: 1,
510 number_of_states,
511 out_of_service: false,
512 status_flags: StatusFlags::empty(),
513 priority_array: [None; 16],
514 relinquish_default: 1,
515 reliability: 0,
516 state_text: (1..=number_of_states)
517 .map(|i| format!("State {i}"))
518 .collect(),
519 alarm_values: Vec::new(),
520 fault_values: Vec::new(),
521 event_detector: ChangeOfStateDetector::default(),
522 })
523 }
524
525 pub fn set_description(&mut self, desc: impl Into<String>) {
527 self.description = desc.into();
528 }
529
530 fn recalculate_present_value(&mut self) {
531 self.present_value =
532 common::recalculate_from_priority_array(&self.priority_array, self.relinquish_default);
533 }
534}
535
536impl BACnetObject for MultiStateValueObject {
537 fn object_identifier(&self) -> ObjectIdentifier {
538 self.oid
539 }
540
541 fn object_name(&self) -> &str {
542 &self.name
543 }
544
545 fn supports_cov(&self) -> bool {
546 true
547 }
548
549 fn evaluate_intrinsic_reporting(&mut self) -> Option<EventStateChange> {
550 self.event_detector.evaluate(self.present_value)
551 }
552
553 fn read_property(
554 &self,
555 property: PropertyIdentifier,
556 array_index: Option<u32>,
557 ) -> Result<PropertyValue, Error> {
558 if let Some(result) = read_common_properties!(self, property, array_index) {
559 return result;
560 }
561 match property {
562 p if p == PropertyIdentifier::OBJECT_TYPE => Ok(PropertyValue::Enumerated(
563 ObjectType::MULTI_STATE_VALUE.to_raw(),
564 )),
565 p if p == PropertyIdentifier::PRESENT_VALUE => {
566 Ok(PropertyValue::Unsigned(self.present_value as u64))
567 }
568 p if p == PropertyIdentifier::EVENT_STATE => Ok(PropertyValue::Enumerated(
569 self.event_detector.event_state.to_raw(),
570 )),
571 p if p == PropertyIdentifier::NUMBER_OF_STATES => {
572 Ok(PropertyValue::Unsigned(self.number_of_states as u64))
573 }
574 p if p == PropertyIdentifier::PRIORITY_ARRAY => {
575 common::read_priority_array!(self, array_index, |v: u32| PropertyValue::Unsigned(
576 v as u64
577 ))
578 }
579 p if p == PropertyIdentifier::RELINQUISH_DEFAULT => {
580 Ok(PropertyValue::Unsigned(self.relinquish_default as u64))
581 }
582 p if p == PropertyIdentifier::CURRENT_COMMAND_PRIORITY => {
583 Ok(common::current_command_priority(&self.priority_array))
584 }
585 p if p == PropertyIdentifier::STATE_TEXT => match array_index {
586 None => Ok(PropertyValue::List(
587 self.state_text
588 .iter()
589 .map(|s| PropertyValue::CharacterString(s.clone()))
590 .collect(),
591 )),
592 Some(0) => Ok(PropertyValue::Unsigned(self.state_text.len() as u64)),
593 Some(idx) if idx >= 1 && (idx as usize) <= self.state_text.len() => Ok(
594 PropertyValue::CharacterString(self.state_text[(idx - 1) as usize].clone()),
595 ),
596 _ => Err(common::invalid_array_index_error()),
597 },
598 p if p == PropertyIdentifier::ALARM_VALUES => Ok(PropertyValue::List(
599 self.alarm_values
600 .iter()
601 .map(|v| PropertyValue::Unsigned(*v as u64))
602 .collect(),
603 )),
604 p if p == PropertyIdentifier::FAULT_VALUES => Ok(PropertyValue::List(
605 self.fault_values
606 .iter()
607 .map(|v| PropertyValue::Unsigned(*v as u64))
608 .collect(),
609 )),
610 p if p == PropertyIdentifier::EVENT_ENABLE => Ok(PropertyValue::BitString {
611 unused_bits: 5,
612 data: vec![self.event_detector.event_enable << 5],
613 }),
614 p if p == PropertyIdentifier::ACKED_TRANSITIONS => Ok(PropertyValue::BitString {
615 unused_bits: 5,
616 data: vec![self.event_detector.acked_transitions << 5],
617 }),
618 p if p == PropertyIdentifier::NOTIFICATION_CLASS => Ok(PropertyValue::Unsigned(
619 self.event_detector.notification_class as u64,
620 )),
621 _ => Err(common::unknown_property_error()),
622 }
623 }
624
625 fn write_property(
626 &mut self,
627 property: PropertyIdentifier,
628 array_index: Option<u32>,
629 value: PropertyValue,
630 priority: Option<u8>,
631 ) -> Result<(), Error> {
632 {
633 let num_states = self.number_of_states;
634 common::write_priority_array_direct!(self, property, array_index, value, |v| {
635 if let PropertyValue::Unsigned(u) = v {
636 if u < 1 || u > num_states as u64 {
637 Err(common::value_out_of_range_error())
638 } else {
639 Ok(u as u32)
640 }
641 } else {
642 Err(common::invalid_data_type_error())
643 }
644 });
645 }
646 if property == PropertyIdentifier::PRESENT_VALUE {
647 let num_states = self.number_of_states;
648 return common::write_priority_array!(self, value, priority, |v| {
649 if let PropertyValue::Unsigned(u) = v {
650 if u < 1 || u > num_states as u64 {
651 Err(common::value_out_of_range_error())
652 } else {
653 Ok(u as u32)
654 }
655 } else {
656 Err(common::invalid_data_type_error())
657 }
658 });
659 }
660 if property == PropertyIdentifier::STATE_TEXT {
661 match array_index {
662 Some(idx) if idx >= 1 && (idx as usize) <= self.state_text.len() => {
663 if let PropertyValue::CharacterString(s) = value {
664 self.state_text[(idx - 1) as usize] = s;
665 return Ok(());
666 }
667 return Err(common::invalid_data_type_error());
668 }
669 None => return Err(common::write_access_denied_error()),
670 _ => return Err(common::invalid_array_index_error()),
671 }
672 }
673 if let Some(result) =
674 common::write_out_of_service(&mut self.out_of_service, property, &value)
675 {
676 return result;
677 }
678 if let Some(result) = common::write_object_name(&mut self.name, property, &value) {
679 return result;
680 }
681 if let Some(result) = common::write_description(&mut self.description, property, &value) {
682 return result;
683 }
684 Err(common::write_access_denied_error())
685 }
686
687 fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
688 static PROPS: &[PropertyIdentifier] = &[
689 PropertyIdentifier::OBJECT_IDENTIFIER,
690 PropertyIdentifier::OBJECT_NAME,
691 PropertyIdentifier::DESCRIPTION,
692 PropertyIdentifier::OBJECT_TYPE,
693 PropertyIdentifier::PRESENT_VALUE,
694 PropertyIdentifier::STATUS_FLAGS,
695 PropertyIdentifier::EVENT_STATE,
696 PropertyIdentifier::OUT_OF_SERVICE,
697 PropertyIdentifier::NUMBER_OF_STATES,
698 PropertyIdentifier::PRIORITY_ARRAY,
699 PropertyIdentifier::RELINQUISH_DEFAULT,
700 PropertyIdentifier::CURRENT_COMMAND_PRIORITY,
701 PropertyIdentifier::RELIABILITY,
702 PropertyIdentifier::STATE_TEXT,
703 ];
704 Cow::Borrowed(PROPS)
705 }
706}
707
708#[cfg(test)]
709mod tests {
710 use super::*;
711
712 #[test]
715 fn msi_read_present_value_default() {
716 let msi = MultiStateInputObject::new(1, "MSI-1", 4).unwrap();
717 let val = msi
718 .read_property(PropertyIdentifier::PRESENT_VALUE, None)
719 .unwrap();
720 assert_eq!(val, PropertyValue::Unsigned(1));
721 }
722
723 #[test]
724 fn msi_read_number_of_states() {
725 let msi = MultiStateInputObject::new(1, "MSI-1", 4).unwrap();
726 let val = msi
727 .read_property(PropertyIdentifier::NUMBER_OF_STATES, None)
728 .unwrap();
729 assert_eq!(val, PropertyValue::Unsigned(4));
730 }
731
732 #[test]
733 fn msi_write_denied_when_in_service() {
734 let mut msi = MultiStateInputObject::new(1, "MSI-1", 4).unwrap();
735 let result = msi.write_property(
736 PropertyIdentifier::PRESENT_VALUE,
737 None,
738 PropertyValue::Unsigned(2),
739 None,
740 );
741 assert!(result.is_err());
742 }
743
744 #[test]
745 fn msi_write_allowed_when_out_of_service() {
746 let mut msi = MultiStateInputObject::new(1, "MSI-1", 4).unwrap();
747 msi.write_property(
748 PropertyIdentifier::OUT_OF_SERVICE,
749 None,
750 PropertyValue::Boolean(true),
751 None,
752 )
753 .unwrap();
754 msi.write_property(
755 PropertyIdentifier::PRESENT_VALUE,
756 None,
757 PropertyValue::Unsigned(3),
758 None,
759 )
760 .unwrap();
761 let val = msi
762 .read_property(PropertyIdentifier::PRESENT_VALUE, None)
763 .unwrap();
764 assert_eq!(val, PropertyValue::Unsigned(3));
765 }
766
767 #[test]
768 fn msi_write_out_of_range_rejected() {
769 let mut msi = MultiStateInputObject::new(1, "MSI-1", 4).unwrap();
770 msi.write_property(
771 PropertyIdentifier::OUT_OF_SERVICE,
772 None,
773 PropertyValue::Boolean(true),
774 None,
775 )
776 .unwrap();
777 assert!(msi
778 .write_property(
779 PropertyIdentifier::PRESENT_VALUE,
780 None,
781 PropertyValue::Unsigned(0),
782 None
783 )
784 .is_err());
785 assert!(msi
786 .write_property(
787 PropertyIdentifier::PRESENT_VALUE,
788 None,
789 PropertyValue::Unsigned(5),
790 None
791 )
792 .is_err());
793 }
794
795 #[test]
796 fn msi_read_reliability_default() {
797 let msi = MultiStateInputObject::new(1, "MSI-1", 4).unwrap();
798 let val = msi
799 .read_property(PropertyIdentifier::RELIABILITY, None)
800 .unwrap();
801 assert_eq!(val, PropertyValue::Enumerated(0)); }
803
804 #[test]
807 fn mso_write_with_priority() {
808 let mut mso = MultiStateOutputObject::new(1, "MSO-1", 5).unwrap();
809 mso.write_property(
810 PropertyIdentifier::PRESENT_VALUE,
811 None,
812 PropertyValue::Unsigned(3),
813 Some(8),
814 )
815 .unwrap();
816 let val = mso
817 .read_property(PropertyIdentifier::PRESENT_VALUE, None)
818 .unwrap();
819 assert_eq!(val, PropertyValue::Unsigned(3));
820 let slot = mso
821 .read_property(PropertyIdentifier::PRIORITY_ARRAY, Some(8))
822 .unwrap();
823 assert_eq!(slot, PropertyValue::Unsigned(3));
824 }
825
826 #[test]
827 fn mso_relinquish_falls_to_default() {
828 let mut mso = MultiStateOutputObject::new(1, "MSO-1", 5).unwrap();
829 mso.write_property(
830 PropertyIdentifier::PRESENT_VALUE,
831 None,
832 PropertyValue::Unsigned(4),
833 Some(16),
834 )
835 .unwrap();
836 assert_eq!(
837 mso.read_property(PropertyIdentifier::PRESENT_VALUE, None)
838 .unwrap(),
839 PropertyValue::Unsigned(4)
840 );
841 mso.write_property(
842 PropertyIdentifier::PRESENT_VALUE,
843 None,
844 PropertyValue::Null,
845 Some(16),
846 )
847 .unwrap();
848 assert_eq!(
849 mso.read_property(PropertyIdentifier::PRESENT_VALUE, None)
850 .unwrap(),
851 PropertyValue::Unsigned(1)
852 ); }
854
855 #[test]
856 fn mso_out_of_range_rejected() {
857 let mut mso = MultiStateOutputObject::new(1, "MSO-1", 5).unwrap();
858 assert!(mso
859 .write_property(
860 PropertyIdentifier::PRESENT_VALUE,
861 None,
862 PropertyValue::Unsigned(0),
863 None
864 )
865 .is_err());
866 assert!(mso
867 .write_property(
868 PropertyIdentifier::PRESENT_VALUE,
869 None,
870 PropertyValue::Unsigned(6),
871 None
872 )
873 .is_err());
874 }
875
876 #[test]
877 fn mso_read_reliability_default() {
878 let mso = MultiStateOutputObject::new(1, "MSO-1", 5).unwrap();
879 let val = mso
880 .read_property(PropertyIdentifier::RELIABILITY, None)
881 .unwrap();
882 assert_eq!(val, PropertyValue::Enumerated(0)); }
884
885 #[test]
888 fn msv_read_present_value_default() {
889 let msv = MultiStateValueObject::new(1, "MSV-1", 3).unwrap();
890 let val = msv
891 .read_property(PropertyIdentifier::PRESENT_VALUE, None)
892 .unwrap();
893 assert_eq!(val, PropertyValue::Unsigned(1));
894 }
895
896 #[test]
897 fn msv_write_with_priority() {
898 let mut msv = MultiStateValueObject::new(1, "MSV-1", 3).unwrap();
899 msv.write_property(
900 PropertyIdentifier::PRESENT_VALUE,
901 None,
902 PropertyValue::Unsigned(2),
903 Some(8),
904 )
905 .unwrap();
906 let val = msv
907 .read_property(PropertyIdentifier::PRESENT_VALUE, None)
908 .unwrap();
909 assert_eq!(val, PropertyValue::Unsigned(2));
910 let slot = msv
911 .read_property(PropertyIdentifier::PRIORITY_ARRAY, Some(8))
912 .unwrap();
913 assert_eq!(slot, PropertyValue::Unsigned(2));
914 }
915
916 #[test]
917 fn msv_relinquish_falls_to_default() {
918 let mut msv = MultiStateValueObject::new(1, "MSV-1", 3).unwrap();
919 msv.write_property(
920 PropertyIdentifier::PRESENT_VALUE,
921 None,
922 PropertyValue::Unsigned(3),
923 Some(16),
924 )
925 .unwrap();
926 assert_eq!(
927 msv.read_property(PropertyIdentifier::PRESENT_VALUE, None)
928 .unwrap(),
929 PropertyValue::Unsigned(3)
930 );
931 msv.write_property(
932 PropertyIdentifier::PRESENT_VALUE,
933 None,
934 PropertyValue::Null,
935 Some(16),
936 )
937 .unwrap();
938 assert_eq!(
939 msv.read_property(PropertyIdentifier::PRESENT_VALUE, None)
940 .unwrap(),
941 PropertyValue::Unsigned(1)
942 ); }
944
945 #[test]
946 fn msv_read_priority_array_all_none() {
947 let msv = MultiStateValueObject::new(1, "MSV-1", 3).unwrap();
948 let val = msv
949 .read_property(PropertyIdentifier::PRIORITY_ARRAY, None)
950 .unwrap();
951 if let PropertyValue::List(elements) = val {
952 assert_eq!(elements.len(), 16);
953 for elem in &elements {
954 assert_eq!(elem, &PropertyValue::Null);
955 }
956 } else {
957 panic!("Expected List for priority array without index");
958 }
959 }
960
961 #[test]
962 fn msv_read_relinquish_default() {
963 let msv = MultiStateValueObject::new(1, "MSV-1", 3).unwrap();
964 let val = msv
965 .read_property(PropertyIdentifier::RELINQUISH_DEFAULT, None)
966 .unwrap();
967 assert_eq!(val, PropertyValue::Unsigned(1));
968 }
969
970 #[test]
971 fn msv_write_out_of_range_rejected() {
972 let mut msv = MultiStateValueObject::new(1, "MSV-1", 3).unwrap();
973 assert!(msv
974 .write_property(
975 PropertyIdentifier::PRESENT_VALUE,
976 None,
977 PropertyValue::Unsigned(0),
978 None
979 )
980 .is_err());
981 assert!(msv
982 .write_property(
983 PropertyIdentifier::PRESENT_VALUE,
984 None,
985 PropertyValue::Unsigned(4),
986 None
987 )
988 .is_err());
989 }
990
991 #[test]
992 fn msv_write_wrong_type_rejected() {
993 let mut msv = MultiStateValueObject::new(1, "MSV-1", 3).unwrap();
994 let result = msv.write_property(
995 PropertyIdentifier::PRESENT_VALUE,
996 None,
997 PropertyValue::Real(1.0),
998 None,
999 );
1000 assert!(result.is_err());
1001 }
1002
1003 #[test]
1004 fn msv_read_object_type() {
1005 let msv = MultiStateValueObject::new(1, "MSV-1", 3).unwrap();
1006 let val = msv
1007 .read_property(PropertyIdentifier::OBJECT_TYPE, None)
1008 .unwrap();
1009 assert_eq!(
1010 val,
1011 PropertyValue::Enumerated(ObjectType::MULTI_STATE_VALUE.to_raw())
1012 );
1013 }
1014
1015 #[test]
1016 fn msv_read_reliability_default() {
1017 let msv = MultiStateValueObject::new(1, "MSV-1", 3).unwrap();
1018 let val = msv
1019 .read_property(PropertyIdentifier::RELIABILITY, None)
1020 .unwrap();
1021 assert_eq!(val, PropertyValue::Enumerated(0)); }
1023
1024 #[test]
1027 fn msv_direct_priority_array_write_value() {
1028 let mut msv = MultiStateValueObject::new(1, "MSV-1", 5).unwrap();
1029 msv.write_property(
1030 PropertyIdentifier::PRIORITY_ARRAY,
1031 Some(5),
1032 PropertyValue::Unsigned(3),
1033 None,
1034 )
1035 .unwrap();
1036 assert_eq!(
1037 msv.read_property(PropertyIdentifier::PRESENT_VALUE, None)
1038 .unwrap(),
1039 PropertyValue::Unsigned(3)
1040 );
1041 assert_eq!(
1042 msv.read_property(PropertyIdentifier::PRIORITY_ARRAY, Some(5))
1043 .unwrap(),
1044 PropertyValue::Unsigned(3)
1045 );
1046 }
1047
1048 #[test]
1049 fn msv_direct_priority_array_relinquish() {
1050 let mut msv = MultiStateValueObject::new(1, "MSV-1", 5).unwrap();
1051 msv.write_property(
1052 PropertyIdentifier::PRIORITY_ARRAY,
1053 Some(5),
1054 PropertyValue::Unsigned(3),
1055 None,
1056 )
1057 .unwrap();
1058 msv.write_property(
1059 PropertyIdentifier::PRIORITY_ARRAY,
1060 Some(5),
1061 PropertyValue::Null,
1062 None,
1063 )
1064 .unwrap();
1065 assert_eq!(
1066 msv.read_property(PropertyIdentifier::PRESENT_VALUE, None)
1067 .unwrap(),
1068 PropertyValue::Unsigned(1)
1069 ); }
1071
1072 #[test]
1073 fn msv_direct_priority_array_no_index_error() {
1074 let mut msv = MultiStateValueObject::new(1, "MSV-1", 5).unwrap();
1075 let result = msv.write_property(
1076 PropertyIdentifier::PRIORITY_ARRAY,
1077 None,
1078 PropertyValue::Unsigned(3),
1079 None,
1080 );
1081 assert!(result.is_err());
1082 }
1083
1084 #[test]
1085 fn msv_direct_priority_array_index_zero_error() {
1086 let mut msv = MultiStateValueObject::new(1, "MSV-1", 5).unwrap();
1087 let result = msv.write_property(
1088 PropertyIdentifier::PRIORITY_ARRAY,
1089 Some(0),
1090 PropertyValue::Unsigned(3),
1091 None,
1092 );
1093 assert!(result.is_err());
1094 }
1095
1096 #[test]
1097 fn msv_direct_priority_array_index_17_error() {
1098 let mut msv = MultiStateValueObject::new(1, "MSV-1", 5).unwrap();
1099 let result = msv.write_property(
1100 PropertyIdentifier::PRIORITY_ARRAY,
1101 Some(17),
1102 PropertyValue::Unsigned(3),
1103 None,
1104 );
1105 assert!(result.is_err());
1106 }
1107
1108 #[test]
1109 fn msv_direct_priority_array_range_validation() {
1110 let mut msv = MultiStateValueObject::new(1, "MSV-1", 5).unwrap();
1111 assert!(msv
1113 .write_property(
1114 PropertyIdentifier::PRIORITY_ARRAY,
1115 Some(1),
1116 PropertyValue::Unsigned(0),
1117 None
1118 )
1119 .is_err());
1120 assert!(msv
1122 .write_property(
1123 PropertyIdentifier::PRIORITY_ARRAY,
1124 Some(1),
1125 PropertyValue::Unsigned(6),
1126 None
1127 )
1128 .is_err());
1129 msv.write_property(
1131 PropertyIdentifier::PRIORITY_ARRAY,
1132 Some(1),
1133 PropertyValue::Unsigned(5),
1134 None,
1135 )
1136 .unwrap();
1137 }
1138
1139 #[test]
1142 fn mso_direct_priority_array_write_value() {
1143 let mut mso = MultiStateOutputObject::new(1, "MSO-1", 5).unwrap();
1144 mso.write_property(
1145 PropertyIdentifier::PRIORITY_ARRAY,
1146 Some(5),
1147 PropertyValue::Unsigned(3),
1148 None,
1149 )
1150 .unwrap();
1151 assert_eq!(
1152 mso.read_property(PropertyIdentifier::PRESENT_VALUE, None)
1153 .unwrap(),
1154 PropertyValue::Unsigned(3)
1155 );
1156 assert_eq!(
1157 mso.read_property(PropertyIdentifier::PRIORITY_ARRAY, Some(5))
1158 .unwrap(),
1159 PropertyValue::Unsigned(3)
1160 );
1161 }
1162
1163 #[test]
1164 fn mso_direct_priority_array_relinquish() {
1165 let mut mso = MultiStateOutputObject::new(1, "MSO-1", 5).unwrap();
1166 mso.write_property(
1167 PropertyIdentifier::PRIORITY_ARRAY,
1168 Some(5),
1169 PropertyValue::Unsigned(3),
1170 None,
1171 )
1172 .unwrap();
1173 mso.write_property(
1174 PropertyIdentifier::PRIORITY_ARRAY,
1175 Some(5),
1176 PropertyValue::Null,
1177 None,
1178 )
1179 .unwrap();
1180 assert_eq!(
1182 mso.read_property(PropertyIdentifier::PRESENT_VALUE, None)
1183 .unwrap(),
1184 PropertyValue::Unsigned(1)
1185 );
1186 }
1187
1188 #[test]
1189 fn mso_direct_priority_array_no_index_error() {
1190 let mut mso = MultiStateOutputObject::new(1, "MSO-1", 5).unwrap();
1191 let result = mso.write_property(
1192 PropertyIdentifier::PRIORITY_ARRAY,
1193 None,
1194 PropertyValue::Unsigned(3),
1195 None,
1196 );
1197 assert!(result.is_err());
1198 }
1199
1200 #[test]
1201 fn mso_direct_priority_array_index_zero_error() {
1202 let mut mso = MultiStateOutputObject::new(1, "MSO-1", 5).unwrap();
1203 let result = mso.write_property(
1204 PropertyIdentifier::PRIORITY_ARRAY,
1205 Some(0),
1206 PropertyValue::Unsigned(3),
1207 None,
1208 );
1209 assert!(result.is_err());
1210 }
1211
1212 #[test]
1213 fn mso_direct_priority_array_index_17_error() {
1214 let mut mso = MultiStateOutputObject::new(1, "MSO-1", 5).unwrap();
1215 let result = mso.write_property(
1216 PropertyIdentifier::PRIORITY_ARRAY,
1217 Some(17),
1218 PropertyValue::Unsigned(3),
1219 None,
1220 );
1221 assert!(result.is_err());
1222 }
1223
1224 #[test]
1227 fn msi_state_text_defaults() {
1228 let msi = MultiStateInputObject::new(1, "MSI-1", 3).unwrap();
1229 let val = msi
1230 .read_property(PropertyIdentifier::STATE_TEXT, None)
1231 .unwrap();
1232 assert_eq!(
1233 val,
1234 PropertyValue::List(vec![
1235 PropertyValue::CharacterString("State 1".into()),
1236 PropertyValue::CharacterString("State 2".into()),
1237 PropertyValue::CharacterString("State 3".into()),
1238 ])
1239 );
1240 }
1241
1242 #[test]
1243 fn msi_state_text_index_zero_returns_length() {
1244 let msi = MultiStateInputObject::new(1, "MSI-1", 4).unwrap();
1245 let val = msi
1246 .read_property(PropertyIdentifier::STATE_TEXT, Some(0))
1247 .unwrap();
1248 assert_eq!(val, PropertyValue::Unsigned(4));
1249 }
1250
1251 #[test]
1252 fn msi_state_text_valid_index() {
1253 let msi = MultiStateInputObject::new(1, "MSI-1", 3).unwrap();
1254 let val = msi
1255 .read_property(PropertyIdentifier::STATE_TEXT, Some(2))
1256 .unwrap();
1257 assert_eq!(val, PropertyValue::CharacterString("State 2".into()));
1258 }
1259
1260 #[test]
1261 fn msi_state_text_invalid_index_error() {
1262 let msi = MultiStateInputObject::new(1, "MSI-1", 3).unwrap();
1263 assert!(msi
1264 .read_property(PropertyIdentifier::STATE_TEXT, Some(4))
1265 .is_err());
1266 assert!(msi
1267 .read_property(PropertyIdentifier::STATE_TEXT, Some(100))
1268 .is_err());
1269 }
1270
1271 #[test]
1272 fn msi_state_text_write_at_index() {
1273 let mut msi = MultiStateInputObject::new(1, "MSI-1", 3).unwrap();
1274 msi.write_property(
1275 PropertyIdentifier::STATE_TEXT,
1276 Some(2),
1277 PropertyValue::CharacterString("Occupied".into()),
1278 None,
1279 )
1280 .unwrap();
1281 let val = msi
1282 .read_property(PropertyIdentifier::STATE_TEXT, Some(2))
1283 .unwrap();
1284 assert_eq!(val, PropertyValue::CharacterString("Occupied".into()));
1285 }
1286
1287 #[test]
1288 fn msi_state_text_write_wrong_type_rejected() {
1289 let mut msi = MultiStateInputObject::new(1, "MSI-1", 3).unwrap();
1290 assert!(msi
1291 .write_property(
1292 PropertyIdentifier::STATE_TEXT,
1293 Some(1),
1294 PropertyValue::Unsigned(42),
1295 None,
1296 )
1297 .is_err());
1298 }
1299
1300 #[test]
1301 fn msi_state_text_write_bad_index_rejected() {
1302 let mut msi = MultiStateInputObject::new(1, "MSI-1", 3).unwrap();
1303 assert!(msi
1305 .write_property(
1306 PropertyIdentifier::STATE_TEXT,
1307 Some(0),
1308 PropertyValue::CharacterString("X".into()),
1309 None,
1310 )
1311 .is_err());
1312 assert!(msi
1314 .write_property(
1315 PropertyIdentifier::STATE_TEXT,
1316 Some(4),
1317 PropertyValue::CharacterString("X".into()),
1318 None,
1319 )
1320 .is_err());
1321 assert!(msi
1323 .write_property(
1324 PropertyIdentifier::STATE_TEXT,
1325 None,
1326 PropertyValue::CharacterString("X".into()),
1327 None,
1328 )
1329 .is_err());
1330 }
1331
1332 #[test]
1333 fn msi_state_text_in_property_list() {
1334 let msi = MultiStateInputObject::new(1, "MSI-1", 3).unwrap();
1335 assert!(msi
1336 .property_list()
1337 .contains(&PropertyIdentifier::STATE_TEXT));
1338 }
1339
1340 #[test]
1341 fn mso_state_text_defaults() {
1342 let mso = MultiStateOutputObject::new(1, "MSO-1", 2).unwrap();
1343 let val = mso
1344 .read_property(PropertyIdentifier::STATE_TEXT, None)
1345 .unwrap();
1346 assert_eq!(
1347 val,
1348 PropertyValue::List(vec![
1349 PropertyValue::CharacterString("State 1".into()),
1350 PropertyValue::CharacterString("State 2".into()),
1351 ])
1352 );
1353 }
1354
1355 #[test]
1356 fn mso_state_text_index_zero_returns_length() {
1357 let mso = MultiStateOutputObject::new(1, "MSO-1", 5).unwrap();
1358 let val = mso
1359 .read_property(PropertyIdentifier::STATE_TEXT, Some(0))
1360 .unwrap();
1361 assert_eq!(val, PropertyValue::Unsigned(5));
1362 }
1363
1364 #[test]
1365 fn mso_state_text_valid_index() {
1366 let mso = MultiStateOutputObject::new(1, "MSO-1", 3).unwrap();
1367 let val = mso
1368 .read_property(PropertyIdentifier::STATE_TEXT, Some(3))
1369 .unwrap();
1370 assert_eq!(val, PropertyValue::CharacterString("State 3".into()));
1371 }
1372
1373 #[test]
1374 fn mso_state_text_invalid_index_error() {
1375 let mso = MultiStateOutputObject::new(1, "MSO-1", 3).unwrap();
1376 assert!(mso
1377 .read_property(PropertyIdentifier::STATE_TEXT, Some(4))
1378 .is_err());
1379 }
1380
1381 #[test]
1382 fn mso_state_text_write_at_index() {
1383 let mut mso = MultiStateOutputObject::new(1, "MSO-1", 3).unwrap();
1384 mso.write_property(
1385 PropertyIdentifier::STATE_TEXT,
1386 Some(1),
1387 PropertyValue::CharacterString("Low".into()),
1388 None,
1389 )
1390 .unwrap();
1391 assert_eq!(
1392 mso.read_property(PropertyIdentifier::STATE_TEXT, Some(1))
1393 .unwrap(),
1394 PropertyValue::CharacterString("Low".into())
1395 );
1396 }
1397
1398 #[test]
1399 fn mso_state_text_in_property_list() {
1400 let mso = MultiStateOutputObject::new(1, "MSO-1", 3).unwrap();
1401 assert!(mso
1402 .property_list()
1403 .contains(&PropertyIdentifier::STATE_TEXT));
1404 }
1405
1406 #[test]
1407 fn msv_state_text_defaults() {
1408 let msv = MultiStateValueObject::new(1, "MSV-1", 3).unwrap();
1409 let val = msv
1410 .read_property(PropertyIdentifier::STATE_TEXT, None)
1411 .unwrap();
1412 assert_eq!(
1413 val,
1414 PropertyValue::List(vec![
1415 PropertyValue::CharacterString("State 1".into()),
1416 PropertyValue::CharacterString("State 2".into()),
1417 PropertyValue::CharacterString("State 3".into()),
1418 ])
1419 );
1420 }
1421
1422 #[test]
1423 fn msv_state_text_index_zero_returns_length() {
1424 let msv = MultiStateValueObject::new(1, "MSV-1", 3).unwrap();
1425 let val = msv
1426 .read_property(PropertyIdentifier::STATE_TEXT, Some(0))
1427 .unwrap();
1428 assert_eq!(val, PropertyValue::Unsigned(3));
1429 }
1430
1431 #[test]
1432 fn msv_state_text_valid_index() {
1433 let msv = MultiStateValueObject::new(1, "MSV-1", 3).unwrap();
1434 let val = msv
1435 .read_property(PropertyIdentifier::STATE_TEXT, Some(1))
1436 .unwrap();
1437 assert_eq!(val, PropertyValue::CharacterString("State 1".into()));
1438 }
1439
1440 #[test]
1441 fn msv_state_text_invalid_index_error() {
1442 let msv = MultiStateValueObject::new(1, "MSV-1", 3).unwrap();
1443 assert!(msv
1444 .read_property(PropertyIdentifier::STATE_TEXT, Some(4))
1445 .is_err());
1446 assert!(msv
1447 .read_property(PropertyIdentifier::STATE_TEXT, Some(0xFF))
1448 .is_err());
1449 }
1450
1451 #[test]
1452 fn msv_state_text_write_at_index() {
1453 let mut msv = MultiStateValueObject::new(1, "MSV-1", 3).unwrap();
1454 msv.write_property(
1455 PropertyIdentifier::STATE_TEXT,
1456 Some(2),
1457 PropertyValue::CharacterString("Comfort".into()),
1458 None,
1459 )
1460 .unwrap();
1461 assert_eq!(
1462 msv.read_property(PropertyIdentifier::STATE_TEXT, Some(2))
1463 .unwrap(),
1464 PropertyValue::CharacterString("Comfort".into())
1465 );
1466 }
1467
1468 #[test]
1469 fn msv_state_text_write_bad_index_rejected() {
1470 let mut msv = MultiStateValueObject::new(1, "MSV-1", 3).unwrap();
1471 assert!(msv
1472 .write_property(
1473 PropertyIdentifier::STATE_TEXT,
1474 None,
1475 PropertyValue::CharacterString("X".into()),
1476 None,
1477 )
1478 .is_err());
1479 assert!(msv
1480 .write_property(
1481 PropertyIdentifier::STATE_TEXT,
1482 Some(0),
1483 PropertyValue::CharacterString("X".into()),
1484 None,
1485 )
1486 .is_err());
1487 assert!(msv
1488 .write_property(
1489 PropertyIdentifier::STATE_TEXT,
1490 Some(4),
1491 PropertyValue::CharacterString("X".into()),
1492 None,
1493 )
1494 .is_err());
1495 }
1496
1497 #[test]
1498 fn msv_state_text_write_wrong_type_rejected() {
1499 let mut msv = MultiStateValueObject::new(1, "MSV-1", 3).unwrap();
1500 assert!(msv
1501 .write_property(
1502 PropertyIdentifier::STATE_TEXT,
1503 Some(1),
1504 PropertyValue::Unsigned(1),
1505 None,
1506 )
1507 .is_err());
1508 }
1509
1510 #[test]
1511 fn msv_state_text_in_property_list() {
1512 let msv = MultiStateValueObject::new(1, "MSV-1", 3).unwrap();
1513 assert!(msv
1514 .property_list()
1515 .contains(&PropertyIdentifier::STATE_TEXT));
1516 }
1517}