mirror of
https://github.com/pestphp/pest.git
synced 2026-03-06 15:57:21 +01:00
feat: toHaveAllMethodsDocumented and toHaveAllPropertiesDocumented
This commit is contained in:
@ -5,3 +5,5 @@
|
|||||||
5. `arch()->preset`
|
5. `arch()->preset`
|
||||||
6. `toHaveFileSystemPermissions`
|
6. `toHaveFileSystemPermissions`
|
||||||
7. `toHaveLineCountLessThan`
|
7. `toHaveLineCountLessThan`
|
||||||
|
8. `toHaveAllMethodsDocumented`
|
||||||
|
9. `toHaveAllPropertiesDocumented`
|
||||||
|
|||||||
@ -11,6 +11,9 @@ use Pest\PendingCalls\UsesCall;
|
|||||||
*/
|
*/
|
||||||
final class Configuration
|
final class Configuration
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* The filename of the configuration.
|
||||||
|
*/
|
||||||
private readonly string $filename;
|
private readonly string $filename;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -33,6 +33,8 @@ use Pest\Support\ExpectationPipeline;
|
|||||||
use PHPUnit\Architecture\Elements\ObjectDescription;
|
use PHPUnit\Architecture\Elements\ObjectDescription;
|
||||||
use PHPUnit\Framework\ExpectationFailedException;
|
use PHPUnit\Framework\ExpectationFailedException;
|
||||||
use ReflectionEnum;
|
use ReflectionEnum;
|
||||||
|
use ReflectionMethod;
|
||||||
|
use ReflectionProperty;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @template TValue
|
* @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.
|
* Asserts that the given expectation target use the "declare(strict_types=1)" declaration.
|
||||||
*/
|
*/
|
||||||
@ -768,6 +807,9 @@ final class Expectation
|
|||||||
return ToUseNothing::make($this);
|
return ToUseNothing::make($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Not supported.
|
||||||
|
*/
|
||||||
public function toBeUsed(): never
|
public function toBeUsed(): never
|
||||||
{
|
{
|
||||||
throw InvalidExpectation::fromMethods(['toBeUsed']);
|
throw InvalidExpectation::fromMethods(['toBeUsed']);
|
||||||
|
|||||||
@ -17,6 +17,9 @@ use function expect;
|
|||||||
*/
|
*/
|
||||||
final class EachExpectation
|
final class EachExpectation
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Indicates if the expectation is the opposite.
|
||||||
|
*/
|
||||||
private bool $opposite = false;
|
private bool $opposite = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -25,8 +25,14 @@ final class HigherOrderExpectation
|
|||||||
*/
|
*/
|
||||||
private Expectation|EachExpectation $expectation;
|
private Expectation|EachExpectation $expectation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the expectation is the opposite.
|
||||||
|
*/
|
||||||
private bool $opposite = false;
|
private bool $opposite = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the expectation should reset the value.
|
||||||
|
*/
|
||||||
private bool $shouldReset = false;
|
private bool $shouldReset = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -96,6 +96,22 @@ final class OppositeExpectation
|
|||||||
throw InvalidExpectation::fromMethods(['not', 'toHaveLineCountLessThan']);
|
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.
|
* Asserts that the given expectation target does not use the "declare(strict_types=1)" declaration.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -26,8 +26,14 @@ use PHPUnit\TestRunner\TestResult\TestResult as PhpUnitTestResult;
|
|||||||
*/
|
*/
|
||||||
final class Converter
|
final class Converter
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* The prefix for the test suite name.
|
||||||
|
*/
|
||||||
private const PREFIX = 'P\\';
|
private const PREFIX = 'P\\';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The state generator.
|
||||||
|
*/
|
||||||
private readonly StateGenerator $stateGenerator;
|
private readonly StateGenerator $stateGenerator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -9,6 +9,9 @@ namespace Pest\Logging\TeamCity;
|
|||||||
*/
|
*/
|
||||||
final class ServiceMessage
|
final class ServiceMessage
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* The flow ID.
|
||||||
|
*/
|
||||||
private static ?int $flowId = null;
|
private static ?int $flowId = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -43,8 +43,14 @@ use Symfony\Component\Console\Output\OutputInterface;
|
|||||||
*/
|
*/
|
||||||
final class TeamCityLogger
|
final class TeamCityLogger
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* The current time.
|
||||||
|
*/
|
||||||
private ?HRTime $time = null;
|
private ?HRTime $time = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the summary test count has been printed.
|
||||||
|
*/
|
||||||
private bool $isSummaryTestCountPrinted = false;
|
private bool $isSummaryTestCountPrinted = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -46,15 +46,27 @@ use function usleep;
|
|||||||
*/
|
*/
|
||||||
final class WrapperRunner implements RunnerInterface
|
final class WrapperRunner implements RunnerInterface
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* The time to sleep between cycles.
|
||||||
|
*/
|
||||||
private const CYCLE_SLEEP = 10000;
|
private const CYCLE_SLEEP = 10000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The result printer.
|
||||||
|
*/
|
||||||
private readonly ResultPrinter $printer;
|
private readonly ResultPrinter $printer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The timer.
|
||||||
|
*/
|
||||||
private readonly Timer $timer;
|
private readonly Timer $timer;
|
||||||
|
|
||||||
/** @var list<non-empty-string> */
|
/** @var list<non-empty-string> */
|
||||||
private array $pending = [];
|
private array $pending = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The exit code.
|
||||||
|
*/
|
||||||
private int $exitcode = -1;
|
private int $exitcode = -1;
|
||||||
|
|
||||||
/** @var array<positive-int,WrapperWorker> */
|
/** @var array<positive-int,WrapperWorker> */
|
||||||
@ -84,6 +96,9 @@ final class WrapperRunner implements RunnerInterface
|
|||||||
/** @var non-empty-string[] */
|
/** @var non-empty-string[] */
|
||||||
private readonly array $parameters;
|
private readonly array $parameters;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The code coverage filter registry.
|
||||||
|
*/
|
||||||
private CodeCoverageFilterRegistry $codeCoverageFilterRegistry;
|
private CodeCoverageFilterRegistry $codeCoverageFilterRegistry;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
|||||||
@ -13,6 +13,9 @@ use ReflectionParameter;
|
|||||||
*/
|
*/
|
||||||
final class Container
|
final class Container
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* The instance of the container.
|
||||||
|
*/
|
||||||
private static ?Container $instance = null;
|
private static ?Container $instance = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -14,15 +14,21 @@ use Symfony\Component\Process\Process;
|
|||||||
final class GitDirtyTestCaseFilter implements TestCaseFilter
|
final class GitDirtyTestCaseFilter implements TestCaseFilter
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var string[]|null
|
* @var array<int, string>|null
|
||||||
*/
|
*/
|
||||||
private ?array $changedFiles = null;
|
private ?array $changedFiles = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of the filter.
|
||||||
|
*/
|
||||||
public function __construct(private readonly string $projectRoot)
|
public function __construct(private readonly string $projectRoot)
|
||||||
{
|
{
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
public function accept(string $testCaseFilename): bool
|
public function accept(string $testCaseFilename): bool
|
||||||
{
|
{
|
||||||
if ($this->changedFiles === null) {
|
if ($this->changedFiles === null) {
|
||||||
@ -41,6 +47,9 @@ final class GitDirtyTestCaseFilter implements TestCaseFilter
|
|||||||
return in_array($relativePath, $this->changedFiles, true);
|
return in_array($relativePath, $this->changedFiles, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the changed files.
|
||||||
|
*/
|
||||||
private function loadChangedFiles(): void
|
private function loadChangedFiles(): void
|
||||||
{
|
{
|
||||||
$process = new Process(['git', 'status', '--short', '--', '*.php']);
|
$process = new Process(['git', 'status', '--short', '--', '*.php']);
|
||||||
|
|||||||
@ -715,6 +715,14 @@
|
|||||||
✓ failures with custom message
|
✓ failures with custom message
|
||||||
✓ not failures
|
✓ 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
|
PASS Tests\Features\Expect\toHaveAttribute
|
||||||
✓ class has attribute
|
✓ class has attribute
|
||||||
✓ opposite class has attribute
|
✓ opposite class has attribute
|
||||||
@ -1525,4 +1533,4 @@
|
|||||||
WARN Tests\Visual\Version
|
WARN Tests\Visual\Version
|
||||||
- visual snapshot of help command output
|
- visual snapshot of help command output
|
||||||
|
|
||||||
Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 13 todos, 24 skipped, 1068 passed (2614 assertions)
|
Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 13 todos, 24 skipped, 1072 passed (2620 assertions)
|
||||||
13
tests/Features/Expect/toHaveAllMethodsDocumented.php
Normal file
13
tests/Features/Expect/toHaveAllMethodsDocumented.php
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Pest\Arch\Exceptions\ArchExpectationFailedException;
|
||||||
|
use Pest\Expectation;
|
||||||
|
use Tests\Fixtures\Inheritance\ExampleTest;
|
||||||
|
|
||||||
|
it('passes', function () {
|
||||||
|
expect(Expectation::class)->toHaveAllMethodsDocumented();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('fails', function () {
|
||||||
|
expect(ExampleTest::class)->toHaveAllMethodsDocumented();
|
||||||
|
})->throws(ArchExpectationFailedException::class);
|
||||||
13
tests/Features/Expect/toHaveAllPropertiesDocumented.php
Normal file
13
tests/Features/Expect/toHaveAllPropertiesDocumented.php
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Pest\Arch\Exceptions\ArchExpectationFailedException;
|
||||||
|
use Pest\Expectation;
|
||||||
|
use Tests\Fixtures\Inheritance\ExampleTest;
|
||||||
|
|
||||||
|
it('passes', function () {
|
||||||
|
expect(Expectation::class)->toHaveAllPropertiesDocumented();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('fails', function () {
|
||||||
|
expect(ExampleTest::class)->toHaveAllPropertiesDocumented();
|
||||||
|
})->throws(ArchExpectationFailedException::class);
|
||||||
@ -4,7 +4,7 @@ use Pest\Arch\Exceptions\ArchExpectationFailedException;
|
|||||||
use Pest\Expectation;
|
use Pest\Expectation;
|
||||||
|
|
||||||
it('passes', function () {
|
it('passes', function () {
|
||||||
expect(Expectation::class)->toHaveLineCountLessThan(1000);
|
expect(Expectation::class)->toHaveLineCountLessThan(2000);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('fails', function () {
|
it('fails', function () {
|
||||||
|
|||||||
@ -4,6 +4,8 @@ namespace Tests\Fixtures\Inheritance;
|
|||||||
|
|
||||||
class ExampleTest extends Base\ExampleTest
|
class ExampleTest extends Base\ExampleTest
|
||||||
{
|
{
|
||||||
|
protected $foo;
|
||||||
|
|
||||||
public function testExample()
|
public function testExample()
|
||||||
{
|
{
|
||||||
$this->assertTrue(true);
|
$this->assertTrue(true);
|
||||||
|
|||||||
@ -16,7 +16,7 @@ $run = function () {
|
|||||||
|
|
||||||
test('parallel', function () use ($run) {
|
test('parallel', function () use ($run) {
|
||||||
expect($run('--exclude-group=integration'))
|
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');
|
->toContain('Parallel: 3 processes');
|
||||||
})->skipOnWindows();
|
})->skipOnWindows();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user