NAME

dependencies.t - Checks that Build.PL lists all required CPAN modules.

DESCRIPTION

This test looks at the dependencies listed in the requires keys in Build.PL, and matches them against the actual run-time dependencies of the distribution's codebase. It then combines the dependencies listed in the requires and build_requires keys, and matches them against the actual compile-time dependencies. If any module is listed in Build.PL and not an actual dependency or vice versa (barring a well-known list of false positives and "pervasive" modules), the test fails.

This tests uses Module::ScanDeps, whose guts it rearranges in a creative fashion so as to eliminate most false positives and be able to pinpoint lines of source code in case the test fails. This results in a somewhat quirky implementation, but OTOH this test is only intended for running on the maintainer's system.

TWEAKABLES

%is_subpackage_of

A hash table that associates dependent packages (e.g. DBIx::Class::Schema, Catalyst::Controller) to the canonical top-level package in their distribution (e.g. DBIx::Class, Catalyst). Requirements and dependencies that name a key in %is_subpackage_of will be treated as though they were the corresponding value instead.

@pervasives

The list of modules that can be assumed to always be present regardless of the version of Perl, and need not be checked for. By default only pragmatic modules (starting with a lowercase letter) and modules that already were in 5.000 according to Module::CoreList are listed.

@maintainer_dependencies

The list of modules that are used in t/maintainer, and for which there should be provisions to bail out cleanly if they are missing (as demonstrated at the top of this very test script). Provided such modules are not listed as dependencies outside of t/maintainer, they will be ignored.

@sunken_dependencies

Put in there any modules that can get required without our crude source code parser being able to spot them.

@ignore

Put any other modules that cause false positives in there. Consider adding them to Build.PL instead, or rewriting your source code in a more contrived way so that Module::ScanDeps won't spot them anymore.

IMPLEMENTATION

We load the Build script so as to be able to enumerate the dependencies and call <find_pm_files() and <find_test_files()> on it.

The run-time dependencies are examined in the blib directory, as the Build script will often muck around with .pm files e.g. to remove the test suites.

On the other hand, we look for test dependencies everywhere, including in the footer of .pm files after the __END__ block (see details in inc/My/Tests/Below.pm)

TEST LIBRARY

file2mod($filename)

Turns $filename into a module name (e.g. Foo/Bar.pm becomes Foo::Bar) and returns it.

mod2file($filename)

The converse of "file2mod".

write_to_temp_file($string)

Writes $string into a newly created temporary file, and return its path.

list_deps(@files)

List dependencies found in @files, and returns them as a reference to a hash whose keys are module names and values are references to lists of hashes of the form

{
  line => $line,
  file => $file,
}

pointing at the precise location in the source code where the dependency was found. Only dependencies against a real .pm file are accounted for (not .so, not .bs); also, "@maintainer_dependencies" are not listed if found in t/maintainer.

skip_pod($filename, $fd, $pm)

skip_here_document($filename, $fd, $line)

Both functions advance $fd, an instance of IO::Handle, to skip past non-Perl source code constructs, and return true if they indeed did skip something (or throw an exception if they tried and failed). $pm is a token returned by "scan_line" in Module::ScanDeps; $line is a line of the Perl source file. $filename is only used to construct the text of error messages.

scan_line_some_more($line, $filename, $fd)

Works like "scan_line" in Module::ScanDeps, and works around the limitations thereof by detecting more forms of dependencies. $fd is available in case the code wants to slurp more lines in order to get hold of a complete Perl statement. $filename is only used to generate error messages.

is_our_own_file($path)

Returns true iff $path is one of the files in this package, and therefore should not be counted as a dependency.

compare_dependencies_ok($gothashref, $expectedlistref)

As the name implies. For each key in $gothashref which is not in $expectedlistref, shows the file name(s) and line number(s) of the chunk(s) that caused the dependency to be added. Conversely, for each entry in $expectedlistref which is not a key in $gothashref, warns about a spurious dependency in Build.PL.