xref: /openbsd-src/gnu/usr.bin/perl/cpan/podlators/t/lib/Test/RRA.pm (revision e068048151d29f2562a32185e21a8ba885482260)
1b8851fccSafresh1# Helper functions for test programs written in Perl.
2b8851fccSafresh1#
3b8851fccSafresh1# This module provides a collection of helper functions used by test programs
4b8851fccSafresh1# written in Perl.  This is a general collection of functions that can be used
5b8851fccSafresh1# by both C packages with Automake and by stand-alone Perl modules.  See
6b8851fccSafresh1# Test::RRA::Automake for additional functions specifically for C Automake
7b8851fccSafresh1# distributions.
8b46d8ef2Safresh1#
9b46d8ef2Safresh1# SPDX-License-Identifier: MIT
10b8851fccSafresh1
11b8851fccSafresh1package Test::RRA;
12b8851fccSafresh1
13*e0680481Safresh1use 5.010;
1456d68f1eSafresh1use base qw(Exporter);
15b8851fccSafresh1use strict;
16b8851fccSafresh1use warnings;
17b8851fccSafresh1
1856d68f1eSafresh1use Carp qw(croak);
195759b3d2Safresh1use File::Temp;
20b8851fccSafresh1
2156d68f1eSafresh1# Abort if Test::More was loaded before Test::RRA to be sure that we get the
2256d68f1eSafresh1# benefits of the Test::More probing below.
2356d68f1eSafresh1if ($INC{'Test/More.pm'}) {
2456d68f1eSafresh1    croak('Test::More loaded before Test::RRA');
2556d68f1eSafresh1}
2656d68f1eSafresh1
2756d68f1eSafresh1# Red Hat's base perl package doesn't include Test::More (one has to install
2856d68f1eSafresh1# the perl-core package in addition).  Try to detect this and skip any Perl
2956d68f1eSafresh1# tests if Test::More is not present.  This relies on Test::RRA being included
3056d68f1eSafresh1# before Test::More.
3156d68f1eSafresh1eval {
3256d68f1eSafresh1    require Test::More;
3356d68f1eSafresh1    Test::More->import();
3456d68f1eSafresh1};
3556d68f1eSafresh1if ($@) {
3656d68f1eSafresh1    print "1..0 # SKIP Test::More required for test\n"
3756d68f1eSafresh1      or croak('Cannot write to stdout');
3856d68f1eSafresh1    exit 0;
3956d68f1eSafresh1}
40b8851fccSafresh1
41b8851fccSafresh1# Declare variables that should be set in BEGIN for robustness.
4256d68f1eSafresh1our (@EXPORT_OK, $VERSION);
43b8851fccSafresh1
44b8851fccSafresh1# Set $VERSION and everything export-related in a BEGIN block for robustness
45b8851fccSafresh1# against circular module loading (not that we load any modules, but
46b8851fccSafresh1# consistency is good).
47b8851fccSafresh1BEGIN {
485759b3d2Safresh1    @EXPORT_OK = qw(
495759b3d2Safresh1        is_file_contents skip_unless_author skip_unless_automated use_prereq
505759b3d2Safresh1    );
51b8851fccSafresh1
52b8851fccSafresh1    # This version should match the corresponding rra-c-util release, but with
53b8851fccSafresh1    # two digits for the minor version, including a leading zero if necessary,
54b8851fccSafresh1    # so that it will sort properly.
55*e0680481Safresh1    $VERSION = '10.03';
565759b3d2Safresh1}
575759b3d2Safresh1
585759b3d2Safresh1# Compare a string to the contents of a file, similar to the standard is()
595759b3d2Safresh1# function, but to show the line-based unified diff between them if they
605759b3d2Safresh1# differ.
615759b3d2Safresh1#
625759b3d2Safresh1# $got      - The output that we received
635759b3d2Safresh1# $expected - The path to the file containing the expected output
645759b3d2Safresh1# $message  - The message to use when reporting the test results
655759b3d2Safresh1#
665759b3d2Safresh1# Returns: undef
675759b3d2Safresh1#  Throws: Exception on failure to read or write files or run diff
685759b3d2Safresh1sub is_file_contents {
695759b3d2Safresh1    my ($got, $expected, $message) = @_;
705759b3d2Safresh1
715759b3d2Safresh1    # If they're equal, this is simple.
725759b3d2Safresh1    open(my $fh, '<', $expected) or BAIL_OUT("Cannot open $expected: $!\n");
735759b3d2Safresh1    my $data = do { local $/ = undef; <$fh> };
745759b3d2Safresh1    close($fh) or BAIL_OUT("Cannot close $expected: $!\n");
755759b3d2Safresh1    if ($got eq $data) {
765759b3d2Safresh1        is($got, $data, $message);
775759b3d2Safresh1        return;
785759b3d2Safresh1    }
795759b3d2Safresh1
8056d68f1eSafresh1    # Otherwise, we show a diff, but only if we have IPC::System::Simple and
8156d68f1eSafresh1    # diff succeeds.  Otherwise, we fall back on showing the full expected and
8256d68f1eSafresh1    # seen output.
8356d68f1eSafresh1    eval {
8456d68f1eSafresh1        require IPC::System::Simple;
855759b3d2Safresh1
865759b3d2Safresh1        my $tmp = File::Temp->new();
875759b3d2Safresh1        my $tmpname = $tmp->filename;
885759b3d2Safresh1        print {$tmp} $got or BAIL_OUT("Cannot write to $tmpname: $!\n");
895759b3d2Safresh1        my @command = ('diff', '-u', $expected, $tmpname);
905759b3d2Safresh1        my $diff = IPC::System::Simple::capturex([0 .. 1], @command);
915759b3d2Safresh1        diag($diff);
9256d68f1eSafresh1    };
9356d68f1eSafresh1    if ($@) {
9456d68f1eSafresh1        diag('Expected:');
9556d68f1eSafresh1        diag($expected);
9656d68f1eSafresh1        diag('Seen:');
9756d68f1eSafresh1        diag($data);
9856d68f1eSafresh1    }
995759b3d2Safresh1
10056d68f1eSafresh1    # Report failure.
1015759b3d2Safresh1    ok(0, $message);
1025759b3d2Safresh1    return;
103b8851fccSafresh1}
104b8851fccSafresh1
105b8851fccSafresh1# Skip this test unless author tests are requested.  Takes a short description
106b8851fccSafresh1# of what tests this script would perform, which is used in the skip message.
107b8851fccSafresh1# Calls plan skip_all, which will terminate the program.
108b8851fccSafresh1#
109b8851fccSafresh1# $description - Short description of the tests
110b8851fccSafresh1#
111b8851fccSafresh1# Returns: undef
112b8851fccSafresh1sub skip_unless_author {
113b8851fccSafresh1    my ($description) = @_;
114b8851fccSafresh1    if (!$ENV{AUTHOR_TESTING}) {
11556d68f1eSafresh1        plan(skip_all => "$description only run for author");
116b8851fccSafresh1    }
117b8851fccSafresh1    return;
118b8851fccSafresh1}
119b8851fccSafresh1
120b8851fccSafresh1# Skip this test unless doing automated testing or release testing.  This is
121b8851fccSafresh1# used for tests that should be run by CPAN smoke testing or during releases,
122b8851fccSafresh1# but not for manual installs by end users.  Takes a short description of what
123b8851fccSafresh1# tests this script would perform, which is used in the skip message.  Calls
124b8851fccSafresh1# plan skip_all, which will terminate the program.
125b8851fccSafresh1#
126b8851fccSafresh1# $description - Short description of the tests
127b8851fccSafresh1#
128b8851fccSafresh1# Returns: undef
129b8851fccSafresh1sub skip_unless_automated {
130b8851fccSafresh1    my ($description) = @_;
131b8851fccSafresh1    for my $env (qw(AUTOMATED_TESTING RELEASE_TESTING AUTHOR_TESTING)) {
132b8851fccSafresh1        return if $ENV{$env};
133b8851fccSafresh1    }
13456d68f1eSafresh1    plan(skip_all => "$description normally skipped");
135b8851fccSafresh1    return;
136b8851fccSafresh1}
137b8851fccSafresh1
138b8851fccSafresh1# Attempt to load a module and skip the test if the module could not be
139b8851fccSafresh1# loaded.  If the module could be loaded, call its import function manually.
140b8851fccSafresh1# If the module could not be loaded, calls plan skip_all, which will terminate
141b8851fccSafresh1# the program.
142b8851fccSafresh1#
143b8851fccSafresh1# The special logic here is based on Test::More and is required to get the
144b8851fccSafresh1# imports to happen in the caller's namespace.
145b8851fccSafresh1#
146b8851fccSafresh1# $module  - Name of the module to load
147b8851fccSafresh1# @imports - Any arguments to import, possibly including a version
148b8851fccSafresh1#
149b8851fccSafresh1# Returns: undef
150b8851fccSafresh1sub use_prereq {
151b8851fccSafresh1    my ($module, @imports) = @_;
152b8851fccSafresh1
153b8851fccSafresh1    # If the first import looks like a version, pass it as a bare string.
154b8851fccSafresh1    my $version = q{};
155b8851fccSafresh1    if (@imports >= 1 && $imports[0] =~ m{ \A \d+ (?: [.][\d_]+ )* \z }xms) {
156b8851fccSafresh1        $version = shift(@imports);
157b8851fccSafresh1    }
158b8851fccSafresh1
159b8851fccSafresh1    # Get caller information to put imports in the correct package.
160b8851fccSafresh1    my ($package) = caller;
161b8851fccSafresh1
162b8851fccSafresh1    # Do the import with eval, and try to isolate it from the surrounding
163b8851fccSafresh1    # context as much as possible.  Based heavily on Test::More::_eval.
164b8851fccSafresh1    ## no critic (BuiltinFunctions::ProhibitStringyEval)
165b8851fccSafresh1    ## no critic (ValuesAndExpressions::ProhibitImplicitNewlines)
166b8851fccSafresh1    my ($result, $error, $sigdie);
167b8851fccSafresh1    {
168b8851fccSafresh1        local $@ = undef;
169b8851fccSafresh1        local $! = undef;
170b8851fccSafresh1        local $SIG{__DIE__} = undef;
171b8851fccSafresh1        $result = eval qq{
172b8851fccSafresh1            package $package;
173b8851fccSafresh1            use $module $version \@imports;
174b8851fccSafresh1            1;
175b8851fccSafresh1        };
176b8851fccSafresh1        $error = $@;
177b8851fccSafresh1        $sigdie = $SIG{__DIE__} || undef;
178b8851fccSafresh1    }
179b8851fccSafresh1
180b8851fccSafresh1    # If the use failed for any reason, skip the test.
181b8851fccSafresh1    if (!$result || $error) {
182b8851fccSafresh1        my $name = length($version) > 0 ? "$module $version" : $module;
18356d68f1eSafresh1        plan(skip_all => "$name required for test");
184b8851fccSafresh1    }
185b8851fccSafresh1
186b8851fccSafresh1    # If the module set $SIG{__DIE__}, we cleared that via local.  Restore it.
187b8851fccSafresh1    ## no critic (Variables::RequireLocalizedPunctuationVars)
188b8851fccSafresh1    if (defined($sigdie)) {
189b8851fccSafresh1        $SIG{__DIE__} = $sigdie;
190b8851fccSafresh1    }
191b8851fccSafresh1    return;
192b8851fccSafresh1}
193b8851fccSafresh1
194b8851fccSafresh11;
195b8851fccSafresh1__END__
196b8851fccSafresh1
197b8851fccSafresh1=for stopwords
198b8851fccSafresh1Allbery Allbery's DESC bareword sublicense MERCHANTABILITY NONINFRINGEMENT
199*e0680481Safresh1rra-c-util CPAN diff
200b8851fccSafresh1
201b8851fccSafresh1=head1 NAME
202b8851fccSafresh1
203b8851fccSafresh1Test::RRA - Support functions for Perl tests
204b8851fccSafresh1
205b8851fccSafresh1=head1 SYNOPSIS
206b8851fccSafresh1
207b8851fccSafresh1    use Test::RRA
208b8851fccSafresh1      qw(skip_unless_author skip_unless_automated use_prereq);
209b8851fccSafresh1
210b8851fccSafresh1    # Skip this test unless author tests are requested.
211b8851fccSafresh1    skip_unless_author('Coding style tests');
212b8851fccSafresh1
213b8851fccSafresh1    # Skip this test unless doing automated or release testing.
214b8851fccSafresh1    skip_unless_automated('POD syntax tests');
215b8851fccSafresh1
216b8851fccSafresh1    # Load modules, skipping the test if they're not available.
217b8851fccSafresh1    use_prereq('Perl6::Slurp', 'slurp');
218b8851fccSafresh1    use_prereq('Test::Script::Run', '0.04');
219b8851fccSafresh1
220b8851fccSafresh1=head1 DESCRIPTION
221b8851fccSafresh1
222b8851fccSafresh1This module collects utility functions that are useful for Perl test scripts.
223b8851fccSafresh1It assumes Russ Allbery's Perl module layout and test conventions and will
224b8851fccSafresh1only be useful for other people if they use the same conventions.
225b8851fccSafresh1
22656d68f1eSafresh1This module B<must> be loaded before Test::More or it will abort during
22756d68f1eSafresh1import.  It will skip the test (by printing a skip message to standard output
22856d68f1eSafresh1and exiting with status 0, equivalent to C<plan skip_all>) during import if
22956d68f1eSafresh1Test::More is not available.  This allows tests written in Perl using this
23056d68f1eSafresh1module to be skipped if run on a system with Perl but not Test::More, such as
23156d68f1eSafresh1Red Hat systems with the C<perl> package but not the C<perl-core> package
23256d68f1eSafresh1installed.
23356d68f1eSafresh1
234b8851fccSafresh1=head1 FUNCTIONS
235b8851fccSafresh1
236b8851fccSafresh1None of these functions are imported by default.  The ones used by a script
237b8851fccSafresh1should be explicitly imported.
238b8851fccSafresh1
239b8851fccSafresh1=over 4
240b8851fccSafresh1
241*e0680481Safresh1=item is_file_contents(GOT, EXPECTED, MESSAGE)
242*e0680481Safresh1
243*e0680481Safresh1Check a string against the contents of a file, showing the differences if any
244*e0680481Safresh1using diff (if IPC::System::Simple and diff are available).  GOT is the output
245*e0680481Safresh1the test received.  EXPECTED is the path to a file containing the expected
246*e0680481Safresh1output (not the output itself).  MESSAGE is a message to display alongside the
247*e0680481Safresh1test results.
248*e0680481Safresh1
249b8851fccSafresh1=item skip_unless_author(DESC)
250b8851fccSafresh1
251b8851fccSafresh1Checks whether AUTHOR_TESTING is set in the environment and skips the whole
252b8851fccSafresh1test (by calling C<plan skip_all> from Test::More) if it is not.  DESC is a
253b8851fccSafresh1description of the tests being skipped.  A space and C<only run for author>
254b8851fccSafresh1will be appended to it and used as the skip reason.
255b8851fccSafresh1
256b8851fccSafresh1=item skip_unless_automated(DESC)
257b8851fccSafresh1
258b8851fccSafresh1Checks whether AUTHOR_TESTING, AUTOMATED_TESTING, or RELEASE_TESTING are set
259b8851fccSafresh1in the environment and skips the whole test (by calling C<plan skip_all> from
260b8851fccSafresh1Test::More) if they are not.  This should be used by tests that should not run
261b8851fccSafresh1during end-user installs of the module, but which should run as part of CPAN
262b8851fccSafresh1smoke testing and release testing.
263b8851fccSafresh1
264b8851fccSafresh1DESC is a description of the tests being skipped.  A space and C<normally
265b8851fccSafresh1skipped> will be appended to it and used as the skip reason.
266b8851fccSafresh1
267b8851fccSafresh1=item use_prereq(MODULE[, VERSION][, IMPORT ...])
268b8851fccSafresh1
269b8851fccSafresh1Attempts to load MODULE with the given VERSION and import arguments.  If this
270b8851fccSafresh1fails for any reason, the test will be skipped (by calling C<plan skip_all>
271b8851fccSafresh1from Test::More) with a skip reason saying that MODULE is required for the
272b8851fccSafresh1test.
273b8851fccSafresh1
274b8851fccSafresh1VERSION will be passed to C<use> as a version bareword if it looks like a
275b8851fccSafresh1version number.  The remaining IMPORT arguments will be passed as the value of
276b8851fccSafresh1an array.
277b8851fccSafresh1
278b8851fccSafresh1=back
279b8851fccSafresh1
280b8851fccSafresh1=head1 AUTHOR
281b8851fccSafresh1
282b8851fccSafresh1Russ Allbery <eagle@eyrie.org>
283b8851fccSafresh1
284b8851fccSafresh1=head1 COPYRIGHT AND LICENSE
285b8851fccSafresh1
286*e0680481Safresh1Copyright 2016, 2018-2019, 2021 Russ Allbery <eagle@eyrie.org>
28756d68f1eSafresh1
28856d68f1eSafresh1Copyright 2013-2014 The Board of Trustees of the Leland Stanford Junior
289b8851fccSafresh1University
290b8851fccSafresh1
291b8851fccSafresh1Permission is hereby granted, free of charge, to any person obtaining a copy
292b8851fccSafresh1of this software and associated documentation files (the "Software"), to deal
293b8851fccSafresh1in the Software without restriction, including without limitation the rights
294b8851fccSafresh1to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
295b8851fccSafresh1copies of the Software, and to permit persons to whom the Software is
296b8851fccSafresh1furnished to do so, subject to the following conditions:
297b8851fccSafresh1
298b8851fccSafresh1The above copyright notice and this permission notice shall be included in all
299b8851fccSafresh1copies or substantial portions of the Software.
300b8851fccSafresh1
301b8851fccSafresh1THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
302b8851fccSafresh1IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
303b8851fccSafresh1FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
304b8851fccSafresh1AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
305b8851fccSafresh1LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
306b8851fccSafresh1OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
307b8851fccSafresh1SOFTWARE.
308b8851fccSafresh1
309b8851fccSafresh1=head1 SEE ALSO
310b8851fccSafresh1
311b8851fccSafresh1Test::More(3), Test::RRA::Automake(3), Test::RRA::Config(3)
312b8851fccSafresh1
313b8851fccSafresh1This module is maintained in the rra-c-util package.  The current version is
3145759b3d2Safresh1available from L<https://www.eyrie.org/~eagle/software/rra-c-util/>.
315b8851fccSafresh1
316b8851fccSafresh1The functions to control when tests are run use environment variables defined
317b8851fccSafresh1by the L<Lancaster
318b8851fccSafresh1Consensus|https://github.com/Perl-Toolchain-Gang/toolchain-site/blob/master/lancaster-consensus.md>.
319b8851fccSafresh1
320b8851fccSafresh1=cut
321b46d8ef2Safresh1
322b46d8ef2Safresh1# Local Variables:
323b46d8ef2Safresh1# copyright-at-end-flag: t
324b46d8ef2Safresh1# End:
325