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