1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
|
package t::Unrandom;
use strict;
use warnings;
use Exporter 'import';
our @EXPORT = qw( unrandomly );
our $randhook;
*CORE::GLOBAL::rand = sub { $randhook ? $randhook->( $_[0] ) : rand $_[0] };
use constant VALUE => 0;
use constant BELOW => 1;
sub unrandomly(&)
{
my $code = shift;
my @rands;
my $randidx;
local $randhook = sub {
my ( $below ) = @_;
if( $randidx > $#rands ) {
push @rands, [ 0, $below ];
$randidx++;
return 0;
}
if( $below != $rands[$randidx][BELOW] ) {
die "ARGH! The function under test is nondeterministic!\n";
}
if( $randidx < $#rands and $rands[$randidx+1][VALUE] == $rands[$randidx+1][BELOW]-1 ) {
die "Fell off the edge" if $rands[$randidx][VALUE] == $rands[$randidx][BELOW]-1;
splice @rands, $randidx+1, @rands-$randidx, ();
$rands[$randidx][VALUE]++;
return $rands[$randidx++][VALUE];
}
elsif( $randidx == $#rands ) {
$rands[$randidx][VALUE]++;
return $rands[$randidx++][VALUE];
}
else {
return $rands[$randidx++][VALUE];
}
};
while(1) {
my $more = 0;
$_->[VALUE] < $_->[BELOW]-1 and $more = 1 for @rands;
last if @rands and !$more;
$randidx = 0;
$code->();
}
}
1;
|