blob: af78ce5ba3a9e305c2266d15afd90ee46b44dea8 [file] [log] [blame] [edit]
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import cgi
import os.path
import struct
import sys
import webtest
import six
from six import binary_type
from six import PY3
from webob import Request
from webtest.debugapp import DebugApp
from webtest.compat import to_bytes
from webtest.forms import NoValue, Submit, Upload
from tests.compat import unittest
from tests.compat import u
class TestForms(unittest.TestCase):
def callFUT(self, filename='form_inputs.html', formid='simple_form'):
dirname = os.path.join(os.path.dirname(__file__), 'html')
app = DebugApp(form=os.path.join(dirname, filename), show_form=True)
resp = webtest.TestApp(app).get('/form.html')
return resp.forms[formid]
def test_set_submit_field(self):
form = self.callFUT()
self.assertRaises(
AttributeError,
form['submit'].value__set,
'foo'
)
def test_button(self):
form = self.callFUT()
button = form['button']
self.assertTrue(isinstance(button, Submit),
"<button> without type is a submit button")
def test_force_select(self):
form = self.callFUT()
form['select'].force_value('notavalue')
form['select'].value__set('value3')
self.assertTrue(
form['select']._forced_value is NoValue,
"Setting a value after having forced a value should keep a forced"
" state")
self.assertEqual(
form['select'].value, 'value3',
"the value should the the one set by value__set")
self.assertEqual(
form['select'].selectedIndex, 2,
"the value index should be the one set by value__set")
def test_form_select(self):
form = self.callFUT()
form.select('select', 'value1')
self.assertEqual(
form['select'].value, 'value1',
"when using form.select, the input selected value should be "
"changed")
def test_get_field_by_index(self):
form = self.callFUT()
self.assertEqual(form['select'],
form.get('select', index=0))
def test_get_unknown_field(self):
form = self.callFUT()
self.assertEqual(form['unknown'].value, '')
form['unknown'].value = '1'
self.assertEqual(form['unknown'].value, '1')
def test_get_non_exist_fields(self):
form = self.callFUT()
self.assertRaises(AssertionError, form.get, 'nonfield')
def test_get_non_exist_fields_with_default(self):
form = self.callFUT()
value = form.get('nonfield', default=1)
self.assertEqual(value, 1)
def test_upload_fields(self):
form = self.callFUT()
fu = webtest.Upload(__file__)
form['file'] = fu
self.assertEqual(form.upload_fields(),
[['file', __file__]])
def test_repr(self):
form = self.callFUT()
self.assertTrue(repr(form).startswith('<Form id='))
def test_the_bs_node_must_not_change(self):
form = self.callFUT()
self.assertEqual(form.text, str(form.html))
def test_set_multiple_checkboxes(self):
form = self.callFUT(formid='multiple_checkbox_form')
form['checkbox'] = [10, 30]
self.assertEqual(form.get('checkbox', index=0).value, '10')
self.assertEqual(form.get('checkbox', index=1).value, None)
self.assertEqual(form.get('checkbox', index=2).value, '30')
def test_button_submit(self):
form = self.callFUT(formid='multiple_buttons_form')
display = form.submit('action')
self.assertIn(u("action=deactivate"), display, display)
def test_button_submit_by_index(self):
form = self.callFUT(formid='multiple_buttons_form')
display = form.submit('action', index=1)
self.assertIn(u("action=activate"), display, display)
def test_button_submit_by_value(self):
form = self.callFUT(formid='multiple_buttons_form')
display = form.submit('action', value='activate')
self.assertIn(u("action=activate"), display, display)
def test_button_submit_by_value_and_index(self):
form = self.callFUT(formid='multiple_buttons_form')
self.assertRaises(ValueError,
form.submit, "action", value="activate",
index=0)
class TestResponseFormAttribute(unittest.TestCase):
def callFUT(self, body):
app = DebugApp(form=to_bytes(body))
return webtest.TestApp(app)
def test_no_form(self):
app = self.callFUT('<html><body></body></html>')
res = app.get('/form.html')
self.assertRaises(TypeError, lambda: res.form)
def test_too_many_forms(self):
app = self.callFUT(
'<html><body><form></form><form></form></body></html>')
res = app.get('/form.html')
self.assertRaises(TypeError, lambda: res.form)
class TestInput(unittest.TestCase):
def callFUT(self, filename='form_inputs.html'):
dirname = os.path.join(os.path.dirname(__file__), 'html')
app = DebugApp(form=os.path.join(dirname, filename), show_form=True)
return webtest.TestApp(app)
def test_input(self):
app = self.callFUT()
res = app.get('/form.html')
self.assertEqual(res.status_int, 200)
self.assertTrue(res.content_type.startswith('text/html'))
form = res.forms['text_input_form']
self.assertEqual(form['foo'].value, 'bar')
self.assertEqual(form.submit_fields(), [('foo', 'bar')])
form = res.forms['radio_input_form']
self.assertEqual(form['foo'].selectedIndex, 1)
self.assertEqual(form['foo'].value, 'baz')
self.assertEqual(form.submit_fields(), [('foo', 'baz')])
form = res.forms['checkbox_input_form']
self.assertEqual(form['foo'].value, 'bar')
self.assertEqual(form.submit_fields(), [('foo', 'bar')])
form = res.forms['password_input_form']
self.assertEqual(form['foo'].value, 'bar')
self.assertEqual(form.submit_fields(), [('foo', 'bar')])
def test_force_radio_input(self):
app = self.callFUT()
res = app.get('/form.html')
form = res.forms['radio_input_form']
form['foo'].force_value('fido')
self.assertEqual(form['foo'].value, 'fido')
self.assertEqual(form.submit_fields(), [('foo', 'fido')])
def test_radio_input_order(self):
app = self.callFUT()
res = app.get('/form.html')
self.assertEqual(res.status_int, 200)
self.assertTrue(res.content_type.startswith('text/html'))
form = res.forms['complex_radio_input_form']
form['foo'].value = 'true'
self.assertEqual(form['foo'].value, 'true')
self.assertEqual(form['foo'].selectedIndex, 0)
self.assertEqual(form.submit_fields(), [
(u'__start__', u'item:mapping'),
('foo', 'true'),
(u'__end__', u'item:mapping'),
(u'__start__', u'item:mapping'),
(u'__end__', u'item:mapping')])
res = app.get('/form.html')
form = res.forms['complex_radio_input_form']
self.assertEqual(form['foo'].value, 'true')
self.assertEqual(form['foo'].selectedIndex, 1)
self.assertEqual(form.submit_fields(), [
(u'__start__', u'item:mapping'),
(u'__end__', u'item:mapping'),
(u'__start__', u'item:mapping'),
('foo', 'true'),
(u'__end__', u'item:mapping')])
def test_input_unicode(self):
app = self.callFUT('form_unicode_inputs.html')
res = app.get('/form.html')
self.assertEqual(res.status_int, 200)
self.assertTrue(res.content_type.startswith('text/html'))
self.assertEqual(res.charset.lower(), 'utf-8')
form = res.forms['text_input_form']
self.assertEqual(form['foo'].value, u('Хармс'))
self.assertEqual(form.submit_fields(), [('foo', u('Хармс'))])
form = res.forms['radio_input_form']
self.assertEqual(form['foo'].selectedIndex, 1)
self.assertEqual(form['foo'].value, u('Блок'))
self.assertEqual(form.submit_fields(), [('foo', u('Блок'))])
form = res.forms['checkbox_input_form']
self.assertEqual(form['foo'].value, u('Хармс'))
self.assertEqual(form.submit_fields(), [('foo', u('Хармс'))])
form = res.forms['password_input_form']
self.assertEqual(form['foo'].value, u('Хармс'))
self.assertEqual(form.submit_fields(), [('foo', u('Хармс'))])
def test_input_no_default(self):
app = self.callFUT('form_inputs_with_defaults.html')
res = app.get('/form.html')
self.assertEqual(res.status_int, 200)
self.assertTrue(res.content_type.startswith('text/html'))
form = res.forms['text_input_form']
self.assertEqual(form['foo'].value, '')
self.assertEqual(form.submit_fields(), [('foo', '')])
form = res.forms['radio_input_form']
self.assertTrue(form['foo'].value is None)
self.assertEqual(form.submit_fields(), [])
form = res.forms['checkbox_input_form']
self.assertTrue(form['foo'].value is None)
self.assertEqual(form.submit_fields(), [])
form = res.forms['password_input_form']
self.assertEqual(form['foo'].value, '')
self.assertEqual(form.submit_fields(), [('foo', '')])
def test_textarea_entities(self):
app = self.callFUT()
res = app.get('/form.html')
form = res.forms.get("textarea_input_form")
self.assertEqual(form.get("textarea").value, "'foo&bar'")
self.assertEqual(form.submit_fields(), [('textarea', "'foo&bar'")])
def test_textarea_emptyfirstline(self):
app = self.callFUT()
res = app.get('/form.html')
form = res.forms.get("textarea_emptyline_form")
self.assertEqual(form.get("textarea").value, "aaa")
self.assertEqual(form.submit_fields(), [('textarea', "aaa")])
class TestFormLint(unittest.TestCase):
def test_form_lint(self):
form = webtest.Form(None, '''<form>
<input type="text" name="field"/>
</form>''')
self.assertRaises(AttributeError, form.lint)
form = webtest.Form(None, '''<form>
<input type="text" id="myfield" name="field"/>
</form>''')
self.assertRaises(AttributeError, form.lint)
form = webtest.Form(None, '''<form>
<label for="myfield">my field</label>
<input type="text" id="myfield" name="field"/>
</form>''')
form.lint()
form = webtest.Form(None, '''<form>
<label class="field" for="myfield" role="r">my field</label>
<input type="text" id="myfield" name="field"/>
</form>''')
form.lint()
def select_app(environ, start_response):
req = Request(environ)
status = b"200 OK"
if req.method == "GET":
body = to_bytes("""
<html>
<head><title>form page</title></head>
<body>
<form method="POST" id="single_select_form">
<select id="single" name="single">
<option value="4">Four</option>
<option value="5" selected="selected">Five</option>
<option value="6">Six</option>
<option value="7">Seven</option>
</select>
<input name="button" type="submit" value="single">
</form>
<form method="POST" id="multiple_select_form">
<select id="multiple" name="multiple" multiple>
<option value="8" selected="selected">Eight</option>
<option value="9">Nine</option>
<option value="10">Ten</option>
<option value="11" selected="selected">Eleven</option>
</select>
<input name="button" type="submit" value="multiple">
</form>
</body>
</html>
""")
else:
select_type = req.POST.get("button")
if select_type == "single":
selection = req.POST.get("single")
elif select_type == "multiple":
selection = ", ".join(req.POST.getall("multiple"))
body = to_bytes("""
<html>
<head><title>display page</title></head>
<body>
<p>You submitted the %(select_type)s </p>
<p>You selected %(selection)s</p>
</body>
</html>
""" % dict(selection=selection, select_type=select_type))
headers = [
('Content-Type', 'text/html; charset=utf-8'),
('Content-Length', str(len(body)))]
# PEP 3333 requires native strings:
headers = [(str(k), str(v)) for k, v in headers]
start_response(status, headers)
return [body]
def select_app_without_values(environ, start_response):
req = Request(environ)
status = b"200 OK"
if req.method == "GET":
body = to_bytes("""
<html>
<head><title>form page</title></head>
<body>
<form method="POST" id="single_select_form">
<select id="single" name="single">
<option>Four</option>
<option>Five</option>
<option>Six</option>
<option>Seven</option>
</select>
<input name="button" type="submit" value="single">
</form>
<form method="POST" id="multiple_select_form">
<select id="multiple" name="multiple" multiple="multiple">
<option>Eight</option>
<option selected value="Nine">Nine</option>
<option>Ten</option>
<option selected>Eleven</option>
</select>
<input name="button" type="submit" value="multiple">
</form>
</body>
</html>
""")
else:
select_type = req.POST.get("button")
if select_type == "single":
selection = req.POST.get("single")
elif select_type == "multiple":
selection = ", ".join(req.POST.getall("multiple"))
body = to_bytes("""
<html>
<head><title>display page</title></head>
<body>
<p>You submitted the %(select_type)s </p>
<p>You selected %(selection)s</p>
</body>
</html>
""" % dict(selection=selection, select_type=select_type))
headers = [
('Content-Type', 'text/html; charset=utf-8'),
('Content-Length', str(len(body)))]
# PEP 3333 requires native strings:
headers = [(str(k), str(v)) for k, v in headers]
start_response(status, headers)
return [body]
def select_app_without_default(environ, start_response):
req = Request(environ)
status = b"200 OK"
if req.method == "GET":
body = to_bytes("""
<html>
<head><title>form page</title></head>
<body>
<form method="POST" id="single_select_form">
<select id="single" name="single">
<option value="4">Four</option>
<option value="5">Five</option>
<option value="6">Six</option>
<option value="7">Seven</option>
</select>
<input name="button" type="submit" value="single">
</form>
<form method="POST" id="multiple_select_form">
<select id="multiple" name="multiple" multiple="multiple">
<option value="8">Eight</option>
<option value="9">Nine</option>
<option value="10">Ten</option>
<option value="11">Eleven</option>
</select>
<input name="button" type="submit" value="multiple">
</form>
</body>
</html>
""")
else:
select_type = req.POST.get("button")
if select_type == "single":
selection = req.POST.get("single")
elif select_type == "multiple":
selection = ", ".join(req.POST.getall("multiple"))
body = to_bytes("""
<html>
<head><title>display page</title></head>
<body>
<p>You submitted the %(select_type)s </p>
<p>You selected %(selection)s</p>
</body>
</html>
""" % dict(selection=selection, select_type=select_type))
headers = [
('Content-Type', 'text/html; charset=utf-8'),
('Content-Length', str(len(body)))]
# PEP 3333 requires native strings:
headers = [(str(k), str(v)) for k, v in headers]
start_response(status, headers)
return [body]
def select_app_unicode(environ, start_response):
req = Request(environ)
status = b"200 OK"
if req.method == "GET":
body = u("""
<html>
<head><title>form page</title></head>
<body>
<form method="POST" id="single_select_form">
<select id="single" name="single">
<option value="ЕКБ">Екатеринбург</option>
<option value="МСК" selected="selected">Москва</option>
<option value="СПБ">Санкт-Петербург</option>
<option value="САМ">Самара</option>
</select>
<input name="button" type="submit" value="single">
</form>
<form method="POST" id="multiple_select_form">
<select id="multiple" name="multiple" multiple="multiple">
<option value="8" selected="selected">Лондон</option>
<option value="9">Париж</option>
<option value="10">Пекин</option>
<option value="11" selected="selected">Бристоль</option>
</select>
<input name="button" type="submit" value="multiple">
</form>
</body>
</html>
""").encode('utf8')
else:
select_type = req.POST.get("button")
if select_type == "single":
selection = req.POST.get("single")
elif select_type == "multiple":
selection = ", ".join(req.POST.getall("multiple"))
body = (u("""
<html>
<head><title>display page</title></head>
<body>
<p>You submitted the %(select_type)s </p>
<p>You selected %(selection)s</p>
</body>
</html>
""") % dict(selection=selection, select_type=select_type)).encode('utf8')
headers = [
('Content-Type', 'text/html; charset=utf-8'),
('Content-Length', str(len(body)))]
# PEP 3333 requires native strings:
headers = [(str(k), str(v)) for k, v in headers]
start_response(status, headers)
if not isinstance(body, binary_type):
raise AssertionError('Body is not %s' % binary_type)
return [body]
class TestSelect(unittest.TestCase):
def test_unicode_select(self):
app = webtest.TestApp(select_app_unicode)
res = app.get('/')
single_form = res.forms["single_select_form"]
self.assertEqual(single_form["single"].value, u("МСК"))
display = single_form.submit("button")
self.assertIn(u("<p>You selected МСК</p>"), display, display)
res = app.get('/')
single_form = res.forms["single_select_form"]
self.assertEqual(single_form["single"].value, u("МСК"))
single_form.set("single", u("СПБ"))
self.assertEqual(single_form["single"].value, u("СПБ"))
display = single_form.submit("button")
self.assertIn(u("<p>You selected СПБ</p>"), display, display)
def test_single_select(self):
app = webtest.TestApp(select_app)
res = app.get('/')
self.assertEqual(res.status_int, 200)
self.assertEqual(res.headers['content-type'],
'text/html; charset=utf-8')
self.assertEqual(res.content_type, 'text/html')
single_form = res.forms["single_select_form"]
self.assertEqual(single_form["single"].value, "5")
display = single_form.submit("button")
self.assertIn("<p>You selected 5</p>", display, display)
res = app.get('/')
self.assertEqual(res.status_int, 200)
self.assertEqual(res.headers['content-type'],
'text/html; charset=utf-8')
self.assertEqual(res.content_type, 'text/html')
single_form = res.forms["single_select_form"]
self.assertEqual(single_form["single"].value, "5")
single_form.set("single", "6")
self.assertEqual(single_form["single"].value, "6")
display = single_form.submit("button")
self.assertIn("<p>You selected 6</p>", display, display)
res = app.get('/')
single_form = res.forms["single_select_form"]
self.assertRaises(ValueError, single_form.select, "single", "5",
text="Five")
self.assertRaises(ValueError, single_form.select, "single",
text="Three")
single_form.select("single", text="Seven")
self.assertEqual(single_form["single"].value, "7")
display = single_form.submit("button")
self.assertIn("<p>You selected 7</p>", display, display)
def test_single_select_forced_value(self):
app = webtest.TestApp(select_app)
res = app.get('/')
self.assertEqual(res.status_int, 200)
self.assertEqual(res.headers['content-type'],
'text/html; charset=utf-8')
self.assertEqual(res.content_type, 'text/html')
single_form = res.forms["single_select_form"]
self.assertEqual(single_form["single"].value, "5")
self.assertRaises(ValueError, single_form.set, "single", "984")
single_form["single"].force_value("984")
self.assertEqual(single_form["single"].value, "984")
display = single_form.submit("button")
self.assertIn("<p>You selected 984</p>", display, display)
def test_single_select_no_default(self):
app = webtest.TestApp(select_app_without_default)
res = app.get('/')
self.assertEqual(res.status_int, 200)
self.assertEqual(res.headers['content-type'],
'text/html; charset=utf-8')
self.assertEqual(res.content_type, 'text/html')
single_form = res.forms["single_select_form"]
self.assertEqual(single_form["single"].value, "4")
display = single_form.submit("button")
self.assertIn("<p>You selected 4</p>", display, display)
res = app.get('/')
self.assertEqual(res.status_int, 200)
self.assertEqual(res.headers['content-type'],
'text/html; charset=utf-8')
self.assertEqual(res.content_type, 'text/html')
single_form = res.forms["single_select_form"]
self.assertEqual(single_form["single"].value, "4")
single_form.set("single", 6)
self.assertEqual(single_form["single"].value, "6")
display = single_form.submit("button")
self.assertIn("<p>You selected 6</p>", display, display)
def test_multiple_select(self):
app = webtest.TestApp(select_app)
res = app.get('/')
self.assertEqual(res.status_int, 200)
self.assertEqual(res.headers['content-type'],
'text/html; charset=utf-8')
self.assertEqual(res.content_type, 'text/html')
multiple_form = res.forms["multiple_select_form"]
self.assertEqual(multiple_form["multiple"].value, ['8', '11'],
multiple_form["multiple"].value)
display = multiple_form.submit("button")
self.assertIn("<p>You selected 8, 11</p>", display, display)
res = app.get('/')
self.assertEqual(res.status_int, 200)
self.assertEqual(res.headers['content-type'],
'text/html; charset=utf-8')
self.assertEqual(res.content_type, 'text/html')
multiple_form = res.forms["multiple_select_form"]
self.assertEqual(multiple_form["multiple"].value, ["8", "11"],
multiple_form["multiple"].value)
multiple_form.set("multiple", ["9"])
self.assertEqual(multiple_form["multiple"].value, ["9"],
multiple_form["multiple"].value)
display = multiple_form.submit("button")
self.assertIn("<p>You selected 9</p>", display, display)
res = app.get('/')
multiple_form = res.forms["multiple_select_form"]
self.assertRaises(ValueError, multiple_form.select_multiple,
"multiple",
["8", "10"], texts=["Eight", "Ten"])
self.assertRaises(ValueError, multiple_form.select_multiple,
"multiple", texts=["Twelve"])
multiple_form.select_multiple("multiple",
texts=["Eight", "Nine", "Ten"])
display = multiple_form.submit("button")
self.assertIn("<p>You selected 8, 9, 10</p>", display, display)
def test_multiple_select_forced_values(self):
app = webtest.TestApp(select_app)
res = app.get('/')
self.assertEqual(res.status_int, 200)
self.assertEqual(res.headers['content-type'],
'text/html; charset=utf-8')
self.assertEqual(res.content_type, 'text/html')
multiple_form = res.forms["multiple_select_form"]
self.assertEqual(multiple_form["multiple"].value, ["8", "11"],
multiple_form["multiple"].value)
self.assertRaises(ValueError, multiple_form.set,
"multiple", ["24", "88"])
multiple_form["multiple"].force_value(["24", "88"])
self.assertEqual(multiple_form["multiple"].value, ["24", "88"],
multiple_form["multiple"].value)
display = multiple_form.submit("button")
self.assertIn("<p>You selected 24, 88</p>", display, display)
def test_multiple_select_no_default(self):
app = webtest.TestApp(select_app_without_default)
res = app.get('/')
self.assertEqual(res.status_int, 200)
self.assertEqual(res.headers['content-type'],
'text/html; charset=utf-8')
self.assertEqual(res.content_type, 'text/html')
multiple_form = res.forms["multiple_select_form"]
self.assertTrue(multiple_form["multiple"].value is None,
repr(multiple_form["multiple"].value))
display = multiple_form.submit("button")
self.assertIn("<p>You selected </p>", display, display)
res = app.get('/')
self.assertEqual(res.status_int, 200)
self.assertEqual(res.headers['content-type'],
'text/html; charset=utf-8')
self.assertEqual(res.content_type, 'text/html')
multiple_form = res.forms["multiple_select_form"]
self.assertTrue(multiple_form["multiple"].value is None,
multiple_form["multiple"].value)
multiple_form.set("multiple", ["9"])
self.assertEqual(multiple_form["multiple"].value, ["9"],
multiple_form["multiple"].value)
display = multiple_form.submit("button")
self.assertIn("<p>You selected 9</p>", display, display)
def test_select_no_value(self):
app = webtest.TestApp(select_app_without_values)
res = app.get('/')
self.assertEqual(res.status_int, 200)
self.assertEqual(res.headers['content-type'],
'text/html; charset=utf-8')
self.assertEqual(res.content_type, 'text/html')
single_form = res.forms["single_select_form"]
self.assertEqual(single_form["single"].value, "Four")
display = single_form.submit("button")
self.assertIn("<p>You selected Four</p>", display, display)
res = app.get('/')
self.assertEqual(res.status_int, 200)
self.assertEqual(res.headers['content-type'],
'text/html; charset=utf-8')
self.assertEqual(res.content_type, 'text/html')
single_form = res.forms["single_select_form"]
self.assertEqual(single_form["single"].value, "Four")
single_form.set("single", "Six")
self.assertEqual(single_form["single"].value, "Six")
display = single_form.submit("button")
self.assertIn("<p>You selected Six</p>", display, display)
def test_multiple_select_no_value(self):
app = webtest.TestApp(select_app_without_values)
res = app.get('/')
self.assertEqual(res.status_int, 200)
self.assertEqual(res.headers['content-type'],
'text/html; charset=utf-8')
self.assertEqual(res.content_type, 'text/html')
multiple_form = res.forms["multiple_select_form"]
self.assertEqual(multiple_form["multiple"].value, ["Nine", "Eleven"])
display = multiple_form.submit("button")
self.assertIn("<p>You selected Nine, Eleven</p>", display, display)
res = app.get('/')
self.assertEqual(res.status_int, 200)
self.assertEqual(res.headers['content-type'],
'text/html; charset=utf-8')
self.assertEqual(res.content_type, 'text/html')
multiple_form = res.forms["multiple_select_form"]
self.assertEqual(multiple_form["multiple"].value, ["Nine", "Eleven"])
multiple_form.set("multiple", ["Nine", "Ten"])
self.assertEqual(multiple_form["multiple"].value, ["Nine", "Ten"])
display = multiple_form.submit("button")
self.assertIn("<p>You selected Nine, Ten</p>", display, display)
def test_multiple_select_reset_value(self):
app = webtest.TestApp(select_app_without_values)
res = app.get('/')
self.assertEqual(res.status_int, 200)
self.assertEqual(res.headers['content-type'],
'text/html; charset=utf-8')
self.assertEqual(res.content_type, 'text/html')
multiple_form = res.forms["multiple_select_form"]
self.assertEqual(multiple_form["multiple"].value, ["Nine", "Eleven"])
multiple_form["multiple"].force_value(None)
self.assertIsNone(multiple_form["multiple"].value)
display = multiple_form.submit("button")
self.assertIn("<p>You selected </p>", display, display)
class SingleUploadFileApp(object):
body = b"""
<html>
<head><title>form page</title></head>
<body>
<form method="POST" id="file_upload_form"
enctype="multipart/form-data">
<input name="file-field" type="file" value="some/path/file.txt" />
<input name="int-field" type="text" value="" />
<input name="button" type="submit" value="single">
</form>
</body>
</html>
"""
def __call__(self, environ, start_response):
req = Request(environ)
status = b"200 OK"
if req.method == "GET":
body = self.body
else:
body = b"""
<html>
<head><title>display page</title></head>
<body>
""" + self.get_files_page(req) + b"""
</body>
</html>
"""
headers = [
('Content-Type', 'text/html; charset=utf-8'),
('Content-Length', str(len(body)))]
# PEP 3333 requires native strings:
headers = [(str(k), str(v)) for k, v in headers]
start_response(status, headers)
assert(isinstance(body, binary_type))
return [body]
def get_files_page(self, req):
file_parts = []
uploaded_files = [(k, v) for k, v in req.POST.items() if 'file' in k]
uploaded_files = sorted(uploaded_files)
for name, uploaded_file in uploaded_files:
if isinstance(uploaded_file, cgi.FieldStorage):
filename = to_bytes(uploaded_file.filename)
value = to_bytes(uploaded_file.value, 'ascii')
content_type = to_bytes(uploaded_file.type, 'ascii')
else:
filename = value = content_type = b''
file_parts.append(b"""
<p>You selected '""" + filename + b"""'</p>
<p>with contents: '""" + value + b"""'</p>
<p>with content type: '""" + content_type + b"""'</p>
""")
return b''.join(file_parts)
class UploadBinaryApp(SingleUploadFileApp):
def get_files_page(self, req):
uploaded_files = [(k, v) for k, v in req.POST.items() if 'file' in k]
data = uploaded_files[0][1].value
if PY3:
data = struct.unpack(b'255h', data[:510])
else:
data = struct.unpack(str('255h'), data)
return b','.join([to_bytes(str(i)) for i in data])
class MultipleUploadFileApp(SingleUploadFileApp):
body = b"""
<html>
<head><title>form page</title></head>
<body>
<form method="POST" id="file_upload_form"
enctype="multipart/form-data">
<input name="file-field-1" type="file" />
<input name="file-field-2" type="file" />
<input name="button" type="submit" value="single">
</form>
</body>
</html>
"""
class TestFileUpload(unittest.TestCase):
def assertFile(self, name, contents, display, content_type=None):
if isinstance(name, six.binary_type):
text_name = name.decode('ascii')
else:
text_name = name
self.assertIn("<p>You selected '" + text_name + "'</p>",
display, display)
if isinstance(contents, six.binary_type):
text_contents = contents.decode('ascii')
else:
text_contents = contents
self.assertIn("<p>with contents: '" + text_contents + "'</p>",
display, display)
if content_type:
self.assertIn("<p>with content type: '" + content_type + "'</p>",
display, display)
def test_no_uploads_error(self):
app = webtest.TestApp(SingleUploadFileApp())
app.get('/').forms["file_upload_form"].upload_fields()
def test_upload_without_file(self):
app = webtest.TestApp(SingleUploadFileApp())
upload_form = app.get('/').forms["file_upload_form"]
upload_form.submit()
def test_file_upload_with_filename_only(self):
uploaded_file_name = os.path.join(os.path.dirname(__file__),
"__init__.py")
uploaded_file_contents = open(uploaded_file_name).read()
if PY3:
uploaded_file_contents = to_bytes(uploaded_file_contents)
app = webtest.TestApp(SingleUploadFileApp())
res = app.get('/')
self.assertEqual(res.status_int, 200)
self.assertEqual(res.headers['content-type'],
'text/html; charset=utf-8')
self.assertEqual(res.content_type, 'text/html')
self.assertEqual(res.charset, 'utf-8')
single_form = res.forms["file_upload_form"]
single_form.set("file-field", (uploaded_file_name,))
display = single_form.submit("button")
self.assertFile(uploaded_file_name, uploaded_file_contents, display)
def test_file_upload_with_filename_and_contents(self):
uploaded_file_name = os.path.join(os.path.dirname(__file__),
"__init__.py")
uploaded_file_contents = open(uploaded_file_name).read()
if PY3:
uploaded_file_contents = to_bytes(uploaded_file_contents)
app = webtest.TestApp(SingleUploadFileApp())
res = app.get('/')
self.assertEqual(res.status_int, 200)
self.assertEqual(res.headers['content-type'],
'text/html; charset=utf-8')
self.assertEqual(res.content_type, 'text/html')
single_form = res.forms["file_upload_form"]
single_form.set("file-field",
(uploaded_file_name, uploaded_file_contents))
display = single_form.submit("button")
self.assertFile(uploaded_file_name, uploaded_file_contents, display)
def test_file_upload_with_content_type(self):
uploaded_file_name = os.path.join(os.path.dirname(__file__),
"__init__.py")
with open(uploaded_file_name, 'rb') as f:
uploaded_file_contents = f.read()
app = webtest.TestApp(SingleUploadFileApp())
res = app.get('/')
single_form = res.forms["file_upload_form"]
single_form["file-field"].value = Upload(uploaded_file_name,
uploaded_file_contents,
'text/x-custom-type')
display = single_form.submit("button")
self.assertFile(uploaded_file_name, uploaded_file_contents, display,
content_type='text/x-custom-type')
def test_file_upload_binary(self):
binary_data = struct.pack(str('255h'), *range(0, 255))
app = webtest.TestApp(UploadBinaryApp())
res = app.get('/')
single_form = res.forms["file_upload_form"]
single_form.set("file-field", ('my_file.dat', binary_data))
display = single_form.submit("button")
self.assertIn(','.join([str(n) for n in range(0, 255)]), display)
def test_multiple_file_uploads_with_filename_and_contents(self):
uploaded_file1_name = os.path.join(os.path.dirname(__file__),
"__init__.py")
uploaded_file1_contents = open(uploaded_file1_name).read()
if PY3:
uploaded_file1_contents = to_bytes(uploaded_file1_contents)
uploaded_file2_name = __file__
uploaded_file2_name = os.path.join(os.path.dirname(__file__), 'html',
"404.html")
uploaded_file2_contents = open(uploaded_file2_name).read()
if PY3:
uploaded_file2_contents = to_bytes(uploaded_file2_contents)
app = webtest.TestApp(MultipleUploadFileApp())
res = app.get('/')
self.assertEqual(res.status_int, 200)
self.assertEqual(res.headers['content-type'],
'text/html; charset=utf-8')
self.assertEqual(res.content_type, 'text/html')
single_form = res.forms["file_upload_form"]
single_form.set("file-field-1",
(uploaded_file1_name, uploaded_file1_contents))
single_form.set("file-field-2",
(uploaded_file2_name, uploaded_file2_contents))
display = single_form.submit("button")
self.assertFile(uploaded_file1_name, uploaded_file1_contents, display)
self.assertFile(uploaded_file1_name, uploaded_file1_contents, display)
def test_post_int(self):
binary_data = struct.pack(str('255h'), *range(0, 255))
app = webtest.TestApp(SingleUploadFileApp())
res = app.get('/')
single_form = res.forms["file_upload_form"]
single_form.set("file-field", ('my_file.dat', binary_data))
single_form.set("int-field", 100)
# just check it does not raise
single_form.submit("button")
def test_invalid_types(self):
binary_data = struct.pack(str('255h'), *range(0, 255))
app = webtest.TestApp(SingleUploadFileApp())
res = app.get('/')
single_form = res.forms["file_upload_form"]
single_form.set("file-field", ('my_file.dat', binary_data))
single_form.set("int-field", SingleUploadFileApp())
self.assertRaises(ValueError, single_form.submit, "button")
def test_upload_invalid_content(self):
app = webtest.TestApp(SingleUploadFileApp())
res = app.get('/')
single_form = res.forms["file_upload_form"]
single_form.set("file-field", ('my_file.dat', 1))
try:
single_form.submit("button")
except ValueError:
e = sys.exc_info()[1]
self.assertEquals(
six.text_type(e),
u('File content must be %s not %s' % (binary_type, int))
)
def test_invalid_uploadfiles(self):
app = webtest.TestApp(SingleUploadFileApp())
self.assertRaises(ValueError, app.post, '/', upload_files=[()])
self.assertRaises(
ValueError,
app.post, '/',
upload_files=[('name', 'filename', 'content', 'extra')]
)
def test_goto_upload_files(self):
app = webtest.TestApp(SingleUploadFileApp())
resp = app.get('/')
resp = resp.goto(
'/',
method='post',
upload_files=[('file', 'filename', b'content')]
)
resp.mustcontain("<p>You selected 'filename'</p>",
"<p>with contents: 'content'</p>")
def test_post_upload_files(self):
app = webtest.TestApp(SingleUploadFileApp())
resp = app.post(
'/',
upload_files=[('file', 'filename', b'content')]
)
resp.mustcontain("<p>You selected 'filename'</p>",
"<p>with contents: 'content'</p>")
def test_post_upload_empty_files(self):
app = webtest.TestApp(SingleUploadFileApp())
resp = app.post(
'/',
upload_files=[('file', 'filename', b'')]
)
resp.mustcontain("<p>You selected 'filename'</p>",
"<p>with contents: ''</p>")
resp = app.get('/')
form = resp.form
form['file-field'] = Upload('filename', b'', 'text/plain')
resp = form.submit()
resp.mustcontain("<p>You selected 'filename'</p>",
"<p>with contents: ''</p>")