Files
nextcloud-workflow-deck-aut…/tests/Unit/Service/WorkflowRunnerTest.php
T
Patrick Niebeling 27717205cd Read Deck due dates as UTC regardless of PHP's default timezone
Deck stores duedate as a zoneless DATETIME holding UTC wall-clock time,
and Entity hydrates it in PHP's default zone. That is only correct
because Nextcloud forces the default to UTC; pin the wall clock to UTC
explicitly so the overdue check compares real instants either way.
2026-09-30 10:27:13 +02:00

68 lines
2.8 KiB
PHP

<?php
declare(strict_types=1);
namespace OCA\WorkflowDeckAutomation\Tests\Unit\Service;
use DateTimeImmutable;
use DateTimeZone;
use OCA\WorkflowDeckAutomation\Service\WorkflowRunner;
use PHPUnit\Framework\TestCase;
class WorkflowRunnerTest extends TestCase {
private static function utc(string $time): DateTimeImmutable {
return new DateTimeImmutable($time, new DateTimeZone('UTC'));
}
public function testIsOverdueReturnsFalseWithoutDueDate(): void {
$this->assertFalse(WorkflowRunner::isOverdue(null, self::utc('2026-01-15 12:00:00')));
}
public function testIsOverdueReturnsFalseForFutureDueDate(): void {
$now = self::utc('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 = self::utc('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 = self::utc('2026-01-15 12:00:00');
$this->assertTrue(WorkflowRunner::isOverdue(self::utc('2026-01-15 06:00:00'), $now));
}
public function testIsOverdueReadsTheStoredWallClockAsUtc(): void {
// What Entity hydration produces if PHP's default zone is not UTC:
// the stored UTC wall clock "12:00", tagged with the local zone.
$due = new DateTimeImmutable('2026-07-15 12:00:00', new DateTimeZone('Europe/Berlin'));
// Taken at face value that would be 10:00 UTC and already overdue.
$this->assertFalse(WorkflowRunner::isOverdue($due, self::utc('2026-07-15 11:30:00')));
$this->assertTrue(WorkflowRunner::isOverdue($due, self::utc('2026-07-15 12:00:01')));
}
public function testIsOverdueComparesNowAsAnAbsoluteInstant(): void {
$due = self::utc('2026-07-15 12:00:00');
$berlin = new DateTimeZone('Europe/Berlin');
// 13:30 in Berlin (CEST) is 11:30 UTC - not yet due.
$this->assertFalse(WorkflowRunner::isOverdue($due, new DateTimeImmutable('2026-07-15 13:30:00', $berlin)));
// 14:30 in Berlin is 12:30 UTC - due.
$this->assertTrue(WorkflowRunner::isOverdue($due, new DateTimeImmutable('2026-07-15 14:30:00', $berlin)));
}
public function testIsOverdueIsFalseAtTheExactDueInstant(): void {
$now = self::utc('2026-01-15 12:00:00');
$this->assertFalse(WorkflowRunner::isOverdue($now, $now));
}
}