NAME

App::Test::Generator::Mutator - Generate and apply mutation tests

VERSION

Version 0.34

DESCRIPTION

App::Test::Generator::Mutator is a mutation engine that programmatically alters Perl source files to evaluate the effectiveness of a project's test suite. It analyses modules, generates systematic code mutations (such as conditional inversions, logical operator changes, and numeric boundary flips), and applies them within an isolated workspace so tests can be executed safely against each modified variant.

By tracking which mutants are killed (cause tests to fail) versus those that survive (tests still pass), the module enables calculation of a mutation score, providing a quantitative measure of how well the test suite detects unintended behavioural changes.

new

Construct a new Mutator for a given source file.

my $mutator = App::Test::Generator::Mutator->new(
    file           => 'lib/My/Module.pm',
    lib_dir        => 'lib',
    mutation_level => 'full',
);

Arguments

  • file

    Path to the Perl source file to mutate. Required. Must exist on disk.

  • lib_dir

    Root library directory. Optional — defaults to lib.

  • mutation_level

    Controls the breadth of mutation. full applies all mutations; fast deduplicates and removes redundant mutants first. Optional — defaults to full.

Returns

A blessed hashref. Croaks if file is missing or does not exist.

API specification

input

{
    file           => { type => SCALAR },
    lib_dir        => { type => SCALAR, optional => 1 },
    mutation_level => { type => SCALAR, optional => 1 },
}

output

{
    type => OBJECT,
    isa  => 'App::Test::Generator::Mutator',
}

generate_mutants

Parse the target file and generate all mutants by running each registered mutation strategy against the PPI document.

my @mutants = $mutator->generate_mutants();

Arguments

None beyond $self.

Returns

A list of App::Test::Generator::Mutant objects. In fast mode, redundant and duplicate mutants are removed before returning.

API specification

input

{
    self => { type => OBJECT, isa => 'App::Test::Generator::Mutator' },
}

output

{
    type     => ARRAYREF,
    elements => { type => OBJECT, isa => 'App::Test::Generator::Mutant' },
}

prepare_workspace

Prepare an isolated temporary workspace for a single mutation test run.

The entire lib_dir tree is copied into the workspace so that all module dependencies resolve correctly when the test suite runs against the mutant. Only after this copy is complete is the single target file overwritten by apply_mutant.

my $workspace = $mutator->prepare_workspace();
$mutator->apply_mutant($mutant);
local $ENV{PERL5LIB} = "$workspace/lib";
my $survived = (system('prove', 't') == 0);

Arguments

None beyond $self.

Returns

A string containing the absolute path to the temporary directory created. The directory is automatically removed when the object goes out of scope via File::Temp's CLEANUP => 1 behaviour.

Side effects

Creates a temporary directory. Recursively copies lib_dir into it. Sets $self->{workspace} and $self->{relative}.

Notes

Call prepare_workspace once per file, then apply_mutant once per mutant within that file. Do not store the returned path beyond the lifetime of the enclosing scope.

API specification

input

{
    self => { type => OBJECT, isa => 'App::Test::Generator::Mutator' },
}

output

{
    type => SCALAR,
}

apply_mutant

Apply a single mutant's transform to the target file in the workspace.

$mutator->apply_mutant($mutant);

Arguments

Returns

Nothing. Modifies the workspace copy of the target file in place.

Side effects

Overwrites the target file in the workspace with the mutated version.

API specification

input

{
    self   => { type => OBJECT, isa => 'App::Test::Generator::Mutator' },
    mutant => { type => OBJECT, isa => 'App::Test::Generator::Mutant'  },
}

output

{ type => UNDEF }

run_tests

Run the test suite against the current workspace and return whether all tests passed.

my $survived = $mutator->run_tests();

Arguments

None beyond $self.

Returns

1 if all tests passed (mutant survived), 0 if any test failed (mutant killed).

Side effects

Executes an external process running the test suite.

Notes

Uses prove found on PATH. Sets PERL5LIB to include the workspace lib directory before running.

API specification

input

{
    self => { type => OBJECT, isa => 'App::Test::Generator::Mutator' },
}

output

{ type => SCALAR }

SEE ALSO

bin/test-generator-mutate
Devel::Mutator

AUTHOR

Nigel Horne, <njh at nigelhorne.com>

Portions of this module's initial design and documentation were created with the assistance of AI.

LICENCE AND COPYRIGHT

Copyright 2026 Nigel Horne.

Usage is subject to the terms of GPL2. If you use it, please let me know.

1 POD Error

The following errors were encountered while parsing the POD:

Around line 75:

Non-ASCII character seen before =encoding in '—'. Assuming UTF-8