1use crate::ber::{Decoder, EncodeBuf, tag};
6use crate::error::{DecodeErrorKind, Error, Result};
7use crate::format::hex;
8use crate::oid::Oid;
9use bytes::Bytes;
10
11#[derive(Debug, Clone, PartialEq)]
15#[non_exhaustive]
16pub enum Value {
17 Integer(i32),
19
20 OctetString(Bytes),
27
28 Null,
30
31 ObjectIdentifier(Oid),
33
34 IpAddress([u8; 4]),
36
37 Counter32(u32),
39
40 Gauge32(u32),
42
43 TimeTicks(u32),
45
46 Opaque(Bytes),
48
49 Counter64(u64),
59
60 NoSuchObject,
62
63 NoSuchInstance,
65
66 EndOfMibView,
68
69 Unknown { tag: u8, data: Bytes },
71}
72
73impl Value {
74 pub fn as_i32(&self) -> Option<i32> {
76 match self {
77 Value::Integer(v) => Some(*v),
78 _ => None,
79 }
80 }
81
82 pub fn as_u32(&self) -> Option<u32> {
84 match self {
85 Value::Counter32(v) | Value::Gauge32(v) | Value::TimeTicks(v) => Some(*v),
86 Value::Integer(v) if *v >= 0 => Some(*v as u32),
87 _ => None,
88 }
89 }
90
91 pub fn as_u64(&self) -> Option<u64> {
93 match self {
94 Value::Counter64(v) => Some(*v),
95 Value::Counter32(v) | Value::Gauge32(v) | Value::TimeTicks(v) => Some(*v as u64),
96 Value::Integer(v) if *v >= 0 => Some(*v as u64),
97 _ => None,
98 }
99 }
100
101 pub fn as_bytes(&self) -> Option<&[u8]> {
103 match self {
104 Value::OctetString(v) | Value::Opaque(v) => Some(v),
105 _ => None,
106 }
107 }
108
109 pub fn as_str(&self) -> Option<&str> {
111 self.as_bytes().and_then(|b| std::str::from_utf8(b).ok())
112 }
113
114 pub fn as_oid(&self) -> Option<&Oid> {
116 match self {
117 Value::ObjectIdentifier(oid) => Some(oid),
118 _ => None,
119 }
120 }
121
122 pub fn as_ip(&self) -> Option<std::net::Ipv4Addr> {
124 match self {
125 Value::IpAddress(bytes) => Some(std::net::Ipv4Addr::from(*bytes)),
126 _ => None,
127 }
128 }
129
130 pub fn is_exception(&self) -> bool {
132 matches!(
133 self,
134 Value::NoSuchObject | Value::NoSuchInstance | Value::EndOfMibView
135 )
136 }
137
138 pub fn format_with_hint(&self, hint: &str) -> Option<String> {
156 match self {
157 Value::OctetString(bytes) => Some(crate::format::display_hint::apply(hint, bytes)),
158 Value::Opaque(bytes) => Some(crate::format::display_hint::apply(hint, bytes)),
159 _ => None,
160 }
161 }
162
163 pub fn encode(&self, buf: &mut EncodeBuf) {
165 match self {
166 Value::Integer(v) => buf.push_integer(*v),
167 Value::OctetString(data) => buf.push_octet_string(data),
168 Value::Null => buf.push_null(),
169 Value::ObjectIdentifier(oid) => buf.push_oid(oid),
170 Value::IpAddress(addr) => buf.push_ip_address(*addr),
171 Value::Counter32(v) => buf.push_unsigned32(tag::application::COUNTER32, *v),
172 Value::Gauge32(v) => buf.push_unsigned32(tag::application::GAUGE32, *v),
173 Value::TimeTicks(v) => buf.push_unsigned32(tag::application::TIMETICKS, *v),
174 Value::Opaque(data) => {
175 buf.push_bytes(data);
176 buf.push_length(data.len());
177 buf.push_tag(tag::application::OPAQUE);
178 }
179 Value::Counter64(v) => buf.push_integer64(*v),
180 Value::NoSuchObject => {
181 buf.push_length(0);
182 buf.push_tag(tag::context::NO_SUCH_OBJECT);
183 }
184 Value::NoSuchInstance => {
185 buf.push_length(0);
186 buf.push_tag(tag::context::NO_SUCH_INSTANCE);
187 }
188 Value::EndOfMibView => {
189 buf.push_length(0);
190 buf.push_tag(tag::context::END_OF_MIB_VIEW);
191 }
192 Value::Unknown { tag: t, data } => {
193 buf.push_bytes(data);
194 buf.push_length(data.len());
195 buf.push_tag(*t);
196 }
197 }
198 }
199
200 pub fn decode(decoder: &mut Decoder) -> Result<Self> {
202 let tag = decoder.read_tag()?;
203 let len = decoder.read_length()?;
204
205 match tag {
206 tag::universal::INTEGER => {
207 let value = decoder.read_integer_value(len)?;
208 Ok(Value::Integer(value))
209 }
210 tag::universal::OCTET_STRING => {
211 let data = decoder.read_bytes(len)?;
212 Ok(Value::OctetString(data))
213 }
214 tag::universal::NULL => {
215 if len != 0 {
216 return Err(Error::decode(
217 decoder.offset(),
218 DecodeErrorKind::InvalidNull,
219 ));
220 }
221 Ok(Value::Null)
222 }
223 tag::universal::OBJECT_IDENTIFIER => {
224 let oid = decoder.read_oid_value(len)?;
225 Ok(Value::ObjectIdentifier(oid))
226 }
227 tag::application::IP_ADDRESS => {
228 if len != 4 {
229 return Err(Error::decode(
230 decoder.offset(),
231 DecodeErrorKind::InvalidIpAddressLength { length: len },
232 ));
233 }
234 let data = decoder.read_bytes(4)?;
235 Ok(Value::IpAddress([data[0], data[1], data[2], data[3]]))
236 }
237 tag::application::COUNTER32 => {
238 let value = decoder.read_unsigned32_value(len)?;
239 Ok(Value::Counter32(value))
240 }
241 tag::application::GAUGE32 => {
242 let value = decoder.read_unsigned32_value(len)?;
243 Ok(Value::Gauge32(value))
244 }
245 tag::application::TIMETICKS => {
246 let value = decoder.read_unsigned32_value(len)?;
247 Ok(Value::TimeTicks(value))
248 }
249 tag::application::OPAQUE => {
250 let data = decoder.read_bytes(len)?;
251 Ok(Value::Opaque(data))
252 }
253 tag::application::COUNTER64 => {
254 let value = decoder.read_integer64_value(len)?;
255 Ok(Value::Counter64(value))
256 }
257 tag::context::NO_SUCH_OBJECT => {
258 if len != 0 {
259 let _ = decoder.read_bytes(len)?;
260 }
261 Ok(Value::NoSuchObject)
262 }
263 tag::context::NO_SUCH_INSTANCE => {
264 if len != 0 {
265 let _ = decoder.read_bytes(len)?;
266 }
267 Ok(Value::NoSuchInstance)
268 }
269 tag::context::END_OF_MIB_VIEW => {
270 if len != 0 {
271 let _ = decoder.read_bytes(len)?;
272 }
273 Ok(Value::EndOfMibView)
274 }
275 tag::universal::OCTET_STRING_CONSTRUCTED => Err(Error::decode(
278 decoder.offset(),
279 DecodeErrorKind::ConstructedOctetString,
280 )),
281 _ => {
282 let data = decoder.read_bytes(len)?;
284 Ok(Value::Unknown { tag, data })
285 }
286 }
287 }
288}
289
290impl std::fmt::Display for Value {
291 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
292 match self {
293 Value::Integer(v) => write!(f, "{}", v),
294 Value::OctetString(data) => {
295 if let Ok(s) = std::str::from_utf8(data) {
297 write!(f, "{}", s)
298 } else {
299 write!(f, "0x{}", hex::encode(data))
300 }
301 }
302 Value::Null => write!(f, "NULL"),
303 Value::ObjectIdentifier(oid) => write!(f, "{}", oid),
304 Value::IpAddress(addr) => {
305 write!(f, "{}.{}.{}.{}", addr[0], addr[1], addr[2], addr[3])
306 }
307 Value::Counter32(v) => write!(f, "{}", v),
308 Value::Gauge32(v) => write!(f, "{}", v),
309 Value::TimeTicks(v) => {
310 let secs = v / 100;
312 let days = secs / 86400;
313 let hours = (secs % 86400) / 3600;
314 let mins = (secs % 3600) / 60;
315 let s = secs % 60;
316 write!(f, "{}d {}h {}m {}s", days, hours, mins, s)
317 }
318 Value::Opaque(data) => write!(f, "Opaque(0x{})", hex::encode(data)),
319 Value::Counter64(v) => write!(f, "{}", v),
320 Value::NoSuchObject => write!(f, "noSuchObject"),
321 Value::NoSuchInstance => write!(f, "noSuchInstance"),
322 Value::EndOfMibView => write!(f, "endOfMibView"),
323 Value::Unknown { tag, data } => {
324 write!(
325 f,
326 "Unknown(tag=0x{:02X}, data=0x{})",
327 tag,
328 hex::encode(data)
329 )
330 }
331 }
332 }
333}
334
335impl From<i32> for Value {
337 fn from(v: i32) -> Self {
338 Value::Integer(v)
339 }
340}
341
342impl From<&str> for Value {
343 fn from(s: &str) -> Self {
344 Value::OctetString(Bytes::copy_from_slice(s.as_bytes()))
345 }
346}
347
348impl From<String> for Value {
349 fn from(s: String) -> Self {
350 Value::OctetString(Bytes::from(s))
351 }
352}
353
354impl From<&[u8]> for Value {
355 fn from(data: &[u8]) -> Self {
356 Value::OctetString(Bytes::copy_from_slice(data))
357 }
358}
359
360impl From<Oid> for Value {
361 fn from(oid: Oid) -> Self {
362 Value::ObjectIdentifier(oid)
363 }
364}
365
366impl From<std::net::Ipv4Addr> for Value {
367 fn from(addr: std::net::Ipv4Addr) -> Self {
368 Value::IpAddress(addr.octets())
369 }
370}
371
372impl From<Bytes> for Value {
373 fn from(data: Bytes) -> Self {
374 Value::OctetString(data)
375 }
376}
377
378impl From<u64> for Value {
379 fn from(v: u64) -> Self {
380 Value::Counter64(v)
381 }
382}
383
384impl From<[u8; 4]> for Value {
385 fn from(addr: [u8; 4]) -> Self {
386 Value::IpAddress(addr)
387 }
388}
389
390#[cfg(test)]
391mod tests {
392 use super::*;
393
394 #[test]
397 fn test_reject_constructed_octet_string() {
398 let data = bytes::Bytes::from_static(&[0x24, 0x03, 0x04, 0x01, 0x41]);
402 let mut decoder = Decoder::new(data);
403 let result = Value::decode(&mut decoder);
404
405 assert!(
406 result.is_err(),
407 "constructed OCTET STRING (0x24) should be rejected"
408 );
409 let err = result.unwrap_err();
410 let err_msg = format!("{}", err);
411 assert!(
412 err_msg.contains("constructed OCTET STRING"),
413 "error message should mention 'constructed OCTET STRING', got: {}",
414 err_msg
415 );
416 }
417
418 #[test]
419 fn test_primitive_octet_string_accepted() {
420 let data = bytes::Bytes::from_static(&[0x04, 0x03, 0x41, 0x42, 0x43]); let mut decoder = Decoder::new(data);
423 let result = Value::decode(&mut decoder);
424
425 assert!(result.is_ok(), "primitive OCTET STRING should be accepted");
426 let value = result.unwrap();
427 assert_eq!(value.as_bytes(), Some(&b"ABC"[..]));
428 }
429
430 fn roundtrip(value: Value) -> Value {
435 let mut buf = EncodeBuf::new();
436 value.encode(&mut buf);
437 let data = buf.finish();
438 let mut decoder = Decoder::new(data);
439 Value::decode(&mut decoder).unwrap()
440 }
441
442 #[test]
443 fn test_integer_positive() {
444 let value = Value::Integer(42);
445 assert_eq!(roundtrip(value.clone()), value);
446 }
447
448 #[test]
449 fn test_integer_negative() {
450 let value = Value::Integer(-42);
451 assert_eq!(roundtrip(value.clone()), value);
452 }
453
454 #[test]
455 fn test_integer_zero() {
456 let value = Value::Integer(0);
457 assert_eq!(roundtrip(value.clone()), value);
458 }
459
460 #[test]
461 fn test_integer_min() {
462 let value = Value::Integer(i32::MIN);
463 assert_eq!(roundtrip(value.clone()), value);
464 }
465
466 #[test]
467 fn test_integer_max() {
468 let value = Value::Integer(i32::MAX);
469 assert_eq!(roundtrip(value.clone()), value);
470 }
471
472 #[test]
473 fn test_octet_string_ascii() {
474 let value = Value::OctetString(Bytes::from_static(b"hello world"));
475 assert_eq!(roundtrip(value.clone()), value);
476 }
477
478 #[test]
479 fn test_octet_string_binary() {
480 let value = Value::OctetString(Bytes::from_static(&[0x00, 0xFF, 0x80, 0x7F]));
481 assert_eq!(roundtrip(value.clone()), value);
482 }
483
484 #[test]
485 fn test_octet_string_empty() {
486 let value = Value::OctetString(Bytes::new());
487 assert_eq!(roundtrip(value.clone()), value);
488 }
489
490 #[test]
491 fn test_null() {
492 let value = Value::Null;
493 assert_eq!(roundtrip(value.clone()), value);
494 }
495
496 #[test]
497 fn test_object_identifier() {
498 let value = Value::ObjectIdentifier(crate::oid!(1, 3, 6, 1, 2, 1, 1, 1, 0));
499 assert_eq!(roundtrip(value.clone()), value);
500 }
501
502 #[test]
503 fn test_ip_address() {
504 let value = Value::IpAddress([192, 168, 1, 1]);
505 assert_eq!(roundtrip(value.clone()), value);
506 }
507
508 #[test]
509 fn test_ip_address_zero() {
510 let value = Value::IpAddress([0, 0, 0, 0]);
511 assert_eq!(roundtrip(value.clone()), value);
512 }
513
514 #[test]
515 fn test_ip_address_broadcast() {
516 let value = Value::IpAddress([255, 255, 255, 255]);
517 assert_eq!(roundtrip(value.clone()), value);
518 }
519
520 #[test]
521 fn test_counter32() {
522 let value = Value::Counter32(999999);
523 assert_eq!(roundtrip(value.clone()), value);
524 }
525
526 #[test]
527 fn test_counter32_zero() {
528 let value = Value::Counter32(0);
529 assert_eq!(roundtrip(value.clone()), value);
530 }
531
532 #[test]
533 fn test_counter32_max() {
534 let value = Value::Counter32(u32::MAX);
535 assert_eq!(roundtrip(value.clone()), value);
536 }
537
538 #[test]
539 fn test_gauge32() {
540 let value = Value::Gauge32(1000000000);
541 assert_eq!(roundtrip(value.clone()), value);
542 }
543
544 #[test]
545 fn test_gauge32_max() {
546 let value = Value::Gauge32(u32::MAX);
547 assert_eq!(roundtrip(value.clone()), value);
548 }
549
550 #[test]
551 fn test_timeticks() {
552 let value = Value::TimeTicks(123456);
553 assert_eq!(roundtrip(value.clone()), value);
554 }
555
556 #[test]
557 fn test_timeticks_max() {
558 let value = Value::TimeTicks(u32::MAX);
559 assert_eq!(roundtrip(value.clone()), value);
560 }
561
562 #[test]
563 fn test_opaque() {
564 let value = Value::Opaque(Bytes::from_static(&[0xDE, 0xAD, 0xBE, 0xEF]));
565 assert_eq!(roundtrip(value.clone()), value);
566 }
567
568 #[test]
569 fn test_opaque_empty() {
570 let value = Value::Opaque(Bytes::new());
571 assert_eq!(roundtrip(value.clone()), value);
572 }
573
574 #[test]
575 fn test_counter64() {
576 let value = Value::Counter64(123456789012345);
577 assert_eq!(roundtrip(value.clone()), value);
578 }
579
580 #[test]
581 fn test_counter64_zero() {
582 let value = Value::Counter64(0);
583 assert_eq!(roundtrip(value.clone()), value);
584 }
585
586 #[test]
587 fn test_counter64_max() {
588 let value = Value::Counter64(u64::MAX);
589 assert_eq!(roundtrip(value.clone()), value);
590 }
591
592 #[test]
593 fn test_no_such_object() {
594 let value = Value::NoSuchObject;
595 assert_eq!(roundtrip(value.clone()), value);
596 }
597
598 #[test]
599 fn test_no_such_instance() {
600 let value = Value::NoSuchInstance;
601 assert_eq!(roundtrip(value.clone()), value);
602 }
603
604 #[test]
605 fn test_end_of_mib_view() {
606 let value = Value::EndOfMibView;
607 assert_eq!(roundtrip(value.clone()), value);
608 }
609
610 #[test]
611 fn test_unknown_tag_preserved() {
612 let data = Bytes::from_static(&[0x45, 0x03, 0x01, 0x02, 0x03]);
614 let mut decoder = Decoder::new(data);
615 let value = Value::decode(&mut decoder).unwrap();
616
617 match value {
618 Value::Unknown { tag, ref data } => {
619 assert_eq!(tag, 0x45);
620 assert_eq!(data.as_ref(), &[0x01, 0x02, 0x03]);
621 }
622 _ => panic!("expected Unknown variant"),
623 }
624
625 assert_eq!(roundtrip(value.clone()), value);
627 }
628
629 #[test]
634 fn test_as_i32() {
635 assert_eq!(Value::Integer(42).as_i32(), Some(42));
636 assert_eq!(Value::Integer(-42).as_i32(), Some(-42));
637 assert_eq!(Value::Counter32(100).as_i32(), None);
638 assert_eq!(Value::Null.as_i32(), None);
639 }
640
641 #[test]
642 fn test_as_u32() {
643 assert_eq!(Value::Counter32(100).as_u32(), Some(100));
644 assert_eq!(Value::Gauge32(200).as_u32(), Some(200));
645 assert_eq!(Value::TimeTicks(300).as_u32(), Some(300));
646 assert_eq!(Value::Integer(50).as_u32(), Some(50));
647 assert_eq!(Value::Integer(-1).as_u32(), None);
648 assert_eq!(Value::Counter64(100).as_u32(), None);
649 }
650
651 #[test]
652 fn test_as_u64() {
653 assert_eq!(Value::Counter64(100).as_u64(), Some(100));
654 assert_eq!(Value::Counter32(100).as_u64(), Some(100));
655 assert_eq!(Value::Gauge32(200).as_u64(), Some(200));
656 assert_eq!(Value::TimeTicks(300).as_u64(), Some(300));
657 assert_eq!(Value::Integer(50).as_u64(), Some(50));
658 assert_eq!(Value::Integer(-1).as_u64(), None);
659 }
660
661 #[test]
662 fn test_as_bytes() {
663 let s = Value::OctetString(Bytes::from_static(b"test"));
664 assert_eq!(s.as_bytes(), Some(b"test".as_slice()));
665
666 let o = Value::Opaque(Bytes::from_static(b"data"));
667 assert_eq!(o.as_bytes(), Some(b"data".as_slice()));
668
669 assert_eq!(Value::Integer(1).as_bytes(), None);
670 }
671
672 #[test]
673 fn test_as_str() {
674 let s = Value::OctetString(Bytes::from_static(b"hello"));
675 assert_eq!(s.as_str(), Some("hello"));
676
677 let invalid = Value::OctetString(Bytes::from_static(&[0xFF, 0xFE]));
679 assert_eq!(invalid.as_str(), None);
680
681 assert_eq!(Value::Integer(1).as_str(), None);
682 }
683
684 #[test]
685 fn test_as_oid() {
686 let oid = crate::oid!(1, 3, 6, 1);
687 let v = Value::ObjectIdentifier(oid.clone());
688 assert_eq!(v.as_oid(), Some(&oid));
689
690 assert_eq!(Value::Integer(1).as_oid(), None);
691 }
692
693 #[test]
694 fn test_as_ip() {
695 let v = Value::IpAddress([192, 168, 1, 1]);
696 assert_eq!(v.as_ip(), Some(std::net::Ipv4Addr::new(192, 168, 1, 1)));
697
698 assert_eq!(Value::Integer(1).as_ip(), None);
699 }
700
701 #[test]
706 fn test_is_exception() {
707 assert!(Value::NoSuchObject.is_exception());
708 assert!(Value::NoSuchInstance.is_exception());
709 assert!(Value::EndOfMibView.is_exception());
710
711 assert!(!Value::Integer(1).is_exception());
712 assert!(!Value::Null.is_exception());
713 assert!(!Value::OctetString(Bytes::new()).is_exception());
714 }
715
716 #[test]
721 fn test_display_integer() {
722 assert_eq!(format!("{}", Value::Integer(42)), "42");
723 assert_eq!(format!("{}", Value::Integer(-42)), "-42");
724 }
725
726 #[test]
727 fn test_display_octet_string_utf8() {
728 let v = Value::OctetString(Bytes::from_static(b"hello"));
729 assert_eq!(format!("{}", v), "hello");
730 }
731
732 #[test]
733 fn test_display_octet_string_binary() {
734 let v = Value::OctetString(Bytes::from_static(&[0xFF, 0xFE]));
736 assert_eq!(format!("{}", v), "0xfffe");
737 }
738
739 #[test]
740 fn test_display_null() {
741 assert_eq!(format!("{}", Value::Null), "NULL");
742 }
743
744 #[test]
745 fn test_display_ip_address() {
746 let v = Value::IpAddress([192, 168, 1, 1]);
747 assert_eq!(format!("{}", v), "192.168.1.1");
748 }
749
750 #[test]
751 fn test_display_counter32() {
752 assert_eq!(format!("{}", Value::Counter32(999)), "999");
753 }
754
755 #[test]
756 fn test_display_gauge32() {
757 assert_eq!(format!("{}", Value::Gauge32(1000)), "1000");
758 }
759
760 #[test]
761 fn test_display_timeticks() {
762 let v = Value::TimeTicks(123456);
765 assert_eq!(format!("{}", v), "0d 0h 20m 34s");
766 }
767
768 #[test]
769 fn test_display_opaque() {
770 let v = Value::Opaque(Bytes::from_static(&[0xBE, 0xEF]));
771 assert_eq!(format!("{}", v), "Opaque(0xbeef)");
772 }
773
774 #[test]
775 fn test_display_counter64() {
776 assert_eq!(format!("{}", Value::Counter64(12345678)), "12345678");
777 }
778
779 #[test]
780 fn test_display_exceptions() {
781 assert_eq!(format!("{}", Value::NoSuchObject), "noSuchObject");
782 assert_eq!(format!("{}", Value::NoSuchInstance), "noSuchInstance");
783 assert_eq!(format!("{}", Value::EndOfMibView), "endOfMibView");
784 }
785
786 #[test]
787 fn test_display_unknown() {
788 let v = Value::Unknown {
789 tag: 0x99,
790 data: Bytes::from_static(&[0x01, 0x02]),
791 };
792 assert_eq!(format!("{}", v), "Unknown(tag=0x99, data=0x0102)");
793 }
794
795 #[test]
800 fn test_from_i32() {
801 let v: Value = 42i32.into();
802 assert_eq!(v, Value::Integer(42));
803 }
804
805 #[test]
806 fn test_from_str() {
807 let v: Value = "hello".into();
808 assert_eq!(v.as_str(), Some("hello"));
809 }
810
811 #[test]
812 fn test_from_string() {
813 let v: Value = String::from("hello").into();
814 assert_eq!(v.as_str(), Some("hello"));
815 }
816
817 #[test]
818 fn test_from_bytes_slice() {
819 let v: Value = (&[1u8, 2, 3][..]).into();
820 assert_eq!(v.as_bytes(), Some(&[1u8, 2, 3][..]));
821 }
822
823 #[test]
824 fn test_from_oid() {
825 let oid = crate::oid!(1, 3, 6, 1);
826 let v: Value = oid.clone().into();
827 assert_eq!(v.as_oid(), Some(&oid));
828 }
829
830 #[test]
831 fn test_from_ipv4addr() {
832 let addr = std::net::Ipv4Addr::new(10, 0, 0, 1);
833 let v: Value = addr.into();
834 assert_eq!(v, Value::IpAddress([10, 0, 0, 1]));
835 }
836
837 #[test]
838 fn test_from_bytes() {
839 let data = Bytes::from_static(b"hello");
840 let v: Value = data.into();
841 assert_eq!(v.as_bytes(), Some(b"hello".as_slice()));
842 }
843
844 #[test]
845 fn test_from_u64() {
846 let v: Value = 12345678901234u64.into();
847 assert_eq!(v, Value::Counter64(12345678901234));
848 }
849
850 #[test]
851 fn test_from_ip_array() {
852 let v: Value = [192u8, 168, 1, 1].into();
853 assert_eq!(v, Value::IpAddress([192, 168, 1, 1]));
854 }
855
856 #[test]
861 fn test_decode_invalid_null_length() {
862 let data = Bytes::from_static(&[0x05, 0x01, 0x00]); let mut decoder = Decoder::new(data);
865 let result = Value::decode(&mut decoder);
866 assert!(result.is_err());
867 }
868
869 #[test]
870 fn test_decode_invalid_ip_address_length() {
871 let data = Bytes::from_static(&[0x40, 0x03, 0x01, 0x02, 0x03]); let mut decoder = Decoder::new(data);
874 let result = Value::decode(&mut decoder);
875 assert!(result.is_err());
876 }
877
878 #[test]
879 fn test_decode_exception_with_content_accepted() {
880 let data = Bytes::from_static(&[0x80, 0x01, 0xFF]); let mut decoder = Decoder::new(data);
883 let result = Value::decode(&mut decoder);
884 assert!(result.is_ok());
885 assert_eq!(result.unwrap(), Value::NoSuchObject);
886 }
887}