test sparse schedule placement
This commit is contained in:
parent
6c8250b3a4
commit
add0684610
3 changed files with 130 additions and 14 deletions
|
|
@ -196,6 +196,40 @@ class ScheduleEndpointTest extends TestCase
|
||||||
$this->assertDatabaseCount('schedules', 1);
|
$this->assertDatabaseCount('schedules', 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_it_packs_sparse_assignments_at_the_requested_end(): void
|
||||||
|
{
|
||||||
|
$user = $this->createUser('reader@example.com');
|
||||||
|
$set = $this->createSet($user, 'Course');
|
||||||
|
$lessonLevel = $this->createLevel($set, 'lesson');
|
||||||
|
$repository = app(ElementRepository::class);
|
||||||
|
|
||||||
|
foreach (range(1, 4) as $number) {
|
||||||
|
$repository->create(new CreateElementDto(
|
||||||
|
name: "Lesson {$number}",
|
||||||
|
level: $lessonLevel,
|
||||||
|
parentElement: null,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
$this->createSession($user, 'valid-token');
|
||||||
|
|
||||||
|
$response = $this->credentialedPost('/api/schedules', [
|
||||||
|
'setId' => $set->getId(),
|
||||||
|
'levelId' => $lessonLevel->getId(),
|
||||||
|
'startDate' => '2026-08-10',
|
||||||
|
'targetDate' => '2026-08-15',
|
||||||
|
'workloadPlacement' => 'end',
|
||||||
|
])->assertCreated();
|
||||||
|
|
||||||
|
$days = $response->json('schedule.days');
|
||||||
|
$this->assertIsArray($days);
|
||||||
|
$this->assertSame(
|
||||||
|
[0, 0, 1, 1, 1, 1],
|
||||||
|
array_map(function (array $day): int {
|
||||||
|
return count($day['assignments']);
|
||||||
|
}, $days),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function test_it_rejects_an_unknown_workload_placement(): void
|
public function test_it_rejects_an_unknown_workload_placement(): void
|
||||||
{
|
{
|
||||||
$user = $this->createUser('reader@example.com');
|
$user = $this->createUser('reader@example.com');
|
||||||
|
|
@ -215,7 +249,34 @@ class ScheduleEndpointTest extends TestCase
|
||||||
'targetDate' => '2026-08-14',
|
'targetDate' => '2026-08-14',
|
||||||
'workloadPlacement' => 'sideways',
|
'workloadPlacement' => 'sideways',
|
||||||
])->assertBadRequest()->assertExactJson([
|
])->assertBadRequest()->assertExactJson([
|
||||||
'error' => 'workloadPlacement must be start, middle, or end',
|
'error' => 'workloadPlacement must be spread, start, middle, or end',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_it_rejects_spread_placement_for_a_dense_schedule(): void
|
||||||
|
{
|
||||||
|
$user = $this->createUser('reader@example.com');
|
||||||
|
$set = $this->createSet($user, 'Course');
|
||||||
|
$lessonLevel = $this->createLevel($set, 'lesson');
|
||||||
|
$repository = app(ElementRepository::class);
|
||||||
|
|
||||||
|
foreach (range(1, 5) as $number) {
|
||||||
|
$repository->create(new CreateElementDto(
|
||||||
|
name: "Lesson {$number}",
|
||||||
|
level: $lessonLevel,
|
||||||
|
parentElement: null,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
$this->createSession($user, 'valid-token');
|
||||||
|
|
||||||
|
$this->credentialedPost('/api/schedules', [
|
||||||
|
'setId' => $set->getId(),
|
||||||
|
'levelId' => $lessonLevel->getId(),
|
||||||
|
'startDate' => '2026-08-10',
|
||||||
|
'targetDate' => '2026-08-13',
|
||||||
|
'workloadPlacement' => 'spread',
|
||||||
|
])->assertBadRequest()->assertExactJson([
|
||||||
|
'error' => 'spread placement requires fewer assignments than days',
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,20 +58,75 @@ class EvenDistributionSchedulerTest extends TestCase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_it_preserves_sparse_distribution_across_the_full_range(): void
|
public function test_it_places_sparse_assignments_at_the_requested_position(): void
|
||||||
{
|
{
|
||||||
$dates = (new EvenDistributionScheduler)->scheduledDates(
|
$scheduler = new EvenDistributionScheduler;
|
||||||
assignmentCount: 3,
|
$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'),
|
startDate: $this->utc('2026-08-10'),
|
||||||
targetDate: $this->utc('2026-08-16'),
|
targetDate: $this->utc('2026-08-15'),
|
||||||
workloadPlacement: WorkloadPlacement::Middle,
|
workloadPlacement: $placement,
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertSame(
|
$this->assertSame(
|
||||||
['2026-08-10', '2026-08-13', '2026-08-16'],
|
$expectedDates[$placement->value],
|
||||||
$this->formattedDates($dates),
|
$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
|
public function test_it_distributes_even_and_single_day_schedules(): void
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -156,7 +156,7 @@ class CreateScheduleTest extends TestCase
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_it_spreads_sparse_work_across_the_full_range(): void
|
public function test_it_defaults_sparse_work_to_spread_across_the_full_range(): void
|
||||||
{
|
{
|
||||||
$user = $this->user();
|
$user = $this->user();
|
||||||
$setRepository = new FakeSetRepository;
|
$setRepository = new FakeSetRepository;
|
||||||
|
|
@ -192,7 +192,7 @@ class CreateScheduleTest extends TestCase
|
||||||
levelId: $lessonLevel->getId(),
|
levelId: $lessonLevel->getId(),
|
||||||
startDate: '2026-08-10',
|
startDate: '2026-08-10',
|
||||||
targetDate: '2026-08-16',
|
targetDate: '2026-08-16',
|
||||||
workloadPlacement: 'middle',
|
workloadPlacement: null,
|
||||||
));
|
));
|
||||||
|
|
||||||
$this->assertSame(
|
$this->assertSame(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue