Skip to content

Commit

Permalink
Do not mutation * to / and vice versa if one of the operand is 1 or -…
Browse files Browse the repository at this point in the history
…1 or 1.0 or -1.0 to avoid equivalent mutation (#673)
  • Loading branch information
maks-rafalko committed Mar 23, 2019
1 parent 7685ed8 commit fc4a96f
Show file tree
Hide file tree
Showing 4 changed files with 185 additions and 27 deletions.
27 changes: 26 additions & 1 deletion src/Mutator/Arithmetic/Division.php
Expand Up @@ -56,6 +56,31 @@ public function mutate(Node $node)

protected function mutatesNode(Node $node): bool
{
return $node instanceof Node\Expr\BinaryOp\Div;
if (!$node instanceof Node\Expr\BinaryOp\Div) {
return false;
}

if ($this->isNumericOne($node->left) || $this->isNumericOne($node->right)) {
return false;
}

if ($node->left instanceof Node\Expr\UnaryMinus && $this->isNumericOne($node->left->expr)) {
return false;
}

if ($node->right instanceof Node\Expr\UnaryMinus && $this->isNumericOne($node->right->expr)) {
return false;
}

return true;
}

private function isNumericOne(Node $node): bool
{
if ($node instanceof Node\Scalar\LNumber && $node->value === 1) {
return true;
}

return $node instanceof Node\Scalar\DNumber && $node->value === 1.0;
}
}
27 changes: 26 additions & 1 deletion src/Mutator/Arithmetic/Multiplication.php
Expand Up @@ -56,6 +56,31 @@ public function mutate(Node $node)

protected function mutatesNode(Node $node): bool
{
return $node instanceof Node\Expr\BinaryOp\Mul;
if (!$node instanceof Node\Expr\BinaryOp\Mul) {
return false;
}

if ($this->isNumericOne($node->left) || $this->isNumericOne($node->right)) {
return false;
}

if ($node->left instanceof Node\Expr\UnaryMinus && $this->isNumericOne($node->left->expr)) {
return false;
}

if ($node->right instanceof Node\Expr\UnaryMinus && $this->isNumericOne($node->right->expr)) {
return false;
}

return true;
}

private function isNumericOne(Node $node): bool
{
if ($node instanceof Node\Scalar\LNumber && $node->value === 1) {
return true;
}

return $node instanceof Node\Scalar\DNumber && $node->value === 1.0;
}
}
81 changes: 64 additions & 17 deletions tests/Mutator/Arithmetic/DivisionTest.php
Expand Up @@ -50,10 +50,9 @@ public function test_mutator($input, $expected = null): void
$this->doTest($input, $expected);
}

public function provideMutationCases(): array
public function provideMutationCases(): \Generator
{
return [
'It changes regular divison' => [
yield 'It changes regular divison' => [
<<<'PHP'
<?php
Expand All @@ -65,31 +64,79 @@ public function provideMutationCases(): array
$a = 10 * 2;
PHP
,
],
'It does not change division equals' => [
];

yield 'It does not change division equals' => [
<<<'PHP'
<?php
$a = 10;
$a /= 5;
PHP
,
],
];
}

public function test_replaces_division_with_multiplication(): void
{
$code = '<?php 1 / 2;';
$mutations = $this->mutate($code);
yield 'It does not mutate when the left side is 1 to avoid an equivalent mutation' => [
<<<'PHP'
<?php
$expectedMutatedCode = <<<'PHP'
$a = 1 / $b;
PHP
];

yield 'It does not mutate when the right side is 1 to avoid an equivalent mutation' => [
<<<'PHP'
<?php
1 * 2;
PHP;
$a = $b / 1;
PHP
];

yield 'It does not mutate when the left side is -1 to avoid an equivalent mutation' => [
<<<'PHP'
<?php
$a = -1 / $b;
PHP
];

yield 'It does not mutate when the right side is -1 to avoid an equivalent mutation' => [
<<<'PHP'
<?php
$this->assertSame($expectedMutatedCode, $mutations[0]);
$a = $b / -1;
PHP
];

yield 'It does not mutate when the left side is 1.0 to avoid an equivalent mutation' => [
<<<'PHP'
<?php
$a = 1.0 / $b;
PHP
];

yield 'It does not mutate when the right side is 1.0 to avoid an equivalent mutation' => [
<<<'PHP'
<?php
$a = $b / 1.0;
PHP
];

yield 'It does not mutate when the left side is -1.0 to avoid an equivalent mutation' => [
<<<'PHP'
<?php
$a = -1.0 / $b;
PHP
];

yield 'It does not mutate when the right side is -1.0 to avoid an equivalent mutation' => [
<<<'PHP'
<?php
$a = $b / -1.0;
PHP
];
}
}
77 changes: 69 additions & 8 deletions tests/Mutator/Arithmetic/MultiplicationTest.php
Expand Up @@ -50,10 +50,9 @@ public function test_mutator($input, $expected = null): void
$this->doTest($input, $expected);
}

public function provideMutationCases(): array
public function provideMutationCases(): \Generator
{
return [
'It mutates normal multiplication' => [
yield 'It mutates normal multiplication' => [
<<<'PHP'
<?php
Expand All @@ -65,17 +64,79 @@ public function provideMutationCases(): array
$a = 10 / 3;
PHP
,
],
'It does not mutate multiplication equals' => [
];

yield 'It does not mutate multiplication equals' => [
<<<'PHP'
<?php
$a = 1;
$a *= 2;
PHP
,
],
];

yield 'It does not mutate when the left side is 1 to avoid an equivalent mutation' => [
<<<'PHP'
<?php
$a = 1 * $b;
PHP
];

yield 'It does not mutate when the right side is 1 to avoid an equivalent mutation' => [
<<<'PHP'
<?php
$a = $b * 1;
PHP
];

yield 'It does not mutate when the left side is -1 to avoid an equivalent mutation' => [
<<<'PHP'
<?php
$a = -1 * $b;
PHP
];

yield 'It does not mutate when the right side is -1 to avoid an equivalent mutation' => [
<<<'PHP'
<?php
$a = $b * -1;
PHP
];

yield 'It does not mutate when the left side is 1.0 to avoid an equivalent mutation' => [
<<<'PHP'
<?php
$a = 1.0 * $b;
PHP
];

yield 'It does not mutate when the right side is 1.0 to avoid an equivalent mutation' => [
<<<'PHP'
<?php
$a = $b * 1.0;
PHP
];

yield 'It does not mutate when the left side is -1.0 to avoid an equivalent mutation' => [
<<<'PHP'
<?php
$a = -1.0 * $b;
PHP
];

yield 'It does not mutate when the right side is -1.0 to avoid an equivalent mutation' => [
<<<'PHP'
<?php
$a = $b * -1.0;
PHP
];
}
}

0 comments on commit fc4a96f

Please sign in to comment.