659dc0efed98019c86cdcd439ee9eaee652041ac
[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                  ('w', {1: 'fruit'}, '\x01\0'),
100                  # passing a dictionary is dodgy, but it gets coerced to keys
101                  # as if you called list()
102                  ]
103
104         for packer in both_packers:
105             for format, values, expected in cases:
106                 self.assertEquals(packer(format, values), expected)
107
108     def test_unpack_extra(self):
109         # Test leftover data
110         for unpacker in both_unpackers:
111             for format, values, packed in self.symm_cases:
112                 out, rest = unpacker(format, packed + 'hello sailor!')
113                 self.assertEquals(rest, 'hello sailor!')
114                 self.assertEquals(list(values), list(out))
115         
116
117     def test_unpack(self):
118         """Cookbook of tricky unpack tests"""
119         cases = [
120                  # Apparently I couldn't think of any tests that weren't
121                  # symmetric :-/
122                  ]
123         for unpacker in both_unpackers:
124             for format, values, expected in cases:
125                 out, rest = unpacker(format, expected)
126                 self.assertEquals(rest, '')
127                 self.assertEquals(list(values), list(out))
128
129
130     def test_pack_failures(self):
131         """Expected errors for incorrect packing"""
132         cases = [('w', [], IndexError),
133                  ('w', (), IndexError),
134                  ('w', {}, IndexError),
135                  ('ww', [2], IndexError),
136                  ('w', 2, TypeError),
137                  ('', [1, 2, 3], IndexError),
138                  ('w', None, TypeError),
139                  ('wwwwwwwwwwww', [], IndexError),
140                  ('w', [2, 3], IndexError),
141                  ('w', [0x60A15EC5L], TypeError),
142                  ('w', [None], TypeError),
143                  ('w', xrange(10000), IndexError),
144                  ('d', [], IndexError),
145                  ('d', [0L], TypeError),
146                  ('p', [], IndexError),
147                  ('f', [2], TypeError),
148                  ('P', [None], TypeError),
149                  ('P', (), IndexError),
150                  ('f', [hex], TypeError),
151                  ('fw', ['hello'], IndexError),
152                  ('f', [u'hello'], TypeError),
153                  ('B', [2], TypeError),
154                  (None, [2, 3, 4], TypeError),
155                  (ord('f'), [20], TypeError),
156                  (['w', 'w'], [2, 2], TypeError),
157                  ('Q', [2], ValueError),
158                  ('fQ', ['2', 3], ValueError),
159                  ('fQ', ['2'], IndexError),
160                  (2, [2], TypeError),
161                  ({}, {}, TypeError)]
162         for packer in both_packers:
163             for format, values, throwable_class in cases:
164                 def do_pack():
165                     packer(format, values)
166                 self.assertRaises(throwable_class, do_pack)
167
168
169     def test_unpack_failures(self):
170         """Expected errors for incorrect unpacking"""
171         cases = [('$', '', ValueError),
172                  ('Q', '', ValueError),
173                  ('Q$', '', ValueError),
174                  ('f', '', IndexError),
175                  ('d', '', IndexError),
176                  ('d', '2', IndexError),
177                  ('d', '22', IndexError),
178                  ('d', '222', IndexError),
179                  ('w', '', IndexError),
180                  ('w', '2', IndexError),
181                  ('f', 'hello', IndexError),
182                  ('f', '', IndexError),
183                  ('p', '\x01\0', IndexError),
184                  ('B', '\xff\0\0\0hello', IndexError),
185                  ('B', '\xff\0', IndexError),
186                  ('B', '\x01\0\0\0', IndexError),
187                  ('B', '\x05\0\0\0hell', IndexError),
188                  ('B', '\xff\xff\xff\xff', ValueError),
189                  ('B', 'foobar', IndexError),
190                  ('BB', '\x01\0\0\0a\x01', IndexError),
191                  ]
192
193         for unpacker in both_unpackers:
194             for format, values, throwable_class in cases:
195                 def do_unpack():
196                     unpacker(format, values)
197             self.assertRaises(throwable_class, do_unpack)
198
199         
200
201 if __name__ == '__main__':
202     unittest.main()
203