File Coverage

blib/lib/Test2/Tools/PDL.pm
Criterion Covered Total %
statement 99 112 88.3
branch 19 24 79.1
condition 5 12 41.6
subroutine 17 17 100.0
pod 2 2 100.0
total 142 167 85.0


line stmt bran cond sub pod time code
1             package Test2::Tools::PDL;
2              
3             # ABSTRACT: Test2 tools for verifying Perl Data Language piddles
4              
5 4     4   853023 use 5.010;
  4         16  
6 4     4   19 use strict;
  4         10  
  4         146  
7 4     4   24 use warnings;
  4         19  
  4         295  
8              
9             our $VERSION = '0.001'; # VERSION
10              
11 4     4   2022 use PDL::Lite ();
  4         299137  
  4         162  
12 4     4   44 use PDL::Primitive qw(which);
  4         8  
  4         30  
13 4     4   494 use PDL::Types;
  4         9  
  4         646  
14              
15 4     4   2108 use Safe::Isa;
  4         2730  
  4         661  
16 4     4   34 use Scalar::Util qw(blessed);
  4         8  
  4         293  
17 4     4   28 use Test2::API 1.302175 qw(context);
  4         110  
  4         271  
18 4     4   26 use Test2::Compare 0.000130 qw(compare strict_convert);
  4         78  
  4         223  
19 4     4   26 use Test2::Util::Table qw(table);
  4         7  
  4         61  
20 4     4   321 use Test2::Util::Ref qw(render_ref);
  4         33  
  4         256  
21              
22 4     4   1866 use parent qw/Exporter/;
  4         1454  
  4         26  
23             our @EXPORT = qw(pdl_ok pdl_is);
24              
25             our $TOLERANCE = $Test2::Compare::Float::DEFAULT_TOLERANCE;
26             our $TOLERANCE_REL = 0;
27              
28              
29             sub pdl_ok {
30 4     4 1 176247 my ( $thing, $name ) = @_;
31 4         10 my $ctx = context();
32              
33 4 100       274 unless ( $thing->$_isa('PDL') ) {
34 2         20 my $thingname = render_ref($thing);
35 2         42 $ctx->fail( $name, "'$thingname' is not a piddle." );
36 2         415 $ctx->release;
37 2         49 return 0;
38             }
39              
40 2         39 $ctx->ok( 1, $name );
41 2         178 $ctx->release;
42 2         66 return 1;
43             }
44              
45              
46             sub pdl_is {
47 14     14 1 56066 my ( $got, $exp, $name, @diag ) = @_;
48 14         37 my $ctx = context();
49              
50 14         1125 my $gotname = render_ref($got);
51 14 100       376 unless ( $got->$_isa('PDL') ) {
52 2         24 $ctx->fail( $name, "First argument '$gotname' is not a piddle." );
53 2         257 $ctx->release;
54 2         52 return 0;
55             }
56 12 50       135 unless ( $exp->$_isa('PDL') ) {
57 0         0 my $expname = render_ref($exp);
58 0         0 $ctx->fail( $name, "Second argument '$expname' is not a piddle." );
59 0         0 $ctx->release;
60 0         0 return 0;
61             }
62              
63 12         84 my $exp_class = ref($exp);
64 12 50       28 if ( ref($got) ne $exp_class ) {
65 0         0 $ctx->fail( $name,
66             "'$gotname' does not match the expected type '$exp_class'." );
67 0         0 $ctx->release;
68 0         0 return 0;
69             }
70              
71             # compare dimensions
72 12         59 my @exp_dims = $exp->dims;
73 12         22 my @got_dims = $got->dims;
74 12         38 my $delta_dims = compare( \@got_dims, \@exp_dims, \&strict_convert );
75              
76 12 100       3286 if ($delta_dims) {
77 2         8 $ctx->fail( $name, 'Dimensions do not match', $delta_dims->diag,
78             @diag );
79 2         5718 $ctx->release;
80 2         95 return 0;
81             }
82              
83             # compare isbad
84 10         12 my $both_bad;
85 10 100 66     103 if ( $got->badflag or $exp->badflag ) {
86 3         115 my $delta_isbad =
87             compare( $got->isbad->unpdl, $exp->isbad->unpdl, \&strict_convert );
88              
89 3 100       2103 if ($delta_isbad) {
90 1         5 $ctx->fail( $name, 'Bad value patterns do not match',
91             $delta_isbad->diag, @diag );
92 1         2328 $ctx->release;
93 1         34 return 0;
94             }
95              
96 2         37 $both_bad = ( $got->isbad & $exp->isbad );
97             }
98              
99             # Compare data values.
100 9         116 my $diff;
101             my $is_numeric = !(
102 27     27   209 List::Util::any { $exp->$_isa($_) }
103 9   33     63 qw(PDL::SV PDL::Factor PDL::DateTime) or $exp->type eq 'byte'
104             );
105 9         458 eval {
106 9 50 33     33 if ( $is_numeric
      33        
107             and ( $exp->type >= PDL::float or $got->type >= PDL::float ) )
108             {
109 9         275 $diff = ( ( $got - $exp )->abs >
110             $TOLERANCE + ( $TOLERANCE_REL * $exp )->abs );
111             }
112             else {
113 0         0 $diff = ( $got != $exp );
114             }
115 9 100       2156 if ( $exp->badflag ) {
116 2         21 $diff->where( $exp->isbad ) .= 0;
117             }
118             };
119 9 50       715 if ($@) {
120 0         0 my $gotname = render_ref($got);
121 0         0 $ctx->fail( $name, "Error occurred during values comparison.",
122             $@, @diag );
123 0         0 $ctx->release;
124 0         0 return 0;
125             }
126 9         41 my $diff_which = which($diff);
127 9 100       1253 unless ( $diff_which->isempty ) {
128             state $at = sub {
129 6     6   1272 my ( $p, @position ) = @_;
130 6 50       23 if ( $p->isa('PDL::DateTime') ) {
131 0         0 return $p->dt_at(@position);
132             }
133             else {
134 6         17 return $p->at(@position);
135             }
136 2         48 };
137              
138 2         8 my $gotname = render_ref($got);
139             my @table = table(
140             sanitize => 1,
141             max_width => 80,
142             collapse => 1,
143             header => [qw(POSITION GOT CHECK)],
144             rows => [
145             map {
146 3         35 my @position = $exp->one2nd($_);
147             [
148 3         1431 join( ',', @position ),
149             $at->( $got, @position ),
150             $at->( $exp, @position )
151             ]
152 2         53 } @{ $diff_which->unpdl }
  2         30  
153             ]
154             );
155 2         3123 $ctx->fail( $name, "Values do not match.", join( "\n", @table ),
156             @diag );
157 2         415 $ctx->release;
158 2         70 return 0;
159             }
160              
161 7         68 $ctx->ok( 1, $name );
162 7         540 $ctx->release;
163 7         229 return 1;
164             }
165              
166             1;
167              
168             __END__