From ac916739f8cb3a7ebb407e469ea322fc411f1da1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Thu, 16 Sep 2021 14:35:48 +0200
Subject: [PATCH 1/2] misc: split file field tests (#54131)

---
 tests/form_pages/test_all.py        | 313 -----------------------
 tests/form_pages/test_file_field.py | 377 ++++++++++++++++++++++++++++
 2 files changed, 377 insertions(+), 313 deletions(-)
 create mode 100644 tests/form_pages/test_file_field.py

diff --git a/tests/form_pages/test_all.py b/tests/form_pages/test_all.py
index b9a2d72f..8cfde7c9 100644
--- a/tests/form_pages/test_all.py
+++ b/tests/form_pages/test_all.py
@@ -3339,319 +3339,6 @@ def test_form_captcha_and_no_validation_page(pub):
     assert 'form_captcha' in resp.text
 
 
-def test_form_file_field_with_fargo(pub, fargo_url):
-    create_user(pub)
-    formdef = create_formdef()
-    file_field = fields.FileField(id='0', label='file')
-    assert file_field.allow_portfolio_picking is False
-    file_field.allow_portfolio_picking = True
-    formdef.fields = [file_field]
-    formdef.store()
-    formdef.data_class().wipe()
-
-    assert file_field.allow_portfolio_picking is True
-
-    resp = get_app(pub).get('/test/')
-    assert 'f0$file' in resp.text
-    assert 'fargo.js' not in resp.text
-    assert 'use-file-from-fargo' not in resp.text
-
-    app = get_app(pub)
-    login(app, username='foo', password='foo')
-    resp = app.get('/test/')
-    assert 'f0$file' in resp.text
-    assert 'fargo.js' in resp.text
-    assert 'use-file-from-fargo' in resp.text
-
-    fargo_resp = app.get('/fargo/pick')  # display file picker
-    assert fargo_resp.location == 'http://fargo.example.net/pick/?pick=http%3A//example.net/fargo/pick'
-    with mock.patch('wcs.portfolio.urlopen') as urlopen:
-        urlopen.side_effect = lambda *args: io.BytesIO(b'...')
-        fargo_resp = app.get('/fargo/pick?url=http://www.example.org/...')
-        assert 'window.top.document.fargo_set_token' in fargo_resp.text
-    resp.form['f0$file'] = None
-    resp.form['f0$token'] = re.findall(r'fargo_set_token\("(.*?)"', fargo_resp.text)[0]
-    resp = resp.form.submit('submit')
-    assert 'Check values then click submit.' in resp.text
-    resp = resp.form.submit('submit')
-    assert formdef.data_class().count() == 1
-    formdata = formdef.data_class().select()[0]
-    assert formdata.data['0'].get_content() == b'...'
-
-    file_field.allow_portfolio_picking = False
-    formdef.store()
-
-    resp = login(get_app(pub), username='foo', password='foo').get('/test/')
-    assert 'f0$file' in resp.text
-    assert 'fargo.js' not in resp.text
-    assert 'use-file-from-fargo' not in resp.text
-
-
-def test_form_file_field_without_fargo(pub):
-    create_user(pub)
-    formdef = create_formdef()
-    file_field = fields.FileField(id='0', label='file')
-    file_field.allow_portfolio_picking = True
-    formdef.fields = [file_field]
-    formdef.store()
-    formdef.data_class().wipe()
-
-    assert file_field.allow_portfolio_picking is True
-
-    resp = get_app(pub).get('/test/')
-    assert 'f0$file' in resp.text
-    assert 'fargo.js' not in resp.text
-    assert 'use-file-from-fargo' not in resp.text
-
-    resp = login(get_app(pub), username='foo', password='foo').get('/test/')
-    assert 'f0$file' in resp.text
-    assert 'fargo.js' not in resp.text
-    assert 'use-file-from-fargo' not in resp.text
-
-
-def test_form_file_field_submit(pub):
-    formdef = create_formdef()
-    formdef.fields = [fields.FileField(id='0', label='file')]
-    formdef.store()
-    formdef.data_class().wipe()
-
-    upload = Upload('test.txt', b'foobar', 'text/plain')
-
-    resp = get_app(pub).get('/test/')
-    resp.forms[0]['f0$file'] = upload
-    resp = resp.forms[0].submit('submit')
-    assert 'Check values then click submit.' in resp.text
-    resp = resp.forms[0].submit('submit')
-    assert resp.status_int == 302
-    resp = resp.follow()
-    assert 'The form has been recorded' in resp.text
-    resp = resp.click('test.txt')
-    assert resp.location.endswith('/test.txt')
-    resp = resp.follow()
-    assert resp.content_type == 'text/plain'
-    assert resp.text == 'foobar'
-
-
-def test_form_preupload_file_field_submit(pub):
-    formdef = create_formdef()
-    formdef.fields = [fields.FileField(id='0', label='file')]
-    formdef.store()
-    formdef.data_class().wipe()
-
-    app = get_app(pub)
-
-    resp = app.get('/test/')
-    upload = Upload('test.txt', b'foobar', 'text/plain')
-    resp.form['f0$file'] = upload
-
-    # this part is actually done in javascript
-    upload_url = resp.form['f0$file'].attrs['data-url']
-    upload_resp = app.post(upload_url, params=resp.form.submit_fields())
-    resp.form['f0$file'] = None
-    resp.form['f0$token'] = upload_resp.json[0]['token']
-
-    resp = resp.forms[0].submit('submit')
-    assert 'Check values then click submit.' in resp.text
-    resp = resp.forms[0].submit('submit')
-    assert resp.status_int == 302
-    resp = resp.follow()
-    assert 'The form has been recorded' in resp.text
-    resp = resp.click('test.txt')
-    assert resp.location.endswith('/test.txt')
-    resp = resp.follow()
-    assert resp.content_type == 'text/plain'
-    assert resp.text == 'foobar'
-
-    # upload error if file storage is unknown (out of order)
-    formdef.fields[0].storage = 'unknown-storage'
-    formdef.store()
-    resp = app.get('/test/')
-    resp.form['f0$file'] = upload
-    # javascript simulation
-    upload_url = resp.form['f0$file'].attrs['data-url']
-    upload_resp = app.post(upload_url, params=resp.form.submit_fields())
-    assert upload_resp.json == [{'error': 'failed to store file (system error)'}]
-    # try to post the form anyway (with file in f0$file, i.e. "no javascript")
-    resp = resp.forms[0].submit('submit')
-    assert 'Check values then click submit.' not in resp.text
-    assert 'failed to store file (system error)' in resp.text
-
-
-def test_form_file_field_image_submit(pub):
-    formdef = create_formdef()
-    formdef.fields = [fields.FileField(id='0', label='file')]
-    formdef.store()
-    formdef.data_class().wipe()
-
-    with open(os.path.join(os.path.dirname(__file__), '..', 'image-with-gps-data.jpeg'), 'rb') as fd:
-        image_content = fd.read()
-    upload = Upload('test.jpg', image_content, 'image/jpeg')
-
-    app = get_app(pub)
-    resp = app.get('/test/')
-    resp.forms[0]['f0$file'] = upload
-    resp = resp.forms[0].submit('submit')
-    assert 'Check values then click submit.' in resp.text
-    assert '<img alt="" src="tempfile?' in resp.text
-    tempfile_id = resp.text[resp.text.index('tempfile?') :].split('&', 1)[0].split('=')[1]
-
-    resp_tempfile = app.get('/test/tempfile?t=%s' % tempfile_id)
-    assert resp_tempfile.body == image_content
-
-    if Image:
-        # check thumbnailing of image in validation page
-        resp_thumbnail = app.get('/test/tempfile?t=%s&thumbnail=1' % tempfile_id)
-        assert resp_thumbnail.content_type == 'image/png'
-
-    resp = resp.form.submit('submit').follow()
-    assert '<img ' in resp.text
-    assert 'download?f=0&thumbnail=1' in resp.text
-    resp = resp.goto('download?f=0&thumbnail=1')
-    assert '/thumbnail/' in resp.location
-    resp = resp.follow()
-    if Image:
-        # check thumbnailing of image in submitted form
-        assert resp.content_type == 'image/png'
-
-        # check a fake image is not sent back
-        upload = Upload('test.jpg', b'<script>evil javascript</script>', 'image/jpeg')
-        app = get_app(pub)
-        resp = app.get('/test/')
-        resp.forms[0]['f0$file'] = upload
-        resp = resp.forms[0].submit('submit')
-        assert '<img alt="" src="tempfile?' not in resp.text
-
-
-def test_form_file_field_submit_document_type(pub):
-    formdef = create_formdef()
-    formdef.fields = [
-        fields.FileField(
-            id='0',
-            label='file',
-            document_type={
-                'id': 1,
-                'mimetypes': ['image/*'],
-                'label': 'Image files',
-            },
-        )
-    ]
-    formdef.store()
-    formdef.data_class().wipe()
-
-    upload = Upload('test.txt', b'foobar', 'application/force-download')
-
-    resp = get_app(pub).get('/test/')
-    resp.form['f0$file'] = upload
-    resp = resp.form.submit('submit')
-    assert 'invalid file type' in resp.text
-
-    with open(os.path.join(os.path.dirname(__file__), '..', 'image-with-gps-data.jpeg'), 'rb') as fd:
-        image_content = fd.read()
-    upload = Upload('test.jpg', image_content, 'image/jpeg')
-    resp = get_app(pub).get('/test/')
-    resp.form['f0$file'] = upload
-    resp = resp.form.submit('submit')
-    assert 'Check values then click submit.' in resp.text
-
-
-def test_form_file_field_submit_max_file_size(pub):
-    formdef = create_formdef()
-    formdef.fields = [fields.FileField(id='0', label='file', max_file_size='1ko')]
-    formdef.store()
-    formdef.data_class().wipe()
-
-    upload = Upload('test.txt', b'foobar' * 1000, 'application/force-download')
-    resp = get_app(pub).get('/test/')
-    resp.form['f0$file'] = upload
-    resp = resp.form.submit('submit')
-    assert 'over file size limit (1ko)' in resp.text
-
-    upload = Upload('test.txt', b'foobar' * 100, 'application/force-download')
-    resp = get_app(pub).get('/test/')
-    resp.form['f0$file'] = upload
-    resp = resp.form.submit('submit')
-    assert 'Check values then click submit.' in resp.text
-
-
-def test_form_file_field_submit_wrong_mimetype(pub):
-    formdef = create_formdef()
-    formdef.fields = [fields.FileField(id='0', label='file')]
-    formdef.store()
-    formdef.data_class().wipe()
-
-    upload = Upload('test.txt', b'foobar', 'application/force-download')
-
-    resp = get_app(pub).get('/test/')
-    resp.forms[0]['f0$file'] = upload
-    resp = resp.forms[0].submit('submit')
-    assert 'Check values then click submit.' in resp.text
-    resp = resp.forms[0].submit('submit')
-    assert resp.status_int == 302
-    resp = resp.follow()
-    assert 'The form has been recorded' in resp.text
-    resp = resp.click('test.txt')
-    assert resp.location.endswith('/test.txt')
-    resp = resp.follow()
-    assert resp.content_type == 'text/plain'
-    assert resp.text == 'foobar'
-
-    upload = Upload('test.pdf', b'%PDF-1.4 ...', 'application/force-download')
-
-    resp = get_app(pub).get('/test/')
-    resp.forms[0]['f0$file'] = upload
-    resp = resp.forms[0].submit('submit')
-    assert 'Check values then click submit.' in resp.text
-    resp = resp.forms[0].submit('submit')
-    assert resp.status_int == 302
-    resp = resp.follow()
-    assert 'The form has been recorded' in resp.text
-    resp = resp.click('test.pdf')
-    assert resp.location.endswith('/test.pdf')
-    resp = resp.follow()
-    assert resp.content_type == 'application/pdf'
-    assert resp.text == '%PDF-1.4 ...'
-
-
-def test_form_file_field_submit_blacklist(pub):
-    formdef = create_formdef()
-    formdef.fields = [fields.FileField(id='0', label='file')]
-    formdef.store()
-    formdef.data_class().wipe()
-
-    # application/x-ms-dos-executable
-    upload = Upload('test.exe', b'MZ...', 'application/force-download')
-    resp = get_app(pub).get('/test/')
-    resp.forms[0]['f0$file'] = upload
-    resp = resp.forms[0].submit('submit')
-    assert 'forbidden file type' in resp.text
-
-    # define custom blacklist
-    pub.load_site_options()
-    if not pub.site_options.has_section('options'):
-        pub.site_options.add_section('options')
-    pub.site_options.set('options', 'blacklisted-file-types', 'application/pdf')
-    with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
-        pub.site_options.write(fd)
-
-    # check against mime type
-    upload = Upload('test.pdf', b'%PDF-1.4 ...', 'application/force-download')
-    resp = get_app(pub).get('/test/')
-    resp.forms[0]['f0$file'] = upload
-    resp = resp.forms[0].submit('submit')
-    assert 'forbidden file type' in resp.text
-
-    # check against extension
-    pub.site_options.set('options', 'blacklisted-file-types', '.pdf')
-    with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
-        pub.site_options.write(fd)
-
-    upload = Upload('test.pdf', b'%PDF-1.4 ...', 'application/force-download')
-    resp = get_app(pub).get('/test/')
-    resp.forms[0]['f0$file'] = upload
-    resp = resp.forms[0].submit('submit')
-    assert 'forbidden file type' in resp.text
-
-
 def test_form_table_field_submit(pub, emails):
     formdef = create_formdef()
     formdef.fields = [
diff --git a/tests/form_pages/test_file_field.py b/tests/form_pages/test_file_field.py
new file mode 100644
index 00000000..f4fff7b1
--- /dev/null
+++ b/tests/form_pages/test_file_field.py
@@ -0,0 +1,377 @@
+import io
+import os
+import re
+from unittest import mock
+
+import pytest
+from webtest import Upload
+
+try:
+    from PIL import Image
+except ImportError:
+    Image = None
+
+from wcs import fields
+from wcs.categories import Category
+from wcs.formdef import FormDef
+
+from ..utilities import clean_temporary_pub, create_temporary_pub, get_app, login
+from .test_all import create_user
+
+
+def pytest_generate_tests(metafunc):
+    if 'pub' in metafunc.fixturenames:
+        metafunc.parametrize('pub', ['pickle', 'sql', 'pickle-templates', 'pickle-lazy'], indirect=True)
+
+
+@pytest.fixture
+def pub(request):
+    pub = create_temporary_pub(
+        sql_mode=bool('sql' in request.param),
+        templates_mode=bool('templates' in request.param),
+        lazy_mode=bool('lazy' in request.param),
+    )
+    pub.cfg['identification'] = {'methods': ['password']}
+    pub.cfg['language'] = {'language': 'en'}
+    pub.write_cfg()
+
+    if Category.count() == 0:
+        cat = Category(name='foobar')
+        cat.store()
+
+    return pub
+
+
+def teardown_module(module):
+    clean_temporary_pub()
+
+
+def test_form_file_field_with_fargo(pub, fargo_url):
+    create_user(pub)
+    FormDef.wipe()
+    formdef = FormDef()
+    formdef.name = 'test'
+    file_field = fields.FileField(id='0', label='file')
+    assert file_field.allow_portfolio_picking is False
+    file_field.allow_portfolio_picking = True
+    formdef.fields = [file_field]
+    formdef.store()
+    formdef.data_class().wipe()
+
+    assert file_field.allow_portfolio_picking is True
+
+    resp = get_app(pub).get('/test/')
+    assert 'f0$file' in resp.text
+    assert 'fargo.js' not in resp.text
+    assert 'use-file-from-fargo' not in resp.text
+
+    app = get_app(pub)
+    login(app, username='foo', password='foo')
+    resp = app.get('/test/')
+    assert 'f0$file' in resp.text
+    assert 'fargo.js' in resp.text
+    assert 'use-file-from-fargo' in resp.text
+
+    fargo_resp = app.get('/fargo/pick')  # display file picker
+    assert fargo_resp.location == 'http://fargo.example.net/pick/?pick=http%3A//example.net/fargo/pick'
+    with mock.patch('wcs.portfolio.urlopen') as urlopen:
+        urlopen.side_effect = lambda *args: io.BytesIO(b'...')
+        fargo_resp = app.get('/fargo/pick?url=http://www.example.org/...')
+        assert 'window.top.document.fargo_set_token' in fargo_resp.text
+    resp.form['f0$file'] = None
+    resp.form['f0$token'] = re.findall(r'fargo_set_token\("(.*?)"', fargo_resp.text)[0]
+    resp = resp.form.submit('submit')
+    assert 'Check values then click submit.' in resp.text
+    resp = resp.form.submit('submit')
+    assert formdef.data_class().count() == 1
+    formdata = formdef.data_class().select()[0]
+    assert formdata.data['0'].get_content() == b'...'
+
+    file_field.allow_portfolio_picking = False
+    formdef.store()
+
+    resp = login(get_app(pub), username='foo', password='foo').get('/test/')
+    assert 'f0$file' in resp.text
+    assert 'fargo.js' not in resp.text
+    assert 'use-file-from-fargo' not in resp.text
+
+
+def test_form_file_field_without_fargo(pub):
+    create_user(pub)
+    FormDef.wipe()
+    formdef = FormDef()
+    formdef.name = 'test'
+    file_field = fields.FileField(id='0', label='file')
+    file_field.allow_portfolio_picking = True
+    formdef.fields = [file_field]
+    formdef.store()
+    formdef.data_class().wipe()
+
+    assert file_field.allow_portfolio_picking is True
+
+    resp = get_app(pub).get('/test/')
+    assert 'f0$file' in resp.text
+    assert 'fargo.js' not in resp.text
+    assert 'use-file-from-fargo' not in resp.text
+
+    resp = login(get_app(pub), username='foo', password='foo').get('/test/')
+    assert 'f0$file' in resp.text
+    assert 'fargo.js' not in resp.text
+    assert 'use-file-from-fargo' not in resp.text
+
+
+def test_form_file_field_submit(pub):
+    FormDef.wipe()
+    formdef = FormDef()
+    formdef.name = 'test'
+    formdef.fields = [fields.FileField(id='0', label='file')]
+    formdef.store()
+    formdef.data_class().wipe()
+
+    upload = Upload('test.txt', b'foobar', 'text/plain')
+
+    resp = get_app(pub).get('/test/')
+    resp.forms[0]['f0$file'] = upload
+    resp = resp.forms[0].submit('submit')
+    assert 'Check values then click submit.' in resp.text
+    resp = resp.forms[0].submit('submit')
+    assert resp.status_int == 302
+    resp = resp.follow()
+    assert 'The form has been recorded' in resp.text
+    resp = resp.click('test.txt')
+    assert resp.location.endswith('/test.txt')
+    resp = resp.follow()
+    assert resp.content_type == 'text/plain'
+    assert resp.text == 'foobar'
+
+
+def test_form_preupload_file_field_submit(pub):
+    FormDef.wipe()
+    formdef = FormDef()
+    formdef.name = 'test'
+    formdef.fields = [fields.FileField(id='0', label='file')]
+    formdef.store()
+    formdef.data_class().wipe()
+
+    app = get_app(pub)
+
+    resp = app.get('/test/')
+    upload = Upload('test.txt', b'foobar', 'text/plain')
+    resp.form['f0$file'] = upload
+
+    # this part is actually done in javascript
+    upload_url = resp.form['f0$file'].attrs['data-url']
+    upload_resp = app.post(upload_url, params=resp.form.submit_fields())
+    resp.form['f0$file'] = None
+    resp.form['f0$token'] = upload_resp.json[0]['token']
+
+    resp = resp.forms[0].submit('submit')
+    assert 'Check values then click submit.' in resp.text
+    resp = resp.forms[0].submit('submit')
+    assert resp.status_int == 302
+    resp = resp.follow()
+    assert 'The form has been recorded' in resp.text
+    resp = resp.click('test.txt')
+    assert resp.location.endswith('/test.txt')
+    resp = resp.follow()
+    assert resp.content_type == 'text/plain'
+    assert resp.text == 'foobar'
+
+    # upload error if file storage is unknown (out of order)
+    formdef.fields[0].storage = 'unknown-storage'
+    formdef.store()
+    resp = app.get('/test/')
+    resp.form['f0$file'] = upload
+    # javascript simulation
+    upload_url = resp.form['f0$file'].attrs['data-url']
+    upload_resp = app.post(upload_url, params=resp.form.submit_fields())
+    assert upload_resp.json == [{'error': 'failed to store file (system error)'}]
+    # try to post the form anyway (with file in f0$file, i.e. "no javascript")
+    resp = resp.forms[0].submit('submit')
+    assert 'Check values then click submit.' not in resp.text
+    assert 'failed to store file (system error)' in resp.text
+
+
+def test_form_file_field_image_submit(pub):
+    FormDef.wipe()
+    formdef = FormDef()
+    formdef.name = 'test'
+    formdef.fields = [fields.FileField(id='0', label='file')]
+    formdef.store()
+    formdef.data_class().wipe()
+
+    with open(os.path.join(os.path.dirname(__file__), '..', 'image-with-gps-data.jpeg'), 'rb') as fd:
+        image_content = fd.read()
+    upload = Upload('test.jpg', image_content, 'image/jpeg')
+
+    app = get_app(pub)
+    resp = app.get('/test/')
+    resp.forms[0]['f0$file'] = upload
+    resp = resp.forms[0].submit('submit')
+    assert 'Check values then click submit.' in resp.text
+    assert '<img alt="" src="tempfile?' in resp.text
+    tempfile_id = resp.text[resp.text.index('tempfile?') :].split('&', 1)[0].split('=')[1]
+
+    resp_tempfile = app.get('/test/tempfile?t=%s' % tempfile_id)
+    assert resp_tempfile.body == image_content
+
+    if Image:
+        # check thumbnailing of image in validation page
+        resp_thumbnail = app.get('/test/tempfile?t=%s&thumbnail=1' % tempfile_id)
+        assert resp_thumbnail.content_type == 'image/png'
+
+    resp = resp.form.submit('submit').follow()
+    assert '<img ' in resp.text
+    assert 'download?f=0&thumbnail=1' in resp.text
+    resp = resp.goto('download?f=0&thumbnail=1')
+    assert '/thumbnail/' in resp.location
+    resp = resp.follow()
+    if Image:
+        # check thumbnailing of image in submitted form
+        assert resp.content_type == 'image/png'
+
+        # check a fake image is not sent back
+        upload = Upload('test.jpg', b'<script>evil javascript</script>', 'image/jpeg')
+        app = get_app(pub)
+        resp = app.get('/test/')
+        resp.forms[0]['f0$file'] = upload
+        resp = resp.forms[0].submit('submit')
+        assert '<img alt="" src="tempfile?' not in resp.text
+
+
+def test_form_file_field_submit_document_type(pub):
+    FormDef.wipe()
+    formdef = FormDef()
+    formdef.name = 'test'
+    formdef.fields = [
+        fields.FileField(
+            id='0',
+            label='file',
+            document_type={
+                'id': 1,
+                'mimetypes': ['image/*'],
+                'label': 'Image files',
+            },
+        )
+    ]
+    formdef.store()
+    formdef.data_class().wipe()
+
+    upload = Upload('test.txt', b'foobar', 'application/force-download')
+
+    resp = get_app(pub).get('/test/')
+    resp.form['f0$file'] = upload
+    resp = resp.form.submit('submit')
+    assert 'invalid file type' in resp.text
+
+    with open(os.path.join(os.path.dirname(__file__), '..', 'image-with-gps-data.jpeg'), 'rb') as fd:
+        image_content = fd.read()
+    upload = Upload('test.jpg', image_content, 'image/jpeg')
+    resp = get_app(pub).get('/test/')
+    resp.form['f0$file'] = upload
+    resp = resp.form.submit('submit')
+    assert 'Check values then click submit.' in resp.text
+
+
+def test_form_file_field_submit_max_file_size(pub):
+    FormDef.wipe()
+    formdef = FormDef()
+    formdef.name = 'test'
+    formdef.fields = [fields.FileField(id='0', label='file', max_file_size='1ko')]
+    formdef.store()
+    formdef.data_class().wipe()
+
+    upload = Upload('test.txt', b'foobar' * 1000, 'application/force-download')
+    resp = get_app(pub).get('/test/')
+    resp.form['f0$file'] = upload
+    resp = resp.form.submit('submit')
+    assert 'over file size limit (1ko)' in resp.text
+
+    upload = Upload('test.txt', b'foobar' * 100, 'application/force-download')
+    resp = get_app(pub).get('/test/')
+    resp.form['f0$file'] = upload
+    resp = resp.form.submit('submit')
+    assert 'Check values then click submit.' in resp.text
+
+
+def test_form_file_field_submit_wrong_mimetype(pub):
+    FormDef.wipe()
+    formdef = FormDef()
+    formdef.name = 'test'
+    formdef.fields = [fields.FileField(id='0', label='file')]
+    formdef.store()
+    formdef.data_class().wipe()
+
+    upload = Upload('test.txt', b'foobar', 'application/force-download')
+
+    resp = get_app(pub).get('/test/')
+    resp.forms[0]['f0$file'] = upload
+    resp = resp.forms[0].submit('submit')
+    assert 'Check values then click submit.' in resp.text
+    resp = resp.forms[0].submit('submit')
+    assert resp.status_int == 302
+    resp = resp.follow()
+    assert 'The form has been recorded' in resp.text
+    resp = resp.click('test.txt')
+    assert resp.location.endswith('/test.txt')
+    resp = resp.follow()
+    assert resp.content_type == 'text/plain'
+    assert resp.text == 'foobar'
+
+    upload = Upload('test.pdf', b'%PDF-1.4 ...', 'application/force-download')
+
+    resp = get_app(pub).get('/test/')
+    resp.forms[0]['f0$file'] = upload
+    resp = resp.forms[0].submit('submit')
+    assert 'Check values then click submit.' in resp.text
+    resp = resp.forms[0].submit('submit')
+    assert resp.status_int == 302
+    resp = resp.follow()
+    assert 'The form has been recorded' in resp.text
+    resp = resp.click('test.pdf')
+    assert resp.location.endswith('/test.pdf')
+    resp = resp.follow()
+    assert resp.content_type == 'application/pdf'
+    assert resp.text == '%PDF-1.4 ...'
+
+
+def test_form_file_field_submit_blacklist(pub):
+    FormDef.wipe()
+    formdef = FormDef()
+    formdef.name = 'test'
+    formdef.fields = [fields.FileField(id='0', label='file')]
+    formdef.store()
+    formdef.data_class().wipe()
+
+    # application/x-ms-dos-executable
+    upload = Upload('test.exe', b'MZ...', 'application/force-download')
+    resp = get_app(pub).get('/test/')
+    resp.forms[0]['f0$file'] = upload
+    resp = resp.forms[0].submit('submit')
+    assert 'forbidden file type' in resp.text
+
+    # define custom blacklist
+    pub.load_site_options()
+    if not pub.site_options.has_section('options'):
+        pub.site_options.add_section('options')
+    pub.site_options.set('options', 'blacklisted-file-types', 'application/pdf')
+    with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
+        pub.site_options.write(fd)
+
+    # check against mime type
+    upload = Upload('test.pdf', b'%PDF-1.4 ...', 'application/force-download')
+    resp = get_app(pub).get('/test/')
+    resp.forms[0]['f0$file'] = upload
+    resp = resp.forms[0].submit('submit')
+    assert 'forbidden file type' in resp.text
+
+    # check against extension
+    pub.site_options.set('options', 'blacklisted-file-types', '.pdf')
+    with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
+        pub.site_options.write(fd)
+
+    upload = Upload('test.pdf', b'%PDF-1.4 ...', 'application/force-download')
+    resp = get_app(pub).get('/test/')
+    resp.forms[0]['f0$file'] = upload
+    resp = resp.forms[0].submit('submit')
+    assert 'forbidden file type' in resp.text
-- 
2.30.2

