File Coverage

blib/lib/Test/PDL.pm
Criterion Covered Total %
statement 93 150 62.0
branch 41 48 85.4
condition 17 17 100.0
subroutine 30 31 96.7
pod 5 5 100.0
total 186 251 74.1


line stmt bran cond sub pod time code
1             package Test::PDL;
2             $Test::PDL::VERSION = '0.12';
3             # ABSTRACT: Test Perl Data Language arrays (a.k.a. piddles) for equality
4              
5              
6 6     6   726107 use strict;
  6     1   13  
  6     1   204  
  0     1      
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
7 6     6   38 use warnings;
  6     1   8  
  6     1   183  
  0     1      
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
8 6     6   2254 use PDL::Lite;
  6     1   243133  
  6     1   141  
  0     0      
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
9 6     6   32 use PDL::Types ();
  6     1   7  
  6     1   95  
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
10              
11 6     6   22 use base qw( Exporter );
  6     1   6  
  6     1   5406  
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
12             our @EXPORT = qw( is_pdl );
13             our @EXPORT_OK = qw( eq_pdl eq_pdl_diag is_pdl test_pdl );
14             our %EXPORT_TAGS = ( deep => [ qw( test_pdl ) ] );
15              
16              
17             our %OPTIONS = (
18             TOLERANCE => 1e-6,
19             EQUAL_TYPES => 1,
20             );
21              
22              
23             sub import
24             {
25 6     6   1655 my $i = 0;
26 6         18 while( $i < @_ ) {
27 12 50       56 if( $_[ $i ] =~ /^-/ ) {
28 1         3 my( $key, $val ) = splice @_, $i, 2;
29 1         1 $key =~ s/^-(.*)/\U$1/;
30 1         21 set_options( $key, $val );
31             }
32 12         24 else { $i++ }
33             }
34 6         749 __PACKAGE__->export_to_level( 1, @_ );
35             }
36              
37              
38             sub _approx
39             {
40 74     74   84 my( $a, $b ) = @_;
41 74         1153 return abs( $a - $b ) < $OPTIONS{ TOLERANCE };
42             }
43              
44              
45             sub _comparison_fails
46             {
47 170     170   176 my ( $got, $expected ) = @_;
48 170 100       174 if( not eval { $got->isa('PDL') } ) {
  170         623  
49 11         34 return 'received value is not a piddle';
50             }
51 160 100       997 if( not eval { $expected->isa('PDL') } ) {
  160         392  
52 6         21 return 'expected value is not a piddle';
53             }
54 155 100 100     778 if( $OPTIONS{ EQUAL_TYPES } && $got->type != $expected->type ) {
55 7         1561 return 'types do not match (EQUAL_TYPES is true)';
56             }
57 149 100       3303 if( $got->ndims != $expected->ndims ) {
58 7         39 return 'dimensions do not match in number';
59             }
60 143 100       328 if( not _dimensions_match( [$got->dims], [$expected->dims] ) ) {
61 4         14 return 'dimensions do not match in extent';
62             }
63             # evaluating these only makes sense for piddles that conform in shape
64 140 100 100     808 if( ( $got->badflag == 1 || $expected->badflag == 1 ) &&
      100        
65 88         1793 not eval { PDL::all( PDL::isbad($got) == PDL::isbad($expected) ) } ) {
66 4         166 return 'bad value patterns do not match';
67             }
68             # if we get here, bad value patterns are sure to match
69 137 100 100     3598 if( $got->type < PDL::float && $expected->type < PDL::float ) {
70 64 100       2661 if( not eval { PDL::all( $got == $expected ) } ) {
  64         550  
71 4         150 return 'values do not match';
72             }
73             }
74             else {
75             # floating-point comparison must be approximate
76 74 100       2197 if( not eval { PDL::all( _approx $got, $expected ) } ) {
  74         133  
77 25         3849 return 'values do not match';
78             }
79             }
80             # if we get here, we didn't fail
81 110         4750 return 0;
82             }
83              
84              
85             sub _dimensions_match
86             {
87 143     143   3536 my @A = @{ +shift };
  143         359  
88 143         1522 my @B = @{ +shift };
  143         168  
89 143   100     528 while( my $a = shift @A and my $b = shift @B ) {
90 107 100       337 if( $a != $b ) { return 0 }
  4         13  
91             }
92 140         295 return 1;
93             }
94              
95              
96             sub is_pdl
97             {
98 27     27 1 15374 require Test::Builder;
99 27         39 my ( $got, $expected, $name ) = @_;
100 27         76 my $tb = Test::Builder->new;
101 27 100       102 if( eval { $name->isa('PDL') } ) {
  27 0       204  
102 2         32 $tb->croak( 'error in arguments: test name is a piddle' );
103             }
104 26   100     92 $name ||= "piddles are equal";
105 26 100       41 if( my $reason = _comparison_fails $got, $expected ) {
106 16         825 my $rc = $tb->ok( 0, $name );
107 16         5455 my $fmt = '%-8T %-12D (%-5S) ';
108             $tb->diag( " $reason\n",
109 16 100       303 " got: ", eval { $got->isa('PDL') && !$got->isnull } ? $got->info( $fmt ) : '', $got, "\n",
    0          
110 16 100       32 " expected: ", eval { $expected->isa('PDL') && !$expected->isnull } ? $expected->info( $fmt ) : '', $expected );
  16 100       3771  
    100          
    0          
111 16         4446 return $rc;
112             }
113             else {
114 11         55 return $tb->ok( 1, $name );
115             }
116             }
117              
118              
119             sub eq_pdl
120             {
121 31     31 1 5073 my ( $got, $expected ) = @_;
122 31         56 return !_comparison_fails( $got, $expected );
123             }
124              
125              
126             sub eq_pdl_diag
127             {
128 115     115 1 53139 my ( $got, $expected ) = @_;
129 115         199 my $reason = _comparison_fails( $got, $expected );
130 115 100       233 if( $reason ) { return 0, $reason }
  25         70  
131 91         204 else { return 1 }
132             }
133              
134              
135             sub test_pdl
136             {
137 32     32 1 17192 require Test::Deep::PDL;
138 32         118 my $expected = pdl( @_ );
139 32         1408 return Test::Deep::PDL->new( $expected );
140             }
141              
142              
143             for my $type ( PDL::Types::types ) {
144             my $sub = sub {
145 37     37   42576 require Test::Deep::PDL;
146 37 100       1084 my $expected = PDL::convert(
147             PDL::Core::alltopdl( 'PDL', scalar(@_) > 1 ? [@_] : shift ),
148             $type->numval
149             );
150 37         1823 return Test::Deep::PDL->new( $expected );
151             };
152             my $sub_name = 'test_' . $type->convertfunc;
153             {
154 6     6   30 no strict 'refs';
  6     1   10  
  6     1   914  
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
155             *$sub_name = $sub;
156             }
157             push @EXPORT_OK, $sub_name;
158             push @{ $EXPORT_TAGS{deep} }, $sub_name;
159             }
160              
161              
162             sub set_options
163             {
164 34     34 1 18874 while( my( $key, $value ) = splice @_, 0, 2 ) {
165 35 100       332 barf( "invalid option $key" ) unless grep { $key eq $_ } keys %OPTIONS;
  68         169  
166 33 100       78 barf( "undefined value for $key" ) unless defined $value;
167 32         141 $OPTIONS{ $key } = $value;
168             }
169             }
170              
171              
172             1;
173              
174             __END__