File Coverage

blib/lib/Test2/Compare/Array.pm
Criterion Covered Total %
statement 117 117 100.0
branch 45 48 93.7
condition 29 30 96.6
subroutine 16 16 100.0
pod 6 10 60.0
total 213 221 96.3


line stmt bran cond sub pod time code
1             package Test2::Compare::Array;
2 169     169   1233 use strict;
  169         322  
  169         5000  
3 169     169   861 use warnings;
  169         347  
  169         4382  
4              
5 169     169   882 use base 'Test2::Compare::Base';
  169         361  
  169         73181  
6              
7             our $VERSION = '0.000155';
8              
9 169     169   1193 use Test2::Util::HashBase qw/inref meta ending items order for_each/;
  169         344  
  169         796  
10              
11 169     169   51179 use Carp qw/croak confess/;
  169         352  
  169         8534  
12 169     169   962 use Scalar::Util qw/reftype looks_like_number/;
  169         364  
  169         171580  
13              
14             sub init {
15 1079     1079 0 18666 my $self = shift;
16              
17 1079 100       3378 if( defined( my $ref = $self->{+INREF}) ) {
18 431 100       1220 croak "Cannot specify both 'inref' and 'items'" if $self->{+ITEMS};
19 430 100       1051 croak "Cannot specify both 'inref' and 'order'" if $self->{+ORDER};
20 429 100       1458 croak "'inref' must be an array reference, got '$ref'" unless reftype($ref) eq 'ARRAY';
21 428         992 my $order = $self->{+ORDER} = [];
22 428         947 my $items = $self->{+ITEMS} = {};
23 428         1311 for (my $i = 0; $i < @$ref; $i++) {
24 1124         1929 push @$order => $i;
25 1124         3187 $items->{$i} = $ref->[$i];
26             }
27             }
28             else {
29 648   100     4147 $self->{+ITEMS} ||= {};
30             croak "All indexes listed in the 'items' hashref must be numeric"
31 648 100       1243 if grep { !looks_like_number($_) } keys %{$self->{+ITEMS}};
  7         276  
  648         3102  
32              
33 647   100     3087 $self->{+ORDER} ||= [sort { $a <=> $b } keys %{$self->{+ITEMS}}];
  1         7  
  645         2891  
34             croak "All indexes listed in the 'order' arrayref must be numeric"
35 647 100 100     1064 if grep { !(looks_like_number($_) || (ref($_) && reftype($_) eq 'CODE')) } @{$self->{+ORDER}};
  7         149  
  647         1918  
36             }
37              
38 1074   50     5662 $self->{+FOR_EACH} ||= [];
39              
40 1074         4961 $self->SUPER::init();
41             }
42              
43 21     21 1 75 sub name { '' }
44              
45 3     3 0 18 sub meta_class { 'Test2::Compare::Meta' }
46              
47             sub verify {
48 1075     1075 1 1995 my $self = shift;
49 1075         3721 my %params = @_;
50              
51 1075 100       2793 return 0 unless $params{exists};
52 1072         1913 my $got = $params{got};
53 1072 100       2241 return 0 unless defined $got;
54 1070 100       2510 return 0 unless ref($got);
55 1065 100       3232 return 0 unless reftype($got) eq 'ARRAY';
56 1057         3239 return 1;
57             }
58              
59             sub add_prop {
60 4     4 0 56 my $self = shift;
61 4 100       28 $self->{+META} = $self->meta_class->new unless defined $self->{+META};
62 4         45 $self->{+META}->add_prop(@_);
63             }
64              
65             sub top_index {
66 2315     2315 1 3359 my $self = shift;
67 2315         3537 my @order = @{$self->{+ORDER}};
  2315         6231  
68              
69 2315         5508 while(@order) {
70 1703         3243 my $idx = pop @order;
71 1703 100       3910 next if ref $idx;
72 1686         3713 return $idx;
73             }
74              
75 629         1345 return undef; # No indexes
76             }
77              
78             sub add_item {
79 2310     2310 1 3965 my $self = shift;
80 2310         3550 my $check = pop;
81 2310         4121 my ($idx) = @_;
82              
83 2310         4499 my $top = $self->top_index;
84              
85 2310 100 100     7784 croak "elements must be added in order!"
      100        
86             if $top && $idx && $idx <= $top;
87              
88 2309 100       6705 $idx = defined($top) ? $top + 1 : 0
    100          
89             unless defined($idx);
90              
91 2309         3263 push @{$self->{+ORDER}} => $idx;
  2309         4702  
92 2309         9841 $self->{+ITEMS}->{$idx} = $check;
93             }
94              
95             sub add_filter {
96 22     22 1 110 my $self = shift;
97 22         52 my ($code) = @_;
98 22 100 100     936 croak "A single coderef is required"
      100        
      100        
99             unless @_ == 1 && $code && ref $code && reftype($code) eq 'CODE';
100              
101 17         46 push @{$self->{+ORDER}} => $code;
  17         70  
102             }
103              
104             sub add_for_each {
105 3     3 0 7 my $self = shift;
106 3         8 push @{$self->{+FOR_EACH}} => @_;
  3         12  
107             }
108              
109             sub deltas {
110 1063     1063 1 2034 my $self = shift;
111 1063         2900 my %params = @_;
112 1063         2782 my ($got, $convert, $seen) = @params{qw/got convert seen/};
113              
114 1063         1658 my @deltas;
115 1063         1908 my $state = 0;
116 1063         1719 my @order = @{$self->{+ORDER}};
  1063         3364  
117 1063         2344 my $items = $self->{+ITEMS};
118 1063         1692 my $for_each = $self->{+FOR_EACH};
119              
120 1063         1782 my $meta = $self->{+META};
121 1063 100       2399 push @deltas => $meta->deltas(%params) if defined $meta;
122              
123             # Make a copy that we can munge as needed.
124 1063         2948 my @list = @$got;
125              
126 1063         3476 while (@order) {
127 3469         6502 my $idx = shift @order;
128 3469         5530 my $overflow = 0;
129 3469         5216 my $val;
130              
131             # We have a filter, not an index
132 3469 100       7094 if (ref($idx)) {
133 18         84 @list = $idx->(@list);
134 18         369 next;
135             }
136              
137 3451 50       7088 confess "Internal Error: Stacks are out of sync (state > idx)"
138             if $state > $idx + 1;
139              
140 3451         7335 while ($state <= $idx) {
141 3455         6030 $overflow = !@list;
142 3455         5234 $val = shift @list;
143              
144             # check-all goes here so we hit each item, even unspecified ones.
145 3455         7291 for my $check (@$for_each) {
146 4         10 $check = $convert->($check);
147 4 50       26 push @deltas => $check->run(
148             id => [ARRAY => $state],
149             convert => $convert,
150             seen => $seen,
151             exists => !$overflow,
152             $overflow ? () : (got => $val),
153             );
154             }
155              
156 3455         7049 $state++;
157             }
158              
159 3451 50       7405 confess "Internal Error: Stacks are out of sync (state != idx + 1)"
160             unless $state == $idx + 1;
161              
162 3451         9702 my $check = $convert->($items->{$idx});
163              
164 3451 100       21811 push @deltas => $check->run(
165             id => [ARRAY => $idx],
166             convert => $convert,
167             seen => $seen,
168             exists => !$overflow,
169             $overflow ? () : (got => $val),
170             );
171             }
172              
173 1063   100     3583 while (@list && (@$for_each || $self->{+ENDING})) {
      100        
174 8         57 my $item = shift @list;
175              
176 8         35 for my $check (@$for_each) {
177 2         7 $check = $convert->($check);
178 2         23 push @deltas => $check->run(
179             id => [ARRAY => $state],
180             convert => $convert,
181             seen => $seen,
182             got => $item,
183             exists => 1,
184             );
185             }
186              
187             # if items are left over, and ending is true, we have a problem!
188 8 100       42 if ($self->{+ENDING}) {
189             push @deltas => $self->delta_class->new(
190             dne => 'check',
191             verified => undef,
192             id => [ARRAY => $state],
193             got => $item,
194             check => undef,
195              
196 7 100       31 $self->{+ENDING} eq 'implicit' ? (note => 'implicit end') : (),
197             );
198             }
199              
200 8         39 $state++;
201             }
202              
203 1063         3530 return @deltas;
204             }
205              
206             1;
207              
208             __END__