1"""
2Test lldb data formatter subsystem.
3"""
4
5
6import lldb
7from lldbsuite.test.lldbtest import *
8import lldbsuite.test.lldbutil as lldbutil
9
10
11class ScriptDataFormatterTestCase(TestBase):
12    def test_with_run_command(self):
13        """Test data formatter commands."""
14        self.build()
15        self.data_formatter_commands()
16
17    def setUp(self):
18        # Call super's setUp().
19        TestBase.setUp(self)
20        # Find the line number to break at.
21        self.line = line_number("main.cpp", "// Set break point at this line.")
22
23    def data_formatter_commands(self):
24        """Test that that file and class static variables display correctly."""
25        self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
26
27        lldbutil.run_break_set_by_file_and_line(
28            self, "main.cpp", self.line, num_expected_locations=1, loc_exact=True
29        )
30
31        self.runCmd("run", RUN_SUCCEEDED)
32
33        # The stop reason of the thread should be breakpoint.
34        self.expect(
35            "thread list",
36            STOPPED_DUE_TO_BREAKPOINT,
37            substrs=["stopped", "stop reason = breakpoint"],
38        )
39
40        # This is the function to remove the custom formats in order to have a
41        # clean slate for the next test case.
42        def cleanup():
43            self.runCmd("type format clear", check=False)
44            self.runCmd("type summary clear", check=False)
45
46        # Execute the cleanup function during test case tear down.
47        self.addTearDownHook(cleanup)
48
49        # Set the script here to ease the formatting
50        script = "a = valobj.GetChildMemberWithName('integer'); a_val = a.GetValue(); str = 'Hello from Python, ' + a_val + ' time'; return str + ('!' if a_val == '1' else 's!');"
51
52        self.runCmd('type summary add i_am_cool --python-script "%s"' % script)
53        self.expect("type summary list i_am_cool", substrs=[script])
54
55        self.expect("frame variable one", substrs=["Hello from Python", "1 time!"])
56
57        self.expect("frame variable two", substrs=["Hello from Python", "4 times!"])
58
59        self.runCmd("n")  # skip ahead to make values change
60
61        self.expect(
62            "frame variable three",
63            substrs=["Hello from Python, 10 times!", "Hello from Python, 4 times!"],
64        )
65
66        self.runCmd("n")  # skip ahead to make values change
67
68        self.expect("frame variable two", substrs=["Hello from Python", "1 time!"])
69
70        script = "a = valobj.GetChildMemberWithName('integer'); a_val = a.GetValue(); str = 'int says ' + a_val; return str;"
71
72        # Check that changes in the script are immediately reflected
73        self.runCmd('type summary add i_am_cool --python-script "%s"' % script)
74
75        self.expect("frame variable two", substrs=["int says 1"])
76
77        self.expect("frame variable twoptr", substrs=["int says 1"])
78
79        # Change the summary
80        self.runCmd(
81            'type summary add --summary-string "int says ${var.integer}, and float says ${var.floating}" i_am_cool'
82        )
83
84        self.expect("frame variable two", substrs=["int says 1", "and float says 2.71"])
85        # Try it for pointers
86        self.expect(
87            "frame variable twoptr", substrs=["int says 1", "and float says 2.71"]
88        )
89
90        # Force a failure for pointers
91        self.runCmd('type summary add i_am_cool -p --python-script "%s"' % script)
92
93        self.expect(
94            "frame variable twoptr", matching=False, substrs=["and float says 2.71"]
95        )
96
97        script = "return 'Python summary'"
98
99        self.runCmd(
100            'type summary add --name test_summary --python-script "%s"' % script
101        )
102
103        # attach the Python named summary to someone
104        self.expect(
105            "frame variable one --summary test_summary", substrs=["Python summary"]
106        )
107
108        # should not bind to the type
109        self.expect("frame variable two", matching=False, substrs=["Python summary"])
110
111        # and should not stick to the variable
112        self.expect("frame variable one", matching=False, substrs=["Python summary"])
113
114        self.runCmd('type summary add i_am_cool --summary-string "Text summary"')
115
116        # should be temporary only
117        self.expect("frame variable one", matching=False, substrs=["Python summary"])
118
119        # use the type summary
120        self.expect("frame variable two", substrs=["Text summary"])
121
122        self.runCmd("n")  # skip ahead to make values change
123
124        # both should use the type summary now
125        self.expect("frame variable one", substrs=["Text summary"])
126
127        self.expect("frame variable two", substrs=["Text summary"])
128
129        # disable type summary for pointers, and make a Python regex summary
130        self.runCmd('type summary add i_am_cool -p --summary-string "Text summary"')
131        self.runCmd('type summary add -x cool --python-script "%s"' % script)
132
133        # variables should stick to the type summary
134        self.expect("frame variable one", substrs=["Text summary"])
135
136        self.expect("frame variable two", substrs=["Text summary"])
137
138        # array and pointer should match the Python one
139        self.expect("frame variable twoptr", substrs=["Python summary"])
140
141        self.expect("frame variable array", substrs=["Python summary"])
142
143        # return pointers to the type summary
144        self.runCmd('type summary add i_am_cool --summary-string "Text summary"')
145
146        self.expect("frame variable one", substrs=["Text summary"])
147
148        self.expect("frame variable two", substrs=["Text summary"])
149
150        self.expect("frame variable twoptr", substrs=["Text summary"])
151
152        self.expect("frame variable array", substrs=["Python summary"])
153