1# coding=utf8
2"""
3Test lldb data formatter subsystem.
4"""
5
6
7import lldb
8from lldbsuite.test.decorators import *
9from lldbsuite.test.lldbtest import *
10from lldbsuite.test import lldbutil
11
12
13class LibcxxStringDataFormatterTestCase(TestBase):
14    def setUp(self):
15        # Call super's setUp().
16        TestBase.setUp(self)
17        # Find the line number to break at.
18        self.main_spec = lldb.SBFileSpec("main.cpp")
19        self.namespace = "std"
20
21    @add_test_categories(["libc++"])
22    @expectedFailureAll(
23        bugnumber="llvm.org/pr36109", debug_info="gmodules", triple=".*-android"
24    )
25    # Inline namespace is randomly ignored as Clang due to broken lookup inside
26    # the std namespace.
27    @expectedFailureAll(debug_info="gmodules")
28    def test_with_run_command(self):
29        """Test that that file and class static variables display correctly."""
30        self.build()
31
32        (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
33            self, "Set break point at this line.", self.main_spec
34        )
35        frame = thread.frames[0]
36
37        # This is the function to remove the custom formats in order to have a
38        # clean slate for the next test case.
39        def cleanup():
40            self.runCmd("type format clear", check=False)
41            self.runCmd("type summary clear", check=False)
42            self.runCmd("type filter clear", check=False)
43            self.runCmd("type synth clear", check=False)
44            self.runCmd("settings set target.max-children-count 256", check=False)
45
46        is_64_bit = self.process().GetAddressByteSize() == 8
47
48        # Execute the cleanup function during test case tear down.
49        self.addTearDownHook(cleanup)
50
51        ns = self.namespace
52
53        self.expect(
54            "frame variable",
55            substrs=[
56                '(%s::wstring) wempty = L""' % ns,
57                '(%s::wstring) s = L"hello world! מזל טוב!"' % ns,
58                '(%s::wstring) S = L"!!!!"' % ns,
59                "(const wchar_t *) mazeltov = 0x",
60                'L"מזל טוב"',
61                '(%s::string) empty = ""' % ns,
62                '(%s::string) q = "hello world"' % ns,
63                '(%s::string) Q = "quite a long std::strin with lots of info inside it"'
64                % ns,
65                '(%s::string) IHaveEmbeddedZeros = "a\\0b\\0c\\0d"' % ns,
66                '(%s::wstring) IHaveEmbeddedZerosToo = L"hello world!\\0てざ ル゜䋨ミ㠧槊 きゅへ狦穤襩 じゃ馩リョ 䤦監"'
67                % ns,
68                '(%s::u16string) u16_string = u"ß水氶"' % ns,
69                # FIXME: This should have a 'u' prefix.
70                '(%s::u16string) u16_empty = ""' % ns,
71                '(%s::u32string) u32_string = U"��������"' % ns,
72                # FIXME: This should have a 'U' prefix.
73                '(%s::u32string) u32_empty = ""' % ns,
74                "(%s::string *) null_str = nullptr" % ns,
75            ],
76        )
77
78        thread.StepOver()
79
80        TheVeryLongOne = frame.FindVariable("TheVeryLongOne")
81        summaryOptions = lldb.SBTypeSummaryOptions()
82        summaryOptions.SetCapping(lldb.eTypeSummaryUncapped)
83        uncappedSummaryStream = lldb.SBStream()
84        TheVeryLongOne.GetSummary(uncappedSummaryStream, summaryOptions)
85        uncappedSummary = uncappedSummaryStream.GetData()
86        self.assertGreater(
87            uncappedSummary.find("someText"),
88            0,
89            "uncappedSummary does not include the full string",
90        )
91        summaryOptions.SetCapping(lldb.eTypeSummaryCapped)
92        cappedSummaryStream = lldb.SBStream()
93        TheVeryLongOne.GetSummary(cappedSummaryStream, summaryOptions)
94        cappedSummary = cappedSummaryStream.GetData()
95        self.assertLessEqual(
96            cappedSummary.find("someText"), 0, "cappedSummary includes the full string"
97        )
98
99        self.expect_expr(
100            "s", result_type=ns + "::wstring", result_summary='L"hello world! מזל טוב!"'
101        )
102
103        self.expect_expr(
104            "q", result_type=ns + "::string", result_summary='"hello world"'
105        )
106
107        self.expect_expr(
108            "Q",
109            result_type=ns + "::string",
110            result_summary='"quite a long std::strin with lots of info inside it"',
111        )
112
113        self.expect(
114            "frame variable",
115            substrs=[
116                '(%s::wstring) S = L"!!!!!"' % ns,
117                "(const wchar_t *) mazeltov = 0x",
118                'L"מזל טוב"',
119                '(%s::string) q = "hello world"' % ns,
120                '(%s::string) Q = "quite a long std::strin with lots of info inside it"'
121                % ns,
122                '(%s::string) IHaveEmbeddedZeros = "a\\0b\\0c\\0d"' % ns,
123                '(%s::wstring) IHaveEmbeddedZerosToo = L"hello world!\\0てざ ル゜䋨ミ㠧槊 きゅへ狦穤襩 じゃ馩リョ 䤦監"'
124                % ns,
125                '(%s::u16string) u16_string = u"ß水氶"' % ns,
126                '(%s::u32string) u32_string = U"��������"' % ns,
127                '(%s::u32string) u32_empty = ""' % ns,
128                "(%s::string *) null_str = nullptr" % ns,
129            ],
130        )
131
132        # The test assumes that std::string is in its cap-size-data layout.
133        is_alternate_layout = (
134            "arm" in self.getArchitecture()
135        ) and self.platformIsDarwin()
136        if is_64_bit and not is_alternate_layout:
137            self.expect(
138                "frame variable garbage1", substrs=["garbage1 = Summary Unavailable"]
139            )
140            self.expect(
141                "frame variable garbage2", substrs=[r'garbage2 = "\xfa\xfa\xfa\xfa"']
142            )
143            self.expect("frame variable garbage3", substrs=[r'garbage3 = "\xf0\xf0"'])
144            self.expect(
145                "frame variable garbage4", substrs=["garbage4 = Summary Unavailable"]
146            )
147            self.expect(
148                "frame variable garbage5", substrs=["garbage5 = Summary Unavailable"]
149            )
150
151        # Finally, make sure that if the string is not readable, we give an error:
152        bkpt_2 = target.BreakpointCreateBySourceRegex(
153            "Break here to look at bad string", self.main_spec
154        )
155        self.assertEqual(bkpt_2.GetNumLocations(), 1, "Got one location")
156        threads = lldbutil.continue_to_breakpoint(process, bkpt_2)
157        self.assertEqual(len(threads), 1, "Stopped at second breakpoint")
158        frame = threads[0].frames[0]
159        var = frame.FindVariable("in_str")
160        self.assertTrue(var.GetError().Success(), "Made variable")
161        summary = var.GetSummary()
162        self.assertEqual(summary, "Summary Unavailable", "No summary for bad value")
163