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