reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
"""
Test DarwinLog "source include debug-level" functionality provided by the
StructuredDataDarwinLog plugin.

These tests are currently only supported when running against Darwin
targets.
"""

from __future__ import print_function

import lldb
import platform
import re

from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbtest_config


class DarwinNSLogOutputTestCase(TestBase):
    NO_DEBUG_INFO_TESTCASE = True
    mydir = TestBase.compute_mydir(__file__)

    @skipUnlessDarwin
    @skipIfRemote   # this test is currently written using lldb commands & assumes running on local system

    def setUp(self):
        # Call super's setUp().
        TestBase.setUp(self)
        self.child = None
        self.child_prompt = '(lldb) '
        self.strict_sources = False

        # Source filename.
        self.source = 'main.m'

        # Output filename.
        self.exe_name = self.getBuildArtifact("a.out")
        self.d = {'OBJC_SOURCES': self.source, 'EXE': self.exe_name}

        # Locate breakpoint.
        self.line = line_number(self.source, '// break here')

    def tearDown(self):
        # Shut down the process if it's still running.
        if self.child:
            self.runCmd('process kill')
            self.expect_prompt()
            self.runCmd('quit')

        # Let parent clean up
        super(DarwinNSLogOutputTestCase, self).tearDown()

    def run_lldb_to_breakpoint(self, exe, source_file, line,
                               settings_commands=None):
        # Set self.child_prompt, which is "(lldb) ".
        prompt = self.child_prompt

        # So that the child gets torn down after the test.
        import pexpect
        import sys
        if sys.version_info.major == 3:
          self.child = pexpect.spawnu('%s %s %s' % (lldbtest_config.lldbExec,
                                                    self.lldbOption, exe))
        else:
          self.child = pexpect.spawn('%s %s %s' % (lldbtest_config.lldbExec,
                                                   self.lldbOption, exe))
        child = self.child

        # Turn on logging for what the child sends back.
        if self.TraceOn():
            child.logfile_read = sys.stdout

        # Disable showing of source lines at our breakpoint.
        # This is necessary for the logging tests, because the very
        # text we want to match for output from the running inferior
        # will show up in the source as well.  We don't want the source
        # output to erroneously make a match with our expected output.
        self.runCmd("settings set stop-line-count-before 0")
        self.expect_prompt()
        self.runCmd("settings set stop-line-count-after 0")
        self.expect_prompt()

        # Run any test-specific settings commands now.
        if settings_commands is not None:
            for setting_command in settings_commands:
                self.runCmd(setting_command)
                self.expect_prompt()

        # Set the breakpoint, and run to it.
        child.sendline('breakpoint set -f %s -l %d' % (source_file, line))
        child.expect_exact(prompt)
        child.sendline('run')
        child.expect_exact(prompt)

        # Ensure we stopped at a breakpoint.
        self.runCmd("thread list")
        self.expect(re.compile(r"stop reason = .*breakpoint"))

    def runCmd(self, cmd):
        if self.child:
            self.child.sendline(cmd)

    def expect_prompt(self, exactly=True):
        self.expect(self.child_prompt, exactly=exactly)

    def expect(self, pattern, exactly=False, *args, **kwargs):
        if exactly:
            return self.child.expect_exact(pattern, *args, **kwargs)
        return self.child.expect(pattern, *args, **kwargs)

    def do_test(self, expect_regexes=None, settings_commands=None):
        """ Run a test. """
        self.build(dictionary=self.d)
        self.setTearDownCleanup(dictionary=self.d)

        exe = self.getBuildArtifact(self.exe_name)
        self.run_lldb_to_breakpoint(exe, self.source, self.line,
                                    settings_commands=settings_commands)
        self.expect_prompt()

        # Now go.
        self.runCmd("process continue")
        self.expect(expect_regexes)

    def test_nslog_output_is_displayed(self):
        """Test that NSLog() output shows up in the command-line debugger."""
        self.do_test(expect_regexes=[
            re.compile(r"(This is a message from NSLog)"),
            re.compile(r"Process \d+ exited with status")
        ])
        self.assertIsNotNone(self.child.match)
        self.assertGreater(len(self.child.match.groups()), 0)
        self.assertEqual(
            "This is a message from NSLog",
            self.child.match.group(1))

    def test_nslog_output_is_suppressed_with_env_var(self):
        """Test that NSLog() output does not show up with the ignore env var."""
        # This test will only work properly on macOS 10.12+.  Skip it on earlier versions.
        # This will require some tweaking on iOS.
        match = re.match(r"^\d+\.(\d+)", platform.mac_ver()[0])
        if match is None or int(match.group(1)) < 12:
            self.skipTest("requires macOS 10.12 or higher")

        self.do_test(
            expect_regexes=[
                re.compile(r"(This is a message from NSLog)"),
                re.compile(r"Process \d+ exited with status")
            ],
            settings_commands=[
                "settings set target.env-vars "
                "\"IDE_DISABLED_OS_ACTIVITY_DT_MODE=1\""
            ])
        self.assertIsNotNone(self.child.match)
        self.assertEqual(len(self.child.match.groups()), 0)