Completed
Pull Request — master (#9)
by Jeroen De
02:54
created

EuroTest::testNewFromStringHandlesLongStrings()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
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 testOneEuroString_getsTurnedInto100cents() {
96
		$this->assertSame( 100, Euro::newFromString( '1.00' )->getEuroCents() );
97
	}
98
99
	public function testOneCentString_getsTurnedInto1cents() {
100
		$this->assertSame( 1, Euro::newFromString( '0.01' )->getEuroCents() );
101
	}
102
103
	public function testTenCentString_getsTurnedInto10cents() {
104
		$this->assertSame( 10, Euro::newFromString( '0.10' )->getEuroCents() );
105
	}
106
107
	public function testShortTenCentString_getsTurnedInto10cents() {
108
		$this->assertSame( 10, Euro::newFromString( '0.1' )->getEuroCents() );
109
	}
110
111
	public function testShortOneEuroString_getsTurnedInto100cents() {
112
		$this->assertSame( 100, Euro::newFromString( '1' )->getEuroCents() );
113
	}
114
115
	public function testOneDecimalOneEuroString_getsTurnedInto100cents() {
116
		$this->assertSame( 100, Euro::newFromString( '1.0' )->getEuroCents() );
117
	}
118
119
	public function testMultiDecimalOneEuroString_getsTurnedInto100cents() {
120
		$this->assertSame( 100, Euro::newFromString( '1.00000' )->getEuroCents() );
121
	}
122
123
	public function testHandlingOfLargeEuroString() {
124
		$this->assertSame( 3133742, Euro::newFromString( '31337.42' )->getEuroCents() );
125
	}
126
127
	public function testEuroStringThatCausedRoundingError_doesNotCauseRoundingError() {
128
		// Regression test for https://phabricator.wikimedia.org/T183481
129
		$this->assertSame( 870, Euro::newFromString( '8.70' )->getEuroCents() );
130
		$this->assertSame( 920, Euro::newFromString( '9.20' )->getEuroCents() );
131
	}
132
133
	public function testEuroStringWithRoundingError_getsRoundedAppropriately() {
134
		$this->assertSame( 101, Euro::newFromString( '1.0100000001' )->getEuroCents() );
135
		$this->assertSame( 101, Euro::newFromString( '1.010000009999' )->getEuroCents() );
136
		$this->assertSame( 101, Euro::newFromString( '1.011' )->getEuroCents() );
137
		$this->assertSame( 101, Euro::newFromString( '1.014' )->getEuroCents() );
138
		$this->assertSame( 101, Euro::newFromString( '1.0149' )->getEuroCents() );
139
		$this->assertSame( 102, Euro::newFromString( '1.015' )->getEuroCents() );
140
		$this->assertSame( 102, Euro::newFromString( '1.019' )->getEuroCents() );
141
		$this->assertSame( 102, Euro::newFromString( '1.0199999' )->getEuroCents() );
142
		$this->assertSame( 870, Euro::newFromString( '8.701' )->getEuroCents() );
143
		$this->assertSame( 870, Euro::newFromString( '8.70499' )->getEuroCents() );
144
		$this->assertSame( 871, Euro::newFromString( '8.705' )->getEuroCents() );
145
		$this->assertSame( 871, Euro::newFromString( '8.705000' )->getEuroCents() );
146
		$this->assertSame( 871, Euro::newFromString( '8.705001' )->getEuroCents() );
147
		$this->assertSame( 871, Euro::newFromString( '8.709999' )->getEuroCents() );
148
	}
149
150
	public function testGivenNegativeAmountString_exceptionIsThrown() {
151
		$this->expectException( \InvalidArgumentException::class );
152
		Euro::newFromString( '-1.00' );
153
	}
154
155
	public function testGivenStringWithComma_exceptionIsThrown() {
156
		$this->expectException( \InvalidArgumentException::class );
157
		Euro::newFromString( '1,00' );
158
	}
159
160
	public function testGivenStringWithMultipleDots_ExceptionIsThrown() {
161
		$this->expectException( \InvalidArgumentException::class );
162
		Euro::newFromString( '1.0.0' );
163
	}
164
165
	public function testGivenNonNumber_exceptionIsThrown() {
166
		$this->expectException( \InvalidArgumentException::class );
167
		Euro::newFromString( '1.00abc' );
168
	}
169
170
	public function testGivenNegativeFloatAmount_exceptionIsThrown() {
171
		$this->expectException( \InvalidArgumentException::class );
172
		Euro::newFromFloat( -1.00 );
173
	}
174
175
	public function testOneEuroFloat_getsTurnedInto100cents() {
176
		$this->assertSame( 100, Euro::newFromFloat( 1.0 )->getEuroCents() );
177
	}
178
179
	public function testOneCentFloat_getsTurnedInto1cent() {
180
		$this->assertSame( 1, Euro::newFromFloat( 0.01 )->getEuroCents() );
181
	}
182
183
	public function testTenCentFloat_getsTurnedInto10cents() {
184
		$this->assertSame( 10, Euro::newFromFloat( 0.1 )->getEuroCents() );
185
	}
186
187
	public function testHandlingOfLargeEuroFloat() {
188
		$this->assertSame( 3133742, Euro::newFromFloat( 31337.42 )->getEuroCents() );
189
	}
190
191
	public function testFloatWithRoundingError_getsRoundedAppropriately() {
192
		$this->assertSame( 101, Euro::newFromFloat( 1.0100000001 )->getEuroCents() );
193
		$this->assertSame( 101, Euro::newFromFloat( 1.010000009999 )->getEuroCents() );
194
		$this->assertSame( 101, Euro::newFromFloat( 1.011 )->getEuroCents() );
195
		$this->assertSame( 101, Euro::newFromFloat( 1.014 )->getEuroCents() );
196
		$this->assertSame( 101, Euro::newFromFloat( 1.0149 )->getEuroCents() );
197
		$this->assertSame( 102, Euro::newFromFloat( 1.015 )->getEuroCents() );
198
		$this->assertSame( 102, Euro::newFromFloat( 1.019 )->getEuroCents() );
199
		$this->assertSame( 102, Euro::newFromFloat( 1.0199999 )->getEuroCents() );
200
		$this->assertSame( 870, Euro::newFromFloat( 8.70 )->getEuroCents() );
201
	}
202
203
	public function testZeroEuroIntegers_isZeroCents() {
204
		$this->assertSame( 0, Euro::newFromInt( 0 )->getEuroCents() );
205
	}
206
207
	public function testOneEuroIntegers_is100cents() {
208
		$this->assertSame( 100, Euro::newFromInt( 1 )->getEuroCents() );
209
	}
210
211
	public function test1337EuroIntegers_is133700cents() {
212
		$this->assertSame( 133700, Euro::newFromInt( 1337 )->getEuroCents() );
213
	}
214
215
	public function testGivenNegativeIntegerAmount_exceptionIsThrown() {
216
		$this->expectException( \InvalidArgumentException::class );
217
		Euro::newFromInt( -1 );
218
	}
219
220
	/**
221
	 * @dataProvider euroProvider
222
	 * @param Euro $euro
223
	 */
224
	public function testEuroEqualsItself( Euro $euro ) {
225
		$this->assertTrue( $euro->equals( clone $euro ) );
226
	}
227
228
	public function euroProvider() {
229
		return [
230
			[ Euro::newFromCents( 0 ) ],
231
			[ Euro::newFromCents( 1 ) ],
232
			[ Euro::newFromCents( 99 ) ],
233
			[ Euro::newFromCents( 100 ) ],
234
			[ Euro::newFromCents( 9999 ) ],
235
		];
236
	}
237
238
	public function testOneCentDoesNotEqualOneEuro() {
239
		$this->assertFalse( Euro::newFromCents( 1 )->equals( Euro::newFromInt( 1 ) ) );
240
	}
241
242
	public function testOneCentDoesNotEqualTwoCents() {
243
		$this->assertFalse( Euro::newFromCents( 1 )->equals( Euro::newFromCents( 2 ) ) );
244
	}
245
246
	public function testOneCentDoesNotEqualOneEuroAndOneCent() {
247
		$this->assertFalse( Euro::newFromCents( 1 )->equals( Euro::newFromCents( 101 ) ) );
248
	}
249
250
	public function test9001centsDoesNotEqual9000cents() {
251
		$this->assertFalse( Euro::newFromCents( 9001 )->equals( Euro::newFromCents( 9000 ) ) );
252
	}
253
254
	/**
255
	 * @dataProvider tooLongStringProvider
256
	 */
257
	public function testNewFromStringThrowsExceptionWhenStringIsTooLong( string $string ) {
258
		$this->expectException( InvalidArgumentException::class );
259
		$this->expectExceptionMessage( 'Number is too big' );
260
261
		Euro::newFromString( $string );
262
	}
263
264
	public function tooLongStringProvider() {
265
		yield [ '1111111111111111111111111111111' ];
266
		yield [ (string)PHP_INT_MAX ];
267
		yield [ substr( (string)PHP_INT_MAX, 0, -2 ) ];
268
	}
269
270
	public function testNewFromStringHandlesLongStrings() {
271
		Euro::newFromString( substr( (string)PHP_INT_MAX, 0, -3 ) );
272
		$this->assertTrue( true );
273
	}
274
275
	/**
276
	 * @dataProvider tooHighIntegerProvider
277
	 */
278
	public function testNewFromIntThrowsExceptionWhenIntegerIsTooHigh( int $int ) {
279
		$this->expectException( InvalidArgumentException::class );
280
		$this->expectExceptionMessage( 'Number is too big' );
281
		Euro::newFromInt( $int );
282
	}
283
284
	public function tooHighIntegerProvider() {
285
		yield [ PHP_INT_MAX ];
286
		yield [ PHP_INT_MAX / 10 ];
287
		yield [ PHP_INT_MAX / 100 ];
288
	}
289
290
	public function testNewFromIntHandlesBigIntegers() {
291
		$number = (int)floor( PHP_INT_MAX / 101 );
292
293
		$this->assertSame(
294
			$number * 100,
295
			Euro::newFromInt( $number )->getEuroCents()
296
		);
297
	}
298
299
}
300