File Coverage

blib/lib/Test2/Tools/Tiny.pm
Criterion Covered Total %
statement 161 165 97.5
branch 53 68 77.9
condition 14 16 87.5
subroutine 31 31 100.0
pod 16 16 100.0
total 275 296 92.9


line stmt bran cond sub pod time code
1             package Test2::Tools::Tiny;
2 94     94   54224 use strict;
  94         594  
  94         2751  
3 94     94   468 use warnings;
  94         199  
  94         11871  
4              
5             BEGIN {
6 94 50   94   6810 if ($] lt "5.008") {
7 0         0 require Test::Builder::IO::Scalar;
8             }
9             }
10              
11 94     94   608 use Scalar::Util qw/blessed/;
  94         181  
  94         15983  
12              
13 94     94   34392 use Test2::Util qw/try/;
  94         242  
  94         5985  
14 94     94   44032 use Test2::API qw/context run_subtest test2_stack/;
  94         264  
  94         8319  
15              
16 94     94   703 use Test2::Hub::Interceptor();
  94         384  
  94         1506  
17 94     94   487 use Test2::Hub::Interceptor::Terminator();
  94         202  
  94         4859  
18              
19             our $VERSION = '1.302181';
20              
21 94     94   2944 BEGIN { require Exporter; our @ISA = qw(Exporter) }
  94         62403  
