NAME

    Dist::Zilla::Tester::DieHard - Die hard Dist::Zilla, but save the
    messages

VERSION

    Version v0.6.4_01, released on 2016-12-18 08:53 UTC.

WHAT?

    Dist-Zilla-Tester-DieHard (or shortly DieHard) is a Dist::Zilla testing
    tool, it extends standard Dist::Zilla::Tester. If Dist::Zilla dies in
    construction, DieHard survives itself and saves the logger to let you
    analyze the messages.

SYNOPSIS

    Use Dist::Zilla::Tester::DieHard instead of Dist::Zilla::Tester:

        use Dist::Zilla::Tester::DieHard;   # instead of Dist::Zilla::Tester
        use Test::Deep qw{ cmp_deeply };
        use Test::Fatal;
        use Test::More;
    
        my $tzil = Builder->from_config( \%args );
        my $ex = exception { $tzil->build(); };
        is( $ex, $expected_exception, 'check status' );
        cmd_deeply( $tzil->log_messages, $expected_messages, 'check log messages' );

DESCRIPTION

    Dist::Zilla::Tester::DieHard (or, for brevity just DieHard) extends
    Dist::Zilla::Tester. If Dist::Zilla dies in construction, DieHard
    catches the exception, saves the exception and Dist::Zilla logger, and
    returns a "survivor" object.

    The returned survivor will fail in build (or release) method: it just
    rethrows the saved exception. However, such "delayed death" saves log
    messages for analysis:

        my $tzil = Builder->from_config( … );
            # ^ Construction never fails,
            #   it always returns an object,
            #   either builder or survivor.
        my $ex = exception { $tzil->build(); }; # or $tzil->release();
            # ^ Builder does build,
            #   survivor rethrows the saved exception.
        is( $ex, $expected_exception, 'check status' );
        cmd_deeply( $tzil->log_messages, $expected_messages, 'check log messages' );
            # ^ In *any* case we can check log messages.

 Survivor

    Survivor is shortened name of real class. Full class name is
    Dist::Zilla::Tester::DieHard::Survivor.

    Following methods can be called on Survivor object: clear_log_events,
    log_events, log_messages.

    build, release methods rethrow the saved exception.

NOTES

 Completeness

    Regular Dist::Zilla::Tester (as of v5.039) is not documented, so and I
    have to study its sources to find out features it provides.

    I have implemented only part of Dist::Zilla::Tester features, shown in
    "SYNOPSIS" and "DESCRIPTION". Minter is not (yet?) implemented — I do
    not need it (yet?). Probably there are other not (yet?) implemented
    features I am not aware of.

 Implementation Detail

    Implementation is simpler if Survivor saves not logger, but entire
    chrome (logger is a part of chrome). In such a case Survivor can
    consume Dist::Zilla::Tester::_Role and get bunch of methods "for free".

 most_recent_log_events Function

    Dist::Zilla::Tester 5.040 introduced most_recent_log_events function
    which can be used to retrieve log events even if builder construction
    failed. However:

      1. This module was implemented and released before DIst::Zilla 5.040.

      2. most_recent_log_events is not documented.

      3. Using most_recent_log_events requires revisiting existing test
      code, while DieHard does not.

WHY?

    Usually I test my Dist::Zilla plugins in such a way:

        ...
        use Dist::Zilla::Tester;
        use Test::Deep qw{ cmp_deeply };
        use Test::Fatal;
        use Test::More;
    
        my $tzil = Builder->from_config( ... );
        my $exception = exception { $tzil->build(); };
        if ( $expected_success ) {
            is( $exception, undef, 'status' );
        } else {
            like( $exception, qr{...}, 'status' );
        };
        cmd_deeply( $tzil->log_messages, $expected_messages, 'log messages' );
        ...

    The approach works well, until Dist::Zilla dies in from_config (e. g.
    if a plugin throws an exception in its construction).

    A straightforward attempt to catch exception thrown in from_config:

        my $tzil;
        my $exception = exception { $tzil = Builder->from_config( … ); };
        if ( $expected_success ) {
            is( $exception, undef, 'status' );
        } else {
            like( $exception, qr{…}, 'status' );
        };

    works but… from_config dies leaving $tzil undefined, log_messages
    method is called on undefined value definitely fails:

        cmd_deeply( $tzil->log_messages, $expected_messages, 'log messages' );
        #           ^^^^^^^^^^^^^^^^^^^
        #           Oops: $tzil undefined.

    Dist::Zilla dies, and all the messages logged by either Dist::Zilla or
    its plugins are buried with Dist::Zilla.

    Using Dist::Zilla::Tester::DieHard instead of regular
    Dist::Zilla::Tester solves this problem: even if a plugin throws an
    exception in constructor, Builder->from_config does not die but returns
    a "survivor" object which can be used to retrieve log messages.

AUTHOR

    Van de Bugger <van.de.bugger@gmail.com>

COPYRIGHT AND LICENSE

    Copyright (C) 2015, 2016 Van de Bugger

    License GPLv3+: The GNU General Public License version 3 or later
    <http://www.gnu.org/licenses/gpl-3.0.txt>.

    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.

