test_jsonutil.py
147 lines
| 4.8 KiB
| text/x-python
|
PythonLexer
Fernando Perez
|
r2947 | """Test suite for our JSON utilities. | ||
""" | ||||
#----------------------------------------------------------------------------- | ||||
Matthias BUSSONNIER
|
r5390 | # Copyright (C) 2010-2011 The IPython Development Team | ||
Fernando Perez
|
r2947 | # | ||
# Distributed under the terms of the BSD License. The full license is in | ||||
# the file COPYING.txt, distributed as part of this software. | ||||
#----------------------------------------------------------------------------- | ||||
#----------------------------------------------------------------------------- | ||||
# Imports | ||||
#----------------------------------------------------------------------------- | ||||
# stdlib | ||||
MinRK
|
r11151 | import datetime | ||
Fernando Perez
|
r2947 | import json | ||
MinRK
|
r7737 | from base64 import decodestring | ||
Fernando Perez
|
r2947 | |||
# third party | ||||
import nose.tools as nt | ||||
# our own | ||||
MinRK
|
r11151 | from IPython.utils import jsonutil, tz | ||
MinRK
|
r7737 | from ..jsonutil import json_clean, encode_images | ||
Thomas Kluyver
|
r13361 | from ..py3compat import unicode_to_str, str_to_bytes, iteritems | ||
Fernando Perez
|
r2947 | |||
#----------------------------------------------------------------------------- | ||||
# Test functions | ||||
#----------------------------------------------------------------------------- | ||||
MinRK
|
r13704 | class Int(int): | ||
def __str__(self): | ||||
return 'Int(%i)' % self | ||||
Fernando Perez
|
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]), | ||||
MinRK
|
r13704 | (Int(5), 5), | ||
Fernando Perez
|
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)) | ||||
MinRK
|
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' | ||||
fmt = { | ||||
'image/png' : pngdata, | ||||
'image/jpeg' : jpegdata, | ||||
} | ||||
encoded = encode_images(fmt) | ||||
Thomas Kluyver
|
r13361 | for key, value in iteritems(fmt): | ||
MinRK
|
r7737 | # encoded has unicode, want bytes | ||
decoded = decodestring(encoded[key].encode('ascii')) | ||||
Thomas Kluyver
|
r12374 | nt.assert_equal(decoded, value) | ||
MinRK
|
r7737 | encoded2 = encode_images(encoded) | ||
Thomas Kluyver
|
r12374 | nt.assert_equal(encoded, encoded2) | ||
MinRK
|
r7737 | |||
b64_str = {} | ||||
Thomas Kluyver
|
r13361 | for key, encoded in iteritems(encoded): | ||
MinRK
|
r7737 | b64_str[key] = unicode_to_str(encoded) | ||
encoded3 = encode_images(b64_str) | ||||
Thomas Kluyver
|
r12374 | nt.assert_equal(encoded3, b64_str) | ||
Thomas Kluyver
|
r13361 | for key, value in iteritems(fmt): | ||
MinRK
|
r7737 | # encoded3 has str, want bytes | ||
decoded = decodestring(str_to_bytes(encoded3[key])) | ||||
Thomas Kluyver
|
r12374 | nt.assert_equal(decoded, value) | ||
MinRK
|
r7737 | |||
Fernando Perez
|
r2947 | def test_lambda(): | ||
jc = json_clean(lambda : 1) | ||||
Thomas Kluyver
|
r7013 | assert isinstance(jc, str) | ||
assert '<lambda>' in jc | ||||
Fernando Perez
|
r2947 | json.dumps(jc) | ||
MinRK
|
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) | ||||
MinRK
|
r13521 | def test_parse_ms_precision(): | ||
base = '2013-07-03T16:34:52.' | ||||
digits = '1234567890' | ||||
for i in range(len(digits)): | ||||
ts = base + digits[:i] | ||||
parsed = jsonutil.parse_date(ts) | ||||
if i >= 1 and i <= 6: | ||||
assert isinstance(parsed, datetime.datetime) | ||||
else: | ||||
assert isinstance(parsed, str) | ||||
MinRK
|
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(): | ||||
nt.assert_true(isinstance(dt, datetime.datetime)) | ||||
Fernando Perez
|
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) | ||||