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   1189 use strict;
  100         187  
  100         2746  
3 100     100   484 use warnings;
  100         199  
  100         2585  
4              
5 100     100   503 use Test::Stream::Compare;
  100         332  
  100         644  
6             use Test::Stream::HashBase(
7 100         778 base => 'Test::Stream::Compare',
8             accessors => [qw/inref ending items order/],
9 100     100   549 );
  100         206  
10              
11 100     100   558 use Carp qw/croak confess/;
  100         181  
  100         5657  
12 100     100   518 use Scalar::Util qw/reftype looks_like_number/;
  100         188  
  100         104312  
13              
14             sub init {
15 912     912 0 1828 my $self = shift;
16              
17 912 100       2766 if(my $ref = $self->{+INREF}) {
18 698 100       2004 croak "Cannot specify both 'inref' and 'items'" if $self->{+ITEMS};
19 697 100       1763 croak "Cannot specify both 'inref' and 'order'" if $self->{+ORDER};
20 696 100       2563 croak "'inref' must be an array reference, got '$ref'" unless reftype($ref) eq 'ARRAY';
21 695         1593 my $order = $self->{+ORDER} = [];
22 695         1495 my $items = $self->{+ITEMS} = {};
23 695         2210 for (my $i = 0; $i < @$ref; $i++) {
24 1431         2394 push @$order => $i;
25 1431         5349 $items->{$i} = $ref->[$i];
26             }
27             }
28             else {
29 214   100     1114 $self->{+ITEMS} ||= {};
30             croak "All indexes listed in the 'items' hashref must be numeric"
31 214 100       332 if grep { !looks_like_number($_) } keys %{$self->{+ITEMS}};
  7         221  
  214         894  
32              
33 213   100     748 $self->{+ORDER} ||= [sort { $a <=> $b } keys %{$self->{+ITEMS}}];
  1         7  
  211         808  
34             croak "All indexes listed in the 'order' arrayref must be numeric"
35 213 100 66     326 if grep { !(looks_like_number($_) || (ref($_) && reftype($_) eq 'CODE')) } @{$self->{+ORDER}};
  7         158  
  213         693  
36             }
37              
38 907         3179 $self->SUPER::init();
39             }
40              
41 16     16 1 60 sub name { '' }
42              
43             sub verify {
44 907     907 1 1348 my $self = shift;
45 907         2891 my %params = @_;
46              
47 907 100       2295 return 0 unless $params{exists};
48 906   100     2229 my $got = $params{got} || return 0;
49 903 100       2176 return 0 unless ref($got);
50 899 100       3100 return 0 unless reftype($got) eq 'ARRAY';
51 896         3188 return 1;
52             }
53              
54             sub top_index {
55 494     494 1 732 my $self = shift;
56 494         589 my @order = @{$self->{+ORDER}};
  494         1200  
57              
58 494         1481 while(@order) {
59 303         471 my $idx = pop @order;
60 303 100       705 next if ref $idx;
61 298         649 return $idx;
62             }
63              
64 196         395 return undef; # No indexes
65             }
66              
67             sub add_item {
68 489     489 1 710 my $self = shift;
69 489         650 my $check = pop;
70 489         732 my ($idx) = @_;
71              
72 489         1020 my $top = $self->top_index;
73              
74 489 100 100     1955 croak "elements must be added in order!"
      100        
75             if $top && $idx && $idx <= $top;
76              
77 488 100       1573 $idx = defined($top) ? $top + 1 : 0
    100          
78             unless defined($idx);
79              
80 488         625 push @{$self->{+ORDER}} => $idx;
  488         1062  
81 488         2151 $self->{+ITEMS}->{$idx} = $check;
82             }
83              
84             sub add_filter {
85 9     9 1 47 my $self = shift;
86 9         16 my ($code) = @_;
87 9 100 100     625 croak "A single coderef is required"
      100        
      100        
88             unless @_ == 1 && $code && ref $code && reftype($code) eq 'CODE';
89              
90 4         8 push @{$self->{+ORDER}} => $code;
  4         16  
91             }
92              
93             sub deltas {
94 902     902 1 1325 my $self = shift;
95 902         2674 my %params = @_;
96 902         2069 my ($got, $convert, $seen) = @params{qw/got convert seen/};
97              
98 902         1524 my @deltas;
99 902         1691 my $state = 0;
100 902         1160 my @order = @{$self->{+ORDER}};
  902         2588  
101 902         1585 my $items = $self->{+ITEMS};
102              
103             # Make a copy that we can munge as needed.
104 902         1922 my @list = @$got;
105              
106 902         2320 while (@order) {
107 1947         2966 my $idx = shift @order;
108 1947         2770 my $overflow = 0;
109 1947         3000 my $val;
110              
111             # We have a filter, not an index
112 1947 100       4212 if (ref($idx)) {
113 5         21 @list = $idx->(@list);
114 5         82 next;
115             }
116              
117 1942 50       4566 confess "Internal Error: Stacks are out of sync (state > idx)"
118             if $state > $idx + 1;
119              
120 1942         4396 while ($state <= $idx) {
121 1948         2355 $state++;
122 1948         3018 $overflow = !@list;
123 1948         5238 $val = shift @list;
124             }
125              
126 1942 50       4295 confess "Internal Error: Stacks are out of sync (state != idx + 1)"
127             unless $state == $idx + 1;
128              
129 1942         6167 my $check = $convert->($items->{$idx});
130              
131 1942 100       10795 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     4429 if($self->{+ENDING} && @list) {
142 3         14 while (@list) {
143 4         8 my $item = shift @list;
144 4         21 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         3660 return @deltas;
155             }
156              
157             1;
158              
159             __END__