Skip to content

Commit

Permalink
tests // add PHPStan to "tests"-folder.
Browse files Browse the repository at this point in the history
  • Loading branch information
Chrico committed Jan 24, 2025
1 parent 25d32c2 commit f5153c1
Show file tree
Hide file tree
Showing 9 changed files with 89 additions and 33 deletions.
2 changes: 2 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
"mikey179/vfsstream": "^v1.6.11",
"phpunit/phpunit": "^9.6.19",
"phpstan/phpstan": "^2.1.1",
"phpstan/phpstan-mockery": "^2.0.0",
"phpstan/phpstan-phpunit": "^2.0.4",
"szepeviktor/phpstan-wordpress": "^2",
"swissspidy/phpstan-no-private": "^v1.0.0",
"phpstan/phpstan-deprecation-rules": "^2.0.1"
Expand Down
17 changes: 14 additions & 3 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
includes:
- vendor/phpstan/phpstan-mockery/extension.neon
- vendor/phpstan/phpstan-phpunit/extension.neon
- vendor/szepeviktor/phpstan-wordpress/extension.neon
- vendor/phpstan/phpstan-deprecation-rules/rules.neon
- vendor/swissspidy/phpstan-no-private/rules.neon
parameters:
level: 8
paths:
- src/
- tests/
treatPhpDocTypesAsCertain: false
ignoreErrors:
- '#Trait Inpsyde\\Modularity\\Module\\ModuleClassNameIdTrait is used zero times and is not analysed.#'
# TODO: Check how we can point ABSPATH constant in phpstan to vendor/roots/wordpress-no-content/
- '#Path in require_once\(\) \".*\" is not a file or it does not exist.#'
# It seems like PHPStan does not like us to test classes to have interfaces implemented, but we want
# to ensure that classes are not accidentally loose their interfaces.
- '#Call to static method PHPUnit\\Framework\\Assert::assertInstanceOf\(\) with .* will always evaluate to true#'
-
messages:
- '#Parameter \$object of anonymous function has invalid type [A-Z]#'
- '#Anonymous function should return [A-Z] but returns object#'
- '#Anonymous function has invalid return type [A-Z]#'
- '#Instantiated class [A-Z] not found#'
- '#Class [A-Z] not found.#'
path: tests/unit/Container/ContainerConfiguratorTest.php
20 changes: 16 additions & 4 deletions tests/src/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,37 +67,47 @@ protected function stubProperties(
/**
* @param string $id
* @param class-string ...$interfaces
* @return Module|MockInterface
*
* @return Module&MockInterface
*/
protected function stubModule(string $id = 'module', string ...$interfaces): Module
{
$interfaces or $interfaces[] = Module::class;
if (!$interfaces) {
$interfaces[] = Module::class;
}

$stub = \Mockery::mock(...$interfaces);
/** @phpstan-ignore-next-line */
$stub->allows('id')->andReturn($id);

if (in_array(ServiceModule::class, $interfaces, true)) {
/** @phpstan-ignore-next-line */
$stub->allows('services')->byDefault()->andReturn([]);
}

if (in_array(FactoryModule::class, $interfaces, true)) {
/** @phpstan-ignore-next-line */
$stub->allows('factories')->byDefault()->andReturn([]);
}

if (in_array(ExtendingModule::class, $interfaces, true)) {
/** @phpstan-ignore-next-line */
$stub->allows('extensions')->byDefault()->andReturn([]);
}

if (in_array(ExecutableModule::class, $interfaces, true)) {
/** @phpstan-ignore-next-line */
$stub->allows('run')->byDefault()->andReturn(false);
}

/** @var MockInterface&Module */
return $stub;
}

/**
* @param string $suffix
* @param bool $debug
*
* @return Package
*/
protected function stubSimplePackage(string $suffix, bool $debug = false): Package
Expand All @@ -111,6 +121,7 @@ protected function stubSimplePackage(string $suffix, bool $debug = false): Packa

/**
* @param string ...$ids
*
* @return array<string, callable>
*/
protected function stubServices(string ...$ids): array
Expand All @@ -127,15 +138,15 @@ protected function stubServices(string ...$ids): array

/**
* @param string ...$ids
*
* @return ContainerInterface
*
* phpcs:disable Inpsyde.CodeQuality.NestingLevel
*/
protected function stubContainer(string ...$ids): ContainerInterface
{
// phpcs:enable Inpsyde.CodeQuality.NestingLevel
return new class ($this->stubServices(...$ids)) implements ContainerInterface
{
return new class ($this->stubServices(...$ids)) implements ContainerInterface {
/** @var array<string, callable> */
private array $services; // phpcs:ignore

Expand Down Expand Up @@ -192,6 +203,7 @@ static function (int $code, string $msg, ?string $file = null, ?int $line = null
/**
* @param \Throwable $throwable
* @param string $pattern
*
* @return void
*/
protected function assertThrowableMessageMatches(\Throwable $throwable, string $pattern): void
Expand Down
16 changes: 14 additions & 2 deletions tests/unit/Container/ContainerConfiguratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,12 @@ public function testExtensionByTypeNested(): void
{
// phpcs:enable Inpsyde.CodeQuality.NestingLevel
$logs = [];
/**
* @param object<\ArrayAccess> $object
* @param int ...$nums
*
* @return object<\ArrayAccess>
*/
$log = static function (object $object, int ...$nums) use (&$logs): object {
foreach ($nums as $num) {
if (!in_array($num, $logs, true)) {
Expand All @@ -434,9 +440,13 @@ public function testExtensionByTypeNested(): void
};

$configurator = new ContainerConfigurator();
$configurator->addService('test', static function (): \ArrayObject {
/**
* @return \ArrayAccess<string,string>
*/
$service = static function (): \ArrayAccess {
return new \ArrayObject();
});
};
$configurator->addService( 'test', $service );

Check failure on line 449 in tests/unit/Container/ContainerConfiguratorTest.php

View workflow job for this annotation

GitHub Actions / coding-standards-analysis / coding-standards-php

Space after opening parenthesis of function call prohibited

Check failure on line 449 in tests/unit/Container/ContainerConfiguratorTest.php

View workflow job for this annotation

GitHub Actions / coding-standards-analysis / coding-standards-php

Expected 0 spaces before closing parenthesis; 1 found

Check failure on line 449 in tests/unit/Container/ContainerConfiguratorTest.php

View workflow job for this annotation

GitHub Actions / coding-standards-analysis / coding-standards-php

Space after opening parenthesis of function call prohibited

Check failure on line 449 in tests/unit/Container/ContainerConfiguratorTest.php

View workflow job for this annotation

GitHub Actions / coding-standards-analysis / coding-standards-php

Expected 0 spaces before closing parenthesis; 1 found

// We can't declare classes inside a class, but we can eval it.
$php = <<<'PHP'
Expand All @@ -463,6 +473,7 @@ static function (\A $object) use (&$log): \A {
$configurator->addExtension(
'@instanceof<ArrayAccess>',
static function (\ArrayAccess $object) use (&$log): \ArrayAccess {
/** @var \ArrayAccess<string, string> */
return $log($object, 2);
}
);
Expand All @@ -481,6 +492,7 @@ static function (object $object) use ($log): object {
$configurator->addExtension(
'@instanceof<ArrayObject>',
static function (\ArrayObject $object) use (&$log): \ArrayObject {
/** @var \ArrayObject<string, string> */
return $log($object, 1);
}
);
Expand Down
40 changes: 21 additions & 19 deletions tests/unit/Container/ReadOnlyContainerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
use Inpsyde\Modularity\Tests\TestCase;
use Psr\Container\ContainerInterface;

/**
* @phpstan-import-type Service from \Inpsyde\Modularity\Module\ServiceModule
* @phpstan-import-type ExtendingService from \Inpsyde\Modularity\Module\ExtendingModule
*/
class ReadOnlyContainerTest extends TestCase
{
/**
Expand Down Expand Up @@ -92,8 +96,7 @@ public function testHasGetServiceFromChildContainer(): void
$expectedKey = 'service';
$expectedValue = new \stdClass();

$childContainer = new class ($expectedKey, $expectedValue) implements ContainerInterface
{
$childContainer = new class ($expectedKey, $expectedValue) implements ContainerInterface {
/** @var array<string, \stdClass> */
private array $data = [];

Expand Down Expand Up @@ -133,31 +136,28 @@ public function testFactoriesAndServices(): void
// phpcs:enable Inpsyde.CodeQuality.NestingLevel
$expectedServiceKey = 'service';
$expectedFactoryKey = 'factory';

$services = [
$expectedServiceKey => function (): object {
return new class
{
protected int $counter = 0;
return new class {
protected int $serviceCounter = 0;

public function count(): int
{
$this->counter++;
$this->serviceCounter++;

return $this->counter;
return $this->serviceCounter;
}
};
},
$expectedFactoryKey => function (): object {
return new class
{
protected int $counter = 0;
return new class {
protected int $factoryCounter = 0;

public function count(): int
{
$this->counter++;
$this->factoryCounter++;

return $this->counter;
return $this->factoryCounter;
}
};
},
Expand Down Expand Up @@ -185,6 +185,7 @@ public function testServiceExtensionsBackwardCompatibility(): void
};

$extension = static function (object $thing): object {
/** @var object{count:integer}&\stdClass $thing */
$thing->count++;

return $thing;
Expand All @@ -204,22 +205,23 @@ public function testServiceExtensionsBackwardCompatibility(): void
public function testServiceExtensionsBackwardCompatibilityBreaksOnWrongType(): void
{
$this->expectException(\TypeError::class);

/** @phpstan-ignore-next-line */
new Container([], [], ServiceExtensions::class, []);
}

/**
* @param array $services
* @param array $factoryIds
* @param array $containers
* @param array<string, Service> $services
* @param array<string, bool> $factoryIds
* @param ContainerInterface[] $containers
*
* @return Container
*/
private function factoryContainer(

Check warning on line 219 in tests/unit/Container/ReadOnlyContainerTest.php

View workflow job for this annotation

GitHub Actions / coding-standards-analysis / coding-standards-php

In functions where arguments declaration spans across multiple lines, function body should start with a blank line.

Check warning on line 219 in tests/unit/Container/ReadOnlyContainerTest.php

View workflow job for this annotation

GitHub Actions / coding-standards-analysis / coding-standards-php

In functions where arguments declaration spans across multiple lines, function body should start with a blank line.
array $services = [],
array $factoryIds = [],
array $containers = []
): Container {

): Container
{

Check warning on line 224 in tests/unit/Container/ReadOnlyContainerTest.php

View workflow job for this annotation

GitHub Actions / coding-standards-analysis / coding-standards-php

The closing parenthesis and the opening brace of a multi-line function declaration must be on the same line

Check warning on line 224 in tests/unit/Container/ReadOnlyContainerTest.php

View workflow job for this annotation

GitHub Actions / coding-standards-analysis / coding-standards-php

The closing parenthesis and the opening brace of a multi-line function declaration must be on the same line
return new Container($services, $factoryIds, new ServiceExtensions(), $containers);
}
}
7 changes: 7 additions & 0 deletions tests/unit/Container/ServiceExtensionsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ class ServiceExtensionsTest extends TestCase
{
/**
* @test
*
* @phpstan-type TestObject object{ count: integer }&\stdClass
*/
public function testBasicFunctionality(): void
{
Expand All @@ -20,6 +22,7 @@ public function testBasicFunctionality(): void
$serviceExtensions->add(
'thing',
static function (object $thing) use (&$expected): object {
/** @var object{count:integer}&\stdClass $thing */
$thing->count++;
$expected++;

Expand All @@ -30,6 +33,7 @@ static function (object $thing) use (&$expected): object {
$serviceExtensions->add(
'nothing',
static function (object $thing): object {
/** @var object{count:integer}&\stdClass $thing */
$thing->count++;

return $thing;
Expand All @@ -39,6 +43,7 @@ static function (object $thing): object {
$serviceExtensions->add(
'thing',
static function (object $thing) use (&$expected): object {
/** @var object{count:integer}&\stdClass $thing */
$thing->count++;
$expected++;

Expand All @@ -49,6 +54,7 @@ static function (object $thing) use (&$expected): object {
$serviceExtensions->add(
ServiceExtensions::typeId(\stdClass::class),
static function (object $thing) use (&$expected): object {
/** @var object{count:integer}&\stdClass $thing */
$thing->count++;
$expected++;

Expand All @@ -59,6 +65,7 @@ static function (object $thing) use (&$expected): object {
$serviceExtensions->add(
ServiceExtensions::typeId(\ArrayObject::class),
static function (object $thing): object {
/** @var object{count:integer}&\stdClass $thing */
$thing->count++;

return $thing;
Expand Down
12 changes: 11 additions & 1 deletion tests/unit/PackageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public function testBasic(): void
static::assertTrue($package->hasReachedStatus(Package::STATUS_DONE));
static::assertFalse($package->hasReachedStatus(6));
// check back compat
// @phpstan-ignore classConstant.deprecated
static::assertTrue($package->hasReachedStatus(Package::STATUS_MODULES_ADDED));

static::assertSame($expectedName, $package->name());
Expand Down Expand Up @@ -488,14 +489,20 @@ public function extensions(): array
'service' => function (\ArrayObject $current): object {
return new class ($current)
{
/**
* @var \ArrayObject<string, string>
*/
public \ArrayObject $object; // phpcs:ignore

/**
* @param \ArrayObject<string, string> $object
*/
public function __construct(\ArrayObject $object)
{
$this->object = $object;
}

public function works(): string
public function works(): string|null

Check failure on line 505 in tests/unit/PackageTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (7.4) / static-analysis-php

Method class@anonymous/tests/unit/PackageTest.php:490::works() has invalid return type Inpsyde\Modularity\Tests\Unit\null.

Check failure on line 505 in tests/unit/PackageTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (7.4) / static-analysis-php

Method class@anonymous/tests/unit/PackageTest.php:490::works() never returns Inpsyde\Modularity\Tests\Unit\null so it can be removed from the return type.

Check failure on line 505 in tests/unit/PackageTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (7.4) / static-analysis-php

Method class@anonymous/tests/unit/PackageTest.php:490::works() uses native union types but they're supported only on PHP 8.0 and later.

Check failure on line 505 in tests/unit/PackageTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (7.4) / static-analysis-php

Method class@anonymous/tests/unit/PackageTest.php:490::works() has invalid return type Inpsyde\Modularity\Tests\Unit\null.

Check failure on line 505 in tests/unit/PackageTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (7.4) / static-analysis-php

Method class@anonymous/tests/unit/PackageTest.php:490::works() never returns Inpsyde\Modularity\Tests\Unit\null so it can be removed from the return type.

Check failure on line 505 in tests/unit/PackageTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (7.4) / static-analysis-php

Method class@anonymous/tests/unit/PackageTest.php:490::works() uses native union types but they're supported only on PHP 8.0 and later.
{
return $this->object->offsetGet('works?');

Check failure on line 507 in tests/unit/PackageTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (7.4) / static-analysis-php

Method class@anonymous/tests/unit/PackageTest.php:490::works() should return Inpsyde\Modularity\Tests\Unit\null|string but returns string|null.

Check failure on line 507 in tests/unit/PackageTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (7.4) / static-analysis-php

Method class@anonymous/tests/unit/PackageTest.php:490::works() should return Inpsyde\Modularity\Tests\Unit\null|string but returns string|null.
}
Expand Down Expand Up @@ -1458,8 +1465,10 @@ function (\Throwable $throwable) use ($package): void {
->whenHappen(
function (\Throwable $throwable) use ($exception, $package): void {
$this->assertThrowableMessageMatches($throwable, 'boot application');
/** @var \Throwable $previous */
$previous = $throwable->getPrevious();
$this->assertThrowableMessageMatches($previous, 'build package');
/** @var \Throwable $previous */
$previous = $previous->getPrevious();
$this->assertThrowableMessageMatches($previous, 'add module');
static::assertSame($exception, $previous->getPrevious());
Expand Down Expand Up @@ -1507,6 +1516,7 @@ static function (\Throwable $throwable) use ($exception, $package): void {
->whenHappen(
function (\Throwable $throwable) use ($exception, $package): void {
$this->assertThrowableMessageMatches($throwable, 'boot application');
/** @var \Throwable $previous */
$previous = $throwable->getPrevious();
$this->assertThrowableMessageMatches($previous, 'two');
static::assertSame($exception, $previous->getPrevious());
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/Properties/BasePropertiesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public static function provideBaseNameData(): \Generator
* @param string $baseName
* @param string $basePath
* @param string|null $baseUrl
* @param array $properties
* @param array<string, string> $properties
* @return BaseProperties
*/
private function factoryBaseProperties(
Expand Down
Loading

0 comments on commit f5153c1

Please sign in to comment.