Files
ephub/tests/Model/SpotGroupTest.php
T

138 lines
4.1 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Tests\Model;
use App\Entity\Booking;
use App\Entity\Resource;
use App\Entity\ResourceGroup;
use App\Entity\User;
use App\Enum\ResourceType;
use App\Model\Spot;
use App\Model\SpotGroup;
use App\Model\TimeRange;
use PHPUnit\Framework\TestCase;
class SpotGroupTest extends TestCase
{
public function testSpotsArePartitionedByTheirRoom(): void
{
$north = $this->room('Raum Nord');
$south = $this->room('Raum Süd');
$groups = SpotGroup::over([
$this->spot('D1', $north),
$this->spot('D2', $north),
$this->spot('D3', $south),
]);
self::assertCount(2, $groups);
self::assertSame($north, $groups[0]->group);
self::assertCount(2, $groups[0]->spots);
self::assertSame($south, $groups[1]->group);
self::assertCount(1, $groups[1]->spots);
}
/**
* The repository orders by group position, so the order spots arrive in is already the order
* they should be drawn in -- grouping must not reshuffle it.
*/
public function testTheOrderSpotsArriveInIsKept(): void
{
$first = $this->room('Erster Raum');
$second = $this->room('Zweiter Raum');
$groups = SpotGroup::over([$this->spot('D1', $second), $this->spot('D2', $first)]);
self::assertSame(['Zweiter Raum', 'Erster Raum'], array_map(
static fn (SpotGroup $group): string => $group->group?->getLabel() ?? '',
$groups,
));
}
/**
* Two unpersisted groups both have a null id, so grouping cannot key on it.
*/
public function testTwoUnsavedRoomsDoNotCollapseIntoOne(): void
{
$groups = SpotGroup::over([$this->spot('D1', $this->room('A')), $this->spot('D2', $this->room('B'))]);
self::assertCount(2, $groups);
}
public function testUngroupedSpotsCollectIntoOneTrailingGroup(): void
{
$room = $this->room('Raum Nord');
$groups = SpotGroup::over([$this->spot('D1', null), $this->spot('D2', $room), $this->spot('D3', null)]);
self::assertCount(2, $groups);
self::assertSame($room, $groups[0]->group);
self::assertNull($groups[1]->group);
self::assertCount(2, $groups[1]->spots);
}
public function testAPlanWithNoGroupsAtAllIsOneNullGroup(): void
{
$groups = SpotGroup::over([$this->spot('P1', null), $this->spot('P2', null)]);
self::assertCount(1, $groups);
self::assertNull($groups[0]->group);
}
public function testNoSpotsMeansNoGroups(): void
{
self::assertSame([], SpotGroup::over([]));
}
/**
* FREE only, deliberately: a partly booked desk is already amber on the plan, and counting
* it here would make the badge disagree with the colours beside it.
*/
public function testOnlyFullyFreeSpotsAreCounted(): void
{
$room = $this->room('Raum Nord');
$group = SpotGroup::over([
$this->spot('D1', $room),
$this->spot('D2', $room, [$this->booking(540, 780)]), // PARTLY
$this->spot('D3', $room, [$this->booking(0, 1440)]), // TAKEN
])[0];
self::assertCount(3, $group->spots);
self::assertSame(1, $group->freeCount());
}
/**
* @param list<Booking> $bookings
*/
private function spot(string $label, ?ResourceGroup $group, array $bookings = []): Spot
{
$resource = new Resource(ResourceType::DESK, $label);
$resource->setGroup($group);
return Spot::for($resource, $bookings, TimeRange::wholeDay(), $this->viewer());
}
private function booking(int $start, int $end): Booking
{
return new Booking(
new UserWithId('[email protected]', 'Bea', 2),
new Resource(ResourceType::DESK, 'X'),
new \DateTimeImmutable('2026-10-01'),
TimeRange::fromMinutes($start, $end),
);
}
private function room(string $label): ResourceGroup
{
return new ResourceGroup(ResourceType::DESK, $label);
}
private function viewer(): User
{
return new UserWithId('[email protected]', 'Anna', 1);
}
}