buildConge('2026-01-05'), $this->buildConge('2026-01-06'), $this->buildConge('2026-01-07'), ]; $result = $this->split($conges, 2.5, '2026-01-01', '2026-01-31'); self::assertSame(2.5, $result['n1PresenceDays']); self::assertSame(0.5, $result['count']); self::assertSame('07/01', $result['dates']); } public function testN1BudgetConsumedInPriorMonthLeavesCurrentMonthFullyDisplayed(): void { // Budget 1 j, consommé par le congé de janvier. Récap de février → le congé de février // est entièrement imputé N (affiché, 0 présence N-1 dans le mois). $conges = [ $this->buildConge('2026-01-12'), $this->buildConge('2026-02-09'), ]; $result = $this->split($conges, 1.0, '2026-02-01', '2026-02-28'); self::assertSame(0.0, $result['n1PresenceDays']); self::assertSame(1.0, $result['count']); self::assertSame('09/02', $result['dates']); } public function testZeroBudgetDisplaysAllCongesInMonth(): void { $conges = [$this->buildConge('2026-03-03')]; $result = $this->split($conges, 0.0, '2026-03-01', '2026-03-31'); self::assertSame(0.0, $result['n1PresenceDays']); self::assertSame(1.0, $result['count']); self::assertSame('03/03', $result['dates']); } /** * @param list $conges * * @return array{count: float, dates: string, n1PresenceDays: float} */ private function split(array $conges, float $budget, string $from, string $to): array { $provider = new ReflectionClass(SalaryRecapPrintProvider::class)->newInstanceWithoutConstructor(); new ReflectionProperty(SalaryRecapPrintProvider::class, 'absenceSegmentsResolver') ->setValue($provider, new AbsenceSegmentsResolver()); return new ReflectionClass($provider::class) ->getMethod('splitForfaitCongesByN1') ->invoke($provider, $conges, $budget, new DateTimeImmutable($from), new DateTimeImmutable($to)); } private function buildConge(string $date): Absence { return new Absence() ->setStartDate(new DateTime($date)) ->setEndDate(new DateTime($date)) ->setStartHalf(HalfDay::AM) ->setEndHalf(HalfDay::PM) ; } }