1"""
2Test lldb-vscode setBreakpoints request
3"""
4
5
6import unittest2
7import vscode
8from lldbsuite.test.decorators import *
9from lldbsuite.test.lldbtest import *
10from lldbsuite.test import lldbutil
11import lldbvscode_testcase
12import os
13
14
15class TestVSCode_launch(lldbvscode_testcase.VSCodeTestCaseBase):
16
17    mydir = TestBase.compute_mydir(__file__)
18
19    @skipIfWindows
20    @skipIfDarwin # Flaky
21    @skipIfRemote
22    def test_default(self):
23        '''
24            Tests the default launch of a simple program. No arguments,
25            environment, or anything else is specified.
26        '''
27        program = self.getBuildArtifact("a.out")
28        self.build_and_launch(program)
29        self.continue_to_exit()
30        # Now get the STDOUT and verify our program argument is correct
31        output = self.get_stdout()
32        self.assertTrue(output and len(output) > 0,
33                        "expect program output")
34        lines = output.splitlines()
35        self.assertTrue(program in lines[0],
36                        "make sure program path is in first argument")
37
38    @skipIfWindows
39    @skipIfRemote
40    def test_stopOnEntry(self):
41        '''
42            Tests the default launch of a simple program that stops at the
43            entry point instead of continuing.
44        '''
45        program = self.getBuildArtifact("a.out")
46        self.build_and_launch(program, stopOnEntry=True)
47        self.set_function_breakpoints(['main'])
48        stopped_events = self.continue_to_next_stop()
49        for stopped_event in stopped_events:
50            if 'body' in stopped_event:
51                body = stopped_event['body']
52                if 'reason' in body:
53                    reason = body['reason']
54                    self.assertTrue(
55                        reason != 'breakpoint',
56                        'verify stop isn\'t "main" breakpoint')
57
58    @skipIfWindows
59    @skipIfRemote
60    def test_cwd(self):
61        '''
62            Tests the default launch of a simple program with a current working
63            directory.
64        '''
65        program = self.getBuildArtifact("a.out")
66        program_parent_dir = os.path.realpath(
67            os.path.dirname(os.path.dirname(program)))
68        self.build_and_launch(program,
69                              cwd=program_parent_dir)
70        self.continue_to_exit()
71        # Now get the STDOUT and verify our program argument is correct
72        output = self.get_stdout()
73        self.assertTrue(output and len(output) > 0,
74                        "expect program output")
75        lines = output.splitlines()
76        found = False
77        for line in lines:
78            if line.startswith('cwd = \"'):
79                quote_path = '"%s"' % (program_parent_dir)
80                found = True
81                self.assertTrue(quote_path in line,
82                                "working directory '%s' not in '%s'" % (
83                                    program_parent_dir, line))
84        self.assertTrue(found, "verified program working directory")
85
86    @skipIfWindows
87    @skipIfRemote
88    def test_debuggerRoot(self):
89        '''
90            Tests the "debuggerRoot" will change the working directory of
91            the lldb-vscode debug adaptor.
92        '''
93        program = self.getBuildArtifact("a.out")
94        program_parent_dir = os.path.realpath(
95            os.path.dirname(os.path.dirname(program)))
96        commands = ['platform shell echo cwd = $PWD']
97        self.build_and_launch(program,
98                              debuggerRoot=program_parent_dir,
99                              initCommands=commands)
100        output = self.get_console()
101        self.assertTrue(output and len(output) > 0,
102                        "expect console output")
103        lines = output.splitlines()
104        prefix = 'cwd = '
105        found = False
106        for line in lines:
107            if line.startswith(prefix):
108                found = True
109                self.assertEquals(program_parent_dir, line[len(prefix):],
110                                "lldb-vscode working dir '%s' == '%s'" % (
111                                    program_parent_dir, line[6:]))
112        self.assertTrue(found, "verified lldb-vscode working directory")
113        self.continue_to_exit()
114
115    @skipIfWindows
116    @skipIfRemote
117    def test_sourcePath(self):
118        '''
119            Tests the "sourcePath" will set the target.source-map.
120        '''
121        program = self.getBuildArtifact("a.out")
122        program_dir = os.path.dirname(program)
123        self.build_and_launch(program,
124                              sourcePath=program_dir)
125        output = self.get_console()
126        self.assertTrue(output and len(output) > 0,
127                        "expect console output")
128        lines = output.splitlines()
129        prefix = '(lldb) settings set target.source-map "." '
130        found = False
131        for line in lines:
132            if line.startswith(prefix):
133                found = True
134                quoted_path = '"%s"' % (program_dir)
135                self.assertEquals(quoted_path, line[len(prefix):],
136                                "lldb-vscode working dir %s == %s" % (
137                                    quoted_path, line[6:]))
138        self.assertTrue(found, 'found "sourcePath" in console output')
139        self.continue_to_exit()
140
141    @skipIfWindows
142    @skipIfRemote
143    def test_disableSTDIO(self):
144        '''
145            Tests the default launch of a simple program with STDIO disabled.
146        '''
147        program = self.getBuildArtifact("a.out")
148        self.build_and_launch(program,
149                              disableSTDIO=True)
150        self.continue_to_exit()
151        # Now get the STDOUT and verify our program argument is correct
152        output = self.get_stdout()
153        self.assertEquals(output, None,
154                        "expect no program output")
155
156    @skipIfWindows
157    @skipIfLinux # shell argument expansion doesn't seem to work on Linux
158    @expectedFailureNetBSD
159    @skipIfRemote
160    def test_shellExpandArguments_enabled(self):
161        '''
162            Tests the default launch of a simple program with shell expansion
163            enabled.
164        '''
165        program = self.getBuildArtifact("a.out")
166        program_dir = os.path.dirname(program)
167        glob = os.path.join(program_dir, '*.out')
168        self.build_and_launch(program, args=[glob], shellExpandArguments=True)
169        self.continue_to_exit()
170        # Now get the STDOUT and verify our program argument is correct
171        output = self.get_stdout()
172        self.assertTrue(output and len(output) > 0,
173                        "expect no program output")
174        lines = output.splitlines()
175        for line in lines:
176            quote_path = '"%s"' % (program)
177            if line.startswith("arg[1] ="):
178                self.assertTrue(quote_path in line,
179                                'verify "%s" expanded to "%s"' % (
180                                    glob, program))
181
182    @skipIfWindows
183    @skipIfRemote
184    def test_shellExpandArguments_disabled(self):
185        '''
186            Tests the default launch of a simple program with shell expansion
187            disabled.
188        '''
189        program = self.getBuildArtifact("a.out")
190        program_dir = os.path.dirname(program)
191        glob = os.path.join(program_dir, '*.out')
192        self.build_and_launch(program,
193                              args=[glob],
194                              shellExpandArguments=False)
195        self.continue_to_exit()
196        # Now get the STDOUT and verify our program argument is correct
197        output = self.get_stdout()
198        self.assertTrue(output and len(output) > 0,
199                        "expect no program output")
200        lines = output.splitlines()
201        for line in lines:
202            quote_path = '"%s"' % (glob)
203            if line.startswith("arg[1] ="):
204                self.assertTrue(quote_path in line,
205                                'verify "%s" stayed to "%s"' % (
206                                    glob, glob))
207
208    @skipIfWindows
209    @skipIfRemote
210    def test_args(self):
211        '''
212            Tests launch of a simple program with arguments
213        '''
214        program = self.getBuildArtifact("a.out")
215        args = ["one", "with space", "'with single quotes'",
216                '"with double quotes"']
217        self.build_and_launch(program,
218                              args=args)
219        self.continue_to_exit()
220
221        # Now get the STDOUT and verify our arguments got passed correctly
222        output = self.get_stdout()
223        self.assertTrue(output and len(output) > 0,
224                        "expect program output")
225        lines = output.splitlines()
226        # Skip the first argument that contains the program name
227        lines.pop(0)
228        # Make sure arguments we specified are correct
229        for (i, arg) in enumerate(args):
230            quoted_arg = '"%s"' % (arg)
231            self.assertTrue(quoted_arg in lines[i],
232                            'arg[%i] "%s" not in "%s"' % (i+1, quoted_arg, lines[i]))
233
234    @skipIfWindows
235    @skipIfRemote
236    def test_environment(self):
237        '''
238            Tests launch of a simple program with environment variables
239        '''
240        program = self.getBuildArtifact("a.out")
241        env = ["NO_VALUE", "WITH_VALUE=BAR", "EMPTY_VALUE=",
242               "SPACE=Hello World"]
243        self.build_and_launch(program,
244                              env=env)
245        self.continue_to_exit()
246
247        # Now get the STDOUT and verify our arguments got passed correctly
248        output = self.get_stdout()
249        self.assertTrue(output and len(output) > 0,
250                        "expect program output")
251        lines = output.splitlines()
252        # Skip the all arguments so we have only environment vars left
253        while len(lines) and lines[0].startswith("arg["):
254            lines.pop(0)
255        # Make sure each environment variable in "env" is actually set in the
256        # program environment that was printed to STDOUT
257        for var in env:
258            found = False
259            for program_var in lines:
260                if var in program_var:
261                    found = True
262                    break
263            self.assertTrue(found,
264                            '"%s" must exist in program environment (%s)' % (
265                                var, lines))
266
267    @skipIfWindows
268    @skipIfRemote
269    def test_commands(self):
270        '''
271            Tests the "initCommands", "preRunCommands", "stopCommands" and
272            "exitCommands" that can be passed during launch.
273
274            "initCommands" are a list of LLDB commands that get executed
275            before the targt is created.
276            "preRunCommands" are a list of LLDB commands that get executed
277            after the target has been created and before the launch.
278            "stopCommands" are a list of LLDB commands that get executed each
279            time the program stops.
280            "exitCommands" are a list of LLDB commands that get executed when
281            the process exits
282        '''
283        program = self.getBuildArtifact("a.out")
284        initCommands = ['target list', 'platform list']
285        preRunCommands = ['image list a.out', 'image dump sections a.out']
286        stopCommands = ['frame variable', 'bt']
287        exitCommands = ['expr 2+3', 'expr 3+4']
288        self.build_and_launch(program,
289                              initCommands=initCommands,
290                              preRunCommands=preRunCommands,
291                              stopCommands=stopCommands,
292                              exitCommands=exitCommands)
293
294        # Get output from the console. This should contain both the
295        # "initCommands" and the "preRunCommands".
296        output = self.get_console()
297        # Verify all "initCommands" were found in console output
298        self.verify_commands('initCommands', output, initCommands)
299        # Verify all "preRunCommands" were found in console output
300        self.verify_commands('preRunCommands', output, preRunCommands)
301
302        source = 'main.c'
303        first_line = line_number(source, '// breakpoint 1')
304        second_line = line_number(source, '// breakpoint 2')
305        lines = [first_line, second_line]
306
307        # Set 2 breakoints so we can verify that "stopCommands" get run as the
308        # breakpoints get hit
309        breakpoint_ids = self.set_source_breakpoints(source, lines)
310        self.assertEquals(len(breakpoint_ids), len(lines),
311                        "expect correct number of breakpoints")
312
313        # Continue after launch and hit the first breakpoint.
314        # Get output from the console. This should contain both the
315        # "stopCommands" that were run after the first breakpoint was hit
316        self.continue_to_breakpoints(breakpoint_ids)
317        output = self.get_console(timeout=1.0)
318        self.verify_commands('stopCommands', output, stopCommands)
319
320        # Continue again and hit the second breakpoint.
321        # Get output from the console. This should contain both the
322        # "stopCommands" that were run after the second breakpoint was hit
323        self.continue_to_breakpoints(breakpoint_ids)
324        output = self.get_console(timeout=1.0)
325        self.verify_commands('stopCommands', output, stopCommands)
326
327        # Continue until the program exits
328        self.continue_to_exit()
329        # Get output from the console. This should contain both the
330        # "exitCommands" that were run after the second breakpoint was hit
331        output = self.get_console(timeout=1.0)
332        self.verify_commands('exitCommands', output, exitCommands)
333
334    @skipIfWindows
335    @skipIfRemote
336    def test_extra_launch_commands(self):
337        '''
338            Tests the "luanchCommands" with extra launching settings
339        '''
340        self.build_and_create_debug_adaptor()
341        program = self.getBuildArtifact("a.out")
342
343        source = 'main.c'
344        first_line = line_number(source, '// breakpoint 1')
345        second_line = line_number(source, '// breakpoint 2')
346        # Set target binary and 2 breakoints
347        # then we can varify the "launchCommands" get run
348        # also we can verify that "stopCommands" get run as the
349        # breakpoints get hit
350        launchCommands = [
351            'target create "%s"' % (program),
352            'br s -f main.c -l %d' % first_line,
353            'br s -f main.c -l %d' % second_line,
354            'process launch --stop-at-entry'
355        ]
356
357        initCommands = ['target list', 'platform list']
358        preRunCommands = ['image list a.out', 'image dump sections a.out']
359        stopCommands = ['frame variable', 'bt']
360        exitCommands = ['expr 2+3', 'expr 3+4']
361        self.launch(program,
362                    initCommands=initCommands,
363                    preRunCommands=preRunCommands,
364                    stopCommands=stopCommands,
365                    exitCommands=exitCommands,
366                    launchCommands=launchCommands)
367
368        # Get output from the console. This should contain both the
369        # "initCommands" and the "preRunCommands".
370        output = self.get_console()
371        # Verify all "initCommands" were found in console output
372        self.verify_commands('initCommands', output, initCommands)
373        # Verify all "preRunCommands" were found in console output
374        self.verify_commands('preRunCommands', output, preRunCommands)
375
376        # Verify all "launchCommands" were founc in console output
377        # After execution, program should launch
378        self.verify_commands('launchCommands', output, launchCommands)
379        # Verify the "stopCommands" here
380        self.continue_to_next_stop()
381        output = self.get_console(timeout=1.0)
382        self.verify_commands('stopCommands', output, stopCommands)
383
384        # Continue and hit the second breakpoint.
385        # Get output from the console. This should contain both the
386        # "stopCommands" that were run after the first breakpoint was hit
387        self.continue_to_next_stop()
388        output = self.get_console(timeout=1.0)
389        self.verify_commands('stopCommands', output, stopCommands)
390
391        # Continue until the program exits
392        self.continue_to_exit()
393        # Get output from the console. This should contain both the
394        # "exitCommands" that were run after the second breakpoint was hit
395        output = self.get_console(timeout=1.0)
396        self.verify_commands('exitCommands', output, exitCommands)
397