# -*- 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.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 def has_encoding(name): try: import codecs codecs.lookup(name) return True except LookupError: return False class TestJSON(object): def test_post_empty_json_adds_exception_to_response_content_in_debug(self): app = flask.Flask(__name__) app.config['DEBUG'] = True @app.route('/json', methods=['POST']) def post_json(): flask.request.get_json() return None c = app.test_client() rv = c.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 = flask.Flask(__name__) app.config['DEBUG'] = False @app.route('/json', methods=['POST']) def post_json(): flask.request.get_json() return None c = app.test_client() rv = c.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 = flask.Flask(__name__) @app.route('/json', methods=['POST']) def return_json(): return flask.jsonify(foo=text_type(flask.request.get_json())) c = app.test_client() rv = c.post('/json', data='malformed', content_type='application/json') assert rv.status_code == 400 def test_json_custom_mimetypes(self): app = flask.Flask(__name__) @app.route('/json', methods=['POST']) def return_json(): return flask.request.get_json() c = app.test_client() rv = c.post('/json', data='"foo"', content_type='application/x+json') assert rv.data == b'foo' def test_json_body_encoding(self): app = flask.Flask(__name__) app.testing = True @app.route('/') def index(): return flask.request.get_json() c = app.test_client() resp = c.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') def test_json_as_unicode(self): app = flask.Flask(__name__) app.config['JSON_AS_ASCII'] = True with app.app_context(): rv = flask.json.dumps(u'\N{SNOWMAN}') assert rv == '"\\u2603"' app.config['JSON_AS_ASCII'] = False with app.app_context(): rv = flask.json.dumps(u'\N{SNOWMAN}') assert rv == u'"\u2603"' def test_json_dump_to_file(self): app = flask.Flask(__name__) test_data = {'name': 'Flask'} out = StringIO() with app.app_context(): flask.json.dump(test_data, out) out.seek(0) rv = flask.json.load(out) assert rv == test_data def test_jsonify_basic_types(self): """Test jsonify with basic types.""" # Should be able to use pytest parametrize on this, but I couldn't # figure out the correct syntax # https://pytest.org/latest/parametrize.html#pytest-mark-parametrize-parametrizing-test-functions test_data = (0, 1, 23, 3.14, 's', "longer string", True, False,) app = flask.Flask(__name__) c = app.test_client() for i, d in enumerate(test_data): url = '/jsonify_basic_types{0}'.format(i) app.add_url_rule(url, str(i), lambda x=d: flask.jsonify(x)) rv = c.get(url) assert rv.mimetype == 'application/json' assert flask.json.loads(rv.data) == d def test_jsonify_dicts(self): """Test jsonify with dicts and kwargs unpacking.""" d = dict( a=0, b=23, c=3.14, d='t', e='Hi', f=True, g=False, h=['test list', 10, False], i={'test':'dict'} ) app = flask.Flask(__name__) @app.route('/kw') def return_kwargs(): return flask.jsonify(**d) @app.route('/dict') def return_dict(): return flask.jsonify(d) c = app.test_client() for url in '/kw', '/dict': rv = c.get(url) assert rv.mimetype == 'application/json' assert flask.json.loads(rv.data) == d def test_jsonify_arrays(self): """Test jsonify of lists and args unpacking.""" l = [ 0, 42, 3.14, 't', 'hello', True, False, ['test list', 2, False], {'test':'dict'} ] app = flask.Flask(__name__) @app.route('/args_unpack') def return_args_unpack(): return flask.jsonify(*l) @app.route('/array') def return_array(): return flask.jsonify(l) c = app.test_client() for url in '/args_unpack', '/array': rv = c.get(url) assert rv.mimetype == 'application/json' assert flask.json.loads(rv.data) == l def test_jsonify_date_types(self): """Test jsonify with datetime.date and datetime.datetime types.""" test_dates = ( datetime.datetime(1973, 3, 11, 6, 30, 45), datetime.date(1975, 1, 5) ) app = flask.Flask(__name__) c = app.test_client() 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 = c.get(url) assert rv.mimetype == 'application/json' assert flask.json.loads(rv.data)['x'] == http_date(d.timetuple()) def test_jsonify_uuid_types(self): """Test jsonify with uuid.UUID types""" test_uuid = uuid.UUID(bytes=b'\xDE\xAD\xBE\xEF'*4) app = flask.Flask(__name__) url = '/uuid_test' app.add_url_rule(url, url, lambda: flask.jsonify(x=test_uuid)) c = app.test_client() rv = c.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 = flask.Flask(__name__) @app.route('/add', methods=['POST']) def add(): json = flask.request.get_json() return text_type(json['a'] + json['b']) c = app.test_client() rv = c.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 = flask.Flask(__name__) render = flask.render_template_string with app.test_request_context(): 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('{{ "