Completed
Push — feature/74 ( 60c27e...f551d9 )
by Marc
04:30
created

EnumTest   B

Complexity

Total Complexity 39

Size/Duplication

Total Lines 303
Duplicated Lines 19.14 %

Coupling/Cohesion

Components 1
Dependencies 8

Importance

Changes 19
Bugs 10 Features 2
Metric Value
wmc 39
c 19
b 10
f 2
lcom 1
cbo 8
dl 58
loc 303
rs 8.2857

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
namespace MabeEnumTest;
4
5
use InvalidArgumentException;
6
use LogicException;
7
use MabeEnum\Enum;
8
use MabeEnumTest\TestAsset\EnumBasic;
9
use MabeEnumTest\TestAsset\EnumInheritance;
10
use MabeEnumTest\TestAsset\EnumAmbiguous;
11
use MabeEnumTest\TestAsset\EnumExtendedAmbiguous;
12
use MabeEnumTest\TestAsset\ConstVisibilityEnum;
13
use MabeEnumTest\TestAsset\ConstVisibilityEnumExtended;
14
use MabeEnumTest\TestAsset\SerializableEnum;
15
use PHPUnit_Framework_TestCase as TestCase;
16
use ReflectionClass;
17
18
/**
19
 * Unit tests for the class MabeEnum\Enum
20
 *
21
 * @link http://github.com/marc-mabe/php-enum for the canonical source repository
22
 * @copyright Copyright (c) 2015 Marc Bennewitz
23
 * @license http://github.com/marc-mabe/php-enum/blob/master/LICENSE.txt New BSD License
24
 */
25
class EnumTest extends TestCase
26
{
27
    public function setUp()
28
    {
29
        $enumRefl = new ReflectionClass(Enum::class);
30
31
        $constantsProp = $enumRefl->getProperty('constants');
32
        $namesProp = $enumRefl->getProperty('names');
33
        $instancesProp = $enumRefl->getProperty('instances');
34
35
        $constantsProp->setAccessible(true);
36
        $namesProp->setAccessible(true);
37
        $instancesProp->setAccessible(true);
38
39
        $constantsProp->setValue(null, []);
40
        $namesProp->setValue(null, []);
41
        $instancesProp->setValue(null, []);
42
    }
43
44
    public function testGetNameReturnsConstantNameOfCurrentValue()
45
    {
46
        $enum = EnumBasic::get(EnumBasic::ONE);
47
        $this->assertSame('ONE', $enum->getName());
48
    }
49
50
    public function testToStringMagicMethodReturnsName()
51
    {
52
        $enum = EnumBasic::get(EnumBasic::ONE);
53
        $this->assertSame('ONE', $enum->__toString());
54
    }
55
56
    public function testEnumInheritance()
57
    {
58
        $this->assertSame(array(
59
            'ONE'           => 1,
60
            'TWO'           => 2,
61
            'THREE'         => 3,
62
            'FOUR'          => 4,
63
            'FIVE'          => 5,
64
            'SIX'           => 6,
65
            'SEVEN'         => 7,
66
            'EIGHT'         => 8,
67
            'NINE'          => 9,
68
            'ZERO'          => 0,
69
            'FLOAT'         => 0.123,
70
            'STR'           => 'str',
71
            'STR_EMPTY'     => '',
72
            'NIL'           => null,
73
            'BOOLEAN_TRUE'  => true,
74
            'BOOLEAN_FALSE' => false,
75
            'INHERITANCE'   => 'Inheritance',
76
        ), EnumInheritance::getConstants());
77
78
        $enum = EnumInheritance::get(EnumInheritance::ONE);
79
        $this->assertSame(EnumInheritance::ONE, $enum->getValue());
80
        $this->assertSame(0, $enum->getOrdinal());
81
82
        $enum = EnumInheritance::get(EnumInheritance::INHERITANCE);
83
        $this->assertSame(EnumInheritance::INHERITANCE, $enum->getValue());
84
        $this->assertSame(16, $enum->getOrdinal());
85
    }
86
87
    public function testGetWithStrictValue()
88
    {
89
        $enum = EnumBasic::get(EnumBasic::ONE);
90
        $this->assertSame(1, $enum->getValue());
91
        $this->assertSame(0, $enum->getOrdinal());
92
    }
93
94
    public function testGetWithNonStrictValueThrowsInvalidArgumentException()
95
    {
96
        $this->setExpectedException(InvalidArgumentException::class);
97
        EnumBasic::get((string)EnumBasic::TWO);
98
    }
99
100
    public function testGetWithInvalidValueThrowsInvalidArgumentException()
101
    {
102
        $this->setExpectedException(InvalidArgumentException::class);
103
        EnumBasic::get('unknown');
104
    }
105
106
    public function testGetWithInvalidTypeOfValueThrowsInvalidArgumentException()
107
    {
108
        $this->setExpectedException(InvalidArgumentException::class);
109
        EnumBasic::get(array());
110
    }
111
112
    public function testGetByInstance()
113
    {
114
        $enum1 = EnumBasic::get(EnumBasic::ONE);
115
        $enum2 = EnumBasic::get($enum1);
116
        $this->assertSame($enum1, $enum2);
117
    }
118
119
    public function testGetByExtendedInstanceOfKnownValue()
120
    {
121
        $enum = EnumInheritance::get(EnumInheritance::ONE);
122
123
        $this->setExpectedException(InvalidArgumentException::class);
124
        EnumBasic::get($enum);
125
    }
126
127
    public function testGetEnumeratorsConstansAlreadyDetected()
128
    {
129
        $constants   = EnumInheritance::getConstants();
130
        $enumerators = EnumInheritance::getEnumerators();
131
        $count       = count($enumerators);
132
133
        $this->assertSame(count($constants), $count);
134
        for ($i = 0; $i < $count; ++$i) {
135
            $this->assertArrayHasKey($i, $enumerators);
136
            $this->assertInstanceOf(EnumInheritance::class, $enumerators[$i]);
137
138
            $enumerator = $enumerators[$i];
139
            $this->assertArrayHasKey($enumerator->getName(), $constants);
140
            $this->assertSame($constants[$enumerator->getName()], $enumerator->getValue());
141
        }
142
    }
143
144
    public function testGetEnumeratorsConstansNotDetected()
145
    {
146
        $enumerators = EnumInheritance::getEnumerators();
147
        $constants   = EnumInheritance::getConstants();
148
        $count       = count($enumerators);
149
150
        $this->assertSame(count($constants), $count);
151
        for ($i = 0; $i < $count; ++$i) {
152
            $this->assertArrayHasKey($i, $enumerators);
153
            $this->assertInstanceOf(EnumInheritance::class, $enumerators[$i]);
154
155
            $enumerator = $enumerators[$i];
156
            $this->assertArrayHasKey($enumerator->getName(), $constants);
157
            $this->assertSame($constants[$enumerator->getName()], $enumerator->getValue());
158
        }
159
    }
160
161
    public function testGetValues()
162
    {
163
        $expectedValues = array_values(EnumInheritance::getConstants());
164
        $values         = EnumInheritance::getValues();
165
        $count          = count($values);
166
167
        $this->assertSame(count($expectedValues), $count);
168
        for ($i = 0; $i < $count; ++$i) {
169
            $this->assertArrayHasKey($i, $values);
170
            $this->assertSame($expectedValues[$i], $values[$i]);
171
        }
172
    }
173
174
    public function testGetNamesConstantsAlreadyDetected()
175
    {
176
        $expectedNames = array_keys(EnumInheritance::getConstants());
177
        $names         = EnumInheritance::getNames();
178
        $count         = count($names);
179
180
        $this->assertSame(count($expectedNames), $count);
181
        for ($i = 0; $i < $count; ++$i) {
182
            $this->assertArrayHasKey($i, $names);
183
            $this->assertSame($expectedNames[$i], $names[$i]);
184
        }
185
    }
186
187
    public function testGetNamesConstantsNotDetected()
188
    {
189
        $names         = EnumInheritance::getNames();
190
        $expectedNames = array_keys(EnumInheritance::getConstants());
191
        $count         = count($names);
192
193
        $this->assertSame(count($expectedNames), $count);
194
        for ($i = 0; $i < $count; ++$i) {
195
            $this->assertArrayHasKey($i, $names);
196
            $this->assertSame($expectedNames[$i], $names[$i]);
197
        }
198
    }
199
    
200
    public function testGetOrdinals()
201
    {
202
        $constants = EnumInheritance::getConstants();
203
        $ordinals  = EnumInheritance::getOrdinals();
204
        $count     = count($ordinals);
205
206
        $this->assertSame(count($constants), $count);
207
        for ($i = 0; $i < $count; ++$i) {
208
            $this->assertArrayHasKey($i, $ordinals);
209
            $this->assertSame($i, $ordinals[$i]);
210
        }
211
    }
212
213
    public function testGetAllValues()
214
    {
215
        $constants = EnumBasic::getConstants();
216
        foreach ($constants as $name => $value) {
217
            $enum = EnumBasic::get($value);
218
            $this->assertSame($value, $enum->getValue());
219
            $this->assertSame($name, $enum->getName());
220
        }
221
    }
222
223
    public function testIsBasic()
224
    {
225
        $enum = EnumBasic::ONE();
226
227
        // by value
228
        $this->assertTrue($enum->is(EnumBasic::ONE));   // same
229
        $this->assertFalse($enum->is('1'));             // wrong value by strict comparison
230
231
        // by instance
232
        $this->assertTrue($enum->is(EnumBasic::ONE()));        // same
233
        $this->assertFalse($enum->is(EnumBasic::TWO()));       // different enumerators
234
        $this->assertFalse($enum->is(EnumInheritance::ONE())); // different enumeration type
235
    }
236
237
    public function testCallingGetOrdinalTwoTimesWillResultTheSameValue()
238
    {
239
        $enum = EnumBasic::get(EnumBasic::TWO);
240
        $this->assertSame(1, $enum->getOrdinal());
241
        $this->assertSame(1, $enum->getOrdinal());
242
    }
243
244
    public function testInstantiateUsingOrdinalNumber()
245
    {
246
        $enum = EnumInheritance::byOrdinal(16);
247
        $this->assertSame(16, $enum->getOrdinal());
248
        $this->assertSame('INHERITANCE', $enum->getName());
249
    }
250
251
    public function testInstantiateUsingInvalidOrdinalNumberThrowsInvalidArgumentException()
252
    {
253
        $this->setExpectedException(InvalidArgumentException::class);
254
        EnumInheritance::byOrdinal(17);
255
    }
256
257
    public function testInstantiateByName()
258
    {
259
        $enum = EnumInheritance::byName('ONE');
260
        $this->assertInstanceOf(EnumInheritance::class, $enum);
261
        $this->assertSame(EnumInheritance::ONE, $enum->getValue());
262
    }
263
264
    public function testInstantiateByUnknownNameThrowsInvalidArgumentException()
265
    {
266
        $this->setExpectedException(InvalidArgumentException::class);
267
        EnumInheritance::byName('UNKNOWN');
268
    }
269
270
    public function testInstantiateUsingMagicMethod()
271
    {
272
        $enum = EnumInheritance::ONE();
273
        $this->assertInstanceOf(EnumInheritance::class, $enum);
274
        $this->assertSame(EnumInheritance::ONE, $enum->getValue());
275
    }
276
277
    public function testAmbiguousConstantsThrowsLogicException()
278
    {
279
        $this->setExpectedException(LogicException::class);
280
        EnumAmbiguous::get('unknown');
281
    }
282
283
    public function testExtendedAmbiguousCanstantsThrowsLogicException()
284
    {
285
        $this->setExpectedException(LogicException::class);
286
        EnumExtendedAmbiguous::get('unknown');
287
    }
288
289
    public function testSingleton()
290
    {
291
        $enum1 = EnumBasic::get(EnumBasic::ONE);
292
        $enum2 = EnumBasic::ONE();
293
        $this->assertSame($enum1, $enum2);
294
    }
295
296
    public function testCloneNotCallableAndThrowsLogicException()
297
    {
298
        $enum = EnumBasic::ONE();
299
300
        $reflectionClass  = new ReflectionClass($enum);
301
        $reflectionMethod = $reflectionClass->getMethod('__clone');
302
        $this->assertTrue($reflectionMethod->isPrivate(), 'The method __clone must be private');
303
        $this->assertTrue($reflectionMethod->isFinal(), 'The method __clone must be final');
304
305
        $reflectionMethod->setAccessible(true);
306
        $this->setExpectedException(LogicException::class);
307
        $reflectionMethod->invoke($enum);
308
    }
309
310
    public function testNotSerializable()
311
    {
312
        $enum = EnumBasic::ONE();
313
314
        $this->setExpectedException(LogicException::class);
315
        serialize($enum);
316
    }
317
318
    public function testNotUnserializable()
319
    {
320
        $this->setExpectedException(LogicException::class);
321
        unserialize('O:' . strlen(EnumBasic::class) . ':"' . EnumBasic::class . '":0:{}');
322
    }
323
324
    public function testHas()
325
    {
326
        $enum = EnumBasic::ONE();
327
328
        $this->assertFalse($enum->has('invalid'));
329
        $this->assertFalse($enum->has(EnumInheritance::ONE()));
330
        $this->assertTrue($enum->has(EnumBasic::ONE()));
331
        $this->assertTrue($enum->has(EnumBasic::ONE));
332
    }
333
    
334
    public function testConstVisibility()
335
    {
336
        if (PHP_VERSION_ID < 70100) {
337
            $this->markTestSkipped('This test is for PHP-7.1 and upper only');
338
        }
339
340
        $constants = ConstVisibilityEnum::getConstants();
341
        $this->assertSame(array(
342
            'IPUB' => ConstVisibilityEnum::IPUB,
343
            'PUB'  => ConstVisibilityEnum::PUB,
344
        ), $constants);
345
    }
346
    
347
    public function testConstVisibilityExtended()
348
    {
349
        if (PHP_VERSION_ID < 70100) {
350
            $this->markTestSkipped('This test is for PHP-7.1 and upper only');
351
        }
352
353
        $constants = ConstVisibilityEnumExtended::getConstants();
354
        $this->assertSame(array(
355
            'IPUB'  => ConstVisibilityEnumExtended::IPUB,
356
            'PUB'   => ConstVisibilityEnumExtended::PUB,
357
            'IPUB2' => ConstVisibilityEnumExtended::IPUB2,
358
            'PUB2'  => ConstVisibilityEnumExtended::PUB2,
359
        ), $constants);
360
    }
361
362
    public function testIsSerializableIssue()
363
    {
364
        if (PHP_VERSION_ID < 50400) {
365
            $this->markTestSkipped('This test is for PHP-5.4 and upper only');
366
        }
367
368
        $enum1 = SerializableEnum::INT();
369
        $enum2 = unserialize(serialize($enum1));
370
371
        $this->assertFalse($enum1 === $enum2, 'Wrong test implementation');
372
        $this->assertTrue($enum1->is($enum2), 'Two different instances of exact the same enumerator should be equal');
373
    }
374
}
375