test_repr.py revision 2e2be3760ccdfd4bdde4afdd66f4078022ba3b61
166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman"""
266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  Test cases for the repr module
366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  Nick Mathewson
466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman"""
566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanimport sys
766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanimport os
866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanimport unittest
966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
1066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanfrom test_support import run_unittest
1166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanfrom repr import repr as r # Don't shadow builtin repr
1266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
1366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
1466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumandef nestedTuple(nesting):
1566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    t = ()
1666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    for i in range(nesting):
1766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        t = (t,)
1866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    return t
1966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
2066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanclass ReprTests(unittest.TestCase):
2166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
2266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    def test_string(self):
2366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        eq = self.assertEquals
2466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        eq(r("abc"), "'abc'")
2566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        eq(r("abcdefghijklmnop"),"'abcdefghijklmnop'")
2666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
2766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        s = "a"*30+"b"*30
2866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        expected = `s`[:13] + "..." + `s`[-14:]
2966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        eq(r(s), expected)
3066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
3166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        eq(r("\"'"), repr("\"'"))
3266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        s = "\""*30+"'"*100
3366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        expected = `s`[:13] + "..." + `s`[-14:]
3466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        eq(r(s), expected)
3566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
3666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    def test_container(self):
3766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        eq = self.assertEquals
3866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        # Tuples give up after 6 elements
3966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        eq(r(()), "()")
4066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        eq(r((1,)), "(1,)")
4166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        eq(r((1, 2, 3)), "(1, 2, 3)")
4266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        eq(r((1, 2, 3, 4, 5, 6)), "(1, 2, 3, 4, 5, 6)")
4366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        eq(r((1, 2, 3, 4, 5, 6, 7)), "(1, 2, 3, 4, 5, 6, ...)")
4466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
4566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        # Lists give up after 6 as well
4666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        eq(r([]), "[]")
4766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        eq(r([1]), "[1]")
4866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        eq(r([1, 2, 3]), "[1, 2, 3]")
4966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        eq(r([1, 2, 3, 4, 5, 6]), "[1, 2, 3, 4, 5, 6]")
50        eq(r([1, 2, 3, 4, 5, 6, 7]), "[1, 2, 3, 4, 5, 6, ...]")
51
52        # Dictionaries give up after 4.
53        eq(r({}), "{}")
54        d = {'alice': 1, 'bob': 2, 'charles': 3, 'dave': 4}
55        eq(r(d), "{'alice': 1, 'bob': 2, 'charles': 3, 'dave': 4}")
56        d['arthur'] = 1
57        eq(r(d), "{'alice': 1, 'arthur': 1, 'bob': 2, 'charles': 3, ...}")
58
59    def test_numbers(self):
60        eq = self.assertEquals
61        eq(r(123), repr(123))
62        eq(r(123L), repr(123L))
63        eq(r(1.0/3), repr(1.0/3))
64
65        n = 10L**100
66        expected = `n`[:18] + "..." + `n`[-19:]
67        eq(r(n), expected)
68
69    def test_instance(self):
70        eq = self.assertEquals
71        i1 = ClassWithRepr("a")
72        eq(r(i1), repr(i1))
73
74        i2 = ClassWithRepr("x"*1000)
75        expected = `i2`[:13] + "..." + `i2`[-14:]
76        eq(r(i2), expected)
77
78        i3 = ClassWithFailingRepr()
79        eq(r(i3), ("<ClassWithFailingRepr instance at %x>"%id(i3)))
80
81        s = r(ClassWithFailingRepr)
82        self.failUnless(s.startswith("<class "))
83        self.failUnless(s.endswith(">"))
84        self.failUnless(s.find("...") == 8)
85
86    def test_file(self):
87        fp = open(unittest.__file__)
88        self.failUnless(repr(fp).startswith(
89            "<open file '%s', mode 'r' at 0x" % unittest.__file__))
90        fp.close()
91        self.failUnless(repr(fp).startswith(
92            "<closed file '%s', mode 'r' at 0x" % unittest.__file__))
93
94    def test_lambda(self):
95        self.failUnless(repr(lambda x: x).startswith(
96            "<function <lambda"))
97        # XXX anonymous functions?  see func_repr
98
99    def test_builtin_function(self):
100        eq = self.assertEquals
101        # Functions
102        eq(repr(hash), '<built-in function hash>')
103        # Methods
104        self.failUnless(repr(''.split).startswith(
105            '<built-in method split of str object at 0x'))
106
107    def test_xrange(self):
108        eq = self.assertEquals
109        eq(repr(xrange(1)), 'xrange(1)')
110        eq(repr(xrange(1, 2)), 'xrange(1, 2)')
111        eq(repr(xrange(1, 2, 3)), 'xrange(1, 4, 3)')
112        # Turn off warnings for deprecated multiplication
113        import warnings
114        warnings.filterwarnings('ignore', category=DeprecationWarning,
115                                module=ReprTests.__module__)
116        eq(repr(xrange(1) * 3), '(xrange(1) * 3)')
117
118    def test_nesting(self):
119        eq = self.assertEquals
120        # everything is meant to give up after 6 levels.
121        eq(r([[[[[[[]]]]]]]), "[[[[[[[]]]]]]]")
122        eq(r([[[[[[[[]]]]]]]]), "[[[[[[[...]]]]]]]")
123
124        eq(r(nestedTuple(6)), "(((((((),),),),),),)")
125        eq(r(nestedTuple(7)), "(((((((...),),),),),),)")
126
127        eq(r({ nestedTuple(5) : nestedTuple(5) }),
128           "{((((((),),),),),): ((((((),),),),),)}")
129        eq(r({ nestedTuple(6) : nestedTuple(6) }),
130           "{((((((...),),),),),): ((((((...),),),),),)}")
131
132        eq(r([[[[[[{}]]]]]]), "[[[[[[{}]]]]]]")
133        eq(r([[[[[[[{}]]]]]]]), "[[[[[[[...]]]]]]]")
134
135    def test_buffer(self):
136        # XXX doesn't test buffers with no b_base or read-write buffers (see
137        # bufferobject.c).  The test is fairly incomplete too.  Sigh.
138        x = buffer('foo')
139        self.failUnless(repr(x).startswith('<read-only buffer for 0x'))
140
141    def test_cell(self):
142        # XXX Hmm? How to get at a cell object?
143        pass
144
145    def test_descriptors(self):
146        eq = self.assertEquals
147        # method descriptors
148        eq(repr(dictionary.items), "<method 'items' of 'dictionary' objects>")
149        # XXX member descriptors
150        # XXX attribute descriptors
151        # XXX slot descriptors
152        # static and class methods
153        class C:
154            def foo(cls): pass
155        x = staticmethod(C.foo)
156        self.failUnless(repr(x).startswith('<staticmethod object at 0x'))
157        x = classmethod(C.foo)
158        self.failUnless(repr(x).startswith('<classmethod object at 0x'))
159
160def touch(path, text=''):
161    fp = open(path, 'w')
162    fp.write(text)
163    fp.close()
164
165def zap(actions, dirname, names):
166    for name in names:
167        actions.append(os.path.join(dirname, name))
168
169class LongReprTest(unittest.TestCase):
170    def setUp(self):
171        longname = 'areallylongpackageandmodulenametotestreprtruncation'
172        self.pkgname = os.path.join(longname)
173        self.subpkgname = os.path.join(longname, longname)
174        # Make the package and subpackage
175        os.mkdir(self.pkgname)
176        touch(os.path.join(self.pkgname, '__init__.py'))
177        os.mkdir(self.subpkgname)
178        touch(os.path.join(self.subpkgname, '__init__.py'))
179        # Remember where we are
180        self.here = os.getcwd()
181        sys.path.insert(0, self.here)
182
183    def tearDown(self):
184        actions = []
185        os.path.walk(self.pkgname, zap, actions)
186        actions.append(self.pkgname)
187        actions.sort()
188        actions.reverse()
189        for p in actions:
190            if os.path.isdir(p):
191                os.rmdir(p)
192            else:
193                os.remove(p)
194        del sys.path[0]
195
196    def test_module(self):
197        eq = self.assertEquals
198        touch(os.path.join(self.subpkgname, self.pkgname + '.py'))
199        from areallylongpackageandmodulenametotestreprtruncation.areallylongpackageandmodulenametotestreprtruncation import areallylongpackageandmodulenametotestreprtruncation
200        eq(repr(areallylongpackageandmodulenametotestreprtruncation),
201           "<module 'areallylongpackageandmodulenametotestreprtruncation.areallylongpackageandmodulenametotestreprtruncation.areallylongpackageandmodulenametotestreprtruncation' from '%s'>" % areallylongpackageandmodulenametotestreprtruncation.__file__)
202
203    def test_type(self):
204        eq = self.assertEquals
205        touch(os.path.join(self.subpkgname, 'foo.py'), '''\
206class foo(object):
207    pass
208''')
209        from areallylongpackageandmodulenametotestreprtruncation.areallylongpackageandmodulenametotestreprtruncation import foo
210        eq(repr(foo.foo),
211               "<type 'areallylongpackageandmodulenametotestreprtruncation.areallylongpackageandmodulenametotestreprtruncation.foo.foo'>")
212
213    def test_object(self):
214        # XXX Test the repr of a type with a really long tp_name but with no
215        # tp_repr.  WIBNI we had ::Inline? :)
216        pass
217
218    def test_class(self):
219        touch(os.path.join(self.subpkgname, 'bar.py'), '''\
220class bar:
221    pass
222''')
223        from areallylongpackageandmodulenametotestreprtruncation.areallylongpackageandmodulenametotestreprtruncation import bar
224        self.failUnless(repr(bar.bar).startswith(
225            "<class areallylongpackageandmodulenametotestreprtruncation.areallylongpackageandmodulenametotestreprtruncation.bar.bar at 0x"))
226
227    def test_instance(self):
228        touch(os.path.join(self.subpkgname, 'baz.py'), '''\
229class baz:
230    pass
231''')
232        from areallylongpackageandmodulenametotestreprtruncation.areallylongpackageandmodulenametotestreprtruncation import baz
233        ibaz = baz.baz()
234        self.failUnless(repr(ibaz).startswith(
235            "<areallylongpackageandmodulenametotestreprtruncation.areallylongpackageandmodulenametotestreprtruncation.baz.baz instance at 0x"))
236
237    def test_method(self):
238        eq = self.assertEquals
239        touch(os.path.join(self.subpkgname, 'qux.py'), '''\
240class aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:
241    def amethod(self): pass
242''')
243        from areallylongpackageandmodulenametotestreprtruncation.areallylongpackageandmodulenametotestreprtruncation import qux
244        # Unbound methods first
245        eq(repr(qux.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.amethod),
246        '<unbound method aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.amethod>')
247        # Bound method next
248        iqux = qux.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa()
249        self.failUnless(repr(iqux.amethod).startswith(
250            '<bound method aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.amethod of <areallylongpackageandmodulenametotestreprtruncation.areallylongpackageandmodulenametotestreprtruncation.qux.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa instance at 0x'))
251
252    def test_builtin_function(self):
253        # XXX test built-in functions and methods with really long names
254        pass
255
256class ClassWithRepr:
257    def __init__(self, s):
258        self.s = s
259    def __repr__(self):
260        return "ClassWithLongRepr(%r)" % self.s
261
262
263class ClassWithFailingRepr:
264    def __repr__(self):
265        raise Exception("This should be caught by Repr.repr_instance")
266
267
268def test_main():
269    run_unittest(ReprTests)
270    if os.name != 'mac':
271        run_unittest(LongReprTest)
272
273
274if __name__ == "__main__":
275    test_main()
276