File Coverage

blib/lib/Test/Deep/DateTime/RFC3339.pm
Criterion Covered Total %
statement 78 78 100.0
branch 25 28 89.2
condition 7 9 77.7
subroutine 19 19 100.0
pod 1 6 16.6
total 130 140 92.8


line stmt bran cond sub pod time code
1             package Test::Deep::DateTime::RFC3339;
2              
3 1     1   52492 use strict;
  1         3  
  1         37  
4 1     1   6 use warnings;
  1         2  
  1         30  
5 1     1   29 use 5.008_005;
  1         7  
  1         46  
6             our $VERSION = '0.04';
7              
8 1     1   878 use Test::Deep::Cmp; # isa
  1         885  
  1         5  
9              
10 1     1   57 use Exporter 'import';
  1         1  
  1         109  
11             our @EXPORT = qw(datetime_rfc3339);
12              
13 1     1   6 use Carp 'confess';
  1         2  
  1         55  
14              
15 1     1   3410 use DateTime;
  1         255623  
  1         48  
16 1     1   14 use DateTime::Duration;
  1         2  
  1         22  
17 1     1   1435 use DateTime::Format::RFC3339;
  1         7988  
  1         35  
18 1     1   1076 use DateTime::Format::Duration::DurationString;
  1         67304  
  1         36  
19 1     1   1107 use DateTime::Format::Human::Duration;
  1         3930  
  1         38  
20 1     1   819 use Safe::Isa '$_isa';
  1         458  
  1         1036  
21              
22             sub datetime_rfc3339 {
23 15     15 1 28147 __PACKAGE__->new(@_);
24             }
25              
26             sub init {
27 15     15 0 115 my $self = shift;
28              
29 15         64 $self->{parser} = DateTime::Format::RFC3339->new;
30 15 100       239 return unless @_;
31              
32 13 50       46 my $expected = shift or confess "Expected datetime required for datetime_rfc3339() with arguments";
33 13   66     502 my $tolerance = shift || DateTime::Duration->new; # default to an ->is_zero duration
34              
35 13 100       496 unless ($expected->$_isa("DateTime")) {
36 2 100       54 my $parsed = eval { $self->{parser}->parse_datetime($expected) }
  2         9  
37             or confess "Expected datetime isn't a DateTime and can't be parsed as RFC3339: '$expected', $@";
38 1         516 $expected = $parsed;
39             }
40 12 100       158 unless ($tolerance->$_isa("DateTime::Duration")) {
41 6         200 my $parser = DateTime::Format::Duration::DurationString->new;
42 6 100       115 my $parsed = eval { $parser->parse($tolerance)->to_duration }
  6         31  
43             or confess "Expected tolerance isn't a DateTime::Duration and can't be parsed: '$tolerance', $@";
44 5         570 $tolerance = $parsed;
45             }
46              
47             # Do all comparisons and math in UTC
48 11         109 $expected->set_time_zone('UTC');
49              
50 11         131 $self->{expected} = $expected;
51 11         18 $self->{tolerance} = $tolerance;
52              
53 11         28 return;
54             }
55              
56             sub descend {
57 10     10 0 20941 my ($self, $got) = @_;
58 10         32 my ($expected, $tolerance) = @$self{'expected', 'tolerance'};
59              
60 10         15 $got = eval { $self->{parser}->parse_datetime($got) };
  10         42  
61              
62 10 100 66     2933 if ($@ or not $got) {
63 2 50       18 $self->{diag_message} = sprintf "Can't parse %s as an RFC3339 timestamp: %s",
64             (defined $_[1] ? "'$_[1]'" : "an undefined value"), $@;
65 2         7 return 0;
66             }
67              
68 8 100       863 $got->set_time_zone('UTC')
69             if $expected;
70              
71             # This lets us receive the DateTime object in renderGot
72 8         455 $self->data->{got_string} = $self->data->{got};
73 8         151 $self->data->{got} = $got;
74              
75 8 100 100     80 return $expected
76             ? ($got >= $expected - $tolerance and $got <= $expected + $tolerance)
77             : 1; # we parsed!
78             }
79              
80             # reported at top of diagnostic output on failure
81             sub diag_message {
82 2     2 0 1026 my ($self, $where) = @_;
83 2         6 my $msg = "Compared $where";
84 2 50       13 $msg .= "\n" . $self->{diag_message}
85             if $self->{diag_message};
86 2         8 return $msg;
87             }
88              
89             # used in diagnostic output on failure to render the expected value
90             sub renderExp {
91 4     4 0 43 my $self = shift;
92 4 100       18 return "any RFC3339 timestamp" unless $self->{expected};
93              
94 3         132 my $expected = $self->_format( $self->{expected} );
95 3 100       318 return $self->{tolerance}->is_zero
96             ? $expected
97             : $expected . " +/- " . DateTime::Format::Human::Duration->new->format_duration($self->{tolerance});
98             }
99              
100             sub renderGot {
101 3     3 0 23 my ($self, $got) = @_;
102 3 100       13 return $got->$_isa("DateTime") ? $self->_format($got) : $got;
103             }
104              
105             sub _format {
106 4     4   17 my $self = shift;
107 4         17 return $self->{parser}->format_datetime(@_);
108             }
109              
110             1;
111             __END__