Test Failed
Pull Request — master (#140)
by
unknown
07:46
created

TimeValueCalculatorTest::setUp()   A

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 DataValues\Tests;
4
5
use DataValues\TimeValue;
6
use DataValues\TimeValueCalculator;
7
8
/**
9
 * @covers DataValues\TimeValueCalculator
10
 *
11
 * @group DataValue
12
 * @group DataValueExtensions
13
 *
14
 * @license GPL-2.0+
15
 * @author Thiemo Kreuz
16
 */
17
class TimeValueCalculatorTest extends \PHPUnit_Framework_TestCase {
18
19
	/**
20
	 * @var TimeValueCalculator
21
	 */
22
	private $calculator;
23
24
	protected function setUp() {
25
		$this->calculator = new TimeValueCalculator();
26
	}
27
28
	/**
29
	 * @param string $time an ISO 8601 date and time
30
	 * @param int $timezone offset from UTC in minutes
31
	 *
32
	 * @return TimeValue
33
	 */
34
	private function getTimeValueMock( $time, $timezone = 0 ) {
35
		$timeValue = $this->getMockBuilder( TimeValue::class )
36
			->disableOriginalConstructor()
37
			->getMock();
38
39
		$timeValue->expects( $this->any() )
40
			->method( 'getTime' )
41
			->will( $this->returnValue( $time ) );
42
		$timeValue->expects( $this->any() )
43
			->method( 'getTimezone' )
44
			->will( $this->returnValue( $timezone ) );
45
		$timeValue->expects( $this->any() )
46
			->method( 'getPrecision' )
47
			->will( $this->returnValue( TimeValue::PRECISION_DAY ) );
48
		$timeValue->expects( $this->any() )
49
			->method( 'getCalendarModel' )
50
			->will( $this->returnValue( 'Stardate' ) );
51
52
		return $timeValue;
53
	}
54
55
	public function timestampProvider() {
56
		return array(
57
			// Make sure it's identical to the PHP/Unix time stamps in current years
58
			array( '+2004-02-29T00:00:00Z', strtotime( '2004-02-29T00:00:00+00:00' ) ),
59
			array( '+2038-00-00T00:00:00Z', strtotime( '2038-01-01T00:00:00+00:00' ) ),
60
61
			// Time zones
62
			array( '+2000-01-01T12:59:59', strtotime( '2000-01-01T12:59:59-02:00' ), -120 ),
63
			array( '+2000-01-01T12:59:59', strtotime( '2000-01-01T12:59:59+04:45' ), 285 ),
64
65
			array( '+0401-00-00T00:00:00Z', -49512816000 ),
66
			array( '+1902-00-00T00:00:00Z', -2145916800 ),
67
			array( '+1939-00-00T00:00:00Z', -978307200 ),
68
			array( '+1969-12-31T23:59:00Z', -60 ),
69
			array( '+1969-12-31T23:59:59Z', -1 ),
70
			array( '+1970-01-01T00:00:00Z', 0 ),
71
			array( '+1970-01-01T00:00:01Z', 1 ),
72
			array( '+1970-01-01T00:01:00Z', 60 ),
73
			array( '+1972-02-29T00:00:00Z', 68169600 ),
74
			array( '+1996-02-29T00:00:00Z', 825552000 ),
75
			array( '+1999-12-31T23:59:59Z', 946684799 ),
76
			array( '+2000-01-01T00:00:00Z', 946684800 ),
77
			array( '+2000-02-01T00:00:00Z', 949363200 ),
78
			array( '+2000-02-29T00:00:00Z', 951782400 ),
79
			array( '+2001-00-00T00:00:00Z', 978307200 ),
80
			array( '+2001-01-01T00:00:00Z', 978307200 ),
81
			array( '+2014-04-30T12:35:55Z', 1398861355 ),
82
			array( '+2401-00-00T00:00:00Z', 13601088000 ),
83
84
			// Make sure there is only 1 second between these two
85
			array( '-0001-12-31T23:59:59Z', -62135596801 ),
86
			array( '+0001-00-00T00:00:00Z', -62135596800 ),
87
88
			// No special calculation for leap seconds, just make sure they pass
89
			array( '+1970-10-11T12:13:61Z', 24495241 ),
90
			array( '+1970-10-11T12:14:01Z', 24495241 ),
91
92
			// Year 0 does not exist, but we do not complain, assume -1
93
			array( '-0000-12-31T23:59:59Z', -62135596801 ),
94
			array( '+0000-00-00T00:00:00Z', floor( ( -1 - 1969 ) * 365.2425 ) * 86400 ),
95
96
			// Since there is no year 0, negative leap years are -1, -5 and so on
97
			array( '-8001-00-00T00:00:00Z', floor( ( -8001 - 1969 ) * 365.2425 ) * 86400 ),
98
			array( '-0005-00-00T00:00:00Z', floor( ( -5 - 1969 ) * 365.2425 ) * 86400 ),
99
			array( '+0004-00-00T00:00:00Z', floor( ( 4 - 1970 ) * 365.2425 ) * 86400 ),
100
			array( '+8000-00-00T00:00:00Z', floor( ( 8000 - 1970 ) * 365.2425 ) * 86400 ),
101
102
			// PHP_INT_MIN is -2147483648
103
			array( '-2147484001-00-00T00:00:00Z', floor( ( -2147484001 - 1969 ) * 365.2425 ) * 86400 ),
104
			// PHP_INT_MAX is +2147483647
105
			array( '+2147484000-00-00T00:00:00Z', floor( ( 2147484000 - 1970 ) * 365.2425 ) * 86400 ),
106
		);
107
	}
108
109
	/**
110
	 * @dataProvider timestampProvider
111
	 */
112
	public function testGetTimestamp( $time, $expectedTimestamp = 0.0, $timezone = 0 ) {
113
		$timeValue = $this->getTimeValueMock( $time, $timezone );
114
		$timestamp = $this->calculator->getTimestamp( $timeValue );
115
116
		$this->assertEquals( $expectedTimestamp, $timestamp );
117
	}
118
119
	public function yearProvider() {
120
		return array(
121
			// Every 4 years
122
			array( 1895, 459 ),
123
			array( 1896, 460, true ),
124
			array( 1897, 460 ),
125
126
			// Not every 100 years but every 400 years
127
			array( 1900, 460 ),
128
			array( 2000, 485, true ),
129
			array( 2100, 509 ),
130
131
			// Extremes
132
			array( 1, 0 ),
133
			array( 9999, 2424 ),
134
			array( 2147483647, 520764784 ),
135
136
			// There is no year zero, assume -1
137
			array( -1, 0, true ),
138
			array( 0, 0, true ),
139
140
			// Off by 1 for negative years because zero is skipped
141
			array( -6, -2 ),
142
			array( -5, -1, true ),
143
			array( -4, -1 ),
144
			array( -3, -1 ),
145
			array( -2, -1 ),
146
			array( -1, 0, true ),
147
			array( 1, 0 ),
148
			array( 2, 0 ),
149
			array( 3, 0 ),
150
			array( 4, 1, true ),
151
			array( 5, 1 ),
152
153
			// Because we can
154
			array( -6.9, -2 ),
155
			array( -6.1, -2 ),
156
			array( -5.501, -1, true ),
157
			array( -5.499, -1, true ),
158
			array( -4.6, -1 ),
159
			array( -4.4, -1 ),
160
			array( 1995.01, 483 ),
161
			array( 1995.09, 483 ),
162
			array( 1996.001, 484, true ),
163
			array( 1996.009, 484, true ),
164
			array( 1997.1, 484 ),
165
			array( 1997.9, 484 ),
166
		);
167
	}
168
169
	/**
170
	 * @dataProvider yearProvider
171
	 */
172
	public function testIsLeapYear( $year, $numberOfLeapYears, $expected = false ) {
0 ignored issues
show
Unused Code introduced by
The parameter $numberOfLeapYears is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
173
		$isLeapYear = $this->calculator->isLeapYear( $year );
174
175
		$this->assertEquals( $expected, $isLeapYear );
176
	}
177
178
	/**
179
	 * @dataProvider yearProvider
180
	 */
181
	public function testGetNumberOfLeapYears( $year, $expected, $isLeapYear = false ) {
0 ignored issues
show
Unused Code introduced by
The parameter $isLeapYear is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
182
		$numberOfLeapYears = $this->calculator->getNumberOfLeapYears( $year );
183
184
		$this->assertEquals( $expected, $numberOfLeapYears );
185
	}
186
187
	public function precisionProvider() {
188
		$secondsPerDay = 60 * 60 * 24;
189
		$daysPerGregorianYear = 365 + 1 / 4 - 1 / 100 + 1 / 400;
190
191
		return array(
192
			array( TimeValue::PRECISION_SECOND, 1 ),
193
			array( TimeValue::PRECISION_MINUTE, 60 ),
194
			array( TimeValue::PRECISION_HOUR, 60 * 60 ),
195
			array( TimeValue::PRECISION_DAY, $secondsPerDay ),
196
			array( TimeValue::PRECISION_MONTH, $secondsPerDay * $daysPerGregorianYear / 12 ),
197
			array( TimeValue::PRECISION_YEAR, $secondsPerDay * $daysPerGregorianYear ),
198
			array( TimeValue::PRECISION_YEAR10, $secondsPerDay * $daysPerGregorianYear * 1e1 ),
199
			array( TimeValue::PRECISION_YEAR1G, $secondsPerDay * $daysPerGregorianYear * 1e9 ),
200
		);
201
	}
202
203
	/**
204
	 * @dataProvider precisionProvider
205
	 */
206
	public function testGetSecondsForPrecision( $precision, $expected ) {
207
		$seconds = $this->calculator->getSecondsForPrecision( $precision );
208
209
		$this->assertEquals( $expected, $seconds );
210
	}
211
212
	/**
213
	 * @return array
214
	 */
215
	private function timestampWithoutSignProvider() {
216
		return [
217
			'16-11-11T06:08:04Z',
218
			'245-04-30T00:00:00Z',
219
			'1054-02-11T14:00:02Z',
220
			'2012-02-29T23:59:59Z',
221
			#'2012-03-01T00:00:00Z',
222
			'2013-12-31T23:59:59Z',
223
			'2014-01-01T00:00:00Z',
224
			'54844518-04-25T02:00:00Z',
225
			'9990994999299999-07-09T14:20:00Z',
226
		];
227
	}
228
229
	/**
230
	 * @return array of precisions from the most to the least precise
231
	 */
232
	private function simplePrecisionProvider() {
233
		return [
234
			TimeValue::PRECISION_SECOND,
235
			TimeValue::PRECISION_MINUTE,
236
			TimeValue::PRECISION_HOUR,
237
			TimeValue::PRECISION_DAY,
238
			TimeValue::PRECISION_MONTH,
239
			TimeValue::PRECISION_YEAR,
240
			TimeValue::PRECISION_YEAR10,
241
			TimeValue::PRECISION_YEAR100,
242
			TimeValue::PRECISION_YEAR1K,
243
			TimeValue::PRECISION_YEAR10K,
244
			TimeValue::PRECISION_YEAR100K,
245
			TimeValue::PRECISION_YEAR1M,
246
			TimeValue::PRECISION_YEAR10M,
247
			TimeValue::PRECISION_YEAR100M,
248
			TimeValue::PRECISION_YEAR1G
249
		];
250
	}
251
252
	/**
253
	 * Check that:
254
	 *   - timestampWithoutSignProvider() values are ordered from earliest to latest according
255
	 *       to getLowerTimestamp(),
256
	 *   - getTimestamp() values are always greater or equal than getLowerTimestamp() ones,
257
	 *   - higher precisions of the same timestamp always correspond to greater or equal
258
	 *       getLowerTimestamp() values than lower precisions,
259
	 *   - higher before values for the same timestamp always correspond to lower or equal
260
	 *       getLowerTimestamp() values than lower before values,
261
	 *   - a few TimeValue values are equal to their expected getLowerTimestamp() ones.
262
	 */
263
	public function testGetLowerTimestamp() {
264
		$timestamps = $this->timestampWithoutSignProvider();
265
		$precisions = $this->simplePrecisionProvider();
266
		$timeValueCalculator = new TimeValueCalculator();
267
		$timeValue = new TimeValue(
268
			'+2013-03-14T12:51:02Z',
269
			0, 0, 0,
270
			TimeValue::PRECISION_MONTH,
271
			TimeValue::CALENDAR_GREGORIAN
272
		);
273
		$unixLowerTimestamp = $timeValueCalculator->getLowerTimestamp( $timeValue );
274
		$this->assertEquals( 1362096000, $unixLowerTimestamp );
275
		$timeValue = new TimeValue(
276
			'+0002-07-17T02:41:22Z',
277
			0, 0, 0,
278
			TimeValue::PRECISION_DAY,
279
			TimeValue::CALENDAR_GREGORIAN
280
		);
281
		$unixLowerTimestamp = $timeValueCalculator->getLowerTimestamp( $timeValue );
282
		$this->assertEquals( -62087040000, $unixLowerTimestamp );
283
		foreach ( [ '+', '-' ] as $sign ) {
284
			$oldUnixLowerTimestampMonth = null;
285
			foreach ( $timestamps as $timestamp ) {
286
				$timestamp = $sign . $timestamp;
287
				$timeValue = new TimeValue(
288
					$timestamp,
289
					0, 0, 0,
290
					TimeValue::PRECISION_MONTH,
291
					TimeValue::CALENDAR_GREGORIAN
292
				);
293
				$unixLowerTimestamp = $timeValueCalculator->getLowerTimestamp( $timeValue );
294
				if ( !empty( $oldUnixLowerTimestampMonth ) ) {
295
					if ( $sign === '+' ) {
296
						$this->assertGreaterThan( $oldUnixLowerTimestampMonth, $unixLowerTimestamp );
297
					} else {
298
						$this->assertGreaterThan( $unixLowerTimestamp, $oldUnixLowerTimestampMonth );
299
					}
300
				}
301
				$oldUnixLowerTimestampMonth = $unixLowerTimestamp;
302
				$oldUnixLowerTimestamp = null;
303
				foreach ( $precisions as $precision ) {
304
					$timeValue = new TimeValue(
305
						$timestamp,
306
						0, 0, 0,
307
						$precision,
308
						TimeValue::CALENDAR_GREGORIAN
309
					);
310
					$unixTimestampAsIs = $timeValueCalculator->getTimestamp( $timeValue );
311
					$unixLowerTimestamp = $timeValueCalculator->getLowerTimestamp( $timeValue );
312
					$this->assertGreaterThanOrEqual( $unixLowerTimestamp, $unixTimestampAsIs );
313
					$timeValueBefore1 = new TimeValue(
314
						$timestamp,
315
						0, 1, 1,
316
						$precision,
317
						TimeValue::CALENDAR_GREGORIAN
318
					);
319
					$unixLowerTimestampBefore1 = $timeValueCalculator->getLowerTimestamp( $timeValueBefore1 );
320
					if ( $unixTimestampAsIs > -10000000000000 && $unixTimestampAsIs < 10000000000000 ) {
321
						$this->assertGreaterThan( $unixLowerTimestampBefore1, $unixLowerTimestamp );
322
					} else {
323
						$this->assertGreaterThanOrEqual( $unixLowerTimestampBefore1, $unixLowerTimestamp );
324
					}
325
					$timeValueBefore2 = new TimeValue(
326
						$timestamp,
327
						0, 2, 2,
328
						$precision,
329
						TimeValue::CALENDAR_GREGORIAN
330
					);
331
					$unixLowerTimestampBefore2 = $timeValueCalculator->getLowerTimestamp( $timeValueBefore2 );
332
					if ( $unixTimestampAsIs > -10000000000000 && $unixTimestampAsIs < 10000000000000 ) {
333
						$this->assertGreaterThan( $unixLowerTimestampBefore2, $unixLowerTimestampBefore1 );
334
					} else {
335
						$this->assertGreaterThanOrEqual( $unixLowerTimestampBefore2, $unixLowerTimestampBefore1 );
336
					}
337
					// As $precisions are ordered from most to least precise, old lower timestamps must be
338
					// greater than or equal to current lower timestamps
339
					if ( !empty( $oldUnixLowerTimestamp ) ) {
340
						$this->assertGreaterThanOrEqual( $unixLowerTimestamp, $oldUnixLowerTimestamp );
341
					}
342
					$oldUnixLowerTimestamp = $unixLowerTimestamp;
343
				}
344
			}
345
		}
346
	}
347
348
	/**
349
	 * Check that:
350
	 *   - timestampWithoutSignProvider() values are ordered from earliest to latest according
351
	 *       to getHigherTimestamp(),
352
	 *   - getHigherTimestamp() values are always greater or equal than getTimestamp() ones,
353
	 *   - lower precisions of the same timestamp always correspond to greater or equal
354
	 *       getHigherTimestamp() values than higher precisions,
355
	 *   - higher after values for the same timestamp always correspond to greater or equal
356
	 *       getHigherTimestamp() values than lower after values,
357
	 *   - a few TimeValue values are equal to their expected getHigherTimestamp() ones.
358
	 */
359
	public function testGetHigherTimestamp() {
360
		$timestamps = $this->timestampWithoutSignProvider();
361
		$precisions = $this->simplePrecisionProvider();
362
		$timeValueCalculator = new TimeValueCalculator();
363
		$timeValue = new TimeValue(
364
			'+2013-03-14T12:51:02Z',
365
			0, 0, 0,
366
			TimeValue::PRECISION_MONTH,
367
			TimeValue::CALENDAR_GREGORIAN
368
		);
369
		$unixHigherTimestamp = $timeValueCalculator->getHigherTimestamp( $timeValue );
370
		$this->assertEquals( 1364774399, $unixHigherTimestamp );
371
		$timeValue = new TimeValue(
372
			'+1002-07-17T02:41:22Z',
373
			0, 0, 0,
374
			TimeValue::PRECISION_DAY,
375
			TimeValue::CALENDAR_GREGORIAN
376
		);
377
		$unixHigherTimestamp = $timeValueCalculator->getHigherTimestamp( $timeValue );
378
		$this->assertEquals( -30530044801, $unixHigherTimestamp );
379
		foreach ( [ '+', '-' ] as $sign ) {
380
			$oldUnixHigherTimestampMonth = null;
381
			foreach ( $timestamps as $timestamp ) {
382
				$timestamp = $sign . $timestamp;
383
				$timeValue = new TimeValue(
384
					$timestamp,
385
					0, 0, 0,
386
					TimeValue::PRECISION_MONTH,
387
					TimeValue::CALENDAR_GREGORIAN
388
				);
389
				$unixHigherTimestamp = $timeValueCalculator->getHigherTimestamp( $timeValue );
390
				if ( !empty( $oldUnixHigherTimestampMonth ) ) {
391
					if ( $sign === '+' ) {
392
						$this->assertGreaterThan( $oldUnixHigherTimestampMonth, $unixHigherTimestamp );
393
					} else {
394
						$this->assertGreaterThan( $unixHigherTimestamp, $oldUnixHigherTimestampMonth );
395
					}
396
				}
397
				$oldUnixHigherTimestampMonth = $unixHigherTimestamp;
398
				$oldUnixHigherTimestamp = null;
399
				foreach ( $precisions as $precision ) {
400
					$timeValue = new TimeValue(
401
						$timestamp,
402
						0, 0, 0,
403
						$precision,
404
						TimeValue::CALENDAR_GREGORIAN
405
					);
406
					$unixTimestampAsIs = $timeValueCalculator->getTimestamp( $timeValue );
407
					$unixHigherTimestamp = $timeValueCalculator->getHigherTimestamp( $timeValue );
408
					$this->assertLessThanOrEqual( $unixHigherTimestamp, $unixTimestampAsIs );
409
					$timeValueAfter1 = new TimeValue(
410
						$timestamp,
411
						0, 1, 1,
412
						$precision,
413
						TimeValue::CALENDAR_GREGORIAN
414
					);
415
					$unixHigherTimestampAfter1 = $timeValueCalculator->getHigherTimestamp( $timeValueAfter1 );
416
					if ( $unixTimestampAsIs > -10000000000000 && $unixTimestampAsIs < 10000000000000 ) {
417
						$this->assertLessThan( $unixHigherTimestampAfter1, $unixHigherTimestamp );
418
					} else {
419
						$this->assertLessThanOrEqual( $unixHigherTimestampAfter1, $unixHigherTimestamp );
420
					}
421
					$timeValueAfter2 = new TimeValue(
422
						$timestamp,
423
						0, 2, 2,
424
						$precision,
425
						TimeValue::CALENDAR_GREGORIAN
426
					);
427
					$unixHigherTimestampAfter2 = $timeValueCalculator->getHigherTimestamp( $timeValueAfter2 );
428
					if ( $unixTimestampAsIs > -10000000000000 && $unixTimestampAsIs < 10000000000000 ) {
429
						$this->assertLessThan( $unixHigherTimestampAfter2, $unixHigherTimestampAfter1 );
430
					} else {
431
						$this->assertLessThanOrEqual( $unixHigherTimestampAfter2, $unixHigherTimestampAfter1 );
432
					}
433
					// As $precisions are ordered from most to least precise, old higher timestamps must be
434
					// less than or equal to current higher timestamps
435
					if ( !empty( $oldUnixHigherTimestamp ) ) {
436
						echo $oldUnixHigherTimestamp . ' < ' . $unixHigherTimestamp . "\n";
437
						$this->assertLessThanOrEqual( $unixHigherTimestamp, $oldUnixHigherTimestamp );
438
					}
439
					$oldUnixHigherTimestamp = $unixHigherTimestamp;
440
				}
441
			}
442
		}
443
	}
444
445
	/**
446
	 * @param string $timestamp
447
	 * @param int $precision
448
	 */
449
	private function auxTestGetHigherTimestamp( $timestamp, $precision ) {
450
		$timeValueCalculator = new TimeValueCalculator();
451
		$timeValue = new TimeValue(
452
			$timestamp,
453
			0, 0, 0,
454
			$precision,
455
			TimeValue::CALENDAR_GREGORIAN
456
		);
457
		$unixTimestampAsIs = $timeValueCalculator->getTimestamp( $timeValue );
458
		$unixHigherTimestamp = $timeValueCalculator->getHigherTimestamp( $timeValue );
459
		$this->assertLessThanOrEqual( $unixHigherTimestamp, $unixTimestampAsIs );
460
461
		$timeValueAfter1 = new TimeValue(
462
			$timestamp,
463
			0, 1, 1,
464
			$precision,
465
			TimeValue::CALENDAR_GREGORIAN
466
		);
467
		$unixHigherTimestampAfter1 = $timeValueCalculator->getHigherTimestamp( $timeValueAfter1 );
468
		if ( $unixTimestampAsIs > -10000000000000 && $unixTimestampAsIs < 10000000000000 ) {
469
			$this->assertLessThan( $unixHigherTimestampAfter1, $unixHigherTimestamp );
470
		} else {
471
			$this->assertLessThanOrEqual( $unixHigherTimestampAfter1, $unixHigherTimestamp );
472
		}
473
		$timeValueAfter2 = new TimeValue(
474
			$timestamp,
475
			0, 2, 2,
476
			$precision,
477
			TimeValue::CALENDAR_GREGORIAN
478
		);
479
		$unixHigherTimestampAfter2 = $timeValueCalculator->getHigherTimestamp( $timeValueAfter2 );
480
		if ( $unixTimestampAsIs > -10000000000000 && $unixTimestampAsIs < 10000000000000 ) {
481
			$this->assertLessThan( $unixHigherTimestampAfter2, $unixHigherTimestampAfter1 );
482
		} else {
483
			$this->assertLessThanOrEqual( $unixHigherTimestampAfter2, $unixHigherTimestampAfter1 );
484
		}
485
	}
486
487
}
488