NAME
Testing - Helper functions for testing Pod-Html
SYNOPSIS
use Testing qw( setup_testing_dir xconvert );
my $tdir = setup_testing_dir( {
debug => $debug,
} );
$args = {
podstub => "htmldir1",
description => "test --htmldir and --htmlroot 1a",
expect => $expect_raw,
p2h => {
podpath => File::Spec::Unix->catdir($relcwd, 't') . ":" .
File::Spec::Unix->catdir($relcwd, 'corpus/test.lib'),
podroot => catpath($v, '/', ''),
htmldir => 't',
quiet => 1,
},
debug => $debug,
};
xconvert($args);
DESCRIPTION
This module exports, upon request only, 2 subroutines which are used in most of the files in the core distribution test suite for Pod-HTML (ext/Pod-Html/t/*.t). In the future we may add additional subroutines, particularly to better diagnose problems with Pod-Html.
Pod-Html's Testing Structure
As of version 1.26 of this module (early 2021), the testing structure consists of 16 .pod files and 18 .t files located in two subdirectories, corpus/ and t/. Let's analyze these by directory.
Files in corpus/
There are currently 2 .pod files in corpus/ both of which are old versions of pod/*.pod files selected to give some complexity to the test suite. Since we don't actually attempt to make HTML out of their POD, we don't need to discuss them further.
Files in t/
There are currently 14 .pod files and 18 .t files in t/. Both of these numbers may change in the future.
Currently there are 2 t/.t files (t/anchorify.t and t/eol.t) which exercise certain functionality of Pod::Html but which do not require t/*.pod files as data input. These files do not make use of the subroutines exported by this module. We may add more test files like this in the future to ensure high test coverage, but don't need to discuss them further here.
The remaining 16 t/*.t test programs make use of the testing subroutines exported by this module. Most, but not all, of these test programs make use of the t/*.pod files. Each such test program makes use of only 1 t/*.pod file at a time, though there are several cases where several, similarly named, test programs make use of the same t/*.pod file for data input. For example,
t/crossref.t
t/crossref2.t
t/crossref3.t
all make use of
t/crossref.pod
Each t/*.pod file consists solely of simple documentation in POD format.
High-level description of programs which use .pod files as input
Each of the t/*.t programs which makes use of a given t/*.pod file slurps the text of a single such t/*.pod file into memory. The test program holds text in a DATA
handle which serves as a template for the HTML expected to be generated by running the t/*.pod file through Pod::Html::pod2html()
. The HTML output by Pod::Html::pod2html()
can vary greatly, particularly with respect to links, depending on the arguments passed to that function. The HTML output will also be affected by the underlying operating system, e.g., with respect to path separators. Hence, we cannot hard-code the expected HTML output into the DATA
template or any place else. We have to allow Pod::Html::pod2html()
to massage the template data to get an "expected output" against which we match the "actual output" which comes from running Pod::Html::pod2html()
over the text originally slurped into memory from the t/*.pod file.
Granted, there is a certain amount of circularity in this testing regimen. On a given operating system, with a given t/*.pod file as raw input, a given POD parser invoked within Pod::Html::pod2html()
and a given set of arguments passed to pod2html()
, there can and should be only one possible HTML string generated as output. What we currently have in a given test program's DATA
handle is merely that HTML string retrofitted with certain template elements as needed to make the "got" and the "expected" identical. We're not testing whether we're generating "good" HTML. We're simply testing that we get consistent results out of pod2html()
year after year.
How a test program works step-by-step
Here we continue to focus on those test programs which make use of the testing functions exported by Testing and which take a t/*.pod file as input.
We assume that we begin our tests from the top level of the Perl 5 core distribution and are using t/harness. Hence, to run the test files we say:
cd t; ./perl harness ../ext/Pod-Html/t/*.t; cd -
The program then slurps contents of the DATA
handle into memory.
The program then calls setup_testing_dir()
from this module to create a temporary directory and populate it as needed. setup_testing_dir()
returns the absolute path to that directory, but at the point where that subroutine returns you are actually located two levels beneath the temporary directory in a directory whose relative path is ext/Pod-Html/. (This is equivalent to being in toplevel/ext/Pod-Html/ for tests in versions of Pod-Html distributed with earlier versions of perl.)
Note that this means that at the end of the program you will have to switch back to your starting directory so that the tempdir can automatically be cleaned up. We automate this via an END
block.
You then prepare arguments for our principal testing function, xconvert()
(which supersedes the former convert_n_test()
. These arguments take the form of a single hash reference. One customary but optional element in that hashref, p2h
, is itself a hashref of key-value pairs corresponding to switches passed to the pod2html command-line utility or to Pod::Html::pod2html()
. The other elements in the hashref passed to xconvert()
include the stub of the basename of the t/*.pod file being used, the text of that file (which we've already slurped into memory), the test description, and whether we want extra debugging output or not. The program then adds a key-value pair to indicate whether we're running via core distribution test harness or not.
The hashref is then passed to xconvert()
which internally generates an expected HTML output string by massaging the text read in from the DATA
handle. xconvert()
reads in the relevant t/*.pod file and passes it to Pod::Html::pod2html()
, which parses the POD and generates the actual HTML output. If "got" matches "expected", a PASS is recorded for this instance of xconvert()
.
As the example of t/htmldir1.t illustrates:
The user can define a variety of arguments to be passed through to
Pod::Html::pod2html()
.my ($v, $d) = splitpath(cwd(), 1); my @dirs = splitdir($d); shift @dirs if $dirs[0] eq ''; my $relcwd = join '/', @dirs; $args = { ... p2h => { podpath => File::Spec::Unix->catdir($relcwd, 't') . ":" . File::Spec::Unix->catdir($relcwd, 'corpus/test.lib'), podroot => catpath($v, '/', ''), htmldir => 't', quiet => 1, }, ... };
The user can try out a variety of different arguments in the
p2h
element and end up with the same HTML output as predicted by theDATA
template by callingxconvert()
more than once per file.$args = { podstub => "htmldir1", description => "test --htmldir and --htmlroot 1a", expect => $expect_raw, p2h => { podpath => File::Spec::Unix->catdir($relcwd, 't') . ":" . File::Spec::Unix->catdir($relcwd, 'corpus/test.lib'), podroot => catpath($v, '/', ''), htmldir => 't', quiet => 1, }, }; xconvert($args); $args = { podstub => "htmldir1", description => "test --htmldir and --htmlroot 1b", expect => $expect_raw, p2h => { podpath => $relcwd, podroot => catpath($v, '/', ''), htmldir => catdir($relcwd, 't'), htmlroot => '/', quiet => 1, }, }; xconvert($args);
Note that in the two "runs" above, the values for
podstub
are the same, but the arguments top2h
differ; we've distinguished the two runs by different values fordescription
.
Note that all runs within an individual t/*.t program share the same temporary directory. Since Pod::Html::pod2html()
typically caches its understanding of where .pod files are located, there is a possibility that the contents of the cache may affect the generated HTML output in an adverse way. This possibility will be addressed in an upcoming version of this program.
When all runs have been completed (as noted above), the END
block brings us back to the directory we started from to permit the temporary directory and its contents to be cleanly deleted.
SUBROUTINES
setup_testing_dir()
Purpose
Create and populate a temporary directory to hold all activity for a single t/*.t program.
Arguments
$tdir = setup_testing_dir( { startdir => $startdir, debug => $debug, } );
Single hash reference with two possible elements.
debug
A Boolean which you will typically set at the start of your program. A Perl-true value prints out your location and creates a temporary directory which is not cleaned up at the program's completion, thereby permitting you to examine the intermediate files created by the program.
Return Value
String holding the absolute path of the temporary directory.
Comments
The function
chdir
s internally and leaves you in a directory called ext/Pod-Html beneath the temporary directory found in the return value.The function is somewhat equivalent to testing helper function
make_test_dir
in t/pod2html-lib.pl in versions of Pod-Html shipped with versions of perl up through 5.32.
xconvert()
Purpose
Compare whether the HTML generated by
Pod::Html::pod2html()
's parsing of a .pod file matches the expectation generated by parsing theDATA
block within the test file.Arguments
Single hash reference.
$args = { podstub => "htmldir5", description => "test --htmldir and --htmlroot 5", expect => $expect_raw, p2h => { podpath => 't:corpus/test.lib', podroot => $cwd, htmldir => $cwd, htmlroot => '/', quiet => 1, }, debug => $debug, }; $args->{core} = 1 if $ENV{PERL_CORE};
Elements are as follows:
podstub
String holding the stub (or stem) of the .pod file being used as input. The stub is the basename of the file less the file extension or suffix. (Equivalent to the first argument passed to the former
convert_and_test
test helper routine.) Required.description
String holding the description (or name or label) in typical TAP syntax. (Equivalent to the second argument passed to the former
convert_and_test
helper routine.) Required.expect
String holding the "raw" expectations read in from the
DATA
handle. Each run ofxconvert()
within a given test file should have the same value for this key. Required.p2h
Hash reference holding arguments passed to
Pod::Html::pod2html()
(though without the leading double hyphens (--
). See documentation for Pod::Html. Optional, but mostly necessary. In particular, if a .pod file contains anyL<>
tags, apodpath
element almost always needs to be supplied with a colon-delimited list of directories from which to begin a search for files containing POD.debug
Boolean, generally set once at the program's top. When Perl-true, displays extra debugging output, including turning on
Pod::Html::pod2html()
'sverbose
option. Optional.core
Boolean. This should be set to a Perl-true value when the file is to be run from the test harness rather than from the top-level of the repository.
Return Value
Not explicitly defined, but should return a Perl-true value upon completion.
Comment
This function essentially asks, "Are we getting the same HTML output the last time we tinkered with the code in this distribution?" Hence, it is dependent on the particular parsing and HTML composition functionality found within
Pod::Html::pod2html()
, which is a somewhat customized subclass of Pod::Simple::XHTML. If, in the future, we offer functionality based on other parsing classes, then theDATA
sections of the t/*.t files will have to be revised and perhaps the guts ofxconvert()
as well.This function is roughly equivalent to test helper function
convert_n_test()
in earlier versions of Pod-Html.
record_state_of_cache()
Purpose
During debugging, enable developer to examine the state of the Pod-Html cache after each call to
xconvert()
.Arguments
Single hash reference.
record_state_of_cache( { outdir => "$ENV{P5P_DIR}/pod-html", stub => $args->{podstub}, run => 1, } );
Hash reference has the following key-value pairs:
outdir
Any directory of your system to which you want a sorted copy of the cache to be printed.
stub
The same value you passed in
$args
toxconvert()
.run
Integer which you set manually to distinguish among multiple runs of this function within the same test file (presumably corresponding to multiple invocations of
xconvert()
).
Return Value
Implicitly returns Perl-true value.
Comment
Function will print out location of cache files and other information.
AUTHORS
The testing code reworked into its present form has many authors and dates back to the dawn of Perl 5, perhaps beyond. The documentation was written by James E Keenan in March 2021.