1addr_ty!(
2 InfiniBandAddr[20]
4);
5
6#[cfg(test)]
7mod tests {
8 use super::*;
9 use crate::TestCase;
10
11 use std::{string::ToString, vec, vec::Vec};
12
13 const INFINI_BAND_ADDRESS_SIZE: usize = 20;
14
15 fn test_cases() -> Vec<TestCase<INFINI_BAND_ADDRESS_SIZE>> {
16 vec![
17 TestCase {
19 input: "00:00:00:00:fe:80:00:00:00:00:00:00:02:00:5e:10:00:00:00:01",
20 output: Some(vec![
21 0x00, 0x00, 0x00, 0x00, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x5e,
22 0x10, 0x00, 0x00, 0x00, 0x01,
23 ]),
24 err: None,
25 },
26 TestCase {
27 input: "00-00-00-00-fe-80-00-00-00-00-00-00-02-00-5e-10-00-00-00-01",
28 output: Some(vec![
29 0x00, 0x00, 0x00, 0x00, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x5e,
30 0x10, 0x00, 0x00, 0x00, 0x01,
31 ]),
32 err: None,
33 },
34 TestCase {
35 input: "0000.0000.fe80.0000.0000.0000.0200.5e10.0000.0001",
36 output: Some(vec![
37 0x00, 0x00, 0x00, 0x00, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x5e,
38 0x10, 0x00, 0x00, 0x00, 0x01,
39 ]),
40 err: None,
41 },
42 ]
43 }
44
45 #[test]
46 fn parse() {
47 let cases = test_cases();
48 for (i, test) in cases.iter().enumerate() {
49 let result = InfiniBandAddr::try_from(test.input);
50
51 match (result, &test.output) {
52 (Ok(out), Some(expected)) => {
53 assert_eq!(
54 out.as_ref(),
55 expected.as_slice(),
56 "Test case {}: InfiniBandAddr::parse({}) output mismatch",
57 i,
58 test.input
59 );
60
61 if test.err.is_none() {
63 let formatted = out.to_string();
64 let round_trip = InfiniBandAddr::try_from(formatted.as_str());
65 assert!(
66 round_trip.is_ok(),
67 "Test case {}: Round-trip parse failed for {}",
68 i,
69 formatted
70 );
71 assert_eq!(
72 round_trip.unwrap(),
73 out,
74 "Test case {}: Round-trip value mismatch",
75 i
76 );
77 }
78 }
79 (Err(err), None) => {
80 assert_eq!(
81 Some(&err),
82 test.err.as_ref(),
83 "Test case {}: Expected error containing '{:?}', got '{:?}'",
84 i,
85 test.err,
86 err
87 );
88 }
89 (Ok(out), None) => {
90 panic!(
91 "Test case {}: Expected error '{:?}', got success: {:?}",
92 i, test.err, out
93 );
94 }
95 (Err(err), Some(expected)) => {
96 panic!(
97 "Test case {}: Expected {:?}, got error: {:?}",
98 i, expected, err
99 );
100 }
101 }
102 }
103 }
104
105 #[test]
106 fn test_default() {
107 let addr = InfiniBandAddr::default();
108 assert_eq!(addr.octets(), [0; INFINI_BAND_ADDRESS_SIZE]);
109 }
110
111 #[test]
112 fn formatted() {
113 let addr =
114 InfiniBandAddr::try_from("00:00:00:00:fe:80:00:00:00:00:00:00:02:00:5e:10:00:00:00:01")
115 .unwrap();
116 assert_eq!(
117 addr.to_string(),
118 "00:00:00:00:fe:80:00:00:00:00:00:00:02:00:5e:10:00:00:00:01"
119 );
120 assert_eq!(
121 addr.to_colon_separated(),
122 "00:00:00:00:fe:80:00:00:00:00:00:00:02:00:5e:10:00:00:00:01"
123 );
124
125 let dot = addr.to_dot_separated_array();
126 let dot_str = core::str::from_utf8(&dot).unwrap();
127 assert_eq!(dot_str, "0000.0000.fe80.0000.0000.0000.0200.5e10.0000.0001");
128 assert_eq!(
129 addr.to_dot_separated(),
130 "0000.0000.fe80.0000.0000.0000.0200.5e10.0000.0001"
131 );
132
133 let dashed = addr.to_hyphen_separated_array();
134 let dashed_str = core::str::from_utf8(&dashed).unwrap();
135 assert_eq!(
136 dashed_str,
137 "00-00-00-00-fe-80-00-00-00-00-00-00-02-00-5e-10-00-00-00-01"
138 );
139 assert_eq!(
140 addr.to_hyphen_separated(),
141 "00-00-00-00-fe-80-00-00-00-00-00-00-02-00-5e-10-00-00-00-01"
142 );
143 }
144
145 #[cfg(feature = "serde")]
146 #[test]
147 fn serde_human_readable() {
148 let addr =
149 InfiniBandAddr::try_from("00:00:00:00:fe:80:00:00:00:00:00:00:02:00:5e:10:00:00:00:01")
150 .unwrap();
151 let json = serde_json::to_string(&addr).unwrap();
152 assert_eq!(
153 json,
154 "\"00:00:00:00:fe:80:00:00:00:00:00:00:02:00:5e:10:00:00:00:01\""
155 );
156
157 let addr2: InfiniBandAddr = serde_json::from_str(&json).unwrap();
158 assert_eq!(addr, addr2);
159 }
160
161 #[cfg(feature = "serde")]
162 #[test]
163 fn serde_human_unreadable() {
164 let addr =
165 InfiniBandAddr::try_from("00:00:00:00:fe:80:00:00:00:00:00:00:02:00:5e:10:00:00:00:01")
166 .unwrap();
167 let encoded = bincode::serde::encode_to_vec(addr, bincode::config::standard()).unwrap();
168 assert_eq!(
169 encoded,
170 [
171 0x00, 0x00, 0x00, 0x00, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x5e,
172 0x10, 0x00, 0x00, 0x00, 0x01,
173 ]
174 );
175 assert_eq!(addr.octets(), encoded.as_slice());
176
177 let addr2: InfiniBandAddr =
178 bincode::serde::decode_from_slice(&encoded, bincode::config::standard())
179 .unwrap()
180 .0;
181 assert_eq!(addr, addr2);
182 let addr3 = InfiniBandAddr::from_raw([
183 0x00, 0x00, 0x00, 0x00, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x5e,
184 0x10, 0x00, 0x00, 0x00, 0x01,
185 ]);
186 assert_eq!(addr, addr3);
187 println!("{:?}", addr);
188 }
189
190 #[cfg(feature = "arbitrary")]
195 #[test]
196 fn arbitrary_is_deterministic() {
197 use arbitrary::{Arbitrary, Unstructured};
198
199 let data = [0xAA; 64];
200 let a =
201 InfiniBandAddr::arbitrary(&mut Unstructured::new(&data)).expect("arbitrary should succeed");
202 let b =
203 InfiniBandAddr::arbitrary(&mut Unstructured::new(&data)).expect("arbitrary should succeed");
204 assert_eq!(a, b, "arbitrary should be deterministic for a fixed input");
205 }
206
207 #[cfg(feature = "arbitrary")]
208 #[test]
209 fn arbitrary_size_hint_matches_byte_array() {
210 use arbitrary::Arbitrary;
211
212 let hint = InfiniBandAddr::size_hint(0);
213 let expected = <[u8; INFINI_BAND_ADDRESS_SIZE] as Arbitrary>::size_hint(0);
214 assert_eq!(hint, expected);
215 }
216
217 #[cfg(feature = "arbitrary")]
218 #[test]
219 fn arbitrary_consumes_expected_bytes() {
220 use arbitrary::{Arbitrary, Unstructured};
221
222 let data = [0xC3u8; 40];
224 let mut u = Unstructured::new(&data);
225 let _first = InfiniBandAddr::arbitrary(&mut u).unwrap();
226 let _second = InfiniBandAddr::arbitrary(&mut u).unwrap();
227 }
228
229 #[cfg(feature = "quickcheck")]
230 #[test]
231 fn quickcheck_arbitrary_roundtrips_through_string() {
232 use quickcheck::{Arbitrary, Gen};
233
234 let mut g = Gen::new(32);
235 for _ in 0..128 {
236 let addr = InfiniBandAddr::arbitrary(&mut g);
237 let parsed = InfiniBandAddr::try_from(addr.to_string().as_str())
238 .expect("to_string() output must parse back");
239 assert_eq!(addr, parsed);
240 }
241 }
242
243 #[cfg(feature = "quickcheck")]
244 #[test]
245 fn quickcheck_shrink_terminates_and_preserves_length() {
246 use quickcheck::Arbitrary;
247
248 let addr = InfiniBandAddr::from_raw([0xFF; INFINI_BAND_ADDRESS_SIZE]);
249 let shrinks: Vec<_> = addr.shrink().take(4096).collect();
252 assert!(!shrinks.is_empty(), "non-zero address should yield shrinks");
253 for s in &shrinks {
254 assert_eq!(s.octets().len(), INFINI_BAND_ADDRESS_SIZE);
255 }
256 }
257
258 #[cfg(feature = "quickcheck")]
259 #[test]
260 fn quickcheck_shrink_zero_is_empty() {
261 use quickcheck::Arbitrary;
262
263 let zero = InfiniBandAddr::from_raw([0; INFINI_BAND_ADDRESS_SIZE]);
264 let shrinks: Vec<_> = zero.shrink().collect();
265 assert!(
266 shrinks.is_empty(),
267 "zero address should yield no shrinks, got {:?}",
268 shrinks
269 );
270 }
271
272 #[cfg(feature = "quickcheck")]
273 #[test]
274 fn quickcheck_roundtrip_property() {
275 fn prop(addr: InfiniBandAddr) -> bool {
276 InfiniBandAddr::try_from(addr.to_string().as_str())
277 .map(|p| p == addr)
278 .unwrap_or(false)
279 }
280 quickcheck::quickcheck(prop as fn(InfiniBandAddr) -> bool);
281 }
282}