Skip to content

Commit

Permalink
More general tests for file submission
Browse files Browse the repository at this point in the history
This is a preparation commit to change the way the enctype field of
forms is dealt with. Test all combinations:

* A file= field is present, or not.

* A file is actually submited, or not.

* The enctype allows sending files, doesn't allow it, or is invalid.
  • Loading branch information
MartinDlry authored and moy committed Jul 16, 2019
1 parent 0b04e8b commit 540c9bc
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 32 deletions.
102 changes: 71 additions & 31 deletions tests/test_browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,54 +81,94 @@ def test__request(httpbin):
"Content-Type"]


@pytest.mark.parametrize('expected_content, set_value', [
(b":-)", True),
(b"", False)
valid_enctypes_file_submit = {"multipart/form-data": True,
"application/x-www-form-urlencoded": False
}

default_enctype = "application/x-www-form-urlencoded"


@pytest.mark.parametrize("file_field", [
"""<input name="pic" type="file" />""",
""])
@pytest.mark.parametrize("submit_file", [
True,
False
])
@pytest.mark.parametrize("enctype", [
pytest.param("multipart/form-data"),
pytest.param("application/x-www-form-urlencoded"),
pytest.param("Invalid enctype")
])
def test__request_file(httpbin, expected_content, set_value):
def test_enctype_and_file_submit(httpbin, enctype, submit_file, file_field):
# test if enctype is respected when specified
# and if files are processed correctly
form_html = """
<form method="post" action="{}/post">
<input name="pic" type="file" />
<form method="post" action="{}/post" enctype="{}">
<input name="in" value="test" />
{}
</form>
""".format(httpbin.url)
""".format(httpbin.url, enctype, file_field)
form = BeautifulSoup(form_html, "lxml").form

if set_value:
# For now, assume that the encoding always allow sending file's
# content.
valid_enctype = True
expected_content = b"" # default
if submit_file and file_field:
# create a temporary file for testing file upload
file_content = b":-)"
pic_filedescriptor, pic_path = tempfile.mkstemp()
os.write(pic_filedescriptor, expected_content)
os.write(pic_filedescriptor, file_content)
os.close(pic_filedescriptor)

if valid_enctype:
# Correct encoding => send the content
expected_content = file_content
else:
# Encoding doesn't allow sending the content, we expect
# the filename as a normal text field.
expected_content = pic_path.encode()
form.find("input", {"name": "pic"})["value"] = pic_path

browser = mechanicalsoup.Browser()
response = browser._request(form)

# Check that only "files" includes a "pic" keyword in the response
if file_field:
expected_enctype = 'multipart/form-data'
else:
expected_enctype = 'application/x-www-form-urlencoded'
assert expected_enctype in response.request.headers["Content-Type"]

resp = response.json()
assert resp["form"]["in"] == "test"

found = False
for key, value in response.json().items():
if key == "files":
if "pic" in value:
if value["pic"].encode() == expected_content:
# If pic is found twice, an error will occur
assert not found
found = True
# One would expect to find "pic" in files, but as of writing,
# httpbin puts it in form when the filename is empty:
elif key == "form":
found_in = None

for key, value in resp.items():
if value:
if "pic" in value:
if value["pic"].encode() == expected_content:
assert not found
found = True
assert b"filename=\"\"" in response.request.body
content = value["pic"].encode()
assert not found
assert key in ("files", "form")
found = True
found_in = key

assert found == bool(file_field)
if file_field:
assert content == expected_content

if valid_enctype:
assert found_in == "files"
if submit_file:
assert ("filename=\"" + pic_path + "\""
).encode() in response.request.body
else:
assert b"filename=\"\"" in response.request.body
else:
assert (value is None) or ("pic" not in value)

assert found
assert "multipart/form-data" in response.request.headers["Content-Type"]
assert found_in == "form"

# In case we created a file for upload, we need to close & delete it
if set_value:
if submit_file and file_field:
os.remove(pic_path)


Expand Down
4 changes: 3 additions & 1 deletion tests/test_stateful_browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -339,8 +339,10 @@ def make_file(content):
("first file content", "second file content"))

# The form doesn't have a type=file field, but the target action
# does show it => add the fields ourselves.
# does show it => add the fields ourselves, and add enctype too.
browser.select_form()
browser._StatefulBrowser__state.form.form[
"enctype"] = "multipart/form-data"
browser.new_control("file", "first", path1)
browser.new_control("file", "second", "")
browser["second"] = path2
Expand Down

0 comments on commit 540c9bc

Please sign in to comment.