File Coverage

inc/Test/Deep/Set.pm
Criterion Covered Total %
statement 53 83 63.8
branch 14 42 33.3
condition 2 6 33.3
subroutine 6 9 66.6
pod 0 6 0.0
total 75 146 51.3


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