1 package Test2::Tools::Tiny;
7 require Test::Builder::IO::Scalar;
11 use Scalar::Util qw/blessed/;
13 use Test2::Util qw/try/;
14 use Test2::API qw/context run_subtest test2_stack/;
16 use Test2::Hub::Interceptor();
17 use Test2::Hub::Interceptor::Terminator();
19 our $VERSION = '1.302113';
21 BEGIN { require Exporter; our @ISA = qw(Exporter) }
23 ok is isnt like unlike is_deeply diag note skip_all todo plan done_testing
24 warnings exception tests capture
28 my ($bool, $name, @diag) = @_;
31 return $ctx->pass_and_release($name) if $bool;
32 return $ctx->fail_and_release($name, @diag);
36 my ($got, $want, $name, @diag) = @_;
40 if (defined($got) && defined($want)) {
41 $bool = "$got" eq "$want";
43 elsif (defined($got) xor defined($want)) {
46 else { # Both are undef
50 return $ctx->pass_and_release($name) if $bool;
52 $got = '*NOT DEFINED*' unless defined $got;
53 $want = '*NOT DEFINED*' unless defined $want;
59 return $ctx->fail_and_release($name, @diag);
63 my ($got, $want, $name, @diag) = @_;
67 if (defined($got) && defined($want)) {
68 $bool = "$got" ne "$want";
70 elsif (defined($got) xor defined($want)) {
73 else { # Both are undef
77 return $ctx->pass_and_release($name) if $bool;
79 unshift @diag => "Strings are the same (they should not be)"
82 return $ctx->fail_and_release($name, @diag);
86 my ($thing, $pattern, $name, @diag) = @_;
90 if (defined($thing)) {
91 $bool = "$thing" =~ $pattern;
94 "Does not match: $pattern"
99 unshift @diag => "Got an undefined value.";
102 return $ctx->pass_and_release($name) if $bool;
103 return $ctx->fail_and_release($name, @diag);
107 my ($thing, $pattern, $name, @diag) = @_;
111 if (defined($thing)) {
112 $bool = "$thing" !~ $pattern;
114 "Unexpected pattern match (it should not match)",
121 unshift @diag => "Got an undefined value.";
124 return $ctx->pass_and_release($name) if $bool;
125 return $ctx->fail_and_release($name, @diag);
128 sub is_deeply($$;$@) {
129 my ($got, $want, $name, @diag) = @_;
133 require Data::Dumper;
135 # Otherwise numbers might be unquoted
136 local $Data::Dumper::Useperl = 1;
138 local $Data::Dumper::Sortkeys = 1;
139 local $Data::Dumper::Deparse = 1;
140 local $Data::Dumper::Freezer = 'XXX';
141 local *UNIVERSAL::XXX = sub {
144 $thing = {%$thing} if "$thing" =~ m/=HASH/;
145 $thing = [@$thing] if "$thing" =~ m/=ARRAY/;
146 $thing = \"$$thing" if "$thing" =~ m/=SCALAR/;
151 my $g = Data::Dumper::Dumper($got);
152 my $w = Data::Dumper::Dumper($want);
156 return $ctx->pass_and_release($name) if $bool;
157 return $ctx->fail_and_release($name, $g, $w, @diag);
162 $ctx->diag(join '', @_);
168 $ctx->note(join '', @_);
175 $ctx->plan(0, SKIP => $reason);
176 $ctx->release if $ctx;
180 my ($reason, $sub) = @_;
183 # This code is mostly copied from Test2::Todo in the Test2-Suite
185 my $hub = test2_stack->top;
186 my $filter = $hub->pre_filter(
188 my ($active_hub, $event) = @_;
189 if ($active_hub == $hub) {
190 $event->set_todo($reason) if $event->can('set_todo');
191 $event->add_amnesty({tag => 'TODO', details => $reason});
194 $event->add_amnesty({tag => 'TODO', details => $reason, inherited => 1});
202 $hub->pre_unfilter($filter);
204 $ctx->release if $ctx;
223 local $SIG{__WARN__} = sub { push @warnings => @_ };
230 local ($@, $!, $SIG{__DIE__});
231 my $ok = eval { $code->(); 1 };
232 my $error = $@ || 'SQUASHED ERROR';
233 return $ok ? undef : $error;
237 my ($name, $code) = @_;
240 my $be = caller->can('before_each');
244 my $bool = run_subtest($name, $code, 1);
254 my ($err, $out) = ("", "");
256 my $handles = test2_stack->top->format->handles;
259 my ($out_fh, $err_fh);
262 # Scalar refs as filehandles were added in 5.8.
264 open($out_fh, '>', \$out) or die "Failed to open a temporary STDOUT: $!";
265 open($err_fh, '>', \$err) or die "Failed to open a temporary STDERR: $!";
267 # Emulate scalar ref filehandles with a tie.
269 $out_fh = Test::Builder::IO::Scalar->new(\$out) or die "Failed to open a temporary STDOUT";
270 $err_fh = Test::Builder::IO::Scalar->new(\$err) or die "Failed to open a temporary STDERR";
273 test2_stack->top->format->set_handles([$out_fh, $err_fh, $out_fh]);
278 test2_stack->top->format->set_handles($handles);
301 Test2::Tools::Tiny - Tiny set of tools for unfortunate souls who cannot use
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.
311 =head1 USE Test2::Suite INSTEAD
313 Use L<Test2::Suite> if at all possible.
319 =item ok($bool, $name)
321 =item ok($bool, $name, @diag)
323 Run a simple assertion.
325 =item is($got, $want, $name)
327 =item is($got, $want, $name, @diag)
329 Assert that 2 strings are the same.
331 =item isnt($got, $do_not_want, $name)
333 =item isnt($got, $do_not_want, $name, @diag)
335 Assert that 2 strings are not the same.
337 =item like($got, $regex, $name)
339 =item like($got, $regex, $name, @diag)
341 Check that the input string matches the regex.
343 =item unlike($got, $regex, $name)
345 =item unlike($got, $regex, $name, @diag)
347 Check that the input string does not match the regex.
349 =item is_deeply($got, $want, $name)
351 =item is_deeply($got, $want, $name, @diag)
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.
358 Issue a diagnostics message to STDERR.
362 Issue a diagnostics message to STDOUT.
364 =item skip_all($reason)
368 =item todo $reason => sub { ... }
370 Run a block in TODO mode.
378 Set the plan to the current test count.
380 =item $warnings = warnings { ... }
382 Capture an arrayref of warnings from the block.
384 =item $exception = exception { ... }
386 Capture an exception.
388 =item tests $name => sub { ... }
392 =item $output = capture { ... }
394 Capture STDOUT and STDERR output.
396 Result looks like this:
407 The source code repository for Test2 can be found at
408 F<http://github.com/Test-More/test-more/>.
414 =item Chad Granum E<lt>exodist@cpan.orgE<gt>
422 =item Chad Granum E<lt>exodist@cpan.orgE<gt>
428 Copyright 2017 Chad Granum E<lt>exodist@cpan.orgE<gt>.
430 This program is free software; you can redistribute it and/or
431 modify it under the same terms as Perl itself.
433 See F<http://dev.perl.org/licenses/>