Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BCrwHHnGCB5XH968Nxokqw
84 lines
3.2 KiB
PHP
84 lines
3.2 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\QuietRule;
|
|
use Carbon\CarbonImmutable;
|
|
use Tests\TestCase; // Laravel TestCase: Eloquent date-casts need the connection grammar even in memory
|
|
|
|
class QuietRuleTest extends TestCase
|
|
{
|
|
private User $user;
|
|
private DueResolver $due;
|
|
private QuietRule $rule;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
$this->user = new User(['login' => 'n', 'tz' => 'UTC', 'quiet_start' => '22:00:00', 'quiet_end' => '09:00:00']);
|
|
$this->due = new DueResolver;
|
|
$this->rule = new QuietRule($this->due);
|
|
}
|
|
|
|
private function event(string $due, string $fireOn, 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::Keep, 'state' => EventState::Preparing, 'payload' => ['title' => 't'],
|
|
]);
|
|
}
|
|
|
|
private function at(string $s): CarbonImmutable
|
|
{
|
|
return CarbonImmutable::parse($s, 'UTC');
|
|
}
|
|
|
|
public function test_preparing_ack_is_quiet_until_next_cascade_point(): void
|
|
{
|
|
$e = $this->event('2026-09-30', '2026-08-31'); // точки: 30,15,7,3,1 → 31.08, 15.09, 23.09, 27.09, 29.09
|
|
$due = $this->due->resolve($e, $this->user);
|
|
|
|
$q = $this->rule->afterAck($e, $this->user, EventState::Preparing, $due, $this->at('2026-09-02 10:00'));
|
|
$this->assertSame('2026-09-15 00:00', $q->format('Y-m-d H:i'));
|
|
|
|
$q = $this->rule->afterAck($e, $this->user, EventState::Preparing, $due, $this->at('2026-09-15 10:00'));
|
|
$this->assertSame('2026-09-23 00:00', $q->format('Y-m-d H:i'), 'на самой точке — до следующей');
|
|
|
|
$q = $this->rule->afterAck($e, $this->user, EventState::Preparing, $due, $this->at('2026-09-29 10:00'));
|
|
$this->assertSame('2026-09-30 00:00', $q->format('Y-m-d H:i'), 'точек больше нет — до старта дня срока');
|
|
}
|
|
|
|
public function test_today_ack_skips_the_next_hour(): void
|
|
{
|
|
$e = $this->event('2026-09-30', '2026-09-30');
|
|
$due = $this->due->resolve($e, $this->user);
|
|
|
|
$q = $this->rule->afterAck($e, $this->user, EventState::Today, $due, $this->at('2026-09-30 11:17'));
|
|
$this->assertSame('2026-09-30 13:00', $q->format('Y-m-d H:i'));
|
|
}
|
|
|
|
public function test_overdue_ack_skips_tomorrow(): void
|
|
{
|
|
$e = $this->event('2026-09-30', '2026-09-30');
|
|
$due = $this->due->resolve($e, $this->user);
|
|
|
|
$q = $this->rule->afterAck($e, $this->user, EventState::Overdue, $due, $this->at('2026-10-05 15:00'));
|
|
$this->assertSame('2026-10-07 00:00', $q->format('Y-m-d H:i'));
|
|
}
|
|
|
|
public function test_scheduled_ack_changes_nothing(): void
|
|
{
|
|
$e = $this->event('2026-09-30', '2026-09-30');
|
|
$due = $this->due->resolve($e, $this->user);
|
|
$now = $this->at('2026-09-01 15:00');
|
|
|
|
$this->assertTrue($this->rule->afterAck($e, $this->user, EventState::Scheduled, $due, $now)->eq($now));
|
|
}
|
|
}
|