assertBool(true, ChronoID::isIsoDate($date), 'Expected valid ISO date: ' . $date); } } public function testIsIsoDateInvalidCases(): void { $invalid = [ '2023-02-29', '2024-13-01', '2024-00-10', '24-10-2024', '2024/10/24', '2024-10-24 12:00:00', '2024-10-24T12:00:00', '0000-01-01', ]; foreach ($invalid as $date) { $this->assertBool(false, ChronoID::isIsoDate($date), 'Expected invalid ISO date: ' . $date); } } public function testDateToDayId(): void { $this->assertStringOrNull('chronological:2024:10:24', ChronoID::dateToDayId('2024-10-24'), 'dateToDayId failed'); $this->assertStringOrNull('journal:chrono:2024:10:24', ChronoID::dateToDayId('2024-10-24', 'journal:chrono'), 'dateToDayId with custom namespace failed'); $this->assertStringOrNull(null, ChronoID::dateToDayId('2024-10-24T12:00:00'), 'datetime should be rejected'); $this->assertStringOrNull(null, ChronoID::dateToDayId('2024-13-01'), 'invalid month should be rejected'); $this->assertStringOrNull(null, ChronoID::dateToDayId('2024-10-24', ''), 'empty namespace should be rejected'); $this->assertStringOrNull(null, ChronoID::dateToDayId('2024-10-24', 'bad namespace!'), 'invalid namespace should be rejected'); } public function testCanonicalIdChecks(): void { $this->assertBool(true, ChronoID::isDayId('chronological:2024:10:24'), 'valid day ID should be accepted'); $this->assertBool(true, ChronoID::isMonthId('chronological:2024:10'), 'valid month ID should be accepted'); $this->assertBool(true, ChronoID::isYearId('chronological:2024'), 'valid year ID should be accepted'); $this->assertBool(false, ChronoID::isDayId('2024:10:24'), 'missing namespace should be rejected as day ID'); $this->assertBool(false, ChronoID::isDayId('chronological:2024-10-24'), 'hyphen date in ID should be rejected as day ID'); $this->assertBool(false, ChronoID::isDayId('chronological:2023:02:29'), 'invalid Gregorian day should be rejected'); $this->assertBool(false, ChronoID::isMonthId('chronological:2024:13'), 'invalid month 13 should be rejected'); $this->assertBool(false, ChronoID::isMonthId('chronological:2024:00'), 'invalid month 00 should be rejected'); $this->assertBool(false, ChronoID::isMonthId('chronological:2024-10'), 'invalid month format should be rejected'); $this->assertBool(false, ChronoID::isYearId('chronological:0000'), 'year 0000 should be rejected'); $this->assertBool(false, ChronoID::isYearId('chronological:24'), 'short year should be rejected'); $this->assertBool(false, ChronoID::isYearId('chronological:2024:10'), 'month ID should not pass as year ID'); } public function testConversions(): void { $this->assertStringOrNull('chronological:2024:10', ChronoID::dayIdToMonthId('chronological:2024:10:24'), 'dayIdToMonthId failed'); $this->assertStringOrNull('chronological:2024', ChronoID::monthIdToYearId('chronological:2024:10'), 'monthIdToYearId failed'); $this->assertStringOrNull(null, ChronoID::dayIdToMonthId('chronological:2024:13:24'), 'invalid day ID should map to null month ID'); $this->assertStringOrNull(null, ChronoID::dayIdToMonthId('chronological:2024:10'), 'month ID should not map via dayIdToMonthId'); $this->assertStringOrNull(null, ChronoID::monthIdToYearId('chronological:2024:13'), 'invalid month ID should map to null year ID'); $this->assertStringOrNull(null, ChronoID::monthIdToYearId('chronological:2024:10:24'), 'day ID should not map via monthIdToYearId'); } /** * Integration-style smoke test for canonical ID matrix acceptance/rejection. */ public function testCanonicalPageIdSmokeMatrix(): void { $accepted = [ ['day', 'chronological:2024:10:24'], ['month', 'chronological:2024:10'], ['year', 'chronological:2024'], ]; foreach ($accepted as [$kind, $id]) { if ($kind === 'day') { $this->assertBool(true, ChronoID::isDayId($id), 'Expected accepted day ID: ' . $id); } elseif ($kind === 'month') { $this->assertBool(true, ChronoID::isMonthId($id), 'Expected accepted month ID: ' . $id); } else { $this->assertBool(true, ChronoID::isYearId($id), 'Expected accepted year ID: ' . $id); } } $rejected = [ '2024:10:24', 'chronological:2024-10-24', 'chronological:2024:13:01', 'chronological:2024:00', 'chronological:0000', ]; foreach ($rejected as $id) { $this->assertBool(false, ChronoID::isDayId($id), 'Unexpected day ID acceptance: ' . $id); $this->assertBool(false, ChronoID::isMonthId($id), 'Unexpected month ID acceptance: ' . $id); $this->assertBool(false, ChronoID::isYearId($id), 'Unexpected year ID acceptance: ' . $id); } } }