Skip to content

Commit 430944a

Browse files
da-vipergithub-actions[bot]
authored andcommitted
Automerge: [lldb-dap] Migrate DAP io tests. (#209538)
the launch_io* tests now allow testing args, input, and environment together. Previously, these test configurations were mutually exclusive. They are now combined, removing the need to create a separate test for each input source. Migrated Tests: - TestDAP_io.py - TestDAP_launch_io_integratedTerminal.py - TestDAP_launch_io_internalConsole.py
2 parents f2b015e + 047f127 commit 430944a

5 files changed

Lines changed: 166 additions & 236 deletions

File tree

lldb/test/API/tools/lldb-dap/io/TestDAP_io.py

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,20 @@
22
Test lldb-dap IO handling.
33
"""
44

5-
import sys
6-
7-
from lldbsuite.test.decorators import *
8-
import lldbdap_testcase
9-
import dap_server
5+
from lldbsuite.test.tools.lldb_dap import DAPTestCaseBase
106

117
EXIT_FAILURE = 1
128
EXIT_SUCCESS = 0
139

1410

15-
class TestDAP_io(lldbdap_testcase.DAPTestCaseBase):
11+
class TestDAP_io(DAPTestCaseBase):
1612
def launch(self):
17-
self.create_debug_adapter()
18-
self.assertIsNotNone(self.dap_server.process)
19-
process = self.dap_server.process
20-
21-
def cleanup():
22-
# If the process is still alive, kill it.
23-
if process.poll() is None:
24-
process.kill()
25-
process.wait()
26-
27-
# Execute the cleanup function during test case tear down.
28-
self.addTearDownHook(cleanup)
13+
adapter = self.create_stdio_debug_adapter()
14+
self.assertTrue(adapter.is_alive)
15+
self.assertIsNotNone(adapter.process)
2916

17+
process = adapter.process
18+
self.assertIsNotNone(process.stdin)
3019
return process
3120

3221
def test_eof_immediately(self):

lldb/test/API/tools/lldb-dap/launch/io/DAP_launch_io.py

Lines changed: 113 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -1,202 +1,172 @@
11
"""
22
Test the redirection of stdio.
3-
There are three ways to launch the debuggee
3+
There are three ways to launch the debuggee:
44
internalConsole, integratedTerminal and externalTerminal.
55
6-
For the three configurations, we test if we can read data
7-
from environments, stdin and cli arguments.
6+
For each redirection configuration we check the stdin, argv, and env
7+
input paths. The C++ test program writes whatever it receives from
8+
each available source.
89
910
NOTE: The testcases do not include all possible configurations of
10-
consoles, environments, stdin and cli arguments.
11+
consoles and input sources.
1112
"""
1213

1314
from abc import abstractmethod
14-
import lldbdap_testcase
1515
from tempfile import NamedTemporaryFile
1616

17+
from lldbsuite.test.tools.lldb_dap import DAPTestCaseBase, DAPTestSession
18+
from lldbsuite.test.tools.lldb_dap.types import Console, LaunchArgs
1719

18-
class DAP_launchIO(lldbdap_testcase.DAPTestCaseBase):
19-
"""The class holds the implementation different ways to redirect the debuggee I/O streams
20-
which is configurable from the Derived classes.
2120

22-
Depending on the console type the output will be in different places.
23-
It also provides two abstract functions `_get_debuggee_stdout` and `_get_debuggee_stderr`
24-
that provides the debuggee stdout and stderr.
21+
class DAP_launchIO(DAPTestCaseBase):
22+
"""Implements the redirection scenarios that are common to every console.
23+
24+
Subclasses provide `console` and override `_get_debuggee_stdout` /
25+
`_get_debuggee_stderr` for the cases where stdout / stderr are not
26+
redirected to files (the streams have to be read from the console
27+
instead, which differs between InternalConsole and IntegratedTerminal).
2528
"""
2629

27-
def all_redirection(self, console: str, with_args: bool = False):
28-
"""Test all standard io redirection."""
29-
self.build_and_create_debug_adapter()
30+
def all_redirection(self, console: Console):
31+
"""All three streams redirected to files. Verify every input path."""
32+
session = self.build_and_create_session()
3033
program = self.getBuildArtifact("a.out")
31-
input_text = "from stdin with redirection"
32-
args_text = "string from argv"
33-
program_args = [args_text] if with_args else None
34+
stdin_input = "from stdin"
35+
args_input = "from argv"
36+
env_input = "from env"
3437

3538
with NamedTemporaryFile("wt") as stdin, NamedTemporaryFile(
3639
"rt"
3740
) as stdout, NamedTemporaryFile("rt") as stderr:
38-
stdin.write(input_text)
41+
stdin.write(stdin_input)
3942
stdin.flush()
40-
self.launch_and_configurationDone(
41-
program,
42-
stdio=[stdin.name, stdout.name, stderr.name],
43-
console=console,
44-
args=program_args,
45-
)
46-
self.verify_process_exited()
47-
48-
all_stdout = stdout.read()
49-
all_stderr = stderr.read()
5043

51-
if with_args:
52-
self.assertEqual(f"[STDOUT][FROM_ARGV]: {args_text}", all_stdout)
53-
self.assertEqual(f"[STDERR][FROM_ARGV]: {args_text}", all_stderr)
54-
55-
self.assertNotIn(f"[STDOUT][FROM_ARGV]: {args_text}", all_stderr)
56-
self.assertNotIn(f"[STDERR][FROM_ARGV]: {args_text}", all_stdout)
44+
session.launch(
45+
LaunchArgs(
46+
program,
47+
stdio=[stdin.name, stdout.name, stderr.name],
48+
console=console,
49+
args=["--read-stdin", args_input],
50+
env={"FROM_ENV": env_input},
51+
)
52+
)
53+
session.verify_process_exited()
5754

58-
else:
59-
self.assertEqual(f"[STDOUT][FROM_STDIN]: {input_text}", all_stdout)
60-
self.assertEqual(f"[STDERR][FROM_STDIN]: {input_text}", all_stderr)
55+
stdout_text = stdout.read()
56+
stderr_text = stderr.read()
57+
self.assertIn(f"[STDOUT][FROM_STDIN]: {stdin_input}", stdout_text)
58+
self.assertIn(f"[STDOUT][FROM_ARGV]: {args_input}", stdout_text)
59+
self.assertIn(f"[STDOUT][FROM_ENV]: {env_input}", stdout_text)
6160

62-
self.assertNotIn(f"[STDERR][FROM_STDIN]: {input_text}", all_stdout)
63-
self.assertNotIn(f"[STDOUT][FROM_STDIN]: {input_text}", all_stderr)
61+
self.assertIn(f"[STDERR][FROM_STDIN]: {stdin_input}", stderr_text)
62+
self.assertIn(f"[STDERR][FROM_ARGV]: {args_input}", stderr_text)
63+
self.assertIn(f"[STDERR][FROM_ENV]: {env_input}", stderr_text)
6464

65-
def stdin_redirection(self, console: str, with_args: bool = False):
66-
"""Test only stdin redirection."""
67-
self.build_and_create_debug_adapter()
65+
def stdin_redirection(self, console: Console):
66+
"""Only stdin redirected. Verify every input path via console output."""
67+
session = self.build_and_create_session()
6868
program = self.getBuildArtifact("a.out")
69-
input_text = "string from stdin"
70-
args_text = "string from argv"
71-
program_args = [args_text] if with_args else None
69+
stdin_input = "from stdin"
70+
args_input = "from argv"
71+
env_input = "from env"
7272

7373
with NamedTemporaryFile("w+t") as stdin:
74-
stdin.write(input_text)
74+
stdin.write(stdin_input)
7575
stdin.flush()
76-
self.launch_and_configurationDone(
77-
program, stdio=[stdin.name], console=console, args=program_args
76+
session.launch(
77+
LaunchArgs(
78+
program,
79+
stdio=[stdin.name],
80+
console=console,
81+
args=["--read-stdin", args_input],
82+
env={"FROM_ENV": env_input},
83+
)
7884
)
79-
self.verify_process_exited()
85+
session.verify_process_exited()
8086

81-
stdout_text = self._get_debuggee_stdout()
82-
stderr_text = self._get_debuggee_stderr()
87+
stdout_text = self._get_debuggee_stdout(session)
88+
stderr_text = self._get_debuggee_stderr(session)
89+
self.assertIn(f"[STDOUT][FROM_STDIN]: {stdin_input}", stdout_text)
90+
self.assertIn(f"[STDOUT][FROM_ARGV]: {args_input}", stdout_text)
91+
self.assertIn(f"[STDOUT][FROM_ENV]: {env_input}", stdout_text)
8392

84-
if with_args:
85-
self.assertIn(f"[STDOUT][FROM_ARGV]: {args_text}", stdout_text)
86-
self.assertIn(f"[STDERR][FROM_ARGV]: {args_text}", stderr_text)
87-
else:
88-
self.assertIn(f"[STDOUT][FROM_STDIN]: {input_text}", stdout_text)
89-
self.assertIn(f"[STDERR][FROM_STDIN]: {input_text}", stderr_text)
90-
91-
def stdout_redirection(self, console: str, with_env: bool = False):
92-
"""Test only stdout redirection."""
93-
self.build_and_create_debug_adapter()
94-
program = self.getBuildArtifact("a.out")
93+
self.assertIn(f"[STDERR][FROM_STDIN]: {stdin_input}", stderr_text)
94+
self.assertIn(f"[STDERR][FROM_ARGV]: {args_input}", stderr_text)
95+
self.assertIn(f"[STDERR][FROM_ENV]: {env_input}", stderr_text)
9596

96-
argv_text = "output with\n multiline"
97-
# By default unix terminals the ONLCR flag is enabled. which replaces '\n' with '\r\n'
98-
# see https://man7.org/linux/man-pages/man3/termios.3.html.
99-
# This does not affect writing to normal files.
100-
argv_replaced_text = argv_text.replace("\n", "\r\n")
97+
def stdout_redirection(self, console: Console):
98+
"""Only stdout redirected. Verify argv and env paths.
10199
102-
program_args = [argv_text]
103-
env_text = "string from env"
104-
env = {"FROM_ENV": env_text} if with_env else {}
100+
stdin is not set up — the C++ program skips reading it because the
101+
file descriptor is a tty (would block).
102+
"""
103+
session = self.build_and_create_session()
104+
program = self.getBuildArtifact("a.out")
105+
args_input = "from argv"
106+
env_input = "from env"
105107

106108
with NamedTemporaryFile("rt") as stdout:
107-
self.launch_and_configurationDone(
108-
program,
109-
stdio=[None, stdout.name],
110-
console=console,
111-
args=program_args,
112-
env=env,
109+
session.launch(
110+
LaunchArgs(
111+
program,
112+
stdio=[None, stdout.name],
113+
console=console,
114+
args=[args_input],
115+
env={"FROM_ENV": env_input},
116+
)
113117
)
114-
self.verify_process_exited()
118+
session.verify_process_exited()
115119

116-
# check stdout
117120
stdout_text = stdout.read()
118-
stderr_text = self._get_debuggee_stderr()
119-
if with_env:
120-
self.assertIn(f"[STDOUT][FROM_ENV]: {env_text}", stdout_text)
121-
self.assertIn(f"[STDERR][FROM_ENV]: {env_text}", stderr_text)
122-
123-
self.assertNotIn(f"[STDERR][FROM_ENV]: {env_text}", stdout_text)
124-
self.assertNotIn(f"[STDOUT][FROM_ENV]: {env_text}", stderr_text)
125-
else:
126-
self.assertIn(f"[STDOUT][FROM_ARGV]: {argv_text}", stdout_text)
127-
128-
self.assertNotIn(
129-
f"[STDERR][FROM_ARGV]: {argv_replaced_text}", stdout_text
130-
)
131-
self.assertNotIn(f"[STDOUT][FROM_ARGV]: {argv_text}", stderr_text)
132-
133-
# check stderr
134-
stderr_text = self._get_debuggee_stderr()
135-
# FIXME: when using 'integrated' or 'external' terminal we do not correctly
136-
# escape newlines that are sent to the terminal.
137-
if console == "integratedConsole":
138-
if with_env:
139-
self.assertNotIn(f"[STDOUT][FROM_ENV]: {env_text}", stderr_text)
140-
self.assertIn(f"[STDERR][FROM_ENV]: {env_text}", stderr_text)
141-
else:
142-
self.assertNotIn(
143-
f"[STDOUT][FROM_ARGV]: {argv_replaced_text}", stderr_text
144-
)
145-
self.assertIn(
146-
f"[STDERR][FROM_ARGV]: {argv_replaced_text}", stderr_text
147-
)
148-
149-
def stderr_redirection(self, console: str, with_env: bool = False):
150-
"""Test only stdout redirection."""
151-
self.build_and_create_debug_adapter()
152-
program = self.getBuildArtifact("a.out")
121+
stderr_text = self._get_debuggee_stderr(session)
122+
self.assertIn(f"[STDOUT][FROM_ARGV]: {args_input}", stdout_text)
123+
self.assertIn(f"[STDOUT][FROM_ENV]: {env_input}", stdout_text)
153124

154-
argv_text = "output with\n multiline"
155-
# By default unix terminals the ONLCR flag is enabled. which replaces '\n' with '\r\n'
156-
# see https://man7.org/linux/man-pages/man3/termios.3.html.
157-
# This does not affect writing to normal files.
158-
# Currently out test implementation for external and integrated Terminal does not run the
159-
# program through a shell terminal.
160-
argv_replaced_text = argv_text
161-
if console == "internalConsole":
162-
argv_replaced_text = argv_text.replace("\n", "\r\n")
163-
program_args = [argv_text]
164-
env_text = "string from env"
165-
env = {"FROM_ENV": env_text} if with_env else {}
125+
self.assertIn(f"[STDERR][FROM_ARGV]: {args_input}", stderr_text)
126+
self.assertIn(f"[STDERR][FROM_ENV]: {env_input}", stderr_text)
127+
128+
def stderr_redirection(self, console: Console):
129+
"""Only stderr redirected. Verify argv and env paths."""
130+
session = self.build_and_create_session()
131+
program = self.getBuildArtifact("a.out")
132+
args_input = "from argv"
133+
env_input = "from env"
166134

167135
with NamedTemporaryFile("rt") as stderr:
168-
self.launch_and_configurationDone(
169-
program,
170-
stdio=[None, None, stderr.name],
171-
console=console,
172-
args=program_args,
173-
env=env,
136+
session.launch(
137+
LaunchArgs(
138+
program,
139+
stdio=[None, None, stderr.name],
140+
console=console,
141+
args=[args_input],
142+
env={"FROM_ENV": env_input},
143+
)
174144
)
175-
self.verify_process_exited()
176-
stdout_text = self._get_debuggee_stdout()
145+
session.verify_process_exited()
146+
147+
stdout_text = self._get_debuggee_stdout(session)
177148
stderr_text = stderr.read()
178-
if with_env:
179-
self.assertIn(f"[STDOUT][FROM_ENV]: {env_text}", stdout_text)
180-
self.assertIn(f"[STDERR][FROM_ENV]: {env_text}", stderr_text)
181-
else:
182-
self.assertIn(f"[STDOUT][FROM_ARGV]: {argv_replaced_text}", stdout_text)
183-
self.assertIn(f"[STDERR][FROM_ARGV]: {argv_text}", stderr_text)
149+
self.assertIn(f"[STDOUT][FROM_ARGV]: {args_input}", stdout_text)
150+
self.assertIn(f"[STDOUT][FROM_ENV]: {env_input}", stdout_text)
151+
152+
self.assertIn(f"[STDERR][FROM_ARGV]: {args_input}", stderr_text)
153+
self.assertIn(f"[STDERR][FROM_ENV]: {env_input}", stderr_text)
184154

185155
@abstractmethod
186-
def _get_debuggee_stdout(self) -> str:
156+
def _get_debuggee_stdout(self, session: DAPTestSession) -> str:
187157
"""Retrieves the standard output (stdout) from the debuggee process.
188158
189-
The default destination of the debuggee's stdout can vary based on how the debugger
159+
The default destination of the debuggee's stdout can vary based on how the debuggee
190160
was launched (either a debug console or a pseudo-terminal (pty)).
191161
It requires subclasses to implement the specific mechanism for obtaining the stdout stream.
192162
"""
193163
raise RuntimeError(f"NotImplemented for {self}")
194164

195165
@abstractmethod
196-
def _get_debuggee_stderr(self) -> str:
166+
def _get_debuggee_stderr(self, session: DAPTestSession) -> str:
197167
"""Retrieves the standard error (stderr) from the debuggee process.
198168
199-
The default destination of the debuggee's stderr can vary based on how the debugger
169+
The default destination of the debuggee's stderr can vary based on how the debuggee
200170
was launched (either a debug console or a pseudo-terminal (pty)).
201171
It requires subclasses to implement the specific mechanism for obtaining the stderr stream.
202172
"""

0 commit comments

Comments
 (0)