// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

#include "pch.h"
#include "../Remoting/Monarch.h"
#include "../Remoting/CommandlineArgs.h"
#include "../Remoting/FindTargetWindowArgs.h"
#include "../Remoting/ProposeCommandlineResult.h"
#include "../inc/WindowingBehavior.h"

using namespace Microsoft::Console;
using namespace WEX::Logging;
using namespace WEX::TestExecution;
using namespace WEX::Common;

using namespace winrt;
using namespace winrt::Microsoft::Terminal;

namespace RemotingUnitTests
{
    struct MockDesktopManager : implements<MockDesktopManager, IVirtualDesktopManager>
    {
        IFACEMETHOD(GetWindowDesktopId)
        (HWND /*topLevelWindow*/, GUID* /*desktopId*/)
        {
            VERIFY_IS_TRUE(false, L"We shouldn't need GetWindowDesktopId in the tests.");
            return E_FAIL;
        }
        IFACEMETHOD(MoveWindowToDesktop)
        (HWND /*topLevelWindow*/, REFGUID /*desktopId*/)
        {
            VERIFY_IS_TRUE(false, L"We shouldn't need GetWindowDesktopId in the tests.");
            return E_FAIL;
        }
        IFACEMETHOD(IsWindowOnCurrentVirtualDesktop)
        (HWND topLevelWindow, BOOL* onCurrentDesktop)
        {
            if (pfnIsWindowOnCurrentVirtualDesktop)
            {
                return pfnIsWindowOnCurrentVirtualDesktop(topLevelWindow, onCurrentDesktop);
            }
            VERIFY_IS_TRUE(false, L"You didn't set up the pfnIsWindowOnCurrentVirtualDesktop for this test!");
            return E_FAIL;
        }

        std::function<HRESULT(HWND, BOOL*)> pfnIsWindowOnCurrentVirtualDesktop;
    };

#define DIE                                                                \
    {                                                                      \
        throw winrt::hresult_error(winrt::hresult{ (int32_t)0x800706ba }); \
    };

    // This is a silly helper struct.
    // It will always throw an hresult_error of "RPC server is unavailable" on any of its methods.
    // The monarch uses this particular error code to check for a dead peasant vs another exception.
    //
    // In the tests, it's hard to emulate a peasant process being totally dead
    // once the Monarch has captured a reference to it. Since everything's
    // in-proc in the tests, we can't decrement the refcount in such a way that
    // the monarch's reference will throw a catchable exception. Instead, this
    // class can be used to replace a peasant inside a Monarch, to emulate that
    // peasant process dying. Any time the monarch tries to do something to this
    // peasant, it'll throw an exception.

