Skip to content

Commit

Permalink
infection#658 added required tests, refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
majkel89 committed Mar 30, 2019
1 parent f5fab01 commit e1fa6ce
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 85 deletions.
63 changes: 30 additions & 33 deletions src/Mutator/Extensions/BCMath.php
Expand Up @@ -57,69 +57,66 @@ public function __construct(MutatorConfig $config)
}

/**
* @param Node|Node\Expr\FuncCall $node
*
* @return Node|Node[]|Generator
*/
public function mutate(Node $node)
{
yield from $this->converters[$this->getFunctionName($node)]($node);
yield from $this->converters[$node->name->toLowerString()]($node);
}

protected function mutatesNode(Node $node): bool
{
$functionName = $this->getFunctionName($node);

return $functionName !== null && isset($this->converters[$functionName]) && \function_exists($functionName);
}

private function getFunctionName(Node $node): ?string
{
if (!$node instanceof Node\Expr\FuncCall || !$node->name instanceof Node\Name) {
return null;
return false;
}

return \strtolower($node->name->toString());
$functionName = $node->name->toLowerString();

return isset($this->converters[$functionName]) && \function_exists($functionName);
}

private function setupConverters(array $functionsMap): void
{
$converters = [
'bcadd' => $this->minArgsCastString(2,
$this->binaryOp(Node\Expr\BinaryOp\Plus::class)
'bcadd' => $this->mapCheckingMinArgsThenCastToString(2,
$this->mapBinaryOperator(Node\Expr\BinaryOp\Plus::class)
),
'bccomp' => $this->minArgsCastString(2,
$this->binaryOp(Node\Expr\BinaryOp\Spaceship::class)
'bccomp' => $this->mapCheckingMinArgsThenCastToString(2,
$this->mapBinaryOperator(Node\Expr\BinaryOp\Spaceship::class)
),
'bcdiv' => $this->minArgsCastString(2,
$this->binaryOp(Node\Expr\BinaryOp\Div::class)
'bcdiv' => $this->mapCheckingMinArgsThenCastToString(2,
$this->mapBinaryOperator(Node\Expr\BinaryOp\Div::class)
),
'bcmod' => $this->minArgsCastString(2,
$this->binaryOp(Node\Expr\BinaryOp\Mod::class)
'bcmod' => $this->mapCheckingMinArgsThenCastToString(2,
$this->mapBinaryOperator(Node\Expr\BinaryOp\Mod::class)
),
'bcmul' => $this->minArgsCastString(2,
$this->binaryOp(Node\Expr\BinaryOp\Mul::class)
'bcmul' => $this->mapCheckingMinArgsThenCastToString(2,
$this->mapBinaryOperator(Node\Expr\BinaryOp\Mul::class)
),
'bcpow' => $this->minArgsCastString(2,
$this->binaryOp(Node\Expr\BinaryOp\Pow::class)
'bcpow' => $this->mapCheckingMinArgsThenCastToString(2,
$this->mapBinaryOperator(Node\Expr\BinaryOp\Pow::class)
),
'bcsub' => $this->minArgsCastString(2,
$this->binaryOp(Node\Expr\BinaryOp\Minus::class)
'bcsub' => $this->mapCheckingMinArgsThenCastToString(2,
$this->mapBinaryOperator(Node\Expr\BinaryOp\Minus::class)
),
'bcsqrt' => $this->minArgsCastString(2,
$this->squareRoots()
'bcsqrt' => $this->mapCheckingMinArgsThenCastToString(2,
$this->mapSquareRoots()
),
'bcpowmod' => $this->minArgsCastString(3,
$this->powerModulo()
'bcpowmod' => $this->mapCheckingMinArgsThenCastToString(3,
$this->mapPowerModulo()
),
];

$functionsToRemove = \array_filter($functionsMap, function ($isOn) {
$functionsToRemove = \array_filter($functionsMap, static function ($isOn) {
return !$isOn;
});

$this->converters = \array_diff_key($converters, $functionsToRemove);
}

private function minArgsCastString(int $minimumArgsCount, callable $converter): callable
private function mapCheckingMinArgsThenCastToString(int $minimumArgsCount, callable $converter): callable
{
return static function (Node\Expr\FuncCall $node) use ($minimumArgsCount, $converter): Generator {
if (\count($node->args) >= $minimumArgsCount) {
Expand All @@ -130,14 +127,14 @@ private function minArgsCastString(int $minimumArgsCount, callable $converter):
};
}

private function binaryOp(string $operator): callable
private function mapBinaryOperator(string $operator): callable
{
return static function (Node\Expr\FuncCall $node) use ($operator): Generator {
yield new $operator($node->args[0]->value, $node->args[1]->value);
};
}

private function squareRoots(): callable
private function mapSquareRoots(): callable
{
return static function (Node\Expr\FuncCall $node): Generator {
yield new Node\Expr\FuncCall(
Expand All @@ -147,7 +144,7 @@ private function squareRoots(): callable
};
}

private function powerModulo(): callable
private function mapPowerModulo(): callable
{
return static function (Node\Expr\FuncCall $node): Generator {
yield new Node\Expr\BinaryOp\Mod(
Expand Down
112 changes: 60 additions & 52 deletions tests/Mutator/Extensions/BCMathTest.php
Expand Up @@ -32,39 +32,6 @@
*/

declare(strict_types=1);
/**
* This code is licensed under the BSD 3-Clause License.
*
* Copyright (c) 2017-2019, Maks Rafalko
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

//declare(strict_types=1);

namespace Infection\Tests\Mutator\Extensions;

Expand All @@ -86,12 +53,6 @@ public function test_mutator(string $input, string $expected = null, array $sett

public function provideMutationCases(): Generator
{
yield 'It does not convert bcadd when disabled' => [
"<?php bcadd('1', '3');",
null,
['settings' => ['bcadd' => false]],
];

yield from $this->provideMutationCasesForBinaryOperator('bcadd', '+', 'summation');

yield from $this->provideMutationCasesForBinaryOperator('bccomp', '<=>', 'spaceship');
Expand All @@ -118,14 +79,17 @@ private function provideMutationCasesForBinaryOperator(string $bcFunc, string $o
"<?php\n\n(string) ('3' $op \$b);",
];

yield "It converts $bcFunc with scale to $expression expression" => [
"<?php $bcFunc(\$a, \$b, 2);",
"<?php\n\n(string) (\$a $op \$b);",
yield "It converts correctly when $bcFunc is wrongly capitalized" => [
"<?php \\{$this->randomizeCase($bcFunc)}(func(), \$b->test());",
"<?php\n\n(string) (func() $op \$b->test());",
];

yield "It does not convert $bcFunc when not enough arguments" => [
"<?php $bcFunc(\$a);",
yield "It converts $bcFunc with scale to $expression expression" => [
"<?php $bcFunc(CONSTANT, \$b, 2);",
"<?php\n\n(string) (CONSTANT $op \$b);",
];

yield from $this->provideCasesWhereMutatorShouldNotApply($bcFunc);
}

private function provideMutationCasesForPowerOperator(): Generator
Expand All @@ -135,14 +99,17 @@ private function provideMutationCasesForPowerOperator(): Generator
"<?php\n\n(string) 5 ** \$b;",
];

yield 'It converts correctly when bcpow is wrongly capitalized' => [
'<?php \\bCpOw(5, $b);',
"<?php\n\n(string) 5 ** \$b;",
];

yield 'It converts bcpow with scale to power expression' => [
'<?php bcpow($a, $b, 2);',
"<?php\n\n(string) \$a ** \$b;",
];

yield 'It does not convert bcpow when not enough arguments' => [
'<?php bcpow($a);',
];
yield from $this->provideCasesWhereMutatorShouldNotApply('bcpow');
}

private function provideMutationCasesForSquareRoot(): Generator
Expand All @@ -152,14 +119,17 @@ private function provideMutationCasesForSquareRoot(): Generator
"<?php\n\n(string) \sqrt(1, \$b);",
];

yield 'It converts correctly when bcsqrt is wrongly capitalized' => [
'<?php \\BCsqRt(1, $b);',
"<?php\n\n(string) \sqrt(1, \$b);",
];

yield 'It converts bcsqrt with scale to sqrt call' => [
'<?php bcsqrt($a, $b, 2);',
"<?php\n\n(string) \sqrt(\$a, \$b);",
];

yield 'It does not convert bcsqrt when not enough arguments' => [
'<?php bcsqrt($a);',
];
yield from $this->provideCasesWhereMutatorShouldNotApply('bcsqrt');
}

private function provideMutationCasesForPowerModulo(): Generator
Expand All @@ -169,13 +139,51 @@ private function provideMutationCasesForPowerModulo(): Generator
"<?php\n\n(string) (\pow(\$a, \$b) % \$mod);",
];

yield 'It converts correctly when bcpowmod is wrongly capitalized' => [
'<?php \\BcPowMod($a, $b, $mod);',
"<?php\n\n(string) (\pow(\$a, \$b) % \$mod);",
];

yield 'It converts bcpowmod with scale to power modulo expression' => [
'<?php bcpowmod($a, $b, 2);',
"<?php\n\n(string) (\pow(\$a, \$b) % 2);",
];

yield 'It does not convert bcpowmod when not enough arguments' => [
'<?php bcpowmod($a, $b);',
yield from $this->provideCasesWhereMutatorShouldNotApply('bcpowmod', 3);
}

private function provideCasesWhereMutatorShouldNotApply(string $bcFunc, int $requiredArgumentsCount = 2): Generator
{
$invalidArgumentsExpression = $this->generateArgumentsExpression($requiredArgumentsCount - 1);
$validArgumentsExpression = $this->generateArgumentsExpression($requiredArgumentsCount);

yield "It does not convert $bcFunc when no enough arguments" => [
"<?php $bcFunc($invalidArgumentsExpression);",
];

yield "It does not mutate $bcFunc called via variable" => [
"<?php \$a = '$bcFunc'; \$a($validArgumentsExpression);",
];

yield "It does not convert $bcFunc when disabled" => [
"<?php $bcFunc($validArgumentsExpression);",
null,
['settings' => [$bcFunc => false]],
];
}

private function randomizeCase(string $bcFunc): string
{
$bcFunc[2] = strtoupper($bcFunc[2]);
$bcFunc[4] = strtoupper($bcFunc[4]);

return ucfirst($bcFunc);
}

private function generateArgumentsExpression(int $numberOfArguments): string
{
return \implode(', ', \array_map(static function (string $argument) {
return "'$argument'";
}, \range(1, $numberOfArguments)));
}
}

0 comments on commit e1fa6ce

Please sign in to comment.