Skip to content

Commit

Permalink
Merge pull request #12 from hungthai1401/feature/enum
Browse files Browse the repository at this point in the history
Enum support
  • Loading branch information
WendellAdriel authored Jun 8, 2023
2 parents 4b2ba1b + 2fc5ca2 commit 52fa9b5
Show file tree
Hide file tree
Showing 4 changed files with 293 additions and 0 deletions.
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,18 @@ $person = Strictus::object((object) ['name' => 'Wendell', 'country' => 'BR']);
//instantiates a class
$calculator = Strictus::instance(CalculatorClass::class, new CalculatorClass());

//instantiates an enum
$role = Strictus::enum(Role::class, Role::CONTRIBUTOR);

class CalculatorClass
{
//...
}

enum Role
{
case CONTRIBUTOR;
}
```

💡 Check out all the available [variable methods](#variable-methods).
Expand Down Expand Up @@ -218,6 +226,9 @@ You can use the following methods to create variables:
| Class Type | No | Strictus::instance($instanceType, $value) |
| Class Type | Yes | Strictus::instance($instanceType, $value, true) |
| Class Type | Yes | Strictus::nullableInstance($instanceType, $value) |
| Enum Type | No | Strictus::enum($enumType, $value) |
| Enum Type | Yes | Strictus::enum($enumType, $value, true) |
| Enum Type | Yes | Strictus::nullableEnum($enumType, $value) |

### Error Handling

Expand Down
11 changes: 11 additions & 0 deletions src/Strictus.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Strictus\Types\StrictusArray;
use Strictus\Types\StrictusBoolean;
use Strictus\Types\StrictusEnum;
use Strictus\Types\StrictusFloat;
use Strictus\Types\StrictusInstance;
use Strictus\Types\StrictusInteger;
Expand Down Expand Up @@ -83,4 +84,14 @@ public static function nullableInstance(string $instanceType, mixed $instance):
{
return new StrictusInstance($instanceType, $instance, true);
}

public static function enum(string $enumType, mixed $enum, bool $nullable = false): StrictusEnum
{
return new StrictusEnum($enumType, $enum, $nullable);
}

public static function nullableEnum(string $enumType, mixed $enum): StrictusEnum
{
return new StrictusEnum($enumType, $enum, true);
}
}
45 changes: 45 additions & 0 deletions src/Types/StrictusEnum.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

declare(strict_types=1);

namespace Strictus\Types;

use Strictus\Exceptions\StrictusTypeException;
use Strictus\Interfaces\StrictusTypeInterface;
use Strictus\Traits\StrictusTyping;

/**
* @internal
*/
final class StrictusEnum implements StrictusTypeInterface
{
use StrictusTyping;

private string $errorMessage;

public function __construct(private string $enumType, private mixed $value, private bool $nullable)
{
$this->errorMessage = 'Expected Enum Of ' . $this->enumType;

if ($this->nullable) {
$this->errorMessage .= ' Or Null';
}

$this->validate($value);
}

private function validate(mixed $value): void
{
if (false === enum_exists($this->enumType)) {
throw new StrictusTypeException('Invalid Enum Type');
}

if ($value === null && ! $this->nullable) {
throw new StrictusTypeException($this->errorMessage);
}

if ($value !== null && ! $value instanceof $this->enumType) {
throw new StrictusTypeException($this->errorMessage);
}
}
}
226 changes: 226 additions & 0 deletions tests/Unit/EnumTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
<?php

declare(strict_types=1);

use Strictus\Exceptions\StrictusTypeException;
use Strictus\Strictus;
use Strictus\Types\StrictusEnum;

it('instantiates variable', function () {
expect(Strictus::enum(MyEnum::class, MyEnum::BAR))
->toBeInstanceOf(StrictusEnum::class)
->and(Strictus::enum(MyBackedEnum::class, MyBackedEnum::BAZ))
->toBeInstanceOf(StrictusEnum::class);
});

it('instantiates a nullable variable', function () {
expect(Strictus::enum(MyEnum::class, null, true))
->toBeInstanceOf(StrictusEnum::class)
->and(Strictus::nullableEnum(MyEnum::class, null))
->toBeInstanceOf(StrictusEnum::class)
->and(Strictus::enum(MyBackedEnum::class, null, true))
->toBeInstanceOf(StrictusEnum::class)
->and(Strictus::nullableEnum(MyBackedEnum::class, null))
->toBeInstanceOf(StrictusEnum::class);
});

it('throws exception when trying to instantiate variable with wrong enum type', function () {
expect(fn () => Strictus::enum('foo', MyEnum::FOO))
->toThrow(StrictusTypeException::class);
});

it('throws exception when trying to instantiate non-nullable variable with null', function () {
expect(fn () => Strictus::enum(MyClass::class, null))
->toThrow(StrictusTypeException::class)
->and(fn () => Strictus::enum(MyBackedEnum::class, null))
->toThrow(StrictusTypeException::class);
});

it('throws exception when trying to instantiate variable with wrong enum', function () {
expect(fn () => Strictus::enum(MyEnum::class, 'foo'))
->toThrow(StrictusTypeException::class)
->and(fn () => Strictus::enum(MyBackedEnum::class, 'foo'))
->toThrow(StrictusTypeException::class);
});

it('returns the value correctly', function () {
$value = Strictus::enum(MyEnum::class, MyEnum::FOO);

expect($value)
->toBeInstanceOf(StrictusEnum::class)
->and($value->value)
->toBeInstanceOf(MyEnum::class)
->toEqual(MyEnum::FOO)
->and($value->value->name)
->toEqual(MyEnum::FOO->name)
->and($value())
->toBeInstanceOf(MyEnum::class)
->toEqual(MyEnum::FOO)
->and($value()->name)
->toEqual(MyEnum::FOO->name);

$backedEnumValue = Strictus::enum(MyBackedEnum::class, MyBackedEnum::BAZ);

expect($backedEnumValue)
->toBeInstanceOf(StrictusEnum::class)
->and($backedEnumValue->value)
->toBeInstanceOf(MyBackedEnum::class)
->toEqual(MyBackedEnum::BAZ)
->and($backedEnumValue->value->name)
->toEqual(MyBackedEnum::BAZ->name)
->and($backedEnumValue->value->value)
->toEqual(MyBackedEnum::BAZ->value)
->and($backedEnumValue())
->toBeInstanceOf(MyBackedEnum::class)
->toEqual(MyBackedEnum::BAZ)
->and($backedEnumValue()->name)
->toEqual(MyBackedEnum::BAZ->name)
->and($backedEnumValue()->value)
->toEqual(MyBackedEnum::BAZ->value);
});

it('updates the value correctly', function () {
$value = Strictus::enum(MyEnum::class, MyEnum::FOO);

expect($value)
->toBeInstanceOf(StrictusEnum::class)
->and($value->value)
->toBeInstanceOf(MyEnum::class)
->toEqual(MyEnum::FOO)
->and($value->value->name)
->toEqual(MyEnum::FOO->name)
->and($value())
->toBeInstanceOf(MyEnum::class)
->toEqual(MyEnum::FOO)
->and($value()->name)
->toEqual(MyEnum::FOO->name);

$value->value = MyEnum::BAR;
expect($value->value)
->toBeInstanceOf(MyEnum::class)
->toEqual(MyEnum::BAR)
->and($value->value->name)
->toEqual(MyEnum::BAR->name);

$value(MyEnum::BAR);
expect($value())
->toBeInstanceOf(MyEnum::class)
->toEqual(MyEnum::BAR)
->and($value()->name)
->toEqual(MyEnum::BAR->name);

$backedEnumValue = Strictus::enum(MyBackedEnum::class, MyBackedEnum::BAZ);

expect($backedEnumValue)
->toBeInstanceOf(StrictusEnum::class)
->and($backedEnumValue->value)
->toBeInstanceOf(MyBackedEnum::class)
->toEqual(MyBackedEnum::BAZ)
->and($backedEnumValue->value->name)
->toEqual(MyBackedEnum::BAZ->name)
->and($backedEnumValue->value->value)
->toEqual(MyBackedEnum::BAZ->value)
->and($backedEnumValue())
->toBeInstanceOf(MyBackedEnum::class)
->toEqual(MyBackedEnum::BAZ)
->and($backedEnumValue()->name)
->toEqual(MyBackedEnum::BAZ->name)
->and($backedEnumValue()->value)
->toEqual(MyBackedEnum::BAZ->value);

$backedEnumValue->value = MyBackedEnum::BAZZ;
expect($backedEnumValue->value)
->toBeInstanceOf(MyBackedEnum::class)
->and($backedEnumValue->value->value)
->toEqual(MyBackedEnum::BAZZ->value);

$backedEnumValue(MyBackedEnum::BAZZ);
expect($backedEnumValue())
->toBeInstanceOf(MyBackedEnum::class)
->and($backedEnumValue()->value)
->toEqual(MyBackedEnum::BAZZ->value);
});

it('updates the nullable value to enum correctly', function () {
$value = Strictus::nullableEnum(MyEnum::class, null);

expect($value->value)
->toBeNull()
->and($value())
->toBeNull();

$value->value = MyEnum::BAR;
expect($value->value)
->toBeInstanceOf(MyEnum::class)
->toEqual(MyEnum::BAR);

$value(MyEnum::BAR);
expect($value())
->toBeInstanceOf(MyEnum::class)
->toEqual(MyEnum::BAR);

$backedEnumValue = Strictus::nullableEnum(MyBackedEnum::class, null);

expect($backedEnumValue->value)
->toBeNull()
->and($backedEnumValue())
->toBeNull();

$backedEnumValue->value = MyBackedEnum::BAZ;
expect($backedEnumValue->value)
->toBeInstanceOf(MyBackedEnum::class)
->toEqual(MyBackedEnum::BAZ);

$backedEnumValue(MyBackedEnum::BAZ);
expect($backedEnumValue())
->toBeInstanceOf(MyBackedEnum::class)
->toEqual(MyBackedEnum::BAZ);
});

it('updates the enum value to nullable correctly', function () {
$value = Strictus::enum(MyEnum::class, MyEnum::FOO, true);

expect($value->value)
->toBeInstanceOf(MyEnum::class)
->toEqual(MyEnum::FOO)
->and($value())
->toBeInstanceOf(MyEnum::class)
->toEqual(MyEnum::FOO);

$value->value = null;
expect($value->value)
->toBeNull();

$value(null);
expect($value())
->toBeNull();

$backedEnumValue = Strictus::enum(MyBackedEnum::class, MyBackedEnum::BAZZ, true);

expect($backedEnumValue->value)
->toBeInstanceOf(MyBackedEnum::class)
->toEqual(MyBackedEnum::BAZZ)
->and($backedEnumValue())
->toBeInstanceOf(MyBackedEnum::class)
->toEqual(MyBackedEnum::BAZZ);

$backedEnumValue->value = null;
expect($backedEnumValue->value)
->toBeNull();

$backedEnumValue(null);
expect($backedEnumValue())
->toBeNull();
});

enum MyEnum
{
case FOO;
case BAR;
}

enum MyBackedEnum: int
{
case BAZ = 1;
case BAZZ = 2;
}

0 comments on commit 52fa9b5

Please sign in to comment.