64 lines
2.6 KiB
Python
64 lines
2.6 KiB
Python
# tests/api/test_llm_json_utils.py
|
|
"""robust_json_parse 五级兜底(QA client.py:36-121 范式+tickflow 尾部修复)."""
|
|
import pytest
|
|
|
|
from sanguo_api.llm.json_utils import JSONParseError, robust_json_parse
|
|
|
|
|
|
@pytest.mark.parametrize("text", [
|
|
'{"title": "a"}', # L1 直读
|
|
'好的,结果如下:\n```json\n{"title": "a"}\n```', # L2 围栏
|
|
'前置说明 {"title": "a"} 后置废话', # L3 首个配平块
|
|
' latex 残留 \\(x\\) {"title": "a"}', # L4 反斜杠修复
|
|
])
|
|
def test_parse_recovers(text):
|
|
assert robust_json_parse(text) == {"title": "a"}
|
|
|
|
|
|
def test_l5_trailing_comma_and_garbage():
|
|
assert robust_json_parse('{"title": "a",}') == {"title": "a"}
|
|
assert robust_json_parse('{"title": "a"} extra }') == {"title": "a"}
|
|
|
|
|
|
def test_l5_string_aware_trailing_comma():
|
|
"""P2-2: 字符串内 ", }" 原值保全,仅外层尾逗号被清——曾把字段值
|
|
"a, }" 损坏为 "a }" 后当成功返回."""
|
|
assert robust_json_parse('{"s": "a, }",}') == {"s": "a, }"}
|
|
assert robust_json_parse('{"s": "a, ]",}') == {"s": "a, ]"}
|
|
|
|
|
|
def test_l5_clean_trailing_commas_escape_aware():
|
|
"""转义引号不终止字符串扫描:字符串内 ,} 保留,外层尾逗号仍清."""
|
|
from sanguo_api.llm.json_utils import _clean_trailing_commas
|
|
assert _clean_trailing_commas('{"s": "a\\", b",}') == '{"s": "a\\", b"}'
|
|
assert _clean_trailing_commas('{"a": 1, }') == '{"a": 1 }'
|
|
|
|
|
|
def test_non_dict_raises():
|
|
with pytest.raises(JSONParseError):
|
|
robust_json_parse('["a", "b"]')
|
|
|
|
|
|
def test_garbage_raises():
|
|
with pytest.raises(JSONParseError):
|
|
robust_json_parse('完全不是 JSON')
|
|
|
|
|
|
def test_non_str_input_raises_json_parse_error():
|
|
"""P2-3: 非 str 输入(含 None)曾 TypeError 裸逃逸,穿透 502 契约变原生 500."""
|
|
for bad in (None, 42, {"a": 1}, ["a"], b"{}"):
|
|
with pytest.raises(JSONParseError):
|
|
robust_json_parse(bad)
|
|
|
|
|
|
def test_l4_l5_fixes_cumulative():
|
|
"""P3-1: L4 反斜杠修复与 L5 尾逗号清洗须累积叠加——并行候选下「LaTeX
|
|
残留+尾逗号」同现时两级各自单独修都不够,整段降级链全败(假阴性 502)."""
|
|
assert robust_json_parse('{"s": "\\(x\\)",}') == {"s": "(x)"}
|
|
|
|
|
|
def test_balanced_start_skips_brace_inside_string():
|
|
"""P3-2: 首个 { 落在字符串内时旧 find("{") 起点错位,配平块从头就坏,
|
|
后续 L4/L5 全被拖死——起点扫描须字符串感知(复用 in_str/esc 状态机)."""
|
|
assert robust_json_parse('他说"{不是json" 然后 {"a": 1}') == {"a": 1}
|