PlanOpticon

planopticon / tests / test_json_parsing.py
Source Blame History 70 lines
321f2f5… leo 1 """Tests for robust JSON parsing from LLM responses."""
321f2f5… leo 2
321f2f5… leo 3 from video_processor.utils.json_parsing import parse_json_from_response
321f2f5… leo 4
321f2f5… leo 5
321f2f5… leo 6 class TestParseJsonFromResponse:
321f2f5… leo 7 def test_direct_dict(self):
321f2f5… leo 8 assert parse_json_from_response('{"key": "value"}') == {"key": "value"}
321f2f5… leo 9
321f2f5… leo 10 def test_direct_array(self):
829e24a… leo 11 assert parse_json_from_response("[1, 2, 3]") == [1, 2, 3]
321f2f5… leo 12
321f2f5… leo 13 def test_markdown_fenced_json(self):
321f2f5… leo 14 text = '```json\n{"key": "value"}\n```'
321f2f5… leo 15 assert parse_json_from_response(text) == {"key": "value"}
321f2f5… leo 16
321f2f5… leo 17 def test_markdown_fenced_no_lang(self):
829e24a… leo 18 text = "```\n[1, 2]\n```"
321f2f5… leo 19 assert parse_json_from_response(text) == [1, 2]
321f2f5… leo 20
321f2f5… leo 21 def test_json_embedded_in_text(self):
321f2f5… leo 22 text = 'Here is the result:\n{"name": "test", "value": 42}\nEnd of result.'
321f2f5… leo 23 result = parse_json_from_response(text)
321f2f5… leo 24 assert result == {"name": "test", "value": 42}
321f2f5… leo 25
321f2f5… leo 26 def test_array_embedded_in_text(self):
321f2f5… leo 27 text = 'The entities are:\n[{"name": "Alice"}, {"name": "Bob"}]\nThat is all.'
321f2f5… leo 28 result = parse_json_from_response(text)
321f2f5… leo 29 assert len(result) == 2
321f2f5… leo 30 assert result[0]["name"] == "Alice"
321f2f5… leo 31
321f2f5… leo 32 def test_nested_json(self):
321f2f5… leo 33 text = '{"outer": {"inner": [1, 2, 3]}}'
321f2f5… leo 34 result = parse_json_from_response(text)
321f2f5… leo 35 assert result["outer"]["inner"] == [1, 2, 3]
321f2f5… leo 36
321f2f5… leo 37 def test_empty_string(self):
321f2f5… leo 38 assert parse_json_from_response("") is None
321f2f5… leo 39
321f2f5… leo 40 def test_none_input(self):
321f2f5… leo 41 assert parse_json_from_response(None) is None
321f2f5… leo 42
321f2f5… leo 43 def test_whitespace_only(self):
321f2f5… leo 44 assert parse_json_from_response(" \n ") is None
321f2f5… leo 45
321f2f5… leo 46 def test_no_json(self):
321f2f5… leo 47 assert parse_json_from_response("This is just plain text.") is None
321f2f5… leo 48
321f2f5… leo 49 def test_invalid_json(self):
321f2f5… leo 50 assert parse_json_from_response("{invalid json}") is None
321f2f5… leo 51
321f2f5… leo 52 def test_multiple_json_objects_picks_first(self):
321f2f5… leo 53 text = '{"a": 1} and {"b": 2}'
321f2f5… leo 54 result = parse_json_from_response(text)
321f2f5… leo 55 assert result == {"a": 1}
321f2f5… leo 56
321f2f5… leo 57 def test_complex_fenced(self):
321f2f5… leo 58 text = """Here is the analysis:
321f2f5… leo 59
321f2f5… leo 60 ```json
321f2f5… leo 61 [
321f2f5… leo 62 {"point": "Architecture uses microservices", "topic": "Architecture"},
321f2f5… leo 63 {"point": "Deployment is automated", "topic": "DevOps"}
321f2f5… leo 64 ]
321f2f5… leo 65 ```
321f2f5… leo 66
321f2f5… leo 67 I hope this helps!"""
321f2f5… leo 68 result = parse_json_from_response(text)
321f2f5… leo 69 assert len(result) == 2
321f2f5… leo 70 assert result[0]["topic"] == "Architecture"

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button