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.
Passed
Push — master ( 795e68...fad79b )
by Tomasz
10:37
created

EnumTest::testHasValueIn()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

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