<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">package Test2::Tools::Tiny;
use strict;
use warnings;

BEGIN {
    if ($] lt "5.008") {
        require Test::Builder::IO::Scalar;
    }
}

use Scalar::Util qw/blessed/;

use Test2::Util qw/try/;
use Test2::API qw/context run_subtest test2_stack/;

use Test2::Hub::Interceptor();
use Test2::Hub::Interceptor::Terminator();

our $VERSION = '1.302199';

BEGIN { require Exporter; our @ISA = qw(Exporter) }
our @EXPORT = qw{
    ok is isnt like unlike is_deeply diag note skip_all todo plan done_testing
    warnings exception tests capture
};

sub ok($;$@) {
    my ($bool, $name, @diag) = @_;
    my $ctx = context();

    return $ctx-&gt;pass_and_release($name) if $bool;
    return $ctx-&gt;fail_and_release($name, @diag);
}

sub is($$;$@) {
    my ($got, $want, $name, @diag) = @_;
    my $ctx = context();

    my $bool;
    if (defined($got) &amp;&amp; defined($want)) {
        $bool = "$got" eq "$want";
    }
    elsif (defined($got) xor defined($want)) {
        $bool = 0;
    }
    else {    # Both are undef
        $bool = 1;
    }

    return $ctx-&gt;pass_and_release($name) if $bool;

    $got  = '*NOT DEFINED*' unless defined $got;
    $want = '*NOT DEFINED*' unless defined $want;
    unshift @diag =&gt; (
        "GOT:      $got",
        "EXPECTED: $want",
    );

    return $ctx-&gt;fail_and_release($name, @diag);
}

sub isnt($$;$@) {
    my ($got, $want, $name, @diag) = @_;
    my $ctx = context();

    my $bool;
    if (defined($got) &amp;&amp; defined($want)) {
        $bool = "$got" ne "$want";
    }
    elsif (defined($got) xor defined($want)) {
        $bool = 1;
    }
    else {    # Both are undef
        $bool = 0;
    }

    return $ctx-&gt;pass_and_release($name) if $bool;

    unshift @diag =&gt; "Strings are the same (they should not be)"
        unless $bool;

    return $ctx-&gt;fail_and_release($name, @diag);
}

sub like($$;$@) {
    my ($thing, $pattern, $name, @diag) = @_;
    my $ctx = context();

    my $bool;
    if (defined($thing)) {
        $bool = "$thing" =~ $pattern;
        unshift @diag =&gt; (
            "Value: $thing",
            "Does not match: $pattern"
        ) unless $bool;
    }
    else {
        $bool = 0;
        unshift @diag =&gt; "Got an undefined value.";
    }

    return $ctx-&gt;pass_and_release($name) if $bool;
    return $ctx-&gt;fail_and_release($name, @diag);
}

sub unlike($$;$@) {
    my ($thing, $pattern, $name, @diag) = @_;
    my $ctx = context();

    my $bool;
    if (defined($thing)) {
        $bool = "$thing" !~ $pattern;
        unshift @diag =&gt; (
            "Unexpected pattern match (it should not match)",
            "Value:   $thing",
            "Matches: $pattern"
        ) unless $bool;
    }
    else {
        $bool = 0;
        unshift @diag =&gt; "Got an undefined value.";
    }

    return $ctx-&gt;pass_and_release($name) if $bool;
    return $ctx-&gt;fail_and_release($name, @diag);
}

sub is_deeply($$;$@) {
    my ($got, $want, $name, @diag) = @_;
    my $ctx = context();

    no warnings 'once';
    require Data::Dumper;

    # Otherwise numbers might be unquoted
    local $Data::Dumper::Useperl  = 1;

    local $Data::Dumper::Sortkeys = 1;
    local $Data::Dumper::Deparse  = 1;
    local $Data::Dumper::Freezer  = 'XXX';
    local *UNIVERSAL::XXX         = sub {
        my ($thing) = @_;
        if (ref($thing)) {
            $thing = {%$thing}  if "$thing" =~ m/=HASH/;
            $thing = [@$thing]  if "$thing" =~ m/=ARRAY/;
            $thing = \"$$thing" if "$thing" =~ m/=SCALAR/;
        }
        $_[0] = $thing;
    };

    my $g = Data::Dumper::Dumper($got);
    my $w = Data::Dumper::Dumper($want);

    my $bool = $g eq $w;

    return $ctx-&gt;pass_and_release($name) if $bool;
    return $ctx-&gt;fail_and_release($name, $g, $w, @diag);
}

sub diag {
    my $ctx = context();
    $ctx-&gt;diag(join '', @_);
    $ctx-&gt;release;
}

sub note {
    my $ctx = context();
    $ctx-&gt;note(join '', @_);
    $ctx-&gt;release;
}

sub skip_all {
    my ($reason) = @_;
    my $ctx = context();
    $ctx-&gt;plan(0, SKIP =&gt; $reason);
    $ctx-&gt;release if $ctx;
}

sub todo {
    my ($reason, $sub) = @_;
    my $ctx = context();

    # This code is mostly copied from Test2::Todo in the Test2-Suite
    # distribution.
    my $hub    = test2_stack-&gt;top;
    my $filter = $hub-&gt;pre_filter(
        sub {
            my ($active_hub, $event) = @_;
            if ($active_hub == $hub) {
                $event-&gt;set_todo($reason) if $event-&gt;can('set_todo');
                $event-&gt;add_amnesty({tag =&gt; 'TODO', details =&gt; $reason});
            }
            else {
                $event-&gt;add_amnesty({tag =&gt; 'TODO', details =&gt; $reason, inherited =&gt; 1});
            }
            return $event;
        },
        inherit =&gt; 1,
        todo    =&gt; $reason,
    );
    $sub-&gt;();
    $hub-&gt;pre_unfilter($filter);

    $ctx-&gt;release if $ctx;
}

