GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

EnumTest   F
last analyzed

Complexity

Total Complexity 65

Size/Duplication

Total Lines 624
Duplicated Lines 0 %

Importance

Changes 6
Bugs 0 Features 1
Metric Value
eloc 287
dl 0
loc 624
rs 3.2
c 6
b 0
f 1
wmc 65

59 Methods

Rating   Name   Duplication   Size   Complexity  
A testCreateFromEnum() 0 8 1
A testCreateFromMember() 0 8 1
A testCreateFromValue() 0 10 1
A testCreateFromConstant() 0 10 1
A testGetInstances() 0 7 1
A testGetMember() 0 6 1
A testImpossibleValueToMemberInvalidMemberTypeException() 0 9 1
A testListMembers() 0 7 1
A runCustomExceptionEmptyMethodTest() 0 24 4
A testHasMemberIn() 0 9 1
A testGetInstancesCold() 0 5 1
A testMembersExist() 0 8 1
A provideCustomExceptions() 0 8 1
A testExceptionMagicClone() 0 7 1
A testExceptionInvalidValue() 0 7 1
A testExtendsCustomException() 0 3 1
A testMemberExists() 0 6 1
A testExtendedExtendedEnum() 0 15 1
A testHasMember() 0 6 1
A testExceptionInvalidMemberToValue() 0 7 1
A testExceptionMagicCall() 0 7 1
A testExceptionInvalidValueToMember() 0 7 1
A testDifferentEnumsInequality() 0 8 1
A testTraitCustomException() 0 3 1
A testExceptionMagicUnset() 0 7 1
A testExceptionMissingResolveMethod() 0 9 1
A testValuesExist() 0 8 1
A testExceptionCreateFromEnumDifferentClass() 0 8 1
A testExceptionNonEmptyConstantArguments() 0 7 1
A testExceptionNonUniformValueType() 0 7 1
A testValueExists() 0 6 1
A testExceptionInvalidMemberConstant() 0 7 1
A testHasValueIn() 0 9 1
A testExceptionNonUniqueMemberValues() 0 7 1
A testExceptionMagicInvoke() 0 7 1
A testExceptionNoMembers() 0 7 1
A testJsonEncode() 0 5 1
A runCustomExceptionTest() 0 27 4
A testSameEnumInequality() 0 13 1
A testValueToMember() 0 7 1
A testSameEnumEquality() 0 16 1
A testExceptionCreateFromInstanceDifferentClass() 0 9 1
A testExceptionInvalidMember() 0 7 1
A testGetValue() 0 6 1
A testSerialize() 0 16 1
A testHasValue() 0 6 1
A testIsIn() 0 8 1
A testListMembersAndValues() 0 7 1
A testIsMemberWarm() 0 12 1
A testExceptionNonScalarValue() 0 7 1
A testExceptionMagicSet() 0 7 1
A testExceptionMagicGet() 0 7 1
A testTraitCustomExceptionEmptyMethod() 0 3 1
A testExtendsCustomExceptionEmptyMethod() 0 3 1
A testMemberToValue() 0 7 1
A testExceptionNonStringMember() 0 7 1
A testListValues() 0 7 1
A testExceptionMagicIsset() 0 7 1
A testCastToString() 0 5 1

How to fix   Complexity   

Complex Class

Complex classes like EnumTest often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use EnumTest, and based on these observations, apply Extract Interface, too.

1
<?php
2
declare(strict_types=1);
3
namespace Thunder\Platenum\Tests;
4
5
use Thunder\Platenum\Enum\AbstractConstantsEnum;
6
use Thunder\Platenum\Enum\AbstractStaticEnum;
7
use Thunder\Platenum\Enum\EnumTrait;
8
use Thunder\Platenum\Exception\PlatenumException;
9
use Thunder\Platenum\Tests\Fake\FakeEnum;
10
11
/**
12
 * @author Tomasz Kowalczyk <[email protected]>
13
 */
