fix: allow booking the free part of a partly booked day
This commit is contained in:
1 parent
a88ff7ff24
commit
78839838f0
15 files changed
+541
-60
No files matched your search
@@ -83,6 +83,57 @@ class TimeRangeTest extends TestCase
|
||||
yield 'out of range is rejected' => ['25:00', '26:00', null];
|
||||
}
|
||||
|
||||
public function testRemainingIsTheWholeSpanWhenNothingIsTaken(): void
|
||||
{
|
||||
$free = TimeRange::remaining(TimeRange::wholeDay(), []);
|
||||
|
||||
self::assertSame(['00:00–24:00'], self::render($free));
|
||||
}
|
||||
|
||||
public function testRemainingSplitsAroundABookingInTheMiddle(): void
|
||||
{
|
||||
$free = TimeRange::remaining(TimeRange::wholeDay(), [TimeRange::fromMinutes(540, 780)]);
|
||||
|
||||
self::assertSame(['00:00–09:00', '13:00–24:00'], self::render($free));
|
||||
}
|
||||
|
||||
public function testRemainingIsEmptyWhenTheSpanIsFullyCovered(): void
|
||||
{
|
||||
self::assertSame([], TimeRange::remaining(TimeRange::wholeDay(), [TimeRange::wholeDay()]));
|
||||
}
|
||||
|
||||
public function testRemainingHandlesOverlappingAndUnsortedInput(): void
|
||||
{
|
||||
// Bookings on one resource cannot overlap, but the span may be covered by several that
|
||||
// touch, and nothing guarantees the order they arrive in.
|
||||
$free = TimeRange::remaining(TimeRange::wholeDay(), [
|
||||
TimeRange::fromMinutes(780, 1020),
|
||||
TimeRange::fromMinutes(540, 900),
|
||||
]);
|
||||
|
||||
self::assertSame(['00:00–09:00', '17:00–24:00'], self::render($free));
|
||||
}
|
||||
|
||||
public function testRemainingIgnoresWhatFallsOutsideTheSpan(): void
|
||||
{
|
||||
$free = TimeRange::remaining(TimeRange::fromMinutes(780, 1020), [TimeRange::fromMinutes(0, 540)]);
|
||||
|
||||
self::assertSame(['13:00–17:00'], self::render($free));
|
||||
}
|
||||
|
||||
public function testRemainingClipsABookingThatOverhangsTheSpan(): void
|
||||
{
|
||||
$free = TimeRange::remaining(TimeRange::fromMinutes(480, 1080), [TimeRange::fromMinutes(0, 600)]);
|
||||
|
||||
self::assertSame(['10:00–18:00'], self::render($free));
|
||||
}
|
||||
|
||||
public function testDurationIsInMinutes(): void
|
||||
{
|
||||
self::assertSame(240, TimeRange::fromMinutes(540, 780)->durationInMinutes());
|
||||
self::assertSame(1440, TimeRange::wholeDay()->durationInMinutes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Regression guard for a trap that cost real debugging time: Twig resolves `range.allDay` by
|
||||
* looking for a method literally named `allDay` BEFORE it tries `isAllDay()`, and it happily
|
||||
@@ -97,4 +148,14 @@ class TimeRangeTest extends TestCase
|
||||
self::assertSame('no', $twig->render('t', ['range' => TimeRange::fromMinutes(9 * 60, 13 * 60)]));
|
||||
self::assertSame('yes', $twig->render('t', ['range' => TimeRange::wholeDay()]));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<TimeRange> $ranges
|
||||
*
|
||||
* @return list<string>
|
||||
*/
|
||||
private static function render(array $ranges): array
|
||||
{
|
||||
return array_map(static fn (TimeRange $range): string => $range->start().'–'.$range->end(), $ranges);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user