1"""
2Test lldb data formatter subsystem.
3"""
4
5import os, time
6import unittest2
7import lldb
8from lldbtest import *
9import lldbutil
10
11class SynthDataFormatterTestCase(TestBase):
12
13    mydir = os.path.join("functionalities", "data-formatter", "data-formatter-synth")
14
15    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
16    @dsym_test
17    def test_with_dsym_and_run_command(self):
18        """Test data formatter commands."""
19        self.buildDsym()
20        self.data_formatter_commands()
21
22    @dwarf_test
23    def test_with_dwarf_and_run_command(self):
24        """Test data formatter commands."""
25        self.buildDwarf()
26        self.data_formatter_commands()
27
28    def setUp(self):
29        # Call super's setUp().
30        TestBase.setUp(self)
31        # Find the line number to break at.
32        self.line = line_number('main.cpp', '// Set break point at this line.')
33
34    def data_formatter_commands(self):
35        """Test that that file and class static variables display correctly."""
36        self.runCmd("file a.out", CURRENT_EXECUTABLE_SET)
37
38        lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.line, num_expected_locations=1, loc_exact=True)
39
40        self.runCmd("run", RUN_SUCCEEDED)
41
42        # The stop reason of the thread should be breakpoint.
43        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
44            substrs = ['stopped',
45                       'stop reason = breakpoint'])
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
54        # Execute the cleanup function during test case tear down.
55        self.addTearDownHook(cleanup)
56
57        # Pick some values and check that the basics work
58        self.runCmd("type filter add BagOfInts --child x --child z")
59        self.expect("frame variable int_bag",
60            substrs = ['x = 6',
61                       'z = 8'])
62
63        # Check we can still access the missing child by summary
64        self.runCmd("type summary add BagOfInts --summary-string \"y=${var.y}\"")
65        self.expect('frame variable int_bag',
66            substrs = ['y=7'])
67
68        # Even if we have synth children, the summary prevails
69        self.expect("frame variable int_bag", matching=False,
70                    substrs = ['x = 6',
71                               'z = 8'])
72
73        # if we skip synth and summary show y
74        self.expect("frame variable int_bag --synthetic-type false --no-summary-depth=1",
75                    substrs = ['x = 6',
76                               'y = 7',
77                               'z = 8'])
78
79        # if we ask for raw output same happens
80        self.expect("frame variable int_bag --raw-output",
81                    substrs = ['x = 6',
82                               'y = 7',
83                               'z = 8'])
84
85        # Summary+Synth must work together
86        self.runCmd("type summary add BagOfInts --summary-string \"x=${var.x}\" -e")
87        self.expect('frame variable int_bag',
88                    substrs = ['x=6',
89                               'x = 6',
90                               'z = 8'])
91
92        # Same output, but using Python
93        self.runCmd("type summary add BagOfInts --python-script \"return 'x=%s' % valobj.GetChildMemberWithName('x').GetValue()\" -e")
94        self.expect('frame variable int_bag',
95                    substrs = ['x=6',
96                               'x = 6',
97                               'z = 8'])
98
99        # If I skip summaries, still give me the artificial children
100        self.expect("frame variable int_bag --no-summary-depth=1",
101                    substrs = ['x = 6',
102                               'z = 8'])
103
104        # Delete synth and check that the view reflects it immediately
105        self.runCmd("type filter delete BagOfInts")
106        self.expect("frame variable int_bag",
107                    substrs = ['x = 6',
108                               'y = 7',
109                               'z = 8'])
110
111        # Add the synth again and check that it's honored deeper in the hierarchy
112        self.runCmd("type filter add BagOfInts --child x --child z")
113        self.expect('frame variable bag_bag',
114            substrs = ['x = x=69 {',
115                       'x = 69',
116                       'z = 71',
117                       'y = x=66 {',
118                       'x = 66',
119                       'z = 68'])
120        self.expect('frame variable bag_bag', matching=False,
121                    substrs = ['y = 70',
122                               'y = 67'])
123
124        # Check that a synth can expand nested stuff
125        self.runCmd("type filter add BagOfBags --child x.y --child y.z")
126        self.expect('frame variable bag_bag',
127                    substrs = ['x.y = 70',
128                               'y.z = 68'])
129
130        # ...even if we get -> and . wrong
131        self.runCmd("type filter add BagOfBags --child x.y --child \"y->z\"")
132        self.expect('frame variable bag_bag',
133                    substrs = ['x.y = 70',
134                               'y->z = 68'])
135
136        # ...even bitfields
137        self.runCmd("type filter add BagOfBags --child x.y --child \"y->z[1-2]\"")
138        self.expect('frame variable bag_bag --show-types',
139                    substrs = ['x.y = 70',
140                               '(int:2) y->z[1-2] = 2'])
141
142        # ...even if we format the bitfields
143        self.runCmd("type filter add BagOfBags --child x.y --child \"y->y[0-0]\"")
144        self.runCmd("type format add \"int:1\" -f bool")
145        self.expect('frame variable bag_bag --show-types',
146                    substrs = ['x.y = 70',
147                               '(int:1) y->y[0-0] = true'])
148
149        # ...even if we use one-liner summaries
150        self.runCmd("type summary add -c BagOfBags")
151        self.expect('frame variable bag_bag',
152            substrs = ['(BagOfBags) bag_bag = (x.y = 70, y->y[0-0] = true)'])
153
154        self.runCmd("type summary delete BagOfBags")
155
156        # now check we are dynamic (and arrays work)
157        self.runCmd("type filter add Plenty --child bitfield --child array[0] --child array[2]")
158        self.expect('frame variable plenty_of_stuff',
159            substrs = ['bitfield = 1',
160                       'array[0] = 5',
161                       'array[2] = 3'])
162
163        self.runCmd("n")
164        self.expect('frame variable plenty_of_stuff',
165                    substrs = ['bitfield = 17',
166                               'array[0] = 5',
167                               'array[2] = 3'])
168
169        # skip synthetic children
170        self.expect('frame variable plenty_of_stuff --synthetic-type no',
171                    substrs = ['some_values = 0x0',
172                               'array = 0x',
173                               'array_size = 5'])
174
175
176        # check flat printing with synthetic children
177        self.expect('frame variable plenty_of_stuff --flat',
178            substrs = ['plenty_of_stuff.bitfield = 17',
179                       '*(plenty_of_stuff.array) = 5',
180                       '*(plenty_of_stuff.array) = 3'])
181
182        # check that we do not lose location information for our children
183        self.expect('frame variable plenty_of_stuff --location',
184                    substrs = ['0x',
185                               ':   bitfield = 17'])
186
187        # check we work across pointer boundaries
188        self.expect('frame variable plenty_of_stuff.some_values --ptr-depth=1',
189                    substrs = ['(BagOfInts *) plenty_of_stuff.some_values',
190                               'x = 5',
191                               'z = 7'])
192
193        # but not if we don't want to
194        self.runCmd("type filter add BagOfInts --child x --child z -p")
195        self.expect('frame variable plenty_of_stuff.some_values --ptr-depth=1',
196                    substrs = ['(BagOfInts *) plenty_of_stuff.some_values',
197                               'x = 5',
198                               'y = 6',
199                               'z = 7'])
200
201        # check we're dynamic even if nested
202        self.runCmd("type filter add BagOfBags --child x.z")
203        self.expect('frame variable bag_bag',
204            substrs = ['x.z = 71'])
205
206        self.runCmd("n")
207        self.expect('frame variable bag_bag',
208                    substrs = ['x.z = 12'])
209
210
211if __name__ == '__main__':
212    import atexit
213    lldb.SBDebugger.Initialize()
214    atexit.register(lambda: lldb.SBDebugger.Terminate())
215    unittest2.main()
216