From b156e32f0df857beb16f7e49533dbdf85bc78233 Mon Sep 17 00:00:00 2001 From: Bailey Spencer Date: Sun, 10 Apr 2022 15:47:19 -0400 Subject: [PATCH 1/2] Add mock for mktime and gmmktime --- README.md | 4 ++-- src/ClockMock.php | 41 ++++++++++++++++++++++++++++++++++++ tests/ClockMockTest.php | 46 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c94c0cb..38d7138 100644 --- a/README.md +++ b/README.md @@ -38,10 +38,12 @@ Note that, as this is not a tool intended for production, it should be required - getdate() - gettimeofday() - gmdate() +- gmmktime() - gmstrftime() - idate() - localtime() - microtime() +- mktime() - strftime() - strtotime() - time() @@ -53,8 +55,6 @@ Note that, as this is not a tool intended for production, it should be required - date_create_from_format() - date_create_immutable_from_format() -- gmmktime() -- mktime() - DateTime::createFromFormat - DateTimeImmutable::createFromFormat - $_SERVER['REQUEST_TIME'] diff --git a/src/ClockMock.php b/src/ClockMock.php index ac2f1d8..997fe70 100644 --- a/src/ClockMock.php +++ b/src/ClockMock.php @@ -56,10 +56,12 @@ public static function reset(): void uopz_unset_return('getdate'); uopz_unset_return('gettimeofday'); uopz_unset_return('gmdate'); + uopz_unset_return('gmmktime'); uopz_unset_return('gmstrftime'); uopz_unset_return('idate'); uopz_unset_return('localtime'); uopz_unset_return('microtime'); + uopz_unset_return('mktime'); uopz_unset_return('strftime'); uopz_unset_return('strtotime'); uopz_unset_return('time'); @@ -87,10 +89,12 @@ private static function activateMocksIfNeeded(): void uopz_set_return('getdate', self::mock_getdate(), true); uopz_set_return('gettimeofday', self::mock_gettimeofday(), true); uopz_set_return('gmdate', self::mock_gmdate(), true); + uopz_set_return('gmmktime', self::mock_gmmktime(), true); uopz_set_return('gmstrftime', self::mock_gmstrftime(), true); uopz_set_return('idate', self::mock_idate(), true); uopz_set_return('localtime', self::mock_localtime(), true); uopz_set_return('microtime', self::mock_microtime(), true); + uopz_set_return('mktime', self::mock_mktime(), true); uopz_set_return('strftime', self::mock_strftime(), true); uopz_set_return('strtotime', self::mock_strtotime(), true); uopz_set_return('time', self::mock_time(), true); @@ -190,6 +194,26 @@ private static function mock_gmstrftime(): callable return fn (string $format, ?int $timestamp = null) => $gmstrftime_mock($format, $timestamp); } + /** + * @see https://www.php.net/manual/en/function.gmmktime.php + */ + private static function mock_gmmktime(): callable + { + $gmmktime_mock = function (int $hour, ?int $minute, ?int $second, ?int $month, ?int $day, ?int $year) { + /** @var \DateTime $gmtDateTime */ + $gmtDateTime = self::mock_date_create()(self::mock_gmdate()('Y-m-d H:i:s.u')); + + return self::mock_mktime()($hour + self::$frozenDateTime->getOffset() / 3600, + $minute ?? (int) $gmtDateTime->format('i'), + $second ?? (int) $gmtDateTime->format('s'), + $month ?? (int) $gmtDateTime->format('m'), + $day ?? (int) $gmtDateTime->format('j'), + $year ?? (int) $gmtDateTime->format('Y')); + }; + + return fn (int $hour, ?int $minute = null, ?int $second = null, ?int $month = null, ?int $day = null, ?int $year = null) => $gmmktime_mock($hour, $minute, $second, $month, $day, $year); + } + /** * @see https://www.php.net/manual/en/function.idate.php */ @@ -242,6 +266,23 @@ private static function mock_strftime(): callable return fn (string $format, ?int $timestamp = null) => $strftime_mock($format, $timestamp); } + /** + * @see https://www.php.net/manual/en/function.mktime.php + */ + private static function mock_mktime(): callable + { + $mktime_mock = function (int $hour, ?int $minute, ?int $second, ?int $month, ?int $day, ?int $year) { + return mktime($hour, + $minute ?? (int) self::$frozenDateTime->format('i'), + $second ?? (int) self::$frozenDateTime->format('s'), + $month ?? (int) self::$frozenDateTime->format('m'), + $day ?? (int) self::$frozenDateTime->format('j'), + $year ?? (int) self::$frozenDateTime->format('Y')); + }; + + return fn (int $hour, ?int $minute = null, ?int $second = null, ?int $month = null, ?int $day = null, ?int $year = null) => $mktime_mock($hour, $minute, $second, $month, $day, $year); + } + /** * @see https://www.php.net/manual/en/function.strtotime.php */ diff --git a/tests/ClockMockTest.php b/tests/ClockMockTest.php index fb046d6..2a68cd2 100644 --- a/tests/ClockMockTest.php +++ b/tests/ClockMockTest.php @@ -182,6 +182,29 @@ public function test_gmstrftime() $this->assertEquals('2022-04-04 11:26:29', gmstrftime('%F %T')); } + public function dateProvider_gmmktime(): array + { + return [ + ['2022-04-04 14:26:29.123456', [10], '2022-04-04 13:26:29.123456'], + ['2022-04-04 14:26:29.123456', [10, 10], '2022-04-04 13:10:29.123456'], + ['2022-04-04 14:26:29.123456', [10, null, 10], '2022-04-04 13:26:10.123456'], + ['2022-04-04 14:26:29.123456', [10, null, null, 10], '2022-10-04 13:26:29.123456'], + ['2022-04-04 14:26:29.123456', [10, null, null, null, 10], '2022-04-10 13:26:29.123456'], + ['2022-04-04 14:26:29.123456', [10, null, null, null, null, 10], '2010-04-04 13:26:29.123456'], + ['2022-04-04 14:26:29.123456', [10, 10, 10, 10, 10, 10], '2010-10-10 13:10:10.123456'], + ]; + } + + /** + * @dataProvider dateProvider_gmmktime + */ + public function test_gmmktime(string $freezeDateTime, array $mktimeArgs, string $expectedDateTime) + { + ClockMock::freeze((new \DateTime($freezeDateTime))->setTimezone(new \DateTimeZone('Europe/Kiev'))); + + $this->assertEquals($expected = strtotime($expectedDateTime), $actual = gmmktime(...$mktimeArgs)); + } + public function test_idate() { ClockMock::freeze(new \DateTime('1986-06-05')); @@ -225,6 +248,29 @@ public function test_strftime() $this->assertEquals('2022-04-04 14:26:29', strftime('%F %T')); } + public function dateProvider_mktime(): array + { + return [ + ['2022-04-04 14:26:29.123456', [10], '2022-04-04 10:26:29.123456'], + ['2022-04-04 14:26:29.123456', [10, 10], '2022-04-04 10:10:29.123456'], + ['2022-04-04 14:26:29.123456', [10, null, 10], '2022-04-04 10:26:10.123456'], + ['2022-04-04 14:26:29.123456', [10, null, null, 10], '2022-10-04 10:26:29.123456'], + ['2022-04-04 14:26:29.123456', [10, null, null, null, 10], '2022-04-10 10:26:29.123456'], + ['2022-04-04 14:26:29.123456', [10, null, null, null, null, 10], '2010-04-04 10:26:29.123456'], + ['2022-04-04 14:26:29.123456', [10, 10, 10, 10, 10, 10], '2010-10-10 10:10:10.123456'], + ]; + } + + /** + * @dataProvider dateProvider_mktime + */ + public function test_mktime(string $freezeDateTime, array $mktimeArgs, string $expectedDateTime) + { + ClockMock::freeze(new \DateTime($freezeDateTime)); + + $this->assertEquals(strtotime($expectedDateTime), mktime(...$mktimeArgs)); + } + public function test_strtotime() { ClockMock::freeze($fakeNow = new \DateTimeImmutable('1986-06-05')); From d809097cbda2e8082522de23318b82689199fa2c Mon Sep 17 00:00:00 2001 From: Andrea Sprega Date: Fri, 27 May 2022 23:36:04 +0200 Subject: [PATCH 2/2] gmmktime: make test a bit more debuggable and understandable --- tests/ClockMockTest.php | 93 +++++++++++++++++++++++++++++++++-------- 1 file changed, 76 insertions(+), 17 deletions(-) diff --git a/tests/ClockMockTest.php b/tests/ClockMockTest.php index 2a68cd2..53b363b 100644 --- a/tests/ClockMockTest.php +++ b/tests/ClockMockTest.php @@ -184,14 +184,45 @@ public function test_gmstrftime() public function dateProvider_gmmktime(): array { + // NOTE: for all datasets, hour in freezeDateTime is completely irrelevant because always overridden by $hour + // parameter provided to gmmktime. Also, in expectedDateTime hour is always "13" because hour 10 in GMT + // corresponds to hour 13 when we are in +03:00 offset. return [ - ['2022-04-04 14:26:29.123456', [10], '2022-04-04 13:26:29.123456'], - ['2022-04-04 14:26:29.123456', [10, 10], '2022-04-04 13:10:29.123456'], - ['2022-04-04 14:26:29.123456', [10, null, 10], '2022-04-04 13:26:10.123456'], - ['2022-04-04 14:26:29.123456', [10, null, null, 10], '2022-10-04 13:26:29.123456'], - ['2022-04-04 14:26:29.123456', [10, null, null, null, 10], '2022-04-10 13:26:29.123456'], - ['2022-04-04 14:26:29.123456', [10, null, null, null, null, 10], '2010-04-04 13:26:29.123456'], - ['2022-04-04 14:26:29.123456', [10, 10, 10, 10, 10, 10], '2010-10-10 13:10:10.123456'], + [ + '2022-04-04T05:26:29+03:00', + [10], + '2022-04-04T13:26:29+00:00' + ], + [ + '2022-04-04T05:26:29+03:00', + [10, 10], + '2022-04-04T13:10:29+00:00' + ], + [ + '2022-04-04T05:26:29+03:00', + [10, null, 10], + '2022-04-04T13:26:10+00:00' + ], + [ + '2022-04-04T05:26:29+03:00', + [10, null, null, 10], + '2022-10-04T13:26:29+00:00' + ], + [ + '2022-04-04T05:26:29+03:00', + [10, null, null, null, 10], + '2022-04-10T13:26:29+00:00' + ], + [ + '2022-04-04T05:26:29+03:00', + [10, null, null, null, null, 10], + '2010-04-04T13:26:29+00:00' + ], + [ + '2022-04-04T05:26:29+03:00', + [10, 10, 10, 10, 10, 10], + '2010-10-10T13:10:10+00:00' + ], ]; } @@ -200,9 +231,9 @@ public function dateProvider_gmmktime(): array */ public function test_gmmktime(string $freezeDateTime, array $mktimeArgs, string $expectedDateTime) { - ClockMock::freeze((new \DateTime($freezeDateTime))->setTimezone(new \DateTimeZone('Europe/Kiev'))); + ClockMock::freeze(new \DateTime($freezeDateTime)); - $this->assertEquals($expected = strtotime($expectedDateTime), $actual = gmmktime(...$mktimeArgs)); + $this->assertEquals($expectedDateTime, date(DATE_ATOM, gmmktime(...$mktimeArgs))); } public function test_idate() @@ -251,13 +282,41 @@ public function test_strftime() public function dateProvider_mktime(): array { return [ - ['2022-04-04 14:26:29.123456', [10], '2022-04-04 10:26:29.123456'], - ['2022-04-04 14:26:29.123456', [10, 10], '2022-04-04 10:10:29.123456'], - ['2022-04-04 14:26:29.123456', [10, null, 10], '2022-04-04 10:26:10.123456'], - ['2022-04-04 14:26:29.123456', [10, null, null, 10], '2022-10-04 10:26:29.123456'], - ['2022-04-04 14:26:29.123456', [10, null, null, null, 10], '2022-04-10 10:26:29.123456'], - ['2022-04-04 14:26:29.123456', [10, null, null, null, null, 10], '2010-04-04 10:26:29.123456'], - ['2022-04-04 14:26:29.123456', [10, 10, 10, 10, 10, 10], '2010-10-10 10:10:10.123456'], + [ + '2022-04-04T14:26:29+00:00', + [10], + '2022-04-04T10:26:29+00:00' + ], + [ + '2022-04-04T14:26:29+00:00', + [10, 10], + '2022-04-04T10:10:29+00:00' + ], + [ + '2022-04-04T14:26:29+00:00', + [10, null, 10], + '2022-04-04T10:26:10+00:00' + ], + [ + '2022-04-04T14:26:29+00:00', + [10, null, null, 10], + '2022-10-04T10:26:29+00:00' + ], + [ + '2022-04-04T14:26:29+00:00', + [10, null, null, null, 10], + '2022-04-10T10:26:29+00:00' + ], + [ + '2022-04-04T14:26:29+00:00', + [10, null, null, null, null, 10], + '2010-04-04T10:26:29+00:00' + ], + [ + '2022-04-04T14:26:29+00:00', + [10, 10, 10, 10, 10, 10], + '2010-10-10T10:10:10+00:00' + ], ]; } @@ -268,7 +327,7 @@ public function test_mktime(string $freezeDateTime, array $mktimeArgs, string $e { ClockMock::freeze(new \DateTime($freezeDateTime)); - $this->assertEquals(strtotime($expectedDateTime), mktime(...$mktimeArgs)); + $this->assertEquals($expectedDateTime, date(DATE_ATOM, mktime(...$mktimeArgs))); } public function test_strtotime()