Completed
Push — master ( 19cfc9...8af716 )
by Daniel
23s
created

validArraySerializationProvider()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 13
rs 9.4285
cc 1
eloc 9
nc 1
nop 0
1
<?php
2
3
namespace DataValues\Tests;
4
5
use DataValues\DecimalValue;
6
use DataValues\QuantityValue;
7
8
/**
9
 * @covers DataValues\QuantityValue
10
 *
11
 * @group DataValue
12
 * @group DataValueExtensions
13
 *
14
 * @license GPL-2.0+
15
 * @author Daniel Kinzler
16
 */
17
class QuantityValueTest extends DataValueTest {
18
19
	/**
20
	 * @see DataValueTest::getClass
21
	 *
22
	 * @return string
23
	 */
24
	public function getClass() {
25
		return 'DataValues\QuantityValue';
26
	}
27
28
	public function validConstructorArgumentsProvider() {
29
		$argLists = array();
30
31
		$argLists[] = array( new DecimalValue( '+42' ), '1', new DecimalValue( '+42' ), new DecimalValue( '+42' ) );
32
		$argLists[] = array( new DecimalValue( '+0.01' ), '1', new DecimalValue( '+0.02' ), new DecimalValue( '+0.0001' ) );
33
		$argLists[] = array( new DecimalValue( '-0.5' ), '1', new DecimalValue( '+0.02' ), new DecimalValue( '-0.7' ) );
34
35
		return $argLists;
36
	}
37
38
	public function invalidConstructorArgumentsProvider() {
39
		$argLists = array();
40
41
		$argLists[] = array( new DecimalValue( '+0' ), '', new DecimalValue( '+0' ), new DecimalValue( '+0' ) );
42
		$argLists[] = array( new DecimalValue( '+0' ), 1, new DecimalValue( '+0' ), new DecimalValue( '+0' ) );
43
44
		$argLists[] = array( new DecimalValue( '+0' ), '1', new DecimalValue( '-0.001' ), new DecimalValue( '-1' ) );
45
		$argLists[] = array( new DecimalValue( '+0' ), '1', new DecimalValue( '+1' ), new DecimalValue( '+0.001' ) );
46
47
		return $argLists;
48
	}
49
50
	/**
51
	 * @dataProvider instanceProvider
52
	 */
53
	public function testGetValue( QuantityValue $quantity, array $arguments ) {
54
		$this->assertInstanceOf( $this->getClass(), $quantity->getValue() );
55
	}
56
57
	/**
58
	 * @dataProvider instanceProvider
59
	 */
60
	public function testGetAmount( QuantityValue $quantity, array $arguments ) {
61
		$this->assertEquals( $arguments[0], $quantity->getAmount() );
62
	}
63
64
	/**
65
	 * @dataProvider instanceProvider
66
	 */
67
	public function testGetUnit( QuantityValue $quantity, array $arguments ) {
68
		$this->assertEquals( $arguments[1], $quantity->getUnit() );
69
	}
70
71
	/**
72
	 * @dataProvider instanceProvider
73
	 */
74
	public function testGetUpperBound( QuantityValue $quantity, array $arguments ) {
75
		$this->assertEquals( $arguments[2], $quantity->getUpperBound() );
76
	}
77
78
	/**
79
	 * @dataProvider instanceProvider
80
	 */
81
	public function testGetLowerBound( QuantityValue $quantity, array $arguments ) {
82
		$this->assertEquals( $arguments[3], $quantity->getLowerBound() );
83
	}
84
85
	/**
86
	 * @dataProvider newFromNumberProvider
87
	 */
88
	public function testNewFromNumber( $amount, $unit, $upperBound, $lowerBound, QuantityValue $expected ) {
89
		$quantity = QuantityValue::newFromNumber( $amount, $unit, $upperBound, $lowerBound );
90
91
		$this->assertEquals( $expected->getAmount()->getValue(), $quantity->getAmount()->getValue() );
92
		$this->assertEquals( $expected->getUpperBound()->getValue(), $quantity->getUpperBound()->getValue() );
93
		$this->assertEquals( $expected->getLowerBound()->getValue(), $quantity->getLowerBound()->getValue() );
94
	}
95
96
	public function newFromNumberProvider() {
97
		return array(
98
			array(
99
				42, '1', null, null,
100
				new QuantityValue( new DecimalValue( '+42' ), '1', new DecimalValue( '+42' ), new DecimalValue( '+42' ) )
101
			),
102
			array(
103
				-0.05, '1', null, null,
104
				new QuantityValue( new DecimalValue( '-0.05' ), '1', new DecimalValue( '-0.05' ), new DecimalValue( '-0.05' ) )
105
			),
106
			array(
107
				0, 'm', 0.5, -0.5,
108
				new QuantityValue( new DecimalValue( '+0' ), 'm', new DecimalValue( '+0.5' ), new DecimalValue( '-0.5' ) )
109
			),
110
			array(
111
				'+23', '1', null, null,
112
				new QuantityValue( new DecimalValue( '+23' ), '1', new DecimalValue( '+23' ), new DecimalValue( '+23' ) )
113
			),
114
			array(
115
				'+42', '1', '+43', '+41',
116
				new QuantityValue( new DecimalValue( '+42' ), '1', new DecimalValue( '+43' ), new DecimalValue( '+41' ) )
117
			),
118
			array(
119
				'-0.05', 'm', '-0.04', '-0.06',
120
				new QuantityValue( new DecimalValue( '-0.05' ), 'm', new DecimalValue( '-0.04' ), new DecimalValue( '-0.06' ) )
121
			),
122
			array(
123
				new DecimalValue( '+42' ), '1', new DecimalValue( 43 ), new DecimalValue( 41.0 ),
124
				new QuantityValue( new DecimalValue( '+42' ), '1', new DecimalValue( 43 ), new DecimalValue( 41.0 ) )
125
			),
126
		);
127
	}
128
129
	/**
130
	 * @dataProvider validArraySerializationProvider
131
	 */
132
	public function testNewFromArray( $data, QuantityValue $expected ) {
133
		$value = QuantityValue::newFromArray( $data );
134
		$this->assertTrue( $expected->equals( $value ), $value . ' should equal ' . $expected );
135
	}
136
137
	public function validArraySerializationProvider() {
138
		return array(
139
			'complete' => array(
140
				array(
141
					'amount' => '+2',
142
					'unit' => '1',
143
					'upperBound' => '+2.5',
144
					'lowerBound' => '+1.5',
145
				),
146
				QuantityValue::newFromNumber( '+2', '1', '+2.5', '+1.5' )
147
			),
148
		);
149
	}
150
151
	/**
152
	 * @dataProvider invalidArraySerializationProvider
153
	 */
154
	public function testNewFromArray_failure( $data ) {
155
		$this->setExpectedException( 'DataValues\IllegalValueException' );
156
		QuantityValue::newFromArray( $data );
157
	}
158
159
	public function invalidArraySerializationProvider() {
160
		return array(
161
			'no-amount' => array(
162
				array(
163
					'unit' => '1',
164
					'upperBound' => '+2.5',
165
					'lowerBound' => '+1.5',
166
				)
167
			),
168
			'no-unit' => array(
169
				array(
170
					'amount' => '+2',
171
					'upperBound' => '+2.5',
172
					'lowerBound' => '+1.5',
173
				)
174
			),
175
			'no-upperBound' => array(
176
				array(
177
					'amount' => '+2',
178
					'unit' => '1',
179
					'lowerBound' => '+1.5',
180
				)
181
			),
182
			'no-lowerBound' => array(
183
				array(
184
					'amount' => '+2',
185
					'unit' => '1',
186
					'upperBound' => '+2.5',
187
				)
188
			),
189
			'unbounded' => array(
190
				array(
191
					'amount' => '+2',
192
					'unit' => '1',
193
				)
194
			),
195
			'bad-amount' => array(
196
				array(
197
					'amount' => 'x',
198
					'unit' => '1',
199
					'upperBound' => '+2.5',
200
					'lowerBound' => '+1.5',
201
				)
202
			),
203
			'bad-upperBound' => array(
204
				array(
205
					'amount' => '+2',
206
					'unit' => '1',
207
					'upperBound' => 'x',
208
					'lowerBound' => '+1.5',
209
				)
210
			),
211
			'bad-lowerBound' => array(
212
				array(
213
					'amount' => '+2',
214
					'unit' => '1',
215
					'upperBound' => '+2.5',
216
					'lowerBound' => 'x',
217
				)
218
			),
219
		);
220
	}
221
222
	/**
223
	 * @see https://phabricator.wikimedia.org/T110728
224
	 * @see http://www.regular-expressions.info/anchors.html#realend
225
	 */
226
	public function testTrailingNewlineRobustness() {
227
		$value = QuantityValue::newFromArray( array(
228
			'amount' => "-0.0\n",
229
			'unit' => "1\n",
230
			'upperBound' => "-0.0\n",
231
			'lowerBound' => "-0.0\n",
232
		) );
233
234
		$this->assertSame( array(
235
			'amount' => '+0.0',
236
			'unit' => "1\n",
237
			'upperBound' => '+0.0',
238
			'lowerBound' => '+0.0',
239
		), $value->getArrayValue() );
240
	}
241
242
	/**
243
	 * @dataProvider instanceProvider
244
	 */
245
	public function testGetSortKey( QuantityValue $quantity ) {
246
		$this->assertEquals( $quantity->getAmount()->getValueFloat(), $quantity->getSortKey() );
247
	}
248
249
	/**
250
	 * @dataProvider getUncertaintyProvider
251
	 */
252
	public function testGetUncertainty( QuantityValue $quantity, $expected ) {
253
		$actual = $quantity->getUncertainty();
254
255
		// floats are wonkey, accept small differences here
256
		$this->assertTrue( abs( $actual - $expected ) < 0.000000001, "expected $expected, got $actual" );
257
	}
258
259
	public function getUncertaintyProvider() {
260
		return array(
261
			array( QuantityValue::newFromNumber( '+0', '1', '+0', '+0' ), 0 ),
262
263
			array( QuantityValue::newFromNumber( '+0', '1', '+1', '-1' ), 2 ),
264
			array( QuantityValue::newFromNumber( '+0.00', '1', '+0.01', '-0.01' ), 0.02 ),
265
			array( QuantityValue::newFromNumber( '+100', '1', '+101', '+99' ), 2 ),
266
			array( QuantityValue::newFromNumber( '+100.0', '1', '+100.1', '+99.9' ), 0.2 ),
267
			array( QuantityValue::newFromNumber( '+12.34', '1', '+12.35', '+12.33' ), 0.02 ),
268
269
			array( QuantityValue::newFromNumber( '+0', '1', '+0.2', '-0.6' ), 0.8 ),
270
			array( QuantityValue::newFromNumber( '+7.3', '1', '+7.7', '+5.2' ), 2.5 ),
271
		);
272
	}
273
274
	/**
275
	 * @dataProvider getUncertaintyMarginProvider
276
	 */
277
	public function testGetUncertaintyMargin( QuantityValue $quantity, $expected ) {
278
		$actual = $quantity->getUncertaintyMargin();
279
280
		$this->assertEquals( $expected, $actual->getValue() );
281
	}
282
283
	public function getUncertaintyMarginProvider() {
284
		return array(
285
			array( QuantityValue::newFromNumber( '+0', '1', '+1', '-1' ), '+1' ),
286
			array( QuantityValue::newFromNumber( '+0.00', '1', '+0.01', '-0.01' ), '+0.01' ),
287
288
			array( QuantityValue::newFromNumber( '-1', '1', '-1', '-1' ), '+0' ),
289
290
			array( QuantityValue::newFromNumber( '+0', '1', '+0.2', '-0.6' ), '+0.6' ),
291
			array( QuantityValue::newFromNumber( '+7.5', '1', '+7.5', '+5.5' ), '+2' ),
292
			array( QuantityValue::newFromNumber( '+11.5', '1', '+15', '+10.5' ), '+3.5' ),
293
		);
294
	}
295
296
	/**
297
	 * @dataProvider getOrderOfUncertaintyProvider
298
	 */
299
	public function testGetOrderOfUncertainty( QuantityValue $quantity, $expected ) {
300
		$actual = $quantity->getOrderOfUncertainty();
301
302
		$this->assertEquals( $expected, $actual );
303
	}
304
305
	public function getOrderOfUncertaintyProvider() {
306
		return array(
307
			0 => array( QuantityValue::newFromNumber( '+0' ), 0 ),
308
			1 => array( QuantityValue::newFromNumber( '-123' ), 0 ),
309
			2 => array( QuantityValue::newFromNumber( '-1.23' ), -2 ),
310
311
			10 => array( QuantityValue::newFromNumber( '-100', '1', '-99', '-101' ), 0 ),
312
			11 => array( QuantityValue::newFromNumber( '+0.00', '1', '+0.01', '-0.01' ), -2 ),
313
			12 => array( QuantityValue::newFromNumber( '-117.3', '1', '-117.2', '-117.4' ), -1 ),
314
315
			20 => array( QuantityValue::newFromNumber( '+100', '1', '+100.01', '+99.97' ), -2 ),
316
			21 => array( QuantityValue::newFromNumber( '-0.002', '1', '-0.001', '-0.004' ), -3 ),
317
			22 => array( QuantityValue::newFromNumber( '-0.002', '1', '+0.001', '-0.06' ), -3 ),
318
			23 => array( QuantityValue::newFromNumber( '-21', '1', '+1.1', '-120' ), 1 ),
319
			24 => array( QuantityValue::newFromNumber( '-2', '1', '+1.1', '-120' ), 0 ),
320
			25 => array( QuantityValue::newFromNumber( '+1000', '1', '+1100', '+900.03' ), 1 ),
321
			26 => array( QuantityValue::newFromNumber( '+1000', '1', '+1100', '+900' ), 2 ),
322
		);
323
	}
324
325
	/**
326
	 * @dataProvider transformProvider
327
	 */
328
	public function testTransform( QuantityValue $quantity, $transformation, QuantityValue $expected ) {
329
		$args = func_get_args();
330
		$extraArgs = array_slice( $args, 3 );
331
332
		$call = array( $quantity, 'transform' );
333
		$callArgs = array_merge( array( 'x', $transformation ), $extraArgs );
334
		$actual = call_user_func_array( $call, $callArgs );
335
336
		$this->assertEquals( 'x', $actual->getUnit() );
337
		$this->assertEquals( $expected->getAmount()->getValue(), $actual->getAmount()->getValue(), 'value' );
338
		$this->assertEquals( $expected->getUpperBound()->getValue(), $actual->getUpperBound()->getValue(), 'upper bound' );
339
		$this->assertEquals( $expected->getLowerBound()->getValue(), $actual->getLowerBound()->getValue(), 'lower bound' );
340
	}
341
342
	public function transformProvider() {
343
		$identity = function ( DecimalValue $value ) {
344
			return $value;
345
		};
346
347
		$square = function ( DecimalValue $value ) {
348
			$v = $value->getValueFloat();
349
			return new DecimalValue( $v * $v * $v );
350
		};
351
352
		$scale = function ( DecimalValue $value, $factor ) {
353
			return new DecimalValue( $value->getValueFloat() * $factor );
354
		};
355
356
		return array(
357
			 0 => array( QuantityValue::newFromNumber( '+10',   '1', '+11',  '+9' ),   $identity, QuantityValue::newFromNumber(   '+10',    '?',   '+11',    '+9' ) ),
358
			 1 => array( QuantityValue::newFromNumber(  '-0.5', '1', '-0.4', '-0.6' ), $identity, QuantityValue::newFromNumber(    '-0.5',  '?',    '-0.4',  '-0.6' ) ),
359
			 2 => array( QuantityValue::newFromNumber(  '+0',   '1', '+1',   '-1' ),   $square,   QuantityValue::newFromNumber(    '+0',    '?',    '+1',    '-1' ) ),
360
			 3 => array( QuantityValue::newFromNumber( '+10',   '1', '+11',  '+9' ),   $square,   QuantityValue::newFromNumber( '+1000',    '?', '+1300',  '+700' ) ), // note how rounding applies to bounds
361
			 4 => array( QuantityValue::newFromNumber(  '+0.5', '1', '+0.6', '+0.4' ), $scale,    QuantityValue::newFromNumber(    '+0.25', '?',    '+0.3',  '+0.2' ), 0.5 ),
362
363
			// note: absolutely exact values require conversion with infinite precision!
364
			10 => array( QuantityValue::newFromNumber( '+100', '1', '+100',   '+100' ),    $scale, QuantityValue::newFromNumber( '+12825.0', '?', '+12825.0', '+12825.0' ), 128.25 ),
365
366
			11 => array( QuantityValue::newFromNumber( '+100', '1', '+110',    '+90' ),    $scale, QuantityValue::newFromNumber( '+330',    '?', '+370',    '+300' ), 3.3333 ),
367
			12 => array( QuantityValue::newFromNumber( '+100', '1', '+100.1',  '+99.9' ),  $scale, QuantityValue::newFromNumber( '+333.3',  '?', '+333.7',  '+333.0' ), 3.3333 ),
368
			13 => array( QuantityValue::newFromNumber( '+100', '1', '+100.01', '+99.99' ), $scale, QuantityValue::newFromNumber( '+333.33', '?', '+333.36', '+333.30' ), 3.3333 ),
369
		);
370
	}
371
372
}
373