|
1 | 1 | import os |
2 | 2 | import sys |
3 | | -import pytest |
| 3 | + |
4 | 4 | import orjson |
| 5 | +import pytest |
5 | 6 |
|
6 | 7 | # Ensure backend root is in sys.path |
7 | 8 | backend_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) |
8 | 9 | if backend_dir not in sys.path: |
9 | 10 | sys.path.insert(0, backend_dir) |
10 | 11 |
|
11 | | -from common.utils.utils import extract_nested_json |
| 12 | +from common.utils.utils import extract_nested_json # noqa: E402 |
12 | 13 |
|
13 | 14 |
|
14 | 15 | def test_standard_json_extraction(): |
@@ -116,6 +117,58 @@ def test_invalid_candidate_before_valid_json(): |
116 | 117 | assert data["sql"] == "SELECT 1" |
117 | 118 |
|
118 | 119 |
|
119 | | -@pytest.mark.parametrize("invalid_input", [None, "", " ", 123, [], {}, "No json at all here"]) |
| 120 | +@pytest.mark.parametrize( |
| 121 | + "invalid_input", [None, "", " ", 123, [], {}, "No json at all here"] |
| 122 | +) |
120 | 123 | def test_invalid_or_empty_inputs(invalid_input): |
121 | 124 | assert extract_nested_json(invalid_input) is None |
| 125 | + |
| 126 | + |
| 127 | +@pytest.mark.parametrize( |
| 128 | + "invalid_candidate", |
| 129 | + [ |
| 130 | + '{"tables": [],}', |
| 131 | + '{"outer": {"success": true, "sql": "SELECT 0"}, bad}', |
| 132 | + '[{"year": 2026, "value": 10},]', |
| 133 | + '{"sql": "SELECT \'{}\'", bad}', |
| 134 | + '{"tables": [}, "other": {"success": true}}', |
| 135 | + '{"value": NaN, "tables": []}', |
| 136 | + '{"sql": "SELECT\n1", "tables": []}', |
| 137 | + ], |
| 138 | +) |
| 139 | +def test_invalid_outer_candidate_does_not_expose_nested_values(invalid_candidate): |
| 140 | + assert extract_nested_json(invalid_candidate) is None |
| 141 | + answer = '{"success": true, "sql": "SELECT 1", "tables": ["t"]}' |
| 142 | + assert extract_nested_json(invalid_candidate + " then " + answer) == answer |
| 143 | + |
| 144 | + |
| 145 | +@pytest.mark.parametrize( |
| 146 | + "truncated", |
| 147 | + [ |
| 148 | + '{"sql": "SELECT 1", "tables": ["t"]', |
| 149 | + '[{"year": 2026, "value": 10},', |
| 150 | + '[{"x": 1}', |
| 151 | + '{"outer": {"success": true, "sql": "SELECT 1"}', |
| 152 | + '{"text": "unterminated [] {}', |
| 153 | + ], |
| 154 | +) |
| 155 | +def test_truncated_outer_candidate_is_rejected(truncated): |
| 156 | + assert extract_nested_json(truncated) is None |
| 157 | + |
| 158 | + |
| 159 | +@pytest.mark.parametrize( |
| 160 | + "answer", |
| 161 | + [ |
| 162 | + '{"outer": [{"inner": [1, 2]}, []], "empty": {}}', |
| 163 | + "{\"sql\": \"SELECT '[', ']', '{', '}'\", \"tables\": []}", |
| 164 | + r'{"text": "escaped quote: \" { [", "tail": "ends in slash \\"}', |
| 165 | + "{}", |
| 166 | + "[]", |
| 167 | + ], |
| 168 | +) |
| 169 | +def test_complete_outer_candidate_is_preserved(answer): |
| 170 | + assert ( |
| 171 | + extract_nested_json('Explanation: "answer" ```json\n' + answer + "\n```") |
| 172 | + == answer |
| 173 | + ) |
| 174 | + assert extract_nested_json(answer + ' {"next": true}') == answer |
0 commit comments