From f44834b728b44028fb7d99c4e3efc88b699728a8 Mon Sep 17 00:00:00 2001 From: Nuno Maduro Date: Mon, 24 Jul 2023 19:04:14 +0100 Subject: [PATCH] fix: assertion count --- src/Blueprint.php | 21 ++++++++--- src/Contracts/ArchExpectation.php | 19 ++++++++++ src/GroupArchExpectation.php | 21 +++++++++++ src/Options/LayerOptions.php | 5 ++- src/PendingArchExpectation.php | 14 +++++--- src/SingleArchExpectation.php | 22 +++++++++--- src/Support/AssertLocker.php | 53 ++++++++++++++++++++++++++++ tests/Fixtures/Contracts/NotUsed.php | 2 +- 8 files changed, 140 insertions(+), 17 deletions(-) create mode 100644 src/Support/AssertLocker.php diff --git a/src/Blueprint.php b/src/Blueprint.php index 8b21a3c..9208d73 100644 --- a/src/Blueprint.php +++ b/src/Blueprint.php @@ -8,6 +8,7 @@ use Pest\Arch\Factories\LayerFactory; use Pest\Arch\Options\LayerOptions; use Pest\Arch\Repositories\ObjectsRepository; +use Pest\Arch\Support\AssertLocker; use Pest\Arch\Support\Composer; use Pest\Arch\ValueObjects\Dependency; use Pest\Arch\ValueObjects\Targets; @@ -59,6 +60,8 @@ public static function make(Targets $target, Dependencies $dependencies): self */ public function expectToUse(LayerOptions $options, callable $failure): void { + AssertLocker::incrementAndLock(); + foreach ($this->target->value as $targetValue) { $targetLayer = $this->layerFactory->make($options, $targetValue); @@ -74,6 +77,8 @@ public function expectToUse(LayerOptions $options, callable $failure): void $failure($targetValue, $dependency->value); } } + + AssertLocker::unlock(); } /** @@ -85,6 +90,8 @@ public function expectToUse(LayerOptions $options, callable $failure): void */ public function targeted(callable $callback, LayerOptions $options, callable $failure, callable $lineFinder): void { + AssertLocker::incrementAndLock(); + foreach ($this->target->value as $targetValue) { $targetLayer = $this->layerFactory->make($options, $targetValue); @@ -96,8 +103,6 @@ public function targeted(callable $callback, LayerOptions $options, callable $fa } if ($callback($object)) { - self::assertTrue(true); - continue; } @@ -108,6 +113,8 @@ public function targeted(callable $callback, LayerOptions $options, callable $fa $failure(new Violation($path, $line, $line)); } } + + AssertLocker::unlock(); } /** @@ -117,6 +124,8 @@ public function targeted(callable $callback, LayerOptions $options, callable $fa */ public function expectToOnlyUse(LayerOptions $options, callable $failure): void { + AssertLocker::incrementAndLock(); + foreach ($this->target->value as $targetValue) { $allowedUses = array_merge( ...array_map(fn (Layer $layer): array => array_map( @@ -140,9 +149,9 @@ public function expectToOnlyUse(LayerOptions $options, callable $failure): void } } } - - self::assertTrue(true); } + + AssertLocker::unlock(); } /** @@ -152,6 +161,8 @@ public function expectToOnlyUse(LayerOptions $options, callable $failure): void */ public function expectToOnlyBeUsedIn(LayerOptions $options, callable $failure): void { + AssertLocker::incrementAndLock(); + foreach (Composer::userNamespaces() as $namespace) { $namespaceLayer = $this->layerFactory->make($options, $namespace); @@ -172,6 +183,8 @@ public function expectToOnlyBeUsedIn(LayerOptions $options, callable $failure): } } } + + AssertLocker::unlock(); } /** diff --git a/src/Contracts/ArchExpectation.php b/src/Contracts/ArchExpectation.php index bfa01fd..431b206 100644 --- a/src/Contracts/ArchExpectation.php +++ b/src/Contracts/ArchExpectation.php @@ -5,6 +5,7 @@ namespace Pest\Arch\Contracts; use Pest\Expectation; +use PHPUnit\Architecture\Elements\ObjectDescription; /** * @internal @@ -27,4 +28,22 @@ public function ignoring(array|string $targetsOrDependencies): self; * @return $this */ public function ignoringGlobalFunctions(): self; + + /** + * Merge the given exclude callbacks. + * + * @param array $callbacks + * + * @internal + */ + public function mergeExcludeCallbacks(array $callbacks): void; + + /** + * Returns the exclude callbacks. + * + * @return array + * + * @internal + */ + public function excludeCallbacks(): array; } diff --git a/src/GroupArchExpectation.php b/src/GroupArchExpectation.php index ee328a5..bf0d6d7 100644 --- a/src/GroupArchExpectation.php +++ b/src/GroupArchExpectation.php @@ -5,6 +5,7 @@ namespace Pest\Arch; use Closure; +use Pest\Arch\Contracts\ArchExpectation; use Pest\Expectation; /** @@ -100,6 +101,26 @@ public function __get(string $name): mixed return $this->original->$name; // @phpstan-ignore-line } + /** + * {@inheritDoc} + */ + public function mergeExcludeCallbacks(array $excludeCallbacks): void + { + foreach ($this->expectations as $expectation) { + $expectation->mergeExcludeCallbacks($excludeCallbacks); + } + } + + /** + * {@inheritDoc} + */ + public function excludeCallbacks(): array + { + return array_merge(...array_map( + fn (ArchExpectation $expectation): array => $expectation->excludeCallbacks(), $this->expectations, + )); + } + /** * Ensures the lazy expectation is verified when the object is destructed. */ diff --git a/src/Options/LayerOptions.php b/src/Options/LayerOptions.php index 908453d..f26160e 100644 --- a/src/Options/LayerOptions.php +++ b/src/Options/LayerOptions.php @@ -4,7 +4,6 @@ namespace Pest\Arch\Options; -use Closure; use Pest\Arch\SingleArchExpectation; use PHPUnit\Architecture\Elements\ObjectDescription; @@ -15,7 +14,7 @@ final class LayerOptions { /** * @param array $exclude - * @param array $excludeCallbacks + * @param array $excludeCallbacks */ private function __construct( public readonly array $exclude, @@ -34,6 +33,6 @@ public static function fromExpectation(SingleArchExpectation $expectation): self $expectation->ignoring, ); - return new self($exclude, $expectation->excludeCallbacks); + return new self($exclude, $expectation->excludeCallbacks()); } } diff --git a/src/PendingArchExpectation.php b/src/PendingArchExpectation.php index 4b571c6..80ebe14 100644 --- a/src/PendingArchExpectation.php +++ b/src/PendingArchExpectation.php @@ -7,6 +7,7 @@ use Closure; use Pest\Arch\Contracts\ArchExpectation; use Pest\Expectation; +use Pest\Expectations\HigherOrderExpectation; use PHPUnit\Architecture\Elements\ObjectDescription; /** @@ -37,7 +38,7 @@ public function __construct( */ public function classes(): self { - $this->excludeCallbacks[] = fn (ObjectDescription $object): bool => ! class_exists($object->name); + $this->excludeCallbacks[] = fn (ObjectDescription $object): bool => ! class_exists($object->name) || enum_exists($object->name); return $this; } @@ -94,10 +95,13 @@ public function __call(string $name, array $arguments): ArchExpectation /** @var $archExpectation SingleArchExpectation */ $archExpectation = $expectation->{$name}(...$arguments); // @phpstan-ignore-line - $archExpectation->excludeCallbacks = array_merge( - $archExpectation->excludeCallbacks, - $this->excludeCallbacks, - ); + if ($archExpectation instanceof HigherOrderExpectation) { + $originalExpectation = (fn (): \Pest\Expectation => $this->original)->call($archExpectation); + } else { + $originalExpectation = $archExpectation; + } + + $originalExpectation->mergeExcludeCallbacks($this->excludeCallbacks); return $archExpectation; } diff --git a/src/SingleArchExpectation.php b/src/SingleArchExpectation.php index a0d8424..97d2b67 100644 --- a/src/SingleArchExpectation.php +++ b/src/SingleArchExpectation.php @@ -41,11 +41,9 @@ final class SingleArchExpectation implements Contracts\ArchExpectation /** * The ignored list of layers. * - * @var array - * - * @internal + * @var array */ - public array $excludeCallbacks = []; + private array $excludeCallbacks = []; /** * Creates a new Arch Expectation instance. @@ -118,6 +116,22 @@ public function __get(string $name): mixed return $this->expectation->$name; // @phpstan-ignore-line } + /** + * {@inheritDoc} + */ + public function mergeExcludeCallbacks(array $callbacks): void + { + $this->excludeCallbacks = [...$this->excludeCallbacks, ...$callbacks]; + } + + /** + * {@inheritDoc} + */ + public function excludeCallbacks(): array + { + return $this->excludeCallbacks; + } + /** * Ensures the lazy expectation is verified when the object is destructed. */ diff --git a/src/Support/AssertLocker.php b/src/Support/AssertLocker.php new file mode 100644 index 0000000..b0aa5c5 --- /dev/null +++ b/src/Support/AssertLocker.php @@ -0,0 +1,53 @@ +setValue(null, self::$count); + } + + /** + * Gets the current assert count reflection. + */ + private static function reflection(): ReflectionProperty + { + $reflectionClass = new ReflectionClass(Assert::class); + + $property = $reflectionClass->getProperty('count'); + $property->setAccessible(true); + + return $property; + } +} diff --git a/tests/Fixtures/Contracts/NotUsed.php b/tests/Fixtures/Contracts/NotUsed.php index c9840fc..6e1e641 100644 --- a/tests/Fixtures/Contracts/NotUsed.php +++ b/tests/Fixtures/Contracts/NotUsed.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Tests\Fixtures\Contracts\Models; +namespace Tests\Fixtures\Contracts; interface NotUsed {