]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-110944: Move pty helper to test.support and add basic pdb completion test (GH...
authorTian Gao <gaogaotiantian@hotmail.com>
Mon, 13 Nov 2023 10:23:06 +0000 (02:23 -0800)
committerGitHub <noreply@github.com>
Mon, 13 Nov 2023 10:23:06 +0000 (11:23 +0100)
Lib/test/support/pty_helper.py [new file with mode: 0644]
Lib/test/test_pdb.py
Lib/test/test_readline.py

diff --git a/Lib/test/support/pty_helper.py b/Lib/test/support/pty_helper.py
new file mode 100644 (file)
index 0000000..11037d2
--- /dev/null
@@ -0,0 +1,60 @@
+"""
+Helper to run a script in a pseudo-terminal.
+"""
+import os
+import selectors
+import subprocess
+import sys
+from contextlib import ExitStack
+from errno import EIO
+
+from test.support.import_helper import import_module
+
+def run_pty(script, input=b"dummy input\r", env=None):
+    pty = import_module('pty')
+    output = bytearray()
+    [master, slave] = pty.openpty()
+    args = (sys.executable, '-c', script)
+    proc = subprocess.Popen(args, stdin=slave, stdout=slave, stderr=slave, env=env)
+    os.close(slave)
+    with ExitStack() as cleanup:
+        cleanup.enter_context(proc)
+        def terminate(proc):
+            try:
+                proc.terminate()
+            except ProcessLookupError:
+                # Workaround for Open/Net BSD bug (Issue 16762)
+                pass
+        cleanup.callback(terminate, proc)
+        cleanup.callback(os.close, master)
+        # Avoid using DefaultSelector and PollSelector. Kqueue() does not
+        # work with pseudo-terminals on OS X < 10.9 (Issue 20365) and Open
+        # BSD (Issue 20667). Poll() does not work with OS X 10.6 or 10.4
+        # either (Issue 20472). Hopefully the file descriptor is low enough
+        # to use with select().
+        sel = cleanup.enter_context(selectors.SelectSelector())
+        sel.register(master, selectors.EVENT_READ | selectors.EVENT_WRITE)
+        os.set_blocking(master, False)
+        while True:
+            for [_, events] in sel.select():
+                if events & selectors.EVENT_READ:
+                    try:
+                        chunk = os.read(master, 0x10000)
+                    except OSError as err:
+                        # Linux raises EIO when slave is closed (Issue 5380)
+                        if err.errno != EIO:
+                            raise
+                        chunk = b""
+                    if not chunk:
+                        return output
+                    output.extend(chunk)
+                if events & selectors.EVENT_WRITE:
+                    try:
+                        input = input[os.write(master, input):]
+                    except OSError as err:
+                        # Apparently EIO means the slave was closed
+                        if err.errno != EIO:
+                            raise
+                        input = b""  # Stop writing
+                    if not input:
+                        sel.modify(master, selectors.EVENT_READ)
index 7cd5ae3cc824436231f5500e8cbd9755fbf4f3f6..2ec4e2ee0e036016b1e7ac54a0c8c4c3b3fa9d12 100644 (file)
@@ -15,6 +15,8 @@ from contextlib import ExitStack, redirect_stdout
 from io import StringIO
 from test import support
 from test.support import os_helper
+from test.support.import_helper import import_module
+from test.support.pty_helper import run_pty
 # This little helper class is essential for testing pdb under doctest.
 from test.test_doctest import _FakeInput
 from unittest.mock import patch
@@ -3260,6 +3262,34 @@ class ChecklineTests(unittest.TestCase):
                 self.assertFalse(db.checkline(os_helper.TESTFN, lineno))
 
 
+@support.requires_subprocess()
+class PdbTestReadline(unittest.TestCase):
+    def setUpClass():
+        # Ensure that the readline module is loaded
+        # If this fails, the test is skipped because SkipTest will be raised
+        readline = import_module('readline')
+        if readline.__doc__ and "libedit" in readline.__doc__:
+            raise unittest.SkipTest("libedit readline is not supported for pdb")
+
+    def test_basic_completion(self):
+        script = textwrap.dedent("""
+            import pdb; pdb.Pdb().set_trace()
+            # Concatenate strings so that the output doesn't appear in the source
+            print('hello' + '!')
+        """)
+
+        # List everything starting with 'co', there should be multiple matches
+        # then add ntin and complete 'contin' to 'continue'
+        input = b"co\t\tntin\t\n"
+
+        output = run_pty(script, input)
+
+        self.assertIn(b'commands', output)
+        self.assertIn(b'condition', output)
+        self.assertIn(b'continue', output)
+        self.assertIn(b'hello!', output)
+
+
 def load_tests(loader, tests, pattern):
     from test import test_pdb
     tests.addTest(doctest.DocTestSuite(test_pdb))
index 59dbef903800530e2b91f904a951174b249cda4d..835280f2281cde69f848b9800a04ae5c1db2cf03 100644 (file)
@@ -1,18 +1,15 @@
 """
 Very minimal unittests for parts of the readline module.
 """
-from contextlib import ExitStack
-from errno import EIO
 import locale
 import os
-import selectors
-import subprocess
 import sys
 import tempfile
 import unittest
 from test.support import verbose
 from test.support.import_helper import import_module
 from test.support.os_helper import unlink, temp_dir, TESTFN
+from test.support.pty_helper import run_pty
 from test.support.script_helper import assert_python_ok
 
 # Skip tests if there is no readline module
@@ -304,55 +301,5 @@ readline.write_history_file(history_file)
             self.assertEqual(lines[-1].strip(), b"last input")
 
 
-def run_pty(script, input=b"dummy input\r", env=None):
-    pty = import_module('pty')
-    output = bytearray()
-    [master, slave] = pty.openpty()
-    args = (sys.executable, '-c', script)
-    proc = subprocess.Popen(args, stdin=slave, stdout=slave, stderr=slave, env=env)
-    os.close(slave)
-    with ExitStack() as cleanup:
-        cleanup.enter_context(proc)
-        def terminate(proc):
-            try:
-                proc.terminate()
-            except ProcessLookupError:
-                # Workaround for Open/Net BSD bug (Issue 16762)
-                pass
-        cleanup.callback(terminate, proc)
-        cleanup.callback(os.close, master)
-        # Avoid using DefaultSelector and PollSelector. Kqueue() does not
-        # work with pseudo-terminals on OS X < 10.9 (Issue 20365) and Open
-        # BSD (Issue 20667). Poll() does not work with OS X 10.6 or 10.4
-        # either (Issue 20472). Hopefully the file descriptor is low enough
-        # to use with select().
-        sel = cleanup.enter_context(selectors.SelectSelector())
-        sel.register(master, selectors.EVENT_READ | selectors.EVENT_WRITE)
-        os.set_blocking(master, False)
-        while True:
-            for [_, events] in sel.select():
-                if events & selectors.EVENT_READ:
-                    try:
-                        chunk = os.read(master, 0x10000)
-                    except OSError as err:
-                        # Linux raises EIO when slave is closed (Issue 5380)
-                        if err.errno != EIO:
-                            raise
-                        chunk = b""
-                    if not chunk:
-                        return output
-                    output.extend(chunk)
-                if events & selectors.EVENT_WRITE:
-                    try:
-                        input = input[os.write(master, input):]
-                    except OSError as err:
-                        # Apparently EIO means the slave was closed
-                        if err.errno != EIO:
-                            raise
-                        input = b""  # Stop writing
-                    if not input:
-                        sel.modify(master, selectors.EVENT_READ)
-
-
 if __name__ == "__main__":
     unittest.main()