EuroTest   C
last analyzed

Complexity

Total Complexity 53

Size/Duplication

Total Lines 304
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
wmc 53
lcom 1
cbo 2
dl 0
loc 304
rs 6.96
c 0
b 0
f 0

53 Methods

Rating   Name   Duplication   Size   Complexity  
A testGetCentsReturnsConstructorArgument() 0 4 1
A unsignedIntegerProvider() 0 6 1
A testGivenZero_getEuroFloatReturnsZeroFloat() 0 5 1
A assertExactFloat() 0 4 1
A testGivenOneEuro_getEuroFloatReturnsOne() 0 4 1
A testGivenOneCent_getEuroFloatReturnsPointZeroOne() 0 4 1
A testGiven33cents_getEuroFloatReturnsPointThreeThree() 0 4 1
A testGivenNegativeAmount_constructorThrowsException() 0 4 1
A testGivenZero_getEuroStringReturnsZeroString() 0 4 1
A testGivenOneEuro_getEuroStringReturnsOnePointZeroZero() 0 4 1
A testGivenTwoEuros_getEuroStringReturnsTwoPointZeroZero() 0 4 1
A testGivenOneCent_getEuroStringReturnsZeroPointZeroOne() 0 4 1
A testGivenTenCents_getEuroStringReturnsZeroPointOneZero() 0 4 1
A testGiven1234Cents_getEuroStringReturns12euro34() 0 4 1
A testGiven9876Cents_stringCastingReturns98euro76() 0 4 1
A testGivenEuroAmount_jsonEncodeWillEncodeProperly() 0 4 1
A testOneEuroString_getsTurnedInto100cents() 0 3 1
A testOneCentString_getsTurnedInto1cents() 0 3 1
A testTenCentString_getsTurnedInto10cents() 0 3 1
A testShortTenCentString_getsTurnedInto10cents() 0 3 1
A testShortOneEuroString_getsTurnedInto100cents() 0 3 1
A testOneDecimalOneEuroString_getsTurnedInto100cents() 0 3 1
A testMultiDecimalOneEuroString_getsTurnedInto100cents() 0 3 1
A testHandlingOfLargeEuroString() 0 3 1
A testEuroStringThatCausedRoundingError_doesNotCauseRoundingError() 0 5 1
A testEuroStringWithRoundingError_getsRoundedAppropriately() 0 16 1
A testGivenNegativeAmountString_exceptionIsThrown() 0 4 1
A testGivenStringWithComma_exceptionIsThrown() 0 4 1
A testGivenStringWithMultipleDots_ExceptionIsThrown() 0 4 1
A testGivenNonNumber_exceptionIsThrown() 0 4 1
A testGivenNegativeFloatAmount_exceptionIsThrown() 0 4 1
A testOneEuroFloat_getsTurnedInto100cents() 0 3 1
A testOneCentFloat_getsTurnedInto1cent() 0 3 1
A testTenCentFloat_getsTurnedInto10cents() 0 3 1
A testHandlingOfLargeEuroFloat() 0 3 1
A testFloatWithRoundingError_getsRoundedAppropriately() 0 11 1
A testZeroEuroIntegers_isZeroCents() 0 3 1
A testOneEuroIntegers_is100cents() 0 3 1
A test1337EuroIntegers_is133700cents() 0 3 1
A testGivenNegativeIntegerAmount_exceptionIsThrown() 0 4 1
A testEuroEqualsItself() 0 3 1
A euroProvider() 0 9 1
A testOneCentDoesNotEqualOneEuro() 0 3 1
A testOneCentDoesNotEqualTwoCents() 0 3 1
A testOneCentDoesNotEqualOneEuroAndOneCent() 0 3 1
A test9001centsDoesNotEqual9000cents() 0 3 1
A testNewFromStringThrowsExceptionWhenStringIsTooLong() 0 6 1
A tooLongStringProvider() 0 5 1
A testNewFromStringHandlesLongStrings() 0 4 1
A testNewFromIntThrowsExceptionWhenIntegerIsTooHigh() 0 5 1
A tooHighNumberProvider() 0 5 1
A testNewFromFloatThrowsExceptionWhenFloatIsTooHigh() 0 5 1
A testNewFromIntHandlesBigIntegers() 0 10 1

