From 68ed1918041c80c976b0f43f969e79ee3453af69 Mon Sep 17 00:00:00 2001 From: Sylvain Fabre Date: Fri, 13 Feb 2026 15:43:33 +0100 Subject: [PATCH 1/2] Apply Rector fixes: make data providers static Co-Authored-By: Claude Opus 4.6 --- tests/AbsoluteDateTest.php | 434 ++++++++++++++-------------- tests/LocalizedStringParserTest.php | 60 ++-- tests/TimeTravelerTest.php | 268 ++++++++--------- 3 files changed, 381 insertions(+), 381 deletions(-) diff --git a/tests/AbsoluteDateTest.php b/tests/AbsoluteDateTest.php index ef5aa95..e834bed 100755 --- a/tests/AbsoluteDateTest.php +++ b/tests/AbsoluteDateTest.php @@ -1,217 +1,217 @@ -expectException(ParsingException::class); - new AbsoluteDate('abc', 'def'); - } - - public function testResetsNonDatePartsToZeroUnixTimeValues(): void - { - $date = new AbsoluteDate('2020-01-01'); - self::assertSame('00:00:00', $date->format('H:i:s')); - } - - public function testToString(): void - { - $date = new AbsoluteDate('2020-01-01'); - self::assertSame('2020-01-01', (string) $date); - } - - public function testFormat(): void - { - $date = new AbsoluteDate('2020-01-02'); - self::assertSame('2020-01-02', $date->format()); - self::assertSame('2020-02-01', $date->format('Y-d-m')); - } - - public function testModifyResultIsCorrect(): void - { - $date = new AbsoluteDate('2020-01-02'); - $newDate = $date->modify('+2 days'); - self::assertNotSame($date, $newDate); - self::assertSame('2020-01-02', $date->format()); - self::assertSame('2020-01-04', $newDate->format()); - - $newDate = $date->modify('+1 month'); - self::assertSame('2020-02-02', $newDate->format()); - } - - /** @dataProvider providerModifyEnforcePattern */ - public function testModifyEnforcePattern(string $pattern, bool $patternIsValid): void - { - if ($patternIsValid) { - self::expectNotToPerformAssertions(); - } else { - $this->expectException(\DomainException::class); - } - - $date = new AbsoluteDate('2020-01-01'); - $date->modify($pattern); - } - - /** - * @return iterable - */ - public function providerModifyEnforcePattern(): iterable - { - // Invalid pattern - yield ['+1 second', false]; - - // Valid pattern - yield ['+1 day', true]; - yield ['1 day ago', true]; - yield ['last day of this month', true]; - } - - public function testWithPointInTime(): void - { - $date = new AbsoluteDate('2020-01-02'); - self::assertSame('2020-01-02', $date->format()); - - $datetime = \DateTime::createFromFormat( - 'Y-m-d H:i:s', - '2019-12-27 23:00:00', - new \DateTimeZone('UTC') - ); - self::assertNotFalse($datetime); - - $date = AbsoluteDate::createInTimezone(new \DateTimeZone('UTC'), $datetime); - self::assertSame('2019-12-27', $date->format()); - - $date = AbsoluteDate::createInTimezone(new \DateTimeZone('Europe/Paris'), $datetime); - self::assertSame('2019-12-28', $date->format()); - - $date = AbsoluteDate::createInTimezone(new \DateTimeZone('America/Los_Angeles'), $datetime); - self::assertSame('2019-12-27', $date->format()); - } - - public function testStartsAt(): void - { - $date1 = \DateTime::createFromFormat( - 'Y-m-d H:i:s', - '2019-12-27 00:00:00', - new \DateTimeZone('Europe/Paris') - ); - - $date2 = \DateTime::createFromFormat( - 'Y-m-d H:i:s', - '2019-12-27 00:00:00', - new \DateTimeZone('America/Los_Angeles') - ); - - $date = new AbsoluteDate('2019-12-27'); - - self::assertEquals($date1, $date->startsAt(new \DateTimeZone('Europe/Paris'))); - self::assertEquals($date2, $date->startsAt(new \DateTimeZone('America/Los_Angeles'))); - } - - public function testEndsAt(): void - { - $date1 = \DateTime::createFromFormat( - 'Y-m-d H:i:s', - '2019-12-27 23:59:59', - new \DateTimeZone('Europe/Paris') - ); - - $date2 = \DateTime::createFromFormat( - 'Y-m-d H:i:s', - '2019-12-27 23:59:59', - new \DateTimeZone('America/Los_Angeles') - ); - - $date = new AbsoluteDate('2019-12-27'); - - self::assertEquals($date1, $date->endsAt(new \DateTimeZone('Europe/Paris'))); - self::assertEquals($date2, $date->endsAt(new \DateTimeZone('America/Los_Angeles'))); - } - - /** - * @throws \Exception - */ - public function testCreateRelative(): void - { - $date = AbsoluteDate::createRelative('yesterday', $timezone = new \DateTimeZone('America/Los_Angeles')); - $now = new \DateTimeImmutable('yesterday', $timezone); - self::assertSame($now->format(AbsoluteDate::DEFAULT_DATE_FORMAT), $date->format()); - } - - public function testSerialization(): void - { - $date = new AbsoluteDate('2022-01-01'); - $serialized = serialize($date); - self::assertSame('O:32:"AssoConnect\PHPDate\AbsoluteDate":1:{s:4:"date";s:10:"2022-01-01";}', $serialized); - self::assertSame('2022-01-01', unserialize($serialized)->format()); - } - - /** @dataProvider providerSerializedData */ - public function testUnserialization(string $serialized): void - { - self::assertSame('2022-01-01', unserialize($serialized)->format()); - } - - /** @return array[] */ - public function providerSerializedData(): iterable - { - yield 'old format' => ['O:32:"AssoConnect\PHPDate\AbsoluteDate":1:{s:4:"date";s:18:"s:10:"2022-01-01";";}']; - yield 'another old format' => [ - 'O:32:"AssoConnect\PHPDate\AbsoluteDate":1:{s:42:" AssoConnect\PHPDate\AbsoluteDate datetime";O:17:"' - . 'DateTimeImmutable":3:{s:4:"date";s:26:"2022-01-01 00:00:00.000000";s:13:"timezone_type";i:3;s:8:"' - . 'timezone";s:3:"UTC";}}', - ]; - yield 'new format' => ['O:32:"AssoConnect\PHPDate\AbsoluteDate":1:{s:4:"date";s:10:"2022-01-01";}']; - } - - public function testComparison(): void - { - $dateBefore = new AbsoluteDate('2023-01-01'); - $dateAfter = new AbsoluteDate('2024-01-01'); - - self::assertTrue($dateBefore->equals($dateBefore)); - self::assertFalse($dateBefore->equals($dateAfter)); - self::assertTrue($dateBefore->equalsTo($dateBefore)); - self::assertFalse($dateBefore->equalsTo($dateAfter)); - - self::assertTrue($dateBefore->isBefore($dateAfter)); - self::assertFalse($dateBefore->isBefore($dateBefore)); - self::assertFalse($dateAfter->isBefore($dateBefore)); - - self::assertTrue($dateBefore->isBeforeOrEqualTo($dateAfter)); - self::assertTrue($dateBefore->isBeforeOrEqualTo($dateBefore)); - self::assertFalse($dateAfter->isBeforeOrEqualTo($dateBefore)); - - self::assertSame(-1, $dateBefore->compare($dateAfter)); - self::assertSame(0, $dateBefore->compare($dateBefore)); - self::assertSame(1, $dateAfter->compare($dateBefore)); - - self::assertTrue($dateAfter->isAfter($dateBefore)); - self::assertFalse($dateAfter->isAfter($dateAfter)); - self::assertFalse($dateBefore->isAfter($dateAfter)); - - self::assertTrue($dateAfter->isAfterOrEqualTo($dateBefore)); - self::assertTrue($dateAfter->isAfterOrEqualTo($dateAfter)); - self::assertFalse($dateBefore->isAfterOrEqualTo($dateAfter)); - - self::assertTrue((new AbsoluteDate('2023-06-01'))->isBetween($dateBefore, $dateAfter)); - self::assertFalse((new AbsoluteDate('2020-01-01'))->isBetween($dateBefore, $dateAfter)); - self::assertFalse((new AbsoluteDate('2025-01-01'))->isBetween($dateBefore, $dateAfter)); - self::assertFalse($dateBefore->isBetween($dateBefore, $dateAfter)); - self::assertFalse($dateAfter->isBetween($dateBefore, $dateAfter)); - - self::assertTrue((new AbsoluteDate('2023-06-01'))->isBetweenOrEqualTo($dateBefore, $dateAfter)); - self::assertFalse((new AbsoluteDate('2020-01-01'))->isBetweenOrEqualTo($dateBefore, $dateAfter)); - self::assertFalse((new AbsoluteDate('2025-01-01'))->isBetweenOrEqualTo($dateBefore, $dateAfter)); - self::assertTrue($dateBefore->isBetweenOrEqualTo($dateBefore, $dateAfter)); - self::assertTrue($dateAfter->isBetweenOrEqualTo($dateBefore, $dateAfter)); - } -} +expectException(ParsingException::class); + new AbsoluteDate('abc', 'def'); + } + + public function testResetsNonDatePartsToZeroUnixTimeValues(): void + { + $date = new AbsoluteDate('2020-01-01'); + self::assertSame('00:00:00', $date->format('H:i:s')); + } + + public function testToString(): void + { + $date = new AbsoluteDate('2020-01-01'); + self::assertSame('2020-01-01', (string) $date); + } + + public function testFormat(): void + { + $date = new AbsoluteDate('2020-01-02'); + self::assertSame('2020-01-02', $date->format()); + self::assertSame('2020-02-01', $date->format('Y-d-m')); + } + + public function testModifyResultIsCorrect(): void + { + $date = new AbsoluteDate('2020-01-02'); + $newDate = $date->modify('+2 days'); + self::assertNotSame($date, $newDate); + self::assertSame('2020-01-02', $date->format()); + self::assertSame('2020-01-04', $newDate->format()); + + $newDate = $date->modify('+1 month'); + self::assertSame('2020-02-02', $newDate->format()); + } + + /** @dataProvider providerModifyEnforcePattern */ + public function testModifyEnforcePattern(string $pattern, bool $patternIsValid): void + { + if ($patternIsValid) { + self::expectNotToPerformAssertions(); + } else { + $this->expectException(\DomainException::class); + } + + $date = new AbsoluteDate('2020-01-01'); + $date->modify($pattern); + } + + /** + * @return iterable + */ + public static function providerModifyEnforcePattern(): iterable + { + // Invalid pattern + yield ['+1 second', false]; + + // Valid pattern + yield ['+1 day', true]; + yield ['1 day ago', true]; + yield ['last day of this month', true]; + } + + public function testWithPointInTime(): void + { + $date = new AbsoluteDate('2020-01-02'); + self::assertSame('2020-01-02', $date->format()); + + $datetime = \DateTime::createFromFormat( + 'Y-m-d H:i:s', + '2019-12-27 23:00:00', + new \DateTimeZone('UTC') + ); + self::assertNotFalse($datetime); + + $date = AbsoluteDate::createInTimezone(new \DateTimeZone('UTC'), $datetime); + self::assertSame('2019-12-27', $date->format()); + + $date = AbsoluteDate::createInTimezone(new \DateTimeZone('Europe/Paris'), $datetime); + self::assertSame('2019-12-28', $date->format()); + + $date = AbsoluteDate::createInTimezone(new \DateTimeZone('America/Los_Angeles'), $datetime); + self::assertSame('2019-12-27', $date->format()); + } + + public function testStartsAt(): void + { + $date1 = \DateTime::createFromFormat( + 'Y-m-d H:i:s', + '2019-12-27 00:00:00', + new \DateTimeZone('Europe/Paris') + ); + + $date2 = \DateTime::createFromFormat( + 'Y-m-d H:i:s', + '2019-12-27 00:00:00', + new \DateTimeZone('America/Los_Angeles') + ); + + $date = new AbsoluteDate('2019-12-27'); + + self::assertEquals($date1, $date->startsAt(new \DateTimeZone('Europe/Paris'))); + self::assertEquals($date2, $date->startsAt(new \DateTimeZone('America/Los_Angeles'))); + } + + public function testEndsAt(): void + { + $date1 = \DateTime::createFromFormat( + 'Y-m-d H:i:s', + '2019-12-27 23:59:59', + new \DateTimeZone('Europe/Paris') + ); + + $date2 = \DateTime::createFromFormat( + 'Y-m-d H:i:s', + '2019-12-27 23:59:59', + new \DateTimeZone('America/Los_Angeles') + ); + + $date = new AbsoluteDate('2019-12-27'); + + self::assertEquals($date1, $date->endsAt(new \DateTimeZone('Europe/Paris'))); + self::assertEquals($date2, $date->endsAt(new \DateTimeZone('America/Los_Angeles'))); + } + + /** + * @throws \Exception + */ + public function testCreateRelative(): void + { + $date = AbsoluteDate::createRelative('yesterday', $timezone = new \DateTimeZone('America/Los_Angeles')); + $now = new \DateTimeImmutable('yesterday', $timezone); + self::assertSame($now->format(AbsoluteDate::DEFAULT_DATE_FORMAT), $date->format()); + } + + public function testSerialization(): void + { + $date = new AbsoluteDate('2022-01-01'); + $serialized = serialize($date); + self::assertSame('O:32:"AssoConnect\PHPDate\AbsoluteDate":1:{s:4:"date";s:10:"2022-01-01";}', $serialized); + self::assertSame('2022-01-01', unserialize($serialized)->format()); + } + + /** @dataProvider providerSerializedData */ + public function testUnserialization(string $serialized): void + { + self::assertSame('2022-01-01', unserialize($serialized)->format()); + } + + /** @return array[] */ + public static function providerSerializedData(): iterable + { + yield 'old format' => ['O:32:"AssoConnect\PHPDate\AbsoluteDate":1:{s:4:"date";s:18:"s:10:"2022-01-01";";}']; + yield 'another old format' => [ + 'O:32:"AssoConnect\PHPDate\AbsoluteDate":1:{s:42:" AssoConnect\PHPDate\AbsoluteDate datetime";O:17:"' + . 'DateTimeImmutable":3:{s:4:"date";s:26:"2022-01-01 00:00:00.000000";s:13:"timezone_type";i:3;s:8:"' + . 'timezone";s:3:"UTC";}}', + ]; + yield 'new format' => ['O:32:"AssoConnect\PHPDate\AbsoluteDate":1:{s:4:"date";s:10:"2022-01-01";}']; + } + + public function testComparison(): void + { + $dateBefore = new AbsoluteDate('2023-01-01'); + $dateAfter = new AbsoluteDate('2024-01-01'); + + self::assertTrue($dateBefore->equals($dateBefore)); + self::assertFalse($dateBefore->equals($dateAfter)); + self::assertTrue($dateBefore->equalsTo($dateBefore)); + self::assertFalse($dateBefore->equalsTo($dateAfter)); + + self::assertTrue($dateBefore->isBefore($dateAfter)); + self::assertFalse($dateBefore->isBefore($dateBefore)); + self::assertFalse($dateAfter->isBefore($dateBefore)); + + self::assertTrue($dateBefore->isBeforeOrEqualTo($dateAfter)); + self::assertTrue($dateBefore->isBeforeOrEqualTo($dateBefore)); + self::assertFalse($dateAfter->isBeforeOrEqualTo($dateBefore)); + + self::assertSame(-1, $dateBefore->compare($dateAfter)); + self::assertSame(0, $dateBefore->compare($dateBefore)); + self::assertSame(1, $dateAfter->compare($dateBefore)); + + self::assertTrue($dateAfter->isAfter($dateBefore)); + self::assertFalse($dateAfter->isAfter($dateAfter)); + self::assertFalse($dateBefore->isAfter($dateAfter)); + + self::assertTrue($dateAfter->isAfterOrEqualTo($dateBefore)); + self::assertTrue($dateAfter->isAfterOrEqualTo($dateAfter)); + self::assertFalse($dateBefore->isAfterOrEqualTo($dateAfter)); + + self::assertTrue((new AbsoluteDate('2023-06-01'))->isBetween($dateBefore, $dateAfter)); + self::assertFalse((new AbsoluteDate('2020-01-01'))->isBetween($dateBefore, $dateAfter)); + self::assertFalse((new AbsoluteDate('2025-01-01'))->isBetween($dateBefore, $dateAfter)); + self::assertFalse($dateBefore->isBetween($dateBefore, $dateAfter)); + self::assertFalse($dateAfter->isBetween($dateBefore, $dateAfter)); + + self::assertTrue((new AbsoluteDate('2023-06-01'))->isBetweenOrEqualTo($dateBefore, $dateAfter)); + self::assertFalse((new AbsoluteDate('2020-01-01'))->isBetweenOrEqualTo($dateBefore, $dateAfter)); + self::assertFalse((new AbsoluteDate('2025-01-01'))->isBetweenOrEqualTo($dateBefore, $dateAfter)); + self::assertTrue($dateBefore->isBetweenOrEqualTo($dateBefore, $dateAfter)); + self::assertTrue($dateAfter->isBetweenOrEqualTo($dateBefore, $dateAfter)); + } +} diff --git a/tests/LocalizedStringParserTest.php b/tests/LocalizedStringParserTest.php index 4fac2a6..6b19655 100644 --- a/tests/LocalizedStringParserTest.php +++ b/tests/LocalizedStringParserTest.php @@ -1,30 +1,30 @@ -create($formattedDate, $locale)->format()); - } - - /** @return array{string, string, string}[] */ - public function provideStringsAndLocales(): iterable - { - yield ['09/01/2023', 'en_US', '2023-09-01']; - yield ['9/1/2023', 'en_US', '2023-09-01']; - yield ['9/1/23', 'en_US', '2023-09-01']; - - yield ['09/01/2023', 'fr_FR', '2023-01-09']; - yield ['9/1/2023', 'fr_FR', '2023-01-09']; - yield ['9/1/23', 'fr_FR', '2023-01-09']; - } -} +create($formattedDate, $locale)->format()); + } + + /** @return array{string, string, string}[] */ + public static function provideStringsAndLocales(): iterable + { + yield ['09/01/2023', 'en_US', '2023-09-01']; + yield ['9/1/2023', 'en_US', '2023-09-01']; + yield ['9/1/23', 'en_US', '2023-09-01']; + + yield ['09/01/2023', 'fr_FR', '2023-01-09']; + yield ['9/1/2023', 'fr_FR', '2023-01-09']; + yield ['9/1/23', 'fr_FR', '2023-01-09']; + } +} diff --git a/tests/TimeTravelerTest.php b/tests/TimeTravelerTest.php index 882135d..eb98dcc 100644 --- a/tests/TimeTravelerTest.php +++ b/tests/TimeTravelerTest.php @@ -1,134 +1,134 @@ -timeTraveler = new TimeTraveler(); - } - - /** @dataProvider provideAddMonths */ - public function testAddMonth(string $from, string $expected): void - { - self::assertSame($expected, $this->timeTraveler->addMonth(new AbsoluteDate($from))->__toString()); - } - - /** @return array{string, string}[] */ - public function provideAddMonths(): iterable - { - yield ['2020-01-01', '2020-02-01']; - yield ['2020-01-28', '2020-02-28']; - yield ['2020-01-29', '2020-02-29']; - yield ['2020-01-30', '2020-02-29']; - yield ['2020-01-31', '2020-02-29']; - yield ['2020-02-29', '2020-03-31']; - yield ['2020-06-30', '2020-07-31']; - } - - /** @dataProvider provideRemoveMonths */ - public function testRemoveMonth(string $from, string $expected): void - { - self::assertSame($expected, $this->timeTraveler->removeMonth(new AbsoluteDate($from))->__toString()); - } - - /** @return iterable */ - public function provideRemoveMonths(): iterable - { - foreach ( - [ - '2020-01-01' => '2019-12-01', - '2020-01-28' => '2019-12-28', - '2020-01-29' => '2019-12-29', - '2020-01-30' => '2019-12-30', - '2020-01-31' => '2019-12-31', - '2020-02-29' => '2020-01-31', - '2020-06-30' => '2020-05-31', - '2023-10-31' => '2023-09-30', - '2023-08-31' => '2023-07-31', - '2023-09-30' => '2023-08-31', - '2023-03-31' => '2023-02-28', - '2024-03-31' => '2024-02-29', - ] as $currentMonth => $expectedPreviousMonth - ) { - yield sprintf('%s: previous month will %s', $currentMonth, $expectedPreviousMonth) => [ - $currentMonth, - $expectedPreviousMonth, - ]; - } - } - - /** @dataProvider provideMonthsWithReference */ - public function testAddMonthWithReference(string $reference, string $from, string $expected): void - { - self::assertSame($expected, $this->timeTraveler->addMonthWithReference( - new AbsoluteDate($reference), - new AbsoluteDate($from) - )->__toString()); - } - - /** @return array{string, string, string}[] */ - public function provideMonthsWithReference(): iterable - { - yield ['2020-01-01', '2020-01-01', '2020-02-01']; - yield ['2020-01-01', '2020-02-01', '2020-03-01']; - - yield ['2020-01-25', '2020-02-25', '2020-03-25']; - - // Test the result day matches the reference day - yield ['2020-01-30', '2020-02-29', '2020-03-30']; - yield ['2020-01-31', '2020-02-29', '2020-03-31']; - yield ['2020-01-31', '2020-03-31', '2020-04-30']; - yield ['2020-06-30', '2020-06-30', '2020-07-31']; - yield ['2020-06-30', '2020-07-31', '2020-08-31']; - yield ['2020-06-30', '2020-08-31', '2020-09-30']; - } - - /** @dataProvider provideMonthsWithReferenceOverYear */ - public function testAddMonthWithReferenceWorksYearOverYear(string $referenceAsString, string $expected): void - { - $reference = new AbsoluteDate($referenceAsString); - - for ($i = 0; $i < 12; $i++) { - $actual = $this->timeTraveler->addMonthWithReference($reference, $actual ?? $reference); - } - self::assertTrue(isset($actual)); - self::assertSame($expected, $actual->__toString()); - } - - /** @return array{string, string}[] */ - public function provideMonthsWithReferenceOverYear(): iterable - { - yield ['2020-01-01', '2021-01-01']; - yield ['2020-01-15', '2021-01-15']; - yield ['2020-01-28', '2021-01-28']; - yield ['2020-01-29', '2021-01-29']; - yield ['2020-01-30', '2021-01-30']; - yield ['2020-01-31', '2021-01-31']; - yield ['2020-06-30', '2021-06-30']; - } - - /** @dataProvider provideYears */ - public function testAddYear(string $from, string $expected): void - { - self::assertSame($expected, $this->timeTraveler->addYear(new AbsoluteDate($from))->__toString()); - } - - /** @return array{string, string}[] */ - public function provideYears(): iterable - { - yield ['2020-01-01', '2021-01-01']; - yield ['2020-01-31', '2021-01-31']; - yield ['2020-02-29', '2021-02-28']; - yield ['2020-06-30', '2021-06-30']; - } -} +timeTraveler = new TimeTraveler(); + } + + /** @dataProvider provideAddMonths */ + public function testAddMonth(string $from, string $expected): void + { + self::assertSame($expected, $this->timeTraveler->addMonth(new AbsoluteDate($from))->__toString()); + } + + /** @return array{string, string}[] */ + public static function provideAddMonths(): iterable + { + yield ['2020-01-01', '2020-02-01']; + yield ['2020-01-28', '2020-02-28']; + yield ['2020-01-29', '2020-02-29']; + yield ['2020-01-30', '2020-02-29']; + yield ['2020-01-31', '2020-02-29']; + yield ['2020-02-29', '2020-03-31']; + yield ['2020-06-30', '2020-07-31']; + } + + /** @dataProvider provideRemoveMonths */ + public function testRemoveMonth(string $from, string $expected): void + { + self::assertSame($expected, $this->timeTraveler->removeMonth(new AbsoluteDate($from))->__toString()); + } + + /** @return iterable */ + public static function provideRemoveMonths(): iterable + { + foreach ( + [ + '2020-01-01' => '2019-12-01', + '2020-01-28' => '2019-12-28', + '2020-01-29' => '2019-12-29', + '2020-01-30' => '2019-12-30', + '2020-01-31' => '2019-12-31', + '2020-02-29' => '2020-01-31', + '2020-06-30' => '2020-05-31', + '2023-10-31' => '2023-09-30', + '2023-08-31' => '2023-07-31', + '2023-09-30' => '2023-08-31', + '2023-03-31' => '2023-02-28', + '2024-03-31' => '2024-02-29', + ] as $currentMonth => $expectedPreviousMonth + ) { + yield sprintf('%s: previous month will %s', $currentMonth, $expectedPreviousMonth) => [ + $currentMonth, + $expectedPreviousMonth, + ]; + } + } + + /** @dataProvider provideMonthsWithReference */ + public function testAddMonthWithReference(string $reference, string $from, string $expected): void + { + self::assertSame($expected, $this->timeTraveler->addMonthWithReference( + new AbsoluteDate($reference), + new AbsoluteDate($from) + )->__toString()); + } + + /** @return array{string, string, string}[] */ + public static function provideMonthsWithReference(): iterable + { + yield ['2020-01-01', '2020-01-01', '2020-02-01']; + yield ['2020-01-01', '2020-02-01', '2020-03-01']; + + yield ['2020-01-25', '2020-02-25', '2020-03-25']; + + // Test the result day matches the reference day + yield ['2020-01-30', '2020-02-29', '2020-03-30']; + yield ['2020-01-31', '2020-02-29', '2020-03-31']; + yield ['2020-01-31', '2020-03-31', '2020-04-30']; + yield ['2020-06-30', '2020-06-30', '2020-07-31']; + yield ['2020-06-30', '2020-07-31', '2020-08-31']; + yield ['2020-06-30', '2020-08-31', '2020-09-30']; + } + + /** @dataProvider provideMonthsWithReferenceOverYear */ + public function testAddMonthWithReferenceWorksYearOverYear(string $referenceAsString, string $expected): void + { + $reference = new AbsoluteDate($referenceAsString); + + for ($i = 0; $i < 12; $i++) { + $actual = $this->timeTraveler->addMonthWithReference($reference, $actual ?? $reference); + } + self::assertTrue(isset($actual)); + self::assertSame($expected, $actual->__toString()); + } + + /** @return array{string, string}[] */ + public static function provideMonthsWithReferenceOverYear(): iterable + { + yield ['2020-01-01', '2021-01-01']; + yield ['2020-01-15', '2021-01-15']; + yield ['2020-01-28', '2021-01-28']; + yield ['2020-01-29', '2021-01-29']; + yield ['2020-01-30', '2021-01-30']; + yield ['2020-01-31', '2021-01-31']; + yield ['2020-06-30', '2021-06-30']; + } + + /** @dataProvider provideYears */ + public function testAddYear(string $from, string $expected): void + { + self::assertSame($expected, $this->timeTraveler->addYear(new AbsoluteDate($from))->__toString()); + } + + /** @return array{string, string}[] */ + public static function provideYears(): iterable + { + yield ['2020-01-01', '2021-01-01']; + yield ['2020-01-31', '2021-01-31']; + yield ['2020-02-29', '2021-02-28']; + yield ['2020-06-30', '2021-06-30']; + } +} From d2a73af2b4be2afdced60890b428b90e6aedeb97 Mon Sep 17 00:00:00 2001 From: Sylvain Fabre Date: Fri, 13 Feb 2026 17:29:06 +0100 Subject: [PATCH 2/2] Fix CRLF line endings to LF Co-Authored-By: Claude Opus 4.6 --- tests/AbsoluteDateTest.php | 434 ++++++++++++++-------------- tests/LocalizedStringParserTest.php | 60 ++-- tests/TimeTravelerTest.php | 268 ++++++++--------- 3 files changed, 381 insertions(+), 381 deletions(-) diff --git a/tests/AbsoluteDateTest.php b/tests/AbsoluteDateTest.php index e834bed..c8ce464 100755 --- a/tests/AbsoluteDateTest.php +++ b/tests/AbsoluteDateTest.php @@ -1,217 +1,217 @@ -expectException(ParsingException::class); - new AbsoluteDate('abc', 'def'); - } - - public function testResetsNonDatePartsToZeroUnixTimeValues(): void - { - $date = new AbsoluteDate('2020-01-01'); - self::assertSame('00:00:00', $date->format('H:i:s')); - } - - public function testToString(): void - { - $date = new AbsoluteDate('2020-01-01'); - self::assertSame('2020-01-01', (string) $date); - } - - public function testFormat(): void - { - $date = new AbsoluteDate('2020-01-02'); - self::assertSame('2020-01-02', $date->format()); - self::assertSame('2020-02-01', $date->format('Y-d-m')); - } - - public function testModifyResultIsCorrect(): void - { - $date = new AbsoluteDate('2020-01-02'); - $newDate = $date->modify('+2 days'); - self::assertNotSame($date, $newDate); - self::assertSame('2020-01-02', $date->format()); - self::assertSame('2020-01-04', $newDate->format()); - - $newDate = $date->modify('+1 month'); - self::assertSame('2020-02-02', $newDate->format()); - } - - /** @dataProvider providerModifyEnforcePattern */ - public function testModifyEnforcePattern(string $pattern, bool $patternIsValid): void - { - if ($patternIsValid) { - self::expectNotToPerformAssertions(); - } else { - $this->expectException(\DomainException::class); - } - - $date = new AbsoluteDate('2020-01-01'); - $date->modify($pattern); - } - - /** - * @return iterable - */ - public static function providerModifyEnforcePattern(): iterable - { - // Invalid pattern - yield ['+1 second', false]; - - // Valid pattern - yield ['+1 day', true]; - yield ['1 day ago', true]; - yield ['last day of this month', true]; - } - - public function testWithPointInTime(): void - { - $date = new AbsoluteDate('2020-01-02'); - self::assertSame('2020-01-02', $date->format()); - - $datetime = \DateTime::createFromFormat( - 'Y-m-d H:i:s', - '2019-12-27 23:00:00', - new \DateTimeZone('UTC') - ); - self::assertNotFalse($datetime); - - $date = AbsoluteDate::createInTimezone(new \DateTimeZone('UTC'), $datetime); - self::assertSame('2019-12-27', $date->format()); - - $date = AbsoluteDate::createInTimezone(new \DateTimeZone('Europe/Paris'), $datetime); - self::assertSame('2019-12-28', $date->format()); - - $date = AbsoluteDate::createInTimezone(new \DateTimeZone('America/Los_Angeles'), $datetime); - self::assertSame('2019-12-27', $date->format()); - } - - public function testStartsAt(): void - { - $date1 = \DateTime::createFromFormat( - 'Y-m-d H:i:s', - '2019-12-27 00:00:00', - new \DateTimeZone('Europe/Paris') - ); - - $date2 = \DateTime::createFromFormat( - 'Y-m-d H:i:s', - '2019-12-27 00:00:00', - new \DateTimeZone('America/Los_Angeles') - ); - - $date = new AbsoluteDate('2019-12-27'); - - self::assertEquals($date1, $date->startsAt(new \DateTimeZone('Europe/Paris'))); - self::assertEquals($date2, $date->startsAt(new \DateTimeZone('America/Los_Angeles'))); - } - - public function testEndsAt(): void - { - $date1 = \DateTime::createFromFormat( - 'Y-m-d H:i:s', - '2019-12-27 23:59:59', - new \DateTimeZone('Europe/Paris') - ); - - $date2 = \DateTime::createFromFormat( - 'Y-m-d H:i:s', - '2019-12-27 23:59:59', - new \DateTimeZone('America/Los_Angeles') - ); - - $date = new AbsoluteDate('2019-12-27'); - - self::assertEquals($date1, $date->endsAt(new \DateTimeZone('Europe/Paris'))); - self::assertEquals($date2, $date->endsAt(new \DateTimeZone('America/Los_Angeles'))); - } - - /** - * @throws \Exception - */ - public function testCreateRelative(): void - { - $date = AbsoluteDate::createRelative('yesterday', $timezone = new \DateTimeZone('America/Los_Angeles')); - $now = new \DateTimeImmutable('yesterday', $timezone); - self::assertSame($now->format(AbsoluteDate::DEFAULT_DATE_FORMAT), $date->format()); - } - - public function testSerialization(): void - { - $date = new AbsoluteDate('2022-01-01'); - $serialized = serialize($date); - self::assertSame('O:32:"AssoConnect\PHPDate\AbsoluteDate":1:{s:4:"date";s:10:"2022-01-01";}', $serialized); - self::assertSame('2022-01-01', unserialize($serialized)->format()); - } - - /** @dataProvider providerSerializedData */ - public function testUnserialization(string $serialized): void - { - self::assertSame('2022-01-01', unserialize($serialized)->format()); - } - - /** @return array[] */ - public static function providerSerializedData(): iterable - { - yield 'old format' => ['O:32:"AssoConnect\PHPDate\AbsoluteDate":1:{s:4:"date";s:18:"s:10:"2022-01-01";";}']; - yield 'another old format' => [ - 'O:32:"AssoConnect\PHPDate\AbsoluteDate":1:{s:42:" AssoConnect\PHPDate\AbsoluteDate datetime";O:17:"' - . 'DateTimeImmutable":3:{s:4:"date";s:26:"2022-01-01 00:00:00.000000";s:13:"timezone_type";i:3;s:8:"' - . 'timezone";s:3:"UTC";}}', - ]; - yield 'new format' => ['O:32:"AssoConnect\PHPDate\AbsoluteDate":1:{s:4:"date";s:10:"2022-01-01";}']; - } - - public function testComparison(): void - { - $dateBefore = new AbsoluteDate('2023-01-01'); - $dateAfter = new AbsoluteDate('2024-01-01'); - - self::assertTrue($dateBefore->equals($dateBefore)); - self::assertFalse($dateBefore->equals($dateAfter)); - self::assertTrue($dateBefore->equalsTo($dateBefore)); - self::assertFalse($dateBefore->equalsTo($dateAfter)); - - self::assertTrue($dateBefore->isBefore($dateAfter)); - self::assertFalse($dateBefore->isBefore($dateBefore)); - self::assertFalse($dateAfter->isBefore($dateBefore)); - - self::assertTrue($dateBefore->isBeforeOrEqualTo($dateAfter)); - self::assertTrue($dateBefore->isBeforeOrEqualTo($dateBefore)); - self::assertFalse($dateAfter->isBeforeOrEqualTo($dateBefore)); - - self::assertSame(-1, $dateBefore->compare($dateAfter)); - self::assertSame(0, $dateBefore->compare($dateBefore)); - self::assertSame(1, $dateAfter->compare($dateBefore)); - - self::assertTrue($dateAfter->isAfter($dateBefore)); - self::assertFalse($dateAfter->isAfter($dateAfter)); - self::assertFalse($dateBefore->isAfter($dateAfter)); - - self::assertTrue($dateAfter->isAfterOrEqualTo($dateBefore)); - self::assertTrue($dateAfter->isAfterOrEqualTo($dateAfter)); - self::assertFalse($dateBefore->isAfterOrEqualTo($dateAfter)); - - self::assertTrue((new AbsoluteDate('2023-06-01'))->isBetween($dateBefore, $dateAfter)); - self::assertFalse((new AbsoluteDate('2020-01-01'))->isBetween($dateBefore, $dateAfter)); - self::assertFalse((new AbsoluteDate('2025-01-01'))->isBetween($dateBefore, $dateAfter)); - self::assertFalse($dateBefore->isBetween($dateBefore, $dateAfter)); - self::assertFalse($dateAfter->isBetween($dateBefore, $dateAfter)); - - self::assertTrue((new AbsoluteDate('2023-06-01'))->isBetweenOrEqualTo($dateBefore, $dateAfter)); - self::assertFalse((new AbsoluteDate('2020-01-01'))->isBetweenOrEqualTo($dateBefore, $dateAfter)); - self::assertFalse((new AbsoluteDate('2025-01-01'))->isBetweenOrEqualTo($dateBefore, $dateAfter)); - self::assertTrue($dateBefore->isBetweenOrEqualTo($dateBefore, $dateAfter)); - self::assertTrue($dateAfter->isBetweenOrEqualTo($dateBefore, $dateAfter)); - } -} +expectException(ParsingException::class); + new AbsoluteDate('abc', 'def'); + } + + public function testResetsNonDatePartsToZeroUnixTimeValues(): void + { + $date = new AbsoluteDate('2020-01-01'); + self::assertSame('00:00:00', $date->format('H:i:s')); + } + + public function testToString(): void + { + $date = new AbsoluteDate('2020-01-01'); + self::assertSame('2020-01-01', (string) $date); + } + + public function testFormat(): void + { + $date = new AbsoluteDate('2020-01-02'); + self::assertSame('2020-01-02', $date->format()); + self::assertSame('2020-02-01', $date->format('Y-d-m')); + } + + public function testModifyResultIsCorrect(): void + { + $date = new AbsoluteDate('2020-01-02'); + $newDate = $date->modify('+2 days'); + self::assertNotSame($date, $newDate); + self::assertSame('2020-01-02', $date->format()); + self::assertSame('2020-01-04', $newDate->format()); + + $newDate = $date->modify('+1 month'); + self::assertSame('2020-02-02', $newDate->format()); + } + + /** @dataProvider providerModifyEnforcePattern */ + public function testModifyEnforcePattern(string $pattern, bool $patternIsValid): void + { + if ($patternIsValid) { + self::expectNotToPerformAssertions(); + } else { + $this->expectException(\DomainException::class); + } + + $date = new AbsoluteDate('2020-01-01'); + $date->modify($pattern); + } + + /** + * @return iterable + */ + public static function providerModifyEnforcePattern(): iterable + { + // Invalid pattern + yield ['+1 second', false]; + + // Valid pattern + yield ['+1 day', true]; + yield ['1 day ago', true]; + yield ['last day of this month', true]; + } + + public function testWithPointInTime(): void + { + $date = new AbsoluteDate('2020-01-02'); + self::assertSame('2020-01-02', $date->format()); + + $datetime = \DateTime::createFromFormat( + 'Y-m-d H:i:s', + '2019-12-27 23:00:00', + new \DateTimeZone('UTC') + ); + self::assertNotFalse($datetime); + + $date = AbsoluteDate::createInTimezone(new \DateTimeZone('UTC'), $datetime); + self::assertSame('2019-12-27', $date->format()); + + $date = AbsoluteDate::createInTimezone(new \DateTimeZone('Europe/Paris'), $datetime); + self::assertSame('2019-12-28', $date->format()); + + $date = AbsoluteDate::createInTimezone(new \DateTimeZone('America/Los_Angeles'), $datetime); + self::assertSame('2019-12-27', $date->format()); + } + + public function testStartsAt(): void + { + $date1 = \DateTime::createFromFormat( + 'Y-m-d H:i:s', + '2019-12-27 00:00:00', + new \DateTimeZone('Europe/Paris') + ); + + $date2 = \DateTime::createFromFormat( + 'Y-m-d H:i:s', + '2019-12-27 00:00:00', + new \DateTimeZone('America/Los_Angeles') + ); + + $date = new AbsoluteDate('2019-12-27'); + + self::assertEquals($date1, $date->startsAt(new \DateTimeZone('Europe/Paris'))); + self::assertEquals($date2, $date->startsAt(new \DateTimeZone('America/Los_Angeles'))); + } + + public function testEndsAt(): void + { + $date1 = \DateTime::createFromFormat( + 'Y-m-d H:i:s', + '2019-12-27 23:59:59', + new \DateTimeZone('Europe/Paris') + ); + + $date2 = \DateTime::createFromFormat( + 'Y-m-d H:i:s', + '2019-12-27 23:59:59', + new \DateTimeZone('America/Los_Angeles') + ); + + $date = new AbsoluteDate('2019-12-27'); + + self::assertEquals($date1, $date->endsAt(new \DateTimeZone('Europe/Paris'))); + self::assertEquals($date2, $date->endsAt(new \DateTimeZone('America/Los_Angeles'))); + } + + /** + * @throws \Exception + */ + public function testCreateRelative(): void + { + $date = AbsoluteDate::createRelative('yesterday', $timezone = new \DateTimeZone('America/Los_Angeles')); + $now = new \DateTimeImmutable('yesterday', $timezone); + self::assertSame($now->format(AbsoluteDate::DEFAULT_DATE_FORMAT), $date->format()); + } + + public function testSerialization(): void + { + $date = new AbsoluteDate('2022-01-01'); + $serialized = serialize($date); + self::assertSame('O:32:"AssoConnect\PHPDate\AbsoluteDate":1:{s:4:"date";s:10:"2022-01-01";}', $serialized); + self::assertSame('2022-01-01', unserialize($serialized)->format()); + } + + /** @dataProvider providerSerializedData */ + public function testUnserialization(string $serialized): void + { + self::assertSame('2022-01-01', unserialize($serialized)->format()); + } + + /** @return array[] */ + public static function providerSerializedData(): iterable + { + yield 'old format' => ['O:32:"AssoConnect\PHPDate\AbsoluteDate":1:{s:4:"date";s:18:"s:10:"2022-01-01";";}']; + yield 'another old format' => [ + 'O:32:"AssoConnect\PHPDate\AbsoluteDate":1:{s:42:" AssoConnect\PHPDate\AbsoluteDate datetime";O:17:"' + . 'DateTimeImmutable":3:{s:4:"date";s:26:"2022-01-01 00:00:00.000000";s:13:"timezone_type";i:3;s:8:"' + . 'timezone";s:3:"UTC";}}', + ]; + yield 'new format' => ['O:32:"AssoConnect\PHPDate\AbsoluteDate":1:{s:4:"date";s:10:"2022-01-01";}']; + } + + public function testComparison(): void + { + $dateBefore = new AbsoluteDate('2023-01-01'); + $dateAfter = new AbsoluteDate('2024-01-01'); + + self::assertTrue($dateBefore->equals($dateBefore)); + self::assertFalse($dateBefore->equals($dateAfter)); + self::assertTrue($dateBefore->equalsTo($dateBefore)); + self::assertFalse($dateBefore->equalsTo($dateAfter)); + + self::assertTrue($dateBefore->isBefore($dateAfter)); + self::assertFalse($dateBefore->isBefore($dateBefore)); + self::assertFalse($dateAfter->isBefore($dateBefore)); + + self::assertTrue($dateBefore->isBeforeOrEqualTo($dateAfter)); + self::assertTrue($dateBefore->isBeforeOrEqualTo($dateBefore)); + self::assertFalse($dateAfter->isBeforeOrEqualTo($dateBefore)); + + self::assertSame(-1, $dateBefore->compare($dateAfter)); + self::assertSame(0, $dateBefore->compare($dateBefore)); + self::assertSame(1, $dateAfter->compare($dateBefore)); + + self::assertTrue($dateAfter->isAfter($dateBefore)); + self::assertFalse($dateAfter->isAfter($dateAfter)); + self::assertFalse($dateBefore->isAfter($dateAfter)); + + self::assertTrue($dateAfter->isAfterOrEqualTo($dateBefore)); + self::assertTrue($dateAfter->isAfterOrEqualTo($dateAfter)); + self::assertFalse($dateBefore->isAfterOrEqualTo($dateAfter)); + + self::assertTrue((new AbsoluteDate('2023-06-01'))->isBetween($dateBefore, $dateAfter)); + self::assertFalse((new AbsoluteDate('2020-01-01'))->isBetween($dateBefore, $dateAfter)); + self::assertFalse((new AbsoluteDate('2025-01-01'))->isBetween($dateBefore, $dateAfter)); + self::assertFalse($dateBefore->isBetween($dateBefore, $dateAfter)); + self::assertFalse($dateAfter->isBetween($dateBefore, $dateAfter)); + + self::assertTrue((new AbsoluteDate('2023-06-01'))->isBetweenOrEqualTo($dateBefore, $dateAfter)); + self::assertFalse((new AbsoluteDate('2020-01-01'))->isBetweenOrEqualTo($dateBefore, $dateAfter)); + self::assertFalse((new AbsoluteDate('2025-01-01'))->isBetweenOrEqualTo($dateBefore, $dateAfter)); + self::assertTrue($dateBefore->isBetweenOrEqualTo($dateBefore, $dateAfter)); + self::assertTrue($dateAfter->isBetweenOrEqualTo($dateBefore, $dateAfter)); + } +} diff --git a/tests/LocalizedStringParserTest.php b/tests/LocalizedStringParserTest.php index 6b19655..4322d08 100644 --- a/tests/LocalizedStringParserTest.php +++ b/tests/LocalizedStringParserTest.php @@ -1,30 +1,30 @@ -create($formattedDate, $locale)->format()); - } - - /** @return array{string, string, string}[] */ - public static function provideStringsAndLocales(): iterable - { - yield ['09/01/2023', 'en_US', '2023-09-01']; - yield ['9/1/2023', 'en_US', '2023-09-01']; - yield ['9/1/23', 'en_US', '2023-09-01']; - - yield ['09/01/2023', 'fr_FR', '2023-01-09']; - yield ['9/1/2023', 'fr_FR', '2023-01-09']; - yield ['9/1/23', 'fr_FR', '2023-01-09']; - } -} +create($formattedDate, $locale)->format()); + } + + /** @return array{string, string, string}[] */ + public static function provideStringsAndLocales(): iterable + { + yield ['09/01/2023', 'en_US', '2023-09-01']; + yield ['9/1/2023', 'en_US', '2023-09-01']; + yield ['9/1/23', 'en_US', '2023-09-01']; + + yield ['09/01/2023', 'fr_FR', '2023-01-09']; + yield ['9/1/2023', 'fr_FR', '2023-01-09']; + yield ['9/1/23', 'fr_FR', '2023-01-09']; + } +} diff --git a/tests/TimeTravelerTest.php b/tests/TimeTravelerTest.php index eb98dcc..559930d 100644 --- a/tests/TimeTravelerTest.php +++ b/tests/TimeTravelerTest.php @@ -1,134 +1,134 @@ -timeTraveler = new TimeTraveler(); - } - - /** @dataProvider provideAddMonths */ - public function testAddMonth(string $from, string $expected): void - { - self::assertSame($expected, $this->timeTraveler->addMonth(new AbsoluteDate($from))->__toString()); - } - - /** @return array{string, string}[] */ - public static function provideAddMonths(): iterable - { - yield ['2020-01-01', '2020-02-01']; - yield ['2020-01-28', '2020-02-28']; - yield ['2020-01-29', '2020-02-29']; - yield ['2020-01-30', '2020-02-29']; - yield ['2020-01-31', '2020-02-29']; - yield ['2020-02-29', '2020-03-31']; - yield ['2020-06-30', '2020-07-31']; - } - - /** @dataProvider provideRemoveMonths */ - public function testRemoveMonth(string $from, string $expected): void - { - self::assertSame($expected, $this->timeTraveler->removeMonth(new AbsoluteDate($from))->__toString()); - } - - /** @return iterable */ - public static function provideRemoveMonths(): iterable - { - foreach ( - [ - '2020-01-01' => '2019-12-01', - '2020-01-28' => '2019-12-28', - '2020-01-29' => '2019-12-29', - '2020-01-30' => '2019-12-30', - '2020-01-31' => '2019-12-31', - '2020-02-29' => '2020-01-31', - '2020-06-30' => '2020-05-31', - '2023-10-31' => '2023-09-30', - '2023-08-31' => '2023-07-31', - '2023-09-30' => '2023-08-31', - '2023-03-31' => '2023-02-28', - '2024-03-31' => '2024-02-29', - ] as $currentMonth => $expectedPreviousMonth - ) { - yield sprintf('%s: previous month will %s', $currentMonth, $expectedPreviousMonth) => [ - $currentMonth, - $expectedPreviousMonth, - ]; - } - } - - /** @dataProvider provideMonthsWithReference */ - public function testAddMonthWithReference(string $reference, string $from, string $expected): void - { - self::assertSame($expected, $this->timeTraveler->addMonthWithReference( - new AbsoluteDate($reference), - new AbsoluteDate($from) - )->__toString()); - } - - /** @return array{string, string, string}[] */ - public static function provideMonthsWithReference(): iterable - { - yield ['2020-01-01', '2020-01-01', '2020-02-01']; - yield ['2020-01-01', '2020-02-01', '2020-03-01']; - - yield ['2020-01-25', '2020-02-25', '2020-03-25']; - - // Test the result day matches the reference day - yield ['2020-01-30', '2020-02-29', '2020-03-30']; - yield ['2020-01-31', '2020-02-29', '2020-03-31']; - yield ['2020-01-31', '2020-03-31', '2020-04-30']; - yield ['2020-06-30', '2020-06-30', '2020-07-31']; - yield ['2020-06-30', '2020-07-31', '2020-08-31']; - yield ['2020-06-30', '2020-08-31', '2020-09-30']; - } - - /** @dataProvider provideMonthsWithReferenceOverYear */ - public function testAddMonthWithReferenceWorksYearOverYear(string $referenceAsString, string $expected): void - { - $reference = new AbsoluteDate($referenceAsString); - - for ($i = 0; $i < 12; $i++) { - $actual = $this->timeTraveler->addMonthWithReference($reference, $actual ?? $reference); - } - self::assertTrue(isset($actual)); - self::assertSame($expected, $actual->__toString()); - } - - /** @return array{string, string}[] */ - public static function provideMonthsWithReferenceOverYear(): iterable - { - yield ['2020-01-01', '2021-01-01']; - yield ['2020-01-15', '2021-01-15']; - yield ['2020-01-28', '2021-01-28']; - yield ['2020-01-29', '2021-01-29']; - yield ['2020-01-30', '2021-01-30']; - yield ['2020-01-31', '2021-01-31']; - yield ['2020-06-30', '2021-06-30']; - } - - /** @dataProvider provideYears */ - public function testAddYear(string $from, string $expected): void - { - self::assertSame($expected, $this->timeTraveler->addYear(new AbsoluteDate($from))->__toString()); - } - - /** @return array{string, string}[] */ - public static function provideYears(): iterable - { - yield ['2020-01-01', '2021-01-01']; - yield ['2020-01-31', '2021-01-31']; - yield ['2020-02-29', '2021-02-28']; - yield ['2020-06-30', '2021-06-30']; - } -} +timeTraveler = new TimeTraveler(); + } + + /** @dataProvider provideAddMonths */ + public function testAddMonth(string $from, string $expected): void + { + self::assertSame($expected, $this->timeTraveler->addMonth(new AbsoluteDate($from))->__toString()); + } + + /** @return array{string, string}[] */ + public static function provideAddMonths(): iterable + { + yield ['2020-01-01', '2020-02-01']; + yield ['2020-01-28', '2020-02-28']; + yield ['2020-01-29', '2020-02-29']; + yield ['2020-01-30', '2020-02-29']; + yield ['2020-01-31', '2020-02-29']; + yield ['2020-02-29', '2020-03-31']; + yield ['2020-06-30', '2020-07-31']; + } + + /** @dataProvider provideRemoveMonths */ + public function testRemoveMonth(string $from, string $expected): void + { + self::assertSame($expected, $this->timeTraveler->removeMonth(new AbsoluteDate($from))->__toString()); + } + + /** @return iterable */ + public static function provideRemoveMonths(): iterable + { + foreach ( + [ + '2020-01-01' => '2019-12-01', + '2020-01-28' => '2019-12-28', + '2020-01-29' => '2019-12-29', + '2020-01-30' => '2019-12-30', + '2020-01-31' => '2019-12-31', + '2020-02-29' => '2020-01-31', + '2020-06-30' => '2020-05-31', + '2023-10-31' => '2023-09-30', + '2023-08-31' => '2023-07-31', + '2023-09-30' => '2023-08-31', + '2023-03-31' => '2023-02-28', + '2024-03-31' => '2024-02-29', + ] as $currentMonth => $expectedPreviousMonth + ) { + yield sprintf('%s: previous month will %s', $currentMonth, $expectedPreviousMonth) => [ + $currentMonth, + $expectedPreviousMonth, + ]; + } + } + + /** @dataProvider provideMonthsWithReference */ + public function testAddMonthWithReference(string $reference, string $from, string $expected): void + { + self::assertSame($expected, $this->timeTraveler->addMonthWithReference( + new AbsoluteDate($reference), + new AbsoluteDate($from) + )->__toString()); + } + + /** @return array{string, string, string}[] */ + public static function provideMonthsWithReference(): iterable + { + yield ['2020-01-01', '2020-01-01', '2020-02-01']; + yield ['2020-01-01', '2020-02-01', '2020-03-01']; + + yield ['2020-01-25', '2020-02-25', '2020-03-25']; + + // Test the result day matches the reference day + yield ['2020-01-30', '2020-02-29', '2020-03-30']; + yield ['2020-01-31', '2020-02-29', '2020-03-31']; + yield ['2020-01-31', '2020-03-31', '2020-04-30']; + yield ['2020-06-30', '2020-06-30', '2020-07-31']; + yield ['2020-06-30', '2020-07-31', '2020-08-31']; + yield ['2020-06-30', '2020-08-31', '2020-09-30']; + } + + /** @dataProvider provideMonthsWithReferenceOverYear */ + public function testAddMonthWithReferenceWorksYearOverYear(string $referenceAsString, string $expected): void + { + $reference = new AbsoluteDate($referenceAsString); + + for ($i = 0; $i < 12; $i++) { + $actual = $this->timeTraveler->addMonthWithReference($reference, $actual ?? $reference); + } + self::assertTrue(isset($actual)); + self::assertSame($expected, $actual->__toString()); + } + + /** @return array{string, string}[] */ + public static function provideMonthsWithReferenceOverYear(): iterable + { + yield ['2020-01-01', '2021-01-01']; + yield ['2020-01-15', '2021-01-15']; + yield ['2020-01-28', '2021-01-28']; + yield ['2020-01-29', '2021-01-29']; + yield ['2020-01-30', '2021-01-30']; + yield ['2020-01-31', '2021-01-31']; + yield ['2020-06-30', '2021-06-30']; + } + + /** @dataProvider provideYears */ + public function testAddYear(string $from, string $expected): void + { + self::assertSame($expected, $this->timeTraveler->addYear(new AbsoluteDate($from))->__toString()); + } + + /** @return array{string, string}[] */ + public static function provideYears(): iterable + { + yield ['2020-01-01', '2021-01-01']; + yield ['2020-01-31', '2021-01-31']; + yield ['2020-02-29', '2021-02-28']; + yield ['2020-06-30', '2021-06-30']; + } +}