11, 'option_ids' => [101, 102], 'correct_option_id' => 102], ['question_id' => 12, 'option_ids' => [201, 202], 'correct_option_id' => 201], ['question_id' => 13, 'option_ids' => [301, 302], 'correct_option_id' => 302], ]; $checks = 0; function expectGrade(array $ids, array $key, array $answers, ?int $expected): void { global $checks; try { $actual = RemediationAttemptGrader::grade($ids, $key, $answers); if ($expected === null || $actual !== $expected) throw new RuntimeException('Unexpected grade'); } catch (InvalidArgumentException $e) { if ($expected !== null) throw $e; } $checks++; } expectGrade($ids, $key, [102, 201, 302], 3); expectGrade($ids, $key, [102, 202, 302], 2); expectGrade($ids, $key, [101, 202, 301], 0); expectGrade($ids, $key, [102, 201], null); expectGrade($ids, $key, [102, 201, 999], null); expectGrade($ids, $key, [102, 102, 302], null); expectGrade($ids, $key, ['102', 201, 302], null); expectGrade($ids, array_reverse($key), [102, 201, 302], null); expectGrade([11, 11, 13], $key, [102, 201, 302], null); echo "PASS {$checks} remediation grading cases\n";