# -*- coding: utf-8 -*- """ tests.helpers ~~~~~~~~~~~~~~~~~~~~~~~ Various helpers. :copyright: (c) 2015 by Armin Ronacher. :license: BSD, see LICENSE for more details. """ import pytest import os import uuid import datetime import flask from logging import StreamHandler from werkzeug.datastructures import Range from werkzeug.exceptions import BadRequest, NotFound from werkzeug.http import parse_cache_control_header, parse_options_header from werkzeug.http import http_date from flask._compat import StringIO, text_type from flask.helpers import get_debug_flag, make_response def has_encoding(name): try: import codecs codecs.lookup(name) return True except LookupError: return False class TestJSON(object): def test_ignore_cached_json(self, app): with app.test_request_context('/', method='POST', data='malformed', content_type='application/json'): assert flask.request.get_json(silent=True, cache=True) is None with pytest.raises(BadRequest): flask.request.get_json(silent=False, cache=False) def test_post_empty_json_adds_exception_to_response_content_in_debug(self, app, client): app.config['DEBUG'] = True app.config['TRAP_BAD_REQUEST_ERRORS'] = False @app.route('/json', methods=['POST']) def post_json(): flask.request.get_json() return None rv = client.post('/json', data=None, content_type='application/json') assert rv.status_code == 400 assert b'Failed to decode JSON object' in rv.data def test_post_empty_json_wont_add_exception_to_response_if_no_debug(self, app, client): app.config['DEBUG'] = False app.config['TRAP_BAD_REQUEST_ERRORS'] = False @app.route('/json', methods=['POST']) def post_json(): flask.request.get_json() return None rv = client.post('/json', data=None, content_type='application/json') assert rv.status_code == 400 assert b'Failed to decode JSON object' not in rv.data def test_json_bad_requests(self, app, client): @app.route('/json', methods=['POST']) def return_json(): return flask.jsonify(foo=text_type(flask.request.get_json())) rv = client.post('/json', data='malformed', content_type='application/json') assert rv.status_code == 400 def test_json_custom_mimetypes(self, app, client): @app.route('/json', methods=['POST']) def return_json(): return flask.request.get_json() rv = client.post('/json', data='"foo"', content_type='application/x+json') assert rv.data == b'foo' def test_json_body_encoding(self, app, client): @app.route('/') def index(): return flask.request.get_json() resp = client.get('/', data=u'"Hällo Wörld"'.encode('iso-8859-15'), content_type='application/json; charset=iso-8859-15') assert resp.data == u'Hällo Wörld'.encode('utf-8') @pytest.mark.parametrize('test_value,expected', [(True, '"\\u2603"'), (False, u'"\u2603"')]) def test_json_as_unicode(self, test_value, expected, app, app_ctx): app.config['JSON_AS_ASCII'] = test_value rv = flask.json.dumps(u'\N{SNOWMAN}') assert rv == expected def test_json_dump_to_file(self, app, app_ctx): test_data = {'name': 'Flask'} out = StringIO() flask.json.dump(test_data, out) out.seek(0) rv = flask.json.load(out) assert rv == test_data @pytest.mark.parametrize('test_value', [0, -1, 1, 23, 3.14, 's', "longer string", True, False, None]) def test_jsonify_basic_types(self, test_value, app, client): """Test jsonify with basic types.""" url = '/jsonify_basic_types' app.add_url_rule(url, url, lambda x=test_value: flask.jsonify(x)) rv = client.get(url) assert rv.mimetype == 'application/json' assert flask.json.loads(rv.data) == test_value def test_jsonify_dicts(self, app, client): """Test jsonify with dicts and kwargs unpacking.""" d = {'a': 0, 'b': 23, 'c': 3.14, 'd': 't', 'e': 'Hi', 'f': True, 'g': False, 'h': ['test list', 10, False], 'i': {'test': 'dict'}} @app.route('/kw') def return_kwargs(): return flask.jsonify(**d) @app.route('/dict') def return_dict(): return flask.jsonify(d) for url in '/kw', '/dict': rv = client.get(url) assert rv.mimetype == 'application/json' assert flask.json.loads(rv.data) == d def test_jsonify_arrays(self, app, client): """Test jsonify of lists and args unpacking.""" l = [ 0, 42, 3.14, 't', 'hello', True, False, ['test list', 2, False], {'test': 'dict'} ] @app.route('/args_unpack') def return_args_unpack(): return flask.jsonify(*l) @app.route('/array') def return_array(): return flask.jsonify(l) for url in '/args_unpack', '/array': rv = client.get(url) assert rv.mimetype == 'application/json' assert flask.json.loads(rv.data) == l def test_jsonify_date_types(self, app, client): """Test jsonify with datetime.date and datetime.datetime types.""" test_dates = ( datetime.datetime(1973, 3, 11, 6, 30, 45), datetime.date(1975, 1, 5) ) for i, d in enumerate(test_dates): url = '/datetest{0}'.format(i) app.add_url_rule(url, str(i), lambda val=d: flask.jsonify(x=val)) rv = client.get(url) assert rv.mimetype == 'application/json' assert flask.json.loads(rv.data)['x'] == http_date(d.timetuple()) def test_jsonify_uuid_types(self, app, client): """Test jsonify with uuid.UUID types""" test_uuid = uuid.UUID(bytes=b'\xDE\xAD\xBE\xEF' * 4) url = '/uuid_test' app.add_url_rule(url, url, lambda: flask.jsonify(x=test_uuid)) rv = client.get(url) rv_x = flask.json.loads(rv.data)['x'] assert rv_x == str(test_uuid) rv_uuid = uuid.UUID(rv_x) assert rv_uuid == test_uuid def test_json_attr(self, app, client): @app.route('/add', methods=['POST']) def add(): json = flask.request.get_json() return text_type(json['a'] + json['b']) rv = client.post('/add', data=flask.json.dumps({'a': 1, 'b': 2}), content_type='application/json') assert rv.data == b'3' def test_template_escaping(self, app, req_ctx): render = flask.render_template_string rv = flask.json.htmlsafe_dumps('') assert rv == u'"\\u003c/script\\u003e"' assert type(rv) == text_type rv = render('{{ ""|tojson }}') assert rv == '"\\u003c/script\\u003e"' rv = render('{{ "<\0/script>"|tojson }}') assert rv == '"\\u003c\\u0000/script\\u003e"' rv = render('{{ "