File Coverage

blib/lib/Test/Time/HiRes.pm
Criterion Covered Total %
statement 64 67 95.5
branch 16 20 80.0
condition n/a
subroutine 15 15 100.0
pod 0 2 0.0
total 95 104 91.3


line stmt bran cond sub pod time code
1             package Test::Time::HiRes;
2              
3 3     3   116034 use strict;
  3         22  
  3         75  
4 3     3   15 use warnings;
  3         5  
  3         67  
5              
6 3     3   13 use Test::More;
  3         5  
  3         17  
7 3     3   1697 use Test::Time;
  3         1632  
  3         15  
8 3     3   988 use Time::HiRes ();
  3         2264  
  3         806  
9              
10             our $VERSION = '0.04';
11              
12             our $time = 0; # epoch in microseconds
13             our $seconds = 0; # i.e. standard epoch
14              
15             my $in_effect = 1;
16             my $imported = 0;
17              
18             sub in_effect {
19 29     29 0 64 $in_effect;
20             }
21              
22             sub set_time {
23 7     7 0 10916 my ( $class, $arg ) = @_;
24              
25 7         19 $Test::Time::time = $seconds = int($arg); # epoch time in seconds
26 7         29 $time = $arg * 1_000_000; # epoch time in microseconds
27             }
28              
29             # synchronise times so time is correct whether using sleep() or usleep().
30             # - assume time only goes forwards
31             # - take the highest as current epoch time
32             sub _synchronise_times {
33              
34 32 100   32   81 if ( $seconds < $Test::Time::time ) {
    100          
35              
36             # update seconds from Test::Time, but keep the fractional microsecond part
37 3         8 my $microseconds = _microseconds(); # part after DP
38 3         5 $seconds = $Test::Time::time;
39 3         8 $time = ( $seconds * 1_000_000 ) + $microseconds;
40             }
41             elsif ( $seconds > $Test::Time::time ) {
42 1         3 $Test::Time::time = $seconds;
43             }
44             }
45              
46             sub _microseconds {
47 13 50   13   28 return 0 unless $time;
48 13         58 return $time % 1_000_000;
49             }
50              
51             sub import {
52 4     4   31 my ( $class, %opts ) = @_;
53              
54 4         8 $in_effect = 1;
55 4         16 Test::Time->import; # make sure Test::Time is enabled, in case
56             # there was a call to ->unimport earlier
57              
58 4 100       8815 return if $imported;
59              
60             # If time set on import then use it and update
61             # Test::Time, otherwise use $Test::Time::time
62 3 100       15 if ( defined $opts{time} ) {
63 2         10 $class->set_time( $opts{time} );
64             }
65             else {
66 1         2 $seconds = $Test::Time::time;
67 1         2 $time = $seconds * 1_000_000;
68             }
69              
70 3     3   20 no warnings 'redefine';
  3         6  
  3         1083  
71              
72             # keep copies of the original subroutines
73 3         6 my $sub_time = \&Time::HiRes::time;
74 3         6 my $sub_usleep = \&Time::HiRes::usleep;
75 3         6 my $sub_gettimeofday = \&Time::HiRes::gettimeofday;
76              
77             *Time::HiRes::time = sub() {
78 16 100   16   1016076 if (in_effect) {
79 15         35 _synchronise_times();
80              
81 15         27 my $t = $time / 1_000_000;
82 15         169 return sprintf( "%.6f", $t );
83             }
84             else {
85 1         18 return $sub_time->();
86             }
87 3         15 };
88              
89             *Time::HiRes::usleep = sub($) {
90              
91 5 50   5   20 unless (@_) {
92 0         0 return $sub_usleep->(); # always give "no argument" error
93             }
94              
95 5 50       11 if (in_effect) {
96 5         9 my $sleep = shift;
97              
98 5         16 _synchronise_times();
99              
100 5 100       11 return 0 unless $sleep;
101              
102 4         8 $time = $time + $sleep;
103 4         12 $seconds = int( $time / 1_000_000 );
104              
105 4         10 _synchronise_times();
106              
107 4         15 note "sleep $sleep";
108              
109 4         1061 return $sleep;
110             }
111             else {
112 0         0 return $sub_usleep->(shift);
113             }
114 3         23 };
115              
116             *Time::HiRes::gettimeofday = sub() {
117 8 50   8   18 if (in_effect) {
118 8         17 _synchronise_times();
119 8         19 return ( $seconds, _microseconds() );
120             }
121             else {
122 0         0 return $sub_gettimeofday->();
123             }
124 3         10 };
125              
126 3         1821 $imported++;
127             }
128              
129             sub unimport {
130 1     1   3 $in_effect = 0;
131 1         7 Test::Time->unimport();
132             }
133              
134             1;
135              
136             __END__