| 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__ |