<commit_before>#include <limits.h>
#include "gtest/gtest.h"

#include "Plugins/Process/Linux/ThreadStateCoordinator.h"

using namespace lldb_private;

namespace
{
    const ThreadStateCoordinator::ThreadIDSet EMPTY_THREAD_ID_SET;

    void
    NOPLogger (const char *format, va_list args)
    {
        // Do nothing.
    }

    void
    StdoutLogger (const char *format, va_list args)
    {
        // Print to stdout.
        vprintf (format, args);
        printf ("\n");
    }

    // These are single-line macros so that IDE integration of gtest results puts
    // the error markers on the correct failure point within the gtest.

#define ASSERT_PROCESS_NEXT_EVENT_SUCCEEDS() ASSERT_EQ (ThreadStateCoordinator::eventLoopResultContinue, m_coordinator.ProcessNextEvent ()); \
if (HasError ()) { printf ("unexpected error in processing of event, error: %s\n", m_error_string.c_str ()); } \
ASSERT_EQ (false, HasError ());

#define ASSERT_PROCESS_NEXT_EVENT_FAILS() ASSERT_EQ (ThreadStateCoordinator::eventLoopResultContinue, m_coordinator.ProcessNextEvent ()); \
ASSERT_EQ (true, HasError ());

    class ThreadStateCoordinatorTest: public ::testing::Test
    {
    protected:
        // Constants.
        const lldb::tid_t TRIGGERING_TID      = 4105;
        const lldb::tid_t PENDING_STOP_TID    = 3;
        const lldb::tid_t PENDING_STOP_TID_02 = 29016;
        const lldb::tid_t NEW_THREAD_TID      = 1234;

        // Member variables.
        bool m_error_called = false;
        std::string m_error_string;

        ThreadStateCoordinator m_coordinator;

        bool m_deferred_notification_called;
        lldb::tid_t m_deferred_notification_tid;

        ThreadStateCoordinator::ThreadIDSet m_requested_stop_tids;

        // Constructors.
        ThreadStateCoordinatorTest () :
        m_error_called (false),
        m_error_string (),
        m_coordinator (StdoutLogger),
        m_deferred_notification_called (false),
        m_deferred_notification_tid (0),
        m_requested_stop_tids ()
        {
        }

        // Member functions.

        // Error handling.
        void
        SetErrorString (const std::string &error_string)
        {
            m_error_called = true;
            m_error_string = error_string;
            printf ("received error: %s (test might be expecting)\n", error_string.c_str ());
        }

        ThreadStateCoordinator::ErrorFunction
        GetErrorFunction ()
        {
            using namespace std::placeholders;
            return std::bind(&ThreadStateCoordinatorTest::SetErrorString, this, _1);
        }

        bool
        HasError () const
        {
            return m_error_called;
        }

        // Deferred notificaton reception.
        void
        DeferredStopNotificationHandler (lldb::tid_t triggered_tid)
        {
            m_deferred_notification_called = true;
            m_deferred_notification_tid = triggered_tid;
        }

        ThreadStateCoordinator::ThreadIDFunction
        GetDeferredStopNotificationFunction ()
        {
            using namespace std::placeholders;
            return std::bind(&ThreadStateCoordinatorTest::DeferredStopNotificationHandler, this, _1);
        }

        bool
        DidFireDeferredNotification () const
        {
            return m_deferred_notification_called;
        }

        lldb::tid_t
        GetDeferredNotificationTID () const
        {
            return m_deferred_notification_tid;
        }

        // Stop request call reception.
        void
        ThreadStopRequested (lldb::tid_t stop_tid)
        {
            m_requested_stop_tids.insert (stop_tid);
        }

        ThreadStateCoordinator::ThreadIDFunction
        GetStopRequestFunction ()
        {
            using namespace std::placeholders;
            return std::bind(&ThreadStateCoordinatorTest::ThreadStopRequested, this, _1);
        }

        ThreadStateCoordinator::ThreadIDSet::size_type
        GetRequestedStopCount () const
        {
            return m_requested_stop_tids.size();
        }

