From d543f9cce8c43b4100a7998084aa6c2071e779a9 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Thu, 20 Jun 2024 04:40:22 -0700 Subject: [PATCH] Define common tests via define_tests! macro Signed-off-by: Joe Richey --- .github/workflows/tests.yml | 8 +-- src/lib.rs | 3 + src/tests.rs | 123 ++++++++++++++++++++++++------------ 3 files changed, 88 insertions(+), 46 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 26f0760c..77fb6fc5 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -38,8 +38,8 @@ jobs: toolchain: ${{ matrix.toolchain }} - uses: Swatinem/rust-cache@v2 - run: cargo test - # Make sure enabling the std and custom features don't break anything - - run: cargo test --features=std,custom + # Ensure enabling features works, and run feature-specific tests. + - run: cargo test --features=std,custom,rdrand - run: cargo test --features=linux_disable_fallback - if: ${{ matrix.toolchain == 'nightly' }} run: cargo test --benches @@ -258,8 +258,8 @@ jobs: - name: Test (Safari) if: runner.os == 'macOS' run: wasm-pack test --headless --safari --features=js,test-in-browser - - name: Test (custom getrandom) - run: wasm-pack test --node --features=custom + - name: Test (custom getrandom, no unit tests) + run: wasm-pack test --node --features=custom --test=custom - name: Test (JS overrides custom) run: wasm-pack test --node --features=custom,js diff --git a/src/lib.rs b/src/lib.rs index f5e13c36..ddd2d913 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -404,3 +404,6 @@ pub fn getrandom_uninit(dest: &mut [MaybeUninit]) -> Result<&mut [u8], Error // since it returned `Ok`. Ok(unsafe { slice_assume_init_mut(dest) }) } + +#[cfg(test)] +mod tests; diff --git a/src/tests.rs b/src/tests.rs index 666f7f57..3f848da1 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,19 +1,12 @@ -use super::getrandom_impl; +use crate::Error; -#[cfg(all(target_arch = "wasm32", target_os = "unknown"))] -use wasm_bindgen_test::wasm_bindgen_test as test; +extern crate std; +use std::{mem::MaybeUninit, sync::mpsc::channel, thread, vec, vec::Vec}; #[cfg(feature = "test-in-browser")] wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); -#[test] -fn test_zero() { - // Test that APIs are happy with zero-length requests - getrandom_impl(&mut [0u8; 0]).unwrap(); -} - // Return the number of bits in which s1 and s2 differ -#[cfg(not(feature = "custom"))] fn num_diff_bits(s1: &[u8], s2: &[u8]) -> usize { assert_eq!(s1.len(), s2.len()); s1.iter() @@ -23,14 +16,9 @@ fn num_diff_bits(s1: &[u8], s2: &[u8]) -> usize { } // Tests the quality of calling getrandom on two large buffers -#[test] -#[cfg(not(feature = "custom"))] -fn test_diff() { - let mut v1 = [0u8; 1000]; - getrandom_impl(&mut v1).unwrap(); - - let mut v2 = [0u8; 1000]; - getrandom_impl(&mut v2).unwrap(); +pub(crate) fn check_diff_large(make_vec: fn(usize) -> Vec) { + let v1 = make_vec(1000); + let v2 = make_vec(1000); // Between 3.5 and 4.5 bits per byte should differ. Probability of failure: // ~ 2^(-94) = 2 * CDF[BinomialDistribution[8000, 0.5], 3500] @@ -40,9 +28,7 @@ fn test_diff() { } // Tests the quality of calling getrandom repeatedly on small buffers -#[test] -#[cfg(not(feature = "custom"))] -fn test_small() { +pub(crate) fn check_small(make_vec: fn(usize) -> Vec) { // For each buffer size, get at least 256 bytes and check that between // 3 and 5 bits per byte differ. Probability of failure: // ~ 2^(-91) = 64 * 2 * CDF[BinomialDistribution[8*256, 0.5], 3*256] @@ -50,11 +36,8 @@ fn test_small() { let mut num_bytes = 0; let mut diff_bits = 0; while num_bytes < 256 { - let mut s1 = vec![0u8; size]; - getrandom_impl(&mut s1).unwrap(); - let mut s2 = vec![0u8; size]; - getrandom_impl(&mut s2).unwrap(); - + let s1 = make_vec(size); + let s2 = make_vec(size); num_bytes += size; diff_bits += num_diff_bits(&s1, &s2); } @@ -63,19 +46,7 @@ fn test_small() { } } -#[test] -fn test_huge() { - let mut huge = [0u8; 100_000]; - getrandom_impl(&mut huge).unwrap(); -} - -// On WASM, the thread API always fails/panics -#[cfg(not(target_arch = "wasm32"))] -#[test] -fn test_multithreading() { - extern crate std; - use std::{sync::mpsc::channel, thread, vec}; - +pub(crate) fn check_multithreading(make_vec: fn(usize) -> Vec) { let mut txs = vec![]; for _ in 0..20 { let (tx, rx) = channel(); @@ -84,10 +55,8 @@ fn test_multithreading() { thread::spawn(move || { // wait until all the tasks are ready to go. rx.recv().unwrap(); - let mut v = [0u8; 1000]; - for _ in 0..100 { - getrandom_impl(&mut v).unwrap(); + make_vec(1000); thread::yield_now(); } }); @@ -98,3 +67,73 @@ fn test_multithreading() { tx.send(()).unwrap(); } } + +// Helper trait for testing different kinds of functions. +// DUMMY generic parameter is needed to avoid conflicting implementations. +pub(crate) trait FillFn { + fn make_vec(self, len: usize) -> Vec; +} +impl Result<(), Error>> FillFn<0> for F { + fn make_vec(self, len: usize) -> Vec { + let mut v = vec![0; len]; + self(&mut v).unwrap(); + v + } +} +impl]) -> Result<(), Error>> FillFn<1> for F { + fn make_vec(self, len: usize) -> Vec { + let mut v = Vec::with_capacity(len); + self(v.spare_capacity_mut()).unwrap(); + unsafe { v.set_len(len) }; + v + } +} +impl]) -> Result<&mut [u8], Error>> FillFn<2> for F { + fn make_vec(self, len: usize) -> Vec { + let mut v = Vec::with_capacity(len); + let ret = self(v.spare_capacity_mut()).unwrap(); + assert_eq!(ret.len(), len); + assert_eq!(ret.as_ptr(), v.as_ptr()); + unsafe { v.set_len(len) }; + v + } +} + +macro_rules! define_tests { + ($fill:path) => { + use crate::tests::FillFn; + #[cfg(all(target_family = "wasm", target_os = "unknown"))] + use wasm_bindgen_test::wasm_bindgen_test as test; + + #[test] + fn zero() { + $fill.make_vec(0); + } + #[test] + fn diff_large() { + crate::tests::check_diff_large(|len| $fill.make_vec(len)); + } + #[test] + fn small() { + crate::tests::check_small(|len| $fill.make_vec(len)); + } + #[test] + fn huge() { + $fill.make_vec(100_000); + } + // On WASM, the thread API always fails/panics. + #[test] + #[cfg_attr(target_family = "wasm", ignore)] + fn multithreading() { + crate::tests::check_multithreading(|len| $fill.make_vec(len)); + } + }; +} +pub(crate) use define_tests; + +mod init { + super::define_tests!(crate::getrandom); +} +mod uninit { + super::define_tests!(crate::getrandom_uninit); +}