File Coverage

blib/lib/Test/Time/HiRes.pm
Criterion Covered Total %
statement 63 66 95.4
branch 16 20 80.0
condition n/a
subroutine 15 15 100.0
pod 0 2 0.0
total 94 103 91.2


line stmt bran cond sub pod time code
1             package Test::Time::HiRes;
2              
3 3     3   100021 use strict;
  3         20  
  3         62  
4 3     3   11 use warnings;
  3         5  
  3         56  
5              
6 3     3   9 use Test::More;
  3         5  
  3         12  
7 3     3   1428 use Test::Time;
  3         1283  
  3         10  
8 3     3   857 use Time::HiRes ();
  3         1893  
  3         740  
9              
10             our $VERSION = '0.03';
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 28     28 0 63 $in_effect;
20             }
21              
22             sub set_time {
23 7     7 0 9139 my ( $class, $arg ) = @_;
24              
25 7         14 $Test::Time::time = $seconds = int($arg); # epoch time in seconds
26 7         14 $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 31 100   31   85 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         23 $time = ( $seconds * 1_000_000 ) + $microseconds;
40             }
41             elsif ( $seconds > $Test::Time::time ) {
42 1         2 $Test::Time::time = $seconds;
43             }
44             }
45              
46             sub _microseconds {
47 13 50   13   28 return 0 unless $time;
48 13         57 return $time % 1_000_000;
49             }
50              
51             sub import {
52 4     4   26 my ( $class, %opts ) = @_;
53              
54 4         6 $in_effect = 1;
55              
56 4 100       13 return if $imported;
57              
58             # If time set on import then use it and update
59             # Test::Time, otherwise use $Test::Time::time
60 3 100       10 if ( defined $opts{time} ) {
61 2         4 $class->set_time( $opts{time} );
62             }
63             else {
64 1         1 $seconds = $Test::Time::time;
65 1         1 $time = $seconds * 1_000_000;
66             }
67              
68 3     3   16 no warnings 'redefine';
  3         4  
  3         847  
69              
70             # keep copies of the original subroutines
71 3         7 my $sub_time = \&Time::HiRes::time;
72 3         4 my $sub_usleep = \&Time::HiRes::usleep;
73 3         4 my $sub_gettimeofday = \&Time::HiRes::gettimeofday;
74              
75             *Time::HiRes::time = sub() {
76 15 100   15   1006788 if (in_effect) {
77 14         35 _synchronise_times();
78              
79 14         29 my $t = $time / 1_000_000;
80 14         153 return sprintf( "%.6f", $t );
81             }
82             else {
83 1         16 return $sub_time->();
84             }
85 3         14 };
86              
87             *Time::HiRes::usleep = sub($) {
88              
89 5 50   5   24 unless (@_) {
90 0         0 return $sub_usleep->(); # always give "no argument" error
91             }
92              
93 5 50       13 if (in_effect) {
94 5         9 my $sleep = shift;
95              
96 5         11 _synchronise_times();
97              
98 5 100       11 return 0 unless $sleep;
99              
100 4         8 $time = $time + $sleep;
101 4         12 $seconds = int( $time / 1_000_000 );
102              
103 4         10 _synchronise_times();
104              
105 4         18 note "sleep $sleep";
106              
107 4         1353 return $sleep;
108             }
109             else {
110 0         0 return $sub_usleep->(shift);
111             }
112 3         11 };
113              
114             *Time::HiRes::gettimeofday = sub() {
115 8 50   8   16 if (in_effect) {
116 8         14 _synchronise_times();
117 8         12 return ( $seconds, _microseconds() );
118             }
119             else {
120 0         0 return $sub_gettimeofday->();
121             }
122 3         9 };
123              
124 3         1483 $imported++;
125             }
126              
127             sub unimport {
128 1     1   3 $in_effect = 0;
129 1         5 Test::Time->unimport();
130             }
131              
132             1;
133              
134             __END__