1 //! Integration tests for `zeroize_derive` proc macros
2
3 #![cfg(feature = "zeroize_derive")]
4
5 use zeroize::{Zeroize, ZeroizeOnDrop};
6
7 #[test]
derive_tuple_struct_test()8 fn derive_tuple_struct_test() {
9 #[derive(Zeroize, ZeroizeOnDrop)]
10 struct Z([u8; 3]);
11
12 let mut value = Z([1, 2, 3]);
13 value.zeroize();
14 assert_eq!(&value.0, &[0, 0, 0])
15 }
16
17 #[test]
18 #[cfg(feature = "alloc")]
derive_struct_test()19 fn derive_struct_test() {
20 #[derive(Zeroize, ZeroizeOnDrop)]
21 struct Z {
22 string: String,
23 vec: Vec<u8>,
24 bytearray: [u8; 3],
25 number: usize,
26 boolean: bool,
27 }
28
29 let mut value = Z {
30 string: String::from("Hello, world!"),
31 vec: vec![1, 2, 3],
32 bytearray: [4, 5, 6],
33 number: 42,
34 boolean: true,
35 };
36
37 value.zeroize();
38
39 assert!(value.string.is_empty());
40 assert!(value.vec.is_empty());
41 assert_eq!(&value.bytearray, &[0, 0, 0]);
42 assert_eq!(value.number, 0);
43 assert!(!value.boolean);
44 }
45
46 #[test]
derive_enum_test()47 fn derive_enum_test() {
48 #[derive(Zeroize, ZeroizeOnDrop)]
49 enum Z {
50 #[allow(dead_code)]
51 Variant1,
52 Variant2(usize),
53 }
54
55 let mut value = Z::Variant2(26);
56
57 value.zeroize();
58
59 assert!(matches!(value, Z::Variant2(0)));
60 }
61
62 /// Test that the custom macro actually derived `Drop` for `Z`
63 #[test]
derive_struct_drop()64 fn derive_struct_drop() {
65 #[derive(Zeroize, ZeroizeOnDrop)]
66 struct Z([u8; 3]);
67
68 assert!(std::mem::needs_drop::<Z>());
69 }
70
71 /// Test that the custom macro actually derived `Drop` for `Z`
72 #[test]
derive_enum_drop()73 fn derive_enum_drop() {
74 #[allow(dead_code)]
75 #[derive(Zeroize, ZeroizeOnDrop)]
76 enum Z {
77 Variant1,
78 Variant2(usize),
79 }
80
81 assert!(std::mem::needs_drop::<Z>());
82 }
83
84 /// Test that the custom macro actually derived `Drop` for `Z`
85 #[test]
derive_struct_only_drop()86 fn derive_struct_only_drop() {
87 #[derive(ZeroizeOnDrop)]
88 struct Z([u8; 3]);
89
90 assert!(std::mem::needs_drop::<Z>());
91 }
92
93 /// Test that the custom macro actually derived `Drop` for `Z`
94 #[test]
derive_enum_only_drop()95 fn derive_enum_only_drop() {
96 #[allow(dead_code)]
97 #[derive(ZeroizeOnDrop)]
98 enum Z {
99 Variant1,
100 Variant2(usize),
101 }
102
103 assert!(std::mem::needs_drop::<Z>());
104 }
105
106 /// Test that `Drop` is not derived in the following case by defining a
107 /// `Drop` impl which should conflict if the custom derive defined one too
108 #[allow(dead_code)]
109 #[derive(Zeroize)]
110 struct ZeroizeNoDropStruct([u8; 3]);
111
112 impl Drop for ZeroizeNoDropStruct {
drop(&mut self)113 fn drop(&mut self) {}
114 }
115
116 #[allow(dead_code)]
117 #[derive(Zeroize)]
118 enum ZeroizeNoDropEnum {
119 Variant([u8; 3]),
120 }
121
122 impl Drop for ZeroizeNoDropEnum {
drop(&mut self)123 fn drop(&mut self) {}
124 }
125
126 #[test]
127 #[cfg(feature = "alloc")]
derive_struct_skip()128 fn derive_struct_skip() {
129 #[derive(Zeroize, ZeroizeOnDrop)]
130 struct Z {
131 string: String,
132 vec: Vec<u8>,
133 #[zeroize(skip)]
134 bytearray: [u8; 3],
135 number: usize,
136 boolean: bool,
137 }
138
139 let mut value = Z {
140 string: String::from("Hello, world!"),
141 vec: vec![1, 2, 3],
142 bytearray: [4, 5, 6],
143 number: 42,
144 boolean: true,
145 };
146
147 value.zeroize();
148
149 assert!(value.string.is_empty());
150 assert!(value.vec.is_empty());
151 assert_eq!(&value.bytearray, &[4, 5, 6]);
152 assert_eq!(value.number, 0);
153 assert!(!value.boolean);
154 }
155
156 #[test]
157 #[cfg(feature = "alloc")]
derive_enum_skip()158 fn derive_enum_skip() {
159 #[derive(Zeroize, ZeroizeOnDrop)]
160 enum Z {
161 #[allow(dead_code)]
162 Variant1,
163 #[zeroize(skip)]
164 Variant2([u8; 3]),
165 #[zeroize(skip)]
166 Variant3 {
167 string: String,
168 vec: Vec<u8>,
169 bytearray: [u8; 3],
170 number: usize,
171 boolean: bool,
172 },
173 Variant4 {
174 string: String,
175 vec: Vec<u8>,
176 #[zeroize(skip)]
177 bytearray: [u8; 3],
178 number: usize,
179 boolean: bool,
180 },
181 }
182
183 let mut value = Z::Variant2([4, 5, 6]);
184
185 value.zeroize();
186
187 assert!(matches!(&value, Z::Variant2([4, 5, 6])));
188
189 let mut value = Z::Variant3 {
190 string: String::from("Hello, world!"),
191 vec: vec![1, 2, 3],
192 bytearray: [4, 5, 6],
193 number: 42,
194 boolean: true,
195 };
196
197 value.zeroize();
198
199 assert!(matches!(
200 &value,
201 Z::Variant3 { string, vec, bytearray, number, boolean }
202 if string == "Hello, world!" &&
203 vec == &[1, 2, 3] &&
204 bytearray == &[4, 5, 6] &&
205 *number == 42 &&
206 *boolean
207 ));
208
209 let mut value = Z::Variant4 {
210 string: String::from("Hello, world!"),
211 vec: vec![1, 2, 3],
212 bytearray: [4, 5, 6],
213 number: 42,
214 boolean: true,
215 };
216
217 value.zeroize();
218
219 assert!(matches!(
220 &value,
221 Z::Variant4 { string, vec, bytearray, number, boolean }
222 if string.is_empty() &&
223 vec.is_empty() &&
224 bytearray == &[4, 5, 6] &&
225 *number == 0 &&
226 !boolean
227 ));
228 }
229
230 #[test]
derive_bound()231 fn derive_bound() {
232 trait T: Zeroize {}
233
234 impl T for u8 {}
235
236 #[derive(Zeroize)]
237 #[zeroize(bound = "X: T")]
238 struct Z<X>(X);
239
240 let mut value = Z(5_u8);
241
242 value.zeroize();
243
244 assert_eq!(value.0, 0);
245 }
246
247 #[test]
derive_inherit_zeroize_on_drop()248 fn derive_inherit_zeroize_on_drop() {
249 #[derive(ZeroizeOnDrop)]
250 struct X([u8; 3]);
251
252 #[derive(ZeroizeOnDrop)]
253 struct Z(X);
254
255 let mut value = Z(X([1, 2, 3]));
256 unsafe {
257 std::ptr::drop_in_place(&mut value);
258 }
259 assert_eq!(&value.0 .0, &[0, 0, 0])
260 }
261
262 #[test]
derive_inherit_from_both()263 fn derive_inherit_from_both() {
264 #[derive(Zeroize, ZeroizeOnDrop)]
265 struct X([u8; 3]);
266
267 #[derive(ZeroizeOnDrop)]
268 struct Z(X);
269
270 let mut value = Z(X([1, 2, 3]));
271 unsafe {
272 std::ptr::drop_in_place(&mut value);
273 }
274 assert_eq!(&value.0 .0, &[0, 0, 0])
275 }
276
277 #[test]
derive_inherit_both()278 fn derive_inherit_both() {
279 #[derive(Zeroize, ZeroizeOnDrop)]
280 struct X([u8; 3]);
281
282 #[derive(Zeroize, ZeroizeOnDrop)]
283 struct Z(X);
284
285 let mut value = Z(X([1, 2, 3]));
286 unsafe {
287 std::ptr::drop_in_place(&mut value);
288 }
289 assert_eq!(&value.0 .0, &[0, 0, 0])
290 }
291
292 #[test]
derive_deref()293 fn derive_deref() {
294 struct X([u8; 3]);
295
296 impl std::ops::Deref for X {
297 type Target = [u8];
298
299 fn deref(&self) -> &Self::Target {
300 &self.0
301 }
302 }
303
304 impl std::ops::DerefMut for X {
305 fn deref_mut(&mut self) -> &mut Self::Target {
306 &mut self.0
307 }
308 }
309
310 #[derive(Zeroize, ZeroizeOnDrop)]
311 struct Z(X);
312
313 let mut value = Z(X([1, 2, 3]));
314 unsafe {
315 std::ptr::drop_in_place(&mut value);
316 }
317 assert_eq!(&value.0 .0, &[0, 0, 0])
318 }
319
320 #[test]
321 #[cfg(feature = "alloc")]
322 #[allow(dead_code)]
derive_zeroize_on_drop_generic()323 fn derive_zeroize_on_drop_generic() {
324 #[derive(ZeroizeOnDrop)]
325 struct Y<T: Zeroize>(Box<T>);
326
327 #[derive(ZeroizeOnDrop)]
328 struct Z<T: Zeroize>(Vec<T>);
329 }
330
331 #[test]
332 #[allow(dead_code)]
derive_zeroize_unused_param()333 fn derive_zeroize_unused_param() {
334 #[derive(Zeroize)]
335 struct Z<T> {
336 arr: [u32; 5],
337 #[zeroize(skip)]
338 skipped: T,
339 }
340 }
341
342 #[test]
343 #[allow(dead_code)]
344 // Issue #878
derive_zeroize_with_marker()345 fn derive_zeroize_with_marker() {
346 #[derive(ZeroizeOnDrop, Zeroize)]
347 struct Test<A: Marker> {
348 #[zeroize(skip)]
349 field: Option<A>,
350 }
351
352 #[allow(dead_code)]
353 trait Secret: ZeroizeOnDrop + Zeroize {}
354
355 impl<A: Marker> Secret for Test<A> {}
356
357 trait Marker {}
358 }
359
360 #[test]
361 #[allow(dead_code)]
362 // Issue #878
derive_zeroize_used_param()363 fn derive_zeroize_used_param() {
364 #[derive(Zeroize)]
365 struct Z<T> {
366 used: T,
367 }
368 }
369