File Coverage

blib/lib/Test/Deep/UnorderedPairs.pm
Criterion Covered Total %
statement 73 75 97.3
branch 14 16 87.5
condition 1 2 50.0
subroutine 20 22 90.9
pod 3 3 100.0
total 111 118 94.0


line stmt bran cond sub pod time code
1 2     2   38232 use strict;
  2         2  
  2         46  
2 2     2   6 use warnings;
  2         2  
  2         89  
3             package Test::Deep::UnorderedPairs; # git description: v0.005-12-g8133cf6
4             # vim: set ts=8 sts=4 sw=4 tw=115 et :
5             # ABSTRACT: A Test::Deep plugin for comparing an unordered list of tuples
6             # KEYWORDS: testing tests plugin hash list tuples pairs unordered
7              
8             our $VERSION = '0.006';
9              
10 2     2   6 use Exporter 5.57 'import';
  2         26  
  2         215  
11              
12             # I'm not sure what name is best; decide later
13             our @EXPORT = qw(tuples unordered_pairs samehash);
14              
15             sub tuples
16             {
17 13     13 1 904 return Test::Deep::UnorderedPairs::Object->new('tuples', @_);
18             }
19             sub unordered_pairs
20             {
21 0     0 1 0 return Test::Deep::UnorderedPairs::Object->new('unordered_pairs', @_);
22             }
23             sub samehash
24             {
25 0     0 1 0 return Test::Deep::UnorderedPairs::Object->new('samehash', @_);
26             }
27              
28              
29             package # hide from PAUSE
30             Test::Deep::UnorderedPairs::Object;
31 2     2   732 use parent 'Test::Deep::Cmp';
  2         464  
  2         7  
32              
33             our $VERSION = '0.006';
34              
35 2     2   3287 use Carp ();
  2         3  
  2         35  
36 2     2   726 use Test::Deep::ArrayLength;
  2         1429  
  2         12  
37              
38             sub init
39             {
40 13     13   52 my ($self, $name, @vals) = @_;
41              
42 13   50     35 $name ||= 'tuples';
43 13 100       189 Carp::confess $name . ' must have an even number of elements'
44             if @vals % 2;
45              
46 12         86 $self->{name} = $name; # use in later diagnostic messages?
47 12         20 $self->{val} = \@vals;
48             }
49              
50             sub descend
51             {
52 12     12   16782 my ($self, $got) = @_;
53              
54 12         19 my $exp = $self->{val};
55              
56 12 100       37 return 0 unless Test::Deep::ArrayLength->new(@$exp + 0)->descend($got);
57              
58             # check that all the keys are present -- can test as a bag
59              
60 10         3930 my @exp_keys = _keys_of_list($exp);
61 10         15 my @got_keys = _keys_of_list($got);
62              
63 10 100       37 return 0 unless Test::Deep::descend(\@got_keys, Test::Deep::UnorderedPairKeys->new(@exp_keys));
64              
65 7         1958 Test::Deep::descend($got, Test::Deep::UnorderedPairElements->new($exp));
66             }
67              
68             sub _keys_of_list
69             {
70 21     21   29 my $list = shift;
71              
72 21         15 my $i = 0;
73 21 100       22 map { $i++ % 2 ? () : $_ } @$list;
  84         143  
74             }
75              
76              
77             package # hide from PAUSE
78             Test::Deep::UnorderedPairKeys;
79 2     2   399 use parent 'Test::Deep::Set';
  2         2  
  2         7  
80              
81             our $VERSION = '0.006';
82              
83             sub init
84             {
85             # quack like a bag
86 10     10   67 shift->SUPER::init(0, '', @_);
87             }
88              
89             sub diagnostics
90             {
91 3     3   2134 my ($self, $where, $last) = @_;
92              
93 3         5 my $error = $last->{diag};
94 3         8 my $diag = <
95             Comparing keys of $where
96             $error
97             EOM
98              
99 3         7 return $diag;
100             }
101              
102              
103             package # hide from PAUSE
104             Test::Deep::UnorderedPairElements;
105 2     2   2348 use parent 'Test::Deep::Cmp';
  2         3  
  2         14  
106              
107             our $VERSION = '0.006';
108              
109             sub init
110             {
111 7     7   28 my ($self, $val) = @_;
112 7         60 $self->{val} = $val;
113             }
114              
115             # we assume the keys are already verified as identical.
116             sub descend
117             {
118 7     7   393 my ($self, $got) = @_;
119              
120             # make copy, as we are going to modify this one!
121 7         8 my @exp = @{$self->{val}};
  7         14  
122 7         31 my $data = $self->data;
123              
124 7         61 GOT_KEY: for (my $got_index = 0; $got_index < @$got; $got_index += 1)
125             {
126             # find the first occurrence of $key in @exp
127 13         23 EXP_KEY: for (my $exp_index = 0; $exp_index < @exp; $exp_index += 1)
128             {
129 19 100       30 if (not Test::Deep::eq_deeply_cache($got->[$got_index], $exp[$exp_index]))
130             {
131             # advance to the next key position
132 6         353 ++$exp_index;
133 6         16 next;
134             }
135              
136             # found a matching key in got and exp
137              
138 13         490 $data->{got_index} = ++$got_index;
139 13         16 $data->{exp_value} = $exp[++$exp_index];
140              
141 13 100       22 if (Test::Deep::eq_deeply_cache($got->[$got_index], $data->{exp_value}))
142             {
143             # splice this out of the exp list and continue with the next key
144 10         357 splice(@exp, $exp_index - 1, 2);
145 10         25 next GOT_KEY;
146             }
147              
148             # values do not match - keep looking for another match unless there are no more!
149             }
150              
151             # got to the end of exp_keys, but still no matches found
152 3         196 return 0;
153             }
154              
155             # exhausted all got_keys. if everything matched, @exp would be empty
156 4 50       10 return @exp ? 0 : 1;
157             }
158              
159             sub render_stack
160             {
161 3     3   962 my ($self, $var, $data) = @_;
162 3 50       9 $var .= "->" unless $Test::Deep::Stack->incArrow;
163 3         39 $var .= '[' . $data->{got_index} . ']';
164              
165 3         4 return $var;
166             }
167              
168             sub reset_arrow
169             {
170 3     3   9 return 0;
171             }
172              
173             sub renderGot
174             {
175 3     3   54 my ($self, $got) = @_;
176 3         8 return $self->SUPER::renderGot($got->[$self->data->{got_index}]);
177             }
178              
179             sub renderExp
180             {
181 3     3   45 my $self = shift;
182 3         5 return $self->SUPER::renderGot($self->data->{exp_value});
183             }
184              
185             1;
186              
187             __END__