diff --git a/src/PHPUnit/DataProviders/EnumCase.php b/src/PHPUnit/DataProviders/EnumCase.php index 86f06a4..096836b 100644 --- a/src/PHPUnit/DataProviders/EnumCase.php +++ b/src/PHPUnit/DataProviders/EnumCase.php @@ -4,44 +4,33 @@ namespace Craftzing\TestBench\PHPUnit\DataProviders; +use LogicException; use ReflectionEnum; use UnitEnum; use ValueError; +use function array_filter; use function array_rand; -use function array_search; use function count; +use function in_array; /** * @template TValue of UnitEnum */ -final class EnumCase +final readonly class EnumCase { /** * @var array */ - private readonly array $options; + private array $options; - private int|string $instanceKeyInOptions { - get { - $key = array_search($this->instance, $this->options, true); - - return match ($key) { - false => '', - default => $key, - }; - } - } - - /** - * @param TValue $instance - * @param array ...$options - */ public function __construct( - public readonly UnitEnum $instance, + /* @var TValue */ + public UnitEnum $instance, + /* @param array ...$options */ UnitEnum ...$options, ) { - count($options) >= 2 or throw new ValueError('At least 2 options should should be given.'); + in_array($instance, $options, true) or throw new ValueError('Options should contain the given instance.'); foreach ($options as $option) { $option::class === $instance::class or throw new ValueError( @@ -57,9 +46,10 @@ public function __construct( */ public function differentInstance(): UnitEnum { - $differentOptions = $this->options; - - unset($differentOptions[$this->instanceKeyInOptions]); + 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); return $differentOptions[array_rand($differentOptions)]; } diff --git a/src/PHPUnit/DataProviders/EnumCaseTest.php b/src/PHPUnit/DataProviders/EnumCaseTest.php index 10fa961..7f005ff 100644 --- a/src/PHPUnit/DataProviders/EnumCaseTest.php +++ b/src/PHPUnit/DataProviders/EnumCaseTest.php @@ -9,6 +9,8 @@ use Craftzing\TestBench\PHPUnit\Doubles\Enums\UnitEnum; use Faker\Factory; use Faker\Generator; +use Illuminate\Support\Arr; +use LogicException; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; @@ -48,58 +50,81 @@ public static function enumFQCNs(): iterable #[Test] #[DataProvider('enumFQCNs')] /** @param class-string $enumFQCN */ - public function itCannotConstructWithoutAtLeastTwoOptions(string $enumFQCN): void + public function itCannotConstructWhenInstanceIsNotInOptions(string $enumFQCN): void { - $cases = $enumFQCN::cases(); + $options = $enumFQCN::cases(); + $case = Arr::pull($options, array_rand($options)); $this->expectException(ValueError::class); - new EnumCase( - $this->faker->randomElement($cases), - $this->faker->randomElement($cases), - ); + new EnumCase($case, ...$options); } #[Test] #[DataProvider('enumFQCNs')] /** @param class-string $enumFQCN */ public function itCannotConstructWhenOptionsHaveDifferentTypeComparedToGivenInstance(string $enumFQCN): void { - $cases = $enumFQCN::cases(); - $case = $this->faker->randomElement($cases); + $options = $enumFQCN::cases(); + $instance = $this->faker->randomElement($options); $differentEnumFQCN = $this->faker->randomElement(array_filter( self::ENUM_FQCNS, - fn (string $enumFQCN): bool => $enumFQCN !== $case::class, + fn (string $enumFQCN): bool => $enumFQCN !== $instance::class, )); - $differentEnumCase = $this->faker->randomElement($differentEnumFQCN::cases()); + $differentEnumInstance = $this->faker->randomElement($differentEnumFQCN::cases()); $this->expectException(ValueError::class); - new EnumCase($case, $differentEnumCase, $differentEnumCase); + new EnumCase($instance, $differentEnumInstance, $differentEnumInstance); } #[Test] #[DataProvider('enumFQCNs')] /** @param class-string $enumFQCN */ - public function itCanConstructWithOptions(string $enumFQCN): void + public function itCanConstructWithSingleOption(string $enumFQCN): void { - $cases = $enumFQCN::cases(); - $case = $cases[array_rand($cases)]; + $options = $enumFQCN::cases(); + $instance = $options[array_rand($options)]; - $provider = new EnumCase($case, ...$cases); + $provider = new EnumCase($instance, $instance); - $this->assertSame($case, $provider->instance); + $this->assertSame($instance, $provider->instance); + } + + #[Test] + #[DataProvider('enumFQCNs')] /** @param class-string $enumFQCN */ + public function itCanConstructWithMultipleOptions(string $enumFQCN): void + { + $options = $enumFQCN::cases(); + $instance = $options[array_rand($options)]; + + $provider = new EnumCase($instance, ...$options); + + $this->assertSame($instance, $provider->instance); } #[Test] #[DataProvider('enumFQCNs')] /** @param class-string $enumFQCN */ public function itCanReturnDifferentInstances(string $enumFQCN): void { - $cases = $enumFQCN::cases(); - $case = $cases[array_rand($cases)]; + $options = $enumFQCN::cases(); + $instance = $options[array_rand($options)]; + $provider = new EnumCase($instance, ...$options); + + $differentInstance = $provider->differentInstance(); + + $this->assertNotEquals($instance, $differentInstance); + } + + #[Test] + #[DataProvider('enumFQCNs')] /** @param class-string $enumFQCN */ + public function itCannotReturnDifferentInstancesWithASingleOption(string $enumFQCN): void + { + $options = $enumFQCN::cases(); + $instance = $options[array_rand($options)]; + $provider = new EnumCase($instance, $instance); - $provider = new EnumCase($case, ...$cases); + $this->expectException(LogicException::class); - $this->assertSame($case, $provider->instance); - $this->assertNotEquals($case, $provider->differentInstance()); + $provider->differentInstance(); } #[Test]