fresco 3.3.2__py3-none-any.whl → 3.3.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of fresco might be problematic. Click here for more details.
- fresco/__init__.py +1 -1
- fresco/request.py +2 -2
- fresco/response.py +1 -1
- fresco/tests/__init__.py +0 -0
- fresco/tests/fixtures.py +67 -0
- fresco/tests/test_cookie.py +59 -0
- fresco/tests/test_core.py +1038 -0
- fresco/tests/test_decorators.py +40 -0
- fresco/tests/test_exceptions.py +30 -0
- fresco/tests/test_middleware.py +92 -0
- fresco/tests/test_multidict.py +234 -0
- fresco/tests/test_options.py +314 -0
- fresco/tests/test_request.py +448 -0
- fresco/tests/test_requestcontext.py +107 -0
- fresco/tests/test_response.py +224 -0
- fresco/tests/test_routeargs.py +223 -0
- fresco/tests/test_routing.py +1126 -0
- fresco/tests/test_static.py +124 -0
- fresco/tests/test_subrequests.py +236 -0
- fresco/tests/util/__init__.py +0 -0
- fresco/tests/util/form_data.py +79 -0
- fresco/tests/util/test_common.py +34 -0
- fresco/tests/util/test_http.py +323 -0
- fresco/tests/util/test_security.py +34 -0
- fresco/tests/util/test_urls.py +176 -0
- fresco/tests/util/test_wsgi.py +107 -0
- fresco/util/contentencodings.py +2 -1
- fresco/util/http.py +3 -1
- fresco/util/wsgi.py +1 -1
- {fresco-3.3.2.dist-info → fresco-3.3.3.dist-info}/METADATA +5 -6
- fresco-3.3.3.dist-info/RECORD +57 -0
- {fresco-3.3.2.dist-info → fresco-3.3.3.dist-info}/WHEEL +1 -1
- fresco-3.3.2.dist-info/RECORD +0 -34
- {fresco-3.3.2.dist-info → fresco-3.3.3.dist-info}/LICENSE.txt +0 -0
- {fresco-3.3.2.dist-info → fresco-3.3.3.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# encoding=UTF-8
|
|
2
|
+
# Copyright 2015 Oliver Cope
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
#
|
|
16
|
+
from unittest.mock import Mock
|
|
17
|
+
import pytest
|
|
18
|
+
|
|
19
|
+
from fresco import FrescoApp
|
|
20
|
+
from fresco.cookie import Cookie
|
|
21
|
+
from fresco.response import Response
|
|
22
|
+
from fresco.routing import GET
|
|
23
|
+
from fresco.routing import RouteNotFound
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class TestCannedResponses(object):
|
|
27
|
+
def test_redirect(self):
|
|
28
|
+
with FrescoApp().requestcontext():
|
|
29
|
+
r = Response.redirect("/new_location")
|
|
30
|
+
assert b"http://localhost/new_location" in b"".join(r.content_iterator)
|
|
31
|
+
assert r.get_header("Location") == "http://localhost/new_location"
|
|
32
|
+
assert r.status == "302 Found"
|
|
33
|
+
|
|
34
|
+
def test_redirect_temporary(self):
|
|
35
|
+
with FrescoApp().requestcontext():
|
|
36
|
+
r = Response.redirect_temporary("/new_location")
|
|
37
|
+
assert b"http://localhost/new_location" in b"".join(r.content_iterator)
|
|
38
|
+
assert r.get_header("Location") == "http://localhost/new_location"
|
|
39
|
+
assert r.status == "302 Found"
|
|
40
|
+
|
|
41
|
+
def test_redirect_permanent(self):
|
|
42
|
+
with FrescoApp().requestcontext():
|
|
43
|
+
r = Response.redirect_permanent("/new_location")
|
|
44
|
+
assert b"http://localhost/new_location" in b"".join(r.content_iterator)
|
|
45
|
+
assert r.get_header("Location") == "http://localhost/new_location"
|
|
46
|
+
assert r.status == "301 Moved Permanently"
|
|
47
|
+
|
|
48
|
+
def test_redirect_to_view(self):
|
|
49
|
+
app = FrescoApp()
|
|
50
|
+
view = Mock(return_value=Response())
|
|
51
|
+
app.route("/arfle/<barfle:int>", GET, view)
|
|
52
|
+
with app.requestcontext():
|
|
53
|
+
r = Response.redirect(view, barfle=42)
|
|
54
|
+
assert r.get_header("Location") == "http://localhost/arfle/42"
|
|
55
|
+
|
|
56
|
+
def test_redirect_to_view_spec(self):
|
|
57
|
+
app = FrescoApp()
|
|
58
|
+
view = Mock(return_value=Response())
|
|
59
|
+
app.route("/arfle/<barfle:int>", GET, view, name="gloop")
|
|
60
|
+
with app.requestcontext():
|
|
61
|
+
r = Response.redirect("gloop", barfle=42)
|
|
62
|
+
assert r.get_header("Location") == "http://localhost/arfle/42"
|
|
63
|
+
|
|
64
|
+
def test_redirect_to_simple_string(self):
|
|
65
|
+
with FrescoApp().requestcontext():
|
|
66
|
+
r = Response.redirect("gloop")
|
|
67
|
+
assert r.get_header("Location") == "http://localhost/gloop"
|
|
68
|
+
|
|
69
|
+
def test_redirect_raises_RouteNotFound(self):
|
|
70
|
+
view = Mock()
|
|
71
|
+
with FrescoApp().requestcontext():
|
|
72
|
+
with pytest.raises(RouteNotFound):
|
|
73
|
+
Response.redirect("gloop", arfle="a")
|
|
74
|
+
with pytest.raises(RouteNotFound):
|
|
75
|
+
Response.redirect(view)
|
|
76
|
+
|
|
77
|
+
def test_redirect_to_unsafe_url(self):
|
|
78
|
+
with pytest.raises(ValueError):
|
|
79
|
+
with FrescoApp().requestcontext():
|
|
80
|
+
Response.redirect("http://bad.example.com/")
|
|
81
|
+
|
|
82
|
+
def test_redirect_uses_fallback_for_unsafe_url(self):
|
|
83
|
+
app = FrescoApp()
|
|
84
|
+
view = Mock(return_value=Response())
|
|
85
|
+
app.route("/arfle/<barfle:int>", GET, view, name="gloop")
|
|
86
|
+
with app.requestcontext():
|
|
87
|
+
r = Response.redirect("http://bad.example.com/", "gloop", barfle=23)
|
|
88
|
+
assert r.get_header("Location") == "http://localhost/arfle/23"
|
|
89
|
+
|
|
90
|
+
def test_not_found(self):
|
|
91
|
+
with FrescoApp().requestcontext():
|
|
92
|
+
r = Response.not_found()
|
|
93
|
+
assert b"not found" in b"".join(r.content_iterator).lower()
|
|
94
|
+
assert r.status_code == 404
|
|
95
|
+
|
|
96
|
+
def test_error(self):
|
|
97
|
+
with FrescoApp().requestcontext():
|
|
98
|
+
r = Response.error()
|
|
99
|
+
assert b"internal server error" in b"".join(r.content_iterator).lower()
|
|
100
|
+
assert r.status_code == 500
|
|
101
|
+
|
|
102
|
+
def test_method_not_allowed(self):
|
|
103
|
+
with FrescoApp().requestcontext():
|
|
104
|
+
r = Response.method_not_allowed(valid_methods=("PUT", "DELETE"))
|
|
105
|
+
assert b"not allowed" in b"".join(r.content_iterator).lower()
|
|
106
|
+
assert r.status == "405 Method Not Allowed"
|
|
107
|
+
assert r.get_header("Allow") == "PUT,DELETE"
|
|
108
|
+
|
|
109
|
+
def test_unauthorized(self):
|
|
110
|
+
with FrescoApp().requestcontext():
|
|
111
|
+
r = Response.unauthorized(authenticate='myscheme realm="spaghetti"')
|
|
112
|
+
assert r.status == "401 Unauthorized"
|
|
113
|
+
assert r.get_header("WWW-Authenticate") == 'myscheme realm="spaghetti"'
|
|
114
|
+
|
|
115
|
+
def test_unauthorized_basic(self):
|
|
116
|
+
with FrescoApp().requestcontext():
|
|
117
|
+
r = Response.unauthorized_basic(realm="spaghetti")
|
|
118
|
+
assert r.status == "401 Unauthorized"
|
|
119
|
+
assert r.get_header("WWW-Authenticate") == 'Basic realm="spaghetti"'
|
|
120
|
+
|
|
121
|
+
def test_meta_refresh(self):
|
|
122
|
+
with FrescoApp().requestcontext():
|
|
123
|
+
r = Response.meta_refresh("/next_page")
|
|
124
|
+
content = b"".join(r.content_iterator)
|
|
125
|
+
assert b'<a href="http://localhost/next_page">' in content
|
|
126
|
+
assert (
|
|
127
|
+
b'<meta http-equiv="refresh" content="0;'
|
|
128
|
+
b' url=http://localhost/next_page">' in content
|
|
129
|
+
)
|
|
130
|
+
assert r.status == "200 OK"
|
|
131
|
+
assert r.get_header("Content-Type") == "text/html"
|
|
132
|
+
|
|
133
|
+
def test_json(self):
|
|
134
|
+
with FrescoApp().requestcontext():
|
|
135
|
+
r = Response.json(
|
|
136
|
+
{"arfle": "barfle"},
|
|
137
|
+
status=201,
|
|
138
|
+
indent=4,
|
|
139
|
+
separators=(",", ":\t"),
|
|
140
|
+
)
|
|
141
|
+
assert r.status == "201 Created"
|
|
142
|
+
assert r.get_header("Content-Type") == "application/json"
|
|
143
|
+
assert b"".join(r.content_iterator) == b'{\n "arfle":\t"barfle"\n}'
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class TestResponse(object):
|
|
147
|
+
def test_unknown_response_header_from_python_symbol(self):
|
|
148
|
+
r = Response(x_myheader="Foo", content_type=None)
|
|
149
|
+
assert r.headers == [("X-Myheader", "Foo")]
|
|
150
|
+
|
|
151
|
+
def test_standard_headers_capitalized_from_symbol(self):
|
|
152
|
+
r = Response(etag="foo")
|
|
153
|
+
assert r.headers == [("ETag", "foo")]
|
|
154
|
+
|
|
155
|
+
r = Response(x_ua_compatible="foo")
|
|
156
|
+
assert r.headers == [("X-UA-Compatible", "foo")]
|
|
157
|
+
|
|
158
|
+
def test_content_type_added_only_if_content(self):
|
|
159
|
+
r = Response(content=[])
|
|
160
|
+
assert "Content-Type" in dict(r.headers)
|
|
161
|
+
|
|
162
|
+
r = Response()
|
|
163
|
+
assert "Content-Type" not in dict(r.headers)
|
|
164
|
+
|
|
165
|
+
r = Response(content=None)
|
|
166
|
+
assert "Content-Type" not in dict(r.headers)
|
|
167
|
+
|
|
168
|
+
def test_add_response_header(self):
|
|
169
|
+
r = Response(x_myheader="Foo")
|
|
170
|
+
r = r.add_header("X-Myheader", "Bar")
|
|
171
|
+
assert r.headers == [("X-Myheader", "Foo"), ("X-Myheader", "Bar")]
|
|
172
|
+
|
|
173
|
+
def test_set_content_type_header(self):
|
|
174
|
+
r = Response(content_type="text/rtf; charset=ISO-8859-1")
|
|
175
|
+
assert r.get_header("Content-Type") == "text/rtf; charset=ISO-8859-1"
|
|
176
|
+
|
|
177
|
+
def test_set_cookie(self):
|
|
178
|
+
r = Response(set_cookie=Cookie(name="fruit", value="banana"))
|
|
179
|
+
assert r.get_header("Set-Cookie") == "fruit=banana;Path=/;SameSite=Lax"
|
|
180
|
+
|
|
181
|
+
def test_delete_cookie(self):
|
|
182
|
+
r = Response().delete_cookie(name="fruit")
|
|
183
|
+
assert r.get_header("Set-Cookie") == (
|
|
184
|
+
"fruit=;Expires=Thu, 01 Jan 1970 00:00:00 GMT;Max-Age=0;Path=/;SameSite=Lax"
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
def test_response_get_headers(self):
|
|
188
|
+
r = Response(
|
|
189
|
+
["whoa nelly!"],
|
|
190
|
+
content_type="text/plain",
|
|
191
|
+
x_test_header=["1", "2"],
|
|
192
|
+
)
|
|
193
|
+
assert r.get_header("content-type") == "text/plain"
|
|
194
|
+
assert r.get_header("x-test-header") == "1,2"
|
|
195
|
+
assert r.get_header("X-Test-Header") == "1,2"
|
|
196
|
+
assert r.get_header("x-does-not-exist", "boo!") == "boo!"
|
|
197
|
+
|
|
198
|
+
def test_response_buffered_sets_content_length(self):
|
|
199
|
+
r = Response(["whoa nelly!"]).buffered()
|
|
200
|
+
assert r.get_header("content-length") == "11"
|
|
201
|
+
|
|
202
|
+
r = Response(["whoa nélly!"]).buffered()
|
|
203
|
+
assert r.get_header("content-length") == "12"
|
|
204
|
+
|
|
205
|
+
def test_it_encodes_a_unicode_string_according_to_content_type(self):
|
|
206
|
+
r = Response("café", content_type="text/plain; charset=utf-8")
|
|
207
|
+
assert list(r({}, Mock())) == ["café".encode("utf-8")]
|
|
208
|
+
r = Response("café", content_type="text/plain; charset=latin-1")
|
|
209
|
+
assert list(r({}, Mock())) == ["café".encode("latin-1")]
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
class TestAddVary(object):
|
|
213
|
+
def test_it_adds_a_vary_header(self):
|
|
214
|
+
r = Response(content_type="text/plain").add_vary("Accept-Encoding")
|
|
215
|
+
assert ("Vary", "Accept-Encoding") in r.headers
|
|
216
|
+
|
|
217
|
+
def test_it_extends_an_existing_header(self):
|
|
218
|
+
r = (
|
|
219
|
+
Response(content_type="text/plain")
|
|
220
|
+
.add_vary("Accept-Encoding")
|
|
221
|
+
.add_vary("Cookie")
|
|
222
|
+
)
|
|
223
|
+
assert "Cookie" in r.get_header("vary")
|
|
224
|
+
assert "Accept-Encoding" in r.get_header("vary")
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# Copyright 2015 Oliver Cope
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
#
|
|
15
|
+
from unittest.mock import Mock, call
|
|
16
|
+
|
|
17
|
+
from fresco import routeargs
|
|
18
|
+
from fresco.core import FrescoApp
|
|
19
|
+
from fresco.response import Response
|
|
20
|
+
from fresco.routing import GET
|
|
21
|
+
from fresco.routing import POST
|
|
22
|
+
from fresco.routing import Route
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class TestRouteArg(object):
|
|
26
|
+
def test_routekwarg_configured(self):
|
|
27
|
+
A = routeargs.RouteArg()
|
|
28
|
+
route = Route("/", GET, lambda r: None, x=A)
|
|
29
|
+
assert A.route is route
|
|
30
|
+
assert A.name == "x"
|
|
31
|
+
|
|
32
|
+
def test_routekwarg_value_passed(self):
|
|
33
|
+
view = Mock(return_value=Response())
|
|
34
|
+
routekwarg = Mock(spec=routeargs.RouteArg)
|
|
35
|
+
routekwarg.return_value = "xyzzy"
|
|
36
|
+
|
|
37
|
+
app = FrescoApp()
|
|
38
|
+
app.route("/", GET, view, x=routekwarg)
|
|
39
|
+
with app.requestcontext("/") as c:
|
|
40
|
+
app.view()
|
|
41
|
+
assert routekwarg.call_args_list == [call(c.request)]
|
|
42
|
+
assert view.call_args_list == [call(x="xyzzy")]
|
|
43
|
+
|
|
44
|
+
def test_queryarg_value_passed(self):
|
|
45
|
+
view = Mock(return_value=Response())
|
|
46
|
+
app = FrescoApp()
|
|
47
|
+
app.route("/", GET, view, x=routeargs.QueryArg())
|
|
48
|
+
with app.requestcontext("/?x=foo"):
|
|
49
|
+
app.view()
|
|
50
|
+
assert view.call_args_list == [call(x="foo")]
|
|
51
|
+
|
|
52
|
+
def test_formarg_value_passed(self):
|
|
53
|
+
view = Mock(return_value=Response())
|
|
54
|
+
app = FrescoApp()
|
|
55
|
+
app.route("/", GET, view, x=routeargs.FormArg())
|
|
56
|
+
with app.requestcontext("/?x=foo"):
|
|
57
|
+
app.view()
|
|
58
|
+
assert view.call_args_list == [call(x="foo")]
|
|
59
|
+
|
|
60
|
+
def test_sessionarg_value_passed(self):
|
|
61
|
+
view = Mock(return_value=Response())
|
|
62
|
+
app = FrescoApp()
|
|
63
|
+
app.route("/", GET, view, x=routeargs.SessionArg())
|
|
64
|
+
with app.requestcontext("/?x=foo") as c:
|
|
65
|
+
c.request.environ[c.request.SESSION_ENV_KEY] = {"x": "foo"}
|
|
66
|
+
app.view()
|
|
67
|
+
assert view.call_args_list == [call(x="foo")]
|
|
68
|
+
|
|
69
|
+
def test_cookiearg_value_passed(self):
|
|
70
|
+
view = Mock(return_value=Response())
|
|
71
|
+
app = FrescoApp()
|
|
72
|
+
app.route("/", GET, view, x=routeargs.CookieArg())
|
|
73
|
+
with app.requestcontext("/", HTTP_COOKIE="x=foo"):
|
|
74
|
+
app.view()
|
|
75
|
+
assert view.call_args_list == [call(x="foo")]
|
|
76
|
+
|
|
77
|
+
def test_cookiearg_listvalue_passed(self):
|
|
78
|
+
view = Mock(return_value=Response())
|
|
79
|
+
app = FrescoApp()
|
|
80
|
+
app.route("/", GET, view, x=routeargs.CookieArg([str]))
|
|
81
|
+
with app.requestcontext("/", HTTP_COOKIE="x=foo;x=bar"):
|
|
82
|
+
app.view()
|
|
83
|
+
assert view.call_args_list == [call(x=["foo", "bar"])]
|
|
84
|
+
|
|
85
|
+
def test_requestarg_value_converted(self):
|
|
86
|
+
view = Mock(return_value=Response())
|
|
87
|
+
app = FrescoApp()
|
|
88
|
+
app.route("/", GET, view, x=routeargs.FormArg(float))
|
|
89
|
+
with app.requestcontext("/?x=0"):
|
|
90
|
+
app.view()
|
|
91
|
+
assert view.call_args_list == [call(x=0.0)]
|
|
92
|
+
|
|
93
|
+
def test_it_converts_lists(self):
|
|
94
|
+
arg = routeargs.RequestArg(converter=[str])
|
|
95
|
+
arg.configure(None, "foo")
|
|
96
|
+
with FrescoApp().requestcontext("/?foo=a&foo=b") as r:
|
|
97
|
+
assert arg(r.request) == ["a", "b"]
|
|
98
|
+
|
|
99
|
+
def test_requestarg_default_value(self):
|
|
100
|
+
view = Mock(return_value=Response())
|
|
101
|
+
app = FrescoApp()
|
|
102
|
+
app.route("/", GET, view, x=routeargs.FormArg(default="d"))
|
|
103
|
+
with app.requestcontext("/"):
|
|
104
|
+
app.view()
|
|
105
|
+
assert view.call_args_list == [call(x="d")]
|
|
106
|
+
|
|
107
|
+
def test_it_doesnt_convert_default_values(self):
|
|
108
|
+
view = Mock(return_value=Response())
|
|
109
|
+
app = FrescoApp()
|
|
110
|
+
app.route("/", GET, view, x=routeargs.FormArg(int, default=None))
|
|
111
|
+
with app.requestcontext("/"):
|
|
112
|
+
app.view()
|
|
113
|
+
assert view.call_args_list == [call(x=None)]
|
|
114
|
+
|
|
115
|
+
def test_access_to_missing_requestarg_returns_badrequest(self):
|
|
116
|
+
def view(x):
|
|
117
|
+
x == 0
|
|
118
|
+
|
|
119
|
+
app = FrescoApp()
|
|
120
|
+
app.route("/", GET, view, x=routeargs.FormArg())
|
|
121
|
+
with app.requestcontext("/"):
|
|
122
|
+
assert "Bad Request" in app.view().status
|
|
123
|
+
|
|
124
|
+
def test_missing_requestarg_with_conversion_returns_badrequest(self):
|
|
125
|
+
def view(x):
|
|
126
|
+
x == 0
|
|
127
|
+
|
|
128
|
+
app = FrescoApp()
|
|
129
|
+
app.route("/", GET, view, x=routeargs.FormArg(int))
|
|
130
|
+
with app.requestcontext("/"):
|
|
131
|
+
assert "Bad Request" in app.view().status
|
|
132
|
+
|
|
133
|
+
def test_routeargs_work_as_positional_arguments(self):
|
|
134
|
+
view = Mock(return_value=Response())
|
|
135
|
+
app = FrescoApp()
|
|
136
|
+
app.route("/", GET, view, args=[routeargs.FormArg(key="x")])
|
|
137
|
+
with app.requestcontext("/?x=foo"):
|
|
138
|
+
app.view()
|
|
139
|
+
assert view.call_args_list == [call("foo")]
|
|
140
|
+
|
|
141
|
+
def test_routearg_classes_are_auto_instantiated(self):
|
|
142
|
+
view = Mock(return_value=Response())
|
|
143
|
+
app = FrescoApp()
|
|
144
|
+
app.route("/", GET, view, x=routeargs.FormArg)
|
|
145
|
+
with app.requestcontext("/?x=foo"):
|
|
146
|
+
app.view()
|
|
147
|
+
assert view.call_args_list == [call(x="foo")]
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
class TestRequestObject(object):
|
|
151
|
+
def test_it_passes_the_request(self):
|
|
152
|
+
view = Mock(return_value=Response())
|
|
153
|
+
app = FrescoApp()
|
|
154
|
+
app.route("/", GET, view, x=routeargs.RequestObject())
|
|
155
|
+
with app.requestcontext("/") as c:
|
|
156
|
+
app.view()
|
|
157
|
+
x = view.call_args[1]["x"]
|
|
158
|
+
assert x is c.request
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class Test_routearg(object):
|
|
162
|
+
def test_it_calls_func(object):
|
|
163
|
+
view = Mock(return_value=Response())
|
|
164
|
+
argfunc = Mock()
|
|
165
|
+
app = FrescoApp()
|
|
166
|
+
app.route("/", GET, view, x=routeargs.routearg(argfunc))
|
|
167
|
+
with app.requestcontext("/"):
|
|
168
|
+
app.view()
|
|
169
|
+
assert argfunc.call_count == 1, argfunc.call_count
|
|
170
|
+
assert view.call_args[1]["x"] is argfunc()
|
|
171
|
+
|
|
172
|
+
def test_it_passes_additional_args(object):
|
|
173
|
+
view = Mock(return_value=Response())
|
|
174
|
+
argfunc = Mock()
|
|
175
|
+
app = FrescoApp()
|
|
176
|
+
app.route("/", GET, view, x=routeargs.routearg(argfunc, "x", y=42))
|
|
177
|
+
with app.requestcontext("/") as c:
|
|
178
|
+
app.view()
|
|
179
|
+
assert argfunc.call_args == ((c.request, "x"), {"y": 42})
|
|
180
|
+
assert view.call_args[1]["x"] is argfunc()
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
class TestFormData(object):
|
|
184
|
+
def test_it_passes_the_form_dict(self):
|
|
185
|
+
view = Mock(return_value=Response())
|
|
186
|
+
app = FrescoApp()
|
|
187
|
+
app.route("/", GET, view, x=routeargs.FormData())
|
|
188
|
+
with app.requestcontext("/") as c:
|
|
189
|
+
app.view()
|
|
190
|
+
x = view.call_args[1]["x"]
|
|
191
|
+
assert x is c.request.form
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
class TestJSONPayload(object):
|
|
195
|
+
def test_it_passes_json_data(self):
|
|
196
|
+
view = Mock(return_value=Response())
|
|
197
|
+
app = FrescoApp()
|
|
198
|
+
app.route("/", POST, view, x=routeargs.JSONPayload())
|
|
199
|
+
with app.requestcontext_post(
|
|
200
|
+
"/", data=b'{"foo":"bar"}', CONTENT_TYPE="application/json"
|
|
201
|
+
):
|
|
202
|
+
app.view()
|
|
203
|
+
x = view.call_args[1]["x"]
|
|
204
|
+
assert x == {"foo": "bar"}
|
|
205
|
+
|
|
206
|
+
def test_it_returns_bad_request_on_invalid_payload(self):
|
|
207
|
+
view = Mock(return_value=Response())
|
|
208
|
+
app = FrescoApp()
|
|
209
|
+
app.route("/", POST, view, x=routeargs.JSONPayload())
|
|
210
|
+
with app.requestcontext_post(
|
|
211
|
+
"/", data=b"invalid json!", CONTENT_TYPE="application/json"
|
|
212
|
+
):
|
|
213
|
+
r = app.view()
|
|
214
|
+
assert r.status_code == 400
|
|
215
|
+
|
|
216
|
+
def test_it_returns_a_default_value(self):
|
|
217
|
+
view = Mock(return_value=Response())
|
|
218
|
+
app = FrescoApp()
|
|
219
|
+
app.route("/", POST, view, x=routeargs.JSONPayload(default="default value"))
|
|
220
|
+
with app.requestcontext_post("/"):
|
|
221
|
+
app.view()
|
|
222
|
+
x = view.call_args[1]["x"]
|
|
223
|
+
assert x == "default value"
|