"""规则校验器测试(第一道防线).""" import json from src.ai.services.evaluation.rule_validator import ( MAX_QUESTION_LENGTH, RuleValidator, ValidationResult, ) class TestRuleValidator: """RuleValidator 测试.""" def setup_method(self) -> None: self.validator = RuleValidator() def test_valid_json_passes(self) -> None: """合法 JSON 通过.""" output = json.dumps({ "question": "什么是勾股定理?", "answer": "a² + b² = c²", "explanation": "直角三角形两直角边的平方和等于斜边的平方", }) result = self.validator.validate(output) assert result.passed is True assert result.score == 1.0 assert result.parsed is not None def test_invalid_json_fails(self) -> None: """非 JSON 失败.""" result = self.validator.validate("这不是 JSON") assert result.passed is False assert "不是有效的 JSON" in result.errors[0] def test_markdown_wrapped_json(self) -> None: """markdown 代码块包裹的 JSON 能解析.""" output = '```json\n{"question": "题", "answer": "答"}\n```' result = self.validator.validate(output) assert result.passed is True def test_missing_question_fails(self) -> None: """缺少 question 字段失败.""" output = json.dumps({"answer": "答"}) result = self.validator.validate(output) assert result.passed is False assert any("question" in e for e in result.errors) def test_missing_answer_fails(self) -> None: """缺少 answer 字段失败.""" output = json.dumps({"question": "题"}) result = self.validator.validate(output) assert result.passed is False assert any("answer" in e for e in result.errors) def test_short_question_warning(self) -> None: """过短 question 产生 warning.""" output = json.dumps({"question": "ab", "answer": "答"}) result = self.validator.validate(output) assert result.passed is True assert any("过短" in w for w in result.warnings) assert result.score == 0.8 # 有 warning def test_difficulty_mismatch_warning(self) -> None: """难度不匹配产生 warning.""" output = json.dumps({ "question": "这是一道题目", "answer": "这是答案", "difficulty": "easy", }) result = self.validator.validate(output, expected_difficulty="hard") assert result.passed is True assert any("difficulty 不匹配" in w for w in result.warnings) def test_invalid_difficulty_warning(self) -> None: """无效难度值产生 warning.""" output = json.dumps({ "question": "这是一道题目", "answer": "这是答案", "difficulty": "impossible", }) result = self.validator.validate(output, expected_difficulty="easy") assert result.passed is True assert any("无效" in w for w in result.warnings) def test_question_type_mismatch_warning(self) -> None: """题型不匹配产生 warning.""" output = json.dumps({ "question": "这是一道题目", "answer": "这是答案", "question_type": "single_choice", }) result = self.validator.validate( output, expected_question_type="essay", ) assert result.passed is True assert any("question_type 不匹配" in w for w in result.warnings) def test_json_array_fails(self) -> None: """JSON 数组(非 dict)失败.""" result = self.validator.validate('[1, 2, 3]') assert result.passed is False def test_long_question_warning(self) -> None: """过长 question 产生 warning.""" output = json.dumps({ "question": "题" * (MAX_QUESTION_LENGTH + 1), "answer": "答", }) result = self.validator.validate(output) assert result.passed is True assert any("过长" in w for w in result.warnings) def test_score_no_warnings(self) -> None: """无 warning 时 score=1.0.""" output = json.dumps({ "question": "这是一道完整的题目", "answer": "这是完整的答案", }) result = self.validator.validate(output) assert result.score == 1.0 def test_validation_result_score_failed(self) -> None: """失败时 score=0.0.""" result = ValidationResult(passed=False, errors=["err"]) assert result.score == 0.0