186 lines
5.9 KiB
PHP
186 lines
5.9 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 ($expectedCounts as $placementValue => $expectedDailyCounts) {
|
|
$placement = WorkloadPlacement::from($placementValue);
|
|
$dates = $scheduler->scheduledDates(
|
|
assignmentCount: 11,
|
|
startDate: $this->utc('2026-08-10'),
|
|
targetDate: $this->utc('2026-08-14'),
|
|
workloadPlacement: $placement,
|
|
);
|
|
|
|
$this->assertSame(
|
|
$expectedDailyCounts,
|
|
$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 ($expectedCounts as $placementValue => $expectedDailyCounts) {
|
|
$placement = WorkloadPlacement::from($placementValue);
|
|
$dates = $scheduler->scheduledDates(
|
|
assignmentCount: 12,
|
|
startDate: $this->utc('2026-08-10'),
|
|
targetDate: $this->utc('2026-08-14'),
|
|
workloadPlacement: $placement,
|
|
);
|
|
|
|
$this->assertSame(
|
|
$expectedDailyCounts,
|
|
$this->dailyCounts($dates),
|
|
);
|
|
}
|
|
}
|
|
|
|
public function test_it_places_sparse_assignments_at_the_requested_position(): void
|
|
{
|
|
$scheduler = new EvenDistributionScheduler;
|
|
$expectedDates = [
|
|
WorkloadPlacement::Spread->value => [
|
|
'2026-08-10',
|
|
'2026-08-12',
|
|
'2026-08-13',
|
|
'2026-08-15',
|
|
],
|
|
WorkloadPlacement::Start->value => [
|
|
'2026-08-10',
|
|
'2026-08-11',
|
|
'2026-08-12',
|
|
'2026-08-13',
|
|
],
|
|
WorkloadPlacement::Middle->value => [
|
|
'2026-08-11',
|
|
'2026-08-12',
|
|
'2026-08-13',
|
|
'2026-08-14',
|
|
],
|
|
WorkloadPlacement::End->value => [
|
|
'2026-08-12',
|
|
'2026-08-13',
|
|
'2026-08-14',
|
|
'2026-08-15',
|
|
],
|
|
];
|
|
|
|
foreach (WorkloadPlacement::cases() as $placement) {
|
|
$dates = $scheduler->scheduledDates(
|
|
assignmentCount: 4,
|
|
startDate: $this->utc('2026-08-10'),
|
|
targetDate: $this->utc('2026-08-15'),
|
|
workloadPlacement: $placement,
|
|
);
|
|
|
|
$this->assertSame(
|
|
$expectedDates[$placement->value],
|
|
$this->formattedDates($dates),
|
|
);
|
|
}
|
|
}
|
|
|
|
public function test_it_places_one_assignment_at_the_requested_position(): void
|
|
{
|
|
$scheduler = new EvenDistributionScheduler;
|
|
$expectedDates = [
|
|
WorkloadPlacement::Spread->value => '2026-08-10',
|
|
WorkloadPlacement::Start->value => '2026-08-10',
|
|
WorkloadPlacement::Middle->value => '2026-08-12',
|
|
WorkloadPlacement::End->value => '2026-08-15',
|
|
];
|
|
|
|
foreach (WorkloadPlacement::cases() as $placement) {
|
|
$dates = $scheduler->scheduledDates(
|
|
assignmentCount: 1,
|
|
startDate: $this->utc('2026-08-10'),
|
|
targetDate: $this->utc('2026-08-15'),
|
|
workloadPlacement: $placement,
|
|
);
|
|
|
|
$this->assertSame(
|
|
[$expectedDates[$placement->value]],
|
|
$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'));
|
|
}
|
|
}
|