File Coverage

blib/lib/Test/Stream/Plugin/Compare.pm
Criterion Covered Total %
statement 213 213 100.0
branch 94 94 100.0
condition 8 8 100.0
subroutine 57 57 100.0
pod 28 31 90.3
total 400 403 99.2


line stmt bran cond sub pod time code
1             package Test::Stream::Plugin::Compare;
2 100     100   1208 use strict;
  100         188  
  100         2685  
3 100     100   490 use warnings;
  100         208  
  100         2535  
4              
5 100     100   534 use Test::Stream::Exporter;
  100         180  
  100         685  
6             default_exports qw/is like/;
7             exports qw{
8             match mismatch validator
9             hash array object meta number string
10             in_set not_in_set check_set
11             item field call prop check
12             end filter_items
13             T F D DNE FDNE
14             event
15             exact_ref
16             };
17 100     100   543 no Test::Stream::Exporter;
  100         179  
  100         414  
18              
19 100     100   532 use Carp qw/croak/;
  100         188  
  100         4655  
20 100     100   514 use Scalar::Util qw/reftype blessed/;
  100         177  
  100         5440  
21              
22 100     100   51816 use Test::Stream::Compare qw/-all/;
  100         252  
  100         413  
23 100     100   595 use Test::Stream::Context qw/context/;
  100         189  
  100         674  
24 100     100   557 use Test::Stream::Util qw/rtype/;
  100         182  
  100         419  
25              
26 100     100   60226 use Test::Stream::Compare::Array;
  100         250  
  100         742  
27 100     100   55325 use Test::Stream::Compare::Custom;
  100         264  
  100         793  
28 100     100   53889 use Test::Stream::Compare::Event;
  100         284  
  100         734  
29 100     100   55385 use Test::Stream::Compare::Hash;
  100         277  
  100         732  
30 100     100   684 use Test::Stream::Compare::Meta;
  100         200  
  100         735  
31 100     100   56224 use Test::Stream::Compare::Number;
  100         262  
  100         815  
32 100     100   636 use Test::Stream::Compare::Object;
  100         202  
  100         742  
33 100     100   53705 use Test::Stream::Compare::Pattern;
  100         266  
  100         719  
34 100     100   55917 use Test::Stream::Compare::Ref;
  100         258  
  100         687  
35 100     100   53776 use Test::Stream::Compare::Regex;
  100         259  
  100         713  
36 100     100   53871 use Test::Stream::Compare::Scalar;
  100         255  
  100         704  
37 100     100   54531 use Test::Stream::Compare::Set;
  100         272  
  100         726  
38 100     100   53703 use Test::Stream::Compare::String;
  100         250  
  100         747  
39 100     100   54014 use Test::Stream::Compare::Undef;
  100         279  
  100         739  
40 100     100   54210 use Test::Stream::Compare::Value;
  100         249  
  100         725  
41 100     100   54341 use Test::Stream::Compare::Wildcard;
  100         273  
  100         883  
