Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 5 additions & 12 deletions src/Laravel/Constraint/Bus/WasHandled.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,13 @@ protected function matches(mixed $other): bool
default => $other,
};
$handler = $this->handler($command);
$assertInvocation = match ($this->givenOrDerivedObjectConstraints($other)) {
[] => null,
default => $this->assertHandlerWasInvokedWithCommandConstraints(...),
};

try {
Assert::assertThat($handler, new WasCalled($assertInvocation, $this->times));
$handler->assert(new WasCalled(function (object $handled) use ($command): void {
foreach ($this->givenOrDerivedObjectConstraints($command) as $constraint) {
Assert::assertThat($handled, $constraint);
}
}, $this->times));
} catch (ExpectationFailedException $expectationFailed) {
$this->additionalFailureDescriptions[] = $expectationFailed->getMessage();

Expand All @@ -107,13 +107,6 @@ private function handler(object $command): SpyCallable
return $handler;
}

private function assertHandlerWasInvokedWithCommandConstraints(object $command): void
{
foreach ($this->givenOrDerivedObjectConstraints($command) as $constraint) {
Assert::assertThat($command, $constraint);
}
}

public function toString(): string
{
return 'command was handled';
Expand Down
34 changes: 33 additions & 1 deletion src/Laravel/Constraint/Bus/WasHandledTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

namespace Craftzing\TestBench\Laravel\Constraint\Bus;

use Craftzing\TestBench\PHPUnit\Constraint\Callables\WasCalled;
use Craftzing\TestBench\PHPUnit\Constraint\Objects\DeriveConstraintsFromObjectUsingFakes;
use Craftzing\TestBench\PHPUnit\Constraint\Objects\DeriveConstraintsFromObjectUsingReflection;
use Craftzing\TestBench\PHPUnit\Constraint\Spy;
use Craftzing\TestBench\PHPUnit\DataProviders\QuantableConstraint;
use Craftzing\TestBench\PHPUnit\Doubles\SpyCallable;
use Illuminate\Support\Facades\Bus;
Expand Down Expand Up @@ -269,7 +271,7 @@ public function itCanDeriveCommandConstraintsFromCommandObjectsUsingCustomImplem
}

#[Test]
public function itFailsWhenNotHandledWithDerivedCommandConstraints(): void
public function itFailsWhenHandledButNotWithDerivedCommandConstraints(): void
{
$command = new stdClass();
WasHandled::using(fn (stdClass $command): string => 'handled', $this->app);
Expand All @@ -293,4 +295,34 @@ public function itPassesWhenDispatchedWithDerivedCommandConstraints(): void

$this->assertThat($command, new WasHandled());
}

#[Test]
public function itDerivesConstraintsFromExpectedCommandsAndMatchesItAgainstActualCommands(): void
{
$expected = $this->command(['id' => 'expected']);
$actual = $this->command(['id' => 'actual']);
$constraint = Spy::passing();
$deriveConstraints = new DeriveConstraintsFromObjectUsingFakes([$constraint]);
WasHandled::deriveConstraintsFromObjectUsing($deriveConstraints);
WasHandled::using(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));
$constraint->matches->assert(new WasCalled()->withSame($actual));
$constraint->matches->assert(new WasCalled()->never()->withSame($expected));
}

private function command(array $properties): stdClass
{
$command = new stdClass();

foreach ($properties as $property => $value) {
$command->{$property} = $value;
}

return $command;
}
}
3 changes: 3 additions & 0 deletions src/Laravel/Constraint/Eloquent/ModelComparatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@

use function compact;

/**
* @codeCoverageIgnore
*/
final class ModelComparatorTest extends TestCase
{
public static function accepts(): iterable
Expand Down
12 changes: 12 additions & 0 deletions src/PHPUnit/Constraint/Callables/WasCalled.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Craftzing\TestBench\PHPUnit\Doubles\SpyCallable;
use InvalidArgumentException;
use Override;
use PHPUnit\Framework\Assert;
use PHPUnit\Framework\Constraint\Constraint;
use PHPUnit\Framework\ExpectationFailedException;

Expand All @@ -26,6 +27,17 @@ public function __construct(
public readonly ?int $times = null,
) {}

public function withSame(mixed ...$expected): self
{
return new self(function (mixed ...$actual) use ($expected): void {
Assert::assertCount(count($expected), $actual);

foreach ($actual as $key => $value) {
Assert::assertSame($expected[$key], $value);
}
}, $this->times);
}

public function times(int $count): self
{
return new self($this->assertInvocation, $count);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,21 @@

namespace Craftzing\TestBench\PHPUnit\Constraint\Objects;

use Craftzing\TestBench\PHPUnit\Doubles\SpyCallable;
use PHPUnit\Framework\Constraint\Callback;

final readonly class DeriveConstraintsFromObjectUsingFakes implements DeriveConstraintsFromObject
{
public SpyCallable $invoke;

/**
* @param array<\PHPUnit\Framework\Constraint\Constraint> $constraints
*/
public function __construct(
public array $constraints,
) {}
) {
$this->invoke = new SpyCallable();
}

public static function failingConstraints(): self
{
Expand All @@ -31,6 +36,8 @@ public static function passingConstraints(): self

public function __invoke(object $object): array
{
$this->invoke->__invoke($object);

return $this->constraints;
}
}
35 changes: 35 additions & 0 deletions src/PHPUnit/Constraint/Spy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

namespace Craftzing\TestBench\PHPUnit\Constraint;

use Craftzing\TestBench\PHPUnit\Doubles\SpyCallable;
use PHPUnit\Framework\Constraint\Constraint;

final class Spy extends Constraint
{
private function __construct(
public readonly SpyCallable $matches,
) {}

public static function passing(): self
{
return new self(new SpyCallable(true));
}

public static function failing(): self
{
return new self(new SpyCallable(false));
}

protected function matches(mixed $other): bool
{
return $this->matches->__invoke($other);
}

public function toString(): string
{
return 'constraint matches as Spy was configured to fail';
}
}
4 changes: 3 additions & 1 deletion src/PHPUnit/Doubles/SpyCallable.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Craftzing\TestBench\PHPUnit\AssertsConstraints;

use function call_user_func_array;
use function func_get_args;
use function is_callable;

final class SpyCallable
Expand All @@ -22,8 +23,9 @@ public function __construct(
public readonly mixed $return = null,
) {}

public function __invoke(mixed ...$arguments): mixed
public function __invoke(): mixed
{
$arguments = func_get_args();
$this->invocations[] = new CallableInvocation(...$arguments);

if (is_callable($this->return)) {
Expand Down