fix: PHPStan and test strictness improvements

Add bin/ scripts to PHPStan scanFiles, suppress property.onlyWritten for
by-ref test properties, add exhaustive default match arm, use explicit
expects() on mock stubs, fix data provider return type, and simplify
redundant null check in NotificationServiceTest.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-22 14:15:36 +01:00
parent ae392d55e8
commit 555199b217
6 changed files with 20 additions and 7 deletions

View File

@@ -275,7 +275,7 @@ class NotificationServiceTest extends TestCase
$this->notifRepo->expects($this->once()) $this->notifRepo->expects($this->once())
->method('create') ->method('create')
->with($this->callback(function (array $data): bool { ->with($this->callback(function (array $data): bool {
return !isset($data['dedupe_fingerprint']) || $data['dedupe_fingerprint'] === null; return !isset($data['dedupe_fingerprint']);
})) }))
->willReturn(56); ->willReturn(56);

View File

@@ -3,6 +3,15 @@ parameters:
phpVersion: 80499 phpVersion: 80499
scanFiles: scanFiles:
- web/index.php - web/index.php
- bin/cli-bootstrap.php
- bin/module-cli-bootstrap.php
- bin/module-migrate.php
- bin/module-deactivate.php
- bin/module-build.php
- bin/module-assets-sync.php
- bin/module-permissions-sync.php
- bin/module-runtime-sync.php
- bin/doctor.php
paths: paths:
- config - config
- lib - lib

View File

@@ -42,7 +42,7 @@ class ModuleI18nContractTest extends TestCase
$modules[$moduleId] = [$moduleId, $resolvedPath]; $modules[$moduleId] = [$moduleId, $resolvedPath];
} }
return $modules; return array_values($modules);
} }
#[DataProvider('moduleProvider')] #[DataProvider('moduleProvider')]

View File

@@ -28,6 +28,7 @@ class SettingsDefaultsGatewayTest extends TestCase
'setDefaultTenantId' => $tenantRepository->expects($this->once())->method('find')->with($id)->willReturn(null), 'setDefaultTenantId' => $tenantRepository->expects($this->once())->method('find')->with($id)->willReturn(null),
'setDefaultRoleId' => $roleRepository->expects($this->once())->method('find')->with($id)->willReturn(null), 'setDefaultRoleId' => $roleRepository->expects($this->once())->method('find')->with($id)->willReturn(null),
'setDefaultDepartmentId' => $departmentRepository->expects($this->once())->method('find')->with($id)->willReturn(null), 'setDefaultDepartmentId' => $departmentRepository->expects($this->once())->method('find')->with($id)->willReturn(null),
default => throw new \LogicException("Unknown setter: {$setter}"),
}; };
$this->assertFalse($gateway->$setter($id)); $this->assertFalse($gateway->$setter($id));

View File

@@ -59,7 +59,7 @@ final class SettingsSessionPolicyGatewayTest extends TestCase
self::assertFalse($gateway->isMicrosoftAutoRememberDefault()); self::assertFalse($gateway->isMicrosoftAutoRememberDefault());
$metadataTrue = $this->createMock(SettingsMetadataGateway::class); $metadataTrue = $this->createMock(SettingsMetadataGateway::class);
$metadataTrue->method('getValue')->with('microsoft_auto_remember_default')->willReturn('1'); $metadataTrue->expects($this->any())->method('getValue')->with('microsoft_auto_remember_default')->willReturn('1');
$gatewayTrue = new SettingsLoginPersistenceGateway($metadataTrue); $gatewayTrue = new SettingsLoginPersistenceGateway($metadataTrue);
self::assertTrue($gatewayTrue->isMicrosoftAutoRememberDefault()); self::assertTrue($gatewayTrue->isMicrosoftAutoRememberDefault());
} }
@@ -82,13 +82,13 @@ final class SettingsSessionPolicyGatewayTest extends TestCase
public function testRememberTokenLifetimeUsesFallbackWhenMissingOrInvalid(): void public function testRememberTokenLifetimeUsesFallbackWhenMissingOrInvalid(): void
{ {
$metadataMissing = $this->createMock(SettingsMetadataGateway::class); $metadataMissing = $this->createMock(SettingsMetadataGateway::class);
$metadataMissing->method('getInt')->with('remember_token_lifetime_days')->willReturn(null); $metadataMissing->expects($this->any())->method('getInt')->with('remember_token_lifetime_days')->willReturn(null);
$gatewayMissing = new SettingsLoginPersistenceGateway($metadataMissing); $gatewayMissing = new SettingsLoginPersistenceGateway($metadataMissing);
self::assertSame(30, $gatewayMissing->getRememberTokenLifetimeDays()); self::assertSame(30, $gatewayMissing->getRememberTokenLifetimeDays());
self::assertSame(30 * 86400, $gatewayMissing->getRememberTokenLifetimeSeconds()); self::assertSame(30 * 86400, $gatewayMissing->getRememberTokenLifetimeSeconds());
$metadataInvalid = $this->createMock(SettingsMetadataGateway::class); $metadataInvalid = $this->createMock(SettingsMetadataGateway::class);
$metadataInvalid->method('getInt')->with('remember_token_lifetime_days')->willReturn(500); $metadataInvalid->expects($this->any())->method('getInt')->with('remember_token_lifetime_days')->willReturn(500);
$gatewayInvalid = new SettingsLoginPersistenceGateway($metadataInvalid); $gatewayInvalid = new SettingsLoginPersistenceGateway($metadataInvalid);
self::assertSame(30, $gatewayInvalid->getRememberTokenLifetimeDays()); self::assertSame(30, $gatewayInvalid->getRememberTokenLifetimeDays());
} }
@@ -96,7 +96,7 @@ final class SettingsSessionPolicyGatewayTest extends TestCase
public function testRememberTokenLifetimeAcceptsValidRangeAndComputesSeconds(): void public function testRememberTokenLifetimeAcceptsValidRangeAndComputesSeconds(): void
{ {
$metadata = $this->createMock(SettingsMetadataGateway::class); $metadata = $this->createMock(SettingsMetadataGateway::class);
$metadata->method('getInt')->with('remember_token_lifetime_days')->willReturn(7); $metadata->expects($this->any())->method('getInt')->with('remember_token_lifetime_days')->willReturn(7);
$metadata->expects($this->once()) $metadata->expects($this->once())
->method('set') ->method('set')
->with('remember_token_lifetime_days', '14', $this->anything()) ->with('remember_token_lifetime_days', '14', $this->anything())

View File

@@ -17,8 +17,11 @@ final class ModuleEventDispatcherTest extends TestCase
$listener = new class ($called, $capturedEvent, $capturedPayload) implements EventListener { $listener = new class ($called, $capturedEvent, $capturedPayload) implements EventListener {
public function __construct( public function __construct(
/** @phpstan-ignore property.onlyWritten */
private bool &$called, private bool &$called,
/** @phpstan-ignore property.onlyWritten */
private string &$capturedEvent, private string &$capturedEvent,
/** @phpstan-ignore property.onlyWritten */
private array &$capturedPayload private array &$capturedPayload
) { ) {
} }
@@ -69,7 +72,7 @@ final class ModuleEventDispatcherTest extends TestCase
}; };
$successListener = new class ($secondCalled) implements EventListener { $successListener = new class ($secondCalled) implements EventListener {
public function __construct(private bool &$called) public function __construct(/** @phpstan-ignore property.onlyWritten */ private bool &$called)
{ {
} }