NAME
tests-covering - Print the tests that cover the files, subs or changes you name.
VERSION
version 0.001
SYNOPSIS
tests-covering [options] FILE...
git diff --cached --name-only --diff-filter=ACMRD | tests-covering
git diff --cached | tests-covering --diff
tests-covering --sub NAME FILE
tests-covering --by TEST...
tests-covering --refresh
Modes, of which you can give one:
--diff read a diff from STDIN, and print the tests it could break
--sub NAME print the tests that ran the sub NAME in FILE
--by print the files that each TEST loaded
--refresh run the stale tests under coverage, and print nothing
Options:
--root DIR the distribution; default: found from the current directory
--test-dir DIR a directory of tests, relative to the root; repeatable; default: t
--lib DIR a directory for PERL5LIB, relative to the root; repeatable; default: lib
--jobs N how many coverage runs at once; default: 1
--cache-dir DIR where the coverage records are kept
--help this text
DESCRIPTION
Prints the tests that cover any of the files you name, one per line, relative to the current directory. With no files on the command line, it reads their names from standard input, one per line. A file that is relative is relative to the current directory.
Tests that are new, or that changed, or whose files changed, run first under Devel::Cover, with their output discarded. Perl::Tests::Covering says what counts as covering and when a test runs again.
With --diff, it reads a unified diff from git on standard input and prints the tests whose runs reached the lines the diff changes. It runs nothing first. "CHOOSING TESTS FOR A CHANGE" in Perl::Tests::Covering says how it decides, and when it falls back to every test that loads a file.
With --sub, it prints the tests that ran a statement of one sub. With --by, it prints the files each test you name loaded, which is the question turned around. With --refresh, it only brings the records up to date.
It exits 0 when it printed an answer, which can be no tests at all, and 2 when the options are wrong.
A PRE-COMMIT HOOK
Put this in .git/hooks/pre-commit and make it executable:
#!/bin/sh
tests=$(git diff --cached --name-only --diff-filter=ACMRD | tests-covering) || exit 1
[ -z "$tests" ] && exit 0
exec prove -l $tests
D is in the filter on purpose. A deleted module is reported as covered by the tests that used it, and those are the tests the deletion breaks.
The tests run against the working tree, not against what is staged. If you stage part of a file, the tests see all of it. Git starts the hook in the top directory of the work tree, so if the distribution is in a subdirectory, pass --root.
The first commit after the hook is installed runs every test under coverage, which is slow. Run tests-covering once by hand beforehand, with --jobs, to have that done when it suits you.
HOOKS THAT CHOOSE BY HUNK
This pair runs only the tests whose runs reached the lines a commit changes. The pre-commit hook reads the diff of what is staged:
#!/bin/sh
tests=$(git diff --cached --full-index | tests-covering --diff) || exit 1
[ -z "$tests" ] && exit 0
exec prove -l $tests
A diff describes the files as they were before the change, so the records it is read against have to be of those files. The post-commit hook, in .git/hooks/post-commit, brings them up to the commit just made, in the background:
#!/bin/sh
tests-covering --refresh >/dev/null 2>&1 &
Without it, a test whose records are older than the last commit is run whenever it loaded a file that changed since, and the choice gets coarser with each commit. Run tests-covering --refresh by hand to catch up.
Choosing by hunk trusts that each changed file still compiles. A syntax error in a sub that no test runs chooses no tests, and still breaks every test that loads the file. Put perl -c over the changed files in the pre-commit hook before the tests, if that matters to you.
FUNCTIONS
main
exit main(@ARGV);
Everything the command does. Returns the exit code.
read_names
The file names in a handle, one per line, without blank lines.
usage_error
Says what is wrong with the options on standard error, then does what "synopsis" does with exit code 2.
synopsis
Prints the synopsis, to standard output when it was asked for and to standard error when the options were wrong, and returns the exit code.
SEE ALSO
Please see those modules/websites for more information related to this module.
BUGS
Please report any bugs or feature requests on the bugtracker website https://github.com/Troglodyne-Internet-Widgets/perl-tests-covering/issues
When submitting a bug or request, please include a test-file or a patch to an existing test-file that illustrates the bug or desired feature.
AUTHORS
Current Maintainers:
George S. Baugh <george@troglodyne.net>
COPYRIGHT AND LICENSE
Copyright (c) 2026 Troglodyne LLC
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.