diff options
author | Serhiy Storchaka <storchaka@gmail.com> | 2018-08-06 17:34:46 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-08-06 17:34:46 +0300 |
commit | 278d975ce158608f6be491c561247d4701c842be (patch) | |
tree | bfd564e6124df2cd9e2f63f76fa0c6fa8fdc3602 /Lib | |
parent | bpo-34273: Change 'Fixed point' to 'Fixed-point notation'. (GH-8673) (diff) | |
download | cpython-278d975ce158608f6be491c561247d4701c842be.tar.gz cpython-278d975ce158608f6be491c561247d4701c842be.tar.bz2 cpython-278d975ce158608f6be491c561247d4701c842be.zip |
[3.6] bpo-34272: Move argument parsing tests from test_capi to test_getargs2. (GH-8567). (GH-8690)
(cherry picked from commit 8f7bb100d0fa7fb2714f3953b5b627878277c7c6)
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/test/test_capi.py | 293 | ||||
-rw-r--r-- | Lib/test/test_getargs2.py | 180 |
2 files changed, 182 insertions, 291 deletions
diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py index 2725333e7e9..ae3bcb92057 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -5,7 +5,6 @@ import os import pickle import random import re -import string import subprocess import sys import sysconfig @@ -373,289 +372,6 @@ class SubinterpreterTest(unittest.TestCase): self.assertNotEqual(pickle.load(f), id(builtins)) -# Bug #6012 -class Test6012(unittest.TestCase): - def test(self): - self.assertEqual(_testcapi.argparsing("Hello", "World"), 1) - - -class EmbeddingTests(unittest.TestCase): - def setUp(self): - here = os.path.abspath(__file__) - basepath = os.path.dirname(os.path.dirname(os.path.dirname(here))) - exename = "_testembed" - if sys.platform.startswith("win"): - ext = ("_d" if "_d" in sys.executable else "") + ".exe" - exename += ext - exepath = os.path.dirname(sys.executable) - else: - exepath = os.path.join(basepath, "Programs") - self.test_exe = exe = os.path.join(exepath, exename) - if not os.path.exists(exe): - self.skipTest("%r doesn't exist" % exe) - # This is needed otherwise we get a fatal error: - # "Py_Initialize: Unable to get the locale encoding - # LookupError: no codec search functions registered: can't find encoding" - self.oldcwd = os.getcwd() - os.chdir(basepath) - - def tearDown(self): - os.chdir(self.oldcwd) - - def run_embedded_interpreter(self, *args, env=None): - """Runs a test in the embedded interpreter""" - cmd = [self.test_exe] - cmd.extend(args) - if env is not None and sys.platform == 'win32': - # Windows requires at least the SYSTEMROOT environment variable to - # start Python. - env = env.copy() - env['SYSTEMROOT'] = os.environ['SYSTEMROOT'] - - p = subprocess.Popen(cmd, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - universal_newlines=True, - env=env) - (out, err) = p.communicate() - self.assertEqual(p.returncode, 0, - "bad returncode %d, stderr is %r" % - (p.returncode, err)) - return out, err - - def test_repeated_init_and_subinterpreters(self): - # This is just a "don't crash" test - out, err = self.run_embedded_interpreter('repeated_init_and_subinterpreters') - if support.verbose: - print() - print(out) - print(err) - - @staticmethod - def _get_default_pipe_encoding(): - rp, wp = os.pipe() - try: - with os.fdopen(wp, 'w') as w: - default_pipe_encoding = w.encoding - finally: - os.close(rp) - return default_pipe_encoding - - def test_forced_io_encoding(self): - # Checks forced configuration of embedded interpreter IO streams - env = dict(os.environ, PYTHONIOENCODING="utf-8:surrogateescape") - out, err = self.run_embedded_interpreter("forced_io_encoding", env=env) - if support.verbose: - print() - print(out) - print(err) - expected_stream_encoding = "utf-8" - expected_errors = "surrogateescape" - expected_pipe_encoding = self._get_default_pipe_encoding() - expected_output = '\n'.join([ - "--- Use defaults ---", - "Expected encoding: default", - "Expected errors: default", - "stdin: {in_encoding}:{errors}", - "stdout: {out_encoding}:{errors}", - "stderr: {out_encoding}:backslashreplace", - "--- Set errors only ---", - "Expected encoding: default", - "Expected errors: ignore", - "stdin: {in_encoding}:ignore", - "stdout: {out_encoding}:ignore", - "stderr: {out_encoding}:backslashreplace", - "--- Set encoding only ---", - "Expected encoding: latin-1", - "Expected errors: default", - "stdin: latin-1:{errors}", - "stdout: latin-1:{errors}", - "stderr: latin-1:backslashreplace", - "--- Set encoding and errors ---", - "Expected encoding: latin-1", - "Expected errors: replace", - "stdin: latin-1:replace", - "stdout: latin-1:replace", - "stderr: latin-1:backslashreplace"]) - expected_output = expected_output.format( - in_encoding=expected_stream_encoding, - out_encoding=expected_stream_encoding, - errors=expected_errors) - # This is useful if we ever trip over odd platform behaviour - self.maxDiff = None - self.assertEqual(out.strip(), expected_output) - - def test_pre_initialization_api(self): - """ - Checks the few parts of the C-API that work before the runtine - is initialized (via Py_Initialize()). - """ - env = dict(os.environ, PYTHONPATH=os.pathsep.join(sys.path)) - out, err = self.run_embedded_interpreter("pre_initialization_api", env=env) - self.assertEqual(out, '') - self.assertEqual(err, '') - - -class SkipitemTest(unittest.TestCase): - - def test_skipitem(self): - """ - If this test failed, you probably added a new "format unit" - in Python/getargs.c, but neglected to update our poor friend - skipitem() in the same file. (If so, shame on you!) - - With a few exceptions**, this function brute-force tests all - printable ASCII*** characters (32 to 126 inclusive) as format units, - checking to see that PyArg_ParseTupleAndKeywords() return consistent - errors both when the unit is attempted to be used and when it is - skipped. If the format unit doesn't exist, we'll get one of two - specific error messages (one for used, one for skipped); if it does - exist we *won't* get that error--we'll get either no error or some - other error. If we get the specific "does not exist" error for one - test and not for the other, there's a mismatch, and the test fails. - - ** Some format units have special funny semantics and it would - be difficult to accommodate them here. Since these are all - well-established and properly skipped in skipitem() we can - get away with not testing them--this test is really intended - to catch *new* format units. - - *** Python C source files must be ASCII. Therefore it's impossible - to have non-ASCII format units. - - """ - empty_tuple = () - tuple_1 = (0,) - dict_b = {'b':1} - keywords = ["a", "b"] - - for i in range(32, 127): - c = chr(i) - - # skip parentheses, the error reporting is inconsistent about them - # skip 'e', it's always a two-character code - # skip '|' and '$', they don't represent arguments anyway - if c in '()e|$': - continue - - # test the format unit when not skipped - format = c + "i" - try: - _testcapi.parse_tuple_and_keywords(tuple_1, dict_b, - format, keywords) - when_not_skipped = False - except SystemError as e: - s = "argument 1 (impossible<bad format char>)" - when_not_skipped = (str(e) == s) - except TypeError: - when_not_skipped = False - - # test the format unit when skipped - optional_format = "|" + format - try: - _testcapi.parse_tuple_and_keywords(empty_tuple, dict_b, - optional_format, keywords) - when_skipped = False - except SystemError as e: - s = "impossible<bad format char>: '{}'".format(format) - when_skipped = (str(e) == s) - - message = ("test_skipitem_parity: " - "detected mismatch between convertsimple and skipitem " - "for format unit '{}' ({}), not skipped {}, skipped {}".format( - c, i, when_skipped, when_not_skipped)) - self.assertIs(when_skipped, when_not_skipped, message) - - def test_skipitem_with_suffix(self): - parse = _testcapi.parse_tuple_and_keywords - empty_tuple = () - tuple_1 = (0,) - dict_b = {'b':1} - keywords = ["a", "b"] - - supported = ('s#', 's*', 'z#', 'z*', 'u#', 'Z#', 'y#', 'y*', 'w#', 'w*') - for c in string.ascii_letters: - for c2 in '#*': - f = c + c2 - with self.subTest(format=f): - optional_format = "|" + f + "i" - if f in supported: - parse(empty_tuple, dict_b, optional_format, keywords) - else: - with self.assertRaisesRegex(SystemError, - 'impossible<bad format char>'): - parse(empty_tuple, dict_b, optional_format, keywords) - - for c in map(chr, range(32, 128)): - f = 'e' + c - optional_format = "|" + f + "i" - with self.subTest(format=f): - if c in 'st': - parse(empty_tuple, dict_b, optional_format, keywords) - else: - with self.assertRaisesRegex(SystemError, - 'impossible<bad format char>'): - parse(empty_tuple, dict_b, optional_format, keywords) - - def test_parse_tuple_and_keywords(self): - # Test handling errors in the parse_tuple_and_keywords helper itself - self.assertRaises(TypeError, _testcapi.parse_tuple_and_keywords, - (), {}, 42, []) - self.assertRaises(ValueError, _testcapi.parse_tuple_and_keywords, - (), {}, '', 42) - self.assertRaises(ValueError, _testcapi.parse_tuple_and_keywords, - (), {}, '', [''] * 42) - self.assertRaises(ValueError, _testcapi.parse_tuple_and_keywords, - (), {}, '', [42]) - - def test_bad_use(self): - # Test handling invalid format and keywords in - # PyArg_ParseTupleAndKeywords() - self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords, - (1,), {}, '||O', ['a']) - self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords, - (1, 2), {}, '|O|O', ['a', 'b']) - self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords, - (), {'a': 1}, '$$O', ['a']) - self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords, - (), {'a': 1, 'b': 2}, '$O$O', ['a', 'b']) - self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords, - (), {'a': 1}, '$|O', ['a']) - self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords, - (), {'a': 1, 'b': 2}, '$O|O', ['a', 'b']) - self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords, - (1,), {}, '|O', ['a', 'b']) - self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords, - (1,), {}, '|OO', ['a']) - self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords, - (), {}, '|$O', ['']) - self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords, - (), {}, '|OO', ['a', '']) - - def test_positional_only(self): - parse = _testcapi.parse_tuple_and_keywords - - parse((1, 2, 3), {}, 'OOO', ['', '', 'a']) - parse((1, 2), {'a': 3}, 'OOO', ['', '', 'a']) - with self.assertRaisesRegex(TypeError, - r'Function takes at least 2 positional arguments \(1 given\)'): - parse((1,), {'a': 3}, 'OOO', ['', '', 'a']) - parse((1,), {}, 'O|OO', ['', '', 'a']) - with self.assertRaisesRegex(TypeError, - r'Function takes at least 1 positional arguments \(0 given\)'): - parse((), {}, 'O|OO', ['', '', 'a']) - parse((1, 2), {'a': 3}, 'OO$O', ['', '', 'a']) - with self.assertRaisesRegex(TypeError, - r'Function takes exactly 2 positional arguments \(1 given\)'): - parse((1,), {'a': 3}, 'OO$O', ['', '', 'a']) - parse((1,), {}, 'O|O$O', ['', '', 'a']) - with self.assertRaisesRegex(TypeError, - r'Function takes at least 1 positional arguments \(0 given\)'): - parse((), {}, 'O|O$O', ['', '', 'a']) - with self.assertRaisesRegex(SystemError, r'Empty parameter name after \$'): - parse((1,), {}, 'O|$OO', ['', '', 'a']) - with self.assertRaisesRegex(SystemError, 'Empty keyword'): - parse((1,), {}, 'O|OO', ['', 'a', '']) @unittest.skipUnless(threading, 'Threading required for this test.') @@ -684,12 +400,9 @@ class TestThreadState(unittest.TestCase): class Test_testcapi(unittest.TestCase): - def test__testcapi(self): - for name in dir(_testcapi): - if name.startswith('test_'): - with self.subTest("internal", name=name): - test = getattr(_testcapi, name) - test() + locals().update((name, getattr(_testcapi, name)) + for name in dir(_testcapi) + if name.startswith('test_') and not name.endswith('_code')) class PyMemDebugTests(unittest.TestCase): diff --git a/Lib/test/test_getargs2.py b/Lib/test/test_getargs2.py index d14a6ee31fd..cdc4cbf7199 100644 --- a/Lib/test/test_getargs2.py +++ b/Lib/test/test_getargs2.py @@ -1,9 +1,10 @@ import unittest import math +import string import sys from test import support # Skip this test if the _testcapi module isn't available. -support.import_module('_testcapi') +_testcapi = support.import_module('_testcapi') from _testcapi import getargs_keywords, getargs_keyword_only # > How about the following counterproposal. This also changes some of @@ -954,5 +955,182 @@ class Object_TestCase(unittest.TestCase): self.assertRaises(TypeError, getargs_U, None) +# Bug #6012 +class Test6012(unittest.TestCase): + def test(self): + self.assertEqual(_testcapi.argparsing("Hello", "World"), 1) + + +class SkipitemTest(unittest.TestCase): + + def test_skipitem(self): + """ + If this test failed, you probably added a new "format unit" + in Python/getargs.c, but neglected to update our poor friend + skipitem() in the same file. (If so, shame on you!) + + With a few exceptions**, this function brute-force tests all + printable ASCII*** characters (32 to 126 inclusive) as format units, + checking to see that PyArg_ParseTupleAndKeywords() return consistent + errors both when the unit is attempted to be used and when it is + skipped. If the format unit doesn't exist, we'll get one of two + specific error messages (one for used, one for skipped); if it does + exist we *won't* get that error--we'll get either no error or some + other error. If we get the specific "does not exist" error for one + test and not for the other, there's a mismatch, and the test fails. + + ** Some format units have special funny semantics and it would + be difficult to accommodate them here. Since these are all + well-established and properly skipped in skipitem() we can + get away with not testing them--this test is really intended + to catch *new* format units. + + *** Python C source files must be ASCII. Therefore it's impossible + to have non-ASCII format units. + + """ + empty_tuple = () + tuple_1 = (0,) + dict_b = {'b':1} + keywords = ["a", "b"] + + for i in range(32, 127): + c = chr(i) + + # skip parentheses, the error reporting is inconsistent about them + # skip 'e', it's always a two-character code + # skip '|' and '$', they don't represent arguments anyway + if c in '()e|$': + continue + + # test the format unit when not skipped + format = c + "i" + try: + _testcapi.parse_tuple_and_keywords(tuple_1, dict_b, + format, keywords) + when_not_skipped = False + except SystemError as e: + s = "argument 1 (impossible<bad format char>)" + when_not_skipped = (str(e) == s) + except TypeError: + when_not_skipped = False + + # test the format unit when skipped + optional_format = "|" + format + try: + _testcapi.parse_tuple_and_keywords(empty_tuple, dict_b, + optional_format, keywords) + when_skipped = False + except SystemError as e: + s = "impossible<bad format char>: '{}'".format(format) + when_skipped = (str(e) == s) + + message = ("test_skipitem_parity: " + "detected mismatch between convertsimple and skipitem " + "for format unit '{}' ({}), not skipped {}, skipped {}".format( + c, i, when_skipped, when_not_skipped)) + self.assertIs(when_skipped, when_not_skipped, message) + + def test_skipitem_with_suffix(self): + parse = _testcapi.parse_tuple_and_keywords + empty_tuple = () + tuple_1 = (0,) + dict_b = {'b':1} + keywords = ["a", "b"] + + supported = ('s#', 's*', 'z#', 'z*', 'u#', 'Z#', 'y#', 'y*', 'w#', 'w*') + for c in string.ascii_letters: + for c2 in '#*': + f = c + c2 + with self.subTest(format=f): + optional_format = "|" + f + "i" + if f in supported: + parse(empty_tuple, dict_b, optional_format, keywords) + else: + with self.assertRaisesRegex(SystemError, + 'impossible<bad format char>'): + parse(empty_tuple, dict_b, optional_format, keywords) + + for c in map(chr, range(32, 128)): + f = 'e' + c + optional_format = "|" + f + "i" + with self.subTest(format=f): + if c in 'st': + parse(empty_tuple, dict_b, optional_format, keywords) + else: + with self.assertRaisesRegex(SystemError, + 'impossible<bad format char>'): + parse(empty_tuple, dict_b, optional_format, keywords) + + +class ParseTupleAndKeywords_Test(unittest.TestCase): + + def test_parse_tuple_and_keywords(self): + # Test handling errors in the parse_tuple_and_keywords helper itself + self.assertRaises(TypeError, _testcapi.parse_tuple_and_keywords, + (), {}, 42, []) + self.assertRaises(ValueError, _testcapi.parse_tuple_and_keywords, + (), {}, '', 42) + self.assertRaises(ValueError, _testcapi.parse_tuple_and_keywords, + (), {}, '', [''] * 42) + self.assertRaises(ValueError, _testcapi.parse_tuple_and_keywords, + (), {}, '', [42]) + + def test_bad_use(self): + # Test handling invalid format and keywords in + # PyArg_ParseTupleAndKeywords() + self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords, + (1,), {}, '||O', ['a']) + self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords, + (1, 2), {}, '|O|O', ['a', 'b']) + self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords, + (), {'a': 1}, '$$O', ['a']) + self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords, + (), {'a': 1, 'b': 2}, '$O$O', ['a', 'b']) + self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords, + (), {'a': 1}, '$|O', ['a']) + self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords, + (), {'a': 1, 'b': 2}, '$O|O', ['a', 'b']) + self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords, + (1,), {}, '|O', ['a', 'b']) + self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords, + (1,), {}, '|OO', ['a']) + self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords, + (), {}, '|$O', ['']) + self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords, + (), {}, '|OO', ['a', '']) + + def test_positional_only(self): + parse = _testcapi.parse_tuple_and_keywords + + parse((1, 2, 3), {}, 'OOO', ['', '', 'a']) + parse((1, 2), {'a': 3}, 'OOO', ['', '', 'a']) + with self.assertRaisesRegex(TypeError, + r'Function takes at least 2 positional arguments \(1 given\)'): + parse((1,), {'a': 3}, 'OOO', ['', '', 'a']) + parse((1,), {}, 'O|OO', ['', '', 'a']) + with self.assertRaisesRegex(TypeError, + r'Function takes at least 1 positional arguments \(0 given\)'): + parse((), {}, 'O|OO', ['', '', 'a']) + parse((1, 2), {'a': 3}, 'OO$O', ['', '', 'a']) + with self.assertRaisesRegex(TypeError, + r'Function takes exactly 2 positional arguments \(1 given\)'): + parse((1,), {'a': 3}, 'OO$O', ['', '', 'a']) + parse((1,), {}, 'O|O$O', ['', '', 'a']) + with self.assertRaisesRegex(TypeError, + r'Function takes at least 1 positional arguments \(0 given\)'): + parse((), {}, 'O|O$O', ['', '', 'a']) + with self.assertRaisesRegex(SystemError, r'Empty parameter name after \$'): + parse((1,), {}, 'O|$OO', ['', '', 'a']) + with self.assertRaisesRegex(SystemError, 'Empty keyword'): + parse((1,), {}, 'O|OO', ['', 'a', '']) + + +class Test_testcapi(unittest.TestCase): + locals().update((name, getattr(_testcapi, name)) + for name in dir(_testcapi) + if name.startswith('test_') and name.endswith('_code')) + + if __name__ == "__main__": unittest.main() |