Files
SIRH/tests/State/AbsencePrintProviderTest.php
tristan e56539f40c fix(calendar) : date-only contract filter + eager-load periods for print
Review follow-ups: (1) createFromFormat('Y-m-d') keeps the current time, so a raw
DateTime comparison wrongly excluded an employee ending on the from-day (and dropped
first-day absences); normalize from/to to day bounds and compare contract periods on
date only (Y-m-d), mirroring the calendar view. (2) eager-load contractPeriods in
findForPrintBySiteIds to avoid an N+1 during filtering. Added a boundary test.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 08:35:23 +02:00

100 lines
3.9 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Tests\State;
use App\Entity\Employee;
use App\Entity\EmployeeContractPeriod;
use App\State\AbsencePrintProvider;
use DateTimeImmutable;
use PHPUnit\Framework\TestCase;
use ReflectionClass;
/**
* The provider constructor takes final-class collaborators (Twig, repositories) that
* PHPUnit cannot double. The pure contract-range helper is exercised via
* newInstanceWithoutConstructor + reflection.
*
* @internal
*/
final class AbsencePrintProviderTest extends TestCase
{
public function testHasContractInRangeFalseWhenContractEndedBeforeRange(): void
{
$provider = new ReflectionClass(AbsencePrintProvider::class)->newInstanceWithoutConstructor();
$employee = $this->buildEmployeeWithPeriod('2025-01-01', '2026-04-30');
// Imprime mai : l'employé parti le 30/04 ne doit pas être inclus.
self::assertFalse($this->hasInRange($provider, $employee, '2026-05-01', '2026-05-31'));
}
public function testHasContractInRangeTrueWhenContractOverlapsRange(): void
{
$provider = new ReflectionClass(AbsencePrintProvider::class)->newInstanceWithoutConstructor();
$employee = $this->buildEmployeeWithPeriod('2025-01-01', '2026-05-15');
// Contrat finissant le 15/05 → chevauche le mois de mai → inclus.
self::assertTrue($this->hasInRange($provider, $employee, '2026-05-01', '2026-05-31'));
}
public function testHasContractInRangeTrueForOpenEndedContract(): void
{
$provider = new ReflectionClass(AbsencePrintProvider::class)->newInstanceWithoutConstructor();
$employee = $this->buildEmployeeWithPeriod('2020-01-01', null);
self::assertTrue($this->hasInRange($provider, $employee, '2026-05-01', '2026-05-31'));
}
public function testHasContractInRangeFalseWhenContractStartsAfterRange(): void
{
$provider = new ReflectionClass(AbsencePrintProvider::class)->newInstanceWithoutConstructor();
$employee = $this->buildEmployeeWithPeriod('2026-06-01', null);
self::assertFalse($this->hasInRange($provider, $employee, '2026-05-01', '2026-05-31'));
}
public function testHasContractInRangeFalseWhenNoPeriods(): void
{
$provider = new ReflectionClass(AbsencePrintProvider::class)->newInstanceWithoutConstructor();
$employee = new Employee();
self::assertFalse($this->hasInRange($provider, $employee, '2026-05-01', '2026-05-31'));
}
public function testHasContractInRangeIncludesEmployeeEndingOnFromDayDespiteTimeComponent(): void
{
// Garde-fou : `from` portant une heure (cf. createFromFormat) ne doit pas exclure
// un employé dont le contrat finit pile le jour de `from` (comparaison date seule).
$provider = new ReflectionClass(AbsencePrintProvider::class)->newInstanceWithoutConstructor();
$employee = $this->buildEmployeeWithPeriod('2025-01-01', '2026-05-01');
$result = new ReflectionClass($provider::class)
->getMethod('hasContractInRange')
->invoke($provider, $employee, new DateTimeImmutable('2026-05-01 08:33:53'), new DateTimeImmutable('2026-05-31 23:59:59'))
;
self::assertTrue($result);
}
private function hasInRange(object $provider, Employee $employee, string $from, string $to): bool
{
return new ReflectionClass($provider::class)
->getMethod('hasContractInRange')
->invoke($provider, $employee, new DateTimeImmutable($from), new DateTimeImmutable($to))
;
}
private function buildEmployeeWithPeriod(string $start, ?string $end): Employee
{
$employee = new Employee();
$period = new EmployeeContractPeriod();
$period->setEmployee($employee);
$period->setStartDate(new DateTimeImmutable($start));
$period->setEndDate(null !== $end ? new DateTimeImmutable($end) : null);
$employee->getContractPeriods()->add($period);
return $employee;
}
}