How to fix   Complexity   

Complex Class

Complex classes like EuroTest 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 EuroTest, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare( strict_types = 1 );
4
5
namespace WMDE\Euro\Tests\Unit;
6
7
use InvalidArgumentException;
8
use PHPUnit\Framework\TestCase;
9
use WMDE\Euro\Euro;
10
11
/**
12
 * @covers \WMDE\Euro\Euro
13
 *
14
 * @license GNU GPL v2+
15
 * @author Jeroen De Dauw < [email protected] >
16
 */
17
class EuroTest extends TestCase {
18
19
	/**
20
	 * @dataProvider unsignedIntegerProvider
21
	 */
22
	public function testGetCentsReturnsConstructorArgument( int $unsignedInteger ) {
23
		$amount = Euro::newFromCents( $unsignedInteger );
24
		$this->assertSame( $unsignedInteger, $amount->getEuroCents() );
25
	}
26
27
	public function unsignedIntegerProvider() {
28
		return [
29
			[ 0 ], [ 1 ], [ 2 ], [ 9 ], [ 10 ], [ 11 ],
30
			[ 99 ], [ 100 ], [ 101 ], [ 999 ], [ 1000 ], [ 1001 ],
31
		];
32
	}
33
34
	public function testGivenZero_getEuroFloatReturnsZeroFloat() {
35
		$amount = Euro::newFromCents( 0 );
36
		$this->assertExactFloat( 0.0, $amount->getEuroFloat() );
37
		$this->assertNotSame( 0, $amount->getEuroFloat() );
38
	}
39
40
	private function assertExactFloat( float $expected, $actual ) {
41
		$this->assertInternalType( 'float', $actual );
42
		$this->assertEquals( $expected, $actual, '', 0 );
43
	}
44
45
	public function testGivenOneEuro_getEuroFloatReturnsOne() {
46
		$amount = Euro::newFromCents( 100 );
47
		$this->assertExactFloat( 1.0, $amount->getEuroFloat() );
48
	}
49
50
	public function testGivenOneCent_getEuroFloatReturnsPointZeroOne() {
51
		$amount = Euro::newFromCents( 1 );
52
		$this->assertExactFloat( 0.01, $amount->getEuroFloat() );
53
	}
54
55
	public function testGiven33cents_getEuroFloatReturnsPointThreeThree() {
56
		$amount = Euro::newFromCents( 33 );
57
		$this->assertExactFloat( 0.33, $amount->getEuroFloat() );
58
	}
59
60
	public function testGivenNegativeAmount_constructorThrowsException() {
61
		$this->expectException( \InvalidArgumentException::class );
62
		Euro::newFromCents( -1 );
63
	}
64
65
	public function testGivenZero_getEuroStringReturnsZeroString() {
66
		$amount = Euro::newFromCents( 0 );
67
		$this->assertSame( '0.00', $amount->getEuroString() );
68
	}
69
70
	public function testGivenOneEuro_getEuroStringReturnsOnePointZeroZero() {
71
		$amount = Euro::newFromCents( 100 );
72
		$this->assertSame( '1.00', $amount->getEuroString() );
73
	}
74
75
	public function testGivenTwoEuros_getEuroStringReturnsTwoPointZeroZero() {
76
		$amount = Euro::newFromCents( 200 );
77
		$this->assertSame( '2.00', $amount->getEuroString() );
78
	}
79
80
	public function testGivenOneCent_getEuroStringReturnsZeroPointZeroOne() {
81
		$amount = Euro::newFromCents( 1 );
82
		$this->assertSame( '0.01', $amount->getEuroString() );
83
	}
84
85
	public function testGivenTenCents_getEuroStringReturnsZeroPointOneZero() {
86
		$amount = Euro::newFromCents( 10 );
87
		$this->assertSame( '0.10', $amount->getEuroString() );
88
	}
89
90
	public function testGiven1234Cents_getEuroStringReturns12euro34() {
91
		$amount = Euro::newFromCents( 1234 );
92
		$this->assertSame( '12.34', $amount->getEuroString() );
93
	}
94
95
	public function testGiven9876Cents_stringCastingReturns98euro76() {
96
		$amount = Euro::newFromCents( 9876 );
97
		$this->assertSame( '98.76', (string) $amount );
98
	}
99
100
	public function testGivenEuroAmount_jsonEncodeWillEncodeProperly() {
101
		$amount = Euro::newFromCents( 9876 );
102
		$this->assertSame( '"98.76"', json_encode( $amount ) );
103
	}
104
105
	public function testOneEuroString_getsTurnedInto100cents() {
106
		$this->assertSame( 100, Euro::newFromString( '1.00' )->getEuroCents() );
107
	}
108
109
	public function testOneCentString_getsTurnedInto1cents() {
110
		$this->assertSame( 1, Euro::newFromString( '0.01' )->getEuroCents() );
111
	}
112
113
	public function testTenCentString_getsTurnedInto10cents() {
114
		$this->assertSame( 10, Euro::newFromString( '0.10' )->getEuroCents() );
115
	}
116
117
	public function testShortTenCentString_getsTurnedInto10cents() {
118
		$this->assertSame( 10, Euro::newFromString( '0.1' )->getEuroCents() );
119
	}
120
121
	public function testShortOneEuroString_getsTurnedInto100cents() {
122
		$this->assertSame( 100, Euro::newFromString( '1' )->getEuroCents() );
123
	}
124
125
	public function testOneDecimalOneEuroString_getsTurnedInto100cents() {
126
		$this->assertSame( 100, Euro::newFromString( '1.0' )->getEuroCents() );
127
	}
128
129
	public function testMultiDecimalOneEuroString_getsTurnedInto100cents() {
130
		$this->assertSame( 100, Euro::newFromString( '1.00000' )->getEuroCents() );
131
	}
132
133
	public function testHandlingOfLargeEuroString() {
134
		$this->assertSame( 3133742, Euro::newFromString( '31337.42' )->getEuroCents() );
135
	}
136
137
	public function testEuroStringThatCausedRoundingError_doesNotCauseRoundingError() {
138
		// Regression test for https://phabricator.wikimedia.org/T183481
139
		$this->assertSame( 870, Euro::newFromString( '8.70' )->getEuroCents() );
140
		$this->assertSame( 920, Euro::newFromString( '9.20' )->getEuroCents() );
141
	}
142
143
	public function testEuroStringWithRoundingError_getsRoundedAppropriately() {
144
		$this->assertSame( 101, Euro::newFromString( '1.0100000001' )->getEuroCents() );
145
		$this->assertSame( 101, Euro::newFromString( '1.010000009999' )->getEuroCents() );
146
		$this->assertSame( 101, Euro::newFromString( '1.011' )->getEuroCents() );
147
		$this->assertSame( 101, Euro::newFromString( '1.014' )->getEuroCents() );
148
		$this->assertSame( 101, Euro::newFromString( '1.0149' )->getEuroCents() );
149
		$this->assertSame( 102, Euro::newFromString( '1.015' )->getEuroCents() );
150
		$this->assertSame( 102, Euro::newFromString( '1.019' )->getEuroCents() );
151
		$this->assertSame( 102, Euro::newFromString( '1.0199999' )->getEuroCents() );
152
		$this->assertSame( 870, Euro::newFromString( '8.701' )->getEuroCents() );
153
		$this->assertSame( 870, Euro::newFromString( '8.70499' )->getEuroCents() );
154
		$this->assertSame( 871, Euro::newFromString( '8.705' )->getEuroCents() );
155
		$this->assertSame( 871, Euro::newFromString( '8.705000' )->getEuroCents() );
156
		$this->assertSame( 871, Euro::newFromString( '8.705001' )->getEuroCents() );
157
		$this->assertSame( 871, Euro::newFromString( '8.709999' )->getEuroCents() );
158
	}
159
160
	public function testGivenNegativeAmountString_exceptionIsThrown() {
161
		$this->expectException( \InvalidArgumentException::class );
162
		Euro::newFromString( '-1.00' );
163
	}
164
165
	public function testGivenStringWithComma_exceptionIsThrown() {
166
		$this->expectException( \InvalidArgumentException::class );
167
		Euro::newFromString( '1,00' );
168
	}
169
170
	public function testGivenStringWithMultipleDots_ExceptionIsThrown() {
171
		$this->expectException( \InvalidArgumentException::class );
172
		Euro::newFromString( '1.0.0' );
173
	}
174
175
	public function testGivenNonNumber_exceptionIsThrown() {
176
		$this->expectException( \InvalidArgumentException::class );
177
		Euro::newFromString( '1.00abc' );
178
	}
179
180
	public function testGivenNegativeFloatAmount_exceptionIsThrown() {
181
		$this->expectException( \InvalidArgumentException::class );
182
		Euro::newFromFloat( -1.00 );
183
	}
184
185
	public function testOneEuroFloat_getsTurnedInto100cents() {
186
		$this->assertSame( 100, Euro::newFromFloat( 1.0 )->getEuroCents() );
187
	}
188
189
	public function testOneCentFloat_getsTurnedInto1cent() {
190
		$this->assertSame( 1, Euro::newFromFloat( 0.01 )->getEuroCents() );
191
	}
192
193
	public function testTenCentFloat_getsTurnedInto10cents() {
194
		$this->assertSame( 10, Euro::newFromFloat( 0.1 )->getEuroCents() );
195
	}
196
197
	public function testHandlingOfLargeEuroFloat() {
198
		$this->assertSame( 3133742, Euro::newFromFloat( 31337.42 )->getEuroCents() );
199
	}
200
201
	public function testFloatWithRoundingError_getsRoundedAppropriately() {
202
		$this->assertSame( 101, Euro::newFromFloat( 1.0100000001 )->getEuroCents() );
203
		$this->assertSame( 101, Euro::newFromFloat( 1.010000009999 )->getEuroCents() );
204
		$this->assertSame( 101, Euro::newFromFloat( 1.011 )->getEuroCents() );
205
		$this->assertSame( 101, Euro::newFromFloat( 1.014 )->getEuroCents() );
206
		$this->assertSame( 101, Euro::newFromFloat( 1.0149 )->getEuroCents() );
207
		$this->assertSame( 102, Euro::newFromFloat( 1.015 )->getEuroCents() );
208
		$this->assertSame( 102, Euro::newFromFloat( 1.019 )->getEuroCents() );
209
		$this->assertSame( 102, Euro::newFromFloat( 1.0199999 )->getEuroCents() );
210
		$this->assertSame( 870, Euro::newFromFloat( 8.70 )->getEuroCents() );
211
	}
212
213
	public function testZeroEuroIntegers_isZeroCents() {
214
		$this->assertSame( 0, Euro::newFromInt( 0 )->getEuroCents() );
215
	}
216
217
	public function testOneEuroIntegers_is100cents() {
218
		$this->assertSame( 100, Euro::newFromInt( 1 )->getEuroCents() );
219
	}
220
221
	public function test1337EuroIntegers_is133700cents() {
222
		$this->assertSame( 133700, Euro::newFromInt( 1337 )->getEuroCents() );
223
	}
224
225
	public function testGivenNegativeIntegerAmount_exceptionIsThrown() {
226
		$this->expectException( \InvalidArgumentException::class );
227
		Euro::newFromInt( -1 );
228
	}
229
230
	/**
231
	 * @dataProvider euroProvider
232
	 * @param Euro $euro
233
	 */
234
	public function testEuroEqualsItself( Euro $euro ) {
235
		$this->assertTrue( $euro->equals( clone $euro ) );
236
	}
237
238
	public function euroProvider() {
239
		return [
240
			[ Euro::newFromCents( 0 ) ],
241
			[ Euro::newFromCents( 1 ) ],
242
			[ Euro::newFromCents( 99 ) ],
243
			[ Euro::newFromCents( 100 ) ],
244
			[ Euro::newFromCents( 9999 ) ],
245
		];
246
	}
247
248
	public function testOneCentDoesNotEqualOneEuro() {
249
		$this->assertFalse( Euro::newFromCents( 1 )->equals( Euro::newFromInt( 1 ) ) );
250
	}
251
252
	public function testOneCentDoesNotEqualTwoCents() {
253
		$this->assertFalse( Euro::newFromCents( 1 )->equals( Euro::newFromCents( 2 ) ) );
254
	}
255
256
	public function testOneCentDoesNotEqualOneEuroAndOneCent() {
257
		$this->assertFalse( Euro::newFromCents( 1 )->equals( Euro::newFromCents( 101 ) ) );
258
	}
259
260
	public function test9001centsDoesNotEqual9000cents() {
261
		$this->assertFalse( Euro::newFromCents( 9001 )->equals( Euro::newFromCents( 9000 ) ) );
262
	}
263
264
	/**
265
	 * @dataProvider tooLongStringProvider
266
	 */
267
	public function testNewFromStringThrowsExceptionWhenStringIsTooLong( string $string ) {
268
		$this->expectException( InvalidArgumentException::class );
269
		$this->expectExceptionMessage( 'Number is too big' );
270
271
		Euro::newFromString( $string );
272
	}
273
274
	public function tooLongStringProvider() {
275
		yield [ '1111111111111111111111111111111' ];
276
		yield [ (string)PHP_INT_MAX ];
277
		yield [ substr( (string)PHP_INT_MAX, 0, -2 ) ];
278
	}
279
280
	public function testNewFromStringHandlesLongStrings() {
281
		Euro::newFromString( substr( (string)PHP_INT_MAX, 0, -3 ) );
282
		$this->assertTrue( true );
283
	}
284
285
	/**
286
	 * @dataProvider tooHighNumberProvider
287
	 */
288
	public function testNewFromIntThrowsExceptionWhenIntegerIsTooHigh( int $int ) {
289
		$this->expectException( InvalidArgumentException::class );
290
		$this->expectExceptionMessage( 'Number is too big' );
291
		Euro::newFromInt( $int );
292
	}
293
294
	public function tooHighNumberProvider() {
295
		yield [ PHP_INT_MAX ];
296
		yield [ PHP_INT_MAX / 10 ];
297
		yield [ PHP_INT_MAX / 100 ];
298
	}
299
300
	/**
301
	 * @dataProvider tooHighNumberProvider
302
	 */
303
	public function testNewFromFloatThrowsExceptionWhenFloatIsTooHigh( int $int ) {
304
		$this->expectException( InvalidArgumentException::class );
305
		$this->expectExceptionMessage( 'Number is too big' );
306
		Euro::newFromFloat( (float)$int );
307
	}
308
309
	public function testNewFromIntHandlesBigIntegers() {
310
		// Edge case test for the highest allowed value (Euro::CENTS_PER_EURO +1 )
311
		// 100 (Euro::CENTS_PER_EURO) does not work due to rounding
312
		$number = (int)floor( PHP_INT_MAX / 101 );
313
314
		$this->assertSame(
315
			$number * 100,
316
			Euro::newFromInt( $number )->getEuroCents()
317
		);
318
	}
319
320
}
321