Skip to content

Commit 32ce620

Browse files
authored
Merge pull request #331 from pitdicker/extra_tests
Extra tests
2 parents 34253b9 + a29b790 commit 32ce620

File tree

8 files changed

+118
-36
lines changed

8 files changed

+118
-36
lines changed

src/distributions/binomial.rs

+24-8
Original file line numberDiff line numberDiff line change
@@ -126,20 +126,36 @@ impl Distribution<u64> for Binomial {
126126

127127
#[cfg(test)]
128128
mod test {
129+
use Rng;
129130
use distributions::Distribution;
130131
use super::Binomial;
131132

133+
fn test_binomial_mean_and_variance<R: Rng>(n: u64, p: f64, rng: &mut R) {
134+
let binomial = Binomial::new(n, p);
135+
136+
let expected_mean = n as f64 * p;
137+
let expected_variance = n as f64 * p * (1.0 - p);
138+
139+
let mut results = [0.0; 1000];
140+
for i in results.iter_mut() { *i = binomial.sample(rng) as f64; }
141+
142+
let mean = results.iter().sum::<f64>() / results.len() as f64;
143+
assert!((mean as f64 - expected_mean).abs() < expected_mean / 50.0);
144+
145+
let variance =
146+
results.iter().map(|x| (x - mean) * (x - mean)).sum::<f64>()
147+
/ results.len() as f64;
148+
assert!((variance - expected_variance).abs() < expected_variance / 10.0);
149+
}
150+
132151
#[test]
133152
fn test_binomial() {
134-
let binomial = Binomial::new(150, 0.1);
135153
let mut rng = ::test::rng(123);
136-
let mut sum = 0;
137-
for _ in 0..1000 {
138-
sum += binomial.sample(&mut rng);
139-
}
140-
let avg = (sum as f64) / 1000.0;
141-
println!("Binomial average: {}", avg);
142-
assert!((avg - 15.0).abs() < 0.5); // not 100% certain, but probable enough
154+
test_binomial_mean_and_variance(150, 0.1, &mut rng);
155+
test_binomial_mean_and_variance(70, 0.6, &mut rng);
156+
test_binomial_mean_and_variance(40, 0.5, &mut rng);
157+
test_binomial_mean_and_variance(20, 0.7, &mut rng);
158+
test_binomial_mean_and_variance(20, 0.5, &mut rng);
143159
}
144160

145161
#[test]

src/distributions/integer.rs

+9-12
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,13 @@
1010

1111
//! The implementations of the `Uniform` distribution for integer types.
1212
13-
use core::mem;
14-
1513
use {Rng};
1614
use distributions::{Distribution, Uniform};
1715

1816
impl Distribution<isize> for Uniform {
1917
#[inline]
2018
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> isize {
21-
if mem::size_of::<isize>() == 4 {
22-
rng.gen::<i32>() as isize
23-
} else {
24-
rng.gen::<i64>() as isize
25-
}
19+
rng.gen::<usize>() as isize
2620
}
2721
}
2822

@@ -64,12 +58,15 @@ impl Distribution<i128> for Uniform {
6458

6559
impl Distribution<usize> for Uniform {
6660
#[inline]
61+
#[cfg(any(target_pointer_width = "32", target_pointer_width = "16"))]
62+
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> usize {
63+
rng.next_u32() as usize
64+
}
65+
66+
#[inline]
67+
#[cfg(target_pointer_width = "64")]
6768
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> usize {
68-
if mem::size_of::<usize>() == 4 {
69-
rng.gen::<u32>() as usize
70-
} else {
71-
rng.gen::<u64>() as usize
72-
}
69+
rng.next_u64() as usize
7370
}
7471
}
7572

src/distributions/other.rs

+28-9
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,12 @@ impl Distribution<char> for Alphanumeric {
6262
b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
6363
abcdefghijklmnopqrstuvwxyz\
6464
0123456789";
65+
// We can pick from 62 characters. This is so close to a power of 2, 64,
66+
// that we can do better than `Range`. Use a simple bitshift and
67+
// rejection sampling. We do not use a bitmask, because for small RNGs
68+
// the most significant bits are usually of higher quality.
6569
loop {
66-
let var = rng.next_u32() >> 26;
70+
let var = rng.next_u32() >> (32 - 6);
6771
if var < RANGE {
6872
return GEN_ASCII_STR_CHARSET[var as usize] as char
6973
}
@@ -161,8 +165,9 @@ impl<T> Distribution<Option<T>> for Uniform where Uniform: Distribution<T> {
161165
#[cfg(test)]
162166
mod tests {
163167
use {Rng, RngCore, Uniform};
168+
use distributions::Alphanumeric;
164169
#[cfg(all(not(feature="std"), feature="alloc"))] use alloc::String;
165-
170+
166171
#[test]
167172
fn test_misc() {
168173
let rng: &mut RngCore = &mut ::test::rng(820);
@@ -175,14 +180,28 @@ mod tests {
175180
#[test]
176181
fn test_chars() {
177182
use core::iter;
178-
use distributions::Alphanumeric;
179183
let mut rng = ::test::rng(805);
180-
181-
let c = rng.sample(Alphanumeric);
182-
assert!((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'));
183-
184+
185+
// Test by generating a relatively large number of chars, so we also
186+
// take the rejection sampling path.
184187
let word: String = iter::repeat(())
185-
.map(|()| rng.sample(Alphanumeric)).take(5).collect();
186-
assert_eq!(word.len(), 5);
188+
.map(|()| rng.gen::<char>()).take(1000).collect();
189+
assert!(word.len() != 0);
190+
}
191+
192+
#[test]
193+
fn test_alphanumeric() {
194+
let mut rng = ::test::rng(806);
195+
196+
// Test by generating a relatively large number of chars, so we also
197+
// take the rejection sampling path.
198+
let mut incorrect = false;
199+
for _ in 0..100 {
200+
let c = rng.sample(Alphanumeric);
201+
incorrect |= !((c >= '0' && c <= '9') ||
202+
(c >= 'A' && c <= 'Z') ||
203+
(c >= 'a' && c <= 'z') );
204+
}
205+
assert!(incorrect == false);
187206
}
188207
}

src/distributions/poisson.rs

+15-1
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ mod test {
117117
use super::Poisson;
118118

119119
#[test]
120-
fn test_poisson() {
120+
fn test_poisson_10() {
121121
let poisson = Poisson::new(10.0);
122122
let mut rng = ::test::rng(123);
123123
let mut sum = 0;
@@ -129,6 +129,20 @@ mod test {
129129
assert!((avg - 10.0).abs() < 0.5); // not 100% certain, but probable enough
130130
}
131131

132+
#[test]
133+
fn test_poisson_15() {
134+
// Take the 'high expected values' path
135+
let poisson = Poisson::new(15.0);
136+
let mut rng = ::test::rng(123);
137+
let mut sum = 0;
138+
for _ in 0..1000 {
139+
sum += poisson.sample(&mut rng);
140+
}
141+
let avg = (sum as f64) / 1000.0;
142+
println!("Poisson average: {}", avg);
143+
assert!((avg - 15.0).abs() < 0.5); // not 100% certain, but probable enough
144+
}
145+
132146
#[test]
133147
#[should_panic]
134148
fn test_poisson_invalid_lambda_zero() {

src/distributions/range.rs

+11
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,17 @@ mod tests {
500500
let v: $ty = rng.sample(my_range);
501501
assert!(low <= v && v < high);
502502
}
503+
504+
let my_range = Range::new_inclusive(low, high);
505+
for _ in 0..1000 {
506+
let v: $ty = rng.sample(my_range);
507+
assert!(low <= v && v <= high);
508+
}
509+
510+
for _ in 0..1000 {
511+
let v: $ty = Range::sample_single(low, high, &mut rng);
512+
assert!(low <= v && v < high);
513+
}
503514
}
504515
)*
505516
}}

src/jitter.rs

+29-2
Original file line numberDiff line numberDiff line change
@@ -785,5 +785,32 @@ impl RngCore for JitterRng {
785785

786786
impl CryptoRng for JitterRng {}
787787

788-
// There are no tests included because (1) this is an "external" RNG, so output
789-
// is not reproducible and (2) `test_timer` *will* fail on some platforms.
788+
#[cfg(test)]
789+
mod test_jitter_init {
790+
use JitterRng;
791+
792+
#[cfg(feature="std")]
793+
#[test]
794+
fn test_jitter_init() {
795+
use RngCore;
796+
// Because this is a debug build, measurements here are not representive
797+
// of the final release build.
798+
// Don't fail this test if initializing `JitterRng` fails because of a
799+
// bad timer (the timer from the standard library may not have enough
800+
// accuracy on all platforms).
801+
match JitterRng::new() {
802+
Ok(ref mut rng) => {
803+
// false positives are possible, but extremely unlikely
804+
assert!(rng.next_u32() | rng.next_u32() != 0);
805+
},
806+
Err(_) => {},
807+
}
808+
}
809+
810+
#[test]
811+
fn test_jitter_bad_timer() {
812+
fn bad_timer() -> u64 { 0 }
813+
let mut rng = JitterRng::new_with_timer(bad_timer);
814+
assert!(rng.test_timer().is_err());
815+
}
816+
}

src/prng/hc128.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ mod test {
434434
// filling the remainder of the buffer.
435435
let mut buffer = [0u8; 16*4*2];
436436
// Consume a value so that we have a remainder.
437-
let _ = rng.next_u64();
437+
assert!(rng.next_u64() == 0x04b4930a518251a4);
438438
rng.fill_bytes(&mut buffer);
439439

440440
// [u8; 128] doesn't implement PartialEq

src/thread_rng.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -171,12 +171,10 @@ pub fn random<T>() -> T where Uniform: Distribution<T> {
171171

172172
#[cfg(test)]
173173
mod test {
174-
use Rng;
175-
176174
#[test]
177-
#[cfg(feature="std")]
178175
#[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))]
179176
fn test_thread_rng() {
177+
use Rng;
180178
let mut r = ::thread_rng();
181179
r.gen::<i32>();
182180
let mut v = [1, 1, 1];

0 commit comments

Comments
 (0)