File Coverage

blib/lib/Test/Stream/Compare/Array.pm
Criterion Covered Total %
statement 98 98 100.0
branch 36 38 94.7
condition 26 27 96.3
subroutine 13 13 100.0
pod 6 7 85.7
total 179 183 97.8


line stmt bran cond sub pod time code
1             package Test::Stream::Compare::Array;
2 100     100   706 use strict;
  100         103  
  100         2323  
3 100     100   297 use warnings;
  100         107  
  100         2019  
4              
5 100     100   295 use base 'Test::Stream::Compare';
  100         115  
  100         7899  
6 100     100   361 use Test::Stream::HashBase accessors => [qw/inref ending items order/];
  100         105  
  100         595  
7              
8 100     100   418 use Carp qw/croak confess/;
  100         111  
  100         4173  
9 100     100   352 use Scalar::Util qw/reftype looks_like_number/;
  100         165  
  100         67069  
10              
11             sub init {
12 929     929 0 875 my $self = shift;
13              
14 929 100       1813 if(my $ref = $self->{+INREF}) {
15 714 100       1265 croak "Cannot specify both 'inref' and 'items'" if $self->{+ITEMS};
16 713 100       1180 croak "Cannot specify both 'inref' and 'order'" if $self->{+ORDER};
17 712 100       1705 croak "'inref' must be an array reference, got '$ref'" unless reftype($ref) eq 'ARRAY';
18 711         1013 my $order = $self->{+ORDER} = [];
19 711         1220 my $items = $self->{+ITEMS} = {};
20 711         1592 for (my $i = 0; $i < @$ref; $i++) {
21 1468         1479 push @$order => $i;
22 1468         3408 $items->{$i} = $ref->[$i];
23             }
24             }
25             else {
26 215   100     788 $self->{+ITEMS} ||= {};
27             croak "All indexes listed in the 'items' hashref must be numeric"
28 215 100       211 if grep { !looks_like_number($_) } keys %{$self->{+ITEMS}};
  7         170  
  215         673  
29              
30 214   100     512 $self->{+ORDER} ||= [sort { $a <=> $b } keys %{$self->{+ITEMS}}];
  1         4  
  212         611  
31             croak "All indexes listed in the 'order' arrayref must be numeric"
32 214 100 66     201 if grep { !(looks_like_number($_) || (ref($_) && reftype($_) eq 'CODE')) } @{$self->{+ORDER}};
  7         113  
  214         467  
33             }
34              
35 924         2098 $self->SUPER::init();
36             }
37              
38 16     16 1 37 sub name { '' }
39              
40             sub verify {
41 924     924 1 838 my $self = shift;
42 924         1761 my %params = @_;
43              
44 924 100       1589 return 0 unless $params{exists};
45 923   100     1529 my $got = $params{got} || return 0;
46 920 100       1441 return 0 unless ref($got);
47 916 100       2056 return 0 unless reftype($got) eq 'ARRAY';
48 913         1904 return 1;
49             }
50              
51             sub top_index {
52 504     504 1 408 my $self = shift;
53 504         370 my @order = @{$self->{+ORDER}};
  504         864  
54              
55 504         861 while(@order) {
56 312         326 my $idx = pop @order;
57 312 100       498 next if ref $idx;
58 307         474 return $idx;
59             }
60              
61 197         246 return undef; # No indexes
62             }
63              
64             sub add_item {
65 499     499 1 421 my $self = shift;
66 499         394 my $check = pop;
67 499         467 my ($idx) = @_;
68              
69 499         695 my $top = $self->top_index;
70              
71 499 100 100     1464 croak "elements must be added in order!"
      100        
72             if $top && $idx && $idx <= $top;
73              
74 498 100       1121 $idx = defined($top) ? $top + 1 : 0
    100          
75             unless defined($idx);
76              
77 498         375 push @{$self->{+ORDER}} => $idx;
  498         697  
78 498         1433 $self->{+ITEMS}->{$idx} = $check;
79             }
80              
81             sub add_filter {
82 9     9 1 36 my $self = shift;
83 9         13 my ($code) = @_;
84 9 100 100     441 croak "A single coderef is required"
      100        
      100        
85             unless @_ == 1 && $code && ref $code && reftype($code) eq 'CODE';
86              
87 4         7 push @{$self->{+ORDER}} => $code;
  4         14  
88             }
89              
90             sub deltas {
91 919     919 1 1399 my $self = shift;
92 919         1508 my %params = @_;
93 919         1295 my ($got, $convert, $seen) = @params{qw/got convert seen/};
94              
95 919         715 my @deltas;
96 919         770 my $state = 0;
97 919         728 my @order = @{$self->{+ORDER}};
  919         1678  
98 919         920 my $items = $self->{+ITEMS};
99              
100             # Make a copy that we can munge as needed.
101 919         1271 my @list = @$got;
102              
103 919         1549 while (@order) {
104 1994         1959 my $idx = shift @order;
105 1994         1609 my $overflow = 0;
106 1994         1301 my $val;
107              
108             # We have a filter, not an index
109 1994 100       2729 if (ref($idx)) {
110 5         16 @list = $idx->(@list);
111 5         69 next;
112             }
113              
114 1989 50       3027 confess "Internal Error: Stacks are out of sync (state > idx)"
115             if $state > $idx + 1;
116              
117 1989         2882 while ($state <= $idx) {
118 1995         1378 $state++;
119 1995         1847 $overflow = !@list;
120 1995         3388 $val = shift @list;
121             }
122              
123 1989 50       2769 confess "Internal Error: Stacks are out of sync (state != idx + 1)"
124             unless $state == $idx + 1;
125              
126 1989         4189 my $check = $convert->($items->{$idx});
127              
128 1989 100       7274 push @deltas => $check->run(
129             id => [ARRAY => $idx],
130             convert => $convert,
131             seen => $seen,
132             exists => !$overflow,
133             $overflow ? () : (got => $val),
134             );
135             }
136              
137             # if items are left over, and ending is true, we have a problem!
138 919 100 100     2940 if($self->{+ENDING} && @list) {
139 3         8 while (@list) {
140 4         6 my $item = shift @list;
141 4         12 push @deltas => $self->delta_class->new(
142             dne => 'check',
143             verified => undef,
144             id => [ARRAY => $state++],
145             got => $item,
146             check => undef,
147             );
148             }
149             }
150              
151 919         2196 return @deltas;
152             }
153              
154             1;
155              
156             __END__