        bool
        DidRequestStopForTid (lldb::tid_t tid)
        {
            return m_requested_stop_tids.find (tid) != m_requested_stop_tids.end ();
        }

        // Test state initialization helpers.
        void
        SetupKnownRunningThread (lldb::tid_t tid)
        {
            NotifyThreadCreate (tid, false);
            ASSERT_PROCESS_NEXT_EVENT_SUCCEEDS ();
        }

        void
        SetupKnownStoppedThread (lldb::tid_t tid)
        {
            NotifyThreadCreate (tid, true);
            ASSERT_PROCESS_NEXT_EVENT_SUCCEEDS ();
        }

        // Convenience wrappers for ThreadStateCoordinator, using defaults for expected arguments
        // that plug into the test case handlers.
        void
        CallAfterThreadsStop (lldb::tid_t deferred_tid,
                              const ThreadStateCoordinator::ThreadIDSet &pending_stop_wait_tids)
        {
            m_coordinator.CallAfterThreadsStop (deferred_tid,
                                                pending_stop_wait_tids,
                                                GetStopRequestFunction (),
                                                GetDeferredStopNotificationFunction (),
                                                GetErrorFunction ());
        }

        void
        CallAfterRunningThreadsStop (lldb::tid_t deferred_tid)
        {
            m_coordinator.CallAfterRunningThreadsStop (deferred_tid,
                                                       GetStopRequestFunction (),
                                                       GetDeferredStopNotificationFunction (),
                                                       GetErrorFunction ());
        }

        void
        NotifyThreadCreate (lldb::tid_t stopped_tid, bool thread_is_stopped)
        {
            m_coordinator.NotifyThreadCreate (stopped_tid, thread_is_stopped, GetErrorFunction ());
        }

        void
        NotifyThreadStop (lldb::tid_t stopped_tid)
        {
            m_coordinator.NotifyThreadStop (stopped_tid, GetErrorFunction ());
        }

        void
        NotifyThreadDeath (lldb::tid_t tid)
        {
            m_coordinator.NotifyThreadDeath (tid, GetErrorFunction ());
        }
};
}

TEST_F (ThreadStateCoordinatorTest, StopCoordinatorWorksNoPriorEvents)
{
    m_coordinator.StopCoordinator ();
    ASSERT_EQ (ThreadStateCoordinator::eventLoopResultStop, m_coordinator.ProcessNextEvent ());
    ASSERT_EQ (false, HasError ());
}

TEST_F (ThreadStateCoordinatorTest, NotifyThreadCreateSignalsErrorOnAlreadyKnownThread)
{
    // Let the coordinator know about our thread.
    SetupKnownStoppedThread (TRIGGERING_TID);

    // Notify an unknown thread has stopped.
    NotifyThreadCreate (TRIGGERING_TID, true);
    ASSERT_PROCESS_NEXT_EVENT_FAILS ();
}


TEST_F (ThreadStateCoordinatorTest, NotifyThreadDeathSignalsErrorOnUnknownThread)
{
    const lldb::tid_t UNKNOWN_TID = 678;

    // Notify an unknown thread has stopped.
    NotifyThreadDeath (UNKNOWN_TID);
    ASSERT_PROCESS_NEXT_EVENT_FAILS ();
}

TEST_F (ThreadStateCoordinatorTest, NotifyThreadStopSignalsErrorOnUnknownThread)
{
    const lldb::tid_t UNKNOWN_TID = 678;

    // Notify an unknown thread has stopped.
    NotifyThreadStop (UNKNOWN_TID);
    ASSERT_PROCESS_NEXT_EVENT_FAILS ();
}

