File Coverage

blib/lib/Test/Timer.pm
Criterion Covered Total %
statement 100 100 100.0
branch 19 20 95.0
condition 4 6 66.6
subroutine 21 21 100.0
pod 5 5 100.0
total 149 152 98.0


line stmt bran cond sub pod time code
1             package Test::Timer;
2              
3 3     3   207137 use warnings;
  3         26  
  3         100  
4 3     3   23 use strict;
  3         5  
  3         73  
5              
6 3     3   15 use vars qw($VERSION @ISA @EXPORT);
  3         7  
  3         179  
7 3     3   1709 use Benchmark; # timestr
  3         19850  
  3         15  
8 3     3   322 use Carp qw(croak);
  3         6  
  3         164  
9 3     3   1654 use Error qw(:try);
  3         15472  
  3         12  
10 3     3   460 use Test::Builder;
  3         8  
  3         71  
11 3     3   15 use base 'Test::Builder::Module';
  3         6  
  3         392  
12              
13 3     3   25 use constant TRUE => 1;
  3         6  
  3         287  
14 3     3   20 use constant FALSE => 0;
  3         7  
  3         151  
15              
16             #own
17 3     3   1339 use Test::Timer::TimeoutException;
  3         7  
  3         27  
18              
19             @EXPORT = qw(time_ok time_nok time_atleast time_atmost time_between);
20              
21             $VERSION = '2.11';
22              
23             my $test = Test::Builder->new;
24             my $timeout = 0;
25              
26             our $alarm = 2; #default alarm
27              
28             # syntactic sugar for time_atmost
29             sub time_ok {
30 2     2 1 3711 return time_atmost(@_);
31             }
32              
33             # inverse test of time_ok
34             sub time_nok {
35 3     3 1 10649 my ( $code, $upperthreshold, $name ) = @_;
36              
37             # timing from zero to upper threshold
38 3         15 my ($within, $time) = _runtest( $code, 0, $upperthreshold );
39              
40             # are we within the specified threshold
41 3 100       19 if ($within == TRUE) {
42              
43             # we inverse the result, since we are the inverse of time_ok
44 1         5 $within = FALSE;
45 1         18 $test->ok( $within, $name ); # no, we fail
46 1         691 $test->diag( "Test ran $time seconds and did not exceed specified threshold of $upperthreshold seconds" );
47             } else {
48              
49             # we inverse the result, since we are the inverse of time_ok
50 2         7 $within = TRUE;
51 2         46 $test->ok( $within, $name ); # yes, we do not fail
52             }
53              
54 3         1413 return $within;
55             }
56              
57             # test to make sure we are below a specified threshold
58             sub time_atmost {
59 4     4 1 9616 my ( $code, $upperthreshold, $name ) = @_;
60              
61             # timing from zero to upper threshold
62 4         19 my ($within, $time) = _runtest( $code, 0, $upperthreshold );
63              
64             # are we within the specified threshold
65 4 100       22 if ($within == TRUE) {
66 2         40 $test->ok( $within, $name ); # yes, we do not fail
67             } else {
68 2         42 $test->ok( $within, $name ); # no, we fail
69 2         1422 $test->diag( "Test ran $time seconds and exceeded specified threshold of $upperthreshold seconds" );
70             }
71              
72 4         1776 return $within;
73             }
74              
75             # test to make sure we are above a specified threshold
76             sub time_atleast {
77 2     2 1 10509 my ( $code, $lowerthreshold, $name ) = @_;
78              
79             # timing from lowerthreshold to nothing
80 2         11 my ($above, $time) = _runtest( $code, $lowerthreshold, undef );
81              
82             # are we above the specified threshold
83 2 100       15 if ($above == TRUE) {
84 1         20 $test->ok( $above, $name ); # yes, we do not fail
85              
86             } else {
87 1         32 $test->ok( $above, $name ); # no, we fail
88 1         647 $test->diag( "Test ran $time seconds and did not exceed specified threshold of $lowerthreshold seconds" );
89             }
90              
91 2         848 return $above;
92             }
93              
94             # test to make sure we are witin a specified threshold time frame
95             sub time_between {
96 3     3 1 14522 my ( $code, $lowerthreshold, $upperthreshold, $name ) = @_;
97              
98             # timing from lower to upper threshold
99 3         13 my ($within, $time) = _runtest( $code, $lowerthreshold, $upperthreshold );
100              
101             # are we within the specified threshold
102 3 100       19 if ($within == TRUE) {
103 1         19 $test->ok( $within, $name ); # yes, we do not fail
104             } else {
105 2         48 $test->ok( $within, $name ); # no, we fail
106 2 100       1536 if ($timeout) {
107 1         12 $test->diag( "Execution ran $timeout seconds and did not execute within specified interval $lowerthreshold - $upperthreshold seconds and timed out");
108             } else {
109 1         14 $test->diag( "Test ran $time seconds and did not execute within specified interval $lowerthreshold - $upperthreshold seconds" );
110             }
111             }
112              
113 3         1044 return $within;
114             }
115              
116             # helper routine to make initiate timing and make initial interpretation of results
117             # test mehtods do the final interpretation
118             sub _runtest {
119 12     12   40 my ( $code, $lowerthreshold, $upperthreshold ) = @_;
120              
121 12         27 my $ok = FALSE;
122 12         22 my $time = 0;
123              
124             try {
125              
126             # we have both a lower and upper threshold (time_between, time_most, time_ok)
127 12 100 66 12   540 if ( defined $lowerthreshold and defined $upperthreshold ) {
    50          
128              
129 10         31 $time = _benchmark( $code, $upperthreshold );
130              
131 8 100 66     154 if ( $time >= $lowerthreshold and $time <= $upperthreshold ) {
132 4         27 $ok = TRUE;
133             } else {
134 4         28 $ok = FALSE;
135             }
136              
137             # we just have a lower threshold (time_atleast)
138             } elsif ( defined $lowerthreshold ) {
139              
140 2         8 $time = _benchmark( $code );
141              
142 2 100       16 if ( $time >= $lowerthreshold ) {
143 1         8 $ok = TRUE;
144             } else {
145 1         8 $ok = FALSE;
146             }
147             }
148             }
149             # catching a timeout so we do not run forever
150             catch Test::Timer::TimeoutException with {
151 2     2   220 my $E = shift;
152              
153 2         8 $timeout = $E->{-text};
154              
155 2         7 return (undef, $time); # we return undef as result
156 12         103 };
157              
158 12         441 return ($ok, $time);
159             }
160              
161             # actual timing using benchmark
162             sub _benchmark {
163 15     15   1516 my ( $code, $threshold ) = @_;
164              
165 15         26 my $time = 0;
166              
167             # We default to no alarm
168 15         25 my $local_alarm = 0;
169              
170             # We only define an alarm if we have an upper threshold
171             # alarm is based on upper threshold + default alarm
172             # default alarm can be extended, see the docs
173 15 100       44 if (defined $threshold) {
174 12         26 $local_alarm = $threshold + $alarm;
175             }
176              
177             # setting first benchmark
178 15         64 my $t0 = Benchmark->new();
179              
180             # defining alarm signal handler
181             # the handler takes care of terminating the
182             # benchmarking
183             local $SIG{ALRM} = sub {
184              
185 3     3   14000641 my $t_alarm = Benchmark->new();
186              
187 3         136 my $alarm_time_string = timediff( $t_alarm, $t0 )->real;
188              
189 3         265 throw Test::Timer::TimeoutException($alarm_time_string);
190 15         642 };
191              
192             # setting alarm
193 15         142 alarm( $local_alarm );
194              
195             # running code
196 15         39 &{$code};
  15         67  
197              
198             # clear alarm
199 12         20002547 alarm( 0 );
200              
201             # setting second benchmark
202 12         224 my $t1 = Benchmark->new();
203              
204             # parsing benchmark output
205 12         516 my $timestring = timediff( $t1, $t0 )->real;
206              
207 12         1156 return $timestring;
208             }
209              
210             1;
211              
212             __END__