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   30 use strict;
  4         9  
  4         125  
2 4     4   20 use warnings;
  4         7  
  4         174  
3              
4             package Test::Deep::Set 1.202;
5              
6 4     4   930 use Test::Deep::Cmp;
  4         8  
  4         20  
7              
8             sub init
9             {
10 82     82 0 169 my $self = shift;
11              
12 82         298 $self->{IgnoreDupes} = shift;
13 82         137 $self->{SubSup} = shift;
14              
15 82         153 $self->{val} = [];
16              
17 82         189 $self->add(@_);
18             }
19              
20             sub descend
21             {
22 90     90 0 134 my $self = shift;
23 90         124 my $d1 = shift;
24              
25 90         148 my $d2 = $self->{val};
26              
27 90         134 my $IgnoreDupes = $self->{IgnoreDupes};
28              
29 90         195 my $data = $self->data;
30              
31 90         160 my $SubSup = $self->{SubSup};
32              
33 90 100       172 my $type = $IgnoreDupes ? "Set" : "Bag";
34              
35 90         140 my $diag;
36              
37 90 100       209 if (ref $d1 ne 'ARRAY')
38             {
39 25         60 my $got = Test::Deep::render_val($d1);
40 25         64 $diag = <
41             got : $got
42             expect : An array to use as a $type
43             EOM
44             }
45              
46 90 100       171 if (not $diag)
47             {
48 65         164 my @got = @$d1;
49 65         114 my @found;
50             my @missing;
51 65         115 foreach my $expect (@$d2)
52             {
53 179         238 my $found = 0;
54              
55 179         383 for (my $i = $#got; $i >= 0; $i--)
56             {
57 411 100       902 if (Test::Deep::eq_deeply_cache($got[$i], $expect))
58             {
59 142         192 $found = 1;
60 142         237 push(@found, $expect);
61 142         220 splice(@got, $i, 1);
62              
63 142 100       363 last unless $IgnoreDupes;
64             }
65             }
66              
67 179 100       435 push(@missing, $expect) unless $found;
68             }
69              
70 65         100 my @diags;
71 65 100 100     203 if (@missing and $SubSup ne "sub" && $SubSup ne "none")
      100        
72             {
73 20         63 push(@diags, "Missing: ".nice_list(\@missing));
74             }
75              
76 65 100 100     246 if (@got and $SubSup ne "sup" && $SubSup ne "none")
      100        
77             {
78 24         77 my $got = __PACKAGE__->new($IgnoreDupes, "", @got);
79 24         73 push(@diags, "Extra: ".nice_list($got->{val}));
80             }
81              
82 65 100 100     230 if (@found and $SubSup eq "none")
83             {
84 2         12 my $found = __PACKAGE__->new($IgnoreDupes, "", @found);
85 2         9 push(@diags, "Extra: ".nice_list($found->{val}));
86             }
87              
88 65         192 $diag = join("\n", @diags);
89             }
90              
91 90 100       164 if ($diag)
92             {
93 56         105 $data->{diag} = $diag;
94              
95 56         151 return 0;
96             }
97             else
98             {
99 34         89 return 1;
100             }
101             }
102              
103             sub diagnostics
104             {
105 23     23 0 42 my $self = shift;
106 23         54 my ($where, $last) = @_;
107              
108 23 100       64 my $type = $self->{IgnoreDupes} ? "Set" : "Bag";
109 23 100       71 $type = "Sub$type" if $self->{SubSup} eq "sub";
110 23 100       61 $type = "Super$type" if $self->{SubSup} eq "sup";
111 23 100       57 $type = "NoneOf" if $self->{SubSup} eq "none";
112              
113 23         41 my $error = $last->{diag};
114 23         82 my $diag = <
115             Comparing $where as a $type
116             $error
117             EOM
118              
119 23         56 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 88     88 0 5876 my $self = shift;
133              
134 88         187 my @array = @_;
135              
136 88         147 my $IgnoreDupes = $self->{IgnoreDupes};
137              
138 88         126 my $already = $self->{val};
139              
140 88         140 local $Test::Deep::Expects = 1;
141 88         170 foreach my $new_elem (@array)
142             {
143 226         375 my $want_push = 1;
144 226         309 my $push_this = $new_elem;
145 226         352 foreach my $old_elem (@$already)
146             {
147 229 100       482 if (Test::Deep::eq_deeply($new_elem, $old_elem))
148             {
149 55         101 $push_this = $old_elem;
150 55         86 $want_push = ! $IgnoreDupes;
151 55         88 last;
152             }
153             }
154 226 100       621 push(@$already, $push_this) if $want_push;
155             }
156              
157             # so we can compare 2 Test::Deep::Set objects using array comparison
158              
159 88 100       309 @$already = sort {(defined $a ? $a : "") cmp (defined $b ? $b : "")} @$already;
  183 50       689  
160             }
161              
162             sub nice_list
163             {
164 46     46 0 78 my $list = shift;
165              
166 46         185 my @scalars = grep ! ref $_, @$list;
167 46         107 my $refs = grep ref $_, @$list;
168              
169 46 100       161 my @ref_string = "$refs reference" if $refs;
170 46 100       101 $ref_string[0] .= "s" if $refs > 1;
171              
172             # sort them so we can predict the diagnostic output
173              
174             return join(", ",
175 46 50       121 (map {Test::Deep::render_val($_)} sort {(defined $a ? $a : "") cmp (defined $b ? $b : "")} @scalars),
  74 50       145  
  43         115  
176             @ref_string
177             );
178             }
179              
180             sub compare
181             {
182 14     14 0 26 my $self = shift;
183              
184 14         20 my $other = shift;
185              
186 14 50       39 return 0 if $self->{IgnoreDupes} != $other->{IgnoreDupes};
187              
188             # this works (kind of) because the arrays are sorted
189              
190 14         38 return Test::Deep::descend($self->{val}, $other->{val});
191             }
192              
193             1;
194              
195             __END__