From 2bcbf0e344aab31ccc96b6e3c323331d0e8afcee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kowalik?= Date: Sun, 10 Mar 2019 13:16:27 +0100 Subject: [PATCH 01/18] #654 mbstring mutator --- src/Mutator/Extensions/MBString.php | 217 ++++++++++ src/Mutator/Util/MutatorProfile.php | 9 + tests/Mutator/Extensions/MBStringTest.php | 462 ++++++++++++++++++++++ 3 files changed, 688 insertions(+) create mode 100644 src/Mutator/Extensions/MBString.php create mode 100644 tests/Mutator/Extensions/MBStringTest.php diff --git a/src/Mutator/Extensions/MBString.php b/src/Mutator/Extensions/MBString.php new file mode 100644 index 000000000..b4b0742ac --- /dev/null +++ b/src/Mutator/Extensions/MBString.php @@ -0,0 +1,217 @@ + 0, + 'MB_CASE_LOWER' => 1, + 'MB_CASE_TITLE' => 2, + 'MB_CASE_FOLD' => 3, + 'MB_CASE_UPPER_SIMPLE' => 4, + 'MB_CASE_LOWER_SIMPLE' => 5, + 'MB_CASE_TITLE_SIMPLE' => 6, + 'MB_CASE_FOLD_SIMPLE' => 7, + ]; + + private $converters; + + public function __construct(MutatorConfig $config) + { + parent::__construct($config); + $this->setupConverters(); + } + + /** + * @return Node|Node[]|Generator + */ + public function mutate(Node $node) + { + yield from $this->converters[$this->getFunctionName($node)]($node); + } + + protected function mutatesNode(Node $node): bool + { + return isset($this->converters[$this->getFunctionName($node)]); + } + + private function setupConverters(): void + { + $this->converters = [ + 'mb_chr' => $this->mapNameSkipArg('chr', 1), + 'mb_ereg_match' => $this->mapNameSkipArg('preg_match', 2), + 'mb_ereg_replace_callback' => $this->mapNameSkipArg('preg_replace_callback', 3), + 'mb_ereg_replace' => $this->mapNameSkipArg('ereg_replace', 3), + 'mb_ereg' => $this->mapNameSkipArg('ereg', 3), + 'mb_eregi_replace' => $this->mapNameSkipArg('eregi_replace', 3), + 'mb_eregi' => $this->mapNameSkipArg('eregi', 3), + 'mb_ord' => $this->mapNameSkipArg('ord', 1), + 'mb_parse_str' => $this->mapName('parse_str'), + 'mb_send_mail' => $this->mapName('mail'), + 'mb_split' => $this->mapName('split'), + 'mb_strcut' => $this->mapNameSkipArg('substr', 3), + 'mb_stripos' => $this->mapNameSkipArg('stripos', 3), + 'mb_stristr' => $this->mapNameSkipArg('stristr', 3), + 'mb_strlen' => $this->mapNameSkipArg('strlen', 1), + 'mb_strpos' => $this->mapNameSkipArg('strpos', 3), + 'mb_strrchr' => $this->mapNameSkipArg('strrchr', 2), + 'mb_strrichr' => $this->mapNameSkipArg('strrchr', 2), + 'mb_strripos' => $this->mapNameSkipArg('strripos', 3), + 'mb_strrpos' => $this->mapNameSkipArg('strrpos', 3), + 'mb_strstr' => $this->mapNameSkipArg('strstr', 3), + 'mb_strtolower' => $this->mapNameSkipArg('strtolower', 1), + 'mb_strtoupper' => $this->mapNameSkipArg('strtoupper', 1), + 'mb_substr_count' => $this->mapNameSkipArg('substr_count', 2), + 'mb_substr' => $this->mapNameSkipArg('substr', 3), + 'mb_convert_case' => $this->mapConvertCase(), + ]; + } + + private function mapName(string $functionName): callable + { + return function (Node\Expr\FuncCall $node) use ($functionName): Generator { + yield $this->createNode($node, $functionName, $node->args); + }; + } + + private function mapNameSkipArg(string $functionName, int $skipArgs): callable + { + return function (Node\Expr\FuncCall $node) use ($functionName, $skipArgs): Generator { + $args = $node->args; + + if ($skipArgs !== null) { + $args = \array_slice($args, 0, $skipArgs); + } + + yield $this->createNode($node, $functionName, $args); + }; + } + + private function mapConvertCase(): callable + { + return function (Node\Expr\FuncCall $node): Generator { + $modeValue = $this->getConvertCaseModeValue($node); + + if ($modeValue === null) { + return; + } + + $functionName = $this->getConvertCaseFunctionName($modeValue); + + if ($functionName === null) { + return; + } + + yield $this->createNode($node, $functionName, [$node->args[0]]); + }; + } + + private function getConvertCaseModeValue(Node\Expr\FuncCall $node): ?int + { + if (\count($node->args) < 2) { + return null; + } + + $mode = $node->args[1]->value; + + $modeValue = null; + + if ($mode instanceof Node\Expr\ConstFetch) { + $modeName = $mode->name->toString(); + + if (\defined($modeName)) { + return \constant($modeName); + } + + if (isset(self::MB_CASES[$modeName])) { + return self::MB_CASES[$modeName]; + } + } + + return null; + } + + private function getConvertCaseFunctionName(int $mode): ?string + { + if ($this->isInMbCaseMode($mode, 'MB_CASE_UPPER', 'MB_CASE_UPPER_SIMPLE')) { + return 'strtoupper'; + } + + if ($this->isInMbCaseMode($mode, 'MB_CASE_LOWER', 'MB_CASE_LOWER_SIMPLE', 'MB_CASE_FOLD', 'MB_CASE_FOLD_SIMPLE')) { + return 'strtolower'; + } + + if ($this->isInMbCaseMode($mode, 'MB_CASE_TITLE', 'MB_CASE_TITLE_SIMPLE')) { + return 'ucwords'; + } + + return null; + } + + private function isInMbCaseMode(int $mode, string ...$cases): bool + { + $modes = \array_flip(self::MB_CASES); + + return isset($modes[$mode]) && \in_array($modes[$mode], $cases); + } + + private function getFunctionName(Node $node): ?string + { + if (!$node instanceof Node\Expr\FuncCall || !$node->name instanceof Node\Name) { + return null; + } + + return \strtolower($node->name->toString()); + } + + private function createNode(Node\Expr\FuncCall $node, string $functionName, array $args): Node\Expr\FuncCall + { + return new Node\Expr\FuncCall( + new Node\Name($functionName, $node->name->getAttributes()), + $args, + $node->getAttributes() + ); + } +} diff --git a/src/Mutator/Util/MutatorProfile.php b/src/Mutator/Util/MutatorProfile.php index ba113192e..a8f46427c 100644 --- a/src/Mutator/Util/MutatorProfile.php +++ b/src/Mutator/Util/MutatorProfile.php @@ -60,6 +60,7 @@ final class MutatorProfile '@zero_iteration' => self::ZERO_ITERATION, '@cast' => self::CAST, '@unwrap' => self::UNWRAP, + '@extensions' => self::EXTENSIONS, //Special Profiles '@default' => self::DEFAULT, @@ -232,6 +233,10 @@ final class MutatorProfile Mutator\Unwrap\UnwrapUcWords::class, ]; + public const EXTENSIONS = [ + Mutator\Extensions\MBString::class, + ]; + public const DEFAULT = [ '@arithmetic', '@boolean', @@ -246,6 +251,7 @@ final class MutatorProfile '@return_value', '@sort', '@zero_iteration', + '@extensions', ]; public const FULL_MUTATOR_LIST = [ @@ -395,5 +401,8 @@ final class MutatorProfile 'UnwrapTrim' => Mutator\Unwrap\UnwrapTrim::class, 'UnwrapUcFirst' => Mutator\Unwrap\UnwrapUcFirst::class, 'UnwrapUcWords' => Mutator\Unwrap\UnwrapUcWords::class, + + // Extensions + 'MBString' => Mutator\Extensions\MBString::class, ]; } diff --git a/tests/Mutator/Extensions/MBStringTest.php b/tests/Mutator/Extensions/MBStringTest.php new file mode 100644 index 000000000..2ba851173 --- /dev/null +++ b/tests/Mutator/Extensions/MBStringTest.php @@ -0,0 +1,462 @@ +doTest($input, $expected); + } + + public function provideMutationCases(): \Generator + { + yield 'It converts mb_strlen with leading slash' => [ + " [ + " [ + " [ + " chr + + yield 'It converts mb_chr to chr' => [ + ' [ + " preg_match + + yield 'It converts mb_ereg_match to preg_match' => [ + " [ + " preg_replace_callback + + yield 'It converts mb_ereg_replace_callback to preg_replace_callback' => [ + " [ + " ereg_replace + + yield 'It converts mb_ereg_replace to ereg_replace' => [ + " [ + " ereg + + yield 'It converts mb_ereg to ereg' => [ + " [ + " eregi_replace + + yield 'It converts mb_eregi_replace to eregi_replace' => [ + " [ + " eregi + + yield 'It converts mb_eregi to eregi' => [ + " [ + " ord + + yield 'It converts mb_ord to ord' => [ + " [ + " parse_str + + yield 'It converts mb_parse_str to parse_str' => [ + " [ + " mail + + yield 'It converts mb_send_mail to mail' => [ + " [ + " split + + yield 'It converts mb_split to split' => [ + " [ + " substr + + yield 'It converts mb_strcut to substr' => [ + " [ + " [ + " strpos + + yield 'It converts mb_strpos to strpos' => [ + " [ + " [ + " stripos + + yield 'It converts mb_stripos to stripos' => [ + " [ + " [ + " stristr + + yield 'It converts mb_stristr to stristr' => [ + " [ + " [ + " strripos + + yield 'It converts mb_strripos to strripos' => [ + " [ + " [ + " strrpos + + yield 'It converts mb_strrpos to strrpos' => [ + " [ + " [ + " strstr + + yield 'It converts mb_strstr to strstr' => [ + " [ + " [ + " strtolower + + yield 'It converts mb_strtolower to strtolower' => [ + " [ + " strtoupper + + yield 'It converts mb_strtoupper to strtoupper' => [ + " [ + " substr_count + + yield 'It converts mb_substr_count to substr_count' => [ + " [ + " substr + + yield 'It converts mb_substr to substr' => [ + " [ + " [ + " strrchr + + yield 'It converts mb_strrchr to strrchr' => [ + " [ + " [ + " strrchr + + yield 'It converts mb_strrichr to strrchr' => [ + " [ + " [ + " [ + " [ + " [ + " [ + " [ + " [ + " [ + " [ + " [ + " [ + " Date: Sun, 10 Mar 2019 13:44:08 +0100 Subject: [PATCH 02/18] #654 mbstring mutator configuration --- src/Mutator/Extensions/MBString.php | 15 ++++++++++++--- tests/Mutator/Extensions/MBStringTest.php | 11 +++++++++-- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/Mutator/Extensions/MBString.php b/src/Mutator/Extensions/MBString.php index b4b0742ac..3dd3e686a 100644 --- a/src/Mutator/Extensions/MBString.php +++ b/src/Mutator/Extensions/MBString.php @@ -61,7 +61,10 @@ final class MBString extends Mutator public function __construct(MutatorConfig $config) { parent::__construct($config); - $this->setupConverters(); + + $settings = $this->getSettings(); + + $this->setupConverters($settings); } /** @@ -77,9 +80,9 @@ protected function mutatesNode(Node $node): bool return isset($this->converters[$this->getFunctionName($node)]); } - private function setupConverters(): void + private function setupConverters(array $functionsMap): void { - $this->converters = [ + $converters = [ 'mb_chr' => $this->mapNameSkipArg('chr', 1), 'mb_ereg_match' => $this->mapNameSkipArg('preg_match', 2), 'mb_ereg_replace_callback' => $this->mapNameSkipArg('preg_replace_callback', 3), @@ -107,6 +110,12 @@ private function setupConverters(): void 'mb_substr' => $this->mapNameSkipArg('substr', 3), 'mb_convert_case' => $this->mapConvertCase(), ]; + + $functionsToRemove = \array_filter($functionsMap, function ($isOn) { + return !$isOn; + }); + + $this->converters = \array_diff_key($converters, $functionsToRemove); } private function mapName(string $functionName): callable diff --git a/tests/Mutator/Extensions/MBStringTest.php b/tests/Mutator/Extensions/MBStringTest.php index 2ba851173..f8180700f 100644 --- a/tests/Mutator/Extensions/MBStringTest.php +++ b/tests/Mutator/Extensions/MBStringTest.php @@ -45,9 +45,9 @@ final class MBStringTest extends AbstractMutatorTestCase /** * @dataProvider provideMutationCases */ - public function test_mutator(string $input, string $expected = null): void + public function test_mutator(string $input, string $expected = null, array $settings = []): void { - $this->doTest($input, $expected); + $this->doTest($input, $expected, $settings); } public function provideMutationCases(): \Generator @@ -69,6 +69,13 @@ public function provideMutationCases(): \Generator yield 'It converts mb_strlen with encoding to strlen' => [ " ['mb_strlen' => true]], + ]; + + yield 'It does not convert mb_strlen when disabled' => [ + " ['mb_strlen' => false]], ]; // mb_chr-> chr From 150ee972ed69fed6bdafe3ff23854ca97234a2c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kowalik?= Date: Sun, 10 Mar 2019 14:04:16 +0100 Subject: [PATCH 03/18] #654 fix code analysis issues --- src/Mutator/Extensions/MBString.php | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/Mutator/Extensions/MBString.php b/src/Mutator/Extensions/MBString.php index 3dd3e686a..adf45ea9c 100644 --- a/src/Mutator/Extensions/MBString.php +++ b/src/Mutator/Extensions/MBString.php @@ -128,13 +128,7 @@ private function mapName(string $functionName): callable private function mapNameSkipArg(string $functionName, int $skipArgs): callable { return function (Node\Expr\FuncCall $node) use ($functionName, $skipArgs): Generator { - $args = $node->args; - - if ($skipArgs !== null) { - $args = \array_slice($args, 0, $skipArgs); - } - - yield $this->createNode($node, $functionName, $args); + yield $this->createNode($node, $functionName, \array_slice($node->args, 0, $skipArgs)); }; } @@ -165,8 +159,6 @@ private function getConvertCaseModeValue(Node\Expr\FuncCall $node): ?int $mode = $node->args[1]->value; - $modeValue = null; - if ($mode instanceof Node\Expr\ConstFetch) { $modeName = $mode->name->toString(); From 97d64bc69a5fade49403fede6f5cfe11bcbc4a35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kowalik?= Date: Sun, 10 Mar 2019 14:09:08 +0100 Subject: [PATCH 04/18] #654 update json scheme for MBString mutator --- resources/schema.json | 99 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/resources/schema.json b/resources/schema.json index 5a37a82f4..5cfec4967 100644 --- a/resources/schema.json +++ b/resources/schema.json @@ -144,6 +144,105 @@ } ] } + }, + "MBString": { + "type": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "settings": { + "type": "object", + "additionalProperties": false, + "properties": { + "mb_chr": { + "type": "boolean" + }, + "mb_ereg_match": { + "type": "boolean" + }, + "mb_ereg_replace_callback": { + "type": "boolean" + }, + "mb_ereg_replace": { + "type": "boolean" + }, + "mb_ereg": { + "type": "boolean" + }, + "mb_eregi_replace": { + "type": "boolean" + }, + "mb_eregi": { + "type": "boolean" + }, + "mb_ord": { + "type": "boolean" + }, + "mb_parse_str": { + "type": "boolean" + }, + "mb_send_mail": { + "type": "boolean" + }, + "mb_split": { + "type": "boolean" + }, + "mb_strcut": { + "type": "boolean" + }, + "mb_stripos": { + "type": "boolean" + }, + "mb_stristr": { + "type": "boolean" + }, + "mb_strlen": { + "type": "boolean" + }, + "mb_strpos": { + "type": "boolean" + }, + "mb_strrchr": { + "type": "boolean" + }, + "mb_strrichr": { + "type": "boolean" + }, + "mb_strripos": { + "type": "boolean" + }, + "mb_strrpos": { + "type": "boolean" + }, + "mb_strstr": { + "type": "boolean" + }, + "mb_strtolower": { + "type": "boolean" + }, + "mb_strtoupper": { + "type": "boolean" + }, + "mb_substr_count": { + "type": "boolean" + }, + "mb_substr": { + "type": "boolean" + }, + "mb_convert_case": { + "type": "boolean" + } + } + } + } + } + ] + } } } }, From 45269900f3a63f4938db6102f7f7a4ff51693dab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kowalik?= Date: Sun, 10 Mar 2019 14:16:19 +0100 Subject: [PATCH 05/18] #654 fix spaceing --- src/Mutator/Extensions/MBString.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Mutator/Extensions/MBString.php b/src/Mutator/Extensions/MBString.php index adf45ea9c..287e851f5 100644 --- a/src/Mutator/Extensions/MBString.php +++ b/src/Mutator/Extensions/MBString.php @@ -111,7 +111,7 @@ private function setupConverters(array $functionsMap): void 'mb_convert_case' => $this->mapConvertCase(), ]; - $functionsToRemove = \array_filter($functionsMap, function ($isOn) { + $functionsToRemove = \array_filter($functionsMap, function($isOn) { return !$isOn; }); @@ -120,21 +120,21 @@ private function setupConverters(array $functionsMap): void private function mapName(string $functionName): callable { - return function (Node\Expr\FuncCall $node) use ($functionName): Generator { + return function(Node\Expr\FuncCall $node) use ($functionName): Generator { yield $this->createNode($node, $functionName, $node->args); }; } private function mapNameSkipArg(string $functionName, int $skipArgs): callable { - return function (Node\Expr\FuncCall $node) use ($functionName, $skipArgs): Generator { + return function(Node\Expr\FuncCall $node) use ($functionName, $skipArgs): Generator { yield $this->createNode($node, $functionName, \array_slice($node->args, 0, $skipArgs)); }; } private function mapConvertCase(): callable { - return function (Node\Expr\FuncCall $node): Generator { + return function(Node\Expr\FuncCall $node): Generator { $modeValue = $this->getConvertCaseModeValue($node); if ($modeValue === null) { From 733b40e66b4e20d2c933f449f23465a62bbc28c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kowalik?= Date: Sun, 10 Mar 2019 18:17:16 +0100 Subject: [PATCH 06/18] #654 remove mutants --- src/Mutator/Extensions/MBString.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Mutator/Extensions/MBString.php b/src/Mutator/Extensions/MBString.php index 287e851f5..0fe91e649 100644 --- a/src/Mutator/Extensions/MBString.php +++ b/src/Mutator/Extensions/MBString.php @@ -87,9 +87,9 @@ private function setupConverters(array $functionsMap): void 'mb_ereg_match' => $this->mapNameSkipArg('preg_match', 2), 'mb_ereg_replace_callback' => $this->mapNameSkipArg('preg_replace_callback', 3), 'mb_ereg_replace' => $this->mapNameSkipArg('ereg_replace', 3), - 'mb_ereg' => $this->mapNameSkipArg('ereg', 3), + 'mb_ereg' => $this->mapName('ereg'), 'mb_eregi_replace' => $this->mapNameSkipArg('eregi_replace', 3), - 'mb_eregi' => $this->mapNameSkipArg('eregi', 3), + 'mb_eregi' => $this->mapName('eregi'), 'mb_ord' => $this->mapNameSkipArg('ord', 1), 'mb_parse_str' => $this->mapName('parse_str'), 'mb_send_mail' => $this->mapName('mail'), From f6f7ff4a6e4659cef5130afc95a5ee95039ecdeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kowalik?= Date: Wed, 13 Mar 2019 00:58:49 +0100 Subject: [PATCH 07/18] #654 drop ereg functions in favoure of preg functions --- src/Mutator/Extensions/MBString.php | 56 +++++- tests/Mutator/Extensions/MBStringTest.php | 224 +++++++++++++++------- 2 files changed, 200 insertions(+), 80 deletions(-) diff --git a/src/Mutator/Extensions/MBString.php b/src/Mutator/Extensions/MBString.php index 0fe91e649..9018e1598 100644 --- a/src/Mutator/Extensions/MBString.php +++ b/src/Mutator/Extensions/MBString.php @@ -84,12 +84,12 @@ private function setupConverters(array $functionsMap): void { $converters = [ 'mb_chr' => $this->mapNameSkipArg('chr', 1), - 'mb_ereg_match' => $this->mapNameSkipArg('preg_match', 2), - 'mb_ereg_replace_callback' => $this->mapNameSkipArg('preg_replace_callback', 3), - 'mb_ereg_replace' => $this->mapNameSkipArg('ereg_replace', 3), - 'mb_ereg' => $this->mapName('ereg'), - 'mb_eregi_replace' => $this->mapNameSkipArg('eregi_replace', 3), - 'mb_eregi' => $this->mapName('eregi'), + 'mb_ereg_match' => $this->mapEreg($this->mapNameSkipArg('preg_match', 2), '^', '', [$this, 'warpEqOne']), + 'mb_ereg_replace_callback' => $this->mapEreg($this->mapNameSkipArg('preg_replace_callback', 3)), + 'mb_ereg_replace' => $this->mapEreg($this->mapNameSkipArg('preg_replace', 3)), + 'mb_ereg' => $this->mapEreg($this->mapName('preg_match'), '', '', [$this, 'warpTernary']), + 'mb_eregi_replace' => $this->mapEreg($this->mapNameSkipArg('preg_replace', 3), '', 'i'), + 'mb_eregi' => $this->mapEreg($this->mapName('preg_match'), '', 'i', [$this, 'warpTernary']), 'mb_ord' => $this->mapNameSkipArg('ord', 1), 'mb_parse_str' => $this->mapName('parse_str'), 'mb_send_mail' => $this->mapName('mail'), @@ -132,6 +132,50 @@ private function mapNameSkipArg(string $functionName, int $skipArgs): callable }; } + private function mapEreg(callable $baseConverter, string $prefix = '', string $suffix = '', callable $warp = null): callable + { + return function (Node\Expr\FuncCall $node) use ($baseConverter, $prefix, $suffix, $warp): Generator { + foreach ($baseConverter($node) as $newNode) { + /* @var Node\Expr\FuncCall $newNode */ + $newNode->args[0] = new Node\Arg( + new Node\Expr\BinaryOp\Concat( + new Node\Expr\BinaryOp\Concat( + new Node\Scalar\String_("/$prefix"), + new Node\Expr\FuncCall( + new Node\Name('\str_replace'), + [ + new Node\Arg(new Node\Scalar\String_('/')), + new Node\Arg(new Node\Scalar\String_('\/')), + new Node\Arg($newNode->args[0]->value), + ] + ) + ), + new Node\Scalar\String_("/$suffix") + ) + ); + + yield $warp ? $warp($newNode) : $newNode; + } + }; + } + + private function warpEqOne(Node\Expr\FuncCall $node): Node + { + return new Node\Expr\BinaryOp\Identical( + $node, + new Node\Scalar\LNumber(1) + ); + } + + private function warpTernary(Node\Expr\FuncCall $node): Node + { + return new Node\Expr\Ternary( + $node, + new Node\Scalar\LNumber(1), + new Node\Expr\ConstFetch(new Node\Name('false')) + ); + } + private function mapConvertCase(): callable { return function(Node\Expr\FuncCall $node): Generator { diff --git a/tests/Mutator/Extensions/MBStringTest.php b/tests/Mutator/Extensions/MBStringTest.php index f8180700f..451190711 100644 --- a/tests/Mutator/Extensions/MBStringTest.php +++ b/tests/Mutator/Extensions/MBStringTest.php @@ -35,6 +35,7 @@ namespace Infection\Tests\Mutator\Extensions; +use Generator; use Infection\Tests\Mutator\AbstractMutatorTestCase; /** @@ -50,7 +51,7 @@ public function test_mutator(string $input, string $expected = null, array $sett $this->doTest($input, $expected, $settings); } - public function provideMutationCases(): \Generator + public function provideMutationCases(): Generator { yield 'It converts mb_strlen with leading slash' => [ " ['mb_strlen' => false]], ]; - // mb_chr-> chr + yield from $this->provideMutationCasesForChr(); + yield from $this->provideMutationCasesForEregMatch(); + + yield from $this->provideMutationCasesForEregReplaceCallback(); + + yield from $this->provideMutationCasesForEregReplace(); + + yield from $this->provideMutationCasesForEreg(); + + yield from $this->provideMutationCasesForEregiReplace(); + + yield from $this->provideMutationCasesForEregi(); + + yield from $this->provideMutationCasesForOrd(); + + yield from $this->provideMutationCasesForParseStr(); + + yield from $this->provideMutationCasesForSendMail(); + + yield from $this->provideMutationCasesForSplit(); + + yield from $this->provideMutationCasesForStrCut(); + + yield from $this->provideMutationCasesForStrPos(); + + yield from $this->provideMutationCasesForStrIPos(); + + yield from $this->provideMutationCasesForStrIStr(); + + yield from $this->provideMutationCasesForStrRiPos(); + + yield from $this->provideMutationCasesForStrRPos(); + + yield from $this->provideMutationCasesForStrStr(); + + yield from $this->provideMutationCasesForStrToLower(); + + yield from $this->provideMutationCasesForStrToUpper(); + + yield from $this->provideMutationCasesForSubStrCount(); + + yield from $this->provideMutationCasesForSubStr(); + + yield from $this->provideMutationCasesForStrRChr(); + + yield from $this->provideMutationCasesForStrRiChr(); + + yield from $this->provideMutationCasesForConvertCase(); + } + + private function provideMutationCasesForChr(): Generator + { yield 'It converts mb_chr to chr' => [ ' preg_match - + private function provideMutationCasesForEregMatch(): Generator + { yield 'It converts mb_ereg_match to preg_match' => [ - " [ - " preg_replace_callback - + private function provideMutationCasesForEregReplaceCallback(): Generator + { yield 'It converts mb_ereg_replace_callback to preg_replace_callback' => [ - " [ - " ereg_replace - + private function provideMutationCasesForEregReplace(): Generator + { yield 'It converts mb_ereg_replace to ereg_replace' => [ - " [ - " ereg - + private function provideMutationCasesForEreg(): Generator + { yield 'It converts mb_ereg to ereg' => [ - " [ - " eregi_replace - + private function provideMutationCasesForEregiReplace(): Generator + { yield 'It converts mb_eregi_replace to eregi_replace' => [ - " [ - " eregi - + private function provideMutationCasesForEregi(): Generator + { yield 'It converts mb_eregi to eregi' => [ - " [ - " ord - + private function provideMutationCasesForOrd(): Generator + { yield 'It converts mb_ord to ord' => [ " parse_str - + private function provideMutationCasesForParseStr(): Generator + { yield 'It converts mb_parse_str to parse_str' => [ " mail - + private function provideMutationCasesForSendMail(): Generator + { yield 'It converts mb_send_mail to mail' => [ " split - + private function provideMutationCasesForSplit(): Generator + { yield 'It converts mb_split to split' => [ " substr - + private function provideMutationCasesForStrCut(): Generator + { yield 'It converts mb_strcut to substr' => [ " strpos - + private function provideMutationCasesForStrPos(): Generator + { yield 'It converts mb_strpos to strpos' => [ " stripos - + private function provideMutationCasesForStrIPos(): Generator + { yield 'It converts mb_stripos to stripos' => [ " stristr - + private function provideMutationCasesForStrIStr(): Generator + { yield 'It converts mb_stristr to stristr' => [ " strripos - + private function provideMutationCasesForStrRiPos(): Generator + { yield 'It converts mb_strripos to strripos' => [ " strrpos - + private function provideMutationCasesForStrRPos(): Generator + { yield 'It converts mb_strrpos to strrpos' => [ " strstr - + private function provideMutationCasesForStrStr(): Generator + { yield 'It converts mb_strstr to strstr' => [ " strtolower - + private function provideMutationCasesForStrToLower(): Generator + { yield 'It converts mb_strtolower to strtolower' => [ " strtoupper - + private function provideMutationCasesForStrToUpper(): Generator + { yield 'It converts mb_strtoupper to strtoupper' => [ " substr_count - + private function provideMutationCasesForSubStrCount(): Generator + { yield 'It converts mb_substr_count to substr_count' => [ " substr - + private function provideMutationCasesForSubStr(): Generator + { yield 'It converts mb_substr to substr' => [ " strrchr - + private function provideMutationCasesForStrRChr(): Generator + { yield 'It converts mb_strrchr to strrchr' => [ " strrchr - + private function provideMutationCasesForStrRiChr(): Generator + { yield 'It converts mb_strrichr to strrchr' => [ " [ " Date: Wed, 13 Mar 2019 01:08:10 +0100 Subject: [PATCH 08/18] #654 fix styles --- src/Mutator/Extensions/MBString.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Mutator/Extensions/MBString.php b/src/Mutator/Extensions/MBString.php index 9018e1598..633630c85 100644 --- a/src/Mutator/Extensions/MBString.php +++ b/src/Mutator/Extensions/MBString.php @@ -111,7 +111,7 @@ private function setupConverters(array $functionsMap): void 'mb_convert_case' => $this->mapConvertCase(), ]; - $functionsToRemove = \array_filter($functionsMap, function($isOn) { + $functionsToRemove = \array_filter($functionsMap, function ($isOn) { return !$isOn; }); @@ -120,21 +120,21 @@ private function setupConverters(array $functionsMap): void private function mapName(string $functionName): callable { - return function(Node\Expr\FuncCall $node) use ($functionName): Generator { + return function (Node\Expr\FuncCall $node) use ($functionName): Generator { yield $this->createNode($node, $functionName, $node->args); }; } private function mapNameSkipArg(string $functionName, int $skipArgs): callable { - return function(Node\Expr\FuncCall $node) use ($functionName, $skipArgs): Generator { + return function (Node\Expr\FuncCall $node) use ($functionName, $skipArgs): Generator { yield $this->createNode($node, $functionName, \array_slice($node->args, 0, $skipArgs)); }; } - private function mapEreg(callable $baseConverter, string $prefix = '', string $suffix = '', callable $warp = null): callable + private function mapEreg(callable $baseConverter, string $prefix = '', string $modifiers = '', callable $warp = null): callable { - return function (Node\Expr\FuncCall $node) use ($baseConverter, $prefix, $suffix, $warp): Generator { + return function (Node\Expr\FuncCall $node) use ($baseConverter, $prefix, $modifiers, $warp): Generator { foreach ($baseConverter($node) as $newNode) { /* @var Node\Expr\FuncCall $newNode */ $newNode->args[0] = new Node\Arg( @@ -150,7 +150,7 @@ private function mapEreg(callable $baseConverter, string $prefix = '', string $s ] ) ), - new Node\Scalar\String_("/$suffix") + new Node\Scalar\String_("/$modifiers") ) ); @@ -178,7 +178,7 @@ private function warpTernary(Node\Expr\FuncCall $node): Node private function mapConvertCase(): callable { - return function(Node\Expr\FuncCall $node): Generator { + return function (Node\Expr\FuncCall $node): Generator { $modeValue = $this->getConvertCaseModeValue($node); if ($modeValue === null) { From 21f83cb746bdc7b9b5b126d7261eacaf26322574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kowalik?= Date: Wed, 13 Mar 2019 23:07:06 +0100 Subject: [PATCH 09/18] #654 drop support fro mb_ereg* functions --- resources/schema.json | 18 ----- src/Mutator/Extensions/MBString.php | 50 ------------- tests/Mutator/Extensions/MBStringTest.php | 90 ----------------------- 3 files changed, 158 deletions(-) diff --git a/resources/schema.json b/resources/schema.json index 5cfec4967..c28edbc7c 100644 --- a/resources/schema.json +++ b/resources/schema.json @@ -162,24 +162,6 @@ "mb_chr": { "type": "boolean" }, - "mb_ereg_match": { - "type": "boolean" - }, - "mb_ereg_replace_callback": { - "type": "boolean" - }, - "mb_ereg_replace": { - "type": "boolean" - }, - "mb_ereg": { - "type": "boolean" - }, - "mb_eregi_replace": { - "type": "boolean" - }, - "mb_eregi": { - "type": "boolean" - }, "mb_ord": { "type": "boolean" }, diff --git a/src/Mutator/Extensions/MBString.php b/src/Mutator/Extensions/MBString.php index 633630c85..9b789792c 100644 --- a/src/Mutator/Extensions/MBString.php +++ b/src/Mutator/Extensions/MBString.php @@ -84,12 +84,6 @@ private function setupConverters(array $functionsMap): void { $converters = [ 'mb_chr' => $this->mapNameSkipArg('chr', 1), - 'mb_ereg_match' => $this->mapEreg($this->mapNameSkipArg('preg_match', 2), '^', '', [$this, 'warpEqOne']), - 'mb_ereg_replace_callback' => $this->mapEreg($this->mapNameSkipArg('preg_replace_callback', 3)), - 'mb_ereg_replace' => $this->mapEreg($this->mapNameSkipArg('preg_replace', 3)), - 'mb_ereg' => $this->mapEreg($this->mapName('preg_match'), '', '', [$this, 'warpTernary']), - 'mb_eregi_replace' => $this->mapEreg($this->mapNameSkipArg('preg_replace', 3), '', 'i'), - 'mb_eregi' => $this->mapEreg($this->mapName('preg_match'), '', 'i', [$this, 'warpTernary']), 'mb_ord' => $this->mapNameSkipArg('ord', 1), 'mb_parse_str' => $this->mapName('parse_str'), 'mb_send_mail' => $this->mapName('mail'), @@ -132,50 +126,6 @@ private function mapNameSkipArg(string $functionName, int $skipArgs): callable }; } - private function mapEreg(callable $baseConverter, string $prefix = '', string $modifiers = '', callable $warp = null): callable - { - return function (Node\Expr\FuncCall $node) use ($baseConverter, $prefix, $modifiers, $warp): Generator { - foreach ($baseConverter($node) as $newNode) { - /* @var Node\Expr\FuncCall $newNode */ - $newNode->args[0] = new Node\Arg( - new Node\Expr\BinaryOp\Concat( - new Node\Expr\BinaryOp\Concat( - new Node\Scalar\String_("/$prefix"), - new Node\Expr\FuncCall( - new Node\Name('\str_replace'), - [ - new Node\Arg(new Node\Scalar\String_('/')), - new Node\Arg(new Node\Scalar\String_('\/')), - new Node\Arg($newNode->args[0]->value), - ] - ) - ), - new Node\Scalar\String_("/$modifiers") - ) - ); - - yield $warp ? $warp($newNode) : $newNode; - } - }; - } - - private function warpEqOne(Node\Expr\FuncCall $node): Node - { - return new Node\Expr\BinaryOp\Identical( - $node, - new Node\Scalar\LNumber(1) - ); - } - - private function warpTernary(Node\Expr\FuncCall $node): Node - { - return new Node\Expr\Ternary( - $node, - new Node\Scalar\LNumber(1), - new Node\Expr\ConstFetch(new Node\Name('false')) - ); - } - private function mapConvertCase(): callable { return function (Node\Expr\FuncCall $node): Generator { diff --git a/tests/Mutator/Extensions/MBStringTest.php b/tests/Mutator/Extensions/MBStringTest.php index 451190711..5bd128fce 100644 --- a/tests/Mutator/Extensions/MBStringTest.php +++ b/tests/Mutator/Extensions/MBStringTest.php @@ -81,18 +81,6 @@ public function provideMutationCases(): Generator yield from $this->provideMutationCasesForChr(); - yield from $this->provideMutationCasesForEregMatch(); - - yield from $this->provideMutationCasesForEregReplaceCallback(); - - yield from $this->provideMutationCasesForEregReplace(); - - yield from $this->provideMutationCasesForEreg(); - - yield from $this->provideMutationCasesForEregiReplace(); - - yield from $this->provideMutationCasesForEregi(); - yield from $this->provideMutationCasesForOrd(); yield from $this->provideMutationCasesForParseStr(); @@ -143,84 +131,6 @@ private function provideMutationCasesForChr(): Generator ]; } - private function provideMutationCasesForEregMatch(): Generator - { - yield 'It converts mb_ereg_match to preg_match' => [ - " [ - " [ - " [ - " [ - " [ - " [ - " [ - " [ - " [ - " [ - " [ - " [ From 13af845844833c21fa8e75fb63245e2205562c3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kowalik?= Date: Thu, 14 Mar 2019 00:05:12 +0100 Subject: [PATCH 10/18] #654 mutate mb_convert_case with integer mode --- src/Mutator/Extensions/MBString.php | 2 ++ tests/Mutator/Extensions/MBStringTest.php | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Mutator/Extensions/MBString.php b/src/Mutator/Extensions/MBString.php index 9b789792c..a7b51e4f5 100644 --- a/src/Mutator/Extensions/MBString.php +++ b/src/Mutator/Extensions/MBString.php @@ -163,6 +163,8 @@ private function getConvertCaseModeValue(Node\Expr\FuncCall $node): ?int if (isset(self::MB_CASES[$modeName])) { return self::MB_CASES[$modeName]; } + } elseif ($mode instanceof Node\Scalar\LNumber) { + return $mode->value; } return null; diff --git a/tests/Mutator/Extensions/MBStringTest.php b/tests/Mutator/Extensions/MBStringTest.php index 5bd128fce..14ed4e064 100644 --- a/tests/Mutator/Extensions/MBStringTest.php +++ b/tests/Mutator/Extensions/MBStringTest.php @@ -414,11 +414,16 @@ private function provideMutationCasesForConvertCase(): Generator " [ + yield 'It converts mb_convert_case with constant similar MB_CASE_LOWER mode to strtolower' => [ " [ + " [ " Date: Tue, 19 Mar 2019 00:30:48 +0100 Subject: [PATCH 11/18] #654 remove functions that cannot be easily mapped --- src/Mutator/Extensions/MBString.php | 2 -- tests/Mutator/Extensions/MBStringTest.php | 35 ----------------------- 2 files changed, 37 deletions(-) diff --git a/src/Mutator/Extensions/MBString.php b/src/Mutator/Extensions/MBString.php index a7b51e4f5..d332870b1 100644 --- a/src/Mutator/Extensions/MBString.php +++ b/src/Mutator/Extensions/MBString.php @@ -87,14 +87,12 @@ private function setupConverters(array $functionsMap): void 'mb_ord' => $this->mapNameSkipArg('ord', 1), 'mb_parse_str' => $this->mapName('parse_str'), 'mb_send_mail' => $this->mapName('mail'), - 'mb_split' => $this->mapName('split'), 'mb_strcut' => $this->mapNameSkipArg('substr', 3), 'mb_stripos' => $this->mapNameSkipArg('stripos', 3), 'mb_stristr' => $this->mapNameSkipArg('stristr', 3), 'mb_strlen' => $this->mapNameSkipArg('strlen', 1), 'mb_strpos' => $this->mapNameSkipArg('strpos', 3), 'mb_strrchr' => $this->mapNameSkipArg('strrchr', 2), - 'mb_strrichr' => $this->mapNameSkipArg('strrchr', 2), 'mb_strripos' => $this->mapNameSkipArg('strripos', 3), 'mb_strrpos' => $this->mapNameSkipArg('strrpos', 3), 'mb_strstr' => $this->mapNameSkipArg('strstr', 3), diff --git a/tests/Mutator/Extensions/MBStringTest.php b/tests/Mutator/Extensions/MBStringTest.php index 14ed4e064..5f2deb203 100644 --- a/tests/Mutator/Extensions/MBStringTest.php +++ b/tests/Mutator/Extensions/MBStringTest.php @@ -87,8 +87,6 @@ public function provideMutationCases(): Generator yield from $this->provideMutationCasesForSendMail(); - yield from $this->provideMutationCasesForSplit(); - yield from $this->provideMutationCasesForStrCut(); yield from $this->provideMutationCasesForStrPos(); @@ -113,8 +111,6 @@ public function provideMutationCases(): Generator yield from $this->provideMutationCasesForStrRChr(); - yield from $this->provideMutationCasesForStrRiChr(); - yield from $this->provideMutationCasesForConvertCase(); } @@ -170,19 +166,6 @@ private function provideMutationCasesForSendMail(): Generator ]; } - private function provideMutationCasesForSplit(): Generator - { - yield 'It converts mb_split to split' => [ - " [ - " [ @@ -384,24 +367,6 @@ private function provideMutationCasesForStrRChr(): Generator ]; } - private function provideMutationCasesForStrRiChr(): Generator - { - yield 'It converts mb_strrichr to strrchr' => [ - " [ - " [ - " [ From 1d6bb5ed541bb670f865ac10b8499df879bc812a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kowalik?= Date: Thu, 21 Mar 2019 23:36:04 +0100 Subject: [PATCH 12/18] #654 rm mb_split from json schema --- resources/schema.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/resources/schema.json b/resources/schema.json index c28edbc7c..5e046901f 100644 --- a/resources/schema.json +++ b/resources/schema.json @@ -171,9 +171,6 @@ "mb_send_mail": { "type": "boolean" }, - "mb_split": { - "type": "boolean" - }, "mb_strcut": { "type": "boolean" }, From 7420b4c2f334706a2390ef0b34c8f0805930d2c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kowalik?= Date: Thu, 21 Mar 2019 23:43:06 +0100 Subject: [PATCH 13/18] #654 rm mb_strrichr from json schema --- resources/schema.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/resources/schema.json b/resources/schema.json index 5e046901f..14b93a998 100644 --- a/resources/schema.json +++ b/resources/schema.json @@ -189,9 +189,6 @@ "mb_strrchr": { "type": "boolean" }, - "mb_strrichr": { - "type": "boolean" - }, "mb_strripos": { "type": "boolean" }, From c683158e2bdebb981b839029bbf8edbd6fb410b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kowalik?= Date: Tue, 26 Mar 2019 23:12:29 +0100 Subject: [PATCH 14/18] #654 code style fixes --- src/Mutator/Extensions/MBString.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mutator/Extensions/MBString.php b/src/Mutator/Extensions/MBString.php index d332870b1..d8035ec70 100644 --- a/src/Mutator/Extensions/MBString.php +++ b/src/Mutator/Extensions/MBString.php @@ -103,7 +103,7 @@ private function setupConverters(array $functionsMap): void 'mb_convert_case' => $this->mapConvertCase(), ]; - $functionsToRemove = \array_filter($functionsMap, function ($isOn) { + $functionsToRemove = \array_filter($functionsMap, static function ($isOn) { return !$isOn; }); From cacb538cf535dcaac117097929a4f3762bcba8d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kowalik?= Date: Wed, 27 Mar 2019 22:14:32 +0100 Subject: [PATCH 15/18] #654 simplify MBString mutator --- src/Mutator/Extensions/MBString.php | 89 ++++++++++------------- tests/Mutator/Extensions/MBStringTest.php | 20 +++++ 2 files changed, 58 insertions(+), 51 deletions(-) diff --git a/src/Mutator/Extensions/MBString.php b/src/Mutator/Extensions/MBString.php index d8035ec70..afa803372 100644 --- a/src/Mutator/Extensions/MBString.php +++ b/src/Mutator/Extensions/MBString.php @@ -45,17 +45,6 @@ */ final class MBString extends Mutator { - private const MB_CASES = [ - 'MB_CASE_UPPER' => 0, - 'MB_CASE_LOWER' => 1, - 'MB_CASE_TITLE' => 2, - 'MB_CASE_FOLD' => 3, - 'MB_CASE_UPPER_SIMPLE' => 4, - 'MB_CASE_LOWER_SIMPLE' => 5, - 'MB_CASE_TITLE_SIMPLE' => 6, - 'MB_CASE_FOLD_SIMPLE' => 7, - ]; - private $converters; public function __construct(MutatorConfig $config) @@ -83,23 +72,23 @@ protected function mutatesNode(Node $node): bool private function setupConverters(array $functionsMap): void { $converters = [ - 'mb_chr' => $this->mapNameSkipArg('chr', 1), - 'mb_ord' => $this->mapNameSkipArg('ord', 1), - 'mb_parse_str' => $this->mapName('parse_str'), - 'mb_send_mail' => $this->mapName('mail'), - 'mb_strcut' => $this->mapNameSkipArg('substr', 3), - 'mb_stripos' => $this->mapNameSkipArg('stripos', 3), - 'mb_stristr' => $this->mapNameSkipArg('stristr', 3), - 'mb_strlen' => $this->mapNameSkipArg('strlen', 1), - 'mb_strpos' => $this->mapNameSkipArg('strpos', 3), - 'mb_strrchr' => $this->mapNameSkipArg('strrchr', 2), - 'mb_strripos' => $this->mapNameSkipArg('strripos', 3), - 'mb_strrpos' => $this->mapNameSkipArg('strrpos', 3), - 'mb_strstr' => $this->mapNameSkipArg('strstr', 3), - 'mb_strtolower' => $this->mapNameSkipArg('strtolower', 1), - 'mb_strtoupper' => $this->mapNameSkipArg('strtoupper', 1), - 'mb_substr_count' => $this->mapNameSkipArg('substr_count', 2), - 'mb_substr' => $this->mapNameSkipArg('substr', 3), + 'mb_chr' => $this->mapFunctionAndRemoveExtraArgs('chr', 1), + 'mb_ord' => $this->mapFunctionAndRemoveExtraArgs('ord', 1), + 'mb_parse_str' => $this->mapFunction('parse_str'), + 'mb_send_mail' => $this->mapFunction('mail'), + 'mb_strcut' => $this->mapFunctionAndRemoveExtraArgs('substr', 3), + 'mb_stripos' => $this->mapFunctionAndRemoveExtraArgs('stripos', 3), + 'mb_stristr' => $this->mapFunctionAndRemoveExtraArgs('stristr', 3), + 'mb_strlen' => $this->mapFunctionAndRemoveExtraArgs('strlen', 1), + 'mb_strpos' => $this->mapFunctionAndRemoveExtraArgs('strpos', 3), + 'mb_strrchr' => $this->mapFunctionAndRemoveExtraArgs('strrchr', 2), + 'mb_strripos' => $this->mapFunctionAndRemoveExtraArgs('strripos', 3), + 'mb_strrpos' => $this->mapFunctionAndRemoveExtraArgs('strrpos', 3), + 'mb_strstr' => $this->mapFunctionAndRemoveExtraArgs('strstr', 3), + 'mb_strtolower' => $this->mapFunctionAndRemoveExtraArgs('strtolower', 1), + 'mb_strtoupper' => $this->mapFunctionAndRemoveExtraArgs('strtoupper', 1), + 'mb_substr_count' => $this->mapFunctionAndRemoveExtraArgs('substr_count', 2), + 'mb_substr' => $this->mapFunctionAndRemoveExtraArgs('substr', 3), 'mb_convert_case' => $this->mapConvertCase(), ]; @@ -110,17 +99,17 @@ private function setupConverters(array $functionsMap): void $this->converters = \array_diff_key($converters, $functionsToRemove); } - private function mapName(string $functionName): callable + private function mapFunction(string $newFunctionName): callable { - return function (Node\Expr\FuncCall $node) use ($functionName): Generator { - yield $this->createNode($node, $functionName, $node->args); + return function (Node\Expr\FuncCall $node) use ($newFunctionName): Generator { + yield $this->mapFunctionCall($node, $newFunctionName, $node->args); }; } - private function mapNameSkipArg(string $functionName, int $skipArgs): callable + private function mapFunctionAndRemoveExtraArgs(string $newFunctionName, int $argsAtMost): callable { - return function (Node\Expr\FuncCall $node) use ($functionName, $skipArgs): Generator { - yield $this->createNode($node, $functionName, \array_slice($node->args, 0, $skipArgs)); + return function (Node\Expr\FuncCall $node) use ($newFunctionName, $argsAtMost): Generator { + yield $this->mapFunctionCall($node, $newFunctionName, \array_slice($node->args, 0, $argsAtMost)); }; } @@ -139,7 +128,7 @@ private function mapConvertCase(): callable return; } - yield $this->createNode($node, $functionName, [$node->args[0]]); + yield $this->mapFunctionCall($node, $functionName, [$node->args[0]]); }; } @@ -151,20 +140,14 @@ private function getConvertCaseModeValue(Node\Expr\FuncCall $node): ?int $mode = $node->args[1]->value; - if ($mode instanceof Node\Expr\ConstFetch) { - $modeName = $mode->name->toString(); - - if (\defined($modeName)) { - return \constant($modeName); - } - - if (isset(self::MB_CASES[$modeName])) { - return self::MB_CASES[$modeName]; - } - } elseif ($mode instanceof Node\Scalar\LNumber) { + if ($mode instanceof Node\Scalar\LNumber) { return $mode->value; } + if ($mode instanceof Node\Expr\ConstFetch) { + return \constant($mode->name->toString()); + } + return null; } @@ -187,9 +170,13 @@ private function getConvertCaseFunctionName(int $mode): ?string private function isInMbCaseMode(int $mode, string ...$cases): bool { - $modes = \array_flip(self::MB_CASES); + foreach ($cases as $constant) { + if (\defined($constant) && \constant($constant) === $mode) { + return true; + } + } - return isset($modes[$mode]) && \in_array($modes[$mode], $cases); + return false; } private function getFunctionName(Node $node): ?string @@ -198,13 +185,13 @@ private function getFunctionName(Node $node): ?string return null; } - return \strtolower($node->name->toString()); + return $node->name->toLowerString(); } - private function createNode(Node\Expr\FuncCall $node, string $functionName, array $args): Node\Expr\FuncCall + private function mapFunctionCall(Node\Expr\FuncCall $node, string $newFuncName, array $args): Node\Expr\FuncCall { return new Node\Expr\FuncCall( - new Node\Name($functionName, $node->name->getAttributes()), + new Node\Name($newFuncName, $node->name->getAttributes()), $args, $node->getAttributes() ); diff --git a/tests/Mutator/Extensions/MBStringTest.php b/tests/Mutator/Extensions/MBStringTest.php index 5f2deb203..f65fac191 100644 --- a/tests/Mutator/Extensions/MBStringTest.php +++ b/tests/Mutator/Extensions/MBStringTest.php @@ -43,6 +43,11 @@ */ final class MBStringTest extends AbstractMutatorTestCase { + public static function setUpBeforeClass(): void + { + self::defineMissingMbCaseConstants(); + } + /** * @dataProvider provideMutationCases */ @@ -422,4 +427,19 @@ private function provideMutationCasesForConvertCase(): Generator " 3, + 'MB_CASE_UPPER_SIMPLE' => 4, + 'MB_CASE_LOWER_SIMPLE' => 5, + 'MB_CASE_TITLE_SIMPLE' => 6, + 'MB_CASE_FOLD_SIMPLE' => 7, + ] as $constantName => $constantValue) { + if (!\defined($constantName)) { + \define($constantName, $constantValue); + } + } + } } From 3b486ca253fe11f1f23c795e3b7900a0e2c96568 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kowalik?= Date: Thu, 28 Mar 2019 07:17:39 +0100 Subject: [PATCH 16/18] #654 remove getFunctionName fx --- src/Mutator/Extensions/MBString.php | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/Mutator/Extensions/MBString.php b/src/Mutator/Extensions/MBString.php index afa803372..c10fc4417 100644 --- a/src/Mutator/Extensions/MBString.php +++ b/src/Mutator/Extensions/MBString.php @@ -57,16 +57,22 @@ public function __construct(MutatorConfig $config) } /** + * @param 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 { - return isset($this->converters[$this->getFunctionName($node)]); + if (!$node instanceof Node\Expr\FuncCall || !$node->name instanceof Node\Name) { + return false; + } + + return isset($this->converters[$node->name->toLowerString()]); } private function setupConverters(array $functionsMap): void @@ -179,15 +185,6 @@ private function isInMbCaseMode(int $mode, string ...$cases): bool return false; } - private function getFunctionName(Node $node): ?string - { - if (!$node instanceof Node\Expr\FuncCall || !$node->name instanceof Node\Name) { - return null; - } - - return $node->name->toLowerString(); - } - private function mapFunctionCall(Node\Expr\FuncCall $node, string $newFuncName, array $args): Node\Expr\FuncCall { return new Node\Expr\FuncCall( From a6a4e4b5794c66ce8bddb3006bac5c89645cff29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kowalik?= Date: Sat, 30 Mar 2019 11:22:45 +0100 Subject: [PATCH 17/18] #654 add tests cases for capitalization --- tests/Mutator/Extensions/MBStringTest.php | 85 +++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/tests/Mutator/Extensions/MBStringTest.php b/tests/Mutator/Extensions/MBStringTest.php index f65fac191..298c7bdb5 100644 --- a/tests/Mutator/Extensions/MBStringTest.php +++ b/tests/Mutator/Extensions/MBStringTest.php @@ -126,6 +126,11 @@ private function provideMutationCasesForChr(): Generator " [ + ' [ " [ + " [ " [ + " [ " [ + " [ " [ + " [ " [ + " [ " [ + " [ " [ + " [ " [ + " [ " [ + " [ " [ + " [ " [ + " [ " [ + " [ " [ + " [ " [ + " [ " [ + " [ " [ + " [ " Date: Sat, 30 Mar 2019 12:05:28 +0100 Subject: [PATCH 18/18] #654 add test for calling functions via variable --- tests/Mutator/Extensions/MBStringTest.php | 68 +++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/tests/Mutator/Extensions/MBStringTest.php b/tests/Mutator/Extensions/MBStringTest.php index 298c7bdb5..6a05a4f62 100644 --- a/tests/Mutator/Extensions/MBStringTest.php +++ b/tests/Mutator/Extensions/MBStringTest.php @@ -135,6 +135,10 @@ private function provideMutationCasesForChr(): Generator " [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ " [ + '