test_jsonutil.py
151 lines
| 4.8 KiB
| text/x-python
|
PythonLexer
|
r17154 | # coding: utf-8 | ||
"""Test suite for our JSON utilities.""" | ||||
# Copyright (c) IPython Development Team. | ||||
# Distributed under the terms of the Modified BSD License. | ||||
|
r11151 | import datetime | ||
|
r2947 | import json | ||
|
r7737 | from base64 import decodestring | ||
|
r2947 | |||
import nose.tools as nt | ||||
|
r11151 | from IPython.utils import jsonutil, tz | ||
|
r7737 | from ..jsonutil import json_clean, encode_images | ||
|
r13361 | from ..py3compat import unicode_to_str, str_to_bytes, iteritems | ||
|
r2947 | |||
|
r17154 | |||
|
r13704 | class Int(int): | ||
def __str__(self): | ||||
return 'Int(%i)' % self | ||||
|
r2947 | |||
def test(): | ||||
# list of input/expected output. Use None for the expected output if it | ||||
# can be the same as the input. | ||||
pairs = [(1, None), # start with scalars | ||||
(1.0, None), | ||||
('a', None), | ||||
(True, None), | ||||
(False, None), | ||||
(None, None), | ||||
# complex numbers for now just go to strings, as otherwise they | ||||
# are unserializable | ||||
(1j, '1j'), | ||||
# Containers | ||||
([1, 2], None), | ||||
((1, 2), [1, 2]), | ||||
(set([1, 2]), [1, 2]), | ||||
(dict(x=1), None), | ||||
({'x': 1, 'y':[1,2,3], '1':'int'}, None), | ||||
# More exotic objects | ||||
((x for x in range(3)), [0, 1, 2]), | ||||
(iter([1, 2]), [1, 2]), | ||||
|
r13704 | (Int(5), 5), | ||
|
r2947 | ] | ||
for val, jval in pairs: | ||||
if jval is None: | ||||
jval = val | ||||
out = json_clean(val) | ||||
# validate our cleanup | ||||
nt.assert_equal(out, jval) | ||||
# and ensure that what we return, indeed encodes cleanly | ||||
json.loads(json.dumps(out)) | ||||
|
r17155 | def test_rekey(): | ||
# This could fail due to modifying the dict keys in-place on Python 3 | ||||
d = { i:i for i in map(str, range(128)) } | ||||
d = jsonutil.rekey(d) | ||||
for key in d: | ||||
nt.assert_is_instance(key, int) | ||||
|
r7737 | |||
def test_encode_images(): | ||||
# invalid data, but the header and footer are from real files | ||||
pngdata = b'\x89PNG\r\n\x1a\nblahblahnotactuallyvalidIEND\xaeB`\x82' | ||||
jpegdata = b'\xff\xd8\xff\xe0\x00\x10JFIFblahblahjpeg(\xa0\x0f\xff\xd9' | ||||
|
r15121 | pdfdata = b'%PDF-1.\ntrailer<</Root<</Pages<</Kids[<</MediaBox[0 0 3 3]>>]>>>>>>' | ||
|
r7737 | |||
fmt = { | ||||
'image/png' : pngdata, | ||||
'image/jpeg' : jpegdata, | ||||
|
r15121 | 'application/pdf' : pdfdata | ||
|
r7737 | } | ||
encoded = encode_images(fmt) | ||||
|
r13361 | for key, value in iteritems(fmt): | ||
|
r7737 | # encoded has unicode, want bytes | ||
decoded = decodestring(encoded[key].encode('ascii')) | ||||
|
r12374 | nt.assert_equal(decoded, value) | ||
|
r7737 | encoded2 = encode_images(encoded) | ||
|
r12374 | nt.assert_equal(encoded, encoded2) | ||
|
r7737 | |||
b64_str = {} | ||||
|
r13361 | for key, encoded in iteritems(encoded): | ||
|
r7737 | b64_str[key] = unicode_to_str(encoded) | ||
encoded3 = encode_images(b64_str) | ||||
|
r12374 | nt.assert_equal(encoded3, b64_str) | ||
|
r13361 | for key, value in iteritems(fmt): | ||
|
r7737 | # encoded3 has str, want bytes | ||
decoded = decodestring(str_to_bytes(encoded3[key])) | ||||
|
r12374 | nt.assert_equal(decoded, value) | ||
|
r7737 | |||
|
r2947 | def test_lambda(): | ||
jc = json_clean(lambda : 1) | ||||
|
r15309 | nt.assert_is_instance(jc, str) | ||
nt.assert_in('<lambda>', jc) | ||||
|
r2947 | json.dumps(jc) | ||
|
r11151 | def test_extract_dates(): | ||
timestamps = [ | ||||
'2013-07-03T16:34:52.249482', | ||||
'2013-07-03T16:34:52.249482Z', | ||||
'2013-07-03T16:34:52.249482Z-0800', | ||||
'2013-07-03T16:34:52.249482Z+0800', | ||||
'2013-07-03T16:34:52.249482Z+08:00', | ||||
'2013-07-03T16:34:52.249482Z-08:00', | ||||
'2013-07-03T16:34:52.249482-0800', | ||||
'2013-07-03T16:34:52.249482+0800', | ||||
'2013-07-03T16:34:52.249482+08:00', | ||||
'2013-07-03T16:34:52.249482-08:00', | ||||
] | ||||
extracted = jsonutil.extract_dates(timestamps) | ||||
ref = extracted[0] | ||||
for dt in extracted: | ||||
nt.assert_true(isinstance(dt, datetime.datetime)) | ||||
nt.assert_equal(dt, ref) | ||||
|
r13521 | def test_parse_ms_precision(): | ||
|
r15309 | base = '2013-07-03T16:34:52' | ||
|
r13521 | digits = '1234567890' | ||
|
r15309 | parsed = jsonutil.parse_date(base) | ||
nt.assert_is_instance(parsed, datetime.datetime) | ||||
|
r13521 | for i in range(len(digits)): | ||
|
r15309 | ts = base + '.' + digits[:i] | ||
|
r13521 | parsed = jsonutil.parse_date(ts) | ||
if i >= 1 and i <= 6: | ||||
|
r15309 | nt.assert_is_instance(parsed, datetime.datetime) | ||
|
r13521 | else: | ||
|
r15309 | nt.assert_is_instance(parsed, str) | ||
|
r13521 | |||
|
r11151 | def test_date_default(): | ||
data = dict(today=datetime.datetime.now(), utcnow=tz.utcnow()) | ||||
jsondata = json.dumps(data, default=jsonutil.date_default) | ||||
nt.assert_in("+00", jsondata) | ||||
nt.assert_equal(jsondata.count("+00"), 1) | ||||
extracted = jsonutil.extract_dates(json.loads(jsondata)) | ||||
for dt in extracted.values(): | ||||
|
r15309 | nt.assert_is_instance(dt, datetime.datetime) | ||
|
r2947 | |||
def test_exception(): | ||||
bad_dicts = [{1:'number', '1':'string'}, | ||||
{True:'bool', 'True':'string'}, | ||||
] | ||||
for d in bad_dicts: | ||||
nt.assert_raises(ValueError, json_clean, d) | ||||
|
r17154 | |||
def test_unicode_dict(): | ||||
data = {u'üniço∂e': u'üniço∂e'} | ||||
clean = jsonutil.json_clean(data) | ||||
nt.assert_equal(data, clean) | ||||