Completed
Pull Request — master (#37)
by no
05:55 queued 03:34
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.9669
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 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
 * @licence GNU GPL v2+
17
 * @author Daniel Kinzler
18
 */
19
class QuantityParserTest extends StringValueParserTest {
20
21
	/**
22
	 * @deprecated since 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
			'1 http://unit' => QuantityValue::newFromNumber( '+1', 'http://unit', '+2', '+0' ),
130
		);
131
132
		$argLists = array();
133
134
		foreach ( $amounts as $amount => $expected ) {
135
			//NOTE: PHP may "helpfully" have converted $amount to an integer. Yay.
136
			$argLists[] = array( strval( $amount ), $expected );
137
		}
138
139
		return $argLists;
140
	}
141
142
	/**
143
	 * @see ValueParserTestBase::invalidInputProvider
144
	 */
145
	public function invalidInputProvider() {
146
		$argLists = parent::invalidInputProvider();
147
148
		$invalid = array(
149
			'foo',
150
			'',
151
			'.',
152
			'+.',
153
			'-.',
154
			'--1',
155
			'++1',
156
			'1-',
157
			'one',
158
			//'0x20', // this is actually valid, "x20" is read as the unit.
159
			'1+1',
160
			'1-1',
161
			'1.2.3',
162
163
			',3,',
164
			'10,000',
165
			'10\'000',
166
167
			'2!!',
168
			'!2',
169
			'2!2',
170
171
			'2!~',
172
			'2~!',
173
			'2~~',
174
			'~2',
175
			'2~2',
176
177
			'2 -- 2',
178
			'2++2',
179
			'2+±2',
180
			'2-±2',
181
182
			'2()',
183
			'2*',
184
			'2x y',
185
			'x 2 y',
186
187
			'100 003',
188
			'1 . 0',
189
190
			'1 2',
191
			'1 2 http://unit',
192
			'1 m http://unit',
193
			'1m http://unit',
194
			'1http://unit',
195
			'1 ftp://unit',
196
			'1 mailto:unit',
197
			'1 //unit',
198
		);
199
200
		foreach ( $invalid as $value ) {
201
			$argLists[] = array( $value );
202
		}
203
204
		return $argLists;
205
	}
206
207
	public function testParseLocalizedQuantity() {
208
		$options = new ParserOptions();
209
		$options->setOption( ValueParser::OPT_LANG, 'test' );
210
211
		$unlocalizer = $this->getMock( 'ValueParsers\NumberUnlocalizer' );
212
213
		$charmap = array(
214
			' ' => '',
215
			',' => '.',
216
		);
217
218
		$unlocalizer->expects( $this->any() )
219
			->method( 'unlocalizeNumber' )
220
			->will( $this->returnCallback(
221
				function( $number ) use ( $charmap ) {
222
					return str_replace( array_keys( $charmap ), array_values( $charmap ), $number );
223
				}
224
			) );
225
226
		$unlocalizer->expects( $this->any() )
227
			->method( 'getNumberRegex' )
228
			->will(  $this->returnValue( '[\d ]+(?:,\d+)?' ) );
229
230
		$unlocalizer->expects( $this->any() )
231
			->method( 'getUnitRegex' )
232
			->will( $this->returnValue( '[a-z~]+' ) );
233
234
		$parser = new QuantityParser( $options, $unlocalizer );
235
236
		$quantity = $parser->parse( '1 22 333,77+-3a~b' );
237
238
		$this->assertEquals( '122333.77', $quantity->getAmount() );
239
		$this->assertEquals( 'a~b', $quantity->getUnit() );
240
	}
241
242
	/**
243
	 * @dataProvider unitOptionProvider
244
	 */
245
	public function testUnitOption( $value, $unit, $expected ) {
246
		$options = new ParserOptions();
247
		$options->setOption( QuantityParser::OPT_UNIT, $unit );
248
249
		$parser = $this->getQuantityParser( $options );
250
251
		$quantity = $parser->parse( $value );
252
		$this->assertEquals( $expected, $quantity->getUnit() );
253
	}
254
255
	public function unitOptionProvider() {
256
		return array(
257
			array( '17 kittens', null, 'kittens' ),
258
			array( '17', 'kittens', 'kittens' ),
259
			array( '17 kittens', 'kittens', 'kittens' ),
260
			array( '17m', 'm', 'm' ),
261
			array( ' 17 ', ' http://concept.uri ', 'http://concept.uri' ),
262
		);
263
	}
264
265
	/**
266
	 * @dataProvider conflictingUnitOptionProvider
267
	 */
268
	public function testConflictingUnitOption( $value, $unit ) {
269
		$options = new ParserOptions();
270
		$options->setOption( QuantityParser::OPT_UNIT, $unit );
271
272
		$parser = $this->getQuantityParser( $options );
273
274
		$this->setExpectedException( 'ValueParsers\ParseException' );
275
		$parser->parse( $value );
276
	}
277
278
	public function conflictingUnitOptionProvider() {
279
		return array(
280
			array( '17 kittens', 'm' ),
281
			array( '17m', 'kittens' ),
282
			array( '17m', '' ),
283
		);
284
	}
285
286
}
287