| 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 |  | 1046774 | use 5.010; | 
|  | 4 |  |  |  |  | 37 |  | 
| 6 | 4 |  |  | 4 |  | 26 | use strict; | 
|  | 4 |  |  |  |  | 5 |  | 
|  | 4 |  |  |  |  | 78 |  | 
| 7 | 4 |  |  | 4 |  | 22 | use warnings; | 
|  | 4 |  |  |  |  | 8 |  | 
|  | 4 |  |  |  |  | 162 |  | 
| 8 |  |  |  |  |  |  |  | 
| 9 |  |  |  |  |  |  | our $VERSION = '0.0005'; # VERSION | 
| 10 |  |  |  |  |  |  |  | 
| 11 | 4 |  |  | 4 |  | 1877 | use PDL::Lite (); | 
|  | 4 |  |  |  |  | 447263 |  | 
|  | 4 |  |  |  |  | 134 |  | 
| 12 | 4 |  |  | 4 |  | 35 | use PDL::Primitive qw(which); | 
|  | 4 |  |  |  |  | 11 |  | 
|  | 4 |  |  |  |  | 28 |  | 
| 13 | 4 |  |  | 4 |  | 373 | use PDL::Types; | 
|  | 4 |  |  |  |  | 10 |  | 
|  | 4 |  |  |  |  | 490 |  | 
| 14 |  |  |  |  |  |  |  | 
| 15 | 4 |  |  | 4 |  | 1906 | use Safe::Isa; | 
|  | 4 |  |  |  |  | 2066 |  | 
|  | 4 |  |  |  |  | 426 |  | 
| 16 | 4 |  |  | 4 |  | 31 | use Scalar::Util qw(blessed); | 
|  | 4 |  |  |  |  | 9 |  | 
|  | 4 |  |  |  |  | 229 |  | 
| 17 | 4 |  |  | 4 |  | 40 | use Test2::API 1.302175 qw(context); | 
|  | 4 |  |  |  |  | 99 |  | 
|  | 4 |  |  |  |  | 242 |  | 
| 18 | 4 |  |  | 4 |  | 33 | use Test2::Compare 0.000130 qw(compare strict_convert); | 
|  | 4 |  |  |  |  | 85 |  | 
|  | 4 |  |  |  |  | 263 |  | 
| 19 | 4 |  |  | 4 |  | 33 | use Test2::Util::Table qw(table); | 
|  | 4 |  |  |  |  | 8 |  | 
|  | 4 |  |  |  |  | 54 |  | 
| 20 | 4 |  |  | 4 |  | 261 | use Test2::Util::Ref qw(render_ref); | 
|  | 4 |  |  |  |  | 11 |  | 
|  | 4 |  |  |  |  | 284 |  | 
| 21 |  |  |  |  |  |  |  | 
| 22 | 4 |  |  | 4 |  | 1940 | use parent qw/Exporter/; | 
|  | 4 |  |  |  |  | 1259 |  | 
|  | 4 |  |  |  |  | 30 |  | 
| 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 | 6924 | my ( $thing, $name ) = @_; | 
| 31 | 4 |  |  |  |  | 11 | my $ctx = context(); | 
| 32 |  |  |  |  |  |  |  | 
| 33 | 4 | 100 |  |  |  | 358 | unless ( $thing->$_isa('PDL') ) { | 
| 34 | 2 |  |  |  |  | 24 | my $thingname = render_ref($thing); | 
| 35 | 2 |  |  |  |  | 60 | $ctx->fail( $name, "'$thingname' is not a piddle." ); | 
| 36 | 2 |  |  |  |  | 556 | $ctx->release; | 
| 37 | 2 |  |  |  |  | 56 | return 0; | 
| 38 |  |  |  |  |  |  | } | 
| 39 |  |  |  |  |  |  |  | 
| 40 | 2 |  |  |  |  | 50 | $ctx->ok( 1, $name ); | 
| 41 | 2 |  |  |  |  | 215 | $ctx->release; | 
| 42 | 2 |  |  |  |  | 67 | return 1; | 
| 43 |  |  |  |  |  |  | } | 
| 44 |  |  |  |  |  |  |  | 
| 45 |  |  |  |  |  |  |  | 
| 46 |  |  |  |  |  |  | sub pdl_is { | 
| 47 | 14 |  |  | 14 | 1 | 41409 | my ( $got, $exp, $name, @diag ) = @_; | 
| 48 | 14 |  |  |  |  | 40 | my $ctx = context(); | 
| 49 |  |  |  |  |  |  |  | 
| 50 | 14 |  |  |  |  | 1302 | my $gotname = render_ref($got); | 
| 51 | 14 | 100 |  |  |  | 426 | unless ( $got->$_isa('PDL') ) { | 
| 52 | 2 |  |  |  |  | 29 | $ctx->fail( $name, "First argument '$gotname' is not a piddle." ); | 
| 53 | 2 |  |  |  |  | 372 | $ctx->release; | 
| 54 | 2 |  |  |  |  | 52 | return 0; | 
| 55 |  |  |  |  |  |  | } | 
| 56 | 12 | 50 |  |  |  | 186 | 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 |  |  |  |  | 139 | my $exp_class = ref($exp); | 
| 64 | 12 | 50 |  |  |  | 35 | 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 |  |  |  |  | 37 | my @exp_dims   = $exp->dims; | 
| 73 | 12 |  |  |  |  | 330 | my @got_dims   = $got->dims; | 
| 74 | 12 |  |  |  |  | 228 | my $delta_dims = compare( \@got_dims, \@exp_dims, \&strict_convert ); | 
| 75 |  |  |  |  |  |  |  | 
| 76 | 12 | 100 |  |  |  | 4371 | if ($delta_dims) { | 
| 77 | 2 |  |  |  |  | 9 | $ctx->fail( $name, 'Dimensions do not match', $delta_dims->diag, | 
| 78 |  |  |  |  |  |  | @diag ); | 
| 79 | 2 |  |  |  |  | 10991 | $ctx->release; | 
| 80 | 2 |  |  |  |  | 73 | return 0; | 
| 81 |  |  |  |  |  |  | } | 
| 82 |  |  |  |  |  |  |  | 
| 83 |  |  |  |  |  |  | # compare isbad | 
| 84 | 10 |  |  |  |  | 18 | my $both_bad; | 
| 85 | 10 | 100 | 66 |  |  | 72 | if ( $got->badflag or $exp->badflag ) { | 
| 86 | 3 |  |  |  |  | 62 | my $delta_isbad = | 
| 87 |  |  |  |  |  |  | compare( $got->isbad->unpdl, $exp->isbad->unpdl, \&strict_convert ); | 
| 88 |  |  |  |  |  |  |  | 
| 89 | 3 | 100 |  |  |  | 3472 | if ($delta_isbad) { | 
| 90 | 1 |  |  |  |  | 6 | $ctx->fail( $name, 'Bad value patterns do not match', | 
| 91 |  |  |  |  |  |  | $delta_isbad->diag, @diag ); | 
| 92 | 1 |  |  |  |  | 4395 | $ctx->release; | 
| 93 | 1 |  |  |  |  | 37 | return 0; | 
| 94 |  |  |  |  |  |  | } | 
| 95 |  |  |  |  |  |  |  | 
| 96 | 2 |  |  |  |  | 49 | $both_bad = ( $got->isbad & $exp->isbad ); | 
| 97 |  |  |  |  |  |  | } | 
| 98 |  |  |  |  |  |  |  | 
| 99 |  |  |  |  |  |  | # Compare data values. | 
| 100 | 9 |  |  |  |  | 24 | my $diff; | 
| 101 |  |  |  |  |  |  | my $is_numeric = !( | 
| 102 | 27 |  |  | 27 |  | 270 | List::Util::any { $exp->$_isa($_) } | 
| 103 | 9 |  | 33 |  |  | 57 | qw(PDL::SV PDL::Factor PDL::DateTime) or $exp->type eq 'byte' | 
| 104 |  |  |  |  |  |  | ); | 
| 105 | 9 |  |  |  |  | 686 | eval { | 
| 106 | 9 | 50 | 33 |  |  | 42 | if ( $is_numeric | 
|  |  |  | 33 |  |  |  |  | 
| 107 |  |  |  |  |  |  | and ( $exp->type >= PDL::float or $got->type >= PDL::float ) ) | 
| 108 |  |  |  |  |  |  | { | 
| 109 | 9 |  |  |  |  | 952 | $diff = ( ( $got - $exp )->abs > | 
| 110 |  |  |  |  |  |  | $TOLERANCE + ( $TOLERANCE_REL * $exp )->abs ); | 
| 111 |  |  |  |  |  |  | } | 
| 112 |  |  |  |  |  |  | else { | 
| 113 | 0 |  |  |  |  | 0 | $diff = ( $got != $exp ); | 
| 114 |  |  |  |  |  |  | } | 
| 115 | 9 | 100 |  |  |  | 135 | if ( $exp->badflag ) { | 
| 116 | 2 |  |  |  |  | 24 | $diff->where( $exp->isbad ) .= 0; | 
| 117 |  |  |  |  |  |  | } | 
| 118 |  |  |  |  |  |  | }; | 
| 119 | 9 | 50 |  |  |  | 241 | 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 |  |  |  |  | 35 | my $diff_which = which($diff); | 
| 127 | 9 | 100 |  |  |  | 390 | unless ( $diff_which->isempty ) { | 
| 128 |  |  |  |  |  |  | state $at = sub { | 
| 129 | 6 |  |  | 6 |  | 223 | my ( $p, @position ) = @_; | 
| 130 | 6 | 50 |  |  |  | 29 | if ( $p->isa('PDL::DateTime') ) { | 
| 131 | 0 |  |  |  |  | 0 | return $p->dt_at(@position); | 
| 132 |  |  |  |  |  |  | } | 
| 133 |  |  |  |  |  |  | else { | 
| 134 | 6 |  |  |  |  | 15 | return $p->at(@position); | 
| 135 |  |  |  |  |  |  | } | 
| 136 | 2 |  |  |  |  | 25 | }; | 
| 137 |  |  |  |  |  |  |  | 
| 138 | 2 |  |  |  |  | 18 | 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 |  |  |  |  | 108 | my @position = $exp->one2nd($_); | 
| 147 |  |  |  |  |  |  | [ | 
| 148 | 3 |  |  |  |  | 671 | join( ',', @position ), | 
| 149 |  |  |  |  |  |  | $at->( $got, @position ), | 
| 150 |  |  |  |  |  |  | $at->( $exp, @position ) | 
| 151 |  |  |  |  |  |  | ] | 
| 152 | 2 |  |  |  |  | 104 | } @{ $diff_which->unpdl } | 
|  | 2 |  |  |  |  | 11 |  | 
| 153 |  |  |  |  |  |  | ] | 
| 154 |  |  |  |  |  |  | ); | 
| 155 | 2 |  |  |  |  | 6383 | $ctx->fail( $name, "Values do not match.", join( "\n", @table ), | 
| 156 |  |  |  |  |  |  | @diag ); | 
| 157 | 2 |  |  |  |  | 476 | $ctx->release; | 
| 158 | 2 |  |  |  |  | 67 | return 0; | 
| 159 |  |  |  |  |  |  | } | 
| 160 |  |  |  |  |  |  |  | 
| 161 | 7 |  |  |  |  | 75 | $ctx->ok( 1, $name ); | 
| 162 | 7 |  |  |  |  | 572 | $ctx->release; | 
| 163 | 7 |  |  |  |  | 228 | return 1; | 
| 164 |  |  |  |  |  |  | } | 
| 165 |  |  |  |  |  |  |  | 
| 166 |  |  |  |  |  |  | 1; | 
| 167 |  |  |  |  |  |  |  | 
| 168 |  |  |  |  |  |  | __END__ |