22             our @EXPORT = qw{
23             ok is isnt like unlike is_deeply diag note skip_all todo plan done_testing
24             warnings exception tests capture
25             };
26              
27             sub ok($;$@) {
28 683     683 1 7173 my ($bool, $name, @diag) = @_;
29 683         2205 my $ctx = context();
30              
31 683 100       3313 return $ctx->pass_and_release($name) if $bool;
32 13         96 return $ctx->fail_and_release($name, @diag);
33             }
34              
35             sub is($$;$@) {
36 669     669 1 2879879 my ($got, $want, $name, @diag) = @_;
37 669         2234 my $ctx = context();
38              
39 669         1249 my $bool;
40 669 100 100     3128 if (defined($got) && defined($want)) {
    100 75        
41 608         1760 $bool = "$got" eq "$want";
42             }
43             elsif (defined($got) xor defined($want)) {
44 2         6 $bool = 0;
45             }
46             else { # Both are undef
47 59         114 $bool = 1;
48             }
49              
50 669 100       2988 return $ctx->pass_and_release($name) if $bool;
51              
52 4 100       19 $got = '*NOT DEFINED*' unless defined $got;
53 4 100       12 $want = '*NOT DEFINED*' unless defined $want;
54 4         20 unshift @diag => (
55             "GOT: $got",
56             "EXPECTED: $want",
57             );
58              
59 4         21 return $ctx->fail_and_release($name, @diag);
60             }
61              
62             sub isnt($$;$@) {
63 16     16 1 2743718 my ($got, $want, $name, @diag) = @_;
64 16         111 my $ctx = context();
65              
66 16         57 my $bool;
67 16 100 100     136 if (defined($got) && defined($want)) {
    100 75        
68 13         76 $bool = "$got" ne "$want";
69             }
70             elsif (defined($got) xor defined($want)) {
71 2         4 $bool = 1;
72             }
73             else { # Both are undef
74 1         3 $bool = 0;
75             }
76              
77 16 100       114 return $ctx->pass_and_release($name) if $bool;
78              
79 2 50       10 unshift @diag => "Strings are the same (they should not be)"
80             unless $bool;
81              
82 2         10 return $ctx->fail_and_release($name, @diag);
83             }
84              
85             sub like($$;$@) {
86 154     154 1 2486 my ($thing, $pattern, $name, @diag) = @_;
87 154         569 my $ctx = context();
88              
89 154         341 my $bool;
90 154 100       425 if (defined($thing)) {
91 153         1513 $bool = "$thing" =~ $pattern;
92 153 100       511 unshift @diag => (
93             "Value: $thing",
94             "Does not match: $pattern"
95             ) unless $bool;
96             }
97             else {
98 1         4 $bool = 0;
99 1         4 unshift @diag => "Got an undefined value.";
100             }
101              
102 154 100       719 return $ctx->pass_and_release($name) if $bool;
103 2         10 return $ctx->fail_and_release($name, @diag);
104             }
105              
106             sub unlike($$;$@) {
107 3     3 1 39 my ($thing, $pattern, $name, @diag) = @_;
108 3         12 my $ctx = context();
109              
110 3         6 my $bool;
111 3 100       15 if (defined($thing)) {
112 2         11 $bool = "$thing" !~ $pattern;
113 2 100       14 unshift @diag => (
114             "Unexpected pattern match (it should not match)",
115             "Value: $thing",
116             "Matches: $pattern"
117             ) unless $bool;
118             }
119             else {
120 1         3 $bool = 0;
121 1         3 unshift @diag => "Got an undefined value.";
122             }
123              
124 3 100       12 return $ctx->pass_and_release($name) if $bool;
125 2         7 return $ctx->fail_and_release($name, @diag);
126             }
127              
128             sub is_deeply($$;$@) {
129 404     404 1 1919 my ($got, $want, $name, @diag) = @_;
130 404         1229 my $ctx = context();
131              
132 94     94   788 no warnings 'once';
  94         224  
  94         116423  
133 404         35606 require Data::Dumper;
134              
135             # Otherwise numbers might be unquoted
136 404         359228 local $Data::Dumper::Useperl = 1;
137              
138 404         770 local $Data::Dumper::Sortkeys = 1;
139 404         696 local $Data::Dumper::Deparse = 1;
140 404         718 local $Data::Dumper::Freezer = 'XXX';
141             local *UNIVERSAL::XXX = sub {
142 368     368   197045 my ($thing) = @_;
143 368 50       1006 if (ref($thing)) {
144 368 100       3027 $thing = {%$thing} if "$thing" =~ m/=HASH/;
145 368 100       1381 $thing = [@$thing] if "$thing" =~ m/=ARRAY/;
146 368 50       1163 $thing = \"$$thing" if "$thing" =~ m/=SCALAR/;
147             }
148 368         886 $_[0] = $thing;
149 404         2475 };
150              
151 404         1478 my $g = Data::Dumper::Dumper($got);
152 404         257771 my $w = Data::Dumper::Dumper($want);
153              
154 404         254662 my $bool = $g eq $w;
155              
156 404 100       1905 return $ctx->pass_and_release($name) if $bool;
157 1         4 return $ctx->fail_and_release($name, $g, $w, @diag);
158             }
159              
160             sub diag {
161 8     8 1 51 my $ctx = context();
162 8         61 $ctx->diag(join '', @_);
163 8         28 $ctx->release;
164             }
165              
166             sub note {
167 11     11 1 75 my $ctx = context();
168 11         79 $ctx->note(join '', @_);
169 11         43 $ctx->release;
170             }
171              
172             sub skip_all {
173 6     6 1 1364 my ($reason) = @_;
174 6         54 my $ctx = context();
175 6         36 $ctx->plan(0, SKIP => $reason);
176 0 0       0 $ctx->release if $ctx;
177             }
178              
179             sub todo {
180 2     2 1 30 my ($reason, $sub) = @_;
181 2         9 my $ctx = context();
182              
183             # This code is mostly copied from Test2::Todo in the Test2-Suite
184             # distribution.
185 2         15 my $hub = test2_stack->top;
186             my $filter = $hub->pre_filter(
187             sub {
188 12     12   28 my ($active_hub, $event) = @_;
189 12 100       31 if ($active_hub == $hub) {
190 9 100       60 $event->set_todo($reason) if $event->can('set_todo');
191 9         45 $event->add_amnesty({tag => 'TODO', details => $reason});
192             }
193             else {
194 3         20 $event->add_amnesty({tag => 'TODO', details => $reason, inherited => 1});
195             }
196 12         28 return $event;
197             },
198 2         26 inherit => 1,
199             todo => $reason,
200             );
201 2         11 $sub->();
202 2         22 $hub->pre_unfilter($filter);
203              
204 2 50       13 $ctx->release if $ctx;
205             }
206              
207             sub plan {
208 7     7 1 51 my ($max) = @_;
209 7         24 my $ctx = context();
210 7         50 $ctx->plan($max);
211 7         35 $ctx->release;
212             }
213              
214             sub done_testing {
215 83     83 1 2744892 my $ctx = context();
216 83         600 $ctx->done_testing;
217 83         361 $ctx->release;
218             }
219              
220             sub warnings(&) {
221 12     12 1 166 my $code = shift;
222 12         41 my @warnings;
223 12     13   206 local $SIG{__WARN__} = sub { push @warnings => @_ };
  13         727  
224 12         94 $code->();
225 12         124 return \@warnings;
226             }
227              
228             sub exception(&) {
229 84     84 1 467 my $code = shift;
230 84         581 local ($@, $!, $SIG{__DIE__});
231 84         200 my $ok = eval { $code->(); 1 };
  84         279  
  8         33  
232 84   100     7266 my $error = $@ || 'SQUASHED ERROR';
233 84 100       1235 return $ok ? undef : $error;
234             }
235              
236             sub tests {
237 89     89 1 1572 my ($name, $code) = @_;
238 89         290 my $ctx = context();
239              
240 89         776 my $be = caller->can('before_each');
241              
242 89 100       286 $be->($name) if $be;
243              
244 89         326 my $bool = run_subtest($name, $code, 1);
245              
246 88         353 $ctx->release;
247              
248 88         245 return $bool;
249             }
250              
251             sub capture(&) {
252 7     7 1 39 my $code = shift;
253              
254 7         20 my ($err, $out) = ("", "");
255              
256 7         22 my $handles = test2_stack->top->format->handles;
257 7         15 my ($ok, $e);
258             {
259 7         15 my ($out_fh, $err_fh);
  7         13  
260              
261             ($ok, $e) = try {
262             # Scalar refs as filehandles were added in 5.8.
263 7 50   7   24 if ($] ge "5.008") {
264 7 50   3   150 open($out_fh, '>', \$out) or die "Failed to open a temporary STDOUT: $!";
  3         23  
  3         8  
  3         25  
265 7 50       2363 open($err_fh, '>', \$err) or die "Failed to open a temporary STDERR: $!";
266             }
267             # Emulate scalar ref filehandles with a tie.
268             else {
269 0 0       0 $out_fh = Test::Builder::IO::Scalar->new(\$out) or die "Failed to open a temporary STDOUT";
270 0 0       0 $err_fh = Test::Builder::IO::Scalar->new(\$err) or die "Failed to open a temporary STDERR";
271             }
272              
273 7         25 test2_stack->top->format->set_handles([$out_fh, $err_fh, $out_fh]);
274              
275 7         19 $code->();
276 7         45 };
277             }
278 7         69 test2_stack->top->format->set_handles($handles);
279              
280 7 50       54 die $e unless $ok;
281              
282 7         29 $err =~ s/ $/_/mg;
283 7         53 $out =~ s/ $/_/mg;
284              
285             return {
286 7         43 STDOUT => $out,
287             STDERR => $err,
288             };
289             }
290              
291             1;
292              
293             __END__
294              
295             =pod
296              
297             =encoding UTF-8
298              
299             =head1 NAME
300              
301             Test2::Tools::Tiny - Tiny set of tools for unfortunate souls who cannot use
302             L<Test2::Suite>.
303              
304             =head1 DESCRIPTION
305              
306             You should really look at L<Test2::Suite>. This package is some very basic
307             essential tools implemented using L<Test2>. This exists only so that L<Test2>
308             and other tools required by L<Test2::Suite> can be tested. This is the package
309             L<Test2> uses to test itself.
310              
311             =head1 USE Test2::Suite INSTEAD
312              
313             Use L<Test2::Suite> if at all possible.
314              
315             =head1 EXPORTS
316              
317             =over 4
318              
319             =item ok($bool, $name)
320              
321             =item ok($bool, $name, @diag)
322              
323             Run a simple assertion.
324              
325             =item is($got, $want, $name)
326              
327             =item is($got, $want, $name, @diag)
328              
329             Assert that 2 strings are the same.
330              
331             =item isnt($got, $do_not_want, $name)
332              
333             =item isnt($got, $do_not_want, $name, @diag)
334              
335             Assert that 2 strings are not the same.
336              
337             =item like($got, $regex, $name)
338              
339             =item like($got, $regex, $name, @diag)
340              
341             Check that the input string matches the regex.
342              
343             =item unlike($got, $regex, $name)
344              
345             =item unlike($got, $regex, $name, @diag)
346              
347             Check that the input string does not match the regex.
348              
349             =item is_deeply($got, $want, $name)
350              
351             =item is_deeply($got, $want, $name, @diag)
352              
353             Check 2 data structures. Please note that this is a I<DUMB> implementation that
354             compares the output of L<Data::Dumper> against both structures.
355              
356             =item diag($msg)
357              
358             Issue a diagnostics message to STDERR.
359              
360             =item note($msg)
361              
362             Issue a diagnostics message to STDOUT.
363              
364             =item skip_all($reason)
365              
366             Skip all tests.
367              
368             =item todo $reason => sub { ... }
369              
370             Run a block in TODO mode.
371              
372             =item plan($count)
373              
374             Set the plan.
375              
376             =item done_testing()
377              
378             Set the plan to the current test count.
379              
380             =item $warnings = warnings { ... }
381              
382             Capture an arrayref of warnings from the block.
383              
384             =item $exception = exception { ... }
385              
386             Capture an exception.
387              
388             =item tests $name => sub { ... }
389              
390             Run a subtest.
391              
392             =item $output = capture { ... }
393              
394             Capture STDOUT and STDERR output.
395              
396             Result looks like this:
397              
398             {
399             STDOUT => "...",
400             STDERR => "...",
401             }
402              
403             =back
404              
405             =head1 SOURCE
406              
407             The source code repository for Test2 can be found at
408             F<http://github.com/Test-More/test-more/>.
409              
410             =head1 MAINTAINERS
411              
412             =over 4
413              
414             =item Chad Granum E<lt>exodist@cpan.orgE<gt>
415              
416             =back
417              
418             =head1 AUTHORS
419              
420             =over 4
421              
422             =item Chad Granum E<lt>exodist@cpan.orgE<gt>
423              
424             =back
425              
426             =head1 COPYRIGHT
427              
428             Copyright 2020 Chad Granum E<lt>exodist@cpan.orgE<gt>.
429              
430             This program is free software; you can redistribute it and/or
431             modify it under the same terms as Perl itself.
432              
433             See F<http://dev.perl.org/licenses/>
434              
435             =cut