TEST_F (ThreadStateCoordinatorTest, CallAfterTheadsStopSignalsErrorOnUnknownDeferredThread)
{
    const lldb::tid_t UNKNOWN_TRIGGER_TID = 678;

    // Defer notify for an unknown thread.
    CallAfterThreadsStop (UNKNOWN_TRIGGER_TID,<commit_msg>Fix stale comments in new tests.<commit_after>#include <limits.h>
#include "gtest/gtest.h"

#include "Plugins/Process/Linux/ThreadStateCoordinator.h"

using namespace lldb_private;

namespace
{
    const ThreadStateCoordinator::ThreadIDSet EMPTY_THREAD_ID_SET;

    void
    NOPLogger (const char *format, va_list args)
    {
        // Do nothing.
    }

    void
    StdoutLogger (const char *format, va_list args)
    {
        // Print to stdout.
        vprintf (format, args);
        printf ("\n");
    }

    // These are single-line macros so that IDE integration of gtest results puts
    // the error markers on the correct failure point within the gtest.

#define ASSERT_PROCESS_NEXT_EVENT_SUCCEEDS() ASSERT_EQ (ThreadStateCoordinator::eventLoopResultContinue, m_coordinator.ProcessNextEvent ()); \
if (HasError ()) { printf ("unexpected error in processing of event, error: %s\n", m_error_string.c_str ()); } \
ASSERT_EQ (false, HasError ());

#define ASSERT_PROCESS_NEXT_EVENT_FAILS() ASSERT_EQ (ThreadStateCoordinator::eventLoopResultContinue, m_coordinator.ProcessNextEvent ()); \
ASSERT_EQ (true, HasError ());

    class ThreadStateCoordinatorTest: public ::testing::Test
    {
    protected:
        // Constants.
        const lldb::tid_t TRIGGERING_TID      = 4105;
        const lldb::tid_t PENDING_STOP_TID    = 3;
        const lldb::tid_t PENDING_STOP_TID_02 = 29016;
        const lldb::tid_t NEW_THREAD_TID      = 1234;

        // Member variables.
        bool m_error_called = false;
        std::string m_error_string;

        ThreadStateCoordinator m_coordinator;

        bool m_deferred_notification_called;
        lldb::tid_t m_deferred_notification_tid;

        ThreadStateCoordinator::ThreadIDSet m_requested_stop_tids;

        // Constructors.
        ThreadStateCoordinatorTest () :
        m_error_called (false),
        m_error_string (),
        m_coordinator (StdoutLogger),
        m_deferred_notification_called (false),
        m_deferred_notification_tid (0),
        m_requested_stop_tids ()
        {
        }

        // Member functions.

        // Error handling.
        void
        SetErrorString (const std::string &error_string)
        {
            m_error_called = true;
            m_error_string = error_string;
            printf ("received error: %s (test might be expecting)\n", error_string.c_str ());
        }

        ThreadStateCoordinator::ErrorFunction
        GetErrorFunction ()
        {
            using namespace std::placeholders;
            return std::bind(&ThreadStateCoordinatorTest::SetErrorString, this, _1);
        }

        bool
        HasError () const
        {
            return m_error_called;
        }

        // Deferred notificaton reception.
        void
        DeferredStopNotificationHandler (lldb::tid_t triggered_tid)
        {
            m_deferred_notification_called = true;
            m_deferred_notification_tid = triggered_tid;
        }

        ThreadStateCoordinator::ThreadIDFunction
        GetDeferredStopNotificationFunction ()
        {
            using namespace std::placeholders;
            return std::bind(&ThreadStateCoordinatorTest::DeferredStopNotificationHandler, this, _1);
        }

        bool
        DidFireDeferredNotification () const
        {
            return m_deferred_notification_called;
        }

        lldb::tid_t
        GetDeferredNotificationTID () const
        {
            return m_deferred_notification_tid;
        }

        // Stop request call reception.
        void
        ThreadStopRequested (lldb::tid_t stop_tid)
        {
            m_requested_stop_tids.insert (stop_tid);
        }

        ThreadStateCoordinator::ThreadIDFunction
        GetStopRequestFunction ()
        {
            using namespace std::placeholders;
            return std::bind(&ThreadStateCoordinatorTest::ThreadStopRequested, this, _1);
        }

        ThreadStateCoordinator::ThreadIDSet::size_type
        GetRequestedStopCount () const
        {
            return m_requested_stop_tids.size();
        }

        bool
        DidRequestStopForTid (lldb::tid_t tid)
        {
            return m_requested_stop_tids.find (tid) != m_requested_stop_tids.end ();
        }

        // Test state initialization helpers.
        void
        SetupKnownRunningThread (lldb::tid_t tid)
        {
            NotifyThreadCreate (tid, false);
            ASSERT_PROCESS_NEXT_EVENT_SUCCEEDS ();
        }

        void
        SetupKnownStoppedThread (lldb::tid_t tid)
        {
            NotifyThreadCreate (tid, true);
            ASSERT_PROCESS_NEXT_EVENT_SUCCEEDS ();
        }

        // Convenience wrappers for ThreadStateCoordinator, using defaults for expected arguments
        // that plug into the test case handlers.
        void
        CallAfterThreadsStop (lldb::tid_t deferred_tid,
                              const ThreadStateCoordinator::ThreadIDSet &pending_stop_wait_tids)
        {
            m_coordinator.CallAfterThreadsStop (deferred_tid,
                                                pending_stop_wait_tids,
                                                GetStopRequestFunction (),
                                                GetDeferredStopNotificationFunction (),
                                                GetErrorFunction ());
        }

        void
        CallAfterRunningThreadsStop (lldb::tid_t deferred_tid)
        {
            m_coordinator.CallAfterRunningThreadsStop (deferred_tid,
                                                       GetStopRequestFunction (),
                                                       GetDeferredStopNotificationFunction (),
                                                       GetErrorFunction ());
        }

        void
        NotifyThreadCreate (lldb::tid_t stopped_tid, bool thread_is_stopped)
        {
            m_coordinator.NotifyThreadCreate (stopped_tid, thread_is_stopped, GetErrorFunction ());
        }

        void
        NotifyThreadStop (lldb::tid_t stopped_tid)
        {
            m_coordinator.NotifyThreadStop (stopped_tid, GetErrorFunction ());
        }

        void
        NotifyThreadDeath (lldb::tid_t tid)
        {
            m_coordinator.NotifyThreadDeath (tid, GetErrorFunction ());
        }
};
}

TEST_F (ThreadStateCoordinatorTest, StopCoordinatorWorksNoPriorEvents)
{
    m_coordinator.StopCoordinator ();
    ASSERT_EQ (ThreadStateCoordinator::eventLoopResultStop, m_coordinator.ProcessNextEvent ());
    ASSERT_EQ (false, HasError ());
}

TEST_F (ThreadStateCoordinatorTest, NotifyThreadCreateSignalsErrorOnAlreadyKnownThread)
{
    // Let the coordinator know about our thread.
    SetupKnownStoppedThread (TRIGGERING_TID);

    // Notify the thread was created - again.
    NotifyThreadCreate (TRIGGERING_TID, true);

    // This should error out.
    ASSERT_PROCESS_NEXT_EVENT_FAILS ();
}


TEST_F (ThreadStateCoordinatorTest, NotifyThreadDeathSignalsErrorOnUnknownThread)
{
    const lldb::tid_t UNKNOWN_TID = 678;

    // Notify an unknown thread has died.
    NotifyThreadDeath (UNKNOWN_TID);

    // This should error out.
    ASSERT_PROCESS_NEXT_EVENT_FAILS ();
}

TEST_F (ThreadStateCoordinatorTest, NotifyThreadStopSignalsErrorOnUnknownThread)
{
    const lldb::tid_t UNKNOWN_TID = 678;

    // Notify an unknown thread has stopped.
    NotifyThreadStop (UNKNOWN_TID);
    ASSERT_PROCESS_NEXT_EVENT_FAILS ();
}

TEST_F (ThreadStateCoordinatorTest, CallAfterTheadsStopSignalsErrorOnUnknownDeferredThread)
{
    const lldb::tid_t UNKNOWN_TRIGGER_TID = 678;

    // Defer notify for an unknown thread.
    CallAfterThreadsStop (UNKNOWN_TRIGGER_TID,
{'fraction_non_alphanumeric': 0.07363654262650128, 'fraction_numerical': 0.00380652359388331, 'mean_word_length': 2.2400595364660854, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 28, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '258436', 'n_tokens_mistral': 4348, 'n_tokens_neox': 4170, 'n_words': 804}