1, 'class_section_id' => 10, 'class_section_name' => '1-A', 'gender' => 'Male', 'fall_score' => 80, 'spring_score' => 100], ['student_id' => 2, 'class_section_id' => 10, 'class_section_name' => '1-A', 'gender' => 'female', 'fall_score' => 55, 'spring_score' => null], ['student_id' => 3, 'class_section_id' => 20, 'class_section_name' => '2-A', 'gender' => 'girl', 'fall_score' => null, 'spring_score' => null], ], '2025-2026'); $this->assertSame(3, $stats['totalStudents']); $this->assertSame(2, $stats['totalClasses']); $this->assertSame(2, $stats['scoredStudents']); $this->assertSame(72.5, $stats['averageScore']); $this->assertSame(50.0, $stats['passRate']); $this->assertSame(1, $stats['topPerformers']); $this->assertSame(['Pass' => 1, 'Fail' => 1, 'Awaiting results' => 1], $stats['results']); $this->assertSame(['Male' => 1, 'Female' => 2], $stats['gender']); $this->assertSame([ 'labels' => ['1-A', '2-A'], 'values' => [2, 1], 'male' => [1, 0], 'female' => [1, 1], ], $stats['classSizes']); $this->assertSame([ 'Passed' => ['Male' => 1, 'Female' => 0], 'Failed' => ['Male' => 0, 'Female' => 1], 'Top performers' => ['Male' => 1, 'Female' => 0], 'Trophy winners' => ['Male' => 1, 'Female' => 1], ], $stats['genderByStat']); $this->assertSame(2, $stats['trophyWinners']); $this->assertSame(['Male' => 1, 'Female' => 1], $stats['trophyGender']); } public function testAveragesMultipleClassScoresOncePerStudent(): void { $stats = AcademicStatisticsService::summarize([ ['student_id' => 9, 'class_section_id' => 1, 'class_section_name' => 'Quran', 'gender' => 'M', 'fall_score' => 100, 'spring_score' => 100], ['student_id' => 9, 'class_section_id' => 2, 'class_section_name' => 'Arabic', 'gender' => 'M', 'fall_score' => 80, 'spring_score' => 80], ]); $this->assertSame(1, $stats['totalStudents']); $this->assertSame(2, $stats['totalClasses']); $this->assertSame(90.0, $stats['averageScore']); $this->assertSame(1, $stats['topPerformers']); } public function testKgStudentsPassWithoutSemesterScores(): void { $stats = AcademicStatisticsService::summarize([ ['student_id' => 21, 'class_section_id' => 3, 'class_section_name' => 'KG-A', 'gender' => 'Male', 'fall_score' => null, 'spring_score' => null], ['student_id' => 22, 'class_section_id' => 4, 'class_section_name' => '1-A', 'gender' => 'Female', 'fall_score' => null, 'spring_score' => null], ]); $this->assertSame(['Pass' => 1, 'Fail' => 0, 'Awaiting results' => 1], $stats['results']); $this->assertSame(100.0, $stats['passRate']); $this->assertSame(1, $stats['scoreBands']['KG – Passed']); $this->assertSame(['Male' => 1, 'Female' => 0], $stats['genderByStat']['Passed']); } public function testTrophyWinnersUseClassThresholdAndAreDistributedByGender(): void { $stats = AcademicStatisticsService::summarize([ ['student_id' => 31, 'class_section_id' => 8, 'class_section_name' => '4-A', 'gender' => 'Male', 'fall_score' => 100, 'spring_score' => 100], ['student_id' => 32, 'class_section_id' => 8, 'class_section_name' => '4-A', 'gender' => 'Female', 'fall_score' => 90, 'spring_score' => 90], ['student_id' => 33, 'class_section_id' => 8, 'class_section_name' => '4-A', 'gender' => 'boy', 'fall_score' => 80, 'spring_score' => 80], ['student_id' => 34, 'class_section_id' => 8, 'class_section_name' => '4-A', 'gender' => 'girl', 'fall_score' => 70, 'spring_score' => 70], ]); $this->assertSame(3, $stats['trophyWinners']); $this->assertSame(['Male' => 2, 'Female' => 1], $stats['trophyGender']); $this->assertSame(['Male' => 2, 'Female' => 1], $stats['genderByStat']['Trophy winners']); } }