1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace DataValues\Tests; |
4
|
|
|
|
5
|
|
|
use DataValues\DecimalValue; |
6
|
|
|
|
7
|
|
|
/** |
8
|
|
|
* @covers DataValues\DecimalValue |
9
|
|
|
* |
10
|
|
|
* @group DataValue |
11
|
|
|
* @group DataValueExtensions |
12
|
|
|
* |
13
|
|
|
* @license GPL-2.0+ |
14
|
|
|
* @author Daniel Kinzler |
15
|
|
|
*/ |
16
|
|
|
class DecimalValueTest extends DataValueTest { |
17
|
|
|
|
18
|
|
|
/** |
19
|
|
|
* @see DataValueTest::getClass |
20
|
|
|
* |
21
|
|
|
* @return string |
22
|
|
|
*/ |
23
|
|
|
public function getClass() { |
24
|
|
|
return DecimalValue::class; |
25
|
|
|
} |
26
|
|
|
|
27
|
|
|
public function validConstructorArgumentsProvider() { |
28
|
|
|
$argLists = []; |
29
|
|
|
|
30
|
|
|
$argLists[] = [ 42 ]; |
31
|
|
|
$argLists[] = [ -42 ]; |
32
|
|
|
$argLists[] = [ '-42' ]; |
33
|
|
|
$argLists[] = [ 4.2 ]; |
34
|
|
|
$argLists[] = [ -4.2 ]; |
35
|
|
|
$argLists[] = [ '+4.2' ]; |
36
|
|
|
$argLists[] = [ " +4.2\n" ]; |
37
|
|
|
$argLists[] = [ 0 ]; |
38
|
|
|
$argLists[] = [ 0.2 ]; |
39
|
|
|
$argLists[] = [ '-0.42' ]; |
40
|
|
|
$argLists[] = [ '-0.0' ]; |
41
|
|
|
$argLists[] = [ '-0' ]; |
42
|
|
|
$argLists[] = [ '+0' ]; |
43
|
|
|
$argLists[] = [ '+0.0' ]; |
44
|
|
|
$argLists[] = [ '+0.000' ]; |
45
|
|
|
$argLists[] = [ '+1.' . str_repeat( '0', 124 ) ]; |
46
|
|
|
$argLists[] = [ '+1.0' . str_repeat( ' ', 124 ) ]; |
47
|
|
|
$argLists[] = [ '4.2' ]; |
48
|
|
|
$argLists[] = [ " 4.2\n" ]; |
49
|
|
|
|
50
|
|
|
return $argLists; |
51
|
|
|
} |
52
|
|
|
|
53
|
|
|
public function invalidConstructorArgumentsProvider() { |
54
|
|
|
$argLists = []; |
55
|
|
|
|
56
|
|
|
$argLists[] = [ 'foo' ]; |
57
|
|
|
$argLists[] = [ '' ]; |
58
|
|
|
$argLists[] = [ '++4.2' ]; |
59
|
|
|
$argLists[] = [ '--4.2' ]; |
60
|
|
|
$argLists[] = [ '-+4.2' ]; |
61
|
|
|
$argLists[] = [ '+-4.2' ]; |
62
|
|
|
$argLists[] = [ '+/-0' ]; |
63
|
|
|
$argLists[] = [ '-.42' ]; |
64
|
|
|
$argLists[] = [ '+.42' ]; |
65
|
|
|
$argLists[] = [ '.42' ]; |
66
|
|
|
$argLists[] = [ '.0' ]; |
67
|
|
|
$argLists[] = [ '-00' ]; |
68
|
|
|
$argLists[] = [ '−1' ]; |
69
|
|
|
$argLists[] = [ '+01.2' ]; |
70
|
|
|
$argLists[] = [ 'x2' ]; |
71
|
|
|
$argLists[] = [ '2x' ]; |
72
|
|
|
$argLists[] = [ '+0100' ]; |
73
|
|
|
$argLists[] = [ false ]; |
74
|
|
|
$argLists[] = [ true ]; |
75
|
|
|
$argLists[] = [ null ]; |
76
|
|
|
$argLists[] = [ '0x20' ]; |
77
|
|
|
$argLists[] = [ '+1.' . str_repeat( '0', 125 ) ]; |
78
|
|
|
|
79
|
|
|
return $argLists; |
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
/** |
83
|
|
|
* @see https://phabricator.wikimedia.org/T110728 |
84
|
|
|
* @see http://www.regular-expressions.info/anchors.html#realend |
85
|
|
|
*/ |
86
|
|
|
public function testTrailingNewlineRobustness() { |
87
|
|
|
$value = DecimalValue::newFromArray( "-0.0\n" ); |
|
|
|
|
88
|
|
|
|
89
|
|
|
$this->assertTrue( $value->isZero() ); |
90
|
|
|
$this->assertSame( 'C:23:"DataValues\DecimalValue":11:{s:4:"+0.0";}', serialize( $value ) ); |
91
|
|
|
$this->assertSame( '+0.0', $value->getValue(), 'getValue' ); |
92
|
|
|
$this->assertSame( '+0.0', $value->getArrayValue(), 'getArrayValue' ); |
93
|
|
|
$this->assertSame( '+0.0', $value->__toString(), '__toString' ); |
94
|
|
|
$this->assertSame( '0', $value->getFractionalPart(), 'getFractionalPart' ); |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* @dataProvider provideFloats |
99
|
|
|
*/ |
100
|
|
|
public function testFloatInputs( $float, $expectedPrefix ) { |
101
|
|
|
$value = DecimalValue::newFromArray( $float ); |
|
|
|
|
102
|
|
|
|
103
|
|
|
$this->assertStringStartsWith( $expectedPrefix, $value->getValue(), 'getValue' ); |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
public function provideFloats() { |
107
|
|
|
return [ |
108
|
|
|
[ 0.000000002, '+0.000000002' ], |
109
|
|
|
[ 0.000003, '+0.000003' ], |
110
|
|
|
[ 0.9, '+0.9' ], |
111
|
|
|
[ 1.2, '+1.2' ], |
112
|
|
|
[ 1.5, '+1.5' ], |
113
|
|
|
[ 123E-1, '+12.3' ], |
114
|
|
|
[ 123E+1, '+1230' ], |
115
|
|
|
[ 1234567890123456, '+1234567890123' ], |
116
|
|
|
[ 1234567890123456789, '+1234567890123' ], |
117
|
|
|
]; |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
/** |
121
|
|
|
* @dataProvider compareProvider |
122
|
|
|
*/ |
123
|
|
|
public function testCompare( DecimalValue $a, DecimalValue $b, $expected ) { |
124
|
|
|
$actual = $a->compare( $b ); |
|
|
|
|
125
|
|
|
$this->assertSame( $expected, $actual ); |
126
|
|
|
|
127
|
|
|
$actual = $b->compare( $a ); |
|
|
|
|
128
|
|
|
$this->assertSame( -$expected, $actual ); |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
public function compareProvider() { |
132
|
|
|
return [ |
133
|
|
|
'zero/equal' => [ new DecimalValue( 0 ), new DecimalValue( 0 ), 0 ], |
134
|
|
|
'zero-signs/equal' => [ new DecimalValue( '+0' ), new DecimalValue( '-0' ), 0 ], |
135
|
|
|
'zero-digits/equal' => [ new DecimalValue( '+0' ), new DecimalValue( '+0.000' ), 0 ], |
136
|
|
|
'digits/equal' => [ new DecimalValue( '+2.2' ), new DecimalValue( '+2.2000' ), 0 ], |
137
|
|
|
'conversion/equal' => [ new DecimalValue( 2.5 ), new DecimalValue( '+2.50' ), 0 ], |
138
|
|
|
'negative/equal' => [ new DecimalValue( '-1.33' ), new DecimalValue( '-1.33' ), 0 ], |
139
|
|
|
|
140
|
|
|
'simple/smaller' => [ new DecimalValue( '+1' ), new DecimalValue( '+2' ), -1 ], |
141
|
|
|
'simple/greater' => [ new DecimalValue( '+2' ), new DecimalValue( '+1' ), 1 ], |
142
|
|
|
'negative/greater' => [ new DecimalValue( '-1' ), new DecimalValue( '-2' ), 1 ], |
143
|
|
|
'negative/smaller' => [ new DecimalValue( '-2' ), new DecimalValue( '-1' ), -1 ], |
144
|
|
|
'negative-small/greater' => [ new DecimalValue( '-0.5' ), new DecimalValue( '-0.7' ), 1 ], |
145
|
|
|
'negative-small/smaller' => [ new DecimalValue( '-0.7' ), new DecimalValue( '-0.5' ), -1 ], |
146
|
|
|
|
147
|
|
|
'digits/greater' => [ new DecimalValue( '+11' ), new DecimalValue( '+8' ), 1 ], |
148
|
|
|
'digits-sub/greater' => [ new DecimalValue( '+11' ), new DecimalValue( '+8.0' ), 1 ], |
149
|
|
|
'negative-digits/greater' => [ new DecimalValue( '-11' ), new DecimalValue( '-80' ), 1 ], |
150
|
|
|
'small/greater' => [ new DecimalValue( '+0.050' ), new DecimalValue( '+0.005' ), 1 ], |
151
|
|
|
|
152
|
|
|
'signs/greater' => [ new DecimalValue( '+1' ), new DecimalValue( '-8' ), 1 ], |
153
|
|
|
'signs/less' => [ new DecimalValue( '-8' ), new DecimalValue( '+1' ), -1 ], |
154
|
|
|
|
155
|
|
|
'with-and-without-point' => [ new DecimalValue( '+100' ), new DecimalValue( '+100.01' ), -1 ], |
156
|
|
|
]; |
157
|
|
|
} |
158
|
|
|
|
159
|
|
|
/** |
160
|
|
|
* @dataProvider getSignProvider |
161
|
|
|
*/ |
162
|
|
|
public function testGetSign( DecimalValue $value, $expected ) { |
163
|
|
|
$actual = $value->getSign(); |
164
|
|
|
$this->assertSame( $expected, $actual ); |
165
|
|
|
} |
166
|
|
|
|
167
|
|
|
public function getSignProvider() { |
168
|
|
|
return [ |
169
|
|
|
'zero is positive' => [ new DecimalValue( 0 ), '+' ], |
170
|
|
|
'zero is always positive' => [ new DecimalValue( '-0' ), '+' ], |
171
|
|
|
'zero is ALWAYS positive' => [ new DecimalValue( '-0.00' ), '+' ], |
172
|
|
|
'+1 is positive' => [ new DecimalValue( '+1' ), '+' ], |
173
|
|
|
'-1 is negative' => [ new DecimalValue( '-1' ), '-' ], |
174
|
|
|
'+0.01 is positive' => [ new DecimalValue( '+0.01' ), '+' ], |
175
|
|
|
'-0.01 is negative' => [ new DecimalValue( '-0.01' ), '-' ], |
176
|
|
|
]; |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
/** |
180
|
|
|
* @dataProvider getValueProvider |
181
|
|
|
*/ |
182
|
|
|
public function testGetValue( DecimalValue $value, $expected ) { |
183
|
|
|
$actual = $value->getValue(); |
184
|
|
|
$this->assertSame( $expected, $actual ); |
185
|
|
|
} |
186
|
|
|
|
187
|
|
|
public function getValueProvider() { |
188
|
|
|
$argLists = []; |
189
|
|
|
|
190
|
|
|
$argLists[] = [ new DecimalValue( 42 ), '+42' ]; |
191
|
|
|
$argLists[] = [ new DecimalValue( -42 ), '-42' ]; |
192
|
|
|
$argLists[] = [ new DecimalValue( -42.0 ), '-42' ]; |
193
|
|
|
$argLists[] = [ new DecimalValue( '-42' ), '-42' ]; |
194
|
|
|
$argLists[] = [ new DecimalValue( 4.5 ), '+4.5' ]; |
195
|
|
|
$argLists[] = [ new DecimalValue( -4.5 ), '-4.5' ]; |
196
|
|
|
$argLists[] = [ new DecimalValue( '+4.2' ), '+4.2' ]; |
197
|
|
|
$argLists[] = [ new DecimalValue( 0 ), '+0' ]; |
198
|
|
|
$argLists[] = [ new DecimalValue( 0.0 ), '+0' ]; |
199
|
|
|
$argLists[] = [ new DecimalValue( 1.0 ), '+1' ]; |
200
|
|
|
$argLists[] = [ new DecimalValue( 0.5 ), '+0.5' ]; |
201
|
|
|
$argLists[] = [ new DecimalValue( '-0.42' ), '-0.42' ]; |
202
|
|
|
$argLists[] = [ new DecimalValue( '-0.0' ), '+0.0' ]; |
203
|
|
|
$argLists[] = [ new DecimalValue( '-0' ), '+0' ]; |
204
|
|
|
$argLists[] = [ new DecimalValue( '+0.0' ), '+0.0' ]; |
205
|
|
|
$argLists[] = [ new DecimalValue( '+0' ), '+0' ]; |
206
|
|
|
$argLists[] = [ new DecimalValue( 2147483649 ), '+2147483649' ]; |
207
|
|
|
$argLists[] = [ new DecimalValue( 1000000000000000 ), '+1000000000000000' ]; |
208
|
|
|
$argLists[] = [ |
209
|
|
|
new DecimalValue( 1 + 1e-12 / 3 ), |
210
|
|
|
'+1.0000000000003' |
211
|
|
|
]; |
212
|
|
|
$argLists[] = [ |
213
|
|
|
new DecimalValue( 1 + 1e-14 / 3 ), |
214
|
|
|
'+1' |
215
|
|
|
]; |
216
|
|
|
|
217
|
|
|
return $argLists; |
218
|
|
|
} |
219
|
|
|
|
220
|
|
|
/** |
221
|
|
|
* @dataProvider getValueFloatProvider |
222
|
|
|
*/ |
223
|
|
|
public function testGetValueFloat( DecimalValue $value, $expected ) { |
224
|
|
|
$actual = $value->getValueFloat(); |
225
|
|
|
$this->assertSame( $expected, $actual ); |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
public function getValueFloatProvider() { |
229
|
|
|
$argLists = []; |
230
|
|
|
|
231
|
|
|
$argLists[] = [ new DecimalValue( 42 ), 42.0 ]; |
232
|
|
|
$argLists[] = [ new DecimalValue( -42 ), -42.0 ]; |
233
|
|
|
$argLists[] = [ new DecimalValue( '-42' ), -42.0 ]; |
234
|
|
|
$argLists[] = [ new DecimalValue( 4.5 ), 4.5 ]; |
235
|
|
|
$argLists[] = [ new DecimalValue( -4.5 ), -4.5 ]; |
236
|
|
|
$argLists[] = [ new DecimalValue( '+4.2' ), 4.2 ]; |
237
|
|
|
$argLists[] = [ new DecimalValue( 0 ), 0.0 ]; |
238
|
|
|
$argLists[] = [ new DecimalValue( 0.5 ), 0.5 ]; |
239
|
|
|
$argLists[] = [ new DecimalValue( '-0.42' ), -0.42 ]; |
240
|
|
|
$argLists[] = [ new DecimalValue( '-0.0' ), 0.0 ]; |
241
|
|
|
$argLists[] = [ new DecimalValue( '-0' ), 0.0 ]; |
242
|
|
|
$argLists[] = [ new DecimalValue( '+0.0' ), 0.0 ]; |
243
|
|
|
$argLists[] = [ new DecimalValue( '+0' ), 0.0 ]; |
244
|
|
|
|
245
|
|
|
return $argLists; |
246
|
|
|
} |
247
|
|
|
|
248
|
|
|
/** |
249
|
|
|
* @dataProvider getGetIntegerPartProvider |
250
|
|
|
*/ |
251
|
|
|
public function testGetIntegerPart( DecimalValue $value, $expected ) { |
252
|
|
|
$actual = $value->getIntegerPart(); |
253
|
|
|
$this->assertSame( $expected, $actual ); |
254
|
|
|
} |
255
|
|
|
|
256
|
|
|
public function getGetIntegerPartProvider() { |
257
|
|
|
return [ |
258
|
|
|
[ new DecimalValue( '+0' ), '0' ], |
259
|
|
|
[ new DecimalValue( '-0.0' ), '0' ], |
260
|
|
|
[ new DecimalValue( '+10' ), '10' ], |
261
|
|
|
[ new DecimalValue( '-10' ), '10' ], |
262
|
|
|
[ new DecimalValue( '+10.663' ), '10' ], |
263
|
|
|
[ new DecimalValue( '-10.001' ), '10' ], |
264
|
|
|
[ new DecimalValue( '+0.01' ), '0' ], |
265
|
|
|
]; |
266
|
|
|
} |
267
|
|
|
|
268
|
|
|
/** |
269
|
|
|
* @dataProvider getGetIntegerPartProvider |
270
|
|
|
*/ |
271
|
|
|
public function testGetFractionalPart( DecimalValue $value, $expected ) { |
272
|
|
|
$actual = $value->getIntegerPart(); |
273
|
|
|
$this->assertSame( $expected, $actual ); |
274
|
|
|
} |
275
|
|
|
|
276
|
|
|
public function getGetFractionalPartProvider() { |
277
|
|
|
return [ |
278
|
|
|
[ new DecimalValue( '+0' ), '' ], |
279
|
|
|
[ new DecimalValue( '-0.0' ), '0' ], |
280
|
|
|
[ new DecimalValue( '+10' ), '' ], |
281
|
|
|
[ new DecimalValue( '+10.663' ), '663' ], |
282
|
|
|
[ new DecimalValue( '-10.001' ), '001' ], |
283
|
|
|
[ new DecimalValue( '+0.01' ), '01' ], |
284
|
|
|
]; |
285
|
|
|
} |
286
|
|
|
|
287
|
|
|
/** |
288
|
|
|
* @dataProvider computeComplementProvider |
289
|
|
|
*/ |
290
|
|
|
public function testComputeComplement( DecimalValue $value, $expected ) { |
291
|
|
|
$complement = $value->computeComplement(); |
292
|
|
|
$this->assertSame( $expected, $complement->getValue() ); |
293
|
|
|
|
294
|
|
|
$actual = $complement->computeComplement(); |
295
|
|
|
$this->assertSame( $value->getValue(), $actual->getValue() ); |
296
|
|
|
} |
297
|
|
|
|
298
|
|
|
public function computeComplementProvider() { |
299
|
|
|
return [ |
300
|
|
|
[ new DecimalValue( '+0' ), '+0' ], |
301
|
|
|
[ new DecimalValue( '+0.00' ), '+0.00' ], |
302
|
|
|
[ new DecimalValue( '+1' ), '-1' ], |
303
|
|
|
[ new DecimalValue( '+100.663' ), '-100.663' ], |
304
|
|
|
[ new DecimalValue( '-0.001' ), '+0.001' ], |
305
|
|
|
]; |
306
|
|
|
} |
307
|
|
|
|
308
|
|
|
/** |
309
|
|
|
* @dataProvider computeComputeAbsolute |
310
|
|
|
*/ |
311
|
|
|
public function testComputeAbsolute( DecimalValue $value, $expected ) { |
312
|
|
|
$absolute = $value->computeAbsolute(); |
313
|
|
|
$this->assertSame( $expected, $absolute->getValue() ); |
314
|
|
|
|
315
|
|
|
$actual = $absolute->computeAbsolute(); |
316
|
|
|
$this->assertSame( $absolute->getValue(), $actual->getValue() ); |
317
|
|
|
} |
318
|
|
|
|
319
|
|
|
public function computeComputeAbsolute() { |
320
|
|
|
return [ |
321
|
|
|
[ new DecimalValue( '+0' ), '+0' ], |
322
|
|
|
[ new DecimalValue( '+1' ), '+1' ], |
323
|
|
|
[ new DecimalValue( '-1' ), '+1' ], |
324
|
|
|
[ new DecimalValue( '+100.663' ), '+100.663' ], |
325
|
|
|
[ new DecimalValue( '-100.663' ), '+100.663' ], |
326
|
|
|
[ new DecimalValue( '+0.001' ), '+0.001' ], |
327
|
|
|
[ new DecimalValue( '-0.001' ), '+0.001' ], |
328
|
|
|
]; |
329
|
|
|
} |
330
|
|
|
|
331
|
|
|
/** |
332
|
|
|
* @dataProvider isZeroProvider |
333
|
|
|
*/ |
334
|
|
|
public function testIsZero( DecimalValue $value, $expected ) { |
335
|
|
|
$actual = $value->isZero(); |
336
|
|
|
$this->assertSame( $expected, $actual ); |
337
|
|
|
} |
338
|
|
|
|
339
|
|
|
public function isZeroProvider() { |
340
|
|
|
return [ |
341
|
|
|
[ new DecimalValue( '+0' ), true ], |
342
|
|
|
[ new DecimalValue( '-0.00' ), true ], |
343
|
|
|
|
344
|
|
|
[ new DecimalValue( '+1' ), false ], |
345
|
|
|
[ new DecimalValue( '+100.663' ), false ], |
346
|
|
|
[ new DecimalValue( '-0.001' ), false ], |
347
|
|
|
]; |
348
|
|
|
} |
349
|
|
|
|
350
|
|
|
/** |
351
|
|
|
* @dataProvider provideGetTrim |
352
|
|
|
*/ |
353
|
|
|
public function testGetTrim( DecimalValue $value, DecimalValue $expected ) { |
354
|
|
|
$actual = $value->getTrimmed(); |
355
|
|
|
$this->assertSame( $expected->getValue(), $actual->getValue() ); |
356
|
|
|
} |
357
|
|
|
|
358
|
|
|
public function provideGetTrim() { |
359
|
|
|
return [ |
360
|
|
|
[ new DecimalValue( '+8' ), new DecimalValue( '+8' ) ], |
361
|
|
|
[ new DecimalValue( '+80' ), new DecimalValue( '+80' ) ], |
362
|
|
|
[ new DecimalValue( '+800' ), new DecimalValue( '+800' ) ], |
363
|
|
|
[ new DecimalValue( '+0' ), new DecimalValue( '+0' ) ], |
364
|
|
|
[ new DecimalValue( '+0.0' ), new DecimalValue( '+0' ) ], |
365
|
|
|
[ new DecimalValue( '+10.00' ), new DecimalValue( '+10' ) ], |
366
|
|
|
[ new DecimalValue( '-0.1' ), new DecimalValue( '-0.1' ) ], |
367
|
|
|
[ new DecimalValue( '-0.10' ), new DecimalValue( '-0.1' ) ], |
368
|
|
|
[ new DecimalValue( '-0.010' ), new DecimalValue( '-0.01' ) ], |
369
|
|
|
[ new DecimalValue( '-0.001' ), new DecimalValue( '-0.001' ) ], |
370
|
|
|
]; |
371
|
|
|
} |
372
|
|
|
|
373
|
|
|
} |
374
|
|
|
|
This method has been deprecated. The supplier of the class has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.