File Coverage

blib/lib/Test/Time/HiRes.pm
Criterion Covered Total %
statement 66 69 95.6
branch 19 24 79.1
condition n/a
subroutine 16 16 100.0
pod 0 2 0.0
total 101 111 90.9


line stmt bran cond sub pod time code
1             package Test::Time::HiRes;
2              
3 3     3   115193 use strict;
  3         22  
  3         72  
4 3     3   13 use warnings;
  3         6  
  3         63  
5              
6 3     3   13 use Test::More;
  3         4  
  3         16  
7 3     3   1697 use Test::Time;
  3         1573  
  3         13  
8 3     3   1009 use Time::HiRes ();
  3         2301  
  3         921  
9              
10             our $VERSION = '0.05';
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 37     37 0 80 $in_effect;
20             }
21              
22             sub set_time {
23 7     7 0 10576 my ( $class, $arg ) = @_;
24              
25 7         18 $Test::Time::time = $seconds = int($arg); # epoch time in seconds
26 7         18 $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 40 100   40   103 if ( $seconds < $Test::Time::time ) {
    100          
35              
36             # update seconds from Test::Time, but keep the fractional microsecond part
37 3         10 my $microseconds = _microseconds(); # part after DP
38 3         7 $seconds = $Test::Time::time;
39 3         7 $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   24 return 0 unless $time;
48 13         59 return $time % 1_000_000;
49             }
50              
51             sub _float {
52 23 50   23   46 return 0 unless $time;
53 23         47 my $t = $time / 1_000_000;
54 23         293 return sprintf( "%.6f", $t ) + 0;
55             }
56              
57             sub import {
58 4     4   30 my ( $class, %opts ) = @_;
59              
60 4         5 $in_effect = 1;
61 4         15 Test::Time->import; # make sure Test::Time is enabled, in case
62             # there was a call to ->unimport earlier
63              
64 4 100       387 return if $imported;
65              
66             # If time set on import then use it and update
67             # Test::Time, otherwise use $Test::Time::time
68 3 100       11 if ( defined $opts{time} ) {
69 2         7 $class->set_time( $opts{time} );
70             }
71             else {
72 1         2 $seconds = $Test::Time::time;
73 1         2 $time = $seconds * 1_000_000;
74             }
75              
76 3     3   19 no warnings 'redefine';
  3         3  
  3         1077  
77              
78             # keep copies of the original subroutines
79 3         5 my $sub_time = \&Time::HiRes::time;
80 3         6 my $sub_usleep = \&Time::HiRes::usleep;
81 3         3 my $sub_gettimeofday = \&Time::HiRes::gettimeofday;
82              
83             *Time::HiRes::time = sub() {
84 16 100   16   1007502 if (in_effect) {
85 15         34 _synchronise_times();
86              
87 15         25 return _float();
88             }
89             else {
90 1         22 return $sub_time->();
91             }
92 3         24 };
93              
94             *Time::HiRes::usleep = sub($) {
95              
96 5 50   5   19 unless (@_) {
97 0         0 return $sub_usleep->(); # always give "no argument" error
98             }
99              
100 5 50       11 if (in_effect) {
101 5         9 my $sleep = shift;
102              
103 5         12 _synchronise_times();
104              
105 5 100       12 return 0 unless $sleep;
106              
107 4         9 $time = $time + $sleep;
108 4         12 $seconds = int( $time / 1_000_000 );
109              
110 4         9 _synchronise_times();
111              
112 4         17 note "sleep $sleep";
113              
114 4         1048 return $sleep;
115             }
116             else {
117 0         0 return $sub_usleep->(shift);
118             }
119 3         12 };
120              
121             *Time::HiRes::gettimeofday = sub() {
122              
123 16 50   16   31 if (in_effect) {
124 16         31 _synchronise_times();
125              
126 16 100       38 return wantarray ? ( $seconds, _microseconds() ) : _float();
127             }
128             else {
129 0         0 return $sub_gettimeofday->();
130             }
131 3         11 };
132              
133 3         2146 $imported++;
134             }
135              
136             sub unimport {
137 1     1   3 $in_effect = 0;
138 1         6 Test::Time->unimport();
139             }
140              
141             1;
142              
143             __END__