"""
Test that the process read-write locks don't get in our way.
"""

import os, time
import unittest2
import lldb
from lldbutil import get_stopped_thread, state_type_to_str
from lldbtest import *

class ProcessRWLock(TestBase):

    mydir = os.path.join("python_api", "process")

    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
    @python_api_test
    @dsym_test
    def test_async_step_with_dsym(self):
        """Test that we can step over a line in Async mode."""
        self.buildDsym()
        self.async_step()

    @python_api_test
    @dwarf_test
    def test_async_step_with_dwarf(self):
        """Test that we can step over a line in Async mode."""
        self.buildDwarf()
        self.async_step()

    def setUp(self):
        # Call super's setUp().
        TestBase.setUp(self)
        # Find the line number to break inside main().
        self.line = line_number("main.cpp", "// 'my_char' should print out as 'x'.")
        self.line2 = line_number("main.cpp", "// Set break point at this line and check variable 'my_char'.")

    def async_step(self):
        """Test that we can step over a line in Async mode."""
        exe = os.path.join(os.getcwd(), "a.out")
        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)

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

        breakpoint = target.BreakpointCreateByLocation("main.cpp", self.line)
        self.assertTrue(breakpoint, VALID_BREAKPOINT)

        # Set Async mode
        self.dbg.SetAsync(True)
        listener = lldb.SBListener("test-listener")
        listener.StartListeningForEventClass(self.dbg, lldb.SBProcess.GetBroadcasterClassName(), lldb.SBProcess.eBroadcastBitStateChanged)

        # Launch the process, and do not stop at the entry point.
        process = target.LaunchSimple(None, None, os.getcwd())

        # Wait for a process stopped event
        event = lldb.SBEvent()
        listener.WaitForEvent(1000, event)
        self.assertTrue(event.IsValid(), "Didn't get a valid event")
        self.assertTrue(lldb.SBProcess.EventIsProcessEvent(event), "Didn't get a valid event")
        self.assertTrue(event.GetType() == lldb.SBProcess.eBroadcastBitStateChanged, "Didn't get the expected SBProcess.eBroadcastBitStateChanged event")
        state = lldb.SBProcess.GetStateFromEvent(event)
        self.assertTrue(state == lldb.eStateStopped, "The process is not in a stopped state (%d)" % state)

        thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint)
        self.assertTrue(thread != None, "There should be a thread stopped due to a breakpoint")
        frame = thread.GetFrameAtIndex(0)
        entry = frame.GetLineEntry()
        line1 = entry.GetLine()
        assertTrue(self.line == entry.GetLine(), "Program stopped at a wrong line (got %d, should get %d)" % (entry.GetLine(), self.line))

        self.dbg.GetSelectedTarget().GetProcess().Continue()
        listener.WaitForEvent(1000, event)
        self.assertTrue(event.IsValid(), "Didn't get a valid event")
        self.assertTrue(lldb.SBProcess.EventIsProcessEvent(event), "Didn't get a valid event")
        self.assertTrue(event.GetType() == lldb.SBProcess.eBroadcastBitStateChanged, "Didn't get the expected SBProcess.eBroadcastBitStateChanged event")
        state = lldb.SBProcess.GetStateFromEvent(event)
        self.assertTrue(state == lldb.eStateStopped, "The process is not in a stopped state")

        thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint)
        self.assertTrue(thread != None, "There should be a thread stopped due to breakpoint")
        frame = thread.GetFrameAtIndex(0)
        entry = frame.GetLineEntry()
        assertTrue(self.line2 == entry.GetLine(), "Program stopped at a wrong line (got %d, should get %d)" % (entry.GetLine(), self.line2))


if __name__ == '__main__':
    import atexit
    lldb.SBDebugger.Initialize()
    atexit.register(lambda: lldb.SBDebugger.Terminate())
    unittest2.main()
