NAME
Test::Which - Skip tests if external programs are missing from PATH (with version checks)
VERSION
Version 0.06
SYNOPSIS
use Test::Which 'ffmpeg' => '>=6.0', 'convert' => '>=7.1';
# At runtime in a subtest or test body
use Test::Which qw(which_ok);
subtest 'needs ffmpeg' => sub {
which_ok 'ffmpeg' => '>=6.0' or return;
... # tests that use ffmpeg
};
DESCRIPTION
Test::Which mirrors Test::Needs but checks for executables in PATH. It can also check version constraints using a built-in heuristic that tries common version flags (--version, -version, -v, -V) and extracts version numbers from the output.
If a version is requested but cannot be determined, the requirement fails.
Key features:
Compile-time and runtime checking of program availability
Version comparison with standard operators (>=, >, <, <=, ==, !=)
Regular expression matching for version strings
Custom version flag support for non-standard programs
Custom version extraction for unusual output formats
Caching to avoid repeated program execution
Cross-platform support (Unix, Linux, macOS, Windows)
EXAMPLES
Basic Usage
Check for program availability without version constraints:
use Test::Which qw(which_ok);
which_ok 'perl', 'ffmpeg', 'convert';
Version Constraints
Check programs with minimum version requirements:
# String constraints with comparison operators
which_ok 'perl' => '>=5.10';
which_ok 'ffmpeg' => '>=4.0', 'convert' => '>=7.1';
# Exact version match
which_ok 'node' => '==18.0.0';
# Version range
which_ok 'python' => '>=3.8', 'python' => '<4.0';
Hashref Syntax
Use hashrefs for more complex constraints:
# String version in hashref
which_ok 'perl', { version => '>=5.10' };
# Regex matching
which_ok 'perl', { version => qr/5\.\d+/ };
which_ok 'ffmpeg', { version => qr/^[4-6]\./ };
Custom Version Flags
Some programs use non-standard flags to display version information:
# Java uses -version (single dash)
which_ok 'java', {
version => '>=11',
version_flag => '-version'
};
# Try multiple flags in order
which_ok 'myprogram', {
version => '>=2.0',
version_flag => ['--show-version', '-version', '--ver']
};
# Program prints version without any flag
which_ok 'sometool', {
version => '>=1.0',
version_flag => '',
timeout => 10, # seconds - the default is 5
};
# Windows-specific flag
which_ok 'cmd', {
version => qr/\d+/,
version_flag => '/?'
} if $^O eq 'MSWin32';
If version_flag is not specified, the module tries these flags in order: --version, -version, -v, -V (and /?, -? on Windows)
Custom Version Extraction
For programs with unusual version output formats:
which_ok 'myprogram', {
version => '>=1.0',
extractor => sub {
my $output = shift;
return $1 if $output =~ /Build (\d+\.\d+)/;
return undef;
}
};
The extractor receives the program's output and should return the version string or undef if no version could be found.
Mixed Usage
Combine different constraint types:
which_ok
'perl' => '>=5.10', # String constraint
'ffmpeg', # No constraint
'convert', { version => qr/^7\./ }; # Regex constraint
Compile-Time Checking
Skip entire test files if requirements aren't met:
use Test::Which 'ffmpeg' => '>=6.0', 'convert' => '>=7.1';
# Test file is skipped if either program is missing or the version is too old
# No tests below this line will run if requirements aren't met
Runtime Checking in Subtests
Check requirements for individual subtests:
use Test::Which qw(which_ok);
subtest 'video conversion' => sub {
which_ok 'ffmpeg' => '>=4.0' or return;
# ... tests using ffmpeg
};
subtest 'image processing' => sub {
which_ok 'convert' => '>=7.0' or return;
# ... tests using ImageMagick
};
Absolute Paths
You can specify absolute paths instead of searching PATH:
which_ok '/usr/local/bin/myprogram' => '>=1.0';
The program must be executable.
VERSION DETECTION
The module attempts to detect version numbers using these strategies in order:
- 1. Look for version near the word "version" (case-insensitive)
-
Matches patterns like:
ffmpeg version 4.2.7,Version: 2.1.0 - 2. Extract dotted version from first line of output
-
Common for programs that print version info prominently
- 3. Find any dotted version number in output
-
Fallback for less standard formats
- 4. Look for single number near "version"
-
For programs that use simple integer versioning
- 5. Use any standalone number found
-
Last resort - least reliable
VERSION COMPARISON
Version comparison uses Perl's version module. Versions are normalized to have the same number of components before comparison to avoid version.pm's parsing quirks.
For example: - 2020.10 becomes 2020.10.0 - 2020.10.15 stays 2020.10.15 - Then they're compared correctly
Supported operators: >=, >, <=, <, =, !=
CACHING
Version detection results are cached to avoid repeated program execution. Each unique combination of program path and version flags creates a separate cache entry.
Cache benefits: - Faster repeated checks in test suites - Reduced system load - Works across multiple test files in the same process
The cache persists for the lifetime of the Perl process.
VERBOSE OUTPUT
Set environment variables to see detected versions:
TEST_WHICH_VERBOSE=1 prove -v t/mytest.t
TEST_VERBOSE=1 perl t/mytest.t
prove -v t/mytest.t # HARNESS_IS_VERBOSE is set automatically
Output includes the detected version for each checked program:
# perl: version 5.38.0
# ffmpeg: version 6.1.1
PLATFORM SUPPORT
Unix/Linux/macOS: Full support for all features
Windows: Basic functionality supported. Complex shell features (STDERR redirection, empty flags) may have limitations.
DIAGNOSTICS
Common error messages:
Missing required program 'foo'-
The program 'foo' could not be found in PATH.
Version issue for foo: no version detected-
The program exists but the module couldn't extract a version number from its output. Try specifying a custom
version_flagorextractor. Version issue for foo: found 1.0 but need=2.0>-
The program's version doesn't meet the constraint.
Version issue for foo: found version 1.0 but doesn't match pattern-
For regex constraints, the detected version didn't match the pattern.
hashref constraint must contain 'version' key-
When using hashref syntax, you must include a
versionkey. invalid constraint 'foo'-
The version constraint string couldn't be parsed. Use formats like
'=1.2.3'>,'2.0'>, or'1.5'.
FUNCTIONS/METHODS
which_ok @programs_or_pairs
Checks the named programs (with optional version constraints). If any requirement is not met, the current test or subtest is skipped via Test::Builder.
Returns true if all requirements are met, false otherwise.
SUPPORT
This module is provided as-is without any warranty.
SEE ALSO
Test::Needs - Similar module for checking Perl module availability
File::Which - Used internally to locate programs
version - Used for version comparison
Test::Builder - Used for test integration
LIMITATIONS
Version detection is heuristic-based and may fail for programs with unusual output formats. Use custom
version_flagorextractorfor such cases, though even those may break.No built-in timeout for program execution. Hanging programs will hang tests.
Cache persists for process lifetime - updated programs won't be re-detected without restarting the test process.
Requires programs to be in PATH or specified with absolute paths.
AUTHOR
Nigel Horne, <njh at nigelhorne.com>
LICENCE AND COPYRIGHT
Copyright 2025 Nigel Horne.
Usage is subject to licence terms.
The licence terms of this software are as follows:
Personal single user, single computer use: GPL2
All other users (including Commercial, Charity, Educational, Government) must apply in writing for a licence for use from Nigel Horne at the above e-mail.