Skip to content

add regression tests for #1113 #1122

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 11, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions tests/server/fastmcp/test_func_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,98 @@ def func_with_str_and_int(a: str, b: int):
assert result["b"] == 123


def test_str_annotation_preserves_json_string():
"""
Regression test for PR #1113: Ensure that when a parameter is annotated as str,
valid JSON strings are NOT parsed into Python objects.

This test would fail before the fix (JSON string would be parsed to dict)
and passes after the fix (JSON string remains as string).
"""

def process_json_config(config: str, enabled: bool = True) -> str:
"""Function that expects a JSON string as a string parameter."""
# In real use, this function might validate or transform the JSON string
# before parsing it, or pass it to another service as-is
return f"Processing config: {config}"

meta = func_metadata(process_json_config)

# Test case 1: JSON object as string
json_obj_str = '{"database": "postgres", "port": 5432}'
result = meta.pre_parse_json({"config": json_obj_str, "enabled": True})

# The config parameter should remain as a string, NOT be parsed to a dict
assert isinstance(result["config"], str)
assert result["config"] == json_obj_str

# Test case 2: JSON array as string
json_array_str = '["item1", "item2", "item3"]'
result = meta.pre_parse_json({"config": json_array_str})

# Should remain as string
assert isinstance(result["config"], str)
assert result["config"] == json_array_str

# Test case 3: JSON string value (double-encoded)
json_string_str = '"This is a JSON string"'
result = meta.pre_parse_json({"config": json_string_str})

# Should remain as the original string with quotes
assert isinstance(result["config"], str)
assert result["config"] == json_string_str

# Test case 4: Complex nested JSON as string
complex_json_str = '{"users": [{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}], "count": 2}'
result = meta.pre_parse_json({"config": complex_json_str})

# Should remain as string
assert isinstance(result["config"], str)
assert result["config"] == complex_json_str


@pytest.mark.anyio
async def test_str_annotation_runtime_validation():
"""
Regression test for PR #1113: Test runtime validation with string parameters
containing valid JSON to ensure they are passed as strings, not parsed objects.
"""

def handle_json_payload(payload: str, strict_mode: bool = False) -> str:
"""Function that processes a JSON payload as a string."""
# This function expects to receive the raw JSON string
# It might parse it later after validation or logging
assert isinstance(payload, str), f"Expected str, got {type(payload)}"
return f"Handled payload of length {len(payload)}"

meta = func_metadata(handle_json_payload)

# Test with a JSON object string
json_payload = '{"action": "create", "resource": "user", "data": {"name": "Test User"}}'

result = await meta.call_fn_with_arg_validation(
handle_json_payload,
fn_is_async=False,
arguments_to_validate={"payload": json_payload, "strict_mode": True},
arguments_to_pass_directly=None,
)

# The function should have received the string and returned successfully
assert result == f"Handled payload of length {len(json_payload)}"

# Test with JSON array string
json_array_payload = '["task1", "task2", "task3"]'

result = await meta.call_fn_with_arg_validation(
handle_json_payload,
fn_is_async=False,
arguments_to_validate={"payload": json_array_payload},
arguments_to_pass_directly=None,
)

assert result == f"Handled payload of length {len(json_array_payload)}"


# Tests for structured output functionality


Expand Down
Loading