42              
43             sub is($$;$@) {
44 1440     1440 1 12692162 my ($got, $exp, $name, @diag) = @_;
45 1440         4007 my $ctx = context();
46              
47 1440         5578 my $delta = compare($got, $exp, \&strict_convert);
48              
49 1440 100       4000 if ($delta) {
50 78         269 $ctx->ok(0, $name, [$delta->table, @diag]);
51             }
52             else {
53 1362         4495 $ctx->ok(1, $name);
54             }
55              
56 1440         4783 $ctx->release;
57 1440         5112 return !$delta;
58             }
59              
60             sub like($$;$@) {
61 430     430 1 1703 my ($got, $exp, $name, @diag) = @_;
62 430         1813 my $ctx = context();
63              
64 430         1813 my $delta = compare($got, $exp, \&relaxed_convert);
65              
66 430 100       1404 if ($delta) {
67 3         15 $ctx->ok(0, $name, [$delta->table, @diag]);
68             }
69             else {
70 427         1542 $ctx->ok(1, $name);
71             }
72              
73 430         1560 $ctx->release;
74 430         1540 return !$delta;
75             }
76              
77 4     4 1 47 sub meta(&) { build('Test::Stream::Compare::Meta', @_) }
78 10     10 1 87 sub hash(&) { build('Test::Stream::Compare::Hash', @_) }
79 198     198 1 1429 sub array(&) { build('Test::Stream::Compare::Array', @_) }
80 125     125 1 701 sub object(&) { build('Test::Stream::Compare::Object', @_) }
81              
82             my $FDNE = Test::Stream::Compare::Custom->new(code => sub { $_ ? 0 : 1 }, name => 'FALSE', operator => 'FALSE() || !exists');
83             my $DNE = Test::Stream::Compare::Custom->new(code => sub { my %p = @_; $p{exists} ? 0 : 1 }, name => '', operator => '!exists');
84             my $F = Test::Stream::Compare::Custom->new(code => sub { my %p = @_; $p{got} ? 0 : $p{exists} }, name => 'FALSE', operator => 'FALSE()');
85             my $T = Test::Stream::Compare::Custom->new(code => sub { $_ ? 1 : 0 }, name => 'TRUE', operator => 'TRUE()');
86             my $D = Test::Stream::Compare::Custom->new(code => sub { defined $_ ? 1 : 0 }, name => 'DEFINED', operator => 'DEFINED()');
87              
88 58     58 1 404 sub T() { $T }
89 31     31 1 138 sub F() { $F }
90 6     6 1 23 sub D() { $D }
91 53     53 1 398 sub DNE() { $DNE }
92 6     6 1 25 sub FDNE() { $FDNE }
93              
94 5141     5141 0 11501 sub strict_convert { convert($_[0], 1) }
95 2235     2235 0 4939 sub relaxed_convert { convert($_[0], 0) }
96              
97             sub exact_ref($) {
98 19     19 1 105 my @caller = caller;
99 19         127 return Test::Stream::Compare::Ref->new(
100             file => $caller[1],
101             lines => [$caller[2]],
102             input => $_[0],
103             );
104             }
105              
106             sub match($) {
107 23     23 1 189 my @caller = caller;
108 23         148 return Test::Stream::Compare::Pattern->new(
109             file => $caller[1],
110             lines => [$caller[2]],
111             pattern => $_[0],
112             );
113             }
114              
115             sub mismatch($) {
116 4     4 1 43 my @caller = caller;
117 4         37 return Test::Stream::Compare::Pattern->new(
118             file => $caller[1],
119             lines => [$caller[2]],
120             negate => 1,
121             pattern => $_[0],
122             );
123             }
124              
125             sub validator {
126 109     109 1 829 my $code = pop;
127 109         157 my $cname = pop;
128 109         135 my $op = pop;
129              
130 109         342 my @caller = caller;
131 109         479 return Test::Stream::Compare::Custom->new(
132             file => $caller[1],
133             lines => [$caller[2]],
134             code => $code,
135             name => $cname,
136             operator => $op,
137             );
138             }
139              
140             sub number($;@) {
141 2     2 1 11 my ($num, @args) = @_;
142 2         7 my @caller = caller;
143 2         21 return Test::Stream::Compare::Number->new(
144             file => $caller[1],
145             lines => [$caller[2]],
146             input => $num,
147             @args,
148             );
149             }
150              
151             sub string($;@) {
152 2     2 1 10 my ($str, @args) = @_;
153 2         8 my @caller = caller;
154 2         16 return Test::Stream::Compare::String->new(
155             file => $caller[1],
156             lines => [$caller[2]],
157             input => $str,
158             @args,
159             );
160             }
161              
162             sub filter_items(&) {
163 5 100   5 1 46 my $build = get_build() or croak "No current build!";
164              
165 4 100       157 croak "'$build' does not support filters"
166             unless $build->can('add_filter');
167              
168 3 100       129 croak "'filter_items' should only ever be called in void context"
169             if defined wantarray;
170              
171 2         14 $build->add_filter(@_);
172             }
173              
174             sub end() {
175 139 100   139 1 673 my $build = get_build() or croak "No current build!";
176              
177 138 100       733 croak "'$build' does not support 'ending'"
178             unless $build->can('ending');
179              
180 137 100       436 croak "'end' should only ever be called in void context"
181             if defined wantarray;
182              
183 136         492 $build->set_ending(1);
184             }
185              
186             sub call($$) {
187 1056     1056 1 2265 my ($name, $expect) = @_;
188 1056 100       2537 my $build = get_build() or croak "No current build!";
189              
190 1055 100       3600 croak "'$build' does not support method calls"
191             unless $build->can('add_call');
192              
193 1054 100       2175 croak "'call' should only ever be called in void context"
194             if defined wantarray;
195              
196 1053         2890 my @caller = caller;
197 1053         4013 $build->add_call(
198             $name,
199             Test::Stream::Compare::Wildcard->new(
200             expect => $expect,
201             file => $caller[1],
202             lines => [$caller[2]],
203             ),
204             );
205             }
206              
207             sub prop($$) {
208 217     217 1 634 my ($name, $expect) = @_;
209 217 100       525 my $build = get_build() or croak "No current build!";
210              
211 216 100       936 croak "'$build' does not support meta-checks"
212             unless $build->can('add_prop');
213              
214 215 100       590 croak "'prop' should only ever be called in void context"
215             if defined wantarray;
216              
217 214         620 my @caller = caller;
218 214         921 $build->add_prop(
219             $name,
220             Test::Stream::Compare::Wildcard->new(
221             expect => $expect,
222             file => $caller[1],
223             lines => [$caller[2]],
224             ),
225             );
226             }
227              
228             sub item($;$) {
229 196     196 1 450 my @args = @_;
230 196         279 my $expect = pop @args;
231              
232 196 100       502 my $build = get_build() or croak "No current build!";
233              
234 195 100       819 croak "'$build' does not support array item checks"
235             unless $build->can('add_item');
236              
237 194 100       567 croak "'item' should only ever be called in void context"
238             if defined wantarray;
239              
240 193         520 my @caller = caller;
241 193         750 push @args => Test::Stream::Compare::Wildcard->new(
242             expect => $expect,
243             file => $caller[1],
244             lines => [$caller[2]],
245             );
246              
247 193         566 $build->add_item(@args);
248             }
249              
250             sub field($$) {
251 80     80 1 284 my ($name, $expect) = @_;
252              
253 80 100       200 my $build = get_build() or croak "No current build!";
254              
255 79 100       397 croak "'$build' does not support hash field checks"
256             unless $build->can('add_field');
257              
258 78 100       278 croak "'field' should only ever be called in void context"
259             if defined wantarray;
260              
261 77         216 my @caller = caller;
262 77         337 $build->add_field(
263             $name,
264             Test::Stream::Compare::Wildcard->new(
265             expect => $expect,
266             file => $caller[1],
267             lines => [$caller[2]],
268             ),
269             );
270             }
271              
272             sub check($) {
273 18     18 1 69 my ($check) = @_;
274              
275 18 100       49 my $build = get_build() or croak "No current build!";
276              
277 17 100       192 croak "'$build' is not a check-set"
278             unless $build->can('add_check');
279              
280 16 100       134 croak "'check' should only ever be called in void context"
281             if defined wantarray;
282              
283 15         43 my @caller = caller;
284 15         80 my $wc = Test::Stream::Compare::Wildcard->new(
285             expect => $check,
286             file => $caller[1],
287             lines => [$caller[2]],
288             );
289              
290 15         43 $build->add_check($wc);
291             }
292              
293 4     4 1 25 sub check_set { return _build_set('all' => @_) }
294 13     13 1 47 sub in_set { return _build_set('any' => @_) }
295 4     4 1 23 sub not_in_set { return _build_set('none' => @_) }
296              
297             sub _build_set {
298 21     21   33 my $redux = shift;
299 21         31 my ($builder) = @_;
300 21   100     89 my $btype = reftype($builder) || '';
301              
302 21         25 my $set;
303 21 100       48 if ($btype eq 'CODE') {
304 7         25 $set = build('Test::Stream::Compare::Set', $builder);
305 6         27 $set->set_builder($builder);
306             }
307             else {
308 14         74 $set = Test::Stream::Compare::Set->new(checks => [@_]);
309             }
310              
311 20         66 $set->set_reduction($redux);
312 20         80 return $set;
313             }
314              
315             sub event($;$) {
316 291     291 1 2111 my ($intype, $spec) = @_;
317              
318 291         930 my @caller = caller;
319              
320 291 100       929 croak "type is required" unless $intype;
321              
322 290         349 my $type;
323 290 100       715 if ($intype =~ m/^\+(.*)$/) {
324 1         4 $type = $1;
325             }
326             else {
327 289         618 $type = "Test::Stream::Event::$intype";
328             }
329              
330 290         381 my $event;
331 290 100       1497 if (!$spec) {
    100          
    100          
332 1         6 $event = Test::Stream::Compare::Event->new(
333             etype => $intype,
334             file => $caller[1],
335             lines => [$caller[2]],
336             );
337             }
338             elsif (!ref $spec) {
339 1         117 croak "'$spec' is not a valid event specification"
340             }
341             elsif (reftype($spec) eq 'CODE') {
342 109         360 $event = build('Test::Stream::Compare::Event', $spec);
343 109         398 $event->set_etype($intype),
344             $event->set_builder($spec);
345             }
346             else {
347 179         1110 my $refcheck = Test::Stream::Compare::Hash->new(
348             inref => $spec,
349             file => $caller[1],
350             lines => [$caller[2]],
351             );
352 179         992 $event = Test::Stream::Compare::Event->new(
353             refcheck => $refcheck,
354             file => $caller[1],
355             lines => [$caller[2]],
356             etype => $intype,
357             );
358             }
359              
360 289         1667 $event->add_prop('blessed' => $type);
361              
362 289 100       723 return $event if defined wantarray;
363              
364 284 100       793 my $build = get_build() or croak "No current build!";
365 283         970 $build->add_item($event);
366             }
367              
368             sub convert {
369 9034     9034 0 18101 my ($thing, $strict) = @_;
370              
371 9034 100       20557 return Test::Stream::Compare::Undef->new()
372             unless defined $thing;
373              
374 8500 100 100     58648 if ($thing && blessed($thing) && $thing->isa('Test::Stream::Compare')) {
      100        
375 2674 100       11820 return $thing unless $thing->isa('Test::Stream::Compare::Wildcard');
376 1649         4552 my $newthing = convert($thing->expect, $strict);
377 1649 100       5011 $newthing->set_builder($thing->builder) unless $newthing->builder;
378 1649 100       15681 $newthing->set_file($thing->_file) unless $newthing->_file;
379 1649 100       15503 $newthing->set_lines($thing->_lines) unless $newthing->_lines;
380 1649         14924 return $newthing;
381             }
382              
383 5826         15520 my $type = rtype($thing);
384              
385 5826 100       17255 return Test::Stream::Compare::Array->new(inref => $thing, $strict ? (ending => 1) : ())
    100          
386             if $type eq 'ARRAY';
387              
388 5136 100       12665 return Test::Stream::Compare::Hash->new(inref => $thing, $strict ? (ending => 1) : ())
    100          
389             if $type eq 'HASH';
390              
391 4534 100       9743 unless ($strict) {
392 1437 100       4891 return Test::Stream::Compare::Pattern->new(pattern => $thing)
393             if $type eq 'REGEXP';
394              
395 937 100       2046 return Test::Stream::Compare::Custom->new(code => $thing)
396             if $type eq 'CODE';
397             }
398              
399 4003 100       8193 return Test::Stream::Compare::Regex->new(input => $thing)
400             if $type eq 'REGEXP';
401              
402 3999 100       7567 if ($type eq 'SCALAR') {
403 9         26 my $nested = convert($$thing, $strict);
404 9         45 return Test::Stream::Compare::Scalar->new(item => $nested)
405             }
406              
407 3990 100       7661 return Test::Stream::Compare::Ref->new(input => $thing)
408             if $type;
409              
410             # is() will assume string and use 'eq'
411 3851         14789 return Test::Stream::Compare::String->new(input => $thing);
412             }
413              
414             1;
415              
416             __END__