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