1import decimal 2from io import StringIO 3from collections import OrderedDict 4from test.test_json import PyTest, CTest 5 6 7class TestDecode: 8 def test_decimal(self): 9 rval = self.loads('1.1', parse_float=decimal.Decimal) 10 self.assertTrue(isinstance(rval, decimal.Decimal)) 11 self.assertEqual(rval, decimal.Decimal('1.1')) 12 13 def test_float(self): 14 rval = self.loads('1', parse_int=float) 15 self.assertTrue(isinstance(rval, float)) 16 self.assertEqual(rval, 1.0) 17 18 def test_empty_objects(self): 19 self.assertEqual(self.loads('{}'), {}) 20 self.assertEqual(self.loads('[]'), []) 21 self.assertEqual(self.loads('""'), "") 22 23 def test_object_pairs_hook(self): 24 s = '{"xkd":1, "kcw":2, "art":3, "hxm":4, "qrt":5, "pad":6, "hoy":7}' 25 p = [("xkd", 1), ("kcw", 2), ("art", 3), ("hxm", 4), 26 ("qrt", 5), ("pad", 6), ("hoy", 7)] 27 self.assertEqual(self.loads(s), eval(s)) 28 self.assertEqual(self.loads(s, object_pairs_hook=lambda x: x), p) 29 self.assertEqual(self.json.load(StringIO(s), 30 object_pairs_hook=lambda x: x), p) 31 od = self.loads(s, object_pairs_hook=OrderedDict) 32 self.assertEqual(od, OrderedDict(p)) 33 self.assertEqual(type(od), OrderedDict) 34 # the object_pairs_hook takes priority over the object_hook 35 self.assertEqual(self.loads(s, object_pairs_hook=OrderedDict, 36 object_hook=lambda x: None), 37 OrderedDict(p)) 38 # check that empty object literals work (see #17368) 39 self.assertEqual(self.loads('{}', object_pairs_hook=OrderedDict), 40 OrderedDict()) 41 self.assertEqual(self.loads('{"empty": {}}', 42 object_pairs_hook=OrderedDict), 43 OrderedDict([('empty', OrderedDict())])) 44 45 def test_decoder_optimizations(self): 46 # Several optimizations were made that skip over calls to 47 # the whitespace regex, so this test is designed to try and 48 # exercise the uncommon cases. The array cases are already covered. 49 rval = self.loads('{ "key" : "value" , "k":"v" }') 50 self.assertEqual(rval, {"key":"value", "k":"v"}) 51 52 def check_keys_reuse(self, source, loads): 53 rval = loads(source) 54 (a, b), (c, d) = sorted(rval[0]), sorted(rval[1]) 55 self.assertIs(a, c) 56 self.assertIs(b, d) 57 58 def test_keys_reuse(self): 59 s = '[{"a_key": 1, "b_\xe9": 2}, {"a_key": 3, "b_\xe9": 4}]' 60 self.check_keys_reuse(s, self.loads) 61 decoder = self.json.decoder.JSONDecoder() 62 self.check_keys_reuse(s, decoder.decode) 63 self.assertFalse(decoder.memo) 64 65 def test_extra_data(self): 66 s = '[1, 2, 3]5' 67 msg = 'Extra data' 68 self.assertRaisesRegex(self.JSONDecodeError, msg, self.loads, s) 69 70 def test_invalid_escape(self): 71 s = '["abc\\y"]' 72 msg = 'escape' 73 self.assertRaisesRegex(self.JSONDecodeError, msg, self.loads, s) 74 75 def test_invalid_input_type(self): 76 msg = 'the JSON object must be str' 77 for value in [1, 3.14, [], {}, None]: 78 self.assertRaisesRegex(TypeError, msg, self.loads, value) 79 80 def test_string_with_utf8_bom(self): 81 # see #18958 82 bom_json = "[1,2,3]".encode('utf-8-sig').decode('utf-8') 83 with self.assertRaises(self.JSONDecodeError) as cm: 84 self.loads(bom_json) 85 self.assertIn('BOM', str(cm.exception)) 86 with self.assertRaises(self.JSONDecodeError) as cm: 87 self.json.load(StringIO(bom_json)) 88 self.assertIn('BOM', str(cm.exception)) 89 # make sure that the BOM is not detected in the middle of a string 90 bom_in_str = '"{}"'.format(''.encode('utf-8-sig').decode('utf-8')) 91 self.assertEqual(self.loads(bom_in_str), '\ufeff') 92 self.assertEqual(self.json.load(StringIO(bom_in_str)), '\ufeff') 93 94 def test_negative_index(self): 95 d = self.json.JSONDecoder() 96 self.assertRaises(ValueError, d.raw_decode, 'a'*42, -50000) 97 98class TestPyDecode(TestDecode, PyTest): pass 99class TestCDecode(TestDecode, CTest): pass 100