Completed
Pull Request — master (#113)
by no
05:11 queued 02:43
created

IsoTimestampParserTest::optionsProvider()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 73
Code Lines 60

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 73
rs 9.0675
cc 1
eloc 60
nc 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 ValueParsers\Test;
4
5
use DataValues\TimeValue;
6
use ValueParsers\IsoTimestampParser;
7
use ValueParsers\ParserOptions;
8
9
/**
10
 * @covers ValueParsers\IsoTimestampParser
11
 *
12
 * @group DataValue
13
 * @group DataValueExtensions
14
 *
15
 * @author Addshore
16
 * @author Thiemo Mättig
17
 */
18
class IsoTimestampParserTest extends ValueParserTestBase {
19
20
	/**
21
	 * @deprecated since 0.3, just use getInstance.
22
	 */
23
	protected function getParserClass() {
24
		throw new \LogicException( 'Should not be called, use getInstance' );
25
	}
26
27
	/**
28
	 * @see ValueParserTestBase::getInstance
29
	 *
30
	 * @return IsoTimestampParser
31
	 */
32
	protected function getInstance() {
33
		return new IsoTimestampParser();
34
	}
35
36
	/**
37
	 * @see ValueParserTestBase::validInputProvider
38
	 */
39
	public function validInputProvider() {
40
		$gregorian = 'http://www.wikidata.org/entity/Q1985727';
41
		$julian = 'http://www.wikidata.org/entity/Q1985786';
42
43
		$julianOpts = new ParserOptions();
44
		$julianOpts->setOption( IsoTimestampParser::OPT_CALENDAR, $julian );
45
46
		$gregorianOpts = new ParserOptions();
47
		$gregorianOpts->setOption( IsoTimestampParser::OPT_CALENDAR, $gregorian );
48
49
		$prec10aOpts = new ParserOptions();
50
		$prec10aOpts->setOption( IsoTimestampParser::OPT_PRECISION, TimeValue::PRECISION_YEAR10 );
51
52
		$precDayOpts = new ParserOptions();
53
		$precDayOpts->setOption( IsoTimestampParser::OPT_PRECISION, TimeValue::PRECISION_DAY );
54
55
		$precSecondOpts = new ParserOptions();
56
		$precSecondOpts->setOption( IsoTimestampParser::OPT_PRECISION, TimeValue::PRECISION_SECOND );
57
58
		$valid = array(
59
			// Empty options tests
60
			'+0000000000002013-07-16T00:00:00Z' => array(
61
				'+2013-07-16T00:00:00Z',
62
				TimeValue::PRECISION_DAY,
63
			),
64
			'+0000000000002013-07-00T00:00:00Z' => array(
65
				'+2013-07-00T00:00:00Z',
66
				TimeValue::PRECISION_MONTH,
67
			),
68
			'+0000000000002013-00-00T00:00:00Z' => array(
69
				'+2013-00-00T00:00:00Z',
70
				TimeValue::PRECISION_YEAR,
71
			),
72
			'+0000000000000000-00-00T00:00:00Z' => array(
73
				'+0000-00-00T00:00:00Z',
74
				TimeValue::PRECISION_YEAR,
75
				$julian
76
			),
77
			'+0000000000002000-00-00T00:00:00Z' => array(
78
				'+2000-00-00T00:00:00Z',
79
				TimeValue::PRECISION_YEAR,
80
			),
81
			'+0000000000008000-00-00T00:00:00Z' => array(
82
				'+8000-00-00T00:00:00Z',
83
				TimeValue::PRECISION_YEAR1K,
84
			),
85
			'+0000000000020000-00-00T00:00:00Z' => array(
86
				'+20000-00-00T00:00:00Z',
87
				TimeValue::PRECISION_YEAR10K,
88
			),
89
			'+0000000000200000-00-00T00:00:00Z' => array(
90
				'+200000-00-00T00:00:00Z',
91
				TimeValue::PRECISION_YEAR100K,
92
			),
93
			'+0000000002000000-00-00T00:00:00Z' => array(
94
				'+2000000-00-00T00:00:00Z',
95
				TimeValue::PRECISION_YEAR1M,
96
			),
97
			'+0000000020000000-00-00T00:00:00Z' => array(
98
				'+20000000-00-00T00:00:00Z',
99
				TimeValue::PRECISION_YEAR10M,
100
			),
101
			'+0000000200000000-00-00T00:00:00Z' => array(
102
				'+200000000-00-00T00:00:00Z',
103
				TimeValue::PRECISION_YEAR100M,
104
			),
105
			'+0000002000000000-00-00T00:00:00Z' => array(
106
				'+2000000000-00-00T00:00:00Z',
107
				TimeValue::PRECISION_YEAR1G,
108
			),
109
			'+0000020000000000-00-00T00:00:00Z' => array(
110
				'+20000000000-00-00T00:00:00Z',
111
				TimeValue::PRECISION_YEAR1G,
112
			),
113
			'+0000200000000000-00-00T00:00:00Z' => array(
114
				'+200000000000-00-00T00:00:00Z',
115
				TimeValue::PRECISION_YEAR1G,
116
			),
117
			'+0002000000000000-00-00T00:00:00Z' => array(
118
				'+2000000000000-00-00T00:00:00Z',
119
				TimeValue::PRECISION_YEAR1G,
120
			),
121
			'+0020000000000000-00-00T00:00:00Z' => array(
122
				'+20000000000000-00-00T00:00:00Z',
123
				TimeValue::PRECISION_YEAR1G,
124
			),
125
			'+0200000000000000-00-00T00:00:00Z' => array(
126
				'+200000000000000-00-00T00:00:00Z',
127
				TimeValue::PRECISION_YEAR1G,
128
			),
129
			'+2000000000000000-00-00T00:00:00Z' => array(
130
				'+2000000000000000-00-00T00:00:00Z',
131
				TimeValue::PRECISION_YEAR1G,
132
			),
133
			'-2000000000000000-00-00T00:00:00Z' => array(
134
				'-2000000000000000-00-00T00:00:00Z',
135
				TimeValue::PRECISION_YEAR1G,
136
				$julian
137
			),
138
			'+0000000000002013-07-16T00:00:00Z (Gregorian)' => array(
139
				'+2013-07-16T00:00:00Z',
140
				TimeValue::PRECISION_DAY,
141
			),
142
			'+0000000000000000-01-01T00:00:00Z (Gregorian)' => array(
143
				'+0000-01-01T00:00:00Z',
144
				TimeValue::PRECISION_DAY,
145
146
			),
147
			'+0000000000002001-01-14T00:00:00Z (Julian)' => array(
148
				'+2001-01-14T00:00:00Z',
149
				TimeValue::PRECISION_DAY,
150
				$julian,
151
			),
152
			'+0000000000010000-01-01T00:00:00Z (Gregorian)' => array(
153
				'+10000-01-01T00:00:00Z',
154
				TimeValue::PRECISION_DAY,
155
			),
156
			'-0000000000000001-01-01T00:00:00Z (Gregorian)' => array(
157
				'-0001-01-01T00:00:00Z',
158
				TimeValue::PRECISION_DAY,
159
				$gregorian
160
			),
161
			'-00000000001-01-01T00:00:00Z (Gregorian)' => array(
162
				'-0001-01-01T00:00:00Z',
163
				TimeValue::PRECISION_DAY,
164
				$gregorian,
165
				$julianOpts // overridden by explicit calendar in input string
166
			),
167
			'-00000000001-01-01T00:00:00Z (Julian)' => array(
168
				'-0001-01-01T00:00:00Z',
169
				TimeValue::PRECISION_DAY,
170
				$julian,
171
				$gregorianOpts // overridden by explicit calendar in input string
172
			),
173
			'-000001-01-01T00:00:00Z (Gregorian)' => array(
174
				'-0001-01-01T00:00:00Z',
175
				TimeValue::PRECISION_DAY,
176
				$gregorian
177
			),
178
			'-1-01-01T00:00:00Z (Gregorian)' => array(
179
				'-0001-01-01T00:00:00Z',
180
				TimeValue::PRECISION_DAY,
181
				$gregorian
182
			),
183
184
			// Tests with different options
185
			'-1-01-02T00:00:00Z' => array(
186
				'-0001-01-02T00:00:00Z',
187
				TimeValue::PRECISION_DAY,
188
				$gregorian,
189
				$gregorianOpts,
190
			),
191
			'+2001-01-03T00:00:00Z' => array(
192
				'+2001-01-03T00:00:00Z',
193
				TimeValue::PRECISION_DAY,
194
				$julian,
195
				$julianOpts,
196
			),
197
			'-1-01-04T00:00:00Z' => array(
198
				'-0001-01-04T00:00:00Z',
199
				TimeValue::PRECISION_YEAR10,
200
				$julian,
201
				$prec10aOpts,
202
			),
203
			'-1-01-05T00:00:00Z' => array(
204
				'-0001-01-05T00:00:00Z',
205
				TimeValue::PRECISION_DAY,
206
				$julian,
207
			),
208
209
			'+1999-00-00T00:00:00Z' => array(
210
				'+1999-00-00T00:00:00Z',
211
				TimeValue::PRECISION_YEAR,
212
			),
213
			'+2000-00-00T00:00:00Z' => array(
214
				'+2000-00-00T00:00:00Z',
215
				TimeValue::PRECISION_YEAR,
216
			),
217
			'+2010-00-00T00:00:00Z' => array(
218
				'+2010-00-00T00:00:00Z',
219
				TimeValue::PRECISION_YEAR,
220
			),
221
222
			// Optional sign character
223
			'2015-01-01T00:00:00Z' => array(
224
				'+2015-01-01T00:00:00Z',
225
				TimeValue::PRECISION_DAY,
226
			),
227
228
			// Optional time zone
229
			'2015-01-01T00:00:00' => array(
230
				'+2015-01-01T00:00:00Z',
231
				TimeValue::PRECISION_DAY,
232
			),
233
234
			// Actual minus character from Unicode; roundtrip with TimeDetailsFormatter
235
			"\xE2\x88\x922015-01-01T00:00:00" => array(
236
				'-2015-01-01T00:00:00Z',
237
				TimeValue::PRECISION_DAY,
238
				$julian
239
			),
240
241
			// Optional colons
242
			'2015-01-01T161718' => array(
243
				'+0000000000002015-01-01T16:17:18Z',
244
				TimeValue::PRECISION_SECOND,
245
			),
246
			'2015-01-01T1617' => array(
247
				'+0000000000002015-01-01T16:17:00Z',
248
				TimeValue::PRECISION_MINUTE,
249
			),
250
251
			// Optional second
252
			'2015-01-01T00:00' => array(
253
				'+2015-01-01T00:00:00Z',
254
				TimeValue::PRECISION_DAY,
255
			),
256
257
			// Optional hour and minute
258
			'2015-01-01' => array(
259
				'+2015-01-01T00:00:00Z',
260
				TimeValue::PRECISION_DAY,
261
			),
262
			'60-01-01' => array(
263
				'+0060-01-01T00:00:00Z',
264
				TimeValue::PRECISION_DAY,
265
				$julian
266
			),
267
			// 32 can not be confused with anything. Can't be day or month. Can't be minute or
268
			// second because a time can not start with minute or second.
269
			'32-01-01' => array(
270
				'+0032-01-01T00:00:00Z',
271
				TimeValue::PRECISION_DAY,
272
				$julian
273
			),
274
275
			// Years <= 31 require either the time part or a year with more than 2 digits
276
			'1-01-01T00:00' => array(
277
				'+0001-01-01T00:00:00Z',
278
				TimeValue::PRECISION_DAY,
279
				$julian
280
			),
281
			'001-01-01' => array(
282
				'+0001-01-01T00:00:00Z',
283
				TimeValue::PRECISION_DAY,
284
				$julian
285
			),
286
			// 00-00-00 to 24-00-00 can be confused with a time, but not if it is signed.
287
			'-01-02-03' => array(
288
				'-0001-02-03T00:00:00Z',
289
				TimeValue::PRECISION_DAY,
290
				$julian
291
			),
292
			'+01-02-03' => array(
293
				'+0001-02-03T00:00:00Z',
294
				TimeValue::PRECISION_DAY,
295
				$julian
296
			),
297
298
			// Day zero
299
			'2015-01-00' => array(
300
				'+2015-01-00T00:00:00Z',
301
				TimeValue::PRECISION_MONTH,
302
			),
303
304
			// Month zero
305
			'2015-00-00' => array(
306
				'+2015-00-00T00:00:00Z',
307
				TimeValue::PRECISION_YEAR,
308
			),
309
310
			// Leap seconds are a valid concept
311
			'+2015-01-01T00:00:61Z' => array(
312
				'+2015-01-01T00:00:61Z',
313
				TimeValue::PRECISION_SECOND,
314
			),
315
316
			// Tests for correct precision when a bad precision is passed through the opts
317
			// @see https://bugzilla.wikimedia.org/show_bug.cgi?id=62730
318
			'+0000000000000012-12-00T00:00:00Z' => array(
319
				'+0012-12-00T00:00:00Z',
320
				TimeValue::PRECISION_MONTH,
321
				$julian,
322
				$precDayOpts,
323
			),
324
			'+2015-01-01T00:00:00Z' => array(
325
				'+2015-01-01T00:00:00Z',
326
				TimeValue::PRECISION_SECOND,
327
				$gregorian,
328
				$precSecondOpts,
329
			),
330
331
			// Test Julian/Gregorian switch in October 1582.
332
			'1583-01-01' => array(
333
				'+1583-01-01T00:00:00Z',
334
				TimeValue::PRECISION_DAY,
335
				$gregorian
336
			),
337
338
			// Test Julian/Gregorian switch in October 1582.
339
			'1582-08-01' => array(
340
				'+1582-08-01T00:00:00Z',
341
				TimeValue::PRECISION_DAY,
342
				$julian
343
			),
344
		);
345
346
		$argLists = array();
347
348
		foreach ( $valid as $key => $value ) {
349
			$timestamp = $value[0];
350
			$precision = isset( $value[1] ) ? $value[1] : TimeValue::PRECISION_DAY;
351
			$calendarModel = isset( $value[2] ) ? $value[2] : $gregorian;
352
			$options = isset( $value[3] ) ? $value[3] : null;
353
354
			$argLists[] = array(
355
				// Because PHP magically turns numeric keys into ints/floats
356
				(string)$key,
357
				new TimeValue( $timestamp, 0, 0, 0, $precision, $calendarModel ),
0 ignored issues
show
Bug introduced by
It seems like $timestamp defined by $value[0] on line 349 can also be of type object<ValueParsers\ParserOptions>; however, DataValues\TimeValue::__construct() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
Bug introduced by
It seems like $calendarModel defined by isset($value[2]) ? $value[2] : $gregorian on line 351 can also be of type object<ValueParsers\ParserOptions>; however, DataValues\TimeValue::__construct() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
358
				new IsoTimestampParser( null, $options )
0 ignored issues
show
Bug introduced by
It seems like $options defined by isset($value[3]) ? $value[3] : null on line 352 can also be of type string; however, ValueParsers\IsoTimestampParser::__construct() does only seem to accept null|object<ValueParsers\ParserOptions>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
359
			);
360
		}
361
362
		return $argLists;
363
	}
364
365
	/**
366
	 * @see ValueParserTestBase::invalidInputProvider
367
	 */
368
	public function invalidInputProvider() {
369
		$argLists = array();
370
371
		$invalid = array(
372
			// Stuff that's not even a string
373
			true,
374
			false,
375
			null,
376
			array(),
377
			'foooooooooo',
378
			'1 June 2014',
379
			// Can be confused with a time (HMS), DMY or MDY
380
			'00-00-00',
381
			'12-01-01',
382
			'24-00-00',
383
			'31-01-01',
384
			// Month and day must be two digits
385
			'2015-12-1',
386
			'2015-1-31',
387
			// Time and seconds are optional, but hour without minutes is not allowed
388
			'+2015-12-31T23',
389
			'+2015-12-31T23Z',
390
			// Elements out of allowed bounds
391
			'+2015-00-01T00:00:00Z',
392
			'+2015-13-01T00:00:00Z',
393
			'+2015-01-32T00:00:00Z',
394
			'+2015-01-01T24:00:00Z',
395
			'+2015-01-01T00:60:00Z',
396
			'+2015-01-01T00:00:62Z',
397
			// This parser should not replace the year parser
398
			'1234567890873',
399
			2134567890
400
		);
401
402
		foreach ( $invalid as $value ) {
403
			$argLists[] = array( $value );
404
		}
405
406
		return $argLists;
407
	}
408
409
	/**
410
	 * @dataProvider optionsProvider
411
	 */
412
	public function testOptions(
413
		$value,
414
		array $options,
415
		$timestamp,
416
		$calendarModel,
417
		$precision = TimeValue::PRECISION_DAY
418
	) {
419
		$parser = new IsoTimestampParser( null, new ParserOptions( $options ) );
420
		$this->assertEquals(
421
			new TimeValue( $timestamp, 0, 0, 0, $precision, $calendarModel ),
422
			$parser->parse( $value )
423
		);
424
	}
425
426
	public function optionsProvider() {
427
		$gregorian = 'http://www.wikidata.org/entity/Q1985727';
428
		$julian = 'http://www.wikidata.org/entity/Q1985786';
429
430
		return array(
431
			'Auto-detected Gregorian' => array(
432
				'1583-01-31',
433
				array(),
434
				'+1583-01-31T00:00:00Z',
435
				$gregorian
436
			),
437
			'Option overrides auto-detected Gregorian' => array(
438
				'1583-01-31',
439
				array( IsoTimestampParser::OPT_CALENDAR => $julian ),
440
				'+1583-01-31T00:00:00Z',
441
				$julian
442
			),
443
			'Auto-detected Julian' => array(
444
				'1582-01-31',
445
				array(),
446
				'+1582-01-31T00:00:00Z',
447
				$julian
448
			),
449
			'Option overrides auto-detected Julian' => array(
450
				'1582-01-31',
451
				array( IsoTimestampParser::OPT_CALENDAR => $gregorian ),
452
				'+1582-01-31T00:00:00Z',
453
				$gregorian
454
			),
455
			'Option can decrease precision' => array(
456
				'2016-01-31',
457
				array( IsoTimestampParser::OPT_PRECISION => TimeValue::PRECISION_MONTH ),
458
				'+2016-01-31T00:00:00Z',
459
				$gregorian,
460
				TimeValue::PRECISION_MONTH
461
			),
462
			'Option can set minimal precision' => array(
463
				'2016-01-31',
464
				array( IsoTimestampParser::OPT_PRECISION => TimeValue::PRECISION_YEAR1G ),
465
				'+2016-01-31T00:00:00Z',
466
				$gregorian,
467
				TimeValue::PRECISION_YEAR1G
468
			),
469
			'Option can not increase year precision' => array(
470
				'2016-00-00',
471
				array( IsoTimestampParser::OPT_PRECISION => TimeValue::PRECISION_MONTH ),
472
				'+2016-00-00T00:00:00Z',
473
				$gregorian,
474
				TimeValue::PRECISION_YEAR
475
			),
476
			'Option can not increase month precision' => array(
477
				'2016-01-00',
478
				array( IsoTimestampParser::OPT_PRECISION => TimeValue::PRECISION_DAY ),
479
				'+2016-01-00T00:00:00Z',
480
				$gregorian,
481
				TimeValue::PRECISION_MONTH
482
			),
483
			'Option can increase day precision' => array(
484
				'2016-01-31',
485
				array( IsoTimestampParser::OPT_PRECISION => TimeValue::PRECISION_HOUR ),
486
				'+2016-01-31T00:00:00Z',
487
				$gregorian,
488
				TimeValue::PRECISION_HOUR
489
			),
490
			'Precision option accepts strings' => array(
491
				'2016-01-31',
492
				array( IsoTimestampParser::OPT_PRECISION => '10' ),
493
				'+2016-01-31T00:00:00Z',
494
				$gregorian,
495
				TimeValue::PRECISION_MONTH
496
			),
497
		);
498
	}
499
500
	/**
501
	 * @dataProvider invalidOptionsProvider
502
	 */
503
	public function testInvalidOptions( array $options ) {
504
		$parser = new IsoTimestampParser( null, new ParserOptions( $options ) );
505
		$this->setExpectedException( 'ValueParsers\ParseException' );
506
		$parser->parse( '2016-01-31' );
507
	}
508
509
	public function invalidOptionsProvider() {
510
		return array(
511
			array( array( IsoTimestampParser::OPT_PRECISION => -1 ) ),
512
			array( array( IsoTimestampParser::OPT_PRECISION => 1.5 ) ),
513
			array( array( IsoTimestampParser::OPT_PRECISION => 1000 ) ),
514
			array( array( IsoTimestampParser::OPT_PRECISION => 'invalid' ) ),
515
		);
516
	}
517
518
}
519