• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""
2  Test cases for the repr module
3  Nick Mathewson
4"""
5
6import sys
7import os
8import shutil
9import unittest
10
11from test.test_support import run_unittest, check_py3k_warnings
12from repr import repr as r # Don't shadow builtin repr
13from repr import Repr
14
15
16def nestedTuple(nesting):
17    t = ()
18    for i in range(nesting):
19        t = (t,)
20    return t
21
22class ReprTests(unittest.TestCase):
23
24    def test_string(self):
25        eq = self.assertEqual
26        eq(r("abc"), "'abc'")
27        eq(r("abcdefghijklmnop"),"'abcdefghijklmnop'")
28
29        s = "a"*30+"b"*30
30        expected = repr(s)[:13] + "..." + repr(s)[-14:]
31        eq(r(s), expected)
32
33        eq(r("\"'"), repr("\"'"))
34        s = "\""*30+"'"*100
35        expected = repr(s)[:13] + "..." + repr(s)[-14:]
36        eq(r(s), expected)
37
38    def test_tuple(self):
39        eq = self.assertEqual
40        eq(r((1,)), "(1,)")
41
42        t3 = (1, 2, 3)
43        eq(r(t3), "(1, 2, 3)")
44
45        r2 = Repr()
46        r2.maxtuple = 2
47        expected = repr(t3)[:-2] + "...)"
48        eq(r2.repr(t3), expected)
49
50    def test_container(self):
51        from array import array
52        from collections import deque
53
54        eq = self.assertEqual
55        # Tuples give up after 6 elements
56        eq(r(()), "()")
57        eq(r((1,)), "(1,)")
58        eq(r((1, 2, 3)), "(1, 2, 3)")
59        eq(r((1, 2, 3, 4, 5, 6)), "(1, 2, 3, 4, 5, 6)")
60        eq(r((1, 2, 3, 4, 5, 6, 7)), "(1, 2, 3, 4, 5, 6, ...)")
61
62        # Lists give up after 6 as well
63        eq(r([]), "[]")
64        eq(r([1]), "[1]")
65        eq(r([1, 2, 3]), "[1, 2, 3]")
66        eq(r([1, 2, 3, 4, 5, 6]), "[1, 2, 3, 4, 5, 6]")
67        eq(r([1, 2, 3, 4, 5, 6, 7]), "[1, 2, 3, 4, 5, 6, ...]")
68
69        # Sets give up after 6 as well
70        eq(r(set([])), "set([])")
71        eq(r(set([1])), "set([1])")
72        eq(r(set([1, 2, 3])), "set([1, 2, 3])")
73        eq(r(set([1, 2, 3, 4, 5, 6])), "set([1, 2, 3, 4, 5, 6])")
74        eq(r(set([1, 2, 3, 4, 5, 6, 7])), "set([1, 2, 3, 4, 5, 6, ...])")
75
76        # Frozensets give up after 6 as well
77        eq(r(frozenset([])), "frozenset([])")
78        eq(r(frozenset([1])), "frozenset([1])")
79        eq(r(frozenset([1, 2, 3])), "frozenset([1, 2, 3])")
80        eq(r(frozenset([1, 2, 3, 4, 5, 6])), "frozenset([1, 2, 3, 4, 5, 6])")
81        eq(r(frozenset([1, 2, 3, 4, 5, 6, 7])), "frozenset([1, 2, 3, 4, 5, 6, ...])")
82
83        # collections.deque after 6
84        eq(r(deque([1, 2, 3, 4, 5, 6, 7])), "deque([1, 2, 3, 4, 5, 6, ...])")
85
86        # Dictionaries give up after 4.
87        eq(r({}), "{}")
88        d = {'alice': 1, 'bob': 2, 'charles': 3, 'dave': 4}
89        eq(r(d), "{'alice': 1, 'bob': 2, 'charles': 3, 'dave': 4}")
90        d['arthur'] = 1
91        eq(r(d), "{'alice': 1, 'arthur': 1, 'bob': 2, 'charles': 3, ...}")
92
93        # array.array after 5.
94        eq(r(array('i')), "array('i', [])")
95        eq(r(array('i', [1])), "array('i', [1])")
96        eq(r(array('i', [1, 2])), "array('i', [1, 2])")
97        eq(r(array('i', [1, 2, 3])), "array('i', [1, 2, 3])")
98        eq(r(array('i', [1, 2, 3, 4])), "array('i', [1, 2, 3, 4])")
99        eq(r(array('i', [1, 2, 3, 4, 5])), "array('i', [1, 2, 3, 4, 5])")
100        eq(r(array('i', [1, 2, 3, 4, 5, 6])),
101                   "array('i', [1, 2, 3, 4, 5, ...])")
102
103    def test_numbers(self):
104        eq = self.assertEqual
105        eq(r(123), repr(123))
106        eq(r(123L), repr(123L))
107        eq(r(1.0/3), repr(1.0/3))
108
109        n = 10L**100
110        expected = repr(n)[:18] + "..." + repr(n)[-19:]
111        eq(r(n), expected)
112
113    def test_instance(self):
114        eq = self.assertEqual
115        i1 = ClassWithRepr("a")
116        eq(r(i1), repr(i1))
117
118        i2 = ClassWithRepr("x"*1000)
119        expected = repr(i2)[:13] + "..." + repr(i2)[-14:]
120        eq(r(i2), expected)
121
122        i3 = ClassWithFailingRepr()
123        eq(r(i3), ("<ClassWithFailingRepr instance at %x>"%id(i3)))
124
125        s = r(ClassWithFailingRepr)
126        self.assertTrue(s.startswith("<class "))
127        self.assertTrue(s.endswith(">"))
128        self.assertTrue(s.find("...") == 8)
129
130    def test_file(self):
131        fp = open(unittest.__file__)
132        self.assertTrue(repr(fp).startswith(
133            "<open file %r, mode 'r' at 0x" % unittest.__file__))
134        fp.close()
135        self.assertTrue(repr(fp).startswith(
136            "<closed file %r, mode 'r' at 0x" % unittest.__file__))
137
138    def test_lambda(self):
139        self.assertTrue(repr(lambda x: x).startswith(
140            "<function <lambda"))
141        # XXX anonymous functions?  see func_repr
142
143    def test_builtin_function(self):
144        eq = self.assertEqual
145        # Functions
146        eq(repr(hash), '<built-in function hash>')
147        # Methods
148        self.assertTrue(repr(''.split).startswith(
149            '<built-in method split of str object at 0x'))
150
151    def test_xrange(self):
152        eq = self.assertEqual
153        eq(repr(xrange(1)), 'xrange(1)')
154        eq(repr(xrange(1, 2)), 'xrange(1, 2)')
155        eq(repr(xrange(1, 2, 3)), 'xrange(1, 4, 3)')
156
157    def test_nesting(self):
158        eq = self.assertEqual
159        # everything is meant to give up after 6 levels.
160        eq(r([[[[[[[]]]]]]]), "[[[[[[[]]]]]]]")
161        eq(r([[[[[[[[]]]]]]]]), "[[[[[[[...]]]]]]]")
162
163        eq(r(nestedTuple(6)), "(((((((),),),),),),)")
164        eq(r(nestedTuple(7)), "(((((((...),),),),),),)")
165
166        eq(r({ nestedTuple(5) : nestedTuple(5) }),
167           "{((((((),),),),),): ((((((),),),),),)}")
168        eq(r({ nestedTuple(6) : nestedTuple(6) }),
169           "{((((((...),),),),),): ((((((...),),),),),)}")
170
171        eq(r([[[[[[{}]]]]]]), "[[[[[[{}]]]]]]")
172        eq(r([[[[[[[{}]]]]]]]), "[[[[[[[...]]]]]]]")
173
174    def test_buffer(self):
175        # XXX doesn't test buffers with no b_base or read-write buffers (see
176        # bufferobject.c).  The test is fairly incomplete too.  Sigh.
177        with check_py3k_warnings():
178            x = buffer('foo')
179        self.assertTrue(repr(x).startswith('<read-only buffer for 0x'))
180
181    def test_cell(self):
182        def get_cell():
183            x = 42
184            def inner():
185                return x
186            return inner
187        x = get_cell().__closure__[0]
188        self.assertRegexpMatches(repr(x), r'<cell at 0x[0-9A-Fa-f]+: '
189                                          r'int object at 0x[0-9A-Fa-f]+>')
190        self.assertRegexpMatches(r(x), r'<cell at.*\.\.\..*>')
191
192    def test_descriptors(self):
193        eq = self.assertEqual
194        # method descriptors
195        eq(repr(dict.items), "<method 'items' of 'dict' objects>")
196        # XXX member descriptors
197        # XXX attribute descriptors
198        # XXX slot descriptors
199        # static and class methods
200        class C:
201            def foo(cls): pass
202        x = staticmethod(C.foo)
203        self.assertTrue(repr(x).startswith('<staticmethod object at 0x'))
204        x = classmethod(C.foo)
205        self.assertTrue(repr(x).startswith('<classmethod object at 0x'))
206
207    def test_unsortable(self):
208        # Repr.repr() used to call sorted() on sets, frozensets and dicts
209        # without taking into account that not all objects are comparable
210        x = set([1j, 2j, 3j])
211        y = frozenset(x)
212        z = {1j: 1, 2j: 2}
213        r(x)
214        r(y)
215        r(z)
216
217def touch(path, text=''):
218    fp = open(path, 'w')
219    fp.write(text)
220    fp.close()
221
222class LongReprTest(unittest.TestCase):
223    def setUp(self):
224        longname = 'areallylongpackageandmodulenametotestreprtruncation'
225        self.pkgname = os.path.join(longname)
226        self.subpkgname = os.path.join(longname, longname)
227        # Make the package and subpackage
228        shutil.rmtree(self.pkgname, ignore_errors=True)
229        os.mkdir(self.pkgname)
230        touch(os.path.join(self.pkgname, '__init__'+os.extsep+'py'))
231        shutil.rmtree(self.subpkgname, ignore_errors=True)
232        os.mkdir(self.subpkgname)
233        touch(os.path.join(self.subpkgname, '__init__'+os.extsep+'py'))
234        # Remember where we are
235        self.here = os.getcwd()
236        sys.path.insert(0, self.here)
237
238    def tearDown(self):
239        actions = []
240        for dirpath, dirnames, filenames in os.walk(self.pkgname):
241            for name in dirnames + filenames:
242                actions.append(os.path.join(dirpath, name))
243        actions.append(self.pkgname)
244        actions.sort()
245        actions.reverse()
246        for p in actions:
247            if os.path.isdir(p):
248                os.rmdir(p)
249            else:
250                os.remove(p)
251        del sys.path[0]
252
253    def test_module(self):
254        eq = self.assertEqual
255        touch(os.path.join(self.subpkgname, self.pkgname + os.extsep + 'py'))
256        from areallylongpackageandmodulenametotestreprtruncation.areallylongpackageandmodulenametotestreprtruncation import areallylongpackageandmodulenametotestreprtruncation
257        eq(repr(areallylongpackageandmodulenametotestreprtruncation),
258           "<module '%s' from '%s'>" % (areallylongpackageandmodulenametotestreprtruncation.__name__, areallylongpackageandmodulenametotestreprtruncation.__file__))
259        eq(repr(sys), "<module 'sys' (built-in)>")
260
261    def test_type(self):
262        eq = self.assertEqual
263        touch(os.path.join(self.subpkgname, 'foo'+os.extsep+'py'), '''\
264class foo(object):
265    pass
266''')
267        from areallylongpackageandmodulenametotestreprtruncation.areallylongpackageandmodulenametotestreprtruncation import foo
268        eq(repr(foo.foo),
269               "<class '%s.foo'>" % foo.__name__)
270
271    @unittest.skip('need a suitable object')
272    def test_object(self):
273        # XXX Test the repr of a type with a really long tp_name but with no
274        # tp_repr.  WIBNI we had ::Inline? :)
275        pass
276
277    def test_class(self):
278        touch(os.path.join(self.subpkgname, 'bar'+os.extsep+'py'), '''\
279class bar:
280    pass
281''')
282        from areallylongpackageandmodulenametotestreprtruncation.areallylongpackageandmodulenametotestreprtruncation import bar
283        # Module name may be prefixed with "test.", depending on how run.
284        self.assertTrue(repr(bar.bar).startswith(
285            "<class %s.bar at 0x" % bar.__name__))
286
287    def test_instance(self):
288        touch(os.path.join(self.subpkgname, 'baz'+os.extsep+'py'), '''\
289class baz:
290    pass
291''')
292        from areallylongpackageandmodulenametotestreprtruncation.areallylongpackageandmodulenametotestreprtruncation import baz
293        ibaz = baz.baz()
294        self.assertTrue(repr(ibaz).startswith(
295            "<%s.baz instance at 0x" % baz.__name__))
296
297    def test_method(self):
298        eq = self.assertEqual
299        touch(os.path.join(self.subpkgname, 'qux'+os.extsep+'py'), '''\
300class aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:
301    def amethod(self): pass
302''')
303        from areallylongpackageandmodulenametotestreprtruncation.areallylongpackageandmodulenametotestreprtruncation import qux
304        # Unbound methods first
305        eq(repr(qux.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.amethod),
306        '<unbound method aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.amethod>')
307        # Bound method next
308        iqux = qux.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa()
309        self.assertTrue(repr(iqux.amethod).startswith(
310            '<bound method aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.amethod of <%s.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa instance at 0x' \
311            % (qux.__name__,) ))
312
313    @unittest.skip('needs a built-in function with a really long name')
314    def test_builtin_function(self):
315        # XXX test built-in functions and methods with really long names
316        pass
317
318class ClassWithRepr:
319    def __init__(self, s):
320        self.s = s
321    def __repr__(self):
322        return "ClassWithLongRepr(%r)" % self.s
323
324
325class ClassWithFailingRepr:
326    def __repr__(self):
327        raise Exception("This should be caught by Repr.repr_instance")
328
329
330def test_main():
331    run_unittest(ReprTests)
332    run_unittest(LongReprTest)
333
334
335if __name__ == "__main__":
336    test_main()
337