test_pack: Coercing a dictionary to a sequence as it is packed is not
[samba.git] / source3 / python / examples / tdbpack / test_tdbpack.py
1 #! /usr/bin/env python2.2
2
3 __doc__ = """test case for samba.tdbkpack functions
4
5 tdbpack provides a means of pickling values into binary formats
6 compatible with that used by the samba tdbpack()/tdbunpack()
7 functions.
8
9 Numbers are always stored in little-endian format; strings are stored
10 in either DOS or Unix codepage as appropriate.
11
12 The format for any particular element is encoded as a short ASCII
13 string, with one character per field."""
14
15 # Copyright (C) 2002 Hewlett-Packard.
16
17 __author__ = 'Martin Pool <mbp@sourcefrog.net>'
18
19 import unittest
20 import oldtdbutil
21 import samba.tdbpack
22
23 both_unpackers = (samba.tdbpack.unpack, oldtdbutil.unpack)
24 both_packers = (samba.tdbpack.pack, oldtdbutil.pack)
25     
26 class PackTests(unittest.TestCase):
27     symm_cases = [('B', ['hello' * 51], '\xff\0\0\0' + 'hello' * 51),
28              ('w', [42], '\x2a\0'),
29              ('www', [42, 2, 69], '\x2a\0\x02\0\x45\0'),
30              ('wd', [42, 256], '\x2a\0\0\x01\0\0'),
31              ('w', [0], '\0\0'),
32              ('w', [255], '\xff\0'),
33              ('w', [256], '\0\x01'),
34              ('w', [0xdead], '\xad\xde'),
35              ('w', [0xffff], '\xff\xff'),
36              ('p', [0], '\0\0\0\0'),
37              ('p', [1], '\x01\0\0\0'),
38              ('d', [0x01020304], '\x04\x03\x02\x01'),
39              ('d', [0x7fffffff], '\xff\xff\xff\x7f'),
40              ('d', [0x80000000], '\x00\x00\x00\x80'),
41              ('d', [-1], '\xff\xff\xff\xff'),
42              ('d', [-255], '\x01\xff\xff\xff'),
43              ('d', [-256], '\x00\xff\xff\xff'),
44              ('ddd', [1, 10, 50], '\x01\0\0\0\x0a\0\0\0\x32\0\0\0'),
45              ('ff', ['hello', 'world'], 'hello\0world\0'),
46              ('fP', ['hello', 'world'], 'hello\0world\0'),
47              ('PP', ['hello', 'world'], 'hello\0world\0'),
48              ('B', [''], '\0\0\0\0'),
49              ('B', ['hello'], '\x05\0\0\0hello'),
50              ('BB', ['hello\0world', 'now'],
51               '\x0b\0\0\0hello\0world\x03\0\0\0now'),
52              ('pd', [1, 10], '\x01\0\0\0\x0a\0\0\0'),
53              ('BBB', ['hello', '', 'world'],
54               '\x05\0\0\0hello\0\0\0\0\x05\0\0\0world'),
55
56              # strings are sequences in Python, there's no getting away
57              # from it
58              ('ffff', 'evil', 'e\0v\0i\0l\0'),
59              ('BBBB', 'evil',                   
60               '\x01\0\0\0e'
61               '\x01\0\0\0v'
62               '\x01\0\0\0i'
63               '\x01\0\0\0l'),
64
65              ('', [], ''),
66
67              # exercise some long strings
68              ('PP', ['hello' * 255, 'world' * 255],
69               'hello' * 255 + '\0' + 'world' * 255 + '\0'),
70              ('PP', ['hello' * 40000, 'world' * 50000],
71               'hello' * 40000 + '\0' + 'world' * 50000 + '\0'),
72              ('B', ['hello' * 51], '\xff\0\0\0' + 'hello' * 51),
73              ('BB', ['hello' * 40000, 'world' * 50000],
74               '\x40\x0d\x03\0' + 'hello' * 40000 + '\x90\xd0\x03\x00' + 'world' * 50000),
75              ]
76
77     def test_symmetric(self):
78         """Cookbook of symmetric pack/unpack tests
79         """
80         for packer in both_packers:
81             for unpacker in both_unpackers:
82                 for format, values, expected in self.symm_cases:
83                     self.assertEquals(packer(format, values), expected)
84                     out, rest = unpacker(format, expected)
85                     self.assertEquals(rest, '')
86                     self.assertEquals(list(values), list(out))
87         
88     
89     def test_pack(self):
90         """Cookbook of expected pack values
91
92         These can't be used for the symmetric test because the unpacked value is
93         not "canonical".
94         """
95         cases = [('w', (42,), '\x2a\0'),
96                  ('p', [None], '\0\0\0\0'),
97                  ('p', ['true'], '\x01\0\0\0'),
98                  ]
99
100         for packer in both_packers:
101             for format, values, expected in cases:
102                 self.assertEquals(packer(format, values), expected)
103
104     def test_unpack_extra(self):
105         # Test leftover data
106         for unpacker in both_unpackers:
107             for format, values, packed in self.symm_cases:
108                 out, rest = unpacker(format, packed + 'hello sailor!')
109                 self.assertEquals(rest, 'hello sailor!')
110                 self.assertEquals(list(values), list(out))
111         
112
113     def test_unpack(self):
114         """Cookbook of tricky unpack tests"""
115         cases = [
116                  # Apparently I couldn't think of any tests that weren't
117                  # symmetric :-/
118                  ]
119         for unpacker in both_unpackers:
120             for format, values, expected in cases:
121                 out, rest = unpacker(format, expected)
122                 self.assertEquals(rest, '')
123                 self.assertEquals(list(values), list(out))
124
125
126     def test_pack_failures(self):
127         """Expected errors for incorrect packing"""
128         cases = [('w', [], IndexError),
129                  ('w', (), IndexError),
130                  ('w', {}, IndexError),
131                  ('ww', [2], IndexError),
132                  ('w', 2, TypeError),
133                  ('', [1, 2, 3], IndexError),
134                  ('w', None, TypeError),
135                  ('wwwwwwwwwwww', [], IndexError),
136                  ('w', [2, 3], IndexError),
137                  ('w', [0x60A15EC5L], TypeError),
138                  ('w', [None], TypeError),
139                  ('w', xrange(10000), IndexError),
140                  ('d', [], IndexError),
141                  ('d', [0L], TypeError),
142                  ('p', [], IndexError),
143                  ('f', [2], TypeError),
144                  ('P', [None], TypeError),
145                  ('P', (), IndexError),
146                  ('f', [hex], TypeError),
147                  ('fw', ['hello'], IndexError),
148                  ('f', [u'hello'], TypeError),
149                  ('B', [2], TypeError),
150                  (None, [2, 3, 4], TypeError),
151                  (ord('f'), [20], TypeError),
152                  (['w', 'w'], [2, 2], TypeError),
153                  ('Q', [2], ValueError),
154                  ('fQ', ['2', 3], ValueError),
155                  ('fQ', ['2'], IndexError),
156                  (2, [2], TypeError),
157                  ({}, {}, TypeError)]
158         for packer in both_packers:
159             for format, values, throwable_class in cases:
160                 def do_pack():
161                     packer(format, values)
162                 self.assertRaises(throwable_class, do_pack)
163
164
165     def test_unpack_failures(self):
166         """Expected errors for incorrect unpacking"""
167         cases = [('$', '', ValueError),
168                  ('Q', '', ValueError),
169                  ('Q$', '', ValueError),
170                  ('f', '', IndexError),
171                  ('d', '', IndexError),
172                  ('d', '2', IndexError),
173                  ('d', '22', IndexError),
174                  ('d', '222', IndexError),
175                  ('w', '', IndexError),
176                  ('w', '2', IndexError),
177                  ('f', 'hello', IndexError),
178                  ('f', '', IndexError),
179                  ('p', '\x01\0', IndexError),
180                  ('B', '\xff\0\0\0hello', IndexError),
181                  ('B', '\xff\0', IndexError),
182                  ('B', '\x01\0\0\0', IndexError),
183                  ('B', '\x05\0\0\0hell', IndexError),
184                  ('B', '\xff\xff\xff\xff', ValueError),
185                  ('B', 'foobar', IndexError),
186                  ('BB', '\x01\0\0\0a\x01', IndexError),
187                  ]
188
189         for unpacker in both_unpackers:
190             for format, values, throwable_class in cases:
191                 def do_unpack():
192                     unpacker(format, values)
193             self.assertRaises(throwable_class, do_unpack)
194
195         
196
197 if __name__ == '__main__':
198     unittest.main()
199