Test Failed
Push — BoundedQuantityValue ( 72482a...61280d )
by Daniel
02:23
created

QuantityParserTest::validInputProvider()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 75
Code Lines 55

Duplication

Lines 0
Ratio 0 %

Importance

Changes 11
Bugs 0 Features 1
Metric Value
c 11
b 0
f 1
dl 0
loc 75
rs 9
cc 2
eloc 55
nc 2
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 ValueParsers\Test;
4
5
use DataValues\QuantityValue;
6
use ValueParsers\ParserOptions;
7
use ValueParsers\QuantityParser;
8
use ValueParsers\ValueParser;
9
10
/**
11
 * @covers ValueParsers\QuantityParser
12
 *
13
 * @group DataValue
14
 * @group DataValueExtensions
15
 *
16
 * @license GPL-2.0+
17
 * @author Daniel Kinzler
18
 */
19
class QuantityParserTest extends StringValueParserTest {
20
21
	/**
22
	 * @deprecated since DataValues Common 0.3, just use getInstance.
23
	 */
24
	protected function getParserClass() {
25
		throw new \LogicException( 'Should not be called, use getInstance' );
26
	}
27
28
	/**
29
	 * @see ValueParserTestBase::getInstance
30
	 *
31
	 * @return QuantityParser
32
	 */
33
	protected function getInstance() {
34
		return $this->getQuantityParser();
35
	}
36
37
	/**
38
	 * @param ParserOptions|null $options
39
	 *
40
	 * @return QuantityParser
41
	 */
42
	private function getQuantityParser( ParserOptions $options = null ) {
43
		$unlocalizer = $this->getMock( 'ValueParsers\NumberUnlocalizer' );
44
45
		$unlocalizer->expects( $this->any() )
46
			->method( 'unlocalizeNumber' )
47
			->will( $this->returnArgument( 0 ) );
48
49
		// The most minimal regex that accepts all the test cases below.
50
		$unlocalizer->expects( $this->any() )
51
			->method( 'getNumberRegex' )
52
			->will( $this->returnValue( '[-+]? *(?:\d+\.\d*|\.?\d+)(?:e-?\d+)?' ) );
53
54
		// This minimal regex supports % and letters, optionally followed by a digit.
55
		$unlocalizer->expects( $this->any() )
56
			->method( 'getUnitRegex' )
57
			->will( $this->returnValue( '[\p{L}%]+[\d³]?' ) );
58
59
		return new QuantityParser( $options, $unlocalizer );
60
	}
61
62
	/**
63
	 * @see ValueParserTestBase::validInputProvider
64
	 */
65
	public function validInputProvider() {
66
		$amounts = array(
67
			// amounts in various styles and forms
68
			'0' => QuantityValue::newFromNumber( 0, '1', 1, -1 ),
69
			'-0' => QuantityValue::newFromNumber( 0, '1', 1, -1 ),
70
			'-00.00' => QuantityValue::newFromNumber( '+0.00', '1', '+0.01', '-0.01' ),
71
			'+00.00' => QuantityValue::newFromNumber( '+0.00', '1', '+0.01', '-0.01' ),
72
			'0001' => QuantityValue::newFromNumber( 1, '1', 2, 0 ),
73
			'+01' => QuantityValue::newFromNumber( 1, '1', 2, 0 ),
74
			'-1' => QuantityValue::newFromNumber( -1, '1', 0, -2 ),
75
			'+42' => QuantityValue::newFromNumber( 42, '1', 43, 41 ),
76
			' -  42' => QuantityValue::newFromNumber( -42, '1', -41, -43 ),
77
			'9001' => QuantityValue::newFromNumber( 9001, '1', 9002, 9000 ),
78
			'.5' => QuantityValue::newFromNumber( '+0.5', '1', '+0.6', '+0.4' ),
79
			'-.125' => QuantityValue::newFromNumber( '-0.125', '1', '-0.124', '-0.126' ),
80
			'3.' => QuantityValue::newFromNumber( 3, '1', 4, 2 ),
81
			' 3 ' => QuantityValue::newFromNumber( 3, '1', 4, 2 ),
82
			'2.125' => QuantityValue::newFromNumber( '+2.125', '1', '+2.126', '+2.124' ),
83
			'2.1250' => QuantityValue::newFromNumber( '+2.1250', '1', '+2.1251', '+2.1249' ),
84
85
			'1.4e-2' => QuantityValue::newFromNumber( '+0.014', '1', '+0.015', '+0.013' ),
86
			'1.4e3' => QuantityValue::newFromNumber( '+1400', '1', '+1500', '+1300' ),
87
			'1.4e3!m' => QuantityValue::newFromNumber( '+1400', 'm', '+1400', '+1400' ),
88
			'1.4e3m2' => QuantityValue::newFromNumber( '+1400', 'm2', '+1500', '+1300' ),
89
			'1.4ev' => QuantityValue::newFromNumber( '+1.4', 'ev', '+1.5', '+1.3' ),
90
			'1.4e' => QuantityValue::newFromNumber( '+1.4', 'e', '+1.5', '+1.3' ),
91
			'12e3e4' => QuantityValue::newFromNumber( '+12000', 'e4', '+13000', '+11000' ),
92
			// FIXME: Add support for 12x10^3, see DecimalParser.
93
			'0.004e3' => QuantityValue::newFromNumber( '+4', '1', '+5', '+3' ),
94
			'0.004e-3' => QuantityValue::newFromNumber( '+0.000004', '1', '+0.000005', '+0.000003' ),
95
			'4000e3' => QuantityValue::newFromNumber( '+4000000', '1', '+4001000', '+3999000' ),
96
			'4000e-3' => QuantityValue::newFromNumber( '+4.000', '1', '+4.001', '+3.999' ),
97
98
			// precision
99
			'0!' => QuantityValue::newFromNumber( 0, '1', 0, 0 ),
100
			'10.003!' => QuantityValue::newFromNumber( '+10.003', '1', '+10.003', '+10.003' ),
101
			'-200!' => QuantityValue::newFromNumber( -200, '1', -200, -200 ),
102
			'0~' => QuantityValue::newFromNumber( 0, '1', 1, -1 ),
103
			'10.003~' => QuantityValue::newFromNumber( '+10.003', '1', '+10.004', '+10.002' ),
104
			'-200~' => QuantityValue::newFromNumber( -200, '1', -199, -201 ),
105
106
			// uncertainty
107
			'5.3 +/- 0.2' => QuantityValue::newFromNumber( '+5.3', '1', '+5.5', '+5.1' ),
108
			'5.3+-0.2' => QuantityValue::newFromNumber( '+5.3', '1', '+5.5', '+5.1' ),
109
			'5.3 ±0.2' => QuantityValue::newFromNumber( '+5.3', '1', '+5.5', '+5.1' ),
110
111
			'5.3 +/- +0.2' => QuantityValue::newFromNumber( '+5.3', '1', '+5.5', '+5.1' ),
112
			'5.3+-+0.2' => QuantityValue::newFromNumber( '+5.3', '1', '+5.5', '+5.1' ),
113
114
			'5.3e3 +/- 0.2e2' => QuantityValue::newFromNumber( '+5300', '1', '+5320', '+5280' ),
115
			'2e-2+/-1.1e-1' => QuantityValue::newFromNumber( '+0.02', '1', '+0.13', '-0.09' ),
116
117
			// negative
118
			'5.3 +/- -0.2' => QuantityValue::newFromNumber( '+5.3', '1', '+5.5', '+5.1' ),
119
			'5.3+--0.2' => QuantityValue::newFromNumber( '+5.3', '1', '+5.5', '+5.1' ),
120
			'5.3 ±-0.2' => QuantityValue::newFromNumber( '+5.3', '1', '+5.5', '+5.1' ),
121
122
			// units
123
			'5.3+-0.2cm' => QuantityValue::newFromNumber( '+5.3', 'cm', '+5.5', '+5.1' ),
124
			'10.003! km' => QuantityValue::newFromNumber( '+10.003', 'km', '+10.003', '+10.003' ),
125
			'-200~ %  ' => QuantityValue::newFromNumber( -200, '%', -199, -201 ),
126
			'100003 m³' => QuantityValue::newFromNumber( 100003, 'm³', 100004, 100002 ),
127
			'3.±-0.2µ' => QuantityValue::newFromNumber( '+3', 'µ', '+3.2', '+2.8' ),
128
			'+00.20 Å' => QuantityValue::newFromNumber( '+0.20', 'Å', '+0.21', '+0.19' ),
129
		);
130
131
		$argLists = array();
132
133
		foreach ( $amounts as $amount => $expected ) {
134
			//NOTE: PHP may "helpfully" have converted $amount to an integer. Yay.
135
			$argLists[] = array( strval( $amount ), $expected );
136
		}
137
138
		return $argLists;
139
	}
140
141
	/**
142
	 * @see StringValueParserTest::invalidInputProvider
143
	 */
144
	public function invalidInputProvider() {
145
		$argLists = parent::invalidInputProvider();
146
147
		$invalid = array(
148
			'foo',
149
			'',
150
			'.',
151
			'+.',
152
			'-.',
153
			'--1',
154
			'++1',
155
			'1-',
156
			'one',
157
			//'0x20', // this is actually valid, "x20" is read as the unit.
158
			'1+1',
159
			'1-1',
160
			'1.2.3',
161
162
			',3,',
163
			'10,000',
164
			'10\'000',
165
166
			'2!!',
167
			'!2',
168
			'2!2',
169
170
			'2!~',
171
			'2~!',
172
			'2~~',
173
			'~2',
174
			'2~2',
175
176
			'2 -- 2',
177
			'2++2',
178
			'2+±2',
179
			'2-±2',
180
181
			'2()',
182
			'2*',
183
			'2x y',
184
			'x 2 y',
185
186
			'100 003',
187
			'1 . 0',
188
		);
189
190
		foreach ( $invalid as $value ) {
191
			$argLists[] = array( $value );
192
		}
193
194
		return $argLists;
195
	}
196
197
	public function testParseLocalizedQuantity() {
198
		$options = new ParserOptions();
199
		$options->setOption( ValueParser::OPT_LANG, 'test' );
200
201
		$unlocalizer = $this->getMock( 'ValueParsers\NumberUnlocalizer' );
202
203
		$charmap = array(
204
			' ' => '',
205
			',' => '.',
206
		);
207
208
		$unlocalizer->expects( $this->any() )
209
			->method( 'unlocalizeNumber' )
210
			->will( $this->returnCallback(
211
				function( $number ) use ( $charmap ) {
212
					return str_replace( array_keys( $charmap ), array_values( $charmap ), $number );
213
				}
214
			) );
215
216
		$unlocalizer->expects( $this->any() )
217
			->method( 'getNumberRegex' )
218
			->will(  $this->returnValue( '[\d ]+(?:,\d+)?' ) );
219
220
		$unlocalizer->expects( $this->any() )
221
			->method( 'getUnitRegex' )
222
			->will( $this->returnValue( '[a-z~]+' ) );
223
224
		$parser = new QuantityParser( $options, $unlocalizer );
225
226
		$quantity = $parser->parse( '1 22 333,77+-3a~b' );
227
228
		$this->assertEquals( '122333.77', $quantity->getAmount() );
229
		$this->assertEquals( 'a~b', $quantity->getUnit() );
230
	}
231
232
	/**
233
	 * @dataProvider unitOptionProvider
234
	 */
235
	public function testUnitOption( $value, $unit, $expected ) {
236
		$options = new ParserOptions();
237
		$options->setOption( QuantityParser::OPT_UNIT, $unit );
238
239
		$parser = $this->getQuantityParser( $options );
240
241
		$quantity = $parser->parse( $value );
242
		$this->assertEquals( $expected, $quantity->getUnit() );
243
	}
244
245
	public function unitOptionProvider() {
246
		return array(
247
			array( '17 kittens', null, 'kittens' ),
248
			array( '17', 'kittens', 'kittens' ),
249
			array( '17 kittens', 'kittens', 'kittens' ),
250
			array( '17m', 'm', 'm' ),
251
			array( ' 17 ', ' http://concept.uri ', 'http://concept.uri' ),
252
		);
253
	}
254
255
	/**
256
	 * @dataProvider conflictingUnitOptionProvider
257
	 */
258
	public function testConflictingUnitOption( $value, $unit ) {
259
		$options = new ParserOptions();
260
		$options->setOption( QuantityParser::OPT_UNIT, $unit );
261
262
		$parser = $this->getQuantityParser( $options );
263
264
		$this->setExpectedException( 'ValueParsers\ParseException' );
265
		$parser->parse( $value );
266
	}
267
268
	public function conflictingUnitOptionProvider() {
269
		return array(
270
			array( '17 kittens', 'm' ),
271
			array( '17m', 'kittens' ),
272
			array( '17m', '' ),
273
		);
274
	}
275
276
}
277