1use crate::ber::{Decoder, EncodeBuf, tag};
6use crate::error::internal::DecodeErrorKind;
7use crate::error::{Error, Result, UNKNOWN_TARGET};
8use crate::format::hex;
9use crate::oid::Oid;
10use bytes::Bytes;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
42pub enum RowStatus {
43 Active = 1,
45 NotInService = 2,
47 NotReady = 3,
49 CreateAndGo = 4,
51 CreateAndWait = 5,
53 Destroy = 6,
55}
56
57impl TryFrom<i32> for RowStatus {
58 type Error = i32;
59
60 fn try_from(value: i32) -> std::result::Result<Self, i32> {
61 match value {
62 1 => Ok(Self::Active),
63 2 => Ok(Self::NotInService),
64 3 => Ok(Self::NotReady),
65 4 => Ok(Self::CreateAndGo),
66 5 => Ok(Self::CreateAndWait),
67 6 => Ok(Self::Destroy),
68 _ => Err(value),
69 }
70 }
71}
72
73impl RowStatus {
74 pub fn from_i32(value: i32) -> Option<Self> {
78 Self::try_from(value).ok()
79 }
80}
81
82impl From<RowStatus> for Value {
83 fn from(status: RowStatus) -> Self {
84 Value::Integer(status as i32)
85 }
86}
87
88impl std::fmt::Display for RowStatus {
89 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
90 match self {
91 Self::Active => write!(f, "active"),
92 Self::NotInService => write!(f, "notInService"),
93 Self::NotReady => write!(f, "notReady"),
94 Self::CreateAndGo => write!(f, "createAndGo"),
95 Self::CreateAndWait => write!(f, "createAndWait"),
96 Self::Destroy => write!(f, "destroy"),
97 }
98 }
99}
100
101#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
129pub enum StorageType {
130 Other = 1,
132 Volatile = 2,
134 NonVolatile = 3,
136 Permanent = 4,
138 ReadOnly = 5,
140}
141
142impl TryFrom<i32> for StorageType {
143 type Error = i32;
144
145 fn try_from(value: i32) -> std::result::Result<Self, i32> {
146 match value {
147 1 => Ok(Self::Other),
148 2 => Ok(Self::Volatile),
149 3 => Ok(Self::NonVolatile),
150 4 => Ok(Self::Permanent),
151 5 => Ok(Self::ReadOnly),
152 _ => Err(value),
153 }
154 }
155}
156
157impl StorageType {
158 pub fn from_i32(value: i32) -> Option<Self> {
162 Self::try_from(value).ok()
163 }
164}
165
166impl From<StorageType> for Value {
167 fn from(storage: StorageType) -> Self {
168 Value::Integer(storage as i32)
169 }
170}
171
172impl std::fmt::Display for StorageType {
173 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
174 match self {
175 Self::Other => write!(f, "other"),
176 Self::Volatile => write!(f, "volatile"),
177 Self::NonVolatile => write!(f, "nonVolatile"),
178 Self::Permanent => write!(f, "permanent"),
179 Self::ReadOnly => write!(f, "readOnly"),
180 }
181 }
182}
183
184#[derive(Debug, Clone, PartialEq, Eq, Hash)]
188#[non_exhaustive]
189pub enum Value {
190 Integer(i32),
192
193 OctetString(Bytes),
200
201 Null,
203
204 ObjectIdentifier(Oid),
206
207 IpAddress([u8; 4]),
209
210 Counter32(u32),
212
213 Gauge32(u32),
215
216 TimeTicks(u32),
218
219 Opaque(Bytes),
221
222 Counter64(u64),
232
233 NoSuchObject,
254
255 NoSuchInstance,
270
271 EndOfMibView,
291
292 Unknown { tag: u8, data: Bytes },
294}
295
296impl Value {
297 pub fn as_i32(&self) -> Option<i32> {
317 match self {
318 Value::Integer(v) => Some(*v),
319 _ => None,
320 }
321 }
322
323 pub fn as_u32(&self) -> Option<u32> {
348 match self {
349 Value::Counter32(v) | Value::Gauge32(v) | Value::TimeTicks(v) => Some(*v),
350 Value::Integer(v) if *v >= 0 => Some(*v as u32),
351 _ => None,
352 }
353 }
354
355 pub fn as_u64(&self) -> Option<u64> {
380 match self {
381 Value::Counter64(v) => Some(*v),
382 Value::Counter32(v) | Value::Gauge32(v) | Value::TimeTicks(v) => Some(*v as u64),
383 Value::Integer(v) if *v >= 0 => Some(*v as u64),
384 _ => None,
385 }
386 }
387
388 pub fn as_bytes(&self) -> Option<&[u8]> {
410 match self {
411 Value::OctetString(v) | Value::Opaque(v) => Some(v),
412 _ => None,
413 }
414 }
415
416 pub fn as_str(&self) -> Option<&str> {
440 self.as_bytes().and_then(|b| std::str::from_utf8(b).ok())
441 }
442
443 pub fn as_oid(&self) -> Option<&Oid> {
460 match self {
461 Value::ObjectIdentifier(oid) => Some(oid),
462 _ => None,
463 }
464 }
465
466 pub fn as_ip(&self) -> Option<std::net::Ipv4Addr> {
483 match self {
484 Value::IpAddress(bytes) => Some(std::net::Ipv4Addr::from(*bytes)),
485 _ => None,
486 }
487 }
488
489 pub fn as_f64(&self) -> Option<f64> {
505 match self {
506 Value::Integer(v) => Some(*v as f64),
507 Value::Counter32(v) | Value::Gauge32(v) | Value::TimeTicks(v) => Some(*v as f64),
508 Value::Counter64(v) => Some(*v as f64),
509 _ => None,
510 }
511 }
512
513 pub fn as_f64_wrapped(&self) -> Option<f64> {
537 const MANTISSA_LIMIT: u64 = 1 << 53;
538 match self {
539 Value::Counter64(v) => Some((*v % MANTISSA_LIMIT) as f64),
540 _ => self.as_f64(),
541 }
542 }
543
544 pub fn as_decimal(&self, places: u8) -> Option<f64> {
572 let divisor = 10f64.powi(places as i32);
573 self.as_f64().map(|v| v / divisor)
574 }
575
576 pub fn as_duration(&self) -> Option<std::time::Duration> {
597 match self {
598 Value::TimeTicks(v) => Some(std::time::Duration::from_millis(*v as u64 * 10)),
599 _ => None,
600 }
601 }
602
603 pub fn as_opaque_float(&self) -> Option<f32> {
629 match self {
630 Value::Opaque(data)
631 if data.len() >= 7
632 && data[0] == 0x9f && data[1] == 0x78 && data[2] == 0x04 =>
635 {
636 let bytes: [u8; 4] = data[3..7].try_into().ok()?;
638 Some(f32::from_be_bytes(bytes))
639 }
640 _ => None,
641 }
642 }
643
644 pub fn as_opaque_double(&self) -> Option<f64> {
666 match self {
667 Value::Opaque(data)
668 if data.len() >= 11
669 && data[0] == 0x9f && data[1] == 0x79 && data[2] == 0x08 =>
672 {
673 let bytes: [u8; 8] = data[3..11].try_into().ok()?;
675 Some(f64::from_be_bytes(bytes))
676 }
677 _ => None,
678 }
679 }
680
681 pub fn as_opaque_counter64(&self) -> Option<u64> {
702 self.as_opaque_unsigned(0x76)
703 }
704
705 pub fn as_opaque_i64(&self) -> Option<i64> {
724 match self {
725 Value::Opaque(data)
726 if data.len() >= 4
727 && data[0] == 0x9f && data[1] == 0x7a =>
729 {
730 let len = data[2] as usize;
732 if data.len() < 3 + len || len == 0 || len > 8 {
733 return None;
734 }
735 let bytes = &data[3..3 + len];
736 let is_negative = bytes[0] & 0x80 != 0;
738 let mut value: i64 = if is_negative { -1 } else { 0 };
739 for &byte in bytes {
740 value = (value << 8) | (byte as i64);
741 }
742 Some(value)
743 }
744 _ => None,
745 }
746 }
747
748 pub fn as_opaque_u64(&self) -> Option<u64> {
767 self.as_opaque_unsigned(0x7b)
768 }
769
770 fn as_opaque_unsigned(&self, expected_type: u8) -> Option<u64> {
772 match self {
773 Value::Opaque(data)
774 if data.len() >= 4
775 && data[0] == 0x9f && data[1] == expected_type =>
777 {
778 let len = data[2] as usize;
779 if data.len() < 3 + len || len == 0 || len > 8 {
780 return None;
781 }
782 let bytes = &data[3..3 + len];
783 let mut value: u64 = 0;
784 for &byte in bytes {
785 value = (value << 8) | (byte as u64);
786 }
787 Some(value)
788 }
789 _ => None,
790 }
791 }
792
793 pub fn as_truth_value(&self) -> Option<bool> {
812 match self {
813 Value::Integer(1) => Some(true),
814 Value::Integer(2) => Some(false),
815 _ => None,
816 }
817 }
818
819 pub fn as_row_status(&self) -> Option<RowStatus> {
837 match self {
838 Value::Integer(v) => RowStatus::from_i32(*v),
839 _ => None,
840 }
841 }
842
843 pub fn as_storage_type(&self) -> Option<StorageType> {
861 match self {
862 Value::Integer(v) => StorageType::from_i32(*v),
863 _ => None,
864 }
865 }
866
867 pub fn is_exception(&self) -> bool {
869 matches!(
870 self,
871 Value::NoSuchObject | Value::NoSuchInstance | Value::EndOfMibView
872 )
873 }
874
875 pub(crate) fn ber_encoded_size(&self) -> usize {
877 use crate::ber::{
878 integer_content_len, length_encoded_len, unsigned32_content_len, unsigned64_content_len,
879 };
880
881 match self {
882 Value::Integer(v) => {
883 let content_len = integer_content_len(*v);
884 1 + length_encoded_len(content_len) + content_len
885 }
886 Value::OctetString(data) => {
887 let content_len = data.len();
888 1 + length_encoded_len(content_len) + content_len
889 }
890 Value::Null => 2, Value::ObjectIdentifier(oid) => oid.ber_encoded_size(),
892 Value::IpAddress(_) => 6, Value::Counter32(v) | Value::Gauge32(v) | Value::TimeTicks(v) => {
894 let content_len = unsigned32_content_len(*v);
895 1 + length_encoded_len(content_len) + content_len
896 }
897 Value::Opaque(data) => {
898 let content_len = data.len();
899 1 + length_encoded_len(content_len) + content_len
900 }
901 Value::Counter64(v) => {
902 let content_len = unsigned64_content_len(*v);
903 1 + length_encoded_len(content_len) + content_len
904 }
905 Value::NoSuchObject | Value::NoSuchInstance | Value::EndOfMibView => 2, Value::Unknown { data, .. } => {
907 let content_len = data.len();
908 1 + length_encoded_len(content_len) + content_len
909 }
910 }
911 }
912
913 pub fn format_with_hint(&self, hint: &str) -> Option<String> {
940 match self {
941 Value::OctetString(bytes) => Some(crate::format::display_hint::apply(hint, bytes)),
942 Value::Opaque(bytes) => Some(crate::format::display_hint::apply(hint, bytes)),
943 Value::Integer(v) => crate::format::display_hint::apply_integer(hint, *v),
944 _ => None,
945 }
946 }
947
948 pub fn encode(&self, buf: &mut EncodeBuf) {
950 match self {
951 Value::Integer(v) => buf.push_integer(*v),
952 Value::OctetString(data) => buf.push_octet_string(data),
953 Value::Null => buf.push_null(),
954 Value::ObjectIdentifier(oid) => buf.push_oid(oid),
955 Value::IpAddress(addr) => buf.push_ip_address(*addr),
956 Value::Counter32(v) => buf.push_unsigned32(tag::application::COUNTER32, *v),
957 Value::Gauge32(v) => buf.push_unsigned32(tag::application::GAUGE32, *v),
958 Value::TimeTicks(v) => buf.push_unsigned32(tag::application::TIMETICKS, *v),
959 Value::Opaque(data) => {
960 buf.push_bytes(data);
961 buf.push_length(data.len());
962 buf.push_tag(tag::application::OPAQUE);
963 }
964 Value::Counter64(v) => buf.push_integer64(*v),
965 Value::NoSuchObject => {
966 buf.push_length(0);
967 buf.push_tag(tag::context::NO_SUCH_OBJECT);
968 }
969 Value::NoSuchInstance => {
970 buf.push_length(0);
971 buf.push_tag(tag::context::NO_SUCH_INSTANCE);
972 }
973 Value::EndOfMibView => {
974 buf.push_length(0);
975 buf.push_tag(tag::context::END_OF_MIB_VIEW);
976 }
977 Value::Unknown { tag: t, data } => {
978 buf.push_bytes(data);
979 buf.push_length(data.len());
980 buf.push_tag(*t);
981 }
982 }
983 }
984
985 pub fn decode(decoder: &mut Decoder) -> Result<Self> {
987 let tag = decoder.read_tag()?;
988 let len = decoder.read_length()?;
989
990 match tag {
991 tag::universal::INTEGER => {
992 let value = decoder.read_integer_value(len)?;
993 Ok(Value::Integer(value))
994 }
995 tag::universal::OCTET_STRING => {
996 let available = decoder.remaining();
997 let len = if len > available {
998 tracing::warn!(
1003 target: "async_snmp::value",
1004 { snmp.offset = %decoder.offset(), declared = len, available },
1005 "OctetString length exceeds varbind SEQUENCE boundary, clamping to available bytes"
1006 );
1007 available
1008 } else {
1009 len
1010 };
1011 let data = decoder.read_bytes(len)?;
1012 Ok(Value::OctetString(data))
1013 }
1014 tag::universal::NULL => {
1015 if len != 0 {
1016 tracing::debug!(target: "async_snmp::value", { offset = decoder.offset(), kind = %DecodeErrorKind::InvalidNull }, "decode error");
1017 return Err(Error::MalformedResponse {
1018 target: UNKNOWN_TARGET,
1019 }
1020 .boxed());
1021 }
1022 Ok(Value::Null)
1023 }
1024 tag::universal::OBJECT_IDENTIFIER => {
1025 let oid = decoder.read_oid_value(len)?;
1026 Ok(Value::ObjectIdentifier(oid))
1027 }
1028 tag::application::IP_ADDRESS => {
1029 if len != 4 {
1030 tracing::debug!(target: "async_snmp::value", { offset = decoder.offset(), length = len, kind = %DecodeErrorKind::InvalidIpAddressLength { length: len } }, "decode error");
1031 return Err(Error::MalformedResponse {
1032 target: UNKNOWN_TARGET,
1033 }
1034 .boxed());
1035 }
1036 let data = decoder.read_bytes(4)?;
1037 Ok(Value::IpAddress([data[0], data[1], data[2], data[3]]))
1038 }
1039 tag::application::COUNTER32 => {
1040 let value = decoder.read_unsigned32_value(len)?;
1041 Ok(Value::Counter32(value))
1042 }
1043 tag::application::GAUGE32 => {
1044 let value = decoder.read_unsigned32_value(len)?;
1045 Ok(Value::Gauge32(value))
1046 }
1047 tag::application::TIMETICKS => {
1048 let value = decoder.read_unsigned32_value(len)?;
1049 Ok(Value::TimeTicks(value))
1050 }
1051 tag::application::OPAQUE => {
1052 let available = decoder.remaining();
1053 let len = if len > available {
1054 tracing::warn!(
1055 target: "async_snmp::value",
1056 { snmp.offset = %decoder.offset(), declared = len, available },
1057 "Opaque length exceeds varbind SEQUENCE boundary, clamping to available bytes"
1058 );
1059 available
1060 } else {
1061 len
1062 };
1063 let data = decoder.read_bytes(len)?;
1064 Ok(Value::Opaque(data))
1065 }
1066 tag::application::NSAP => {
1067 let data = decoder.read_bytes(len)?;
1068 Ok(Value::OctetString(data))
1069 }
1070 tag::application::COUNTER64 => {
1071 let value = decoder.read_integer64_value(len)?;
1072 Ok(Value::Counter64(value))
1073 }
1074 tag::application::UINTEGER32 => {
1075 let value = decoder.read_unsigned32_value(len)?;
1076 Ok(Value::Gauge32(value))
1077 }
1078 tag::context::NO_SUCH_OBJECT => {
1079 if len != 0 {
1080 let _ = decoder.read_bytes(len)?;
1081 }
1082 Ok(Value::NoSuchObject)
1083 }
1084 tag::context::NO_SUCH_INSTANCE => {
1085 if len != 0 {
1086 let _ = decoder.read_bytes(len)?;
1087 }
1088 Ok(Value::NoSuchInstance)
1089 }
1090 tag::context::END_OF_MIB_VIEW => {
1091 if len != 0 {
1092 let _ = decoder.read_bytes(len)?;
1093 }
1094 Ok(Value::EndOfMibView)
1095 }
1096 tag::universal::OCTET_STRING_CONSTRUCTED => {
1099 tracing::debug!(target: "async_snmp::value", { offset = decoder.offset(), kind = %DecodeErrorKind::ConstructedOctetString }, "decode error");
1100 Err(Error::MalformedResponse {
1101 target: UNKNOWN_TARGET,
1102 }
1103 .boxed())
1104 }
1105 _ => {
1106 let data = decoder.read_bytes(len)?;
1108 Ok(Value::Unknown { tag, data })
1109 }
1110 }
1111 }
1112}
1113
1114impl std::fmt::Display for Value {
1115 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1116 match self {
1117 Value::Integer(v) => write!(f, "{}", v),
1118 Value::OctetString(data) => {
1119 if let Ok(s) = std::str::from_utf8(data) {
1121 write!(f, "{}", s)
1122 } else {
1123 write!(f, "0x{}", hex::encode(data))
1124 }
1125 }
1126 Value::Null => write!(f, "NULL"),
1127 Value::ObjectIdentifier(oid) => write!(f, "{}", oid),
1128 Value::IpAddress(addr) => {
1129 write!(f, "{}.{}.{}.{}", addr[0], addr[1], addr[2], addr[3])
1130 }
1131 Value::Counter32(v) => write!(f, "{}", v),
1132 Value::Gauge32(v) => write!(f, "{}", v),
1133 Value::TimeTicks(v) => {
1134 write!(f, "{}", crate::format::format_timeticks(*v))
1135 }
1136 Value::Opaque(data) => write!(f, "Opaque(0x{})", hex::encode(data)),
1137 Value::Counter64(v) => write!(f, "{}", v),
1138 Value::NoSuchObject => write!(f, "noSuchObject"),
1139 Value::NoSuchInstance => write!(f, "noSuchInstance"),
1140 Value::EndOfMibView => write!(f, "endOfMibView"),
1141 Value::Unknown { tag, data } => {
1142 write!(
1143 f,
1144 "Unknown(tag=0x{:02X}, data=0x{})",
1145 tag,
1146 hex::encode(data)
1147 )
1148 }
1149 }
1150 }
1151}
1152
1153impl From<i32> for Value {
1195 fn from(v: i32) -> Self {
1196 Value::Integer(v)
1197 }
1198}
1199
1200impl From<&str> for Value {
1201 fn from(s: &str) -> Self {
1202 Value::OctetString(Bytes::copy_from_slice(s.as_bytes()))
1203 }
1204}
1205
1206impl From<String> for Value {
1207 fn from(s: String) -> Self {
1208 Value::OctetString(Bytes::from(s))
1209 }
1210}
1211
1212impl From<&[u8]> for Value {
1213 fn from(data: &[u8]) -> Self {
1214 Value::OctetString(Bytes::copy_from_slice(data))
1215 }
1216}
1217
1218impl From<Oid> for Value {
1219 fn from(oid: Oid) -> Self {
1220 Value::ObjectIdentifier(oid)
1221 }
1222}
1223
1224impl From<std::net::Ipv4Addr> for Value {
1225 fn from(addr: std::net::Ipv4Addr) -> Self {
1226 Value::IpAddress(addr.octets())
1227 }
1228}
1229
1230impl From<Bytes> for Value {
1231 fn from(data: Bytes) -> Self {
1232 Value::OctetString(data)
1233 }
1234}
1235
1236impl From<u64> for Value {
1237 fn from(v: u64) -> Self {
1238 Value::Counter64(v)
1239 }
1240}
1241
1242impl From<[u8; 4]> for Value {
1248 fn from(addr: [u8; 4]) -> Self {
1249 Value::IpAddress(addr)
1250 }
1251}
1252
1253#[cfg(test)]
1254mod tests {
1255 use super::*;
1256
1257 #[test]
1260 fn test_reject_constructed_octet_string() {
1261 let data = bytes::Bytes::from_static(&[0x24, 0x03, 0x04, 0x01, 0x41]);
1265 let mut decoder = Decoder::new(data);
1266 let result = Value::decode(&mut decoder);
1267
1268 assert!(
1269 result.is_err(),
1270 "constructed OCTET STRING (0x24) should be rejected"
1271 );
1272 let err = result.unwrap_err();
1274 assert!(
1275 matches!(&*err, crate::Error::MalformedResponse { .. }),
1276 "expected MalformedResponse error, got: {:?}",
1277 err
1278 );
1279 }
1280
1281 #[test]
1282 fn test_primitive_octet_string_accepted() {
1283 let data = bytes::Bytes::from_static(&[0x04, 0x03, 0x41, 0x42, 0x43]); let mut decoder = Decoder::new(data);
1286 let result = Value::decode(&mut decoder);
1287
1288 assert!(result.is_ok(), "primitive OCTET STRING should be accepted");
1289 let value = result.unwrap();
1290 assert_eq!(value.as_bytes(), Some(&b"ABC"[..]));
1291 }
1292
1293 fn roundtrip(value: Value) -> Value {
1298 let mut buf = EncodeBuf::new();
1299 value.encode(&mut buf);
1300 let data = buf.finish();
1301 let mut decoder = Decoder::new(data);
1302 Value::decode(&mut decoder).unwrap()
1303 }
1304
1305 #[test]
1306 fn test_integer_positive() {
1307 let value = Value::Integer(42);
1308 assert_eq!(roundtrip(value.clone()), value);
1309 }
1310
1311 #[test]
1312 fn test_integer_negative() {
1313 let value = Value::Integer(-42);
1314 assert_eq!(roundtrip(value.clone()), value);
1315 }
1316
1317 #[test]
1318 fn test_integer_zero() {
1319 let value = Value::Integer(0);
1320 assert_eq!(roundtrip(value.clone()), value);
1321 }
1322
1323 #[test]
1324 fn test_integer_min() {
1325 let value = Value::Integer(i32::MIN);
1326 assert_eq!(roundtrip(value.clone()), value);
1327 }
1328
1329 #[test]
1330 fn test_integer_max() {
1331 let value = Value::Integer(i32::MAX);
1332 assert_eq!(roundtrip(value.clone()), value);
1333 }
1334
1335 #[test]
1336 fn test_octet_string_ascii() {
1337 let value = Value::OctetString(Bytes::from_static(b"hello world"));
1338 assert_eq!(roundtrip(value.clone()), value);
1339 }
1340
1341 #[test]
1342 fn test_octet_string_binary() {
1343 let value = Value::OctetString(Bytes::from_static(&[0x00, 0xFF, 0x80, 0x7F]));
1344 assert_eq!(roundtrip(value.clone()), value);
1345 }
1346
1347 #[test]
1348 fn test_octet_string_empty() {
1349 let value = Value::OctetString(Bytes::new());
1350 assert_eq!(roundtrip(value.clone()), value);
1351 }
1352
1353 #[test]
1354 fn test_null() {
1355 let value = Value::Null;
1356 assert_eq!(roundtrip(value.clone()), value);
1357 }
1358
1359 #[test]
1360 fn test_object_identifier() {
1361 let value = Value::ObjectIdentifier(crate::oid!(1, 3, 6, 1, 2, 1, 1, 1, 0));
1362 assert_eq!(roundtrip(value.clone()), value);
1363 }
1364
1365 #[test]
1366 fn test_ip_address() {
1367 let value = Value::IpAddress([192, 168, 1, 1]);
1368 assert_eq!(roundtrip(value.clone()), value);
1369 }
1370
1371 #[test]
1372 fn test_ip_address_zero() {
1373 let value = Value::IpAddress([0, 0, 0, 0]);
1374 assert_eq!(roundtrip(value.clone()), value);
1375 }
1376
1377 #[test]
1378 fn test_ip_address_broadcast() {
1379 let value = Value::IpAddress([255, 255, 255, 255]);
1380 assert_eq!(roundtrip(value.clone()), value);
1381 }
1382
1383 #[test]
1384 fn test_counter32() {
1385 let value = Value::Counter32(999999);
1386 assert_eq!(roundtrip(value.clone()), value);
1387 }
1388
1389 #[test]
1390 fn test_counter32_zero() {
1391 let value = Value::Counter32(0);
1392 assert_eq!(roundtrip(value.clone()), value);
1393 }
1394
1395 #[test]
1396 fn test_counter32_max() {
1397 let value = Value::Counter32(u32::MAX);
1398 assert_eq!(roundtrip(value.clone()), value);
1399 }
1400
1401 #[test]
1402 fn test_gauge32() {
1403 let value = Value::Gauge32(1000000000);
1404 assert_eq!(roundtrip(value.clone()), value);
1405 }
1406
1407 #[test]
1408 fn test_gauge32_max() {
1409 let value = Value::Gauge32(u32::MAX);
1410 assert_eq!(roundtrip(value.clone()), value);
1411 }
1412
1413 #[test]
1414 fn test_timeticks() {
1415 let value = Value::TimeTicks(123456);
1416 assert_eq!(roundtrip(value.clone()), value);
1417 }
1418
1419 #[test]
1420 fn test_timeticks_max() {
1421 let value = Value::TimeTicks(u32::MAX);
1422 assert_eq!(roundtrip(value.clone()), value);
1423 }
1424
1425 #[test]
1426 fn test_opaque() {
1427 let value = Value::Opaque(Bytes::from_static(&[0xDE, 0xAD, 0xBE, 0xEF]));
1428 assert_eq!(roundtrip(value.clone()), value);
1429 }
1430
1431 #[test]
1432 fn test_opaque_empty() {
1433 let value = Value::Opaque(Bytes::new());
1434 assert_eq!(roundtrip(value.clone()), value);
1435 }
1436
1437 #[test]
1438 fn test_counter64() {
1439 let value = Value::Counter64(123456789012345);
1440 assert_eq!(roundtrip(value.clone()), value);
1441 }
1442
1443 #[test]
1444 fn test_counter64_zero() {
1445 let value = Value::Counter64(0);
1446 assert_eq!(roundtrip(value.clone()), value);
1447 }
1448
1449 #[test]
1450 fn test_counter64_max() {
1451 let value = Value::Counter64(u64::MAX);
1452 assert_eq!(roundtrip(value.clone()), value);
1453 }
1454
1455 #[test]
1456 fn test_no_such_object() {
1457 let value = Value::NoSuchObject;
1458 assert_eq!(roundtrip(value.clone()), value);
1459 }
1460
1461 #[test]
1462 fn test_no_such_instance() {
1463 let value = Value::NoSuchInstance;
1464 assert_eq!(roundtrip(value.clone()), value);
1465 }
1466
1467 #[test]
1468 fn test_end_of_mib_view() {
1469 let value = Value::EndOfMibView;
1470 assert_eq!(roundtrip(value.clone()), value);
1471 }
1472
1473 #[test]
1474 fn test_unknown_tag_preserved() {
1475 let data = Bytes::from_static(&[0x48, 0x03, 0x01, 0x02, 0x03]);
1477 let mut decoder = Decoder::new(data);
1478 let value = Value::decode(&mut decoder).unwrap();
1479
1480 match value {
1481 Value::Unknown { tag, ref data } => {
1482 assert_eq!(tag, 0x48);
1483 assert_eq!(data.as_ref(), &[0x01, 0x02, 0x03]);
1484 }
1485 _ => panic!("expected Unknown variant"),
1486 }
1487
1488 assert_eq!(roundtrip(value.clone()), value);
1490 }
1491
1492 #[test]
1493 fn test_nsap_decodes_as_octet_string() {
1494 let data = Bytes::from_static(&[0x45, 0x03, 0x01, 0x02, 0x03]);
1496 let mut decoder = Decoder::new(data);
1497 let value = Value::decode(&mut decoder).unwrap();
1498 assert_eq!(
1499 value,
1500 Value::OctetString(Bytes::from_static(&[0x01, 0x02, 0x03]))
1501 );
1502 }
1503
1504 #[test]
1505 fn test_uinteger32_decodes_as_gauge32() {
1506 let data = Bytes::from_static(&[0x47, 0x01, 0x2a]);
1508 let mut decoder = Decoder::new(data);
1509 let value = Value::decode(&mut decoder).unwrap();
1510 assert_eq!(value, Value::Gauge32(42));
1511 }
1512
1513 #[test]
1518 fn test_as_i32() {
1519 assert_eq!(Value::Integer(42).as_i32(), Some(42));
1520 assert_eq!(Value::Integer(-42).as_i32(), Some(-42));
1521 assert_eq!(Value::Counter32(100).as_i32(), None);
1522 assert_eq!(Value::Null.as_i32(), None);
1523 }
1524
1525 #[test]
1526 fn test_as_u32() {
1527 assert_eq!(Value::Counter32(100).as_u32(), Some(100));
1528 assert_eq!(Value::Gauge32(200).as_u32(), Some(200));
1529 assert_eq!(Value::TimeTicks(300).as_u32(), Some(300));
1530 assert_eq!(Value::Integer(50).as_u32(), Some(50));
1531 assert_eq!(Value::Integer(-1).as_u32(), None);
1532 assert_eq!(Value::Counter64(100).as_u32(), None);
1533 }
1534
1535 #[test]
1536 fn test_as_u64() {
1537 assert_eq!(Value::Counter64(100).as_u64(), Some(100));
1538 assert_eq!(Value::Counter32(100).as_u64(), Some(100));
1539 assert_eq!(Value::Gauge32(200).as_u64(), Some(200));
1540 assert_eq!(Value::TimeTicks(300).as_u64(), Some(300));
1541 assert_eq!(Value::Integer(50).as_u64(), Some(50));
1542 assert_eq!(Value::Integer(-1).as_u64(), None);
1543 }
1544
1545 #[test]
1546 fn test_as_bytes() {
1547 let s = Value::OctetString(Bytes::from_static(b"test"));
1548 assert_eq!(s.as_bytes(), Some(b"test".as_slice()));
1549
1550 let o = Value::Opaque(Bytes::from_static(b"data"));
1551 assert_eq!(o.as_bytes(), Some(b"data".as_slice()));
1552
1553 assert_eq!(Value::Integer(1).as_bytes(), None);
1554 }
1555
1556 #[test]
1557 fn test_as_str() {
1558 let s = Value::OctetString(Bytes::from_static(b"hello"));
1559 assert_eq!(s.as_str(), Some("hello"));
1560
1561 let invalid = Value::OctetString(Bytes::from_static(&[0xFF, 0xFE]));
1563 assert_eq!(invalid.as_str(), None);
1564
1565 assert_eq!(Value::Integer(1).as_str(), None);
1566 }
1567
1568 #[test]
1569 fn test_as_oid() {
1570 let oid = crate::oid!(1, 3, 6, 1);
1571 let v = Value::ObjectIdentifier(oid.clone());
1572 assert_eq!(v.as_oid(), Some(&oid));
1573
1574 assert_eq!(Value::Integer(1).as_oid(), None);
1575 }
1576
1577 #[test]
1578 fn test_as_ip() {
1579 let v = Value::IpAddress([192, 168, 1, 1]);
1580 assert_eq!(v.as_ip(), Some(std::net::Ipv4Addr::new(192, 168, 1, 1)));
1581
1582 assert_eq!(Value::Integer(1).as_ip(), None);
1583 }
1584
1585 #[test]
1590 fn test_is_exception() {
1591 assert!(Value::NoSuchObject.is_exception());
1592 assert!(Value::NoSuchInstance.is_exception());
1593 assert!(Value::EndOfMibView.is_exception());
1594
1595 assert!(!Value::Integer(1).is_exception());
1596 assert!(!Value::Null.is_exception());
1597 assert!(!Value::OctetString(Bytes::new()).is_exception());
1598 }
1599
1600 #[test]
1605 fn test_display_integer() {
1606 assert_eq!(format!("{}", Value::Integer(42)), "42");
1607 assert_eq!(format!("{}", Value::Integer(-42)), "-42");
1608 }
1609
1610 #[test]
1611 fn test_display_octet_string_utf8() {
1612 let v = Value::OctetString(Bytes::from_static(b"hello"));
1613 assert_eq!(format!("{}", v), "hello");
1614 }
1615
1616 #[test]
1617 fn test_display_octet_string_binary() {
1618 let v = Value::OctetString(Bytes::from_static(&[0xFF, 0xFE]));
1620 assert_eq!(format!("{}", v), "0xfffe");
1621 }
1622
1623 #[test]
1624 fn test_display_null() {
1625 assert_eq!(format!("{}", Value::Null), "NULL");
1626 }
1627
1628 #[test]
1629 fn test_display_ip_address() {
1630 let v = Value::IpAddress([192, 168, 1, 1]);
1631 assert_eq!(format!("{}", v), "192.168.1.1");
1632 }
1633
1634 #[test]
1635 fn test_display_counter32() {
1636 assert_eq!(format!("{}", Value::Counter32(999)), "999");
1637 }
1638
1639 #[test]
1640 fn test_display_gauge32() {
1641 assert_eq!(format!("{}", Value::Gauge32(1000)), "1000");
1642 }
1643
1644 #[test]
1645 fn test_display_timeticks() {
1646 let v = Value::TimeTicks(123456);
1648 assert_eq!(format!("{}", v), "00:20:34.56");
1649 }
1650
1651 #[test]
1652 fn test_display_opaque() {
1653 let v = Value::Opaque(Bytes::from_static(&[0xBE, 0xEF]));
1654 assert_eq!(format!("{}", v), "Opaque(0xbeef)");
1655 }
1656
1657 #[test]
1658 fn test_display_counter64() {
1659 assert_eq!(format!("{}", Value::Counter64(12345678)), "12345678");
1660 }
1661
1662 #[test]
1663 fn test_display_exceptions() {
1664 assert_eq!(format!("{}", Value::NoSuchObject), "noSuchObject");
1665 assert_eq!(format!("{}", Value::NoSuchInstance), "noSuchInstance");
1666 assert_eq!(format!("{}", Value::EndOfMibView), "endOfMibView");
1667 }
1668
1669 #[test]
1670 fn test_display_unknown() {
1671 let v = Value::Unknown {
1672 tag: 0x99,
1673 data: Bytes::from_static(&[0x01, 0x02]),
1674 };
1675 assert_eq!(format!("{}", v), "Unknown(tag=0x99, data=0x0102)");
1676 }
1677
1678 #[test]
1683 fn test_from_i32() {
1684 let v: Value = 42i32.into();
1685 assert_eq!(v, Value::Integer(42));
1686 }
1687
1688 #[test]
1689 fn test_from_str() {
1690 let v: Value = "hello".into();
1691 assert_eq!(v.as_str(), Some("hello"));
1692 }
1693
1694 #[test]
1695 fn test_from_string() {
1696 let v: Value = String::from("hello").into();
1697 assert_eq!(v.as_str(), Some("hello"));
1698 }
1699
1700 #[test]
1701 fn test_from_bytes_slice() {
1702 let v: Value = (&[1u8, 2, 3][..]).into();
1703 assert_eq!(v.as_bytes(), Some(&[1u8, 2, 3][..]));
1704 }
1705
1706 #[test]
1707 fn test_from_oid() {
1708 let oid = crate::oid!(1, 3, 6, 1);
1709 let v: Value = oid.clone().into();
1710 assert_eq!(v.as_oid(), Some(&oid));
1711 }
1712
1713 #[test]
1714 fn test_from_ipv4addr() {
1715 let addr = std::net::Ipv4Addr::new(10, 0, 0, 1);
1716 let v: Value = addr.into();
1717 assert_eq!(v, Value::IpAddress([10, 0, 0, 1]));
1718 }
1719
1720 #[test]
1721 fn test_from_bytes() {
1722 let data = Bytes::from_static(b"hello");
1723 let v: Value = data.into();
1724 assert_eq!(v.as_bytes(), Some(b"hello".as_slice()));
1725 }
1726
1727 #[test]
1728 fn test_from_u64() {
1729 let v: Value = 12345678901234u64.into();
1730 assert_eq!(v, Value::Counter64(12345678901234));
1731 }
1732
1733 #[test]
1734 fn test_from_ip_array() {
1735 let v: Value = [192u8, 168, 1, 1].into();
1736 assert_eq!(v, Value::IpAddress([192, 168, 1, 1]));
1737 }
1738
1739 #[test]
1744 fn test_value_eq_and_hash() {
1745 use std::collections::HashSet;
1746
1747 let mut set = HashSet::new();
1748 set.insert(Value::Integer(42));
1749 set.insert(Value::Integer(42)); set.insert(Value::Integer(100));
1751
1752 assert_eq!(set.len(), 2);
1753 assert!(set.contains(&Value::Integer(42)));
1754 assert!(set.contains(&Value::Integer(100)));
1755 }
1756
1757 #[test]
1762 fn test_decode_invalid_null_length() {
1763 let data = Bytes::from_static(&[0x05, 0x01, 0x00]); let mut decoder = Decoder::new(data);
1766 let result = Value::decode(&mut decoder);
1767 assert!(result.is_err());
1768 }
1769
1770 #[test]
1771 fn test_decode_invalid_ip_address_length() {
1772 let data = Bytes::from_static(&[0x40, 0x03, 0x01, 0x02, 0x03]); let mut decoder = Decoder::new(data);
1775 let result = Value::decode(&mut decoder);
1776 assert!(result.is_err());
1777 }
1778
1779 #[test]
1780 fn test_decode_exception_with_content_accepted() {
1781 let data = Bytes::from_static(&[0x80, 0x01, 0xFF]); let mut decoder = Decoder::new(data);
1784 let result = Value::decode(&mut decoder);
1785 assert!(result.is_ok());
1786 assert_eq!(result.unwrap(), Value::NoSuchObject);
1787 }
1788
1789 #[test]
1794 fn test_as_f64() {
1795 assert_eq!(Value::Integer(42).as_f64(), Some(42.0));
1796 assert_eq!(Value::Integer(-42).as_f64(), Some(-42.0));
1797 assert_eq!(Value::Counter32(1000).as_f64(), Some(1000.0));
1798 assert_eq!(Value::Gauge32(2000).as_f64(), Some(2000.0));
1799 assert_eq!(Value::TimeTicks(3000).as_f64(), Some(3000.0));
1800 assert_eq!(
1801 Value::Counter64(10_000_000_000).as_f64(),
1802 Some(10_000_000_000.0)
1803 );
1804 assert_eq!(Value::Null.as_f64(), None);
1805 assert_eq!(
1806 Value::OctetString(Bytes::from_static(b"test")).as_f64(),
1807 None
1808 );
1809 }
1810
1811 #[test]
1812 fn test_as_f64_wrapped() {
1813 assert_eq!(Value::Counter64(1000).as_f64_wrapped(), Some(1000.0));
1815 assert_eq!(Value::Counter32(1000).as_f64_wrapped(), Some(1000.0));
1816 assert_eq!(Value::Integer(42).as_f64_wrapped(), Some(42.0));
1817
1818 let mantissa_limit = 1u64 << 53;
1820 assert_eq!(Value::Counter64(mantissa_limit).as_f64_wrapped(), Some(0.0));
1821 assert_eq!(
1822 Value::Counter64(mantissa_limit + 1).as_f64_wrapped(),
1823 Some(1.0)
1824 );
1825 }
1826
1827 #[test]
1828 fn test_as_decimal() {
1829 assert_eq!(Value::Integer(2350).as_decimal(2), Some(23.50));
1830 assert_eq!(Value::Integer(9999).as_decimal(2), Some(99.99));
1831 assert_eq!(Value::Integer(12500).as_decimal(3), Some(12.5));
1832 assert_eq!(Value::Integer(-500).as_decimal(2), Some(-5.0));
1833 assert_eq!(Value::Counter32(1000).as_decimal(1), Some(100.0));
1834 assert_eq!(Value::Null.as_decimal(2), None);
1835 }
1836
1837 #[test]
1838 fn test_as_duration() {
1839 use std::time::Duration;
1840
1841 assert_eq!(
1843 Value::TimeTicks(100).as_duration(),
1844 Some(Duration::from_secs(1))
1845 );
1846 assert_eq!(
1848 Value::TimeTicks(360000).as_duration(),
1849 Some(Duration::from_secs(3600))
1850 );
1851 assert_eq!(
1853 Value::TimeTicks(1).as_duration(),
1854 Some(Duration::from_millis(10))
1855 );
1856
1857 assert_eq!(Value::Integer(100).as_duration(), None);
1859 assert_eq!(Value::Counter32(100).as_duration(), None);
1860 }
1861
1862 #[test]
1867 fn test_as_opaque_float() {
1868 let data = Bytes::from_static(&[0x9f, 0x78, 0x04, 0x40, 0x49, 0x0f, 0xdb]);
1871 let value = Value::Opaque(data);
1872 let pi = value.as_opaque_float().unwrap();
1873 assert!((pi - std::f32::consts::PI).abs() < 0.0001);
1874
1875 assert_eq!(Value::Integer(42).as_opaque_float(), None);
1877
1878 let wrong_type = Bytes::from_static(&[0x9f, 0x79, 0x04, 0x40, 0x49, 0x0f, 0xdb]);
1880 assert_eq!(Value::Opaque(wrong_type).as_opaque_float(), None);
1881
1882 let short = Bytes::from_static(&[0x9f, 0x78, 0x04, 0x40, 0x49]);
1884 assert_eq!(Value::Opaque(short).as_opaque_float(), None);
1885 }
1886
1887 #[test]
1888 fn test_as_opaque_double() {
1889 let data = Bytes::from_static(&[
1892 0x9f, 0x79, 0x08, 0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18,
1893 ]);
1894 let value = Value::Opaque(data);
1895 let pi = value.as_opaque_double().unwrap();
1896 assert!((pi - std::f64::consts::PI).abs() < 1e-10);
1897
1898 assert_eq!(Value::Integer(42).as_opaque_double(), None);
1900 }
1901
1902 #[test]
1903 fn test_as_opaque_counter64() {
1904 let data = Bytes::from_static(&[
1906 0x9f, 0x76, 0x08, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
1907 ]);
1908 let value = Value::Opaque(data);
1909 assert_eq!(value.as_opaque_counter64(), Some(0x0123456789ABCDEF));
1910
1911 let small = Bytes::from_static(&[0x9f, 0x76, 0x01, 0x42]);
1913 assert_eq!(Value::Opaque(small).as_opaque_counter64(), Some(0x42));
1914
1915 let zero = Bytes::from_static(&[0x9f, 0x76, 0x01, 0x00]);
1917 assert_eq!(Value::Opaque(zero).as_opaque_counter64(), Some(0));
1918 }
1919
1920 #[test]
1921 fn test_as_opaque_i64() {
1922 let positive = Bytes::from_static(&[0x9f, 0x7a, 0x02, 0x01, 0x00]);
1924 assert_eq!(Value::Opaque(positive).as_opaque_i64(), Some(256));
1925
1926 let minus_one = Bytes::from_static(&[0x9f, 0x7a, 0x01, 0xFF]);
1928 assert_eq!(Value::Opaque(minus_one).as_opaque_i64(), Some(-1));
1929
1930 let full_neg = Bytes::from_static(&[
1932 0x9f, 0x7a, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1933 ]);
1934 assert_eq!(Value::Opaque(full_neg).as_opaque_i64(), Some(-1));
1935
1936 let min = Bytes::from_static(&[
1938 0x9f, 0x7a, 0x08, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1939 ]);
1940 assert_eq!(Value::Opaque(min).as_opaque_i64(), Some(i64::MIN));
1941 }
1942
1943 #[test]
1944 fn test_as_opaque_u64() {
1945 let data = Bytes::from_static(&[
1947 0x9f, 0x7b, 0x08, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
1948 ]);
1949 let value = Value::Opaque(data);
1950 assert_eq!(value.as_opaque_u64(), Some(0x0123456789ABCDEF));
1951
1952 let max = Bytes::from_static(&[
1954 0x9f, 0x7b, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1955 ]);
1956 assert_eq!(Value::Opaque(max).as_opaque_u64(), Some(u64::MAX));
1957 }
1958
1959 #[test]
1960 fn test_format_with_hint_integer() {
1961 assert_eq!(
1963 Value::Integer(2350).format_with_hint("d-2"),
1964 Some("23.50".into())
1965 );
1966 assert_eq!(
1967 Value::Integer(-500).format_with_hint("d-2"),
1968 Some("-5.00".into())
1969 );
1970
1971 assert_eq!(Value::Integer(255).format_with_hint("x"), Some("ff".into()));
1973 assert_eq!(Value::Integer(8).format_with_hint("o"), Some("10".into()));
1974 assert_eq!(Value::Integer(5).format_with_hint("b"), Some("101".into()));
1975 assert_eq!(Value::Integer(42).format_with_hint("d"), Some("42".into()));
1976
1977 assert_eq!(Value::Integer(42).format_with_hint("invalid"), None);
1979
1980 assert_eq!(Value::Counter32(42).format_with_hint("d-2"), None);
1982 }
1983
1984 #[test]
1985 fn test_as_truth_value() {
1986 assert_eq!(Value::Integer(1).as_truth_value(), Some(true));
1988 assert_eq!(Value::Integer(2).as_truth_value(), Some(false));
1989
1990 assert_eq!(Value::Integer(0).as_truth_value(), None);
1992 assert_eq!(Value::Integer(3).as_truth_value(), None);
1993 assert_eq!(Value::Integer(-1).as_truth_value(), None);
1994
1995 assert_eq!(Value::Null.as_truth_value(), None);
1997 assert_eq!(Value::Counter32(1).as_truth_value(), None);
1998 assert_eq!(Value::Gauge32(1).as_truth_value(), None);
1999 }
2000
2001 #[test]
2006 fn test_row_status_from_i32() {
2007 assert_eq!(RowStatus::from_i32(1), Some(RowStatus::Active));
2008 assert_eq!(RowStatus::from_i32(2), Some(RowStatus::NotInService));
2009 assert_eq!(RowStatus::from_i32(3), Some(RowStatus::NotReady));
2010 assert_eq!(RowStatus::from_i32(4), Some(RowStatus::CreateAndGo));
2011 assert_eq!(RowStatus::from_i32(5), Some(RowStatus::CreateAndWait));
2012 assert_eq!(RowStatus::from_i32(6), Some(RowStatus::Destroy));
2013
2014 assert_eq!(RowStatus::from_i32(0), None);
2016 assert_eq!(RowStatus::from_i32(7), None);
2017 assert_eq!(RowStatus::from_i32(-1), None);
2018 }
2019
2020 #[test]
2021 fn test_row_status_try_from() {
2022 assert_eq!(RowStatus::try_from(1), Ok(RowStatus::Active));
2023 assert_eq!(RowStatus::try_from(6), Ok(RowStatus::Destroy));
2024 assert_eq!(RowStatus::try_from(0), Err(0));
2025 assert_eq!(RowStatus::try_from(7), Err(7));
2026 assert_eq!(RowStatus::try_from(-1), Err(-1));
2027 }
2028
2029 #[test]
2030 fn test_row_status_into_value() {
2031 let v: Value = RowStatus::Active.into();
2032 assert_eq!(v, Value::Integer(1));
2033
2034 let v: Value = RowStatus::Destroy.into();
2035 assert_eq!(v, Value::Integer(6));
2036 }
2037
2038 #[test]
2039 fn test_row_status_display() {
2040 assert_eq!(format!("{}", RowStatus::Active), "active");
2041 assert_eq!(format!("{}", RowStatus::NotInService), "notInService");
2042 assert_eq!(format!("{}", RowStatus::NotReady), "notReady");
2043 assert_eq!(format!("{}", RowStatus::CreateAndGo), "createAndGo");
2044 assert_eq!(format!("{}", RowStatus::CreateAndWait), "createAndWait");
2045 assert_eq!(format!("{}", RowStatus::Destroy), "destroy");
2046 }
2047
2048 #[test]
2049 fn test_as_row_status() {
2050 assert_eq!(Value::Integer(1).as_row_status(), Some(RowStatus::Active));
2052 assert_eq!(Value::Integer(6).as_row_status(), Some(RowStatus::Destroy));
2053
2054 assert_eq!(Value::Integer(0).as_row_status(), None);
2056 assert_eq!(Value::Integer(7).as_row_status(), None);
2057
2058 assert_eq!(Value::Null.as_row_status(), None);
2060 assert_eq!(Value::Counter32(1).as_row_status(), None);
2061 }
2062
2063 #[test]
2068 fn test_storage_type_from_i32() {
2069 assert_eq!(StorageType::from_i32(1), Some(StorageType::Other));
2070 assert_eq!(StorageType::from_i32(2), Some(StorageType::Volatile));
2071 assert_eq!(StorageType::from_i32(3), Some(StorageType::NonVolatile));
2072 assert_eq!(StorageType::from_i32(4), Some(StorageType::Permanent));
2073 assert_eq!(StorageType::from_i32(5), Some(StorageType::ReadOnly));
2074
2075 assert_eq!(StorageType::from_i32(0), None);
2077 assert_eq!(StorageType::from_i32(6), None);
2078 assert_eq!(StorageType::from_i32(-1), None);
2079 }
2080
2081 #[test]
2082 fn test_storage_type_try_from() {
2083 assert_eq!(StorageType::try_from(1), Ok(StorageType::Other));
2084 assert_eq!(StorageType::try_from(5), Ok(StorageType::ReadOnly));
2085 assert_eq!(StorageType::try_from(0), Err(0));
2086 assert_eq!(StorageType::try_from(6), Err(6));
2087 assert_eq!(StorageType::try_from(-1), Err(-1));
2088 }
2089
2090 #[test]
2091 fn test_storage_type_into_value() {
2092 let v: Value = StorageType::Volatile.into();
2093 assert_eq!(v, Value::Integer(2));
2094
2095 let v: Value = StorageType::NonVolatile.into();
2096 assert_eq!(v, Value::Integer(3));
2097 }
2098
2099 #[test]
2100 fn test_storage_type_display() {
2101 assert_eq!(format!("{}", StorageType::Other), "other");
2102 assert_eq!(format!("{}", StorageType::Volatile), "volatile");
2103 assert_eq!(format!("{}", StorageType::NonVolatile), "nonVolatile");
2104 assert_eq!(format!("{}", StorageType::Permanent), "permanent");
2105 assert_eq!(format!("{}", StorageType::ReadOnly), "readOnly");
2106 }
2107
2108 #[test]
2109 fn test_as_storage_type() {
2110 assert_eq!(
2112 Value::Integer(2).as_storage_type(),
2113 Some(StorageType::Volatile)
2114 );
2115 assert_eq!(
2116 Value::Integer(3).as_storage_type(),
2117 Some(StorageType::NonVolatile)
2118 );
2119
2120 assert_eq!(Value::Integer(0).as_storage_type(), None);
2122 assert_eq!(Value::Integer(6).as_storage_type(), None);
2123
2124 assert_eq!(Value::Null.as_storage_type(), None);
2126 assert_eq!(Value::Counter32(1).as_storage_type(), None);
2127 }
2128}