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

1"""Tests for JSON output AI metadata serialization.""" 

2 

3from __future__ import annotations 

4 

5from assertpy import assert_that 

6 

7from lintro.enums.action import Action 

8from lintro.models.core.tool_result import ToolResult 

9from lintro.utils.json_output import create_json_output 

10 

11 

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 } 

40 

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 ) 

49 

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 ) 

56 

57 

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 } 

66 

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 ) 

75 

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 ) 

82 

83 

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 } 

92 

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 ) 

101 

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) 

107 

108 

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 } 

120 

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 ) 

129 

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) 

134 

135 

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 } 

151 

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 ) 

160 

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)