|string> */ final class SingleArchExpectation implements Contracts\ArchExpectation { /** * The "opposite" callback. */ private ?Closure $opposite = null; /** * Whether the expectation has been verified. */ private bool $lazyExpectationVerified = false; /** * The ignored list of layers. * * @var array */ public array $ignoring = []; /** * The ignored list of layers. * * @var array */ private array $excludeCallbacks = []; /** * Creates a new Arch Expectation instance. * * @param Expectation|string> $expectation */ private function __construct(private readonly Expectation $expectation, private readonly Closure $lazyExpectation) { // ... } /** * {@inheritDoc} */ public function ignoring(array|string $targetsOrDependencies): self { $targetsOrDependencies = is_array($targetsOrDependencies) ? $targetsOrDependencies : [$targetsOrDependencies]; $this->ignoring = array_unique([...$this->ignoring, ...$targetsOrDependencies]); return $this; } /** * {@inheritDoc} */ public function ignoringGlobalFunctions(): self { return $this->ignoring(UserDefinedFunctions::get()); } /** * Sets the "opposite" callback. */ public function opposite(Closure $callback): self { $this->opposite = $callback; return $this; } /** * Creates a new Arch Expectation instance from the given expectation. * * @param Expectation|string> $expectation */ public static function fromExpectation(Expectation $expectation, Closure $lazyExpectation): self { return new self($expectation, $lazyExpectation); } /** * Proxies the call to the expectation. * * @param array $arguments * @return Expectation */ public function __call(string $name, array $arguments): mixed { $this->ensureLazyExpectationIsVerified(); return $this->expectation->$name(...$arguments); // @phpstan-ignore-line } /** * Proxies the call to the expectation. * * @return Expectation */ public function __get(string $name): mixed { $this->ensureLazyExpectationIsVerified(); return $this->expectation->$name; // @phpstan-ignore-line } /** * {@inheritDoc} */ public function mergeExcludeCallbacks(array $callbacks): void { $this->excludeCallbacks = [...$this->excludeCallbacks, ...$callbacks]; } /** * {@inheritDoc} * * @return array */ public function excludeCallbacks(): array { return $this->excludeCallbacks; } /** * Ensures the lazy expectation is verified when the object is destructed. */ public function __destruct() { $this->ensureLazyExpectationIsVerified(); } /** * Ensures the lazy expectation is verified. */ public function ensureLazyExpectationIsVerified(): void { if (TestSuite::getInstance()->test instanceof TestCase && ! $this->lazyExpectationVerified) { $this->lazyExpectationVerified = true; $e = null; $options = LayerOptions::fromExpectation($this); try { ($this->lazyExpectation)($options); } catch (ExpectationFailedException|AssertionFailedError $e) { if (! $this->opposite instanceof \Closure) { throw $e; } } if (! $this->opposite instanceof Closure) { return; } if (! is_null($e)) { return; } ($this->opposite)(); // @phpstan-ignore-line } } }