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   55729 use strict;
  94         595  
  94         2765  
3 94     94   553 use warnings;
  94         202  
  94         8560  
4              
5             BEGIN {
6 94 50   94   6734 if ($] lt "5.008") {
7 0         0 require Test::Builder::IO::Scalar;
8             }
9             }
10              
11 94     94   4253 use Scalar::Util qw/blessed/;
  94         192  
  94         13693  
12              
13 94     94   33826 use Test2::Util qw/try/;
  94         246  
  94         6324  
14 94     94   43023 use Test2::API qw/context run_subtest test2_stack/;
  94         282  
  94         8152  
15              
16 94     94   768 use Test2::Hub::Interceptor();
  94         378  
  94         1523  
17 94     94   578 use Test2::Hub::Interceptor::Terminator();
  94         194  
  94         4886  
18              
19             our $VERSION = '1.302182';
20              
21 94     94   2809 BEGIN { require Exporter; our @ISA = qw(Exporter) }
  94         62636  
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 6688 my ($bool, $name, @diag) = @_;
29 683         2114 my $ctx = context();
30              
31 683 100       3227 return $ctx->pass_and_release($name) if $bool;
32 13         60 return $ctx->fail_and_release($name, @diag);
33             }
34              
35             sub is($$;$@) {
36 669     669 1 2857124 my ($got, $want, $name, @diag) = @_;
37 669         2336 my $ctx = context();
38              
39 669         1312 my $bool;
40 669 100 100     3287 if (defined($got) && defined($want)) {
    100 75        
41 608         1868 $bool = "$got" eq "$want";
42             }
43             elsif (defined($got) xor defined($want)) {
44 2         3 $bool = 0;
45             }
46             else { # Both are undef
47 59         112 $bool = 1;
48             }
49              
50 669 100       2991 return $ctx->pass_and_release($name) if $bool;
51              
52 4 100       14 $got = '*NOT DEFINED*' unless defined $got;
53 4 100       13 $want = '*NOT DEFINED*' unless defined $want;
54 4         18 unshift @diag => (
55             "GOT: $got",
56             "EXPECTED: $want",
57             );
58              
59 4         19 return $ctx->fail_and_release($name, @diag);
60             }
61              
62             sub isnt($$;$@) {
63 16     16 1 2714056 my ($got, $want, $name, @diag) = @_;
64 16         105 my $ctx = context();
65              
66 16         56 my $bool;
67 16 100 100     137 if (defined($got) && defined($want)) {
    100 75        
68 13         73 $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       119 return $ctx->pass_and_release($name) if $bool;
78              
79 2 50       13 unshift @diag => "Strings are the same (they should not be)"
80             unless $bool;
81              
82 2         9 return $ctx->fail_and_release($name, @diag);
83             }
84              
85             sub like($$;$@) {
86 154     154 1 2552 my ($thing, $pattern, $name, @diag) = @_;
87 154         571 my $ctx = context();
88              
89 154         330 my $bool;
90 154 100       441 if (defined($thing)) {
91 153         1629 $bool = "$thing" =~ $pattern;
92 153 100       559 unshift @diag => (
93             "Value: $thing",
94             "Does not match: $pattern"
95             ) unless $bool;
96             }
97             else {
98 1         3 $bool = 0;
99 1         5 unshift @diag => "Got an undefined value.";
100             }
101              
102 154 100       752 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 42 my ($thing, $pattern, $name, @diag) = @_;
108 3         11 my $ctx = context();
109              
110 3         6 my $bool;
111 3 100       10 if (defined($thing)) {
112 2         12 $bool = "$thing" !~ $pattern;
113 2 100       10 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         4 unshift @diag => "Got an undefined value.";
122             }
123              
124 3 100       12 return $ctx->pass_and_release($name) if $bool;
125 2         9 return $ctx->fail_and_release($name, @diag);
126             }
127              
128             sub is_deeply($$;$@) {
129 404     404 1 1892 my ($got, $want, $name, @diag) = @_;
130 404         1221 my $ctx = context();
131              
132 94     94   828 no warnings 'once';
  94         253  
  94         117704  
133 404         36368 require Data::Dumper;
134              
135             # Otherwise numbers might be unquoted
136 404         359696 local $Data::Dumper::Useperl = 1;
137              
138 404         761 local $Data::Dumper::Sortkeys = 1;
139 404         665 local $Data::Dumper::Deparse = 1;
140 404         709 local $Data::Dumper::Freezer = 'XXX';
141             local *UNIVERSAL::XXX = sub {
142 368     368   195867 my ($thing) = @_;
143 368 50       971 if (ref($thing)) {
144 368 100       2567 $thing = {%$thing} if "$thing" =~ m/=HASH/;
145 368 100       1387 $thing = [@$thing] if "$thing" =~ m/=ARRAY/;
146 368 50       1089 $thing = \"$$thing" if "$thing" =~ m/=SCALAR/;
147             }
148 368         931 $_[0] = $thing;
149 404         2506 };
150              
151 404         1532 my $g = Data::Dumper::Dumper($got);
152 404         257584 my $w = Data::Dumper::Dumper($want);
153              
154 404         256939 my $bool = $g eq $w;
155              
156 404 100       2059 return $ctx->pass_and_release($name) if $bool;
157 1         6 return $ctx->fail_and_release($name, $g, $w, @diag);
158             }
159              
160             sub diag {
161 8     8 1 70 my $ctx = context();
162 8         50 $ctx->diag(join '', @_);
163 8         26 $ctx->release;
164             }
165              
166             sub note {
167 11     11 1 69 my $ctx = context();
168 11         97 $ctx->note(join '', @_);
169 11         48 $ctx->release;
170             }
171              
172             sub skip_all {
173 6     6 1 652 my ($reason) = @_;
174 6         64 my $ctx = context();
175 6         38 $ctx->plan(0, SKIP => $reason);
176 0 0       0 $ctx->release if $ctx;
177             }
178              
179             sub todo {
180 2     2 1 34 my ($reason, $sub) = @_;
181 2         8 my $ctx = context();
182              
183             # This code is mostly copied from Test2::Todo in the Test2-Suite
184             # distribution.
185 2         9 my $hub = test2_stack->top;
186             my $filter = $hub->pre_filter(
187             sub {
188 12     12   22 my ($active_hub, $event) = @_;
189 12 100       29 if ($active_hub == $hub) {
190 9 100       57 $event->set_todo($reason) if $event->can('set_todo');
191 9         36 $event->add_amnesty({tag => 'TODO', details => $reason});
192             }
193             else {
194 3         18 $event->add_amnesty({tag => 'TODO', details => $reason, inherited => 1});
195             }
196 12         27 return $event;
197             },
198 2         22 inherit => 1,
199             todo => $reason,
200             );
201 2         10 $sub->();
202 2         15 $hub->pre_unfilter($filter);
203              
204 2 50       10 $ctx->release if $ctx;
205             }
206              
207             sub plan {
208 7     7 1 68 my ($max) = @_;
209 7         29 my $ctx = context();
210 7         56 $ctx->plan($max);
211 7         33 $ctx->release;
212             }
213              
214             sub done_testing {
215 83     83 1 2669085 my $ctx = context();
216 83         707 $ctx->done_testing;
217 83         387 $ctx->release;
218             }
219              
220             sub warnings(&) {
221 12     12 1 167 my $code = shift;
222 12         47 my @warnings;
223 12     13   232 local $SIG{__WARN__} = sub { push @warnings => @_ };
  13         721  
224 12         88 $code->();
225 12         133 return \@warnings;
226             }
227              
228             sub exception(&) {
229 84     84 1 486 my $code = shift;
230 84         626 local ($@, $!, $SIG{__DIE__});
231 84         203 my $ok = eval { $code->(); 1 };
  84         259  
  8         22  
232 84   100     7449 my $error = $@ || 'SQUASHED ERROR';
233 84 100       1137 return $ok ? undef : $error;
234             }
235              
236             sub tests {
237 89     89 1 1600 my ($name, $code) = @_;
238 89         280 my $ctx = context();
239              
240 89         791 my $be = caller->can('before_each');
241              
242 89 100       287 $be->($name) if $be;
243              
244 89         361 my $bool = run_subtest($name, $code, 1);
245              
246 88         346 $ctx->release;
247              
248 88         240 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         21 my $handles = test2_stack->top->format->handles;
257 7         16 my ($ok, $e);
258             {
259 7         13 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   26 if ($] ge "5.008") {
264 7 50   3   167 open($out_fh, '>', \$out) or die "Failed to open a temporary STDOUT: $!";
  3         21  
  3         6  
  3         19  
265 7 50       2295 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         29 test2_stack->top->format->set_handles([$out_fh, $err_fh, $out_fh]);
274              
275 7         22 $code->();
276 7         43 };
277             }
278 7         63 test2_stack->top->format->set_handles($handles);
279              
280 7 50       27 die $e unless $ok;
281              
282 7         23 $err =~ s/ $/_/mg;
283 7         54 $out =~ s/ $/_/mg;
284              
285             return {
286 7         35 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