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.14';
3             # ABSTRACT: Test Perl Data Language arrays (a.k.a. piddles) for equality
4              
5              
6 6     6   861223 use strict;
  6     1   32  
  6     1   157  
  0     1      
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
7 6     6   26 use warnings;
  6     1   21  
  6     1   150  
  0     1      
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
8 6     6   1728 use PDL::Lite;
  6     1   207187  
  6     1   39  
  0     0      
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
9 6     6   671 use PDL::Types ();
  6     1   11  
  6     1   97  
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
10              
11 6     6   25 use base qw( Exporter );
  6     1   9  
  6     1   5695  
  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   1808 my $i = 0;
26 6         20 while( $i < @_ ) {
27 12 50       47 if( $_[ $i ] =~ /^-/ ) {
28 1         4 my( $key, $val ) = splice @_, $i, 2;
29 1         1 $key =~ s/^-(.*)/\U$1/;
30 1         20 set_options( $key, $val );
31             }
32 12         24 else { $i++ }
33             }
34 6         692 __PACKAGE__->export_to_level( 1, @_ );
35             }
36              
37              
38             sub _approx
39             {
40 65     65   98 my( $a, $b ) = @_;
41 65         1062 return abs( $a - $b ) < $OPTIONS{ TOLERANCE };
42             }
43              
44              
45             sub _comparison_fails
46             {
47 161     161   214 my ( $got, $expected ) = @_;
48 161 100       206 if( not eval { $got->isa('PDL') } ) {
  161         542  
49 11         37 return 'received value is not a piddle';
50             }
51 151 100       1054 if( not eval { $expected->isa('PDL') } ) {
  151         348  
52 6         19 return 'expected value is not a piddle';
53             }
54 146 100 100     651 if( $OPTIONS{ EQUAL_TYPES } && $got->type != $expected->type ) {
55 7         1869 return 'types do not match (EQUAL_TYPES is true)';
56             }
57 140 100       3540 if( $got->ndims != $expected->ndims ) {
58 7         38 return 'dimensions do not match in number';
59             }
60 134 100       333 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 131 100 100     609 if( ( $got->badflag == 1 || $expected->badflag == 1 ) &&
      100        
65 79         1490 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 128 100 100     3729 if( $got->type < PDL::float && $expected->type < PDL::float ) {
70 64 100       3163 if( not eval { PDL::all( $got == $expected ) } ) {
  64         534  
71 4         169 return 'values do not match';
72             }
73             }
74             else {
75             # floating-point comparison must be approximate
76 65 100       2006 if( not eval { PDL::all( _approx $got, $expected ) } ) {
  65         122  
77 25         3911 return 'values do not match';
78             }
79             }
80             # if we get here, we didn't fail
81 101         4887 return 0;
82             }
83              
84              
85             sub _dimensions_match
86             {
87 134     134   4378 my @A = @{ +shift };
  134         398  
88 134         1756 my @B = @{ +shift };
  134         164  
89 134   100     452 while( my $a = shift @A and my $b = shift @B ) {
90 101 100       266 if( $a != $b ) { return 0 }
  4         11  
91             }
92 131         290 return 1;
93             }
94              
95              
96             sub is_pdl
97             {
98 27     27 1 46498 require Test::Builder;
99 27         55 my ( $got, $expected, $name ) = @_;
100 27         62 my $tb = Test::Builder->new;
101 27 100       224 if( eval { $name->isa('PDL') } ) {
  27 0       193  
102 2         21 $tb->croak( 'error in arguments: test name is a piddle' );
103             }
104 26   100     102 $name ||= "piddles are equal";
105 26 100       49 if( my $reason = _comparison_fails $got, $expected ) {
106 16         914 my $rc = $tb->ok( 0, $name );
107 16         12001 my $fmt = '%-8T %-12D (%-5S) ';
108             $tb->diag( " $reason\n",
109 16 100       291 " got: ", eval { $got->isa('PDL') && !$got->isnull } ? $got->info( $fmt ) : '', $got, "\n",
    0          
110 16 100       37 " expected: ", eval { $expected->isa('PDL') && !$expected->isnull } ? $expected->info( $fmt ) : '', $expected );
  16 100       3766  
    100          
    0          
111 16         7187 return $rc;
112             }
113             else {
114 11         46 return $tb->ok( 1, $name );
115             }
116             }
117              
118              
119             sub eq_pdl
120             {
121 31     31 1 8171 my ( $got, $expected ) = @_;
122 31         64 return !_comparison_fails( $got, $expected );
123             }
124              
125              
126             sub eq_pdl_diag
127             {
128 106     106 1 102004 my ( $got, $expected ) = @_;
129 106         193 my $reason = _comparison_fails( $got, $expected );
130 106 100       216 if( $reason ) { return 0, $reason }
  25         71  
131 82         306 else { return 1 }
132             }
133              
134              
135             sub test_pdl
136             {
137 29     29 1 28747 require Test::Deep::PDL;
138 29         108 my $expected = PDL::Core::pdl( @_ );
139 29         1600 return Test::Deep::PDL->new( $expected );
140             }
141              
142              
143             for my $type ( PDL::Types::types ) {
144             my $sub = sub {
145 33     33   60669 require Test::Deep::PDL;
146 33 100       965 my $expected = PDL::convert(
147             PDL::Core::alltopdl( 'PDL', scalar(@_) > 1 ? [@_] : shift ),
148             $type->numval
149             );
150 33         2046 return Test::Deep::PDL->new( $expected );
151             };
152             my $sub_name = 'test_' . $type->convertfunc;
153             {
154 6     6   41 no strict 'refs';
  6     1   11  
  6     1   1008  
  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 25748 while( my( $key, $value ) = splice @_, 0, 2 ) {
165 35 100       295 PDL::barf( "invalid option $key" ) unless grep { $key eq $_ } keys %OPTIONS;
  68         166  
166 33 100       74 PDL::barf( "undefined value for $key" ) unless defined $value;
167 32         109 $OPTIONS{ $key } = $value;
168             }
169             }
170              
171              
172             1;
173              
174             __END__