[3.12] gh-104231: Add more tests for str(), repr(), ascii(), and bytes() (GH-112551) (GH-112555)

(cherry picked from commit 2223899adc)
This commit is contained in:
Serhiy Storchaka 2023-12-01 10:16:47 +02:00 committed by GitHub
parent 88d9142639
commit ae1ea41cf3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 121 additions and 50 deletions

View file

@ -46,6 +46,10 @@ class Indexable:
class BaseBytesTest: class BaseBytesTest:
def assertTypedEqual(self, actual, expected):
self.assertIs(type(actual), type(expected))
self.assertEqual(actual, expected)
def test_basics(self): def test_basics(self):
b = self.type2test() b = self.type2test()
self.assertEqual(type(b), self.type2test) self.assertEqual(type(b), self.type2test)
@ -1023,36 +1027,63 @@ class BytesTest(BaseBytesTest, unittest.TestCase):
self.assertRaises(TypeError, f.readinto, b"") self.assertRaises(TypeError, f.readinto, b"")
def test_custom(self): def test_custom(self):
class A: self.assertEqual(bytes(BytesSubclass(b'abc')), b'abc')
def __bytes__(self): self.assertEqual(BytesSubclass(OtherBytesSubclass(b'abc')),
return b'abc' BytesSubclass(b'abc'))
self.assertEqual(bytes(A()), b'abc') self.assertEqual(bytes(WithBytes(b'abc')), b'abc')
class A: pass self.assertEqual(BytesSubclass(WithBytes(b'abc')), BytesSubclass(b'abc'))
self.assertRaises(TypeError, bytes, A())
class A: class NoBytes: pass
def __bytes__(self): self.assertRaises(TypeError, bytes, NoBytes())
return None self.assertRaises(TypeError, bytes, WithBytes('abc'))
self.assertRaises(TypeError, bytes, A()) self.assertRaises(TypeError, bytes, WithBytes(None))
class A: class IndexWithBytes:
def __bytes__(self): def __bytes__(self):
return b'a' return b'a'
def __index__(self): def __index__(self):
return 42 return 42
self.assertEqual(bytes(A()), b'a') self.assertEqual(bytes(IndexWithBytes()), b'a')
# Issue #25766 # Issue #25766
class A(str): class StrWithBytes(str):
def __new__(cls, value):
self = str.__new__(cls, '\u20ac')
self.value = value
return self
def __bytes__(self): def __bytes__(self):
return b'abc' return self.value
self.assertEqual(bytes(A('\u20ac')), b'abc') self.assertEqual(bytes(StrWithBytes(b'abc')), b'abc')
self.assertEqual(bytes(A('\u20ac'), 'iso8859-15'), b'\xa4') self.assertEqual(bytes(StrWithBytes(b'abc'), 'iso8859-15'), b'\xa4')
self.assertEqual(bytes(StrWithBytes(BytesSubclass(b'abc'))), b'abc')
self.assertEqual(BytesSubclass(StrWithBytes(b'abc')), BytesSubclass(b'abc'))
self.assertEqual(BytesSubclass(StrWithBytes(b'abc'), 'iso8859-15'),
BytesSubclass(b'\xa4'))
self.assertEqual(BytesSubclass(StrWithBytes(BytesSubclass(b'abc'))),
BytesSubclass(b'abc'))
self.assertEqual(BytesSubclass(StrWithBytes(OtherBytesSubclass(b'abc'))),
BytesSubclass(b'abc'))
# Issue #24731 # Issue #24731
class A: self.assertTypedEqual(bytes(WithBytes(BytesSubclass(b'abc'))), BytesSubclass(b'abc'))
self.assertTypedEqual(BytesSubclass(WithBytes(BytesSubclass(b'abc'))),
BytesSubclass(b'abc'))
self.assertTypedEqual(BytesSubclass(WithBytes(OtherBytesSubclass(b'abc'))),
BytesSubclass(b'abc'))
class BytesWithBytes(bytes):
def __new__(cls, value):
self = bytes.__new__(cls, b'\xa4')
self.value = value
return self
def __bytes__(self): def __bytes__(self):
return OtherBytesSubclass(b'abc') return self.value
self.assertEqual(bytes(A()), b'abc') self.assertTypedEqual(bytes(BytesWithBytes(b'abc')), b'abc')
self.assertIs(type(bytes(A())), OtherBytesSubclass) self.assertTypedEqual(BytesSubclass(BytesWithBytes(b'abc')),
self.assertEqual(BytesSubclass(A()), b'abc') BytesSubclass(b'abc'))
self.assertIs(type(BytesSubclass(A())), BytesSubclass) self.assertTypedEqual(bytes(BytesWithBytes(BytesSubclass(b'abc'))),
BytesSubclass(b'abc'))
self.assertTypedEqual(BytesSubclass(BytesWithBytes(BytesSubclass(b'abc'))),
BytesSubclass(b'abc'))
self.assertTypedEqual(BytesSubclass(BytesWithBytes(OtherBytesSubclass(b'abc'))),
BytesSubclass(b'abc'))
# Test PyBytes_FromFormat() # Test PyBytes_FromFormat()
def test_from_format(self): def test_from_format(self):
@ -2069,6 +2100,12 @@ class BytesSubclass(bytes):
class OtherBytesSubclass(bytes): class OtherBytesSubclass(bytes):
pass pass
class WithBytes:
def __init__(self, value):
self.value = value
def __bytes__(self):
return self.value
class ByteArraySubclassTest(SubclassTest, unittest.TestCase): class ByteArraySubclassTest(SubclassTest, unittest.TestCase):
basetype = bytearray basetype = bytearray
type2test = ByteArraySubclass type2test = ByteArraySubclass

