"""code-to10 v6 A8 第二轮:audit_loop_driver 剩余子集缺口补测。 本文件补驱动相关测试子集(test_audit_loop_driver + test_v6_a8_audit_loop_driver_gaps + wiring + server_audit_loop) 覆盖率实测后仍缺的 59 行中可达的部分;不可达的两行单列 在文件尾注释与交回报告里,不写成通过: - validate_ledger_event:792:changed 非空时 (added or changed) 恒真,该错误分支逻辑上不可达。 - apply_correction:1393:original/corrected 经映射后恒为 pass/fail,该校验分支逻辑上不可达。 只加测试,不改生产代码;依赖缺失用 sys.modules 注入 ImportError 模拟(不 mock 被测函数本身)。 """ import sys import unittest from contextlib import contextmanager from pathlib import Path try: import cloud.audit_loop_driver as driver from cloud.audit_loop_driver import ( _check_first_gate, _map_conditional, _root_cause_signals, _triage_third_failure, after_fix, apply_correction, confirm_rebuild, decide_audit, emit, new_loop_state, validate_ledger_event, ) except ImportError: # discover -s cloud/tests 时把项目根目录补进 sys.path sys.path.insert(0, str(Path(__file__).resolve().parents[2])) import cloud.audit_loop_driver as driver from cloud.audit_loop_driver import ( _check_first_gate, _map_conditional, _root_cause_signals, _triage_third_failure, after_fix, apply_correction, confirm_rebuild, decide_audit, emit, new_loop_state, validate_ledger_event, ) @contextmanager def _missing_pushback_module(): """让 audit_pushback 的 import 在函数内抛 ImportError, 走本地镜像回落分支;用完恢复原模块对象。""" key = "cloud.audit_pushback" had = key in sys.modules old = sys.modules.get(key) sys.modules[key] = None try: yield finally: if had: sys.modules[key] = old else: sys.modules.pop(key, None) def _fail_verdict(**overrides): verdict = { "source": "audit", "verdict": "fail", "verdict_text": "audit fail", "failures": [{"check": "ci_green", "detail": "ci red"}], "passed_items": [], } verdict.update(overrides) return verdict def _pass_verdict(**overrides): verdict = { "source": "audit", "verdict": "pass", "verdict_text": "audit pass", "failures": [], "passed_items": [], } verdict.update(overrides) return verdict class FirstGateAcceptanceTestCase(unittest.TestCase): def test_missing_test_and_missing_and_failed_acceptance(self): gate = _check_first_gate( ["t1", "t2"], [{"id": "a1"}, "a2"], {"t1": True}, {"a1": False}) self.assertFalse(gate["gate_pass"]) self.assertEqual(gate["missing"], ["test:t2", "acceptance:a2"]) self.assertEqual(gate["failed"], ["acceptance:a1"]) class DependencyFallbackTestCase(unittest.TestCase): def test_validate_test_changes_falls_back_to_local(self): with _missing_pushback_module(): violations = driver._validate_test_changes( [{"action": "delete", "test_id": "t1"}], False, []) self.assertEqual(len(violations), 2) def test_classify_root_cause_falls_back_to_local(self): rounds = [[{"root_cause": "contract"}], [{"root_cause": "contract"}]] with _missing_pushback_module(): self.assertEqual(driver._classify_root_cause(rounds), "contract") class RootCauseSignalsTestCase(unittest.TestCase): def test_classified_contract_rounds_signal(self): rounds = [[{"root_cause": "contract"}], [{"root_cause": "contract"}]] contract, impl = _root_cause_signals(_fail_verdict(), [], rounds) self.assertTrue(contract) self.assertFalse(impl) def test_structural_kind_and_core_touch_signal(self): failures = [{"check": "x", "structural_kind": "tech_stack"}, {"check": "y", "touches_core_structure": True}] contract, impl = _root_cause_signals(_fail_verdict(), failures, []) self.assertFalse(contract) self.assertTrue(impl) def test_repeated_clause_in_two_rounds_signals_contract(self): failures = [{"check": "x", "root_cause": "contract", "evidence": {"contract_clause": "C1"}}] rounds = [[{"evidence": {"contract_clause": "C1"}}], [{"evidence": {"contract_clause": "C1"}}]] contract, impl = _root_cause_signals(_fail_verdict(), failures, rounds) self.assertTrue(contract) class TriageCapReasonTestCase(unittest.TestCase): def test_too_many_failures_lists_cap_reason(self): state = new_loop_state("m1", "v1") failures = [{"check": "f%d" % i} for i in range(5)] triage = _triage_third_failure( state, _fail_verdict(broken_passed_items=None), failures, [{"check": "p1"}], []) self.assertEqual(triage["verdict"], "normal_pushback") self.assertTrue(any("exceeds near-complete cap" in r for r in triage["reasons"])) class LedgerValidationBranchesTestCase(unittest.TestCase): def test_non_dict_payload(self): self.assertEqual(validate_ledger_event("audit_verdict", "x"), ["ledger payload must be a dict"]) def test_enum_violation(self): errors = validate_ledger_event("audit_verdict", { "module_id": "m1", "contract_version": "v1", "verdict": "bogus", "source": "audit", "failures": []}) self.assertTrue(any("invalid verdict" in e for e in errors)) def test_rebuild_no_below_one(self): errors = validate_ledger_event("audit_rebuild", { "module_id": "m1", "contract_version": "v1", "rebuild_no": 0, "root_cause": "implementation", "status": "decided", "retained_assets": {}}) self.assertIn("rebuild_no must be >= 1", errors) def test_test_change_names_nothing(self): errors = validate_ledger_event("audit_test_change", { "module_id": "m1", "contract_version": "v1", "test_changes": {"added": [], "modified": [], "deleted": []}, "auditor": "a", "contract_refrozen": False, "reason": "none"}) self.assertIn("test_changes must name at least one change", errors) def test_refreeze_without_ref(self): errors = validate_ledger_event("audit_test_change", { "module_id": "m1", "contract_version": "v1", "test_changes": {"added": ["t9"], "modified": [], "deleted": []}, "auditor": "a", "contract_refrozen": True, "reason": "ok"}) self.assertIn("refreeze_ref required when contract_refrozen", errors) def test_meta_review_misjudgment_pairing(self): base = {"original_entry_id": "e1", "original_verdict": "fail", "reviewer": "b", "findings": [], "triggered_process": "re-review"} errors = validate_ledger_event("audit_meta_review", dict( base, misjudgment_found=True, corrected_verdict=None)) self.assertIn("corrected_verdict required when misjudgment_found", errors) errors = validate_ledger_event("audit_meta_review", dict( base, misjudgment_found=False, corrected_verdict="pass")) self.assertIn("corrected_verdict must be None without a misjudgment", errors) def test_rebuild_notice_empty_content(self): errors = validate_ledger_event("audit_rebuild_notice", { "module_id": "m1", "contract_version": "v1", "rebuild_no": 1, "notification_content": "", "notified_party": "user", "confirmation_status": "pending"}) self.assertIn("notification_content must be non-empty", errors) class ConditionalReviewAndSinkTestCase(unittest.TestCase): def test_re_review_result_mapped_to_fail(self): mapped = _map_conditional({ "verdict": "pass", "re_review_result": {"verdict": "conditional", "note": "x"}, }) self.assertEqual(mapped["re_review_result"]["verdict"], "fail") self.assertEqual( mapped["re_review_result"]["original_verdict"], "conditional") def test_emit_calls_sink(self): seen = [] event = emit("audit_verdict", { "module_id": "m1", "contract_version": "v1", "verdict": "pass", "source": "audit", "failures": []}, sink=seen.append) self.assertEqual(seen, [event]) class DecideAuditGuardsTestCase(unittest.TestCase): def test_non_loop_state_and_non_dict_verdict(self): with self.assertRaises(TypeError): decide_audit("not-a-state", _pass_verdict()) with self.assertRaises(TypeError): decide_audit(new_loop_state("m1", "v1"), "not-a-dict") def test_unknown_source(self): with self.assertRaises(ValueError): decide_audit(new_loop_state("m1", "v1"), _fail_verdict(source="mystery")) def test_qa_failed_links_not_rerun_adds_failure(self): state = new_loop_state("m1", "v1") action = decide_audit(state, _fail_verdict( qa_failed_links=["https://example.invalid/broken"], qa_links_rerun_passed=False)) checks = [f.get("check") for f in action.pushback_package["failures"]] self.assertIn("qa_failed_links_rerun", checks) def test_pass_with_version_change_resets(self): state = new_loop_state("m1", "v1") for _ in range(2): state = decide_audit(state, _fail_verdict()).next_state action = decide_audit(state, _pass_verdict(contract_version="v2")) self.assertEqual(action.kind, "pass") self.assertEqual(action.next_state.contract_version, "v2") self.assertEqual(action.next_state.failure_count, 0) def test_rebuilding_gate_bool_form(self): state = new_loop_state("m1", "v1") for _ in range(3): state = decide_audit(state, _fail_verdict()).next_state rebuilding = decide_audit( state, _fail_verdict(retained_tests=["t1"])).next_state self.assertEqual(rebuilding.status, "rebuilding") action = decide_audit(rebuilding, _pass_verdict( retained_tests_passed=True)) self.assertEqual(action.kind, "pass") # bool 门表单为 False 时门失败,pass 被门失败项挡下。 action = decide_audit(rebuilding, _pass_verdict( retained_tests_passed=False)) self.assertEqual(action.kind, "pushback") checks = [f.get("check") for f in action.pushback_package["failures"]] self.assertIn("rebuild_first_gate", checks) def test_fourth_failure_with_contract_signal_refreezes(self): state = new_loop_state("m1", "v1") for _ in range(3): state = decide_audit(state, _fail_verdict()).next_state action = decide_audit(state, _fail_verdict( root_cause_hint="contract")) self.assertEqual(action.kind, "refreeze") class AfterFixAndCorrectionGuardsTestCase(unittest.TestCase): def test_after_fix_non_dict_and_non_dict_reaudit(self): state = new_loop_state("m1", "v1") with self.assertRaises(TypeError): after_fix(state, "not-a-dict") with self.assertRaises(TypeError): after_fix(state, {"reaudit_verdict": 123}) def test_correction_non_dict(self): with self.assertRaises(TypeError): apply_correction(new_loop_state("m1", "v1"), "not-a-dict") def test_correction_same_verdict_rejected(self): with self.assertRaises(ValueError): apply_correction(new_loop_state("m1", "v1"), { "original_verdict": "fail", "corrected_verdict": "fail", "reviewer": "b", "original_entry_id": "e1", "reason": "same"}) def test_correction_without_reviewer(self): with self.assertRaises(ValueError): apply_correction(new_loop_state("m1", "v1"), { "original_verdict": "fail", "corrected_verdict": "pass", "original_entry_id": "e1", "reason": "no reviewer"}) def test_correction_unknown_source(self): with self.assertRaises(ValueError): apply_correction(new_loop_state("m1", "v1"), { "original_verdict": "fail", "corrected_verdict": "pass", "reviewer": "b", "original_entry_id": "e1", "reason": "x", "source": "mystery"}) class ConfirmRebuildBranchesTestCase(unittest.TestCase): def _pending_state(self): state = new_loop_state("m1", "v1") for _ in range(3): state = decide_audit( state, _fail_verdict(source="acceptance")).next_state action = decide_audit(state, _fail_verdict(source="acceptance")) self.assertEqual(action.kind, "pending_user_confirmation") return action.next_state def test_confirm_non_loop_state(self): with self.assertRaises(TypeError): confirm_rebuild("not-a-state", user_confirmed=True) def test_confirm_quota_blocked_keeps_pending(self): pending = self._pending_state() action = confirm_rebuild(pending, user_confirmed=True, quota_check=lambda estimate: False) self.assertEqual(action.kind, "quota_blocked") self.assertIs(action.next_state, pending) self.assertTrue(action.next_state.pending_confirmation) def test_confirm_budget_exhausted_escalates(self): pending = self._pending_state() pending.rebuild_no = 1 # MAX_REBUILDS_PER_CONTRACT_VERSION action = confirm_rebuild(pending, user_confirmed=True) self.assertEqual(action.kind, "escalate") self.assertEqual(action.escalation_target, "coordinator") self.assertEqual(action.next_state.rebuild_no, 1) def test_confirm_cost_threshold_escalates_to_user(self): pending = self._pending_state() action = confirm_rebuild(pending, user_confirmed=True, cost_threshold=100, cost_estimate=500) self.assertEqual(action.kind, "escalate") self.assertEqual(action.escalation_target, "user") self.assertEqual(action.cost_estimate, 500) if __name__ == "__main__": unittest.main()