File Coverage

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


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