From 66be4a9f520bbe5736f9aaff6381ae2840d9fa55 Mon Sep 17 00:00:00 2001 From: Padraic Fanning Date: Sat, 17 Apr 2021 15:41:54 -0400 Subject: [PATCH 1/2] Add test_reprlib from CPython 3.8 --- Lib/test/test_reprlib.py | 405 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 405 insertions(+) create mode 100644 Lib/test/test_reprlib.py diff --git a/Lib/test/test_reprlib.py b/Lib/test/test_reprlib.py new file mode 100644 index 000000000..4bf91945e --- /dev/null +++ b/Lib/test/test_reprlib.py @@ -0,0 +1,405 @@ +""" + Test cases for the repr module + Nick Mathewson +""" + +import sys +import os +import shutil +import importlib +import importlib.util +import unittest + +from test.support import create_empty_file, verbose +from reprlib import repr as r # Don't shadow builtin repr +from reprlib import Repr +from reprlib import recursive_repr + + +def nestedTuple(nesting): + t = () + for i in range(nesting): + t = (t,) + return t + +class ReprTests(unittest.TestCase): + + def test_string(self): + eq = self.assertEqual + eq(r("abc"), "'abc'") + eq(r("abcdefghijklmnop"),"'abcdefghijklmnop'") + + s = "a"*30+"b"*30 + expected = repr(s)[:13] + "..." + repr(s)[-14:] + eq(r(s), expected) + + eq(r("\"'"), repr("\"'")) + s = "\""*30+"'"*100 + expected = repr(s)[:13] + "..." + repr(s)[-14:] + eq(r(s), expected) + + def test_tuple(self): + eq = self.assertEqual + eq(r((1,)), "(1,)") + + t3 = (1, 2, 3) + eq(r(t3), "(1, 2, 3)") + + r2 = Repr() + r2.maxtuple = 2 + expected = repr(t3)[:-2] + "...)" + eq(r2.repr(t3), expected) + + def test_container(self): + from array import array + from collections import deque + + eq = self.assertEqual + # Tuples give up after 6 elements + eq(r(()), "()") + eq(r((1,)), "(1,)") + eq(r((1, 2, 3)), "(1, 2, 3)") + eq(r((1, 2, 3, 4, 5, 6)), "(1, 2, 3, 4, 5, 6)") + eq(r((1, 2, 3, 4, 5, 6, 7)), "(1, 2, 3, 4, 5, 6, ...)") + + # Lists give up after 6 as well + eq(r([]), "[]") + eq(r([1]), "[1]") + eq(r([1, 2, 3]), "[1, 2, 3]") + eq(r([1, 2, 3, 4, 5, 6]), "[1, 2, 3, 4, 5, 6]") + eq(r([1, 2, 3, 4, 5, 6, 7]), "[1, 2, 3, 4, 5, 6, ...]") + + # Sets give up after 6 as well + eq(r(set([])), "set()") + eq(r(set([1])), "{1}") + eq(r(set([1, 2, 3])), "{1, 2, 3}") + eq(r(set([1, 2, 3, 4, 5, 6])), "{1, 2, 3, 4, 5, 6}") + eq(r(set([1, 2, 3, 4, 5, 6, 7])), "{1, 2, 3, 4, 5, 6, ...}") + + # Frozensets give up after 6 as well + eq(r(frozenset([])), "frozenset()") + eq(r(frozenset([1])), "frozenset({1})") + eq(r(frozenset([1, 2, 3])), "frozenset({1, 2, 3})") + eq(r(frozenset([1, 2, 3, 4, 5, 6])), "frozenset({1, 2, 3, 4, 5, 6})") + eq(r(frozenset([1, 2, 3, 4, 5, 6, 7])), "frozenset({1, 2, 3, 4, 5, 6, ...})") + + # collections.deque after 6 + eq(r(deque([1, 2, 3, 4, 5, 6, 7])), "deque([1, 2, 3, 4, 5, 6, ...])") + + # Dictionaries give up after 4. + eq(r({}), "{}") + d = {'alice': 1, 'bob': 2, 'charles': 3, 'dave': 4} + eq(r(d), "{'alice': 1, 'bob': 2, 'charles': 3, 'dave': 4}") + d['arthur'] = 1 + eq(r(d), "{'alice': 1, 'arthur': 1, 'bob': 2, 'charles': 3, ...}") + + # array.array after 5. + eq(r(array('i')), "array('i')") + eq(r(array('i', [1])), "array('i', [1])") + eq(r(array('i', [1, 2])), "array('i', [1, 2])") + eq(r(array('i', [1, 2, 3])), "array('i', [1, 2, 3])") + eq(r(array('i', [1, 2, 3, 4])), "array('i', [1, 2, 3, 4])") + eq(r(array('i', [1, 2, 3, 4, 5])), "array('i', [1, 2, 3, 4, 5])") + eq(r(array('i', [1, 2, 3, 4, 5, 6])), + "array('i', [1, 2, 3, 4, 5, ...])") + + def test_set_literal(self): + eq = self.assertEqual + eq(r({1}), "{1}") + eq(r({1, 2, 3}), "{1, 2, 3}") + eq(r({1, 2, 3, 4, 5, 6}), "{1, 2, 3, 4, 5, 6}") + eq(r({1, 2, 3, 4, 5, 6, 7}), "{1, 2, 3, 4, 5, 6, ...}") + + def test_frozenset(self): + eq = self.assertEqual + eq(r(frozenset({1})), "frozenset({1})") + eq(r(frozenset({1, 2, 3})), "frozenset({1, 2, 3})") + eq(r(frozenset({1, 2, 3, 4, 5, 6})), "frozenset({1, 2, 3, 4, 5, 6})") + eq(r(frozenset({1, 2, 3, 4, 5, 6, 7})), "frozenset({1, 2, 3, 4, 5, 6, ...})") + + def test_numbers(self): + eq = self.assertEqual + eq(r(123), repr(123)) + eq(r(123), repr(123)) + eq(r(1.0/3), repr(1.0/3)) + + n = 10**100 + expected = repr(n)[:18] + "..." + repr(n)[-19:] + eq(r(n), expected) + + def test_instance(self): + eq = self.assertEqual + i1 = ClassWithRepr("a") + eq(r(i1), repr(i1)) + + i2 = ClassWithRepr("x"*1000) + expected = repr(i2)[:13] + "..." + repr(i2)[-14:] + eq(r(i2), expected) + + i3 = ClassWithFailingRepr() + eq(r(i3), (""%id(i3))) + + s = r(ClassWithFailingRepr) + self.assertTrue(s.startswith("")) + self.assertIn(s.find("..."), [12, 13]) + + def test_lambda(self): + r = repr(lambda x: x) + self.assertTrue(r.startswith(".') + # Methods + self.assertTrue(repr(''.split).startswith( + '') + self.assertRegex(r(x), r'') + + def test_descriptors(self): + eq = self.assertEqual + # method descriptors + eq(repr(dict.items), "") + # XXX member descriptors + # XXX attribute descriptors + # XXX slot descriptors + # static and class methods + class C: + def foo(cls): pass + x = staticmethod(C.foo) + self.assertTrue(repr(x).startswith('= 258: + # Under Windows, the max path len is 260 including C's terminating + # NUL character. + # (see http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx#maxpath) + self.skipTest("test paths too long (%d characters) for Windows' 260 character limit" + % cached_path_len) + elif os.name == 'nt' and verbose: + print("cached_path_len =", cached_path_len) + + def test_module(self): + self.maxDiff = None + self._check_path_limitations(self.pkgname) + create_empty_file(os.path.join(self.subpkgname, self.pkgname + '.py')) + importlib.invalidate_caches() + from areallylongpackageandmodulenametotestreprtruncation.areallylongpackageandmodulenametotestreprtruncation import areallylongpackageandmodulenametotestreprtruncation + module = areallylongpackageandmodulenametotestreprtruncation + self.assertEqual(repr(module), "" % (module.__name__, module.__file__)) + self.assertEqual(repr(sys), "") + + def test_type(self): + self._check_path_limitations('foo') + eq = self.assertEqual + write_file(os.path.join(self.subpkgname, 'foo.py'), '''\ +class foo(object): + pass +''') + importlib.invalidate_caches() + from areallylongpackageandmodulenametotestreprtruncation.areallylongpackageandmodulenametotestreprtruncation import foo + eq(repr(foo.foo), + "" % foo.__name__) + + @unittest.skip('need a suitable object') + def test_object(self): + # XXX Test the repr of a type with a really long tp_name but with no + # tp_repr. WIBNI we had ::Inline? :) + pass + + def test_class(self): + self._check_path_limitations('bar') + write_file(os.path.join(self.subpkgname, 'bar.py'), '''\ +class bar: + pass +''') + importlib.invalidate_caches() + from areallylongpackageandmodulenametotestreprtruncation.areallylongpackageandmodulenametotestreprtruncation import bar + # Module name may be prefixed with "test.", depending on how run. + self.assertEqual(repr(bar.bar), "" % bar.__name__) + + def test_instance(self): + self._check_path_limitations('baz') + write_file(os.path.join(self.subpkgname, 'baz.py'), '''\ +class baz: + pass +''') + importlib.invalidate_caches() + from areallylongpackageandmodulenametotestreprtruncation.areallylongpackageandmodulenametotestreprtruncation import baz + ibaz = baz.baz() + self.assertTrue(repr(ibaz).startswith( + "<%s.baz object at 0x" % baz.__name__)) + + def test_method(self): + self._check_path_limitations('qux') + eq = self.assertEqual + write_file(os.path.join(self.subpkgname, 'qux.py'), '''\ +class aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: + def amethod(self): pass +''') + importlib.invalidate_caches() + from areallylongpackageandmodulenametotestreprtruncation.areallylongpackageandmodulenametotestreprtruncation import qux + # Unbound methods first + r = repr(qux.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.amethod) + self.assertTrue(r.startswith('' + +class MyContainer2(MyContainer): + @recursive_repr('+++') + def __repr__(self): + return '<' + ', '.join(map(str, self.values)) + '>' + +class MyContainer3: + def __repr__(self): + 'Test document content' + pass + wrapped = __repr__ + wrapper = recursive_repr()(wrapped) + +class TestRecursiveRepr(unittest.TestCase): + def test_recursive_repr(self): + m = MyContainer(list('abcde')) + m.append(m) + m.append('x') + m.append(m) + self.assertEqual(repr(m), '') + m = MyContainer2(list('abcde')) + m.append(m) + m.append('x') + m.append(m) + self.assertEqual(repr(m), '') + + def test_assigned_attributes(self): + from functools import WRAPPER_ASSIGNMENTS as assigned + wrapped = MyContainer3.wrapped + wrapper = MyContainer3.wrapper + for name in assigned: + self.assertIs(getattr(wrapper, name), getattr(wrapped, name)) + +if __name__ == "__main__": + unittest.main() From bb8b9cff18327040e71d970c10f6b5156b1f0126 Mon Sep 17 00:00:00 2001 From: Padraic Fanning Date: Sat, 17 Apr 2021 15:43:59 -0400 Subject: [PATCH 2/2] Mark erroring/failing tests --- Lib/test/test_reprlib.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Lib/test/test_reprlib.py b/Lib/test/test_reprlib.py index 4bf91945e..b698aadb0 100644 --- a/Lib/test/test_reprlib.py +++ b/Lib/test/test_reprlib.py @@ -144,11 +144,15 @@ class ReprTests(unittest.TestCase): self.assertTrue(s.endswith(">")) self.assertIn(s.find("..."), [12, 13]) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_lambda(self): r = repr(lambda x: x) self.assertTrue(r.startswith(".') self.assertRegex(r(x), r'') + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_descriptors(self): eq = self.assertEqual # method descriptors @@ -312,6 +320,8 @@ class bar: # Module name may be prefixed with "test.", depending on how run. self.assertEqual(repr(bar.bar), "" % bar.__name__) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_instance(self): self._check_path_limitations('baz') write_file(os.path.join(self.subpkgname, 'baz.py'), '''\ @@ -324,6 +334,8 @@ class baz: self.assertTrue(repr(ibaz).startswith( "<%s.baz object at 0x" % baz.__name__)) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_method(self): self._check_path_limitations('qux') eq = self.assertEqual