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:

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:

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:

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

DIAGNOSTICS

Common error messages:

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

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: