Completed
Push — optimize_byOrdinal ( 61c23d...77e489 )
by Marc
01:51
created

EnumTest   B

Complexity

Total Complexity 44

Size/Duplication

Total Lines 350
Duplicated Lines 29.14 %

Coupling/Cohesion

Components 1
Dependencies 8

Importance

Changes 20
Bugs 10 Features 2
Metric Value
wmc 44
lcom 1
cbo 8
dl 102
loc 350
rs 8.3396
c 20
b 10
f 2

34 Methods

Rating   Name   Duplication   Size   Complexity  
A setUp() 0 16 1
A testGetNameReturnsConstantNameOfCurrentValue() 0 5 1
A testToStringMagicMethodReturnsName() 0 5 1
B testEnumInheritance() 0 30 1
A testGetWithStrictValue() 0 6 1
A testGetWithNonStrictValueThrowsInvalidArgumentException() 0 5 1
A testGetWithInvalidValueThrowsInvalidArgumentException() 0 5 1
A testGetWithInvalidTypeOfValueThrowsInvalidArgumentException() 0 5 1
A testGetByInstance() 0 6 1
A testGetByExtendedInstanceOfKnownValue() 0 7 1
A testGetEnumeratorsConstansAlreadyDetected() 16 16 2
A testGetEnumeratorsConstansNotDetected() 16 16 2
A testGetValues() 12 12 2
A testGetNamesConstantsAlreadyDetected() 12 12 2
A testGetNamesConstantsNotDetected() 12 12 2
A testGetOrdinals() 12 12 2
A testGetAllValues() 0 9 2
A testIsBasic() 13 13 1
A testCallingGetOrdinalTwoTimesWillResultTheSameValue() 0 6 1
A testInstantiateUsingOrdinalNumber() 0 6 1
A testInstantiateUsingInvalidOrdinalNumberThrowsInvalidArgumentException() 0 5 1
A testInstantiateByName() 0 6 1
A testInstantiateByUnknownNameThrowsInvalidArgumentException() 0 5 1
A testInstantiateUsingMagicMethod() 0 6 1
A testAmbiguousConstantsThrowsLogicException() 0 5 1
A testExtendedAmbiguousCanstantsThrowsLogicException() 0 5 1
A testSingleton() 0 6 1
A testCloneNotCallableAndThrowsLogicException() 0 13 1
A testNotSerializable() 0 7 1
A testNotUnserializable() 0 5 1
A testHas() 9 9 1
A testConstVisibility() 0 12 2
A testConstVisibilityExtended() 0 14 2
A testIsSerializableIssue() 0 12 2

How to fix   Duplicated Code    Complexity   

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:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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
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 View Code Duplication
    public function testGetEnumeratorsConstansAlreadyDetected()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public function testGetEnumeratorsConstansNotDetected()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public function testGetValues()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public function testGetNamesConstantsAlreadyDetected()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public function testGetNamesConstantsNotDetected()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public function testGetOrdinals()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public function testIsBasic()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public function testHas()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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