14
final class EnumTest extends AbstractTestCase
15
{
16
    /* --- CREATE --- */
17
18
    public function testCreateFromMember(): void
19
    {
20
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
21
        $first = $enum::fromMember('FIRST');
22
        $second = $enum::fromMember('SECOND');
23
24
        $this->assertSame('FIRST', $first->getMember());
25
        $this->assertSame('SECOND', $second->getMember());
26
    }
27
28
    public function testCreateFromValue(): void
29
    {
30
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
31
        $first = $enum::fromValue(1);
32
        $second = $enum::fromValue(2);
33
34
        $this->assertSame('FIRST', $first->getMember());
35
        $this->assertSame('SECOND', $second->getMember());
36
        $this->assertSame(1, $first->getValue());
37
        $this->assertSame(2, $second->getValue());
38
    }
39
40
    public function testCreateFromConstant(): void
41
    {
42
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
43
        $first = $enum::FIRST();
44
        $second = $enum::SECOND();
45
46
        $this->assertSame('FIRST', $first->getMember());
47
        $this->assertSame('SECOND', $second->getMember());
48
        $this->assertSame(1, $first->getValue());
49
        $this->assertSame(2, $second->getValue());
50
    }
51
52
    public function testCreateFromEnum(): void
53
    {
54
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
55
        $first = $enum::fromMember('FIRST');
56
        $otherFirst = $enum::fromEnum($first);
57
58
        $this->assertSame('FIRST', $otherFirst->getMember());
59
        $this->assertSame(1, $otherFirst->getValue());
60
    }
61
62
    public function testGetInstances(): void
63
    {
64
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
65
        $first = $enum::fromMember('FIRST');
66
        $otherFirst = $enum::fromEnum($first);
0 ignored issues
show
Unused Code introduced by
The assignment to $otherFirst is dead and can be removed.
Loading history...
67
68
        $this->assertSame([$first, $enum::SECOND()], $enum::getInstances());
69
    }
70
71
    public function testGetInstancesCold(): void
72
    {
73
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
74
75
        $this->assertCount(2, $enum::getInstances());
76
    }
77
78
    public function testExceptionNonScalarValue(): void
79
    {
80
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
81
82
        $this->expectException(PlatenumException::class);
83
        $this->expectExceptionMessage('Enum `'.$enum.'` value must be a scalar, `array` given.');
84
        $enum::fromValue([]);
85
    }
86
87
    public function testExceptionInvalidMemberConstant(): void
88
    {
89
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
90
91
        $this->expectException(PlatenumException::class);
92
        $this->expectExceptionMessage('Enum `'.$enum.'` does not contain member `THIRD` among `FIRST,SECOND`.');
93
        $enum::THIRD();
94
    }
95
96
    public function testExceptionInvalidMember(): void
97
    {
98
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
99
100
        $this->expectException(PlatenumException::class);
101
        $this->expectExceptionMessage('Enum `'.$enum.'` does not contain member `THIRD` among `FIRST,SECOND`.');
102
        $enum::fromMember('THIRD');
103
    }
104
105
    public function testExceptionInvalidValue(): void
106
    {
107
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
108
109
        $this->expectException(PlatenumException::class);
110
        $this->expectExceptionMessage('Enum `'.$enum.'` does not contain any member with value `42`.');
111
        $enum::fromValue(42);
112
    }
113
114
    public function testExceptionNonEmptyConstantArguments(): void
115
    {
116
        $enum = $this->makeRawEnum(['FIRST' => 'first', 'SECOND' => 'second']);
117
118
        $this->expectException(PlatenumException::class);
119
        $this->expectExceptionMessage('Enum `'.$enum.'` constant methods must not have any arguments.');
120
        $enum::SECOND('invalid');
121
    }
122
123
    public function testExceptionCreateFromEnumDifferentClass(): void
124
    {
125
        $enumA = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
126
        $enumB = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
127
128
        $this->expectException(PlatenumException::class);
129
        $this->expectExceptionMessage('Attempting to recreate enum '.$enumA.' from instance of '.$enumB.'.');
130
        $enumA::fromEnum($enumB::FIRST());
131
    }
132
133
    public function testExceptionCreateFromInstanceDifferentClass(): void
134
    {
135
        $enumA = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
136
        $enumB = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
137
138
        $b = $enumB::FIRST();
139
        $this->expectException(PlatenumException::class);
140
        $this->expectExceptionMessage('Attempting to recreate enum '.$enumA.' from instance of '.$enumB.'.');
141
        $enumA::FIRST()->fromInstance($b);
142
    }
143
144
    public function testExceptionMissingResolveMethod(): void
145
    {
146
        /** @var FakeEnum $enum */
147
        $enum = $this->computeUniqueClassName('ExtendsExtends');
148
        eval('class '.$enum.' { use Thunder\Platenum\Enum\EnumTrait; }');
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
149
150
        $this->expectException(PlatenumException::class);
151
        $this->expectExceptionMessage('Enum `'.$enum.'` does not implement resolve() method.');
152
        $enum::FIRST();
153
    }
154
155
    public function testExceptionNonStringMember(): void
156
    {
157
        $enum = $this->makeRawEnum([42 => 'invalid']);
158
159
        $this->expectException(PlatenumException::class);
160
        $this->expectExceptionMessage('Enum `'.$enum.'` requires all members to be strings.');
161
        $enum::fromValue(42);
162
    }
163
164
    public function testExceptionNonUniformValueType(): void
165
    {
166
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => '2', 'THIRD' => '3']);
167
168
        $this->expectException(PlatenumException::class);
