terminal/src/cascadia/UnitTests_Remoting/RemotingTests.cpp
Leonard Hecker 32fbd4cbb6
Enable /Zc:preprocessor (#10593)
This commit is a preparation for upcoming changes to KeyChordSerialization for #7539 and #10203.
In order to support variadic macros, /Zc:preprocessor was enabled, which required changing unrelated parts of the project.

## PR Checklist
* [x] I work here
* [x] Tests added/passed

## Validation Steps Performed

* Project still compiles ✔️
2021-07-13 23:00:11 +00:00

2372 lines
99 KiB
C++

// 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;
};
// This is a silly helper struct.
// It will always throw an hresult_error on any of its methods.
//
// 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*/) { throw winrt::hresult_error{}; };
uint64_t GetID() { throw winrt::hresult_error{}; };
winrt::hstring WindowName() { throw winrt::hresult_error{}; };
uint64_t GetPID() { throw winrt::hresult_error{}; };
bool ExecuteCommandline(const Remoting::CommandlineArgs& /*args*/) { throw winrt::hresult_error{}; }
void ActivateWindow(const Remoting::WindowActivatedArgs& /*args*/) { throw winrt::hresult_error{}; }
void RequestIdentifyWindows() { throw winrt::hresult_error{}; };
void DisplayWindowId() { throw winrt::hresult_error{}; };
Remoting::CommandlineArgs InitialArgs() { throw winrt::hresult_error{}; }
Remoting::WindowActivatedArgs GetLastActivatedArgs() { throw winrt::hresult_error{}; }
void RequestRename(const Remoting::RenameRequestArgs& /*args*/) { throw winrt::hresult_error{}; }
void Summon(const Remoting::SummonWindowBehavior& /*args*/) { throw winrt::hresult_error{}; };
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);
};
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_CLASS_SETUP(ClassSetup)
{
return true;
}
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 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"" } };
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"" } };
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"" } };
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"" } };
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"" } };
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"" } };
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"" } };
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"" } };
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"" } };
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"" } };
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"" } };
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"" } };
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"" } };
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"" } };
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());
bool p1ExpectedToBeSummoned = false;
bool 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());
bool p1ExpectedToBeSummoned = false;
bool 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());
bool p1ExpectedToBeSummoned = false;
bool 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>(peasant1PID);
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());
bool p1ExpectedToBeSummoned = false;
bool 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());
bool p1ExpectedToBeSummoned = false;
bool p2ExpectedToBeSummoned = false;
bool 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 uint64_t 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 uint64_t 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 uint64_t 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 uint64_t 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 uint64_t 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());
bool p1ExpectedToBeSummoned = false;
bool p2ExpectedToBeSummoned = false;
bool 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 uint64_t 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());
bool p1ExpectedToBeSummoned = false;
bool p2ExpectedToBeSummoned = false;
bool 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 uint64_t 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());
bool p1ExpectedToBeSummoned = false;
bool 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);
});
bool p1ExpectedCommandline = false;
bool 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"" } };
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());
}
}
}