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
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;
}