Blame t/lib/Test/RRA.pm

Packit Service d987f3
# Helper functions for test programs written in Perl.
Packit Service d987f3
#
Packit Service d987f3
# This module provides a collection of helper functions used by test programs
Packit Service d987f3
# written in Perl.  This is a general collection of functions that can be used
Packit Service d987f3
# by both C packages with Automake and by stand-alone Perl modules.  See
Packit Service d987f3
# Test::RRA::Automake for additional functions specifically for C Automake
Packit Service d987f3
# distributions.
Packit Service d987f3
Packit Service d987f3
package Test::RRA;
Packit Service d987f3
Packit Service d987f3
use 5.006;
Packit Service d987f3
use strict;
Packit Service d987f3
use warnings;
Packit Service d987f3
Packit Service d987f3
use Exporter;
Packit Service d987f3
use File::Temp;
Packit Service d987f3
use Test::More;
Packit Service d987f3
Packit Service d987f3
# For Perl 5.006 compatibility.
Packit Service d987f3
## no critic (ClassHierarchies::ProhibitExplicitISA)
Packit Service d987f3
Packit Service d987f3
# Declare variables that should be set in BEGIN for robustness.
Packit Service d987f3
our (@EXPORT_OK, @ISA, $VERSION);
Packit Service d987f3
Packit Service d987f3
# Set $VERSION and everything export-related in a BEGIN block for robustness
Packit Service d987f3
# against circular module loading (not that we load any modules, but
Packit Service d987f3
# consistency is good).
Packit Service d987f3
BEGIN {
Packit Service d987f3
    @ISA       = qw(Exporter);
Packit Service d987f3
    @EXPORT_OK = qw(
Packit Service d987f3
      is_file_contents skip_unless_author skip_unless_automated use_prereq
Packit Service d987f3
    );
Packit Service d987f3
Packit Service d987f3
    # This version should match the corresponding rra-c-util release, but with
Packit Service d987f3
    # two digits for the minor version, including a leading zero if necessary,
Packit Service d987f3
    # so that it will sort properly.
Packit Service d987f3
    $VERSION = '6.02';
Packit Service d987f3
}
Packit Service d987f3
Packit Service d987f3
# Compare a string to the contents of a file, similar to the standard is()
Packit Service d987f3
# function, but to show the line-based unified diff between them if they
Packit Service d987f3
# differ.
Packit Service d987f3
#
Packit Service d987f3
# $got      - The output that we received
Packit Service d987f3
# $expected - The path to the file containing the expected output
Packit Service d987f3
# $message  - The message to use when reporting the test results
Packit Service d987f3
#
Packit Service d987f3
# Returns: undef
Packit Service d987f3
#  Throws: Exception on failure to read or write files or run diff
Packit Service d987f3
sub is_file_contents {
Packit Service d987f3
    my ($got, $expected, $message) = @_;
Packit Service d987f3
Packit Service d987f3
    # If they're equal, this is simple.
Packit Service d987f3
    open(my $fh, '<', $expected) or BAIL_OUT("Cannot open $expected: $!\n");
Packit Service d987f3
    my $data = do { local $/ = undef; <$fh> };
Packit Service d987f3
    close($fh) or BAIL_OUT("Cannot close $expected: $!\n");
Packit Service d987f3
    if ($got eq $data) {
Packit Service d987f3
        is($got, $data, $message);
Packit Service d987f3
        return;
Packit Service d987f3
    }
Packit Service d987f3
Packit Service d987f3
    # Otherwise, we show a diff, but only if we have IPC::System::Simple.
Packit Service d987f3
    eval { require IPC::System::Simple };
Packit Service d987f3
    if ($@) {
Packit Service d987f3
        ok(0, $message);
Packit Service d987f3
        return;
Packit Service d987f3
    }
Packit Service d987f3
Packit Service d987f3
    # They're not equal.  Write out what we got so that we can run diff.
Packit Service d987f3
    my $tmp     = File::Temp->new();
Packit Service d987f3
    my $tmpname = $tmp->filename;
Packit Service d987f3
    print {$tmp} $got or BAIL_OUT("Cannot write to $tmpname: $!\n");
Packit Service d987f3
    my @command = ('diff', '-u', $expected, $tmpname);
Packit Service d987f3
    my $diff = IPC::System::Simple::capturex([0 .. 1], @command);
Packit Service d987f3
    diag($diff);
Packit Service d987f3
Packit Service d987f3
    # Remove the temporary file and report failure.
Packit Service d987f3
    ok(0, $message);
Packit Service d987f3
    return;
Packit Service d987f3
}
Packit Service d987f3
Packit Service d987f3
# Skip this test unless author tests are requested.  Takes a short description
Packit Service d987f3
# of what tests this script would perform, which is used in the skip message.
Packit Service d987f3
# Calls plan skip_all, which will terminate the program.
Packit Service d987f3
#
Packit Service d987f3
# $description - Short description of the tests
Packit Service d987f3
#
Packit Service d987f3
# Returns: undef
Packit Service d987f3
sub skip_unless_author {
Packit Service d987f3
    my ($description) = @_;
Packit Service d987f3
    if (!$ENV{AUTHOR_TESTING}) {
Packit Service d987f3
        plan skip_all => "$description only run for author";
Packit Service d987f3
    }
Packit Service d987f3
    return;
Packit Service d987f3
}
Packit Service d987f3
Packit Service d987f3
# Skip this test unless doing automated testing or release testing.  This is
Packit Service d987f3
# used for tests that should be run by CPAN smoke testing or during releases,
Packit Service d987f3
# but not for manual installs by end users.  Takes a short description of what
Packit Service d987f3
# tests this script would perform, which is used in the skip message.  Calls
Packit Service d987f3
# plan skip_all, which will terminate the program.
Packit Service d987f3
#
Packit Service d987f3
# $description - Short description of the tests
Packit Service d987f3
#
Packit Service d987f3
# Returns: undef
Packit Service d987f3
sub skip_unless_automated {
Packit Service d987f3
    my ($description) = @_;
Packit Service d987f3
    for my $env (qw(AUTOMATED_TESTING RELEASE_TESTING AUTHOR_TESTING)) {
Packit Service d987f3
        return if $ENV{$env};
Packit Service d987f3
    }
Packit Service d987f3
    plan skip_all => "$description normally skipped";
Packit Service d987f3
    return;
Packit Service d987f3
}
Packit Service d987f3
Packit Service d987f3
# Attempt to load a module and skip the test if the module could not be
Packit Service d987f3
# loaded.  If the module could be loaded, call its import function manually.
Packit Service d987f3
# If the module could not be loaded, calls plan skip_all, which will terminate
Packit Service d987f3
# the program.
Packit Service d987f3
#
Packit Service d987f3
# The special logic here is based on Test::More and is required to get the
Packit Service d987f3
# imports to happen in the caller's namespace.
Packit Service d987f3
#
Packit Service d987f3
# $module  - Name of the module to load
Packit Service d987f3
# @imports - Any arguments to import, possibly including a version
Packit Service d987f3
#
Packit Service d987f3
# Returns: undef
Packit Service d987f3
sub use_prereq {
Packit Service d987f3
    my ($module, @imports) = @_;
Packit Service d987f3
Packit Service d987f3
    # If the first import looks like a version, pass it as a bare string.
Packit Service d987f3
    my $version = q{};
Packit Service d987f3
    if (@imports >= 1 && $imports[0] =~ m{ \A \d+ (?: [.][\d_]+ )* \z }xms) {
Packit Service d987f3
        $version = shift(@imports);
Packit Service d987f3
    }
Packit Service d987f3
Packit Service d987f3
    # Get caller information to put imports in the correct package.
Packit Service d987f3
    my ($package) = caller;
Packit Service d987f3
Packit Service d987f3
    # Do the import with eval, and try to isolate it from the surrounding
Packit Service d987f3
    # context as much as possible.  Based heavily on Test::More::_eval.
Packit Service d987f3
    ## no critic (BuiltinFunctions::ProhibitStringyEval)
Packit Service d987f3
    ## no critic (ValuesAndExpressions::ProhibitImplicitNewlines)
Packit Service d987f3
    my ($result, $error, $sigdie);
Packit Service d987f3
    {
Packit Service d987f3
        local $@            = undef;
Packit Service d987f3
        local $!            = undef;
Packit Service d987f3
        local $SIG{__DIE__} = undef;
Packit Service d987f3
        $result = eval qq{
Packit Service d987f3
            package $package;
Packit Service d987f3
            use $module $version \@imports;
Packit Service d987f3
            1;
Packit Service d987f3
        };
Packit Service d987f3
        $error = $@;
Packit Service d987f3
        $sigdie = $SIG{__DIE__} || undef;
Packit Service d987f3
    }
Packit Service d987f3
Packit Service d987f3
    # If the use failed for any reason, skip the test.
Packit Service d987f3
    if (!$result || $error) {
Packit Service d987f3
        my $name = length($version) > 0 ? "$module $version" : $module;
Packit Service d987f3
        plan skip_all => "$name required for test";
Packit Service d987f3
    }
Packit Service d987f3
Packit Service d987f3
    # If the module set $SIG{__DIE__}, we cleared that via local.  Restore it.
Packit Service d987f3
    ## no critic (Variables::RequireLocalizedPunctuationVars)
Packit Service d987f3
    if (defined($sigdie)) {
Packit Service d987f3
        $SIG{__DIE__} = $sigdie;
Packit Service d987f3
    }
Packit Service d987f3
    return;
Packit Service d987f3
}
Packit Service d987f3
Packit Service d987f3
1;
Packit Service d987f3
__END__
Packit Service d987f3
Packit Service d987f3
=for stopwords
Packit Service d987f3
Allbery Allbery's DESC bareword sublicense MERCHANTABILITY NONINFRINGEMENT
Packit Service d987f3
rra-c-util CPAN
Packit Service d987f3
Packit Service d987f3
=head1 NAME
Packit Service d987f3
Packit Service d987f3
Test::RRA - Support functions for Perl tests
Packit Service d987f3
Packit Service d987f3
=head1 SYNOPSIS
Packit Service d987f3
Packit Service d987f3
    use Test::RRA
