1""" 2Test DarwinLog "source include debug-level" functionality provided by the 3StructuredDataDarwinLog plugin. 4 5These tests are currently only supported when running against Darwin 6targets. 7""" 8 9 10import lldb 11import platform 12import re 13import sys 14 15from lldbsuite.test.decorators import * 16from lldbsuite.test.lldbtest import * 17from lldbsuite.test import lldbtest_config 18 19 20class DarwinNSLogOutputTestCase(TestBase): 21 NO_DEBUG_INFO_TESTCASE = True 22 23 def setUp(self): 24 # Call super's setUp(). 25 TestBase.setUp(self) 26 self.child = None 27 self.child_prompt = "(lldb) " 28 self.strict_sources = False 29 30 # Source filename. 31 self.source = "main.m" 32 33 # Output filename. 34 self.exe_name = self.getBuildArtifact("a.out") 35 self.d = {"OBJC_SOURCES": self.source, "EXE": self.exe_name} 36 37 # Locate breakpoint. 38 self.line = line_number(self.source, "// break here") 39 40 def tearDown(self): 41 # Shut down the process if it's still running. 42 if self.child: 43 self.runCmd("process kill") 44 self.expect_prompt() 45 self.runCmd("quit") 46 47 # Let parent clean up 48 super(DarwinNSLogOutputTestCase, self).tearDown() 49 50 def run_lldb_to_breakpoint(self, exe, source_file, line, settings_commands=None): 51 # Set self.child_prompt, which is "(lldb) ". 52 prompt = self.child_prompt 53 54 # So that the child gets torn down after the test. 55 import pexpect 56 57 self.child = pexpect.spawn( 58 "%s %s %s" % (lldbtest_config.lldbExec, self.lldbOption, exe), 59 encoding="utf-8", 60 ) 61 child = self.child 62 63 # Turn on logging for what the child sends back. 64 if self.TraceOn(): 65 child.logfile_read = sys.stdout 66 67 # Disable showing of source lines at our breakpoint. 68 # This is necessary for the logging tests, because the very 69 # text we want to match for output from the running inferior 70 # will show up in the source as well. We don't want the source 71 # output to erroneously make a match with our expected output. 72 self.runCmd("settings set stop-line-count-before 0") 73 self.expect_prompt() 74 self.runCmd("settings set stop-line-count-after 0") 75 self.expect_prompt() 76 77 # Run any test-specific settings commands now. 78 if settings_commands is not None: 79 for setting_command in settings_commands: 80 self.runCmd(setting_command) 81 self.expect_prompt() 82 83 # Set the breakpoint, and run to it. 84 child.sendline("breakpoint set -f %s -l %d" % (source_file, line)) 85 child.expect_exact(prompt) 86 child.sendline("run") 87 child.expect_exact(prompt) 88 89 # Ensure we stopped at a breakpoint. 90 self.runCmd("thread list") 91 self.expect(re.compile(r"stop reason = .*breakpoint")) 92 93 def runCmd(self, cmd): 94 if self.child: 95 self.child.sendline(cmd) 96 97 def expect_prompt(self, exactly=True): 98 self.expect(self.child_prompt, exactly=exactly) 99 100 def expect(self, pattern, exactly=False, *args, **kwargs): 101 if exactly: 102 return self.child.expect_exact(pattern, *args, **kwargs) 103 return self.child.expect(pattern, *args, **kwargs) 104 105 def do_test(self, expect_regexes=None, settings_commands=None): 106 """Run a test.""" 107 self.build(dictionary=self.d) 108 self.setTearDownCleanup(dictionary=self.d) 109 110 exe = self.getBuildArtifact(self.exe_name) 111 self.run_lldb_to_breakpoint( 112 exe, self.source, self.line, settings_commands=settings_commands 113 ) 114 self.expect_prompt() 115 116 # Now go. 117 self.runCmd("process continue") 118 self.expect(expect_regexes) 119 120 @skipIfAsan # avoid dealing with pexpect timeout flakyness on bots 121 @skipIf(oslist=["linux"], archs=["arm", "aarch64"]) 122 @skipUnlessDarwin 123 @skipIfRemote # this test is currently written using lldb commands & assumes running on local system 124 def test_nslog_output_is_displayed(self): 125 """Test that NSLog() output shows up in the command-line debugger.""" 126 self.do_test( 127 expect_regexes=[ 128 re.compile(r"(This is a message from NSLog)"), 129 re.compile(r"Process \d+ exited with status"), 130 ] 131 ) 132 self.assertIsNotNone(self.child.match) 133 self.assertGreater(len(self.child.match.groups()), 0) 134 self.assertEqual("This is a message from NSLog", self.child.match.group(1)) 135 136 @skipIfAsan # avoid dealing with pexpect timeout flakyness on bots 137 @skipIf(oslist=["linux"], archs=["arm", "aarch64"]) 138 @skipUnlessDarwin 139 @skipIfRemote # this test is currently written using lldb commands & assumes running on local system 140 def test_nslog_output_is_suppressed_with_env_var(self): 141 """Test that NSLog() output does not show up with the ignore env var.""" 142 # This test will only work properly on macOS 10.12+. Skip it on earlier versions. 143 # This will require some tweaking on iOS. 144 match = re.match(r"^\d+\.(\d+)", platform.mac_ver()[0]) 145 if match is None or int(match.group(1)) < 12: 146 self.skipTest("requires macOS 10.12 or higher") 147 148 self.do_test( 149 expect_regexes=[ 150 re.compile(r"(This is a message from NSLog)"), 151 re.compile(r"Process \d+ exited with status"), 152 ], 153 settings_commands=[ 154 "settings set target.env-vars " '"IDE_DISABLED_OS_ACTIVITY_DT_MODE=1"' 155 ], 156 ) 157 self.assertIsNotNone(self.child.match) 158 self.assertEqual(len(self.child.match.groups()), 0) 159