Attainly/backend/tests/Unit/Schedule/EvenDistributionSchedulerTest.php

129 lines
4 KiB
PHP

<?php
namespace Tests\Unit\Schedule;
use App\Schedule\EvenDistributionScheduler;
use App\Schedule\WorkloadPlacement;
use DateTimeImmutable;
use DateTimeZone;
use PHPUnit\Framework\TestCase;
class EvenDistributionSchedulerTest extends TestCase
{
public function test_it_places_one_heavier_day_at_the_requested_position(): void
{
$scheduler = new EvenDistributionScheduler;
$expectedCounts = [
WorkloadPlacement::Start->value => [3, 2, 2, 2, 2],
WorkloadPlacement::Middle->value => [2, 2, 3, 2, 2],
WorkloadPlacement::End->value => [2, 2, 2, 2, 3],
];
foreach (WorkloadPlacement::cases() as $placement) {
$dates = $scheduler->scheduledDates(
assignmentCount: 11,
startDate: $this->utc('2026-08-10'),
targetDate: $this->utc('2026-08-14'),
workloadPlacement: $placement,
);
$this->assertSame(
$expectedCounts[$placement->value],
$this->dailyCounts($dates),
);
}
}
public function test_it_keeps_multiple_heavier_days_together(): void
{
$scheduler = new EvenDistributionScheduler;
$expectedCounts = [
WorkloadPlacement::Start->value => [3, 3, 2, 2, 2],
WorkloadPlacement::Middle->value => [2, 3, 3, 2, 2],
WorkloadPlacement::End->value => [2, 2, 2, 3, 3],
];
foreach (WorkloadPlacement::cases() as $placement) {
$dates = $scheduler->scheduledDates(
assignmentCount: 12,
startDate: $this->utc('2026-08-10'),
targetDate: $this->utc('2026-08-14'),
workloadPlacement: $placement,
);
$this->assertSame(
$expectedCounts[$placement->value],
$this->dailyCounts($dates),
);
}
}
public function test_it_preserves_sparse_distribution_across_the_full_range(): void
{
$dates = (new EvenDistributionScheduler)->scheduledDates(
assignmentCount: 3,
startDate: $this->utc('2026-08-10'),
targetDate: $this->utc('2026-08-16'),
workloadPlacement: WorkloadPlacement::Middle,
);
$this->assertSame(
['2026-08-10', '2026-08-13', '2026-08-16'],
$this->formattedDates($dates),
);
}
public function test_it_distributes_even_and_single_day_schedules(): void
{
$scheduler = new EvenDistributionScheduler;
$evenDates = $scheduler->scheduledDates(
assignmentCount: 10,
startDate: $this->utc('2026-08-10'),
targetDate: $this->utc('2026-08-14'),
workloadPlacement: WorkloadPlacement::End,
);
$singleDayDates = $scheduler->scheduledDates(
assignmentCount: 4,
startDate: $this->utc('2026-08-10'),
targetDate: $this->utc('2026-08-10'),
workloadPlacement: WorkloadPlacement::Middle,
);
$this->assertSame([2, 2, 2, 2, 2], $this->dailyCounts($evenDates));
$this->assertSame(
[
'2026-08-10',
'2026-08-10',
'2026-08-10',
'2026-08-10',
],
$this->formattedDates($singleDayDates),
);
}
/**
* @param list<DateTimeImmutable> $dates
* @return list<int>
*/
private function dailyCounts(array $dates): array
{
return array_values(array_count_values($this->formattedDates($dates)));
}
/**
* @param list<DateTimeImmutable> $dates
* @return list<string>
*/
private function formattedDates(array $dates): array
{
return array_map(function (DateTimeImmutable $date): string {
return $date->format('Y-m-d');
}, $dates);
}
private function utc(string $date): DateTimeImmutable
{
return new DateTimeImmutable($date, new DateTimeZone('UTC'));
}
}