From 59efb4596a0788ee0337f13bccac19e5637935c6 Mon Sep 17 00:00:00 2001 From: Ilario Pierbattista <987038+ilario-pierbattista@users.noreply.github.com> Date: Sun, 5 Dec 2021 19:30:27 +0100 Subject: [PATCH] Add Psalm (#146) --- .github/workflows/ci.yml | 12 +++++--- .github/workflows/static-analysis.yml | 4 ++- .gitignore | 1 + composer.json | 8 +++-- examples/AlwaysFailsTest.php | 5 ++-- examples/AssociativeArrayTest.php | 9 +++--- examples/BindTest.php | 13 ++++---- examples/BooleanTest.php | 5 ++-- examples/CharacterTest.php | 23 ++++++++------- examples/ChooseTest.php | 7 +++-- examples/CollectTest.php | 19 ++++++------ examples/ConstantTest.php | 8 ++--- examples/DateTest.php | 13 ++++---- examples/DifferentElementsTest.php | 11 +++---- examples/DisableShrinkingTest.php | 5 ++-- examples/ElementsTest.php | 11 +++---- examples/ErrorTest.php | 5 ++-- examples/FloatTest.php | 7 +++-- examples/FrequencyTest.php | 13 ++++---- examples/GeneratorSamplesTest.php | 7 +++-- examples/IntegerTest.php | 15 +++++----- examples/LimitToTest.php | 9 +++--- examples/LogFileTest.php | 13 ++++---- examples/MapTest.php | 19 ++++++------ examples/MinimumEvaluationsTest.php | 9 +++--- examples/NamesTest.php | 4 ++- examples/OneOfTest.php | 9 +++--- examples/RandConfigurationTest.php | 13 ++++---- examples/ReadmeTest.php | 5 ++-- examples/RegexTest.php | 7 +++-- examples/SequenceTest.php | 9 +++--- examples/SetTest.php | 5 ++-- examples/ShrinkingTest.php | 7 +++-- examples/ShrinkingTimeLimitTest.php | 6 ++-- examples/SizeTest.php | 5 ++-- examples/SortTest.php | 5 ++-- examples/StringTest.php | 13 ++++---- examples/SubsetTest.php | 5 ++-- examples/SuchThatTest.php | 41 +++++++++++++------------- examples/SumTest.php | 15 +++++----- examples/TupleTest.php | 9 +++--- examples/VectorTest.php | 7 +++-- examples/WhenTest.php | 23 ++++++++------- examples/generating_integers.php | 5 ++-- psalm-baseline.xml | 28 ++++++++++++++++++ psalm.xml | 19 ++++++++++++ src/Antecedent/PrintableCharacter.php | 11 +++++-- src/Antecedents.php | 18 +++++++++++ src/Generator/GeneratedValueSingle.php | 14 +++++++-- src/Listener/CollectFrequencies.php | 8 +++-- src/Listener/Log.php | 7 +++-- src/Listeners.php | 19 ++++++++++++ src/Shrinker.php | 2 +- test/Generator/SubsetGeneratorTest.php | 15 +++++----- test/SampleTest.php | 4 +-- 55 files changed, 373 insertions(+), 216 deletions(-) create mode 100644 psalm-baseline.xml create mode 100644 psalm.xml create mode 100644 src/Antecedents.php create mode 100644 src/Listeners.php diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fb125c65..31c2bd54 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,9 +19,11 @@ jobs: uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} - - name: Remove phpstan from dev dependecies for older php versions + - name: Remove dev dependecies for older php versions if: ${{ matrix.php < 7.1 }} - run: composer remove --dev phpstan/phpstan --ignore-platform-reqs --no-update + run: | + composer remove --dev phpstan/phpstan --ignore-platform-reqs --no-update + composer remove --dev psalm/phar --ignore-platform-reqs --no-update - name: Install dependencies uses: ramsey/composer-install@v1 with: @@ -48,9 +50,11 @@ jobs: uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} - - name: Remove phpstan from dev dependecies for older php versions + - name: Remove dev dependecies for older php versions if: ${{ matrix.php < 7.1 }} - run: composer remove --dev phpstan/phpstan --ignore-platform-reqs --no-update + run: | + composer remove --dev phpstan/phpstan --ignore-platform-reqs --no-update + composer remove --dev psalm/phar --ignore-platform-reqs --no-update - name: Install dependencies uses: ramsey/composer-install@v1 - name: Download phpunit phar diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 4ac9fccd..2959357d 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -12,7 +12,9 @@ jobs: - description: Code style script: vendor/bin/php-cs-fixer fix --verbose --diff --dry-run - description: PHPStan - script: vendor/bin/phpstan analyse -c phpstan.neon + script: vendor/bin/phpstan + - description: Psalm + script: vendor/bin/psalm.phar name: ${{ matrix.description }} runs-on: ubuntu-latest steps: diff --git a/.gitignore b/.gitignore index 5e528b6f..423a8762 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ composer.lock docs/_build .phpunit.result.cache docker-compose.override.yml +.psalm-cache/ diff --git a/composer.json b/composer.json index c6961d0a..ceaf6132 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,8 @@ "sebastian/comparator": ">=1.2.4", "friendsofphp/php-cs-fixer": "^2.0", "icomefromthenet/reverse-regex": "v0.0.6.3", - "phpstan/phpstan": "^1.2" + "phpstan/phpstan": "^1.2", + "psalm/phar": "^4.13" }, "suggest": { @@ -55,8 +56,9 @@ "composer update", "vendor/bin/phpunit test" ], - "phpstan": [ - "vendor/bin/phpstan analyse -c phpstan.neon" + "static": [ + "vendor/bin/phpstan", + "vendor/bin/psalm.phar" ], "phpstan-baseline": [ "vendor/bin/phpstan analyse -c phpstan.neon --generate-baseline" diff --git a/examples/AlwaysFailsTest.php b/examples/AlwaysFailsTest.php index c1f6aedd..a178bf5b 100644 --- a/examples/AlwaysFailsTest.php +++ b/examples/AlwaysFailsTest.php @@ -1,5 +1,6 @@ forAll( - Generator\elements(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']) + Generators::elements(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']) ) ->then(function ($someChar) { $this->fail("This test fails by design. '$someChar' was passed in"); diff --git a/examples/AssociativeArrayTest.php b/examples/AssociativeArrayTest.php index 9d43425b..db04d338 100644 --- a/examples/AssociativeArrayTest.php +++ b/examples/AssociativeArrayTest.php @@ -1,5 +1,6 @@ forAll( - Generator\associative([ - 'letter' => Generator\elements("A", "B", "C"), - 'cipher' => Generator\choose(0, 9), + Generators::associative([ + 'letter' => Generators::elements("A", "B", "C"), + 'cipher' => Generators::choose(0, 9), ]) ) ->then(function ($array) { diff --git a/examples/BindTest.php b/examples/BindTest.php index 909c12ec..c690cb07 100644 --- a/examples/BindTest.php +++ b/examples/BindTest.php @@ -1,5 +1,6 @@ forAll( - Generator\bind( - Generator\vector(4, Generator\nat()), + Generators::bind( + Generators::vector(4, Generators::nat()), function ($vector) { - return Generator\tuple( - Generator\elements($vector), - Generator\constant($vector) + return Generators::tuple( + Generators::elements($vector), + Generators::constant($vector) ); } ) diff --git a/examples/BooleanTest.php b/examples/BooleanTest.php index 989fb8ae..b13e288c 100644 --- a/examples/BooleanTest.php +++ b/examples/BooleanTest.php @@ -1,5 +1,6 @@ forAll( - Generator\bool() + Generators::bool() ) ->then(function ($boolValue) { $this->assertTrue( diff --git a/examples/CharacterTest.php b/examples/CharacterTest.php index 1390f5b4..0890aabf 100644 --- a/examples/CharacterTest.php +++ b/examples/CharacterTest.php @@ -1,6 +1,7 @@ forAll( - Generator\char(['basic-latin']) + Generators::char(['basic-latin']) ) ->then(function ($char) { $this->assertLenghtIs1($char); @@ -19,9 +20,9 @@ public function testLengthOfAsciiCharactersInPhp() public function testLengthOfPrintableAsciiCharacters() { $this->forAll( - Generator\char(['basic-latin']) + Generators::char(['basic-latin']) ) - ->when(Antecedent\printableCharacter()) + ->when(Antecedents::printableCharacter()) ->then(function ($char) { $this->assertFalse(ord($char) < 32); }); @@ -32,10 +33,10 @@ public function testMultiplePrintableCharacters() $this ->minimumEvaluationRatio(0.1) ->forAll( - Generator\char(['basic-latin']), - Generator\char(['basic-latin']) + Generators::char(['basic-latin']), + Generators::char(['basic-latin']) ) - ->when(Antecedent\printableCharacters()) + ->when(Antecedents::printableCharacters()) ->then(function ($first, $second) { $this->assertFalse(ord($first) < 32); $this->assertFalse(ord($second) < 32); @@ -49,10 +50,10 @@ public function testMultiplePrintableCharactersFromAnnotation() { $this ->forAll( - Generator\char(['basic-latin']), - Generator\char(['basic-latin']) + Generators::char(['basic-latin']), + Generators::char(['basic-latin']) ) - ->when(Antecedent\printableCharacters()) + ->when(Antecedents::printableCharacters()) ->then(function ($first, $second) { $this->assertFalse(ord($first) < 32); $this->assertFalse(ord($second) < 32); diff --git a/examples/ChooseTest.php b/examples/ChooseTest.php index 20283736..734e15be 100644 --- a/examples/ChooseTest.php +++ b/examples/ChooseTest.php @@ -1,5 +1,6 @@ forAll( - Generator\choose(-1000, 430), - Generator\choose(230, -30000) + Generators::choose(-1000, 430), + Generators::choose(230, -30000) ) ->then(function ($first, $second) { $x = $first + $second; diff --git a/examples/CollectTest.php b/examples/CollectTest.php index 764152b3..aabce91e 100644 --- a/examples/CollectTest.php +++ b/examples/CollectTest.php @@ -1,7 +1,8 @@ forAll(Generator\neg()) - ->hook(Listener\collectFrequencies()) + ->forAll(Generators::neg()) + ->hook(Listeners::collectFrequencies()) ->then(function ($x) { $this->assertTrue($x < $x + 1); }); @@ -21,10 +22,10 @@ public function testGeneratedDataCollectionOnMoreComplexDataStructures() { $this ->forAll( - Generator\vector(2, Generator\int()), - Generator\char() + Generators::vector(2, Generators::int()), + Generators::char() ) - ->hook(Listener\collectFrequencies()) + ->hook(Listeners::collectFrequencies()) ->then(function ($vector) { $this->assertEquals(2, count($vector)); }); @@ -34,10 +35,10 @@ public function testGeneratedDataCollectionWithCustomMapper() { $this ->forAll( - Generator\seq(Generator\nat()) + Generators::seq(Generators::nat()) ) ->withMaxSize(10) - ->hook(Listener\collectFrequencies(function ($array) { + ->hook(Listeners::collectFrequencies(function ($array) { return count($array); })) ->then(function ($array) { diff --git a/examples/ConstantTest.php b/examples/ConstantTest.php index 06aee749..855c6695 100644 --- a/examples/ConstantTest.php +++ b/examples/ConstantTest.php @@ -1,6 +1,6 @@ forAll( - Generator\nat(), - Generator\constant(2) + Generators::nat(), + Generators::constant(2) ) ->then(function ($number, $alwaysTwo) { $this->assertTrue(($number * $alwaysTwo % 2) === 0); @@ -22,7 +22,7 @@ public function testUseConstantGeneratorImplicitly() { $this ->forAll( - Generator\nat(), + Generators::nat(), 2 ) ->then(function ($number, $alwaysTwo) { diff --git a/examples/DateTest.php b/examples/DateTest.php index 1b663356..66f9d627 100644 --- a/examples/DateTest.php +++ b/examples/DateTest.php @@ -1,5 +1,6 @@ forAll( - Generator\date("2014-01-01T00:00:00", "2014-12-31T23:59:59") + Generators::date("2014-01-01T00:00:00", "2014-12-31T23:59:59") ) ->then(function (DateTime $date) { $this->assertEquals( @@ -21,7 +22,7 @@ public function testYearOfADate() public function testDefaultValuesForTheInterval() { $this->forAll( - Generator\date() + Generators::date() ) ->then(function (DateTime $date) { $this->assertGreaterThanOrEqual( @@ -38,9 +39,9 @@ public function testDefaultValuesForTheInterval() public function testFromDayOfYearFactoryMethodRespectsDistanceBetweenDays() { $this->forAll( - Generator\choose(2000, 2020), - Generator\choose(0, 364), - Generator\choose(0, 364) + Generators::choose(2000, 2020), + Generators::choose(0, 364), + Generators::choose(0, 364) ) ->then(function ($year, $dayOfYear, $anotherDayOfYear) { $day = fromZeroBasedDayOfYear($year, $dayOfYear); diff --git a/examples/DifferentElementsTest.php b/examples/DifferentElementsTest.php index 01d3bf06..2174e1f1 100644 --- a/examples/DifferentElementsTest.php +++ b/examples/DifferentElementsTest.php @@ -1,5 +1,6 @@ forAll(Generator\bind( + ->forAll(Generators::bind( call_user_func_array('Eris\Generator\elements', $allTypes), function ($first) use ($allTypes, $remove) { - return Generator\tuple( - Generator\constant($first), - Generator\elements($remove($allTypes, $first)) + return Generators::tuple( + Generators::constant($first), + Generators::elements($remove($allTypes, $first)) ); } )) diff --git a/examples/DisableShrinkingTest.php b/examples/DisableShrinkingTest.php index c82cf0e1..aa69ec35 100644 --- a/examples/DisableShrinkingTest.php +++ b/examples/DisableShrinkingTest.php @@ -1,5 +1,6 @@ calls = 0; $this ->forAll( - Generator\nat() + Generators::nat() ) ->disableShrinking() ->then(function ($number) { diff --git a/examples/ElementsTest.php b/examples/ElementsTest.php index f5560db3..5b28402b 100644 --- a/examples/ElementsTest.php +++ b/examples/ElementsTest.php @@ -1,5 +1,6 @@ forAll( - Generator\elements(1, 2, 3) + Generators::elements(1, 2, 3) ) ->then(function ($number) { $this->assertContains( @@ -26,7 +27,7 @@ public function testElementsOnlyProducesElementsFromTheGivenArguments() public function testElementsOnlyProducesElementsFromTheGivenArrayDomain() { $this->forAll( - Generator\elements([1, 2, 3]) + Generators::elements([1, 2, 3]) ) ->then(function ($number) { $this->assertContains( @@ -40,9 +41,9 @@ public function testElementsOnlyProducesElementsFromTheGivenArrayDomain() public function testVectorOfElementsGenerators() { $this->forAll( - Generator\vector( + Generators::vector( 4, - Generator\elements([2, 4, 6, 8, 10, 12]) + Generators::elements([2, 4, 6, 8, 10, 12]) ) ) ->then(function ($vector) { diff --git a/examples/ErrorTest.php b/examples/ErrorTest.php index 10fc35ab..be00b1e6 100644 --- a/examples/ErrorTest.php +++ b/examples/ErrorTest.php @@ -1,5 +1,6 @@ forAll( - Generator\string() + Generators::string() ) ->then(function ($string) { throw new RuntimeException("Something like a missing array index happened."); diff --git a/examples/FloatTest.php b/examples/FloatTest.php index 62dbedf8..92d54280 100644 --- a/examples/FloatTest.php +++ b/examples/FloatTest.php @@ -1,5 +1,6 @@ forAll(Generator\float()) + $this->forAll(Generators::float()) ->then(function ($number) { $this->assertEquals( 0.0, @@ -18,7 +19,7 @@ public function testAPropertyHoldingForAllNumbers() public function testAPropertyHoldingOnlyForPositiveNumbers() { - $this->forAll(Generator\float()) + $this->forAll(Generators::float()) ->then(function ($number) { $this->assertTrue( $number >= 0, diff --git a/examples/FrequencyTest.php b/examples/FrequencyTest.php index e2988852..a895d463 100644 --- a/examples/FrequencyTest.php +++ b/examples/FrequencyTest.php @@ -1,5 +1,6 @@ forAll( - Generator\frequency( + Generators::frequency( [8, false], [4, 0], [4, ''] @@ -24,10 +25,10 @@ public function testAlwaysFails() { $this ->forAll( - Generator\frequency( - [8, Generator\choose(1, 100)], - [4, Generator\choose(100, 200)], - [4, Generator\choose(200, 300)] + Generators::frequency( + [8, Generators::choose(1, 100)], + [4, Generators::choose(100, 200)], + [4, Generators::choose(200, 300)] ) ) ->then(function ($element) { diff --git a/examples/GeneratorSamplesTest.php b/examples/GeneratorSamplesTest.php index e8ae5303..0fc97af0 100644 --- a/examples/GeneratorSamplesTest.php +++ b/examples/GeneratorSamplesTest.php @@ -1,5 +1,6 @@ Generator\int(), - "Gen\\neg" => Generator\neg(), + "Gen\\neg" => Generators::neg(), //"Gen\\nat" => Generator\nat(), - "Gen\\pos" => Generator\pos(), + "Gen\\pos" => Generators::pos(), /* "Gen\\float" => Generator\float(), "Gen\\choose(30, 9000) - no size used" => Generator\choose(30, 9000), diff --git a/examples/IntegerTest.php b/examples/IntegerTest.php index 4aef46be..f2184704 100644 --- a/examples/IntegerTest.php +++ b/examples/IntegerTest.php @@ -1,5 +1,6 @@ forAll( - Generator\int(), - Generator\int() + Generators::int(), + Generators::int() ) ->then(function ($first, $second) { $x = $first + $second; @@ -26,9 +27,9 @@ public function testSumIsCommutative() public function testSumIsAssociative() { $this->forAll( - Generator\int(), - Generator\neg(), - Generator\pos() + Generators::int(), + Generators::neg(), + Generators::pos() ) ->then(function ($first, $second, $third) { $x = $first + ($second + $third); @@ -44,7 +45,7 @@ public function testSumIsAssociative() public function testByteData() { $this->forAll( - Generator\byte() + Generators::byte() ) ->then(function ($byte) { $this->assertTrue( diff --git a/examples/LimitToTest.php b/examples/LimitToTest.php index 9c0ed7e3..cfa3a27f 100644 --- a/examples/LimitToTest.php +++ b/examples/LimitToTest.php @@ -1,5 +1,6 @@ forAll( - Generator\int() + Generators::int() ) ->then(function ($value) { $this->assertInternalType('integer', $value); @@ -41,7 +42,7 @@ public function testTimeIntervalToRunForCanBeConfiguredAndAVeryLowNumberOfIterat ->minimumEvaluationRatio(0) ->limitTo(new DateInterval('PT2S')) ->forAll( - Generator\int() + Generators::int() ) ->then(function ($value) { usleep(100 * 1000); @@ -56,7 +57,7 @@ public function testTimeIntervalToRunForCanBeConfiguredAndAVeryLowNumberOfIterat public function testTimeIntervalToRunForCanBeConfiguredAndAVeryLowNumberOfIterationsCanBeIgnoredFromAnnotation() { $this->forAll( - Generator\int() + Generators::int() ) ->then(function ($value) { usleep(100 * 1000); diff --git a/examples/LogFileTest.php b/examples/LogFileTest.php index fcca1490..98d79303 100644 --- a/examples/LogFileTest.php +++ b/examples/LogFileTest.php @@ -1,7 +1,8 @@ forAll( - Generator\int() + Generators::int() ) - ->hook(Listener\log(sys_get_temp_dir().'/eris-log-file-test.log')) + ->hook(Listeners::log(sys_get_temp_dir().'/eris-log-file-test.log')) ->then(function ($number) { $this->assertInternalType('integer', $number); }); @@ -23,9 +24,9 @@ public function testLogOfFailuresAndShrinking() { $this ->forAll( - Generator\int() + Generators::int() ) - ->hook(Listener\log(sys_get_temp_dir().'/eris-log-file-shrinking.log')) + ->hook(Listeners::log(sys_get_temp_dir().'/eris-log-file-shrinking.log')) ->then(function ($number) { $this->assertLessThanOrEqual(42, $number); }); diff --git a/examples/MapTest.php b/examples/MapTest.php index e99a5168..eab1f1a5 100644 --- a/examples/MapTest.php +++ b/examples/MapTest.php @@ -1,5 +1,6 @@ forAll( - Generator\vector( + Generators::vector( 3, - Generator\map( + Generators::map( function ($n) { return $n * 2; }, - Generator\nat() + Generators::nat() ) ) ) @@ -31,11 +32,11 @@ function ($n) { public function testShrinkingJustMappedValues() { $this->forAll( - Generator\map( + Generators::map( function ($n) { return $n * 2; }, - Generator\nat() + Generators::nat() ) ) ->then(function ($evenNumber) { @@ -50,13 +51,13 @@ function ($n) { public function testShrinkingMappedValuesInsideOtherGenerators() { $this->forAll( - Generator\vector( + Generators::vector( 3, - Generator\map( + Generators::map( function ($n) { return $n * 2; }, - Generator\nat() + Generators::nat() ) ) ) diff --git a/examples/MinimumEvaluationsTest.php b/examples/MinimumEvaluationsTest.php index c3e09b87..69aca00f 100644 --- a/examples/MinimumEvaluationsTest.php +++ b/examples/MinimumEvaluationsTest.php @@ -1,5 +1,6 @@ forAll( - Generator\choose(0, 100) + Generators::choose(0, 100) ) ->when(function ($n) { return $n > 90; @@ -24,7 +25,7 @@ public function testPassesBecauseOfTheArtificiallyLowMinimumEvaluationRatio() $this ->minimumEvaluationRatio(0.01) ->forAll( - Generator\choose(0, 100) + Generators::choose(0, 100) ) ->when(function ($n) { return $n > 90; @@ -41,7 +42,7 @@ public function testPassesBecauseOfTheArtificiallyLowMinimumEvaluationRatioFromA { $this ->forAll( - Generator\choose(0, 100) + Generators::choose(0, 100) ) ->when(function ($n) { return $n > 90; diff --git a/examples/NamesTest.php b/examples/NamesTest.php index c47aa19f..70614c50 100644 --- a/examples/NamesTest.php +++ b/examples/NamesTest.php @@ -1,5 +1,7 @@ forAll( - Generator\names() + Generators::names() )->then(function ($name) { $this->assertInternalType('string', $name); var_dump($name); diff --git a/examples/OneOfTest.php b/examples/OneOfTest.php index 25e80e11..c1729ac6 100644 --- a/examples/OneOfTest.php +++ b/examples/OneOfTest.php @@ -1,5 +1,6 @@ forAll( - Generator\oneOf( - Generator\pos(), - Generator\neg() + Generators::oneOf( + Generators::pos(), + Generators::neg() ) ) ->then(function ($number) { diff --git a/examples/RandConfigurationTest.php b/examples/RandConfigurationTest.php index 9fefd8e1..e74c5bdc 100644 --- a/examples/RandConfigurationTest.php +++ b/examples/RandConfigurationTest.php @@ -1,5 +1,6 @@ withRand('rand') ->forAll( - Generator\int() + Generators::int() ) ->withMaxSize(1000 * 1000* 1000) ->then($this->isInteger()); @@ -25,7 +26,7 @@ public function testUsingTheDefaultRandFunctionFromAnnotation() { $this ->forAll( - Generator\int() + Generators::int() ) ->withMaxSize(1000 * 1000* 1000) ->then($this->isInteger()); @@ -36,7 +37,7 @@ public function testUsingTheDefaultMtRandFunction() $this ->withRand('mt_rand') ->forAll( - Generator\int() + Generators::int() ) ->then($this->isInteger()); } @@ -49,7 +50,7 @@ public function testUsingTheDefaultMtRandFunctionFromAnnotation() { $this ->forAll( - Generator\int() + Generators::int() ) ->then($this->isInteger()); } @@ -63,7 +64,7 @@ public function testUsingThePurePhpMtRandFunction() $this ->withRand(Random\purePhpMtRand()) ->forAll( - Generator\int() + Generators::int() ) ->then($this->isInteger()); } diff --git a/examples/ReadmeTest.php b/examples/ReadmeTest.php index 972bdad9..53b3e70b 100644 --- a/examples/ReadmeTest.php +++ b/examples/ReadmeTest.php @@ -1,5 +1,6 @@ forAll( - Generator\choose(0, 1000) + Generators::choose(0, 1000) ) ->then(function ($number) { $this->assertTrue( diff --git a/examples/RegexTest.php b/examples/RegexTest.php index 66489b71..82c45d54 100644 --- a/examples/RegexTest.php +++ b/examples/RegexTest.php @@ -1,17 +1,18 @@ forAll( - Generator\regex("[a-z]{10}") + Generators::regex("[a-z]{10}") ) ->then(function ($string) { $this->assertEquals(10, strlen($string)); diff --git a/examples/SequenceTest.php b/examples/SequenceTest.php index ae4f72fa..ce84258c 100644 --- a/examples/SequenceTest.php +++ b/examples/SequenceTest.php @@ -1,5 +1,6 @@ forAll( - Generator\seq(Generator\nat()) + Generators::seq(Generators::nat()) ) ->then(function ($array) { $this->assertEquals(count($array), count(array_reverse($array))); @@ -20,7 +21,7 @@ public function testArrayReverse() { $this ->forAll( - Generator\seq(Generator\nat()) + Generators::seq(Generators::nat()) ) ->then(function ($array) { $this->assertEquals($array, array_reverse(array_reverse($array))); @@ -31,7 +32,7 @@ public function testArraySortingIsIdempotent() { $this ->forAll( - Generator\seq(Generator\nat()) + Generators::seq(Generators::nat()) ) ->then(function ($array) { sort($array); diff --git a/examples/SetTest.php b/examples/SetTest.php index 2b37a65b..fa2d0222 100644 --- a/examples/SetTest.php +++ b/examples/SetTest.php @@ -1,5 +1,6 @@ forAll( - Generator\set(Generator\nat()) + Generators::set(Generators::nat()) ) ->then(function ($set) { $this->assertInternalType('array', $set); diff --git a/examples/ShrinkingTest.php b/examples/ShrinkingTest.php index 5feaffcf..1f6e36e8 100644 --- a/examples/ShrinkingTest.php +++ b/examples/ShrinkingTest.php @@ -1,5 +1,6 @@ forAll( - Generator\string() + Generators::string() ) ->then(function ($string) { var_dump($string); @@ -20,7 +21,7 @@ public function testShrinkingAString() public function testShrinkingRespectsAntecedents() { $this->forAll( - Generator\choose(0, 20) + Generators::choose(0, 20) ) ->when(function ($number) { return $number > 10; diff --git a/examples/ShrinkingTimeLimitTest.php b/examples/ShrinkingTimeLimitTest.php index a435d7c4..2c9a47ba 100644 --- a/examples/ShrinkingTimeLimitTest.php +++ b/examples/ShrinkingTimeLimitTest.php @@ -1,5 +1,7 @@ shrinkingTimeLimit(2) ->forAll( - Generator\string(), - Generator\string() + Generators::string(), + Generators::string() ) ->then(function ($first, $second) { $result = very_slow_concatenation($first, $second); diff --git a/examples/SizeTest.php b/examples/SizeTest.php index bf7ff977..9a79c721 100644 --- a/examples/SizeTest.php +++ b/examples/SizeTest.php @@ -1,5 +1,6 @@ forAll( - Generator\int() + Generators::int() ) ->withMaxSize(1000 * 1000) ->then(function ($number) { diff --git a/examples/SortTest.php b/examples/SortTest.php index f8d3136e..f3bd2d62 100644 --- a/examples/SortTest.php +++ b/examples/SortTest.php @@ -1,5 +1,6 @@ forAll( - Generator\seq(Generator\nat()) + Generators::seq(Generators::nat()) ) ->then(function ($array) { sort($array); diff --git a/examples/StringTest.php b/examples/StringTest.php index c2fafc43..27cab426 100644 --- a/examples/StringTest.php +++ b/examples/StringTest.php @@ -1,6 +1,7 @@ forAll( - Generator\string() + Generators::string() ) ->then(function ($string) { $this->assertEquals( @@ -33,10 +34,10 @@ public function testLengthPreservation() { $this ->forAll( - Generator\string(), - Generator\string() + Generators::string(), + Generators::string() ) - ->hook(Listener\log(sys_get_temp_dir().'/eris-string-shrinking.log')) + ->hook(Listeners::log(sys_get_temp_dir().'/eris-string-shrinking.log')) ->then(function ($first, $second) { $result = string_concatenation($first, $second); $this->assertEquals( diff --git a/examples/SubsetTest.php b/examples/SubsetTest.php index 19f9a758..4111747b 100644 --- a/examples/SubsetTest.php +++ b/examples/SubsetTest.php @@ -1,5 +1,6 @@ forAll( - Generator\subset([ + Generators::subset([ 2, 4, 6, 8, 10 ]) ) diff --git a/examples/SuchThatTest.php b/examples/SuchThatTest.php index 0523626c..9817a1cd 100644 --- a/examples/SuchThatTest.php +++ b/examples/SuchThatTest.php @@ -1,6 +1,7 @@ forAll( - Generator\vector( + Generators::vector( 5, - Generator\suchThat( + Generators::suchThat( function ($n) { return $n > 42; }, - Generator\choose(0, 1000) + Generators::choose(0, 1000) ) ) ) @@ -27,13 +28,13 @@ public function testFilterSyntax() { $this ->forAll( - Generator\vector( + Generators::vector( 5, - Generator\filter( + Generators::filter( function ($n) { return $n > 42; }, - Generator\choose(0, 1000) + Generators::choose(0, 1000) ) ) ) @@ -44,18 +45,18 @@ public function testSuchThatAcceptsPHPUnitConstraints() { $this ->forAll( - Generator\vector( + Generators::vector( 5, - Generator\suchThat( + Generators::suchThat( $this->isType('integer'), - Generator\oneOf( - Generator\choose(0, 1000), - Generator\string() + Generators::oneOf( + Generators::choose(0, 1000), + Generators::string() ) ) ) ) - ->hook(Listener\log(sys_get_temp_dir().'/eris-such-that.log')) + ->hook(Listeners::log(sys_get_temp_dir().'/eris-such-that.log')) ->then($this->allNumbersAreBiggerThan(42)); } @@ -64,11 +65,11 @@ public function testSuchThatShrinkingRespectsTheCondition() { $this ->forAll( - Generator\suchThat( + Generators::suchThat( function ($n) { return $n > 42; }, - Generator\choose(0, 1000) + Generators::choose(0, 1000) ) ) ->then($this->numberIsBiggerThan(100)); @@ -78,11 +79,11 @@ public function testSuchThatShrinkingRespectsTheConditionButTriesToSkipOverTheNo { $this ->forAll( - Generator\suchThat( + Generators::suchThat( function ($n) { return $n <> 42; }, - Generator\choose(0, 1000) + Generators::choose(0, 1000) ) ) ->then($this->numberIsBiggerThan(100)); @@ -92,11 +93,11 @@ public function testSuchThatAvoidingTheEmptyListDoesNotGetStuckOnASmallGenerator { $this ->forAll( - Generator\suchThat( + Generators::suchThat( function (array $ints) { return count($ints) > 0; }, - Generator\seq(Generator\int()) + Generators::seq(Generators::int()) ) ) ->then(function (array $ints) use (&$i) { diff --git a/examples/SumTest.php b/examples/SumTest.php index 6b5afb2c..d321490a 100644 --- a/examples/SumTest.php +++ b/examples/SumTest.php @@ -1,5 +1,6 @@ forAll( - Generator\nat(1000) + Generators::nat(1000) ) ->then(function ($number) { $this->assertEquals( @@ -30,7 +31,7 @@ public function testRightIdentityElement() public function testLeftIdentityElement() { $this->forAll( - Generator\nat(1000) + Generators::nat(1000) ) ->then(function ($number) { $this->assertEquals( @@ -44,8 +45,8 @@ public function testLeftIdentityElement() public function testEqualToReferencePhpImplementation() { $this->forAll( - Generator\nat(1000), - Generator\nat(1000) + Generators::nat(1000), + Generators::nat(1000) ) ->then(function ($first, $second) { $this->assertEquals( @@ -59,8 +60,8 @@ public function testEqualToReferencePhpImplementation() public function testPropertyNeverSatisfied() { $this->forAll( - Generator\nat(1000), - Generator\nat(1000) + Generators::nat(1000), + Generators::nat(1000) ) ->then(function ($first, $second) { $this->assertEquals( diff --git a/examples/TupleTest.php b/examples/TupleTest.php index 8c6a00a2..3822ddc7 100644 --- a/examples/TupleTest.php +++ b/examples/TupleTest.php @@ -1,5 +1,6 @@ forAll( - Generator\tuple( - Generator\elements("A", "B", "C"), - Generator\choose(0, 9) + Generators::tuple( + Generators::elements("A", "B", "C"), + Generators::choose(0, 9) ) ) ->then(function ($tuple) { diff --git a/examples/VectorTest.php b/examples/VectorTest.php index 7300b634..61dcd472 100644 --- a/examples/VectorTest.php +++ b/examples/VectorTest.php @@ -1,5 +1,6 @@ forAll( - Generator\vector(10, Generator\nat(1000)), - Generator\vector(10, Generator\nat(1000)) + Generators::vector(10, Generators::nat(1000)), + Generators::vector(10, Generators::nat(1000)) ) ->then(function ($first, $second) { $concatenated = array_merge($first, $second); diff --git a/examples/WhenTest.php b/examples/WhenTest.php index ee94d1b5..8ae68bc1 100644 --- a/examples/WhenTest.php +++ b/examples/WhenTest.php @@ -1,5 +1,6 @@ forAll( - Generator\choose(0, 1000) + Generators::choose(0, 1000) ) ->when(function ($n) { return $n > 42; @@ -24,8 +25,8 @@ public function testWhenWithAnAnonymousFunctionWithGherkinSyntax() public function testWhenWithAnAnonymousFunctionForMultipleArguments() { $this->forAll( - Generator\choose(0, 1000), - Generator\choose(0, 1000) + Generators::choose(0, 1000), + Generators::choose(0, 1000) ) ->when(function ($first, $second) { return $first > 42 && $second > 23; @@ -41,7 +42,7 @@ public function testWhenWithAnAnonymousFunctionForMultipleArguments() public function testWhenWithOnePHPUnitConstraint() { $this->forAll( - Generator\choose(0, 1000) + Generators::choose(0, 1000) ) ->when($this->greaterThan(42)) ->then(function ($number) { @@ -55,8 +56,8 @@ public function testWhenWithOnePHPUnitConstraint() public function testWhenWithMultiplePHPUnitConstraints() { $this->forAll( - Generator\choose(0, 1000), - Generator\choose(0, 1000) + Generators::choose(0, 1000), + Generators::choose(0, 1000) ) ->when($this->greaterThan(42), $this->greaterThan(23)) ->then(function ($first, $second) { @@ -70,7 +71,7 @@ public function testWhenWithMultiplePHPUnitConstraints() public function testMultipleWhenClausesWithGherkinSyntax() { $this->forAll( - Generator\choose(0, 1000) + Generators::choose(0, 1000) ) ->when($this->greaterThan(42)) ->and($this->lessThan(900)) @@ -85,7 +86,7 @@ public function testMultipleWhenClausesWithGherkinSyntax() public function testWhenWhichSkipsTooManyValues() { $this->forAll( - Generator\choose(0, 1000) + Generators::choose(0, 1000) ) ->when($this->greaterThan(800)) ->then(function ($number) { @@ -103,7 +104,7 @@ public function testWhenWhichSkipsTooManyValues() public function testWhenFailingWillNaturallyHaveALowEvaluationRatioSoWeDontWantThatErrorToObscureTheTrueOne() { $this->forAll( - Generator\choose(0, 1000) + Generators::choose(0, 1000) ) ->when($this->greaterThan(100)) ->then(function ($number) { @@ -117,7 +118,7 @@ public function testWhenFailingWillNaturallyHaveALowEvaluationRatioSoWeDontWantT public function testSizeIncreasesEvenIfEvaluationsAreSkippedDueToAntecedentsNotBeingSatisfied() { $this->forAll( - Generator\seq(Generator\elements(1, 2, 3)) + Generators::seq(Generators::elements(1, 2, 3)) ) ->when(function ($seq) { return count($seq) > 0; diff --git a/examples/generating_integers.php b/examples/generating_integers.php index b155840e..4b425860 100644 --- a/examples/generating_integers.php +++ b/examples/generating_integers.php @@ -1,11 +1,12 @@ forAll(Generator\int()) + ->forAll(Generators::int()) ->then(function ($integer) { echo var_export($integer, true) . PHP_EOL; }); diff --git a/psalm-baseline.xml b/psalm-baseline.xml new file mode 100644 index 00000000..ae34e755 --- /dev/null +++ b/psalm-baseline.xml @@ -0,0 +1,28 @@ + + + + + PHPUnit_Framework_ExpectationFailedException + + + + + PHPUnit_Framework_Constraint + + + callable|PHPUnit_Framework_Constraint|Constraint + callable|PHPUnit_Framework_Constraint|Constraint + + + + + callable|PHPUnit_Framework_Constraint|Constraint + callable|PHPUnit_Framework_Constraint|Constraint + + + + + PHPUnit_Framework_Constraint + + + diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 00000000..21a07cc8 --- /dev/null +++ b/psalm.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + diff --git a/src/Antecedent/PrintableCharacter.php b/src/Antecedent/PrintableCharacter.php index 1e3a12f0..860ad9e0 100644 --- a/src/Antecedent/PrintableCharacter.php +++ b/src/Antecedent/PrintableCharacter.php @@ -2,15 +2,22 @@ namespace Eris\Antecedent; use Eris\Antecedent; +use Eris\Antecedents; +/** + * @see Antecedents::printableCharacter() + */ function printableCharacter() { - return new PrintableCharacter(); + return Antecedents::printableCharacter(); } +/** + * @see Antecedents::printableCharacters() + */ function printableCharacters() { - return new PrintableCharacter(); + return Antecedents::printableCharacters(); } class PrintableCharacter implements Antecedent diff --git a/src/Antecedents.php b/src/Antecedents.php new file mode 100644 index 00000000..c1db9666 --- /dev/null +++ b/src/Antecedents.php @@ -0,0 +1,18 @@ + of its value. * Immutable object, modifiers return a new GeneratedValueSingle instance. + * + * @template T */ final class GeneratedValueSingle implements GeneratedValue // TODO? interface ShrunkValue extends IteratorAggregate[, Countable] { + /** @var T */ private $value; private $input; private $generatorName; @@ -22,7 +25,9 @@ final class GeneratedValueSingle implements GeneratedValue // TODO? interface Sh * A value and the input that was used to derive it. * The input usually comes from another Generator. * - * @param T $value + * @template T + * @psalm-param T $value + * @param mixed $value * @param GeneratedValueSingle|mixed $input * @param string $generatorName 'tuple' * @return GeneratedValueSingle @@ -35,7 +40,9 @@ public static function fromValueAndInput($value, $input, $generatorName = null) /** * Input will be copied from value. * - * @param T $value + * @template T + * @psalm-param T $value + * @param mixed $value * @param string $generatorName 'tuple' * @return GeneratedValueSingle */ @@ -64,7 +71,8 @@ public function input() } /** - * @return T + * @psalm-return T + * @return mixed */ public function unbox() { diff --git a/src/Listener/CollectFrequencies.php b/src/Listener/CollectFrequencies.php index b76f177f..25b63e8b 100644 --- a/src/Listener/CollectFrequencies.php +++ b/src/Listener/CollectFrequencies.php @@ -2,12 +2,16 @@ namespace Eris\Listener; use Eris\Listener; -use InvalidArgumentException; +use Eris\Listeners; use Exception; +use InvalidArgumentException; +/** + * @see Listeners::collectFrequencies() + */ function collectFrequencies(callable $collectFunction = null) { - return new CollectFrequencies($collectFunction); + return Listeners::collectFrequencies($collectFunction); } class CollectFrequencies extends EmptyListener implements Listener diff --git a/src/Listener/Log.php b/src/Listener/Log.php index 1a4aadee..4d846b58 100644 --- a/src/Listener/Log.php +++ b/src/Listener/Log.php @@ -2,12 +2,15 @@ namespace Eris\Listener; use Eris\Listener; -use Eris\Listener\EmptyListener; +use Eris\Listeners; use Exception; +/** + * @see Listeners::log() + */ function log($file) { - return new Log($file, 'time', getmypid()); + return Listeners::log($file); } class Log extends EmptyListener implements Listener diff --git a/src/Listeners.php b/src/Listeners.php new file mode 100644 index 00000000..ca87a603 --- /dev/null +++ b/src/Listeners.php @@ -0,0 +1,19 @@ +> $subsetSizes */ $subsetSizes = []; for ($size = 0; $size < $maxSize; $size++) { $subsetSizes[] = count($this->generator->__invoke($size, $this->rand)->unbox()); @@ -43,7 +44,7 @@ public function testScalesGenerationSizeToTouchAllPossibleSubsets() $subsetSizeFrequencies = array_count_values($subsetSizes); // notice the full universe is very rarely generated // hence its presence is not asserted here - for ($subsetSize = 0; $subsetSize < count($this->universe); $subsetSize++) { + for ($subsetSize = 0, $subsetSizeMax = count($this->universe); $subsetSize < $subsetSizeMax; $subsetSize++) { $this->assertGreaterThan( 0, $subsetSizeFrequencies[$subsetSize], @@ -75,17 +76,17 @@ public function testShrinksOnlyInSizeBecauseShrinkingElementsMayCauseCollisions( public function testShrinkEmptySet() { $elements = $this->generator->__invoke($size = 0, $this->rand); - $this->assertEquals(0, count($elements->unbox())); - $this->assertEquals(0, count($this->generator->shrink($elements)->unbox())); + $this->assertCount(0, $elements->unbox()); + $this->assertCount(0, $this->generator->shrink($elements)->unbox()); } private function assertNoRepeatedElements($generated) { sort($generated); - $this->assertTrue( - array_unique($generated) === $generated, - "There are repeated elements inside a generated value: " - . var_export($generated, true) + $this->assertSame( + array_unique($generated), + $generated, + "There are repeated elements inside a generated value: " . var_export($generated, true) ); } } diff --git a/test/SampleTest.php b/test/SampleTest.php index dec26b7e..98abb63a 100644 --- a/test/SampleTest.php +++ b/test/SampleTest.php @@ -10,9 +10,9 @@ public function testWithGeneratorSize() { $times = 100; $generatorSize = 100; - $generator = Generator\suchThat(function ($n) { + $generator = Generators::suchThat(function ($n) { return $n > 10; - }, Generator\nat()); + }, Generators::nat()); $sample = $this->sample($generator, $times, $generatorSize); $this->assertNotEmpty(count($sample->collected())); }