1"""
2Test lldb-vscode setBreakpoints request
3"""
4
5from __future__ import print_function
6
7import unittest2
8import vscode
9from lldbsuite.test.decorators import *
10from lldbsuite.test.lldbtest import *
11from lldbsuite.test import lldbutil
12import lldbvscode_testcase
13
14
15def make_buffer_verify_dict(start_idx, count, offset=0):
16    verify_dict = {}
17    for i in range(start_idx, start_idx + count):
18        verify_dict['[%i]' % (i)] = {'type': 'int', 'value': str(i+offset)}
19    return verify_dict
20
21
22class TestVSCode_variables(lldbvscode_testcase.VSCodeTestCaseBase):
23
24    mydir = TestBase.compute_mydir(__file__)
25
26    def verify_values(self, verify_dict, actual, varref_dict=None):
27        if 'equals' in verify_dict:
28            verify = verify_dict['equals']
29            for key in verify:
30                verify_value = verify[key]
31                actual_value = actual[key]
32                self.assertEqual(verify_value, actual_value,
33                                '"%s" keys don\'t match (%s != %s)' % (
34                                    key, actual_value, verify_value))
35        if 'startswith' in verify_dict:
36            verify = verify_dict['startswith']
37            for key in verify:
38                verify_value = verify[key]
39                actual_value = actual[key]
40                startswith = actual_value.startswith(verify_value)
41                self.assertTrue(startswith,
42                                ('"%s" value "%s" doesn\'t start with'
43                                 ' "%s")') % (
44                                    key, actual_value,
45                                    verify_value))
46        hasVariablesReference = 'variablesReference' in actual
47        varRef = None
48        if hasVariablesReference:
49            # Remember variable references in case we want to test further
50            # by using the evaluate name.
51            varRef = actual['variablesReference']
52            if varRef != 0 and varref_dict is not None:
53                varref_dict[actual['evaluateName']] = varRef
54        if ('hasVariablesReference' in verify_dict and
55                verify_dict['hasVariablesReference']):
56            self.assertTrue(hasVariablesReference,
57                            "verify variable reference")
58        if 'children' in verify_dict:
59            self.assertTrue(hasVariablesReference and varRef is not None and
60                            varRef != 0,
61                            ("children verify values specified for "
62                             "variable without children"))
63
64            response = self.vscode.request_variables(varRef)
65            self.verify_variables(verify_dict['children'],
66                                  response['body']['variables'],
67                                  varref_dict)
68
69    def verify_variables(self, verify_dict, variables, varref_dict=None):
70        for variable in variables:
71            name = variable['name']
72            self.assertIn(name, verify_dict,
73                          'variable "%s" in verify dictionary' % (name))
74            self.verify_values(verify_dict[name], variable, varref_dict)
75
76    @skipIfWindows
77    @skipIfRemote
78    def test_scopes_variables_setVariable_evaluate(self):
79        '''
80            Tests the "scopes", "variables", "setVariable", and "evaluate"
81            packets.
82        '''
83        program = self.getBuildArtifact("a.out")
84        self.build_and_launch(program)
85        source = 'main.cpp'
86        breakpoint1_line = line_number(source, '// breakpoint 1')
87        lines = [breakpoint1_line]
88        # Set breakpoint in the thread function so we can step the threads
89        breakpoint_ids = self.set_source_breakpoints(source, lines)
90        self.assertEqual(len(breakpoint_ids), len(lines),
91                        "expect correct number of breakpoints")
92        self.continue_to_breakpoints(breakpoint_ids)
93        locals = self.vscode.get_local_variables()
94        globals = self.vscode.get_global_variables()
95        buffer_children = make_buffer_verify_dict(0, 32)
96        verify_locals = {
97            'argc': {
98                'equals': {'type': 'int', 'value': '1'}
99            },
100            'argv': {
101                'equals': {'type': 'const char **'},
102                'startswith': {'value': '0x'},
103                'hasVariablesReference': True
104            },
105            'pt': {
106                'equals': {'type': 'PointType'},
107                'hasVariablesReference': True,
108                'children': {
109                    'x': {'equals': {'type': 'int', 'value': '11'}},
110                    'y': {'equals': {'type': 'int', 'value': '22'}},
111                    'buffer': {'children': buffer_children}
112                }
113            },
114            'x': {
115                'equals': {'type': 'int'}
116            }
117        }
118        verify_globals = {
119            's_local': {
120                'equals': {'type': 'float', 'value': '2.25'}
121            },
122            '::g_global': {
123                'equals': {'type': 'int', 'value': '123'}
124            },
125            's_global': {
126                'equals': {'type': 'int', 'value': '234'}
127            },
128        }
129        varref_dict = {}
130        self.verify_variables(verify_locals, locals, varref_dict)
131        self.verify_variables(verify_globals, globals, varref_dict)
132        # pprint.PrettyPrinter(indent=4).pprint(varref_dict)
133        # We need to test the functionality of the "variables" request as it
134        # has optional parameters like "start" and "count" to limit the number
135        # of variables that are fetched
136        varRef = varref_dict['pt.buffer']
137        response = self.vscode.request_variables(varRef)
138        self.verify_variables(buffer_children, response['body']['variables'])
139        # Verify setting start=0 in the arguments still gets all children
140        response = self.vscode.request_variables(varRef, start=0)
141        self.verify_variables(buffer_children, response['body']['variables'])
142        # Verify setting count=0 in the arguments still gets all children.
143        # If count is zero, it means to get all children.
144        response = self.vscode.request_variables(varRef, count=0)
145        self.verify_variables(buffer_children, response['body']['variables'])
146        # Verify setting count to a value that is too large in the arguments
147        # still gets all children, and no more
148        response = self.vscode.request_variables(varRef, count=1000)
149        self.verify_variables(buffer_children, response['body']['variables'])
150        # Verify setting the start index and count gets only the children we
151        # want
152        response = self.vscode.request_variables(varRef, start=5, count=5)
153        self.verify_variables(make_buffer_verify_dict(5, 5),
154                              response['body']['variables'])
155        # Verify setting the start index to a value that is out of range
156        # results in an empty list
157        response = self.vscode.request_variables(varRef, start=32, count=1)
158        self.assertEqual(len(response['body']['variables']), 0,
159                        'verify we get no variable back for invalid start')
160
161        # Test evaluate
162        expressions = {
163            'pt.x': {
164                'equals': {'result': '11', 'type': 'int'},
165                'hasVariablesReference': False
166            },
167            'pt.buffer[2]': {
168                'equals': {'result': '2', 'type': 'int'},
169                'hasVariablesReference': False
170            },
171            'pt': {
172                'equals': {'type': 'PointType'},
173                'startswith': {'result': 'PointType @ 0x'},
174                'hasVariablesReference': True
175            },
176            'pt.buffer': {
177                'equals': {'type': 'int [32]'},
178                'startswith': {'result': 'int [32] @ 0x'},
179                'hasVariablesReference': True
180            },
181            'argv': {
182                'equals': {'type': 'const char **'},
183                'startswith': {'result': '0x'},
184                'hasVariablesReference': True
185            },
186            'argv[0]': {
187                'equals': {'type': 'const char *'},
188                'startswith': {'result': '0x'},
189                'hasVariablesReference': True
190            },
191            '2+3': {
192                'equals': {'result': '5', 'type': 'int'},
193                'hasVariablesReference': False
194            },
195        }
196        for expression in expressions:
197            response = self.vscode.request_evaluate(expression)
198            self.verify_values(expressions[expression], response['body'])
199
200        # Test setting variables
201        self.set_local('argc', 123)
202        argc = self.get_local_as_int('argc')
203        self.assertEqual(argc, 123,
204                        'verify argc was set to 123 (123 != %i)' % (argc))
205
206        self.set_local('argv', 0x1234)
207        argv = self.get_local_as_int('argv')
208        self.assertEqual(argv, 0x1234,
209                        'verify argv was set to 0x1234 (0x1234 != %#x)' % (
210                            argv))
211
212        # Set a variable value whose name is synthetic, like a variable index
213        # and verify the value by reading it
214        self.vscode.request_setVariable(varRef, "[0]", 100)
215        response = self.vscode.request_variables(varRef, start=0, count=1)
216        self.verify_variables(make_buffer_verify_dict(0, 1, 100),
217                              response['body']['variables'])
218
219        # Set a variable value whose name is a real child value, like "pt.x"
220        # and verify the value by reading it
221        varRef = varref_dict['pt']
222        self.vscode.request_setVariable(varRef, "x", 111)
223        response = self.vscode.request_variables(varRef, start=0, count=1)
224        value = response['body']['variables'][0]['value']
225        self.assertEqual(value, '111',
226                        'verify pt.x got set to 111 (111 != %s)' % (value))
227
228        # We check shadowed variables and that a new get_local_variables request
229        # gets the right data
230        breakpoint2_line = line_number(source, '// breakpoint 2')
231        lines = [breakpoint2_line]
232        breakpoint_ids = self.set_source_breakpoints(source, lines)
233        self.assertEqual(len(breakpoint_ids), len(lines),
234                        "expect correct number of breakpoints")
235        self.continue_to_breakpoints(breakpoint_ids)
236
237        verify_locals['argc']['equals']['value'] = '123'
238        verify_locals['pt']['children']['x']['equals']['value'] = '111'
239        verify_locals['x @ main.cpp:17'] = {'equals': {'type': 'int', 'value': '89'}}
240        verify_locals['x @ main.cpp:19'] = {'equals': {'type': 'int', 'value': '42'}}
241        verify_locals['x @ main.cpp:21'] = {'equals': {'type': 'int', 'value': '72'}}
242
243        self.verify_variables(verify_locals, self.vscode.get_local_variables())
244
245        # Now we verify that we correctly change the name of a variable with and without differentiator suffix
246        self.assertFalse(self.vscode.request_setVariable(1, "x2", 9)['success'])
247        self.assertFalse(self.vscode.request_setVariable(1, "x @ main.cpp:0", 9)['success'])
248
249        self.assertTrue(self.vscode.request_setVariable(1, "x @ main.cpp:17", 17)['success'])
250        self.assertTrue(self.vscode.request_setVariable(1, "x @ main.cpp:19", 19)['success'])
251        self.assertTrue(self.vscode.request_setVariable(1, "x @ main.cpp:21", 21)['success'])
252
253        # The following should have no effect
254        self.assertFalse(self.vscode.request_setVariable(1, "x @ main.cpp:21", "invalid")['success'])
255
256        verify_locals['x @ main.cpp:17']['equals']['value'] = '17'
257        verify_locals['x @ main.cpp:19']['equals']['value'] = '19'
258        verify_locals['x @ main.cpp:21']['equals']['value'] = '21'
259
260        self.verify_variables(verify_locals, self.vscode.get_local_variables())
261
262        # The plain x variable shold refer to the innermost x
263        self.assertTrue(self.vscode.request_setVariable(1, "x", 22)['success'])
264        verify_locals['x @ main.cpp:21']['equals']['value'] = '22'
265
266        self.verify_variables(verify_locals, self.vscode.get_local_variables())
267
268        # In breakpoint 3, there should be no shadowed variables
269        breakpoint3_line = line_number(source, '// breakpoint 3')
270        lines = [breakpoint3_line]
271        breakpoint_ids = self.set_source_breakpoints(source, lines)
272        self.assertEqual(len(breakpoint_ids), len(lines),
273                        "expect correct number of breakpoints")
274        self.continue_to_breakpoints(breakpoint_ids)
275
276        locals = self.vscode.get_local_variables()
277        names = [var['name'] for var in locals]
278        # The first shadowed x shouldn't have a suffix anymore
279        verify_locals['x'] = {'equals': {'type': 'int', 'value': '17'}}
280        self.assertNotIn('x @ main.cpp:17', names)
281        self.assertNotIn('x @ main.cpp:19', names)
282        self.assertNotIn('x @ main.cpp:21', names)
283
284        self.verify_variables(verify_locals, locals)
285