feat: all-season assignments
This commit is contained in:
1 parent
675cec1b69
commit
cf876ed224
119 files changed
+6194
-294
No files matched your search
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Validator;
|
||||
|
||||
use App\Config\SeasonCalendar;
|
||||
use App\Entity\SeasonAssignment;
|
||||
use App\Entity\Teamer;
|
||||
use App\Repository\SeasonAssignmentRepository;
|
||||
use App\Validator\Constraints\SeasonAssignment as SeasonAssignmentConstraint;
|
||||
use App\Validator\Constraints\SeasonAssignmentValidator;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use Symfony\Component\Validator\Test\ConstraintValidatorTestCase;
|
||||
|
||||
/**
|
||||
* "One season assignment per teamer per season" was a stated fact before this rule; what is
|
||||
* pinned here is which season window a given assignment is counted against, and the cases that
|
||||
* must not be refused - an unstaffed assignment, and the assignment being edited itself.
|
||||
*/
|
||||
class SeasonAssignmentValidatorTest extends ConstraintValidatorTestCase
|
||||
{
|
||||
private SeasonAssignmentRepository&MockObject $repository;
|
||||
|
||||
protected function createValidator(): SeasonAssignmentValidator
|
||||
{
|
||||
$this->repository = $this->createMock(SeasonAssignmentRepository::class);
|
||||
|
||||
return new SeasonAssignmentValidator($this->repository, new SeasonCalendar('11-01', '04-01'));
|
||||
}
|
||||
|
||||
public function testASecondAssignmentInTheSameSeasonIsRefused(): void
|
||||
{
|
||||
$this->repository->method('countInSeasonWindow')->willReturn(1);
|
||||
|
||||
$this->validator->validate($this->seasonAssignment('2026-12-20'), $this->constraint());
|
||||
|
||||
$this->buildViolation('Für diese:n Teamer:in existiert in dieser Saison bereits ein Saisoneinsatz')
|
||||
->assertRaised()
|
||||
;
|
||||
}
|
||||
|
||||
public function testTheFirstAssignmentOfASeasonPasses(): void
|
||||
{
|
||||
$this->repository->method('countInSeasonWindow')->willReturn(0);
|
||||
|
||||
$this->validator->validate($this->seasonAssignment('2026-12-20'), $this->constraint());
|
||||
|
||||
$this->assertNoViolation();
|
||||
}
|
||||
|
||||
public function testItCountsAgainstTheSeasonTheAssignmentStartsIn(): void
|
||||
{
|
||||
// 20.02.2027 belongs to the season that began on 01.11.2026, so the window asked for has
|
||||
// to be that one and not the calendar year the date happens to fall in
|
||||
$this->repository
|
||||
->expects($this->once())
|
||||
->method('countInSeasonWindow')
|
||||
->with(
|
||||
$this->isInstanceOf(Teamer::class),
|
||||
$this->callback(static fn (\DateTimeImmutable $start): bool => '2026-11-01' === $start->format('Y-m-d')),
|
||||
$this->callback(static fn (\DateTimeImmutable $end): bool => '2027-04-01' === $end->format('Y-m-d')),
|
||||
null
|
||||
)
|
||||
->willReturn(0)
|
||||
;
|
||||
|
||||
$this->validator->validate($this->seasonAssignment('2027-02-20'), $this->constraint());
|
||||
|
||||
$this->assertNoViolation();
|
||||
}
|
||||
|
||||
public function testEditingAnAssignmentDoesNotCountItAgainstItself(): void
|
||||
{
|
||||
$seasonAssignment = $this->seasonAssignment('2026-12-20');
|
||||
|
||||
// the id is never set by hand in the app; it is what tells the query to leave the row
|
||||
// being edited out, so an edit that changes nothing cannot refuse itself
|
||||
$id = new \ReflectionProperty(SeasonAssignment::class, 'id');
|
||||
$id->setValue($seasonAssignment, 42);
|
||||
|
||||
$this->repository
|
||||
->expects($this->once())
|
||||
->method('countInSeasonWindow')
|
||||
->with($this->anything(), $this->anything(), $this->anything(), 42)
|
||||
->willReturn(0)
|
||||
;
|
||||
|
||||
$this->validator->validate($seasonAssignment, $this->constraint());
|
||||
|
||||
$this->assertNoViolation();
|
||||
}
|
||||
|
||||
public function testAnAssignmentWithoutATeamerPasses(): void
|
||||
{
|
||||
$this->repository->expects($this->never())->method('countInSeasonWindow');
|
||||
|
||||
$seasonAssignment = $this->seasonAssignment('2026-12-20')->setTeamer(null);
|
||||
|
||||
$this->validator->validate($seasonAssignment, $this->constraint());
|
||||
|
||||
$this->assertNoViolation();
|
||||
}
|
||||
|
||||
public function testAnAssignmentOutsideAnySeasonWindowPasses(): void
|
||||
{
|
||||
$this->repository->expects($this->never())->method('countInSeasonWindow');
|
||||
|
||||
$this->validator->validate($this->seasonAssignment('2027-07-15'), $this->constraint());
|
||||
|
||||
$this->assertNoViolation();
|
||||
}
|
||||
|
||||
private function constraint(): SeasonAssignmentConstraint
|
||||
{
|
||||
return new SeasonAssignmentConstraint();
|
||||
}
|
||||
|
||||
private function seasonAssignment(string $dateFrom): SeasonAssignment
|
||||
{
|
||||
return (new SeasonAssignment())
|
||||
->setTeamer(new Teamer())
|
||||
->setDateFrom(new \DateTimeImmutable($dateFrom))
|
||||
->setDateTo(new \DateTimeImmutable($dateFrom.' +6 months'))
|
||||
->setHotelCode('AGR')
|
||||
;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user