1 """ 2 Test cases for the repr module 3 Nick Mathewson 4 """ 5 6 import sys 7 import os 8 import shutil 9 import unittest 10 11 from test.test_support import run_unittest, check_py3k_warnings 12 from repr import repr as r # Don't shadow builtin repr 13 from repr import Repr 14 15 16 def nestedTuple(nesting): 17 t = () 18 for i in range(nesting): 19 t = (t,) 20 return t 21 22 class 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 210 def touch(path, text=''): 211 fp = open(path, 'w') 212 fp.write(text) 213 fp.close() 214 215 class 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'), '''\ 257 class 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'), '''\ 271 class 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'), '''\ 281 class 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'), '''\ 292 class 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 309 class ClassWithRepr: 310 def __init__(self, s): 311 self.s = s 312 def __repr__(self): 313 return "ClassWithLongRepr(%r)" % self.s 314 315 316 class ClassWithFailingRepr: 317 def __repr__(self): 318 raise Exception("This should be caught by Repr.repr_instance") 319 320 321 def test_main(): 322 run_unittest(ReprTests) 323 run_unittest(LongReprTest) 324 325 326 if __name__ == "__main__": 327 test_main() 328