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        s = 'c' + ('X' * 4*4) + '{' * 2**20
231        self.assertRaises(ValueError, marshal.loads, s)
232
233    def test_recursion_limit(self):
234        # Create a deeply nested structure.
235        head = last = []
236        # The max stack depth should match the value in Python/marshal.c.
237        if os.name == 'nt' and hasattr(sys, 'gettotalrefcount'):
238            MAX_MARSHAL_STACK_DEPTH = 1000
239        else:
240            MAX_MARSHAL_STACK_DEPTH = 2000
241        for i in range(MAX_MARSHAL_STACK_DEPTH - 2):
242            last.append([0])
243            last = last[-1]
244
245        # Verify we don't blow out the stack with dumps/load.
246        data = marshal.dumps(head)
247        new_head = marshal.loads(data)
248        # Don't use == to compare objects, it can exceed the recursion limit.
249        self.assertEqual(len(new_head), len(head))
250        self.assertEqual(len(new_head[0]), len(head[0]))
251        self.assertEqual(len(new_head[-1]), len(head[-1]))
252
253        last.append([0])
254        self.assertRaises(ValueError, marshal.dumps, head)
255
256    def test_exact_type_match(self):
257        # Former bug:
258        #   >>> class Int(int): pass
259        #   >>> type(loads(dumps(Int())))
260        #   <type 'int'>
261        for typ in (int, long, float, complex, tuple, list, dict, set, frozenset):
262            # Note: str and unicode subclasses are not tested because they get handled
263            # by marshal's routines for objects supporting the buffer API.
264            subtyp = type('subtyp', (typ,), {})
265            self.assertRaises(ValueError, marshal.dumps, subtyp())
266
267    # Issue #1792 introduced a change in how marshal increases the size of its
268    # internal buffer; this test ensures that the new code is exercised.
269    def test_large_marshal(self):
270        size = int(1e6)
271        testString = 'abc' * size
272        marshal.dumps(testString)
273
274    def test_invalid_longs(self):
275        # Issue #7019: marshal.loads shouldn't produce unnormalized PyLongs
276        invalid_string = 'l\x02\x00\x00\x00\x00\x00\x00\x00'
277        self.assertRaises(ValueError, marshal.loads, invalid_string)
278
279LARGE_SIZE = 2**31
280character_size = 4 if sys.maxunicode > 0xFFFF else 2
281pointer_size = 8 if sys.maxsize > 0xFFFFFFFF else 4
282
283@unittest.skipIf(LARGE_SIZE > sys.maxsize, "test cannot run on 32-bit systems")
284class LargeValuesTestCase(unittest.TestCase):
285    def check_unmarshallable(self, data):
286        f = open(test_support.TESTFN, 'wb')
287        self.addCleanup(test_support.unlink, test_support.TESTFN)
288        with f:
289            self.assertRaises(ValueError, marshal.dump, data, f)
290
291    @test_support.precisionbigmemtest(size=LARGE_SIZE, memuse=1, dry_run=False)
292    def test_string(self, size):
293        self.check_unmarshallable('x' * size)
294
295    @test_support.precisionbigmemtest(size=LARGE_SIZE,
296            memuse=character_size + 2, dry_run=False)
297    def test_unicode(self, size):
298        self.check_unmarshallable(u'x' * size)
299
300    @test_support.precisionbigmemtest(size=LARGE_SIZE,
301            memuse=pointer_size, dry_run=False)
302    def test_tuple(self, size):
303        self.check_unmarshallable((None,) * size)
304
305    @test_support.precisionbigmemtest(size=LARGE_SIZE,
306            memuse=pointer_size, dry_run=False)
307    def test_list(self, size):
308        self.check_unmarshallable([None] * size)
309
310    @test_support.precisionbigmemtest(size=LARGE_SIZE,
311            memuse=pointer_size*12 + sys.getsizeof(LARGE_SIZE-1),
312            dry_run=False)
313    def test_set(self, size):
314        self.check_unmarshallable(set(range(size)))
315
316    @test_support.precisionbigmemtest(size=LARGE_SIZE,
317            memuse=pointer_size*12 + sys.getsizeof(LARGE_SIZE-1),
318            dry_run=False)
319    def test_frozenset(self, size):
320        self.check_unmarshallable(frozenset(range(size)))
321
322    @test_support.precisionbigmemtest(size=LARGE_SIZE, memuse=1, dry_run=False)
323    def test_bytearray(self, size):
324        self.check_unmarshallable(bytearray(size))
325
326
327@test_support.cpython_only
328@unittest.skipUnless(_testcapi, 'requires _testcapi')
329class CAPI_TestCase(unittest.TestCase):
330
331    def test_write_long_to_file(self):
332        for v in range(marshal.version + 1):
333            _testcapi.pymarshal_write_long_to_file(0x12345678, test_support.TESTFN, v)
334            with open(test_support.TESTFN, 'rb') as f:
335                data = f.read()
336            test_support.unlink(test_support.TESTFN)
337            self.assertEqual(data, b'\x78\x56\x34\x12')
338
339    def test_write_object_to_file(self):
340        obj = ('\u20ac', b'abc', 123, 45.6, 7+8j, 'long line '*1000)
341        for v in range(marshal.version + 1):
342            _testcapi.pymarshal_write_object_to_file(obj, test_support.TESTFN, v)
343            with open(test_support.TESTFN, 'rb') as f:
344                data = f.read()
345            test_support.unlink(test_support.TESTFN)
346            self.assertEqual(marshal.loads(data), obj)
347
348    def test_read_short_from_file(self):
349        with open(test_support.TESTFN, 'wb') as f:
350            f.write(b'\x34\x12xxxx')
351        r, p = _testcapi.pymarshal_read_short_from_file(test_support.TESTFN)
352        test_support.unlink(test_support.TESTFN)
353        self.assertEqual(r, 0x1234)
354        self.assertEqual(p, 2)
355
356    def test_read_long_from_file(self):
357        with open(test_support.TESTFN, 'wb') as f:
358            f.write(b'\x78\x56\x34\x12xxxx')
359        r, p = _testcapi.pymarshal_read_long_from_file(test_support.TESTFN)
360        test_support.unlink(test_support.TESTFN)
361        self.assertEqual(r, 0x12345678)
362        self.assertEqual(p, 4)
363
364    def test_read_last_object_from_file(self):
365        obj = ('\u20ac', b'abc', 123, 45.6, 7+8j)
366        for v in range(marshal.version + 1):
367            data = marshal.dumps(obj, v)
368            with open(test_support.TESTFN, 'wb') as f:
369                f.write(data + b'xxxx')
370            r, p = _testcapi.pymarshal_read_last_object_from_file(test_support.TESTFN)
371            test_support.unlink(test_support.TESTFN)
372            self.assertEqual(r, obj)
373
374    def test_read_object_from_file(self):
375        obj = ('\u20ac', b'abc', 123, 45.6, 7+8j)
376        for v in range(marshal.version + 1):
377            data = marshal.dumps(obj, v)
378            with open(test_support.TESTFN, 'wb') as f:
379                f.write(data + b'xxxx')
380            r, p = _testcapi.pymarshal_read_object_from_file(test_support.TESTFN)
381            test_support.unlink(test_support.TESTFN)
382            self.assertEqual(r, obj)
383            self.assertEqual(p, len(data))
384
385
386def test_main():
387    test_support.run_unittest(IntTestCase,
388                              FloatTestCase,
389                              StringTestCase,
390                              CodeTestCase,
391                              ContainerTestCase,
392                              ExceptionTestCase,
393                              BugsTestCase,
394                              LargeValuesTestCase,
395                              CAPI_TestCase,
396                             )
397
398if __name__ == "__main__":
399    test_main()
400