1"""
2Test display and Python APIs on file and class static variables.
3"""
4
5
6
7import lldb
8from lldbsuite.test.decorators import *
9from lldbsuite.test.lldbtest import *
10from lldbsuite.test import lldbutil
11
12
13class StaticVariableTestCase(TestBase):
14
15    def setUp(self):
16        # Call super's setUp().
17        TestBase.setUp(self)
18        # Find the line number to break at.
19        self.line = line_number('main.cpp', '// Set break point at this line.')
20
21    def test_with_run_command(self):
22        """Test that file and class static variables display correctly."""
23        self.build()
24        self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
25
26        lldbutil.run_break_set_by_file_and_line(
27            self, "main.cpp", self.line, num_expected_locations=1, loc_exact=True)
28
29        self.runCmd("run", RUN_SUCCEEDED)
30
31        # The stop reason of the thread should be breakpoint.
32        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
33                    substrs=['stopped',
34                             'stop reason = breakpoint'])
35
36        # Global variables are no longer displayed with the "frame variable"
37        # command.
38        self.expect(
39            'target variable A::g_points',
40            VARIABLES_DISPLAYED_CORRECTLY,
41            patterns=['\(PointType\[[1-9]*\]\) A::g_points = {'])
42        self.expect('target variable g_points', VARIABLES_DISPLAYED_CORRECTLY,
43                    substrs=['(PointType[2]) g_points'])
44
45        # On Mac OS X, gcc 4.2 emits the wrong debug info for A::g_points.
46        # A::g_points is an array of two elements.
47        if self.platformIsDarwin() or self.getPlatform() == "linux":
48            self.expect(
49                "target variable A::g_points[1].x",
50                VARIABLES_DISPLAYED_CORRECTLY,
51                startstr="(int) A::g_points[1].x = 11")
52
53    @expectedFailureAll(
54        compiler=["gcc"],
55        bugnumber="Compiler emits incomplete debug info")
56    @expectedFailureAll(
57        compiler=["clang"],
58        compiler_version=["<", "3.9"],
59        bugnumber='llvm.org/pr20550')
60    def test_with_run_command_complete(self):
61        """
62        Test that file and class static variables display correctly with
63        complete debug information.
64        """
65        self.build()
66        target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
67        self.assertTrue(target, VALID_TARGET)
68
69        # Global variables are no longer displayed with the "frame variable"
70        # command.
71        self.expect(
72            'target variable A::g_points',
73            VARIABLES_DISPLAYED_CORRECTLY,
74            patterns=[
75                '\(PointType\[[1-9]*\]\) A::g_points = {', '(x = 1, y = 2)',
76                '(x = 11, y = 22)'
77            ])
78
79        # Ensure that we take the context into account and only print
80        # A::g_points.
81        self.expect(
82            'target variable A::g_points',
83            VARIABLES_DISPLAYED_CORRECTLY,
84            matching=False,
85            patterns=['(x = 3, y = 4)', '(x = 33, y = 44)'])
86
87        # Finally, ensure that we print both points when not specifying a
88        # context.
89        self.expect(
90            'target variable g_points',
91            VARIABLES_DISPLAYED_CORRECTLY,
92            substrs=[
93                '(PointType[2]) g_points', '(x = 1, y = 2)',
94                '(x = 11, y = 22)', '(x = 3, y = 4)', '(x = 33, y = 44)'
95            ])
96
97    @expectedFailureAll(
98        compiler=["gcc"],
99        bugnumber="Compiler emits incomplete debug info")
100    @expectedFailureAll(
101        compiler=["clang"],
102        compiler_version=["<", "3.9"],
103        bugnumber='llvm.org/pr20550')
104    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24764")
105    @add_test_categories(['pyapi'])
106    def test_with_python_api(self):
107        """Test Python APIs on file and class static variables."""
108        self.build()
109        exe = self.getBuildArtifact("a.out")
110
111        target = self.dbg.CreateTarget(exe)
112        self.assertTrue(target, VALID_TARGET)
113
114        breakpoint = target.BreakpointCreateByLocation("main.cpp", self.line)
115        self.assertTrue(breakpoint, VALID_BREAKPOINT)
116
117        # Now launch the process, and do not stop at entry point.
118        process = target.LaunchSimple(
119            None, None, self.get_process_working_directory())
120        self.assertTrue(process, PROCESS_IS_VALID)
121
122        # The stop reason of the thread should be breakpoint.
123        thread = lldbutil.get_stopped_thread(
124            process, lldb.eStopReasonBreakpoint)
125        self.assertIsNotNone(thread)
126
127        # Get the SBValue of 'A::g_points' and 'g_points'.
128        frame = thread.GetFrameAtIndex(0)
129
130        # arguments =>     False
131        # locals =>        False
132        # statics =>       True
133        # in_scope_only => False
134        valList = frame.GetVariables(False, False, True, False)
135
136        for val in valList:
137            self.DebugSBValue(val)
138            name = val.GetName()
139            self.assertIn(name, ['g_points', 'A::g_points'])
140            if name == 'g_points':
141                self.assertEqual(
142                    val.GetValueType(), lldb.eValueTypeVariableStatic)
143                self.assertEqual(val.GetNumChildren(), 2)
144            elif name == 'A::g_points':
145                self.assertEqual(
146                    val.GetValueType(), lldb.eValueTypeVariableGlobal)
147                self.assertEqual(val.GetNumChildren(), 2)
148                child1 = val.GetChildAtIndex(1)
149                self.DebugSBValue(child1)
150                child1_x = child1.GetChildAtIndex(0)
151                self.DebugSBValue(child1_x)
152                self.assertEqual(child1_x.GetTypeName(), 'int')
153                self.assertEqual(child1_x.GetValue(), '11')
154
155        # SBFrame.FindValue() should also work.
156        val = frame.FindValue("A::g_points", lldb.eValueTypeVariableGlobal)
157        self.DebugSBValue(val)
158        self.assertEqual(val.GetName(), 'A::g_points')
159
160        # Also exercise the "parameter" and "local" scopes while we are at it.
161        val = frame.FindValue("argc", lldb.eValueTypeVariableArgument)
162        self.DebugSBValue(val)
163        self.assertEqual(val.GetName(), 'argc')
164
165        val = frame.FindValue("argv", lldb.eValueTypeVariableArgument)
166        self.DebugSBValue(val)
167        self.assertEqual(val.GetName(), 'argv')
168
169        val = frame.FindValue("hello_world", lldb.eValueTypeVariableLocal)
170        self.DebugSBValue(val)
171        self.assertEqual(val.GetName(), 'hello_world')
172