169
        $this->expectExceptionMessage('Enum `'.$enum.'` member values must be of the same type, `integer,string` given.');
170
        $enum::fromValue(42);
171
    }
172
173
    /* --- GENERIC --- */
174
175
    public function testExtendedExtendedEnum(): void
176
    {
177
        /** @var FakeEnum $classA */
178
        $classA = $this->computeUniqueClassName('X');
179
        /** @var FakeEnum $classB */
180
        $classB = $this->computeUniqueClassName('X');
181
        eval('class '.$classA.' extends '.AbstractConstantsEnum::class.' {
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
182
            protected const A = 1;
183
            protected const B = 2;
184
        }
185
186
        final class '.$classB.' extends '.$classA.' {}');
187
188
        $this->assertSame('B', $classA::B()->getMember());
189
        $this->assertSame('B', $classB::B()->getMember());
190
    }
191
192
    /* --- COMPARE --- */
193
194
    public function testSameEnumEquality(): void
195
    {
196
        $enumA = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
197
        $enumB = $this->makeRawEnum(['FIRST' => 'first', 'SECOND' => 'second']);
198
199
        $this->assertTrue($enumA::FIRST()->equals($enumA::FIRST()), 'constant equals constant');
200
        $this->assertSame($enumA::SECOND(), $enumA::SECOND(), 'constant === constant');
201
        $this->assertEquals($enumA::SECOND(), $enumA::SECOND(), 'constant == constant');
202
        $this->assertSame($enumA::fromMember('FIRST'), $enumA::fromMember('FIRST'), 'key === key');
203
        $this->assertSame($enumA::fromMember('FIRST'), $enumA::FIRST(), 'key === constant');
204
205
        $this->assertTrue($enumB::fromValue('first')->equals($enumB::FIRST()), 'value equals constant');
206
        $this->assertTrue($enumB::fromValue('first')->equals($enumB::fromValue('first')), 'value equals value');
207
        $this->assertTrue($enumB::FIRST()->equals($enumB::fromValue('first')), 'constant equals value');
208
        $this->assertSame($enumB::FIRST(), $enumB::fromValue('first'), 'constant === value');
209
        $this->assertSame($enumB::fromValue('second'), $enumB::SECOND(), 'value === constant');
210
    }
211
212
    public function testSameEnumInequality(): void
213
    {
214
        $enumA = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
215
        $enumB = $this->makeRawEnum(['FIRST' => 'first', 'SECOND' => 'second']);
216
217
        $this->assertFalse($enumA::FIRST()->equals($enumA::SECOND()), 'constant !equals constant');
218
        $this->assertNotSame($enumA::FIRST(), $enumA::SECOND(), 'constant !== constant');
219
220
        $this->assertFalse($enumB::fromValue('first')->equals($enumB::SECOND()), 'value !equals constant');
221
        $this->assertFalse($enumB::fromValue('first')->equals($enumB::fromValue('second')), 'value !equals value');
222
        $this->assertFalse($enumB::FIRST()->equals($enumB::fromValue('second')), 'constant !equals value');
223
        $this->assertNotSame($enumB::FIRST(), $enumB::fromValue('second'), 'constant !== value');
224
        $this->assertNotSame($enumB::fromValue('first'), $enumB::SECOND(), 'value !== constant');
225
    }
