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