View file

@ -55,6 +55,21 @@ def duplicate_string(text):
class StrSubclass(str): class StrSubclass(str):
pass pass
class OtherStrSubclass(str):
pass
class WithStr:
def __init__(self, value):
self.value = value
def __str__(self):
return self.value
class WithRepr:
def __init__(self, value):
self.value = value
def __repr__(self):
return self.value
class UnicodeTest(string_tests.CommonTest, class UnicodeTest(string_tests.CommonTest,
string_tests.MixinStrUnicodeUserStringTest, string_tests.MixinStrUnicodeUserStringTest,
string_tests.MixinStrUnicodeTest, string_tests.MixinStrUnicodeTest,
@ -84,6 +99,10 @@ class UnicodeTest(string_tests.CommonTest,
self.assertEqual(realresult, result) self.assertEqual(realresult, result)
self.assertTrue(object is not realresult) self.assertTrue(object is not realresult)
def assertTypedEqual(self, actual, expected):
self.assertIs(type(actual), type(expected))
self.assertEqual(actual, expected)
def test_literals(self): def test_literals(self):
self.assertEqual('\xff', '\u00ff') self.assertEqual('\xff', '\u00ff')
self.assertEqual('\uffff', '\U0000ffff') self.assertEqual('\uffff', '\U0000ffff')
@ -128,10 +147,13 @@ class UnicodeTest(string_tests.CommonTest,
self.assertEqual(ascii("\U00010000" * 39 + "\uffff" * 4096), self.assertEqual(ascii("\U00010000" * 39 + "\uffff" * 4096),
ascii("\U00010000" * 39 + "\uffff" * 4096)) ascii("\U00010000" * 39 + "\uffff" * 4096))
class WrongRepr: self.assertTypedEqual(ascii('\U0001f40d'), r"'\U0001f40d'")
def __repr__(self): self.assertTypedEqual(ascii(StrSubclass('abc')), "'abc'")
return b'byte-repr' self.assertTypedEqual(ascii(WithRepr('<abc>')), '<abc>')
self.assertRaises(TypeError, ascii, WrongRepr()) self.assertTypedEqual(ascii(WithRepr(StrSubclass('<abc>'))), StrSubclass('<abc>'))
self.assertTypedEqual(ascii(WithRepr('<\U0001f40d>')), r'<\U0001f40d>')
self.assertTypedEqual(ascii(WithRepr(StrSubclass('<\U0001f40d>'))), r'<\U0001f40d>')
self.assertRaises(TypeError, ascii, WithRepr(b'byte-repr'))
def test_repr(self): def test_repr(self):
# Test basic sanity of repr() # Test basic sanity of repr()
@ -169,10 +191,13 @@ class UnicodeTest(string_tests.CommonTest,
self.assertEqual(repr("\U00010000" * 39 + "\uffff" * 4096), self.assertEqual(repr("\U00010000" * 39 + "\uffff" * 4096),
repr("\U00010000" * 39 + "\uffff" * 4096)) repr("\U00010000" * 39 + "\uffff" * 4096))
class WrongRepr: self.assertTypedEqual(repr('\U0001f40d'), "'\U0001f40d'")
def __repr__(self): self.assertTypedEqual(repr(StrSubclass('abc')), "'abc'")
return b'byte-repr' self.assertTypedEqual(repr(WithRepr('<abc>')), '<abc>')
self.assertRaises(TypeError, repr, WrongRepr()) self.assertTypedEqual(repr(WithRepr(StrSubclass('<abc>'))), StrSubclass('<abc>'))
self.assertTypedEqual(repr(WithRepr('<\U0001f40d>')), '<\U0001f40d>')
self.assertTypedEqual(repr(WithRepr(StrSubclass('<\U0001f40d>'))), StrSubclass('<\U0001f40d>'))
self.assertRaises(TypeError, repr, WithRepr(b'byte-repr'))
def test_iterators(self): def test_iterators(self):
# Make sure unicode objects have an __iter__ method # Make sure unicode objects have an __iter__ method
@ -2378,28 +2403,37 @@ class UnicodeTest(string_tests.CommonTest,
def test_conversion(self): def test_conversion(self):
# Make sure __str__() works properly # Make sure __str__() works properly
class ObjectToStr: class StrWithStr(str):
def __str__(self): def __new__(cls, value):
return "foo" self = str.__new__(cls, "")
self.value = value
class StrSubclassToStr(str):
def __str__(self):
return "foo"
class StrSubclassToStrSubclass(str):
def __new__(cls, content=""):
return str.__new__(cls, 2*content)
def __str__(self):
return self return self
def __str__(self):
return self.value
self.assertEqual(str(ObjectToStr()), "foo") self.assertTypedEqual(str(WithStr('abc')), 'abc')
self.assertEqual(str(StrSubclassToStr("bar")), "foo") self.assertTypedEqual(str(WithStr(StrSubclass('abc'))), StrSubclass('abc'))
s = str(StrSubclassToStrSubclass("foo")) self.assertTypedEqual(StrSubclass(WithStr('abc')), StrSubclass('abc'))
self.assertEqual(s, "foofoo") self.assertTypedEqual(StrSubclass(WithStr(StrSubclass('abc'))),
self.assertIs(type(s), StrSubclassToStrSubclass) StrSubclass('abc'))
s = StrSubclass(StrSubclassToStrSubclass("foo")) self.assertTypedEqual(StrSubclass(WithStr(OtherStrSubclass('abc'))),
self.assertEqual(s, "foofoo") StrSubclass('abc'))
self.assertIs(type(s), StrSubclass)
self.assertTypedEqual(str(StrWithStr('abc')), 'abc')
self.assertTypedEqual(str(StrWithStr(StrSubclass('abc'))), StrSubclass('abc'))
self.assertTypedEqual(StrSubclass(StrWithStr('abc')), StrSubclass('abc'))
self.assertTypedEqual(StrSubclass(StrWithStr(StrSubclass('abc'))),
StrSubclass('abc'))
self.assertTypedEqual(StrSubclass(StrWithStr(OtherStrSubclass('abc'))),
StrSubclass('abc'))
self.assertTypedEqual(str(WithRepr('<abc>')), '<abc>')
self.assertTypedEqual(str(WithRepr(StrSubclass('<abc>'))), StrSubclass('<abc>'))
self.assertTypedEqual(StrSubclass(WithRepr('<abc>')), StrSubclass('<abc>'))
self.assertTypedEqual(StrSubclass(WithRepr(StrSubclass('<abc>'))),
StrSubclass('<abc>'))
self.assertTypedEqual(StrSubclass(WithRepr(OtherStrSubclass('<abc>'))),
StrSubclass('<abc>'))
def test_unicode_repr(self): def test_unicode_repr(self):
class s1: class s1: