setAccessible(true); $this->assertSame(5, $method->invoke($controller, '2019-09-15', '2025-2026')); $this->assertSame(5, $method->invoke($controller, '2020-01-01', '2025-2026')); $this->assertSame(4, $method->invoke($controller, '2020-09-02', '2025-2026')); } public function testEnrollmentAgeRejectsInvalidInputs(): void { $controller = new class extends ParentController { public function __construct() { } }; $method = new ReflectionMethod(ParentController::class, 'calculateAgeAsOfSchoolYearStartYear'); $method->setAccessible(true); $this->assertNull($method->invoke($controller, '', '2025-2026')); $this->assertNull($method->invoke($controller, 'not-a-date', '2025-2026')); $this->assertNull($method->invoke($controller, '2026-01-01', '2025-2026')); $this->assertNull($method->invoke($controller, '2019-09-15', '')); } public function testRegistrationValidationUsesDecemberThirtyFirstOnlyForMinimumAgeGrace(): void { $controller = new class extends ParentController { public function __construct() { } }; $this->assertTrue($controller->validateDobAge('2020-12-31', '2025-12-31', 5, 18, '2025-09-01')['isValid']); $this->assertFalse($controller->validateDobAge('2021-01-01', '2025-12-31', 5, 18, '2025-09-01')['isValid']); $this->assertTrue($controller->validateDobAge('2006-09-02', '2025-12-31', 5, 18, '2025-09-01')['isValid']); $this->assertFalse($controller->validateDobAge('2006-08-31', '2025-12-31', 5, 18, '2025-09-01')['isValid']); } public function testEnrollmentEligibilityBlocksFinalDecisionStatuses(): void { $controller = new class extends ParentController { public function __construct() { } }; $method = new ReflectionMethod(ParentController::class, 'enrollmentEligibilityMessageForStudent'); $method->setAccessible(true); foreach (['expel', 'withdrawn', 'deferred decision'] as $decision) { $message = $method->invoke( $controller, ['firstname' => 'Ali', 'lastname' => 'Ahmed', 'dob' => '2010-01-01'], ['decision' => $decision, 'source' => 'manual', 'class_section_name' => 'Level 5'], '2025-2026', null ); $this->assertTrue($message['blocking'], $decision . ' should block enrollment.'); $this->assertNotSame('', $message['message']); } } public function testEnrollmentEligibilityBlocksAdultStudentsOnSeptemberFirst(): void { $controller = new class extends ParentController { public function __construct() { } }; $method = new ReflectionMethod(ParentController::class, 'enrollmentEligibilityMessageForStudent'); $method->setAccessible(true); $message = $method->invoke( $controller, ['firstname' => 'Ali', 'lastname' => 'Ahmed', 'dob' => '2006-08-31'], ['decision' => 'pass', 'source' => 'manual', 'class_section_name' => 'Level 9'], '2025-2026', null ); $this->assertTrue($message['blocking']); $this->assertStringContainsString('18 years old or older on September 1', $message['message']); $this->assertStringContainsString('A parent or guardian cannot complete registration', $message['message']); } public function testEnrollmentEligibilityAllowsFallMakeupExamWithWarning(): void { $controller = new class extends ParentController { public function __construct() { } }; $method = new ReflectionMethod(ParentController::class, 'enrollmentEligibilityMessageForStudent'); $method->setAccessible(true); $message = $method->invoke( $controller, ['firstname' => 'Ali', 'lastname' => 'Ahmed', 'dob' => '2010-01-01'], ['decision' => 'Make Up Exam in Fall', 'source' => 'manual', 'class_section_name' => 'Level 5'], '2025-2026', '2025-09-10' ); $this->assertFalse($message['blocking']); $this->assertSame('warning', $message['level']); $this->assertStringContainsString('will initially remain in the same grade', $message['message']); } public function testRequiredActionDoesNotDefaultToContactAdministration(): void { $controller = new class extends ParentController { public function __construct() { } }; $method = new ReflectionMethod(ParentController::class, 'requiredActionLabel'); $method->setAccessible(true); $this->assertSame( 'Complete re-enrollment before the registration deadline.', $method->invoke($controller, null) ); $this->assertSame( 'Complete re-enrollment before the registration deadline.', $method->invoke($controller, [ 'blockers' => [], 'deliberation_decision' => DeliberationDecision::PASSED, 'parent_enrollment_allowed' => true, ]) ); $this->assertSame( 'Contact the school administration.', $method->invoke($controller, [ 'blockers' => ['Final decision is pending.'], 'deliberation_decision' => DeliberationDecision::DEFERRED_DECISION, 'parent_enrollment_allowed' => false, ]) ); } }