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
36 changes: 13 additions & 23 deletions src/PHPUnit/DataProviders/EnumCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -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<int, TValue>
*/
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<int, TValue> ...$options
*/
public function __construct(
public readonly UnitEnum $instance,
/* @var TValue */
public UnitEnum $instance,
/* @param array<int, TValue> ...$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(
Expand All @@ -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)];
}
Expand Down
67 changes: 46 additions & 21 deletions src/PHPUnit/DataProviders/EnumCaseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -48,58 +50,81 @@ public static function enumFQCNs(): iterable

#[Test]
#[DataProvider('enumFQCNs')] /** @param class-string<UnitEnumInterface> $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<UnitEnumInterface> $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<UnitEnumInterface> $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<UnitEnumInterface> $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<UnitEnumInterface> $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<UnitEnumInterface> $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]
Expand Down