=pod

=head1 NAME

Test2::Transition - How to transition from Test::Builder to Test2

=head1 DESCRIPTION

This document demonstrates how to transition code from Test::Builder to Test2.
This is a list of things people frequently need to do, and how to do them with
both systems. This document also provides a list of things that had been done
in legacy Test::Builder that will break with Test2.

=head1 THINGS THAT BREAK

=head2 Test::Builder1.5/2 Support

=head3 The Problem

If you modified your code or tests such that they have behavior that is
conditional on the Test-Simple version, it is likely to break. A vast majority
of modules broken by Test2 fall into this category.

=head3 The Fix

The fix is to remove all Test::Builder1.5/2.0 related code. Either use the
lagacy Test::Builder API, or use Test2 directly.

=head2 Replacing the Test::Builder singleton

=head3 The Problem

Some test modules would replace the Test::Builder singleton instance with their
own instance or subclass. This was usually done to intercept, or modify results
as they happened.

The Test::Builder singleton is now a simple compatibility wrapper around
Test2. The Test::Builder singleton is no longer the central place for
results. Most results bypass the Test::Builder singleton completely, which
breaks and behavior intended when replacing the singleton.

=head3 The Fix

If you simply want to intercept all results instead of letting them go to TAP,
you should look at the L<Test2::API> docs and read about pushing a new hub onto
the hub stack. Replacing the hub temporarily is now the correct way to
intercept results.

If your goal is purely monitoring of events use the C<< Test2::Hub->listen() >>
method exported by Test::More to watch events as they are fired. If you wish to
modify results before they go to TAP look at the C<< Test2::Hub->filter() >>
method.

=head2 Directly Accessing Hash Elements

=head3 The Problem

Some modules look directly at hash keys on the Test::Builder singleton. The
problem here is that the Test::Builder singleton no longer holds anything
important.

=head3 The Fix

The fix is to use the API specified in L<Test2::API> to look at or modify state
as needed.

=head1 MAKE ASSERTIONS -> SEND EVENTS

=head2 LEGACY

    use Test::Builder;

    # A majority of tools out there do this:
    # my $TB = Test::Builder->new;
    # This works, but has always been wrong, forcing Test::Builder to implement
    # subtests as a horrific hack. It also causes problems for tools that try
    # to replace the singleton (also discouraged).

    sub my_ok($;$) {
        my ($bool, $name) = @_;
        my $TB = Test::Builder->new;
        $TB->ok($bool, $name);
    }

    sub my_diag($) {
        my ($msg) = @_;
        my $TB = Test::Builder->new;
        $TB->diag($msg);
    }

=head2 TEST2

    use Test2::API qw/context/;

    sub my_ok($;$) {
        my ($bool, $name) = @_;
        my $ctx = context();
        $ctx->ok($bool, $name);
        $ctx->release;
    }

    sub my_diag($) {
        my ($msg) = @_;
        my $ctx = context();
        $ctx->diag($msg);
        $ctx->release;
    }

The context object has API compatible implementations of the following methods:

=over 4

=item ok($bool, $name)

=item diag(@messages)

=item note(@messages)

=item subtest($name, $code)

=back

If you are looking for helpers with C<is>, C<like>, and others, see
L<Test2::Suite>.

=head1 WRAP EXISTING TOOLS

=head2 LEGACY

    use Test::More;

    sub exclusive_ok {
        my ($bool1, $bool2, $name) = @_;

        # Ensure errors are reported 1 level higher
        local $Test::Builder::Level = $Test::Builder::Level + 1;

        $ok = $bool1 || $bool2;
        $ok &&= !($bool1 && $bool2);
        ok($ok, $name);

        return $bool;
    }

Every single tool in the chain from this, to C<ok>, to anything C<ok> calls
needs to increment the C<$Level> variable. When an error occurs Test::Builder
will do a trace to the stack frame determined by C<$Level>, and report that
file+line as the one where the error occurred. If you or any other tool you use
forgets to set C<$Level> then errors will be reported to the wrong place.

=head2 TEST2

    use Test::More;

    sub exclusive_ok {
        my ($bool1, $bool2, $name) = @_;

        # Grab and store the context, even if you do not need to use it
        # directly.
        my $ctx = context();

        $ok = $bool1 || $bool2;
        $ok &&= !($bool1 && $bool2);
        ok($ok, $name);

        $ctx->release;
        return $bool;
    }

Instead of using C<$Level> to perform a backtrace, Test2 uses a context
object. In this sample you create a context object and store it. This locks the
context (errors report 1 level up from here) for all wrapped tools to find. You
do not need to use the context object, but you do need to store it in a
variable. Once the sub ends the C<$ctx> variable is destroyed which lets future
tools find their own.

=head1 USING UTF8

=head2 LEGACY

    # Set the mode BEFORE anything loads Test::Builder
    use open ':std', ':encoding(utf8)';
    use Test::More;

Or

    # Modify the filehandles
    my $builder = Test::More->builder;
    binmode $builder->output,         ":encoding(utf8)";
    binmode $builder->failure_output, ":encoding(utf8)";
    binmode $builder->todo_output,    ":encoding(utf8)";

=head2 TEST2

    use Test2::API qw/test2_stack/;

    test2_stack->top->format->encoding('utf8');

Though a much better way is to use the L<Test2::Plugin::UTF8> plugin, which is
part of L<Test2::Suite>.

=head1 AUTHORS, CONTRIBUTORS AND REVIEWERS

The following people have all contributed to this document in some way, even if
only for review.

=over 4

=item Chad Granum (EXODIST) E<lt>exodist@cpan.orgE<gt>

=back

=head1 SOURCE

The source code repository for Test2 can be found at
F<http://github.com/Test-More/Test2/>.

=head1 MAINTAINER

=over 4

=item Chad Granum E<lt>exodist@cpan.orgE<gt>

=back

=head1 COPYRIGHT

Copyright 2016 Chad Granum E<lt>exodist7@gmail.comE<gt>.

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

See F<http://www.perl.com/perl/misc/Artistic.html>

=cut
