File Coverage

blib/lib/Test/MockRandom.pm
Criterion Covered Total %
statement 88 88 100.0
branch 32 32 100.0
condition 11 13 84.6
subroutine 18 18 100.0
pod 7 7 100.0
total 156 158 98.7


line stmt bran cond sub pod time code
1 13     13   631094 use strict;
  13         37  
  13         663  
2 13     13   74 use warnings;
  13         22  
  13         887  
3              
4             package Test::MockRandom;
5             # ABSTRACT: Replaces random number generation with non-random number generation
6             our $VERSION = '1.01'; # VERSION
7              
8 13     13   70 use Carp qw/croak/;
  13         27  
  13         6893  
9              
10             #--------------------------------------------------------------------------#
11             # Class data
12             #--------------------------------------------------------------------------#
13              
14             my @data = (0);
15              
16             #--------------------------------------------------------------------------#
17             # new()
18             #--------------------------------------------------------------------------#
19              
20             sub new {
21 7     7 1 2158 my ( $class, @data ) = @_;
22 7   66     43 my $self = bless( [], ref($class) || $class );
23 7         19 $self->srand(@data);
24 4         13 return $self;
25             }
26              
27             #--------------------------------------------------------------------------#
28             # srand()
29             #--------------------------------------------------------------------------#
30              
31             sub srand { ## no critic
32 38 100   38 1 23229 if ( ref( $_[0] ) eq __PACKAGE__ ) {
33 17         23 my $self = shift;
34 17         35 @$self = $self->_test_srand(@_);
35 11         23 return;
36             }
37             else {
38 21         107 @data = Test::MockRandom->_test_srand(@_);
39 18         49 return;
40             }
41             }
42              
43             sub _test_srand {
44 38     38   88 my ( $self, @data ) = @_;
45 38         63 my $error =
46             "Seeds for " . __PACKAGE__ . " must be between 0 (inclusive) and 1 (exclusive)";
47 38 100       79 croak $error if grep { $_ < 0 or $_ >= 1 } @data;
  47 100       2031  
48 29 100       169 return @data ? @data : (0);
49             }
50              
51             #--------------------------------------------------------------------------#
52             # rand()
53             #--------------------------------------------------------------------------#
54              
55             sub rand(;$) { ## no critic
56 38     38 1 722 my ( $mult, $val );
57 38 100       141 if ( ref( $_[0] ) eq __PACKAGE__ ) { # we're a MockRandom object
58 10         15 $mult = $_[1];
59 10   100     12 $val = shift @{ $_[0] } || 0;
60             }
61             else {
62             # we might be called as a method of some other class
63             # so we need to ignore that and get the right multiplier
64 28 100       119 $mult = $_[ ref( $_[0] ) ? 1 : 0 ];
65 28   100     132 $val = shift @data || 0;
66             }
67             # default to 1 for undef, 0, or strings that aren't numbers
68 13     13   86 eval { no warnings; local $^W = 0; my $bogus = 1 / $mult };
  13         26  
  13         11124  
  38         76  
  38         133  
  38         309  
69 38 100       125 $mult = 1 if $@;
70 38         1386 return $val * $mult;
71             }
72              
73             #--------------------------------------------------------------------------#
74             # oneish()
75             #--------------------------------------------------------------------------#
76              
77             sub oneish {
78 19     19 1 19201 return ( 2**32 - 1 ) / ( 2**32 );
79             }
80              
81             #--------------------------------------------------------------------------#
82             # import()
83             #--------------------------------------------------------------------------#
84              
85             sub import {
86 13     13   133 my ( $class, @import_list ) = @_;
87 13         40 my $caller = caller(0);
88              
89             # Nothing exported by default or if empty string requested
90 13 100       3643 return unless @import_list;
91 10 100 100     3207 return if ( @import_list == 1 && $import_list[0] eq '' );
92              
93 9         21 for my $tgt (@import_list) {
94             # custom handling if it's a hashref
95 10 100       44 if ( ref($tgt) eq "HASH" ) {
96 2         17 for my $sym ( keys %$tgt ) {
97 12         267 croak "Unrecognized symbol '$sym'"
98 4 100       7 unless grep { $sym eq $_ } qw (rand srand oneish);
99 3 100       9 my @custom = ref( $tgt->{$sym} ) eq 'ARRAY' ? @{ $tgt->{$sym} } : $tgt->{$sym};
  1         2  
100 3         10 _custom_export( $sym, $_ ) for (@custom);
101             }
102             }
103             # otherwise, export rand to target and srand/oneish to caller
104             else {
105 8 100       103 my $pkg = ( $tgt =~ /^__PACKAGE__$/ ) ? $caller : $tgt; # DWIM
106 8         28 _export_symbol( "rand", $pkg );
107 8         37 _export_symbol( $_, $caller ) for qw( srand oneish );
108             }
109             }
110 8         10570 return;
111             }
112              
113             #--------------------------------------------------------------------------#
114             # export_oneish_to()
115             #--------------------------------------------------------------------------#
116              
117             sub export_oneish_to {
118 2     2 1 10 my ( $class, @args ) = @_;
119 2         8 _export_fcn_to( $class, "oneish", @args );
120 2         8820 return;
121             }
122              
123             #--------------------------------------------------------------------------#
124             # export_rand_to()
125             #--------------------------------------------------------------------------#
126              
127             sub export_rand_to {
128 5     5 1 3116 my ( $class, @args ) = @_;
129 5         14 _export_fcn_to( $class, "rand", @args );
130 3         3354 return;
131             }
132              
133             #--------------------------------------------------------------------------#
134             # export_srand_to()
135             #--------------------------------------------------------------------------#
136              
137             sub export_srand_to {
138 2     2 1 12 my ( $class, @args ) = @_;
139 2         6 _export_fcn_to( $class, "srand", @args );
140 2         5 return;
141             }
142              
143             #--------------------------------------------------------------------------#
144             # _custom_export
145             #--------------------------------------------------------------------------#
146              
147             sub _custom_export {
148 4     4   6 my ( $sym, $custom ) = @_;
149 4 100       8 if ( ref($custom) eq 'HASH' ) {
150 2         5 _export_symbol( $sym, %$custom ); # flatten { pkg => 'alias' }
151             }
152             else {
153 2         6 _export_symbol( $sym, $custom );
154             }
155 4         12 return;
156             }
157              
158             #--------------------------------------------------------------------------#
159             # _export_fcn_to
160             #--------------------------------------------------------------------------#
161              
162             sub _export_fcn_to {
163 9     9   20 my ( $self, $fcn, $pkg, $alias ) = @_;
164 9 100       266 croak "Must call to export_${fcn}_to() as a class method"
165             unless ( $self eq __PACKAGE__ );
166 8 100       153 croak("export_${fcn}_to() requires a package name") unless $pkg;
167 7         20 _export_symbol( $fcn, $pkg, $alias );
168 7         10 return;
169             }
170              
171             #--------------------------------------------------------------------------#
172             # _export_symbol()
173             #--------------------------------------------------------------------------#
174              
175             sub _export_symbol {
176 35     35   126 my ( $sym, $pkg, $alias ) = @_;
177 35   66     157 $alias ||= $sym;
178             {
179 13     13   92 no strict 'refs'; ## no critic
  13         37  
  13         477  
  35         39  
180 13     13   68 no warnings 'redefine';
  13         26  
  13         2428  
181 35         98 local $^W = 0; # no redefine warnings
182 35         45 *{"${pkg}::${alias}"} = \&{"Test::MockRandom::${sym}"};
  35         223  
  35         118  
183             }
184 35         96 return;
185             }
186              
187             1;
188              
189             __END__