mirror of
https://github.com/pestphp/pest.git
synced 2026-03-06 15:57:21 +01:00
170 lines
5.2 KiB
PHP
170 lines
5.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Pest\Expectations;
|
|
|
|
use Pest\Arch\Contracts\ArchExpectation;
|
|
use Pest\Arch\Expectations\ToBeUsedIn;
|
|
use Pest\Arch\Expectations\ToBeUsedInNothing;
|
|
use Pest\Arch\Expectations\ToUse;
|
|
use Pest\Arch\GroupArchExpectation;
|
|
use Pest\Arch\SingleArchExpectation;
|
|
use Pest\Exceptions\InvalidExpectation;
|
|
use Pest\Expectation;
|
|
use Pest\Support\Arr;
|
|
use Pest\Support\Exporter;
|
|
use PHPUnit\Framework\ExpectationFailedException;
|
|
|
|
/**
|
|
* @internal
|
|
*
|
|
* @template TValue
|
|
*
|
|
* @mixin Expectation<TValue>
|
|
*/
|
|
final class OppositeExpectation
|
|
{
|
|
/**
|
|
* Creates a new opposite expectation.
|
|
*
|
|
* @param Expectation<TValue> $original
|
|
*/
|
|
public function __construct(private readonly Expectation $original)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Asserts that the value array not has the provided $keys.
|
|
*
|
|
* @param array<int, int|string|array<int-string, mixed>> $keys
|
|
* @return Expectation<TValue>
|
|
*/
|
|
public function toHaveKeys(array $keys): Expectation
|
|
{
|
|
foreach ($keys as $k => $key) {
|
|
try {
|
|
if (is_array($key)) {
|
|
$this->toHaveKeys(array_keys(Arr::dot($key, $k.'.')));
|
|
} else {
|
|
$this->original->toHaveKey($key);
|
|
}
|
|
} catch (ExpectationFailedException) {
|
|
continue;
|
|
}
|
|
|
|
$this->throwExpectationFailedException('toHaveKey', [$key]);
|
|
}
|
|
|
|
return $this->original;
|
|
}
|
|
|
|
/**
|
|
* Asserts that the given expectation target does not use any of the given dependencies.
|
|
*
|
|
* @param array<int, string>|string $targets
|
|
*/
|
|
public function toUse(array|string $targets): ArchExpectation
|
|
{
|
|
return GroupArchExpectation::fromExpectations($this->original, array_map(fn (string $target): SingleArchExpectation => ToUse::make($this->original, $target)->opposite(
|
|
fn () => $this->throwExpectationFailedException('toUse', $target),
|
|
), is_string($targets) ? [$targets] : $targets));
|
|
}
|
|
|
|
/**
|
|
* @param array<int, string>|string $targets
|
|
*/
|
|
public function toOnlyUse(array|string $targets): never
|
|
{
|
|
throw InvalidExpectation::fromMethods(['not', 'toOnlyUse']);
|
|
}
|
|
|
|
public function toUseNothing(): never
|
|
{
|
|
throw InvalidExpectation::fromMethods(['not', 'toUseNothing']);
|
|
}
|
|
|
|
/**
|
|
* Asserts that the given expectation dependency is not used.
|
|
*/
|
|
public function toBeUsed(): ArchExpectation
|
|
{
|
|
return ToBeUsedInNothing::make($this->original);
|
|
}
|
|
|
|
/**
|
|
* Asserts that the given expectation dependency is not used by any of the given targets.
|
|
*
|
|
* @param array<int, string>|string $targets
|
|
*/
|
|
public function toBeUsedIn(array|string $targets): ArchExpectation
|
|
{
|
|
return GroupArchExpectation::fromExpectations($this->original, array_map(fn (string $target): GroupArchExpectation => ToBeUsedIn::make($this->original, $target)->opposite(
|
|
fn () => $this->throwExpectationFailedException('toBeUsedIn', $target),
|
|
), is_string($targets) ? [$targets] : $targets));
|
|
}
|
|
|
|
public function toOnlyBeUsedIn(): never
|
|
{
|
|
throw InvalidExpectation::fromMethods(['not', 'toOnlyBeUsedIn']);
|
|
}
|
|
|
|
/**
|
|
* Asserts that the given expectation dependency is not used.
|
|
*/
|
|
public function toBeUsedInNothing(): never
|
|
{
|
|
throw InvalidExpectation::fromMethods(['not', 'toBeUsedInNothing']);
|
|
}
|
|
|
|
/**
|
|
* Handle dynamic method calls into the original expectation.
|
|
*
|
|
* @param array<int, mixed> $arguments
|
|
* @return Expectation<TValue>|Expectation<mixed>|never
|
|
*/
|
|
public function __call(string $name, array $arguments): Expectation
|
|
{
|
|
try {
|
|
/* @phpstan-ignore-next-line */
|
|
$this->original->{$name}(...$arguments);
|
|
} catch (ExpectationFailedException) {
|
|
return $this->original;
|
|
}
|
|
|
|
$this->throwExpectationFailedException($name, $arguments);
|
|
}
|
|
|
|
/**
|
|
* Handle dynamic properties gets into the original expectation.
|
|
*
|
|
* @return Expectation<TValue>|Expectation<mixed>|never
|
|
*/
|
|
public function __get(string $name): Expectation
|
|
{
|
|
try {
|
|
$this->original->{$name}; // @phpstan-ignore-line
|
|
} catch (ExpectationFailedException) { // @phpstan-ignore-line
|
|
return $this->original;
|
|
}
|
|
|
|
$this->throwExpectationFailedException($name);
|
|
}
|
|
|
|
/**
|
|
* Creates a new expectation failed exception with a nice readable message.
|
|
*
|
|
* @param array<int, mixed>|string $arguments
|
|
*/
|
|
public function throwExpectationFailedException(string $name, array|string $arguments = []): never
|
|
{
|
|
$arguments = is_array($arguments) ? $arguments : [$arguments];
|
|
|
|
$exporter = Exporter::default();
|
|
|
|
$toString = fn ($argument): string => $exporter->shortenedExport($argument);
|
|
|
|
throw new ExpectationFailedException(sprintf('Expecting %s not %s %s.', $toString($this->original->value), strtolower((string) preg_replace('/(?<!\ )[A-Z]/', ' $0', $name)), implode(' ', array_map(fn ($argument): string => $toString($argument), $arguments))));
|
|
}
|
|
}
|