blob: fef9f3997237e1b5dd9275cefe028e9da7452161 [file] [log] [blame]
Ronald Oussorenc5cf7972013-11-21 15:46:49 +01001# Copyright (C) 2003-2013 Python Software Foundation
Jack Jansen838e76a2003-02-25 12:58:58 +00002
3import unittest
4import plistlib
5import os
Just van Rossumfc93e172004-10-26 11:02:08 +00006import datetime
Ronald Oussorenc5cf7972013-11-21 15:46:49 +01007import codecs
8import binascii
9import collections
Ronald Oussoren6db66532014-01-15 11:32:35 +010010import struct
Benjamin Petersonee8712c2008-05-20 21:35:26 +000011from test import support
Ronald Oussorenc5cf7972013-11-21 15:46:49 +010012from io import BytesIO
Jack Jansen838e76a2003-02-25 12:58:58 +000013
Ronald Oussorenc5cf7972013-11-21 15:46:49 +010014ALL_FORMATS=(plistlib.FMT_XML, plistlib.FMT_BINARY)
Just van Rossumfc93e172004-10-26 11:02:08 +000015
Ronald Oussorenc5cf7972013-11-21 15:46:49 +010016# The testdata is generated using Mac/Tools/plistlib_generate_testdata.py
17# (which using PyObjC to control the Cocoa classes for generating plists)
18TESTDATA={
19 plistlib.FMT_XML: binascii.a2b_base64(b'''
20 PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCFET0NU
21 WVBFIHBsaXN0IFBVQkxJQyAiLS8vQXBwbGUvL0RURCBQTElTVCAxLjAvL0VO
22 IiAiaHR0cDovL3d3dy5hcHBsZS5jb20vRFREcy9Qcm9wZXJ0eUxpc3QtMS4w
Ronald Oussoren6db66532014-01-15 11:32:35 +010023 LmR0ZCI+CjxwbGlzdCB2ZXJzaW9uPSIxLjAiPgo8ZGljdD4KCTxrZXk+YUJp
24 Z0ludDwva2V5PgoJPGludGVnZXI+OTIyMzM3MjAzNjg1NDc3NTc2NDwvaW50
Ronald Oussoren94e44a92014-02-06 11:19:18 +010025 ZWdlcj4KCTxrZXk+YUJpZ0ludDI8L2tleT4KCTxpbnRlZ2VyPjkyMjMzNzIw
26 MzY4NTQ3NzU4NTI8L2ludGVnZXI+Cgk8a2V5PmFEYXRlPC9rZXk+Cgk8ZGF0
27 ZT4yMDA0LTEwLTI2VDEwOjMzOjMzWjwvZGF0ZT4KCTxrZXk+YURpY3Q8L2tl
28 eT4KCTxkaWN0PgoJCTxrZXk+YUZhbHNlVmFsdWU8L2tleT4KCQk8ZmFsc2Uv
29 PgoJCTxrZXk+YVRydWVWYWx1ZTwva2V5PgoJCTx0cnVlLz4KCQk8a2V5PmFV
30 bmljb2RlVmFsdWU8L2tleT4KCQk8c3RyaW5nPk3DpHNzaWcsIE1hw588L3N0
31 cmluZz4KCQk8a2V5PmFub3RoZXJTdHJpbmc8L2tleT4KCQk8c3RyaW5nPiZs
32 dDtoZWxsbyAmYW1wOyAnaGknIHRoZXJlISZndDs8L3N0cmluZz4KCQk8a2V5
33 PmRlZXBlckRpY3Q8L2tleT4KCQk8ZGljdD4KCQkJPGtleT5hPC9rZXk+CgkJ
34 CTxpbnRlZ2VyPjE3PC9pbnRlZ2VyPgoJCQk8a2V5PmI8L2tleT4KCQkJPHJl
35 YWw+MzIuNTwvcmVhbD4KCQkJPGtleT5jPC9rZXk+CgkJCTxhcnJheT4KCQkJ
36 CTxpbnRlZ2VyPjE8L2ludGVnZXI+CgkJCQk8aW50ZWdlcj4yPC9pbnRlZ2Vy
37 PgoJCQkJPHN0cmluZz50ZXh0PC9zdHJpbmc+CgkJCTwvYXJyYXk+CgkJPC9k
38 aWN0PgoJPC9kaWN0PgoJPGtleT5hRmxvYXQ8L2tleT4KCTxyZWFsPjAuNTwv
39 cmVhbD4KCTxrZXk+YUxpc3Q8L2tleT4KCTxhcnJheT4KCQk8c3RyaW5nPkE8
40 L3N0cmluZz4KCQk8c3RyaW5nPkI8L3N0cmluZz4KCQk8aW50ZWdlcj4xMjwv
41 aW50ZWdlcj4KCQk8cmVhbD4zMi41PC9yZWFsPgoJCTxhcnJheT4KCQkJPGlu
42 dGVnZXI+MTwvaW50ZWdlcj4KCQkJPGludGVnZXI+MjwvaW50ZWdlcj4KCQkJ
43 PGludGVnZXI+MzwvaW50ZWdlcj4KCQk8L2FycmF5PgoJPC9hcnJheT4KCTxr
44 ZXk+YU5lZ2F0aXZlQmlnSW50PC9rZXk+Cgk8aW50ZWdlcj4tODAwMDAwMDAw
45 MDA8L2ludGVnZXI+Cgk8a2V5PmFOZWdhdGl2ZUludDwva2V5PgoJPGludGVn
46 ZXI+LTU8L2ludGVnZXI+Cgk8a2V5PmFTdHJpbmc8L2tleT4KCTxzdHJpbmc+
47 RG9vZGFoPC9zdHJpbmc+Cgk8a2V5PmFuRW1wdHlEaWN0PC9rZXk+Cgk8ZGlj
48 dC8+Cgk8a2V5PmFuRW1wdHlMaXN0PC9rZXk+Cgk8YXJyYXkvPgoJPGtleT5h
49 bkludDwva2V5PgoJPGludGVnZXI+NzI4PC9pbnRlZ2VyPgoJPGtleT5uZXN0
50 ZWREYXRhPC9rZXk+Cgk8YXJyYXk+CgkJPGRhdGE+CgkJUEd4dmRITWdiMlln
Ronald Oussoren6db66532014-01-15 11:32:35 +010051 WW1sdVlYSjVJR2QxYm1zK0FBRUNBenhzYjNSeklHOW1JR0pwYm1GeWVTQm5k
Ronald Oussoren94e44a92014-02-06 11:19:18 +010052 VzVyCgkJUGdBQkFnTThiRzkwY3lCdlppQmlhVzVoY25rZ1ozVnVhejRBQVFJ
53 RFBHeHZkSE1nYjJZZ1ltbHVZWEo1CgkJSUdkMWJtcytBQUVDQXp4c2IzUnpJ
54 RzltSUdKcGJtRnllU0JuZFc1clBnQUJBZ004Ykc5MGN5QnZaaUJpCgkJYVc1
55 aGNua2daM1Z1YXo0QUFRSURQR3h2ZEhNZ2IyWWdZbWx1WVhKNUlHZDFibXMr
56 QUFFQ0F6eHNiM1J6CgkJSUc5bUlHSnBibUZ5ZVNCbmRXNXJQZ0FCQWdNOGJH
57 OTBjeUJ2WmlCaWFXNWhjbmtnWjNWdWF6NEFBUUlECgkJUEd4dmRITWdiMlln
58 WW1sdVlYSjVJR2QxYm1zK0FBRUNBdz09CgkJPC9kYXRhPgoJPC9hcnJheT4K
59 CTxrZXk+c29tZURhdGE8L2tleT4KCTxkYXRhPgoJUEdKcGJtRnllU0JuZFc1
60 clBnPT0KCTwvZGF0YT4KCTxrZXk+c29tZU1vcmVEYXRhPC9rZXk+Cgk8ZGF0
61 YT4KCVBHeHZkSE1nYjJZZ1ltbHVZWEo1SUdkMWJtcytBQUVDQXp4c2IzUnpJ
62 RzltSUdKcGJtRnllU0JuZFc1clBnQUJBZ004CgliRzkwY3lCdlppQmlhVzVo
63 Y25rZ1ozVnVhejRBQVFJRFBHeHZkSE1nYjJZZ1ltbHVZWEo1SUdkMWJtcytB
64 QUVDQXp4cwoJYjNSeklHOW1JR0pwYm1GeWVTQm5kVzVyUGdBQkFnTThiRzkw
65 Y3lCdlppQmlhVzVoY25rZ1ozVnVhejRBQVFJRFBHeHYKCWRITWdiMllnWW1s
66 dVlYSjVJR2QxYm1zK0FBRUNBenhzYjNSeklHOW1JR0pwYm1GeWVTQm5kVzVy
67 UGdBQkFnTThiRzkwCgljeUJ2WmlCaWFXNWhjbmtnWjNWdWF6NEFBUUlEUEd4
68 dmRITWdiMllnWW1sdVlYSjVJR2QxYm1zK0FBRUNBdz09Cgk8L2RhdGE+Cgk8
69 a2V5PsOFYmVucmFhPC9rZXk+Cgk8c3RyaW5nPlRoYXQgd2FzIGEgdW5pY29k
70 ZSBrZXkuPC9zdHJpbmc+CjwvZGljdD4KPC9wbGlzdD4K'''),
Ronald Oussorenc5cf7972013-11-21 15:46:49 +010071 plistlib.FMT_BINARY: binascii.a2b_base64(b'''
Ronald Oussoren94e44a92014-02-06 11:19:18 +010072 YnBsaXN0MDDfEBABAgMEBQYHCAkKCwwNDg8QERITFCgpLzAxMjM0NTc2OFdh
73 QmlnSW50WGFCaWdJbnQyVWFEYXRlVWFEaWN0VmFGbG9hdFVhTGlzdF8QD2FO
74 ZWdhdGl2ZUJpZ0ludFxhTmVnYXRpdmVJbnRXYVN0cmluZ1thbkVtcHR5RGlj
75 dFthbkVtcHR5TGlzdFVhbkludFpuZXN0ZWREYXRhWHNvbWVEYXRhXHNvbWVN
76 b3JlRGF0YWcAxQBiAGUAbgByAGEAYRN/////////1BQAAAAAAAAAAIAAAAAA
77 AAAsM0GcuX30AAAA1RUWFxgZGhscHR5bYUZhbHNlVmFsdWVaYVRydWVWYWx1
78 ZV1hVW5pY29kZVZhbHVlXWFub3RoZXJTdHJpbmdaZGVlcGVyRGljdAgJawBN
79 AOQAcwBzAGkAZwAsACAATQBhAN9fEBU8aGVsbG8gJiAnaGknIHRoZXJlIT7T
80 HyAhIiMkUWFRYlFjEBEjQEBAAAAAAACjJSYnEAEQAlR0ZXh0Iz/gAAAAAAAA
81 pSorLCMtUUFRQhAMoyUmLhADE////+1foOAAE//////////7VkRvb2RhaNCg
82 EQLYoTZPEPo8bG90cyBvZiBiaW5hcnkgZ3Vuaz4AAQIDPGxvdHMgb2YgYmlu
83 YXJ5IGd1bms+AAECAzxsb3RzIG9mIGJpbmFyeSBndW5rPgABAgM8bG90cyBv
84 ZiBiaW5hcnkgZ3Vuaz4AAQIDPGxvdHMgb2YgYmluYXJ5IGd1bms+AAECAzxs
85 b3RzIG9mIGJpbmFyeSBndW5rPgABAgM8bG90cyBvZiBiaW5hcnkgZ3Vuaz4A
86 AQIDPGxvdHMgb2YgYmluYXJ5IGd1bms+AAECAzxsb3RzIG9mIGJpbmFyeSBn
87 dW5rPgABAgM8bG90cyBvZiBiaW5hcnkgZ3Vuaz4AAQIDTTxiaW5hcnkgZ3Vu
88 az5fEBdUaGF0IHdhcyBhIHVuaWNvZGUga2V5LgAIACsAMwA8AEIASABPAFUA
89 ZwB0AHwAiACUAJoApQCuALsAygDTAOQA7QD4AQQBDwEdASsBNgE3ATgBTwFn
90 AW4BcAFyAXQBdgF/AYMBhQGHAYwBlQGbAZ0BnwGhAaUBpwGwAbkBwAHBAcIB
91 xQHHAsQC0gAAAAAAAAIBAAAAAAAAADkAAAAAAAAAAAAAAAAAAALs'''),
Ronald Oussorenc5cf7972013-11-21 15:46:49 +010092}
Just van Rossumfc93e172004-10-26 11:02:08 +000093
94
Jack Jansen838e76a2003-02-25 12:58:58 +000095class TestPlistlib(unittest.TestCase):
96
97 def tearDown(self):
98 try:
Benjamin Petersonee8712c2008-05-20 21:35:26 +000099 os.unlink(support.TESTFN)
Jack Jansen838e76a2003-02-25 12:58:58 +0000100 except:
101 pass
102
Ronald Oussorenc5cf7972013-11-21 15:46:49 +0100103 def _create(self, fmt=None):
Just van Rossumfc93e172004-10-26 11:02:08 +0000104 pl = dict(
Jack Jansen838e76a2003-02-25 12:58:58 +0000105 aString="Doodah",
Just van Rossumfc93e172004-10-26 11:02:08 +0000106 aList=["A", "B", 12, 32.5, [1, 2, 3]],
107 aFloat = 0.5,
Jack Jansen838e76a2003-02-25 12:58:58 +0000108 anInt = 728,
Ronald Oussoren6db66532014-01-15 11:32:35 +0100109 aBigInt = 2 ** 63 - 44,
Ronald Oussoren94e44a92014-02-06 11:19:18 +0100110 aBigInt2 = 2 ** 63 + 44,
Ronald Oussoren6db66532014-01-15 11:32:35 +0100111 aNegativeInt = -5,
112 aNegativeBigInt = -80000000000,
Just van Rossumfc93e172004-10-26 11:02:08 +0000113 aDict=dict(
114 anotherString="<hello & 'hi' there!>",
Guido van Rossumef87d6e2007-05-02 19:09:54 +0000115 aUnicodeValue='M\xe4ssig, Ma\xdf',
Jack Jansen838e76a2003-02-25 12:58:58 +0000116 aTrueValue=True,
117 aFalseValue=False,
Just van Rossumfc93e172004-10-26 11:02:08 +0000118 deeperDict=dict(a=17, b=32.5, c=[1, 2, "text"]),
Jack Jansen838e76a2003-02-25 12:58:58 +0000119 ),
Ronald Oussorenc5cf7972013-11-21 15:46:49 +0100120 someData = b"<binary gunk>",
121 someMoreData = b"<lots of binary gunk>\0\1\2\3" * 10,
122 nestedData = [b"<lots of binary gunk>\0\1\2\3" * 10],
Just van Rossumfc93e172004-10-26 11:02:08 +0000123 aDate = datetime.datetime(2004, 10, 26, 10, 33, 33),
Hynek Schlawack52209d32012-05-29 12:04:54 +0200124 anEmptyDict = dict(),
125 anEmptyList = list()
Jack Jansen838e76a2003-02-25 12:58:58 +0000126 )
Guido van Rossumef87d6e2007-05-02 19:09:54 +0000127 pl['\xc5benraa'] = "That was a unicode key."
Jack Jansen838e76a2003-02-25 12:58:58 +0000128 return pl
Tim Peters669454e2003-03-07 17:30:48 +0000129
Jack Jansen838e76a2003-02-25 12:58:58 +0000130 def test_create(self):
131 pl = self._create()
132 self.assertEqual(pl["aString"], "Doodah")
133 self.assertEqual(pl["aDict"]["aFalseValue"], False)
134
135 def test_io(self):
136 pl = self._create()
Ronald Oussorenc5cf7972013-11-21 15:46:49 +0100137 with open(support.TESTFN, 'wb') as fp:
138 plistlib.dump(pl, fp)
139
140 with open(support.TESTFN, 'rb') as fp:
141 pl2 = plistlib.load(fp)
142
Tim Peters669454e2003-03-07 17:30:48 +0000143 self.assertEqual(dict(pl), dict(pl2))
Jack Jansen838e76a2003-02-25 12:58:58 +0000144
Ronald Oussorenc5cf7972013-11-21 15:46:49 +0100145 self.assertRaises(AttributeError, plistlib.dump, pl, 'filename')
146 self.assertRaises(AttributeError, plistlib.load, 'filename')
147
Ronald Oussoren6db66532014-01-15 11:32:35 +0100148 def test_invalid_type(self):
149 pl = [ object() ]
150
151 for fmt in ALL_FORMATS:
152 with self.subTest(fmt=fmt):
153 self.assertRaises(TypeError, plistlib.dumps, pl, fmt=fmt)
154
155 def test_int(self):
156 for pl in [0, 2**8-1, 2**8, 2**16-1, 2**16, 2**32-1, 2**32,
Ronald Oussoren94e44a92014-02-06 11:19:18 +0100157 2**63-1, 2**64-1, 1, -2**63]:
Ronald Oussoren6db66532014-01-15 11:32:35 +0100158 for fmt in ALL_FORMATS:
159 with self.subTest(pl=pl, fmt=fmt):
160 data = plistlib.dumps(pl, fmt=fmt)
161 pl2 = plistlib.loads(data)
162 self.assertIsInstance(pl2, int)
163 self.assertEqual(pl, pl2)
164 data2 = plistlib.dumps(pl2, fmt=fmt)
165 self.assertEqual(data, data2)
166
167 for fmt in ALL_FORMATS:
168 for pl in (2 ** 64 + 1, 2 ** 127-1, -2**64, -2 ** 127):
169 with self.subTest(pl=pl, fmt=fmt):
170 self.assertRaises(OverflowError, plistlib.dumps,
171 pl, fmt=fmt)
Ronald Oussorenc5cf7972013-11-21 15:46:49 +0100172
Guido van Rossumcd869d82007-08-07 14:26:40 +0000173 def test_bytes(self):
Just van Rossumfc93e172004-10-26 11:02:08 +0000174 pl = self._create()
Ronald Oussorenc5cf7972013-11-21 15:46:49 +0100175 data = plistlib.dumps(pl)
176 pl2 = plistlib.loads(data)
177 self.assertNotIsInstance(pl, plistlib._InternalDict)
Just van Rossumfc93e172004-10-26 11:02:08 +0000178 self.assertEqual(dict(pl), dict(pl2))
Ronald Oussorenc5cf7972013-11-21 15:46:49 +0100179 data2 = plistlib.dumps(pl2)
Just van Rossumfc93e172004-10-26 11:02:08 +0000180 self.assertEqual(data, data2)
181
Ronald Oussoren326edfd2013-04-23 13:47:22 +0200182 def test_indentation_array(self):
Ronald Oussorenc5cf7972013-11-21 15:46:49 +0100183 data = [[[[[[[[{'test': b'aaaaaa'}]]]]]]]]
184 self.assertEqual(plistlib.loads(plistlib.dumps(data)), data)
Ronald Oussoren326edfd2013-04-23 13:47:22 +0200185
186 def test_indentation_dict(self):
Ronald Oussorenc5cf7972013-11-21 15:46:49 +0100187 data = {'1': {'2': {'3': {'4': {'5': {'6': {'7': {'8': {'9': b'aaaaaa'}}}}}}}}}
188 self.assertEqual(plistlib.loads(plistlib.dumps(data)), data)
Ronald Oussoren326edfd2013-04-23 13:47:22 +0200189
190 def test_indentation_dict_mix(self):
Ronald Oussorenc5cf7972013-11-21 15:46:49 +0100191 data = {'1': {'2': [{'3': [[[[[{'test': b'aaaaaa'}]]]]]}]}}
192 self.assertEqual(plistlib.loads(plistlib.dumps(data)), data)
Ronald Oussoren326edfd2013-04-23 13:47:22 +0200193
Just van Rossumfc93e172004-10-26 11:02:08 +0000194 def test_appleformatting(self):
Ronald Oussorenc5cf7972013-11-21 15:46:49 +0100195 for use_builtin_types in (True, False):
196 for fmt in ALL_FORMATS:
197 with self.subTest(fmt=fmt, use_builtin_types=use_builtin_types):
198 pl = plistlib.loads(TESTDATA[fmt],
199 use_builtin_types=use_builtin_types)
200 data = plistlib.dumps(pl, fmt=fmt)
201 self.assertEqual(data, TESTDATA[fmt],
202 "generated data was not identical to Apple's output")
203
Just van Rossumfc93e172004-10-26 11:02:08 +0000204
205 def test_appleformattingfromliteral(self):
Ronald Oussorenc5cf7972013-11-21 15:46:49 +0100206 self.maxDiff = None
207 for fmt in ALL_FORMATS:
208 with self.subTest(fmt=fmt):
209 pl = self._create(fmt=fmt)
Serhiy Storchaka89667592014-07-23 18:49:31 +0300210 pl2 = plistlib.loads(TESTDATA[fmt], fmt=fmt)
211 self.assertEqual(dict(pl), dict(pl2),
212 "generated data was not identical to Apple's output")
Ronald Oussorenc5cf7972013-11-21 15:46:49 +0100213 pl2 = plistlib.loads(TESTDATA[fmt])
214 self.assertEqual(dict(pl), dict(pl2),
215 "generated data was not identical to Apple's output")
Just van Rossumfc93e172004-10-26 11:02:08 +0000216
Guido van Rossumcd869d82007-08-07 14:26:40 +0000217 def test_bytesio(self):
Ronald Oussorenc5cf7972013-11-21 15:46:49 +0100218 for fmt in ALL_FORMATS:
219 with self.subTest(fmt=fmt):
220 b = BytesIO()
221 pl = self._create(fmt=fmt)
222 plistlib.dump(pl, b, fmt=fmt)
Serhiy Storchaka89667592014-07-23 18:49:31 +0300223 pl2 = plistlib.load(BytesIO(b.getvalue()), fmt=fmt)
224 self.assertEqual(dict(pl), dict(pl2))
Ronald Oussorenc5cf7972013-11-21 15:46:49 +0100225 pl2 = plistlib.load(BytesIO(b.getvalue()))
226 self.assertEqual(dict(pl), dict(pl2))
227
228 def test_keysort_bytesio(self):
229 pl = collections.OrderedDict()
230 pl['b'] = 1
231 pl['a'] = 2
232 pl['c'] = 3
233
234 for fmt in ALL_FORMATS:
235 for sort_keys in (False, True):
236 with self.subTest(fmt=fmt, sort_keys=sort_keys):
237 b = BytesIO()
238
239 plistlib.dump(pl, b, fmt=fmt, sort_keys=sort_keys)
240 pl2 = plistlib.load(BytesIO(b.getvalue()),
241 dict_type=collections.OrderedDict)
242
243 self.assertEqual(dict(pl), dict(pl2))
244 if sort_keys:
245 self.assertEqual(list(pl2.keys()), ['a', 'b', 'c'])
246 else:
247 self.assertEqual(list(pl2.keys()), ['b', 'a', 'c'])
248
249 def test_keysort(self):
250 pl = collections.OrderedDict()
251 pl['b'] = 1
252 pl['a'] = 2
253 pl['c'] = 3
254
255 for fmt in ALL_FORMATS:
256 for sort_keys in (False, True):
257 with self.subTest(fmt=fmt, sort_keys=sort_keys):
258 data = plistlib.dumps(pl, fmt=fmt, sort_keys=sort_keys)
259 pl2 = plistlib.loads(data, dict_type=collections.OrderedDict)
260
261 self.assertEqual(dict(pl), dict(pl2))
262 if sort_keys:
263 self.assertEqual(list(pl2.keys()), ['a', 'b', 'c'])
264 else:
265 self.assertEqual(list(pl2.keys()), ['b', 'a', 'c'])
266
267 def test_keys_no_string(self):
268 pl = { 42: 'aNumber' }
269
270 for fmt in ALL_FORMATS:
271 with self.subTest(fmt=fmt):
272 self.assertRaises(TypeError, plistlib.dumps, pl, fmt=fmt)
273
274 b = BytesIO()
275 self.assertRaises(TypeError, plistlib.dump, pl, b, fmt=fmt)
276
277 def test_skipkeys(self):
278 pl = {
279 42: 'aNumber',
280 'snake': 'aWord',
281 }
282
283 for fmt in ALL_FORMATS:
284 with self.subTest(fmt=fmt):
285 data = plistlib.dumps(
286 pl, fmt=fmt, skipkeys=True, sort_keys=False)
287
288 pl2 = plistlib.loads(data)
289 self.assertEqual(pl2, {'snake': 'aWord'})
290
291 fp = BytesIO()
292 plistlib.dump(
293 pl, fp, fmt=fmt, skipkeys=True, sort_keys=False)
294 data = fp.getvalue()
295 pl2 = plistlib.loads(fp.getvalue())
296 self.assertEqual(pl2, {'snake': 'aWord'})
297
298 def test_tuple_members(self):
299 pl = {
300 'first': (1, 2),
301 'second': (1, 2),
302 'third': (3, 4),
303 }
304
305 for fmt in ALL_FORMATS:
306 with self.subTest(fmt=fmt):
307 data = plistlib.dumps(pl, fmt=fmt)
308 pl2 = plistlib.loads(data)
309 self.assertEqual(pl2, {
310 'first': [1, 2],
311 'second': [1, 2],
312 'third': [3, 4],
313 })
314 self.assertIsNot(pl2['first'], pl2['second'])
315
316 def test_list_members(self):
317 pl = {
318 'first': [1, 2],
319 'second': [1, 2],
320 'third': [3, 4],
321 }
322
323 for fmt in ALL_FORMATS:
324 with self.subTest(fmt=fmt):
325 data = plistlib.dumps(pl, fmt=fmt)
326 pl2 = plistlib.loads(data)
327 self.assertEqual(pl2, {
328 'first': [1, 2],
329 'second': [1, 2],
330 'third': [3, 4],
331 })
332 self.assertIsNot(pl2['first'], pl2['second'])
333
334 def test_dict_members(self):
335 pl = {
336 'first': {'a': 1},
337 'second': {'a': 1},
338 'third': {'b': 2 },
339 }
340
341 for fmt in ALL_FORMATS:
342 with self.subTest(fmt=fmt):
343 data = plistlib.dumps(pl, fmt=fmt)
344 pl2 = plistlib.loads(data)
345 self.assertEqual(pl2, {
346 'first': {'a': 1},
347 'second': {'a': 1},
348 'third': {'b': 2 },
349 })
350 self.assertIsNot(pl2['first'], pl2['second'])
Just van Rossumbcc58e82003-07-01 20:22:30 +0000351
Just van Rossum48ecacc2004-11-12 08:34:32 +0000352 def test_controlcharacters(self):
Just van Rossum2dae7642004-11-12 09:36:12 +0000353 for i in range(128):
354 c = chr(i)
355 testString = "string containing %s" % c
356 if i >= 32 or c in "\r\n\t":
357 # \r, \n and \t are the only legal control chars in XML
Ronald Oussorenc5cf7972013-11-21 15:46:49 +0100358 plistlib.dumps(testString, fmt=plistlib.FMT_XML)
Just van Rossum2dae7642004-11-12 09:36:12 +0000359 else:
360 self.assertRaises(ValueError,
Ronald Oussorenc5cf7972013-11-21 15:46:49 +0100361 plistlib.dumps,
Just van Rossum2dae7642004-11-12 09:36:12 +0000362 testString)
Just van Rossum48ecacc2004-11-12 08:34:32 +0000363
364 def test_nondictroot(self):
Ronald Oussorenc5cf7972013-11-21 15:46:49 +0100365 for fmt in ALL_FORMATS:
366 with self.subTest(fmt=fmt):
367 test1 = "abc"
368 test2 = [1, 2, 3, "abc"]
369 result1 = plistlib.loads(plistlib.dumps(test1, fmt=fmt))
370 result2 = plistlib.loads(plistlib.dumps(test2, fmt=fmt))
371 self.assertEqual(test1, result1)
372 self.assertEqual(test2, result2)
Jack Jansen838e76a2003-02-25 12:58:58 +0000373
Ned Deilyb8e59f72011-05-28 02:19:19 -0700374 def test_invalidarray(self):
375 for i in ["<key>key inside an array</key>",
376 "<key>key inside an array2</key><real>3</real>",
377 "<true/><key>key inside an array3</key>"]:
Ronald Oussorenc5cf7972013-11-21 15:46:49 +0100378 self.assertRaises(ValueError, plistlib.loads,
Ned Deilyb8e59f72011-05-28 02:19:19 -0700379 ("<plist><array>%s</array></plist>"%i).encode())
380
381 def test_invaliddict(self):
382 for i in ["<key><true/>k</key><string>compound key</string>",
383 "<key>single key</key>",
384 "<string>missing key</string>",
385 "<key>k1</key><string>v1</string><real>5.3</real>"
386 "<key>k1</key><key>k2</key><string>double key</string>"]:
Ronald Oussorenc5cf7972013-11-21 15:46:49 +0100387 self.assertRaises(ValueError, plistlib.loads,
Ned Deilyb8e59f72011-05-28 02:19:19 -0700388 ("<plist><dict>%s</dict></plist>"%i).encode())
Ronald Oussorenc5cf7972013-11-21 15:46:49 +0100389 self.assertRaises(ValueError, plistlib.loads,
Ned Deilyb8e59f72011-05-28 02:19:19 -0700390 ("<plist><array><dict>%s</dict></array></plist>"%i).encode())
391
392 def test_invalidinteger(self):
Ronald Oussorenc5cf7972013-11-21 15:46:49 +0100393 self.assertRaises(ValueError, plistlib.loads,
Ned Deilyb8e59f72011-05-28 02:19:19 -0700394 b"<plist><integer>not integer</integer></plist>")
395
396 def test_invalidreal(self):
Ronald Oussorenc5cf7972013-11-21 15:46:49 +0100397 self.assertRaises(ValueError, plistlib.loads,
Ned Deilyb8e59f72011-05-28 02:19:19 -0700398 b"<plist><integer>not real</integer></plist>")
399
Ronald Oussorenc5cf7972013-11-21 15:46:49 +0100400 def test_xml_encodings(self):
401 base = TESTDATA[plistlib.FMT_XML]
402
403 for xml_encoding, encoding, bom in [
404 (b'utf-8', 'utf-8', codecs.BOM_UTF8),
405 (b'utf-16', 'utf-16-le', codecs.BOM_UTF16_LE),
406 (b'utf-16', 'utf-16-be', codecs.BOM_UTF16_BE),
407 # Expat does not support UTF-32
408 #(b'utf-32', 'utf-32-le', codecs.BOM_UTF32_LE),
409 #(b'utf-32', 'utf-32-be', codecs.BOM_UTF32_BE),
410 ]:
411
412 pl = self._create(fmt=plistlib.FMT_XML)
413 with self.subTest(encoding=encoding):
414 data = base.replace(b'UTF-8', xml_encoding)
415 data = bom + data.decode('utf-8').encode(encoding)
416 pl2 = plistlib.loads(data)
417 self.assertEqual(dict(pl), dict(pl2))
418
Serhiy Storchaka06526642014-05-23 16:13:33 +0300419 def test_nonstandard_refs_size(self):
420 # Issue #21538: Refs and offsets are 24-bit integers
421 data = (b'bplist00'
422 b'\xd1\x00\x00\x01\x00\x00\x02QaQb'
423 b'\x00\x00\x08\x00\x00\x0f\x00\x00\x11'
424 b'\x00\x00\x00\x00\x00\x00'
425 b'\x03\x03'
426 b'\x00\x00\x00\x00\x00\x00\x00\x03'
427 b'\x00\x00\x00\x00\x00\x00\x00\x00'
428 b'\x00\x00\x00\x00\x00\x00\x00\x13')
429 self.assertEqual(plistlib.loads(data), {'a': 'b'})
430
Ronald Oussorenc5cf7972013-11-21 15:46:49 +0100431
432class TestPlistlibDeprecated(unittest.TestCase):
433 def test_io_deprecated(self):
434 pl_in = {
435 'key': 42,
436 'sub': {
437 'key': 9,
438 'alt': 'value',
439 'data': b'buffer',
440 }
441 }
442 pl_out = plistlib._InternalDict({
443 'key': 42,
444 'sub': plistlib._InternalDict({
445 'key': 9,
446 'alt': 'value',
447 'data': plistlib.Data(b'buffer'),
448 })
449 })
450
451 self.addCleanup(support.unlink, support.TESTFN)
452 with self.assertWarns(DeprecationWarning):
453 plistlib.writePlist(pl_in, support.TESTFN)
454
455 with self.assertWarns(DeprecationWarning):
456 pl2 = plistlib.readPlist(support.TESTFN)
457
458 self.assertEqual(pl_out, pl2)
459
460 os.unlink(support.TESTFN)
461
462 with open(support.TESTFN, 'wb') as fp:
463 with self.assertWarns(DeprecationWarning):
464 plistlib.writePlist(pl_in, fp)
465
466 with open(support.TESTFN, 'rb') as fp:
467 with self.assertWarns(DeprecationWarning):
468 pl2 = plistlib.readPlist(fp)
469
470 self.assertEqual(pl_out, pl2)
471
472 def test_bytes_deprecated(self):
473 pl = {
474 'key': 42,
475 'sub': {
476 'key': 9,
477 'alt': 'value',
478 'data': b'buffer',
479 }
480 }
481 with self.assertWarns(DeprecationWarning):
482 data = plistlib.writePlistToBytes(pl)
483
484 with self.assertWarns(DeprecationWarning):
485 pl2 = plistlib.readPlistFromBytes(data)
486
487 self.assertIsInstance(pl2, plistlib._InternalDict)
488 self.assertEqual(pl2, plistlib._InternalDict(
489 key=42,
490 sub=plistlib._InternalDict(
491 key=9,
492 alt='value',
493 data=plistlib.Data(b'buffer'),
494 )
495 ))
496
497 with self.assertWarns(DeprecationWarning):
498 data2 = plistlib.writePlistToBytes(pl2)
499 self.assertEqual(data, data2)
500
501 def test_dataobject_deprecated(self):
502 in_data = { 'key': plistlib.Data(b'hello') }
503 out_data = { 'key': b'hello' }
504
505 buf = plistlib.dumps(in_data)
506
507 cur = plistlib.loads(buf)
508 self.assertEqual(cur, out_data)
509 self.assertNotEqual(cur, in_data)
510
511 cur = plistlib.loads(buf, use_builtin_types=False)
512 self.assertNotEqual(cur, out_data)
513 self.assertEqual(cur, in_data)
514
515 with self.assertWarns(DeprecationWarning):
516 cur = plistlib.readPlistFromBytes(buf)
517 self.assertNotEqual(cur, out_data)
518 self.assertEqual(cur, in_data)
519
Jack Jansen838e76a2003-02-25 12:58:58 +0000520
521def test_main():
Ronald Oussorenc5cf7972013-11-21 15:46:49 +0100522 support.run_unittest(TestPlistlib, TestPlistlibDeprecated)
Jack Jansen838e76a2003-02-25 12:58:58 +0000523
524
525if __name__ == '__main__':
526 test_main()