test_json_parser.py
8.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
"""
测试RobustJSONParser的各种修复能力。
验证解析器能够处理:
1. 基本的markdown包裹
2. 思考内容清理
3. 缺少逗号的修复
4. 括号不平衡的修复
5. 控制字符转义
6. 尾随逗号移除
"""
import json
import unittest
from json_parser import RobustJSONParser, JSONParseError
class TestRobustJSONParser(unittest.TestCase):
"""测试鲁棒JSON解析器的各种修复策略。"""
def setUp(self):
"""初始化解析器。"""
self.parser = RobustJSONParser(
enable_json_repair=False, # 先测试本地修复
enable_llm_repair=False,
)
def test_basic_json(self):
"""测试解析基本的合法JSON。"""
json_str = '{"name": "test", "value": 123}'
result = self.parser.parse(json_str, "基本测试")
self.assertEqual(result["name"], "test")
self.assertEqual(result["value"], 123)
def test_markdown_wrapped(self):
"""测试解析被```json包裹的JSON。"""
json_str = """```json
{
"name": "test",
"value": 123
}
```"""
result = self.parser.parse(json_str, "Markdown包裹测试")
self.assertEqual(result["name"], "test")
self.assertEqual(result["value"], 123)
def test_thinking_content_removal(self):
"""测试清理思考内容。"""
json_str = """<thinking>让我想想如何构造这个JSON</thinking>
{
"name": "test",
"value": 123
}"""
result = self.parser.parse(json_str, "思考内容清理测试")
self.assertEqual(result["name"], "test")
self.assertEqual(result["value"], 123)
def test_missing_comma_fix(self):
"""测试修复缺少的逗号。"""
# 这是实际错误中常见的情况:数组元素之间缺少逗号
json_str = """{
"totalWords": 40000,
"globalGuidelines": [
"重点突出技术红利分配失衡"
"详略策略:技术创新"
],
"chapters": []
}"""
result = self.parser.parse(json_str, "缺少逗号修复测试")
self.assertEqual(len(result["globalGuidelines"]), 2)
def test_unbalanced_brackets(self):
"""测试修复括号不平衡。"""
# 缺少结束括号
json_str = """{
"name": "test",
"nested": {
"value": 123
}
""" # 缺少最外层的 }
result = self.parser.parse(json_str, "括号不平衡测试")
self.assertEqual(result["name"], "test")
self.assertEqual(result["nested"]["value"], 123)
def test_control_character_escape(self):
"""测试转义控制字符。"""
# JSON字符串中的裸换行符应该被转义
json_str = """{
"text": "这是第一行
这是第二行",
"value": 123
}"""
result = self.parser.parse(json_str, "控制字符转义测试")
# 确保换行符被正确处理
self.assertIn("第一行", result["text"])
self.assertIn("第二行", result["text"])
def test_trailing_comma_removal(self):
"""测试移除尾随逗号。"""
json_str = """{
"name": "test",
"value": 123,
"items": [1, 2, 3,],
}"""
result = self.parser.parse(json_str, "尾随逗号测试")
self.assertEqual(result["name"], "test")
self.assertEqual(len(result["items"]), 3)
def test_colon_equals_fix(self):
"""测试修复冒号等号错误。"""
json_str = """{
"name":= "test",
"value": 123
}"""
result = self.parser.parse(json_str, "冒号等号测试")
self.assertEqual(result["name"], "test")
def test_extract_first_json(self):
"""测试从文本中提取第一个JSON结构。"""
json_str = """这是一些说明文字,下面是JSON:
{
"name": "test",
"value": 123
}
后面还有一些其他文字"""
result = self.parser.parse(json_str, "提取JSON测试")
self.assertEqual(result["name"], "test")
self.assertEqual(result["value"], 123)
def test_unterminated_string_with_json_repair(self):
"""测试使用json_repair库修复未终止的字符串。"""
# 创建启用json_repair的解析器
parser_with_repair = RobustJSONParser(
enable_json_repair=True,
enable_llm_repair=False,
)
# 模拟实际错误:字符串中有未转义的控制字符或引号
json_str = """{
"template_name": "特定政策报告",
"selection_reason": "这是测试内容"
}"""
result = parser_with_repair.parse(json_str, "未终止字符串测试")
# 只要能够解析成功,不报错就可以了
self.assertIsInstance(result, dict)
self.assertIn("template_name", result)
def test_array_with_best_match(self):
"""测试从数组中提取最佳匹配的元素。"""
json_str = """[
{
"name": "test",
"value": 123
},
{
"totalWords": 40000,
"globalGuidelines": ["guide1", "guide2"],
"chapters": []
}
]"""
result = self.parser.parse(
json_str,
"数组最佳匹配测试",
expected_keys=["totalWords", "globalGuidelines", "chapters"],
)
# 应该提取第二个元素,因为它匹配了3个键
self.assertEqual(result["totalWords"], 40000)
self.assertEqual(len(result["globalGuidelines"]), 2)
def test_key_alias_recovery(self):
"""测试键名别名恢复。"""
json_str = """{
"templateName": "test_template",
"selectionReason": "This is a test"
}"""
result = self.parser.parse(
json_str,
"键别名测试",
expected_keys=["template_name", "selection_reason"],
)
# 应该自动映射 templateName -> template_name
self.assertEqual(result["template_name"], "test_template")
self.assertEqual(result["selection_reason"], "This is a test")
def test_complex_real_world_case(self):
"""测试真实世界的复杂案例(类似实际错误)。"""
# 模拟实际错误:缺少逗号、有markdown包裹、有思考内容
json_str = """<thinking>我需要构造一个篇幅规划</thinking>
```json
{
"totalWords": 40000,
"tolerance": 2000,
"globalGuidelines": [
"重点突出技术红利分配失衡、人才流失与职业认同危机等结构性矛盾"
"详略策略:技术创新与传统技艺的碰撞"
"案例导向:优先引用真实数据和调研"
],
"chapters": [
{
"chapterId": "ch1",
"targetWords": 5000
}
]
}
```"""
result = self.parser.parse(json_str, "复杂真实案例测试")
self.assertEqual(result["totalWords"], 40000)
self.assertEqual(result["tolerance"], 2000)
self.assertEqual(len(result["globalGuidelines"]), 3)
self.assertEqual(len(result["chapters"]), 1)
def test_expected_keys_validation(self):
"""测试期望键的验证。"""
json_str = '{"name": "test"}'
# 不应该因为缺少键而失败,只是警告
result = self.parser.parse(
json_str, "键验证测试", expected_keys=["name", "value"]
)
self.assertIn("name", result)
def test_wrapper_key_extraction(self):
"""测试从包裹键中提取数据。"""
json_str = """{
"wrapper": {
"name": "test",
"value": 123
}
}"""
result = self.parser.parse(
json_str, "包裹键测试", extract_wrapper_key="wrapper"
)
self.assertEqual(result["name"], "test")
self.assertEqual(result["value"], 123)
def test_empty_input(self):
"""测试空输入。"""
with self.assertRaises(JSONParseError):
self.parser.parse("", "空输入测试")
def test_invalid_json_after_all_repairs(self):
"""测试所有修复策略都无法处理的情况。"""
# 这是一个严重损坏的JSON,无法修复
json_str = "{完全不是JSON格式的内容###"
with self.assertRaises(JSONParseError):
self.parser.parse(json_str, "无法修复测试")
def run_manual_test():
"""手动运行测试,打印详细信息。"""
print("=" * 60)
print("开始测试RobustJSONParser")
print("=" * 60)
parser = RobustJSONParser(enable_json_repair=False, enable_llm_repair=False)
# 测试实际错误案例
test_case = """```json
{
"totalWords": 40000,
"tolerance": 2000,
"globalGuidelines": [
"重点突出技术红利分配失衡、人才流失与职业认同危机等结构性矛盾"
"详略策略:技术创新与传统技艺的碰撞"
],
"chapters": []
}
```"""
print("\n测试案例:")
print(test_case)
print("\n" + "=" * 60)
try:
result = parser.parse(test_case, "手动测试")
print("\n✓ 解析成功!")
print("\n解析结果:")
print(json.dumps(result, ensure_ascii=False, indent=2))
except Exception as e:
print(f"\n✗ 解析失败: {e}")
print("\n" + "=" * 60)
if __name__ == "__main__":
# 运行手动测试
run_manual_test()
# 运行单元测试
print("\n\n运行单元测试...")
unittest.main(verbosity=2)