smb_tests/
binrw.rs

1//! Test utilities for binrw-related code.
2
3pub fn __hex_stream_decode(hex_stream: &str) -> Vec<u8> {
4    let hex_stream = hex_stream.split_whitespace().collect::<String>();
5    ::hex::decode(hex_stream).expect("Invalid hex string")
6}
7
8/// Converts a byte array or hex stream into a `Vec<u8>`.
9/// ```ignore
10/// hex_to_u8_array! {
11///     [0x01, 0x02, 0x03, 0x04]
12/// }
13/// // or
14/// hex_to_u8_array! {
15///   "01020304" // any valid expressions that results in &str
16/// }
17#[macro_export]
18macro_rules! hex_to_u8_array {
19    (
20        [$($bytes:expr),* $(,)?]
21    ) => {
22        {
23            vec![$($bytes),*]
24        }
25    };
26    (
27        $expr_for_string:expr
28    ) => {
29        {
30            let s = $expr_for_string;
31            $crate::binrw::__hex_stream_decode(s)
32        }
33    }
34}
35
36/// BinWrite test macro.
37///
38/// Creates a test
39/// ```ignore
40/// test_binrw_write! {
41///     struct StructName {
42///         field1: value1,
43///         field2: value2,
44///         // ...
45///     }: [byte1, byte2, byte3, ...]
46/// }
47/// ```
48#[macro_export]
49macro_rules! test_binrw_write {
50    // Struct
51    (
52        struct $name:ident $(=> $suffix:ident)? {
53            $(
54                $field:ident : $value:expr,
55            )*
56        } => $byte_arr_or_hex_stream:tt
57    ) => {
58        $crate::test_binrw_write! {
59            $name $(=> $suffix)?: $name {
60                $(
61                    $field: $value,
62                )*
63            } => $byte_arr_or_hex_stream
64        }
65    };
66    // Expression
67    (
68        $type:ty: $value_expr:expr => $byte_arr_or_hex_stream:tt
69    ) => {
70        pastey::paste! {
71            #[test]
72            fn [<test_ $type:snake _write>]() {
73                let expr_eval = $value_expr;
74                $crate::binrw_write_and_assert_eq!(
75                    expr_eval,
76                    $byte_arr_or_hex_stream
77                );
78            }
79        }
80    };
81
82    // Full Expression with test name suffix
83    (
84        $type:ty => $suffix:ident: $value_expr:expr => $byte_arr_or_hex_stream:tt
85    ) => {
86        pastey::paste! {
87            #[test]
88            fn [<test_ $type:snake _write $suffix:lower>]() {
89                let expr_eval = $value_expr;
90                $crate::binrw_write_and_assert_eq!(
91                    expr_eval,
92                    $byte_arr_or_hex_stream
93                );
94            }
95        }
96    }
97}
98
99#[macro_export]
100macro_rules! binrw_write_and_assert_eq {
101    (
102        $value:expr,
103        $byte_arr_or_hex_stream:tt
104    ) => {{
105        use ::binrw::{io::Cursor, prelude::*};
106        let mut writer = Cursor::new(Vec::new());
107        $value.write_le(&mut writer).unwrap();
108        let expected = $crate::hex_to_u8_array! { $byte_arr_or_hex_stream };
109        assert_eq!(writer.into_inner(), expected);
110    }};
111}
112
113/// BinRead test macro.
114/// ```ignore
115/// test_binrw_read! {
116///     StructName {
117///         field1: value1,
118///         field2: value2,
119///         // ...
120///     }: [byte1, byte2, byte3, ...]
121/// }
122/// ```
123#[macro_export]
124macro_rules! test_binrw_read {
125    // Struct
126    (
127        struct $name:ident $(=> $suffix:ident)? {
128            $(
129                $field:ident : $value:expr,
130            )*
131        } => $byte_arr_or_hex_stream:tt
132    ) => {
133        $crate::test_binrw_read! {
134            $name $(=> $suffix)?: $name {
135                $(
136                    $field: $value,
137                )*
138            } => $byte_arr_or_hex_stream
139        }
140    };
141    // Expression
142    (
143        $type:ty: $value_expr:expr => $byte_arr_or_hex_stream:tt
144    ) => {
145        pastey::paste! {
146            #[test]
147            fn [<test_ $type:snake _read>]() {
148                $crate::binrw_read_and_assert_eq!(
149                    $type,
150                    $byte_arr_or_hex_stream,
151                    $value_expr
152                );
153            }
154        }
155    };
156    // Full Expression with test name suffix
157    (
158        $type:ty => $suffix:ident: $value_expr:expr => $byte_arr_or_hex_stream:tt
159    ) => {
160        pastey::paste! {
161            #[test]
162            fn [<test_ $type:snake _read $suffix:lower>]() {
163                $crate::binrw_read_and_assert_eq!(
164                    $type,
165                    $byte_arr_or_hex_stream,
166                    $value_expr
167                );
168            }
169        }
170    }
171}
172
173#[macro_export]
174macro_rules! binrw_read_and_assert_eq {
175    (
176        $type:ty,
177        $byte_arr_or_hex_stream:tt,
178        $expected:expr
179    ) => {{
180        use ::binrw::{io::Cursor, prelude::*};
181        let bytes = $crate::hex_to_u8_array! { $byte_arr_or_hex_stream };
182        let mut reader = Cursor::new(bytes);
183        let value: $type = <$type>::read_le(&mut reader).unwrap();
184        assert_eq!(value, $expected);
185    }};
186}
187
188/// BinRead + BinWrite test macro.
189#[macro_export]
190macro_rules! test_binrw {
191    (
192        $($v:tt)+
193    ) => {
194        $crate::test_binrw_read! {$($v)+}
195        $crate::test_binrw_write! {$($v)+}
196    };
197}
198
199#[macro_export]
200macro_rules! test_binrw_read_fail {
201    (
202        $type:ty:
203        $byte_arr_or_hex_stream:tt
204    ) => {
205        pastey::paste! {
206            #[test]
207            fn [<test_ $type:snake _read_fail>]() {
208                use ::binrw::{io::Cursor, prelude::*};
209                let bytes = $crate::hex_to_u8_array! { $byte_arr_or_hex_stream };
210                let mut reader = Cursor::new(bytes);
211                let result: ::binrw::BinResult<$type> = <$type>::read_le(&mut reader);
212                assert!(result.is_err());
213            }
214        }
215    };
216}
217
218pub use binrw_read_and_assert_eq;
219pub use binrw_write_and_assert_eq;
220pub use test_binrw;
221pub use test_binrw_read;
222pub use test_binrw_read_fail;
223pub use test_binrw_write;