Files
wehub-resource-sync 7a0da7932b
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Has been cancelled
Docker Tests (Consolidated) / Accessibility Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Unit Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Example Tests (push) Has been cancelled
Docker Tests (Consolidated) / Production Image Smoke Test (push) Has been cancelled
Docker Tests (Consolidated) / Infrastructure Tests (push) Has been cancelled
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Has been cancelled
Backwards Compatibility / Verify Encryption Constants (push) Has been cancelled
Backwards Compatibility / PyPI Version Compatibility (push) Has been cancelled
Backwards Compatibility / Database Migration Tests (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Docker Tests (Consolidated) / detect-changes (push) Has been cancelled
Docker Tests (Consolidated) / Build Test Image (push) Has been cancelled
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:08:55 +08:00

487 lines
18 KiB
Python

"""Tests for json_utils module."""
from unittest.mock import Mock
class TestGetLlmResponseText:
"""Tests for get_llm_response_text function."""
def test_extracts_content_attribute(self):
"""Test that .content attribute is extracted from response."""
from local_deep_research.utilities.json_utils import (
get_llm_response_text,
)
response = Mock()
response.content = "Hello world"
assert get_llm_response_text(response) == "Hello world"
def test_falls_back_to_text_attribute(self):
"""Test that .text is used when .content is not available."""
from local_deep_research.utilities.json_utils import (
get_llm_response_text,
)
response = Mock(spec=[])
response.text = "Hello text"
assert get_llm_response_text(response) == "Hello text"
def test_content_takes_precedence_over_text(self):
"""Test that .content is preferred over .text."""
from local_deep_research.utilities.json_utils import (
get_llm_response_text,
)
response = Mock()
response.content = "from content"
response.text = "from text"
assert get_llm_response_text(response) == "from content"
def test_plain_string_passthrough(self):
"""Test that a plain string is returned via str()."""
from local_deep_research.utilities.json_utils import (
get_llm_response_text,
)
assert get_llm_response_text("plain string") == "plain string"
def test_none_input_returns_empty_string(self):
"""Test that None input returns empty string."""
from local_deep_research.utilities.json_utils import (
get_llm_response_text,
)
assert get_llm_response_text(None) == ""
def test_content_none_falls_through_to_text(self):
"""Test that content=None falls through to .text."""
from local_deep_research.utilities.json_utils import (
get_llm_response_text,
)
response = Mock()
response.content = None
response.text = "from text"
assert get_llm_response_text(response) == "from text"
def test_non_string_content_converted(self):
"""Test that non-string .content is converted to string."""
from local_deep_research.utilities.json_utils import (
get_llm_response_text,
)
response = Mock()
response.content = 42
assert get_llm_response_text(response) == "42"
def test_removes_paired_think_tags(self):
"""Test that paired <think>...</think> tags are removed."""
from local_deep_research.utilities.json_utils import (
get_llm_response_text,
)
response = Mock()
response.content = "<think>reasoning</think>Result here"
assert get_llm_response_text(response) == "Result here"
def test_removes_orphaned_think_tags(self):
"""Test that orphaned opening or closing think tags are removed."""
from local_deep_research.utilities.json_utils import (
get_llm_response_text,
)
response = Mock()
response.content = "</think>Result<think>"
assert get_llm_response_text(response) == "Result"
def test_removes_multiline_think_tags(self):
"""Test that multiline think tag content is removed."""
from local_deep_research.utilities.json_utils import (
get_llm_response_text,
)
response = Mock()
response.content = "<think>\nline1\nline2\n</think>\nActual content"
assert get_llm_response_text(response) == "Actual content"
class TestExtractJson:
"""Tests for extract_json function."""
def test_pure_json_dict(self):
"""Test parsing a pure JSON dict string."""
from local_deep_research.utilities.json_utils import extract_json
result = extract_json('{"key": "value"}')
assert result == {"key": "value"}
def test_pure_json_list(self):
"""Test parsing a pure JSON list string."""
from local_deep_research.utilities.json_utils import extract_json
result = extract_json("[1, 2, 3]")
assert result == [1, 2, 3]
def test_nested_structures(self):
"""Test parsing nested JSON structures."""
from local_deep_research.utilities.json_utils import extract_json
text = '{"items": [{"id": 1}, {"id": 2}]}'
result = extract_json(text)
assert result == {"items": [{"id": 1}, {"id": 2}]}
def test_code_fence_json(self):
"""Test extracting JSON from ```json code fences."""
from local_deep_research.utilities.json_utils import extract_json
text = '```json\n{"key": "value"}\n```'
result = extract_json(text)
assert result == {"key": "value"}
def test_bare_code_fence(self):
"""Test extracting JSON from bare ``` code fences."""
from local_deep_research.utilities.json_utils import extract_json
text = "```\n[1, 2, 3]\n```"
result = extract_json(text)
assert result == [1, 2, 3]
def test_code_fence_with_surrounding_prose(self):
"""Test extracting JSON from code fences with text around them."""
from local_deep_research.utilities.json_utils import extract_json
text = (
'Here is the result:\n```json\n{"key": "value"}\n```\n'
"Hope that helps!"
)
result = extract_json(text)
assert result == {"key": "value"}
def test_dict_embedded_in_prose(self):
"""Test extracting JSON dict embedded in prose text."""
from local_deep_research.utilities.json_utils import extract_json
text = 'The answer is {"key": "value"} as shown above.'
result = extract_json(text)
assert result == {"key": "value"}
def test_list_embedded_in_prose(self):
"""Test extracting JSON list embedded in prose text."""
from local_deep_research.utilities.json_utils import extract_json
text = "Here are the indices: [3, 0, 7, 1] sorted by relevance."
result = extract_json(text, expected_type=list)
assert result == [3, 0, 7, 1]
def test_expected_type_list_prefers_brackets(self):
"""Test that expected_type=list tries [] before {}."""
from local_deep_research.utilities.json_utils import extract_json
text = 'Prefix {"a": 1} and also [1, 2, 3] suffix'
result = extract_json(text, expected_type=list)
assert result == [1, 2, 3]
def test_expected_type_dict_prefers_braces(self):
"""Test that expected_type=dict tries {} before []."""
from local_deep_research.utilities.json_utils import extract_json
text = 'Prefix [1, 2, 3] and also {"a": 1} suffix'
result = extract_json(text, expected_type=dict)
assert result == {"a": 1}
def test_type_mismatch_falls_through(self):
"""Test that type mismatch on direct parse falls to extraction."""
from local_deep_research.utilities.json_utils import extract_json
text = '{"items": [1, 2, 3]}'
result = extract_json(text, expected_type=list)
assert result == [1, 2, 3]
def test_type_mismatch_no_alternative_returns_none(self):
"""Test that type mismatch with no matching brackets returns None."""
from local_deep_research.utilities.json_utils import extract_json
text = "just plain text no json here"
result = extract_json(text, expected_type=list)
assert result is None
def test_think_tags_cleaned_before_parse(self):
"""Test that think tags are removed before JSON parsing."""
from local_deep_research.utilities.json_utils import extract_json
text = '<think>reasoning here</think>{"key": "value"}'
result = extract_json(text)
assert result == {"key": "value"}
def test_none_input_returns_none(self):
"""Test that None input returns None."""
from local_deep_research.utilities.json_utils import extract_json
assert extract_json(None) is None
def test_empty_string_returns_none(self):
"""Test that empty string returns None."""
from local_deep_research.utilities.json_utils import extract_json
assert extract_json("") is None
def test_whitespace_only_returns_none(self):
"""Test that whitespace-only string returns None."""
from local_deep_research.utilities.json_utils import extract_json
assert extract_json(" \n\t ") is None
def test_no_json_returns_none(self):
"""Test that text without JSON returns None."""
from local_deep_research.utilities.json_utils import extract_json
assert extract_json("Hello, I have no JSON here.") is None
def test_invalid_json_in_brackets_returns_none(self):
"""Test that invalid JSON inside brackets returns None."""
from local_deep_research.utilities.json_utils import extract_json
assert extract_json("{not valid json at all}") is None
def test_json_scalar_returns_none(self):
"""Test that JSON scalars (number, string) return None."""
from local_deep_research.utilities.json_utils import extract_json
assert extract_json("42") is None
assert extract_json('"just a string"') is None
def test_unicode_content_preserved(self):
"""Test that unicode content in JSON is preserved."""
from local_deep_research.utilities.json_utils import extract_json
text = '{"name": "café", "city": "München"}'
result = extract_json(text)
assert result == {"name": "café", "city": "München"}
def test_multiline_json(self):
"""Test parsing multiline JSON with whitespace."""
from local_deep_research.utilities.json_utils import extract_json
text = '{\n "key1": "value1",\n "key2": "value2"\n}'
result = extract_json(text)
assert result == {"key1": "value1", "key2": "value2"}
def test_expected_type_none_accepts_dict(self):
"""Test that expected_type=None accepts dict."""
from local_deep_research.utilities.json_utils import extract_json
result = extract_json('{"a": 1}', expected_type=None)
assert result == {"a": 1}
def test_expected_type_none_accepts_list(self):
"""Test that expected_type=None accepts list."""
from local_deep_research.utilities.json_utils import extract_json
result = extract_json("[1, 2]", expected_type=None)
assert result == [1, 2]
def test_nested_brackets_extracted_correctly(self):
"""Test that nested brackets use outermost match."""
from local_deep_research.utilities.json_utils import extract_json
text = 'prefix {"a": {"b": [1, 2]}} suffix'
result = extract_json(text)
assert result == {"a": {"b": [1, 2]}}
def test_list_of_dicts(self):
"""Test parsing a list of dictionaries."""
from local_deep_research.utilities.json_utils import extract_json
text = '[{"id": 1, "name": "a"}, {"id": 2, "name": "b"}]'
result = extract_json(text, expected_type=list)
assert result == [
{"id": 1, "name": "a"},
{"id": 2, "name": "b"},
]
class TestExtractJsonLlmArtifacts:
"""Tests for LLM artifact cleaning in extract_json."""
def test_trailing_comma_in_array(self):
"""Test that trailing commas in arrays are handled."""
from local_deep_research.utilities.json_utils import extract_json
result = extract_json("[1, 2, 3,]")
assert result == [1, 2, 3]
def test_trailing_comma_in_object(self):
"""Test that trailing commas in objects are handled."""
from local_deep_research.utilities.json_utils import extract_json
result = extract_json('{"a": 1, "b": 2,}')
assert result == {"a": 1, "b": 2}
def test_inline_comments(self):
"""Test that // comments are cleaned from JSON."""
from local_deep_research.utilities.json_utils import extract_json
text = "[1, 2, // this is best\n3]"
result = extract_json(text, expected_type=list)
assert result == [1, 2, 3]
def test_ellipsis_in_array(self):
"""Test that ellipsis entries are removed from arrays."""
from local_deep_research.utilities.json_utils import extract_json
result = extract_json("[1, 2, ...]")
assert result == [1, 2]
def test_quoted_ellipsis_in_array(self):
"""Test that quoted ellipsis in valid JSON is preserved (valid JSON)."""
from local_deep_research.utilities.json_utils import extract_json
# This is valid JSON, so direct parse succeeds without artifact cleaning
result = extract_json('[1, 2, "..."]')
assert result == [1, 2, "..."]
def test_unquoted_ellipsis_in_malformed_json(self):
"""Test that ellipsis is cleaned from malformed JSON."""
from local_deep_research.utilities.json_utils import extract_json
# Trailing comma + ellipsis makes this invalid, triggers cleaning
result = extract_json("[1, 2, ...,]")
assert result == [1, 2]
def test_combined_artifacts(self):
"""Test cleaning multiple artifact types at once."""
from local_deep_research.utilities.json_utils import extract_json
text = "[1, 2, // comment\n3, ...,]"
result = extract_json(text, expected_type=list)
assert result == [1, 2, 3]
def test_clean_json_not_modified(self):
"""Test that valid JSON is not affected by artifact cleaning."""
from local_deep_research.utilities.json_utils import extract_json
text = '{"url": "https://example.com/path", "count": 5}'
result = extract_json(text)
assert result == {
"url": "https://example.com/path",
"count": 5,
}
def test_trailing_comma_in_prose(self):
"""Test trailing comma cleanup with surrounding prose."""
from local_deep_research.utilities.json_utils import extract_json
text = "The result is: [1, 2, 3,] as expected"
result = extract_json(text, expected_type=list)
assert result == [1, 2, 3]
class TestStripCodeFences:
"""Tests for _strip_code_fences private helper."""
def test_json_code_fence(self):
"""Test stripping ```json code fences."""
from local_deep_research.utilities.json_utils import (
_strip_code_fences,
)
text = '```json\n{"key": "value"}\n```'
assert _strip_code_fences(text) == '{"key": "value"}'
def test_bare_code_fence(self):
"""Test stripping bare ``` code fences."""
from local_deep_research.utilities.json_utils import (
_strip_code_fences,
)
text = "```\n[1, 2, 3]\n```"
assert _strip_code_fences(text) == "[1, 2, 3]"
def test_no_code_fence(self):
"""Test that text without code fences is returned unchanged."""
from local_deep_research.utilities.json_utils import (
_strip_code_fences,
)
text = '{"key": "value"}'
assert _strip_code_fences(text) == '{"key": "value"}'
def test_stray_backticks_not_treated_as_fence(self):
"""Test that stray backticks are not treated as code fences."""
from local_deep_research.utilities.json_utils import (
_strip_code_fences,
)
text = "Use ``` for code blocks"
assert _strip_code_fences(text) == "Use ``` for code blocks"
def test_json_fence_with_surrounding_text(self):
"""Test code fence extraction with text before and after."""
from local_deep_research.utilities.json_utils import (
_strip_code_fences,
)
text = 'Here is the JSON:\n```json\n{"a": 1}\n```\nDone!'
assert _strip_code_fences(text) == '{"a": 1}'
class TestExtractByBrackets:
"""Tests for _extract_by_brackets private helper."""
def test_extract_dict_brackets(self):
"""Test extracting content between { and }."""
from local_deep_research.utilities.json_utils import (
_extract_by_brackets,
)
text = 'prefix {"key": "value"} suffix'
result = _extract_by_brackets(text, "{", "}")
assert result == '{"key": "value"}'
def test_extract_list_brackets(self):
"""Test extracting content between [ and ]."""
from local_deep_research.utilities.json_utils import (
_extract_by_brackets,
)
text = "prefix [1, 2, 3] suffix"
result = _extract_by_brackets(text, "[", "]")
assert result == "[1, 2, 3]"
def test_missing_open_bracket_returns_none(self):
"""Test that missing open bracket returns None."""
from local_deep_research.utilities.json_utils import (
_extract_by_brackets,
)
result = _extract_by_brackets("no brackets here}", "{", "}")
assert result is None
def test_missing_close_bracket_returns_none(self):
"""Test that missing close bracket returns None."""
from local_deep_research.utilities.json_utils import (
_extract_by_brackets,
)
result = _extract_by_brackets("{no close bracket", "{", "}")
assert result is None
def test_close_before_open_returns_none(self):
"""Test that close bracket before open returns None."""
from local_deep_research.utilities.json_utils import (
_extract_by_brackets,
)
result = _extract_by_brackets("} before {", "{", "}")
assert result is None
def test_nested_brackets_uses_outermost(self):
"""Test that nested brackets extract outermost pair."""
from local_deep_research.utilities.json_utils import (
_extract_by_brackets,
)
text = '{"a": {"b": 1}}'
result = _extract_by_brackets(text, "{", "}")
assert result == '{"a": {"b": 1}}'