Option C Tools
Loading...
Searching...
No Matches
test_rule_registry.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3# tests/tests_linter/test_rule_registry.py
4
5"""
6Purpose
7-------
8FS-509 regression coverage for the lint rule registry and ``--explain`` flag.
9
10Responsibilities
11----------------
12- Validate that every rule in ``_DEFAULT_RULES`` has a ``RuleInfo`` entry.
13- Validate ``get_rule_info()`` and ``list_rules()`` API surface.
14- Validate that ``--explain`` produces human-readable and JSON output.
15- Validate that ``--explain`` for an unknown rule returns exit code 1.
16
17Diagnostics
18-----------
19Domain: LINTER-TESTS
20 Levels:
21 L2 — test lifecycle
22 L3 — assertion details
23 L4 — deep tracing
24
25Contracts
26---------
27- Tests are read-only introspection of the rule registry; no files
28 are written.
29"""
30
31from __future__ import annotations
32
33import json
34
35import pytest
36
37from oct.linter.rule_registry import (
38 RULE_REGISTRY,
39 RuleInfo,
40 get_rule_info,
41 list_rules,
42)
43from oct.linter.oct_lint import _DEFAULT_RULES, run_linter
44
45
46# -------------------------------------------------------------------
47# Registry completeness
48# -------------------------------------------------------------------
49
51
53 for rule_name in _DEFAULT_RULES:
54 assert rule_name in RULE_REGISTRY, (
55 f"Rule '{rule_name}' is in _DEFAULT_RULES but missing from RULE_REGISTRY"
56 )
57
59 for rule_name in RULE_REGISTRY:
60 assert rule_name in _DEFAULT_RULES, (
61 f"Rule '{rule_name}' is in RULE_REGISTRY but missing from _DEFAULT_RULES"
62 )
63
65 rules = list_rules()
66 assert len(rules) == len(_DEFAULT_RULES)
67
69 for rule in list_rules():
70 assert isinstance(rule, RuleInfo)
71
72
73# -------------------------------------------------------------------
74# Lookup API
75# -------------------------------------------------------------------
76
78
80 info = get_rule_info("header")
81 assert info is not None
82 assert info.name == "header"
83
85 assert get_rule_info("nonexistent_rule") is None
86
88 for name in _DEFAULT_RULES:
89 info = get_rule_info(name)
90 assert info is not None
91 assert info.name == name
92
93
94# -------------------------------------------------------------------
95# RuleInfo field validation
96# -------------------------------------------------------------------
97
99
100 @pytest.mark.parametrize("rule_name", list(_DEFAULT_RULES.keys()))
101 def test_all_string_fields_non_empty(self, rule_name: str):
102 info = RULE_REGISTRY[rule_name]
103 assert info.label, f"{rule_name}: label is empty"
104 assert info.rationale, f"{rule_name}: rationale is empty"
105 assert info.correct_pattern, f"{rule_name}: correct_pattern is empty"
106 assert info.common_mistake, f"{rule_name}: common_mistake is empty"
107 assert info.spec_reference, f"{rule_name}: spec_reference is empty"
108
109 @pytest.mark.parametrize("rule_name", list(_DEFAULT_RULES.keys()))
110 def test_profiles_non_empty(self, rule_name: str):
111 info = RULE_REGISTRY[rule_name]
112 assert len(info.profiles) >= 1, f"{rule_name}: profiles is empty"
113
115 info = get_rule_info("header")
116 assert info is not None
117 assert info.fixable is True
118
120 for name in ("docstring", "dbg_usage", "tests_exist"):
121 info = get_rule_info(name)
122 assert info is not None
123 assert info.fixable is False
124
125
126# -------------------------------------------------------------------
127# --explain integration (via run_linter)
128# -------------------------------------------------------------------
129
131
132 def test_explain_known_rule_returns_zero(self, tmp_path, capsys):
133 result = run_linter(tmp_path, ["--explain", "header"])
134 assert result == 0
135 captured = capsys.readouterr()
136 assert "Rule: header" in captured.out
137 assert "Rationale:" in captured.out
138 assert "Correct pattern:" in captured.out
139 assert "Common mistake:" in captured.out
140
141 def test_explain_json_output(self, tmp_path, capsys):
142 result = run_linter(tmp_path, ["--explain", "header", "--json"])
143 assert result == 0
144 captured = capsys.readouterr()
145 data = json.loads(captured.out)
146 assert data["name"] == "header"
147 assert "rationale" in data
148 assert "correct_pattern" in data
149 assert "common_mistake" in data
150 assert "spec_reference" in data
151 assert "fixable" in data
152 assert "profiles" in data
153
154 def test_explain_unknown_rule_returns_one(self, tmp_path, capsys):
155 result = run_linter(tmp_path, ["--explain", "nonexistent"])
156 assert result == 1
157 captured = capsys.readouterr()
158 assert "unknown rule" in captured.err
159
160 def test_explain_unknown_rule_lists_available(self, tmp_path, capsys):
161 run_linter(tmp_path, ["--explain", "nonexistent"])
162 captured = capsys.readouterr()
163 assert "Available rules:" in captured.err
164 assert "header" in captured.err
test_explain_unknown_rule_lists_available(self, tmp_path, capsys)