1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
|
import pytest
import falcon
import falcon.testing
class TestMultipartMixed:
"""Test parsing example from the now-obsolete RFC 1867:
--AaB03x
Content-Disposition: form-data; name="field1"
Joe Blow
--AaB03x
Content-Disposition: form-data; name="docs"
Content-Type: multipart/mixed; boundary=BbC04y
--BbC04y
Content-Disposition: attachment; filename="file1.txt"
This is file1.
--BbC04y
Content-Disposition: attachment; filename="file2.txt"
Hello, World!
--BbC04y--
--AaB03x--
"""
@classmethod
def prepare_form(cls):
lines = [line.strip() for line in cls.__doc__.splitlines()[2:]]
# NOTE(vytas): On CPython 3.13-rc1, the last newline was missing.
if lines[-1]:
lines.append('')
return '\r\n'.join(lines).encode()
def test_parse(self, util):
recipe = util.load_module('examples/recipes/multipart_mixed_main.py')
result = falcon.testing.simulate_post(
recipe.app,
'/forms',
body=self.prepare_form(),
content_type='multipart/form-data; boundary=AaB03x',
)
assert result.status_code == 200
assert result.json == {
'file1.txt': 'This is file1.\r\n',
'file2.txt': 'Hello, World!\r\n',
}
class TestOutputCSV:
@pytest.mark.parametrize(
'recipe,expected_head',
[
('output_csv_text', '"fruit","quantity"\r\n"apples",13\r\n'),
('output_csv_stream', '"n","Fibonacci Fn"\r\n0,0\r\n1,1\r\n'),
],
ids=['simple', 'stream'],
)
def test_csv_output(self, asgi, app_kind, util, recipe, expected_head):
module = util.load_module(
recipe, parent_dir='examples/recipes', suffix=app_kind
)
app = util.create_app(asgi)
app.add_route('/report', module.Report())
result = falcon.testing.simulate_get(app, '/report')
assert result.status_code == 200
assert result.text.startswith(expected_head)
class TestPrettyJSON:
class QuoteResource:
def on_get(self, req, resp):
resp.media = {
'author': 'Grace Hopper',
'quote': (
"I've always been more interested in "
'the future than in the past.'
),
}
class NegotiationMiddleware:
def process_request(self, req, resp):
resp.content_type = req.accept
def test_optional_indent(self, util):
recipe = util.load_module('examples/recipes/pretty_json_main.py')
app = falcon.App(middleware=[self.NegotiationMiddleware()])
app.add_route('/quote', self.QuoteResource())
app.resp_options.media_handlers.update(
{falcon.MEDIA_JSON: recipe.CustomJSONHandler()}
)
result = falcon.testing.simulate_get(
app, '/quote', headers={'Accept': 'application/json; indent=4'}
)
assert result.status_code == 200
assert result.text == (
'{\n'
' "author": "Grace Hopper",\n'
' "quote": "I\'ve always been more interested in the future '
'than in the past."\n'
'}'
)
class TestRawURLPath:
def path_extras(self, asgi, url):
if asgi:
return {'raw_path': url.encode()}
return None
def test_raw_path(self, asgi, app_kind, util):
recipe = util.load_module(
'raw_url_path', parent_dir='examples/recipes', suffix=app_kind
)
# TODO(vytas): Improve TestClient to automatically add ASGI raw_path
# (as it does for WSGI): GH #2262.
url1 = '/cache/http%3A%2F%2Ffalconframework.org'
result1 = falcon.testing.simulate_get(
recipe.app, url1, extras=self.path_extras(asgi, url1)
)
assert result1.status_code == 200
assert result1.json == {'url': 'http://falconframework.org'}
url2 = '/cache/http%3A%2F%2Ffalconframework.org/status'
result2 = falcon.testing.simulate_get(
recipe.app, url2, extras=self.path_extras(asgi, url2)
)
assert result2.status_code == 200
assert result2.json == {'cached': True}
|