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