1"""
2Test lldb data formatter subsystem.
3"""
4
5
6import lldb
7from lldbsuite.test.decorators import *
8from lldbsuite.test.lldbtest import *
9from lldbsuite.test import lldbutil
10
11USE_LIBSTDCPP = "USE_LIBSTDCPP"
12USE_LIBCPP = "USE_LIBCPP"
13
14
15class GenericMultiSetDataFormatterTestCase(TestBase):
16    def setUp(self):
17        TestBase.setUp(self)
18        self.namespace = "std"
19
20    def findVariable(self, name):
21        var = self.frame().FindVariable(name)
22        self.assertTrue(var.IsValid())
23        return var
24
25    def getVariableType(self, name):
26        var = self.findVariable(name)
27        return var.GetType().GetDisplayTypeName()
28
29    def check(self, var_name, size):
30        var = self.findVariable(var_name)
31        self.assertEqual(var.GetNumChildren(), size)
32        children = []
33        for i in range(size):
34            child = var.GetChildAtIndex(i)
35            children.append(ValueCheck(value=child.GetValue()))
36        self.expect_var_path(
37            var_name, type=self.getVariableType(var_name), children=children
38        )
39
40    def do_test_with_run_command(self, stdlib_type):
41        """Test that that file and class static variables display correctly."""
42        self.build(dictionary={stdlib_type: "1"})
43        (self.target, process, _, bkpt) = lldbutil.run_to_source_breakpoint(
44            self, "Set break point at this line.", lldb.SBFileSpec("main.cpp", False)
45        )
46
47        # This is the function to remove the custom formats in order to have a
48        # clean slate for the next test case.
49        def cleanup():
50            self.runCmd("type format clear", check=False)
51            self.runCmd("type summary clear", check=False)
52            self.runCmd("type filter clear", check=False)
53            self.runCmd("type synth clear", check=False)
54            self.runCmd("settings set target.max-children-count 256", check=False)
55
56        # Execute the cleanup function during test case tear down.
57        self.addTearDownHook(cleanup)
58
59        ii_type = self.getVariableType("ii")
60        self.assertTrue(
61            ii_type.startswith(self.namespace + "::multiset"), "Type: " + ii_type
62        )
63
64        self.expect("frame variable ii", substrs=["size=0", "{}"])
65        lldbutil.continue_to_breakpoint(process, bkpt)
66        self.expect(
67            "frame variable ii",
68            substrs=[
69                "size=6",
70                "[0] = 0",
71                "[1] = 1",
72                "[2] = 2",
73                "[3] = 3",
74                "[4] = 4",
75                "[5] = 5",
76            ],
77        )
78        lldbutil.continue_to_breakpoint(process, bkpt)
79
80        self.check("ii", 7)
81
82        lldbutil.continue_to_breakpoint(process, bkpt)
83        self.expect("frame variable ii", substrs=["size=0", "{}"])
84        self.check("ii", 0)
85        lldbutil.continue_to_breakpoint(process, bkpt)
86        self.expect("frame variable ii", substrs=["size=0", "{}"])
87        ss_type = self.getVariableType("ss")
88        self.assertTrue(
89            ss_type.startswith(self.namespace + "::multiset"), "Type: " + ss_type
90        )
91        self.expect("frame variable ss", substrs=["size=0", "{}"])
92        self.check("ss", 0)
93        lldbutil.continue_to_breakpoint(process, bkpt)
94        self.expect(
95            "frame variable ss",
96            substrs=["size=2", '[0] = "a"', '[1] = "a very long string is right here"'],
97        )
98        self.check("ss", 2)
99        lldbutil.continue_to_breakpoint(process, bkpt)
100        self.expect(
101            "frame variable ss",
102            substrs=[
103                "size=4",
104                '[0] = "a"',
105                '[1] = "a very long string is right here"',
106                '[2] = "b"',
107                '[3] = "c"',
108            ],
109        )
110        self.check("ss", 4)
111        self.expect(
112            "expression ss",
113            substrs=[
114                "size=4",
115                '[0] = "a"',
116                '[1] = "a very long string is right here"',
117                '[2] = "b"',
118                '[3] = "c"',
119            ],
120        )
121        self.expect("frame variable ss[2]", substrs=[' = "b"'])
122        lldbutil.continue_to_breakpoint(process, bkpt)
123        self.expect(
124            "frame variable ss",
125            substrs=[
126                "size=3",
127                '[0] = "a"',
128                '[1] = "a very long string is right here"',
129                '[2] = "c"',
130            ],
131        )
132
133    def do_test_ref_and_ptr(self, stdlib_type):
134        """Test that the data formatters work on ref and ptr."""
135        self.build(dictionary={stdlib_type: "1"})
136        (self.target, process, _, bkpt) = lldbutil.run_to_source_breakpoint(
137            self,
138            "Stop here to check by ref and ptr.",
139            lldb.SBFileSpec("main.cpp", False),
140        )
141        # The reference should print just like the value:
142        self.check("ref", 7)
143
144        self.expect("frame variable ptr", substrs=["ptr =", "size=7"])
145        self.expect("expr ptr", substrs=["size=7"])
146
147    @add_test_categories(["libstdcxx"])
148    def test_with_run_command_libstdcpp(self):
149        self.do_test_with_run_command(USE_LIBSTDCPP)
150
151    @add_test_categories(["libc++"])
152    def test_with_run_command_libcpp(self):
153        self.do_test_with_run_command(USE_LIBCPP)
154
155    @add_test_categories(["libstdcxx"])
156    def test_ref_and_ptr_libstdcpp(self):
157        self.do_test_ref_and_ptr(USE_LIBSTDCPP)
158
159    @add_test_categories(["libc++"])
160    def test_ref_and_ptr_libcpp(self):
161        self.do_test_ref_and_ptr(USE_LIBCPP)
162