Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BCrwHHnGCB5XH968Nxokqw
90 lines
4.4 KiB
PHP
90 lines
4.4 KiB
PHP
<?php
|
||
|
||
namespace Tests\Unit\Scheduling;
|
||
|
||
use App\Enums\AfterDue;
|
||
use App\Enums\DueMode;
|
||
use App\Enums\EventState;
|
||
use App\Models\Event;
|
||
use App\Models\User;
|
||
use App\Scheduling\DueResolver;
|
||
use App\Scheduling\StateResolver;
|
||
use Carbon\CarbonImmutable;
|
||
use Tests\TestCase; // Laravel TestCase: Eloquent date-casts need the connection grammar even in memory
|
||
|
||
class StateResolverTest extends TestCase
|
||
{
|
||
private User $user;
|
||
private StateResolver $resolver;
|
||
|
||
protected function setUp(): void
|
||
{
|
||
parent::setUp();
|
||
$this->user = new User(['login' => 'n', 'tz' => 'America/Montevideo', 'quiet_start' => '22:00:00', 'quiet_end' => '09:00:00']);
|
||
$this->resolver = new StateResolver(new DueResolver);
|
||
}
|
||
|
||
private function event(string $due, string $fireOn, AfterDue $afterDue = AfterDue::Keep, string $time = '24:00:00'): Event
|
||
{
|
||
return new Event([
|
||
'due_mode' => DueMode::Local, 'due_date' => $due, 'due_time' => $time, 'fire_on' => $fireOn,
|
||
'after_due' => $afterDue, 'state' => EventState::Scheduled, 'payload' => ['title' => 't'],
|
||
]);
|
||
}
|
||
|
||
private function at(string $local): CarbonImmutable
|
||
{
|
||
return CarbonImmutable::parse($local, 'America/Montevideo');
|
||
}
|
||
|
||
public function test_deadline_walks_through_states(): void
|
||
{
|
||
$e = $this->event('2026-09-30', '2026-08-31', AfterDue::Keep);
|
||
|
||
$this->assertSame(EventState::Scheduled, $this->resolver->resolve($e, $this->user, $this->at('2026-08-30 23:59')));
|
||
$this->assertSame(EventState::Preparing, $this->resolver->resolve($e, $this->user, $this->at('2026-08-31 00:00')));
|
||
$this->assertSame(EventState::Preparing, $this->resolver->resolve($e, $this->user, $this->at('2026-09-29 23:59')));
|
||
$this->assertSame(EventState::Today, $this->resolver->resolve($e, $this->user, $this->at('2026-09-30 00:00')));
|
||
$this->assertSame(EventState::Today, $this->resolver->resolve($e, $this->user, $this->at('2026-09-30 23:59')));
|
||
$this->assertSame(EventState::Overdue, $this->resolver->resolve($e, $this->user, $this->at('2026-10-01 00:00')));
|
||
}
|
||
|
||
public function test_day_of_never_prepares_and_expires(): void
|
||
{
|
||
$e = $this->event('2026-08-14', '2026-08-14', AfterDue::Expire);
|
||
|
||
$this->assertSame(EventState::Scheduled, $this->resolver->resolve($e, $this->user, $this->at('2026-08-13 23:59')));
|
||
$this->assertSame(EventState::Today, $this->resolver->resolve($e, $this->user, $this->at('2026-08-14 00:00')));
|
||
$this->assertSame(EventState::Expired, $this->resolver->resolve($e, $this->user, $this->at('2026-08-15 00:00')));
|
||
}
|
||
|
||
public function test_timed_moment_ends_today_mid_day(): void
|
||
{
|
||
$e = $this->event('2026-09-10', '2026-09-03', AfterDue::Expire, '14:00:00');
|
||
|
||
$this->assertSame(EventState::Today, $this->resolver->resolve($e, $this->user, $this->at('2026-09-10 13:59')));
|
||
$this->assertSame(EventState::Expired, $this->resolver->resolve($e, $this->user, $this->at('2026-09-10 14:00')));
|
||
}
|
||
|
||
public function test_early_moment_starts_today_the_evening_before(): void
|
||
{
|
||
$e = $this->event('2026-09-10', '2026-09-03', AfterDue::Expire, '07:00:00');
|
||
|
||
$this->assertSame(EventState::Preparing, $this->resolver->resolve($e, $this->user, $this->at('2026-09-09 19:59')));
|
||
$this->assertSame(EventState::Today, $this->resolver->resolve($e, $this->user, $this->at('2026-09-09 20:00')));
|
||
$this->assertSame(EventState::Expired, $this->resolver->resolve($e, $this->user, $this->at('2026-09-10 07:00')));
|
||
}
|
||
|
||
public function test_fixed_flight_uses_user_timezone(): void
|
||
{
|
||
$e = new Event([
|
||
'due_mode' => DueMode::Fixed, 'due_instant' => CarbonImmutable::parse('2026-09-10T08:15:00+02:00'),
|
||
'fire_on' => '2026-09-03', 'after_due' => AfterDue::Expire, 'state' => EventState::Scheduled, 'payload' => ['title' => 't'],
|
||
]);
|
||
// 03:15 по Монтевидео → раньше активных часов → today с 20:00 накануне
|
||
$this->assertSame(EventState::Today, $this->resolver->resolve($e, $this->user, $this->at('2026-09-09 20:00')));
|
||
$this->assertSame(EventState::Today, $this->resolver->resolve($e, $this->user, $this->at('2026-09-10 03:14')));
|
||
$this->assertSame(EventState::Expired, $this->resolver->resolve($e, $this->user, $this->at('2026-09-10 03:15')));
|
||
}
|
||
}
|