Passed
Pull Request — master (#22)
by
unknown
62:59
created

EuroTest::getEurosDataProvider()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 6
rs 10
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 GPL-2.0-or-later
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( $expected, $actual ) {
41
		$this->assertIsFloat( $actual );
42
		$this->assertEquals( $expected, $actual, '', 0 );
0 ignored issues
show
Unused Code introduced by
The call to PHPUnit\Framework\Assert::assertEquals() has too many arguments starting with 0. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

42
		$this->/** @scrutinizer ignore-call */ 
43
         assertEquals( $expected, $actual, '', 0 );

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
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
	/**
61
	 * @dataProvider getEurosDataProvider
62
	 */
63
	public function testGetEurosReturnsCorrectValues( int $cents, int $expectedEuros) {
0 ignored issues
show
introduced by
Single space expected before closing parenthesis
Loading history...
Coding Style introduced by
Expected 1 spaces before closing parenthesis; 0 found
Loading history...
64
		$amount = Euro::newFromCents( $cents );
65
		$this->assertEquals( $expectedEuros, $amount->getEuros() );
66
	}
67
68
	private function getEurosDataProvider(): array {
0 ignored issues
show
Unused Code introduced by
The method getEurosDataProvider() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
69
		return [
70
			[ 0, 0 ],
71
			[ 3, 0 ],
72
			[ 102, 1 ],
73
			[ 1033, 10 ],
74
		];
75
	}
76
77
	public function testGivenNegativeAmount_constructorThrowsException() {
78
		$this->expectException( \InvalidArgumentException::class );
79
		Euro::newFromCents( -1 );
80
	}
81
82
	public function testGivenZero_getEuroStringReturnsZeroString() {
83
		$amount = Euro::newFromCents( 0 );
84
		$this->assertSame( '0.00', $amount->getEuroString() );
85
	}
86
87
	public function testGivenOneEuro_getEuroStringReturnsOnePointZeroZero() {
88
		$amount = Euro::newFromCents( 100 );
89
		$this->assertSame( '1.00', $amount->getEuroString() );
90
	}
91
92
	public function testGivenTwoEuros_getEuroStringReturnsTwoPointZeroZero() {
93
		$amount = Euro::newFromCents( 200 );
94
		$this->assertSame( '2.00', $amount->getEuroString() );
95
	}
96
97
	public function testGivenOneCent_getEuroStringReturnsZeroPointZeroOne() {
98
		$amount = Euro::newFromCents( 1 );
99
		$this->assertSame( '0.01', $amount->getEuroString() );
100
	}
101
102
	public function testGivenTenCents_getEuroStringReturnsZeroPointOneZero() {
103
		$amount = Euro::newFromCents( 10 );
104
		$this->assertSame( '0.10', $amount->getEuroString() );
105
	}
106
107
	public function testGiven1234Cents_getEuroStringReturns12euro34() {
108
		$amount = Euro::newFromCents( 1234 );
109
		$this->assertSame( '12.34', $amount->getEuroString() );
110
	}
111
112
	public function testGiven9876Cents_stringCastingReturns98euro76() {
113
		$amount = Euro::newFromCents( 9876 );
114
		$this->assertSame( '98.76', (string)$amount );
115
	}
116
117
	public function testGivenEuroAmount_jsonEncodeWillEncodeProperly() {
118
		$amount = Euro::newFromCents( 9876 );
119
		$this->assertSame( '"98.76"', json_encode( $amount ) );
120
	}
121
122
	public function testOneEuroString_getsTurnedInto100cents() {
123
		$this->assertSame( 100, Euro::newFromString( '1.00' )->getEuroCents() );
124
	}
125
126
	public function testOneCentString_getsTurnedInto1cents() {
127
		$this->assertSame( 1, Euro::newFromString( '0.01' )->getEuroCents() );
128
	}
129
130
	public function testTenCentString_getsTurnedInto10cents() {
131
		$this->assertSame( 10, Euro::newFromString( '0.10' )->getEuroCents() );
132
	}
133
134
	public function testShortTenCentString_getsTurnedInto10cents() {
135
		$this->assertSame( 10, Euro::newFromString( '0.1' )->getEuroCents() );
136
	}
137
138
	public function testShortOneEuroString_getsTurnedInto100cents() {
139
		$this->assertSame( 100, Euro::newFromString( '1' )->getEuroCents() );
140
	}
141
142
	public function testOneDecimalOneEuroString_getsTurnedInto100cents() {
143
		$this->assertSame( 100, Euro::newFromString( '1.0' )->getEuroCents() );
144
	}
145
146
	public function testMultiDecimalOneEuroString_getsTurnedInto100cents() {
147
		$this->assertSame( 100, Euro::newFromString( '1.00000' )->getEuroCents() );
148
	}
149
150
	public function testHandlingOfLargeEuroString() {
151
		$this->assertSame( 3133742, Euro::newFromString( '31337.42' )->getEuroCents() );
152
	}
153
154
	public function testEuroStringThatCausedRoundingError_doesNotCauseRoundingError() {
155
		// Regression test for https://phabricator.wikimedia.org/T183481
156
		$this->assertSame( 870, Euro::newFromString( '8.70' )->getEuroCents() );
157
		$this->assertSame( 920, Euro::newFromString( '9.20' )->getEuroCents() );
158
	}
159
160
	public function testEuroStringWithRoundingError_getsRoundedAppropriately() {
161
		$this->assertSame( 101, Euro::newFromString( '1.0100000001' )->getEuroCents() );
162
		$this->assertSame( 101, Euro::newFromString( '1.010000009999' )->getEuroCents() );
163
		$this->assertSame( 101, Euro::newFromString( '1.011' )->getEuroCents() );
164
		$this->assertSame( 101, Euro::newFromString( '1.014' )->getEuroCents() );
165
		$this->assertSame( 101, Euro::newFromString( '1.0149' )->getEuroCents() );
166
		$this->assertSame( 102, Euro::newFromString( '1.015' )->getEuroCents() );
167
		$this->assertSame( 102, Euro::newFromString( '1.019' )->getEuroCents() );
168
		$this->assertSame( 102, Euro::newFromString( '1.0199999' )->getEuroCents() );
169
		$this->assertSame( 870, Euro::newFromString( '8.701' )->getEuroCents() );
170
		$this->assertSame( 870, Euro::newFromString( '8.70499' )->getEuroCents() );
171
		$this->assertSame( 871, Euro::newFromString( '8.705' )->getEuroCents() );
172
		$this->assertSame( 871, Euro::newFromString( '8.705000' )->getEuroCents() );
173
		$this->assertSame( 871, Euro::newFromString( '8.705001' )->getEuroCents() );
174
		$this->assertSame( 871, Euro::newFromString( '8.709999' )->getEuroCents() );
175
	}
176
177
	public function testGivenNegativeAmountString_exceptionIsThrown() {
178
		$this->expectException( \InvalidArgumentException::class );
179
		Euro::newFromString( '-1.00' );
180
	}
181
182
	public function testGivenStringWithComma_exceptionIsThrown() {
183
		$this->expectException( \InvalidArgumentException::class );
184
		Euro::newFromString( '1,00' );
185
	}
186
187
	public function testGivenStringWithMultipleDots_ExceptionIsThrown() {
188
		$this->expectException( \InvalidArgumentException::class );
189
		Euro::newFromString( '1.0.0' );
190
	}
191
192
	public function testGivenNonNumber_exceptionIsThrown() {
193
		$this->expectException( \InvalidArgumentException::class );
194
		Euro::newFromString( '1.00abc' );
195
	}
196
197
	public function testGivenNegativeFloatAmount_exceptionIsThrown() {
198
		$this->expectException( \InvalidArgumentException::class );
199
		Euro::newFromFloat( -1.00 );
200
	}
201
202
	public function testOneEuroFloat_getsTurnedInto100cents() {
203
		$this->assertSame( 100, Euro::newFromFloat( 1.0 )->getEuroCents() );
204
	}
205
206
	public function testOneCentFloat_getsTurnedInto1cent() {
207
		$this->assertSame( 1, Euro::newFromFloat( 0.01 )->getEuroCents() );
208
	}
209
210
	public function testTenCentFloat_getsTurnedInto10cents() {
211
		$this->assertSame( 10, Euro::newFromFloat( 0.1 )->getEuroCents() );
212
	}
213
214
	public function testHandlingOfLargeEuroFloat() {
215
		$this->assertSame( 3133742, Euro::newFromFloat( 31337.42 )->getEuroCents() );
216
	}
217
218
	public function testFloatWithRoundingError_getsRoundedAppropriately() {
219
		$this->assertSame( 101, Euro::newFromFloat( 1.0100000001 )->getEuroCents() );
220
		$this->assertSame( 101, Euro::newFromFloat( 1.010000009999 )->getEuroCents() );
221
		$this->assertSame( 101, Euro::newFromFloat( 1.011 )->getEuroCents() );
222
		$this->assertSame( 101, Euro::newFromFloat( 1.014 )->getEuroCents() );
223
		$this->assertSame( 101, Euro::newFromFloat( 1.0149 )->getEuroCents() );
224
		$this->assertSame( 102, Euro::newFromFloat( 1.015 )->getEuroCents() );
225
		$this->assertSame( 102, Euro::newFromFloat( 1.019 )->getEuroCents() );
226
		$this->assertSame( 102, Euro::newFromFloat( 1.0199999 )->getEuroCents() );
227
		$this->assertSame( 870, Euro::newFromFloat( 8.70 )->getEuroCents() );
228
	}
229
230
	public function testZeroEuroIntegers_isZeroCents() {
231
		$this->assertSame( 0, Euro::newFromInt( 0 )->getEuroCents() );
232
	}
233
234
	public function testOneEuroIntegers_is100Cents() {
235
		$this->assertSame( 100, Euro::newFromInt( 1 )->getEuroCents() );
236
	}
237
238
	// phpcs:ignore MediaWiki.NamingConventions.LowerCamelFunctionsName.FunctionName
239
	public function test1337EuroIntegers_is133700Cents() {
240
		$this->assertSame( 133700, Euro::newFromInt( 1337 )->getEuroCents() );
241
	}
242
243
	public function testGivenNegativeIntegerAmount_exceptionIsThrown() {
244
		$this->expectException( \InvalidArgumentException::class );
245
		Euro::newFromInt( -1 );
246
	}
247
248
	/**
249
	 * @dataProvider euroProvider
250
	 * @param Euro $euro
251
	 */
252
	public function testEuroEqualsItself( Euro $euro ) {
253
		$this->assertTrue( $euro->equals( clone $euro ) );
254
	}
255
256
	public function euroProvider() {
257
		return [
258
			[ Euro::newFromCents( 0 ) ],
259
			[ Euro::newFromCents( 1 ) ],
260
			[ Euro::newFromCents( 99 ) ],
261
			[ Euro::newFromCents( 100 ) ],
262
			[ Euro::newFromCents( 9999 ) ],
263
		];
264
	}
265
266
	public function testOneCentDoesNotEqualOneEuro() {
267
		$this->assertFalse( Euro::newFromCents( 1 )->equals( Euro::newFromInt( 1 ) ) );
268
	}
269
270
	public function testOneCentDoesNotEqualTwoCents() {
271
		$this->assertFalse( Euro::newFromCents( 1 )->equals( Euro::newFromCents( 2 ) ) );
272
	}
273
274
	public function testOneCentDoesNotEqualOneEuroAndOneCent() {
275
		$this->assertFalse( Euro::newFromCents( 1 )->equals( Euro::newFromCents( 101 ) ) );
276
	}
277
278
	public function test9001centsDoesNotEqual9000cents() {
279
		$this->assertFalse( Euro::newFromCents( 9001 )->equals( Euro::newFromCents( 9000 ) ) );
280
	}
281
282
	/**
283
	 * @dataProvider tooLongStringProvider
284
	 */
285
	public function testNewFromStringThrowsExceptionWhenStringIsTooLong( string $string ) {
286
		$this->expectException( InvalidArgumentException::class );
287
		$this->expectExceptionMessage( 'Number is too big' );
288
289
		Euro::newFromString( $string );
290
	}
291
292
	public function tooLongStringProvider() {
293
		yield [ '1111111111111111111111111111111' ];
294
		yield [ (string)PHP_INT_MAX ];
295
		yield [ substr( (string)PHP_INT_MAX, 0, -2 ) ];
296
	}
297
298
	public function testNewFromStringHandlesLongStrings() {
299
		Euro::newFromString( substr( (string)PHP_INT_MAX, 0, -3 ) );
300
		$this->assertTrue( true );
301
	}
302
303
	/**
304
	 * @dataProvider tooHighNumberProvider
305
	 */
306
	public function testNewFromIntThrowsExceptionWhenIntegerIsTooHigh( int $int ) {
307
		$this->expectException( InvalidArgumentException::class );
308
		$this->expectExceptionMessage( 'Number is too big' );
309
		Euro::newFromInt( $int );
310
	}
311
312
	public function tooHighNumberProvider() {
313
		yield [ PHP_INT_MAX ];
314
		yield [ (int)floor( PHP_INT_MAX / 10 ) ];
315
		yield [ (int)floor( PHP_INT_MAX / 100 ) ];
316
	}
317
318
	/**
319
	 * @dataProvider tooHighNumberProvider
320
	 */
321
	public function testNewFromFloatThrowsExceptionWhenFloatIsTooHigh( int $int ) {
322
		$this->expectException( InvalidArgumentException::class );
323
		$this->expectExceptionMessage( 'Number is too big' );
324
		Euro::newFromFloat( (float)$int );
325
	}
326
327
	public function testNewFromIntHandlesBigIntegers() {
328
		// Edge case test for the highest allowed value (Euro::CENTS_PER_EURO +1 )
329
		// 100 (Euro::CENTS_PER_EURO) does not work due to rounding
330
		$number = (int)floor( PHP_INT_MAX / 101 );
331
332
		$this->assertSame(
333
			$number * 100,
334
			Euro::newFromInt( $number )->getEuroCents()
335
		);
336
	}
337
338
}
339