Coverage for tests / unit / utils / test_json_output.py: 100%
48 statements
« prev ^ index » next coverage.py v7.13.0, created at 2026-04-03 18:53 +0000
« prev ^ index » next coverage.py v7.13.0, created at 2026-04-03 18:53 +0000
1"""Tests for JSON output AI metadata serialization."""
3from __future__ import annotations
5from assertpy import assert_that
7from lintro.enums.action import Action
8from lintro.models.core.tool_result import ToolResult
9from lintro.utils.json_output import create_json_output
12def test_create_json_output_includes_summary_and_fix_suggestions_together() -> None:
13 """Verify JSON output includes both AI summary and fix suggestions."""
14 result = ToolResult(name="ruff", success=False, issues_count=1)
15 result.ai_metadata = {
16 "summary": {
17 "overview": "Summary text",
18 "key_patterns": [],
19 "priority_actions": [],
20 "triage_suggestions": [],
21 "estimated_effort": "10 minutes",
22 "input_tokens": 10,
23 "output_tokens": 5,
24 "cost_estimate": 0.001,
25 },
26 "fix_suggestions": [
27 {
28 "file": "src/main.py",
29 "line": 1,
30 "code": "B101",
31 "explanation": "Replace assert",
32 "confidence": "high",
33 "diff": "--- a/src/main.py",
34 "input_tokens": 5,
35 "output_tokens": 4,
36 "cost_estimate": 0.001,
37 },
38 ],
39 }
41 data = create_json_output(
42 action=Action.CHECK,
43 results=[result],
44 total_issues=1,
45 total_fixed=0,
46 total_remaining=0,
47 exit_code=1,
48 )
50 assert_that(data).contains_key("ai_summary")
51 assert_that(data["ai_summary"]["overview"]).is_equal_to("Summary text")
52 assert_that(data["results"][0]["ai_metadata"]).contains_key("summary")
53 assert_that(data["results"][0]["ai_metadata"]).contains_key(
54 "fix_suggestions",
55 )
58def test_create_json_output_normalizes_legacy_suggestions_key() -> None:
59 """Test that legacy suggestions key is normalized correctly."""
60 result = ToolResult(name="ruff", success=False, issues_count=1)
61 result.ai_metadata = {
62 "summary": {"overview": "Legacy"},
63 "suggestions": [{"file": "a.py", "line": 1}],
64 "type": "fix_suggestions",
65 }
67 data = create_json_output(
68 action=Action.CHECK,
69 results=[result],
70 total_issues=1,
71 total_fixed=0,
72 total_remaining=0,
73 exit_code=1,
74 )
76 assert_that(data["results"][0]["ai_metadata"]).contains_key(
77 "fix_suggestions",
78 )
79 assert_that(data["results"][0]["ai_metadata"]).does_not_contain_key(
80 "suggestions",
81 )
84def test_create_json_output_includes_ai_count_fields() -> None:
85 """Verify AI count fields are serialized into JSON output."""
86 result = ToolResult(name="ruff", success=False, issues_count=3)
87 result.ai_metadata = {
88 "fixed_count": 2,
89 "verified_count": 1,
90 "unverified_count": 1,
91 }
93 data = create_json_output(
94 action=Action.CHECK,
95 results=[result],
96 total_issues=3,
97 total_fixed=0,
98 total_remaining=0,
99 exit_code=1,
100 )
102 ai_meta = data["results"][0]["ai_metadata"]
103 assert_that(ai_meta["fixed_count"]).is_equal_to(2)
104 assert_that(ai_meta["applied_count"]).is_equal_to(2)
105 assert_that(ai_meta["verified_count"]).is_equal_to(1)
106 assert_that(ai_meta["unverified_count"]).is_equal_to(1)
109def test_create_json_output_includes_ai_metrics() -> None:
110 """Verify AI telemetry metrics are preserved through normalization."""
111 result = ToolResult(name="ruff", success=False, issues_count=1)
112 result.ai_metadata = {
113 "ai_metrics": {
114 "total_api_calls": 5,
115 "total_input_tokens": 1000,
116 "total_output_tokens": 500,
117 "total_cost_usd": 0.01,
118 },
119 }
121 data = create_json_output(
122 action=Action.CHECK,
123 results=[result],
124 total_issues=1,
125 total_fixed=0,
126 total_remaining=0,
127 exit_code=1,
128 )
130 ai_meta = data["results"][0]["ai_metadata"]
131 assert_that(ai_meta).contains_key("ai_metrics")
132 assert_that(ai_meta["ai_metrics"]["total_api_calls"]).is_equal_to(5)
133 assert_that(ai_meta["ai_metrics"]["total_cost_usd"]).is_equal_to(0.01)
136def test_create_json_output_counts_survive_legacy_normalization() -> None:
137 """Verify counts and metrics survive alongside legacy key normalization."""
138 result = ToolResult(name="ruff", success=False, issues_count=1)
139 result.ai_metadata = {
140 "summary": {"overview": "Legacy with counts"},
141 "suggestions": [{"file": "a.py", "line": 1}],
142 "type": "fix_suggestions",
143 "fixed_count": 1,
144 "verified_count": 1,
145 "unverified_count": 0,
146 "ai_metrics": {
147 "total_api_calls": 2,
148 "total_cost_usd": 0.005,
149 },
150 }
152 data = create_json_output(
153 action=Action.CHECK,
154 results=[result],
155 total_issues=1,
156 total_fixed=0,
157 total_remaining=0,
158 exit_code=1,
159 )
161 ai_meta = data["results"][0]["ai_metadata"]
162 assert_that(ai_meta).contains_key("fix_suggestions")
163 assert_that(ai_meta).does_not_contain_key("suggestions")
164 assert_that(ai_meta["fixed_count"]).is_equal_to(1)
165 assert_that(ai_meta["verified_count"]).is_equal_to(1)
166 assert_that(ai_meta["unverified_count"]).is_equal_to(0)
167 assert_that(ai_meta).contains_key("ai_metrics")
168 assert_that(ai_meta["ai_metrics"]["total_api_calls"]).is_equal_to(2)