diff options
author | Bénédikt Tran <10796600+picnixz@users.noreply.github.com> | 2024-12-17 11:12:45 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-12-17 11:12:45 (GMT) |
commit | 7303f06846b69016a075bca7ad7c6055f29ad024 (patch) | |
tree | fa3abb9f0a3b3b18bbd60590cbfb1c3c6a91d70f /Lib/test | |
parent | b9a492b809d8765ee365a5dd3c6ba4e5130a80af (diff) | |
download | cpython-7303f06846b69016a075bca7ad7c6055f29ad024.zip cpython-7303f06846b69016a075bca7ad7c6055f29ad024.tar.gz cpython-7303f06846b69016a075bca7ad7c6055f29ad024.tar.bz2 |
gh-126742: Add _PyErr_SetLocaleString, use it for gdbm & dlerror messages (GH-126746)
- Add a helper to set an error from locale-encoded `char*`
- Use the helper for gdbm & dlerror messages
Co-authored-by: Victor Stinner <vstinner@python.org>
Diffstat (limited to 'Lib/test')
-rw-r--r-- | Lib/test/test_ctypes/test_dlerror.py | 80 | ||||
-rw-r--r-- | Lib/test/test_dbm_gnu.py | 21 |
2 files changed, 86 insertions, 15 deletions
diff --git a/Lib/test/test_ctypes/test_dlerror.py b/Lib/test/test_ctypes/test_dlerror.py index 4441e30..c3c34d4 100644 --- a/Lib/test/test_ctypes/test_dlerror.py +++ b/Lib/test/test_ctypes/test_dlerror.py @@ -1,7 +1,12 @@ +import _ctypes import os +import platform import sys +import test.support import unittest -import platform +from ctypes import CDLL, c_int +from ctypes.util import find_library + FOO_C = r""" #include <unistd.h> @@ -26,7 +31,7 @@ void *foo(void) @unittest.skipUnless(sys.platform.startswith('linux'), - 'Test only valid for Linux') + 'test requires GNU IFUNC support') class TestNullDlsym(unittest.TestCase): """GH-126554: Ensure that we catch NULL dlsym return values @@ -53,14 +58,6 @@ class TestNullDlsym(unittest.TestCase): import subprocess import tempfile - # To avoid ImportErrors on Windows, where _ctypes does not have - # dlopen and dlsym, - # import here, i.e., inside the test function. - # The skipUnless('linux') decorator ensures that we're on linux - # if we're executing these statements. - from ctypes import CDLL, c_int - from _ctypes import dlopen, dlsym - retcode = subprocess.call(["gcc", "--version"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) @@ -111,6 +108,8 @@ class TestNullDlsym(unittest.TestCase): self.assertEqual(os.read(pipe_r, 2), b'OK') # Case #3: Test 'py_dl_sym' from Modules/_ctypes/callproc.c + dlopen = test.support.get_attribute(_ctypes, 'dlopen') + dlsym = test.support.get_attribute(_ctypes, 'dlsym') L = dlopen(dstname) with self.assertRaisesRegex(OSError, "symbol 'foo' not found"): dlsym(L, "foo") @@ -119,5 +118,66 @@ class TestNullDlsym(unittest.TestCase): self.assertEqual(os.read(pipe_r, 2), b'OK') +@unittest.skipUnless(os.name != 'nt', 'test requires dlerror() calls') +class TestLocalization(unittest.TestCase): + + @staticmethod + def configure_locales(func): + return test.support.run_with_locale( + 'LC_ALL', + 'fr_FR.iso88591', 'ja_JP.sjis', 'zh_CN.gbk', + 'fr_FR.utf8', 'en_US.utf8', + '', + )(func) + + @classmethod + def setUpClass(cls): + cls.libc_filename = find_library("c") + + @configure_locales + def test_localized_error_from_dll(self): + dll = CDLL(self.libc_filename) + with self.assertRaises(AttributeError) as cm: + dll.this_name_does_not_exist + if sys.platform.startswith('linux'): + # On macOS, the filename is not reported by dlerror(). + self.assertIn(self.libc_filename, str(cm.exception)) + + @configure_locales + def test_localized_error_in_dll(self): + dll = CDLL(self.libc_filename) + with self.assertRaises(ValueError) as cm: + c_int.in_dll(dll, 'this_name_does_not_exist') + if sys.platform.startswith('linux'): + # On macOS, the filename is not reported by dlerror(). + self.assertIn(self.libc_filename, str(cm.exception)) + + @unittest.skipUnless(hasattr(_ctypes, 'dlopen'), + 'test requires _ctypes.dlopen()') + @configure_locales + def test_localized_error_dlopen(self): + missing_filename = b'missing\xff.so' + # Depending whether the locale, we may encode '\xff' differently + # but we are only interested in avoiding a UnicodeDecodeError + # when reporting the dlerror() error message which contains + # the localized filename. + filename_pattern = r'missing.*?\.so' + with self.assertRaisesRegex(OSError, filename_pattern): + _ctypes.dlopen(missing_filename, 2) + + @unittest.skipUnless(hasattr(_ctypes, 'dlopen'), + 'test requires _ctypes.dlopen()') + @unittest.skipUnless(hasattr(_ctypes, 'dlsym'), + 'test requires _ctypes.dlsym()') + @configure_locales + def test_localized_error_dlsym(self): + dll = _ctypes.dlopen(self.libc_filename) + with self.assertRaises(OSError) as cm: + _ctypes.dlsym(dll, 'this_name_does_not_exist') + if sys.platform.startswith('linux'): + # On macOS, the filename is not reported by dlerror(). + self.assertIn(self.libc_filename, str(cm.exception)) + + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_dbm_gnu.py b/Lib/test/test_dbm_gnu.py index e20addf..66268c4 100644 --- a/Lib/test/test_dbm_gnu.py +++ b/Lib/test/test_dbm_gnu.py @@ -1,10 +1,11 @@ -from test import support -from test.support import import_helper, cpython_only -gdbm = import_helper.import_module("dbm.gnu") #skip if not supported -import unittest import os -from test.support.os_helper import TESTFN, TESTFN_NONASCII, unlink, FakePath +import unittest +from test import support +from test.support import cpython_only, import_helper +from test.support.os_helper import (TESTFN, TESTFN_NONASCII, FakePath, + create_empty_file, temp_dir, unlink) +gdbm = import_helper.import_module("dbm.gnu") # skip if not supported filename = TESTFN @@ -205,6 +206,16 @@ class TestGdbm(unittest.TestCase): self.assertNotIn(k, db) self.assertEqual(len(db), 0) + @support.run_with_locale( + 'LC_ALL', + 'fr_FR.iso88591', 'ja_JP.sjis', 'zh_CN.gbk', + 'fr_FR.utf8', 'en_US.utf8', + '', + ) + def test_localized_error(self): + with temp_dir() as d: + create_empty_file(os.path.join(d, 'test')) + self.assertRaises(gdbm.error, gdbm.open, filename, 'r') if __name__ == '__main__': |