File Coverage

blib/lib/Test2/Tools/ClassicCompare.pm
Criterion Covered Total %
statement 164 179 91.6
branch 36 52 69.2
condition 4 12 33.3
subroutine 36 36 100.0
pod 6 10 60.0
total 246 289 85.1


line stmt bran cond sub pod time code
1             package Test2::Tools::ClassicCompare;
2 160     160   2103 use strict;
  160         374  
  160         4928  
3 160     160   817 use warnings;
  160         345  
  160         9147  
4              
5             our $VERSION = '0.000156';
6              
7             our @EXPORT = qw/is is_deeply isnt like unlike cmp_ok/;
8 160     160   1180 use base 'Exporter';
  160         614  
  160         17723  
9              
10 160     160   1583 use Carp qw/carp/;
  160         544  
  160         9529  
11 160     160   1269 use Scalar::Util qw/reftype/;
  160         600  
  160         10611  
12              
13 160     160   2640 use Test2::API qw/context/;
  160         158816  
  160         8127  
14 160     160   3421 use Test2::Compare qw/compare strict_convert/;
  160         383  
  160         8505  
15 160     160   1018 use Test2::Util::Ref qw/rtype render_ref/;
  160         408  
  160         8233  
16 160     160   3291 use Test2::Util::Table qw/table/;
  160         424  
  160         1551  
17              
18 160     160   3434 use Test2::Compare::Array();
  160         462  
  160         2415  
19 160     160   3029 use Test2::Compare::Bag();
  160         321  
  160         2375  
20 160     160   2859 use Test2::Compare::Custom();
  160         297  
  160         2798  
21 160     160   2851 use Test2::Compare::Event();
  160         328  
  160         3446  
22 160     160   3199 use Test2::Compare::Hash();
  160         353  
  160         3201  
23 160     160   1006 use Test2::Compare::Meta();
  160         354  
  160         3416  
24 160     160   3194 use Test2::Compare::Number();
  160         482  
  160         3085  
25 160     160   885 use Test2::Compare::Object();
  160         392  
  160         4283  
26 160     160   3083 use Test2::Compare::OrderedSubset();
  160         368  
  160         3412  
27 160     160   3105 use Test2::Compare::Pattern();
  160         397  
  160         2942  
28 160     160   3165 use Test2::Compare::Ref();
  160         363  
  160         3350  
29 160     160   2912 use Test2::Compare::Regex();
  160         362  
  160         3050  
30 160     160   2887 use Test2::Compare::Scalar();
  160         451  
  160         3247  
31 160     160   2911 use Test2::Compare::Set();
  160         428  
  160         4449  
32 160     160   3081 use Test2::Compare::String();
  160         346  
  160         3826  
33 160     160   3026 use Test2::Compare::Undef();
  160         396  
  160         2894  
34 160     160   2922 use Test2::Compare::Wildcard();
  160         330  
  160         239942  
