assertFalse(WorkflowRunner::isOverdue(null, new DateTimeImmutable('2026-01-15 12:00:00'))); } public function testIsOverdueReturnsFalseForFutureDueDate(): void { $now = new DateTimeImmutable('2026-01-15 12:00:00'); $this->assertFalse(WorkflowRunner::isOverdue($now->modify('+1 hour'), $now)); $this->assertFalse(WorkflowRunner::isOverdue($now->modify('+3 days'), $now)); } public function testIsOverdueReturnsTrueForPastDueDate(): void { $now = new DateTimeImmutable('2026-01-15 12:00:00'); $this->assertTrue(WorkflowRunner::isOverdue($now->modify('-1 hour'), $now)); $this->assertTrue(WorkflowRunner::isOverdue($now->modify('-30 days'), $now)); } public function testIsOverdueReturnsTrueForADueTimeEarlierTheSameDay(): void { // Regression: comparing whole calendar days (as Deck's own // Card::getDaysUntilDue() does) reports a card due earlier today as // "0 days until due", not overdue, until the calendar date rolls // over - holding every card back for up to 24h after it actually // fell due. isOverdue() must compare the real timestamps instead. $now = new DateTimeImmutable('2026-01-15 12:00:00'); $this->assertTrue(WorkflowRunner::isOverdue(new DateTimeImmutable('2026-01-15 06:00:00'), $now)); } }