Skip to content

Commit 52fa9b5

Browse files
Merge pull request #12 from hungthai1401/feature/enum
Enum support
2 parents 4b2ba1b + 2fc5ca2 commit 52fa9b5

File tree

4 files changed

+293
-0
lines changed

4 files changed

+293
-0
lines changed

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,10 +131,18 @@ $person = Strictus::object((object) ['name' => 'Wendell', 'country' => 'BR']);
131131
//instantiates a class
132132
$calculator = Strictus::instance(CalculatorClass::class, new CalculatorClass());
133133

134+
//instantiates an enum
135+
$role = Strictus::enum(Role::class, Role::CONTRIBUTOR);
136+
134137
class CalculatorClass
135138
{
136139
//...
137140
}
141+
142+
enum Role
143+
{
144+
case CONTRIBUTOR;
145+
}
138146
```
139147

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

222233
### Error Handling
223234

src/Strictus.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Strictus\Types\StrictusArray;
88
use Strictus\Types\StrictusBoolean;
9+
use Strictus\Types\StrictusEnum;
910
use Strictus\Types\StrictusFloat;
1011
use Strictus\Types\StrictusInstance;
1112
use Strictus\Types\StrictusInteger;
@@ -83,4 +84,14 @@ public static function nullableInstance(string $instanceType, mixed $instance):
8384
{
8485
return new StrictusInstance($instanceType, $instance, true);
8586
}
87+
88+
public static function enum(string $enumType, mixed $enum, bool $nullable = false): StrictusEnum
89+
{
90+
return new StrictusEnum($enumType, $enum, $nullable);
91+
}
92+
93+
public static function nullableEnum(string $enumType, mixed $enum): StrictusEnum
94+
{
95+
return new StrictusEnum($enumType, $enum, true);
96+
}
8697
}

src/Types/StrictusEnum.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Strictus\Types;
6+
7+
use Strictus\Exceptions\StrictusTypeException;
8+
use Strictus\Interfaces\StrictusTypeInterface;
9+
use Strictus\Traits\StrictusTyping;
10+
11+
/**
12+
* @internal
13+
*/
14+
final class StrictusEnum implements StrictusTypeInterface
15+
{
16+
use StrictusTyping;
17+
18+
private string $errorMessage;
19+
20+
public function __construct(private string $enumType, private mixed $value, private bool $nullable)
21+
{
22+
$this->errorMessage = 'Expected Enum Of ' . $this->enumType;
23+
24+
if ($this->nullable) {
25+
$this->errorMessage .= ' Or Null';
26+
}
27+
28+
$this->validate($value);
29+
}
30+
31+
private function validate(mixed $value): void
32+
{
33+
if (false === enum_exists($this->enumType)) {
34+
throw new StrictusTypeException('Invalid Enum Type');
35+
}
36+
37+
if ($value === null && ! $this->nullable) {
38+
throw new StrictusTypeException($this->errorMessage);
39+
}
40+
41+
if ($value !== null && ! $value instanceof $this->enumType) {
42+
throw new StrictusTypeException($this->errorMessage);
43+
}
44+
}
45+
}

tests/Unit/EnumTest.php

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Strictus\Exceptions\StrictusTypeException;
6+
use Strictus\Strictus;
7+
use Strictus\Types\StrictusEnum;
8+
9+
it('instantiates variable', function () {
10+
expect(Strictus::enum(MyEnum::class, MyEnum::BAR))
11+
->toBeInstanceOf(StrictusEnum::class)
12+
->and(Strictus::enum(MyBackedEnum::class, MyBackedEnum::BAZ))
13+
->toBeInstanceOf(StrictusEnum::class);
14+
});
15+
16+
it('instantiates a nullable variable', function () {
17+
expect(Strictus::enum(MyEnum::class, null, true))
18+
->toBeInstanceOf(StrictusEnum::class)
19+
->and(Strictus::nullableEnum(MyEnum::class, null))
20+
->toBeInstanceOf(StrictusEnum::class)
21+
->and(Strictus::enum(MyBackedEnum::class, null, true))
22+
->toBeInstanceOf(StrictusEnum::class)
23+
->and(Strictus::nullableEnum(MyBackedEnum::class, null))
24+
->toBeInstanceOf(StrictusEnum::class);
25+
});
26+
27+
it('throws exception when trying to instantiate variable with wrong enum type', function () {
28+
expect(fn () => Strictus::enum('foo', MyEnum::FOO))
29+
->toThrow(StrictusTypeException::class);
30+
});
31+
32+
it('throws exception when trying to instantiate non-nullable variable with null', function () {
33+
expect(fn () => Strictus::enum(MyClass::class, null))
34+
->toThrow(StrictusTypeException::class)
35+
->and(fn () => Strictus::enum(MyBackedEnum::class, null))
36+
->toThrow(StrictusTypeException::class);
37+
});
38+
39+
it('throws exception when trying to instantiate variable with wrong enum', function () {
40+
expect(fn () => Strictus::enum(MyEnum::class, 'foo'))
41+
->toThrow(StrictusTypeException::class)
42+
->and(fn () => Strictus::enum(MyBackedEnum::class, 'foo'))
43+
->toThrow(StrictusTypeException::class);
44+
});
45+
46+
it('returns the value correctly', function () {
47+
$value = Strictus::enum(MyEnum::class, MyEnum::FOO);
48+
49+
expect($value)
50+
->toBeInstanceOf(StrictusEnum::class)
51+
->and($value->value)
52+
->toBeInstanceOf(MyEnum::class)
53+
->toEqual(MyEnum::FOO)
54+
->and($value->value->name)
55+
->toEqual(MyEnum::FOO->name)
56+
->and($value())
57+
->toBeInstanceOf(MyEnum::class)
58+
->toEqual(MyEnum::FOO)
59+
->and($value()->name)
60+
->toEqual(MyEnum::FOO->name);
61+
62+
$backedEnumValue = Strictus::enum(MyBackedEnum::class, MyBackedEnum::BAZ);
63+
64+
expect($backedEnumValue)
65+
->toBeInstanceOf(StrictusEnum::class)
66+
->and($backedEnumValue->value)
67+
->toBeInstanceOf(MyBackedEnum::class)
68+
->toEqual(MyBackedEnum::BAZ)
69+
->and($backedEnumValue->value->name)
70+
->toEqual(MyBackedEnum::BAZ->name)
71+
->and($backedEnumValue->value->value)
72+
->toEqual(MyBackedEnum::BAZ->value)
73+
->and($backedEnumValue())
74+
->toBeInstanceOf(MyBackedEnum::class)
75+
->toEqual(MyBackedEnum::BAZ)
76+
->and($backedEnumValue()->name)
77+
->toEqual(MyBackedEnum::BAZ->name)
78+
->and($backedEnumValue()->value)
79+
->toEqual(MyBackedEnum::BAZ->value);
80+
});
81+
82+
it('updates the value correctly', function () {
83+
$value = Strictus::enum(MyEnum::class, MyEnum::FOO);
84+
85+
expect($value)
86+
->toBeInstanceOf(StrictusEnum::class)
87+
->and($value->value)
88+
->toBeInstanceOf(MyEnum::class)
89+
->toEqual(MyEnum::FOO)
90+
->and($value->value->name)
91+
->toEqual(MyEnum::FOO->name)
92+
->and($value())
93+
->toBeInstanceOf(MyEnum::class)
94+
->toEqual(MyEnum::FOO)
95+
->and($value()->name)
96+
->toEqual(MyEnum::FOO->name);
97+
98+
$value->value = MyEnum::BAR;
99+
expect($value->value)
100+
->toBeInstanceOf(MyEnum::class)
101+
->toEqual(MyEnum::BAR)
102+
->and($value->value->name)
103+
->toEqual(MyEnum::BAR->name);
104+
105+
$value(MyEnum::BAR);
106+
expect($value())
107+
->toBeInstanceOf(MyEnum::class)
108+
->toEqual(MyEnum::BAR)
109+
->and($value()->name)
110+
->toEqual(MyEnum::BAR->name);
111+
112+
$backedEnumValue = Strictus::enum(MyBackedEnum::class, MyBackedEnum::BAZ);
113+
114+
expect($backedEnumValue)
115+
->toBeInstanceOf(StrictusEnum::class)
116+
->and($backedEnumValue->value)
117+
->toBeInstanceOf(MyBackedEnum::class)
118+
->toEqual(MyBackedEnum::BAZ)
119+
->and($backedEnumValue->value->name)
120+
->toEqual(MyBackedEnum::BAZ->name)
121+
->and($backedEnumValue->value->value)
122+
->toEqual(MyBackedEnum::BAZ->value)
123+
->and($backedEnumValue())
124+
->toBeInstanceOf(MyBackedEnum::class)
125+
->toEqual(MyBackedEnum::BAZ)
126+
->and($backedEnumValue()->name)
127+
->toEqual(MyBackedEnum::BAZ->name)
128+
->and($backedEnumValue()->value)
129+
->toEqual(MyBackedEnum::BAZ->value);
130+
131+
$backedEnumValue->value = MyBackedEnum::BAZZ;
132+
expect($backedEnumValue->value)
133+
->toBeInstanceOf(MyBackedEnum::class)
134+
->and($backedEnumValue->value->value)
135+
->toEqual(MyBackedEnum::BAZZ->value);
136+
137+
$backedEnumValue(MyBackedEnum::BAZZ);
138+
expect($backedEnumValue())
139+
->toBeInstanceOf(MyBackedEnum::class)
140+
->and($backedEnumValue()->value)
141+
->toEqual(MyBackedEnum::BAZZ->value);
142+
});
143+
144+
it('updates the nullable value to enum correctly', function () {
145+
$value = Strictus::nullableEnum(MyEnum::class, null);
146+
147+
expect($value->value)
148+
->toBeNull()
149+
->and($value())
150+
->toBeNull();
151+
152+
$value->value = MyEnum::BAR;
153+
expect($value->value)
154+
->toBeInstanceOf(MyEnum::class)
155+
->toEqual(MyEnum::BAR);
156+
157+
$value(MyEnum::BAR);
158+
expect($value())
159+
->toBeInstanceOf(MyEnum::class)
160+
->toEqual(MyEnum::BAR);
161+
162+
$backedEnumValue = Strictus::nullableEnum(MyBackedEnum::class, null);
163+
164+
expect($backedEnumValue->value)
165+
->toBeNull()
166+
->and($backedEnumValue())
167+
->toBeNull();
168+
169+
$backedEnumValue->value = MyBackedEnum::BAZ;
170+
expect($backedEnumValue->value)
171+
->toBeInstanceOf(MyBackedEnum::class)
172+
->toEqual(MyBackedEnum::BAZ);
173+
174+
$backedEnumValue(MyBackedEnum::BAZ);
175+
expect($backedEnumValue())
176+
->toBeInstanceOf(MyBackedEnum::class)
177+
->toEqual(MyBackedEnum::BAZ);
178+
});
179+
180+
it('updates the enum value to nullable correctly', function () {
181+
$value = Strictus::enum(MyEnum::class, MyEnum::FOO, true);
182+
183+
expect($value->value)
184+
->toBeInstanceOf(MyEnum::class)
185+
->toEqual(MyEnum::FOO)
186+
->and($value())
187+
->toBeInstanceOf(MyEnum::class)
188+
->toEqual(MyEnum::FOO);
189+
190+
$value->value = null;
191+
expect($value->value)
192+
->toBeNull();
193+
194+
$value(null);
195+
expect($value())
196+
->toBeNull();
197+
198+
$backedEnumValue = Strictus::enum(MyBackedEnum::class, MyBackedEnum::BAZZ, true);
199+
200+
expect($backedEnumValue->value)
201+
->toBeInstanceOf(MyBackedEnum::class)
202+
->toEqual(MyBackedEnum::BAZZ)
203+
->and($backedEnumValue())
204+
->toBeInstanceOf(MyBackedEnum::class)
205+
->toEqual(MyBackedEnum::BAZZ);
206+
207+
$backedEnumValue->value = null;
208+
expect($backedEnumValue->value)
209+
->toBeNull();
210+
211+
$backedEnumValue(null);
212+
expect($backedEnumValue())
213+
->toBeNull();
214+
});
215+
216+
enum MyEnum
217+
{
218+
case FOO;
219+
case BAR;
220+
}
221+
222+
enum MyBackedEnum: int
223+
{
224+
case BAZ = 1;
225+
case BAZZ = 2;
226+
}

0 commit comments

Comments
 (0)