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        # XXX Hmm? How to get at a cell object?
183        pass
184
185    def test_descriptors(self):
186        eq = self.assertEqual
187        # method descriptors
188        eq(repr(dict.items), "<method 'items' of 'dict' objects>")
189        # XXX member descriptors
190        # XXX attribute descriptors
191        # XXX slot descriptors
192        # static and class methods
193        class C:
194            def foo(cls): pass
195        x = staticmethod(C.foo)
196        self.assertTrue(repr(x).startswith('<staticmethod object at 0x'))
197        x = classmethod(C.foo)
198        self.assertTrue(repr(x).startswith('<classmethod object at 0x'))
199
200    def test_unsortable(self):
201        # Repr.repr() used to call sorted() on sets, frozensets and dicts
202        # without taking into account that not all objects are comparable
203        x = set([1j, 2j, 3j])
204        y = frozenset(x)
205        z = {1j: 1, 2j: 2}
206        r(x)
207        r(y)
208        r(z)
209
210def touch(path, text=''):
211    fp = open(path, 'w')
212    fp.write(text)
213    fp.close()
214
215class LongReprTest(unittest.TestCase):
216    def setUp(self):
217        longname = 'areallylongpackageandmodulenametotestreprtruncation'
218        self.pkgname = os.path.join(longname)
219        self.subpkgname = os.path.join(longname, longname)
220        # Make the package and subpackage
221        shutil.rmtree(self.pkgname, ignore_errors=True)
222        os.mkdir(self.pkgname)
223        touch(os.path.join(self.pkgname, '__init__'+os.extsep+'py'))
224        shutil.rmtree(self.subpkgname, ignore_errors=True)
225        os.mkdir(self.subpkgname)
226        touch(os.path.join(self.subpkgname, '__init__'+os.extsep+'py'))
227        # Remember where we are
228        self.here = os.getcwd()
229        sys.path.insert(0, self.here)
230
231    def tearDown(self):
232        actions = []
233        for dirpath, dirnames, filenames in os.walk(self.pkgname):
234            for name in dirnames + filenames:
235                actions.append(os.path.join(dirpath, name))
236        actions.append(self.pkgname)
237        actions.sort()
238        actions.reverse()
239        for p in actions:
240            if os.path.isdir(p):
241                os.rmdir(p)
242            else:
243                os.remove(p)
244        del sys.path[0]
245
246    def test_module(self):
247        eq = self.assertEqual
248        touch(os.path.join(self.subpkgname, self.pkgname + os.extsep + 'py'))
249        from areallylongpackageandmodulenametotestreprtruncation.areallylongpackageandmodulenametotestreprtruncation import areallylongpackageandmodulenametotestreprtruncation
250        eq(repr(areallylongpackageandmodulenametotestreprtruncation),
251           "<module '%s' from '%s'>" % (areallylongpackageandmodulenametotestreprtruncation.__name__, areallylongpackageandmodulenametotestreprtruncation.__file__))
252        eq(repr(sys), "<module 'sys' (built-in)>")
253
254    def test_type(self):
255        eq = self.assertEqual
256        touch(os.path.join(self.subpkgname, 'foo'+os.extsep+'py'), '''\
257class foo(object):
258    pass
259''')
260        from areallylongpackageandmodulenametotestreprtruncation.areallylongpackageandmodulenametotestreprtruncation import foo
261        eq(repr(foo.foo),
262               "<class '%s.foo'>" % foo.__name__)
263
264    def test_object(self):
265        # XXX Test the repr of a type with a really long tp_name but with no
266        # tp_repr.  WIBNI we had ::Inline? :)
267        pass
268
269    def test_class(self):
270        touch(os.path.join(self.subpkgname, 'bar'+os.extsep+'py'), '''\
271class bar:
272    pass
273''')
274        from areallylongpackageandmodulenametotestreprtruncation.areallylongpackageandmodulenametotestreprtruncation import bar
275        # Module name may be prefixed with "test.", depending on how run.
276        self.assertTrue(repr(bar.bar).startswith(
277            "<class %s.bar at 0x" % bar.__name__))
278
279    def test_instance(self):
280        touch(os.path.join(self.subpkgname, 'baz'+os.extsep+'py'), '''\
281class baz:
282    pass
283''')
284        from areallylongpackageandmodulenametotestreprtruncation.areallylongpackageandmodulenametotestreprtruncation import baz
285        ibaz = baz.baz()
286        self.assertTrue(repr(ibaz).startswith(
287            "<%s.baz instance at 0x" % baz.__name__))
288
289    def test_method(self):
290        eq = self.assertEqual
291        touch(os.path.join(self.subpkgname, 'qux'+os.extsep+'py'), '''\
292class aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:
293    def amethod(self): pass
294''')
295        from areallylongpackageandmodulenametotestreprtruncation.areallylongpackageandmodulenametotestreprtruncation import qux
296        # Unbound methods first
297        eq(repr(qux.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.amethod),
298        '<unbound method aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.amethod>')
299        # Bound method next
300        iqux = qux.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa()
301        self.assertTrue(repr(iqux.amethod).startswith(
302            '<bound method aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.amethod of <%s.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa instance at 0x' \
303            % (qux.__name__,) ))
304
305    def test_builtin_function(self):
306        # XXX test built-in functions and methods with really long names
307        pass
308
309class ClassWithRepr:
310    def __init__(self, s):
311        self.s = s
312    def __repr__(self):
313        return "ClassWithLongRepr(%r)" % self.s
314
315
316class ClassWithFailingRepr:
317    def __repr__(self):
318        raise Exception("This should be caught by Repr.repr_instance")
319
320
321def test_main():
322    run_unittest(ReprTests)
323    run_unittest(LongReprTest)
324
325
326if __name__ == "__main__":
327    test_main()
328