fix: adjust detection of overlapping applications
addresses #869ar02xk
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Repository;
|
||||
|
||||
use App\Entity\Application;
|
||||
use App\Entity\Assignment;
|
||||
use App\Entity\Teamer;
|
||||
use App\Repository\ApplicationRepository;
|
||||
use Carbon\CarbonPeriod;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Query;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||
|
||||
/**
|
||||
* The overlap query behind the automatic purge of applications is expressed in DQL, so its semantics
|
||||
* cannot be covered by mocking the query builder - doing so is what let a wrong comparison ship
|
||||
* unnoticed. These tests compile the query instead and pin the parts that carry the semantics.
|
||||
*/
|
||||
class ApplicationRepositoryTest extends KernelTestCase
|
||||
{
|
||||
public function testOverlappingQueryUsesInclusiveBoundariesAndEffectiveDates(): void
|
||||
{
|
||||
$dql = $this->createOverlappingQuery()->getDQL();
|
||||
|
||||
// an assignment overrides the date range of its destination, so both have to be considered
|
||||
$this->assertStringContainsString(
|
||||
'(assignment.dateFrom IS NULL AND destination.dateFrom <= :dateTo)'
|
||||
.' OR (assignment.dateFrom IS NOT NULL AND assignment.dateFrom <= :dateTo)',
|
||||
$dql
|
||||
);
|
||||
$this->assertStringContainsString(
|
||||
'(assignment.dateTo IS NULL AND destination.dateTo >= :dateFrom)'
|
||||
.' OR (assignment.dateTo IS NOT NULL AND assignment.dateTo >= :dateFrom)',
|
||||
$dql
|
||||
);
|
||||
|
||||
// strict comparisons would let assignments that touch on a boundary pass and could never
|
||||
// match a single day assignment at all
|
||||
$this->assertDoesNotMatchRegularExpression('/date(From|To) [<>] :date(From|To)/', $dql);
|
||||
}
|
||||
|
||||
public function testOverlappingQueryExcludesRejectedApplicationsAndDeadAssignments(): void
|
||||
{
|
||||
$dql = $this->createOverlappingQuery()->getDQL();
|
||||
|
||||
$this->assertStringContainsString('application.teamer = :teamer', $dql);
|
||||
$this->assertStringContainsString('application.status <> :application_rejected', $dql);
|
||||
$this->assertStringContainsString('assignment.status <> :assignment_called_off', $dql);
|
||||
$this->assertStringContainsString('assignment.deletedAt IS NULL', $dql);
|
||||
$this->assertStringContainsString('destination.deletedAt IS NULL', $dql);
|
||||
}
|
||||
|
||||
public function testOverlappingQueryBindsThePeriodBoundaries(): void
|
||||
{
|
||||
$teamer = new Teamer();
|
||||
$period = new CarbonPeriod('2025-01-10', '2025-01-20');
|
||||
|
||||
$query = $this->createOverlappingQuery($teamer, $period);
|
||||
|
||||
$this->assertSame($teamer, $query->getParameter('teamer')->getValue());
|
||||
$this->assertSame(Application::STATUS_REJECTED, $query->getParameter('application_rejected')->getValue());
|
||||
$this->assertSame(Assignment::STATUS_CALLED_OFF, $query->getParameter('assignment_called_off')->getValue());
|
||||
$this->assertSame('2025-01-10', $query->getParameter('dateFrom')->getValue()->format('Y-m-d'));
|
||||
$this->assertSame('2025-01-20', $query->getParameter('dateTo')->getValue()->format('Y-m-d'));
|
||||
}
|
||||
|
||||
private function createOverlappingQuery(?Teamer $teamer = null, ?CarbonPeriod $period = null): Query
|
||||
{
|
||||
/** @var EntityManagerInterface $entityManager */
|
||||
$entityManager = static::getContainer()->get(EntityManagerInterface::class);
|
||||
|
||||
/** @var ApplicationRepository $repository */
|
||||
$repository = $entityManager->getRepository(Application::class);
|
||||
|
||||
return $repository->getOverlappingForTeamerQuery(
|
||||
$teamer ?? new Teamer(),
|
||||
$period ?? new CarbonPeriod('2025-01-10', '2025-01-20')
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user