1# -*- coding: iso-8859-1 -*-
2
3from test import test_support
4import marshal
5import sys
6import unittest
7import os
8
9try:
10    import _testcapi
11except ImportError:
12    _testcapi = None
13
14class IntTestCase(unittest.TestCase):
15    def test_ints(self):
16        # Test the full range of Python ints.
17        n = sys.maxint
18        while n:
19            for expected in (-n, n):
20                s = marshal.dumps(expected)
21                got = marshal.loads(s)
22                self.assertEqual(expected, got)
23                marshal.dump(expected, file(test_support.TESTFN, "wb"))
24                got = marshal.load(file(test_support.TESTFN, "rb"))
25                self.assertEqual(expected, got)
26            n = n >> 1
27        os.unlink(test_support.TESTFN)
28
29    def test_int64(self):
30        # Simulate int marshaling on a 64-bit box.  This is most interesting if
31        # we're running the test on a 32-bit box, of course.
32
33        def to_little_endian_string(value, nbytes):
34            bytes = []
35            for i in range(nbytes):
36                bytes.append(chr(value & 0xff))
37                value >>= 8
38            return ''.join(bytes)
39
40        maxint64 = (1L << 63) - 1
41        minint64 = -maxint64-1
42
43        for base in maxint64, minint64, -maxint64, -(minint64 >> 1):
44            while base:
45                s = 'I' + to_little_endian_string(base, 8)
46                got = marshal.loads(s)
47                self.assertEqual(base, got)
48                if base == -1:  # a fixed-point for shifting right 1
49                    base = 0
50                else:
51                    base >>= 1
52
53    def test_bool(self):
54        for b in (True, False):
55            new = marshal.loads(marshal.dumps(b))
56            self.assertEqual(b, new)
57            self.assertEqual(type(b), type(new))
58            marshal.dump(b, file(test_support.TESTFN, "wb"))
59            new = marshal.load(file(test_support.TESTFN, "rb"))
60            self.assertEqual(b, new)
61            self.assertEqual(type(b), type(new))
62
63class FloatTestCase(unittest.TestCase):
64    def test_floats(self):
65        # Test a few floats
66        small = 1e-25
67        n = sys.maxint * 3.7e250
68        while n > small:
69            for expected in (-n, n):
70                f = float(expected)
71                s = marshal.dumps(f)
72                got = marshal.loads(s)
73                self.assertEqual(f, got)
74                marshal.dump(f, file(test_support.TESTFN, "wb"))
75                got = marshal.load(file(test_support.TESTFN, "rb"))
76                self.assertEqual(f, got)
77            n /= 123.4567
78
79        f = 0.0
80        s = marshal.dumps(f, 2)
81        got = marshal.loads(s)
82        self.assertEqual(f, got)
83        # and with version <= 1 (floats marshalled differently then)
84        s = marshal.dumps(f, 1)
85        got = marshal.loads(s)
86        self.assertEqual(f, got)
87
88        n = sys.maxint * 3.7e-250
89        while n < small:
90            for expected in (-n, n):
91                f = float(expected)
92
93                s = marshal.dumps(f)
94                got = marshal.loads(s)
95                self.assertEqual(f, got)
96
97                s = marshal.dumps(f, 1)
98                got = marshal.loads(s)
99                self.assertEqual(f, got)
100
101                marshal.dump(f, file(test_support.TESTFN, "wb"))
102                got = marshal.load(file(test_support.TESTFN, "rb"))
103                self.assertEqual(f, got)
104
105                marshal.dump(f, file(test_support.TESTFN, "wb"), 1)
106                got = marshal.load(file(test_support.TESTFN, "rb"))
107                self.assertEqual(f, got)
108            n *= 123.4567
109        os.unlink(test_support.TESTFN)
110
111class StringTestCase(unittest.TestCase):
112    def test_unicode(self):
113        for s in [u"", u"Andr� Previn", u"abc", u" "*10000]:
114            new = marshal.loads(marshal.dumps(s))
115            self.assertEqual(s, new)
116            self.assertEqual(type(s), type(new))
117            marshal.dump(s, file(test_support.TESTFN, "wb"))
118            new = marshal.load(file(test_support.TESTFN, "rb"))
119            self.assertEqual(s, new)
120            self.assertEqual(type(s), type(new))
121        os.unlink(test_support.TESTFN)
122
123    def test_string(self):
124        for s in ["", "Andr� Previn", "abc", " "*10000]:
125            new = marshal.loads(marshal.dumps(s))
126            self.assertEqual(s, new)
127            self.assertEqual(type(s), type(new))
128            marshal.dump(s, file(test_support.TESTFN, "wb"))
129            new = marshal.load(file(test_support.TESTFN, "rb"))
130            self.assertEqual(s, new)
131            self.assertEqual(type(s), type(new))
132        os.unlink(test_support.TESTFN)
133
134    def test_buffer(self):
135        for s in ["", "Andr� Previn", "abc", " "*10000]:
136            with test_support.check_py3k_warnings(("buffer.. not supported",
137                                                     DeprecationWarning)):
138                b = buffer(s)
139            new = marshal.loads(marshal.dumps(b))
140            self.assertEqual(s, new)
141            marshal.dump(b, file(test_support.TESTFN, "wb"))
142            new = marshal.load(file(test_support.TESTFN, "rb"))
143            self.assertEqual(s, new)
144        os.unlink(test_support.TESTFN)
145
146class ExceptionTestCase(unittest.TestCase):
147    def test_exceptions(self):
148        new = marshal.loads(marshal.dumps(StopIteration))
149        self.assertEqual(StopIteration, new)
150
151class CodeTestCase(unittest.TestCase):
152    def test_code(self):
153        co = ExceptionTestCase.test_exceptions.func_code
154        new = marshal.loads(marshal.dumps(co))
155        self.assertEqual(co, new)
156
157class ContainerTestCase(unittest.TestCase):
158    d = {'astring': 'foo@bar.baz.spam',
159         'afloat': 7283.43,
160         'anint': 2**20,
161         'ashortlong': 2L,
162         'alist': ['.zyx.41'],
163         'atuple': ('.zyx.41',)*10,
164         'aboolean': False,
165         'aunicode': u"Andr� Previn"
166         }
167    def test_dict(self):
168        new = marshal.loads(marshal.dumps(self.d))
169        self.assertEqual(self.d, new)
170        marshal.dump(self.d, file(test_support.TESTFN, "wb"))
171        new = marshal.load(file(test_support.TESTFN, "rb"))
172        self.assertEqual(self.d, new)
173        os.unlink(test_support.TESTFN)
174
175    def test_list(self):
176        lst = self.d.items()
177        new = marshal.loads(marshal.dumps(lst))
178        self.assertEqual(lst, new)
179        marshal.dump(lst, file(test_support.TESTFN, "wb"))
180        new = marshal.load(file(test_support.TESTFN, "rb"))
181        self.assertEqual(lst, new)
182        os.unlink(test_support.TESTFN)
183
184    def test_tuple(self):
185        t = tuple(self.d.keys())
186        new = marshal.loads(marshal.dumps(t))
187        self.assertEqual(t, new)
188        marshal.dump(t, file(test_support.TESTFN, "wb"))
189        new = marshal.load(file(test_support.TESTFN, "rb"))
190        self.assertEqual(t, new)
191        os.unlink(test_support.TESTFN)
192
193    def test_sets(self):
194        for constructor in (set, frozenset):
195            t = constructor(self.d.keys())
196            new = marshal.loads(marshal.dumps(t))
197            self.assertEqual(t, new)
198            self.assertTrue(isinstance(new, constructor))
199            self.assertNotEqual(id(t), id(new))
200            marshal.dump(t, file(test_support.TESTFN, "wb"))
201            new = marshal.load(file(test_support.TESTFN, "rb"))
202            self.assertEqual(t, new)
203            os.unlink(test_support.TESTFN)
204
205class BugsTestCase(unittest.TestCase):
206    def test_bug_5888452(self):
207        # Simple-minded check for SF 588452: Debug build crashes
208        marshal.dumps([128] * 1000)
209
210    def test_patch_873224(self):
211        self.assertRaises(Exception, marshal.loads, '0')
212        self.assertRaises(Exception, marshal.loads, 'f')
213        self.assertRaises(Exception, marshal.loads, marshal.dumps(5L)[:-1])
214
215    def test_version_argument(self):
216        # Python 2.4.0 crashes for any call to marshal.dumps(x, y)
217        self.assertEqual(marshal.loads(marshal.dumps(5, 0)), 5)
218        self.assertEqual(marshal.loads(marshal.dumps(5, 1)), 5)
219
220    def test_fuzz(self):
221        # simple test that it's at least not *totally* trivial to
222        # crash from bad marshal data
223        for c in [chr(i) for i in range(256)]:
224            try:
225                marshal.loads(c)
226            except Exception:
227                pass
228
229    def test_loads_recursion(self):
230        def run_tests(N, check):
231            # (((...None...),),)
232            check(b'(\x01\x00\x00\x00' * N + b'N')
233            # [[[...None...]]]
234            check(b'[\x01\x00\x00\x00' * N + b'N')
235            # {None: {None: {None: ...None...}}}
236            check(b'{N' * N + b'N' + b'0' * N)
237            # frozenset([frozenset([frozenset([...None...])])])
238            check(b'>\x01\x00\x00\x00' * N + b'N')
239        # Check that the generated marshal data is valid and marshal.loads()
240        # works for moderately deep nesting
241        run_tests(100, marshal.loads)
242        # Very deeply nested structure shouldn't blow the stack
243        def check(s):
244            self.assertRaises(ValueError, marshal.loads, s)
245        run_tests(2**20, check)
246
247    def test_recursion_limit(self):
248        # Create a deeply nested structure.
249        head = last = []
250        # The max stack depth should match the value in Python/marshal.c.
251        if os.name == 'nt' and hasattr(sys, 'gettotalrefcount'):
252            MAX_MARSHAL_STACK_DEPTH = 1000
253        else:
254            MAX_MARSHAL_STACK_DEPTH = 2000
255        for i in range(MAX_MARSHAL_STACK_DEPTH - 2):
256            last.append([0])
257            last = last[-1]
258
259        # Verify we don't blow out the stack with dumps/load.
260        data = marshal.dumps(head)
261        new_head = marshal.loads(data)
262        # Don't use == to compare objects, it can exceed the recursion limit.
263        self.assertEqual(len(new_head), len(head))
264        self.assertEqual(len(new_head[0]), len(head[0]))
265        self.assertEqual(len(new_head[-1]), len(head[-1]))
266
267        last.append([0])
268        self.assertRaises(ValueError, marshal.dumps, head)
269
270    def test_exact_type_match(self):
271        # Former bug:
272        #   >>> class Int(int): pass
273        #   >>> type(loads(dumps(Int())))
274        #   <type 'int'>
275        for typ in (int, long, float, complex, tuple, list, dict, set, frozenset):
276            # Note: str and unicode subclasses are not tested because they get handled
277            # by marshal's routines for objects supporting the buffer API.
278            subtyp = type('subtyp', (typ,), {})
279            self.assertRaises(ValueError, marshal.dumps, subtyp())
280
281    # Issue #1792 introduced a change in how marshal increases the size of its
282    # internal buffer; this test ensures that the new code is exercised.
283    def test_large_marshal(self):
284        size = int(1e6)
285        testString = 'abc' * size
286        marshal.dumps(testString)
287
288    def test_invalid_longs(self):
289        # Issue #7019: marshal.loads shouldn't produce unnormalized PyLongs
290        invalid_string = 'l\x02\x00\x00\x00\x00\x00\x00\x00'
291        self.assertRaises(ValueError, marshal.loads, invalid_string)
292
293LARGE_SIZE = 2**31
294character_size = 4 if sys.maxunicode > 0xFFFF else 2
295pointer_size = 8 if sys.maxsize > 0xFFFFFFFF else 4
296
297@unittest.skipIf(LARGE_SIZE > sys.maxsize, "test cannot run on 32-bit systems")
298class LargeValuesTestCase(unittest.TestCase):
299    def check_unmarshallable(self, data):
300        f = open(test_support.TESTFN, 'wb')
301        self.addCleanup(test_support.unlink, test_support.TESTFN)
302        with f:
303            self.assertRaises(ValueError, marshal.dump, data, f)
304
305    @test_support.precisionbigmemtest(size=LARGE_SIZE, memuse=1, dry_run=False)
306    def test_string(self, size):
307        self.check_unmarshallable('x' * size)
308
309    @test_support.precisionbigmemtest(size=LARGE_SIZE,
310            memuse=character_size + 2, dry_run=False)
311    def test_unicode(self, size):
312        self.check_unmarshallable(u'x' * size)
313
314    @test_support.precisionbigmemtest(size=LARGE_SIZE,
315            memuse=pointer_size, dry_run=False)
316    def test_tuple(self, size):
317        self.check_unmarshallable((None,) * size)
318
319    @test_support.precisionbigmemtest(size=LARGE_SIZE,
320            memuse=pointer_size, dry_run=False)
321    def test_list(self, size):
322        self.check_unmarshallable([None] * size)
323
324    @test_support.precisionbigmemtest(size=LARGE_SIZE,
325            memuse=pointer_size*12 + sys.getsizeof(LARGE_SIZE-1),
326            dry_run=False)
327    def test_set(self, size):
328        self.check_unmarshallable(set(range(size)))
329
330    @test_support.precisionbigmemtest(size=LARGE_SIZE,
331            memuse=pointer_size*12 + sys.getsizeof(LARGE_SIZE-1),
332            dry_run=False)
333    def test_frozenset(self, size):
334        self.check_unmarshallable(frozenset(range(size)))
335
336    @test_support.precisionbigmemtest(size=LARGE_SIZE, memuse=1, dry_run=False)
337    def test_bytearray(self, size):
338        self.check_unmarshallable(bytearray(size))
339
340
341@test_support.cpython_only
342@unittest.skipUnless(_testcapi, 'requires _testcapi')
343class CAPI_TestCase(unittest.TestCase):
344
345    def test_write_long_to_file(self):
346        for v in range(marshal.version + 1):
347            _testcapi.pymarshal_write_long_to_file(0x12345678, test_support.TESTFN, v)
348            with open(test_support.TESTFN, 'rb') as f:
349                data = f.read()
350            test_support.unlink(test_support.TESTFN)
351            self.assertEqual(data, b'\x78\x56\x34\x12')
352
353    def test_write_object_to_file(self):
354        obj = ('\u20ac', b'abc', 123, 45.6, 7+8j, 'long line '*1000)
355        for v in range(marshal.version + 1):
356            _testcapi.pymarshal_write_object_to_file(obj, test_support.TESTFN, v)
357            with open(test_support.TESTFN, 'rb') as f:
358                data = f.read()
359            test_support.unlink(test_support.TESTFN)
360            self.assertEqual(marshal.loads(data), obj)
361
362    def test_read_short_from_file(self):
363        with open(test_support.TESTFN, 'wb') as f:
364            f.write(b'\x34\x12xxxx')
365        r, p = _testcapi.pymarshal_read_short_from_file(test_support.TESTFN)
366        test_support.unlink(test_support.TESTFN)
367        self.assertEqual(r, 0x1234)
368        self.assertEqual(p, 2)
369
370    def test_read_long_from_file(self):
371        with open(test_support.TESTFN, 'wb') as f:
372            f.write(b'\x78\x56\x34\x12xxxx')
373        r, p = _testcapi.pymarshal_read_long_from_file(test_support.TESTFN)
374        test_support.unlink(test_support.TESTFN)
375        self.assertEqual(r, 0x12345678)
376        self.assertEqual(p, 4)
377
378    def test_read_last_object_from_file(self):
379        obj = ('\u20ac', b'abc', 123, 45.6, 7+8j)
380        for v in range(marshal.version + 1):
381            data = marshal.dumps(obj, v)
382            with open(test_support.TESTFN, 'wb') as f:
383                f.write(data + b'xxxx')
384            r, p = _testcapi.pymarshal_read_last_object_from_file(test_support.TESTFN)
385            test_support.unlink(test_support.TESTFN)
386            self.assertEqual(r, obj)
387
388    def test_read_object_from_file(self):
389        obj = ('\u20ac', b'abc', 123, 45.6, 7+8j)
390        for v in range(marshal.version + 1):
391            data = marshal.dumps(obj, v)
392            with open(test_support.TESTFN, 'wb') as f:
393                f.write(data + b'xxxx')
394            r, p = _testcapi.pymarshal_read_object_from_file(test_support.TESTFN)
395            test_support.unlink(test_support.TESTFN)
396            self.assertEqual(r, obj)
397            self.assertEqual(p, len(data))
398
399
400def test_main():
401    test_support.run_unittest(IntTestCase,
402                              FloatTestCase,
403                              StringTestCase,
404                              CodeTestCase,
405                              ContainerTestCase,
406                              ExceptionTestCase,
407                              BugsTestCase,
408                              LargeValuesTestCase,
409                              CAPI_TestCase,
410                             )
411
412if __name__ == "__main__":
413    test_main()
414