sub plan {
    my ($max) = @_;
    my $ctx = context();
    $ctx-&gt;plan($max);
    $ctx-&gt;release;
}

sub done_testing {
    my $ctx = context();
    $ctx-&gt;done_testing;
    $ctx-&gt;release;
}

sub warnings(&amp;) {
    my $code = shift;
    my @warnings;
    local $SIG{__WARN__} = sub { push @warnings =&gt; @_ };
    $code-&gt;();
    return \@warnings;
}

sub exception(&amp;) {
    my $code = shift;
    local ($@, $!, $SIG{__DIE__});
    my $ok = eval { $code-&gt;(); 1 };
    my $error = $@ || 'SQUASHED ERROR';
    return $ok ? undef : $error;
}

sub tests {
    my ($name, $code) = @_;
    my $ctx = context();

    my $be = caller-&gt;can('before_each');

    $be-&gt;($name) if $be;

    my $bool = run_subtest($name, $code, 1);

    $ctx-&gt;release;

    return $bool;
}

sub capture(&amp;) {
    my $code = shift;

    my ($err, $out) = ("", "");

    my $handles = test2_stack-&gt;top-&gt;format-&gt;handles;
    my ($ok, $e);
    {
        my ($out_fh, $err_fh);

        ($ok, $e) = try {
          # Scalar refs as filehandles were added in 5.8.
          if ($] ge "5.008") {
            open($out_fh, '&gt;', \$out) or die "Failed to open a temporary STDOUT: $!";
            open($err_fh, '&gt;', \$err) or die "Failed to open a temporary STDERR: $!";
          }
          # Emulate scalar ref filehandles with a tie.
          else {
            $out_fh = Test::Builder::IO::Scalar-&gt;new(\$out) or die "Failed to open a temporary STDOUT";
            $err_fh = Test::Builder::IO::Scalar-&gt;new(\$err) or die "Failed to open a temporary STDERR";
          }

            test2_stack-&gt;top-&gt;format-&gt;set_handles([$out_fh, $err_fh, $out_fh]);

            $code-&gt;();
        };
    }
    test2_stack-&gt;top-&gt;format-&gt;set_handles($handles);

    die $e unless $ok;

    $err =~ s/ $/_/mg;
    $out =~ s/ $/_/mg;

    return {
        STDOUT =&gt; $out,
        STDERR =&gt; $err,
    };
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Test2::Tools::Tiny - Tiny set of tools for unfortunate souls who cannot use
L&lt;Test2::Suite&gt;.

=head1 DESCRIPTION

You should really look at L&lt;Test2::Suite&gt;. This package is some very basic
essential tools implemented using L&lt;Test2&gt;. This exists only so that L&lt;Test2&gt;
and other tools required by L&lt;Test2::Suite&gt; can be tested. This is the package
L&lt;Test2&gt; uses to test itself.

=head1 USE Test2::Suite INSTEAD

Use L&lt;Test2::Suite&gt; if at all possible.

=head1 EXPORTS

=over 4

=item ok($bool, $name)

=item ok($bool, $name, @diag)

Run a simple assertion.

=item is($got, $want, $name)

=item is($got, $want, $name, @diag)

Assert that 2 strings are the same.

=item isnt($got, $do_not_want, $name)

=item isnt($got, $do_not_want, $name, @diag)

Assert that 2 strings are not the same.

=item like($got, $regex, $name)

=item like($got, $regex, $name, @diag)

Check that the input string matches the regex.

=item unlike($got, $regex, $name)

=item unlike($got, $regex, $name, @diag)

Check that the input string does not match the regex.

=item is_deeply($got, $want, $name)

=item is_deeply($got, $want, $name, @diag)

Check 2 data structures. Please note that this is a I&lt;DUMB&gt; implementation that
compares the output of L&lt;Data::Dumper&gt; against both structures.

=item diag($msg)

Issue a diagnostics message to STDERR.

=item note($msg)

Issue a diagnostics message to STDOUT.

=item skip_all($reason)

Skip all tests.

=item todo $reason =&gt; sub { ... }

Run a block in TODO mode.

=item plan($count)

Set the plan.

=item done_testing()

Set the plan to the current test count.

=item $warnings = warnings { ... }

Capture an arrayref of warnings from the block.

=item $exception = exception { ... }

Capture an exception.

=item tests $name =&gt; sub { ... }

Run a subtest.

=item $output = capture { ... }

Capture STDOUT and STDERR output.

Result looks like this:

    {
        STDOUT =&gt; "...",
        STDERR =&gt; "...",
    }

=back

=head1 SOURCE

The source code repository for Test2 can be found at
L&lt;https://github.com/Test-More/test-more/&gt;.

=head1 MAINTAINERS

=over 4

=item Chad Granum E&lt;lt&gt;exodist@cpan.orgE&lt;gt&gt;

=back

=head1 AUTHORS

=over 4

=item Chad Granum E&lt;lt&gt;exodist@cpan.orgE&lt;gt&gt;

=back

=head1 COPYRIGHT

Copyright 2020 Chad Granum E&lt;lt&gt;exodist@cpan.orgE&lt;gt&gt;.

This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.

See L&lt;https://dev.perl.org/licenses/&gt;

=cut
</pre></body></html>