import pytest
from mindie_llm.runtime.utils.helpers.json_completor import complete_json_for_tool_calls, FillMode
def test_complete_json_invalid_input_type():
with pytest.raises(ValueError, match="expected str"):
complete_json_for_tool_calls(123, FillMode.Full)
def test_complete_json_not_start_with_brace():
with pytest.raises(ValueError, match="not start with a `{`"):
complete_json_for_tool_calls('"invalid"', FillMode.Full)
def test_brace_only_valid_json():
result = complete_json_for_tool_calls('{"name": "test"}', FillMode.BraceOnly)
assert result == {"name": "test"}
def test_brace_only_missing_closing_brace():
result = complete_json_for_tool_calls('{"name": "test"', FillMode.BraceOnly)
assert result == {"name": "test"}
def test_brace_only_multiple_missing_braces():
result = complete_json_for_tool_calls('{"a": {"b": "c"', FillMode.BraceOnly)
assert result == {"a": {"b": "c"}}
def test_brace_only_trailing_comma():
result = complete_json_for_tool_calls('{"name": "test",', FillMode.BraceOnly)
assert result == {"name": "test"}
def test_brace_only_invalid_json_after_fix():
result = complete_json_for_tool_calls('{"name":', FillMode.BraceOnly)
assert result == {}
def test_brace_only_edge_cases():
assert complete_json_for_tool_calls('{', FillMode.BraceOnly) == {}
assert complete_json_for_tool_calls('{"', FillMode.BraceOnly) == {}
assert complete_json_for_tool_calls('{"key":', FillMode.BraceOnly) == {}
def test_full_valid_json():
result = complete_json_for_tool_calls('{"name": "test", "value": 42}', FillMode.Full)
assert result == {"name": "test", "value": 42}
def test_full_incomplete_string():
result = complete_json_for_tool_calls('{"name": "incom', FillMode.Full)
assert result == {"name": "incom"}
def test_full_incomplete_number():
result = complete_json_for_tool_calls('{"value": 12', FillMode.Full)
assert result == {"value": 12}
def test_full_incomplete_array():
result = complete_json_for_tool_calls('{"items": [1, 2', FillMode.Full)
assert result == {"items": [1, 2]}
def test_full_incomplete_nested_object():
result = complete_json_for_tool_calls('{"outer": {"inner": "val', FillMode.Full)
assert result == {"outer": {"inner": "val"}}
def test_full_with_escaped_characters():
result = complete_json_for_tool_calls('{"text": "hello \\"world\\" \\n', FillMode.Full)
assert result["text"] == 'hello "world" \n'
def test_full_with_valid_unicode_escape():
"""Test Full mode handles 4-digit unicode escapes correctly."""
result = complete_json_for_tool_calls('{"sun": "\\u2600', FillMode.Full)
assert result["sun"] == "\u2600"
def test_full_skips_invalid_fields_simple():
"""Test Full mode skips a simple invalid field."""
result = complete_json_for_tool_calls('{"valid": 1, , "also_valid": 2}', FillMode.Full)
assert "valid" in result
result2 = complete_json_for_tool_calls('{"first": 1} invalid_trailing', FillMode.Full)
assert result2 == {"first": 1}
def test_full_skips_invalid_fields_after_comma():
"""Test skipping invalid field right after comma."""
result = complete_json_for_tool_calls('{"a": 1, /*comment*/, "b": 2}', FillMode.Full)
result = complete_json_for_tool_calls('{"a": 1, XXX, "b": 2}', FillMode.Full)
assert result.get("a") == 1
def test_full_literal_values():
result = complete_json_for_tool_calls('{"flag": true, "empty": null, "yes": false}', FillMode.Full)
assert result == {"flag": True, "empty": None, "yes": False}
def test_full_float_numbers():
result = complete_json_for_tool_calls('{"pi": 3.14, "big": 1e5}', FillMode.Full)
assert result == {"pi": 3.14, "big": 100000.0}
def test_brace_only_vs_full_incomplete():
incomplete = '{"name": "test", "details": {"age": 30'
brace_result = complete_json_for_tool_calls(incomplete, FillMode.BraceOnly)
full_result = complete_json_for_tool_calls(incomplete, FillMode.Full)
assert full_result == {"name": "test", "details": {"age": 30}}