From 1f3af03f83fead5cd86d54e1b2f47fc5866e635c Mon Sep 17 00:00:00 2001 From: AN Long Date: Fri, 6 Oct 2023 01:52:26 +0800 Subject: gh-110147: test_msvcrt: run console I/O tests in new processes (#110268) --- Lib/test/test_msvcrt.py | 49 +++++++++++++++++++------------- PC/_testconsole.c | 19 ------------- PC/clinic/_testconsole.c.h | 70 +--------------------------------------------- 3 files changed, 31 insertions(+), 107 deletions(-) diff --git a/Lib/test/test_msvcrt.py b/Lib/test/test_msvcrt.py index 81ec130..600c444 100644 --- a/Lib/test/test_msvcrt.py +++ b/Lib/test/test_msvcrt.py @@ -1,17 +1,17 @@ import os +import subprocess import sys import unittest +from textwrap import dedent -from test.support import os_helper +from test.support import os_helper, requires_resource from test.support.os_helper import TESTFN, TESTFN_ASCII if sys.platform != "win32": raise unittest.SkipTest("windows related tests") import _winapi -import msvcrt; - -from _testconsole import write_input, flush_console_input_buffer +import msvcrt class TestFileOperations(unittest.TestCase): @@ -61,34 +61,45 @@ c_encoded = b'\x57\x5b' # utf-16-le (which windows internally used) encoded char class TestConsoleIO(unittest.TestCase): + # CREATE_NEW_CONSOLE creates a "popup" window. + @requires_resource('gui') + def run_in_separated_process(self, code): + # Run test in a seprated process to avoid stdin conflicts. + # See: gh-110147 + cmd = [sys.executable, '-c', code] + subprocess.run(cmd, check=True, capture_output=True, + creationflags=subprocess.CREATE_NEW_CONSOLE) + def test_kbhit(self): - h = msvcrt.get_osfhandle(sys.stdin.fileno()) - flush_console_input_buffer(h) - self.assertEqual(msvcrt.kbhit(), 0) + code = dedent(''' + import msvcrt + assert msvcrt.kbhit() == 0 + ''') + self.run_in_separated_process(code) def test_getch(self): msvcrt.ungetch(b'c') self.assertEqual(msvcrt.getch(), b'c') - def test_getwch(self): - with open('CONIN$', 'rb', buffering=0) as stdin: - h = msvcrt.get_osfhandle(stdin.fileno()) - flush_console_input_buffer(h) + def check_getwch(self, funcname): + code = dedent(f''' + import msvcrt + from _testconsole import write_input + with open("CONIN$", "rb", buffering=0) as stdin: + write_input(stdin, {ascii(c_encoded)}) + assert msvcrt.{funcname}() == "{c}" + ''') + self.run_in_separated_process(code) - write_input(stdin, c_encoded) - self.assertEqual(msvcrt.getwch(), c) + def test_getwch(self): + self.check_getwch('getwch') def test_getche(self): msvcrt.ungetch(b'c') self.assertEqual(msvcrt.getche(), b'c') def test_getwche(self): - with open('CONIN$', 'rb', buffering=0) as stdin: - h = msvcrt.get_osfhandle(stdin.fileno()) - flush_console_input_buffer(h) - - write_input(stdin, c_encoded) - self.assertEqual(msvcrt.getwche(), c) + self.check_getwch('getwche') def test_putch(self): msvcrt.putch(b'c') diff --git a/PC/_testconsole.c b/PC/_testconsole.c index 5e5a771..1dc0d23 100644 --- a/PC/_testconsole.c +++ b/PC/_testconsole.c @@ -133,31 +133,12 @@ _testconsole_read_output_impl(PyObject *module, PyObject *file) Py_RETURN_NONE; } -/*[clinic input] -_testconsole.flush_console_input_buffer - handle: HANDLE - -Flushes the console input buffer. - -All input records currently in the input buffer are discarded. -[clinic start generated code]*/ - -static PyObject * -_testconsole_flush_console_input_buffer_impl(PyObject *module, void *handle) -/*[clinic end generated code: output=1f923a81331465ce input=be8203ae84a288f5]*/ -/*[clinic end generated code:]*/ -{ - FlushConsoleInputBuffer(handle); - - Py_RETURN_NONE; -} #include "clinic\_testconsole.c.h" PyMethodDef testconsole_methods[] = { _TESTCONSOLE_WRITE_INPUT_METHODDEF _TESTCONSOLE_READ_OUTPUT_METHODDEF - _TESTCONSOLE_FLUSH_CONSOLE_INPUT_BUFFER_METHODDEF {NULL, NULL} }; diff --git a/PC/clinic/_testconsole.c.h b/PC/clinic/_testconsole.c.h index b765889..99cd302 100644 --- a/PC/clinic/_testconsole.c.h +++ b/PC/clinic/_testconsole.c.h @@ -132,70 +132,6 @@ exit: #endif /* defined(MS_WINDOWS) */ -#if defined(MS_WINDOWS) - -PyDoc_STRVAR(_testconsole_flush_console_input_buffer__doc__, -"flush_console_input_buffer($module, /, handle)\n" -"--\n" -"\n" -"Flushes the console input buffer.\n" -"\n" -"All input records currently in the input buffer are discarded."); - -#define _TESTCONSOLE_FLUSH_CONSOLE_INPUT_BUFFER_METHODDEF \ - {"flush_console_input_buffer", _PyCFunction_CAST(_testconsole_flush_console_input_buffer), METH_FASTCALL|METH_KEYWORDS, _testconsole_flush_console_input_buffer__doc__}, - -static PyObject * -_testconsole_flush_console_input_buffer_impl(PyObject *module, void *handle); - -static PyObject * -_testconsole_flush_console_input_buffer(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -{ - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 1 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(handle), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - - static const char * const _keywords[] = {"handle", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "flush_console_input_buffer", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[1]; - void *handle; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); - if (!args) { - goto exit; - } - handle = PyLong_AsVoidPtr(args[0]); - if (!handle && PyErr_Occurred()) { - goto exit; - } - return_value = _testconsole_flush_console_input_buffer_impl(module, handle); - -exit: - return return_value; -} - -#endif /* defined(MS_WINDOWS) */ - #ifndef _TESTCONSOLE_WRITE_INPUT_METHODDEF #define _TESTCONSOLE_WRITE_INPUT_METHODDEF #endif /* !defined(_TESTCONSOLE_WRITE_INPUT_METHODDEF) */ @@ -203,8 +139,4 @@ exit: #ifndef _TESTCONSOLE_READ_OUTPUT_METHODDEF #define _TESTCONSOLE_READ_OUTPUT_METHODDEF #endif /* !defined(_TESTCONSOLE_READ_OUTPUT_METHODDEF) */ - -#ifndef _TESTCONSOLE_FLUSH_CONSOLE_INPUT_BUFFER_METHODDEF - #define _TESTCONSOLE_FLUSH_CONSOLE_INPUT_BUFFER_METHODDEF -#endif /* !defined(_TESTCONSOLE_FLUSH_CONSOLE_INPUT_BUFFER_METHODDEF) */ -/*[clinic end generated code: output=5d488564f2500dd9 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=f59fe72cd4e73704 input=a9049054013a1b77]*/ -- cgit v0.12