1# Copyright (C) 2003 Python Software Foundation
2
3import unittest
4import plistlib
5import os
6import datetime
7from test import test_support
8
9
10# This test data was generated through Cocoa's NSDictionary class
11TESTDATA = """<?xml version="1.0" encoding="UTF-8"?>
12<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" \
13"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
14<plist version="1.0">
15<dict>
16        <key>aDate</key>
17        <date>2004-10-26T10:33:33Z</date>
18        <key>aDict</key>
19        <dict>
20                <key>aFalseValue</key>
21                <false/>
22                <key>aTrueValue</key>
23                <true/>
24                <key>aUnicodeValue</key>
25                <string>M\xc3\xa4ssig, Ma\xc3\x9f</string>
26                <key>anotherString</key>
27                <string>&lt;hello &amp; 'hi' there!&gt;</string>
28                <key>deeperDict</key>
29                <dict>
30                        <key>a</key>
31                        <integer>17</integer>
32                        <key>b</key>
33                        <real>32.5</real>
34                        <key>c</key>
35                        <array>
36                                <integer>1</integer>
37                                <integer>2</integer>
38                                <string>text</string>
39                        </array>
40                </dict>
41        </dict>
42        <key>aFloat</key>
43        <real>0.5</real>
44        <key>aList</key>
45        <array>
46                <string>A</string>
47                <string>B</string>
48                <integer>12</integer>
49                <real>32.5</real>
50                <array>
51                        <integer>1</integer>
52                        <integer>2</integer>
53                        <integer>3</integer>
54                </array>
55        </array>
56        <key>aString</key>
57        <string>Doodah</string>
58        <key>anInt</key>
59        <integer>728</integer>
60        <key>nestedData</key>
61        <array>
62                <data>
63                PGxvdHMgb2YgYmluYXJ5IGd1bms+AAECAzxsb3RzIG9mIGJpbmFyeSBndW5r
64                PgABAgM8bG90cyBvZiBiaW5hcnkgZ3Vuaz4AAQIDPGxvdHMgb2YgYmluYXJ5
65                IGd1bms+AAECAzxsb3RzIG9mIGJpbmFyeSBndW5rPgABAgM8bG90cyBvZiBi
66                aW5hcnkgZ3Vuaz4AAQIDPGxvdHMgb2YgYmluYXJ5IGd1bms+AAECAzxsb3Rz
67                IG9mIGJpbmFyeSBndW5rPgABAgM8bG90cyBvZiBiaW5hcnkgZ3Vuaz4AAQID
68                PGxvdHMgb2YgYmluYXJ5IGd1bms+AAECAw==
69                </data>
70        </array>
71        <key>someData</key>
72        <data>
73        PGJpbmFyeSBndW5rPg==
74        </data>
75        <key>someMoreData</key>
76        <data>
77        PGxvdHMgb2YgYmluYXJ5IGd1bms+AAECAzxsb3RzIG9mIGJpbmFyeSBndW5rPgABAgM8
78        bG90cyBvZiBiaW5hcnkgZ3Vuaz4AAQIDPGxvdHMgb2YgYmluYXJ5IGd1bms+AAECAzxs
79        b3RzIG9mIGJpbmFyeSBndW5rPgABAgM8bG90cyBvZiBiaW5hcnkgZ3Vuaz4AAQIDPGxv
80        dHMgb2YgYmluYXJ5IGd1bms+AAECAzxsb3RzIG9mIGJpbmFyeSBndW5rPgABAgM8bG90
81        cyBvZiBiaW5hcnkgZ3Vuaz4AAQIDPGxvdHMgb2YgYmluYXJ5IGd1bms+AAECAw==
82        </data>
83        <key>\xc3\x85benraa</key>
84        <string>That was a unicode key.</string>
85</dict>
86</plist>
87""".replace(" " * 8, "\t")  # Apple as well as plistlib.py output hard tabs
88
89
90class TestPlistlib(unittest.TestCase):
91
92    def tearDown(self):
93        try:
94            os.unlink(test_support.TESTFN)
95        except:
96            pass
97
98    def _create(self):
99        pl = dict(
100            aString="Doodah",
101            aList=["A", "B", 12, 32.5, [1, 2, 3]],
102            aFloat = 0.5,
103            anInt = 728,
104            aDict=dict(
105                anotherString="<hello & 'hi' there!>",
106                aUnicodeValue=u'M\xe4ssig, Ma\xdf',
107                aTrueValue=True,
108                aFalseValue=False,
109                deeperDict=dict(a=17, b=32.5, c=[1, 2, "text"]),
110            ),
111            someData = plistlib.Data("<binary gunk>"),
112            someMoreData = plistlib.Data("<lots of binary gunk>\0\1\2\3" * 10),
113            nestedData = [plistlib.Data("<lots of binary gunk>\0\1\2\3" * 10)],
114            aDate = datetime.datetime(2004, 10, 26, 10, 33, 33),
115        )
116        pl[u'\xc5benraa'] = "That was a unicode key."
117        return pl
118
119    def test_create(self):
120        pl = self._create()
121        self.assertEqual(pl["aString"], "Doodah")
122        self.assertEqual(pl["aDict"]["aFalseValue"], False)
123
124    def test_io(self):
125        pl = self._create()
126        plistlib.writePlist(pl, test_support.TESTFN)
127        pl2 = plistlib.readPlist(test_support.TESTFN)
128        self.assertEqual(dict(pl), dict(pl2))
129
130    def test_string(self):
131        pl = self._create()
132        data = plistlib.writePlistToString(pl)
133        pl2 = plistlib.readPlistFromString(data)
134        self.assertEqual(dict(pl), dict(pl2))
135        data2 = plistlib.writePlistToString(pl2)
136        self.assertEqual(data, data2)
137
138    def test_indentation_array(self):
139        data = [[[[[[[[{'test': plistlib.Data(b'aaaaaa')}]]]]]]]]
140        self.assertEqual(plistlib.readPlistFromString(plistlib.writePlistToString(data)), data)
141
142    def test_indentation_dict(self):
143        data = {'1': {'2': {'3': {'4': {'5': {'6': {'7': {'8': {'9': plistlib.Data(b'aaaaaa')}}}}}}}}}
144        self.assertEqual(plistlib.readPlistFromString(plistlib.writePlistToString(data)), data)
145
146    def test_indentation_dict_mix(self):
147        data = {'1': {'2': [{'3': [[[[[{'test': plistlib.Data(b'aaaaaa')}]]]]]}]}}
148        self.assertEqual(plistlib.readPlistFromString(plistlib.writePlistToString(data)), data)
149
150    def test_appleformatting(self):
151        pl = plistlib.readPlistFromString(TESTDATA)
152        data = plistlib.writePlistToString(pl)
153        self.assertEqual(data, TESTDATA,
154                         "generated data was not identical to Apple's output")
155
156    def test_appleformattingfromliteral(self):
157        pl = self._create()
158        pl2 = plistlib.readPlistFromString(TESTDATA)
159        self.assertEqual(dict(pl), dict(pl2),
160                         "generated data was not identical to Apple's output")
161
162    def test_stringio(self):
163        from StringIO import StringIO
164        f = StringIO()
165        pl = self._create()
166        plistlib.writePlist(pl, f)
167        pl2 = plistlib.readPlist(StringIO(f.getvalue()))
168        self.assertEqual(dict(pl), dict(pl2))
169
170    def test_cstringio(self):
171        from cStringIO import StringIO
172        f = StringIO()
173        pl = self._create()
174        plistlib.writePlist(pl, f)
175        pl2 = plistlib.readPlist(StringIO(f.getvalue()))
176        self.assertEqual(dict(pl), dict(pl2))
177
178    def test_controlcharacters(self):
179        for i in range(128):
180            c = chr(i)
181            testString = "string containing %s" % c
182            if i >= 32 or c in "\r\n\t":
183                # \r, \n and \t are the only legal control chars in XML
184                plistlib.writePlistToString(testString)
185            else:
186                self.assertRaises(ValueError,
187                                  plistlib.writePlistToString,
188                                  testString)
189
190    def test_nondictroot(self):
191        test1 = "abc"
192        test2 = [1, 2, 3, "abc"]
193        result1 = plistlib.readPlistFromString(plistlib.writePlistToString(test1))
194        result2 = plistlib.readPlistFromString(plistlib.writePlistToString(test2))
195        self.assertEqual(test1, result1)
196        self.assertEqual(test2, result2)
197
198
199def test_main():
200    test_support.run_unittest(TestPlistlib)
201
202
203if __name__ == '__main__':
204    test_main()
205