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   2003 use strict;
  160         341  
  160         4697  
3 160     160   866 use warnings;
  160         427  
  160         8584  
4              
5             our $VERSION = '0.000155';
6              
7             our @EXPORT = qw/is is_deeply isnt like unlike cmp_ok/;
8 160     160   1108 use base 'Exporter';
  160         376  
  160         16630  
9              
10 160     160   1363 use Carp qw/carp/;
  160         448  
  160         8510  
11 160     160   1037 use Scalar::Util qw/reftype/;
  160         366  
  160         8869  
12              
13 160     160   2256 use Test2::API qw/context/;
  160         150114  
  160         8266  
14 160     160   3482 use Test2::Compare qw/compare strict_convert/;
  160         407  
  160         8938  
15 160     160   1064 use Test2::Util::Ref qw/rtype render_ref/;
  160         404  
  160         8488  
16 160     160   3268 use Test2::Util::Table qw/table/;
  160         352  
  160         1747  
17              
18 160     160   3375 use Test2::Compare::Array();
  160         359  
  160         2298  
19 160     160   2820 use Test2::Compare::Bag();
  160         334  
  160         2091  
20 160     160   2861 use Test2::Compare::Custom();
  160         345  
  160         2722  
21 160     160   2778 use Test2::Compare::Event();
  160         378  
  160         2879  
22 160     160   3039 use Test2::Compare::Hash();
  160         360  
  160         3369  
23 160     160   806 use Test2::Compare::Meta();
  160         365  
  160         3007  
24 160     160   3114 use Test2::Compare::Number();
  160         538  
  160         2915  
25 160     160   837 use Test2::Compare::Object();
  160         379  
  160         3236  
26 160     160   3380 use Test2::Compare::OrderedSubset();
  160         365  
  160         4354  
27 160     160   3061 use Test2::Compare::Pattern();
  160         370  
  160         3162  
28 160     160   2784 use Test2::Compare::Ref();
  160         297  
  160         4198  
29 160     160   2803 use Test2::Compare::Regex();
  160         337  
  160         2997  
30 160     160   2849 use Test2::Compare::Scalar();
  160         321  
  160         3040  
31 160     160   2913 use Test2::Compare::Set();
  160         400  
  160         2976  
32 160     160   2840 use Test2::Compare::String();
  160         630  
  160         2819  
33 160     160   2770 use Test2::Compare::Undef();
  160         383  
  160         3175  
34 160     160   3004 use Test2::Compare::Wildcard();
  160         370  
  160         230274  
