You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

104 lines
3.3 KiB

"""
Test for issue #13533: Multiple regressions in the handling of forms & form validation
This test verifies that empty strings in form fields are correctly handled:
- For optional fields with None default, empty string should result in None
- For optional fields with int type, empty string should result in None (not parsing error)
- This applies to both x-www-form-urlencoded and multipart/form-data
"""
from typing import Optional
from fastapi import FastAPI, File, Form
from fastapi.testclient import TestClient
from typing_extensions import Annotated
# Test app for URL-encoded forms with optional string
app_urlencoded_str = FastAPI()
@app_urlencoded_str.post("/test")
def endpoint_urlencoded_str(
name: Annotated[Optional[str], Form(embed=True)] = None,
):
return {"name": name}
# Test app for URL-encoded forms with optional int
app_urlencoded_int = FastAPI()
@app_urlencoded_int.post("/test")
def endpoint_urlencoded_int(
age: Annotated[Optional[int], Form()] = None,
):
return {"age": age}
# Test app for multipart forms
app_multipart = FastAPI()
@app_multipart.post("/test")
def endpoint_multipart(
file: Annotated[Optional[bytes], File()] = None,
name: Annotated[Optional[str], Form(embed=True)] = None,
):
return {"file_size": len(file) if file else None, "name": name}
def test_urlencoded_empty_string_optional_str():
"""
Regression test for #13533: Empty string in URL-encoded form
with optional str field should use default value (None)
"""
client = TestClient(app_urlencoded_str)
response = client.post("/test", data={"name": ""})
assert response.status_code == 200
assert response.json() == {"name": None}
def test_urlencoded_empty_string_optional_int():
"""
Regression test for #13533: Empty string in URL-encoded form
with optional int field should use default value (None), not cause parsing error
"""
client = TestClient(app_urlencoded_int)
response = client.post("/test", data={"age": ""})
assert response.status_code == 200
assert response.json() == {"age": None}
def test_multipart_empty_string_optional_str():
"""
Regression test for #13533: Empty string in multipart form
with optional str field should use default value (None)
"""
client = TestClient(app_multipart)
response = client.post("/test", data={"name": ""})
assert response.status_code == 200
assert response.json() == {"file_size": None, "name": None}
def test_urlencoded_with_actual_value():
"""Verify that actual values still work correctly"""
client = TestClient(app_urlencoded_str)
response = client.post("/test", data={"name": "John"})
assert response.status_code == 200
assert response.json() == {"name": "John"}
def test_urlencoded_int_with_actual_value():
"""Verify that actual int values still work correctly"""
client = TestClient(app_urlencoded_int)
response = client.post("/test", data={"age": "25"})
assert response.status_code == 200
assert response.json() == {"age": 25}
def test_multipart_with_actual_value():
"""Verify that actual values in multipart forms still work correctly"""
client = TestClient(app_multipart)
response = client.post("/test", data={"name": "John"})
assert response.status_code == 200
assert response.json() == {"file_size": None, "name": "John"}