App-Test-Generator
view release on metacpan or search on metacpan
t/Mutation-ConditionalInversion.t view on Meta::CPAN
# ==================================================================
# mutate -- transform flips if to unless
# ==================================================================
subtest 'mutate: transform flips if to unless' => sub {
my $m = _mutation();
my $src = 'sub foo { if($x) { return 1; } }';
my $doc = _doc($src);
my @mutants = $m->mutate($doc);
is(scalar @mutants, 1, 'one mutant produced');
# Apply transform to a fresh copy
my $copy = _doc($src);
$mutants[0]->transform->($copy);
my $transformed = $copy->serialize;
# The if keyword must have been replaced by unless
like($transformed, qr/\bunless\b/, 'transform inserts unless');
unlike($transformed, qr/\bif\b/, 'transform removes if');
};
# ==================================================================
# mutate -- transform flips unless to if
# ==================================================================
subtest 'mutate: transform flips unless to if' => sub {
my $m = _mutation();
my $src = 'sub foo { unless($err) { proceed(); } }';
my $doc = _doc($src);
my @mutants = $m->mutate($doc);
is(scalar @mutants, 1, 'one mutant produced');
# Apply transform to a fresh copy
my $copy = _doc($src);
$mutants[0]->transform->($copy);
my $transformed = $copy->serialize;
# The unless keyword must have been replaced by if
like($transformed, qr/\bif\b/, 'transform inserts if');
unlike($transformed, qr/\bunless\b/, 'transform removes unless');
};
# ==================================================================
# mutate -- transform targets correct conditional when multiple exist
# ==================================================================
subtest 'mutate: transform targets correct conditional' => sub {
my $m = _mutation();
my $src = <<'CODE';
sub check {
if($a) { return 1; }
if($b) { return 2; }
}
CODE
my $doc = _doc($src);
my @mutants = $m->mutate($doc);
is(scalar @mutants, 2, 'two mutants for two if statements');
# Apply each transform to a fresh copy and verify only one keyword flips
for my $mut (@mutants) {
my $copy = _doc($src);
$mut->transform->($copy);
my $transformed = $copy->serialize;
# Count how many unless keywords appear â exactly one should be added
my @unless_count = ($transformed =~ /\bunless\b/g);
is(scalar @unless_count, 1,
"transform for mutant ${\$mut->id} flips exactly one if to unless");
}
};
# ==================================================================
# mutate -- transform does not modify original document
# ==================================================================
subtest 'mutate: transform does not modify original document' => sub {
my $m = _mutation();
my $src = 'sub foo { if($x) { return 1; } }';
my $doc = _doc($src);
my @mutants = $m->mutate($doc);
# Capture original serialisation before any transform
my $before = $doc->serialize;
# Apply transform to a different copy
my $copy = _doc($src);
$mutants[0]->transform->($copy);
# Original document must be unchanged
is($doc->serialize, $before, 'original document not modified by transform');
};
# ==================================================================
# mutate -- original field captures the condition content
# ==================================================================
subtest 'mutate: original captures condition content' => sub {
my $m = _mutation();
my $doc = _doc('sub foo { if($x > 0) { return 1; } }');
my @mutants = $m->mutate($doc);
is(scalar @mutants, 1, 'one mutant produced');
# Original should contain the condition expression
like($mutants[0]->original, qr/\$x.*>.*0/,
'original contains the condition expression');
};
# ==================================================================
# mutate -- conditional without a condition block is skipped
# ==================================================================
subtest 'mutate: conditional without condition block skipped' => sub {
my $m = _mutation();
# A well-formed if always has a condition -- test that the guard works
# by verifying normal operation first
my @mutants = $m->mutate(_doc('sub foo { if($x) { 1; } }'));
is(scalar @mutants, 1, 'normal if with condition produces one mutant');
};
# ==================================================================
# mutate -- ID uniqueness: group contains same line as ID
# ==================================================================
subtest 'mutate: group line matches ID line' => sub {
my $m = _mutation();
my $doc = _doc(<<'CODE');
sub foo {
if($a) { return 1; }
unless($b) { return 0; }
}
CODE
my @mutants = $m->mutate($doc);
is(scalar @mutants, 2, 'two mutants produced');
for my $mut (@mutants) {
my ($id_line) = $mut->id =~ /COND_INV_(\d+)/;
my ($group_line) = $mut->group =~ /COND_INV:(\d+)/;
is($id_line, $group_line, "group line matches ID line for mutant ${\$mut->id}");
is($mut->line, $id_line, "line() matches ID line for mutant ${\$mut->id}");
}
};
# ==================================================================
# mutate -- returns a list (current API)
# ==================================================================
subtest 'mutate: returns a list' => sub {
my $m = _mutation();
my $doc = _doc('sub foo { if($a) { 1; } unless($b) { 2; } }');
# Current API returns a flat list
my @mutants = $m->mutate($doc);
is(scalar @mutants, 2, 'mutate returns flat list assignable to array');
# TODO: API should return arrayref for efficiency â same change
# needed across all Mutation::* subclasses simultaneously
};
# ==================================================================
# applies_to() â new function
# ==================================================================
subtest 'applies_to() returns 1 for document containing if statement' => sub {
require PPI;
my $m = App::Test::Generator::Mutation::ConditionalInversion->new();
my $doc = PPI::Document->new(\'sub foo { if($x > 0) { return 1; } }');
is($m->applies_to($doc), 1, 'if statement -> applies_to returns 1');
};
subtest 'applies_to() returns 1 for document containing unless statement' => sub {
require PPI;
my $m = App::Test::Generator::Mutation::ConditionalInversion->new();
my $doc = PPI::Document->new(\'sub foo { unless($x) { return 0; } }');
is($m->applies_to($doc), 1, 'unless statement -> applies_to returns 1');
};
( run in 1.089 second using v1.01-cache-2.11-cpan-e1769b4cff6 )