226
227
    public function testDifferentEnumsInequality(): void
228
    {
229
        $enumA = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
230
        $enumB = $this->makeRawEnum(['FIRST' => 'first', 'SECOND' => 'second']);
231
232
        $this->assertFalse($enumA::FIRST()->equals($enumB::FIRST()));
233
        $this->assertNotSame($enumA::FIRST(), $enumB::FIRST());
234
        $this->assertNotSame($enumA::SECOND(), $enumB::SECOND());
235
    }
236
237
    /* --- LOGIC --- */
238
239
    public function testExceptionNoMembers(): void
240
    {
241
        $enum = $this->makeRawEnum([]);
242
243
        $this->expectException(PlatenumException::class);
244
        $this->expectExceptionMessage('Enum `'.$enum.'` does not contain any members.');
245
        $enum::memberExists('WHICH_IT_DOES_NOT');
246
    }
247
248
    public function testExceptionNonUniqueMemberValues(): void
249
    {
250
        $enum = $this->makeRawEnum(['X1' => 1, 'X2' => 1]);
251
252
        $this->expectException(PlatenumException::class);
253
        $this->expectExceptionMessage('Enum `'.$enum.'` members values are not unique.');
254
        $enum::X1();
255
    }
256
257
    /* --- CHECK --- */
258
259
    public function testHasMember(): void
260
    {
261
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
262
263
        $this->assertTrue($enum::SECOND()->hasMember('SECOND'));
264
        $this->assertFalse($enum::SECOND()->hasMember('FIRST'));
265
    }
266
267
    public function testHasValue(): void
268
    {
269
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
270
271
        $this->assertTrue($enum::SECOND()->hasValue(2));
272
        $this->assertFalse($enum::SECOND()->hasValue(1));
273
    }
274
275
    public function testHasMemberIn(): void
276
    {
277
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
278
279
        $this->assertTrue($enum::SECOND()->hasMemberIn(['FIRST', 'SECOND']));
280
        $this->assertTrue($enum::SECOND()->hasMemberIn(['SECOND', 'THIRD']));
281
        $this->assertFalse($enum::SECOND()->hasMemberIn(['THIRD', 'FOURTH']));
282
        $this->assertFalse($enum::SECOND()->hasMemberIn(['FIRST', 'FOURTH']));
283
        $this->assertFalse($enum::SECOND()->hasMemberIn([1.5, null, 'invalid']));
284
    }
285
286
    public function testHasValueIn(): void
287
    {
288
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
289
290
        $this->assertTrue($enum::SECOND()->hasValueIn([1, 2]));
291
        $this->assertTrue($enum::SECOND()->hasValueIn([2, 3]));
292
        $this->assertFalse($enum::SECOND()->hasValueIn([1, 4]));
293
        $this->assertFalse($enum::SECOND()->hasValueIn([3, 4]));
294
        $this->assertFalse($enum::SECOND()->hasValueIn([1.5, null, 'invalid']));
295
    }
296
297
    public function testMemberExists(): void
298
    {
299
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
300
301
        $this->assertTrue($enum::memberExists('FIRST'));
302
        $this->assertFalse($enum::memberExists('THIRD'));
303
    }
304
305
    public function testValueExists(): void
306
    {
307
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
308
309
        $this->assertTrue($enum::valueExists(1));
310
        $this->assertFalse($enum::valueExists(3));
311
    }
312
313
    public function testMembersExist(): void
314
    {
315
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
316
317
        $this->assertTrue($enum::membersExist(['FIRST', 'SECOND']));
318
        $this->assertTrue($enum::membersExist(['FIRST', 'THIRD']));
319
        $this->assertFalse($enum::membersExist(['THIRD', 'FOURTH']));
320
        $this->assertFalse($enum::membersExist([1.5, null, 'invalid']));
321
    }
322
323
    public function testValuesExist(): void
324
    {
325
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
326
327
        $this->assertTrue($enum::valuesExist([1, 2]));
328
        $this->assertTrue($enum::valuesExist([1, 3]));
329
        $this->assertFalse($enum::valuesExist([3, 4]));
330
        $this->assertFalse($enum::valuesExist([1.5, null, 'invalid']));
331
    }
