File Coverage

blib/lib/Test/Deep/Set.pm
Criterion Covered Total %
statement 88 88 100.0
branch 42 46 91.3
condition 15 15 100.0
subroutine 9 9 100.0
pod 0 6 0.0
total 154 164 93.9


line stmt bran cond sub pod time code
1 4     4   32 use strict;
  4         10  
  4         181  
2 4     4   21 use warnings;
  4         10  
  4         345  
3              
4             package Test::Deep::Set 1.205;
5              
6 4     4   1277 use Test::Deep::Cmp;
  4         10  
  4         27  
7              
8             sub init
9             {
10 84     84 0 158 my $self = shift;
11              
12 84         421 $self->{IgnoreDupes} = shift;
13 84         196 $self->{SubSup} = shift;
14              
15 84         218 $self->{val} = [];
16              
17 84         260 $self->add(@_);
18             }
19              
20             sub descend
21             {
22 92     92 0 155 my $self = shift;
23 92         140 my $d1 = shift;
24              
25 92         195 my $d2 = $self->{val};
26              
27 92         187 my $IgnoreDupes = $self->{IgnoreDupes};
28              
29 92         404 my $data = $self->data;
30              
31 92         203 my $SubSup = $self->{SubSup};
32              
33 92 100       909 my $type = $IgnoreDupes ? "Set" : "Bag";
34              
35 92         145 my $diag;
36              
37 92 100       261 if (ref $d1 ne 'ARRAY')
38             {
39 25         79 my $got = Test::Deep::render_val($d1);
40 25         74 $diag = <
41             got : $got
42             expect : An array to use as a $type
43             EOM
44             }
45              
46 92 100       219 if (not $diag)
47             {
48 67         219 my @got = @$d1;
49 67         137 my @found;
50             my @missing;
51 67         151 foreach my $expect (@$d2)
52             {
53 185         302 my $found = 0;
54              
55 185         560 for (my $i = $#got; $i >= 0; $i--)
56             {
57 425 100       1150 if (Test::Deep::eq_deeply_cache($got[$i], $expect))
58             {
59 144         254 $found = 1;
60 144         2017 push(@found, $expect);
61 144         308 splice(@got, $i, 1);
62              
63 144 100       427 last unless $IgnoreDupes;
64             }
65             }
66              
67 185 100       602 push(@missing, $expect) unless $found;
68             }
69              
70 67         145 my @diags;
71 67 100 100     353 if (@missing and $SubSup ne "sub" && $SubSup ne "none")
      100        
72             {
73 22         107 push(@diags, "Missing: ".nice_list(\@missing));
74             }
75              
76 67 100 100     284 if (@got and $SubSup ne "sup" && $SubSup ne "none")
      100        
77             {
78 26         191 my $got = __PACKAGE__->new($IgnoreDupes, "", @got);
79 26         108 push(@diags, "Extra: ".nice_list($got->{val}));
80             }
81              
82 67 100 100     294 if (@found and $SubSup eq "none")
83             {
84 2         10 my $found = __PACKAGE__->new($IgnoreDupes, "", @found);
85 2         10 push(@diags, "Extra: ".nice_list($found->{val}));
86             }
87              
88 67         272 $diag = join("\n", @diags);
89             }
90              
91 92 100       208 if ($diag)
92             {
93 58         152 $data->{diag} = $diag;
94              
95 58         210 return 0;
96             }
97             else
98             {
99 34         182 return 1;
100             }
101             }
102              
103             sub diagnostics
104             {
105 23     23 0 48 my $self = shift;
106 23         56 my ($where, $last) = @_;
107              
108 23 100       78 my $type = $self->{IgnoreDupes} ? "Set" : "Bag";
109 23 100       91 $type = "Sub$type" if $self->{SubSup} eq "sub";
110 23 100       68 $type = "Super$type" if $self->{SubSup} eq "sup";
111 23 100       74 $type = "NoneOf" if $self->{SubSup} eq "none";
112              
113 23         51 my $error = $last->{diag};
114 23         80 my $diag = <
115             Comparing $where as a $type
116             $error
117             EOM
118              
119 23         64 return $diag;
120             }
121              
122             sub add
123             {
124             # this takes an array.
125              
126             # For each element A of the array, it looks for an element, B, already in
127             # the set which are deeply equal to A. If no matching B is found then A is
128             # added to the set. If a B is found and IgnoreDupes is true, then A will
129             # be discarded, if IgnoreDupes is false, then B will be added to the set
130             # again.
131            
132 90     90 0 11381 my $self = shift;
133              
134 90         289 my @array = @_;
135              
136 90         213 my $IgnoreDupes = $self->{IgnoreDupes};
137              
138 90         161 my $already = $self->{val};
139              
140 90         158 local $Test::Deep::Expects = 1;
141 90         206 foreach my $new_elem (@array)
142             {
143 230         377 my $want_push = 1;
144 230         381 my $push_this = $new_elem;
145 230         458 foreach my $old_elem (@$already)
146             {
147 231 100       607 if (Test::Deep::eq_deeply($new_elem, $old_elem))
148             {
149 56         99 $push_this = $old_elem;
150 56         105 $want_push = ! $IgnoreDupes;
151 56         135 last;
152             }
153             }
154 230 100       925 push(@$already, $push_this) if $want_push;
155             }
156              
157             # so we can compare 2 Test::Deep::Set objects using array comparison
158              
159 90 100       417 @$already = sort {(defined $a ? $a : "") cmp (defined $b ? $b : "")} @$already;
  187 50       900  
160             }
161              
162             sub nice_list
163             {
164 50     50 0 117 my $list = shift;
165              
166 50         199 my @scalars = grep ! ref $_, @$list;
167 50         126 my $refs = grep ref $_, @$list;
168              
169 50 100       176 my @ref_string = "$refs reference" if $refs;
170 50 100       123 $ref_string[0] .= "s" if $refs > 1;
171              
172             # sort them so we can predict the diagnostic output
173              
174             return join(", ",
175 50 50       161 (map {Test::Deep::render_val($_)} sort {(defined $a ? $a : "") cmp (defined $b ? $b : "")} @scalars),
  82 50       209  
  49         167  
176             @ref_string
177             );
178             }
179              
180             sub compare
181             {
182 14     14 0 27 my $self = shift;
183              
184 14         23 my $other = shift;
185              
186 14 50       54 return 0 if $self->{IgnoreDupes} != $other->{IgnoreDupes};
187              
188             # this works (kind of) because the arrays are sorted
189              
190 14         49 return Test::Deep::descend($self->{val}, $other->{val});
191             }
192              
193             1;
194              
195             __END__