Packit Service d987f3
      qw(skip_unless_author skip_unless_automated use_prereq);
Packit Service d987f3
Packit Service d987f3
    # Skip this test unless author tests are requested.
Packit Service d987f3
    skip_unless_author('Coding style tests');
Packit Service d987f3
Packit Service d987f3
    # Skip this test unless doing automated or release testing.
Packit Service d987f3
    skip_unless_automated('POD syntax tests');
Packit Service d987f3
Packit Service d987f3
    # Load modules, skipping the test if they're not available.
Packit Service d987f3
    use_prereq('Perl6::Slurp', 'slurp');
Packit Service d987f3
    use_prereq('Test::Script::Run', '0.04');
Packit Service d987f3
Packit Service d987f3
=head1 DESCRIPTION
Packit Service d987f3
Packit Service d987f3
This module collects utility functions that are useful for Perl test scripts.
Packit Service d987f3
It assumes Russ Allbery's Perl module layout and test conventions and will
Packit Service d987f3
only be useful for other people if they use the same conventions.
Packit Service d987f3
Packit Service d987f3
=head1 FUNCTIONS
Packit Service d987f3
Packit Service d987f3
None of these functions are imported by default.  The ones used by a script
Packit Service d987f3
should be explicitly imported.
Packit Service d987f3
Packit Service d987f3
=over 4
Packit Service d987f3
Packit Service d987f3
=item skip_unless_author(DESC)
Packit Service d987f3
Packit Service d987f3
Checks whether AUTHOR_TESTING is set in the environment and skips the whole
Packit Service d987f3
test (by calling C<plan skip_all> from Test::More) if it is not.  DESC is a
Packit Service d987f3
description of the tests being skipped.  A space and C<only run for author>
Packit Service d987f3
will be appended to it and used as the skip reason.
Packit Service d987f3
Packit Service d987f3
=item skip_unless_automated(DESC)
Packit Service d987f3
Packit Service d987f3
Checks whether AUTHOR_TESTING, AUTOMATED_TESTING, or RELEASE_TESTING are set
Packit Service d987f3
in the environment and skips the whole test (by calling C<plan skip_all> from
Packit Service d987f3
Test::More) if they are not.  This should be used by tests that should not run
Packit Service d987f3
during end-user installs of the module, but which should run as part of CPAN
Packit Service d987f3
smoke testing and release testing.
Packit Service d987f3
Packit Service d987f3
DESC is a description of the tests being skipped.  A space and C
Packit Service d987f3
skipped> will be appended to it and used as the skip reason.
Packit Service d987f3
Packit Service d987f3
=item use_prereq(MODULE[, VERSION][, IMPORT ...])
Packit Service d987f3
Packit Service d987f3
Attempts to load MODULE with the given VERSION and import arguments.  If this
Packit Service d987f3
fails for any reason, the test will be skipped (by calling C<plan skip_all>
Packit Service d987f3
from Test::More) with a skip reason saying that MODULE is required for the
Packit Service d987f3
test.
Packit Service d987f3
Packit Service d987f3
VERSION will be passed to C<use> as a version bareword if it looks like a
Packit Service d987f3
version number.  The remaining IMPORT arguments will be passed as the value of
Packit Service d987f3
an array.
Packit Service d987f3
Packit Service d987f3
=back
Packit Service d987f3
Packit Service d987f3
=head1 AUTHOR
Packit Service d987f3
Packit Service d987f3
Russ Allbery <eagle@eyrie.org>
Packit Service d987f3
Packit Service d987f3
=head1 COPYRIGHT AND LICENSE
Packit Service d987f3
Packit Service d987f3
Copyright 2013, 2014 The Board of Trustees of the Leland Stanford Junior
Packit Service d987f3
University
Packit Service d987f3
Packit Service d987f3
Permission is hereby granted, free of charge, to any person obtaining a copy
Packit Service d987f3
of this software and associated documentation files (the "Software"), to deal
Packit Service d987f3
in the Software without restriction, including without limitation the rights
Packit Service d987f3
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
Packit Service d987f3
copies of the Software, and to permit persons to whom the Software is
Packit Service d987f3
furnished to do so, subject to the following conditions:
Packit Service d987f3
Packit Service d987f3
The above copyright notice and this permission notice shall be included in all
Packit Service d987f3
copies or substantial portions of the Software.
Packit Service d987f3
Packit Service d987f3
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Packit Service d987f3
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Packit Service d987f3
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
Packit Service d987f3
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Packit Service d987f3
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
Packit Service d987f3
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
Packit Service d987f3
SOFTWARE.
Packit Service d987f3
Packit Service d987f3
=head1 SEE ALSO
Packit Service d987f3
Packit Service d987f3
Test::More(3), Test::RRA::Automake(3), Test::RRA::Config(3)
Packit Service d987f3
Packit Service d987f3
This module is maintained in the rra-c-util package.  The current version is
Packit Service d987f3
available from L<https://www.eyrie.org/~eagle/software/rra-c-util/>.
Packit Service d987f3
Packit Service d987f3
The functions to control when tests are run use environment variables defined
Packit Service d987f3
by the L
Packit Service d987f3
Consensus|https://github.com/Perl-Toolchain-Gang/toolchain-site/blob/master/lancaster-consensus.md>.
Packit Service d987f3
Packit Service d987f3
=cut