1## no critic (RCS,VERSION,encapsulation,Module) 2 3use strict; 4use warnings; 5use Test::More; 6 7 8use Bytes::Random::Secure; 9 10# We'll use a weaker source because we're testing for function, quality 11# isn't being contested here. Weak=>1 should assure we use /dev/urandom where 12# it's available. Low entropy chosen to preserve our source. 13my $random = Bytes::Random::Secure->new( 14 NonBlocking => 1, 15 Weak => 1, 16 Bits => 64 17); 18 19 20# Tests for _closest_divisor(). 21 22my @divisors = ( 1, 1, 2, 4, 4, 8, 8, 8, 8, 23 16, 16, 16, 16, 16, 16, 16, 16, 24 32, 32, 32, 32, 32, 32, 32, 32, 32 25); 26 27# Nearest factor of 2**32 >= $ix; 28 29for my $ix ( 0 .. $#divisors ) { 30 is( $random->_closest_divisor($ix), $divisors[$ix], 31 "_closest_divisor($ix) == $divisors[$ix]" ); 32} 33 34is( $random->_closest_divisor(), 1, 35 '_closest_divisor() == 1; No param list defaults to zero.' ); 36 37ok( ! eval { $random->_closest_divisor(-1); 1; }, 38 '_closest_divisor(-1) throws on negative input.' ); 39 40ok( ! eval { $random->_closest_divisor(2**33); 1 }, 41 '_closest_divisor(2**33) throws (out of range input).' ); 42 43is( $random->_closest_divisor(2**32), 2**32, 44 "_closest_divisor(2**32) == 2**32." ); 45 46is( $random->_closest_divisor( 2**32 - 1 ), 2**32, 47 '_closest_divisor(2**32-1) == 2**32' ); 48 49# Tests for _ranged_randoms(). 50 51for my $count ( 0 .. 11 ) { 52 is( scalar @{[ $random->_ranged_randoms(16,$count) ]}, $count, 53 "Requested $count ranged randoms, and got $count." ); 54} 55 56is( scalar @{[ $random->_ranged_randoms(16) ]}, 0, 57 'Requested undefined quantity of ranged randoms, and got zero (default).' ); 58 59my( $min, $max ); 60$min = $max = $random->_ranged_randoms(200, 1); 61 62my $MAX_TRIES = 1_000_000; 63my $tries = 0; 64while( ( $min > 0 || $max < 199 ) && $tries++ < $MAX_TRIES ) { 65 my $random = ($random->_ranged_randoms(200,1))[0]; 66 $min = $random < $min ? $random : $min; 67 $max = $random > $max ? $random : $max; 68} 69is( $min, 0, '_ranged_randoms generates range minimum.' ); 70is( $max, 199, '_ranged_randoms generates range maximum.' ); 71note "It took $tries tries to hit both min and max."; 72 73# Testing random_string_from(). 74 75is( $random->string_from( 'abc', 0 ), '', 76 'string_from() with a quantity of zero returns empty string.' ); 77 78is( $random->string_from( 'abc' ), '', 79 'string_from() with an undefined quantity defaults to zero.' ); 80 81is( length( $random->string_from( 'abc', 5 ) ), 5, 82 'string_from(): Requested 5, got 5.' ); 83 84my %bag; 85$tries = 0; 86while( scalar( keys %bag ) < 26 && $tries++ < $MAX_TRIES ) { 87 $bag{ $random->string_from( 'abcdefghijklmnopqrstuvwxyz', 1 ) }++; 88} 89 90is( scalar( keys %bag ), 26, 91 'string_from() returned all bytes from bag, and only bytes from bag.' 92); 93 94ok( ! scalar( grep{ $_ =~ m/[^abcdefghijklmnopqrstuvwxyz]/ } keys %bag ), 95 'string_from(): No out of range characters in output.' ); 96 97ok( $tries >= 26, 98 'string_from():Test validation: took at least 26 tries to hit all 26.' ); 99 100note "It took $tries tries to hit them all at least once."; 101 102ok( ! eval { $random->string_from(); 1; }, 103 'No bag string passed (or bag of zero length) throws an exception.' ); 104 105done_testing(); 106