332
333
    public function testIsIn(): void
334
    {
335
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
336
337
        $this->assertTrue($enum::SECOND()->isIn([$enum::FIRST(), $enum::SECOND()]));
338
        $this->assertTrue($enum::SECOND()->isIn([$enum::SECOND(), new \stdClass()]));
339
        $this->assertFalse($enum::SECOND()->isIn([new \stdClass(), new \DateTimeImmutable()]));
340
        $this->assertFalse($enum::SECOND()->isIn([1.5, null, 'invalid']));
341
    }
342
343
    public function testIsMemberWarm(): void
344
    {
345
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
346
347
        $this->assertFalse($enum::isMemberWarm('FIRST'));
348
        $this->assertFalse($enum::isMemberWarm('SECOND'));
349
        $enum::FIRST();
350
        $this->assertTrue($enum::isMemberWarm('FIRST'));
351
        $this->assertFalse($enum::isMemberWarm('SECOND'));
352
        $enum::SECOND();
353
        $this->assertTrue($enum::isMemberWarm('FIRST'));
354
        $this->assertTrue($enum::isMemberWarm('SECOND'));
355
    }
356
357
    /* --- CONVERT --- */
358
359
    public function testGetMember(): void
360
    {
361
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
362
363
        $this->assertSame('FIRST', $enum::FIRST()->getMember());
364
        $this->assertSame('SECOND', $enum::SECOND()->getMember());
365
    }
366
367
    public function testGetValue(): void
368
    {
369
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
370
371
        $this->assertSame(1, $enum::FIRST()->getValue());
372
        $this->assertSame(2, $enum::SECOND()->getValue());
373
    }
374
375
    public function testMemberToValue(): void
376
    {
377
        $intEnum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
378
        $stringEnum = $this->makeRawEnum(['FIRST' => 'first', 'SECOND' => 'second']);
379
380
        $this->assertSame(1, $intEnum::memberToValue('FIRST'));
381
        $this->assertSame('first', $stringEnum::memberToValue('FIRST'));
382
    }
383
384
    public function testValueToMember(): void
385
    {
386
        $intEnum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
387
        $stringEnum = $this->makeRawEnum(['FIRST' => 'first', 'SECOND' => 'second']);
388
389
        $this->assertSame('FIRST', $intEnum::valueToMember(1));
390
        $this->assertSame('FIRST', $stringEnum::valueToMember('first'));
391
    }
392
393
    public function testImpossibleValueToMemberInvalidMemberTypeException(): void
394
    {
395
        $enum = $this->makeRawEnum(['FIRST' => 'first', 'SECOND' => 'second']);
396
        $ref = new \ReflectionClass($enum);
397
        $members = $ref->getProperty('members');
398
        $members->setAccessible(true);
399
        $members->setValue($enum, [$enum => [0 => 'first']]);
400
401
        $this->assertSame('0', $enum::valueToMember('first'));
402
    }
403
404
    public function testJsonEncode(): void
405
    {
406
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
407
408
        $this->assertSame('2', json_encode($enum::SECOND()));
409
    }
410
411
    public function testCastToString(): void
412
    {
413
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
414
415
        $this->assertSame('2', (string)$enum::SECOND());
416
    }
417
418
    public function testExceptionInvalidMemberToValue(): void
419
    {
420
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
421
422
        $this->expectException(PlatenumException::class);
423
        $this->expectExceptionMessage('Enum `'.$enum.'` does not contain member `INVALID` among `FIRST,SECOND`.');
424
        $enum::memberToValue('INVALID');
425
    }
426
427
    public function testExceptionInvalidValueToMember(): void
428
    {
429
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
430
431
        $this->expectException(PlatenumException::class);
432
        $this->expectExceptionMessage('Enum `'.$enum.'` does not contain any member with value `invalid`.');
433
        $enum::valueToMember('invalid');
434
    }
435
436
    /* --- LIST --- */
437
438
    public function testListMembers(): void
439
    {
440
        $intEnum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
441
        $stringEnum = $this->makeRawEnum(['FIRST' => 'first', 'SECOND' => 'second']);
442
443
        $this->assertSame(['FIRST', 'SECOND'], $intEnum::getMembers());
444
        $this->assertSame(['FIRST', 'SECOND'], $stringEnum::getMembers());
445
    }
