271 lines · python
1"""2Test lldb-dap logpoints feature.3"""4 5 6import dap_server7import shutil8from lldbsuite.test.decorators import *9from lldbsuite.test.lldbtest import *10from lldbsuite.test import lldbutil11import lldbdap_testcase12import os13 14 15class TestDAP_logpoints(lldbdap_testcase.DAPTestCaseBase):16 def setUp(self):17 lldbdap_testcase.DAPTestCaseBase.setUp(self)18 19 self.main_basename = "main-copy.cpp"20 self.main_path = os.path.realpath(self.getBuildArtifact(self.main_basename))21 22 @skipIfWindows23 def test_logmessage_basic(self):24 """Tests breakpoint logmessage basic functionality."""25 before_loop_line = line_number("main.cpp", "// before loop")26 loop_line = line_number("main.cpp", "// break loop")27 after_loop_line = line_number("main.cpp", "// after loop")28 29 program = self.getBuildArtifact("a.out")30 self.build_and_launch(program)31 32 # Set a breakpoint at a line before loop33 before_loop_breakpoint_ids = self.set_source_breakpoints(34 self.main_path, [before_loop_line]35 )36 self.assertEqual(len(before_loop_breakpoint_ids), 1, "expect one breakpoint")37 38 self.dap_server.request_continue()39 40 # Verify we hit the breakpoint before loop line41 self.verify_breakpoint_hit(before_loop_breakpoint_ids)42 43 # Swallow old console output44 self.get_console()45 46 # Set two breakpoints:47 # 1. First at the loop line with logMessage48 # 2. Second guard breakpoint at a line after loop49 logMessage_prefix = "This is log message for { -- "50 logMessage = logMessage_prefix + "{i + 3}, {message}"51 [loop_breakpoint_id, post_loop_breakpoint_id] = self.set_source_breakpoints(52 self.main_path,53 [loop_line, after_loop_line],54 [{"logMessage": logMessage}, {}],55 )56 57 # Continue to trigger the breakpoint with log messages58 self.dap_server.request_continue()59 60 # Verify we hit the breakpoint after loop line61 self.verify_breakpoint_hit([post_loop_breakpoint_id])62 63 output = self.get_console()64 lines = output.splitlines()65 logMessage_output = []66 for line in lines:67 if line.startswith(logMessage_prefix):68 logMessage_output.append(line)69 70 # Verify logMessage count71 loop_count = 1072 self.assertEqual(len(logMessage_output), loop_count)73 74 message_addr_pattern = r"\b0x[0-9A-Fa-f]+\b"75 message_content = '"Hello from main!"'76 # Verify log message match77 for idx, logMessage_line in enumerate(logMessage_output):78 result = idx + 379 reg_str = (80 f"{logMessage_prefix}{result}, {message_addr_pattern} {message_content}"81 )82 self.assertRegex(logMessage_line, reg_str)83 84 @skipIfWindows85 def test_logmessage_advanced(self):86 """Tests breakpoint logmessage functionality for complex expression."""87 before_loop_line = line_number("main.cpp", "// before loop")88 loop_line = line_number("main.cpp", "// break loop")89 after_loop_line = line_number("main.cpp", "// after loop")90 91 program = self.getBuildArtifact("a.out")92 self.build_and_launch(program)93 94 # Set a breakpoint at a line before loop95 before_loop_breakpoint_ids = self.set_source_breakpoints(96 self.main_path, [before_loop_line]97 )98 self.assertEqual(len(before_loop_breakpoint_ids), 1, "expect one breakpoint")99 100 self.dap_server.request_continue()101 102 # Verify we hit the breakpoint before loop line103 self.verify_breakpoint_hit(before_loop_breakpoint_ids)104 105 # Swallow old console output106 self.get_console()107 108 # Set two breakpoints:109 # 1. First at the loop line with logMessage110 # 2. Second guard breakpoint at a line after loop111 logMessage_prefix = "This is log message for { -- "112 logMessage = (113 logMessage_prefix114 + "{int y = 0; if (i % 3 == 0) { y = i + 3;} else {y = i * 3;} y}"115 )116 [loop_breakpoint_id, post_loop_breakpoint_id] = self.set_source_breakpoints(117 self.main_path,118 [loop_line, after_loop_line],119 [{"logMessage": logMessage}, {}],120 )121 122 # Continue to trigger the breakpoint with log messages123 self.dap_server.request_continue()124 125 # Verify we hit the breakpoint after loop line126 self.verify_breakpoint_hit([post_loop_breakpoint_id])127 128 output = self.get_console()129 lines = output.splitlines()130 logMessage_output = []131 for line in lines:132 if line.startswith(logMessage_prefix):133 logMessage_output.append(line)134 135 # Verify logMessage count136 loop_count = 10137 self.assertEqual(len(logMessage_output), loop_count)138 139 # Verify log message match140 for idx, logMessage_line in enumerate(logMessage_output):141 result = idx + 3 if idx % 3 == 0 else idx * 3142 self.assertEqual(logMessage_line, logMessage_prefix + str(result))143 144 @skipIfWindows145 def test_logmessage_format(self):146 """147 Tests breakpoint logmessage functionality with format.148 """149 before_loop_line = line_number("main.cpp", "// before loop")150 loop_line = line_number("main.cpp", "// break loop")151 after_loop_line = line_number("main.cpp", "// after loop")152 153 program = self.getBuildArtifact("a.out")154 self.build_and_launch(program)155 156 # Set a breakpoint at a line before loop157 before_loop_breakpoint_ids = self.set_source_breakpoints(158 self.main_path, [before_loop_line]159 )160 self.assertEqual(len(before_loop_breakpoint_ids), 1, "expect one breakpoint")161 162 self.dap_server.request_continue()163 164 # Verify we hit the breakpoint before loop line165 self.verify_breakpoint_hit(before_loop_breakpoint_ids)166 167 # Swallow old console output168 self.get_console()169 170 # Set two breakpoints:171 # 1. First at the loop line with logMessage172 # 2. Second guard breakpoint at a line after loop173 logMessage_prefix = "This is log message for -- "174 logMessage_with_format = "part1\tpart2\bpart3\x64part4"175 logMessage_with_format_raw = r"part1\tpart2\bpart3\x64part4"176 logMessage = logMessage_prefix + logMessage_with_format_raw + "{i - 1}"177 [loop_breakpoint_id, post_loop_breakpoint_id] = self.set_source_breakpoints(178 self.main_path,179 [loop_line, after_loop_line],180 [{"logMessage": logMessage}, {}],181 )182 183 # Continue to trigger the breakpoint with log messages184 self.dap_server.request_continue()185 186 # Verify we hit the breakpoint after loop line187 self.verify_breakpoint_hit([post_loop_breakpoint_id])188 189 output = self.get_console()190 lines = output.splitlines()191 logMessage_output = []192 for line in lines:193 if line.startswith(logMessage_prefix):194 logMessage_output.append(line)195 196 # Verify logMessage count197 loop_count = 10198 self.assertEqual(len(logMessage_output), loop_count)199 200 # Verify log message match201 for idx, logMessage_line in enumerate(logMessage_output):202 result = idx - 1203 self.assertEqual(204 logMessage_line,205 logMessage_prefix + logMessage_with_format + str(result),206 )207 208 @skipIfWindows209 def test_logmessage_format_failure(self):210 """211 Tests breakpoint logmessage format with parsing failure.212 """213 before_loop_line = line_number("main.cpp", "// before loop")214 loop_line = line_number("main.cpp", "// break loop")215 after_loop_line = line_number("main.cpp", "// after loop")216 217 program = self.getBuildArtifact("a.out")218 self.build_and_launch(program)219 220 # Set a breakpoint at a line before loop221 before_loop_breakpoint_ids = self.set_source_breakpoints(222 self.main_path, [before_loop_line]223 )224 self.assertEqual(len(before_loop_breakpoint_ids), 1, "expect one breakpoint")225 226 self.dap_server.request_continue()227 228 # Verify we hit the breakpoint before loop line229 self.verify_breakpoint_hit(before_loop_breakpoint_ids)230 231 # Swallow old console output232 self.get_console()233 234 # Set two breakpoints:235 # 1. First at the loop line with logMessage236 # 2. Second guard breakpoint at a line after loop237 logMessage_prefix = "This is log message for -- "238 # log message missing hex number.239 logMessage_with_format_raw = r"part1\x"240 logMessage = logMessage_prefix + logMessage_with_format_raw241 [loop_breakpoint_id, post_loop_breakpoint_id] = self.set_source_breakpoints(242 self.main_path,243 [loop_line, after_loop_line],244 [{"logMessage": logMessage}, {}],245 )246 247 # Continue to trigger the breakpoint with log messages248 self.dap_server.request_continue()249 250 # Verify we hit logpoint breakpoint if it's format has error.251 self.verify_breakpoint_hit([loop_breakpoint_id])252 253 output = self.get_console()254 lines = output.splitlines()255 256 failure_prefix = "Log message has error:"257 logMessage_output = []258 logMessage_failure_output = []259 for line in lines:260 if line.startswith(logMessage_prefix):261 logMessage_output.append(line)262 elif line.startswith(failure_prefix):263 logMessage_failure_output.append(line)264 265 # Verify logMessage failure message266 self.assertEqual(len(logMessage_failure_output), 1)267 self.assertEqual(268 logMessage_failure_output[0].strip(),269 failure_prefix + " missing hex number following '\\x'",270 )271