Passed
Pull Request — 2.x (#116)
by Marc
05:33 queued 03:37
created

EnumTest   B

Complexity

Total Complexity 40

Size/Duplication

Total Lines 314
Duplicated Lines 22.61 %

Coupling/Cohesion

Components 1
Dependencies 8

Importance

Changes 17
Bugs 9 Features 2
Metric Value
wmc 40
c 17
b 9
f 2
lcom 1
cbo 8
dl 71
loc 314
rs 8.2608

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