/rust/registry/src/index.crates.io-1949cf8c6b5b557f/aws-lc-rs-1.16.2/src/test.rs
Line | Count | Source |
1 | | // Copyright 2015-2016 Brian Smith. |
2 | | // SPDX-License-Identifier: ISC |
3 | | // Modifications copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. |
4 | | // SPDX-License-Identifier: Apache-2.0 OR ISC |
5 | | |
6 | | //! Testing framework. |
7 | | //! |
8 | | //! Unlike the rest of *aws-lc-rs*, this testing framework uses panics pretty |
9 | | //! liberally. It was originally designed for internal use--it drives most of |
10 | | //! *aws-lc-rs*'s internal tests, and so it is optimized for getting *aws-lc-rs*'s tests |
11 | | //! written quickly at the expense of some usability. The documentation is |
12 | | //! lacking. The best way to learn it is to look at some examples. The digest |
13 | | //! tests are the most complicated because they use named sections. Other tests |
14 | | //! avoid named sections and so are easier to understand. |
15 | | //! |
16 | | //! # Examples |
17 | | //! |
18 | | //! ## Writing Tests |
19 | | //! |
20 | | //! Input files look like this: |
21 | | //! |
22 | | //! ```text |
23 | | //! # This is a comment. |
24 | | //! |
25 | | //! HMAC = SHA1 |
26 | | //! Input = "My test data" |
27 | | //! Key = "" |
28 | | //! Output = 61afdecb95429ef494d61fdee15990cabf0826fc |
29 | | //! |
30 | | //! HMAC = SHA256 |
31 | | //! Input = "Sample message for keylen<blocklen" |
32 | | //! Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F |
33 | | //! Output = A28CF43130EE696A98F14A37678B56BCFCBDD9E5CF69717FECF5480F0EBDF790 |
34 | | //! ``` |
35 | | //! |
36 | | //! Test cases are separated with blank lines. Note how the bytes of the `Key` |
37 | | //! attribute are specified as a quoted string in the first test case and as |
38 | | //! hex in the second test case; you can use whichever form is more convenient |
39 | | //! and you can mix and match within the same file. The empty sequence of bytes |
40 | | //! can only be represented with the quoted string form (`""`). |
41 | | //! |
42 | | //! Here's how you would consume the test data: |
43 | | //! |
44 | | //! ```ignore |
45 | | //! use aws_lc_rs::test; |
46 | | //! |
47 | | //! test::run(test::test_file!("hmac_tests.txt"), |section, test_case| { |
48 | | //! assert_eq!(section, ""); // This test doesn't use named sections. |
49 | | //! |
50 | | //! let digest_alg = test_case.consume_digest_alg("HMAC"); |
51 | | //! let input = test_case.consume_bytes("Input"); |
52 | | //! let key = test_case.consume_bytes("Key"); |
53 | | //! let output = test_case.consume_bytes("Output"); |
54 | | //! |
55 | | //! // Do the actual testing here |
56 | | //! }); |
57 | | //! ``` |
58 | | //! |
59 | | //! Note that `consume_digest_alg` automatically maps the string "SHA1" to a |
60 | | //! reference to `digest::SHA1_FOR_LEGACY_USE_ONLY`, "SHA256" to |
61 | | //! `digest::SHA256`, etc. |
62 | | //! |
63 | | //! ## Output When a Test Fails |
64 | | //! |
65 | | //! When a test case fails, the framework automatically prints out the test |
66 | | //! case. If the test case failed with a panic, then the backtrace of the panic |
67 | | //! will be printed too. For example, let's say the failing test case looks |
68 | | //! like this: |
69 | | //! |
70 | | //! ```text |
71 | | //! Curve = P-256 |
72 | | //! a = 2b11cb945c8cf152ffa4c9c2b1c965b019b35d0b7626919ef0ae6cb9d232f8af |
73 | | //! b = 18905f76a53755c679fb732b7762251075ba95fc5fedb60179e730d418a9143c |
74 | | //! r = 18905f76a53755c679fb732b7762251075ba95fc5fedb60179e730d418a9143c |
75 | | //! ``` |
76 | | //! If the test fails, this will be printed (if `$RUST_BACKTRACE` is `1`): |
77 | | //! |
78 | | //! ```text |
79 | | //! src/example_tests.txt: Test panicked. |
80 | | //! Curve = P-256 |
81 | | //! a = 2b11cb945c8cf152ffa4c9c2b1c965b019b35d0b7626919ef0ae6cb9d232f8af |
82 | | //! b = 18905f76a53755c679fb732b7762251075ba95fc5fedb60179e730d418a9143c |
83 | | //! r = 18905f76a53755c679fb732b7762251075ba95fc5fedb60179e730d418a9143c |
84 | | //! thread 'example_test' panicked at 'Test failed.', src\test.rs:206 |
85 | | //! stack backtrace: |
86 | | //! 0: 0x7ff654a05c7c - std::rt::lang_start::h61f4934e780b4dfc |
87 | | //! 1: 0x7ff654a04f32 - std::rt::lang_start::h61f4934e780b4dfc |
88 | | //! 2: 0x7ff6549f505d - std::panicking::rust_panic_with_hook::hfe203e3083c2b544 |
89 | | //! 3: 0x7ff654a0825b - rust_begin_unwind |
90 | | //! 4: 0x7ff6549f63af - std::panicking::begin_panic_fmt::h484cd47786497f03 |
91 | | //! 5: 0x7ff654a07e9b - rust_begin_unwind |
92 | | //! 6: 0x7ff654a0ae95 - core::panicking::panic_fmt::h257ceb0aa351d801 |
93 | | //! 7: 0x7ff654a0b190 - core::panicking::panic::h4bb1497076d04ab9 |
94 | | //! 8: 0x7ff65496dc41 - from_file<closure> |
95 | | //! at C:\Users\Example\example\<core macros>:4 |
96 | | //! 9: 0x7ff65496d49c - example_test |
97 | | //! at C:\Users\Example\example\src\example.rs:652 |
98 | | //! 10: 0x7ff6549d192a - test::stats::Summary::new::ha139494ed2e4e01f |
99 | | //! 11: 0x7ff6549d51a2 - test::stats::Summary::new::ha139494ed2e4e01f |
100 | | //! 12: 0x7ff654a0a911 - _rust_maybe_catch_panic |
101 | | //! 13: 0x7ff6549d56dd - test::stats::Summary::new::ha139494ed2e4e01f |
102 | | //! 14: 0x7ff654a03783 - std::sys::thread::Thread::new::h2b08da6cd2517f79 |
103 | | //! 15: 0x7ff968518101 - BaseThreadInitThunk |
104 | | //! ``` |
105 | | //! |
106 | | //! Notice that the output shows the name of the data file |
107 | | //! (`src/example_tests.txt`), the test inputs that led to the failure, and the |
108 | | //! stack trace to the line in the test code that panicked: entry 9 in the |
109 | | //! stack trace pointing to line 652 of the file `example.rs`. |
110 | | |
111 | | #![doc(hidden)] |
112 | | |
113 | | extern crate alloc; |
114 | | extern crate std; |
115 | | |
116 | | use std::error::Error; |
117 | | |
118 | | use crate::{digest, error}; |
119 | | |
120 | | pub use crate::hex::{ |
121 | | decode as from_hex, decode_dirty as from_dirty_hex, encode as to_hex, |
122 | | encode_upper as to_hex_upper, |
123 | | }; |
124 | | |
125 | | /// `compile_time_assert_clone::<T>();` fails to compile if `T` doesn't |
126 | | /// implement `Clone`. |
127 | | #[allow(clippy::extra_unused_type_parameters)] |
128 | 0 | pub fn compile_time_assert_clone<T: Clone>() {} |
129 | | |
130 | | /// `compile_time_assert_copy::<T>();` fails to compile if `T` doesn't |
131 | | /// implement `Copy`. |
132 | | #[allow(clippy::extra_unused_type_parameters)] |
133 | 0 | pub fn compile_time_assert_copy<T: Copy>() {} |
134 | | |
135 | | /// `compile_time_assert_eq::<T>();` fails to compile if `T` doesn't |
136 | | /// implement `Eq`. |
137 | | #[allow(clippy::extra_unused_type_parameters)] |
138 | 0 | pub fn compile_time_assert_eq<T: Eq>() {} |
139 | | |
140 | | /// `compile_time_assert_send::<T>();` fails to compile if `T` doesn't |
141 | | /// implement `Send`. |
142 | | #[allow(clippy::extra_unused_type_parameters)] |
143 | 0 | pub fn compile_time_assert_send<T: Send>() {} |
144 | | |
145 | | /// `compile_time_assert_sync::<T>();` fails to compile if `T` doesn't |
146 | | /// implement `Sync`. |
147 | | #[allow(clippy::extra_unused_type_parameters)] |
148 | 0 | pub fn compile_time_assert_sync<T: Sync>() {} |
149 | | |
150 | | /// `compile_time_assert_std_error_error::<T>();` fails to compile if `T` |
151 | | /// doesn't implement `std::error::Error`. |
152 | | #[allow(clippy::extra_unused_type_parameters)] |
153 | 0 | pub fn compile_time_assert_std_error_error<T: Error>() {} |
154 | | |
155 | | /// A test case. A test case consists of a set of named attributes. Every |
156 | | /// attribute in the test case must be consumed exactly once; this helps catch |
157 | | /// typos and omissions. |
158 | | /// |
159 | | /// Requires the `alloc` default feature to be enabled. |
160 | | #[derive(Debug)] |
161 | | #[allow(clippy::module_name_repetitions)] |
162 | | pub struct TestCase { |
163 | | attributes: Vec<(String, String, bool)>, |
164 | | } |
165 | | |
166 | | impl TestCase { |
167 | | /// Maps the strings "SHA1", "SHA256", "SHA384", and "SHA512" to digest |
168 | | /// algorithms, maps "SHA224" to `None`, and panics on other (erroneous) |
169 | | /// inputs. "SHA224" is mapped to None because *ring* intentionally does |
170 | | /// not support SHA224, but we need to consume test vectors from NIST that |
171 | | /// have SHA224 vectors in them. |
172 | 0 | pub fn consume_digest_alg(&mut self, key: &str) -> Option<&'static digest::Algorithm> { |
173 | 0 | let name = self.consume_string(key); |
174 | 0 | match name.as_ref() { |
175 | 0 | "SHA1" => Some(&digest::SHA1_FOR_LEGACY_USE_ONLY), |
176 | 0 | "SHA224" => Some(&digest::SHA224), |
177 | 0 | "SHA256" => Some(&digest::SHA256), |
178 | 0 | "SHA384" => Some(&digest::SHA384), |
179 | 0 | "SHA512" => Some(&digest::SHA512), |
180 | 0 | "SHA512_256" => Some(&digest::SHA512_256), |
181 | 0 | "SHA3_256" => Some(&digest::SHA3_256), |
182 | 0 | "SHA3_384" => Some(&digest::SHA3_384), |
183 | 0 | "SHA3_512" => Some(&digest::SHA3_512), |
184 | 0 | _ => unreachable!("Unsupported digest algorithm: {}", name), |
185 | | } |
186 | 0 | } |
187 | | |
188 | | /// Returns the value of an attribute that is encoded as a sequence of an |
189 | | /// even number of hex digits, or as a double-quoted UTF-8 string. The |
190 | | /// empty (zero-length) value is represented as "". |
191 | 0 | pub fn consume_bytes(&mut self, key: &str) -> Vec<u8> { |
192 | 0 | self.consume_optional_bytes(key) |
193 | 0 | .unwrap_or_else(|| panic!("No attribute named \"{key}\"")) |
194 | 0 | } |
195 | | |
196 | | /// Like `consume_bytes()` except it returns `None` if the test case |
197 | | /// doesn't have the attribute. |
198 | 0 | pub fn consume_optional_bytes(&mut self, key: &str) -> Option<Vec<u8>> { |
199 | 0 | let s = self.consume_optional_string(key)?; |
200 | 0 | let result = if s.starts_with('\"') { |
201 | | // The value is a quoted UTF-8 string. |
202 | 0 | let s = s.as_bytes(); |
203 | 0 | let mut bytes = Vec::with_capacity(s.len()); |
204 | 0 | let mut s = s.iter().skip(1); |
205 | | loop { |
206 | 0 | let b = match s.next() { |
207 | | Some(b'\\') => { |
208 | 0 | match s.next() { |
209 | | // We don't allow all octal escape sequences, only "\0" for null. |
210 | 0 | Some(b'0') => 0u8, |
211 | 0 | Some(b't') => b'\t', |
212 | 0 | Some(b'n') => b'\n', |
213 | | _ => { |
214 | 0 | panic!("Invalid hex escape sequence in string."); |
215 | | } |
216 | | } |
217 | | } |
218 | | Some(b'"') => { |
219 | 0 | assert!( |
220 | 0 | s.next().is_none(), |
221 | | "characters after the closing quote of a quoted string." |
222 | | ); |
223 | 0 | break; |
224 | | } |
225 | 0 | Some(b) => *b, |
226 | 0 | None => panic!("Missing terminating '\"' in string literal."), |
227 | | }; |
228 | 0 | bytes.push(b); |
229 | | } |
230 | 0 | bytes |
231 | | } else { |
232 | | // The value is hex encoded. |
233 | 0 | match from_hex(&s) { |
234 | 0 | Ok(s) => s, |
235 | 0 | Err(err_str) => { |
236 | 0 | panic!("{err_str} in {s}"); |
237 | | } |
238 | | } |
239 | | }; |
240 | 0 | Some(result) |
241 | 0 | } |
242 | | |
243 | | /// Returns the value of an attribute that is an integer, in decimal |
244 | | /// notation. |
245 | 0 | pub fn consume_usize(&mut self, key: &str) -> usize { |
246 | 0 | let s = self.consume_string(key); |
247 | 0 | s.parse::<usize>().unwrap() |
248 | 0 | } |
249 | | |
250 | | /// Returns the value of an attribute that is an integer, in decimal |
251 | | /// notation. |
252 | 0 | pub fn consume_bool(&mut self, key: &str) -> bool { |
253 | 0 | let value_str = self |
254 | 0 | .consume_optional_string(key) |
255 | 0 | .unwrap_or_else(|| panic!("No attribute named \"{key}\"")) |
256 | 0 | .to_ascii_lowercase(); |
257 | 0 | value_str.starts_with('t') || value_str.starts_with('y') |
258 | 0 | } |
259 | | |
260 | | /// Returns the raw value of an attribute, without any unquoting or |
261 | | /// other interpretation. |
262 | 0 | pub fn consume_string(&mut self, key: &str) -> String { |
263 | 0 | self.consume_optional_string(key) |
264 | 0 | .unwrap_or_else(|| panic!("No attribute named \"{key}\"")) |
265 | 0 | } |
266 | | |
267 | | /// Like `consume_string()` except it returns `None` if the test case |
268 | | /// doesn't have the attribute. |
269 | 0 | pub fn consume_optional_string(&mut self, key: &str) -> Option<String> { |
270 | 0 | for (name, value, consumed) in &mut self.attributes { |
271 | 0 | if key == name { |
272 | 0 | assert!(!(*consumed), "Attribute {key} was already consumed"); |
273 | 0 | *consumed = true; |
274 | 0 | return Some(value.clone()); |
275 | 0 | } |
276 | | } |
277 | 0 | None |
278 | 0 | } |
279 | | } |
280 | | |
281 | | /// References a test input file. |
282 | | #[macro_export] |
283 | | #[allow(clippy::module_name_repetitions)] |
284 | | macro_rules! test_file { |
285 | | ($file_name: expr) => { |
286 | | $crate::test::File { |
287 | | file_name: $file_name, |
288 | | contents: include_str!($file_name), |
289 | | } |
290 | | }; |
291 | | } |
292 | | |
293 | | /// A test input file. |
294 | | #[derive(Clone, Copy)] |
295 | | pub struct File<'a> { |
296 | | /// The name (path) of the file. |
297 | | pub file_name: &'a str, |
298 | | |
299 | | /// The contents of the file. |
300 | | pub contents: &'a str, |
301 | | } |
302 | | |
303 | | /// Parses test cases out of the given file, calling `f` on each vector until |
304 | | /// `f` fails or until all the test vectors have been read. `f` can indicate |
305 | | /// failure either by returning `Err()` or by panicking. |
306 | | /// |
307 | | /// # Panics |
308 | | /// Panics on test failure. |
309 | | #[allow(clippy::needless_pass_by_value)] |
310 | 0 | pub fn run<F>(test_file: File, mut f: F) |
311 | 0 | where |
312 | 0 | F: FnMut(&str, &mut TestCase) -> Result<(), error::Unspecified>, |
313 | | { |
314 | 0 | let lines = &mut test_file.contents.lines(); |
315 | | |
316 | 0 | let mut current_section = String::new(); |
317 | 0 | let mut failed = false; |
318 | | |
319 | 0 | while let Some(mut test_case) = parse_test_case(&mut current_section, lines) { |
320 | 0 | let result = match f(¤t_section, &mut test_case) { |
321 | | Ok(()) => { |
322 | 0 | if test_case |
323 | 0 | .attributes |
324 | 0 | .iter() |
325 | 0 | .any(|&(_, _, consumed)| !consumed) |
326 | | { |
327 | 0 | failed = true; |
328 | 0 | Err("Test didn't consume all attributes.") |
329 | | } else { |
330 | 0 | Ok(()) |
331 | | } |
332 | | } |
333 | 0 | Err(error::Unspecified) => Err("Test returned Err(error::Unspecified)."), |
334 | | }; |
335 | | |
336 | 0 | if result.is_err() { |
337 | 0 | failed = true; |
338 | 0 | } |
339 | | |
340 | | #[cfg(feature = "test_logging")] |
341 | | { |
342 | | if let Err(msg) = result { |
343 | | println!("{}: {}", test_file.file_name, msg); |
344 | | |
345 | | for (name, value, consumed) in test_case.attributes { |
346 | | let consumed_str = if consumed { "" } else { " (unconsumed)" }; |
347 | | println!("{}{} = {}", name, consumed_str, value); |
348 | | } |
349 | | }; |
350 | | } |
351 | | } |
352 | | |
353 | 0 | assert!(!failed, "Test failed."); |
354 | 0 | } |
355 | | |
356 | 0 | fn parse_test_case( |
357 | 0 | current_section: &mut String, |
358 | 0 | lines: &mut dyn Iterator<Item = &str>, |
359 | 0 | ) -> Option<TestCase> { |
360 | 0 | let mut attributes = Vec::new(); |
361 | | |
362 | 0 | let mut is_first_line = true; |
363 | | loop { |
364 | 0 | let line = lines.next(); |
365 | | |
366 | | #[cfg(feature = "test_logging")] |
367 | | { |
368 | | if let Some(text) = &line { |
369 | | println!("Line: {}", text); |
370 | | } |
371 | | } |
372 | | |
373 | 0 | match line { |
374 | | // If we get to EOF when we're not in the middle of a test case, |
375 | | // then we're done. |
376 | 0 | None if is_first_line => { |
377 | 0 | return None; |
378 | | } |
379 | | |
380 | | // End of the file on a non-empty test cases ends the test case. |
381 | | None => { |
382 | 0 | return Some(TestCase { attributes }); |
383 | | } |
384 | | |
385 | | // A blank line ends a test case if the test case isn't empty. |
386 | 0 | Some("") => { |
387 | 0 | if !is_first_line { |
388 | 0 | return Some(TestCase { attributes }); |
389 | 0 | } |
390 | | // Ignore leading blank lines. |
391 | | } |
392 | | |
393 | | // Comments start with '#'; ignore them. |
394 | 0 | Some(line) if line.starts_with('#') => (), |
395 | | |
396 | 0 | Some(line) if line.starts_with('[') => { |
397 | 0 | assert!(is_first_line); |
398 | 0 | assert!(line.ends_with(']')); |
399 | 0 | current_section.truncate(0); |
400 | 0 | current_section.push_str(line); |
401 | 0 | let _: Option<char> = current_section.pop(); |
402 | 0 | let _: char = current_section.remove(0); |
403 | | } |
404 | | |
405 | 0 | Some(line) => { |
406 | 0 | is_first_line = false; |
407 | | |
408 | 0 | let parts: Vec<&str> = line.splitn(2, " = ").collect(); |
409 | 0 | assert_eq!(parts.len(), 2, "Syntax error: Expected Key = Value."); |
410 | | |
411 | 0 | let key = parts[0].trim(); |
412 | 0 | let value = parts[1].trim(); |
413 | | |
414 | | // Don't allow the value to be ommitted. An empty value can be |
415 | | // represented as an empty quoted string. |
416 | 0 | assert_ne!(value.len(), 0); |
417 | | |
418 | | // Checking is_none() ensures we don't accept duplicate keys. |
419 | 0 | attributes.push((String::from(key), String::from(value), false)); |
420 | | } |
421 | | } |
422 | | } |
423 | 0 | } |
424 | | |
425 | | /// Deterministic implementations of `ring::rand::SecureRandom`. |
426 | | /// |
427 | | /// These are only used for testing KATs where a random number should be generated. |
428 | | pub mod rand { |
429 | | use crate::error; |
430 | | |
431 | | /// An implementation of `SecureRandom` that always fills the output slice |
432 | | /// with the given byte. |
433 | | #[derive(Debug)] |
434 | | pub struct FixedByteRandom { |
435 | | pub byte: u8, |
436 | | } |
437 | | |
438 | | impl crate::rand::sealed::SecureRandom for FixedByteRandom { |
439 | 0 | fn fill_impl(&self, dest: &mut [u8]) -> Result<(), error::Unspecified> { |
440 | 0 | dest.fill(self.byte); |
441 | 0 | Ok(()) |
442 | 0 | } |
443 | | } |
444 | | |
445 | | /// An implementation of `SecureRandom` that always fills the output slice |
446 | | /// with the slice in `bytes`. The length of the slice given to `slice` |
447 | | /// must match exactly. |
448 | | #[derive(Debug)] |
449 | | pub struct FixedSliceRandom<'a> { |
450 | | pub bytes: &'a [u8], |
451 | | } |
452 | | |
453 | | impl crate::rand::sealed::SecureRandom for FixedSliceRandom<'_> { |
454 | | #[inline] |
455 | 0 | fn fill_impl(&self, dest: &mut [u8]) -> Result<(), error::Unspecified> { |
456 | 0 | dest.copy_from_slice(self.bytes); |
457 | 0 | Ok(()) |
458 | 0 | } |
459 | | } |
460 | | |
461 | | /// An implementation of `SecureRandom` where each slice in `bytes` is a |
462 | | /// test vector for one call to `fill()`. *Not thread-safe.* |
463 | | /// |
464 | | /// The first slice in `bytes` is the output for the first call to |
465 | | /// `fill()`, the second slice is the output for the second call to |
466 | | /// `fill()`, etc. The output slice passed to `fill()` must have exactly |
467 | | /// the length of the corresponding entry in `bytes`. `current` must be |
468 | | /// initialized to zero. `fill()` must be called exactly once for each |
469 | | /// entry in `bytes`. |
470 | | #[derive(Debug)] |
471 | | pub struct FixedSliceSequenceRandom<'a> { |
472 | | /// The value. |
473 | | pub bytes: &'a [&'a [u8]], |
474 | | pub current: core::cell::UnsafeCell<usize>, |
475 | | } |
476 | | |
477 | | impl crate::rand::sealed::SecureRandom for FixedSliceSequenceRandom<'_> { |
478 | 0 | fn fill_impl(&self, dest: &mut [u8]) -> Result<(), error::Unspecified> { |
479 | 0 | let current = unsafe { *self.current.get() }; |
480 | 0 | let bytes = self.bytes[current]; |
481 | 0 | dest.copy_from_slice(bytes); |
482 | | // Remember that we returned this slice and prepare to return |
483 | | // the next one, if any. |
484 | 0 | unsafe { *self.current.get() += 1 }; |
485 | 0 | Ok(()) |
486 | 0 | } |
487 | | } |
488 | | |
489 | | impl Drop for FixedSliceSequenceRandom<'_> { |
490 | 0 | fn drop(&mut self) { |
491 | | // Ensure that `fill()` was called exactly the right number of |
492 | | // times. |
493 | 0 | assert_eq!(unsafe { *self.current.get() }, self.bytes.len()); |
494 | 0 | } |
495 | | } |
496 | | } |
497 | | |
498 | | #[cfg(test)] |
499 | | mod tests { |
500 | | use crate::rand::sealed::SecureRandom; |
501 | | use crate::test::rand::{FixedByteRandom, FixedSliceRandom, FixedSliceSequenceRandom}; |
502 | | use crate::test::{from_dirty_hex, to_hex_upper}; |
503 | | use crate::{error, test}; |
504 | | use core::cell::UnsafeCell; |
505 | | |
506 | | #[test] |
507 | | fn fixed_byte_random() { |
508 | | let fbr = FixedByteRandom { byte: 42 }; |
509 | | let mut bs = [0u8; 42]; |
510 | | fbr.fill_impl(&mut bs).expect("filled"); |
511 | | assert_eq!([42u8; 42], bs); |
512 | | } |
513 | | |
514 | | #[test] |
515 | | fn fixed_slice_random() { |
516 | | let fbr = FixedSliceRandom { bytes: &[42u8; 42] }; |
517 | | let mut bs = [0u8; 42]; |
518 | | fbr.fill_impl(&mut bs).expect("fill"); |
519 | | } |
520 | | |
521 | | #[test] |
522 | | #[should_panic( |
523 | | expected = "source slice length (42) does not match destination slice length (0)" |
524 | | )] |
525 | | fn fixed_slice_random_length_mismatch() { |
526 | | let fbr = FixedSliceRandom { bytes: &[42u8; 42] }; |
527 | | let _: Result<(), error::Unspecified> = fbr.fill_impl(&mut []); |
528 | | } |
529 | | |
530 | | #[test] |
531 | | fn fixed_slice_sequence_random() { |
532 | | let fbr = FixedSliceSequenceRandom { |
533 | | bytes: &[&[7u8; 7], &[42u8; 42]], |
534 | | current: UnsafeCell::new(0), |
535 | | }; |
536 | | let mut bs_one = [0u8; 7]; |
537 | | fbr.fill_impl(&mut bs_one).expect("fill"); |
538 | | assert_eq!([7u8; 7], bs_one); |
539 | | let mut bs_two = [42u8; 42]; |
540 | | fbr.fill_impl(&mut bs_two).expect("filled"); |
541 | | assert_eq!([42u8; 42], bs_two); |
542 | | } |
543 | | |
544 | | #[test] |
545 | | #[should_panic(expected = "index out of bounds: the len is 0 but the index is 0")] |
546 | | fn fixed_slice_sequence_random_no_remaining() { |
547 | | let fbr = FixedSliceSequenceRandom { |
548 | | bytes: &[], |
549 | | current: UnsafeCell::new(0), |
550 | | }; |
551 | | let mut bs_one = [0u8; 7]; |
552 | | let _: Result<(), error::Unspecified> = fbr.fill_impl(&mut bs_one); |
553 | | } |
554 | | |
555 | | // TODO: This test is causing a thread panic which prevents capture with should_panic |
556 | | // #[test] |
557 | | // #[should_panic] |
558 | | // fn fixed_slice_sequence_random_length_mismatch() { |
559 | | // let fbr = FixedSliceSequenceRandom { |
560 | | // bytes: &[&[42u8; 42]], |
561 | | // current: UnsafeCell::new(0), |
562 | | // }; |
563 | | // let _: Result<(), error::Unspecified> = fbr.fill_impl(&mut []); |
564 | | // } |
565 | | |
566 | | #[test] |
567 | | fn one_ok() { |
568 | | test::run(test_file!("test/test_1_tests.txt"), |_, test_case| { |
569 | | test_case.consume_string("Key"); |
570 | | Ok(()) |
571 | | }); |
572 | | } |
573 | | |
574 | | #[test] |
575 | | #[should_panic(expected = "Test failed.")] |
576 | | fn one_err() { |
577 | | test::run(test_file!("test/test_1_tests.txt"), |_, test_case| { |
578 | | test_case.consume_string("Key"); |
579 | | Err(error::Unspecified) |
580 | | }); |
581 | | } |
582 | | |
583 | | #[test] |
584 | | #[should_panic(expected = "Oh noes!")] |
585 | | fn one_panics() { |
586 | | test::run(test_file!("test/test_1_tests.txt"), |_, test_case| { |
587 | | test_case.consume_string("Key"); |
588 | | panic!("Oh noes!"); |
589 | | }); |
590 | | } |
591 | | |
592 | | #[test] |
593 | | #[should_panic(expected = "Test failed.")] |
594 | | fn first_err() { |
595 | | err_one(0); |
596 | | } |
597 | | |
598 | | #[test] |
599 | | #[should_panic(expected = "Test failed.")] |
600 | | fn middle_err() { |
601 | | err_one(1); |
602 | | } |
603 | | |
604 | | #[test] |
605 | | #[should_panic(expected = "Test failed.")] |
606 | | fn last_err() { |
607 | | err_one(2); |
608 | | } |
609 | | |
610 | | fn err_one(test_to_fail: usize) { |
611 | | let mut n = 0; |
612 | | test::run(test_file!("test/test_3_tests.txt"), |_, test_case| { |
613 | | test_case.consume_string("Key"); |
614 | | let result = if n == test_to_fail { |
615 | | Err(error::Unspecified) |
616 | | } else { |
617 | | Ok(()) |
618 | | }; |
619 | | n += 1; |
620 | | result |
621 | | }); |
622 | | } |
623 | | |
624 | | #[test] |
625 | | #[should_panic(expected = "Oh Noes!")] |
626 | | fn first_panic() { |
627 | | panic_one(0); |
628 | | } |
629 | | |
630 | | #[test] |
631 | | #[should_panic(expected = "Oh Noes!")] |
632 | | fn middle_panic() { |
633 | | panic_one(1); |
634 | | } |
635 | | |
636 | | #[test] |
637 | | #[should_panic(expected = "Oh Noes!")] |
638 | | fn last_panic() { |
639 | | panic_one(2); |
640 | | } |
641 | | |
642 | | fn panic_one(test_to_fail: usize) { |
643 | | let mut n = 0; |
644 | | test::run(test_file!("test/test_3_tests.txt"), |_, test_case| { |
645 | | test_case.consume_string("Key"); |
646 | | assert_ne!(n, test_to_fail, "Oh Noes!"); |
647 | | n += 1; |
648 | | Ok(()) |
649 | | }); |
650 | | } |
651 | | |
652 | | #[test] |
653 | | #[should_panic(expected = "Syntax error: Expected Key = Value.")] |
654 | | fn syntax_error() { |
655 | | test::run(test_file!("test/test_1_syntax_error_tests.txt"), |_, _| { |
656 | | Ok(()) |
657 | | }); |
658 | | } |
659 | | |
660 | | #[test] |
661 | | fn test_to_hex_upper() { |
662 | | let hex = "abcdef0123"; |
663 | | let bytes = from_dirty_hex(hex); |
664 | | assert_eq!(hex.to_ascii_uppercase(), to_hex_upper(bytes)); |
665 | | } |
666 | | } |