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   1267 use strict;
  100         188  
  100         2598  
3 100     100   505 use warnings;
  100         187  
  100         2594  
4              
5 100     100   513 use Test::Stream::Compare;
  100         400  
  100         677  
6             use Test::Stream::HashBase(
7 100         793 base => 'Test::Stream::Compare',
8             accessors => [qw/inref ending items order/],
9 100     100   562 );
  100         202  
10              
11 100     100   592 use Carp qw/croak confess/;
  100         181  
  100         5494  
12 100     100   515 use Scalar::Util qw/reftype looks_like_number/;
  100         205  
  100         104277  
13              
14             sub init {
15 912     912 0 1794 my $self = shift;
16              
17 912 100       2536 if(my $ref = $self->{+INREF}) {
18 698 100       1772 croak "Cannot specify both 'inref' and 'items'" if $self->{+ITEMS};
19 697 100       1648 croak "Cannot specify both 'inref' and 'order'" if $self->{+ORDER};
20 696 100       2507 croak "'inref' must be an array reference, got '$ref'" unless reftype($ref) eq 'ARRAY';
21 695         1532 my $order = $self->{+ORDER} = [];
22 695         1403 my $items = $self->{+ITEMS} = {};
23 695         2129 for (my $i = 0; $i < @$ref; $i++) {
24 1431         2276 push @$order => $i;
25 1431         5206 $items->{$i} = $ref->[$i];
26             }
27             }
28             else {
29 214   100     1178 $self->{+ITEMS} ||= {};
30             croak "All indexes listed in the 'items' hashref must be numeric"
31 214 100       299 if grep { !looks_like_number($_) } keys %{$self->{+ITEMS}};
  7         226  
  214         878  
32              
33 213   100     818 $self->{+ORDER} ||= [sort { $a <=> $b } keys %{$self->{+ITEMS}}];
  1         11  
  211         820  
34             croak "All indexes listed in the 'order' arrayref must be numeric"
35 213 100 66     387 if grep { !(looks_like_number($_) || (ref($_) && reftype($_) eq 'CODE')) } @{$self->{+ORDER}};
  7         159  
  213         679  
36             }
37              
38 907         3036 $self->SUPER::init();
39             }
40              
41 16     16 1 58 sub name { '' }
42              
43             sub verify {
44 907     907 1 1438 my $self = shift;
45 907         2890 my %params = @_;
46              
47 907 100       2275 return 0 unless $params{exists};
48 906   100     2107 my $got = $params{got} || return 0;
49 903 100       2030 return 0 unless ref($got);
50 899 100       2962 return 0 unless reftype($got) eq 'ARRAY';
51 896         2977 return 1;
52             }
53              
54             sub top_index {
55 494     494 1 626 my $self = shift;
56 494         559 my @order = @{$self->{+ORDER}};
  494         1229  
57              
58 494         1206 while(@order) {
59 303         455 my $idx = pop @order;
60 303 100       689 next if ref $idx;
61 298         672 return $idx;
62             }
63              
64 196         376 return undef; # No indexes
65             }
66              
67             sub add_item {
68 489     489 1 665 my $self = shift;
69 489         650 my $check = pop;
70 489         676 my ($idx) = @_;
71              
72 489         1022 my $top = $self->top_index;
73              
74 489 100 100     2013 croak "elements must be added in order!"
      100        
75             if $top && $idx && $idx <= $top;
76              
77 488 100       1510 $idx = defined($top) ? $top + 1 : 0
    100          
78             unless defined($idx);
79              
80 488         575 push @{$self->{+ORDER}} => $idx;
  488         1031  
81 488         2138 $self->{+ITEMS}->{$idx} = $check;
82             }
83              
84             sub add_filter {
85 9     9 1 41 my $self = shift;
86 9         15 my ($code) = @_;
87 9 100 100     600 croak "A single coderef is required"
      100        
      100        
88             unless @_ == 1 && $code && ref $code && reftype($code) eq 'CODE';
89              
90 4         7 push @{$self->{+ORDER}} => $code;
  4         16  
91             }
92              
93             sub deltas {
94 902     902 1 1273 my $self = shift;
95 902         2649 my %params = @_;
96 902         1972 my ($got, $convert, $seen) = @params{qw/got convert seen/};
97              
98 902         1613 my @deltas;
99 902         1630 my $state = 0;
100 902         1131 my @order = @{$self->{+ORDER}};
  902         2474  
101 902         1488 my $items = $self->{+ITEMS};
102              
103             # Make a copy that we can munge as needed.
104 902         1882 my @list = @$got;
105              
106 902         2283 while (@order) {
107 1947         3092 my $idx = shift @order;
108 1947         2714 my $overflow = 0;
109 1947         2931 my $val;
110              
111             # We have a filter, not an index
112 1947 100       3997 if (ref($idx)) {
113 5         19 @list = $idx->(@list);
114 5         85 next;
115             }
116              
117 1942 50       4092 confess "Internal Error: Stacks are out of sync (state > idx)"
118             if $state > $idx + 1;
119              
120 1942         4257 while ($state <= $idx) {
121 1948         2247 $state++;
122 1948         2892 $overflow = !@list;
123 1948         5010 $val = shift @list;
124             }
125              
126 1942 50       4133 confess "Internal Error: Stacks are out of sync (state != idx + 1)"
127             unless $state == $idx + 1;
128              
129 1942         5921 my $check = $convert->($items->{$idx});
130              
131 1942 100       10507 push @deltas => $check->run(
132             id => [ARRAY => $idx],
133             convert => $convert,
134             seen => $seen,
135             exists => !$overflow,
136             $overflow ? () : (got => $val),
137             );
138             }
139              
140             # if items are left over, and ending is true, we have a problem!
141 902 100 100     4023 if($self->{+ENDING} && @list) {
142 3         14 while (@list) {
143 4         9 my $item = shift @list;
144 4         22 push @deltas => $self->delta_class->new(
145             dne => 'check',
146             verified => undef,
147             id => [ARRAY => $state++],
148             got => $item,
149             check => undef,
150             );
151             }
152             }
153              
154 902         3459 return @deltas;
155             }
156              
157             1;
158              
159             __END__