35              
36             sub is($$;$@) {
37 7     7 1 429 my ($got, $exp, $name, @diag) = @_;
38 7         23 my $ctx = context();
39              
40 7         619 my @caller = caller;
41              
42 7         26 my $delta = compare($got, $exp, \&is_convert);
43              
44 7 100       31 if ($delta) {
45 3         10 $ctx->fail($name, $delta->diag, @diag);
46             }
47             else {
48 4         15 $ctx->ok(1, $name);
49             }
50              
51 7         1354 $ctx->release;
52 7         219 return !$delta;
53             }
54              
55             sub isnt($$;$@) {
56 4     4 1 48 my ($got, $exp, $name, @diag) = @_;
57 4         14 my $ctx = context();
58              
59 4         356 my @caller = caller;
60              
61 4         17 my $delta = compare($got, $exp, \&isnt_convert);
62              
63 4 100       16 if ($delta) {
64 1         5 $ctx->fail($name, $delta->diag, @diag);
65             }
66             else {
67 3         13 $ctx->ok(1, $name);
68             }
69              
70 4         645 $ctx->release;
71 4         119 return !$delta;
72             }
73              
74             sub is_convert {
75 7     7 0 14 my ($thing) = @_;
76 7 100       30 return Test2::Compare::Undef->new()
77             unless defined $thing;
78 5         30 return Test2::Compare::String->new(input => $thing);
79             }
80              
81             sub isnt_convert {
82 4     4 0 11 my ($thing) = @_;
83 4 50       13 return Test2::Compare::Undef->new()
84             unless defined $thing;
85 4         17 my $str = Test2::Compare::String->new(input => $thing, negate => 1);
86             }
87              
88             sub like($$;$@) {
89 4     4 1 43 my ($got, $exp, $name, @diag) = @_;
90 4         15 my $ctx = context();
91              
92 4         353 my $delta = compare($got, $exp, \&like_convert);
93              
94 4 100       17 if ($delta) {
95 1         6 $ctx->fail($name, $delta->diag, @diag);
96             }
97             else {
98 3         18 $ctx->ok(1, $name);
99             }
100              
101 4         632 $ctx->release;
102 4         114 return !$delta;
103             }
104              
105             sub unlike($$;$@) {
106 3     3 1 40 my ($got, $exp, $name, @diag) = @_;
107 3         10 my $ctx = context();
108              
109 3         257 my $delta = compare($got, $exp, \&unlike_convert);
110              
111 3 100       16 if ($delta) {
112 1         6 $ctx->fail($name, $delta->diag, @diag);
113             }
114             else {
115 2         9 $ctx->ok(1, $name);
116             }
117              
118 3         487 $ctx->release;
119 3         86 return !$delta;
120             }
121              
122             sub like_convert {
123 4     4 0 9 my ($thing) = @_;
124 4         27 return Test2::Compare::Pattern->new(
125             pattern => $thing,
126             stringify_got => 1,
127             );
128             }
129              
130             sub unlike_convert {
131 3     3 0 19 my ($thing) = @_;
132 3         15 return Test2::Compare::Pattern->new(
133             negate => 1,
134             stringify_got => 1,
135             pattern => $thing,
136             );
137             }
138              
139             sub is_deeply($$;$@) {
140 5     5 1 310 my ($got, $exp, $name, @diag) = @_;
141 5         20 my $ctx = context();
142              
143 5         18837 my @caller = caller;
144              
145 5         29 my $delta = compare($got, $exp, \&strict_convert);
146              
147 5 50       30 if ($delta) {
148             # Temporary thing.
149 0         0 my $count = 0;
150 0         0 my $implicit = 0;
151 0         0 my @deltas = ($delta);
152 0         0 while (my $d = shift @deltas) {
153 0         0 my $add = $d->children;
154 0 0 0     0 push @deltas => @$add if $add && @$add;
155 0 0       0 next if $d->verified;
156 0         0 $count++;
157 0 0 0     0 $implicit++ if $d->note && $d->note eq 'implicit end';
158             }
159              
160 0 0       0 if ($implicit == $count) {
161 0         0 $ctx->ok(1, $name);
162 0 0       0 my $meth = $ENV{AUTHOR_TESTING} ? 'throw' : 'alert';
163 0         0 my $type = $delta->render_check;
164 0         0 $ctx->$meth(
165             join "\n",
166             "!!! NOTICE OF BEHAVIOR CHANGE !!!",
167             "This test uses at least 1 $type check without using end() or etc().",
168             "The exising behavior is to default to etc() when inside is_deeply().",
169             "The new behavior is to default to end().",
170             "This test will soon start to fail with the following diagnostics:",
171             $delta->diag->as_string,
172             "",
173             );
174             }
175             else {
176 0         0 $ctx->fail($name, $delta->diag, @diag);
177             }
178             }
179             else {
180 5         23 $ctx->ok(1, $name);
181             }
182              
183 5         1144 $ctx->release;
184 5         175 return !$delta;
185             }
186              
187             our %OPS = (
188             '==' => 'num',
189             '!=' => 'num',
190             '>=' => 'num',
191             '<=' => 'num',
192             '>' => 'num',
193             '<' => 'num',
194             '<=>' => 'num',
195              
196             'eq' => 'str',
197             'ne' => 'str',
198             'gt' => 'str',
199             'lt' => 'str',
200             'ge' => 'str',
201             'le' => 'str',
202             'cmp' => 'str',
203             '!~' => 'str',
204             '=~' => 'str',
205              
206             '&&' => 'logic',
207             '||' => 'logic',
208             'xor' => 'logic',
209             'or' => 'logic',
210             'and' => 'logic',
211             '//' => 'logic',
212              
213             '&' => 'bitwise',
214             '|' => 'bitwise',
215              
216             '~~' => 'match',
217             );
218             sub cmp_ok($$$;$@) {
219 15     15 1 1706 my ($got, $op, $exp, $name, @diag) = @_;
220              
221 15         44 my $ctx = context();
222              
223             # Warnings and syntax errors should report to the cmp_ok call, not the test
224             # context. They may not be the same.
225 15         1366 my ($pkg, $file, $line) = caller;
226              
227 15         58 my $type = $OPS{$op};
228 15 100       36 if (!$type) {
229 2         400 carp "operator '$op' is not supported (you can add it to %Test2::Tools::ClassicCompare::OPS)";
230 2         6 $type = 'unsupported';
231             }
232              
233 15         67 local ($@, $!, $SIG{__DIE__});
234              
235 15         26 my $test;
236 15         1230 my $lived = eval <<" EOT";
237             #line $line "(eval in cmp_ok) $file"
238             \$test = (\$got $op \$exp);
239             1;
240             EOT
241 15         417 my $error = $@;
242 15 100       52 $ctx->send_event('Exception', error => $error) unless $lived;
243              
244 15 100 66     563 if ($test && $lived) {
245 7         33 $ctx->ok(1, $name);
246 7         1186 $ctx->release;
247 7         224 return 1;
248             }
249              
250             # Ugh, it failed. Do roughly the same thing Test::More did to try and show
251             # diagnostics, but make it better by showing both the overloaded and
252             # unoverloaded form if overloading is in play. Also unoverload numbers,
253             # Test::More only unoverloaded strings.
254              
255 8         26 my ($display_got, $display_exp);
256 8 100       48 if($type eq 'str') {
    100          
257 2 50       9 $display_got = defined($got) ? "$got" : undef;
258 2 50       9 $display_exp = defined($exp) ? "$exp" : undef;
259             }
260             elsif($type eq 'num') {
261 4 50       14 $display_got = defined($got) ? $got + 0 : undef;
262 4 50       11 $display_exp = defined($exp) ? $exp + 0 : undef;
263             }
264             else { # Well, we did what we could.
265 2         4 $display_got = $got;
266 2         5 $display_exp = $exp;
267             }
268              
269 8 100       34 my $got_ref = ref($got) ? render_ref($got) : $got;
270 8 100       21 my $exp_ref = ref($exp) ? render_ref($exp) : $exp;
271              
272 8         28 my @table;
273 8   66     91 my $show_both = (
274             (defined($got) && $got_ref ne "$display_got")
275             ||
276             (defined($exp) && $exp_ref ne "$display_exp")
277             );
278              
279 8 100       21 if ($show_both) {
280 4 100       41 @table = table(
281             header => ['TYPE', 'GOT', 'OP', 'CHECK'],
282             rows => [
283             [$type, $display_got, $op, $lived ? $display_exp : ''],
284             ['orig', $got_ref, '', $exp_ref],
285             ],
286             );
287             }
288             else {
289 4 100       27 @table = table(
290             header => ['GOT', 'OP', 'CHECK'],
291             rows => [[$display_got, $op, $lived ? $display_exp : '']],
292             );
293             }
294              
295 8         35246 $ctx->ok(0, $name, [join("\n", @table), @diag]);
296 8         5671 $ctx->release;
297 8         250 return 0;
298             }
299              
300              
301             1;
302              
303             __END__