Completed
Push — master ( dcf061...b72d09 )
by Daniel
26s
created

QuantityParserTest::validInputProvider()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 76
Code Lines 56

Duplication

Lines 0
Ratio 0 %

Importance

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