ldc-arcadia-api/tests/Integration/Shared/Helpers/DateHelperTest.php

126 lines
4.9 KiB
PHP
Raw Permalink Normal View History

<?php
declare(strict_types=1);
namespace Tests\Integration\Shared\Helpers;
use Carbon\CarbonImmutable;
use Shared\Helpers\DatesHelper;
use Shared\Helpers\Exceptions\InvalidDateFormatException;
covers(DatesHelper::class);
afterEach(function (): void {
CarbonImmutable::setTestNow();
});
describe('Date Helper Integration Tests', function (): void {
it('prevents direct instantiation but covers constructor', function (): void {
// GIVEN
$reflection = new \ReflectionClass(DatesHelper::class);
// WHEN
$constructor = $reflection->getConstructor();
$constructor->invoke($reflection->newInstanceWithoutConstructor());
// THEN
expect(fn () => $reflection->newInstance())
->toThrow(\ReflectionException::class);
});
it('can parse various date formats and normalizes to UTC', function (string $input, string $expectedFormat): void {
// GIVEN & WHEN
$result = DatesHelper::parseDateTime($input);
// THEN
expect($result)->toBeInstanceOf(\DateTimeInterface::class)
->and($result->format('Y-m-d'))->toBe($expectedFormat)
->and($result->getTimezone()->getName())->toBe('UTC');
})->with([
['2025-12-25 12:10:23', '2025-12-25'],
['2025-12-25', '2025-12-25'],
['25-12-2025', '2025-12-25'],
['2025-12-25T12:10:23Z', '2025-12-25'],
['2025-12-25T12:10:23+02:00', '2025-12-25'],
['2025-12-25T12:10:23.123456+02:00', '2025-12-25'],
['2025/12/25', '2025-12-25'],
]);
it('converts non-UTC input timezone to exact UTC instant', function (): void {
// GIVEN
$inputWithOffset = '2025-12-25T14:10:23+02:00';
// WHEN
$result = DatesHelper::parseDateTime($inputWithOffset);
// THEN
expect($result->getTimezone()->getName())->toBe('UTC')
->and($result->format('Y-m-d H:i:s'))->toBe('2025-12-25 12:10:23');
});
it('throws InvalidDateFormatException for unparseable date strings', function (): void {
// GIVEN
$invalidDate = 'not-a-real-date-string';
// WHEN & THEN
expect(fn () => DatesHelper::parseDateTime($invalidDate))
->toThrow(InvalidDateFormatException::class, 'Unrecognized date/time format: not-a-real-date-string');
});
it('falls back to DateTimeImmutable for valid formats not fully handled by createFromFormat', function (): void {
// GIVEN
$fallbackDate = '2025-12-25T12:10:23.1234567Z'; // 7 digit microsecond matches regex but fails createFromFormat 'u' (6 digits)
// WHEN
$result = DatesHelper::parseDateTime($fallbackDate);
// THEN
expect($result)->toBeInstanceOf(\DateTimeInterface::class)
->and($result->format('Y-m-d'))->toBe('2025-12-25')
->and($result->getTimezone()->getName())->toBe('UTC');
});
it('throws InvalidDateFormatException in parseFallback when fallback date is completely invalid logically', function (): void {
// GIVEN
$invalidFallbackDate = '2025-12-25T25:10:23.1234567Z'; // Invalid hour 25, matches regex but fails both createFromFormat and new DateTimeImmutable
// WHEN & THEN
expect(fn () => DatesHelper::parseDateTime($invalidFallbackDate))
->toThrow(InvalidDateFormatException::class, "Unrecognized date/time format: {$invalidFallbackDate}");
});
it('handles isIn date boundary checks correctly in UTC', function (): void {
// GIVEN
$now = CarbonImmutable::create(2025, 6, 15, 12, 0, 0, 'UTC');
CarbonImmutable::setTestNow($now);
$past = CarbonImmutable::create(2025, 1, 1, 0, 0, 0, 'UTC');
$future = CarbonImmutable::create(2025, 12, 31, 0, 0, 0, 'UTC');
$farFuture = CarbonImmutable::create(2025, 12, 30, 0, 0, 0, 'UTC');
// WHEN & THEN
expect(DatesHelper::isIn($past, $future))->toBeTrue()
->and(DatesHelper::isIn($farFuture, $future))->toBeFalse()
->and(DatesHelper::isIn($past, null))->toBeTrue()
->and(DatesHelper::isIn($future, null))->toBeFalse()
->and(DatesHelper::isIn(null, $future))->toBeTrue()
->and(DatesHelper::isIn(null, $past))->toBeFalse()
->and(DatesHelper::isIn(null, null))->toBeFalse();
});
it('formats string or DateTimeInterface to RFC3339 in UTC', function (): void {
// GIVEN
$dateTimeObj = new \DateTimeImmutable('2025-12-25 12:10:23', new \DateTimeZone('Europe/Paris'));
// WHEN
$resultFromObj = DatesHelper::toRfc3339($dateTimeObj);
$resultFromStr = DatesHelper::toRfc3339('2025-12-25 12:10:23');
// THEN
expect($resultFromObj)->toBe('2025-12-25T11:10:23+00:00')
->and($resultFromStr)->toBe('2025-12-25T12:10:23+00:00')
->and(DatesHelper::toNullableRfc3339(null))->toBeNull()
->and(DatesHelper::toNullableRfc3339($dateTimeObj))->toBe('2025-12-25T11:10:23+00:00');
});
});