35              
36             sub is($$;$@) {
37 7     7 1 523 my ($got, $exp, $name, @diag) = @_;
38 7         19 my $ctx = context();
39              
40 7         697 my @caller = caller;
41              
42 7         31 my $delta = compare($got, $exp, \&is_convert);
43              
44 7 100       34 if ($delta) {
45 3         16 $ctx->fail($name, $delta->diag, @diag);
46             }
47             else {
48 4         13 $ctx->ok(1, $name);
49             }
50              
51 7         1280 $ctx->release;
52 7         211 return !$delta;
53             }
54              
55             sub isnt($$;$@) {
56 4     4 1 60 my ($got, $exp, $name, @diag) = @_;
57 4         11 my $ctx = context();
58              
59 4         340 my @caller = caller;
60              
61 4         16 my $delta = compare($got, $exp, \&isnt_convert);
62              
63 4 100       17 if ($delta) {
64 1         4 $ctx->fail($name, $delta->diag, @diag);
65             }
66             else {
67 3         14 $ctx->ok(1, $name);
68             }
69              
70 4         673 $ctx->release;
71 4         114 return !$delta;
72             }
73              
74             sub is_convert {
75 7     7 0 10 my ($thing) = @_;
76 7 100       34 return Test2::Compare::Undef->new()
77             unless defined $thing;
78 5         29 return Test2::Compare::String->new(input => $thing);
79             }
80              
81             sub isnt_convert {
82 4     4 0 10 my ($thing) = @_;
83 4 50       12 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 51 my ($got, $exp, $name, @diag) = @_;
90 4         14 my $ctx = context();
91              
92 4         366 my $delta = compare($got, $exp, \&like_convert);
93              
94 4 100       35 if ($delta) {
95 1         6 $ctx->fail($name, $delta->diag, @diag);
96             }
97             else {
98 3         11 $ctx->ok(1, $name);
99             }
100              
101 4         664 $ctx->release;
102 4         113 return !$delta;
103             }
104              
105             sub unlike($$;$@) {
106 3     3 1 50 my ($got, $exp, $name, @diag) = @_;
107 3         10 my $ctx = context();
108              
109 3         252 my $delta = compare($got, $exp, \&unlike_convert);
110              
111 3 100       17 if ($delta) {
112 1         8 $ctx->fail($name, $delta->diag, @diag);
113             }
114             else {
115 2         8 $ctx->ok(1, $name);
116             }
117              
118 3         487 $ctx->release;
119 3         83 return !$delta;
120             }
121              
122             sub like_convert {
123 4     4 0 8 my ($thing) = @_;
124 4         24 return Test2::Compare::Pattern->new(
125             pattern => $thing,
126             stringify_got => 1,
127             );
128             }
129              
130             sub unlike_convert {
131 3     3 0 6 my ($thing) = @_;
132 3         11 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 312 my ($got, $exp, $name, @diag) = @_;
141 5         29 my $ctx = context();
142              
143 5         18088 my @caller = caller;
144              
145 5         35 my $delta = compare($got, $exp, \&strict_convert);
146              
147 5 50       44 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         36 $ctx->ok(1, $name);
181             }
182              
183 5         1211 $ctx->release;
184 5         195 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 1567 my ($got, $op, $exp, $name, @diag) = @_;
220              
221 15         38 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         1222 my ($pkg, $file, $line) = caller;
226              
227 15         59 my $type = $OPS{$op};
228 15 100       35 if (!$type) {
229 2         429 carp "operator '$op' is not supported (you can add it to %Test2::Tools::ClassicCompare::OPS)";
230 2         6 $type = 'unsupported';
231             }
232              
233 15         66 local ($@, $!, $SIG{__DIE__});
234              
235 15         25 my $test;
236 15         1073 my $lived = eval <<" EOT";
237             #line $line "(eval in cmp_ok) $file"
238             \$test = (\$got $op \$exp);
239             1;
240             EOT
241 15         388 my $error = $@;
242 15 100       49 $ctx->send_event('Exception', error => $error) unless $lived;
243              
244 15 100 66     505 if ($test && $lived) {
245 7         41 $ctx->ok(1, $name);
246 7         1079 $ctx->release;
247 7         219 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         18 my ($display_got, $display_exp);
256 8 100       54 if($type eq 'str') {
    100          
257 2 50       8 $display_got = defined($got) ? "$got" : undef;
258 2 50       7 $display_exp = defined($exp) ? "$exp" : undef;
259             }
260             elsif($type eq 'num') {
261 4 50       16 $display_got = defined($got) ? $got + 0 : undef;
262 4 50       13 $display_exp = defined($exp) ? $exp + 0 : undef;
263             }
264             else { # Well, we did what we could.
265 2         5 $display_got = $got;
266 2         5 $display_exp = $exp;
267             }
268              
269 8 100       40 my $got_ref = ref($got) ? render_ref($got) : $got;
270 8 100       33 my $exp_ref = ref($exp) ? render_ref($exp) : $exp;
271              
272 8         12 my @table;
273 8   66     120 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       40 @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       29 @table = table(
290             header => ['GOT', 'OP', 'CHECK'],
291             rows => [[$display_got, $op, $lived ? $display_exp : '']],
292             );
293             }
294              
295 8         35155 $ctx->ok(0, $name, [join("\n", @table), @diag]);
296 8         5638 $ctx->release;
297 8         250 return 0;
298             }
299              
300              
301             1;
302              
303             __END__