    struct DeadPeasant : implements<DeadPeasant, winrt::Microsoft::Terminal::Remoting::IPeasant>
    {
        DeadPeasant() = default;
        void AssignID(uint64_t /*id*/) DIE;
        uint64_t GetID() DIE;
        winrt::hstring WindowName() DIE;
        winrt::hstring ActiveTabTitle() DIE;
        void ActiveTabTitle(const winrt::hstring& /*value*/) DIE;
        uint64_t GetPID() DIE;
        bool ExecuteCommandline(const Remoting::CommandlineArgs& /*args*/) DIE;
        void ActivateWindow(const Remoting::WindowActivatedArgs& /*args*/) DIE;
        void RequestIdentifyWindows() DIE;
        void DisplayWindowId() DIE;
        Remoting::CommandlineArgs InitialArgs() DIE;
        Remoting::WindowActivatedArgs GetLastActivatedArgs() DIE;
        void RequestRename(const Remoting::RenameRequestArgs& /*args*/) DIE;
        void Summon(const Remoting::SummonWindowBehavior& /*args*/) DIE;
        void RequestShowNotificationIcon() DIE;
        void RequestHideNotificationIcon() DIE;
        winrt::hstring GetWindowLayout() DIE;
        void RequestQuitAll() DIE;
        void Quit() DIE;
        void AttachContentToWindow(Remoting::AttachRequest) DIE;
        void SendContent(winrt::Microsoft::Terminal::Remoting::RequestReceiveContentArgs) DIE;
        TYPED_EVENT(WindowActivated, winrt::Windows::Foundation::IInspectable, Remoting::WindowActivatedArgs);
        TYPED_EVENT(ExecuteCommandlineRequested, winrt::Windows::Foundation::IInspectable, Remoting::CommandlineArgs);
        TYPED_EVENT(IdentifyWindowsRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
        TYPED_EVENT(DisplayWindowIdRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
        TYPED_EVENT(RenameRequested, winrt::Windows::Foundation::IInspectable, Remoting::RenameRequestArgs);
        TYPED_EVENT(SummonRequested, winrt::Windows::Foundation::IInspectable, Remoting::SummonWindowBehavior);
        TYPED_EVENT(ShowNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
        TYPED_EVENT(HideNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
        TYPED_EVENT(QuitAllRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
        TYPED_EVENT(QuitRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
        TYPED_EVENT(GetWindowLayoutRequested, winrt::Windows::Foundation::IInspectable, Remoting::GetWindowLayoutArgs);
        TYPED_EVENT(AttachRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::AttachRequest);
        TYPED_EVENT(SendContentRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::RequestReceiveContentArgs);
    };

    // Same idea.
    struct DeadMonarch : implements<DeadMonarch, winrt::Microsoft::Terminal::Remoting::IMonarch>
    {
        DeadMonarch() = default;
        uint64_t GetPID() DIE;
        uint64_t AddPeasant(Remoting::IPeasant /*peasant*/) DIE;
        uint64_t GetNumberOfPeasants() DIE;
        Remoting::ProposeCommandlineResult ProposeCommandline(Remoting::CommandlineArgs /*args*/) DIE;
        void HandleActivatePeasant(Remoting::WindowActivatedArgs /*args*/) DIE;
        void SummonWindow(Remoting::SummonWindowSelectionArgs /*args*/) DIE;
        void SignalClose(uint64_t /*peasantId*/) DIE;

        void SummonAllWindows() DIE;
        bool DoesQuakeWindowExist() DIE;
        winrt::Windows::Foundation::Collections::IVectorView<Remoting::PeasantInfo> GetPeasantInfos() DIE;
        winrt::Windows::Foundation::Collections::IVector<winrt::hstring> GetAllWindowLayouts() DIE;
        void RequestMoveContent(winrt::hstring, winrt::hstring, uint32_t, winrt::Windows::Foundation::IReference<winrt::Windows::Foundation::Rect>) DIE;
        void RequestSendContent(Remoting::RequestReceiveContentArgs) DIE;

        TYPED_EVENT(FindTargetWindowRequested, winrt::Windows::Foundation::IInspectable, Remoting::FindTargetWindowArgs);
        TYPED_EVENT(ShowNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
        TYPED_EVENT(HideNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
        TYPED_EVENT(WindowCreated, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
        TYPED_EVENT(WindowClosed, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
        TYPED_EVENT(QuitAllRequested, winrt::Windows::Foundation::IInspectable, Remoting::QuitAllRequestedArgs);
        TYPED_EVENT(RequestNewWindow, winrt::Windows::Foundation::IInspectable, Remoting::WindowRequestedArgs);
    };

    class RemotingTests
    {
        BEGIN_TEST_CLASS(RemotingTests)
        END_TEST_CLASS()

        TEST_METHOD(CreateMonarch);
        TEST_METHOD(CreatePeasant);
        TEST_METHOD(CreatePeasantWithNew);
        TEST_METHOD(AddPeasants);
        TEST_METHOD(GetPeasantsByID);
        TEST_METHOD(AddPeasantsToNewMonarch);
        TEST_METHOD(RemovePeasantFromMonarchWhenFreed);

        TEST_METHOD(ProposeCommandlineNoWindow);
        TEST_METHOD(ProposeCommandlineGivenWindow);
        TEST_METHOD(ProposeCommandlineNegativeWindow);
        TEST_METHOD(ProposeCommandlineCurrentWindow);
        TEST_METHOD(ProposeCommandlineNonExistentWindow);
        TEST_METHOD(ProposeCommandlineDeadWindow);

        TEST_METHOD(MostRecentWindowSameDesktops);
        TEST_METHOD(MostRecentWindowDifferentDesktops);
        TEST_METHOD(MostRecentWindowMoveDesktops);
        TEST_METHOD(GetMostRecentAnyDesktop);
        TEST_METHOD(MostRecentIsDead);

        TEST_METHOD(MostRecentIsQuake);

        TEST_METHOD(GetPeasantsByName);
        TEST_METHOD(AddNamedPeasantsToNewMonarch);
        TEST_METHOD(LookupNamedPeasantWhenOthersDied);
        TEST_METHOD(LookupNamedPeasantWhenItDied);
        TEST_METHOD(GetMruPeasantAfterNameLookupForDeadPeasant);

        TEST_METHOD(ProposeCommandlineForNamedDeadWindow);

        TEST_METHOD(TestRenameWindowSuccessfully);
        TEST_METHOD(TestRenameSameNameAsAnother);
        TEST_METHOD(TestRenameSameNameAsADeadPeasant);

        TEST_METHOD(TestSummonMostRecentWindow);
        TEST_METHOD(TestSummonNamedWindow);
        TEST_METHOD(TestSummonNamedDeadWindow);
        TEST_METHOD(TestSummonMostRecentDeadWindow);

        TEST_METHOD(TestSummonOnCurrent);
        TEST_METHOD(TestSummonOnCurrentWithName);
        TEST_METHOD(TestSummonOnCurrentDeadWindow);

        TEST_METHOD(TestSummonMostRecentIsQuake);

        TEST_METHOD(TestSummonAfterWindowClose);

        TEST_METHOD(TestProposeCommandlineWithDeadMonarch);

        TEST_CLASS_SETUP(ClassSetup)
        {
            return true;
        }

        static void _closePeasant(const com_ptr<Remoting::implementation::Monarch>& m,
                                  const uint64_t peasantID);

        static void _killPeasant(const com_ptr<Remoting::implementation::Monarch>& m,
                                 const uint64_t peasantID);

        static void _findTargetWindowHelper(const winrt::Windows::Foundation::IInspectable& sender,
                                            const winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs& args);

        static void _findTargetWindowByNameHelper(const winrt::Windows::Foundation::IInspectable& sender,
                                                  const winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs& args);

        // This template that lets us call a private ctor for Monarch/Peasant, unlike make_self.
        // Currently I use a private implementation detail of winrt::make_self,
        // which is bad, but I didn't want to deal with the alternatives.
        template<typename T, typename... Args>
        static winrt::com_ptr<T> make_private(Args&&... args)
        {
            return { new winrt::impl::heap_implements<T>(std::forward<Args>(args)...), winrt::take_ownership_from_abi };
        }
    };

    // Helper to tell the monarch that a peasant is closing, this emulates when
    // a peasant is closed normally instead of when it crashes.
    void RemotingTests::_closePeasant(const com_ptr<Remoting::implementation::Monarch>& m,
                                      const uint64_t peasantID)
    {
        if (peasantID <= 0)
        {
            return;
        }

        m->SignalClose(peasantID);
    }

    // Helper to replace the specified peasant in a monarch with a
    // "DeadPeasant", which will emulate what happens when the peasant process
    // dies.
    void RemotingTests::_killPeasant(const com_ptr<Remoting::implementation::Monarch>& m,
                                     const uint64_t peasantID)
    {
        if (peasantID <= 0)
        {
            return;
        }

        m->_peasants[peasantID] = winrt::make<DeadPeasant>();
    }

    // Helper to get the first argument out of the commandline, and try to
    // convert it to an int.
    void RemotingTests::_findTargetWindowHelper(const winrt::Windows::Foundation::IInspectable& /*sender*/,
                                                const winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs& args)
    {
        const auto arguments = args.Args().Commandline();
        if (arguments.size() > 0)
        {
            const auto index = std::stoi(arguments.at(0).c_str());
            args.ResultTargetWindow(index >= 0 ? index : -1);
        }
    }

    // Helper to get the first argument out of the commandline, and return it as
    // a name to use.
    void RemotingTests::_findTargetWindowByNameHelper(const winrt::Windows::Foundation::IInspectable& /*sender*/,
                                                      const winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs& args)
    {
        const auto arguments = args.Args().Commandline();
        if (arguments.size() > 0)
        {
            args.ResultTargetWindow(WindowingBehaviorUseName);
            args.ResultTargetWindowName(arguments.at(0));
        }
    }

    void RemotingTests::CreateMonarch()
    {
        auto m1 = make_private<Remoting::implementation::Monarch>();
        VERIFY_ARE_EQUAL(GetCurrentProcessId(),
                         m1->GetPID(),
                         L"A Monarch without an explicit PID should use the current PID");

        Log::Comment(L"That's what we need for window process management, but for tests, it'll be more useful to fake the PIDs.");

        auto expectedFakePID = 1234u;
        auto m2 = make_private<Remoting::implementation::Monarch>(expectedFakePID);
        VERIFY_ARE_EQUAL(expectedFakePID,
                         m2->GetPID(),
                         L"A Monarch with an explicit PID should use the one we provided");
    }

    void RemotingTests::CreatePeasant()
    {
        auto p1 = make_private<Remoting::implementation::Peasant>();
        VERIFY_ARE_EQUAL(GetCurrentProcessId(),
                         p1->GetPID(),
                         L"A Peasant without an explicit PID should use the current PID");

        Log::Comment(L"That's what we need for window process management, but for tests, it'll be more useful to fake the PIDs.");

        auto expectedFakePID = 2345u;
        auto p2 = make_private<Remoting::implementation::Monarch>(expectedFakePID);
        VERIFY_ARE_EQUAL(expectedFakePID,
                         p2->GetPID(),
                         L"A Peasant with an explicit PID should use the one we provided");
    }

    void RemotingTests::CreatePeasantWithNew()
    {
        Log::Comment(L"The same thing as the above test, but with `new` instead of insanity on the stack");

        auto p1 = make_private<Remoting::implementation::Peasant>();
        VERIFY_ARE_EQUAL(GetCurrentProcessId(),
                         p1->GetPID(),
                         L"A Peasant without an explicit PID should use the current PID");

        auto expectedFakePID = 2345u;

        auto p2 = make_private<Remoting::implementation::Peasant>(expectedFakePID);
        VERIFY_ARE_EQUAL(expectedFakePID,
                         p2->GetPID(),
                         L"A Peasant with an explicit PID should use the one we provided");
    }

    void RemotingTests::AddPeasants()
    {
        const auto monarch0PID = 12345u;
        const auto peasant1PID = 23456u;
        const auto peasant2PID = 34567u;

        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
        auto p1 = make_private<Remoting::implementation::Peasant>(peasant1PID);
        auto p2 = make_private<Remoting::implementation::Peasant>(peasant2PID);

        VERIFY_ARE_EQUAL(0, p1->GetID());
        VERIFY_ARE_EQUAL(0, p2->GetID());

        m0->AddPeasant(*p1);
        m0->AddPeasant(*p2);

        VERIFY_ARE_EQUAL(1, p1->GetID());
        VERIFY_ARE_EQUAL(2, p2->GetID());
    }

    void RemotingTests::GetPeasantsByID()
    {
        const auto monarch0PID = 12345u;
        const auto peasant1PID = 23456u;
        const auto peasant2PID = 34567u;

        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
        auto p1 = make_private<Remoting::implementation::Peasant>(peasant1PID);
        auto p2 = make_private<Remoting::implementation::Peasant>(peasant2PID);

        VERIFY_ARE_EQUAL(0, p1->GetID());
        VERIFY_ARE_EQUAL(0, p2->GetID());

        m0->AddPeasant(*p1);
        m0->AddPeasant(*p2);

        VERIFY_ARE_EQUAL(1, p1->GetID());
        VERIFY_ARE_EQUAL(2, p2->GetID());

        auto maybeP1 = m0->_getPeasant(1);
        VERIFY_ARE_EQUAL(peasant1PID, maybeP1.GetPID());

        auto maybeP2 = m0->_getPeasant(2);
        VERIFY_ARE_EQUAL(peasant2PID, maybeP2.GetPID());
    }

    void RemotingTests::AddPeasantsToNewMonarch()
    {
        const auto monarch0PID = 12345u;
        const auto peasant1PID = 23456u;
        const auto peasant2PID = 34567u;
        const auto monarch3PID = 45678u;

        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
        auto p1 = make_private<Remoting::implementation::Peasant>(peasant1PID);
        auto p2 = make_private<Remoting::implementation::Peasant>(peasant2PID);
        auto m3 = make_private<Remoting::implementation::Monarch>(monarch3PID);

        VERIFY_ARE_EQUAL(0, p1->GetID());
        VERIFY_ARE_EQUAL(0, p2->GetID());

        m0->AddPeasant(*p1);
        m0->AddPeasant(*p2);

        VERIFY_ARE_EQUAL(1, p1->GetID());
        VERIFY_ARE_EQUAL(2, p2->GetID());

        m3->AddPeasant(*p1);
        m3->AddPeasant(*p2);

        VERIFY_ARE_EQUAL(1, p1->GetID());
        VERIFY_ARE_EQUAL(2, p2->GetID());
    }

    void RemotingTests::RemovePeasantFromMonarchWhenFreed()
    {
        const auto monarch0PID = 12345u;
        const auto peasant1PID = 23456u;
        const auto peasant2PID = 34567u;

        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
        auto p1 = make_private<Remoting::implementation::Peasant>(peasant1PID);
        auto p2 = make_private<Remoting::implementation::Peasant>(peasant2PID);

        VERIFY_ARE_EQUAL(0, p1->GetID());
        VERIFY_ARE_EQUAL(0, p2->GetID());

        m0->AddPeasant(*p1);
        m0->AddPeasant(*p2);

        VERIFY_ARE_EQUAL(1, p1->GetID());
        VERIFY_ARE_EQUAL(2, p2->GetID());

        VERIFY_ARE_EQUAL(2u, m0->_peasants.size());

        Log::Comment(L"Kill peasant 1. Make sure that it gets removed from the monarch.");
        RemotingTests::_killPeasant(m0, p1->GetID());

        auto maybeP2 = m0->_getPeasant(2);
        VERIFY_ARE_EQUAL(peasant2PID, maybeP2.GetPID());

        auto maybeP1 = m0->_getPeasant(1);
        VERIFY_IS_NULL(maybeP1);

        VERIFY_ARE_EQUAL(1u, m0->_peasants.size());
    }

    void RemotingTests::ProposeCommandlineNoWindow()
    {
        Log::Comment(L"Test proposing a commandline that doesn't have a window specified in it");

        const auto monarch0PID = 12345u;

        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
        m0->FindTargetWindowRequested(&RemotingTests::_findTargetWindowHelper);

        std::vector<winrt::hstring> args{};
        Remoting::CommandlineArgs eventArgs{ { args }, { L"" }, SW_NORMAL, L"" };

        auto result = m0->ProposeCommandline(eventArgs);
        VERIFY_ARE_EQUAL(true, result.ShouldCreateWindow());
        VERIFY_ARE_EQUAL(false, (bool)result.Id());

        Log::Comment(L"Add a peasant");
        const auto peasant1PID = 23456u;
        auto p1 = make_private<Remoting::implementation::Peasant>(peasant1PID);
        m0->AddPeasant(*p1);

        Log::Comment(L"Propose the same args again after adding a peasant - we should still return {create new window, no ID}");
        result = m0->ProposeCommandline(eventArgs);
        VERIFY_ARE_EQUAL(true, result.ShouldCreateWindow());
        VERIFY_ARE_EQUAL(false, (bool)result.Id());
    }

    void RemotingTests::ProposeCommandlineGivenWindow()
    {
        Log::Comment(L"Test proposing a commandline for a window that currently exists");

        const auto monarch0PID = 12345u;
        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
        m0->FindTargetWindowRequested(&RemotingTests::_findTargetWindowHelper);

        Log::Comment(L"Add a peasant");
        const auto peasant1PID = 23456u;
        auto p1 = make_private<Remoting::implementation::Peasant>(peasant1PID);
        m0->AddPeasant(*p1);

        p1->ExecuteCommandlineRequested([&](auto&&, const Remoting::CommandlineArgs& cmdlineArgs) {
            Log::Comment(L"Commandline dispatched to p1");
            VERIFY_IS_GREATER_THAN(cmdlineArgs.Commandline().size(), 1u);
            VERIFY_ARE_EQUAL(L"arg[1]", cmdlineArgs.Commandline().at(1));
        });

        std::vector<winrt::hstring> args{ L"1", L"arg[1]" };
        Remoting::CommandlineArgs eventArgs{ { args }, { L"" }, SW_NORMAL, L"" };

        auto result = m0->ProposeCommandline(eventArgs);
        VERIFY_ARE_EQUAL(false, result.ShouldCreateWindow());
        VERIFY_ARE_EQUAL(false, (bool)result.Id());
    }
    void RemotingTests::ProposeCommandlineNegativeWindow()
    {
        Log::Comment(L"Test proposing a commandline for an invalid window ID, like -1");

        const auto monarch0PID = 12345u;
        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
        m0->FindTargetWindowRequested(&RemotingTests::_findTargetWindowHelper);

        Log::Comment(L"Add a peasant");
        const auto peasant1PID = 23456u;
        auto p1 = make_private<Remoting::implementation::Peasant>(peasant1PID);
        m0->AddPeasant(*p1);

        {
            std::vector<winrt::hstring> args{ L"-1" };
            Remoting::CommandlineArgs eventArgs{ { args }, { L"" }, SW_NORMAL, L"" };

            auto result = m0->ProposeCommandline(eventArgs);
            VERIFY_ARE_EQUAL(true, result.ShouldCreateWindow());
            VERIFY_ARE_EQUAL(false, (bool)result.Id());
        }
        {
            std::vector<winrt::hstring> args{ L"-2" };
            Remoting::CommandlineArgs eventArgs{ { args }, { L"" }, SW_NORMAL, L"" };

            auto result = m0->ProposeCommandline(eventArgs);
            VERIFY_ARE_EQUAL(true, result.ShouldCreateWindow());
            VERIFY_ARE_EQUAL(false, (bool)result.Id());
        }
    }
    void RemotingTests::ProposeCommandlineCurrentWindow()
    {
        Log::Comment(L"Test proposing a commandline for the current window (ID=0)");

        const auto monarch0PID = 12345u;
        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
        m0->FindTargetWindowRequested(&RemotingTests::_findTargetWindowHelper);

        Log::Comment(L"Add a peasant");
        const auto peasant1PID = 23456u;
        auto p1 = make_private<Remoting::implementation::Peasant>(peasant1PID);
        m0->AddPeasant(*p1);
        p1->ExecuteCommandlineRequested([&](auto&&, const Remoting::CommandlineArgs& cmdlineArgs) {
            Log::Comment(L"Commandline dispatched to p1");
            VERIFY_IS_GREATER_THAN(cmdlineArgs.Commandline().size(), 1u);
            VERIFY_ARE_EQUAL(L"arg[1]", cmdlineArgs.Commandline().at(1));
        });

        std::vector<winrt::hstring> p1Args{ L"0", L"arg[1]" };
        std::vector<winrt::hstring> p2Args{ L"0", L"this is for p2" };

        {
            Log::Comment(L"Manually activate the first peasant");
            // This would usually happen immediately when the window is created, but
            // there's no actual window in these tests.
            Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
                                                         winrt::guid{},
                                                         winrt::clock().now() };
            p1->ActivateWindow(activatedArgs);

            Remoting::CommandlineArgs eventArgs{ { p1Args }, { L"" }, SW_NORMAL, L"" };

            auto result = m0->ProposeCommandline(eventArgs);
            VERIFY_ARE_EQUAL(false, result.ShouldCreateWindow());
            VERIFY_ARE_EQUAL(false, (bool)result.Id());
        }

        Log::Comment(L"Add a second peasant");
        const auto peasant2PID = 34567u;
        auto p2 = make_private<Remoting::implementation::Peasant>(peasant2PID);
        m0->AddPeasant(*p2);
        p2->ExecuteCommandlineRequested([&](auto&&, const Remoting::CommandlineArgs& cmdlineArgs) {
            Log::Comment(L"Commandline dispatched to p2");
            VERIFY_IS_GREATER_THAN(cmdlineArgs.Commandline().size(), 1u);
            VERIFY_ARE_EQUAL(L"this is for p2", cmdlineArgs.Commandline().at(1));
        });

        {
            Log::Comment(L"Activate the second peasant");
            Remoting::WindowActivatedArgs activatedArgs{ p2->GetID(),
                                                         winrt::guid{},
                                                         winrt::clock().now() };
            p2->ActivateWindow(activatedArgs);

            Log::Comment(L"Send a commandline to the current window, which should be p2");
            Remoting::CommandlineArgs eventArgs{ { p2Args }, { L"" }, SW_NORMAL, L"" };
            auto result = m0->ProposeCommandline(eventArgs);
            VERIFY_ARE_EQUAL(false, result.ShouldCreateWindow());
            VERIFY_ARE_EQUAL(false, (bool)result.Id());
        }
        {
            Log::Comment(L"Reactivate the first peasant");
            Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
                                                         winrt::guid{},
                                                         winrt::clock().now() };
            p1->ActivateWindow(activatedArgs);

            Log::Comment(L"Send a commandline to the current window, which should be p1 again");
            Remoting::CommandlineArgs eventArgs{ { p1Args }, { L"" }, SW_NORMAL, L"" };
            auto result = m0->ProposeCommandline(eventArgs);
            VERIFY_ARE_EQUAL(false, result.ShouldCreateWindow());
            VERIFY_ARE_EQUAL(false, (bool)result.Id());
        }
    }
    void RemotingTests::ProposeCommandlineNonExistentWindow()
    {
        Log::Comment(L"Test proposing a commandline for an ID that doesn't have a current peasant");

        const auto monarch0PID = 12345u;
        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
        m0->FindTargetWindowRequested(&RemotingTests::_findTargetWindowHelper);

        Log::Comment(L"Add a peasant");
        const auto peasant1PID = 23456u;
        auto p1 = make_private<Remoting::implementation::Peasant>(peasant1PID);
        m0->AddPeasant(*p1);

        {
            std::vector<winrt::hstring> args{ L"2" };
            Remoting::CommandlineArgs eventArgs{ { args }, { L"" }, SW_NORMAL, L"" };

            auto result = m0->ProposeCommandline(eventArgs);
            VERIFY_ARE_EQUAL(true, result.ShouldCreateWindow());
            VERIFY_ARE_EQUAL(true, (bool)result.Id());
            VERIFY_ARE_EQUAL(2u, result.Id().Value());
        }
        {
            std::vector<winrt::hstring> args{ L"10" };
            Remoting::CommandlineArgs eventArgs{ { args }, { L"" }, SW_NORMAL, L"" };

            auto result = m0->ProposeCommandline(eventArgs);
            VERIFY_ARE_EQUAL(true, result.ShouldCreateWindow());
            VERIFY_ARE_EQUAL(true, (bool)result.Id());
            VERIFY_ARE_EQUAL(10u, result.Id().Value());
        }
    }

    void RemotingTests::ProposeCommandlineDeadWindow()
    {
        Log::Comment(L"Test proposing a commandline for a peasant that previously died");

        const auto monarch0PID = 12345u;
        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
        m0->FindTargetWindowRequested(&RemotingTests::_findTargetWindowHelper);

        Log::Comment(L"Add a peasant");
        const auto peasant1PID = 23456u;
        auto p1 = make_private<Remoting::implementation::Peasant>(peasant1PID);
        m0->AddPeasant(*p1);
        p1->ExecuteCommandlineRequested([&](auto&&, const Remoting::CommandlineArgs& /*cmdlineArgs*/) {
            Log::Comment(L"Commandline dispatched to p1");
            VERIFY_IS_TRUE(false, L"This should not happen, this peasant should be dead.");
        });

        Log::Comment(L"Add a second peasant");
        const auto peasant2PID = 34567u;
        auto p2 = make_private<Remoting::implementation::Peasant>(peasant2PID);
        m0->AddPeasant(*p2);
        p2->ExecuteCommandlineRequested([&](auto&&, const Remoting::CommandlineArgs& cmdlineArgs) {
            Log::Comment(L"Commandline dispatched to p2");
            VERIFY_IS_GREATER_THAN(cmdlineArgs.Commandline().size(), 1u);
            VERIFY_ARE_EQUAL(L"this is for p2", cmdlineArgs.Commandline().at(1));
        });

        std::vector<winrt::hstring> p1Args{ L"1", L"arg[1]" };
        std::vector<winrt::hstring> p2Args{ L"2", L"this is for p2" };

        Log::Comment(L"Kill peasant 1");

        _killPeasant(m0, 1);

        {
            Log::Comment(L"Send a commandline to p2, who is still alive. We won't create a new window.");

            Remoting::CommandlineArgs eventArgs{ { p2Args }, { L"" }, SW_NORMAL, L"" };

            auto result = m0->ProposeCommandline(eventArgs);
            VERIFY_ARE_EQUAL(false, result.ShouldCreateWindow());
            VERIFY_ARE_EQUAL(false, (bool)result.Id());
        }
        {
            Log::Comment(L"Send a commandline to p1, who is dead. We will create a new window.");
            Remoting::CommandlineArgs eventArgs{ { p1Args }, { L"" }, SW_NORMAL, L"" };

            auto result = m0->ProposeCommandline(eventArgs);
            VERIFY_ARE_EQUAL(true, result.ShouldCreateWindow());
            VERIFY_ARE_EQUAL(true, (bool)result.Id());
            VERIFY_ARE_EQUAL(1u, result.Id().Value());
        }
    }

    // TODO:projects/5
    //
    // In order to test WindowingBehaviorUseExisting, we'll have to
    // create our own IVirtualDesktopManager implementation that can be subbed
    // in for testing. We can't _actually_ create HWNDs as a part of the test
    // and move them to different desktops. Instead, we'll have to create a stub
    // impl that can fake a result for IsWindowOnCurrentVirtualDesktop.

    void RemotingTests::MostRecentWindowSameDesktops()
    {
        Log::Comment(L"Make windows on the same desktop. Validate the contents of _mruPeasants are as expected.");

        const winrt::guid guid1{ Utils::GuidFromString(L"{11111111-1111-1111-1111-111111111111}") };
        const winrt::guid guid2{ Utils::GuidFromString(L"{22222222-2222-2222-2222-222222222222}") };

        const auto monarch0PID = 12345u;
        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
        m0->FindTargetWindowRequested(&RemotingTests::_findTargetWindowHelper);

        Log::Comment(L"Add a peasant");
        const auto peasant1PID = 23456u;
        auto p1 = make_private<Remoting::implementation::Peasant>(peasant1PID);
        m0->AddPeasant(*p1);

        Log::Comment(L"Add a second peasant");
        const auto peasant2PID = 34567u;
        auto p2 = make_private<Remoting::implementation::Peasant>(peasant2PID);
        m0->AddPeasant(*p2);

        {
            Log::Comment(L"Activate the first peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
                                                         guid1,
                                                         winrt::clock().now() };
            p1->ActivateWindow(activatedArgs);
        }
        {
            Log::Comment(L"Activate the second peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p2->GetID(),
                                                         guid1,
                                                         winrt::clock().now() };
            p2->ActivateWindow(activatedArgs);
        }
        VERIFY_ARE_EQUAL(2u, m0->_mruPeasants.size());
        VERIFY_ARE_EQUAL(p2->GetID(), m0->_mruPeasants[0].PeasantID());
        VERIFY_ARE_EQUAL(p1->GetID(), m0->_mruPeasants[1].PeasantID());

        {
            Log::Comment(L"Activate the first peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
                                                         guid1,
                                                         winrt::clock().now() };
            p1->ActivateWindow(activatedArgs);
        }
        VERIFY_ARE_EQUAL(2u, m0->_mruPeasants.size());
        VERIFY_ARE_EQUAL(p1->GetID(), m0->_mruPeasants[0].PeasantID());
        VERIFY_ARE_EQUAL(p2->GetID(), m0->_mruPeasants[1].PeasantID());
    }

    void RemotingTests::MostRecentWindowDifferentDesktops()
    {
        Log::Comment(L"Make windows on different desktops. Validate the contents of _mruPeasants are as expected.");

        const winrt::guid guid1{ Utils::GuidFromString(L"{11111111-1111-1111-1111-111111111111}") };
        const winrt::guid guid2{ Utils::GuidFromString(L"{22222222-2222-2222-2222-222222222222}") };

        const auto monarch0PID = 12345u;
        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
        m0->FindTargetWindowRequested(&RemotingTests::_findTargetWindowHelper);

        Log::Comment(L"Add a peasant");
        const auto peasant1PID = 23456u;
        auto p1 = make_private<Remoting::implementation::Peasant>(peasant1PID);
        m0->AddPeasant(*p1);

        Log::Comment(L"Add a second peasant");
        const auto peasant2PID = 34567u;
        auto p2 = make_private<Remoting::implementation::Peasant>(peasant2PID);
        m0->AddPeasant(*p2);

        {
            Log::Comment(L"Activate the first peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
                                                         guid1,
                                                         winrt::clock().now() };
            p1->ActivateWindow(activatedArgs);
        }
        {
            Log::Comment(L"Activate the second peasant, second desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p2->GetID(),
                                                         guid2,
                                                         winrt::clock().now() };
            p2->ActivateWindow(activatedArgs);
        }
        VERIFY_ARE_EQUAL(2u, m0->_mruPeasants.size());
        VERIFY_ARE_EQUAL(p2->GetID(), m0->_mruPeasants[0].PeasantID());
        VERIFY_ARE_EQUAL(p1->GetID(), m0->_mruPeasants[1].PeasantID());

        Log::Comment(L"Add a third peasant");
        const auto peasant3PID = 45678u;
        auto p3 = make_private<Remoting::implementation::Peasant>(peasant3PID);
        m0->AddPeasant(*p3);
        {
            Log::Comment(L"Activate the third peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p3->GetID(),
                                                         guid1,
                                                         winrt::clock().now() };
            p3->ActivateWindow(activatedArgs);
        }
        VERIFY_ARE_EQUAL(3u, m0->_mruPeasants.size());
        VERIFY_ARE_EQUAL(p3->GetID(), m0->_mruPeasants[0].PeasantID());
        VERIFY_ARE_EQUAL(p2->GetID(), m0->_mruPeasants[1].PeasantID());
        VERIFY_ARE_EQUAL(p1->GetID(), m0->_mruPeasants[2].PeasantID());

        {
            Log::Comment(L"Activate the first peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
                                                         guid1,
                                                         winrt::clock().now() };
            p1->ActivateWindow(activatedArgs);
        }
        VERIFY_ARE_EQUAL(3u, m0->_mruPeasants.size());
        VERIFY_ARE_EQUAL(p1->GetID(), m0->_mruPeasants[0].PeasantID());
        VERIFY_ARE_EQUAL(p3->GetID(), m0->_mruPeasants[1].PeasantID());
        VERIFY_ARE_EQUAL(p2->GetID(), m0->_mruPeasants[2].PeasantID());
    }

    void RemotingTests::MostRecentWindowMoveDesktops()
    {
        Log::Comment(L"Make windows on different desktops. Move one to another "
                     L"desktop. Validate the contents of _mruPeasants are as expected.");

        const winrt::guid guid1{ Utils::GuidFromString(L"{11111111-1111-1111-1111-111111111111}") };
        const winrt::guid guid2{ Utils::GuidFromString(L"{22222222-2222-2222-2222-222222222222}") };

        const auto monarch0PID = 12345u;
        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
        m0->FindTargetWindowRequested(&RemotingTests::_findTargetWindowHelper);

        Log::Comment(L"Add a peasant");
        const auto peasant1PID = 23456u;
        auto p1 = make_private<Remoting::implementation::Peasant>(peasant1PID);
        m0->AddPeasant(*p1);

        Log::Comment(L"Add a second peasant");
        const auto peasant2PID = 34567u;
        auto p2 = make_private<Remoting::implementation::Peasant>(peasant2PID);
        m0->AddPeasant(*p2);

        {
            Log::Comment(L"Activate the first peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
                                                         guid1,
                                                         winrt::clock().now() };
            p1->ActivateWindow(activatedArgs);
        }
        {
            Log::Comment(L"Activate the second peasant, second desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p2->GetID(),
                                                         guid2,
                                                         winrt::clock().now() };
            p2->ActivateWindow(activatedArgs);
        }
        VERIFY_ARE_EQUAL(2u, m0->_mruPeasants.size());
        VERIFY_ARE_EQUAL(p2->GetID(), m0->_mruPeasants[0].PeasantID());
        VERIFY_ARE_EQUAL(p1->GetID(), m0->_mruPeasants[1].PeasantID());

        Log::Comment(L"Add a third peasant");
        const auto peasant3PID = 45678u;
        auto p3 = make_private<Remoting::implementation::Peasant>(peasant3PID);
        m0->AddPeasant(*p3);
        {
            Log::Comment(L"Activate the third peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p3->GetID(),
                                                         guid1,
                                                         winrt::clock().now() };
            p3->ActivateWindow(activatedArgs);
        }
        VERIFY_ARE_EQUAL(3u, m0->_mruPeasants.size());
        VERIFY_ARE_EQUAL(p3->GetID(), m0->_mruPeasants[0].PeasantID());
        VERIFY_ARE_EQUAL(p2->GetID(), m0->_mruPeasants[1].PeasantID());
        VERIFY_ARE_EQUAL(p1->GetID(), m0->_mruPeasants[2].PeasantID());

        {
            Log::Comment(L"Activate the first peasant, second desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
                                                         guid2,
                                                         winrt::clock().now() };
            p1->ActivateWindow(activatedArgs);
        }
        VERIFY_ARE_EQUAL(3u, m0->_mruPeasants.size());
        VERIFY_ARE_EQUAL(p1->GetID(), m0->_mruPeasants[0].PeasantID());
        VERIFY_ARE_EQUAL(p3->GetID(), m0->_mruPeasants[1].PeasantID());
        VERIFY_ARE_EQUAL(p2->GetID(), m0->_mruPeasants[2].PeasantID());

        {
            Log::Comment(L"Activate the third peasant, second desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p3->GetID(),
                                                         guid2,
                                                         winrt::clock().now() };
            p3->ActivateWindow(activatedArgs);
        }
        VERIFY_ARE_EQUAL(3u, m0->_mruPeasants.size());
        VERIFY_ARE_EQUAL(p3->GetID(), m0->_mruPeasants[0].PeasantID());
        VERIFY_ARE_EQUAL(p1->GetID(), m0->_mruPeasants[1].PeasantID());
        VERIFY_ARE_EQUAL(p2->GetID(), m0->_mruPeasants[2].PeasantID());

        {
            Log::Comment(L"Activate the second peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p2->GetID(),
                                                         guid1,
                                                         winrt::clock().now() };
            p2->ActivateWindow(activatedArgs);
        }
        VERIFY_ARE_EQUAL(3u, m0->_mruPeasants.size());
        VERIFY_ARE_EQUAL(p2->GetID(), m0->_mruPeasants[0].PeasantID());
        VERIFY_ARE_EQUAL(p3->GetID(), m0->_mruPeasants[1].PeasantID());
        VERIFY_ARE_EQUAL(p1->GetID(), m0->_mruPeasants[2].PeasantID());
    }

    void RemotingTests::GetMostRecentAnyDesktop()
    {
        Log::Comment(L"Make windows on different desktops. Confirm that "
                     L"getting the most recent of all windows works as expected.");

        const winrt::guid guid1{ Utils::GuidFromString(L"{11111111-1111-1111-1111-111111111111}") };
        const winrt::guid guid2{ Utils::GuidFromString(L"{22222222-2222-2222-2222-222222222222}") };

        const auto monarch0PID = 12345u;
        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
        m0->FindTargetWindowRequested(&RemotingTests::_findTargetWindowHelper);

        Log::Comment(L"Add a peasant");
        const auto peasant1PID = 23456u;
        auto p1 = make_private<Remoting::implementation::Peasant>(peasant1PID);
        m0->AddPeasant(*p1);

        Log::Comment(L"Add a second peasant");
        const auto peasant2PID = 34567u;
        auto p2 = make_private<Remoting::implementation::Peasant>(peasant2PID);
        m0->AddPeasant(*p2);

        {
            Log::Comment(L"Activate the first peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
                                                         guid1,
                                                         winrt::clock().now() };
            p1->ActivateWindow(activatedArgs);
        }
        {
            Log::Comment(L"Activate the second peasant, second desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p2->GetID(),
                                                         guid2,
                                                         winrt::clock().now() };
            p2->ActivateWindow(activatedArgs);
        }
        VERIFY_ARE_EQUAL(p2->GetID(), m0->_getMostRecentPeasantID(false, true));

        Log::Comment(L"Add a third peasant");
        const auto peasant3PID = 45678u;
        auto p3 = make_private<Remoting::implementation::Peasant>(peasant3PID);
        m0->AddPeasant(*p3);
        {
            Log::Comment(L"Activate the third peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p3->GetID(),
                                                         guid1,
                                                         winrt::clock().now() };
            p3->ActivateWindow(activatedArgs);
        }
        VERIFY_ARE_EQUAL(p3->GetID(), m0->_getMostRecentPeasantID(false, true));

        {
            Log::Comment(L"Activate the first peasant, second desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
                                                         guid2,
                                                         winrt::clock().now() };
            p1->ActivateWindow(activatedArgs);
        }
        VERIFY_ARE_EQUAL(p1->GetID(), m0->_getMostRecentPeasantID(false, true));
    }

    void RemotingTests::MostRecentIsDead()
    {
        Log::Comment(L"Make two windows. Activate the first, then the second. "
                     L"Kill the second. The most recent should be the _first_ window.");

        const winrt::guid guid1{ Utils::GuidFromString(L"{11111111-1111-1111-1111-111111111111}") };
        const winrt::guid guid2{ Utils::GuidFromString(L"{22222222-2222-2222-2222-222222222222}") };

        const auto monarch0PID = 12345u;
        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
        m0->FindTargetWindowRequested(&RemotingTests::_findTargetWindowHelper);

        Log::Comment(L"Add a peasant");
        const auto peasant1PID = 23456u;
        auto p1 = make_private<Remoting::implementation::Peasant>(peasant1PID);
        m0->AddPeasant(*p1);

        Log::Comment(L"Add a second peasant");
        const auto peasant2PID = 34567u;
        auto p2 = make_private<Remoting::implementation::Peasant>(peasant2PID);
        m0->AddPeasant(*p2);

        {
            Log::Comment(L"Activate the first peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
                                                         guid1,
                                                         winrt::clock().now() };
            p1->ActivateWindow(activatedArgs);
        }
        {
            Log::Comment(L"Activate the second peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p2->GetID(),
                                                         guid1,
                                                         winrt::clock().now() };
            p2->ActivateWindow(activatedArgs);
        }
        VERIFY_ARE_EQUAL(2u, m0->_mruPeasants.size());
        VERIFY_ARE_EQUAL(p2->GetID(), m0->_mruPeasants[0].PeasantID());
        VERIFY_ARE_EQUAL(p1->GetID(), m0->_mruPeasants[1].PeasantID());

        Log::Comment(L"Kill peasant 2");
        RemotingTests::_killPeasant(m0, p2->GetID());
        Log::Comment(L"Peasant 1 should be the new MRU peasant");
        VERIFY_ARE_EQUAL(p1->GetID(), m0->_getMostRecentPeasantID(false, true));

        Log::Comment(L"Peasant 2 should not be in the monarch at all anymore");
        VERIFY_ARE_EQUAL(1u, m0->_peasants.size());
        VERIFY_ARE_EQUAL(1u, m0->_mruPeasants.size());
        VERIFY_ARE_EQUAL(1u, m0->_mruPeasants.size());
        VERIFY_ARE_EQUAL(p1->GetID(), m0->_mruPeasants[0].PeasantID());
    }

    void RemotingTests::MostRecentIsQuake()
    {
        Log::Comment(L"When a window is named _quake, it shouldn't participate "
                     L"in window glomming via the MRU window.");

        const winrt::guid guid1{ Utils::GuidFromString(L"{11111111-1111-1111-1111-111111111111}") };

        const auto monarch0PID = 12345u;
        const auto peasant1PID = 23456u;
        const auto peasant2PID = 34567u;

        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
        auto p1 = make_private<Remoting::implementation::Peasant>(peasant1PID);
        auto p2 = make_private<Remoting::implementation::Peasant>(peasant2PID);

        p1->WindowName(L"one");
        p2->WindowName(L"_quake");

        VERIFY_ARE_EQUAL(0, p1->GetID());
        VERIFY_ARE_EQUAL(0, p2->GetID());

        m0->AddPeasant(*p1);
        m0->AddPeasant(*p2);

        VERIFY_ARE_EQUAL(1, p1->GetID());
        VERIFY_ARE_EQUAL(2, p2->GetID());

        VERIFY_ARE_EQUAL(2u, m0->_peasants.size());

        {
            Log::Comment(L"Activate the first peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
                                                         guid1,
                                                         winrt::clock().now() };
            p1->ActivateWindow(activatedArgs);
        }
        {
            Log::Comment(L"Activate the _quake peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p2->GetID(),
                                                         guid1,
                                                         winrt::clock().now() };
            p2->ActivateWindow(activatedArgs);
        }

        VERIFY_ARE_EQUAL(2u, m0->_mruPeasants.size());
        VERIFY_ARE_EQUAL(p2->GetID(), m0->_mruPeasants[0].PeasantID());
        VERIFY_ARE_EQUAL(p1->GetID(), m0->_mruPeasants[1].PeasantID());

        Log::Comment(L"When we look up the MRU window, we find peasant 1 (who's name is \"one\"), not 2 (who's name is \"_quake\")");
        VERIFY_ARE_EQUAL(p1->GetID(), m0->_getMostRecentPeasantID(false, true));

        VERIFY_ARE_EQUAL(p1->GetID(), m0->_lookupPeasantIdForName(L"one"));
        VERIFY_ARE_EQUAL(p2->GetID(), m0->_lookupPeasantIdForName(L"_quake"));

        {
            Log::Comment(L"rename p2 to \"two\"");
            Remoting::RenameRequestArgs eventArgs{ L"two" };
            p2->RequestRename(eventArgs);
            VERIFY_IS_TRUE(eventArgs.Succeeded());
        }
        VERIFY_ARE_EQUAL(L"two", p2->WindowName());

        Log::Comment(L"Now, the MRU window will correctly be p2");
        VERIFY_ARE_EQUAL(p2->GetID(), m0->_getMostRecentPeasantID(false, true));
        VERIFY_ARE_EQUAL(p1->GetID(), m0->_lookupPeasantIdForName(L"one"));
        VERIFY_ARE_EQUAL(p2->GetID(), m0->_lookupPeasantIdForName(L"two"));

        {
            Log::Comment(L"rename p1 to \"_quake\"");
            Remoting::RenameRequestArgs eventArgs{ L"_quake" };
            p1->RequestRename(eventArgs);
            VERIFY_IS_TRUE(eventArgs.Succeeded());
        }
        VERIFY_ARE_EQUAL(L"_quake", p1->WindowName());

        Log::Comment(L"Now, the MRU window will still be p2");
        VERIFY_ARE_EQUAL(p2->GetID(), m0->_getMostRecentPeasantID(false, true));
        VERIFY_ARE_EQUAL(p1->GetID(), m0->_lookupPeasantIdForName(L"_quake"));
        VERIFY_ARE_EQUAL(p2->GetID(), m0->_lookupPeasantIdForName(L"two"));

        {
            Log::Comment(L"Activate the first peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
                                                         guid1,
                                                         winrt::clock().now() };
            p1->ActivateWindow(activatedArgs);
        }

        Log::Comment(L"Now, the MRU window will still be p2, because p1 is still named \"_quake\"");
        VERIFY_ARE_EQUAL(p2->GetID(), m0->_getMostRecentPeasantID(false, true));
        VERIFY_ARE_EQUAL(p1->GetID(), m0->_lookupPeasantIdForName(L"_quake"));
        VERIFY_ARE_EQUAL(p2->GetID(), m0->_lookupPeasantIdForName(L"two"));
    }

    void RemotingTests::GetPeasantsByName()
    {
        Log::Comment(L"Test that looking up a peasant by name finds the window we expect");

        const auto monarch0PID = 12345u;
        const auto peasant1PID = 23456u;
        const auto peasant2PID = 34567u;

        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
        auto p1 = make_private<Remoting::implementation::Peasant>(peasant1PID);
        auto p2 = make_private<Remoting::implementation::Peasant>(peasant2PID);

        p1->WindowName(L"one");
        p2->WindowName(L"two");

        VERIFY_ARE_EQUAL(0, p1->GetID());
        VERIFY_ARE_EQUAL(0, p2->GetID());
        VERIFY_ARE_EQUAL(L"one", p1->WindowName());
        VERIFY_ARE_EQUAL(L"two", p2->WindowName());

        m0->AddPeasant(*p1);
        m0->AddPeasant(*p2);

        VERIFY_ARE_EQUAL(1, p1->GetID());
        VERIFY_ARE_EQUAL(2, p2->GetID());
        VERIFY_ARE_EQUAL(L"one", p1->WindowName());
        VERIFY_ARE_EQUAL(L"two", p2->WindowName());

        VERIFY_ARE_EQUAL(p1->GetID(), m0->_lookupPeasantIdForName(L"one"));
        VERIFY_ARE_EQUAL(p2->GetID(), m0->_lookupPeasantIdForName(L"two"));

        Log::Comment(L"Rename p2");

        p2->WindowName(L"foo");

        VERIFY_ARE_EQUAL(0, m0->_lookupPeasantIdForName(L"two"));
        VERIFY_ARE_EQUAL(p2->GetID(), m0->_lookupPeasantIdForName(L"foo"));
    }

    void RemotingTests::AddNamedPeasantsToNewMonarch()
    {
        Log::Comment(L"Test that moving peasants to a new monarch persists their original names");

        const auto monarch0PID = 12345u;
        const auto peasant1PID = 23456u;
        const auto peasant2PID = 34567u;
        const auto monarch3PID = 45678u;

        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
        auto p1 = make_private<Remoting::implementation::Peasant>(peasant1PID);
        auto p2 = make_private<Remoting::implementation::Peasant>(peasant2PID);
        auto m3 = make_private<Remoting::implementation::Monarch>(monarch3PID);

        p1->WindowName(L"one");
        p2->WindowName(L"two");

        VERIFY_ARE_EQUAL(0, p1->GetID());
        VERIFY_ARE_EQUAL(0, p2->GetID());

        m0->AddPeasant(*p1);
        m0->AddPeasant(*p2);

        VERIFY_ARE_EQUAL(p1->GetID(), m0->_lookupPeasantIdForName(L"one"));
        VERIFY_ARE_EQUAL(p2->GetID(), m0->_lookupPeasantIdForName(L"two"));

        VERIFY_ARE_EQUAL(1, p1->GetID());
        VERIFY_ARE_EQUAL(2, p2->GetID());
        VERIFY_ARE_EQUAL(L"one", p1->WindowName());
        VERIFY_ARE_EQUAL(L"two", p2->WindowName());

        Log::Comment(L"When the peasants go to a new monarch, make sure they have the same name");
        m3->AddPeasant(*p1);
        m3->AddPeasant(*p2);

        VERIFY_ARE_EQUAL(1, p1->GetID());
        VERIFY_ARE_EQUAL(2, p2->GetID());
        VERIFY_ARE_EQUAL(L"one", p1->WindowName());
        VERIFY_ARE_EQUAL(L"two", p2->WindowName());

        VERIFY_ARE_EQUAL(p1->GetID(), m3->_lookupPeasantIdForName(L"one"));
        VERIFY_ARE_EQUAL(p2->GetID(), m3->_lookupPeasantIdForName(L"two"));
    }

    void RemotingTests::LookupNamedPeasantWhenOthersDied()
    {
        Log::Comment(L"Test that looking for a peasant by name when a different"
                     L" peasant has died cleans up the corpses of any peasants "
                     L"we may have tripped over.");

        const auto monarch0PID = 12345u;
        const auto peasant1PID = 23456u;
        const auto peasant2PID = 34567u;

        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
        auto p1 = make_private<Remoting::implementation::Peasant>(peasant1PID);
        auto p2 = make_private<Remoting::implementation::Peasant>(peasant2PID);

        p1->WindowName(L"one");
        p2->WindowName(L"two");

        VERIFY_ARE_EQUAL(0, p1->GetID());
        VERIFY_ARE_EQUAL(0, p2->GetID());

        m0->AddPeasant(*p1);
        m0->AddPeasant(*p2);

        VERIFY_ARE_EQUAL(1, p1->GetID());
        VERIFY_ARE_EQUAL(2, p2->GetID());

        VERIFY_ARE_EQUAL(2u, m0->_peasants.size());

        VERIFY_ARE_EQUAL(p1->GetID(), m0->_lookupPeasantIdForName(L"one"));
        VERIFY_ARE_EQUAL(p2->GetID(), m0->_lookupPeasantIdForName(L"two"));

        Log::Comment(L"Kill peasant 1. Make sure that it gets removed from the monarch.");
        RemotingTests::_killPeasant(m0, p1->GetID());

        // By killing 1, then looking for "two", we happen to iterate over the
        // corpse of 1 when looking for the peasant named "two". This causes us
        // to remove 1 while looking for "two". Technically, we shouldn't be
        // relying on any sort of ordering for an unordered_map iterator, but
        // this one just so happens to work.
        VERIFY_ARE_EQUAL(p2->GetID(), m0->_lookupPeasantIdForName(L"two"));

        Log::Comment(L"Peasant 1 should have been pruned");
        VERIFY_ARE_EQUAL(1u, m0->_peasants.size());
    }

    void RemotingTests::LookupNamedPeasantWhenItDied()
    {
        Log::Comment(L"Test that looking up a dead peasant by name returns 0, "
                     L"indicating there's no peasant with that name.");

        const auto monarch0PID = 12345u;
        const auto peasant1PID = 23456u;
        const auto peasant2PID = 34567u;

        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
        auto p1 = make_private<Remoting::implementation::Peasant>(peasant1PID);
        auto p2 = make_private<Remoting::implementation::Peasant>(peasant2PID);

        p1->WindowName(L"one");
        p2->WindowName(L"two");

        VERIFY_ARE_EQUAL(0, p1->GetID());
        VERIFY_ARE_EQUAL(0, p2->GetID());

        m0->AddPeasant(*p1);
        m0->AddPeasant(*p2);

        VERIFY_ARE_EQUAL(1, p1->GetID());
        VERIFY_ARE_EQUAL(2, p2->GetID());

        VERIFY_ARE_EQUAL(2u, m0->_peasants.size());

        VERIFY_ARE_EQUAL(p1->GetID(), m0->_lookupPeasantIdForName(L"one"));
        VERIFY_ARE_EQUAL(p2->GetID(), m0->_lookupPeasantIdForName(L"two"));

        Log::Comment(L"Kill peasant 1. Make sure that it gets removed from the monarch.");
        RemotingTests::_killPeasant(m0, p1->GetID());

        VERIFY_ARE_EQUAL(0, m0->_lookupPeasantIdForName(L"one"));

        Log::Comment(L"Peasant 1 should have been pruned");
        VERIFY_ARE_EQUAL(1u, m0->_peasants.size());
        VERIFY_ARE_EQUAL(p2->GetID(), m0->_lookupPeasantIdForName(L"two"));
    }

    void RemotingTests::GetMruPeasantAfterNameLookupForDeadPeasant()
    {
        // This test is trying to hit the catch in Monarch::_lookupPeasantIdForName.
        //
        // We need to:
        // * add some peasants,
        // * make one the mru, then make a named two the mru
        // * then kill two
        // * then try to get the mru peasant -> it should be one

        const winrt::guid guid1{ Utils::GuidFromString(L"{11111111-1111-1111-1111-111111111111}") };
        const auto monarch0PID = 12345u;
        const auto peasant1PID = 23456u;
        const auto peasant2PID = 34567u;

        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
        auto p1 = make_private<Remoting::implementation::Peasant>(peasant1PID);
        auto p2 = make_private<Remoting::implementation::Peasant>(peasant2PID);

        p1->WindowName(L"one");
        p2->WindowName(L"two");

        VERIFY_ARE_EQUAL(0, p1->GetID());
        VERIFY_ARE_EQUAL(0, p2->GetID());

        m0->AddPeasant(*p1);
        m0->AddPeasant(*p2);

        VERIFY_ARE_EQUAL(1, p1->GetID());
        VERIFY_ARE_EQUAL(2, p2->GetID());

        VERIFY_ARE_EQUAL(2u, m0->_peasants.size());

        VERIFY_ARE_EQUAL(p1->GetID(), m0->_lookupPeasantIdForName(L"one"));
        VERIFY_ARE_EQUAL(p2->GetID(), m0->_lookupPeasantIdForName(L"two"));

        {
            Log::Comment(L"Activate the first peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
                                                         guid1,
                                                         winrt::clock().now() };
            p1->ActivateWindow(activatedArgs);
        }
        {
            Log::Comment(L"Activate the second peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p2->GetID(),
                                                         guid1,
                                                         winrt::clock().now() };
            p2->ActivateWindow(activatedArgs);
        }
        Log::Comment(L"Kill peasant 2.");
        RemotingTests::_killPeasant(m0, p2->GetID());

        VERIFY_ARE_EQUAL(p1->GetID(), m0->_getMostRecentPeasantID(false, true));
        VERIFY_ARE_EQUAL(p1->GetID(), m0->_getMostRecentPeasantID(true, true));
    }

    void RemotingTests::ProposeCommandlineForNamedDeadWindow()
    {
        Log::Comment(L"Test proposing a commandline for a named window that's "
                     L"currently dead. This should result in a new window with "
                     L"the given name.");

        const auto monarch0PID = 12345u;
        const auto peasant1PID = 23456u;
        const auto peasant2PID = 34567u;

        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
        m0->FindTargetWindowRequested(&RemotingTests::_findTargetWindowByNameHelper);
        auto p1 = make_private<Remoting::implementation::Peasant>(peasant1PID);
        auto p2 = make_private<Remoting::implementation::Peasant>(peasant2PID);

        p1->WindowName(L"one");
        p2->WindowName(L"two");

        VERIFY_ARE_EQUAL(0, p1->GetID());
        VERIFY_ARE_EQUAL(0, p2->GetID());

        p1->ExecuteCommandlineRequested([&](auto&&, const Remoting::CommandlineArgs& cmdlineArgs) {
            Log::Comment(L"Commandline dispatched to p1");
            VERIFY_IS_GREATER_THAN(cmdlineArgs.Commandline().size(), 1u);
            VERIFY_ARE_EQUAL(L"arg[1]", cmdlineArgs.Commandline().at(1));
        });
        p2->ExecuteCommandlineRequested([&](auto&&, const Remoting::CommandlineArgs& cmdlineArgs) {
            Log::Comment(L"Commandline dispatched to p2");
            VERIFY_IS_GREATER_THAN(cmdlineArgs.Commandline().size(), 1u);
            VERIFY_ARE_EQUAL(L"this is for p2", cmdlineArgs.Commandline().at(1));
        });

        p1->WindowName(L"one");
        p2->WindowName(L"two");

        m0->AddPeasant(*p1);
        m0->AddPeasant(*p2);

        std::vector<winrt::hstring> p1Args{ L"one", L"arg[1]" };
        std::vector<winrt::hstring> p2Args{ L"two", L"this is for p2" };

        {
            Remoting::CommandlineArgs eventArgs{ { p1Args }, { L"" }, SW_NORMAL, L"" };
            auto result = m0->ProposeCommandline(eventArgs);
            VERIFY_ARE_EQUAL(false, result.ShouldCreateWindow());
            VERIFY_ARE_EQUAL(false, (bool)result.Id()); // Casting to (bool) checks if the reference has a value
            VERIFY_ARE_EQUAL(L"", result.WindowName());
        }

        {
            Log::Comment(L"Send a commandline to \"two\", which should be p2");
            Remoting::CommandlineArgs eventArgs{ { p2Args }, { L"" }, SW_NORMAL, L"" };
            auto result = m0->ProposeCommandline(eventArgs);
            VERIFY_ARE_EQUAL(false, result.ShouldCreateWindow());
            VERIFY_ARE_EQUAL(false, (bool)result.Id()); // Casting to (bool) checks if the reference has a value
            VERIFY_ARE_EQUAL(L"", result.WindowName());
        }

        Log::Comment(L"Kill peasant 2.");
        RemotingTests::_killPeasant(m0, p2->GetID());

        {
            Log::Comment(L"Send a commandline to \"two\", who is now dead.");
            Remoting::CommandlineArgs eventArgs{ { p2Args }, { L"" }, SW_NORMAL, L"" };
            auto result = m0->ProposeCommandline(eventArgs);
            VERIFY_ARE_EQUAL(true, result.ShouldCreateWindow());
            VERIFY_ARE_EQUAL(false, (bool)result.Id()); // Casting to (bool) checks if the reference has a value
            VERIFY_ARE_EQUAL(L"two", result.WindowName());
        }
    }

    void RemotingTests::TestRenameWindowSuccessfully()
    {
        Log::Comment(L"Attempt to rename a window. This should succeed.");

        const auto monarch0PID = 12345u;
        const auto peasant1PID = 23456u;
        const auto peasant2PID = 34567u;

        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
        auto p1 = make_private<Remoting::implementation::Peasant>(peasant1PID);
        auto p2 = make_private<Remoting::implementation::Peasant>(peasant2PID);

        p1->WindowName(L"one");
        p2->WindowName(L"two");

        VERIFY_ARE_EQUAL(0, p1->GetID());
        VERIFY_ARE_EQUAL(0, p2->GetID());

        m0->AddPeasant(*p1);
        m0->AddPeasant(*p2);

        VERIFY_ARE_EQUAL(1, p1->GetID());
        VERIFY_ARE_EQUAL(2, p2->GetID());

        VERIFY_ARE_EQUAL(2u, m0->_peasants.size());

        Remoting::RenameRequestArgs eventArgs{ L"foo" };
        p1->RequestRename(eventArgs);

        VERIFY_IS_TRUE(eventArgs.Succeeded());
        VERIFY_ARE_EQUAL(L"foo", p1->WindowName());

        VERIFY_ARE_EQUAL(0, m0->_lookupPeasantIdForName(L"one"));
        VERIFY_ARE_EQUAL(p2->GetID(), m0->_lookupPeasantIdForName(L"two"));
        VERIFY_ARE_EQUAL(p1->GetID(), m0->_lookupPeasantIdForName(L"foo"));
    }

    void RemotingTests::TestRenameSameNameAsAnother()
    {
        Log::Comment(L"Try renaming a window to a name used by another peasant."
                     L" This should fail.");

        const auto monarch0PID = 12345u;
        const auto peasant1PID = 23456u;
        const auto peasant2PID = 34567u;

        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
        auto p1 = make_private<Remoting::implementation::Peasant>(peasant1PID);
        auto p2 = make_private<Remoting::implementation::Peasant>(peasant2PID);

        p1->WindowName(L"one");
        p2->WindowName(L"two");

        VERIFY_ARE_EQUAL(0, p1->GetID());
        VERIFY_ARE_EQUAL(0, p2->GetID());

        m0->AddPeasant(*p1);
        m0->AddPeasant(*p2);

        VERIFY_ARE_EQUAL(1, p1->GetID());
        VERIFY_ARE_EQUAL(2, p2->GetID());

        VERIFY_ARE_EQUAL(2u, m0->_peasants.size());

        Remoting::RenameRequestArgs eventArgs{ L"two" };
        p1->RequestRename(eventArgs);

        VERIFY_IS_FALSE(eventArgs.Succeeded());
        VERIFY_ARE_EQUAL(L"one", p1->WindowName());

        VERIFY_ARE_EQUAL(p1->GetID(), m0->_lookupPeasantIdForName(L"one"));
        VERIFY_ARE_EQUAL(p2->GetID(), m0->_lookupPeasantIdForName(L"two"));
    }
    void RemotingTests::TestRenameSameNameAsADeadPeasant()
    {
        Log::Comment(L"We'll try renaming a window to the name of a window that"
                     L" has died. This should succeed, without crashing.");

        const auto monarch0PID = 12345u;
        const auto peasant1PID = 23456u;
        const auto peasant2PID = 34567u;

        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
        auto p1 = make_private<Remoting::implementation::Peasant>(peasant1PID);
        auto p2 = make_private<Remoting::implementation::Peasant>(peasant2PID);

        p1->WindowName(L"one");
        p2->WindowName(L"two");

        VERIFY_ARE_EQUAL(0, p1->GetID());
        VERIFY_ARE_EQUAL(0, p2->GetID());

        m0->AddPeasant(*p1);
        m0->AddPeasant(*p2);

        VERIFY_ARE_EQUAL(1, p1->GetID());
        VERIFY_ARE_EQUAL(2, p2->GetID());

        VERIFY_ARE_EQUAL(2u, m0->_peasants.size());

        Remoting::RenameRequestArgs eventArgs{ L"two" };
        p1->RequestRename(eventArgs);

        VERIFY_IS_FALSE(eventArgs.Succeeded());
        VERIFY_ARE_EQUAL(L"one", p1->WindowName());

        VERIFY_ARE_EQUAL(p1->GetID(), m0->_lookupPeasantIdForName(L"one"));
        VERIFY_ARE_EQUAL(p2->GetID(), m0->_lookupPeasantIdForName(L"two"));

        RemotingTests::_killPeasant(m0, p2->GetID());

        p1->RequestRename(eventArgs);

        VERIFY_IS_TRUE(eventArgs.Succeeded());
        VERIFY_ARE_EQUAL(L"two", p1->WindowName());
        VERIFY_ARE_EQUAL(p1->GetID(), m0->_lookupPeasantIdForName(L"two"));
    }

    void RemotingTests::TestSummonMostRecentWindow()
    {
        Log::Comment(L"Attempt to summon the most recent window");

        const winrt::guid guid1{ Utils::GuidFromString(L"{11111111-1111-1111-1111-111111111111}") };

        const auto monarch0PID = 12345u;
        const auto peasant1PID = 23456u;
        const auto peasant2PID = 34567u;

        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
        auto p1 = make_private<Remoting::implementation::Peasant>(peasant1PID);
        auto p2 = make_private<Remoting::implementation::Peasant>(peasant2PID);

        p1->WindowName(L"one");
        p2->WindowName(L"two");

        VERIFY_ARE_EQUAL(0, p1->GetID());
        VERIFY_ARE_EQUAL(0, p2->GetID());

        m0->AddPeasant(*p1);
        m0->AddPeasant(*p2);

        VERIFY_ARE_EQUAL(1, p1->GetID());
        VERIFY_ARE_EQUAL(2, p2->GetID());

        VERIFY_ARE_EQUAL(2u, m0->_peasants.size());

        auto p1ExpectedToBeSummoned = false;
        auto p2ExpectedToBeSummoned = false;

        p1->SummonRequested([&](auto&&, auto&&) {
            Log::Comment(L"p1 summoned");
            VERIFY_IS_TRUE(p1ExpectedToBeSummoned);
        });
        p2->SummonRequested([&](auto&&, auto&&) {
            Log::Comment(L"p2 summoned");
            VERIFY_IS_TRUE(p2ExpectedToBeSummoned);
        });

        {
            Log::Comment(L"Activate the first peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
                                                         guid1,
                                                         winrt::clock().now() };
            p1->ActivateWindow(activatedArgs);
        }
        {
            Log::Comment(L"Activate the second peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p2->GetID(),
                                                         guid1,
                                                         winrt::clock().now() };
            p2->ActivateWindow(activatedArgs);
        }

        p2ExpectedToBeSummoned = true;
        Remoting::SummonWindowSelectionArgs args;
        // Without setting the WindowName, SummonWindowSelectionArgs defaults to
        // the MRU window
        Log::Comment(L"Summon the MRU window, which is window two");
        m0->SummonWindow(args);
        VERIFY_IS_TRUE(args.FoundMatch());

        {
            Log::Comment(L"Activate the first peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
                                                         guid1,
                                                         winrt::clock().now() };
            p1->ActivateWindow(activatedArgs);
        }

        Log::Comment(L"Now that one is the MRU, summon it");
        p2ExpectedToBeSummoned = false;
        p1ExpectedToBeSummoned = true;
        args.FoundMatch(false);
        m0->SummonWindow(args);
        VERIFY_IS_TRUE(args.FoundMatch());
    }

    void RemotingTests::TestSummonNamedWindow()
    {
        Log::Comment(L"Attempt to summon a window by name. When there isn't a "
                     L"window with that name, set FoundMatch to false, so the "
                     L"caller can handle that case.");

        const auto monarch0PID = 12345u;
        const auto peasant1PID = 23456u;
        const auto peasant2PID = 34567u;

        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
        auto p1 = make_private<Remoting::implementation::Peasant>(peasant1PID);
        auto p2 = make_private<Remoting::implementation::Peasant>(peasant2PID);

        p1->WindowName(L"one");
        p2->WindowName(L"two");

        VERIFY_ARE_EQUAL(0, p1->GetID());
        VERIFY_ARE_EQUAL(0, p2->GetID());

        m0->AddPeasant(*p1);
        m0->AddPeasant(*p2);

        VERIFY_ARE_EQUAL(1, p1->GetID());
        VERIFY_ARE_EQUAL(2, p2->GetID());

        VERIFY_ARE_EQUAL(2u, m0->_peasants.size());

        auto p1ExpectedToBeSummoned = false;
        auto p2ExpectedToBeSummoned = false;

        p1->SummonRequested([&](auto&&, auto&&) {
            Log::Comment(L"p1 summoned");
            VERIFY_IS_TRUE(p1ExpectedToBeSummoned);
        });
        p2->SummonRequested([&](auto&&, auto&&) {
            Log::Comment(L"p2 summoned");
            VERIFY_IS_TRUE(p2ExpectedToBeSummoned);
        });

        Remoting::SummonWindowSelectionArgs args;

        Log::Comment(L"Summon window two by name");
        p2ExpectedToBeSummoned = true;
        args.WindowName(L"two");
        m0->SummonWindow(args);
        VERIFY_IS_TRUE(args.FoundMatch());

        Log::Comment(L"Summon window one by name");
        p2ExpectedToBeSummoned = false;
        p1ExpectedToBeSummoned = true;
        args.FoundMatch(false);
        args.WindowName(L"one");
        m0->SummonWindow(args);
        VERIFY_IS_TRUE(args.FoundMatch());

        Log::Comment(L"Fail to summon window three by name");
        p1ExpectedToBeSummoned = false;
        args.FoundMatch(false);
        args.WindowName(L"three");
        m0->SummonWindow(args);
        VERIFY_IS_FALSE(args.FoundMatch());
    }

    void RemotingTests::TestSummonNamedDeadWindow()
    {
        Log::Comment(L"Attempt to summon a dead window by name. This will fail, but not crash.");

        const auto monarch0PID = 12345u;
        const auto peasant1PID = 23456u;
        const auto peasant2PID = 34567u;

        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
        auto p1 = make_private<Remoting::implementation::Peasant>(peasant1PID);
        auto p2 = make_private<Remoting::implementation::Peasant>(peasant2PID);

        p1->WindowName(L"one");
        p2->WindowName(L"two");

        VERIFY_ARE_EQUAL(0, p1->GetID());
        VERIFY_ARE_EQUAL(0, p2->GetID());

        m0->AddPeasant(*p1);
        m0->AddPeasant(*p2);

        VERIFY_ARE_EQUAL(1, p1->GetID());
        VERIFY_ARE_EQUAL(2, p2->GetID());

        VERIFY_ARE_EQUAL(2u, m0->_peasants.size());

        auto p1ExpectedToBeSummoned = false;
        auto p2ExpectedToBeSummoned = false;

        p1->SummonRequested([&](auto&&, auto&&) {
            Log::Comment(L"p1 summoned");
            VERIFY_IS_TRUE(p1ExpectedToBeSummoned);
        });
        p2->SummonRequested([&](auto&&, auto&&) {
            Log::Comment(L"p2 summoned");
            VERIFY_IS_TRUE(p2ExpectedToBeSummoned);
        });

        Remoting::SummonWindowSelectionArgs args;

        Log::Comment(L"Summon window two by name");
        p2ExpectedToBeSummoned = true;
        args.WindowName(L"two");
        m0->SummonWindow(args);
        VERIFY_IS_TRUE(args.FoundMatch());

        Log::Comment(L"Summon window one by name");
        p2ExpectedToBeSummoned = false;
        p1ExpectedToBeSummoned = true;
        args.FoundMatch(false);
        args.WindowName(L"one");
        m0->SummonWindow(args);
        VERIFY_IS_TRUE(args.FoundMatch());

        Log::Comment(L"Kill peasant one.");
        RemotingTests::_killPeasant(m0, p1->GetID());

        Log::Comment(L"Fail to summon window one by name");
        p1ExpectedToBeSummoned = false;
        args.FoundMatch(false);
        args.WindowName(L"one");
        m0->SummonWindow(args);
        VERIFY_IS_FALSE(args.FoundMatch());
    }

    void RemotingTests::TestSummonMostRecentDeadWindow()
    {
        Log::Comment(L"Attempt to summon the MRU window, when the MRU window "
                     L"has died. This will fall back to the next MRU window.");

        const winrt::guid guid1{ Utils::GuidFromString(L"{11111111-1111-1111-1111-111111111111}") };

        const auto monarch0PID = 12345u;
        const auto peasant1PID = 23456u;
        const auto peasant2PID = 34567u;

        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
        auto p1 = make_private<Remoting::implementation::Peasant>(peasant1PID);
        auto p2 = make_private<Remoting::implementation::Peasant>(peasant2PID);

        p1->WindowName(L"one");
        p2->WindowName(L"two");

        VERIFY_ARE_EQUAL(0, p1->GetID());
        VERIFY_ARE_EQUAL(0, p2->GetID());

        m0->AddPeasant(*p1);
        m0->AddPeasant(*p2);

        VERIFY_ARE_EQUAL(1, p1->GetID());
        VERIFY_ARE_EQUAL(2, p2->GetID());

        VERIFY_ARE_EQUAL(2u, m0->_peasants.size());

        auto p1ExpectedToBeSummoned = false;
        auto p2ExpectedToBeSummoned = false;

        p1->SummonRequested([&](auto&&, auto&&) {
            Log::Comment(L"p1 summoned");
            VERIFY_IS_TRUE(p1ExpectedToBeSummoned);
        });
        p2->SummonRequested([&](auto&&, auto&&) {
            Log::Comment(L"p2 summoned");
            VERIFY_IS_TRUE(p2ExpectedToBeSummoned);
        });

        {
            Log::Comment(L"Activate the first peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
                                                         guid1,
                                                         winrt::clock().now() };
            p1->ActivateWindow(activatedArgs);
        }
        {
            Log::Comment(L"Activate the second peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p2->GetID(),
                                                         guid1,
                                                         winrt::clock().now() };
            p2->ActivateWindow(activatedArgs);
        }

        p2ExpectedToBeSummoned = true;
        Remoting::SummonWindowSelectionArgs args;
        // Without setting the WindowName, SummonWindowSelectionArgs defaults to
        // the MRU window
        Log::Comment(L"Summon the MRU window, which is window two");
        m0->SummonWindow(args);
        VERIFY_IS_TRUE(args.FoundMatch());

        {
            Log::Comment(L"Activate the first peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
                                                         guid1,
                                                         winrt::clock().now() };
            p1->ActivateWindow(activatedArgs);
        }

        Log::Comment(L"Now that one is the MRU, summon it");
        p2ExpectedToBeSummoned = false;
        p1ExpectedToBeSummoned = true;
        args.FoundMatch(false);
        m0->SummonWindow(args);
        VERIFY_IS_TRUE(args.FoundMatch());

        Log::Comment(L"Kill peasant one.");
        RemotingTests::_killPeasant(m0, p1->GetID());

        Log::Comment(L"We now expect to summon two, since the MRU peasant (one) is actually dead.");
        p2ExpectedToBeSummoned = true;
        p1ExpectedToBeSummoned = false;
        args.FoundMatch(false);
        m0->SummonWindow(args);
        VERIFY_IS_TRUE(args.FoundMatch());
    }

    void RemotingTests::TestSummonOnCurrent()
    {
        Log::Comment(L"Tests summoning a window, using OnCurrentDesktop to only"
                     L"select windows on the current desktop.");

        const winrt::guid guid1{ Utils::GuidFromString(L"{11111111-1111-1111-1111-111111111111}") };
        const winrt::guid guid2{ Utils::GuidFromString(L"{22222222-2222-2222-2222-222222222222}") };

        constexpr auto monarch0PID = 12345u;
        constexpr auto peasant1PID = 23456u;
        constexpr auto peasant2PID = 34567u;
        constexpr auto peasant3PID = 45678u;

        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
        auto p1 = make_private<Remoting::implementation::Peasant>(peasant1PID);
        auto p2 = make_private<Remoting::implementation::Peasant>(peasant2PID);
        auto p3 = make_private<Remoting::implementation::Peasant>(peasant3PID);

        p1->WindowName(L"one");
        p2->WindowName(L"two");
        p3->WindowName(L"three");

        VERIFY_ARE_EQUAL(0, p1->GetID());
        VERIFY_ARE_EQUAL(0, p2->GetID());
        VERIFY_ARE_EQUAL(0, p3->GetID());

        m0->AddPeasant(*p1);
        m0->AddPeasant(*p2);
        m0->AddPeasant(*p3);

        VERIFY_ARE_EQUAL(1, p1->GetID());
        VERIFY_ARE_EQUAL(2, p2->GetID());
        VERIFY_ARE_EQUAL(3, p3->GetID());

        VERIFY_ARE_EQUAL(3u, m0->_peasants.size());

        auto p1ExpectedToBeSummoned = false;
        auto p2ExpectedToBeSummoned = false;
        auto p3ExpectedToBeSummoned = false;

        p1->SummonRequested([&](auto&&, auto&&) {
            Log::Comment(L"p1 summoned");
            VERIFY_IS_TRUE(p1ExpectedToBeSummoned);
        });
        p2->SummonRequested([&](auto&&, auto&&) {
            Log::Comment(L"p2 summoned");
            VERIFY_IS_TRUE(p2ExpectedToBeSummoned);
        });
        p3->SummonRequested([&](auto&&, auto&&) {
            Log::Comment(L"p3 summoned");
            VERIFY_IS_TRUE(p3ExpectedToBeSummoned);
        });

        {
            Log::Comment(L"Activate the first peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
                                                         p1->GetPID(), // USE PID as HWND, because these values don't _really_ matter
                                                         guid1,
                                                         winrt::clock().now() };
            p1->ActivateWindow(activatedArgs);
        }
        {
            Log::Comment(L"Activate the second peasant, second desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p2->GetID(),
                                                         p2->GetPID(), // USE PID as HWND, because these values don't _really_ matter
                                                         guid2,
                                                         winrt::clock().now() };
            p2->ActivateWindow(activatedArgs);
        }
        {
            Log::Comment(L"Activate the third peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p3->GetID(),
                                                         p3->GetPID(), // USE PID as HWND, because these values don't _really_ matter
                                                         guid1,
                                                         winrt::clock().now() };
            p3->ActivateWindow(activatedArgs);
        }

        Log::Comment(L"Create a mock IVirtualDesktopManager to handle checking if a window is on a given desktop");
        auto manager = winrt::make_self<MockDesktopManager>();
        m0->_desktopManager = manager.try_as<IVirtualDesktopManager>();

        auto firstCallback = [&](HWND h, BOOL* result) -> HRESULT {
            Log::Comment(L"firstCallback: Checking if window is on desktop 1");

            const auto hwnd = reinterpret_cast<uint64_t>(h);
            if (hwnd == peasant1PID || hwnd == peasant3PID)
            {
                *result = true;
            }
            else if (hwnd == peasant2PID)
            {
                *result = false;
            }
            else
            {
                VERIFY_IS_TRUE(false, L"IsWindowOnCurrentVirtualDesktop called with unexpected value");
            }
            return S_OK;
        };
        manager->pfnIsWindowOnCurrentVirtualDesktop = firstCallback;

        Remoting::SummonWindowSelectionArgs args;

        Log::Comment(L"Summon window three - it is the MRU on desktop 1");
        p3ExpectedToBeSummoned = true;
        args.OnCurrentDesktop(true);
        m0->SummonWindow(args);
        VERIFY_IS_TRUE(args.FoundMatch());

        {
            Log::Comment(L"Activate the first peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
                                                         p1->GetPID(), // USE PID as HWND, because these values don't _really_ matter
                                                         guid1,
                                                         winrt::clock().now() };
            p1->ActivateWindow(activatedArgs);
        }

        Log::Comment(L"Summon window one - it is the MRU on desktop 1");
        p1ExpectedToBeSummoned = true;
        p2ExpectedToBeSummoned = false;
        p3ExpectedToBeSummoned = false;
        args.FoundMatch(false);
        args.OnCurrentDesktop(true);
        m0->SummonWindow(args);
        VERIFY_IS_TRUE(args.FoundMatch());

        Log::Comment(L"Now we'll pretend we switched to desktop 2");

        auto secondCallback = [&](HWND h, BOOL* result) -> HRESULT {
            Log::Comment(L"secondCallback: Checking if window is on desktop 2");
            const auto hwnd = reinterpret_cast<uint64_t>(h);
            if (hwnd == peasant1PID || hwnd == peasant3PID)
            {
                *result = false;
            }
            else if (hwnd == peasant2PID)
            {
                *result = true;
            }
            else
            {
                VERIFY_IS_TRUE(false, L"IsWindowOnCurrentVirtualDesktop called with unexpected value");
            }
            return S_OK;
        };
        manager->pfnIsWindowOnCurrentVirtualDesktop = secondCallback;

        Log::Comment(L"Summon window one - it is the MRU on desktop 2");
        p1ExpectedToBeSummoned = false;
        p2ExpectedToBeSummoned = true;
        p3ExpectedToBeSummoned = false;
        args.FoundMatch(false);
        args.OnCurrentDesktop(true);
        m0->SummonWindow(args);
        VERIFY_IS_TRUE(args.FoundMatch());

        {
            Log::Comment(L"Activate the third peasant, second desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p3->GetID(),
                                                         p3->GetPID(), // USE PID as HWND, because these values don't _really_ matter
                                                         guid2,
                                                         winrt::clock().now() };
            p3->ActivateWindow(activatedArgs);
        }

        auto thirdCallback = [&](HWND h, BOOL* result) -> HRESULT {
            Log::Comment(L"thirdCallback: Checking if window is on desktop 2. (windows 2 and 3 are)");
            const auto hwnd = reinterpret_cast<uint64_t>(h);
            if (hwnd == peasant1PID)
            {
                *result = false;
            }
            else if (hwnd == peasant2PID || hwnd == peasant3PID)
            {
                *result = true;
            }
            else
            {
                VERIFY_IS_TRUE(false, L"IsWindowOnCurrentVirtualDesktop called with unexpected value");
            }
            return S_OK;
        };
        manager->pfnIsWindowOnCurrentVirtualDesktop = thirdCallback;

        Log::Comment(L"Summon window three - it is the MRU on desktop 2");
        p1ExpectedToBeSummoned = false;
        p2ExpectedToBeSummoned = false;
        p3ExpectedToBeSummoned = true;
        args.FoundMatch(false);
        args.OnCurrentDesktop(true);
        m0->SummonWindow(args);
        VERIFY_IS_TRUE(args.FoundMatch());

        Log::Comment(L"Now we'll pretend we switched to desktop 1");

        auto fourthCallback = [&](HWND h, BOOL* result) -> HRESULT {
            Log::Comment(L"fourthCallback: Checking if window is on desktop 1. (window 1 is)");
            const auto hwnd = reinterpret_cast<uint64_t>(h);
            if (hwnd == peasant1PID)
            {
                *result = true;
            }
            else if (hwnd == peasant2PID || hwnd == peasant3PID)
            {
                *result = false;
            }
            else
            {
                VERIFY_IS_TRUE(false, L"IsWindowOnCurrentVirtualDesktop called with unexpected value");
            }
            return S_OK;
        };
        manager->pfnIsWindowOnCurrentVirtualDesktop = fourthCallback;

        Log::Comment(L"Summon window one - it is the only window on desktop 1");
        p1ExpectedToBeSummoned = true;
        p2ExpectedToBeSummoned = false;
        p3ExpectedToBeSummoned = false;
        args.FoundMatch(false);
        args.OnCurrentDesktop(true);
        m0->SummonWindow(args);
        VERIFY_IS_TRUE(args.FoundMatch());

        Log::Comment(L"Now we'll pretend we switched to desktop 3");

        auto fifthCallback = [&](HWND h, BOOL* result) -> HRESULT {
            Log::Comment(L"fifthCallback: Checking if window is on desktop 3. (none are)");
            const auto hwnd = reinterpret_cast<uint64_t>(h);
            if (hwnd == peasant1PID || hwnd == peasant2PID || hwnd == peasant3PID)
            {
                *result = false;
            }
            else
            {
                VERIFY_IS_TRUE(false, L"IsWindowOnCurrentVirtualDesktop called with unexpected value");
            }
            return S_OK;
        };
        manager->pfnIsWindowOnCurrentVirtualDesktop = fifthCallback;

        Log::Comment(L"This summon won't find a window.");
        p1ExpectedToBeSummoned = false;
        p2ExpectedToBeSummoned = false;
        p3ExpectedToBeSummoned = false;
        args.FoundMatch(false);
        args.OnCurrentDesktop(true);
        m0->SummonWindow(args);
        VERIFY_IS_FALSE(args.FoundMatch());
    }

    void RemotingTests::TestSummonOnCurrentWithName()
    {
        Log::Comment(L"Test that specifying a WindowName forces us to ignore OnCurrentDesktop");

        const winrt::guid guid1{ Utils::GuidFromString(L"{11111111-1111-1111-1111-111111111111}") };
        const winrt::guid guid2{ Utils::GuidFromString(L"{22222222-2222-2222-2222-222222222222}") };

        constexpr auto monarch0PID = 12345u;
        constexpr auto peasant1PID = 23456u;
        constexpr auto peasant2PID = 34567u;
        constexpr auto peasant3PID = 45678u;

        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
        auto p1 = make_private<Remoting::implementation::Peasant>(peasant1PID);
        auto p2 = make_private<Remoting::implementation::Peasant>(peasant2PID);
        auto p3 = make_private<Remoting::implementation::Peasant>(peasant3PID);

        p1->WindowName(L"one");
        p2->WindowName(L"two");
        p3->WindowName(L"three");

        VERIFY_ARE_EQUAL(0, p1->GetID());
        VERIFY_ARE_EQUAL(0, p2->GetID());
        VERIFY_ARE_EQUAL(0, p3->GetID());

        m0->AddPeasant(*p1);
        m0->AddPeasant(*p2);
        m0->AddPeasant(*p3);

        VERIFY_ARE_EQUAL(1, p1->GetID());
        VERIFY_ARE_EQUAL(2, p2->GetID());
        VERIFY_ARE_EQUAL(3, p3->GetID());

        VERIFY_ARE_EQUAL(3u, m0->_peasants.size());

        auto p1ExpectedToBeSummoned = false;
        auto p2ExpectedToBeSummoned = false;
        auto p3ExpectedToBeSummoned = false;

        p1->SummonRequested([&](auto&&, auto&&) {
            Log::Comment(L"p1 summoned");
            VERIFY_IS_TRUE(p1ExpectedToBeSummoned);
        });
        p2->SummonRequested([&](auto&&, auto&&) {
            Log::Comment(L"p2 summoned");
            VERIFY_IS_TRUE(p2ExpectedToBeSummoned);
        });
        p3->SummonRequested([&](auto&&, auto&&) {
            Log::Comment(L"p3 summoned");
            VERIFY_IS_TRUE(p3ExpectedToBeSummoned);
        });

        {
            Log::Comment(L"Activate the first peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
                                                         p1->GetPID(), // USE PID as HWND, because these values don't _really_ matter
                                                         guid1,
                                                         winrt::clock().now() };
            p1->ActivateWindow(activatedArgs);
        }
        {
            Log::Comment(L"Activate the second peasant, second desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p2->GetID(),
                                                         p2->GetPID(), // USE PID as HWND, because these values don't _really_ matter
                                                         guid2,
                                                         winrt::clock().now() };
            p2->ActivateWindow(activatedArgs);
        }
        {
            Log::Comment(L"Activate the third peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p3->GetID(),
                                                         p3->GetPID(), // USE PID as HWND, because these values don't _really_ matter
                                                         guid1,
                                                         winrt::clock().now() };
            p3->ActivateWindow(activatedArgs);
        }

        Log::Comment(L"Create a mock IVirtualDesktopManager to handle checking if a window is on a given desktop");
        auto manager = winrt::make_self<MockDesktopManager>();
        m0->_desktopManager = manager.try_as<IVirtualDesktopManager>();

        auto firstCallback = [&](HWND h, BOOL* result) -> HRESULT {
            Log::Comment(L"firstCallback: Checking if window is on desktop 1");

            const auto hwnd = reinterpret_cast<uint64_t>(h);
            if (hwnd == peasant1PID || hwnd == peasant3PID)
            {
                *result = true;
            }
            else if (hwnd == peasant2PID)
            {
                *result = false;
            }
            else
            {
                VERIFY_IS_TRUE(false, L"IsWindowOnCurrentVirtualDesktop called with unexpected value");
            }
            return S_OK;
        };
        manager->pfnIsWindowOnCurrentVirtualDesktop = firstCallback;

        Remoting::SummonWindowSelectionArgs args;

        Log::Comment(L"Summon window three - it is the MRU on desktop 1");
        p3ExpectedToBeSummoned = true;
        args.OnCurrentDesktop(true);
        m0->SummonWindow(args);
        VERIFY_IS_TRUE(args.FoundMatch());

        Log::Comment(L"Look for window 1 by name. When given a name, we don't care about OnCurrentDesktop.");
        p1ExpectedToBeSummoned = true;
        p2ExpectedToBeSummoned = false;
        p3ExpectedToBeSummoned = false;
        args.FoundMatch(false);
        args.WindowName(L"one");
        args.OnCurrentDesktop(true);
        m0->SummonWindow(args);
        VERIFY_IS_TRUE(args.FoundMatch());

        Log::Comment(L"Look for window 2 by name. When given a name, we don't care about OnCurrentDesktop.");
        p1ExpectedToBeSummoned = false;
        p2ExpectedToBeSummoned = true;
        p3ExpectedToBeSummoned = false;
        args.FoundMatch(false);
        args.WindowName(L"two");
        args.OnCurrentDesktop(true);
        m0->SummonWindow(args);
        VERIFY_IS_TRUE(args.FoundMatch());

        Log::Comment(L"Look for window 3 by name. When given a name, we don't care about OnCurrentDesktop.");
        p1ExpectedToBeSummoned = false;
        p2ExpectedToBeSummoned = false;
        p3ExpectedToBeSummoned = true;
        args.FoundMatch(false);
        args.WindowName(L"three");
        args.OnCurrentDesktop(true);
        m0->SummonWindow(args);
        VERIFY_IS_TRUE(args.FoundMatch());
    }

    void RemotingTests::TestSummonOnCurrentDeadWindow()
    {
        Log::Comment(L"Test that we can summon a window on the current desktop,"
                     L" when the MRU window on that desktop dies.");

        const winrt::guid guid1{ Utils::GuidFromString(L"{11111111-1111-1111-1111-111111111111}") };
        const winrt::guid guid2{ Utils::GuidFromString(L"{22222222-2222-2222-2222-222222222222}") };

        constexpr auto monarch0PID = 12345u;
        constexpr auto peasant1PID = 23456u;
        constexpr auto peasant2PID = 34567u;
        constexpr auto peasant3PID = 45678u;

        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
        auto p1 = make_private<Remoting::implementation::Peasant>(peasant1PID);
        auto p2 = make_private<Remoting::implementation::Peasant>(peasant2PID);
        auto p3 = make_private<Remoting::implementation::Peasant>(peasant3PID);

        p1->WindowName(L"one");
        p2->WindowName(L"two");
        p3->WindowName(L"three");

        VERIFY_ARE_EQUAL(0, p1->GetID());
        VERIFY_ARE_EQUAL(0, p2->GetID());
        VERIFY_ARE_EQUAL(0, p3->GetID());

        m0->AddPeasant(*p1);
        m0->AddPeasant(*p2);
        m0->AddPeasant(*p3);

        VERIFY_ARE_EQUAL(1, p1->GetID());
        VERIFY_ARE_EQUAL(2, p2->GetID());
        VERIFY_ARE_EQUAL(3, p3->GetID());

        VERIFY_ARE_EQUAL(3u, m0->_peasants.size());

        auto p1ExpectedToBeSummoned = false;
        auto p2ExpectedToBeSummoned = false;
        auto p3ExpectedToBeSummoned = false;

        p1->SummonRequested([&](auto&&, auto&&) {
            Log::Comment(L"p1 summoned");
            VERIFY_IS_TRUE(p1ExpectedToBeSummoned);
        });
        p2->SummonRequested([&](auto&&, auto&&) {
            Log::Comment(L"p2 summoned");
            VERIFY_IS_TRUE(p2ExpectedToBeSummoned);
        });
        p3->SummonRequested([&](auto&&, auto&&) {
            Log::Comment(L"p3 summoned");
            VERIFY_IS_TRUE(p3ExpectedToBeSummoned);
        });

        {
            Log::Comment(L"Activate the first peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
                                                         p1->GetPID(), // USE PID as HWND, because these values don't _really_ matter
                                                         guid1,
                                                         winrt::clock().now() };
            p1->ActivateWindow(activatedArgs);
        }
        {
            Log::Comment(L"Activate the second peasant, second desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p2->GetID(),
                                                         p2->GetPID(), // USE PID as HWND, because these values don't _really_ matter
                                                         guid2,
                                                         winrt::clock().now() };
            p2->ActivateWindow(activatedArgs);
        }
        {
            Log::Comment(L"Activate the third peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p3->GetID(),
                                                         p3->GetPID(), // USE PID as HWND, because these values don't _really_ matter
                                                         guid1,
                                                         winrt::clock().now() };
            p3->ActivateWindow(activatedArgs);
        }

        Log::Comment(L"Create a mock IVirtualDesktopManager to handle checking if a window is on a given desktop");
        auto manager = winrt::make_self<MockDesktopManager>();
        m0->_desktopManager = manager.try_as<IVirtualDesktopManager>();

        auto firstCallback = [&](HWND h, BOOL* result) -> HRESULT {
            Log::Comment(L"firstCallback: Checking if window is on desktop 1");

            const auto hwnd = reinterpret_cast<uint64_t>(h);
            if (hwnd == peasant1PID || hwnd == peasant3PID)
            {
                *result = true;
            }
            else if (hwnd == peasant2PID)
            {
                *result = false;
            }
            else
            {
                VERIFY_IS_TRUE(false, L"IsWindowOnCurrentVirtualDesktop called with unexpected value");
            }
            return S_OK;
        };
        manager->pfnIsWindowOnCurrentVirtualDesktop = firstCallback;

        Remoting::SummonWindowSelectionArgs args;

        Log::Comment(L"Summon window three - it is the MRU on desktop 1");
        p3ExpectedToBeSummoned = true;
        args.OnCurrentDesktop(true);
        m0->SummonWindow(args);
        VERIFY_IS_TRUE(args.FoundMatch());

        Log::Comment(L"Kill window 3. Window 1 is now the MRU on desktop 1.");
        RemotingTests::_killPeasant(m0, p3->GetID());

        Log::Comment(L"Summon window three - it is the MRU on desktop 1");
        p1ExpectedToBeSummoned = true;
        p2ExpectedToBeSummoned = false;
        p3ExpectedToBeSummoned = false;
        args.FoundMatch(false);
        args.OnCurrentDesktop(true);
        m0->SummonWindow(args);
        VERIFY_IS_TRUE(args.FoundMatch());
    }

    void RemotingTests::TestSummonMostRecentIsQuake()
    {
        Log::Comment(L"When a window is named _quake, it shouldn't participate "
                     L"in window glomming via the MRU window, but it should be able to be summoned");

        const winrt::guid guid1{ Utils::GuidFromString(L"{11111111-1111-1111-1111-111111111111}") };

        const auto monarch0PID = 12345u;
        const auto peasant1PID = 23456u;
        const auto peasant2PID = 34567u;

        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
        auto p1 = make_private<Remoting::implementation::Peasant>(peasant1PID);
        auto p2 = make_private<Remoting::implementation::Peasant>(peasant2PID);

        p1->WindowName(L"one");
        p2->WindowName(L"_quake");

        VERIFY_ARE_EQUAL(0, p1->GetID());
        VERIFY_ARE_EQUAL(0, p2->GetID());

        m0->AddPeasant(*p1);
        m0->AddPeasant(*p2);

        VERIFY_ARE_EQUAL(1, p1->GetID());
        VERIFY_ARE_EQUAL(2, p2->GetID());

        VERIFY_ARE_EQUAL(2u, m0->_peasants.size());

        auto p1ExpectedToBeSummoned = false;
        auto p2ExpectedToBeSummoned = false;

        p1->SummonRequested([&](auto&&, auto&&) {
            Log::Comment(L"p1 summoned");
            VERIFY_IS_TRUE(p1ExpectedToBeSummoned);
        });
        p2->SummonRequested([&](auto&&, auto&&) {
            Log::Comment(L"p2 summoned");
            VERIFY_IS_TRUE(p2ExpectedToBeSummoned);
        });

        auto p1ExpectedCommandline = false;
        auto p2ExpectedCommandline = false;
        p1->ExecuteCommandlineRequested([&](auto&&, const Remoting::CommandlineArgs& /*cmdlineArgs*/) {
            Log::Comment(L"Commandline dispatched to p1");
            VERIFY_IS_TRUE(p1ExpectedCommandline);
        });
        p2->ExecuteCommandlineRequested([&](auto&&, const Remoting::CommandlineArgs& /*cmdlineArgs*/) {
            Log::Comment(L"Commandline dispatched to p2");
            VERIFY_IS_TRUE(p2ExpectedCommandline);
        });
        m0->FindTargetWindowRequested(&RemotingTests::_findTargetWindowHelper);

        {
            Log::Comment(L"Activate the first peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
                                                         guid1,
                                                         winrt::clock().now() };
            p1->ActivateWindow(activatedArgs);
        }
        {
            Log::Comment(L"Activate the _quake peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p2->GetID(),
                                                         guid1,
                                                         winrt::clock().now() };
            p2->ActivateWindow(activatedArgs);
        }

        VERIFY_ARE_EQUAL(2u, m0->_mruPeasants.size());
        VERIFY_ARE_EQUAL(p2->GetID(), m0->_mruPeasants[0].PeasantID());
        VERIFY_ARE_EQUAL(p1->GetID(), m0->_mruPeasants[1].PeasantID());

        std::vector<winrt::hstring> commandlineArgs{ L"0", L"arg[1]" };
        Remoting::CommandlineArgs eventArgs{ { commandlineArgs }, { L"" }, SW_NORMAL, L"" };

        Log::Comment(L"When we attempt to send a commandline to the MRU window,"
                     L" we should find peasant 1 (who's name is \"one\"), not 2"
                     L" (who's name is \"_quake\")");
        p1ExpectedCommandline = true;
        p2ExpectedCommandline = false;
        auto result = m0->ProposeCommandline(eventArgs);
        VERIFY_ARE_EQUAL(false, result.ShouldCreateWindow());
        VERIFY_ARE_EQUAL(false, (bool)result.Id());

        {
            Log::Comment(L"When we summon the MRU window, we'll still summon the _quake window");
            p1ExpectedToBeSummoned = false;
            p2ExpectedToBeSummoned = true;
            Remoting::SummonWindowSelectionArgs args;
            args.OnCurrentDesktop(false);
            m0->SummonWindow(args);
            VERIFY_IS_TRUE(args.FoundMatch());
        }

        {
            Log::Comment(L"rename p2 to \"two\"");
            Remoting::RenameRequestArgs renameArgs{ L"two" };
            p2->RequestRename(renameArgs);
            VERIFY_IS_TRUE(renameArgs.Succeeded());
        }
        VERIFY_ARE_EQUAL(L"two", p2->WindowName());

        Log::Comment(L"Now, the MRU window will correctly be p2, and we can glom to it");
        p1ExpectedCommandline = false;
        p2ExpectedCommandline = true;
        result = m0->ProposeCommandline(eventArgs);
        VERIFY_ARE_EQUAL(false, result.ShouldCreateWindow());
        VERIFY_ARE_EQUAL(false, (bool)result.Id());

        {
            Log::Comment(L"When we summon the MRU window, we'll still summon the window 2");
            p1ExpectedToBeSummoned = false;
            p2ExpectedToBeSummoned = true;
            Remoting::SummonWindowSelectionArgs args;
            args.OnCurrentDesktop(false);
            m0->SummonWindow(args);
            VERIFY_IS_TRUE(args.FoundMatch());
        }
    }

    void RemotingTests::TestSummonAfterWindowClose()
    {
        Log::Comment(L"Test that we can summon a window on the current desktop,"
                     L" when the MRU window on that desktop closes normally.");

        const winrt::guid guid1{ Utils::GuidFromString(L"{11111111-1111-1111-1111-111111111111}") };
        const winrt::guid guid2{ Utils::GuidFromString(L"{22222222-2222-2222-2222-222222222222}") };

        constexpr auto monarch0PID = 12345u;
        constexpr auto peasant1PID = 23456u;
        constexpr auto peasant2PID = 34567u;
        constexpr auto peasant3PID = 45678u;

        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
        auto p1 = make_private<Remoting::implementation::Peasant>(peasant1PID);
        auto p2 = make_private<Remoting::implementation::Peasant>(peasant2PID);
        auto p3 = make_private<Remoting::implementation::Peasant>(peasant3PID);

        p1->WindowName(L"one");
        p2->WindowName(L"two");
        p3->WindowName(L"three");

        VERIFY_ARE_EQUAL(0, p1->GetID());
        VERIFY_ARE_EQUAL(0, p2->GetID());
        VERIFY_ARE_EQUAL(0, p3->GetID());

        m0->AddPeasant(*p1);
        m0->AddPeasant(*p2);
        m0->AddPeasant(*p3);

        VERIFY_ARE_EQUAL(1, p1->GetID());
        VERIFY_ARE_EQUAL(2, p2->GetID());
        VERIFY_ARE_EQUAL(3, p3->GetID());

        VERIFY_ARE_EQUAL(3u, m0->_peasants.size());

        auto p1ExpectedToBeSummoned = false;
        auto p2ExpectedToBeSummoned = false;
        auto p3ExpectedToBeSummoned = false;

        p1->SummonRequested([&](auto&&, auto&&) {
            Log::Comment(L"p1 summoned");
            VERIFY_IS_TRUE(p1ExpectedToBeSummoned);
        });
        p2->SummonRequested([&](auto&&, auto&&) {
            Log::Comment(L"p2 summoned");
            VERIFY_IS_TRUE(p2ExpectedToBeSummoned);
        });
        p3->SummonRequested([&](auto&&, auto&&) {
            Log::Comment(L"p3 summoned");
            VERIFY_IS_TRUE(p3ExpectedToBeSummoned);
        });

        {
            Log::Comment(L"Activate the first peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
                                                         p1->GetPID(), // USE PID as HWND, because these values don't _really_ matter
                                                         guid1,
                                                         winrt::clock().now() };
            p1->ActivateWindow(activatedArgs);
        }
        {
            Log::Comment(L"Activate the second peasant, second desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p2->GetID(),
                                                         p2->GetPID(), // USE PID as HWND, because these values don't _really_ matter
                                                         guid2,
                                                         winrt::clock().now() };
            p2->ActivateWindow(activatedArgs);
        }
        {
            Log::Comment(L"Activate the third peasant, first desktop");
            Remoting::WindowActivatedArgs activatedArgs{ p3->GetID(),
                                                         p3->GetPID(), // USE PID as HWND, because these values don't _really_ matter
                                                         guid1,
                                                         winrt::clock().now() };
            p3->ActivateWindow(activatedArgs);
        }

        Log::Comment(L"Create a mock IVirtualDesktopManager to handle checking if a window is on a given desktop");
        auto manager = winrt::make_self<MockDesktopManager>();
        m0->_desktopManager = manager.try_as<IVirtualDesktopManager>();

        auto firstCallback = [&](HWND h, BOOL* result) -> HRESULT {
            Log::Comment(L"firstCallback: Checking if window is on desktop 1");

            const auto hwnd = reinterpret_cast<uint64_t>(h);
            if (hwnd == peasant1PID || hwnd == peasant3PID)
            {
                *result = true;
            }
            else if (hwnd == peasant2PID)
            {
                *result = false;
            }
            else
            {
                VERIFY_IS_TRUE(false, L"IsWindowOnCurrentVirtualDesktop called with unexpected value");
            }
            return S_OK;
        };
        manager->pfnIsWindowOnCurrentVirtualDesktop = firstCallback;

        Remoting::SummonWindowSelectionArgs args;

        Log::Comment(L"Summon window three - it is the MRU on desktop 1");
        p3ExpectedToBeSummoned = true;
        args.OnCurrentDesktop(true);
        m0->SummonWindow(args);
        VERIFY_IS_TRUE(args.FoundMatch());

        Log::Comment(L"Close window 3. Window 1 is now the MRU on desktop 1.");
        RemotingTests::_closePeasant(m0, p3->GetID());

        Log::Comment(L"Summon window three - it is the MRU on desktop 1");
        p1ExpectedToBeSummoned = true;
        p2ExpectedToBeSummoned = false;
        p3ExpectedToBeSummoned = false;
        args.FoundMatch(false);
        args.OnCurrentDesktop(true);
        m0->SummonWindow(args);
        VERIFY_IS_TRUE(args.FoundMatch());
    }

    void RemotingTests::TestProposeCommandlineWithDeadMonarch()
    {
        Log::Comment(L"MSFT:32279047 - It's possible for a window to start "
                     L"right as the monarch is exiting. In that case, "
                     L"WindowManager relies on getting a "
                     L"RPC_E_SERVER_UNAVAILABLE when the process dies. ");

        const winrt::guid guid1{ Utils::GuidFromString(L"{11111111-1111-1111-1111-111111111111}") };
        const winrt::guid guid2{ Utils::GuidFromString(L"{22222222-2222-2222-2222-222222222222}") };

        constexpr auto monarch0PID = 12345u;

        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);

        {
            Remoting::CommandlineArgs args{ { L"wt.exe" }, { L"-Embedding" }, SW_NORMAL, L"" };
            const auto result = m0->ProposeCommandline(args);
            auto shouldCreateWindow = result.ShouldCreateWindow();
            VERIFY_IS_TRUE(shouldCreateWindow);
        }

        auto m1 = make_self<DeadMonarch>();
        {
            Remoting::CommandlineArgs args{ { L"wt.exe" }, { L"-Embedding" }, SW_NORMAL, L"" };

            try
            {
                const auto result = m1->ProposeCommandline(args);
                VERIFY_IS_FALSE(true, L"This should have thrown");
            }
            catch (const winrt::hresult_error& e)
            {
                // these two errors are Win32 errors, convert them to HRESULTS so we can actually compare here.
                constexpr auto RPC_SERVER_UNAVAILABLE_HR = HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE);
                constexpr auto RPC_CALL_FAILED_HR = HRESULT_FROM_WIN32(RPC_S_CALL_FAILED);

                // This is the same check in WindowManager::_proposeToMonarch.
                VERIFY_IS_TRUE(e.code() == RPC_SERVER_UNAVAILABLE_HR || e.code() == RPC_CALL_FAILED_HR);
            }
            // just don't catch other types of exceptions. They'll take out
            // TAEF, which will count as a failure.
        }
    }

}
