diff --git a/.php_cs.dist b/.php_cs.dist index 78bc9fa..c3742ac 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -1,4 +1,21 @@ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +declare(strict_types=1); $header = <<<'EOF' Copyright 2017, 2018 Alexey Kopytko @@ -20,6 +37,8 @@ return PhpCsFixer\Config::create() ->setRiskyAllowed(true) ->setRules([ '@Symfony' => true, + '@Symfony:risky' => true, + '@PHP70Migration:risky' => true, 'array_syntax' => ['syntax' => 'short'], 'declare_strict_types' => true, 'explicit_indirect_variable' => true, @@ -31,13 +50,21 @@ return PhpCsFixer\Config::create() 'non_printable_character' => true, 'ordered_imports' => true, 'php_unit_test_class_requires_covers' => true, + 'php_unit_strict' => true, 'phpdoc_add_missing_param_annotation' => true, 'phpdoc_order' => true, 'visibility_required' => true, 'header_comment' => ['header' => $header, 'separate' => 'bottom', 'location' => 'after_open'], 'ternary_to_null_coalescing' => true, - 'yoda_style' => null, + 'yoda_style' => true, 'phpdoc_to_comment' => false, + 'strict_comparison' => true, + 'is_null' => true, + 'function_to_constant' => true, + 'void_return' => false, + 'return_assignment' => true, + 'array_syntax' => ['syntax' => 'short'], + 'array_indentation' => true, ]) ->setFinder( PhpCsFixer\Finder::create() diff --git a/Makefile b/Makefile index 9845e9f..71c9c73 100644 --- a/Makefile +++ b/Makefile @@ -40,7 +40,7 @@ COMPOSER=$(PHP) $(shell which composer) # Infection INFECTION=vendor/bin/infection -MIN_MSI=90 +MIN_MSI=100 MIN_COVERED_MSI=100 INFECTION_ARGS=--min-msi=$(MIN_MSI) --min-covered-msi=$(MIN_COVERED_MSI) --threads=$(JOBS) --coverage=build/logs --log-verbosity=default --show-mutations diff --git a/composer.json b/composer.json index ba5c773..ec22c37 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,10 @@ "psr-4": {"Pipeline\\": "src/"} }, "autoload-dev": { - "psr-4": {"Pipeline\\": "tests/"} + "psr-4": { + "Tests\\Pipeline\\": "tests/", + "Pipeline\\": "tests/" + } }, "require": { "php": ">=7" diff --git a/example.php b/example.php index db9b850..e6a22a2 100644 --- a/example.php +++ b/example.php @@ -29,9 +29,9 @@ }); // next processing step -$pipeline->map(function ($i) { - yield pow($i, 2); - yield pow($i, 3); +$pipeline->map(function ($value) { + yield $value ** 2; + yield $value ** 3; }); // simple one-to-one mapper diff --git a/infection.json.dist b/infection.json.dist index 86f9c88..9c232a3 100644 --- a/infection.json.dist +++ b/infection.json.dist @@ -5,6 +5,11 @@ "src" ] }, + "mutators": { + "@default": true, + "IdenticalEqual": false, + "NotIdenticalNotEqual": false + }, "logs": { "text": "infection-log.txt", "badge": {"branch": "master"} diff --git a/src/Principal.php b/src/Principal.php index e6005ff..6ad2693 100644 --- a/src/Principal.php +++ b/src/Principal.php @@ -49,14 +49,14 @@ public function map(callable $func) // This also allows inheriting classes to replace the pipeline if ($func instanceof self) { /** @psalm-suppress MixedAssignment */ - $this->pipeline = call_user_func($func); + $this->pipeline = \call_user_func($func); return $this; } if (!$this->pipeline) { /** @psalm-suppress MixedAssignment */ - $this->pipeline = call_user_func($func); + $this->pipeline = \call_user_func($func); // Not a generator means we were given a simple value to be treated as an array if (!($this->pipeline instanceof \Generator)) { diff --git a/src/Simple.php b/src/Simple.php index 16b4767..d1ad0c3 100644 --- a/src/Simple.php +++ b/src/Simple.php @@ -22,7 +22,7 @@ /** * Legacy alias from early days. Please do not remove. * - * @deprecated + * @deprecated use Standard */ class Simple extends Standard { diff --git a/src/Standard.php b/src/Standard.php index 391460b..59cd8c5 100644 --- a/src/Standard.php +++ b/src/Standard.php @@ -49,7 +49,7 @@ public function unpack(callable $func = null) public function filter(callable $func = null) { // Strings usually are internal functions, which require exact number of parameters. - if (is_string($func)) { + if (\is_string($func)) { $func = static function ($value) use ($func) { return $func($value); }; diff --git a/tests/ArraysTest.php b/tests/ArraysTest.php new file mode 100644 index 0000000..d05ea13 --- /dev/null +++ b/tests/ArraysTest.php @@ -0,0 +1,70 @@ + + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +declare(strict_types=1); + +namespace Tests\Pipeline; + +use PHPUnit\Framework\TestCase; +use Pipeline\Standard; + +/** + * @covers \Pipeline\Standard + * @covers \Pipeline\Principal + */ +class ArraysTest extends TestCase +{ + public function testInitialCallbackNotGenerator() + { + $pipeline = new Standard(); + $pipeline->map(function () { + return PHP_INT_MAX; + }); + + $this->assertSame([PHP_INT_MAX], iterator_to_array($pipeline)); + } + + public function testArrayToArray() + { + $pipeline = new Standard(); + $pipeline->map(function () { + return 42; + }); + + $this->assertSame([42], $pipeline->toArray()); + } + + public function testArrayFilter() + { + $pipeline = new Standard(); + $pipeline->map(function () { + return false; + })->filter()->filter(); + + $this->assertSame([], $pipeline->toArray()); + } + + public function testArrayReduce() + { + $pipeline = new Standard(); + $pipeline->map(function () { + return 3; + }); + + $this->assertSame(3, $pipeline->reduce()); + } +} diff --git a/tests/EdgeCasesTest.php b/tests/EdgeCasesTest.php index b8e91aa..18ecc94 100644 --- a/tests/EdgeCasesTest.php +++ b/tests/EdgeCasesTest.php @@ -34,7 +34,7 @@ public function testInitialCallbackNotGenerator() return PHP_INT_MAX; }); - $this->assertEquals([PHP_INT_MAX], iterator_to_array($pipeline)); + $this->assertSame([PHP_INT_MAX], iterator_to_array($pipeline)); } public function testStandardStringFunctions() @@ -42,7 +42,7 @@ public function testStandardStringFunctions() $pipeline = new Standard(new \ArrayIterator([1, 2, 'foo', 'bar'])); $pipeline->filter('is_int'); - $this->assertEquals([1, 2], iterator_to_array($pipeline)); + $this->assertSame([1, 2], iterator_to_array($pipeline)); } public function testFilterAnyFalseValue() @@ -70,7 +70,7 @@ public function testMapUnprimed() return 1; }); - $this->assertEquals([1], $pipeline->toArray()); + $this->assertSame([1], $pipeline->toArray()); } public function testFilterUnprimed() @@ -78,7 +78,7 @@ public function testFilterUnprimed() $pipeline = new Standard(); $pipeline->filter()->unpack(); - $this->assertEquals([], $pipeline->toArray()); + $this->assertSame([], $pipeline->toArray()); } public function testUnpackUnprimed() @@ -88,7 +88,7 @@ public function testUnpackUnprimed() return 1; }); - $this->assertEquals([1], $pipeline->toArray()); + $this->assertSame([1], $pipeline->toArray()); } public function testInitialInvokeReturnsScalar() @@ -96,7 +96,7 @@ public function testInitialInvokeReturnsScalar() $pipeline = new Standard(); $pipeline->map($this); - $this->assertEquals([null], iterator_to_array($pipeline)); + $this->assertSame([null], iterator_to_array($pipeline)); } private function firstValueFromIterator(\Iterator $iterator) @@ -115,11 +115,11 @@ public function testIteratorIterator() $iterator = new \IteratorIterator($pipeline); /* @var $iterator \Iterator */ - $this->assertEquals(42, $this->firstValueFromIterator($iterator)); + $this->assertSame(42, $this->firstValueFromIterator($iterator)); $pipeline = new Standard(new \ArrayIterator([42])); $iterator = new \IteratorIterator($pipeline); - $this->assertEquals(42, $this->firstValueFromIterator($iterator)); + $this->assertSame(42, $this->firstValueFromIterator($iterator)); } public function testIteratorToArrayWithSameKeys() @@ -135,7 +135,7 @@ public function testIteratorToArrayWithSameKeys() yield $i + 2; }); - $this->assertEquals([3, 4], iterator_to_array($pipeline)); + $this->assertSame([3, 4], iterator_to_array($pipeline)); } public function testPointlessReplace() @@ -171,7 +171,7 @@ public function testInvokeMaps() $pipeline = new \Pipeline\Standard(new \ArrayIterator(range(1, 5))); $pipeline->map($this); - $this->assertEquals(range(1, 5), iterator_to_array($pipeline)); + $this->assertSame(range(1, 5), iterator_to_array($pipeline)); } public function __invoke($default = null) diff --git a/tests/ErrorsTest.php b/tests/ErrorsTest.php index 1ae34ab..d77b523 100644 --- a/tests/ErrorsTest.php +++ b/tests/ErrorsTest.php @@ -61,7 +61,7 @@ public function testPipelineInPipelineUsesSelf() }); $pipeline->map($pipeline)->filter(function ($i) { - return $i % 2 != 0; + return 0 !== $i % 2; }); $this->expectExceptionMessage('Cannot resume an already running generator'); diff --git a/tests/IterableTest.php b/tests/IterableTest.php new file mode 100644 index 0000000..729ee2c --- /dev/null +++ b/tests/IterableTest.php @@ -0,0 +1,98 @@ + + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +declare(strict_types=1); + +namespace Tests\Pipeline; + +use PHPUnit\Framework\TestCase; +use Pipeline\Standard; + +/** + * @covers \Pipeline\Standard + * @covers \Pipeline\Principal + */ +class IterableTest extends TestCase +{ + private static $usesIterable; + + public static function setUpBeforeClass() + { + if (\PHP_VERSION_ID < 70100) { + self::$usesIterable = false; + + return; + } + + $reflection = new \ReflectionClass(Standard::class); + $type = $reflection->getConstructor()->getParameters()[0]->getType(); + self::$usesIterable = $type->isBuiltin(); // Traversable isn't builtin + } + + protected function setUp() + { + if (!self::$usesIterable) { + $this->markTestSkipped('Not testing iterables: not yet supported by the interface'); + } + } + + public function testArrayToArray() + { + $pipeline = new Standard([1, 2, 3]); + $this->assertSame([1, 2, 3], $pipeline->toArray()); + } + + public function testArrayToIterator() + { + $pipeline = new Standard([1, 2, 3]); + $this->assertSame([1, 2, 3], iterator_to_array($pipeline)); + } + + public function testEmptyArrayStaysEmpty() + { + $pipeline = new Standard([]); + + $pipeline->filter()->map(function ($value) { + yield $value; + yield $value; + })->filter()->unpack(); + + $this->assertSame([], $pipeline->toArray()); + } + + public function testArrayFilter() + { + $pipeline = new Standard([0, 1, 2, 3, 0]); + $this->assertSame([1, 2, 3], $pipeline->filter()->toArray()); + } + + public function testArrayMap() + { + $pipeline = new Standard([1 => 0, 1, 2, 3]); + $this->assertSame([0 => 0, 1, 2, 3], $pipeline->map(function ($value) { + return $value; + })->toArray()); + } + + public function testArrayMapFilter() + { + $pipeline = new Standard([1 => 0, 1, 2, 3]); + $this->assertSame([0 => 1, 2, 3], $pipeline->map(function ($value) { + return $value; + })->filter()->toArray()); + } +} diff --git a/tests/LeaguePipelineTest.php b/tests/LeaguePipelineTest.php index 0d52939..7afc456 100644 --- a/tests/LeaguePipelineTest.php +++ b/tests/LeaguePipelineTest.php @@ -34,11 +34,11 @@ public function testWithLeaguePipeline() return $payload * 2; }); - $this->assertEquals(22, $leaguePipeline(10)); + $this->assertSame(22, $leaguePipeline(10)); $pipeline = new \Pipeline\Standard(new \ArrayIterator([10, 20, 30])); $pipeline->map($leaguePipeline); - $this->assertEquals([22, 42, 62], iterator_to_array($pipeline)); + $this->assertSame([22, 42, 62], iterator_to_array($pipeline)); } } diff --git a/tests/StandardTest.php b/tests/StandardTest.php index 7667341..93be442 100644 --- a/tests/StandardTest.php +++ b/tests/StandardTest.php @@ -29,10 +29,10 @@ class StandardTest extends TestCase { public function testEmpty() { - $this->assertEquals([], iterator_to_array(new Standard())); + $this->assertSame([], iterator_to_array(new Standard())); $pipeline = new Standard(); - $this->assertEquals([], $pipeline->toArray()); + $this->assertSame([], $pipeline->toArray()); } public function testSingle() @@ -45,7 +45,7 @@ public function testSingle() } }); - $this->assertEquals([1, 2, 3], iterator_to_array($pipeline)); + $this->assertSame([1, 2, 3], iterator_to_array($pipeline)); } public function testDouble() @@ -64,7 +64,7 @@ public function testDouble() yield $i * 1000; }); - $this->assertEquals([10, 100, 1000, 20, 200, 2000, 30, 300, 3000], $pipeline->toArray()); + $this->assertSame([10, 100, 1000, 20, 200, 2000, 30, 300, 3000], $pipeline->toArray()); } public function testTriple() @@ -72,8 +72,8 @@ public function testTriple() $pipeline = new Standard(new \ArrayIterator(range(1, 3))); $pipeline->map(function ($i) { - yield pow($i, 2); - yield pow($i, 3); + yield $i ** 2; + yield $i ** 3; }); $pipeline->map(function ($i) { @@ -91,7 +91,7 @@ public function testTriple() } }); - $this->assertEquals([52, 104], $pipeline->toArray()); + $this->assertSame([52, 104], $pipeline->toArray()); } public function testFilter() @@ -105,7 +105,7 @@ public function testFilter() }); $pipeline->filter(function ($i) { - return $i % 7 == 0; + return 0 === $i % 7; }); $pipeline->map(function ($i) { @@ -114,7 +114,7 @@ public function testFilter() $pipeline->filter(); - $this->assertEquals([6, 13, 20, 27, 34, 41, 48], $pipeline->toArray()); + $this->assertSame([6, 13, 20, 27, 34, 41, 48], $pipeline->toArray()); } public function testReduce() @@ -129,7 +129,7 @@ public function testReduce() $result = $pipeline->reduce(); - $this->assertEquals(55, $result); + $this->assertSame(55, $result); } public function testReduceFloat() @@ -144,7 +144,7 @@ public function testReduceFloat() $result = $pipeline->reduce(); - $this->assertEquals(55 * 1.05, $result); + $this->assertSame(55 * 1.05, $result); } public function testReduceArrays() @@ -159,7 +159,7 @@ public function testReduceArrays() $result = $pipeline->reduce(null, []); - $this->assertEquals([1, 2], $result); + $this->assertSame([1, 2], $result); } public function testReduceToArray() @@ -173,12 +173,12 @@ public function testReduceToArray() }); $pipeline->map(function ($i) { - yield pow($i, 2); - yield pow($i, 3); + yield $i ** 2; + yield $i ** 3; }); $pipeline->filter(function ($i) { - return $i % 3 == 0; + return 0 === $i % 3; }); // just what iterator_to_array does @@ -188,7 +188,7 @@ public function testReduceToArray() return $sum; }, []); - $this->assertEquals([9, 27, 36, 216, 81, 729], $result); + $this->assertSame([9, 27, 36, 216, 81, 729], $result); } public function testMeaningless() @@ -201,7 +201,7 @@ public function testMeaningless() yield $i + 1; }); - $this->assertEquals(0, $pipeline->reduce()); + $this->assertSame(0, $pipeline->reduce()); } public function testPipelineInPipeline() @@ -214,10 +214,10 @@ public function testPipelineInPipeline() $pipeline2 = new Standard(); $pipeline2->map($pipeline1)->filter(function ($i) { - return $i % 2 != 0; + return 0 !== $i % 2; }); - $this->assertEquals(3 + 5 + 7 + 11, $pipeline2->reduce()); + $this->assertSame(3 + 5 + 7 + 11, $pipeline2->reduce()); $foo = new Standard(); $foo->map(function () { @@ -227,7 +227,7 @@ public function testPipelineInPipeline() $bar = new Standard(); $bar->map($foo); - $this->assertEquals(3, $bar->reduce()); + $this->assertSame(3, $bar->reduce()); } public function testFiltersPipeline() @@ -240,10 +240,10 @@ public function testFiltersPipeline() $output = new Standard($input); $output->filter(function ($i) { - return $i % 2 != 0; + return 0 !== $i % 2; }); - $this->assertEquals(3 + 5 + 7 + 11, $output->reduce()); + $this->assertSame(3 + 5 + 7 + 11, $output->reduce()); } private $double; @@ -255,14 +255,14 @@ public function testTestableGenerator() return $value * 2; }; - $this->assertSame(8, call_user_func($this->double, 4)); + $this->assertSame(8, \call_user_func($this->double, 4)); $this->plusone = function ($value) { yield $value; yield $value + 1; }; - $this->assertSame([4, 5], iterator_to_array(call_user_func($this->plusone, 4))); + $this->assertSame([4, 5], iterator_to_array(\call_user_func($this->plusone, 4))); // initial generator $sourceData = new \ArrayIterator(range(1, 5)); @@ -286,8 +286,8 @@ public function testMethodChaining() yield $b; yield $c; })->map(function ($i) { - yield pow($i, 2); - yield pow($i, 3); + yield $i ** 2; + yield $i ** 3; })->map(function ($i) { return $i - 1; })->map(function ($i) { @@ -299,6 +299,6 @@ public function testMethodChaining() return $i; }); - $this->assertEquals([52, 104], iterator_to_array($pipeline)); + $this->assertSame([52, 104], iterator_to_array($pipeline)); } } diff --git a/tests/UnpackTest.php b/tests/UnpackTest.php index 6bfaf07..efd6ec7 100644 --- a/tests/UnpackTest.php +++ b/tests/UnpackTest.php @@ -44,7 +44,7 @@ public function testMapVector() return sqrt($x ** 2 + $y ** 2); }); - $this->assertEquals(37, round($pipeline->reduce())); + $this->assertSame(37.0, round($pipeline->reduce())); } /** @@ -61,7 +61,7 @@ public function testFlatMap() yield [7, 8, 9, 10]; })->unpack(); - $this->assertEquals((10 * 11) / 2, round($pipeline->reduce())); + $this->assertSame((10 * 11) / 2, $pipeline->reduce()); } /**