Passed
Pull Request — master (#130)
by
unknown
10:11
created

QuantityValueTest::newFromNumberProvider()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 56

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 56
rs 8.9599
c 0
b 0
f 0
nc 1
cc 1
nop 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace DataValues\Tests;
4
5
use DataValues\DecimalValue;
6
use DataValues\IllegalValueException;
7
use DataValues\QuantityValue;
8
use DataValues\UnboundedQuantityValue;
9
10
/**
11
 * @covers \DataValues\QuantityValue
12
 *
13
 * @group DataValue
14
 * @group DataValueExtensions
15
 *
16
 * @license GPL-2.0-or-later
17
 * @author Daniel Kinzler
18
 */
19
class QuantityValueTest extends DataValuesTestBase {
20
21
	public function setUp(): void {
22
		if ( !\extension_loaded( 'bcmath' ) ) {
23
			$this->markTestSkipped( 'bcmath extension not loaded' );
24
		}
25
	}
26
27
	/**
28
	 * @see DataValueTest::getClass
29
	 *
30
	 * @return string
31
	 */
32
	public function getClass() {
33
		return QuantityValue::class;
34
	}
35
36
	public function validConstructorArgumentsProvider() {
37
		$argLists = [];
38
39
		$argLists[] = [ new DecimalValue( '+42' ), '1', new DecimalValue( '+42' ), new DecimalValue( '+42' ) ];
40
		$argLists[] = [ new DecimalValue( '+0.01' ), '1', new DecimalValue( '+0.02' ), new DecimalValue( '+0.0001' ) ];
41
		$argLists[] = [ new DecimalValue( '-0.5' ), '1', new DecimalValue( '+0.02' ), new DecimalValue( '-0.7' ) ];
42
43
		return $argLists;
44
	}
45
46
	public function invalidConstructorArgumentsProvider() {
47
		$argLists = [];
48
49
		$argLists[] = [ new DecimalValue( '+0' ), '', new DecimalValue( '+0' ), new DecimalValue( '+0' ) ];
50
		$argLists[] = [ new DecimalValue( '+0' ), 1, new DecimalValue( '+0' ), new DecimalValue( '+0' ) ];
51
52
		$argLists[] = [ new DecimalValue( '+0' ), '1', new DecimalValue( '-0.001' ), new DecimalValue( '-1' ) ];
53
		$argLists[] = [ new DecimalValue( '+0' ), '1', new DecimalValue( '+1' ), new DecimalValue( '+0.001' ) ];
54
55
		return $argLists;
56
	}
57
58
	/**
59
	 * @dataProvider instanceProvider
60
	 */
61
	public function testGetValue( QuantityValue $quantity, array $arguments ) {
0 ignored issues
show
Unused Code introduced by
The parameter $arguments is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
62
		$this->assertSame( $quantity, $quantity->getValue() );
63
	}
64
65
	/**
66
	 * @dataProvider instanceProvider
67
	 */
68
	public function testGetAmount( QuantityValue $quantity, array $arguments ) {
69
		$this->assertSame( $arguments[0], $quantity->getAmount() );
70
	}
71
72
	/**
73
	 * @dataProvider instanceProvider
74
	 */
75
	public function testGetUnit( QuantityValue $quantity, array $arguments ) {
76
		$this->assertSame( $arguments[1], $quantity->getUnit() );
77
	}
78
79
	/**
80
	 * @dataProvider instanceProvider
81
	 */
82
	public function testGetUpperBound( QuantityValue $quantity, array $arguments ) {
83
		$this->assertSame( $arguments[2], $quantity->getUpperBound() );
84
	}
85
86
	/**
87
	 * @dataProvider instanceProvider
88
	 */
89
	public function testGetLowerBound( QuantityValue $quantity, array $arguments ) {
90
		$this->assertSame( $arguments[3], $quantity->getLowerBound() );
91
	}
92
93
	/**
94
	 * @dataProvider newFromNumberProvider
95
	 */
96
	public function testNewFromNumber( $amount, $unit, $upperBound, $lowerBound, QuantityValue $expected ) {
97
		$quantity = QuantityValue::newFromNumber( $amount, $unit, $upperBound, $lowerBound );
98
99
		$this->assertEquals( $expected->getAmount()->getValue(), $quantity->getAmount()->getValue() );
100
		$this->assertEquals( $expected->getUpperBound()->getValue(), $quantity->getUpperBound()->getValue() );
101
		$this->assertEquals( $expected->getLowerBound()->getValue(), $quantity->getLowerBound()->getValue() );
102
	}
103
104
	public function newFromNumberProvider() {
105
		$value = new DecimalValue( '+42' );
106
		$unit = '1';
107
		yield [
108
			$value->getValueFloat(), $unit, null, null,
109
			new QuantityValue( $value, $unit, $value, $value )
110
		];
111
		$value = new DecimalValue( '-0.05' );
112
		$decimalValueFromFloat = new DecimalValue( $value->getValueFloat() );
113
		yield [
114
			$value->getValueFloat(), $unit, null, null,
115
			new QuantityValue( $decimalValueFromFloat, $unit, $decimalValueFromFloat, $decimalValueFromFloat )
116
		];
117
		$value = new DecimalValue( '+0' );
118
		$value1 = new DecimalValue( '+0.5' );
119
		$value2 = new DecimalValue( '-0.5' );
120
		$unit = 'm';
121
		yield [
122
			$value->getValueFloat(), $unit, $value1->getValueFloat(), $value2->getValueFloat(),
123
			new QuantityValue( $value, $unit, $value1, $value2 )
124
		];
125
		$value = new DecimalValue( '+23' );
126
		$unit = '1';
127
		yield [
128
			$value->getValueFloat(), $unit, null, null,
129
			new QuantityValue( $value, $unit, $value, $value )
130
		];
131
		$value = new DecimalValue( '+42' );
132
		$value1 = new DecimalValue( '+43' );
133
		$value2 = new DecimalValue( '+41' );
134
		$unit = '1';
135
		yield [
136
			$value->getValueFloat(), $unit, $value1->getValueFloat(), $value2->getValueFloat(),
137
			new QuantityValue( $value, $unit, $value1, $value2 )
138
		];
139
		$value = new DecimalValue( '-0.05' );
140
		$value1 = new DecimalValue( '-0.04' );
141
		$value2 = new DecimalValue( '-0.06' );
142
		$decimalValueFromFloat = new DecimalValue( $value->getValueFloat() );
143
		$decimalValueFromFloat1 = new DecimalValue( $value1->getValueFloat() );
144
		$decimalValueFromFloat2 = new DecimalValue( $value2->getValueFloat() );
145
146
		$unit = 'm';
147
		yield [
148
			$value->getValueFloat(), $unit, $value1->getValueFloat(), $value2->getValueFloat(),
149
			new QuantityValue( $decimalValueFromFloat, $unit, $decimalValueFromFloat1, $decimalValueFromFloat2 )
150
		];
151
		$value = new DecimalValue( '+42' );
152
		$value1 = new DecimalValue( 43 );
153
		$value2 = new DecimalValue( 41.0 );
154
		$unit = '1';
155
		yield [
156
			$value, $unit, $value1, $value2,
157
			new QuantityValue( $value, $unit, $value1, $value2 )
158
		];
159
	}
160
161
	/**
162
	 * @dataProvider validArraySerializationProvider
163
	 */
164
	public function testNewFromArray( $data, UnboundedQuantityValue $expected ) {
165
		$value = QuantityValue::newFromArray( $data );
0 ignored issues
show
Deprecated Code introduced by
The method DataValues\UnboundedQuantityValue::newFromArray() has been deprecated with message: since 0.8.3. Static DataValue::newFromArray constructors like this are underspecified (not in the DataValue interface), and misleadingly named (should be named newFromArrayValue). Instead, use DataValue builder callbacks in @see DataValueDeserializer.

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.

Loading history...
166
		$this->assertTrue( $expected->equals( $value ), $value . ' should equal ' . $expected );
167
	}
168
169
	public function validArraySerializationProvider() {
170
		return [
171
			'complete' => [
172
				[
173
					'amount' => '+2',
174
					'unit' => '1',
175
					'upperBound' => '+2.5',
176
					'lowerBound' => '+1.5',
177
				],
178
				QuantityValue::newFromNumber( '+2', '1', '+2.5', '+1.5' )
179
			],
180
			'unbounded' => [
181
				[
182
					'amount' => '+2',
183
					'unit' => '1',
184
				],
185
				UnboundedQuantityValue::newFromNumber( '+2', '1' )
186
			],
187
			'unbounded with existing array keys' => [
188
				[
189
					'amount' => '+2',
190
					'unit' => '1',
191
					'upperBound' => null,
192
					'lowerBound' => null,
193
				],
194
				UnboundedQuantityValue::newFromNumber( '+2', '1' )
195
			],
196
		];
197
	}
198
199
	/**
200
	 * @dataProvider invalidArraySerializationProvider
201
	 */
202
	public function testNewFromArray_failure( $data ) {
203
		$this->expectException( IllegalValueException::class );
204
		QuantityValue::newFromArray( $data );
0 ignored issues
show
Deprecated Code introduced by
The method DataValues\UnboundedQuantityValue::newFromArray() has been deprecated with message: since 0.8.3. Static DataValue::newFromArray constructors like this are underspecified (not in the DataValue interface), and misleadingly named (should be named newFromArrayValue). Instead, use DataValue builder callbacks in @see DataValueDeserializer.

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.

Loading history...
205
	}
206
207
	public function invalidArraySerializationProvider() {
208
		return [
209
			'no-amount' => [
210
				[
211
					'unit' => '1',
212
					'upperBound' => '+2.5',
213
					'lowerBound' => '+1.5',
214
				]
215
			],
216
			'no-unit' => [
217
				[
218
					'amount' => '+2',
219
					'upperBound' => '+2.5',
220
					'lowerBound' => '+1.5',
221
				]
222
			],
223
			'no-upperBound' => [
224
				[
225
					'amount' => '+2',
226
					'unit' => '1',
227
					'lowerBound' => '+1.5',
228
				]
229
			],
230
			'no-lowerBound' => [
231
				[
232
					'amount' => '+2',
233
					'unit' => '1',
234
					'upperBound' => '+2.5',
235
				]
236
			],
237
			'bad-amount' => [
238
				[
239
					'amount' => 'x',
240
					'unit' => '1',
241
					'upperBound' => '+2.5',
242
					'lowerBound' => '+1.5',
243
				]
244
			],
245
			'bad-upperBound' => [
246
				[
247
					'amount' => '+2',
248
					'unit' => '1',
249
					'upperBound' => 'x',
250
					'lowerBound' => '+1.5',
251
				]
252
			],
253
			'bad-lowerBound' => [
254
				[
255
					'amount' => '+2',
256
					'unit' => '1',
257
					'upperBound' => '+2.5',
258
					'lowerBound' => 'x',
259
				]
260
			],
261
		];
262
	}
263
264
	/**
265
	 * @see https://phabricator.wikimedia.org/T110728
266
	 * @see http://www.regular-expressions.info/anchors.html#realend
267
	 */
268
	public function testTrailingNewlineRobustness() {
269
		$value = QuantityValue::newFromArray( [
0 ignored issues
show
Deprecated Code introduced by
The method DataValues\UnboundedQuantityValue::newFromArray() has been deprecated with message: since 0.8.3. Static DataValue::newFromArray constructors like this are underspecified (not in the DataValue interface), and misleadingly named (should be named newFromArrayValue). Instead, use DataValue builder callbacks in @see DataValueDeserializer.

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.

Loading history...
270
			'amount' => "-0.0\n",
271
			'unit' => "1\n",
272
			'upperBound' => "-0.0\n",
273
			'lowerBound' => "-0.0\n",
274
		] );
275
276
		$this->assertSame( [
277
			'amount' => '+0.0',
278
			'unit' => "1\n",
279
			'upperBound' => '+0.0',
280
			'lowerBound' => '+0.0',
281
		], $value->getArrayValue() );
282
	}
283
284
	/**
285
	 * @dataProvider instanceProvider
286
	 */
287
	public function testGetSortKey( QuantityValue $quantity ) {
288
		$this->assertSame( $quantity->getAmount()->getValueFloat(), $quantity->getSortKey() );
289
	}
290
291
	/**
292
	 * @dataProvider getUncertaintyProvider
293
	 */
294
	public function testGetUncertainty( QuantityValue $quantity, $expected ) {
295
		$this->assertSame( $expected, $quantity->getUncertainty() );
296
	}
297
298
	public function getUncertaintyProvider() {
299
		return [
300
			[ QuantityValue::newFromNumber( '+0', '1', '+0', '+0' ), 0.0 ],
301
302
			[ QuantityValue::newFromNumber( '+0', '1', '+1', '-1' ), 2.0 ],
303
			[ QuantityValue::newFromNumber( '+0.00', '1', '+0.01', '-0.01' ), 0.02 ],
304
			[ QuantityValue::newFromNumber( '+100', '1', '+101', '+99' ), 2.0 ],
305
			[ QuantityValue::newFromNumber( '+100.0', '1', '+100.1', '+99.9' ), 0.2 ],
306
			[ QuantityValue::newFromNumber( '+12.34', '1', '+12.35', '+12.33' ), 0.02 ],
307
308
			[ QuantityValue::newFromNumber( '+0', '1', '+0.2', '-0.6' ), 0.8 ],
309
			[ QuantityValue::newFromNumber( '+7.3', '1', '+7.7', '+5.2' ), 2.5 ],
310
		];
311
	}
312
313
	/**
314
	 * @dataProvider getUncertaintyMarginProvider
315
	 */
316
	public function testGetUncertaintyMargin( QuantityValue $quantity, $expected ) {
317
		$this->assertSame( $expected, $quantity->getUncertaintyMargin()->getValue() );
318
	}
319
320
	public function getUncertaintyMarginProvider() {
321
		return [
322
			[ QuantityValue::newFromNumber( '+0', '1', '+1', '-1' ), '+1' ],
323
			[ QuantityValue::newFromNumber( '+0.00', '1', '+0.01', '-0.01' ), '+0.01' ],
324
325
			[ QuantityValue::newFromNumber( '-1', '1', '-1', '-1' ), '+0' ],
326
327
			[ QuantityValue::newFromNumber( '+0', '1', '+0.2', '-0.6' ), '+0.6' ],
328
			[ QuantityValue::newFromNumber( '+7.5', '1', '+7.5', '+5.5' ), '+2.0' ],
329
			[ QuantityValue::newFromNumber( '+11.5', '1', '+15', '+10.5' ), '+3.5' ],
330
		];
331
	}
332
333
	/**
334
	 * @dataProvider getOrderOfUncertaintyProvider
335
	 */
336
	public function testGetOrderOfUncertainty( QuantityValue $quantity, $expected ) {
337
		$this->assertSame( $expected, $quantity->getOrderOfUncertainty() );
338
	}
339
340
	public function getOrderOfUncertaintyProvider() {
341
		return [
342
			0 => [ QuantityValue::newFromNumber( '+0' ), 0 ],
343
			1 => [ QuantityValue::newFromNumber( '-123' ), 0 ],
344
			2 => [ QuantityValue::newFromNumber( '-1.23' ), -2 ],
345
346
			10 => [ QuantityValue::newFromNumber( '-100', '1', '-99', '-101' ), 0 ],
347
			11 => [ QuantityValue::newFromNumber( '+0.00', '1', '+0.01', '-0.01' ), -2 ],
348
			12 => [ QuantityValue::newFromNumber( '-117.3', '1', '-117.2', '-117.4' ), -1 ],
349
350
			20 => [ QuantityValue::newFromNumber( '+100', '1', '+100.01', '+99.97' ), -2 ],
351
			21 => [ QuantityValue::newFromNumber( '-0.002', '1', '-0.001', '-0.004' ), -3 ],
352
			22 => [ QuantityValue::newFromNumber( '-0.002', '1', '+0.001', '-0.06' ), -3 ],
353
			23 => [ QuantityValue::newFromNumber( '-21', '1', '+1.1', '-120' ), 1 ],
354
			24 => [ QuantityValue::newFromNumber( '-2', '1', '+1.1', '-120' ), 0 ],
355
			25 => [ QuantityValue::newFromNumber( '+1000', '1', '+1100', '+900.03' ), 1 ],
356
			26 => [ QuantityValue::newFromNumber( '+1000', '1', '+1100', '+900' ), 2 ],
357
		];
358
	}
359
360
	/**
361
	 * @dataProvider transformProvider
362
	 */
363
	public function testTransform( QuantityValue $quantity, $transformation, QuantityValue $expected ) {
364
		$args = func_get_args();
365
		$extraArgs = array_slice( $args, 3 );
366
367
		$call = [ $quantity, 'transform' ];
368
		$callArgs = array_merge( [ 'x', $transformation ], $extraArgs );
369
		$actual = call_user_func_array( $call, $callArgs );
370
371
		$this->assertSame( 'x', $actual->getUnit() );
372
		$this->assertEquals(
373
			$expected->getAmount()->getValue(),
374
			$actual->getAmount()->getValue(),
375
			'value'
376
		);
377
		$this->assertEquals(
378
			$expected->getUpperBound()->getValue(),
379
			$actual->getUpperBound()->getValue(),
380
			'upper bound'
381
		);
382
		$this->assertEquals(
383
			$expected->getLowerBound()->getValue(),
384
			$actual->getLowerBound()->getValue(),
385
			'lower bound'
386
		);
387
	}
388
389
	public function transformProvider() {
390
		$identity = function ( DecimalValue $value ) {
391
			return $value;
392
		};
393
394
		$square = function ( DecimalValue $value ) {
395
			$v = $value->getValueFloat();
396
			return new DecimalValue( $v * $v * $v );
397
		};
398
399
		$scale = function ( DecimalValue $value, $factor ) {
400
			return new DecimalValue( $value->getValueFloat() * $factor );
401
		};
402
403
		return [
404
			0 => [
405
				QuantityValue::newFromNumber( '+10', '1', '+11', '+9' ),
406
				$identity,
407
				QuantityValue::newFromNumber( '+10', '?', '+11', '+9' )
408
			],
409
			1 => [
410
				QuantityValue::newFromNumber( '-0.5', '1', '-0.4', '-0.6' ),
411
				$identity,
412
				QuantityValue::newFromNumber( '-0.5', '?', '-0.4', '-0.6' )
413
			],
414
			2 => [
415
				QuantityValue::newFromNumber( '+0', '1', '+1', '-1' ),
416
				$square,
417
				QuantityValue::newFromNumber( '+0', '?', '+1', '-1' )
418
			],
419
			3 => [
420
				QuantityValue::newFromNumber( '+10', '1', '+11', '+9' ),
421
				$square,
422
				// note how rounding applies to bounds
423
				QuantityValue::newFromNumber( '+1000', '?', '+1300', '+700' )
424
			],
425
			4 => [
426
				QuantityValue::newFromNumber( '+0.5', '1', '+0.6', '+0.4' ),
427
				$scale,
428
				QuantityValue::newFromNumber( '+0.25', '?', '+0.30', '+0.20' ),
429
				0.5
430
			],
431
432
			// note: absolutely exact values require conversion with infinite precision!
433
			10 => [
434
				QuantityValue::newFromNumber( '+100', '1', '+100', '+100' ),
435
				$scale,
436
				QuantityValue::newFromNumber( '+12825', '?', '+12825', '+12825' ),
437
				128.25
438
			],
439
440
			11 => [
441
				QuantityValue::newFromNumber( '+100', '1', '+110', '+90' ),
442
				$scale,
443
				QuantityValue::newFromNumber( '+330', '?', '+370', '+300' ),
444
				3.3333
445
			],
446
			12 => [
447
				QuantityValue::newFromNumber( '+100', '1', '+100.1', '+99.9' ),
448
				$scale,
449
				QuantityValue::newFromNumber( '+333.3', '?', '+333.7', '+333.0' ),
450
				3.3333
451
			],
452
			13 => [
453
				QuantityValue::newFromNumber( '+100', '1', '+100.01', '+99.99' ),
454
				$scale,
455
				QuantityValue::newFromNumber( '+333.33', '?', '+333.36', '+333.30' ),
456
				3.3333
457
			],
458
		];
459
	}
460
461
}
462