446
447
    public function testListValues(): void
448
    {
449
        $intEnum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
450
        $stringEnum = $this->makeRawEnum(['FIRST' => 'first', 'SECOND' => 'second']);
451
452
        $this->assertSame([1, 2], $intEnum::getValues());
453
        $this->assertSame(['first', 'second'], $stringEnum::getValues());
454
    }
455
456
    public function testListMembersAndValues(): void
457
    {
458
        $intEnum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
459
        $stringEnum = $this->makeRawEnum(['FIRST' => 'first', 'SECOND' => 'second']);
460
461
        $this->assertSame(['FIRST' => 1, 'SECOND' => 2], $intEnum::getMembersAndValues());
462
        $this->assertSame(['FIRST' => 'first', 'SECOND' => 'second'], $stringEnum::getMembersAndValues());
463
    }
464
465
    /* --- RUNTIME --- */
466
467
    public function testSerialize(): void
468
    {
469
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
470
        $className = $this->computeUniqueClassName('X');
471
        eval('final class '.$className.' {
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
472
            /** @var EnumTrait; */
473
            private $enum;
474
            public function __construct($enum) { $this->enum = $enum; }
475
            public function getEnum() { return $this->enum; }
476
            public function __wakeup() { $this->enum->fromInstance($this->enum); }
477
        };');
478
479
        $original = $enum::FIRST();
480
        $unserialized = unserialize(serialize(new $className($original)))->getEnum();
481
482
        $this->assertSame($original, $unserialized);
483
    }
484
485
    public function testExceptionMagicClone(): void
486
    {
487
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
488
489
        $this->expectException(PlatenumException::class);
490
        $this->expectExceptionMessage('Enum `'.$enum.'` does not allow magic `__clone` method.');
491
        $var = clone $enum::FIRST();
0 ignored issues
show
Unused Code introduced by
The assignment to $var is dead and can be removed.
Loading history...
492
    }
493
494
    public function testExceptionMagicInvoke(): void
495
    {
496
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
497
498
        $this->expectException(PlatenumException::class);
499
        $this->expectExceptionMessage('Enum `'.$enum.'` does not allow magic `__invoke` method.');
500
        $enum::FIRST()();
501
    }
502
503
    public function testExceptionMagicCall(): void
504
    {
505
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
506
507
        $this->expectException(PlatenumException::class);
508
        $this->expectExceptionMessage('Enum `'.$enum.'` does not allow magic `__call` method.');
509
        $enum::FIRST()->invalidMethod();
510
    }
511
512
    public function testExceptionMagicGet(): void
513
    {
514
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
515
516
        $this->expectException(PlatenumException::class);
517
        $this->expectExceptionMessage('Enum `'.$enum.'` does not allow magic `__get` method.');
518
        $enum::FIRST()->invalidProperty;
519
    }
520
521
    public function testExceptionMagicSet(): void
522
    {
523
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
524
525
        $this->expectException(PlatenumException::class);
526
        $this->expectExceptionMessage('Enum `'.$enum.'` does not allow magic `__set` method.');
527
        $enum::FIRST()->invalidProperty = 'value';
528
    }
529
530
    public function testExceptionMagicIsset(): void
531
    {
532
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
533
534
        $this->expectException(PlatenumException::class);
535
        $this->expectExceptionMessage('Enum `'.$enum.'` does not allow magic `__isset` method.');
536
        $is = isset($enum::FIRST()->invalidProperty);
0 ignored issues
show
Unused Code introduced by
The assignment to $is is dead and can be removed.
Loading history...
537
    }
538
539
    public function testExceptionMagicUnset(): void
540
    {
541
        $enum = $this->makeRawEnum(['FIRST' => 1, 'SECOND' => 2]);
542
543
        $this->expectException(PlatenumException::class);
544
        $this->expectExceptionMessage('Enum `'.$enum.'` does not allow magic `__unset` method.');
545
        unset($enum::FIRST()->invalidProperty);
546
    }
547
548
    /* --- CUSTOM EXCEPTION --- */
549
550
    /** @dataProvider provideCustomExceptions */
551
    public function testTraitCustomException(string $type, callable $handler): void
552
    {
553
        $this->runCustomExceptionTest('trait', $type, $handler);
554
    }
