From e03bd163d1d92509eed86506fdada02cc2865e28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Re=CC=81mi=20Pelhate?= Date: Thu, 4 Jun 2026 10:38:12 +0200 Subject: [PATCH 01/31] Setup mago --- composer.json | 2 ++ mago.toml | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 mago.toml diff --git a/composer.json b/composer.json index e6df89b..7b42581 100644 --- a/composer.json +++ b/composer.json @@ -24,6 +24,7 @@ "fakerphp/faker": "^1.24" }, "require-dev": { + "carthage-software/mago": "^1.29.0", "friendsofphp/php-cs-fixer": "^3.75", "illuminate/collections": "^10.10|^11.0|^12.0", "illuminate/console": "^10.10|^11.0|^12.0", @@ -63,6 +64,7 @@ "minimum-stability": "dev", "prefer-stable": true, "scripts": { + "mago": "vendor/bin/mago", "cs:check": "PHP_CS_FIXER_IGNORE_ENV=1 vendor/bin/php-cs-fixer fix --verbose --dry-run", "cs:fix": "PHP_CS_FIXER_IGNORE_ENV=1 vendor/bin/php-cs-fixer fix --verbose", "phpstan": "vendor/bin/phpstan analyse --memory-limit=2G --ansi", diff --git a/mago.toml b/mago.toml new file mode 100644 index 0000000..733499e --- /dev/null +++ b/mago.toml @@ -0,0 +1,16 @@ +#:schema https://mago.carthage.software/1.29.0/schema.json +# For full documentation, see https://mago.carthage.software/tools/overview +version = "1" +php-version = "8.4.0" + +[source] +workspace = "." +paths = ["src"] +includes = ["vendor"] +excludes = [] + +[source.glob] +literal-separator = true + +[formatter] +preset = "psr-12" From c10091c901d09245652e0316fc024fa525b3b4bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Re=CC=81mi=20Pelhate?= Date: Thu, 4 Jun 2026 10:39:19 +0200 Subject: [PATCH 02/31] Mago fix prefer-static-closure --- src/Factories/ImmutableFactoryTest.php | 10 ++-- .../Constraints/HasErrorOnPathTest.php | 4 +- .../Constraint/Bus/WasDispatchedTest.php | 22 ++++----- src/Laravel/Constraint/Bus/WasHandledTest.php | 48 +++++++++---------- .../Constraint/Bus/WithoutBusMiddleware.php | 2 +- .../Bus/WithoutBusMiddlewareTest.php | 2 +- .../Constraint/Events/WasDispatchedTest.php | 22 ++++----- .../Constraint/Scheduling/IsScheduled.php | 2 +- src/Laravel/ServiceProvider.php | 2 +- .../Constraint/Callables/WasCalled.php | 2 +- .../Constraint/Callables/WasCalledTest.php | 10 ++-- .../DeriveConstraintsFromObjectUsingFakes.php | 4 +- ...veConstraintsFromObjectUsingReflection.php | 2 +- .../Constraint/Objects/PropertyValueTest.php | 4 +- .../ProvidesAdditionalFailureDescription.php | 2 +- src/PHPUnit/DataProviders/EnumCase.php | 2 +- src/PHPUnit/DataProviders/EnumCaseTest.php | 2 +- src/PHPUnit/Doubles/SpyCallableTest.php | 2 +- src/Saloon/Constraints/WasSent.php | 2 +- src/Saloon/Constraints/WasSentTest.php | 22 ++++----- src/Saloon/DataProviders/FakeResponse.php | 2 +- 21 files changed, 85 insertions(+), 85 deletions(-) diff --git a/src/Factories/ImmutableFactoryTest.php b/src/Factories/ImmutableFactoryTest.php index e95cb35..20f0693 100644 --- a/src/Factories/ImmutableFactoryTest.php +++ b/src/Factories/ImmutableFactoryTest.php @@ -262,13 +262,13 @@ public function itCanMakeCollectionsWithState(array $attributes, array $state, a public static function nestedFactories(): iterable { yield [ - fn (ImmutableFactory $instance): ImmutableFactory => $instance->state([ + static fn (ImmutableFactory $instance): ImmutableFactory => $instance->state([ 'nested' => $instance->state([ 'deeplyNested' => $instance->state(['resolved' => true]), ]), 'nestedArray' => $instance->times(2)->state(['resolvedTimes' => true]), ]), - function (stdClass $result): void { + static function (stdClass $result): void { self::assertObjectHasProperty('nested', $result); self::assertInstanceOf(stdClass::class, $result->nested); self::assertObjectHasProperty('deeplyNested', $result->nested); @@ -277,7 +277,7 @@ function (stdClass $result): void { self::assertObjectHasProperty('nestedArray', $result); self::assertContainsOnlyInstancesOf(stdClass::class, $result->nestedArray); self::assertCount(2, $result->nestedArray); - collect($result->nestedArray)->each(function (stdClass $item): void { + collect($result->nestedArray)->each(static function (stdClass $item): void { self::assertObjectHasProperty('resolvedTimes', $item); self::assertTrue($item->resolvedTimes); }); @@ -312,7 +312,7 @@ public function itCanReturnManyRawAttributesWithNestedFactories(callable $resolv $results = $instance->rawMany(); - collect($results)->each(function (array $result) use ($assert): void { + collect($results)->each(static function (array $result) use ($assert): void { $assert((object) $result); }); } @@ -331,7 +331,7 @@ public function itCanReturnRawAttributesCollectionsWithNestedFactories( $results = $instance->rawCollection(); - $results->each(function (array $result) use ($assert): void { + $results->each(static function (array $result) use ($assert): void { $assert((object) $result); }); } diff --git a/src/GraphQL/Constraints/HasErrorOnPathTest.php b/src/GraphQL/Constraints/HasErrorOnPathTest.php index cc3d11b..0433921 100644 --- a/src/GraphQL/Constraints/HasErrorOnPathTest.php +++ b/src/GraphQL/Constraints/HasErrorOnPathTest.php @@ -194,7 +194,7 @@ public function itPassesWhenErrorOnPathIsOfGivenCategory(string $path, string $c #[Test] public function itFailsWhenResponseCouldNotBeResolvedForSubject(): void { - HasErrorOnPath::resolveResponseUsing(fn (Arrayable $subject): array => $subject->toArray()); + HasErrorOnPath::resolveResponseUsing(static fn (Arrayable $subject): array => $subject->toArray()); $response = new readonly class { public function toArray(): array @@ -212,7 +212,7 @@ public function toArray(): array #[Test] public function itPassesResponseCouldBeResolvedForSubject(): void { - HasErrorOnPath::resolveResponseUsing(fn (Arrayable $subject): array => $subject->toArray()); + HasErrorOnPath::resolveResponseUsing(static fn (Arrayable $subject): array => $subject->toArray()); $category = Factory::create()->word(); $path = 'somePath'; diff --git a/src/Laravel/Constraint/Bus/WasDispatchedTest.php b/src/Laravel/Constraint/Bus/WasDispatchedTest.php index db5c923..7215e5c 100644 --- a/src/Laravel/Constraint/Bus/WasDispatchedTest.php +++ b/src/Laravel/Constraint/Bus/WasDispatchedTest.php @@ -111,7 +111,7 @@ public function itPassesWhenDispatched(QuantableConstraint $quantise): void WasDispatched::spy(); $command = new stdClass(); - $quantise->applyTo(fn () => Bus::dispatch($command)); + $quantise->applyTo(static fn () => Bus::dispatch($command)); $this->assertThat($command::class, $quantise(new WasDispatched())); } @@ -127,7 +127,7 @@ public function itFailsWhenDispatchedButNotWithGivenCommandConstraints(): void $this->expectExceptionMessage('command was dispatched with given command constraints.'); $this->assertThat($command, new WasDispatched()->withConstraints( - new Callback(fn () => false), + new Callback(static fn () => false), )); } @@ -140,7 +140,7 @@ public function itPassesWhenDispatchedWithGivenCommandConstraints(): void Bus::dispatch($command); $this->assertThat($command, new WasDispatched()->withConstraints( - new Callback(fn () => true), + new Callback(static fn () => true), )); } @@ -150,7 +150,7 @@ public function itFailsWhenDispatchedButNotGivenTimes(QuantableConstraint $quant { WasDispatched::spy(); $command = new stdClass(); - $quantise->applyTo(fn () => Bus::dispatch($command)); + $quantise->applyTo(static fn () => Bus::dispatch($command)); $this->expectException(ExpectationFailedException::class); $this->expectExceptionMessage("command was dispatched $quantise->expected time(s)."); @@ -165,7 +165,7 @@ public function itPassesWhenDispatchedGivenTimes(QuantableConstraint $quantise): WasDispatched::spy(); $command = new stdClass(); - $quantise->applyTo(fn () => Bus::dispatch($command)); + $quantise->applyTo(static fn () => Bus::dispatch($command)); $this->assertThat($command::class, $quantise(new WasDispatched())); } @@ -177,13 +177,13 @@ public function itFailsWhenDispatchedWithGivenCommandConstrainsButNotGivenTimes( ): void { WasDispatched::spy(); $command = new stdClass(); - $quantise->applyTo(fn () => Bus::dispatch($command)); + $quantise->applyTo(static fn () => Bus::dispatch($command)); $this->expectException(ExpectationFailedException::class); $this->expectExceptionMessage("command was dispatched $quantise->expected time(s)"); $this->assertThat($command, new WasDispatched()->times($quantise->expected)->withConstraints( - new Callback(fn () => true), + new Callback(static fn () => true), )); } @@ -194,7 +194,7 @@ public function itFailsWhenDispatchedGivenTimesButNotWithGivenCommandConstrains( ): void { WasDispatched::spy(); $command = new stdClass(); - $quantise->applyTo(fn () => Bus::dispatch($command)); + $quantise->applyTo(static fn () => Bus::dispatch($command)); $this->expectException(ExpectationFailedException::class); $this->expectExceptionMessage( @@ -202,7 +202,7 @@ public function itFailsWhenDispatchedGivenTimesButNotWithGivenCommandConstrains( ); $this->assertThat($command, new WasDispatched()->times($quantise->expected)->withConstraints( - new Callback(fn () => false), + new Callback(static fn () => false), )); } @@ -214,10 +214,10 @@ public function itPassesWhenDispatchedGivenTimesWithGivenCommandConstraints( WasDispatched::spy(); $command = new stdClass(); - $quantise->applyTo(fn () => Bus::dispatch($command)); + $quantise->applyTo(static fn () => Bus::dispatch($command)); $this->assertThat($command, $quantise(new WasDispatched()->withConstraints( - new Callback(fn () => true), + new Callback(static fn () => true), ))); } diff --git a/src/Laravel/Constraint/Bus/WasHandledTest.php b/src/Laravel/Constraint/Bus/WasHandledTest.php index cd13903..0f647c6 100644 --- a/src/Laravel/Constraint/Bus/WasHandledTest.php +++ b/src/Laravel/Constraint/Bus/WasHandledTest.php @@ -36,7 +36,7 @@ public function resetDeriveConstraintsFromObjectUsing(): void public static function callableHandlers(): iterable { - yield 'Closure' => [fn (stdClass $object): string => 'handled']; + yield 'Closure' => [static fn (stdClass $object): string => 'handled']; yield 'Invokable class' => [ new readonly class { @@ -101,7 +101,7 @@ public function itFailsWhenNotUsingGivenCallables(): void #[Test] public function itFailsWhenNotHandled(): void { - WasHandled::using(fn (stdClass $command): string => 'handled', $this->app); + WasHandled::using(static fn (stdClass $command): string => 'handled', $this->app); $this->expectException(ExpectationFailedException::class); $this->expectExceptionMessage('command was handled.'); @@ -113,10 +113,10 @@ public function itFailsWhenNotHandled(): void #[DataProviderExternal(QuantableConstraint::class, 'cases')] public function itPassesWhenHandled(QuantableConstraint $quantise): void { - WasHandled::using(fn (stdClass $command): string => 'handled', $this->app); + WasHandled::using(static fn (stdClass $command): string => 'handled', $this->app); $command = new stdClass(); - $quantise->applyTo(fn () => Bus::dispatch($command)); + $quantise->applyTo(static fn () => Bus::dispatch($command)); $this->assertThat($command::class, $quantise(new WasHandled())); } @@ -124,7 +124,7 @@ public function itPassesWhenHandled(QuantableConstraint $quantise): void #[Test] public function itFailsWhenHandledButNotWithGivenCommandConstraints(): void { - WasHandled::using(fn (stdClass $command): string => 'handled', $this->app); + WasHandled::using(static fn (stdClass $command): string => 'handled', $this->app); $command = new stdClass(); Bus::dispatch($command); @@ -132,20 +132,20 @@ public function itFailsWhenHandledButNotWithGivenCommandConstraints(): void $this->expectExceptionMessage('command was handled with given command constraints.'); $this->assertThat($command::class, new WasHandled()->withConstraints( - new Callback(fn () => false), + new Callback(static fn () => false), )); } #[Test] public function itPassesWhenHandledWithGivenCommandConstraints(): void { - WasHandled::using(fn (stdClass $command): string => 'handled', $this->app); + WasHandled::using(static fn (stdClass $command): string => 'handled', $this->app); $command = new stdClass(); Bus::dispatch($command); $this->assertThat($command::class, new WasHandled()->withConstraints( - new Callback(fn () => true), + new Callback(static fn () => true), )); } @@ -153,9 +153,9 @@ public function itPassesWhenHandledWithGivenCommandConstraints(): void #[DataProviderExternal(QuantableConstraint::class, 'tooFewOrTooManyTimes')] public function itFailsWhenHandledButNotGivenTimes(QuantableConstraint $quantise): void { - WasHandled::using(fn (stdClass $command): string => 'handled', $this->app); + WasHandled::using(static fn (stdClass $command): string => 'handled', $this->app); $command = new stdClass(); - $quantise->applyTo(fn () => Bus::dispatch($command)); + $quantise->applyTo(static fn () => Bus::dispatch($command)); $this->expectException(ExpectationFailedException::class); $this->expectExceptionMessage("command was handled $quantise->expected time(s)."); @@ -167,10 +167,10 @@ public function itFailsWhenHandledButNotGivenTimes(QuantableConstraint $quantise #[DataProviderExternal(QuantableConstraint::class, 'cases')] public function itPassesWhenHandledGivenTimes(QuantableConstraint $quantise): void { - WasHandled::using(fn (stdClass $command): string => 'handled', $this->app); + WasHandled::using(static fn (stdClass $command): string => 'handled', $this->app); $command = new stdClass(); - $quantise->applyTo(fn () => Bus::dispatch($command)); + $quantise->applyTo(static fn () => Bus::dispatch($command)); $this->assertThat($command::class, $quantise(new WasHandled())); } @@ -180,15 +180,15 @@ public function itPassesWhenHandledGivenTimes(QuantableConstraint $quantise): vo public function itFailsWhenHandledWithGivenCommandConstrainsButNotGivenTimes( QuantableConstraint $quantise, ): void { - WasHandled::using(fn (stdClass $command): string => 'handled', $this->app); + WasHandled::using(static fn (stdClass $command): string => 'handled', $this->app); $command = new stdClass(); - $quantise->applyTo(fn () => Bus::dispatch($command)); + $quantise->applyTo(static fn () => Bus::dispatch($command)); $this->expectException(ExpectationFailedException::class); $this->expectExceptionMessage("command was handled $quantise->expected time(s)"); $this->assertThat($command, new WasHandled()->times($quantise->expected)->withConstraints( - new Callback(fn () => true), + new Callback(static fn () => true), )); } @@ -197,9 +197,9 @@ public function itFailsWhenHandledWithGivenCommandConstrainsButNotGivenTimes( public function itFailsWhenHandledGivenTimesButNotWithGivenCommandConstrains( QuantableConstraint $quantise, ): void { - WasHandled::using(fn (stdClass $command): string => 'handled', $this->app); + WasHandled::using(static fn (stdClass $command): string => 'handled', $this->app); $command = new stdClass(); - $quantise->applyTo(fn () => Bus::dispatch($command)); + $quantise->applyTo(static fn () => Bus::dispatch($command)); $this->expectException(ExpectationFailedException::class); $this->expectExceptionMessage( @@ -207,7 +207,7 @@ public function itFailsWhenHandledGivenTimesButNotWithGivenCommandConstrains( ); $this->assertThat($command, new WasHandled()->times($quantise->expected)->withConstraints( - new Callback(fn () => false), + new Callback(static fn () => false), )); } @@ -216,13 +216,13 @@ public function itFailsWhenHandledGivenTimesButNotWithGivenCommandConstrains( public function itPassesWhenHandledGivenTimesWithGivenCommandConstraints( QuantableConstraint $quantise, ): void { - WasHandled::using(fn (stdClass $command): string => 'handled', $this->app); + WasHandled::using(static fn (stdClass $command): string => 'handled', $this->app); $command = new stdClass(); - $quantise->applyTo(fn () => Bus::dispatch($command)); + $quantise->applyTo(static fn () => Bus::dispatch($command)); $this->assertThat($command, $quantise(new WasHandled()->withConstraints( - new Callback(fn () => true), + new Callback(static fn () => true), ))); } @@ -274,7 +274,7 @@ public function itCanDeriveCommandConstraintsFromCommandObjectsUsingCustomImplem public function itFailsWhenHandledButNotWithDerivedCommandConstraints(): void { $command = new stdClass(); - WasHandled::using(fn (stdClass $command): string => 'handled', $this->app); + WasHandled::using(static fn (stdClass $command): string => 'handled', $this->app); WasHandled::deriveConstraintsFromObjectUsing(DeriveConstraintsFromObjectUsingFakes::failingConstraints()); Bus::dispatch($command); @@ -288,7 +288,7 @@ public function itFailsWhenHandledButNotWithDerivedCommandConstraints(): void public function itPassesWhenDispatchedWithDerivedCommandConstraints(): void { $command = new stdClass(); - WasHandled::using(fn (stdClass $command): string => 'handled', $this->app); + WasHandled::using(static fn (stdClass $command): string => 'handled', $this->app); WasHandled::deriveConstraintsFromObjectUsing(DeriveConstraintsFromObjectUsingFakes::passingConstraints()); Bus::dispatch($command); @@ -304,7 +304,7 @@ public function itDerivesConstraintsFromExpectedCommandsAndMatchesItAgainstActua $constraint = Spy::passing(); $deriveConstraints = new DeriveConstraintsFromObjectUsingFakes([$constraint]); WasHandled::deriveConstraintsFromObjectUsing($deriveConstraints); - WasHandled::using(fn (stdClass $command): string => 'handled', $this->app); + WasHandled::using(static fn (stdClass $command): string => 'handled', $this->app); Bus::dispatch($actual); $this->assertThat($expected, new WasHandled()); diff --git a/src/Laravel/Constraint/Bus/WithoutBusMiddleware.php b/src/Laravel/Constraint/Bus/WithoutBusMiddleware.php index d3035af..78747f0 100644 --- a/src/Laravel/Constraint/Bus/WithoutBusMiddleware.php +++ b/src/Laravel/Constraint/Bus/WithoutBusMiddleware.php @@ -10,7 +10,7 @@ trait WithoutBusMiddleware { public function setUpWithoutBusMiddleware(): void { - $this->afterApplicationCreated(function (): void { + $this->afterApplicationCreated(static function (): void { Bus::pipeThrough([]); }); } diff --git a/src/Laravel/Constraint/Bus/WithoutBusMiddlewareTest.php b/src/Laravel/Constraint/Bus/WithoutBusMiddlewareTest.php index ce35700..e6d40d6 100644 --- a/src/Laravel/Constraint/Bus/WithoutBusMiddlewareTest.php +++ b/src/Laravel/Constraint/Bus/WithoutBusMiddlewareTest.php @@ -17,7 +17,7 @@ final class WithoutBusMiddlewareTest extends TestCase public function itCanRemoveBusMiddleware(): void { Bus::pipeThrough([ - fn (mixed $command, mixed $next): mixed => throw new LogicException('This should not happen'), + static fn (mixed $command, mixed $next): mixed => throw new LogicException('This should not happen'), ]); $this->setUpWithoutBusMiddleware(); diff --git a/src/Laravel/Constraint/Events/WasDispatchedTest.php b/src/Laravel/Constraint/Events/WasDispatchedTest.php index 8463c29..40d761e 100644 --- a/src/Laravel/Constraint/Events/WasDispatchedTest.php +++ b/src/Laravel/Constraint/Events/WasDispatchedTest.php @@ -111,7 +111,7 @@ public function itPassesWhenDispatched(QuantableConstraint $quantise): void WasDispatched::spy(); $event = 'some.event'; - $quantise->applyTo(fn () => Event::dispatch($event)); + $quantise->applyTo(static fn () => Event::dispatch($event)); $this->assertThat($event, $quantise(new WasDispatched())); } @@ -127,7 +127,7 @@ public function itFailsWhenDispatchedButNotWithGivenEventConstraints(): void $this->expectExceptionMessage('event was dispatched with given event constraints.'); $this->assertThat($event, new WasDispatched()->withConstraints( - new Callback(fn () => false), + new Callback(static fn () => false), )); } @@ -140,7 +140,7 @@ public function itPassesWhenDispatchedWithGivenEventConstraints(): void Event::dispatch($event); $this->assertThat($event, new WasDispatched()->withConstraints( - new Callback(fn () => true), + new Callback(static fn () => true), )); } @@ -150,7 +150,7 @@ public function itFailsWhenDispatchedButNotGivenTimes(QuantableConstraint $quant { WasDispatched::spy(); $event = 'some.event'; - $quantise->applyTo(fn () => Event::dispatch($event)); + $quantise->applyTo(static fn () => Event::dispatch($event)); $this->expectException(ExpectationFailedException::class); $this->expectExceptionMessage("event was dispatched $quantise->expected time(s)."); @@ -165,7 +165,7 @@ public function itPassesWhenDispatchedGivenTimes(QuantableConstraint $quantise): WasDispatched::spy(); $event = 'some.event'; - $quantise->applyTo(fn () => Event::dispatch($event)); + $quantise->applyTo(static fn () => Event::dispatch($event)); $this->assertThat($event, $quantise(new WasDispatched())); } @@ -177,13 +177,13 @@ public function itFailsWhenDispatchedWithGivenEventConstrainsButNotGivenTimes( ): void { WasDispatched::spy(); $event = new DummyEvent('first', 'last'); - $quantise->applyTo(fn () => Event::dispatch($event)); + $quantise->applyTo(static fn () => Event::dispatch($event)); $this->expectException(ExpectationFailedException::class); $this->expectExceptionMessage("event was dispatched $quantise->expected time(s)"); $this->assertThat($event, new WasDispatched()->times($quantise->expected)->withConstraints( - new Callback(fn () => true), + new Callback(static fn () => true), )); } @@ -194,13 +194,13 @@ public function itFailsWhenDispatchedGivenTimesButNotWithGivenEventConstrains( ): void { WasDispatched::spy(); $event = new DummyEvent('first', 'last'); - $quantise->applyTo(fn () => Event::dispatch($event)); + $quantise->applyTo(static fn () => Event::dispatch($event)); $this->expectException(ExpectationFailedException::class); $this->expectExceptionMessage("event was dispatched $quantise->expected time(s) with given event constraints."); $this->assertThat($event, new WasDispatched()->times($quantise->expected)->withConstraints( - new Callback(fn () => false), + new Callback(static fn () => false), )); } @@ -212,10 +212,10 @@ public function itPassesWhenDispatchedGivenTimesWithGivenEventConstraints( WasDispatched::spy(); $event = new DummyEvent('first', 'last'); - $quantise->applyTo(fn () => Event::dispatch($event)); + $quantise->applyTo(static fn () => Event::dispatch($event)); $this->assertThat($event, $quantise(new WasDispatched()->withConstraints( - new Callback(fn () => true), + new Callback(static fn () => true), ))); } diff --git a/src/Laravel/Constraint/Scheduling/IsScheduled.php b/src/Laravel/Constraint/Scheduling/IsScheduled.php index 8e3dd83..46e9fdc 100644 --- a/src/Laravel/Constraint/Scheduling/IsScheduled.php +++ b/src/Laravel/Constraint/Scheduling/IsScheduled.php @@ -40,7 +40,7 @@ protected function matches(mixed $other): bool ); $matchingScheduledTask = new Collection($this->schedule->events()) - ->first(fn (Event $event): bool => $event->description === $other); + ->first(static fn (Event $event): bool => $event->description === $other); if ($matchingScheduledTask === null) { $this->additionalFailureDescriptions[] = 'Not scheduled.'; diff --git a/src/Laravel/ServiceProvider.php b/src/Laravel/ServiceProvider.php index 487838d..ff76457 100644 --- a/src/Laravel/ServiceProvider.php +++ b/src/Laravel/ServiceProvider.php @@ -12,6 +12,6 @@ final class ServiceProvider extends IlluminateServiceProvider { public function boot(): void { - HasErrorOnPath::resolveResponseUsing(fn (TestResponse $response): array => $response->json()); + HasErrorOnPath::resolveResponseUsing(static fn (TestResponse $response): array => $response->json()); } } diff --git a/src/PHPUnit/Constraint/Callables/WasCalled.php b/src/PHPUnit/Constraint/Callables/WasCalled.php index 396d82b..1430fbe 100644 --- a/src/PHPUnit/Constraint/Callables/WasCalled.php +++ b/src/PHPUnit/Constraint/Callables/WasCalled.php @@ -29,7 +29,7 @@ public function __construct( public function withSame(mixed ...$expected): self { - return new self(function (mixed ...$actual) use ($expected): void { + return new self(static function (mixed ...$actual) use ($expected): void { Assert::assertCount(count($expected), $actual); foreach ($actual as $key => $value) { diff --git a/src/PHPUnit/Constraint/Callables/WasCalledTest.php b/src/PHPUnit/Constraint/Callables/WasCalledTest.php index 9f76843..3a33e8c 100644 --- a/src/PHPUnit/Constraint/Callables/WasCalledTest.php +++ b/src/PHPUnit/Constraint/Callables/WasCalledTest.php @@ -29,7 +29,7 @@ public function itCanConstructWithoutArguments(): void #[Test] public function itCanConstructWithInvocationAssertions(): void { - $assertInvocation = function (): void {}; + $assertInvocation = static function (): void {}; $instance = new WasCalled($assertInvocation); @@ -41,7 +41,7 @@ public function itCanConstructWithInvocationAssertions(): void #[DataProviderExternal(QuantableConstraint::class, 'cases')] public function itImplementsTheQuantableInterface(QuantableConstraint $quantise): void { - $assertInvocation = function (): void {}; + $assertInvocation = static function (): void {}; $instance = new WasCalled($assertInvocation); $quantisedInstance = $quantise($instance); @@ -57,7 +57,7 @@ public function itFailsWhenEvaluatingForNonSpyCallableInstances(): void { $this->expectException(InvalidArgumentException::class); - $this->assertThat(function (): void {}, new WasCalled()); + $this->assertThat(static function (): void {}, new WasCalled()); } #[Test] @@ -137,7 +137,7 @@ public function itPassesWhenCalledExpectedTimes(QuantableConstraint $quantise): public function itFailsWhenNotCalledExpectedTimesWithExpectedArguments(QuantableConstraint $quantise): void { $callable = new SpyCallable(); - $quantise->applyTo(fn () => $callable('first', 'last')); + $quantise->applyTo(static fn () => $callable('first', 'last')); $this->expectException(ExpectationFailedException::class); $this->expectExceptionMessage("was called $quantise->expected time(s) with given invocation assertions."); @@ -154,7 +154,7 @@ public function itPassesWhenCalledExpectedTimesWithExpectedArguments(QuantableCo { $callable = new SpyCallable(); - $quantise->applyTo(fn () => $callable('first', 'last')); + $quantise->applyTo(static fn () => $callable('first', 'last')); $this->assertThat($callable, $quantise(new WasCalled(function (string $first, string $last): void { $this->assertSame('first', $first); diff --git a/src/PHPUnit/Constraint/Objects/DeriveConstraintsFromObjectUsingFakes.php b/src/PHPUnit/Constraint/Objects/DeriveConstraintsFromObjectUsingFakes.php index e2d6dbb..f95e3c6 100644 --- a/src/PHPUnit/Constraint/Objects/DeriveConstraintsFromObjectUsingFakes.php +++ b/src/PHPUnit/Constraint/Objects/DeriveConstraintsFromObjectUsingFakes.php @@ -23,14 +23,14 @@ public function __construct( public static function failingConstraints(): self { return new self([ - new Callback(fn () => false), + new Callback(static fn () => false), ]); } public static function passingConstraints(): self { return new self([ - new Callback(fn () => true), + new Callback(static fn () => true), ]); } diff --git a/src/PHPUnit/Constraint/Objects/DeriveConstraintsFromObjectUsingReflection.php b/src/PHPUnit/Constraint/Objects/DeriveConstraintsFromObjectUsingReflection.php index 30cbed2..f2c873d 100644 --- a/src/PHPUnit/Constraint/Objects/DeriveConstraintsFromObjectUsingReflection.php +++ b/src/PHPUnit/Constraint/Objects/DeriveConstraintsFromObjectUsingReflection.php @@ -18,7 +18,7 @@ */ public function __invoke(object $object): array { - return array_map(function (ReflectionProperty $property) use ($object): Constraint { + return array_map(static function (ReflectionProperty $property) use ($object): Constraint { return new PropertyValue($property->name, new IsEqual($property->getValue($object))); }, new ReflectionClass($object)->getProperties(ReflectionProperty::IS_PUBLIC)); } diff --git a/src/PHPUnit/Constraint/Objects/PropertyValueTest.php b/src/PHPUnit/Constraint/Objects/PropertyValueTest.php index 922df35..80db8c1 100644 --- a/src/PHPUnit/Constraint/Objects/PropertyValueTest.php +++ b/src/PHPUnit/Constraint/Objects/PropertyValueTest.php @@ -60,7 +60,7 @@ public function itFailsWhenPropertiesDontExist(): void #[Test] public function itFailsWhenPropertiesDontMatchGivenConstraints(): void { - $constraint = new Callback(fn (): bool => false); + $constraint = new Callback(static fn (): bool => false); $object = $this->objectWithIdProperty(); $this->expectException(ExpectationFailedException::class); @@ -71,7 +71,7 @@ public function itFailsWhenPropertiesDontMatchGivenConstraints(): void #[Test] public function itPassesWhenPropertiesMatchGivenConstraints(): void { - $constraint = new Callback(fn (): bool => true); + $constraint = new Callback(static fn (): bool => true); $object = $this->objectWithIdProperty(); $this->assertThat($object, new PropertyValue('id', $constraint)); diff --git a/src/PHPUnit/Constraint/ProvidesAdditionalFailureDescription.php b/src/PHPUnit/Constraint/ProvidesAdditionalFailureDescription.php index b321bb8..07aa72f 100644 --- a/src/PHPUnit/Constraint/ProvidesAdditionalFailureDescription.php +++ b/src/PHPUnit/Constraint/ProvidesAdditionalFailureDescription.php @@ -18,7 +18,7 @@ trait ProvidesAdditionalFailureDescription protected function additionalFailureDescription(mixed $other): string { return new Collection($this->additionalFailureDescriptions) - ->map(fn (string $description): string => "\n* $description\n") + ->map(static fn (string $description): string => "\n* $description\n") ->implode(''); } } diff --git a/src/PHPUnit/DataProviders/EnumCase.php b/src/PHPUnit/DataProviders/EnumCase.php index a5f5f34..b7d49cd 100644 --- a/src/PHPUnit/DataProviders/EnumCase.php +++ b/src/PHPUnit/DataProviders/EnumCase.php @@ -89,7 +89,7 @@ public static function options(UnitEnum ...$options): iterable */ public static function except(string $enumFQCN, UnitEnum ...$except): iterable { - $options = array_map(function (ReflectionEnumUnitCase $reflection) use ($except): ?UnitEnum { + $options = array_map(static function (ReflectionEnumUnitCase $reflection) use ($except): ?UnitEnum { $case = $reflection->getValue(); return match (in_array($case, $except, true)) { diff --git a/src/PHPUnit/DataProviders/EnumCaseTest.php b/src/PHPUnit/DataProviders/EnumCaseTest.php index e2d22bb..77b2f53 100644 --- a/src/PHPUnit/DataProviders/EnumCaseTest.php +++ b/src/PHPUnit/DataProviders/EnumCaseTest.php @@ -68,7 +68,7 @@ public function itCannotConstructWhenOptionsHaveDifferentTypeComparedToGivenInst $instance = $this->faker->randomElement($options); $differentEnumFQCN = $this->faker->randomElement(array_filter( self::ENUM_FQCNS, - fn (string $enumFQCN): bool => $enumFQCN !== $instance::class, + static fn (string $enumFQCN): bool => $enumFQCN !== $instance::class, )); $differentEnumInstance = $this->faker->randomElement($differentEnumFQCN::cases()); diff --git a/src/PHPUnit/Doubles/SpyCallableTest.php b/src/PHPUnit/Doubles/SpyCallableTest.php index 22ec0aa..c9a69d1 100644 --- a/src/PHPUnit/Doubles/SpyCallableTest.php +++ b/src/PHPUnit/Doubles/SpyCallableTest.php @@ -35,7 +35,7 @@ public static function returnValues(): iterable yield 'Array' => [['foo']]; yield 'Zero' => [0]; yield 'Integer' => [PHP_INT_MAX]; - yield 'Callable' => [fn (): null => null]; + yield 'Callable' => [static fn (): null => null]; yield 'Class' => [new stdClass()]; } diff --git a/src/Saloon/Constraints/WasSent.php b/src/Saloon/Constraints/WasSent.php index 20ae6e4..583fae0 100644 --- a/src/Saloon/Constraints/WasSent.php +++ b/src/Saloon/Constraints/WasSent.php @@ -72,7 +72,7 @@ protected function matches(mixed $other): bool ), }; - $matchingSentRequests = array_reduce($this->client->getRecordedResponses(), function ( + $matchingSentRequests = array_reduce($this->client->getRecordedResponses(), static function ( array $matchingSentRequests, Response $response, ) use ($requestName): array { diff --git a/src/Saloon/Constraints/WasSentTest.php b/src/Saloon/Constraints/WasSentTest.php index 7275cff..a264e53 100644 --- a/src/Saloon/Constraints/WasSentTest.php +++ b/src/Saloon/Constraints/WasSentTest.php @@ -133,7 +133,7 @@ public function itPassesWhenSent(QuantableConstraint $quantise): void { $connector = new FakeConnector()->withMockClient($this->mockClient(FakeRequest::class)); - $quantise->applyTo(fn () => $connector->send(new FakeRequest())); + $quantise->applyTo(static fn () => $connector->send(new FakeRequest())); $this->assertThat(FakeRequest::class, $quantise(new WasSent($connector))); } @@ -162,7 +162,7 @@ public function itFailsWhenSentButNotWithGivenConstraints(): void $this->expectExceptionMessage('was sent with given constraints.'); $this->assertThat(FakeRequest::class, new WasSent($connector)->withConstraints( - new Callback(fn () => false), + new Callback(static fn () => false), )); } @@ -174,7 +174,7 @@ public function itPassesWhenSentWithGivenConstraints(): void $connector->send(new FakeRequest()); $this->assertThat(FakeRequest::class, new WasSent($connector)->withConstraints( - new Callback(fn () => true), + new Callback(static fn () => true), )); } @@ -183,7 +183,7 @@ public function itPassesWhenSentWithGivenConstraints(): void public function itFailsWhenSentButNotGivenTimes(QuantableConstraint $quantise): void { $connector = new FakeConnector()->withMockClient($this->mockClient(FakeRequest::class)); - $quantise->applyTo(fn () => $connector->send(new FakeRequest())); + $quantise->applyTo(static fn () => $connector->send(new FakeRequest())); $this->expectException(ExpectationFailedException::class); $this->expectExceptionMessage("was sent $quantise->expected time(s)."); @@ -197,7 +197,7 @@ public function itPassesWhenSentGivenTimes(QuantableConstraint $quantise): void { $connector = new FakeConnector()->withMockClient($this->mockClient(FakeRequest::class)); - $quantise->applyTo(fn () => $connector->send(new FakeRequest())); + $quantise->applyTo(static fn () => $connector->send(new FakeRequest())); $this->assertThat(FakeRequest::class, $quantise(new WasSent($connector))); } @@ -207,13 +207,13 @@ public function itPassesWhenSentGivenTimes(QuantableConstraint $quantise): void public function itFailsWhenSentWithGivenConstrainsButNotGivenTimes(QuantableConstraint $quantise): void { $connector = new FakeConnector()->withMockClient($this->mockClient(FakeRequest::class)); - $quantise->applyTo(fn () => $connector->send(new FakeRequest())); + $quantise->applyTo(static fn () => $connector->send(new FakeRequest())); $this->expectException(ExpectationFailedException::class); $this->expectExceptionMessage("was sent $quantise->expected time(s)"); $this->assertThat(FakeRequest::class, new WasSent($connector)->times($quantise->expected)->withConstraints( - new Callback(fn () => true), + new Callback(static fn () => true), )); } @@ -222,13 +222,13 @@ public function itFailsWhenSentWithGivenConstrainsButNotGivenTimes(QuantableCons public function itFailsWhenSentGivenTimesButNotWithGivenConstrains(QuantableConstraint $quantise): void { $connector = new FakeConnector()->withMockClient($this->mockClient(FakeRequest::class)); - $quantise->applyTo(fn () => $connector->send(new FakeRequest())); + $quantise->applyTo(static fn () => $connector->send(new FakeRequest())); $this->expectException(ExpectationFailedException::class); $this->expectExceptionMessage("was sent $quantise->expected time(s) with given constraints."); $this->assertThat(FakeRequest::class, new WasSent($connector)->times($quantise->expected)->withConstraints( - new Callback(fn () => false), + new Callback(static fn () => false), )); } @@ -238,10 +238,10 @@ public function itPassesWhenSentGivenTimesWithGivenConstraints(QuantableConstrai { $connector = new FakeConnector()->withMockClient($this->mockClient(FakeRequest::class)); - $quantise->applyTo(fn () => $connector->send(new FakeRequest())); + $quantise->applyTo(static fn () => $connector->send(new FakeRequest())); $this->assertThat(FakeRequest::class, $quantise(new WasSent($connector)->withConstraints( - new Callback(fn () => true), + new Callback(static fn () => true), ))); } diff --git a/src/Saloon/DataProviders/FakeResponse.php b/src/Saloon/DataProviders/FakeResponse.php index 400e0ef..93f34ef 100644 --- a/src/Saloon/DataProviders/FakeResponse.php +++ b/src/Saloon/DataProviders/FakeResponse.php @@ -76,7 +76,7 @@ public function __invoke(string $requestFQCN, ?Connector $connector = null): voi $client->addResponses([ $requestFQCN => $this->response, - '*' => function (PendingRequest $pendingRequest): void { + '*' => static function (PendingRequest $pendingRequest): void { throw new LogicException("Missing response mock for {$pendingRequest->getUrl()}."); }, ]); From dd264068e133cda3bce17e7a2e0c66604ef0fdb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Re=CC=81mi=20Pelhate?= Date: Thu, 4 Jun 2026 10:40:25 +0200 Subject: [PATCH 03/31] Mago fix braced-string-interpolatio --- src/GraphQL/Constraints/HasErrorOnPath.php | 2 +- src/GraphQL/Constraints/HasErrorOnPathTest.php | 6 +++--- src/Laravel/Constraint/Bus/HasHandler.php | 6 +++--- src/Laravel/Constraint/Bus/HasHandlerTest.php | 2 +- src/Laravel/Constraint/Bus/WasDispatched.php | 2 +- src/Laravel/Constraint/Bus/WasDispatchedTest.php | 6 +++--- src/Laravel/Constraint/Bus/WasHandled.php | 2 +- src/Laravel/Constraint/Bus/WasHandledTest.php | 6 +++--- src/Laravel/Constraint/Eloquent/ModelComparator.php | 2 +- src/Laravel/Constraint/Events/HasListener.php | 4 ++-- src/Laravel/Constraint/Events/HasListenerTest.php | 2 +- src/Laravel/Constraint/Events/WasDispatched.php | 2 +- src/Laravel/Constraint/Events/WasDispatchedTest.php | 6 +++--- src/Laravel/Constraint/Scheduling/IsScheduled.php | 2 +- src/PHPUnit/Constraint/Callables/WasCalled.php | 2 +- src/PHPUnit/Constraint/Callables/WasCalledTest.php | 4 ++-- src/PHPUnit/Constraint/Objects/PropertyValue.php | 2 +- .../Constraint/ProvidesAdditionalFailureDescription.php | 2 +- src/PHPUnit/DataProviders/EnumCase.php | 4 ++-- src/Saloon/Constraints/WasSent.php | 2 +- src/Saloon/Constraints/WasSentTest.php | 6 +++--- 21 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/GraphQL/Constraints/HasErrorOnPath.php b/src/GraphQL/Constraints/HasErrorOnPath.php index 28c6bc7..2ad88ca 100644 --- a/src/GraphQL/Constraints/HasErrorOnPath.php +++ b/src/GraphQL/Constraints/HasErrorOnPath.php @@ -102,6 +102,6 @@ private function resolveResponse(mixed $other): ?array public function toString(): string { - return "has error on `$this->path` of category `$this->category`"; + return "has error on `{$this->path}` of category `{$this->category}`"; } } diff --git a/src/GraphQL/Constraints/HasErrorOnPathTest.php b/src/GraphQL/Constraints/HasErrorOnPathTest.php index 0433921..745c38c 100644 --- a/src/GraphQL/Constraints/HasErrorOnPathTest.php +++ b/src/GraphQL/Constraints/HasErrorOnPathTest.php @@ -85,7 +85,7 @@ public function ifFailsWhenNoError(): void $response = ['data' => 'ok']; $this->expectException(ExpectationFailedException::class); - $this->expectExceptionMessage("has error on `$path` of category `$category`"); + $this->expectExceptionMessage("has error on `{$path}` of category `{$category}`"); $this->assertThat($response, new HasErrorOnPath($path, $category)); } @@ -130,7 +130,7 @@ public function itFailsWhenErrorNotOnGivenPath(): void ]; $this->expectException(ExpectationFailedException::class); - $this->expectExceptionMessage("has error on `$path` of category `$category`"); + $this->expectExceptionMessage("has error on `{$path}` of category `{$category}`"); $this->assertThat($response, new HasErrorOnPath($path, $category)); } @@ -152,7 +152,7 @@ public function itFailsWhenErrorNotOfGivenCategory(): void ]; $this->expectException(ExpectationFailedException::class); - $this->expectExceptionMessage("has error on `$path` of category `$category`"); + $this->expectExceptionMessage("has error on `{$path}` of category `{$category}`"); $this->assertThat($response, new HasErrorOnPath($path, $category)); } diff --git a/src/Laravel/Constraint/Bus/HasHandler.php b/src/Laravel/Constraint/Bus/HasHandler.php index 667d793..7e37c1d 100644 --- a/src/Laravel/Constraint/Bus/HasHandler.php +++ b/src/Laravel/Constraint/Bus/HasHandler.php @@ -34,19 +34,19 @@ protected function matches(mixed $other): bool self::class . ' can only be evaluated for strings, got ' . gettype($other) . '.', ); class_exists($other) or throw new InvalidArgumentException( - self::class . " can only be evaluated for existing classes, got $other.", + self::class . " can only be evaluated for existing classes, got {$other}.", ); $message = new ReflectionClass($other)->newInstanceWithoutConstructor(); $actualHandler = $this->bus->getCommandHandler($message); if ($actualHandler === false) { - $this->additionalFailureDescriptions[] = "$other has no handler mapped to it."; + $this->additionalFailureDescriptions[] = "{$other} has no handler mapped to it."; return false; } if ($actualHandler::class !== $this->handlerClassFQN) { - $this->additionalFailureDescriptions[] = "$other has a different handler mapped to it."; + $this->additionalFailureDescriptions[] = "{$other} has a different handler mapped to it."; return false; } diff --git a/src/Laravel/Constraint/Bus/HasHandlerTest.php b/src/Laravel/Constraint/Bus/HasHandlerTest.php index 91b0a74..4ce569a 100644 --- a/src/Laravel/Constraint/Bus/HasHandlerTest.php +++ b/src/Laravel/Constraint/Bus/HasHandlerTest.php @@ -36,7 +36,7 @@ public function itCannotEvaluateStringThatAreNotExistingClasses(): void $value = 'NotAClass'; $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage(HasHandler::class . " can only be evaluated for existing classes, got $value."); + $this->expectExceptionMessage(HasHandler::class . " can only be evaluated for existing classes, got {$value}."); $this->assertThat($value, new HasHandler('SomeHandlerClassFCN')); } diff --git a/src/Laravel/Constraint/Bus/WasDispatched.php b/src/Laravel/Constraint/Bus/WasDispatched.php index 92bcc4b..344697e 100644 --- a/src/Laravel/Constraint/Bus/WasDispatched.php +++ b/src/Laravel/Constraint/Bus/WasDispatched.php @@ -114,7 +114,7 @@ protected function failureDescription(mixed $other): string $message = parent::failureDescription($other); if ($this->times !== null) { - $message .= " $this->times time(s)"; + $message .= " {$this->times} time(s)"; } $message .= match (true) { diff --git a/src/Laravel/Constraint/Bus/WasDispatchedTest.php b/src/Laravel/Constraint/Bus/WasDispatchedTest.php index 7215e5c..4a0a2a3 100644 --- a/src/Laravel/Constraint/Bus/WasDispatchedTest.php +++ b/src/Laravel/Constraint/Bus/WasDispatchedTest.php @@ -153,7 +153,7 @@ public function itFailsWhenDispatchedButNotGivenTimes(QuantableConstraint $quant $quantise->applyTo(static fn () => Bus::dispatch($command)); $this->expectException(ExpectationFailedException::class); - $this->expectExceptionMessage("command was dispatched $quantise->expected time(s)."); + $this->expectExceptionMessage("command was dispatched {$quantise->expected} time(s)."); $this->assertThat($command::class, new WasDispatched()->times($quantise->expected)); } @@ -180,7 +180,7 @@ public function itFailsWhenDispatchedWithGivenCommandConstrainsButNotGivenTimes( $quantise->applyTo(static fn () => Bus::dispatch($command)); $this->expectException(ExpectationFailedException::class); - $this->expectExceptionMessage("command was dispatched $quantise->expected time(s)"); + $this->expectExceptionMessage("command was dispatched {$quantise->expected} time(s)"); $this->assertThat($command, new WasDispatched()->times($quantise->expected)->withConstraints( new Callback(static fn () => true), @@ -198,7 +198,7 @@ public function itFailsWhenDispatchedGivenTimesButNotWithGivenCommandConstrains( $this->expectException(ExpectationFailedException::class); $this->expectExceptionMessage( - "command was dispatched $quantise->expected time(s) with given command constraints.", + "command was dispatched {$quantise->expected} time(s) with given command constraints.", ); $this->assertThat($command, new WasDispatched()->times($quantise->expected)->withConstraints( diff --git a/src/Laravel/Constraint/Bus/WasHandled.php b/src/Laravel/Constraint/Bus/WasHandled.php index a1295dd..ec7ed4e 100644 --- a/src/Laravel/Constraint/Bus/WasHandled.php +++ b/src/Laravel/Constraint/Bus/WasHandled.php @@ -117,7 +117,7 @@ protected function failureDescription(mixed $other): string $message = parent::failureDescription($other); if ($this->times !== null) { - $message .= " $this->times time(s)"; + $message .= " {$this->times} time(s)"; } $message .= match (true) { diff --git a/src/Laravel/Constraint/Bus/WasHandledTest.php b/src/Laravel/Constraint/Bus/WasHandledTest.php index 0f647c6..19fd162 100644 --- a/src/Laravel/Constraint/Bus/WasHandledTest.php +++ b/src/Laravel/Constraint/Bus/WasHandledTest.php @@ -158,7 +158,7 @@ public function itFailsWhenHandledButNotGivenTimes(QuantableConstraint $quantise $quantise->applyTo(static fn () => Bus::dispatch($command)); $this->expectException(ExpectationFailedException::class); - $this->expectExceptionMessage("command was handled $quantise->expected time(s)."); + $this->expectExceptionMessage("command was handled {$quantise->expected} time(s)."); $this->assertThat($command::class, new WasHandled()->times($quantise->expected)); } @@ -185,7 +185,7 @@ public function itFailsWhenHandledWithGivenCommandConstrainsButNotGivenTimes( $quantise->applyTo(static fn () => Bus::dispatch($command)); $this->expectException(ExpectationFailedException::class); - $this->expectExceptionMessage("command was handled $quantise->expected time(s)"); + $this->expectExceptionMessage("command was handled {$quantise->expected} time(s)"); $this->assertThat($command, new WasHandled()->times($quantise->expected)->withConstraints( new Callback(static fn () => true), @@ -203,7 +203,7 @@ public function itFailsWhenHandledGivenTimesButNotWithGivenCommandConstrains( $this->expectException(ExpectationFailedException::class); $this->expectExceptionMessage( - "command was handled $quantise->expected time(s) with given command constraints.", + "command was handled {$quantise->expected} time(s) with given command constraints.", ); $this->assertThat($command, new WasHandled()->times($quantise->expected)->withConstraints( diff --git a/src/Laravel/Constraint/Eloquent/ModelComparator.php b/src/Laravel/Constraint/Eloquent/ModelComparator.php index 5142c78..e4ec90c 100644 --- a/src/Laravel/Constraint/Eloquent/ModelComparator.php +++ b/src/Laravel/Constraint/Eloquent/ModelComparator.php @@ -41,7 +41,7 @@ public function assertEquals( private static function notInstanceOfModel(string $argumentName, mixed $value): AssertionError { return new AssertionError( - "Argument $argumentName must be an instance of " . Model::class . ', received ' . gettype($value) . '.', + "Argument {$argumentName} must be an instance of " . Model::class . ', received ' . gettype($value) . '.', ); } diff --git a/src/Laravel/Constraint/Events/HasListener.php b/src/Laravel/Constraint/Events/HasListener.php index 244dbce..91e242b 100644 --- a/src/Laravel/Constraint/Events/HasListener.php +++ b/src/Laravel/Constraint/Events/HasListener.php @@ -27,7 +27,7 @@ final class HasListener extends Constraint public function __construct( public string $listener { set(string $listener) { - class_exists($listener) or throw new InvalidArgumentException("$listener is not an existing class."); + class_exists($listener) or throw new InvalidArgumentException("{$listener} is not an existing class."); $this->listener = $listener; } @@ -35,7 +35,7 @@ class_exists($listener) or throw new InvalidArgumentException("$listener is not public string $method = self::DEFAULT_METHOD { set(string $method) { method_exists($this->listener, $method) or throw new InvalidArgumentException( - "Method $this->listener::$method does not exist.", + "Method {$this->listener}::{$method} does not exist.", ); $this->method = $method; diff --git a/src/Laravel/Constraint/Events/HasListenerTest.php b/src/Laravel/Constraint/Events/HasListenerTest.php index 2c4891f..4b19c04 100644 --- a/src/Laravel/Constraint/Events/HasListenerTest.php +++ b/src/Laravel/Constraint/Events/HasListenerTest.php @@ -36,7 +36,7 @@ public function itFailsToConstructWithNonListenerMethods(): void $method = 'thisIsNotTheMethodYouAreLookingFor'; $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage("$method does not exist."); + $this->expectExceptionMessage("{$method} does not exist."); new HasListener(DummyListener::class, $method); } diff --git a/src/Laravel/Constraint/Events/WasDispatched.php b/src/Laravel/Constraint/Events/WasDispatched.php index a4d119c..97d8bc0 100644 --- a/src/Laravel/Constraint/Events/WasDispatched.php +++ b/src/Laravel/Constraint/Events/WasDispatched.php @@ -116,7 +116,7 @@ protected function failureDescription(mixed $other): string $message = parent::failureDescription($other); if ($this->times !== null) { - $message .= " $this->times time(s)"; + $message .= " {$this->times} time(s)"; } $message .= match (true) { diff --git a/src/Laravel/Constraint/Events/WasDispatchedTest.php b/src/Laravel/Constraint/Events/WasDispatchedTest.php index 40d761e..42c0fd8 100644 --- a/src/Laravel/Constraint/Events/WasDispatchedTest.php +++ b/src/Laravel/Constraint/Events/WasDispatchedTest.php @@ -153,7 +153,7 @@ public function itFailsWhenDispatchedButNotGivenTimes(QuantableConstraint $quant $quantise->applyTo(static fn () => Event::dispatch($event)); $this->expectException(ExpectationFailedException::class); - $this->expectExceptionMessage("event was dispatched $quantise->expected time(s)."); + $this->expectExceptionMessage("event was dispatched {$quantise->expected} time(s)."); $this->assertThat($event, new WasDispatched()->times($quantise->expected)); } @@ -180,7 +180,7 @@ public function itFailsWhenDispatchedWithGivenEventConstrainsButNotGivenTimes( $quantise->applyTo(static fn () => Event::dispatch($event)); $this->expectException(ExpectationFailedException::class); - $this->expectExceptionMessage("event was dispatched $quantise->expected time(s)"); + $this->expectExceptionMessage("event was dispatched {$quantise->expected} time(s)"); $this->assertThat($event, new WasDispatched()->times($quantise->expected)->withConstraints( new Callback(static fn () => true), @@ -197,7 +197,7 @@ public function itFailsWhenDispatchedGivenTimesButNotWithGivenEventConstrains( $quantise->applyTo(static fn () => Event::dispatch($event)); $this->expectException(ExpectationFailedException::class); - $this->expectExceptionMessage("event was dispatched $quantise->expected time(s) with given event constraints."); + $this->expectExceptionMessage("event was dispatched {$quantise->expected} time(s) with given event constraints."); $this->assertThat($event, new WasDispatched()->times($quantise->expected)->withConstraints( new Callback(static fn () => false), diff --git a/src/Laravel/Constraint/Scheduling/IsScheduled.php b/src/Laravel/Constraint/Scheduling/IsScheduled.php index 46e9fdc..874dbc7 100644 --- a/src/Laravel/Constraint/Scheduling/IsScheduled.php +++ b/src/Laravel/Constraint/Scheduling/IsScheduled.php @@ -62,6 +62,6 @@ protected function matches(mixed $other): bool public function toString(): string { - return "is scheduled $this->frequency"; + return "is scheduled {$this->frequency}"; } } diff --git a/src/PHPUnit/Constraint/Callables/WasCalled.php b/src/PHPUnit/Constraint/Callables/WasCalled.php index 1430fbe..ac9f4b9 100644 --- a/src/PHPUnit/Constraint/Callables/WasCalled.php +++ b/src/PHPUnit/Constraint/Callables/WasCalled.php @@ -86,7 +86,7 @@ public function toString(): string $message = 'was called'; if ($this->times !== null) { - $message .= " $this->times time(s)"; + $message .= " {$this->times} time(s)"; } if ($this->assertInvocation !== null) { diff --git a/src/PHPUnit/Constraint/Callables/WasCalledTest.php b/src/PHPUnit/Constraint/Callables/WasCalledTest.php index 3a33e8c..b8b9df2 100644 --- a/src/PHPUnit/Constraint/Callables/WasCalledTest.php +++ b/src/PHPUnit/Constraint/Callables/WasCalledTest.php @@ -116,7 +116,7 @@ public function itFailsWhenNotCalledExpectedTimes(QuantableConstraint $quantise) $quantise->applyTo($callable(...)); $this->expectException(ExpectationFailedException::class); - $this->expectExceptionMessage("was called $quantise->expected time(s)."); + $this->expectExceptionMessage("was called {$quantise->expected} time(s)."); $this->assertThat($callable, new WasCalled()->times($quantise->expected)); } @@ -140,7 +140,7 @@ public function itFailsWhenNotCalledExpectedTimesWithExpectedArguments(Quantable $quantise->applyTo(static fn () => $callable('first', 'last')); $this->expectException(ExpectationFailedException::class); - $this->expectExceptionMessage("was called $quantise->expected time(s) with given invocation assertions."); + $this->expectExceptionMessage("was called {$quantise->expected} time(s) with given invocation assertions."); $this->assertThat($callable, new WasCalled(function (string $first, string $last): void { $this->assertSame('first', $first); diff --git a/src/PHPUnit/Constraint/Objects/PropertyValue.php b/src/PHPUnit/Constraint/Objects/PropertyValue.php index d560fdc..bba64a1 100644 --- a/src/PHPUnit/Constraint/Objects/PropertyValue.php +++ b/src/PHPUnit/Constraint/Objects/PropertyValue.php @@ -49,6 +49,6 @@ public function toString(): string ->classBasename() ->snake(' '); - return "`$this->name` property value $comparesTo"; + return "`{$this->name}` property value {$comparesTo}"; } } diff --git a/src/PHPUnit/Constraint/ProvidesAdditionalFailureDescription.php b/src/PHPUnit/Constraint/ProvidesAdditionalFailureDescription.php index 07aa72f..64b4254 100644 --- a/src/PHPUnit/Constraint/ProvidesAdditionalFailureDescription.php +++ b/src/PHPUnit/Constraint/ProvidesAdditionalFailureDescription.php @@ -18,7 +18,7 @@ trait ProvidesAdditionalFailureDescription protected function additionalFailureDescription(mixed $other): string { return new Collection($this->additionalFailureDescriptions) - ->map(static fn (string $description): string => "\n* $description\n") + ->map(static fn (string $description): string => "\n* {$description}\n") ->implode(''); } } diff --git a/src/PHPUnit/DataProviders/EnumCase.php b/src/PHPUnit/DataProviders/EnumCase.php index b7d49cd..9ffc53e 100644 --- a/src/PHPUnit/DataProviders/EnumCase.php +++ b/src/PHPUnit/DataProviders/EnumCase.php @@ -66,7 +66,7 @@ public static function cases(string $enumFQCN): iterable { foreach (new ReflectionEnum($enumFQCN)->getCases() as $case) { // @phpstan-ignore generator.valueType - yield "$enumFQCN::$case->name" => [ + yield "{$enumFQCN}::{$case->name}" => [ new self($case->getValue(), ...$enumFQCN::cases()), ]; } @@ -79,7 +79,7 @@ public static function cases(string $enumFQCN): iterable public static function options(UnitEnum ...$options): iterable { foreach ($options as $case) { - yield "$case->name" => [new self($case, ...$options)]; + yield "{$case->name}" => [new self($case, ...$options)]; } } diff --git a/src/Saloon/Constraints/WasSent.php b/src/Saloon/Constraints/WasSent.php index 583fae0..480e8ed 100644 --- a/src/Saloon/Constraints/WasSent.php +++ b/src/Saloon/Constraints/WasSent.php @@ -132,7 +132,7 @@ protected function failureDescription(mixed $other): string $message = parent::failureDescription($other); if ($this->times !== null) { - $message .= " $this->times time(s)"; + $message .= " {$this->times} time(s)"; } $message .= match (true) { diff --git a/src/Saloon/Constraints/WasSentTest.php b/src/Saloon/Constraints/WasSentTest.php index a264e53..2b7d347 100644 --- a/src/Saloon/Constraints/WasSentTest.php +++ b/src/Saloon/Constraints/WasSentTest.php @@ -186,7 +186,7 @@ public function itFailsWhenSentButNotGivenTimes(QuantableConstraint $quantise): $quantise->applyTo(static fn () => $connector->send(new FakeRequest())); $this->expectException(ExpectationFailedException::class); - $this->expectExceptionMessage("was sent $quantise->expected time(s)."); + $this->expectExceptionMessage("was sent {$quantise->expected} time(s)."); $this->assertThat(FakeRequest::class, new WasSent($connector)->times($quantise->expected)); } @@ -210,7 +210,7 @@ public function itFailsWhenSentWithGivenConstrainsButNotGivenTimes(QuantableCons $quantise->applyTo(static fn () => $connector->send(new FakeRequest())); $this->expectException(ExpectationFailedException::class); - $this->expectExceptionMessage("was sent $quantise->expected time(s)"); + $this->expectExceptionMessage("was sent {$quantise->expected} time(s)"); $this->assertThat(FakeRequest::class, new WasSent($connector)->times($quantise->expected)->withConstraints( new Callback(static fn () => true), @@ -225,7 +225,7 @@ public function itFailsWhenSentGivenTimesButNotWithGivenConstrains(QuantableCons $quantise->applyTo(static fn () => $connector->send(new FakeRequest())); $this->expectException(ExpectationFailedException::class); - $this->expectExceptionMessage("was sent $quantise->expected time(s) with given constraints."); + $this->expectExceptionMessage("was sent {$quantise->expected} time(s) with given constraints."); $this->assertThat(FakeRequest::class, new WasSent($connector)->times($quantise->expected)->withConstraints( new Callback(static fn () => false), From a020a5b3baf933cc129bab93f95d5138bf585c87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Re=CC=81mi=20Pelhate?= Date: Thu, 4 Jun 2026 10:43:44 +0200 Subject: [PATCH 04/31] Mago fix prefer-arrow-function --- .../Objects/DeriveConstraintsFromObjectUsingReflection.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PHPUnit/Constraint/Objects/DeriveConstraintsFromObjectUsingReflection.php b/src/PHPUnit/Constraint/Objects/DeriveConstraintsFromObjectUsingReflection.php index f2c873d..0a3b9b0 100644 --- a/src/PHPUnit/Constraint/Objects/DeriveConstraintsFromObjectUsingReflection.php +++ b/src/PHPUnit/Constraint/Objects/DeriveConstraintsFromObjectUsingReflection.php @@ -18,8 +18,8 @@ */ public function __invoke(object $object): array { - return array_map(static function (ReflectionProperty $property) use ($object): Constraint { - return new PropertyValue($property->name, new IsEqual($property->getValue($object))); - }, new ReflectionClass($object)->getProperties(ReflectionProperty::IS_PUBLIC)); + return array_map(static fn (ReflectionProperty $property): PropertyValue => ( + new PropertyValue($property->name, new IsEqual($property->getValue($object))) + ), new ReflectionClass($object)->getProperties(ReflectionProperty::IS_PUBLIC)); } } From 50cf726105ecedbc73af5695578f2beaef07566f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Re=CC=81mi=20Pelhate?= Date: Thu, 4 Jun 2026 10:53:19 +0200 Subject: [PATCH 05/31] Mago fix no-shorthand-ternary --- .../Constraint/Objects/DerivesConstraintsFromObjects.php | 2 +- src/Saloon/Constraints/WasSent.php | 2 +- src/Saloon/DataProviders/FakeResponse.php | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/PHPUnit/Constraint/Objects/DerivesConstraintsFromObjects.php b/src/PHPUnit/Constraint/Objects/DerivesConstraintsFromObjects.php index 3254e37..f722609 100644 --- a/src/PHPUnit/Constraint/Objects/DerivesConstraintsFromObjects.php +++ b/src/PHPUnit/Constraint/Objects/DerivesConstraintsFromObjects.php @@ -30,7 +30,7 @@ public function givenOrDerivedObjectConstraints(string|object $expected): array return []; } - return (self::$deriveConstraintsFromObject ?: new DeriveConstraintsFromObjectUsingReflection())($expected); + return (self::$deriveConstraintsFromObject ?? new DeriveConstraintsFromObjectUsingReflection())($expected); } public static function deriveConstraintsFromObjectUsing( diff --git a/src/Saloon/Constraints/WasSent.php b/src/Saloon/Constraints/WasSent.php index 480e8ed..a5677ec 100644 --- a/src/Saloon/Constraints/WasSent.php +++ b/src/Saloon/Constraints/WasSent.php @@ -35,7 +35,7 @@ public function __construct( public readonly ?int $times = null, Constraint ...$constraints, ) { - $this->client = $connector->getMockClient() ?: MockClient::getGlobal() ?: throw new LogicException( + $this->client = $connector->getMockClient() ?? MockClient::getGlobal() ?? throw new LogicException( 'Missing either a global or connector specific ' . MockClient::class . '.', ); $this->objectConstraints = $constraints; diff --git a/src/Saloon/DataProviders/FakeResponse.php b/src/Saloon/DataProviders/FakeResponse.php index 93f34ef..d6cb906 100644 --- a/src/Saloon/DataProviders/FakeResponse.php +++ b/src/Saloon/DataProviders/FakeResponse.php @@ -67,11 +67,11 @@ public function __invoke(string $requestFQCN, ?Connector $connector = null): voi $client = match ($connector) { // When not given a connector instance, we should use the global // MockClient to fake responses for all connectors... - null => MockClient::getGlobal() ?: MockClient::global(), + null => MockClient::getGlobal() ?? MockClient::global(), // When given a connector instance, we should use its specific MockClient // to only fake responses for that specific connector instance... - default => $connector->getMockClient() ?: new MockClient(), + default => $connector->getMockClient() ?? new MockClient(), }; $client->addResponses([ From 5d9a5b45dfd9f045095ee2a09b66c9ab779a28c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Re=CC=81mi=20Pelhate?= Date: Thu, 4 Jun 2026 11:06:38 +0200 Subject: [PATCH 06/31] Mago config too-many-methods --- mago.toml | 4 ++++ src/Factories/ImmutableFactory.php | 1 + 2 files changed, 5 insertions(+) diff --git a/mago.toml b/mago.toml index 733499e..849007a 100644 --- a/mago.toml +++ b/mago.toml @@ -14,3 +14,7 @@ literal-separator = true [formatter] preset = "psr-12" + +[linter.rules] +no-boolean-flag-parameter = { enabled = false } +too-many-methods = { exclude = ["src/**/*Test.php"] } diff --git a/src/Factories/ImmutableFactory.php b/src/Factories/ImmutableFactory.php index 40570dd..8934ed4 100644 --- a/src/Factories/ImmutableFactory.php +++ b/src/Factories/ImmutableFactory.php @@ -14,6 +14,7 @@ /** * @template TClass of object + * @mago-expect lint:too-many-methods */ abstract class ImmutableFactory { From b38a44724c61ab2cf1c1d20dda564b63b3acd76b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Re=CC=81mi=20Pelhate?= Date: Thu, 4 Jun 2026 11:13:59 +0200 Subject: [PATCH 07/31] Mago fix literal-named-argument --- mago.toml | 1 + src/PHPUnit/DataProviders/EnumCase.php | 4 ++-- src/PHPUnit/DataProviders/QuantableConstraint.php | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/mago.toml b/mago.toml index 849007a..1439ffe 100644 --- a/mago.toml +++ b/mago.toml @@ -18,3 +18,4 @@ preset = "psr-12" [linter.rules] no-boolean-flag-parameter = { enabled = false } too-many-methods = { exclude = ["src/**/*Test.php"] } +literal-named-argument = { exclude = ["src/**/*Test.php"] } diff --git a/src/PHPUnit/DataProviders/EnumCase.php b/src/PHPUnit/DataProviders/EnumCase.php index 9ffc53e..7af100a 100644 --- a/src/PHPUnit/DataProviders/EnumCase.php +++ b/src/PHPUnit/DataProviders/EnumCase.php @@ -34,7 +34,7 @@ public function __construct( public UnitEnum $instance, UnitEnum ...$options, ) { - in_array($instance, $options, true) or throw new ValueError('Options should contain the given instance.'); + in_array($instance, $options, strict: true) or throw new ValueError('Options should contain the given instance.'); foreach ($options as $option) { $option::class === $instance::class or throw new ValueError( @@ -92,7 +92,7 @@ public static function except(string $enumFQCN, UnitEnum ...$except): iterable $options = array_map(static function (ReflectionEnumUnitCase $reflection) use ($except): ?UnitEnum { $case = $reflection->getValue(); - return match (in_array($case, $except, true)) { + return match (in_array($case, $except, strict: true)) { true => null, false => $case, }; diff --git a/src/PHPUnit/DataProviders/QuantableConstraint.php b/src/PHPUnit/DataProviders/QuantableConstraint.php index 7f9fd21..b54b4c3 100644 --- a/src/PHPUnit/DataProviders/QuantableConstraint.php +++ b/src/PHPUnit/DataProviders/QuantableConstraint.php @@ -53,7 +53,7 @@ public static function cases(): iterable */ public static function atLeastOnce(): iterable { - yield 'Multiple times' => [new self('times', random_int(2, 10))]; + yield 'Multiple times' => [new self('times', random_int(2, max: 10))]; yield 'Once' => [new self('once', 1)]; } From febaf69b22b98a13055518a603327befac078f12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Re=CC=81mi=20Pelhate?= Date: Thu, 4 Jun 2026 11:14:52 +0200 Subject: [PATCH 08/31] Mago fix readable-literal --- src/Laravel/Constraint/Eloquent/ModelComparatorTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Laravel/Constraint/Eloquent/ModelComparatorTest.php b/src/Laravel/Constraint/Eloquent/ModelComparatorTest.php index 0d5c82a..c83b05f 100644 --- a/src/Laravel/Constraint/Eloquent/ModelComparatorTest.php +++ b/src/Laravel/Constraint/Eloquent/ModelComparatorTest.php @@ -123,7 +123,7 @@ public function itPassesWhenEqual(Model $expected, Model $actual): void private static function model(string $table, string $connection, string $id = ''): Model { - $id ??= new Randomizer()->getInt(1, 10000000000); + $id ??= new Randomizer()->getInt(1, 10_000_000_000); $model = new class(compact('id')) extends Model { protected $fillable = ['id']; protected $keyType = 'string'; From 66eb8c9fcf7e21c185ae3aa126e8cd44789571fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Re=CC=81mi=20Pelhate?= Date: Thu, 4 Jun 2026 11:17:54 +0200 Subject: [PATCH 09/31] Mago fix no-else-clause --- src/GraphQL/Constraints/HasErrorOnPath.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/GraphQL/Constraints/HasErrorOnPath.php b/src/GraphQL/Constraints/HasErrorOnPath.php index 2ad88ca..bfaa125 100644 --- a/src/GraphQL/Constraints/HasErrorOnPath.php +++ b/src/GraphQL/Constraints/HasErrorOnPath.php @@ -33,9 +33,11 @@ public static function resolveResponseUsing(?callable $resolveResponseUsing): vo { if ($resolveResponseUsing === null) { self::$responseResolvers = []; - } else { - self::$responseResolvers[] = $resolveResponseUsing; + + return; } + + self::$responseResolvers[] = $resolveResponseUsing; } public function authentication(): self From 2a94591f8910407bd2cfd947428c3bb73a78c61f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Re=CC=81mi=20Pelhate?= Date: Thu, 4 Jun 2026 11:18:53 +0200 Subject: [PATCH 10/31] Mago fix no-empty-comment --- src/Laravel/Doubles/Events/DummyListener.php | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/Laravel/Doubles/Events/DummyListener.php b/src/Laravel/Doubles/Events/DummyListener.php index 43491d6..54d0bf0 100644 --- a/src/Laravel/Doubles/Events/DummyListener.php +++ b/src/Laravel/Doubles/Events/DummyListener.php @@ -9,13 +9,6 @@ */ final readonly class DummyListener { - public function __invoke(mixed ...$arguments): void - { - // - } - - public function handle(): void - { - // - } + public function __invoke(mixed ...$arguments): void {} + public function handle(): void {} } From 1a185cfa58717da68095a0df20d775f37e6d1937 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Re=CC=81mi=20Pelhate?= Date: Thu, 4 Jun 2026 11:36:07 +0200 Subject: [PATCH 11/31] Run mago lint in static-analysis workflow --- .github/workflows/static-analysis.yml | 25 +++++-------------------- composer.json | 1 + 2 files changed, 6 insertions(+), 20 deletions(-) diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index a0ee0bf..ff71040 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -5,30 +5,15 @@ on: branches: ['main'] jobs: - phpstan: + mago: runs-on: ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # https://github.com/actions/checkout/releases/tag/v6.0.2 - uses: shivammathur/setup-php@7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc # https://github.com/shivammathur/setup-php/releases/tag/2.37.1 with: - php-version: 8.4 + php-version: 8.5 extensions: -pdo_mysql, -mysqli - run: composer update --prefer-stable --prefer-dist --no-interaction - - run: composer phpstan - - php-cs-fixer: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # https://github.com/actions/checkout/releases/tag/v6.0.2 - with: - ref: ${{ github.head_ref }} - - name: 'Run PHP CS fixer' - uses: ./.github/actions/php-cs-fixer - with: - workspace: ${{ github.workspace }} - args: --config=.php-cs-fixer.dist.php --allow-risky=yes - github-token: ${{ secrets.GITHUB_TOKEN }} - - name: 'Commit CS fixes' - uses: craftzing/git-auto-commit-action@778341af668090896ca464160c2def5d1d1a3eb0 - with: - commit_message: Fix code style violations + - run: composer mago:lint + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/composer.json b/composer.json index 7b42581..88a634c 100644 --- a/composer.json +++ b/composer.json @@ -65,6 +65,7 @@ "prefer-stable": true, "scripts": { "mago": "vendor/bin/mago", + "mago:lint": "vendor/bin/mago --colors always lint --minimum-fail-level warning", "cs:check": "PHP_CS_FIXER_IGNORE_ENV=1 vendor/bin/php-cs-fixer fix --verbose --dry-run", "cs:fix": "PHP_CS_FIXER_IGNORE_ENV=1 vendor/bin/php-cs-fixer fix --verbose", "phpstan": "vendor/bin/phpstan analyse --memory-limit=2G --ansi", From 4b2d696053486e18118ddb469986579382f2f3ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Re=CC=81mi=20Pelhate?= Date: Thu, 4 Jun 2026 14:24:52 +0200 Subject: [PATCH 12/31] Mago fix formatting according to PER-CS --- mago.toml | 8 ++ src/Factories/ImmutableFactory.php | 6 +- src/Factories/ImmutableFactoryTest.php | 33 ++----- src/Factories/InstanceFactory.php | 1 - src/Factories/InstanceFactoryTest.php | 9 +- src/GraphQL/Constraints/HasErrorOnPath.php | 8 +- .../Constraints/HasErrorOnPathTest.php | 10 +-- src/Laravel/Constraint/Bus/HasHandler.php | 18 ++-- .../Constraint/Bus/RequiresBusFake.php | 8 +- src/Laravel/Constraint/Bus/WasDispatched.php | 2 +- .../Constraint/Bus/WasDispatchedTest.php | 47 +++++----- src/Laravel/Constraint/Bus/WasHandled.php | 2 +- src/Laravel/Constraint/Bus/WasHandledTest.php | 88 +++++++++++-------- .../Bus/WithoutBusMiddlewareTest.php | 2 +- .../Constraint/Eloquent/ModelComparator.php | 16 ++-- .../Eloquent/ModelComparatorTest.php | 2 +- src/Laravel/Constraint/Events/HasListener.php | 14 +-- .../Constraint/Events/HasListenerTest.php | 2 +- .../Constraint/Events/RequiresEventFake.php | 8 +- .../Constraint/Events/WasDispatched.php | 2 +- .../Constraint/Events/WasDispatchedTest.php | 41 +++++---- .../Constraint/Scheduling/IsScheduled.php | 11 +-- src/Laravel/Doubles/Events/DummyListener.php | 9 +- src/Laravel/ServiceProvider.php | 2 +- .../Constraint/Callables/WasCalled.php | 8 +- .../Constraint/Callables/WasCalledTest.php | 15 ++-- .../DeriveConstraintsFromObjectUsingFakes.php | 4 +- ...veConstraintsFromObjectUsingReflection.php | 4 +- ...nstraintsFromObjectUsingReflectionTest.php | 15 ++-- .../Objects/DerivesConstraintsFromObjects.php | 2 +- .../Constraint/Objects/PropertyValue.php | 4 +- .../Constraint/Objects/PropertyValueTest.php | 7 +- .../ProvidesAdditionalFailureDescription.php | 4 +- src/PHPUnit/Constraint/Quantable.php | 2 + src/PHPUnit/DataProviders/EnumCase.php | 23 +++-- src/PHPUnit/DataProviders/EnumCaseTest.php | 2 +- .../DataProviders/QuantableConstraintTest.php | 12 +-- src/PHPUnit/Doubles/SpyCallableTest.php | 5 +- src/Saloon/Constraints/WasSent.php | 33 ++++--- src/Saloon/Constraints/WasSentTest.php | 41 +++++---- src/Saloon/DataProviders/FakeResponse.php | 1 - src/Saloon/DataProviders/FakeResponseTest.php | 29 +++--- 42 files changed, 307 insertions(+), 253 deletions(-) diff --git a/mago.toml b/mago.toml index 1439ffe..f0dffbf 100644 --- a/mago.toml +++ b/mago.toml @@ -14,6 +14,14 @@ literal-separator = true [formatter] preset = "psr-12" +print-width = 9999 # Horizontal limits are considered a guideline, not a requirement +space-around-assignment-in-declare = false +inline-empty-constructor-braces = true +trailing-comma = true +preserve-breaking-argument-list = true +preserve-breaking-parameter-list = true +preserve-breaking-array-like = true +preserve-breaking-attribute-list = true [linter.rules] no-boolean-flag-parameter = { enabled = false } diff --git a/src/Factories/ImmutableFactory.php b/src/Factories/ImmutableFactory.php index 8934ed4..b553ef1 100644 --- a/src/Factories/ImmutableFactory.php +++ b/src/Factories/ImmutableFactory.php @@ -65,7 +65,7 @@ private function resolveValue(mixed $value): mixed return array_map($this->resolveValue(...), iterator_to_array($value)); } - if (! $value instanceof self) { + if (!$value instanceof self) { return $value; } @@ -103,7 +103,7 @@ public function rawMany(array $attributes = []): array */ public function rawCollection(array $attributes = []): Collection { - return Collection::times($this->count, fn (): array => $this->raw($attributes)); + return Collection::times($this->count, fn(): array => $this->raw($attributes)); } /** @@ -130,6 +130,6 @@ public function makeMany(array $attributes = []): array */ public function makeCollection(array $attributes = []): Collection { - return Collection::times($this->count, fn (): mixed => $this->makeOne($attributes)); + return Collection::times($this->count, fn(): mixed => $this->makeOne($attributes)); } } diff --git a/src/Factories/ImmutableFactoryTest.php b/src/Factories/ImmutableFactoryTest.php index 20f0693..9328cd6 100644 --- a/src/Factories/ImmutableFactoryTest.php +++ b/src/Factories/ImmutableFactoryTest.php @@ -25,8 +25,7 @@ final class ImmutableFactoryTest extends TestCase use Conditionable; private ImmutableFactory $instance { - get => $this->instance ??= new class extends ImmutableFactory - { + get => $this->instance ??= new class extends ImmutableFactory { public function definition(): array { return [ @@ -164,9 +163,7 @@ public static function state(): iterable #[DataProvider('state')] public function itCanReturnRawAttributesWithState(array $attributes, array $state, array $expected): void { - $result = $this->instance - ->state($state) - ->raw($attributes); + $result = $this->instance->state($state)->raw($attributes); collect($expected)->each(function (mixed $value, string $attribute) use ($result): void { $this->assertSame($value, $result[$attribute]); @@ -178,10 +175,7 @@ public function itCanReturnRawAttributesWithState(array $attributes, array $stat #[DataProvider('state')] public function itCanReturnManyRawAttributesWithState(array $attributes, array $state, array $expected): void { - $results = $this->instance - ->times(random_int(1, 10)) - ->state($state) - ->rawMany($attributes); + $results = $this->instance->times(random_int(1, 10))->state($state)->rawMany($attributes); collect($results)->each(function (array $result) use ($expected): void { collect($expected)->each(function (mixed $value, string $attribute) use ($result): void { @@ -195,10 +189,7 @@ public function itCanReturnManyRawAttributesWithState(array $attributes, array $ #[DataProvider('state')] public function itCanReturnRawAttributesCollectionsWithState(array $attributes, array $state, array $expected): void { - $results = $this->instance - ->times(random_int(1, 10)) - ->state($state) - ->rawCollection($attributes); + $results = $this->instance->times(random_int(1, 10))->state($state)->rawCollection($attributes); $results->each(function (array $result) use ($expected): void { collect($expected)->each(function (mixed $value, string $attribute) use ($result): void { @@ -212,9 +203,7 @@ public function itCanReturnRawAttributesCollectionsWithState(array $attributes, #[DataProvider('state')] public function itCanMakeOneWithState(array $attributes, array $state, array $expected): void { - $result = $this->instance - ->state($state) - ->makeOne($attributes); + $result = $this->instance->state($state)->makeOne($attributes); $this->assertInstanceOf(stdClass::class, $result); collect($expected)->each(function (mixed $value, string $attribute) use ($result): void { @@ -227,10 +216,7 @@ public function itCanMakeOneWithState(array $attributes, array $state, array $ex #[DataProvider('state')] public function itCanMakeManyWithState(array $attributes, array $state, array $expected): void { - $results = $this->instance - ->times(random_int(1, 10)) - ->state($state) - ->makeMany($attributes); + $results = $this->instance->times(random_int(1, 10))->state($state)->makeMany($attributes); $this->assertContainsOnlyInstancesOf(stdClass::class, $results); collect($results)->each(function (stdClass $result) use ($expected): void { @@ -245,10 +231,7 @@ public function itCanMakeManyWithState(array $attributes, array $state, array $e #[DataProvider('state')] public function itCanMakeCollectionsWithState(array $attributes, array $state, array $expected): void { - $results = $this->instance - ->times(random_int(1, 10)) - ->state($state) - ->makeCollection($attributes); + $results = $this->instance->times(random_int(1, 10))->state($state)->makeCollection($attributes); $this->assertContainsOnlyInstancesOf(stdClass::class, $results); $results->each(function (stdClass $result) use ($expected): void { @@ -262,7 +245,7 @@ public function itCanMakeCollectionsWithState(array $attributes, array $state, a public static function nestedFactories(): iterable { yield [ - static fn (ImmutableFactory $instance): ImmutableFactory => $instance->state([ + static fn(ImmutableFactory $instance): ImmutableFactory => $instance->state([ 'nested' => $instance->state([ 'deeplyNested' => $instance->state(['resolved' => true]), ]), diff --git a/src/Factories/InstanceFactory.php b/src/Factories/InstanceFactory.php index 21b414d..a9de1ab 100644 --- a/src/Factories/InstanceFactory.php +++ b/src/Factories/InstanceFactory.php @@ -32,4 +32,3 @@ public function make(array $attributes): object return $instance; } } - diff --git a/src/Factories/InstanceFactoryTest.php b/src/Factories/InstanceFactoryTest.php index e8ad155..321533e 100644 --- a/src/Factories/InstanceFactoryTest.php +++ b/src/Factories/InstanceFactoryTest.php @@ -14,8 +14,7 @@ final class InstanceFactoryTest extends TestCase #[Test] public function itFailsWhenConstructingInstancesWithPropertiesThatDoNotExist(): void { - $subject = new readonly class('some-id') - { + $subject = new readonly class('some-id') { public function __construct( public string $id, ) {} @@ -34,8 +33,7 @@ public function itCanConstructInstances(): void 'protected' => 'Protected', 'private' => 'Private', ]; - $subject = new readonly class(...$attributes) - { + $subject = new readonly class(...$attributes) { public function __construct( public string $public, protected string $protected, @@ -63,8 +61,7 @@ public function private(): string #[Test] public function itConstructsInstancesWithUninitializedPropertiesWhenNotProvidingAttributes(): void { - $subject = new readonly class('some-id') - { + $subject = new readonly class('some-id') { public function __construct( public string $id, ) {} diff --git a/src/GraphQL/Constraints/HasErrorOnPath.php b/src/GraphQL/Constraints/HasErrorOnPath.php index bfaa125..9b0a0eb 100644 --- a/src/GraphQL/Constraints/HasErrorOnPath.php +++ b/src/GraphQL/Constraints/HasErrorOnPath.php @@ -64,9 +64,11 @@ protected function matches(mixed $other): bool default => $this->resolveResponse($other), }; - is_array($response) or throw new InvalidArgumentException( - self::class . ' can only be evaluated for iterable values, got ' . gettype($other) . '.', - ); + if (is_array($response) === false) { + throw new InvalidArgumentException( + self::class . ' can only be evaluated for iterable values, got ' . gettype($other) . '.', + ); + } foreach ($response['errors'] ?? [] as $error) { $path = implode('.', $error['path'] ?? ''); diff --git a/src/GraphQL/Constraints/HasErrorOnPathTest.php b/src/GraphQL/Constraints/HasErrorOnPathTest.php index 745c38c..90f7ec6 100644 --- a/src/GraphQL/Constraints/HasErrorOnPathTest.php +++ b/src/GraphQL/Constraints/HasErrorOnPathTest.php @@ -194,9 +194,8 @@ public function itPassesWhenErrorOnPathIsOfGivenCategory(string $path, string $c #[Test] public function itFailsWhenResponseCouldNotBeResolvedForSubject(): void { - HasErrorOnPath::resolveResponseUsing(static fn (Arrayable $subject): array => $subject->toArray()); - $response = new readonly class - { + HasErrorOnPath::resolveResponseUsing(static fn(Arrayable $subject): array => $subject->toArray()); + $response = new readonly class { public function toArray(): array { return []; @@ -212,12 +211,11 @@ public function toArray(): array #[Test] public function itPassesResponseCouldBeResolvedForSubject(): void { - HasErrorOnPath::resolveResponseUsing(static fn (Arrayable $subject): array => $subject->toArray()); + HasErrorOnPath::resolveResponseUsing(static fn(Arrayable $subject): array => $subject->toArray()); $category = Factory::create()->word(); $path = 'somePath'; - $response = new readonly class ($path, $category) implements Arrayable - { + $response = new readonly class($path, $category) implements Arrayable { public function __construct( private string $path, private string $category, diff --git a/src/Laravel/Constraint/Bus/HasHandler.php b/src/Laravel/Constraint/Bus/HasHandler.php index 7e37c1d..c542b73 100644 --- a/src/Laravel/Constraint/Bus/HasHandler.php +++ b/src/Laravel/Constraint/Bus/HasHandler.php @@ -30,12 +30,18 @@ public function __construct( protected function matches(mixed $other): bool { - is_string($other) or throw new InvalidArgumentException( - self::class . ' can only be evaluated for strings, got ' . gettype($other) . '.', - ); - class_exists($other) or throw new InvalidArgumentException( - self::class . " can only be evaluated for existing classes, got {$other}.", - ); + if (is_string($other) === false) { + throw new InvalidArgumentException( + self::class . ' can only be evaluated for strings, got ' . gettype($other) . '.', + ); + } + + if (class_exists($other) === false) { + throw new InvalidArgumentException( + self::class . " can only be evaluated for existing classes, got {$other}.", + ); + } + $message = new ReflectionClass($other)->newInstanceWithoutConstructor(); $actualHandler = $this->bus->getCommandHandler($message); diff --git a/src/Laravel/Constraint/Bus/RequiresBusFake.php b/src/Laravel/Constraint/Bus/RequiresBusFake.php index da2e119..359ee1b 100644 --- a/src/Laravel/Constraint/Bus/RequiresBusFake.php +++ b/src/Laravel/Constraint/Bus/RequiresBusFake.php @@ -24,9 +24,11 @@ private function resolveBusFake(): BusFake { $bus = Bus::getFacadeRoot(); - $bus instanceof BusFake or throw new LogicException( - 'To use the ' . self::class . ' constraint, make sure to call ' . self::class . '::spy() first.', - ); + if (!$bus instanceof BusFake) { + throw new LogicException( + 'To use the ' . self::class . ' constraint, make sure to call ' . self::class . '::spy() first.', + ); + } return $bus; } diff --git a/src/Laravel/Constraint/Bus/WasDispatched.php b/src/Laravel/Constraint/Bus/WasDispatched.php index 344697e..6f8cd13 100644 --- a/src/Laravel/Constraint/Bus/WasDispatched.php +++ b/src/Laravel/Constraint/Bus/WasDispatched.php @@ -68,7 +68,7 @@ protected function matches(mixed $other): bool $matchingDispatchedCommands = $this->busFake->dispatched($commandName); $dispatchedEventsMatchingConstraints = $matchingDispatchedCommands->filter( - fn (object $dispatchedCommand): bool => $this->matchesCommandConstraints( + fn(object $dispatchedCommand): bool => $this->matchesCommandConstraints( $other, $dispatchedCommand, // When the command was dispatched exactly once, we should add all nested expectation failures to the diff --git a/src/Laravel/Constraint/Bus/WasDispatchedTest.php b/src/Laravel/Constraint/Bus/WasDispatchedTest.php index 4a0a2a3..537074c 100644 --- a/src/Laravel/Constraint/Bus/WasDispatchedTest.php +++ b/src/Laravel/Constraint/Bus/WasDispatchedTest.php @@ -111,7 +111,7 @@ public function itPassesWhenDispatched(QuantableConstraint $quantise): void WasDispatched::spy(); $command = new stdClass(); - $quantise->applyTo(static fn () => Bus::dispatch($command)); + $quantise->applyTo(static fn() => Bus::dispatch($command)); $this->assertThat($command::class, $quantise(new WasDispatched())); } @@ -127,7 +127,7 @@ public function itFailsWhenDispatchedButNotWithGivenCommandConstraints(): void $this->expectExceptionMessage('command was dispatched with given command constraints.'); $this->assertThat($command, new WasDispatched()->withConstraints( - new Callback(static fn () => false), + new Callback(static fn() => false), )); } @@ -140,7 +140,7 @@ public function itPassesWhenDispatchedWithGivenCommandConstraints(): void Bus::dispatch($command); $this->assertThat($command, new WasDispatched()->withConstraints( - new Callback(static fn () => true), + new Callback(static fn() => true), )); } @@ -150,7 +150,7 @@ public function itFailsWhenDispatchedButNotGivenTimes(QuantableConstraint $quant { WasDispatched::spy(); $command = new stdClass(); - $quantise->applyTo(static fn () => Bus::dispatch($command)); + $quantise->applyTo(static fn() => Bus::dispatch($command)); $this->expectException(ExpectationFailedException::class); $this->expectExceptionMessage("command was dispatched {$quantise->expected} time(s)."); @@ -165,7 +165,7 @@ public function itPassesWhenDispatchedGivenTimes(QuantableConstraint $quantise): WasDispatched::spy(); $command = new stdClass(); - $quantise->applyTo(static fn () => Bus::dispatch($command)); + $quantise->applyTo(static fn() => Bus::dispatch($command)); $this->assertThat($command::class, $quantise(new WasDispatched())); } @@ -177,14 +177,16 @@ public function itFailsWhenDispatchedWithGivenCommandConstrainsButNotGivenTimes( ): void { WasDispatched::spy(); $command = new stdClass(); - $quantise->applyTo(static fn () => Bus::dispatch($command)); + $quantise->applyTo(static fn() => Bus::dispatch($command)); $this->expectException(ExpectationFailedException::class); $this->expectExceptionMessage("command was dispatched {$quantise->expected} time(s)"); - $this->assertThat($command, new WasDispatched()->times($quantise->expected)->withConstraints( - new Callback(static fn () => true), - )); + $this->assertThat($command, new WasDispatched() + ->times($quantise->expected) + ->withConstraints( + new Callback(static fn() => true), + )); } #[Test] @@ -194,16 +196,18 @@ public function itFailsWhenDispatchedGivenTimesButNotWithGivenCommandConstrains( ): void { WasDispatched::spy(); $command = new stdClass(); - $quantise->applyTo(static fn () => Bus::dispatch($command)); + $quantise->applyTo(static fn() => Bus::dispatch($command)); $this->expectException(ExpectationFailedException::class); $this->expectExceptionMessage( "command was dispatched {$quantise->expected} time(s) with given command constraints.", ); - $this->assertThat($command, new WasDispatched()->times($quantise->expected)->withConstraints( - new Callback(static fn () => false), - )); + $this->assertThat($command, new WasDispatched() + ->times($quantise->expected) + ->withConstraints( + new Callback(static fn() => false), + )); } #[Test] @@ -214,19 +218,21 @@ public function itPassesWhenDispatchedGivenTimesWithGivenCommandConstraints( WasDispatched::spy(); $command = new stdClass(); - $quantise->applyTo(static fn () => Bus::dispatch($command)); + $quantise->applyTo(static fn() => Bus::dispatch($command)); - $this->assertThat($command, $quantise(new WasDispatched()->withConstraints( - new Callback(static fn () => true), - ))); + $this->assertThat( + $command, + $quantise(new WasDispatched()->withConstraints( + new Callback(static fn() => true), + )), + ); } #[Test] public function itCannotDeriveCommandConstraintsFromCommandStrings(): void { WasDispatched::spy(); - $command = new readonly class - { + $command = new readonly class { public function __construct( public string $first = 'first', ) {} @@ -241,8 +247,7 @@ public function __construct( public function itCanDeriveCommandConstraintsFromCommandObjects(): void { WasDispatched::spy(); - $command = new readonly class - { + $command = new readonly class { public function __construct( public string $first = 'first', ) {} diff --git a/src/Laravel/Constraint/Bus/WasHandled.php b/src/Laravel/Constraint/Bus/WasHandled.php index ec7ed4e..88a0f29 100644 --- a/src/Laravel/Constraint/Bus/WasHandled.php +++ b/src/Laravel/Constraint/Bus/WasHandled.php @@ -98,7 +98,7 @@ private function handler(object $command): SpyCallable { $handler = $this->bus->getCommandHandler($command); - if (! $handler instanceof SpyCallable) { + if (!$handler instanceof SpyCallable) { throw new LogicException( 'To use the ' . self::class . ' constraint, make sure to call ' . self::class . '::using() first.', ); diff --git a/src/Laravel/Constraint/Bus/WasHandledTest.php b/src/Laravel/Constraint/Bus/WasHandledTest.php index 19fd162..372d60b 100644 --- a/src/Laravel/Constraint/Bus/WasHandledTest.php +++ b/src/Laravel/Constraint/Bus/WasHandledTest.php @@ -36,10 +36,9 @@ public function resetDeriveConstraintsFromObjectUsing(): void public static function callableHandlers(): iterable { - yield 'Closure' => [static fn (stdClass $object): string => 'handled']; + yield 'Closure' => [static fn(stdClass $object): string => 'handled']; yield 'Invokable class' => [ - new readonly class - { + new readonly class { public function __invoke(stdClass $command): string { return 'handled'; @@ -101,7 +100,7 @@ public function itFailsWhenNotUsingGivenCallables(): void #[Test] public function itFailsWhenNotHandled(): void { - WasHandled::using(static fn (stdClass $command): string => 'handled', $this->app); + WasHandled::using(static fn(stdClass $command): string => 'handled', $this->app); $this->expectException(ExpectationFailedException::class); $this->expectExceptionMessage('command was handled.'); @@ -113,10 +112,10 @@ public function itFailsWhenNotHandled(): void #[DataProviderExternal(QuantableConstraint::class, 'cases')] public function itPassesWhenHandled(QuantableConstraint $quantise): void { - WasHandled::using(static fn (stdClass $command): string => 'handled', $this->app); + WasHandled::using(static fn(stdClass $command): string => 'handled', $this->app); $command = new stdClass(); - $quantise->applyTo(static fn () => Bus::dispatch($command)); + $quantise->applyTo(static fn() => Bus::dispatch($command)); $this->assertThat($command::class, $quantise(new WasHandled())); } @@ -124,7 +123,7 @@ public function itPassesWhenHandled(QuantableConstraint $quantise): void #[Test] public function itFailsWhenHandledButNotWithGivenCommandConstraints(): void { - WasHandled::using(static fn (stdClass $command): string => 'handled', $this->app); + WasHandled::using(static fn(stdClass $command): string => 'handled', $this->app); $command = new stdClass(); Bus::dispatch($command); @@ -132,20 +131,20 @@ public function itFailsWhenHandledButNotWithGivenCommandConstraints(): void $this->expectExceptionMessage('command was handled with given command constraints.'); $this->assertThat($command::class, new WasHandled()->withConstraints( - new Callback(static fn () => false), + new Callback(static fn() => false), )); } #[Test] public function itPassesWhenHandledWithGivenCommandConstraints(): void { - WasHandled::using(static fn (stdClass $command): string => 'handled', $this->app); + WasHandled::using(static fn(stdClass $command): string => 'handled', $this->app); $command = new stdClass(); Bus::dispatch($command); $this->assertThat($command::class, new WasHandled()->withConstraints( - new Callback(static fn () => true), + new Callback(static fn() => true), )); } @@ -153,9 +152,9 @@ public function itPassesWhenHandledWithGivenCommandConstraints(): void #[DataProviderExternal(QuantableConstraint::class, 'tooFewOrTooManyTimes')] public function itFailsWhenHandledButNotGivenTimes(QuantableConstraint $quantise): void { - WasHandled::using(static fn (stdClass $command): string => 'handled', $this->app); + WasHandled::using(static fn(stdClass $command): string => 'handled', $this->app); $command = new stdClass(); - $quantise->applyTo(static fn () => Bus::dispatch($command)); + $quantise->applyTo(static fn() => Bus::dispatch($command)); $this->expectException(ExpectationFailedException::class); $this->expectExceptionMessage("command was handled {$quantise->expected} time(s)."); @@ -167,10 +166,10 @@ public function itFailsWhenHandledButNotGivenTimes(QuantableConstraint $quantise #[DataProviderExternal(QuantableConstraint::class, 'cases')] public function itPassesWhenHandledGivenTimes(QuantableConstraint $quantise): void { - WasHandled::using(static fn (stdClass $command): string => 'handled', $this->app); + WasHandled::using(static fn(stdClass $command): string => 'handled', $this->app); $command = new stdClass(); - $quantise->applyTo(static fn () => Bus::dispatch($command)); + $quantise->applyTo(static fn() => Bus::dispatch($command)); $this->assertThat($command::class, $quantise(new WasHandled())); } @@ -180,16 +179,18 @@ public function itPassesWhenHandledGivenTimes(QuantableConstraint $quantise): vo public function itFailsWhenHandledWithGivenCommandConstrainsButNotGivenTimes( QuantableConstraint $quantise, ): void { - WasHandled::using(static fn (stdClass $command): string => 'handled', $this->app); + WasHandled::using(static fn(stdClass $command): string => 'handled', $this->app); $command = new stdClass(); - $quantise->applyTo(static fn () => Bus::dispatch($command)); + $quantise->applyTo(static fn() => Bus::dispatch($command)); $this->expectException(ExpectationFailedException::class); $this->expectExceptionMessage("command was handled {$quantise->expected} time(s)"); - $this->assertThat($command, new WasHandled()->times($quantise->expected)->withConstraints( - new Callback(static fn () => true), - )); + $this->assertThat($command, new WasHandled() + ->times($quantise->expected) + ->withConstraints( + new Callback(static fn() => true), + )); } #[Test] @@ -197,18 +198,20 @@ public function itFailsWhenHandledWithGivenCommandConstrainsButNotGivenTimes( public function itFailsWhenHandledGivenTimesButNotWithGivenCommandConstrains( QuantableConstraint $quantise, ): void { - WasHandled::using(static fn (stdClass $command): string => 'handled', $this->app); + WasHandled::using(static fn(stdClass $command): string => 'handled', $this->app); $command = new stdClass(); - $quantise->applyTo(static fn () => Bus::dispatch($command)); + $quantise->applyTo(static fn() => Bus::dispatch($command)); $this->expectException(ExpectationFailedException::class); $this->expectExceptionMessage( "command was handled {$quantise->expected} time(s) with given command constraints.", ); - $this->assertThat($command, new WasHandled()->times($quantise->expected)->withConstraints( - new Callback(static fn () => false), - )); + $this->assertThat($command, new WasHandled() + ->times($quantise->expected) + ->withConstraints( + new Callback(static fn() => false), + )); } #[Test] @@ -216,21 +219,23 @@ public function itFailsWhenHandledGivenTimesButNotWithGivenCommandConstrains( public function itPassesWhenHandledGivenTimesWithGivenCommandConstraints( QuantableConstraint $quantise, ): void { - WasHandled::using(static fn (stdClass $command): string => 'handled', $this->app); + WasHandled::using(static fn(stdClass $command): string => 'handled', $this->app); $command = new stdClass(); - $quantise->applyTo(static fn () => Bus::dispatch($command)); + $quantise->applyTo(static fn() => Bus::dispatch($command)); - $this->assertThat($command, $quantise(new WasHandled()->withConstraints( - new Callback(static fn () => true), - ))); + $this->assertThat( + $command, + $quantise(new WasHandled()->withConstraints( + new Callback(static fn() => true), + )), + ); } #[Test] public function itCannotDeriveCommandConstraintsFromCommandStrings(): void { - $command = new readonly class - { + $command = new readonly class { public function __construct( public string $first = 'first', ) {} @@ -244,8 +249,7 @@ public function __construct( #[Test] public function itCanDeriveCommandConstraintsFromCommandObjects(): void { - $command = new readonly class - { + $command = new readonly class { public function __construct( public string $first = 'first', ) {} @@ -274,7 +278,7 @@ public function itCanDeriveCommandConstraintsFromCommandObjectsUsingCustomImplem public function itFailsWhenHandledButNotWithDerivedCommandConstraints(): void { $command = new stdClass(); - WasHandled::using(static fn (stdClass $command): string => 'handled', $this->app); + WasHandled::using(static fn(stdClass $command): string => 'handled', $this->app); WasHandled::deriveConstraintsFromObjectUsing(DeriveConstraintsFromObjectUsingFakes::failingConstraints()); Bus::dispatch($command); @@ -288,7 +292,7 @@ public function itFailsWhenHandledButNotWithDerivedCommandConstraints(): void public function itPassesWhenDispatchedWithDerivedCommandConstraints(): void { $command = new stdClass(); - WasHandled::using(static fn (stdClass $command): string => 'handled', $this->app); + WasHandled::using(static fn(stdClass $command): string => 'handled', $this->app); WasHandled::deriveConstraintsFromObjectUsing(DeriveConstraintsFromObjectUsingFakes::passingConstraints()); Bus::dispatch($command); @@ -304,15 +308,23 @@ public function itDerivesConstraintsFromExpectedCommandsAndMatchesItAgainstActua $constraint = Spy::passing(); $deriveConstraints = new DeriveConstraintsFromObjectUsingFakes([$constraint]); WasHandled::deriveConstraintsFromObjectUsing($deriveConstraints); - WasHandled::using(static fn (stdClass $command): string => 'handled', $this->app); + WasHandled::using(static fn(stdClass $command): string => 'handled', $this->app); Bus::dispatch($actual); $this->assertThat($expected, new WasHandled()); $deriveConstraints->invoke->assert(new WasCalled()->withSame($expected)); - $deriveConstraints->invoke->assert(new WasCalled()->never()->withSame($actual)); + $deriveConstraints->invoke->assert( + new WasCalled() + ->never() + ->withSame($actual), + ); $constraint->matches->assert(new WasCalled()->withSame($actual)); - $constraint->matches->assert(new WasCalled()->never()->withSame($expected)); + $constraint->matches->assert( + new WasCalled() + ->never() + ->withSame($expected), + ); } private function command(array $properties): stdClass diff --git a/src/Laravel/Constraint/Bus/WithoutBusMiddlewareTest.php b/src/Laravel/Constraint/Bus/WithoutBusMiddlewareTest.php index e6d40d6..cc541ab 100644 --- a/src/Laravel/Constraint/Bus/WithoutBusMiddlewareTest.php +++ b/src/Laravel/Constraint/Bus/WithoutBusMiddlewareTest.php @@ -17,7 +17,7 @@ final class WithoutBusMiddlewareTest extends TestCase public function itCanRemoveBusMiddleware(): void { Bus::pipeThrough([ - static fn (mixed $command, mixed $next): mixed => throw new LogicException('This should not happen'), + static fn(mixed $command, mixed $next): mixed => throw new LogicException('This should not happen'), ]); $this->setUpWithoutBusMiddleware(); diff --git a/src/Laravel/Constraint/Eloquent/ModelComparator.php b/src/Laravel/Constraint/Eloquent/ModelComparator.php index e4ec90c..44f72ba 100644 --- a/src/Laravel/Constraint/Eloquent/ModelComparator.php +++ b/src/Laravel/Constraint/Eloquent/ModelComparator.php @@ -29,13 +29,15 @@ public function assertEquals( $expected instanceof Model or throw self::notInstanceOfModel('expected', $expected); $actual instanceof Model or throw self::notInstanceOfModel('actual', $actual); - $actual->is($expected) or throw new ComparisonFailure( - $expected, - $actual, - $this->serializeModelForException($expected), - $this->serializeModelForException($actual), - 'Failed asserting that two Eloquent models are equal.', - ); + if ($actual->isNot($expected)) { + throw new ComparisonFailure( + $expected, + $actual, + $this->serializeModelForException($expected), + $this->serializeModelForException($actual), + 'Failed asserting that two Eloquent models are equal.', + ); + } } private static function notInstanceOfModel(string $argumentName, mixed $value): AssertionError diff --git a/src/Laravel/Constraint/Eloquent/ModelComparatorTest.php b/src/Laravel/Constraint/Eloquent/ModelComparatorTest.php index c83b05f..753e9bb 100644 --- a/src/Laravel/Constraint/Eloquent/ModelComparatorTest.php +++ b/src/Laravel/Constraint/Eloquent/ModelComparatorTest.php @@ -124,7 +124,7 @@ public function itPassesWhenEqual(Model $expected, Model $actual): void private static function model(string $table, string $connection, string $id = ''): Model { $id ??= new Randomizer()->getInt(1, 10_000_000_000); - $model = new class(compact('id')) extends Model { + $model = new class(compact('id')) extends Model { protected $fillable = ['id']; protected $keyType = 'string'; }; diff --git a/src/Laravel/Constraint/Events/HasListener.php b/src/Laravel/Constraint/Events/HasListener.php index 91e242b..ac5cf8f 100644 --- a/src/Laravel/Constraint/Events/HasListener.php +++ b/src/Laravel/Constraint/Events/HasListener.php @@ -34,9 +34,9 @@ class_exists($listener) or throw new InvalidArgumentException("{$listener} is no }, public string $method = self::DEFAULT_METHOD { set(string $method) { - method_exists($this->listener, $method) or throw new InvalidArgumentException( - "Method {$this->listener}::{$method} does not exist.", - ); + if (method_exists($this->listener, $method) === false) { + throw new InvalidArgumentException("Method {$this->listener}::{$method} does not exist."); + } $this->method = $method; } @@ -68,9 +68,11 @@ public static function method(array $listen): self #[Override] protected function matches(mixed $other): bool { - is_string($other) or throw new InvalidArgumentException( - self::class . ' can only be evaluated for strings, got ' . gettype($other) . '.', - ); + if (is_string($other) === false) { + throw new InvalidArgumentException( + self::class . ' can only be evaluated for strings, got ' . gettype($other) . '.', + ); + } try { Event::assertListening($other, match ($this->method) { diff --git a/src/Laravel/Constraint/Events/HasListenerTest.php b/src/Laravel/Constraint/Events/HasListenerTest.php index 4b19c04..a562828 100644 --- a/src/Laravel/Constraint/Events/HasListenerTest.php +++ b/src/Laravel/Constraint/Events/HasListenerTest.php @@ -120,7 +120,7 @@ public function itCannotEvaluateValuesThatAreNotStrings(): void HasListener::class . ' can only be evaluated for strings', ); - $this->assertThat(new DummyEvent(), new HasListener(DummyListener::class)); + $this->assertThat(new DummyEvent(), new HasListener(DummyListener::class)); } #[Test] diff --git a/src/Laravel/Constraint/Events/RequiresEventFake.php b/src/Laravel/Constraint/Events/RequiresEventFake.php index afb4bfb..c3bc4ea 100644 --- a/src/Laravel/Constraint/Events/RequiresEventFake.php +++ b/src/Laravel/Constraint/Events/RequiresEventFake.php @@ -22,9 +22,11 @@ public static function spy(string ...$eventsToSpyOn): void private function resolveEventFake(): EventFake { - Event::isFake() or throw new LogicException( - 'To use the ' . self::class . ' constraint, make sure to call ' . self::class . '::spy() first.', - ); + if (Event::isFake() === false) { + throw new LogicException( + 'To use the ' . self::class . ' constraint, make sure to call ' . self::class . '::spy() first.', + ); + } return Event::getFacadeRoot(); } diff --git a/src/Laravel/Constraint/Events/WasDispatched.php b/src/Laravel/Constraint/Events/WasDispatched.php index 97d8bc0..eae4815 100644 --- a/src/Laravel/Constraint/Events/WasDispatched.php +++ b/src/Laravel/Constraint/Events/WasDispatched.php @@ -70,7 +70,7 @@ protected function matches(mixed $other): bool $dispatchedEventsMatchingConstraints = array_filter( $matchingDispatchedEvents, - fn (array $dispatchedEvent): bool => $this->matchesEventConstraints( + fn(array $dispatchedEvent): bool => $this->matchesEventConstraints( $other, $dispatchedEvent[0], // When the event was dispatched exactly once, we should add all nested expectation failures to the diff --git a/src/Laravel/Constraint/Events/WasDispatchedTest.php b/src/Laravel/Constraint/Events/WasDispatchedTest.php index 42c0fd8..623b1a7 100644 --- a/src/Laravel/Constraint/Events/WasDispatchedTest.php +++ b/src/Laravel/Constraint/Events/WasDispatchedTest.php @@ -111,7 +111,7 @@ public function itPassesWhenDispatched(QuantableConstraint $quantise): void WasDispatched::spy(); $event = 'some.event'; - $quantise->applyTo(static fn () => Event::dispatch($event)); + $quantise->applyTo(static fn() => Event::dispatch($event)); $this->assertThat($event, $quantise(new WasDispatched())); } @@ -127,7 +127,7 @@ public function itFailsWhenDispatchedButNotWithGivenEventConstraints(): void $this->expectExceptionMessage('event was dispatched with given event constraints.'); $this->assertThat($event, new WasDispatched()->withConstraints( - new Callback(static fn () => false), + new Callback(static fn() => false), )); } @@ -140,7 +140,7 @@ public function itPassesWhenDispatchedWithGivenEventConstraints(): void Event::dispatch($event); $this->assertThat($event, new WasDispatched()->withConstraints( - new Callback(static fn () => true), + new Callback(static fn() => true), )); } @@ -150,7 +150,7 @@ public function itFailsWhenDispatchedButNotGivenTimes(QuantableConstraint $quant { WasDispatched::spy(); $event = 'some.event'; - $quantise->applyTo(static fn () => Event::dispatch($event)); + $quantise->applyTo(static fn() => Event::dispatch($event)); $this->expectException(ExpectationFailedException::class); $this->expectExceptionMessage("event was dispatched {$quantise->expected} time(s)."); @@ -165,7 +165,7 @@ public function itPassesWhenDispatchedGivenTimes(QuantableConstraint $quantise): WasDispatched::spy(); $event = 'some.event'; - $quantise->applyTo(static fn () => Event::dispatch($event)); + $quantise->applyTo(static fn() => Event::dispatch($event)); $this->assertThat($event, $quantise(new WasDispatched())); } @@ -177,14 +177,16 @@ public function itFailsWhenDispatchedWithGivenEventConstrainsButNotGivenTimes( ): void { WasDispatched::spy(); $event = new DummyEvent('first', 'last'); - $quantise->applyTo(static fn () => Event::dispatch($event)); + $quantise->applyTo(static fn() => Event::dispatch($event)); $this->expectException(ExpectationFailedException::class); $this->expectExceptionMessage("event was dispatched {$quantise->expected} time(s)"); - $this->assertThat($event, new WasDispatched()->times($quantise->expected)->withConstraints( - new Callback(static fn () => true), - )); + $this->assertThat($event, new WasDispatched() + ->times($quantise->expected) + ->withConstraints( + new Callback(static fn() => true), + )); } #[Test] @@ -194,14 +196,16 @@ public function itFailsWhenDispatchedGivenTimesButNotWithGivenEventConstrains( ): void { WasDispatched::spy(); $event = new DummyEvent('first', 'last'); - $quantise->applyTo(static fn () => Event::dispatch($event)); + $quantise->applyTo(static fn() => Event::dispatch($event)); $this->expectException(ExpectationFailedException::class); $this->expectExceptionMessage("event was dispatched {$quantise->expected} time(s) with given event constraints."); - $this->assertThat($event, new WasDispatched()->times($quantise->expected)->withConstraints( - new Callback(static fn () => false), - )); + $this->assertThat($event, new WasDispatched() + ->times($quantise->expected) + ->withConstraints( + new Callback(static fn() => false), + )); } #[Test] @@ -212,11 +216,14 @@ public function itPassesWhenDispatchedGivenTimesWithGivenEventConstraints( WasDispatched::spy(); $event = new DummyEvent('first', 'last'); - $quantise->applyTo(static fn () => Event::dispatch($event)); + $quantise->applyTo(static fn() => Event::dispatch($event)); - $this->assertThat($event, $quantise(new WasDispatched()->withConstraints( - new Callback(static fn () => true), - ))); + $this->assertThat( + $event, + $quantise(new WasDispatched()->withConstraints( + new Callback(static fn() => true), + )), + ); } #[Test] diff --git a/src/Laravel/Constraint/Scheduling/IsScheduled.php b/src/Laravel/Constraint/Scheduling/IsScheduled.php index 874dbc7..7b69b69 100644 --- a/src/Laravel/Constraint/Scheduling/IsScheduled.php +++ b/src/Laravel/Constraint/Scheduling/IsScheduled.php @@ -35,12 +35,13 @@ public function __construct( #[Override] protected function matches(mixed $other): bool { - is_string($other) && class_exists($other) or throw new InvalidArgumentException( - self::class . ' can only be evaluated for classnames of scheduled tasks.', - ); + if (is_string($other) === false || class_exists($other) === false) { + throw new InvalidArgumentException( + self::class . ' can only be evaluated for classnames of scheduled tasks.', + ); + } - $matchingScheduledTask = new Collection($this->schedule->events()) - ->first(static fn (Event $event): bool => $event->description === $other); + $matchingScheduledTask = new Collection($this->schedule->events())->first(static fn(Event $event): bool => $event->description === $other); if ($matchingScheduledTask === null) { $this->additionalFailureDescriptions[] = 'Not scheduled.'; diff --git a/src/Laravel/Doubles/Events/DummyListener.php b/src/Laravel/Doubles/Events/DummyListener.php index 54d0bf0..ce29b11 100644 --- a/src/Laravel/Doubles/Events/DummyListener.php +++ b/src/Laravel/Doubles/Events/DummyListener.php @@ -9,6 +9,11 @@ */ final readonly class DummyListener { - public function __invoke(mixed ...$arguments): void {} - public function handle(): void {} + public function __invoke(mixed ...$arguments): void + { + } + + public function handle(): void + { + } } diff --git a/src/Laravel/ServiceProvider.php b/src/Laravel/ServiceProvider.php index ff76457..8090da3 100644 --- a/src/Laravel/ServiceProvider.php +++ b/src/Laravel/ServiceProvider.php @@ -12,6 +12,6 @@ final class ServiceProvider extends IlluminateServiceProvider { public function boot(): void { - HasErrorOnPath::resolveResponseUsing(static fn (TestResponse $response): array => $response->json()); + HasErrorOnPath::resolveResponseUsing(static fn(TestResponse $response): array => $response->json()); } } diff --git a/src/PHPUnit/Constraint/Callables/WasCalled.php b/src/PHPUnit/Constraint/Callables/WasCalled.php index ac9f4b9..3500b80 100644 --- a/src/PHPUnit/Constraint/Callables/WasCalled.php +++ b/src/PHPUnit/Constraint/Callables/WasCalled.php @@ -56,9 +56,11 @@ public function once(): self #[Override] protected function matches(mixed $other): bool { - $other instanceof SpyCallable or throw new InvalidArgumentException( - self::class . ' can only be evaluated for instances of ' . SpyCallable::class, - ); + if (!$other instanceof SpyCallable) { + throw new InvalidArgumentException( + self::class . ' can only be evaluated for instances of ' . SpyCallable::class, + ); + } $matchingInvocations = array_filter($other->invocations, $this->matchesInvocationAssertions(...)); diff --git a/src/PHPUnit/Constraint/Callables/WasCalledTest.php b/src/PHPUnit/Constraint/Callables/WasCalledTest.php index b8b9df2..c31a1c9 100644 --- a/src/PHPUnit/Constraint/Callables/WasCalledTest.php +++ b/src/PHPUnit/Constraint/Callables/WasCalledTest.php @@ -137,15 +137,18 @@ public function itPassesWhenCalledExpectedTimes(QuantableConstraint $quantise): public function itFailsWhenNotCalledExpectedTimesWithExpectedArguments(QuantableConstraint $quantise): void { $callable = new SpyCallable(); - $quantise->applyTo(static fn () => $callable('first', 'last')); + $quantise->applyTo(static fn() => $callable('first', 'last')); $this->expectException(ExpectationFailedException::class); $this->expectExceptionMessage("was called {$quantise->expected} time(s) with given invocation assertions."); - $this->assertThat($callable, new WasCalled(function (string $first, string $last): void { - $this->assertSame('first', $first); - $this->assertSame('last', $last); - })->times($quantise->expected)); + $this->assertThat( + $callable, + new WasCalled(function (string $first, string $last): void { + $this->assertSame('first', $first); + $this->assertSame('last', $last); + })->times($quantise->expected), + ); } #[Test] @@ -154,7 +157,7 @@ public function itPassesWhenCalledExpectedTimesWithExpectedArguments(QuantableCo { $callable = new SpyCallable(); - $quantise->applyTo(static fn () => $callable('first', 'last')); + $quantise->applyTo(static fn() => $callable('first', 'last')); $this->assertThat($callable, $quantise(new WasCalled(function (string $first, string $last): void { $this->assertSame('first', $first); diff --git a/src/PHPUnit/Constraint/Objects/DeriveConstraintsFromObjectUsingFakes.php b/src/PHPUnit/Constraint/Objects/DeriveConstraintsFromObjectUsingFakes.php index f95e3c6..37d8eb7 100644 --- a/src/PHPUnit/Constraint/Objects/DeriveConstraintsFromObjectUsingFakes.php +++ b/src/PHPUnit/Constraint/Objects/DeriveConstraintsFromObjectUsingFakes.php @@ -23,14 +23,14 @@ public function __construct( public static function failingConstraints(): self { return new self([ - new Callback(static fn () => false), + new Callback(static fn() => false), ]); } public static function passingConstraints(): self { return new self([ - new Callback(static fn () => true), + new Callback(static fn() => true), ]); } diff --git a/src/PHPUnit/Constraint/Objects/DeriveConstraintsFromObjectUsingReflection.php b/src/PHPUnit/Constraint/Objects/DeriveConstraintsFromObjectUsingReflection.php index 0a3b9b0..5e09add 100644 --- a/src/PHPUnit/Constraint/Objects/DeriveConstraintsFromObjectUsingReflection.php +++ b/src/PHPUnit/Constraint/Objects/DeriveConstraintsFromObjectUsingReflection.php @@ -18,8 +18,6 @@ */ public function __invoke(object $object): array { - return array_map(static fn (ReflectionProperty $property): PropertyValue => ( - new PropertyValue($property->name, new IsEqual($property->getValue($object))) - ), new ReflectionClass($object)->getProperties(ReflectionProperty::IS_PUBLIC)); + return array_map(static fn(ReflectionProperty $property): PropertyValue => new PropertyValue($property->name, new IsEqual($property->getValue($object))), new ReflectionClass($object)->getProperties(ReflectionProperty::IS_PUBLIC)); } } diff --git a/src/PHPUnit/Constraint/Objects/DeriveConstraintsFromObjectUsingReflectionTest.php b/src/PHPUnit/Constraint/Objects/DeriveConstraintsFromObjectUsingReflectionTest.php index 5da7b55..b10a5f7 100644 --- a/src/PHPUnit/Constraint/Objects/DeriveConstraintsFromObjectUsingReflectionTest.php +++ b/src/PHPUnit/Constraint/Objects/DeriveConstraintsFromObjectUsingReflectionTest.php @@ -16,8 +16,7 @@ final class DeriveConstraintsFromObjectUsingReflectionTest extends TestCase #[Test] public function itShouldNotDeriveConstraintsFromNonPublicProperties(): void { - $object = new readonly class - { + $object = new readonly class { public function __construct( protected mixed $protected = 'protected', protected mixed $private = 'private', @@ -33,8 +32,7 @@ public function __construct( public function itCanDeriveConstraintsFromPublicProperties(): void { $value = 'SomePublicValue'; - $object = new readonly class ($value) - { + $object = new readonly class($value) { public function __construct( public mixed $somePublicProperty, ) {} @@ -42,8 +40,11 @@ public function __construct( $results = new DeriveConstraintsFromObjectUsingReflection()->__invoke($object); - $this->assertEquals([ - new PropertyValue('somePublicProperty', new IsEqual($value)), - ], $results); + $this->assertEquals( + [ + new PropertyValue('somePublicProperty', new IsEqual($value)), + ], + $results, + ); } } diff --git a/src/PHPUnit/Constraint/Objects/DerivesConstraintsFromObjects.php b/src/PHPUnit/Constraint/Objects/DerivesConstraintsFromObjects.php index f722609..aa60d48 100644 --- a/src/PHPUnit/Constraint/Objects/DerivesConstraintsFromObjects.php +++ b/src/PHPUnit/Constraint/Objects/DerivesConstraintsFromObjects.php @@ -30,7 +30,7 @@ public function givenOrDerivedObjectConstraints(string|object $expected): array return []; } - return (self::$deriveConstraintsFromObject ?? new DeriveConstraintsFromObjectUsingReflection())($expected); + return ( self::$deriveConstraintsFromObject ?? new DeriveConstraintsFromObjectUsingReflection() )($expected); } public static function deriveConstraintsFromObjectUsing( diff --git a/src/PHPUnit/Constraint/Objects/PropertyValue.php b/src/PHPUnit/Constraint/Objects/PropertyValue.php index bba64a1..dee70f5 100644 --- a/src/PHPUnit/Constraint/Objects/PropertyValue.php +++ b/src/PHPUnit/Constraint/Objects/PropertyValue.php @@ -45,9 +45,7 @@ protected function matches(mixed $other): bool public function toString(): string { - $comparesTo = Str::of($this->constraint::class) - ->classBasename() - ->snake(' '); + $comparesTo = Str::of($this->constraint::class)->classBasename()->snake(' '); return "`{$this->name}` property value {$comparesTo}"; } diff --git a/src/PHPUnit/Constraint/Objects/PropertyValueTest.php b/src/PHPUnit/Constraint/Objects/PropertyValueTest.php index 80db8c1..06b5799 100644 --- a/src/PHPUnit/Constraint/Objects/PropertyValueTest.php +++ b/src/PHPUnit/Constraint/Objects/PropertyValueTest.php @@ -60,7 +60,7 @@ public function itFailsWhenPropertiesDontExist(): void #[Test] public function itFailsWhenPropertiesDontMatchGivenConstraints(): void { - $constraint = new Callback(static fn (): bool => false); + $constraint = new Callback(static fn(): bool => false); $object = $this->objectWithIdProperty(); $this->expectException(ExpectationFailedException::class); @@ -71,7 +71,7 @@ public function itFailsWhenPropertiesDontMatchGivenConstraints(): void #[Test] public function itPassesWhenPropertiesMatchGivenConstraints(): void { - $constraint = new Callback(static fn (): bool => true); + $constraint = new Callback(static fn(): bool => true); $object = $this->objectWithIdProperty(); $this->assertThat($object, new PropertyValue('id', $constraint)); @@ -82,8 +82,7 @@ public function itPassesWhenPropertiesMatchGivenConstraints(): void */ private function objectWithIdProperty(): object { - return new class - { + return new class { public function __construct( public string $id = 'SomeId', ) {} diff --git a/src/PHPUnit/Constraint/ProvidesAdditionalFailureDescription.php b/src/PHPUnit/Constraint/ProvidesAdditionalFailureDescription.php index 64b4254..97f27bb 100644 --- a/src/PHPUnit/Constraint/ProvidesAdditionalFailureDescription.php +++ b/src/PHPUnit/Constraint/ProvidesAdditionalFailureDescription.php @@ -17,8 +17,6 @@ trait ProvidesAdditionalFailureDescription #[Override] protected function additionalFailureDescription(mixed $other): string { - return new Collection($this->additionalFailureDescriptions) - ->map(static fn (string $description): string => "\n* {$description}\n") - ->implode(''); + return new Collection($this->additionalFailureDescriptions)->map(static fn(string $description): string => "\n* {$description}\n")->implode(''); } } diff --git a/src/PHPUnit/Constraint/Quantable.php b/src/PHPUnit/Constraint/Quantable.php index 6732285..d6b9ae0 100644 --- a/src/PHPUnit/Constraint/Quantable.php +++ b/src/PHPUnit/Constraint/Quantable.php @@ -7,6 +7,8 @@ interface Quantable { public function times(int $count): self; + public function never(): self; + public function once(): self; } diff --git a/src/PHPUnit/DataProviders/EnumCase.php b/src/PHPUnit/DataProviders/EnumCase.php index 7af100a..659c8be 100644 --- a/src/PHPUnit/DataProviders/EnumCase.php +++ b/src/PHPUnit/DataProviders/EnumCase.php @@ -34,12 +34,16 @@ public function __construct( public UnitEnum $instance, UnitEnum ...$options, ) { - in_array($instance, $options, strict: true) or throw new ValueError('Options should contain the given instance.'); + if (in_array($instance, $options, strict: true) === false) { + throw new ValueError('Options should contain the given instance.'); + } foreach ($options as $option) { - $option::class === $instance::class or throw new ValueError( - 'Given options should have the same type as the given instance.', - ); + if ($option::class !== $instance::class) { + throw new ValueError( + 'Given options should have the same type as the given instance.', + ); + } } $this->options = $options; @@ -50,10 +54,13 @@ public function __construct( */ public function differentInstance(): UnitEnum { - count($this->options) > 1 or throw new LogicException( - self::class . ' was configured with a single option and can therefore not return a different instance.', - ); - $differentOptions = array_filter($this->options, fn (UnitEnum $option): bool => $option !== $this->instance); + if (count($this->options) <= 1) { + throw new LogicException( + self::class . ' was configured with a single option and can therefore not return a different instance.', + ); + } + + $differentOptions = array_filter($this->options, fn(UnitEnum $option): bool => $option !== $this->instance); return $differentOptions[array_rand($differentOptions)]; } diff --git a/src/PHPUnit/DataProviders/EnumCaseTest.php b/src/PHPUnit/DataProviders/EnumCaseTest.php index 77b2f53..3d21327 100644 --- a/src/PHPUnit/DataProviders/EnumCaseTest.php +++ b/src/PHPUnit/DataProviders/EnumCaseTest.php @@ -68,7 +68,7 @@ public function itCannotConstructWhenOptionsHaveDifferentTypeComparedToGivenInst $instance = $this->faker->randomElement($options); $differentEnumFQCN = $this->faker->randomElement(array_filter( self::ENUM_FQCNS, - static fn (string $enumFQCN): bool => $enumFQCN !== $instance::class, + static fn(string $enumFQCN): bool => $enumFQCN !== $instance::class, )); $differentEnumInstance = $this->faker->randomElement($differentEnumFQCN::cases()); diff --git a/src/PHPUnit/DataProviders/QuantableConstraintTest.php b/src/PHPUnit/DataProviders/QuantableConstraintTest.php index 1ddcf14..4b78a46 100644 --- a/src/PHPUnit/DataProviders/QuantableConstraintTest.php +++ b/src/PHPUnit/DataProviders/QuantableConstraintTest.php @@ -63,10 +63,11 @@ public function itCanBeInvokedOnConstraints(string $method, int $times): void $instance($constraint); - $constraint->spy->assert(new WasCalled(function (string $method, int $times) use ($instance): void { - $this->assertSame($instance->method, $method); - $this->assertSame($instance->times, $times); - })->once()); + $constraint->spy->assert( + new WasCalled() + ->withSame($instance->method, $instance->times) + ->once(), + ); } #[Test] @@ -110,8 +111,7 @@ public function itCanConstructTooFewOrTooManyTimesCases(): void private function constraint(): object { - return new class implements Quantable - { + return new class implements Quantable { public function __construct( public SpyCallable $spy = new SpyCallable(), ) {} diff --git a/src/PHPUnit/Doubles/SpyCallableTest.php b/src/PHPUnit/Doubles/SpyCallableTest.php index c9a69d1..ab681bd 100644 --- a/src/PHPUnit/Doubles/SpyCallableTest.php +++ b/src/PHPUnit/Doubles/SpyCallableTest.php @@ -35,7 +35,7 @@ public static function returnValues(): iterable yield 'Array' => [['foo']]; yield 'Zero' => [0]; yield 'Integer' => [PHP_INT_MAX]; - yield 'Callable' => [static fn (): null => null]; + yield 'Callable' => [static fn(): null => null]; yield 'Class' => [new stdClass()]; } @@ -66,8 +66,7 @@ public function itReturnsGivenReturnValuesWhenCalled(SpyCallable $instance, mixe #[Test] public function itCanAssertConstraints(): void { - $constraint = new class extends Constraint - { + $constraint = new class extends Constraint { public function toString(): string { return 'was constrained'; diff --git a/src/Saloon/Constraints/WasSent.php b/src/Saloon/Constraints/WasSent.php index a5677ec..8574f21 100644 --- a/src/Saloon/Constraints/WasSent.php +++ b/src/Saloon/Constraints/WasSent.php @@ -35,9 +35,10 @@ public function __construct( public readonly ?int $times = null, Constraint ...$constraints, ) { - $this->client = $connector->getMockClient() ?? MockClient::getGlobal() ?? throw new LogicException( - 'Missing either a global or connector specific ' . MockClient::class . '.', - ); + $this->client = + $connector->getMockClient() ?? MockClient::getGlobal() ?? throw new LogicException( + 'Missing either a global or connector specific ' . MockClient::class . '.', + ); $this->objectConstraints = $constraints; } @@ -72,21 +73,25 @@ protected function matches(mixed $other): bool ), }; - $matchingSentRequests = array_reduce($this->client->getRecordedResponses(), static function ( - array $matchingSentRequests, - Response $response, - ) use ($requestName): array { - $request = $response->getPendingRequest()->getRequest(); + $matchingSentRequests = array_reduce( + $this->client->getRecordedResponses(), + static function ( + array $matchingSentRequests, + Response $response, + ) use ($requestName): array { + $request = $response->getPendingRequest()->getRequest(); - if ($request::class === $requestName) { - $matchingSentRequests[] = $request; - } + if ($request::class === $requestName) { + $matchingSentRequests[] = $request; + } - return $matchingSentRequests; - }, []); + return $matchingSentRequests; + }, + [], + ); $sentRequestsMatchingConstraints = array_filter( $matchingSentRequests, - fn (Request $request): bool => $this->matchesRequestConstraints( + fn(Request $request): bool => $this->matchesRequestConstraints( $other, $request, // When the request was sent exactly once, we should add all nested expectation failures to the diff --git a/src/Saloon/Constraints/WasSentTest.php b/src/Saloon/Constraints/WasSentTest.php index 2b7d347..c30b486 100644 --- a/src/Saloon/Constraints/WasSentTest.php +++ b/src/Saloon/Constraints/WasSentTest.php @@ -133,7 +133,7 @@ public function itPassesWhenSent(QuantableConstraint $quantise): void { $connector = new FakeConnector()->withMockClient($this->mockClient(FakeRequest::class)); - $quantise->applyTo(static fn () => $connector->send(new FakeRequest())); + $quantise->applyTo(static fn() => $connector->send(new FakeRequest())); $this->assertThat(FakeRequest::class, $quantise(new WasSent($connector))); } @@ -162,7 +162,7 @@ public function itFailsWhenSentButNotWithGivenConstraints(): void $this->expectExceptionMessage('was sent with given constraints.'); $this->assertThat(FakeRequest::class, new WasSent($connector)->withConstraints( - new Callback(static fn () => false), + new Callback(static fn() => false), )); } @@ -174,7 +174,7 @@ public function itPassesWhenSentWithGivenConstraints(): void $connector->send(new FakeRequest()); $this->assertThat(FakeRequest::class, new WasSent($connector)->withConstraints( - new Callback(static fn () => true), + new Callback(static fn() => true), )); } @@ -183,7 +183,7 @@ public function itPassesWhenSentWithGivenConstraints(): void public function itFailsWhenSentButNotGivenTimes(QuantableConstraint $quantise): void { $connector = new FakeConnector()->withMockClient($this->mockClient(FakeRequest::class)); - $quantise->applyTo(static fn () => $connector->send(new FakeRequest())); + $quantise->applyTo(static fn() => $connector->send(new FakeRequest())); $this->expectException(ExpectationFailedException::class); $this->expectExceptionMessage("was sent {$quantise->expected} time(s)."); @@ -197,7 +197,7 @@ public function itPassesWhenSentGivenTimes(QuantableConstraint $quantise): void { $connector = new FakeConnector()->withMockClient($this->mockClient(FakeRequest::class)); - $quantise->applyTo(static fn () => $connector->send(new FakeRequest())); + $quantise->applyTo(static fn() => $connector->send(new FakeRequest())); $this->assertThat(FakeRequest::class, $quantise(new WasSent($connector))); } @@ -207,14 +207,16 @@ public function itPassesWhenSentGivenTimes(QuantableConstraint $quantise): void public function itFailsWhenSentWithGivenConstrainsButNotGivenTimes(QuantableConstraint $quantise): void { $connector = new FakeConnector()->withMockClient($this->mockClient(FakeRequest::class)); - $quantise->applyTo(static fn () => $connector->send(new FakeRequest())); + $quantise->applyTo(static fn() => $connector->send(new FakeRequest())); $this->expectException(ExpectationFailedException::class); $this->expectExceptionMessage("was sent {$quantise->expected} time(s)"); - $this->assertThat(FakeRequest::class, new WasSent($connector)->times($quantise->expected)->withConstraints( - new Callback(static fn () => true), - )); + $this->assertThat(FakeRequest::class, new WasSent($connector) + ->times($quantise->expected) + ->withConstraints( + new Callback(static fn() => true), + )); } #[Test] @@ -222,14 +224,16 @@ public function itFailsWhenSentWithGivenConstrainsButNotGivenTimes(QuantableCons public function itFailsWhenSentGivenTimesButNotWithGivenConstrains(QuantableConstraint $quantise): void { $connector = new FakeConnector()->withMockClient($this->mockClient(FakeRequest::class)); - $quantise->applyTo(static fn () => $connector->send(new FakeRequest())); + $quantise->applyTo(static fn() => $connector->send(new FakeRequest())); $this->expectException(ExpectationFailedException::class); $this->expectExceptionMessage("was sent {$quantise->expected} time(s) with given constraints."); - $this->assertThat(FakeRequest::class, new WasSent($connector)->times($quantise->expected)->withConstraints( - new Callback(static fn () => false), - )); + $this->assertThat(FakeRequest::class, new WasSent($connector) + ->times($quantise->expected) + ->withConstraints( + new Callback(static fn() => false), + )); } #[Test] @@ -238,11 +242,14 @@ public function itPassesWhenSentGivenTimesWithGivenConstraints(QuantableConstrai { $connector = new FakeConnector()->withMockClient($this->mockClient(FakeRequest::class)); - $quantise->applyTo(static fn () => $connector->send(new FakeRequest())); + $quantise->applyTo(static fn() => $connector->send(new FakeRequest())); - $this->assertThat(FakeRequest::class, $quantise(new WasSent($connector)->withConstraints( - new Callback(static fn () => true), - ))); + $this->assertThat( + FakeRequest::class, + $quantise(new WasSent($connector)->withConstraints( + new Callback(static fn() => true), + )), + ); } #[Test] diff --git a/src/Saloon/DataProviders/FakeResponse.php b/src/Saloon/DataProviders/FakeResponse.php index d6cb906..4f8c902 100644 --- a/src/Saloon/DataProviders/FakeResponse.php +++ b/src/Saloon/DataProviders/FakeResponse.php @@ -68,7 +68,6 @@ public function __invoke(string $requestFQCN, ?Connector $connector = null): voi // When not given a connector instance, we should use the global // MockClient to fake responses for all connectors... null => MockClient::getGlobal() ?? MockClient::global(), - // When given a connector instance, we should use its specific MockClient // to only fake responses for that specific connector instance... default => $connector->getMockClient() ?? new MockClient(), diff --git a/src/Saloon/DataProviders/FakeResponseTest.php b/src/Saloon/DataProviders/FakeResponseTest.php index 3c04a1e..53441c2 100644 --- a/src/Saloon/DataProviders/FakeResponseTest.php +++ b/src/Saloon/DataProviders/FakeResponseTest.php @@ -89,8 +89,7 @@ public function itShouldFailRequestsWithoutResponseMock(?Connector $connector): $this->expectException(LogicException::class); - new FakeConnector()->send(new class extends Request - { + new FakeConnector()->send(new class extends Request { public function resolveEndpoint(): string { return 'not-faked'; @@ -103,19 +102,25 @@ public function itCanProvideCommonErrors(): void { $cases = iterator_to_array(FakeResponse::commonErrors()); - $this->assertEquals([ - 'Bad request' => [FakeResponse::badRequest()], - 'Forbidden' => [FakeResponse::forbidden()], - 'Not found' => [FakeResponse::notFound()], - 'Server error' => [FakeResponse::serverError()], - ], $cases); + $this->assertEquals( + [ + 'Bad request' => [FakeResponse::badRequest()], + 'Forbidden' => [FakeResponse::forbidden()], + 'Not found' => [FakeResponse::notFound()], + 'Server error' => [FakeResponse::serverError()], + ], + $cases, + ); } private function assertBody(string|array $body, SaloonResponse $response): void { - $this->assertSame(match (is_array($body)) { - true => json_encode($body), - false => $body, - }, $response->body()); + $this->assertSame( + match (is_array($body)) { + true => json_encode($body), + false => $body, + }, + $response->body(), + ); } } From 9875a841af1981637b607528264d5bc2cf91bea7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Re=CC=81mi=20Pelhate?= Date: Thu, 4 Jun 2026 14:44:56 +0200 Subject: [PATCH 13/31] Dry-run formatting in static-analysis workflow --- .github/workflows/static-analysis.yml | 22 ++++++++++++++++++++++ composer.json | 1 + 2 files changed, 23 insertions(+) diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index ff71040..4ff3edc 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -15,5 +15,27 @@ jobs: extensions: -pdo_mysql, -mysqli - run: composer update --prefer-stable --prefer-dist --no-interaction - run: composer mago:lint + id: lint + continue-on-error: true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - run: composer mago:format -- --dry-run + id: format + continue-on-error: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: 'Check status' + if: steps.lint.outcome == 'failure' || steps.format.outcome == 'failure' + env: + LINT_OUTCOME: ${{ steps.lint.outcome }} + FORMAT_OUTCOME: ${{ steps.format.outcome }} + run: | + if [ "$LINT_OUTCOME" == "failure" ]; then + echo "::error title=Mago linter detected issues::" + fi + + if [ "$FORMAT_OUTCOME" == "failure" ]; then + echo "::error title=Mago formatter detected issues::" + fi + + exit 1 diff --git a/composer.json b/composer.json index 88a634c..3b05b3f 100644 --- a/composer.json +++ b/composer.json @@ -66,6 +66,7 @@ "scripts": { "mago": "vendor/bin/mago", "mago:lint": "vendor/bin/mago --colors always lint --minimum-fail-level warning", + "mago:format": "vendor/bin/mago --colors always format", "cs:check": "PHP_CS_FIXER_IGNORE_ENV=1 vendor/bin/php-cs-fixer fix --verbose --dry-run", "cs:fix": "PHP_CS_FIXER_IGNORE_ENV=1 vendor/bin/php-cs-fixer fix --verbose", "phpstan": "vendor/bin/phpstan analyse --memory-limit=2G --ansi", From b524fd0153057c6551f0fee2bc5382494469a103 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Re=CC=81mi=20Pelhate?= Date: Thu, 4 Jun 2026 15:04:14 +0200 Subject: [PATCH 14/31] Intentionally trigger Mago issues --- mago.toml | 2 +- src/PHPUnit/DataProviders/EnumCase.php | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/mago.toml b/mago.toml index f0dffbf..5d72044 100644 --- a/mago.toml +++ b/mago.toml @@ -26,4 +26,4 @@ preserve-breaking-attribute-list = true [linter.rules] no-boolean-flag-parameter = { enabled = false } too-many-methods = { exclude = ["src/**/*Test.php"] } -literal-named-argument = { exclude = ["src/**/*Test.php"] } +#literal-named-argument = { exclude = ["src/**/*Test.php"] } diff --git a/src/PHPUnit/DataProviders/EnumCase.php b/src/PHPUnit/DataProviders/EnumCase.php index 659c8be..ef0ded0 100644 --- a/src/PHPUnit/DataProviders/EnumCase.php +++ b/src/PHPUnit/DataProviders/EnumCase.php @@ -35,7 +35,8 @@ public function __construct( UnitEnum ...$options, ) { if (in_array($instance, $options, strict: true) === false) { - throw new ValueError('Options should contain the given instance.'); + throw new + ValueError('Options should contain the given instance.'); } foreach ($options as $option) { From 9852b374b4b71691ca748202920a095cb7354fbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Re=CC=81mi=20Pelhate?= Date: Thu, 4 Jun 2026 15:48:13 +0200 Subject: [PATCH 15/31] Remove redudant check status step --- .github/workflows/static-analysis.yml | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 4ff3edc..f3aa8a6 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -24,18 +24,3 @@ jobs: continue-on-error: true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: 'Check status' - if: steps.lint.outcome == 'failure' || steps.format.outcome == 'failure' - env: - LINT_OUTCOME: ${{ steps.lint.outcome }} - FORMAT_OUTCOME: ${{ steps.format.outcome }} - run: | - if [ "$LINT_OUTCOME" == "failure" ]; then - echo "::error title=Mago linter detected issues::" - fi - - if [ "$FORMAT_OUTCOME" == "failure" ]; then - echo "::error title=Mago formatter detected issues::" - fi - - exit 1 From 919a7d0b15581a76f7df4d10168989fbb7c4477b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Re=CC=81mi=20Pelhate?= Date: Thu, 4 Jun 2026 16:03:20 +0200 Subject: [PATCH 16/31] Re-add Mago report step to ensure the workflow fails in case of errors --- .github/workflows/static-analysis.yml | 15 +++++++++++++++ composer.json | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index f3aa8a6..d7ff6df 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -24,3 +24,18 @@ jobs: continue-on-error: true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: 'Report issues detected by Mago' + if: steps.lint.outcome == 'failure' || steps.format.outcome == 'failure' + env: + LINT_OUTCOME: ${{ steps.lint.outcome }} + FORMAT_OUTCOME: ${{ steps.format.outcome }} + run: | + if [ "$LINT_OUTCOME" == "failure" ]; then + echo "::error title=Mago linter detected issues::" + fi + + if [ "$FORMAT_OUTCOME" == "failure" ]; then + echo "::error title=Mago formatter detected issues::" + fi + + exit 1 diff --git a/composer.json b/composer.json index 3b05b3f..816c7c7 100644 --- a/composer.json +++ b/composer.json @@ -65,7 +65,7 @@ "prefer-stable": true, "scripts": { "mago": "vendor/bin/mago", - "mago:lint": "vendor/bin/mago --colors always lint --minimum-fail-level warning", + "mago:lint": "vendor/bin/mago --colors always lint --minimum-fail-level warning --reporting-format rich", "mago:format": "vendor/bin/mago --colors always format", "cs:check": "PHP_CS_FIXER_IGNORE_ENV=1 vendor/bin/php-cs-fixer fix --verbose --dry-run", "cs:fix": "PHP_CS_FIXER_IGNORE_ENV=1 vendor/bin/php-cs-fixer fix --verbose", From 1da3c88652ed2fbfed8e7cce2d0f78fa5a0f003a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Re=CC=81mi=20Pelhate?= Date: Thu, 4 Jun 2026 16:20:44 +0200 Subject: [PATCH 17/31] Cleanup static analysis output --- .github/workflows/static-analysis.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index d7ff6df..b48f386 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -14,6 +14,9 @@ jobs: php-version: 8.5 extensions: -pdo_mysql, -mysqli - run: composer update --prefer-stable --prefer-dist --no-interaction + # Mago is installed through Composer, but the package is just a thin wrapper. By checking the version, we force + # the wrapper to download the binary before running actual checks in order not to pollute the check output... + - run: vendor/bin/mago --version - run: composer mago:lint id: lint continue-on-error: true @@ -31,11 +34,11 @@ jobs: FORMAT_OUTCOME: ${{ steps.format.outcome }} run: | if [ "$LINT_OUTCOME" == "failure" ]; then - echo "::error title=Mago linter detected issues::" + echo "::error::Mago linter detected issues." fi if [ "$FORMAT_OUTCOME" == "failure" ]; then - echo "::error title=Mago formatter detected issues::" + echo "::error::Mago formatter detected issues." fi exit 1 From f785b6d880026136bcdffdfa9d19683b46712c6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Re=CC=81mi=20Pelhate?= Date: Thu, 4 Jun 2026 16:43:04 +0200 Subject: [PATCH 18/31] Streamline composer scripts --- .github/workflows/static-analysis.yml | 10 +++++----- .github/workflows/test.yml | 2 +- Taskfile.yml | 2 +- composer.json | 27 +++++++++++++++------------ 4 files changed, 22 insertions(+), 19 deletions(-) diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index b48f386..c506877 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -16,13 +16,13 @@ jobs: - run: composer update --prefer-stable --prefer-dist --no-interaction # Mago is installed through Composer, but the package is just a thin wrapper. By checking the version, we force # the wrapper to download the binary before running actual checks in order not to pollute the check output... - - run: vendor/bin/mago --version - - run: composer mago:lint + - run: composer mago -- --version + - run: composer lint:check id: lint continue-on-error: true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - run: composer mago:format -- --dry-run + - run: composer format:check id: format continue-on-error: true env: @@ -34,11 +34,11 @@ jobs: FORMAT_OUTCOME: ${{ steps.format.outcome }} run: | if [ "$LINT_OUTCOME" == "failure" ]; then - echo "::error::Mago linter detected issues." + echo "::error title=lint:check::One or more issues detected." fi if [ "$FORMAT_OUTCOME" == "failure" ]; then - echo "::error::Mago formatter detected issues." + echo "::error title=format:check::One or more files need formatting." fi exit 1 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bf5aadf..95593d1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -22,4 +22,4 @@ jobs: coverage: pcov extensions: -pdo_mysql, -mysqli - run: composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction - - run: composer coverage:summary + - run: composer test:coverage diff --git a/Taskfile.yml b/Taskfile.yml index 7c2d679..b59860d 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -58,4 +58,4 @@ tasks: - for: var: versions split: ',' - cmd: docker compose exec php-{{ .ITEM }} composer phpunit + cmd: docker compose exec php-{{ .ITEM }} composer test diff --git a/composer.json b/composer.json index 816c7c7..c4c97c9 100644 --- a/composer.json +++ b/composer.json @@ -64,20 +64,23 @@ "minimum-stability": "dev", "prefer-stable": true, "scripts": { - "mago": "vendor/bin/mago", - "mago:lint": "vendor/bin/mago --colors always lint --minimum-fail-level warning --reporting-format rich", - "mago:format": "vendor/bin/mago --colors always format", - "cs:check": "PHP_CS_FIXER_IGNORE_ENV=1 vendor/bin/php-cs-fixer fix --verbose --dry-run", - "cs:fix": "PHP_CS_FIXER_IGNORE_ENV=1 vendor/bin/php-cs-fixer fix --verbose", - "phpstan": "vendor/bin/phpstan analyse --memory-limit=2G --ansi", + "mago": "vendor/bin/mago --colors=always", "phpunit": "vendor/bin/phpunit --colors=always --display-phpunit-deprecations --display-deprecations", - "test": [ - "@composer cs:check", - "@composer phpstan", - "@composer phpunit" + "lint:check": "@composer mago -- lint --minimum-fail-level=warning --reporting-format=rich", + "lint:fix": "@composer mago -- lint --fix", + "format:check": "@composer mago -- format --dry-run", + "format:fix": "@composer mago -- format", + "static-analysis:check": [ + "@composer lint:check", + "@composer format:check" ], - "coverage:summary": "@composer phpunit -- --coverage-text", - "coverage:report": "@composer phpunit -- --coverage-html=.reports/coverage" + "static-analysis:fix": [ + "@composer lint:fix", + "@composer format:fix" + ], + "test": "@composer phpunit", + "test:coverage": "@composer phpunit -- --coverage-text", + "test:report": "@composer phpunit -- --coverage-html=.reports/coverage" }, "extra": { "branch-alias": { From 44c74852d692640e6e018635ed79eece2412d6ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Re=CC=81mi=20Pelhate?= Date: Thu, 4 Jun 2026 17:05:04 +0200 Subject: [PATCH 19/31] Intentionally trigger Mago issues --- mago.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mago.toml b/mago.toml index 5d72044..6a3ec8a 100644 --- a/mago.toml +++ b/mago.toml @@ -24,6 +24,6 @@ preserve-breaking-array-like = true preserve-breaking-attribute-list = true [linter.rules] -no-boolean-flag-parameter = { enabled = false } -too-many-methods = { exclude = ["src/**/*Test.php"] } +#no-boolean-flag-parameter = { enabled = false } +#too-many-methods = { exclude = ["src/**/*Test.php"] } #literal-named-argument = { exclude = ["src/**/*Test.php"] } From a3b9300ebb704ad1c265c1fe28f6a977434e3b79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Re=CC=81mi=20Pelhate?= Date: Thu, 4 Jun 2026 17:07:35 +0200 Subject: [PATCH 20/31] Fix intentional errors --- mago.toml | 6 +++--- src/PHPUnit/DataProviders/EnumCase.php | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/mago.toml b/mago.toml index 6a3ec8a..f0dffbf 100644 --- a/mago.toml +++ b/mago.toml @@ -24,6 +24,6 @@ preserve-breaking-array-like = true preserve-breaking-attribute-list = true [linter.rules] -#no-boolean-flag-parameter = { enabled = false } -#too-many-methods = { exclude = ["src/**/*Test.php"] } -#literal-named-argument = { exclude = ["src/**/*Test.php"] } +no-boolean-flag-parameter = { enabled = false } +too-many-methods = { exclude = ["src/**/*Test.php"] } +literal-named-argument = { exclude = ["src/**/*Test.php"] } diff --git a/src/PHPUnit/DataProviders/EnumCase.php b/src/PHPUnit/DataProviders/EnumCase.php index ef0ded0..659c8be 100644 --- a/src/PHPUnit/DataProviders/EnumCase.php +++ b/src/PHPUnit/DataProviders/EnumCase.php @@ -35,8 +35,7 @@ public function __construct( UnitEnum ...$options, ) { if (in_array($instance, $options, strict: true) === false) { - throw new - ValueError('Options should contain the given instance.'); + throw new ValueError('Options should contain the given instance.'); } foreach ($options as $option) { From 748a8190dd32adf0ba025225629cc5692c2f0499 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Re=CC=81mi=20Pelhate?= Date: Thu, 4 Jun 2026 17:11:23 +0200 Subject: [PATCH 21/31] Enable phpunit linter integration --- mago.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mago.toml b/mago.toml index f0dffbf..c849e8e 100644 --- a/mago.toml +++ b/mago.toml @@ -23,7 +23,11 @@ preserve-breaking-parameter-list = true preserve-breaking-array-like = true preserve-breaking-attribute-list = true +[linter] +integrations = ["phpunit"] + [linter.rules] no-boolean-flag-parameter = { enabled = false } too-many-methods = { exclude = ["src/**/*Test.php"] } literal-named-argument = { exclude = ["src/**/*Test.php"] } +prefer-test-attribute = { enabled = true } From f66d87d83cf072b3f2912fd3a8ff5e6d72b3d9c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Re=CC=81mi=20Pelhate?= Date: Thu, 4 Jun 2026 18:46:35 +0200 Subject: [PATCH 22/31] Setup Mago analyse --- composer.json | 1 + mago.toml | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/composer.json b/composer.json index c4c97c9..6295c91 100644 --- a/composer.json +++ b/composer.json @@ -70,6 +70,7 @@ "lint:fix": "@composer mago -- lint --fix", "format:check": "@composer mago -- format --dry-run", "format:fix": "@composer mago -- format", + "analyse:check": "@composer mago -- analyse", "static-analysis:check": [ "@composer lint:check", "@composer format:check" diff --git a/mago.toml b/mago.toml index c849e8e..8b84598 100644 --- a/mago.toml +++ b/mago.toml @@ -31,3 +31,10 @@ no-boolean-flag-parameter = { enabled = false } too-many-methods = { exclude = ["src/**/*Test.php"] } literal-named-argument = { exclude = ["src/**/*Test.php"] } prefer-test-attribute = { enabled = true } + +[analyzer] +excludes = ["src/**/*Test.php"] +ignore = [ + "mixed-argument", + "mixed-assignment", +] From d3e79d6faf6aa43043d5e879ce1961a3da53f125 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Re=CC=81mi=20Pelhate?= Date: Thu, 4 Jun 2026 19:20:48 +0200 Subject: [PATCH 23/31] Run analyse:check in static-analysis workflow --- .github/workflows/static-analysis.yml | 21 +++++++++++++++++---- composer.json | 5 +++-- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index c506877..12bb8e6 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -27,18 +27,31 @@ jobs: continue-on-error: true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: 'Report issues detected by Mago' - if: steps.lint.outcome == 'failure' || steps.format.outcome == 'failure' + - run: composer analyse:check + id: analyse + continue-on-error: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: 'Fail upon detected issues' + if: | + steps.lint.outcome == 'failure' || + steps.format.outcome == 'failure' || + steps.analyse.outcome == 'failure' env: LINT_OUTCOME: ${{ steps.lint.outcome }} FORMAT_OUTCOME: ${{ steps.format.outcome }} + ANALYSE_OUTCOME: ${{ steps.analyse.outcome }} run: | if [ "$LINT_OUTCOME" == "failure" ]; then - echo "::error title=lint:check::One or more issues detected." + echo "::error title=Lint::Linter detected issues." fi if [ "$FORMAT_OUTCOME" == "failure" ]; then - echo "::error title=format:check::One or more files need formatting." + echo "::error title=Format::Formatter detected files needing formatting." + fi + + if [ "$ANALYSE_OUTCOME" == "failure" ]; then + echo "::error title=Analyse::Analyzer detected issues." fi exit 1 diff --git a/composer.json b/composer.json index 6295c91..7998e81 100644 --- a/composer.json +++ b/composer.json @@ -70,10 +70,11 @@ "lint:fix": "@composer mago -- lint --fix", "format:check": "@composer mago -- format --dry-run", "format:fix": "@composer mago -- format", - "analyse:check": "@composer mago -- analyse", + "analyse:check": "@composer mago -- analyse --minimum-fail-level=warning --reporting-format=rich", "static-analysis:check": [ "@composer lint:check", - "@composer format:check" + "@composer format:check", + "@composer analyse:check" ], "static-analysis:fix": [ "@composer lint:fix", From f8d7179fabb38a34830e4b6a2d7553471f7c484b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Re=CC=81mi=20Pelhate?= Date: Thu, 4 Jun 2026 19:38:33 +0200 Subject: [PATCH 24/31] Remove php-cs-fixer and phpstan --- composer.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/composer.json b/composer.json index 7998e81..ae1dfc5 100644 --- a/composer.json +++ b/composer.json @@ -25,14 +25,12 @@ }, "require-dev": { "carthage-software/mago": "^1.29.0", - "friendsofphp/php-cs-fixer": "^3.75", "illuminate/collections": "^10.10|^11.0|^12.0", "illuminate/console": "^10.10|^11.0|^12.0", "illuminate/container": "^10.10|^11.0|^12.0", "illuminate/contracts": "^10.10|^11.0|^12.0", "illuminate/support": "^10.10|^11.0|^12.0", "orchestra/testbench": "^9.9", - "phpstan/phpstan": "^2.1", "phpunit/phpunit": "^11.5", "saloonphp/saloon": "^3.13" }, From 00b11e8042edbc1833ce9568242f8cdbb7b166ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Re=CC=81mi=20Pelhate?= Date: Fri, 5 Jun 2026 10:29:51 +0200 Subject: [PATCH 25/31] Fix analyzer issues --- src/Factories/ImmutableFactoryTest.php | 7 +++-- src/GraphQL/Constraints/HasErrorOnPath.php | 18 +++++------- src/Laravel/Constraint/Bus/HasHandler.php | 12 +++++--- src/Laravel/Constraint/Bus/WasHandled.php | 5 ++-- .../Constraint/Bus/WithoutBusMiddleware.php | 2 ++ .../Constraint/Eloquent/ModelComparator.php | 11 +++++-- .../Constraint/Events/RequiresEventFake.php | 1 + src/Laravel/Doubles/Events/DummyEvent.php | 4 +-- .../Constraint/Callables/WasCalled.php | 1 + src/PHPUnit/Constraint/Spy.php | 1 + src/PHPUnit/DataProviders/EnumCase.php | 29 ++++++++++--------- .../DataProviders/QuantableConstraint.php | 18 ++++++------ src/PHPUnit/Doubles/CallableInvocation.php | 4 +-- src/PHPUnit/Doubles/SpyCallable.php | 14 ++++----- src/Saloon/Constraints/WasSent.php | 6 ++-- 15 files changed, 71 insertions(+), 62 deletions(-) diff --git a/src/Factories/ImmutableFactoryTest.php b/src/Factories/ImmutableFactoryTest.php index 9328cd6..5cb4ab4 100644 --- a/src/Factories/ImmutableFactoryTest.php +++ b/src/Factories/ImmutableFactoryTest.php @@ -12,6 +12,7 @@ use PHPUnit\Framework\TestCase; use stdClass; +use function array_keys; use function collect; use function count; use function mt_rand; @@ -351,7 +352,7 @@ public function itCanMakeManyWithNestedFactories(callable $resolveInstance, call /** * @param callable(ImmutableFactory): ImmutableFactory $resolveInstance - * @param callable(stdClass): void $assert + * @param callable(stdClass, int): mixed $assert */ #[Test] #[DataProvider('nestedFactories')] @@ -380,14 +381,14 @@ private function assertFactoryProperties( private function assertHasPropertyForEachDefinition(stdClass $result): void { - foreach ($this->instance->definition() as $attribute => $value) { + foreach (array_keys($this->instance->definition()) as $attribute) { self::assertObjectHasProperty($attribute, $result); } } private function assertHasArrayKeyForEachDefinition(array $result): void { - foreach ($this->instance->definition() as $attribute => $value) { + foreach (array_keys($this->instance->definition()) as $attribute) { self::assertArrayHasKey($attribute, $result); } } diff --git a/src/GraphQL/Constraints/HasErrorOnPath.php b/src/GraphQL/Constraints/HasErrorOnPath.php index 9b0a0eb..a6a2a98 100644 --- a/src/GraphQL/Constraints/HasErrorOnPath.php +++ b/src/GraphQL/Constraints/HasErrorOnPath.php @@ -16,9 +16,7 @@ final class HasErrorOnPath extends Constraint { - /** - * @var array> - */ + /** @var array> */ private static array $responseResolvers = []; public function __construct( @@ -26,9 +24,7 @@ public function __construct( public readonly string $category = 'graphql', ) {} - /** - * @param (callable(mixed): array)|null $resolveResponseUsing - */ + /** @param (callable(mixed): array)|null $resolveResponseUsing */ public static function resolveResponseUsing(?callable $resolveResponseUsing): void { if ($resolveResponseUsing === null) { @@ -70,7 +66,11 @@ protected function matches(mixed $other): bool ); } - foreach ($response['errors'] ?? [] as $error) { + if (!is_array($response['errors'] ?? null)) { + return false; + } + + foreach ($response['errors'] as $error) { $path = implode('.', $error['path'] ?? ''); $category = $error['extensions']['category'] ?? ''; @@ -88,9 +88,7 @@ protected function matches(mixed $other): bool return false; } - /** - * @return array|null - */ + /** @return array|null */ private function resolveResponse(mixed $other): ?array { foreach (self::$responseResolvers as $resolver) { diff --git a/src/Laravel/Constraint/Bus/HasHandler.php b/src/Laravel/Constraint/Bus/HasHandler.php index c542b73..22abfa9 100644 --- a/src/Laravel/Constraint/Bus/HasHandler.php +++ b/src/Laravel/Constraint/Bus/HasHandler.php @@ -6,13 +6,14 @@ use Craftzing\TestBench\PHPUnit\Constraint\ProvidesAdditionalFailureDescription; use Illuminate\Contracts\Bus\Dispatcher; -use Illuminate\Support\Facades\Bus; use InvalidArgumentException; use PHPUnit\Framework\Constraint\Constraint; use ReflectionClass; +use function app; use function class_exists; use function gettype; +use function is_object; use function is_string; final class HasHandler extends Constraint @@ -22,10 +23,10 @@ final class HasHandler extends Constraint private readonly Dispatcher $bus; public function __construct( - /* @var class-string */ + /** @var class-string */ private readonly string $handlerClassFQN, ) { - $this->bus = Bus::getFacadeRoot(); + $this->bus = app(Dispatcher::class); } protected function matches(mixed $other): bool @@ -43,6 +44,7 @@ protected function matches(mixed $other): bool } $message = new ReflectionClass($other)->newInstanceWithoutConstructor(); + /** @var object|string|false $actualHandler */ $actualHandler = $this->bus->getCommandHandler($message); if ($actualHandler === false) { @@ -51,7 +53,9 @@ protected function matches(mixed $other): bool return false; } - if ($actualHandler::class !== $this->handlerClassFQN) { + $actualHandlerClass = is_object($actualHandler) ? $actualHandler::class : $actualHandler; + + if ($actualHandlerClass !== $this->handlerClassFQN) { $this->additionalFailureDescriptions[] = "{$other} has a different handler mapped to it."; return false; diff --git a/src/Laravel/Constraint/Bus/WasHandled.php b/src/Laravel/Constraint/Bus/WasHandled.php index 88a0f29..fa813e8 100644 --- a/src/Laravel/Constraint/Bus/WasHandled.php +++ b/src/Laravel/Constraint/Bus/WasHandled.php @@ -11,7 +11,6 @@ use Craftzing\TestBench\PHPUnit\Doubles\SpyCallable; use Illuminate\Contracts\Bus\Dispatcher; use Illuminate\Contracts\Container\Container; -use Illuminate\Support\Facades\Bus; use Illuminate\Support\Traits\ReflectsClosures; use InvalidArgumentException; use LogicException; @@ -21,6 +20,7 @@ use PHPUnit\Framework\ExpectationFailedException; use ReflectionClass; +use function app; use function class_basename; use function class_exists; use function gettype; @@ -39,7 +39,7 @@ public function __construct( public readonly ?int $times = null, Constraint ...$constraints, ) { - $this->bus = Bus::getFacadeRoot(); + $this->bus = app(Dispatcher::class); $this->objectConstraints = $constraints; } @@ -77,6 +77,7 @@ protected function matches(mixed $other): bool $commandName => new ReflectionClass($other)->newInstanceWithoutConstructor(), default => $other, }; + // @mago-expect analyzer:possibly-invalid-argument $handler = $this->handler($command); try { diff --git a/src/Laravel/Constraint/Bus/WithoutBusMiddleware.php b/src/Laravel/Constraint/Bus/WithoutBusMiddleware.php index 78747f0..83ba9f5 100644 --- a/src/Laravel/Constraint/Bus/WithoutBusMiddleware.php +++ b/src/Laravel/Constraint/Bus/WithoutBusMiddleware.php @@ -8,6 +8,8 @@ trait WithoutBusMiddleware { + abstract public function afterApplicationCreated(callable $callback): void; + public function setUpWithoutBusMiddleware(): void { $this->afterApplicationCreated(static function (): void { diff --git a/src/Laravel/Constraint/Eloquent/ModelComparator.php b/src/Laravel/Constraint/Eloquent/ModelComparator.php index 44f72ba..2db93c8 100644 --- a/src/Laravel/Constraint/Eloquent/ModelComparator.php +++ b/src/Laravel/Constraint/Eloquent/ModelComparator.php @@ -26,8 +26,13 @@ public function assertEquals( bool $canonicalize = false, bool $ignoreCase = false, ): void { - $expected instanceof Model or throw self::notInstanceOfModel('expected', $expected); - $actual instanceof Model or throw self::notInstanceOfModel('actual', $actual); + if (!$expected instanceof Model) { + throw self::notInstanceOfModel('expected', $expected); + } + + if (!$actual instanceof Model) { + throw self::notInstanceOfModel('actual', $actual); + } if ($actual->isNot($expected)) { throw new ComparisonFailure( @@ -57,6 +62,6 @@ private function serializeModelForException(Model $model): string 'table' => $properties['table'], 'primaryKey' => $properties['primaryKey'], 'attributes' => $properties['attributes'], - ], JSON_PRETTY_PRINT); + ], JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR); } } diff --git a/src/Laravel/Constraint/Events/RequiresEventFake.php b/src/Laravel/Constraint/Events/RequiresEventFake.php index c3bc4ea..cbe6062 100644 --- a/src/Laravel/Constraint/Events/RequiresEventFake.php +++ b/src/Laravel/Constraint/Events/RequiresEventFake.php @@ -28,6 +28,7 @@ private function resolveEventFake(): EventFake ); } + // @mago-expect analyzer:mixed-return-statement return Event::getFacadeRoot(); } } diff --git a/src/Laravel/Doubles/Events/DummyEvent.php b/src/Laravel/Doubles/Events/DummyEvent.php index 0bf2c0e..800e998 100644 --- a/src/Laravel/Doubles/Events/DummyEvent.php +++ b/src/Laravel/Doubles/Events/DummyEvent.php @@ -9,9 +9,7 @@ */ final readonly class DummyEvent { - /** - * @var array - */ + /** @var array */ public array $arguments; public function __construct(mixed ...$arguments) diff --git a/src/PHPUnit/Constraint/Callables/WasCalled.php b/src/PHPUnit/Constraint/Callables/WasCalled.php index 3500b80..37751de 100644 --- a/src/PHPUnit/Constraint/Callables/WasCalled.php +++ b/src/PHPUnit/Constraint/Callables/WasCalled.php @@ -73,6 +73,7 @@ protected function matches(mixed $other): bool private function matchesInvocationAssertions(CallableInvocation $invocation): bool { try { + // @mago-expect analyzer:invalid-method-access $this->assertInvocation?->__invoke(...$invocation->arguments); } catch (ExpectationFailedException $expectationFailed) { $this->additionalFailureDescriptions[] = $expectationFailed->getMessage(); diff --git a/src/PHPUnit/Constraint/Spy.php b/src/PHPUnit/Constraint/Spy.php index a82a42c..e7e9378 100644 --- a/src/PHPUnit/Constraint/Spy.php +++ b/src/PHPUnit/Constraint/Spy.php @@ -10,6 +10,7 @@ final class Spy extends Constraint { private function __construct( + /** @var SpyCallable */ public readonly SpyCallable $matches, ) {} diff --git a/src/PHPUnit/DataProviders/EnumCase.php b/src/PHPUnit/DataProviders/EnumCase.php index 659c8be..df2f41b 100644 --- a/src/PHPUnit/DataProviders/EnumCase.php +++ b/src/PHPUnit/DataProviders/EnumCase.php @@ -4,6 +4,7 @@ namespace Craftzing\TestBench\PHPUnit\DataProviders; +use InvalidArgumentException; use LogicException; use ReflectionEnum; use ReflectionEnumUnitCase; @@ -16,14 +17,10 @@ use function count; use function in_array; -/** - * @template TValue of UnitEnum - */ +/** @template TValue of UnitEnum */ final readonly class EnumCase { - /** - * @var array - */ + /** @var array */ private array $options; /** @@ -49,9 +46,7 @@ public function __construct( $this->options = $options; } - /** - * @return TValue - */ + /** @return TValue */ public function differentInstance(): UnitEnum { if (count($this->options) <= 1) { @@ -67,13 +62,18 @@ public function differentInstance(): UnitEnum /** * @param class-string $enumFQCN - * @return iterable}> + * @return iterable>> */ public static function cases(string $enumFQCN): iterable { + if (!enum_exists($enumFQCN)) { + throw new InvalidArgumentException("Expected a concrete Enum class string, got: {$enumFQCN}"); + } + foreach (new ReflectionEnum($enumFQCN)->getCases() as $case) { - // @phpstan-ignore generator.valueType + // @mago-expect analyzer:invalid-yield-value-type yield "{$enumFQCN}::{$case->name}" => [ + // @mago-expect analyzer:possibly-static-access-on-interface new self($case->getValue(), ...$enumFQCN::cases()), ]; } @@ -81,21 +81,22 @@ public static function cases(string $enumFQCN): iterable /** * @param TValue ...$options - * @return iterable}> + * @return iterable>> */ public static function options(UnitEnum ...$options): iterable { foreach ($options as $case) { - yield "{$case->name}" => [new self($case, ...$options)]; + yield $case->name => [new self($case, ...$options)]; } } /** * @param class-string $enumFQCN - * @return iterable}> + * @return iterable>> */ public static function except(string $enumFQCN, UnitEnum ...$except): iterable { + /** @var TValue[] $options */ $options = array_map(static function (ReflectionEnumUnitCase $reflection) use ($except): ?UnitEnum { $case = $reflection->getValue(); diff --git a/src/PHPUnit/DataProviders/QuantableConstraint.php b/src/PHPUnit/DataProviders/QuantableConstraint.php index b54b4c3..fc6e67b 100644 --- a/src/PHPUnit/DataProviders/QuantableConstraint.php +++ b/src/PHPUnit/DataProviders/QuantableConstraint.php @@ -7,6 +7,7 @@ use Craftzing\TestBench\PHPUnit\Constraint\Quantable; use Illuminate\Support\Collection; +use function method_exists; use function random_int; final readonly class QuantableConstraint @@ -31,6 +32,11 @@ public function __construct( */ public function __invoke(Quantable $constraint): Quantable { + if (!method_exists($constraint, $this->method)) { + throw new \InvalidArgumentException(Quantable::class . "::{$this->method}() does not exist."); + } + + // @mago-expect analyzer:mixed-return-statement,string-member-selector return $constraint->{$this->method}($this->times); } @@ -39,27 +45,21 @@ public function applyTo(callable $callback): void Collection::times($this->times, $callback(...)); } - /** - * @return iterable - */ + /** @return iterable> */ public static function cases(): iterable { yield 'Never' => [new self('never', 0)]; yield from self::atLeastOnce(); } - /** - * @return iterable - */ + /** @return iterable> */ public static function atLeastOnce(): iterable { yield 'Multiple times' => [new self('times', random_int(2, max: 10))]; yield 'Once' => [new self('once', 1)]; } - /** - * @return iterable - */ + /** @return iterable> */ public static function tooFewOrTooManyTimes(): iterable { yield 'Too few times' => [new self('times', 2, 1)]; diff --git a/src/PHPUnit/Doubles/CallableInvocation.php b/src/PHPUnit/Doubles/CallableInvocation.php index e371aef..7b965f2 100644 --- a/src/PHPUnit/Doubles/CallableInvocation.php +++ b/src/PHPUnit/Doubles/CallableInvocation.php @@ -6,9 +6,7 @@ final readonly class CallableInvocation { - /** - * @var array - */ + /** @var array */ public array $arguments; public function __construct(mixed ...$arguments) diff --git a/src/PHPUnit/Doubles/SpyCallable.php b/src/PHPUnit/Doubles/SpyCallable.php index f170260..a67af29 100644 --- a/src/PHPUnit/Doubles/SpyCallable.php +++ b/src/PHPUnit/Doubles/SpyCallable.php @@ -7,28 +7,28 @@ use Craftzing\TestBench\PHPUnit\AssertsConstraints; use function call_user_func_array; -use function func_get_args; use function is_callable; +/** @template TReturn */ final class SpyCallable { use AssertsConstraints; - /** - * @var array - */ - public private(set) array $invocations = []; + /** @var array */ + private(set) array $invocations = []; public function __construct( + /** @var TReturn */ public readonly mixed $return = null, ) {} - public function __invoke(): mixed + /** @return TReturn */ + public function __invoke(mixed ...$arguments): mixed { - $arguments = func_get_args(); $this->invocations[] = new CallableInvocation(...$arguments); if (is_callable($this->return)) { + // @mago-expect analyzer:mixed-return-statement return call_user_func_array($this->return, $arguments); } diff --git a/src/Saloon/Constraints/WasSent.php b/src/Saloon/Constraints/WasSent.php index 8574f21..5aeaf3e 100644 --- a/src/Saloon/Constraints/WasSent.php +++ b/src/Saloon/Constraints/WasSent.php @@ -75,10 +75,7 @@ protected function matches(mixed $other): bool $matchingSentRequests = array_reduce( $this->client->getRecordedResponses(), - static function ( - array $matchingSentRequests, - Response $response, - ) use ($requestName): array { + static function (array $matchingSentRequests, Response $response) use ($requestName): array { $request = $response->getPendingRequest()->getRequest(); if ($request::class === $requestName) { @@ -132,6 +129,7 @@ public function toString(): string return 'was sent'; } + /** @param string|object $other */ protected function failureDescription(mixed $other): string { $message = parent::failureDescription($other); From c719d7edd0a733d61974e17afecb5d7d5331946a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Re=CC=81mi=20Pelhate?= Date: Fri, 5 Jun 2026 10:36:32 +0200 Subject: [PATCH 26/31] Remove redundant HasErrorOnPath::resolveResponseUsing() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was implementated to allow using the constraint on Laravel’s TestResponse object. However, there is no need for it. This can be solved by passing $response->json() instead of the TestResponse instance. --- composer.json | 5 -- src/GraphQL/Constraints/HasErrorOnPath.php | 40 +------------ .../Constraints/HasErrorOnPathTest.php | 56 ------------------- src/Laravel/ServiceProvider.php | 17 ------ src/Laravel/ServiceProviderTest.php | 45 --------------- 5 files changed, 3 insertions(+), 160 deletions(-) delete mode 100644 src/Laravel/ServiceProvider.php delete mode 100644 src/Laravel/ServiceProviderTest.php diff --git a/composer.json b/composer.json index ae1dfc5..ed57f5e 100644 --- a/composer.json +++ b/composer.json @@ -85,11 +85,6 @@ "extra": { "branch-alias": { "dev-main": "1.0.x-dev" - }, - "laravel": { - "providers": [ - "Craftzing\\TestBench\\Laravel\\ServiceProvider" - ] } } } diff --git a/src/GraphQL/Constraints/HasErrorOnPath.php b/src/GraphQL/Constraints/HasErrorOnPath.php index a6a2a98..423c8f7 100644 --- a/src/GraphQL/Constraints/HasErrorOnPath.php +++ b/src/GraphQL/Constraints/HasErrorOnPath.php @@ -7,7 +7,6 @@ use InvalidArgumentException; use Override; use PHPUnit\Framework\Constraint\Constraint; -use TypeError; use function gettype; use function implode; @@ -16,26 +15,11 @@ final class HasErrorOnPath extends Constraint { - /** @var array> */ - private static array $responseResolvers = []; - public function __construct( public readonly string $path, public readonly string $category = 'graphql', ) {} - /** @param (callable(mixed): array)|null $resolveResponseUsing */ - public static function resolveResponseUsing(?callable $resolveResponseUsing): void - { - if ($resolveResponseUsing === null) { - self::$responseResolvers = []; - - return; - } - - self::$responseResolvers[] = $resolveResponseUsing; - } - public function authentication(): self { return new self($this->path, 'authentication'); @@ -57,14 +41,10 @@ protected function matches(mixed $other): bool $response = match (true) { is_array($other) => $other, is_iterable($other) => iterator_to_array($other), - default => $this->resolveResponse($other), - }; - - if (is_array($response) === false) { - throw new InvalidArgumentException( + default => throw new InvalidArgumentException( self::class . ' can only be evaluated for iterable values, got ' . gettype($other) . '.', - ); - } + ), + }; if (!is_array($response['errors'] ?? null)) { return false; @@ -88,20 +68,6 @@ protected function matches(mixed $other): bool return false; } - /** @return array|null */ - private function resolveResponse(mixed $other): ?array - { - foreach (self::$responseResolvers as $resolver) { - try { - return $resolver($other); - } catch (TypeError) { - continue; - } - } - - return null; - } - public function toString(): string { return "has error on `{$this->path}` of category `{$this->category}`"; diff --git a/src/GraphQL/Constraints/HasErrorOnPathTest.php b/src/GraphQL/Constraints/HasErrorOnPathTest.php index 90f7ec6..6f65d55 100644 --- a/src/GraphQL/Constraints/HasErrorOnPathTest.php +++ b/src/GraphQL/Constraints/HasErrorOnPathTest.php @@ -5,10 +5,8 @@ namespace Craftzing\TestBench\GraphQL\Constraints; use Faker\Factory; -use Illuminate\Contracts\Support\Arrayable; use Illuminate\Support\Collection; use InvalidArgumentException; -use PHPUnit\Framework\Attributes\Before; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\Attributes\TestWith; @@ -20,12 +18,6 @@ */ final class HasErrorOnPathTest extends TestCase { - #[Before] - public function setupHasErrorOnPath(): void - { - HasErrorOnPath::resolveResponseUsing(null); - } - #[Test] public function itCanExpectErrorsOfCategoryAuthentication(): void { @@ -190,52 +182,4 @@ public function itPassesWhenErrorOnPathIsOfGivenCategory(string $path, string $c { $this->assertThat($response, new HasErrorOnPath($path, $category)); } - - #[Test] - public function itFailsWhenResponseCouldNotBeResolvedForSubject(): void - { - HasErrorOnPath::resolveResponseUsing(static fn(Arrayable $subject): array => $subject->toArray()); - $response = new readonly class { - public function toArray(): array - { - return []; - } - }; - - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage(HasErrorOnPath::class . ' can only be evaluated for iterable values'); - - $this->assertThat($response, new HasErrorOnPath('somePath')); - } - - #[Test] - public function itPassesResponseCouldBeResolvedForSubject(): void - { - HasErrorOnPath::resolveResponseUsing(static fn(Arrayable $subject): array => $subject->toArray()); - $category = Factory::create()->word(); - $path = 'somePath'; - - $response = new readonly class($path, $category) implements Arrayable { - public function __construct( - private string $path, - private string $category, - ) {} - - public function toArray(): array - { - return [ - 'errors' => [ - [ - 'path' => [$this->path], - 'extensions' => [ - 'category' => $this->category, - ], - ], - ], - ]; - } - }; - - $this->assertThat($response, new HasErrorOnPath($path, $category)); - } } diff --git a/src/Laravel/ServiceProvider.php b/src/Laravel/ServiceProvider.php deleted file mode 100644 index 8090da3..0000000 --- a/src/Laravel/ServiceProvider.php +++ /dev/null @@ -1,17 +0,0 @@ - $response->json()); - } -} diff --git a/src/Laravel/ServiceProviderTest.php b/src/Laravel/ServiceProviderTest.php deleted file mode 100644 index c425c82..0000000 --- a/src/Laravel/ServiceProviderTest.php +++ /dev/null @@ -1,45 +0,0 @@ - [ - [ - 'path' => [$path], - 'extensions' => [ - 'category' => $category, - ], - ], - ], - ]))); - - $this->assertThat($response, new HasErrorOnPath($path, $category)); - } -} From 3df525e4c61b0310ab6ef06099d6b8a84b4e0d6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Re=CC=81mi=20Pelhate?= Date: Fri, 5 Jun 2026 10:43:04 +0200 Subject: [PATCH 27/31] Fix last few analyzer issues --- src/Laravel/Constraint/Events/HasListener.php | 9 +++++---- .../Objects/DerivesConstraintsFromObjects.php | 17 +++++++++-------- src/Saloon/Constraints/WasSent.php | 1 - 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/Laravel/Constraint/Events/HasListener.php b/src/Laravel/Constraint/Events/HasListener.php index ac5cf8f..ff40c18 100644 --- a/src/Laravel/Constraint/Events/HasListener.php +++ b/src/Laravel/Constraint/Events/HasListener.php @@ -50,12 +50,13 @@ public static function instance(object $listener): self return new self($listener::class); } - /** - * @param array{object|class-string, string} $listen - */ + /** @param array{object|class-string, string} $listen */ public static function method(array $listen): self { - is_callable($listen) or throw new InvalidArgumentException('The given listener method is not callable.'); + if (!is_callable($listen)) { + throw new InvalidArgumentException('The given listener method is not callable.'); + } + [$listener, $method] = $listen; if (is_object($listener)) { diff --git a/src/PHPUnit/Constraint/Objects/DerivesConstraintsFromObjects.php b/src/PHPUnit/Constraint/Objects/DerivesConstraintsFromObjects.php index aa60d48..4335462 100644 --- a/src/PHPUnit/Constraint/Objects/DerivesConstraintsFromObjects.php +++ b/src/PHPUnit/Constraint/Objects/DerivesConstraintsFromObjects.php @@ -6,21 +6,18 @@ use PHPUnit\Framework\Constraint\Constraint; +use function is_object; use function is_string; trait DerivesConstraintsFromObjects { private static ?DeriveConstraintsFromObject $deriveConstraintsFromObject = null; - /** - * @var array - */ + /** @var array */ public readonly array $objectConstraints; - /** - * @return array - */ - public function givenOrDerivedObjectConstraints(string|object $expected): array + /** @return array */ + public function givenOrDerivedObjectConstraints(mixed $expected): array { if ($this->objectConstraints !== []) { return $this->objectConstraints; @@ -30,7 +27,11 @@ public function givenOrDerivedObjectConstraints(string|object $expected): array return []; } - return ( self::$deriveConstraintsFromObject ?? new DeriveConstraintsFromObjectUsingReflection() )($expected); + if (is_object($expected)) { + return ( self::$deriveConstraintsFromObject ?? new DeriveConstraintsFromObjectUsingReflection() )($expected); + } + + return []; } public static function deriveConstraintsFromObjectUsing( diff --git a/src/Saloon/Constraints/WasSent.php b/src/Saloon/Constraints/WasSent.php index 5aeaf3e..d13af45 100644 --- a/src/Saloon/Constraints/WasSent.php +++ b/src/Saloon/Constraints/WasSent.php @@ -129,7 +129,6 @@ public function toString(): string return 'was sent'; } - /** @param string|object $other */ protected function failureDescription(mixed $other): string { $message = parent::failureDescription($other); From e17e2cff0cf6fa27491fc53fd7492a1a0a9438fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Re=CC=81mi=20Pelhate?= Date: Fri, 5 Jun 2026 10:44:50 +0200 Subject: [PATCH 28/31] Fix tests --- src/PHPUnit/DataProviders/EnumCaseTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PHPUnit/DataProviders/EnumCaseTest.php b/src/PHPUnit/DataProviders/EnumCaseTest.php index 3d21327..61465fc 100644 --- a/src/PHPUnit/DataProviders/EnumCaseTest.php +++ b/src/PHPUnit/DataProviders/EnumCaseTest.php @@ -10,11 +10,11 @@ use Faker\Factory; use Faker\Generator; use Illuminate\Support\Arr; +use InvalidArgumentException; use LogicException; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; -use ReflectionException; use stdClass; use UnitEnum as UnitEnumInterface; use ValueError; @@ -130,7 +130,7 @@ public function itCannotReturnDifferentInstancesWithASingleOption(string $enumFQ #[Test] public function itCannotProvideFromNonEnumFQCNs(): void { - $this->expectException(ReflectionException::class); + $this->expectException(InvalidArgumentException::class); iterator_to_array(EnumCase::cases(stdClass::class)); } From cfa878ed3dbe39ff4f28fc91be64a351575a0321 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Re=CC=81mi=20Pelhate?= Date: Fri, 5 Jun 2026 10:52:20 +0200 Subject: [PATCH 29/31] Remove phpstan annotations --- src/Factories/ImmutableFactory.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Factories/ImmutableFactory.php b/src/Factories/ImmutableFactory.php index b553ef1..f4b47c7 100644 --- a/src/Factories/ImmutableFactory.php +++ b/src/Factories/ImmutableFactory.php @@ -35,7 +35,6 @@ final public function __construct( */ public function state(array $state): static { - // @phpstan-ignore-next-line return.type return new static($this->faker, [...$this->state, ...$state], $this->count); } @@ -44,7 +43,6 @@ public function state(array $state): static */ public function times(int $count): static { - // @phpstan-ignore-next-line return.type return new static($this->faker, $this->state, $count); } From d3de10f1f551bba5daf6072d6fc4da1e05ee4ca2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Re=CC=81mi=20Pelhate?= Date: Fri, 5 Jun 2026 10:52:32 +0200 Subject: [PATCH 30/31] Remove config files --- .gitattributes | 1 - .github/actions/php-cs-fixer/action.yml | 41 ------------------ .gitignore | 2 - .php-cs-fixer.dist.php | 55 ------------------------- phpstan.neon.dist | 9 ---- 5 files changed, 108 deletions(-) delete mode 100644 .github/actions/php-cs-fixer/action.yml delete mode 100644 .php-cs-fixer.dist.php delete mode 100644 phpstan.neon.dist diff --git a/.gitattributes b/.gitattributes index a143f13..d4fd5de 100644 --- a/.gitattributes +++ b/.gitattributes @@ -11,5 +11,4 @@ *.dist export-ignore *.md export-ignore *.yml export-ignore -.php-cs-fixer.dist.php export-ignore Taskfile.yml export-ignore diff --git a/.github/actions/php-cs-fixer/action.yml b/.github/actions/php-cs-fixer/action.yml deleted file mode 100644 index 2b6cbee..0000000 --- a/.github/actions/php-cs-fixer/action.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: PHP CS Fixer -description: Run PHP CS Fixer in a Docker container - -inputs: - workspace: - description: 'The workspace directory to mount in the container' - required: true - args: - description: 'Additional arguments to pass to php-cs-fixer' - required: false - default: '--allow-risky=yes' - github-token: - description: 'GitHub token for authenticating with GHCR' - required: true - -runs: - using: composite - steps: - - name: Login to GitHub Container Registry - shell: bash - run: echo "${{ inputs.github-token }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin - - - name: Pull a Craftzing owned image - shell: bash - run: docker pull ghcr.io/craftzing/docker-images/php:8.4 - - - name: Run php-cs-fixer inside the container - shell: bash - run: | - docker run --rm \ - -v "${{ inputs.workspace }}:/app" \ - -w /app \ - ghcr.io/craftzing/docker-images/php:8.4 \ - bash -c " - VERSION=3.88.2 && \ - wget https://github.com/FriendsOfPHP/PHP-CS-Fixer/releases/download/v\$VERSION/php-cs-fixer.phar -O php-cs-fixer && \ - chmod a+x php-cs-fixer && \ - mv php-cs-fixer /usr/local/bin/php-cs-fixer && \ - php-cs-fixer --version && \ - php-cs-fixer fix ${{ inputs.args }} - " diff --git a/.gitignore b/.gitignore index fb19485..229729c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,3 @@ /vendor /composer.lock /.phpunit.result.cache -/.php_cs.cache -/.php-cs-fixer.cache diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php deleted file mode 100644 index 1434259..0000000 --- a/.php-cs-fixer.dist.php +++ /dev/null @@ -1,55 +0,0 @@ -in([ - __DIR__ . '/src', - ]) - ->name('*.php') - ->ignoreDotFiles(true) - ->ignoreVCS(true); - -return (new Config()) - ->setParallelConfig(ParallelConfigFactory::detect()) - ->setRiskyAllowed(true) - ->setRules([ - '@PHP84Migration' => true, - 'array_syntax' => ['syntax' => 'short'], - 'ordered_imports' => [ - 'imports_order' => ['class', 'function', 'const'], - 'sort_algorithm' => 'alpha', - ], - 'fully_qualified_strict_types' => [ - 'phpdoc_tags' => [], - ], - 'no_unused_imports' => true, - 'blank_line_after_opening_tag' => true, - 'declare_strict_types' => true, - 'not_operator_with_successor_space' => true, - 'trailing_comma_in_multiline' => [ - 'elements' => ['arguments', 'arrays', 'match', 'parameters'], - ], - 'phpdoc_scalar' => true, - 'unary_operator_spaces' => true, - 'binary_operator_spaces' => true, - 'blank_line_before_statement' => [ - 'statements' => ['break', 'continue', 'declare', 'return', 'throw', 'try'], - ], - 'no_extra_blank_lines' => [ - 'tokens' => ['parenthesis_brace_block', 'return', 'square_brace_block', 'extra'], - ], - 'phpdoc_single_line_var_spacing' => true, - 'phpdoc_var_without_name' => true, - 'method_argument_space' => [ - 'on_multiline' => 'ensure_fully_multiline', - 'keep_multiple_spaces_after_comma' => true, - ], - 'void_return' => true, - 'single_quote' => true, - ]) - ->setFinder($finder); diff --git a/phpstan.neon.dist b/phpstan.neon.dist deleted file mode 100644 index 6e56e6e..0000000 --- a/phpstan.neon.dist +++ /dev/null @@ -1,9 +0,0 @@ -parameters: - level: 6 - paths: - - src - excludePaths: - - ./*/*Test.php - - ./*/Testing/* - ignoreErrors: - - '#is used zero times and is not analysed\.$#' From ef67bb256c4d5261c8174d71ee54f3e116fb0fd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Re=CC=81mi=20Pelhate?= Date: Fri, 5 Jun 2026 12:15:09 +0200 Subject: [PATCH 31/31] Preserve breaking member access chain --- mago.toml | 1 + src/Factories/ImmutableFactoryTest.php | 20 +++++++++++++++---- .../ProvidesAdditionalFailureDescription.php | 8 ++++---- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/mago.toml b/mago.toml index 8b84598..cbc5a53 100644 --- a/mago.toml +++ b/mago.toml @@ -22,6 +22,7 @@ preserve-breaking-argument-list = true preserve-breaking-parameter-list = true preserve-breaking-array-like = true preserve-breaking-attribute-list = true +preserve-breaking-member-access-chain = true [linter] integrations = ["phpunit"] diff --git a/src/Factories/ImmutableFactoryTest.php b/src/Factories/ImmutableFactoryTest.php index 5cb4ab4..65b2607 100644 --- a/src/Factories/ImmutableFactoryTest.php +++ b/src/Factories/ImmutableFactoryTest.php @@ -176,7 +176,10 @@ public function itCanReturnRawAttributesWithState(array $attributes, array $stat #[DataProvider('state')] public function itCanReturnManyRawAttributesWithState(array $attributes, array $state, array $expected): void { - $results = $this->instance->times(random_int(1, 10))->state($state)->rawMany($attributes); + $results = $this->instance + ->times(random_int(1, 10)) + ->state($state) + ->rawMany($attributes); collect($results)->each(function (array $result) use ($expected): void { collect($expected)->each(function (mixed $value, string $attribute) use ($result): void { @@ -190,7 +193,10 @@ public function itCanReturnManyRawAttributesWithState(array $attributes, array $ #[DataProvider('state')] public function itCanReturnRawAttributesCollectionsWithState(array $attributes, array $state, array $expected): void { - $results = $this->instance->times(random_int(1, 10))->state($state)->rawCollection($attributes); + $results = $this->instance + ->times(random_int(1, 10)) + ->state($state) + ->rawCollection($attributes); $results->each(function (array $result) use ($expected): void { collect($expected)->each(function (mixed $value, string $attribute) use ($result): void { @@ -217,7 +223,10 @@ public function itCanMakeOneWithState(array $attributes, array $state, array $ex #[DataProvider('state')] public function itCanMakeManyWithState(array $attributes, array $state, array $expected): void { - $results = $this->instance->times(random_int(1, 10))->state($state)->makeMany($attributes); + $results = $this->instance + ->times(random_int(1, 10)) + ->state($state) + ->makeMany($attributes); $this->assertContainsOnlyInstancesOf(stdClass::class, $results); collect($results)->each(function (stdClass $result) use ($expected): void { @@ -232,7 +241,10 @@ public function itCanMakeManyWithState(array $attributes, array $state, array $e #[DataProvider('state')] public function itCanMakeCollectionsWithState(array $attributes, array $state, array $expected): void { - $results = $this->instance->times(random_int(1, 10))->state($state)->makeCollection($attributes); + $results = $this->instance + ->times(random_int(1, 10)) + ->state($state) + ->makeCollection($attributes); $this->assertContainsOnlyInstancesOf(stdClass::class, $results); $results->each(function (stdClass $result) use ($expected): void { diff --git a/src/PHPUnit/Constraint/ProvidesAdditionalFailureDescription.php b/src/PHPUnit/Constraint/ProvidesAdditionalFailureDescription.php index 97f27bb..3efe079 100644 --- a/src/PHPUnit/Constraint/ProvidesAdditionalFailureDescription.php +++ b/src/PHPUnit/Constraint/ProvidesAdditionalFailureDescription.php @@ -9,14 +9,14 @@ trait ProvidesAdditionalFailureDescription { - /** - * @var array - */ + /** @var array */ private array $additionalFailureDescriptions = []; #[Override] protected function additionalFailureDescription(mixed $other): string { - return new Collection($this->additionalFailureDescriptions)->map(static fn(string $description): string => "\n* {$description}\n")->implode(''); + return new Collection($this->additionalFailureDescriptions) + ->map(static fn(string $description): string => "\n* {$description}\n") + ->implode(''); } }