From f2691623cf8696feb2c4b4d0f695b4705ccb9f96 Mon Sep 17 00:00:00 2001 From: Nuno Maduro Date: Fri, 19 Jul 2024 14:03:59 +0100 Subject: [PATCH] feat: `toHaveAllMethodsDocumented` and `toHaveAllPropertiesDocumented` --- Features.md | 2 + src/Configuration.php | 3 ++ src/Expectation.php | 42 +++++++++++++++++++ src/Expectations/EachExpectation.php | 3 ++ src/Expectations/HigherOrderExpectation.php | 6 +++ src/Expectations/OppositeExpectation.php | 16 +++++++ src/Logging/Converter.php | 6 +++ src/Logging/TeamCity/ServiceMessage.php | 3 ++ src/Logging/TeamCity/TeamCityLogger.php | 6 +++ .../Parallel/Paratest/WrapperRunner.php | 15 +++++++ src/Support/Container.php | 3 ++ .../GitDirtyTestCaseFilter.php | 11 ++++- tests/.snapshots/success.txt | 10 ++++- .../Expect/toHaveAllMethodsDocumented.php | 13 ++++++ .../Expect/toHaveAllPropertiesDocumented.php | 13 ++++++ .../Expect/toHaveLineCountLessThan.php | 2 +- tests/Fixtures/Inheritance/ExampleTest.php | 2 + tests/Visual/Parallel.php | 2 +- 18 files changed, 154 insertions(+), 4 deletions(-) create mode 100644 tests/Features/Expect/toHaveAllMethodsDocumented.php create mode 100644 tests/Features/Expect/toHaveAllPropertiesDocumented.php diff --git a/Features.md b/Features.md index 3cccc7a1..3a82e82d 100644 --- a/Features.md +++ b/Features.md @@ -5,3 +5,5 @@ 5. `arch()->preset` 6. `toHaveFileSystemPermissions` 7. `toHaveLineCountLessThan` +8. `toHaveAllMethodsDocumented` +9. `toHaveAllPropertiesDocumented` diff --git a/src/Configuration.php b/src/Configuration.php index 1eb53ed0..06c00b14 100644 --- a/src/Configuration.php +++ b/src/Configuration.php @@ -11,6 +11,9 @@ use Pest\PendingCalls\UsesCall; */ final class Configuration { + /** + * The filename of the configuration. + */ private readonly string $filename; /** diff --git a/src/Expectation.php b/src/Expectation.php index 2fd592c8..21ed25e8 100644 --- a/src/Expectation.php +++ b/src/Expectation.php @@ -33,6 +33,8 @@ use Pest\Support\ExpectationPipeline; use PHPUnit\Architecture\Elements\ObjectDescription; use PHPUnit\Framework\ExpectationFailedException; use ReflectionEnum; +use ReflectionMethod; +use ReflectionProperty; /** * @template TValue @@ -460,6 +462,43 @@ final class Expectation ); } + /** + * Asserts that the given expectation target have all methods documented. + */ + public function toHaveAllMethodsDocumented(): ArchExpectation + { + return Targeted::make( + $this, + fn (ObjectDescription $object): bool => isset($object->reflectionClass) === false + || array_filter( + $object->reflectionClass->getMethods(), + fn (ReflectionMethod $method): bool => $method->class === $object->name + && $method->getDocComment() === false, + ) === [], + 'to have all methods documented', + FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')) + ); + } + + /** + * Asserts that the given expectation target have all properties documented. + */ + public function toHaveAllPropertiesDocumented(): ArchExpectation + { + return Targeted::make( + $this, + fn (ObjectDescription $object): bool => isset($object->reflectionClass) === false + || array_filter( + $object->reflectionClass->getProperties(), + fn (ReflectionProperty $property): bool => $property->class === $object->name + && $property->isPromoted() === false + && $property->getDocComment() === false, + ) === [], + 'to have all properties documented', + FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')) + ); + } + /** * Asserts that the given expectation target use the "declare(strict_types=1)" declaration. */ @@ -768,6 +807,9 @@ final class Expectation return ToUseNothing::make($this); } + /** + * Not supported. + */ public function toBeUsed(): never { throw InvalidExpectation::fromMethods(['toBeUsed']); diff --git a/src/Expectations/EachExpectation.php b/src/Expectations/EachExpectation.php index bbca0592..51a049a8 100644 --- a/src/Expectations/EachExpectation.php +++ b/src/Expectations/EachExpectation.php @@ -17,6 +17,9 @@ use function expect; */ final class EachExpectation { + /** + * Indicates if the expectation is the opposite. + */ private bool $opposite = false; /** diff --git a/src/Expectations/HigherOrderExpectation.php b/src/Expectations/HigherOrderExpectation.php index c7685ace..0feb886f 100644 --- a/src/Expectations/HigherOrderExpectation.php +++ b/src/Expectations/HigherOrderExpectation.php @@ -25,8 +25,14 @@ final class HigherOrderExpectation */ private Expectation|EachExpectation $expectation; + /** + * Indicates if the expectation is the opposite. + */ private bool $opposite = false; + /** + * Indicates if the expectation should reset the value. + */ private bool $shouldReset = false; /** diff --git a/src/Expectations/OppositeExpectation.php b/src/Expectations/OppositeExpectation.php index 4a523bff..061e9f68 100644 --- a/src/Expectations/OppositeExpectation.php +++ b/src/Expectations/OppositeExpectation.php @@ -96,6 +96,22 @@ final class OppositeExpectation throw InvalidExpectation::fromMethods(['not', 'toHaveLineCountLessThan']); } + /** + * Not supported. + */ + public function toHaveAllMethodsDocumented(): ArchExpectation + { + throw InvalidExpectation::fromMethods(['not', 'toHaveAllMethodsDocumented']); + } + + /** + * Not supported. + */ + public function toHaveAllPropertiesDocumented(): ArchExpectation + { + throw InvalidExpectation::fromMethods(['not', 'toHaveAllPropertiesDocumented']); + } + /** * Asserts that the given expectation target does not use the "declare(strict_types=1)" declaration. */ diff --git a/src/Logging/Converter.php b/src/Logging/Converter.php index f213776e..f74b53c8 100644 --- a/src/Logging/Converter.php +++ b/src/Logging/Converter.php @@ -26,8 +26,14 @@ use PHPUnit\TestRunner\TestResult\TestResult as PhpUnitTestResult; */ final class Converter { + /** + * The prefix for the test suite name. + */ private const PREFIX = 'P\\'; + /** + * The state generator. + */ private readonly StateGenerator $stateGenerator; /** diff --git a/src/Logging/TeamCity/ServiceMessage.php b/src/Logging/TeamCity/ServiceMessage.php index 0fbbaccb..ed73b0dd 100644 --- a/src/Logging/TeamCity/ServiceMessage.php +++ b/src/Logging/TeamCity/ServiceMessage.php @@ -9,6 +9,9 @@ namespace Pest\Logging\TeamCity; */ final class ServiceMessage { + /** + * The flow ID. + */ private static ?int $flowId = null; /** diff --git a/src/Logging/TeamCity/TeamCityLogger.php b/src/Logging/TeamCity/TeamCityLogger.php index 5b3044b7..d111041f 100644 --- a/src/Logging/TeamCity/TeamCityLogger.php +++ b/src/Logging/TeamCity/TeamCityLogger.php @@ -43,8 +43,14 @@ use Symfony\Component\Console\Output\OutputInterface; */ final class TeamCityLogger { + /** + * The current time. + */ private ?HRTime $time = null; + /** + * Indicates if the summary test count has been printed. + */ private bool $isSummaryTestCountPrinted = false; /** diff --git a/src/Plugins/Parallel/Paratest/WrapperRunner.php b/src/Plugins/Parallel/Paratest/WrapperRunner.php index b0dc5232..14eaa068 100644 --- a/src/Plugins/Parallel/Paratest/WrapperRunner.php +++ b/src/Plugins/Parallel/Paratest/WrapperRunner.php @@ -46,15 +46,27 @@ use function usleep; */ final class WrapperRunner implements RunnerInterface { + /** + * The time to sleep between cycles. + */ private const CYCLE_SLEEP = 10000; + /** + * The result printer. + */ private readonly ResultPrinter $printer; + /** + * The timer. + */ private readonly Timer $timer; /** @var list */ private array $pending = []; + /** + * The exit code. + */ private int $exitcode = -1; /** @var array */ @@ -84,6 +96,9 @@ final class WrapperRunner implements RunnerInterface /** @var non-empty-string[] */ private readonly array $parameters; + /** + * The code coverage filter registry. + */ private CodeCoverageFilterRegistry $codeCoverageFilterRegistry; public function __construct( diff --git a/src/Support/Container.php b/src/Support/Container.php index b780fd72..0f0220bd 100644 --- a/src/Support/Container.php +++ b/src/Support/Container.php @@ -13,6 +13,9 @@ use ReflectionParameter; */ final class Container { + /** + * The instance of the container. + */ private static ?Container $instance = null; /** diff --git a/src/TestCaseFilters/GitDirtyTestCaseFilter.php b/src/TestCaseFilters/GitDirtyTestCaseFilter.php index a4620a91..6eb90c2f 100644 --- a/src/TestCaseFilters/GitDirtyTestCaseFilter.php +++ b/src/TestCaseFilters/GitDirtyTestCaseFilter.php @@ -14,15 +14,21 @@ use Symfony\Component\Process\Process; final class GitDirtyTestCaseFilter implements TestCaseFilter { /** - * @var string[]|null + * @var array|null */ private ?array $changedFiles = null; + /** + * Creates a new instance of the filter. + */ public function __construct(private readonly string $projectRoot) { // ... } + /** + * {@inheritdoc} + */ public function accept(string $testCaseFilename): bool { if ($this->changedFiles === null) { @@ -41,6 +47,9 @@ final class GitDirtyTestCaseFilter implements TestCaseFilter return in_array($relativePath, $this->changedFiles, true); } + /** + * Loads the changed files. + */ private function loadChangedFiles(): void { $process = new Process(['git', 'status', '--short', '--', '*.php']); diff --git a/tests/.snapshots/success.txt b/tests/.snapshots/success.txt index fa9dd55b..575a192b 100644 --- a/tests/.snapshots/success.txt +++ b/tests/.snapshots/success.txt @@ -715,6 +715,14 @@ ✓ failures with custom message ✓ not failures + PASS Tests\Features\Expect\toHaveAllMethodsDocumented + ✓ it passes + ✓ it fails + + PASS Tests\Features\Expect\toHaveAllPropertiesDocumented + ✓ it passes + ✓ it fails + PASS Tests\Features\Expect\toHaveAttribute ✓ class has attribute ✓ opposite class has attribute @@ -1525,4 +1533,4 @@ WARN Tests\Visual\Version - visual snapshot of help command output - Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 13 todos, 24 skipped, 1068 passed (2614 assertions) \ No newline at end of file + Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 13 todos, 24 skipped, 1072 passed (2620 assertions) \ No newline at end of file diff --git a/tests/Features/Expect/toHaveAllMethodsDocumented.php b/tests/Features/Expect/toHaveAllMethodsDocumented.php new file mode 100644 index 00000000..c212c74a --- /dev/null +++ b/tests/Features/Expect/toHaveAllMethodsDocumented.php @@ -0,0 +1,13 @@ +toHaveAllMethodsDocumented(); +}); + +it('fails', function () { + expect(ExampleTest::class)->toHaveAllMethodsDocumented(); +})->throws(ArchExpectationFailedException::class); diff --git a/tests/Features/Expect/toHaveAllPropertiesDocumented.php b/tests/Features/Expect/toHaveAllPropertiesDocumented.php new file mode 100644 index 00000000..f8ad5b89 --- /dev/null +++ b/tests/Features/Expect/toHaveAllPropertiesDocumented.php @@ -0,0 +1,13 @@ +toHaveAllPropertiesDocumented(); +}); + +it('fails', function () { + expect(ExampleTest::class)->toHaveAllPropertiesDocumented(); +})->throws(ArchExpectationFailedException::class); diff --git a/tests/Features/Expect/toHaveLineCountLessThan.php b/tests/Features/Expect/toHaveLineCountLessThan.php index a7a53c74..caf932d1 100644 --- a/tests/Features/Expect/toHaveLineCountLessThan.php +++ b/tests/Features/Expect/toHaveLineCountLessThan.php @@ -4,7 +4,7 @@ use Pest\Arch\Exceptions\ArchExpectationFailedException; use Pest\Expectation; it('passes', function () { - expect(Expectation::class)->toHaveLineCountLessThan(1000); + expect(Expectation::class)->toHaveLineCountLessThan(2000); }); it('fails', function () { diff --git a/tests/Fixtures/Inheritance/ExampleTest.php b/tests/Fixtures/Inheritance/ExampleTest.php index f2469d84..a4ef960d 100644 --- a/tests/Fixtures/Inheritance/ExampleTest.php +++ b/tests/Fixtures/Inheritance/ExampleTest.php @@ -4,6 +4,8 @@ namespace Tests\Fixtures\Inheritance; class ExampleTest extends Base\ExampleTest { + protected $foo; + public function testExample() { $this->assertTrue(true); diff --git a/tests/Visual/Parallel.php b/tests/Visual/Parallel.php index 222eba3c..66b5c629 100644 --- a/tests/Visual/Parallel.php +++ b/tests/Visual/Parallel.php @@ -16,7 +16,7 @@ $run = function () { test('parallel', function () use ($run) { expect($run('--exclude-group=integration')) - ->toContain('Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 13 todos, 19 skipped, 1054 passed (2582 assertions)') + ->toContain('Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 13 todos, 19 skipped, 1058 passed (2588 assertions)') ->toContain('Parallel: 3 processes'); })->skipOnWindows();