Update test_unicodedata.py to 3.14.4 (#7750)

* Update `test_unicodedata.py` to 3.14.4

* Add test asset

* Mark failing tests

* Add `expectedSuccess` docorator

* Add support for nee decorator in patch_spec

* Reapply patches
This commit is contained in:
Shahar Naveh authored and GitHub committed 2026-05-01 19:48:41 +09:00
1 parent c0005f744b
commit b1df45bd09
4 files changed
+17551 -90

No files matched your search

File diff suppressed because it is too large. Load diff
+506 -88
View File
@@ -6,6 +6,7 @@
"""
from functools import partial
import hashlib
from http.client import HTTPException
import sys
@@ -18,21 +19,32 @@ from test.support import (
cpython_only,
check_disallow_instantiation,
force_not_colorized,
is_resource_enabled,
findfile,
)
quicktest = not is_resource_enabled('cpu')
def iterallchars():
maxunicode = 0xffff if quicktest else sys.maxunicode
return map(chr, range(maxunicode + 1))
class UnicodeMethodsTest(unittest.TestCase):
# update this, if the database changes
expectedchecksum = '9e43ee3929471739680c0e705482b4ae1c4122e4'
expectedchecksum = ('486bf97d506d0ccf0e463fd1f40c51029805af5a'
if quicktest else
'9e43ee3929471739680c0e705482b4ae1c4122e4')
@unittest.expectedFailure # TODO: RUSTPYTHON; + 9e43ee3929471739680c0e705482b4ae1c4122e4
@requires_resource('cpu')
def test_method_checksum(self):
h = hashlib.sha1()
for i in range(sys.maxunicode + 1):
char = chr(i)
data = [
for char in iterallchars():
s1 = char + 'abc'
s2 = char + 'ABC'
s3 = char + '123'
data = (
# Predicates (single char)
"01"[char.isalnum()],
"01"[char.isalpha()],
@@ -45,15 +57,15 @@ class UnicodeMethodsTest(unittest.TestCase):
"01"[char.isupper()],
# Predicates (multiple chars)
"01"[(char + 'abc').isalnum()],
"01"[(char + 'abc').isalpha()],
"01"[(char + '123').isdecimal()],
"01"[(char + '123').isdigit()],
"01"[(char + 'abc').islower()],
"01"[(char + '123').isnumeric()],
"01"[s1.isalnum()],
"01"[s1.isalpha()],
"01"[s3.isdecimal()],
"01"[s3.isdigit()],
"01"[s1.islower()],
"01"[s3.isnumeric()],
"01"[(char + ' \t').isspace()],
"01"[(char + 'abc').istitle()],
"01"[(char + 'ABC').isupper()],
"01"[s1.istitle()],
"01"[s2.isupper()],
# Mappings (single char)
char.lower(),
@@ -61,55 +73,106 @@ class UnicodeMethodsTest(unittest.TestCase):
char.title(),
# Mappings (multiple chars)
(char + 'abc').lower(),
(char + 'ABC').upper(),
(char + 'abc').title(),
(char + 'ABC').title(),
s1.lower(),
s2.upper(),
s1.title(),
s2.title(),
]
)
h.update(''.join(data).encode('utf-8', 'surrogatepass'))
result = h.hexdigest()
self.assertEqual(result, self.expectedchecksum)
class UnicodeDatabaseTest(unittest.TestCase):
db = unicodedata
class UnicodeFunctionsTest(UnicodeDatabaseTest):
class UnicodeFunctionsTest(unittest.TestCase):
db = unicodedata
old = False
# Update this if the database changes. Make sure to do a full rebuild
# (e.g. 'make distclean && make') to get the correct checksum.
expectedchecksum = '23ab09ed4abdf93db23b97359108ed630dd8311d'
expectedchecksum = ('1ba453ec456896f1190d849b6e9b7c2e1a4128e0'
if quicktest else
'46ca89d9fe34881d0be3a4a4b29f5aa8c019640c')
@unittest.expectedFailure # TODO: RUSTPYTHON; AttributeError: module 'unicodedata' has no attribute 'digit'
@requires_resource('cpu')
def test_function_checksum(self):
db = self.db
data = []
h = hashlib.sha1()
for i in range(sys.maxunicode + 1):
char = chr(i)
data = [
for char in iterallchars():
data = "%.12g%.12g%.12g%s%s%s%s%s%s%s" % (
# Properties
format(self.db.digit(char, -1), '.12g'),
format(self.db.numeric(char, -1), '.12g'),
format(self.db.decimal(char, -1), '.12g'),
self.db.category(char),
self.db.bidirectional(char),
self.db.decomposition(char),
str(self.db.mirrored(char)),
str(self.db.combining(char)),
unicodedata.east_asian_width(char),
self.db.name(char, ""),
]
h.update(''.join(data).encode("ascii"))
db.digit(char, -1),
db.numeric(char, -1),
db.decimal(char, -1),
db.category(char),
db.bidirectional(char),
db.decomposition(char),
db.mirrored(char),
db.combining(char),
db.east_asian_width(char),
db.name(char, ""),
)
h.update(data.encode("ascii"))
result = h.hexdigest()
self.assertEqual(result, self.expectedchecksum)
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: None != 'EGYPTIAN HIEROGLYPH-13460'
def test_name(self):
name = self.db.name
self.assertRaises(ValueError, name, '\0')
self.assertRaises(ValueError, name, '\n')
self.assertRaises(ValueError, name, '\x1F')
self.assertRaises(ValueError, name, '\x7F')
self.assertRaises(ValueError, name, '\x9F')
self.assertRaises(ValueError, name, '\uFFFE')
self.assertRaises(ValueError, name, '\uFFFF')
self.assertRaises(ValueError, name, '\U0010FFFF')
self.assertEqual(name('\U0010FFFF', 42), 42)
self.assertEqual(name(' '), 'SPACE')
self.assertEqual(name('1'), 'DIGIT ONE')
self.assertEqual(name('A'), 'LATIN CAPITAL LETTER A')
self.assertEqual(name('\xA0'), 'NO-BREAK SPACE')
self.assertEqual(name('\u0221', None), None if self.old else
'LATIN SMALL LETTER D WITH CURL')
self.assertEqual(name('\u3400'), 'CJK UNIFIED IDEOGRAPH-3400')
self.assertEqual(name('\u9FA5'), 'CJK UNIFIED IDEOGRAPH-9FA5')
self.assertEqual(name('\uAC00'), 'HANGUL SYLLABLE GA')
self.assertEqual(name('\uD7A3'), 'HANGUL SYLLABLE HIH')
self.assertEqual(name('\uF900'), 'CJK COMPATIBILITY IDEOGRAPH-F900')
self.assertEqual(name('\uFA6A'), 'CJK COMPATIBILITY IDEOGRAPH-FA6A')
self.assertEqual(name('\uFBF9'),
'ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA '
'ABOVE WITH ALEF MAKSURA ISOLATED FORM')
self.assertEqual(name('\U00013460', None), None if self.old else
'EGYPTIAN HIEROGLYPH-13460')
self.assertEqual(name('\U000143FA', None), None if self.old else
'EGYPTIAN HIEROGLYPH-143FA')
self.assertEqual(name('\U00018B00', None), None if self.old else
'KHITAN SMALL SCRIPT CHARACTER-18B00')
self.assertEqual(name('\U00018CD5', None), None if self.old else
'KHITAN SMALL SCRIPT CHARACTER-18CD5')
self.assertEqual(name('\U00018CFF', None), None if self.old else
'KHITAN SMALL SCRIPT CHARACTER-18CFF')
self.assertEqual(name('\U0001B170', None), None if self.old else
'NUSHU CHARACTER-1B170')
self.assertEqual(name('\U0001B2FB', None), None if self.old else
'NUSHU CHARACTER-1B2FB')
self.assertEqual(name('\U0001FBA8', None), None if self.old else
'BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO '
'MIDDLE LEFT AND MIDDLE RIGHT TO LOWER CENTRE')
self.assertEqual(name('\U0002A6D6'), 'CJK UNIFIED IDEOGRAPH-2A6D6')
self.assertEqual(name('\U0002FA1D'), 'CJK COMPATIBILITY IDEOGRAPH-2FA1D')
self.assertEqual(name('\U000323AF', None), None if self.old else
'CJK UNIFIED IDEOGRAPH-323AF')
@requires_resource('cpu')
def test_name_inverse_lookup(self):
for i in range(sys.maxunicode + 1):
char = chr(i)
if looked_name := self.db.name(char, None):
for char in iterallchars():
looked_name = self.db.name(char, None)
if looked_name is not None:
self.assertEqual(self.db.lookup(looked_name), char)
def test_no_names_in_pua(self):
@@ -120,6 +183,7 @@ class UnicodeFunctionsTest(UnicodeDatabaseTest):
char = chr(i)
self.assertRaises(ValueError, self.db.name, char)
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: KeyError not raised by lookup
def test_lookup_nonexistant(self):
# just make sure that lookup can fail
for nonexistent in [
@@ -129,9 +193,21 @@ class UnicodeFunctionsTest(UnicodeDatabaseTest):
"HANDBUG",
"MODIFIER LETTER CYRILLIC SMALL QUESTION MARK",
"???",
"CJK UNIFIED IDEOGRAPH-03400",
"CJK UNIFIED IDEOGRAPH-020000",
"CJK UNIFIED IDEOGRAPH-33FF",
"CJK UNIFIED IDEOGRAPH-F900",
"CJK UNIFIED IDEOGRAPH-13460",
"CJK UNIFIED IDEOGRAPH-17000",
"CJK UNIFIED IDEOGRAPH-18B00",
"CJK UNIFIED IDEOGRAPH-1B170",
"CJK COMPATIBILITY IDEOGRAPH-3400",
"TANGUT IDEOGRAPH-3400",
"HANGUL SYLLABLE AC00",
]:
self.assertRaises(KeyError, self.db.lookup, nonexistent)
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: None != 9
def test_digit(self):
self.assertEqual(self.db.digit('A', None), None)
self.assertEqual(self.db.digit('9'), 9)
@@ -140,23 +216,51 @@ class UnicodeFunctionsTest(UnicodeDatabaseTest):
self.assertEqual(self.db.digit('\U00020000', None), None)
self.assertEqual(self.db.digit('\U0001D7FD'), 7)
# New in 13.0.0
self.assertEqual(self.db.digit('\U0001fbf9', None), 9)
# New in 14.0.0
self.assertEqual(self.db.digit('\U00016ac9', None), 9)
# New in 15.0.0
self.assertEqual(self.db.digit('\U0001e4f9', None), 9)
self.assertRaises(TypeError, self.db.digit)
self.assertRaises(TypeError, self.db.digit, 'xx')
self.assertRaises(ValueError, self.db.digit, 'x')
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_numeric(self):
self.assertEqual(self.db.numeric('A',None), None)
self.assertEqual(self.db.numeric('9'), 9)
self.assertEqual(self.db.numeric('\u215b'), 0.125)
self.assertEqual(self.db.numeric('\u2468'), 9.0)
self.assertEqual(self.db.numeric('\ua627'), 7.0)
self.assertEqual(self.db.numeric('\U00020000', None), None)
self.assertEqual(self.db.numeric('\U0001012A'), 9000)
# New in 4.1.0
self.assertEqual(self.db.numeric('\U0001012A', None), None if self.old else 9000)
# Changed in 4.1.0
self.assertEqual(self.db.numeric('\u5793', None), 1e20 if self.old else None)
# New in 5.0.0
self.assertEqual(self.db.numeric('\u07c0', None), None if self.old else 0.0)
# New in 5.1.0
self.assertEqual(self.db.numeric('\ua627', None), None if self.old else 7.0)
# Changed in 5.2.0
self.assertEqual(self.db.numeric('\u09f6'), 3.0 if self.old else 3/16)
# New in 6.0.0
self.assertEqual(self.db.numeric('\u0b72', None), None if self.old else 0.25)
# New in 12.0.0
self.assertEqual(self.db.numeric('\U0001ed3c', None), None if self.old else 0.5)
# New in 13.0.0
self.assertEqual(self.db.numeric('\U0001fbf9', None), None if self.old else 9)
# New in 14.0.0
self.assertEqual(self.db.numeric('\U00016ac9', None), None if self.old else 9)
# New in 15.0.0
self.assertEqual(self.db.numeric('\U0001e4f9', None), None if self.old else 9)
self.assertRaises(TypeError, self.db.numeric)
self.assertRaises(TypeError, self.db.numeric, 'xx')
self.assertRaises(ValueError, self.db.numeric, 'x')
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: None != 2
def test_decimal(self):
self.assertEqual(self.db.decimal('A',None), None)
self.assertEqual(self.db.decimal('9'), 9)
@@ -165,16 +269,43 @@ class UnicodeFunctionsTest(UnicodeDatabaseTest):
self.assertEqual(self.db.decimal('\U00020000', None), None)
self.assertEqual(self.db.decimal('\U0001D7FD'), 7)
# New in 4.1.0
self.assertEqual(self.db.decimal('\xb2', None), 2 if self.old else None)
self.assertEqual(self.db.decimal('\u1369', None), 1 if self.old else None)
# New in 5.0.0
self.assertEqual(self.db.decimal('\u07c0', None), None if self.old else 0)
# New in 13.0.0
self.assertEqual(self.db.decimal('\U0001fbf9', None), None if self.old else 9)
# New in 14.0.0
self.assertEqual(self.db.decimal('\U00016ac9', None), None if self.old else 9)
# New in 15.0.0
self.assertEqual(self.db.decimal('\U0001e4f9', None), None if self.old else 9)
self.assertRaises(TypeError, self.db.decimal)
self.assertRaises(TypeError, self.db.decimal, 'xx')
self.assertRaises(ValueError, self.db.decimal, 'x')
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: 'Cn' != 'Mn'
def test_category(self):
self.assertEqual(self.db.category('\uFFFE'), 'Cn')
self.assertEqual(self.db.category('a'), 'Ll')
self.assertEqual(self.db.category('A'), 'Lu')
self.assertEqual(self.db.category('\U00020000'), 'Lo')
self.assertEqual(self.db.category('\U0001012A'), 'No')
# New in 4.1.0
self.assertEqual(self.db.category('\U0001012A'), 'Cn' if self.old else 'No')
self.assertEqual(self.db.category('\U000e01ef'), 'Cn' if self.old else 'Mn')
# New in 5.1.0
self.assertEqual(self.db.category('\u0374'), 'Sk' if self.old else 'Lm')
# Changed in 13.0.0
self.assertEqual(self.db.category('\u0b55'), 'Cn' if self.old else 'Mn')
self.assertEqual(self.db.category('\U0003134a'), 'Cn' if self.old else 'Lo')
# Changed in 14.0.0
self.assertEqual(self.db.category('\u061d'), 'Cn' if self.old else 'Po')
self.assertEqual(self.db.category('\U0002b738'), 'Cn' if self.old else 'Lo')
# Changed in 15.0.0
self.assertEqual(self.db.category('\u0cf3'), 'Cn' if self.old else 'Mc')
self.assertEqual(self.db.category('\U000323af'), 'Cn' if self.old else 'Lo')
self.assertRaises(TypeError, self.db.category)
self.assertRaises(TypeError, self.db.category, 'xx')
@@ -186,34 +317,262 @@ class UnicodeFunctionsTest(UnicodeDatabaseTest):
self.assertEqual(self.db.bidirectional('A'), 'L')
self.assertEqual(self.db.bidirectional('\U00020000'), 'L')
# New in 4.1.0
self.assertEqual(self.db.bidirectional('+'), 'ET' if self.old else 'ES')
self.assertEqual(self.db.bidirectional('\u0221'), '' if self.old else 'L')
self.assertEqual(self.db.bidirectional('\U000e01ef'), '' if self.old else 'NSM')
# New in 13.0.0
self.assertEqual(self.db.bidirectional('\u0b55'), '' if self.old else 'NSM')
self.assertEqual(self.db.bidirectional('\U0003134a'), '' if self.old else 'L')
# New in 14.0.0
self.assertEqual(self.db.bidirectional('\u061d'), '' if self.old else 'AL')
self.assertEqual(self.db.bidirectional('\U0002b738'), '' if self.old else 'L')
# New in 15.0.0
self.assertEqual(self.db.bidirectional('\u0cf3'), '' if self.old else 'L')
self.assertEqual(self.db.bidirectional('\U000323af'), '' if self.old else 'L')
# New in 16.0.0
self.assertEqual(self.db.bidirectional('\u0897'), '' if self.old else 'NSM')
self.assertEqual(self.db.bidirectional('\U0001fbef'), '' if self.old else 'ON')
self.assertRaises(TypeError, self.db.bidirectional)
self.assertRaises(TypeError, self.db.bidirectional, 'xx')
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: 'D4CC 11B6' != '1111 1171 11B6'
def test_decomposition(self):
self.assertEqual(self.db.decomposition('\uFFFE'),'')
self.assertEqual(self.db.decomposition('\u00bc'), '<fraction> 0031 2044 0034')
# New in 4.1.0
self.assertEqual(self.db.decomposition('\u03f9'), '' if self.old else '<compat> 03A3')
# New in 13.0.0
self.assertEqual(self.db.decomposition('\uab69'), '' if self.old else '<super> 028D')
self.assertEqual(self.db.decomposition('\U00011938'), '' if self.old else '11935 11930')
self.assertEqual(self.db.decomposition('\U0001fbf9'), '' if self.old else '<font> 0039')
# New in 14.0.0
self.assertEqual(self.db.decomposition('\ua7f2'), '' if self.old else '<super> 0043')
self.assertEqual(self.db.decomposition('\U000107ba'), '' if self.old else '<super> 1DF1E')
# New in 15.0.0
self.assertEqual(self.db.decomposition('\U0001e06d'), '' if self.old else '<super> 04B1')
# New in 16.0.0
self.assertEqual(self.db.decomposition('\U0001CCD6'), '' if self.old else '<font> 0041')
# Hangul characters
self.assertEqual(self.db.decomposition('\uAC00'), '1100 1161')
self.assertEqual(self.db.decomposition('\uD4DB'), '1111 1171 11B6')
self.assertEqual(self.db.decomposition('\uC2F8'), '110A 1161')
self.assertEqual(self.db.decomposition('\uD7A3'), '1112 1175 11C2')
self.assertRaises(TypeError, self.db.decomposition)
self.assertRaises(TypeError, self.db.decomposition, 'xx')
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: 1 != 0
def test_mirrored(self):
self.assertEqual(self.db.mirrored('\uFFFE'), 0)
self.assertEqual(self.db.mirrored('a'), 0)
self.assertEqual(self.db.mirrored('\u2201'), 1)
self.assertEqual(self.db.mirrored('\U00020000'), 0)
# New in 5.0.0
self.assertEqual(self.db.mirrored('\u0f3a'), 0 if self.old else 1)
self.assertEqual(self.db.mirrored('\U0001d7c3'), 0 if self.old else 1)
# New in 11.0.0
self.assertEqual(self.db.mirrored('\u29a1'), 1 if self.old else 0)
# New in 14.0.0
self.assertEqual(self.db.mirrored('\u2e5c'), 0 if self.old else 1)
# New in 16.0.0
self.assertEqual(self.db.mirrored('\u226D'), 0 if self.old else 1)
self.assertRaises(TypeError, self.db.mirrored)
self.assertRaises(TypeError, self.db.mirrored, 'xx')
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: 0 != 220
def test_combining(self):
self.assertEqual(self.db.combining('\uFFFE'), 0)
self.assertEqual(self.db.combining('a'), 0)
self.assertEqual(self.db.combining('\u20e1'), 230)
self.assertEqual(self.db.combining('\U00020000'), 0)
# New in 4.1.0
self.assertEqual(self.db.combining('\u0350'), 0 if self.old else 230)
# New in 9.0.0
self.assertEqual(self.db.combining('\U0001e94a'), 0 if self.old else 7)
# New in 13.0.0
self.assertEqual(self.db.combining('\u1abf'), 0 if self.old else 220)
self.assertEqual(self.db.combining('\U00016ff1'), 0 if self.old else 6)
# New in 14.0.0
self.assertEqual(self.db.combining('\u0c3c'), 0 if self.old else 7)
self.assertEqual(self.db.combining('\U0001e2ae'), 0 if self.old else 230)
# New in 15.0.0
self.assertEqual(self.db.combining('\U00010efd'), 0 if self.old else 220)
# New in 16.0.0
self.assertEqual(self.db.combining('\u0897'), 0 if self.old else 230)
self.assertRaises(TypeError, self.db.combining)
self.assertRaises(TypeError, self.db.combining, 'xx')
def test_normalization(self):
# Test normalize() and is_normalized()
def check(ch, expected):
if isinstance(expected, str):
expected = [expected]*4
forms = ('NFC', 'NFD', 'NFKC', 'NFKD')
result = [self.db.normalize(form, ch) for form in forms]
self.assertEqual(ascii(result), ascii(list(expected)))
self.assertEqual([self.db.is_normalized(form, ch) for form in forms],
[ch == y for x, y in zip(result, expected)])
check('', '')
check('A', 'A')
check(' ', ' ')
check('\U0010ffff', '\U0010ffff')
check('abc', 'abc')
# Broken in 4.0.0
check('\u0340', '\u0300')
check('\u0300', '\u0300')
check('\U0002fa1d', '\U0002a600')
check('\U0002a600', '\U0002a600')
check('\u0344', '\u0308\u0301')
check('\u0308\u0301', '\u0308\u0301')
# Broken in 4.0.0 and 4.0.1
check('\U0001d1bc', '\U0001d1ba\U0001d165')
check('\U0001d1ba\U0001d165', '\U0001d1ba\U0001d165')
check('\ufb2c', '\u05e9\u05bc\u05c1')
check('\u05e9\u05bc\u05c1', '\u05e9\u05bc\u05c1')
check('\U0001d1c0', '\U0001d1ba\U0001d165\U0001d16f')
check('\U0001d1ba\U0001d165\U0001d16f', '\U0001d1ba\U0001d165\U0001d16f')
# Broken in 4.0.0
check('\xa0', ['\xa0', '\xa0', ' ', ' '])
check('\u2003', ['\u2003', '\u2003', ' ', ' '])
check('\U0001d7ff', ['\U0001d7ff', '\U0001d7ff', '9', '9'])
check('\xa8', ['\xa8', '\xa8', ' \u0308', ' \u0308'])
check(' \u0308', ' \u0308')
check('\xc0', ['\xc0', 'A\u0300']*2)
check('A\u0300', ['\xc0', 'A\u0300']*2)
check('\ud7a3', ['\ud7a3', '\u1112\u1175\u11c2']*2)
check('\u1112\u1175\u11c2', ['\ud7a3', '\u1112\u1175\u11c2']*2)
check('\xb4', ['\xb4', '\xb4', ' \u0301', ' \u0301'])
check('\u1ffd', ['\xb4', '\xb4', ' \u0301', ' \u0301'])
check(' \u0301', ' \u0301')
check('\xc5', ['\xc5', 'A\u030a']*2)
check('\u212b', ['\xc5', 'A\u030a']*2)
check('A\u030a', ['\xc5', 'A\u030a']*2)
check('\u1f71', ['\u03ac', '\u03b1\u0301']*2)
check('\u03ac', ['\u03ac', '\u03b1\u0301']*2)
check('\u03b1\u0301', ['\u03ac', '\u03b1\u0301']*2)
check('\u01c4', ['\u01c4', '\u01c4', 'D\u017d', 'DZ\u030c'])
check('D\u017d', ['D\u017d', 'DZ\u030c']*2)
check('DZ\u030c', ['D\u017d', 'DZ\u030c']*2)
check('\u1fed', ['\u1fed', '\xa8\u0300', ' \u0308\u0300', ' \u0308\u0300'])
check('\xa8\u0300', ['\u1fed', '\xa8\u0300', ' \u0308\u0300', ' \u0308\u0300'])
check(' \u0308\u0300', ' \u0308\u0300')
check('\u326e', ['\u326e', '\u326e', '\uac00', '\u1100\u1161'])
check('\u320e', ['\u320e', '\u320e', '(\uac00)', '(\u1100\u1161)'])
check('(\uac00)', ['(\uac00)', '(\u1100\u1161)']*2)
check('(\u1100\u1161)', ['(\uac00)', '(\u1100\u1161)']*2)
check('\u0385', ['\u0385', '\xa8\u0301', ' \u0308\u0301', ' \u0308\u0301'])
check('\u1fee', ['\u0385', '\xa8\u0301', ' \u0308\u0301', ' \u0308\u0301'])
check('\xa8\u0301', ['\u0385', '\xa8\u0301', ' \u0308\u0301', ' \u0308\u0301'])
check(' \u0308\u0301', ' \u0308\u0301')
check('\u1fdf', ['\u1fdf', '\u1ffe\u0342', ' \u0314\u0342', ' \u0314\u0342'])
check('\u1ffe\u0342', ['\u1fdf', '\u1ffe\u0342', ' \u0314\u0342', ' \u0314\u0342'])
check('\u1ffe', ['\u1ffe', '\u1ffe', ' \u0314', ' \u0314'])
check(' \u0314\u0342', ' \u0314\u0342')
check('\u03d3', ['\u03d3', '\u03d2\u0301', '\u038e', '\u03a5\u0301'])
check('\u03d2\u0301', ['\u03d3', '\u03d2\u0301', '\u038e', '\u03a5\u0301'])
check('\u038e', ['\u038e', '\u03a5\u0301']*2)
check('\u1feb', ['\u038e', '\u03a5\u0301']*2)
check('\u03a5\u0301', ['\u038e', '\u03a5\u0301']*2)
check('\u0626', ['\u0626', '\u064a\u0654']*2)
check('\u064a\u0654', ['\u0626', '\u064a\u0654']*2)
check('\ufe89', ['\ufe89', '\ufe89', '\u0626', '\u064a\u0654'])
check('\ufe8a', ['\ufe8a', '\ufe8a', '\u0626', '\u064a\u0654'])
check('\ufe8b', ['\ufe8b', '\ufe8b', '\u0626', '\u064a\u0654'])
check('\ufe8c', ['\ufe8c', '\ufe8c', '\u0626', '\u064a\u0654'])
check('\ufef9', ['\ufef9', '\ufef9', '\u0644\u0625', '\u0644\u0627\u0655'])
check('\ufefa', ['\ufefa', '\ufefa', '\u0644\u0625', '\u0644\u0627\u0655'])
check('\ufefb', ['\ufefb', '\ufefb', '\u0644\u0627', '\u0644\u0627'])
check('\ufefc', ['\ufefc', '\ufefc', '\u0644\u0627', '\u0644\u0627'])
check('\u0644\u0625', ['\u0644\u0625', '\u0644\u0627\u0655']*2)
check('\u0644\u0627\u0655', ['\u0644\u0625', '\u0644\u0627\u0655']*2)
check('\u0644\u0627', '\u0644\u0627')
# Broken in 4.0.0
check('\u327c', '\u327c' if self.old else
['\u327c', '\u327c', '\ucc38\uace0', '\u110e\u1161\u11b7\u1100\u1169'])
check('\ucc38\uace0', ['\ucc38\uace0', '\u110e\u1161\u11b7\u1100\u1169']*2)
check('\ucc38', ['\ucc38', '\u110e\u1161\u11b7']*2)
check('\u110e\u1161\u11b7\u1100\u1169',
['\ucc38\uace0', '\u110e\u1161\u11b7\u1100\u1169']*2)
check('\u110e\u1161\u11b7\u1100',
['\ucc38\u1100', '\u110e\u1161\u11b7\u1100']*2)
check('\u110e\u1161\u11b7',
['\ucc38', '\u110e\u1161\u11b7']*2)
check('\u110e\u1161',
['\ucc28', '\u110e\u1161']*2)
check('\u110e', '\u110e')
# Broken in 4.0.0-12.0.0
check('\U00011938', '\U00011938' if self.old else
['\U00011938', '\U00011935\U00011930']*2)
check('\U00011935\U00011930', ['\U00011938', '\U00011935\U00011930']*2)
# New in 4.0.1
check('\u321d', '\u321d' if self.old else
['\u321d', '\u321d', '(\uc624\uc804)', '(\u110b\u1169\u110c\u1165\u11ab)'])
check('(\uc624\uc804)',
['(\uc624\uc804)', '(\u110b\u1169\u110c\u1165\u11ab)']*2)
check('(\u110b\u1169\u110c\u1165\u11ab)',
['(\uc624\uc804)', '(\u110b\u1169\u110c\u1165\u11ab)']*2)
check('\u4d57', '\u4d57')
check('\u45d7', '\u45d7' if self.old else '\u45d7')
check('\U0002f9bf', '\u4d57' if self.old else '\u45d7')
# New in 4.1.0
check('\u03a3', '\u03a3')
check('\u03f9', '\u03f9' if self.old else
['\u03f9', '\u03f9', '\u03a3', '\u03a3'])
# New in 5.0.0
check('\u1b06', '\u1b06' if self.old else ['\u1b06', '\u1b05\u1b35']*2)
# New in 5.2.0
check('\U0001f213', '\U0001f213' if self.old else
['\U0001f213', '\U0001f213', '\u30c7', '\u30c6\u3099'])
# New in 6.1.0
check('\ufa2e', '\ufa2e' if self.old else '\u90de')
# New in 13.0.0
check('\U00011938', '\U00011938' if self.old else
['\U00011938', '\U00011935\U00011930', '\U00011938', '\U00011935\U00011930'])
check('\U0001fbf9', '\U0001fbf9' if self.old else
['\U0001fbf9', '\U0001fbf9', '9', '9'])
# New in 14.0.0
check('\U000107ba', '\U000107ba' if self.old else
['\U000107ba', '\U000107ba', '\U0001df1e', '\U0001df1e'])
# New in 15.0.0
check('\U0001e06d', '\U0001e06d' if self.old else
['\U0001e06d', '\U0001e06d', '\u04b1', '\u04b1'])
# New in 16.0.0
check('\U0001ccd6', '\U0001ccd6' if self.old else
['\U0001ccd6', '\U0001ccd6', 'A', 'A'])
self.assertRaises(TypeError, self.db.normalize)
self.assertRaises(TypeError, self.db.normalize, 'NFC')
self.assertRaises(ValueError, self.db.normalize, 'SPAM', 'A')
self.assertRaises(TypeError, self.db.is_normalized)
self.assertRaises(TypeError, self.db.is_normalized, 'NFC')
self.assertRaises(ValueError, self.db.is_normalized, 'SPAM', 'A')
def test_pr29(self):
# https://www.unicode.org/review/pr-29.html
# See issues #1054943 and #10254.
@@ -228,6 +587,7 @@ class UnicodeFunctionsTest(UnicodeDatabaseTest):
def test_issue10254(self):
# Crash reported in #10254
# New in 4.1.0
a = 'C\u0338' * 20 + 'C\u0327'
b = 'C\u0338' * 20 + '\xC7'
self.assertEqual(self.db.normalize('NFC', a), b)
@@ -241,9 +601,11 @@ class UnicodeFunctionsTest(UnicodeDatabaseTest):
u11c3_str_a = '\u1100\u1175\u11c3'
u11c3_str_b = '\uae30\u11c3'
self.assertEqual(self.db.normalize('NFC', u1176_str_a), u1176_str_b)
# New in 4.1.0
self.assertEqual(self.db.normalize('NFC', u11a7_str_a), u11a7_str_b)
self.assertEqual(self.db.normalize('NFC', u11c3_str_a), u11c3_str_b)
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: 'W' != 'N'
def test_east_asian_width(self):
eaw = self.db.east_asian_width
self.assertRaises(TypeError, eaw, b'a')
@@ -258,6 +620,32 @@ class UnicodeFunctionsTest(UnicodeDatabaseTest):
self.assertEqual(eaw('\u2010'), 'A')
self.assertEqual(eaw('\U00020000'), 'W')
# New in 4.1.0
self.assertEqual(eaw('\u0350'), 'N' if self.old else 'A')
self.assertEqual(eaw('\U000e01ef'), 'N' if self.old else 'A')
# New in 5.2.0
self.assertEqual(eaw('\u115a'), 'N' if self.old else 'W')
# New in 9.0.0
self.assertEqual(eaw('\u231a'), 'N' if self.old else 'W')
self.assertEqual(eaw('\u2614'), 'N' if self.old else 'W')
self.assertEqual(eaw('\U0001f19a'), 'N' if self.old else 'W')
self.assertEqual(eaw('\U0001f991'), 'N' if self.old else 'W')
self.assertEqual(eaw('\U0001f9c0'), 'N' if self.old else 'W')
# New in 12.0.0
self.assertEqual(eaw('\u32ff'), 'N' if self.old else 'W')
self.assertEqual(eaw('\U0001fa95'), 'N' if self.old else 'W')
# New in 13.0.0
self.assertEqual(eaw('\u31bb'), 'N' if self.old else 'W')
self.assertEqual(eaw('\U0003134a'), 'N' if self.old else 'W')
# New in 14.0.0
self.assertEqual(eaw('\u9ffd'), 'N' if self.old else 'W')
self.assertEqual(eaw('\U0002b738'), 'N' if self.old else 'W')
# New in 15.0.0
self.assertEqual(eaw('\U000323af'), 'N' if self.old else 'W')
# New in 16.0.0
self.assertEqual(eaw('\u2630'), 'N' if self.old else 'W')
self.assertEqual(eaw('\U0001FAE9'), 'N' if self.old else 'W')
@unittest.expectedFailure # TODO: RUSTPYTHON; + W
def test_east_asian_width_unassigned(self):
eaw = self.db.east_asian_width
@@ -267,7 +655,8 @@ class UnicodeFunctionsTest(UnicodeDatabaseTest):
self.assertIs(self.db.name(char, None), None)
# unassigned but reserved for CJK
for char in '\uFA6E\uFADA\U0002A6E0\U0002FA20\U0003134B\U0003FFFD':
for char in ('\U0002A6E0\U0002FA20\U0003134B\U0003FFFD'
'\uFA6E\uFADA'): # New in 5.2.0
self.assertEqual(eaw(char), 'W')
self.assertIs(self.db.name(char, None), None)
@@ -278,10 +667,31 @@ class UnicodeFunctionsTest(UnicodeDatabaseTest):
@unittest.expectedFailure # TODO: RUSTPYTHON; + N
def test_east_asian_width_9_0_changes(self):
self.assertEqual(self.db.ucd_3_2_0.east_asian_width('\u231a'), 'N')
self.assertEqual(self.db.east_asian_width('\u231a'), 'W')
return super().test_east_asian_width_9_0_changes()
class UnicodeMiscTest(UnicodeDatabaseTest):
class Unicode_3_2_0_FunctionsTest(UnicodeFunctionsTest):
db = unicodedata.ucd_3_2_0
old = True
expectedchecksum = ('883824cb6c0ccf994e4451ebf281e2d6d479af47'
if quicktest else
'caf1a7f2f380f927461837f1901ef20683f98683')
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_normalization(self):
return super().test_normalization()
@unittest.expectedSuccess # TODO: RUSTPYTHON
def test_combining(self):
return super().test_combining()
@unittest.expectedSuccess # TODO: RUSTPYTHON
def test_name(self):
return super().test_name()
class UnicodeMiscTest(unittest.TestCase):
db = unicodedata
@cpython_only
def test_disallow_instantiation(self):
@@ -311,33 +721,40 @@ class UnicodeMiscTest(UnicodeDatabaseTest):
# i.e. if a character has a decimal value,
# its numeric value should be the same.
count = 0
for i in range(0x10000):
c = chr(i)
for c in iterallchars():
dec = self.db.decimal(c, -1)
if dec != -1:
self.assertEqual(dec, self.db.numeric(c))
count += 1
self.assertTrue(count >= 10) # should have tested at least the ASCII digits
self.assertTrue(count >= 10, count) # should have tested at least the ASCII digits
def test_digit_numeric_consistent(self):
# Test that digit and numeric are consistent,
# i.e. if a character has a digit value,
# its numeric value should be the same.
count = 0
for i in range(0x10000):
c = chr(i)
for c in iterallchars():
dec = self.db.digit(c, -1)
if dec != -1:
self.assertEqual(dec, self.db.numeric(c))
count += 1
self.assertTrue(count >= 10) # should have tested at least the ASCII digits
self.assertTrue(count >= 10, count) # should have tested at least the ASCII digits
def test_normalize_consistent(self):
allchars = list(iterallchars())
for form in ('NFC', 'NFD', 'NFKC', 'NFKD'):
for c in allchars:
norm = self.db.normalize(form, c)
self.assertEqual(self.db.is_normalized(form, c), norm == c)
if norm != c:
self.assertEqual(self.db.normalize(form, norm), norm)
self.assertTrue(self.db.is_normalized(form, norm))
def test_bug_1704793(self):
self.assertEqual(self.db.lookup("GOTHIC LETTER FAIHU"), '\U00010346')
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: False is not true
def test_ucd_510(self):
import unicodedata
# In UCD 5.1.0, a mirrored property changed wrt. UCD 3.2.0
self.assertTrue(unicodedata.mirrored("\u0f3a"))
self.assertTrue(not unicodedata.ucd_3_2_0.mirrored("\u0f3a"))
@@ -353,10 +770,10 @@ class UnicodeMiscTest(UnicodeDatabaseTest):
# Only U+0000 should have U+0000 as its upper/lower/titlecase variant
self.assertEqual(
[
c for c in range(sys.maxunicode+1)
if "\x00" in chr(c).lower()+chr(c).upper()+chr(c).title()
c for c in iterallchars()
if "\x00" in (c.lower(), c.upper(), c.title())
],
[0]
["\x00"]
)
def test_bug_4971(self):
@@ -366,15 +783,16 @@ class UnicodeMiscTest(UnicodeDatabaseTest):
self.assertEqual("\u01c6".title(), "\u01c5")
def test_linebreak_7643(self):
for i in range(0x10000):
lines = (chr(i) + 'A').splitlines()
if i in (0x0a, 0x0b, 0x0c, 0x0d, 0x85,
0x1c, 0x1d, 0x1e, 0x2028, 0x2029):
for c in iterallchars():
lines = (c + 'A').splitlines()
if c in ('\x0a', '\x0b', '\x0c', '\x0d', '\x85',
'\x1c', '\x1d', '\x1e', '\u2028', '\u2029'):
self.assertEqual(len(lines), 2,
r"\u%.4x should be a linebreak" % i)
r"%a should be a linebreak" % c)
else:
self.assertEqual(len(lines), 1,
r"\u%.4x should not be a linebreak" % i)
r"%a should not be a linebreak" % c)
class NormalizationTest(unittest.TestCase):
@staticmethod
@@ -405,23 +823,24 @@ class NormalizationTest(unittest.TestCase):
self.skipTest(f"Failed to download {TESTDATAURL}: {exc}")
with testdata:
self.run_normalization_tests(testdata)
self.run_normalization_tests(testdata, unicodedata)
def run_normalization_tests(self, testdata):
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: False is not true : 2F868;2136A;2136A;2136A;2136A
@requires_resource('cpu')
def test_normalization_3_2_0(self):
testdatafile = findfile('NormalizationTest-3.2.0.txt')
with open(testdatafile, encoding='utf-8') as testdata:
self.run_normalization_tests(testdata, unicodedata.ucd_3_2_0)
def run_normalization_tests(self, testdata, ucd):
part = None
part1_data = {}
part1_data = set()
def NFC(str):
return unicodedata.normalize("NFC", str)
def NFKC(str):
return unicodedata.normalize("NFKC", str)
def NFD(str):
return unicodedata.normalize("NFD", str)
def NFKD(str):
return unicodedata.normalize("NFKD", str)
NFC = partial(ucd.normalize, "NFC")
NFKC = partial(ucd.normalize, "NFKC")
NFD = partial(ucd.normalize, "NFD")
NFKD = partial(ucd.normalize, "NFKD")
is_normalized = ucd.is_normalized
for line in testdata:
if '#' in line:
@@ -446,25 +865,24 @@ class NormalizationTest(unittest.TestCase):
NFKD(c3) == NFKD(c4) == NFKD(c5),
line)
self.assertTrue(unicodedata.is_normalized("NFC", c2))
self.assertTrue(unicodedata.is_normalized("NFC", c4))
self.assertTrue(is_normalized("NFC", c2))
self.assertTrue(is_normalized("NFC", c4))
self.assertTrue(unicodedata.is_normalized("NFD", c3))
self.assertTrue(unicodedata.is_normalized("NFD", c5))
self.assertTrue(is_normalized("NFD", c3))
self.assertTrue(is_normalized("NFD", c5))
self.assertTrue(unicodedata.is_normalized("NFKC", c4))
self.assertTrue(unicodedata.is_normalized("NFKD", c5))
self.assertTrue(is_normalized("NFKC", c4))
self.assertTrue(is_normalized("NFKD", c5))
# Record part 1 data
if part == "@Part1":
part1_data[c1] = 1
part1_data.add(c1)
# Perform tests for all other data
for c in range(sys.maxunicode+1):
X = chr(c)
for X in iterallchars():
if X in part1_data:
continue
self.assertTrue(X == NFC(X) == NFD(X) == NFKC(X) == NFKD(X), c)
self.assertTrue(X == NFC(X) == NFD(X) == NFKC(X) == NFKD(X), ord(X))
def test_edge_cases(self):
self.assertRaises(TypeError, unicodedata.normalize)
+8 -1
View File
@@ -109,4 +109,11 @@ def expectedFailureIf(condition, reason):
# Even more useful because most of them are windows only.
def expectedFailureIfWindows(reason):
import sys
return expectedFailureIf(sys.platform == 'win32', reason)
return expectedFailureIf(sys.platform == 'win32', reason)
# XXX: RUSTPYTHON
# For a rare case when the parent class test fails but the child pass.
def expectedSuccess(test_item):
test_item.__unittest_expecting_failure__ = False
return test_item
+2 -1
View File
@@ -32,7 +32,7 @@ class UtMethod(enum.StrEnum):
return name[0].lower() + name[1:]
def has_args(self) -> bool:
return self != self.ExpectedFailure
return self not in (self.ExpectedFailure, self.ExpectedSuccess)
def has_cond(self) -> bool:
return self.endswith(("If", "Unless"))
@@ -40,6 +40,7 @@ class UtMethod(enum.StrEnum):
ExpectedFailure = enum.auto()
ExpectedFailureIf = enum.auto()
ExpectedFailureIfWindows = enum.auto()
ExpectedSuccess = enum.auto()
Skip = enum.auto()
SkipIf = enum.auto()
SkipUnless = enum.auto()