File Coverage

inc/My/Module/Test.pm
Criterion Covered Total %
statement 105 121 86.7
branch 23 32 71.8
condition 11 26 42.3
subroutine 17 19 89.4
pod 5 6 83.3
total 161 204 78.9


line stmt bran cond sub pod time code
1             package My::Module::Test;
2              
3 9     9   155161 use 5.006002;
  9         45  
4              
5 9     9   44 use strict;
  9         15  
  9         174  
6 9     9   42 use warnings;
  9         13  
  9         435  
7              
8             our $VERSION = '0.130';
9              
10 9     9   48 use Exporter qw{ import };
  9         17  
  9         395  
11              
12 9     9   10021 use Astro::Coord::ECI::TLE qw{ :constants };
  9         35  
  9         1795  
13 9     9   69 use Astro::Coord::ECI::Utils qw{ rad2deg };
  9         16  
  9         471  
14 9     9   4973 use Test::More 0.88;
  9         460798  
  9         87  
15              
16 9     9   2650 use constant CODE_REF => ref sub {};
  9         18  
  9         2330  
17              
18             our @EXPORT_OK = qw{
19             format_pass format_time
20             magnitude
21             tolerance tolerance_frac
22             velocity_sanity
23             };
24             our %EXPORT_TAGS = (
25             all => \@EXPORT_OK,
26             format => [ qw{ format_pass format_time } ],
27             tolerance => [ qw{ tolerance tolerance_frac } ],
28             );
29              
30             # Perl::Critic can't find interpolated sub calls
31             sub _dor { ## no critic (ProhibitUnusedPrivateSubroutines)
32 0     0   0 foreach ( @_ ) {
33 0 0       0 defined $_ and return $_;
34             }
35 0         0 return;
36             }
37              
38             {
39              
40             my @decoder;
41              
42             # We jump through this hoop in case the constants turn out not to be
43             # dualvars.
44             BEGIN {
45 9     9   43 $decoder[ PASS_EVENT_NONE ] = '';
46 9         24 $decoder[ PASS_EVENT_SHADOWED ] = 'shdw';
47 9         15 $decoder[ PASS_EVENT_LIT ] = 'lit';
48 9         20 $decoder[ PASS_EVENT_DAY ] = 'day';
49 9         20 $decoder[ PASS_EVENT_RISE ] = 'rise';
50 9         27 $decoder[ PASS_EVENT_MAX ] = 'max';
51 9         17 $decoder[ PASS_EVENT_SET ] = 'set';
52 9         14 $decoder[ PASS_EVENT_APPULSE ] = 'apls';
53 9         34 $decoder[ PASS_EVENT_START ] = 'start';
54 9         14965 $decoder[ PASS_EVENT_END ] = 'end';
55             }
56              
57             sub _format_event {
58 304     304   479 my ( $event ) = @_;
59 304 100       448 defined $event or return '';
60 297         766 return $decoder[ $event + 0 ];
61             }
62              
63             }
64              
65             sub format_pass {
66 36     36 1 8424 my @passes = @_;
67 36         64 my $rslt = '';
68 36         77 foreach my $pass ( @passes ) {
69 36 50       105 $pass
70             or next;
71 36         66 $rslt .= "\n";
72 36         48 foreach my $event ( @{ $pass->{events} } ) {
  36         117  
73             $rslt .= sprintf '%19s %5s %5s %7s %-5s %-5s',
74             format_time( $event->{time} ),
75             _format_optional( '%5.1f', $event, 'elevation', \&rad2deg ),
76             _format_optional( '%5.1f', $event, 'azimuth', \&rad2deg ),
77             _format_optional( '%7.1f', $event, 'range' ),
78             _format_event( $event->{illumination} ),
79 152         380 _format_event( $event->{event} ),
80             ;
81 152         1457 $rslt =~ s/ \s+ \z //smx;
82 152         212 $rslt .= "\n";
83 152 100       340 if ( $event->{appulse} ) {
84 10         20 my $sta = $event->{station};
85             my ( $az, $el ) = $sta->azel(
86 10         54 $event->{appulse}{body}->universal( $event->{time} ) );
87             $rslt .= sprintf '%19s %5.1f %5.1f %7.1f %s', '',
88             rad2deg( $el ),
89             rad2deg( $az ),
90             rad2deg( $event->{appulse}{angle} ),
91 10         50 $event->{appulse}{body}->get( 'name' ),
92             ;
93 10         98 $rslt =~ s/ \s+ \z //smx;
94 10         46 $rslt .= "\n";
95             }
96             }
97             }
98 36         160 $rslt =~ s/ \A \n //smx;
99 36         237 $rslt =~ s/ (?<= \s ) - (?= 0 [.] 0+ \s ) / /smxg;
100 36         261 return $rslt;
101             }
102              
103             sub _format_optional {
104 456     456   759 my ( $tplt, $hash, $key, $xfrm ) = @_;
105 456 100       1023 defined( my $val = $hash->{$key} )
106             or return '';
107 411 100       938 CODE_REF eq ref $xfrm
108             and $val = $xfrm->( $val );
109 411         1991 return sprintf $tplt, $val;
110             }
111              
112             sub format_time {
113 157     157 1 257 my ( $time ) = @_;
114 157         544 my @parts = gmtime int( $time + 0.5 );
115 157         911 return sprintf '%04d/%02d/%02d %02d:%02d:%02d', $parts[5] + 1900,
116             $parts[4] + 1, @parts[ 3, 2, 1, 0 ];
117             }
118              
119             sub magnitude {
120 1     1 1 4 my ( $tle, @arg ) = @_;
121 1         4 my ( $time, $want, $name ) = splice @arg, -3;
122 1         2 my $got;
123             eval {
124 1         6 $got = $tle->universal( $time )->magnitude( @arg );
125 1 50       13 defined $got
126             and $got = sprintf '%.1f', $got;
127 1         4 1;
128 1 50       2 } or do {
129 0         0 @_ = "$name failed: $@";
130 0         0 goto &fail;
131             };
132 1 50       4 if ( defined $want ) {
133 1         5 $want = sprintf '%.1f', $want;
134 1         4 @_ = ( $got, 'eq', $want, $name );
135 1         7 goto &cmp_ok;
136             } else {
137 0         0 @_ = ( ! defined $got, $name );
138 0         0 goto &ok;
139             }
140             }
141              
142             sub tolerance {
143 3430     3430 1 91146 my ( $got, $want, $tolerance, $title, $fmtr ) = @_;
144 3430   100 0   19660 $fmtr ||= sub { return $_[0] };
  0         0  
145 3430         17671 $title =~ s{ (?
146 3430         9583 my $delta = $got - $want;
147 3430         6911 my $rslt = abs( $delta ) < $tolerance;
148 3430 50       5494 $rslt or $title .= <<"EOD";
149              
150 0         0 Got: @{[ $fmtr->( $got ) ]}
151 0         0 Expected: @{[ $fmtr->( $want ) ]}
152             Difference: $delta
153             Tolerance: $tolerance
154             EOD
155 3430         4577 chomp $title;
156 3430         4621 local $Test::Builder::Level = $Test::Builder::Level + 1;
157 3430         7684 return ok( $rslt, $title );
158             }
159              
160             sub tolerance_frac {
161 50     50 1 5470 my ( $got, $want, $tolerance, $title, $fmtr ) = @_;
162 50         177 @_ = ( $got, $want, $tolerance * abs $want, $title, $fmtr );
163 50         156 goto &tolerance;
164             }
165              
166             {
167             my @dim_name = qw{ X Y Z };
168             my %method_dim_name = (
169             azel => [ qw{ azimuth elevation range } ],
170             equatorial => [ 'right ascension', 'declination', 'range' ],
171             );
172             my %tweak = (
173             azel => sub {
174             my ( $delta, $current, $previous ) = @_;
175             $delta->[0] *= cos( ( $current->[1] + $previous->[1] ) / 2 );
176             return;
177             },
178             equatorial => sub {
179             my ( $delta, $current, $previous ) = @_;
180             $delta->[1] *= cos( ( $current->[0] + $previous->[0] ) / 2 );
181             return;
182             },
183             );
184              
185             sub velocity_sanity {
186 6     6 0 27 my ( $method, $body, $sta ) = @_;
187 6         14 my $time = $body->universal();
188 6         8 my @rslt;
189 6         9 foreach my $delta_t ( 0, 1 ) {
190 12 100       33 $delta_t
191             and $body->universal( $time + $delta_t );
192 12 100       30 my @coord = $sta ? $sta->$method( $body ) :
193             $body->$method();
194             # Accommodate internal methods that return a reference to an
195             # array of intermediate results.
196 12 50       30 ref @coord and shift @coord;
197 12         23 push @rslt, \@coord;
198             }
199 6         13 my @delta_p = map { $rslt[1][$_] - $rslt[0][$_] } ( 0 .. 2 );
  18         37  
200             $tweak{$method}
201 6 100       26 and $tweak{$method}->( \@delta_p, @rslt );
202 6         19 my @time_a = gmtime $time;
203 6   33     13 my $title = sprintf
204             '%s converted to %s at %i/%i/%i %i:%02i:%02i GMT',
205             $body->get( 'name' ) || $body->get( 'id' ), $method,
206             $time_a[5] + 1900, $time_a[4] + 1, @time_a[ 3, 2, 1, 0 ];
207 6         17 my $grade = \&pass;
208 6         12 foreach my $inx ( 0 .. 2 ) {
209 18         19 my $v_inx = $inx + 3;
210 18 100 33     97 defined $rslt[0][$v_inx]
      66        
      66        
211             and defined $rslt[1][$v_inx]
212             and $rslt[0][$v_inx] <= $delta_p[$inx]
213             and $delta_p[$inx] <= $rslt[1][$v_inx]
214             and next;
215 13 50 33     70 defined $rslt[0][$v_inx]
      33        
      33        
216             and defined $rslt[1][$v_inx]
217             and $rslt[0][$v_inx] >= $delta_p[$inx]
218             and $delta_p[$inx] >= $rslt[1][$v_inx]
219             and next;
220 0   0     0 my $dim = $method_dim_name{$method}[$inx] || $dim_name[$inx];
221 0         0 $grade = \&fail;
222 0         0 $title .= <<"EOD";
223              
224             $dim( t + 1 ): $rslt[1][$inx]
225             $dim( t ): $rslt[0][$inx]
226 0         0 $dim dot ( t ): @{[ _dor( $rslt[0][$v_inx], '' ) ]}
227             $dim( t + 1 ) - $dim( t ): $delta_p[$inx]
228 0         0 $dim dot ( t + 1 ): @{[ _dor( $rslt[1][$v_inx], '' ) ]}
229             EOD
230 0         0 chomp $title;
231             }
232 6         15 @_ = ( $title );
233 6         31 goto &$grade;
234             }
235             }
236              
237             1;
238              
239             __END__