555
556
    /** @dataProvider provideCustomExceptions */
557
    public function testExtendsCustomException(string $type, callable $handler): void
558
    {
559
        $this->runCustomExceptionTest('extends', $type, $handler);
560
    }
561
562
    private function runCustomExceptionTest(string $const, string $type, callable $handler): void
563
    {
564
        $members = ['FIRST' => 1];
565
        $methodMap = [
566
            'invalidMember' => 'throwInvalidMemberException(string $member)',
567
            'invalidValue' => 'throwInvalidValueException($value)',
568
        ];
569
        if(false === isset($methodMap[$type])) {
570
            throw new \LogicException(sprintf('Unrecognized override type `%s`.', $type));
571
        }
572
573
        $exceptionClass = $this->computeUniqueClassName('EnumException');
574
        eval('final class '.$exceptionClass.' extends \Exception {}');
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
575
576
        $class = $this->computeUniqueClassName('EnumCustomException');
577
        $resolve = 'private static function resolve(): array { return '.var_export($members, true).'; }';
578
        $mapping = 'protected static $mapping = '.var_export($members, true).';';
579
        $override = 'protected static function '.$methodMap[$type].': void { throw new '.$exceptionClass.'(); }';
580
        switch($const) {
581
            case 'extends': { $code = 'final class '.$class.' extends '.AbstractStaticEnum::class.' {  '.$mapping.$override.' }'; break; }
582
            case 'trait':   { $code = 'final class '.$class.' { use '.EnumTrait::class.'; '.$resolve.$override.' }'; break; }
583
            default: { throw new \LogicException(sprintf('Invalid extension type `%s`.', $const)); }
584
        }
585
        eval($code);
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
586
587
        $this->expectException($exceptionClass);
588
        $handler($class);
589
    }
590
591
    public static function provideCustomExceptions(): array
592
    {
593
        return [
594
            ['invalidMember', function(string $class) { return $class::INVALID(); }],
595
            ['invalidMember', function(string $class) { return $class::fromMember('INVALID'); }],
596
            ['invalidValue', function(string $class) { return $class::fromValue('invalid'); }],
597
            ['invalidMember', function(string $class) { return $class::memberToValue('INVALID'); }],
598
            ['invalidValue', function(string $class) { return $class::valueToMember('invalid'); }],
599
        ];
600
    }
601
602
    /** @dataProvider provideCustomExceptions */
603
    public function testTraitCustomExceptionEmptyMethod(string $type, callable $handler): void
604
    {
605
        $this->runCustomExceptionEmptyMethodTest('trait', $type, $handler);
606
    }
607
608
    /** @dataProvider provideCustomExceptions */
609
    public function testExtendsCustomExceptionEmptyMethod(string $type, callable $handler): void
610
    {
611
        $this->runCustomExceptionEmptyMethodTest('extends', $type, $handler);
612
    }
613
614
    private function runCustomExceptionEmptyMethodTest(string $const, string $type, callable $handler): void
615
    {
616
        $members = ['FIRST' => 1];
617
        $methodMap = [
618
            'invalidMember' => 'throwInvalidMemberException(string $member)',
619
            'invalidValue' => 'throwInvalidValueException($value)',
620
        ];
621
        if(false === isset($methodMap[$type])) {
622
            throw new \LogicException(sprintf('Unrecognized override type `%s`.', $type));
623
        }
624
625
        $class = $this->computeUniqueClassName('EnumCustomException');
626
        $resolve = 'private static function resolve(): array { return '.var_export($members, true).'; }';
627
        $mapping = 'protected static $mapping = '.var_export($members, true).';';
628
        $override = 'protected static function '.$methodMap[$type].': void {}';
629
        switch($const) {
630
            case 'extends': { $code = 'final class '.$class.' extends '.AbstractStaticEnum::class.' {  '.$mapping.$override.' }'; break; }
631
            case 'trait':   { $code = 'final class '.$class.' { use '.EnumTrait::class.'; '.$resolve.$override.' }'; break; }
632
            default: { throw new \LogicException(sprintf('Invalid extension type `%s`.', $const)); }
633
        }
634
        eval($code);
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
635
636
        $this->expectException(PlatenumException::class);
637
        $handler($class);
638
    }
639
}
640