YearMonthDayTimeParserTest::getInstance()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace ValueParsers\Test;
4
5
use DataValues\TimeValue;
6
use ValueParsers\IsoTimestampParser;
7
use ValueParsers\ParseException;
8
use ValueParsers\ParserOptions;
9
use ValueParsers\YearMonthDayTimeParser;
10
11
/**
12
 * @covers ValueParsers\YearMonthDayTimeParser
13
 *
14
 * @group DataValue
15
 * @group DataValueExtensions
16
 * @group TimeParsers
17
 * @group ValueParsers
18
 *
19
 * @license GPL-2.0+
20
 * @author Thiemo Kreuz
21
 */
22
class YearMonthDayTimeParserTest extends StringValueParserTest {
23
24
	/**
25
	 * @see ValueParserTestBase::getInstance
26
	 *
27
	 * @return YearMonthDayTimeParser
28
	 */
29
	protected function getInstance() {
30
		return new YearMonthDayTimeParser();
31
	}
32
33
	/**
34
	 * @see ValueParserTestBase::validInputProvider
35
	 */
36
	public function validInputProvider() {
37
		$gregorian = 'http://www.wikidata.org/entity/Q1985727';
38
		$julian = 'http://www.wikidata.org/entity/Q1985786';
39
40
		$valid = array(
41
			// Whitespace
42
			"2016-01-01\n" => array( '+2016-01-01T00:00:00Z' ),
43
			' 2016-01-01 ' => array( '+2016-01-01T00:00:00Z' ),
44
45
			// YMD, typically used in ISO 8601
46
			'2015-12-31' => array( '+2015-12-31T00:00:00Z' ),
47
			'2015 12 31' => array( '+2015-12-31T00:00:00Z' ),
48
			'2015 1 13' => array( '+2015-01-13T00:00:00Z' ),
49
50
			// DMY
51
			'31.12.2015' => array( '+2015-12-31T00:00:00Z' ),
52
			'31. 12. 2015' => array( '+2015-12-31T00:00:00Z' ),
53
			'31/12/2015' => array( '+2015-12-31T00:00:00Z' ),
54
			'31 12 2015' => array( '+2015-12-31T00:00:00Z' ),
55
			'31th 12th 2015' => array( '+2015-12-31T00:00:00Z' ),
56
			'day 31, month 12, year 2015' => array( '+2015-12-31T00:00:00Z' ),
57
58
			// MDY, almost exclusively used in the United States
59
			'12/31/2015' => array( '+2015-12-31T00:00:00Z' ),
60
			'12-31-2015' => array( '+2015-12-31T00:00:00Z' ),
61
			'12 31 2015' => array( '+2015-12-31T00:00:00Z' ),
62
63
			// YDM, exclusively used in Kazakhstan
64
			// https://en.wikipedia.org/wiki/Calendar_date#Gregorian.2C_year-day-month_.28YDM.29
65
			'2015.31.12' => array( '+2015-12-31T00:00:00Z' ),
66
			'2015 13 1' => array( '+2015-01-13T00:00:00Z' ),
67
68
			// Month and day are the same, does not matter if DMY or MDY
69
			'01 1 2015' => array( '+2015-01-01T00:00:00Z' ),
70
			'12 12 2015' => array( '+2015-12-12T00:00:00Z' ),
71
72
			// Month and day are the same, does not matter if YMD or YDM
73
			'2015 01 1' => array( '+2015-01-01T00:00:00Z' ),
74
			'2015 12 12' => array( '+2015-12-12T00:00:00Z' ),
75
76
			// Julian
77
			'32-12-31' => array( '+0032-12-31T00:00:00Z', $julian ),
78
			'31.12.32' => array( '+0032-12-31T00:00:00Z', $julian ),
79
			'12/31/60' => array( '+0060-12-31T00:00:00Z', $julian ),
80
81
			// Negative years
82
			'-2015-12-31' => array( '-2015-12-31T00:00:00Z', $julian ),
83
			'year -2015-12-31' => array( '-2015-12-31T00:00:00Z', $julian ),
84
			'31 12 -2015' => array( '-2015-12-31T00:00:00Z', $julian ),
85
			'12/31/-2015' => array( '-2015-12-31T00:00:00Z', $julian ),
86
			'2015-12-31 BC' => array( '-2015-12-31T00:00:00Z', $julian ),
87
			'31 12 2015 BC' => array( '-2015-12-31T00:00:00Z', $julian ),
88
			'12/31/2015 BC' => array( '-2015-12-31T00:00:00Z', $julian ),
89
90
			// A negative number must be the year.
91
			'year -3-2-13' => array( '-0003-02-13T00:00:00Z', $julian ),
92
			'13. 2. -3' => array( '-0003-02-13T00:00:00Z', $julian ),
93
			'23:12:-59' => array( '-0059-12-23T00:00:00Z', $julian ),
94
		);
95
96
		$cases = array();
97
98
		foreach ( $valid as $value => $args ) {
99
			$timestamp = $args[0];
100
			$calendarModel = isset( $args[1] ) ? $args[1] : $gregorian;
101
102
			$cases[] = array(
103
				// Because PHP magically turns numeric keys into ints/floats
104
				(string)$value,
105
				new TimeValue( $timestamp, 0, 0, 0, TimeValue::PRECISION_DAY, $calendarModel )
106
			);
107
		}
108
109
		return $cases;
110
	}
111
112
	/**
113
	 * @see StringValueParserTest::invalidInputProvider
114
	 */
115
	public function invalidInputProvider() {
116
		$invalid = array(
117
			// This parser can only parse strings that contain exactly three numbers.
118
			'2015',
119
			'12.2015',
120
			'May 1 2015',
121
			'1. May 2015',
122
			'1 2015-12-31',
123
			'31.12.2015 23',
124
			'31.12.2015 23:59',
125
			'+2015-12-31T00:00:00Z',
126
127
			// Can be confused with a time (HMS)
128
			'12:31:59',
129
			'12:59:59',
130
			'23:12:59',
131
			'23:12:31',
132
			'-23:12:31',
133
			'-24:00:00',
134
135
			// No year can be identified if all numbers are smaller than 32.
136
			'12 12 12',
137
			'31 12 12',
138
			'12 31 12',
139
			'31 31 12',
140
			'12 12 31',
141
			'31 12 31',
142
			'12 31 31',
143
			'31 31 31',
144
145
			// Two or more candidates for the year.
146
			'32 32 12',
147
			'32 12 32',
148
			'12 32 32',
149
			'32 32 32',
150
151
			// Year can be identified, but month and day can not be distinguished.
152
			'32 2 1',
153
			'2015-12-11',
154
			'1 2 32',
155
			'11.12.2015',
156
157
			// Formats DYM and MYD do not exist and should not be parsed.
158
			'12 -1 12',
159
			'12 32 12',
160
			'12 2015 31',
161
			'31 2015 12',
162
163
			// Duplicate era.
164
			'year -2015-12-31 BC',
165
			'31.12.-2015 BC',
166
167
			// Zeros.
168
			'-2015-00-00',
169
			'0000-00-00',
170
			'2015-00-00',
171
			'2015-12-00',
172
			'0. 0. -2015',
173
			'0. 0. 0',
174
			'0. 0. 2015',
175
			'0. 12. 2015',
176
177
			// To long.
178
			'2015-12-031',
179
			'2015-012-31',
180
		);
181
182
		$cases = parent::invalidInputProvider();
183
184
		foreach ( $invalid as $value ) {
185
			$cases[] = array( $value );
186
		}
187
188
		return $cases;
189
	}
190
191
	/**
192
	 * @dataProvider optionsProvider
193
	 */
194
	public function testOptions(
195
		$value,
196
		array $options,
197
		$timestamp,
198
		$calendarModel,
199
		$precision = TimeValue::PRECISION_DAY
200
	) {
201
		$parser = new YearMonthDayTimeParser( null, new ParserOptions( $options ) );
202
		$this->assertEquals(
203
			new TimeValue( $timestamp, 0, 0, 0, $precision, $calendarModel ),
204
			$parser->parse( $value )
205
		);
206
	}
207
208
	public function optionsProvider() {
209
		$gregorian = 'http://www.wikidata.org/entity/Q1985727';
210
		$julian = 'http://www.wikidata.org/entity/Q1985786';
211
212
		return array(
213
			'Auto-detected Gregorian' => array(
214
				'1583-01-31',
215
				array(),
216
				'+1583-01-31T00:00:00Z',
217
				$gregorian
218
			),
219
			'Option overrides auto-detected Gregorian' => array(
220
				'1583-01-31',
221
				array( IsoTimestampParser::OPT_CALENDAR => $julian ),
222
				'+1583-01-31T00:00:00Z',
223
				$julian
224
			),
225
			'Plain text option overrides auto-detected Gregorian' => array(
226
				'1583-01-31',
227
				array( IsoTimestampParser::OPT_CALENDAR => 'Julian' ),
228
				'+1583-01-31T00:00:00Z',
229
				$julian
230
			),
231
			'Auto-detected Julian' => array(
232
				'1582-01-31',
233
				array(),
234
				'+1582-01-31T00:00:00Z',
235
				$julian
236
			),
237
			'Option overrides auto-detected Julian' => array(
238
				'1582-01-31',
239
				array( IsoTimestampParser::OPT_CALENDAR => $gregorian ),
240
				'+1582-01-31T00:00:00Z',
241
				$gregorian
242
			),
243
			'Option can decrease precision' => array(
244
				'2016-01-31',
245
				array( IsoTimestampParser::OPT_PRECISION => TimeValue::PRECISION_MONTH ),
246
				'+2016-01-31T00:00:00Z',
247
				$gregorian,
248
				TimeValue::PRECISION_MONTH
249
			),
250
			'Option can set minimal precision' => array(
251
				'2016-01-31',
252
				array( IsoTimestampParser::OPT_PRECISION => TimeValue::PRECISION_YEAR1G ),
253
				'+2016-01-31T00:00:00Z',
254
				$gregorian,
255
				TimeValue::PRECISION_YEAR1G
256
			),
257
			'Option can increase day precision' => array(
258
				'2016-01-31',
259
				array( IsoTimestampParser::OPT_PRECISION => TimeValue::PRECISION_HOUR ),
260
				'+2016-01-31T00:00:00Z',
261
				$gregorian,
262
				TimeValue::PRECISION_HOUR
263
			),
264
			'Precision option accepts strings' => array(
265
				'2016-01-31',
266
				array( IsoTimestampParser::OPT_PRECISION => '10' ),
267
				'+2016-01-31T00:00:00Z',
268
				$gregorian,
269
				TimeValue::PRECISION_MONTH
270
			),
271
		);
272
	}
273
274
	/**
275
	 * @dataProvider invalidOptionsProvider
276
	 */
277
	public function testInvalidOptions( array $options ) {
278
		$parser = new YearMonthDayTimeParser( null, new ParserOptions( $options ) );
279
		$this->setExpectedException( ParseException::class );
280
		$parser->parse( '2016-01-31' );
281
	}
282
283
	public function invalidOptionsProvider() {
284
		return array(
285
			array( array( IsoTimestampParser::OPT_CALENDAR => 'invalid' ) ),
286
			array( array( IsoTimestampParser::OPT_PRECISION => -1 ) ),
287
			array( array( IsoTimestampParser::OPT_PRECISION => 1.5 ) ),
288
			array( array( IsoTimestampParser::OPT_PRECISION => 1000 ) ),
289
			array( array( IsoTimestampParser::OPT_PRECISION => 'invalid' ) ),
290
		);
291
	}
292
293
}
294