1"""
2Test lldb data formatter subsystem.
3"""
4
5
6import lldb
7from lldbsuite.test.lldbtest import *
8from lldbsuite.test.decorators import *
9from lldbsuite.test.lldbtest import *
10from lldbsuite.test import lldbutil
11
12USE_LIBSTDCPP = "USE_LIBSTDCPP"
13USE_LIBCPP = "USE_LIBCPP"
14
15
16class GenericMultiMapDataFormatterTestCase(TestBase):
17    def setUp(self):
18        TestBase.setUp(self)
19        self.namespace = "std"
20
21    def findVariable(self, name):
22        var = self.frame().FindVariable(name)
23        self.assertTrue(var.IsValid())
24        return var
25
26    def getVariableType(self, name):
27        var = self.findVariable(name)
28        return var.GetType().GetDisplayTypeName()
29
30    def check(self, var_name, size):
31        var = self.findVariable(var_name)
32        self.assertEqual(var.GetNumChildren(), size)
33        children = []
34        for i in range(size):
35            child = var.GetChildAtIndex(i)
36            children.append(ValueCheck(value=child.GetValue()))
37        self.expect_var_path(
38            var_name, type=self.getVariableType(var_name), children=children
39        )
40
41    def do_test_with_run_command(self, stdlib_type):
42        """Test that that file and class static variables display correctly."""
43        self.build(dictionary={stdlib_type: "1"})
44        self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
45
46        bkpt = self.target().FindBreakpointByID(
47            lldbutil.run_break_set_by_source_regexp(
48                self, "Set break point at this line."
49            )
50        )
51
52        self.runCmd("run", RUN_SUCCEEDED)
53
54        # The stop reason of the thread should be breakpoint.
55        self.expect(
56            "thread list",
57            STOPPED_DUE_TO_BREAKPOINT,
58            substrs=["stopped", "stop reason = breakpoint"],
59        )
60
61        # This is the function to remove the custom formats in order to have a
62        # clean slate for the next test case.
63        def cleanup():
64            self.runCmd("type format clear", check=False)
65            self.runCmd("type summary clear", check=False)
66            self.runCmd("type filter clear", check=False)
67            self.runCmd("type synth clear", check=False)
68            self.runCmd("settings set target.max-children-count 256", check=False)
69
70        # Execute the cleanup function during test case tear down.
71        self.addTearDownHook(cleanup)
72
73        multimap = self.namespace + "::multimap"
74
75        # We expect that in some malformed cases the map shows size 0
76        self.expect("frame variable corrupt_map", substrs=[multimap, "size=0", "{}"])
77
78        lldbutil.continue_to_breakpoint(self.process(), bkpt)
79
80        self.expect("frame variable ii", substrs=[multimap, "size=0", "{}"])
81
82        lldbutil.continue_to_breakpoint(self.process(), bkpt)
83
84        self.expect(
85            "frame variable ii",
86            substrs=[
87                multimap,
88                "size=2",
89                "[0] = (first = 0, second = 0)",
90                "[1] = (first = 1, second = 1)",
91            ],
92        )
93
94        self.check("ii", 2)
95
96        lldbutil.continue_to_breakpoint(self.process(), bkpt)
97
98        self.expect(
99            "frame variable ii",
100            substrs=[
101                multimap,
102                "size=4",
103                "[2] = ",
104                "first = 2",
105                "second = 0",
106                "[3] = ",
107                "first = 3",
108                "second = 1",
109            ],
110        )
111
112        self.check("ii", 4)
113
114        lldbutil.continue_to_breakpoint(self.process(), bkpt)
115
116        self.expect(
117            "frame variable ii",
118            substrs=[
119                multimap,
120                "size=8",
121                "[5] = ",
122                "first = 5",
123                "second = 0",
124                "[7] = ",
125                "first = 7",
126                "second = 1",
127            ],
128        )
129
130        self.check("ii", 8)
131
132        self.expect(
133            "expression ii",
134            substrs=[
135                multimap,
136                "size=8",
137                "[5] = ",
138                "first = 5",
139                "second = 0",
140                "[7] = ",
141                "first = 7",
142                "second = 1",
143            ],
144        )
145
146        # check access-by-index
147        self.expect("frame variable ii[0]", substrs=["first = 0", "second = 0"])
148        self.expect("frame variable ii[3]", substrs=["first =", "second ="])
149
150        # check that MightHaveChildren() gets it right
151        self.assertTrue(
152            self.frame().FindVariable("ii").MightHaveChildren(),
153            "ii.MightHaveChildren() says False for non empty!",
154        )
155
156        # check that the expression parser does not make use of
157        # synthetic children instead of running code
158        # TOT clang has a fix for this, which makes the expression command here succeed
159        # since this would make the test fail or succeed depending on clang version in use
160        # this is safer commented for the time being
161        # self.expect("expression ii[8]", matching=False, error=True,
162        #            substrs = ['1234567'])
163
164        lldbutil.continue_to_breakpoint(self.process(), bkpt)
165
166        self.expect("frame variable ii", substrs=[multimap, "size=0", "{}"])
167
168        self.expect("frame variable si", substrs=[multimap, "size=0", "{}"])
169
170        lldbutil.continue_to_breakpoint(self.process(), bkpt)
171
172        self.expect(
173            "frame variable si",
174            substrs=[multimap, "size=1", "[0] = ", 'first = "zero"', "second = 0"],
175        )
176
177        lldbutil.continue_to_breakpoint(self.process(), bkpt)
178
179        self.expect(
180            "frame variable si",
181            substrs=[
182                multimap,
183                "size=4",
184                '[0] = (first = "one", second = 1)',
185                '[1] = (first = "three", second = 3)',
186                '[2] = (first = "two", second = 2)',
187                '[3] = (first = "zero", second = 0)',
188            ],
189        )
190
191        self.expect(
192            "expression si",
193            substrs=[
194                multimap,
195                "size=4",
196                '[0] = (first = "one", second = 1)',
197                '[1] = (first = "three", second = 3)',
198                '[2] = (first = "two", second = 2)',
199                '[3] = (first = "zero", second = 0)',
200            ],
201        )
202
203        # check that MightHaveChildren() gets it right
204        self.assertTrue(
205            self.frame().FindVariable("si").MightHaveChildren(),
206            "si.MightHaveChildren() says False for non empty!",
207        )
208
209        # check access-by-index
210        self.expect("frame variable si[0]", substrs=["first = ", "one", "second = 1"])
211
212        # check that the expression parser does not make use of
213        # synthetic children instead of running code
214        # TOT clang has a fix for this, which makes the expression command here succeed
215        # since this would make the test fail or succeed depending on clang version in use
216        # this is safer commented for the time being
217        # self.expect("expression si[0]", matching=False, error=True,
218        #            substrs = ['first = ', 'zero'])
219
220        lldbutil.continue_to_breakpoint(self.process(), bkpt)
221
222        self.expect("frame variable si", substrs=[multimap, "size=0", "{}"])
223
224        lldbutil.continue_to_breakpoint(self.process(), bkpt)
225
226        self.expect("frame variable is", substrs=[multimap, "size=0", "{}"])
227
228        lldbutil.continue_to_breakpoint(self.process(), bkpt)
229
230        self.expect(
231            "frame variable is",
232            substrs=[
233                multimap,
234                "size=4",
235                '[0] = (first = 1, second = "is")',
236                '[1] = (first = 2, second = "smart")',
237                '[2] = (first = 3, second = "!!!")',
238                '[3] = (first = 85, second = "goofy")',
239            ],
240        )
241
242        self.expect(
243            "expression is",
244            substrs=[
245                multimap,
246                "size=4",
247                '[0] = (first = 1, second = "is")',
248                '[1] = (first = 2, second = "smart")',
249                '[2] = (first = 3, second = "!!!")',
250                '[3] = (first = 85, second = "goofy")',
251            ],
252        )
253
254        # check that MightHaveChildren() gets it right
255        self.assertTrue(
256            self.frame().FindVariable("is").MightHaveChildren(),
257            "is.MightHaveChildren() says False for non empty!",
258        )
259
260        # check access-by-index
261        self.expect("frame variable is[0]", substrs=["first = ", "second ="])
262
263        # check that the expression parser does not make use of
264        # synthetic children instead of running code
265        # TOT clang has a fix for this, which makes the expression command here succeed
266        # since this would make the test fail or succeed depending on clang version in use
267        # this is safer commented for the time being
268        # self.expect("expression is[0]", matching=False, error=True,
269        #            substrs = ['first = ', 'goofy'])
270
271        lldbutil.continue_to_breakpoint(self.process(), bkpt)
272
273        self.expect("frame variable is", substrs=[multimap, "size=0", "{}"])
274
275        self.check("is", 0)
276
277        lldbutil.continue_to_breakpoint(self.process(), bkpt)
278
279        self.expect("frame variable ss", substrs=[multimap, "size=0", "{}"])
280
281        self.check("ss", 0)
282
283        lldbutil.continue_to_breakpoint(self.process(), bkpt)
284
285        self.expect(
286            "frame variable ss",
287            substrs=[
288                multimap,
289                "size=3",
290                '[0] = (first = "casa", second = "house")',
291                '[1] = (first = "ciao", second = "hello")',
292                '[2] = (first = "gatto", second = "cat")',
293            ],
294        )
295
296        self.check("ss", 3)
297
298        self.expect(
299            "expression ss",
300            substrs=[
301                multimap,
302                "size=3",
303                '[0] = (first = "casa", second = "house")',
304                '[1] = (first = "ciao", second = "hello")',
305                '[2] = (first = "gatto", second = "cat")',
306            ],
307        )
308
309        # check that MightHaveChildren() gets it right
310        self.assertTrue(
311            self.frame().FindVariable("ss").MightHaveChildren(),
312            "ss.MightHaveChildren() says False for non empty!",
313        )
314
315        # check access-by-index
316        self.expect("frame variable ss[2]", substrs=["gatto", "cat"])
317
318        # check that the expression parser does not make use of
319        # synthetic children instead of running code
320        # TOT clang has a fix for this, which makes the expression command here succeed
321        # since this would make the test fail or succeed depending on clang version in use
322        # this is safer commented for the time being
323        # self.expect("expression ss[3]", matching=False, error=True,
324        #            substrs = ['gatto'])
325
326        lldbutil.continue_to_breakpoint(self.process(), bkpt)
327
328        self.expect("frame variable ss", substrs=[multimap, "size=0", "{}"])
329
330        self.check("ss", 0)
331
332    @add_test_categories(["libstdcxx"])
333    @skipIf(compiler="clang", compiler_version=["<", "9.0"])
334    def test_with_run_command_libstdcpp(self):
335        self.do_test_with_run_command(USE_LIBSTDCPP)
336
337    @skipIf(compiler="clang", compiler_version=["<", "9.0"])
338    @add_test_categories(["libc++"])
339    def test_with_run_command_libcpp(self):
340        self.do_test_with_run_command(USE_LIBCPP)
341