"""
Test thread step-in, step-over and step-out work with the "Avoid no debug" option.
"""

from __future__ import print_function


import os
import re
import sys

import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil


class StepAvoidsNoDebugTestCase(TestBase):

    mydir = TestBase.compute_mydir(__file__)

    @add_test_categories(['pyapi'])
    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr32343")
    def test_step_out_with_python(self):
        """Test stepping out using avoid-no-debug with dsyms."""
        self.build()
        self.get_to_starting_point()
        self.do_step_out_past_nodebug()

    @add_test_categories(['pyapi'])
    @decorators.expectedFailureAll(
        compiler="gcc", bugnumber="llvm.org/pr28549")
    @decorators.expectedFailureAll(
        compiler="clang",
        compiler_version=[
            ">=",
            "3.9"],
        archs=["i386"],
        bugnumber="llvm.org/pr28549")
    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr32343")
    def test_step_over_with_python(self):
        """Test stepping over using avoid-no-debug with dwarf."""
        self.build()
        self.get_to_starting_point()
        self.do_step_over_past_nodebug()

    @add_test_categories(['pyapi'])
    @decorators.expectedFailureAll(
        compiler="gcc", bugnumber="llvm.org/pr28549")
    @decorators.expectedFailureAll(
        compiler="clang",
        compiler_version=[
            ">=",
            "3.9"],
        archs=["i386"],
        bugnumber="llvm.org/pr28549")
    @expectedFailureAll(oslist=["ios", "tvos", "bridgeos"], bugnumber="<rdar://problem/34026777>")  # lldb doesn't step past last source line in function on arm64
    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr32343")
    def test_step_in_with_python(self):
        """Test stepping in using avoid-no-debug with dwarf."""
        self.build()
        self.get_to_starting_point()
        self.do_step_in_past_nodebug()

    def setUp(self):
        TestBase.setUp(self)
        self.main_source = "with-debug.c"
        self.main_source_spec = lldb.SBFileSpec("with-debug.c")
        self.dbg.HandleCommand(
            "settings set target.process.thread.step-out-avoid-nodebug true")

    def tearDown(self):
        self.dbg.HandleCommand(
            "settings set target.process.thread.step-out-avoid-nodebug false")
        TestBase.tearDown(self)

    def hit_correct_line(self, pattern):
        target_line = line_number(self.main_source, pattern)
        self.assertTrue(
            target_line != 0,
            "Could not find source pattern " +
            pattern)
        cur_line = self.thread.frames[0].GetLineEntry().GetLine()
        self.assertTrue(
            cur_line == target_line,
            "Stepped to line %d instead of expected %d with pattern '%s'." %
            (cur_line,
             target_line,
             pattern))

    def hit_correct_function(self, pattern):
        name = self.thread.frames[0].GetFunctionName()
        self.assertTrue(
            pattern in name, "Got to '%s' not the expected function '%s'." %
            (name, pattern))

    def get_to_starting_point(self):
        exe = self.getBuildArtifact("a.out")
        error = lldb.SBError()

        self.target = self.dbg.CreateTarget(exe)
        self.assertTrue(self.target, VALID_TARGET)

        inner_bkpt = self.target.BreakpointCreateBySourceRegex(
            "Stop here and step out of me", self.main_source_spec)
        self.assertTrue(inner_bkpt, VALID_BREAKPOINT)

        # Now launch the process, and do not stop at entry point.
        self.process = self.target.LaunchSimple(
            None, None, self.get_process_working_directory())

        self.assertTrue(self.process, PROCESS_IS_VALID)

        # Now finish, and make sure the return value is correct.
        threads = lldbutil.get_threads_stopped_at_breakpoint(
            self.process, inner_bkpt)
        self.assertTrue(len(threads) == 1, "Stopped at inner breakpoint.")
        self.thread = threads[0]

    def do_step_out_past_nodebug(self):
        # The first step out takes us to the called_from_nodebug frame, just to make sure setting
        # step-out-avoid-nodebug doesn't change the behavior in frames with
        # debug info.
        self.thread.StepOut()
        self.hit_correct_line(
            "intermediate_return_value = called_from_nodebug_actual(some_value)")
        self.thread.StepOut()
        self.hit_correct_line(
            "int return_value = no_debug_caller(5, called_from_nodebug)")

    def do_step_over_past_nodebug(self):
        self.thread.StepOver()
        self.hit_correct_line(
            "intermediate_return_value = called_from_nodebug_actual(some_value)")
        self.thread.StepOver()
        self.hit_correct_line("return intermediate_return_value")
        self.thread.StepOver()
        # Note, lldb doesn't follow gdb's distinction between "step-out" and "step-over/step-in"
        # when exiting a frame.  In all cases we leave the pc at the point where we exited the
        # frame.  In gdb, step-over/step-in move to the end of the line they stepped out to.
        # If we ever change this we will need to fix this test.
        self.hit_correct_line(
            "int return_value = no_debug_caller(5, called_from_nodebug)")

    def do_step_in_past_nodebug(self):
        self.thread.StepInto()
        self.hit_correct_line(
            "intermediate_return_value = called_from_nodebug_actual(some_value)")
        self.thread.StepInto()
        self.hit_correct_line("return intermediate_return_value")
        self.thread.StepInto()
        # Note, lldb doesn't follow gdb's distinction between "step-out" and "step-over/step-in"
        # when exiting a frame.  In all cases we leave the pc at the point where we exited the
        # frame.  In gdb, step-over/step-in move to the end of the line they stepped out to.
        # If we ever change this we will need to fix this test.
        self.hit_correct_line(
            "int return_value = no_debug_caller(5, called_from_nodebug)")
