From 9e8facaa6fc74227fb5f1d0dea37fd796985f9c3 Mon Sep 17 00:00:00 2001 From: vldmr11080 <57061786+vldmr11080@users.noreply.github.com> Date: Tue, 24 Mar 2020 18:50:26 +0100 Subject: [PATCH] Windows snap hotkeys to move windows between screens (#1603) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * When moving window into zones using arrow keys, support multi-monitor scenario * Minor coding style adjustments * Split implementation into separate functions because of readability * Rename certain arguments * Modify unit tests after API changes * Address PR comments and add unit tests * Return true from MoveWindowIntoZoneByDirection only if window is successfully added to new zone * Improved monitor ordering (#1) * Implemented improved monitor ordering v1 * Fixed some embarrassing bugs, added some tests * Added one more test * Extracted a value to a variable * ASCII art in unit test comments describing monitor layouts * Removed empty line for consistency * Update comment to match the code * Refactored tests, added tests for X,Y offsets Co-authored-by: Ivan Stošić --- src/modules/fancyzones/lib/FancyZones.cpp | 88 +- src/modules/fancyzones/lib/ZoneSet.cpp | 22 +- src/modules/fancyzones/lib/ZoneSet.h | 9 +- src/modules/fancyzones/lib/ZoneWindow.cpp | 16 +- src/modules/fancyzones/lib/ZoneWindow.h | 6 +- src/modules/fancyzones/lib/util.cpp | 83 + src/modules/fancyzones/lib/util.h | 3 +- .../fancyzones/tests/UnitTests/Util.Spec.cpp | 249 ++- src/modules/fancyzones/tests/UnitTests/Util.h | 9 + .../tests/UnitTests/ZoneSet.Spec.cpp | 1548 +++++++++-------- .../tests/UnitTests/ZoneWindow.Spec.cpp | 8 +- 11 files changed, 1228 insertions(+), 813 deletions(-) diff --git a/src/modules/fancyzones/lib/FancyZones.cpp b/src/modules/fancyzones/lib/FancyZones.cpp index e8d53977c1b9..1cccc210667f 100644 --- a/src/modules/fancyzones/lib/FancyZones.cpp +++ b/src/modules/fancyzones/lib/FancyZones.cpp @@ -162,6 +162,10 @@ struct FancyZones : public winrt::implements> GetRawMonitorData() noexcept; + std::vector GetMonitorsSorted() noexcept; + bool MoveWindowIntoZoneByDirection(HMONITOR monitor, HWND window, DWORD vkCode, bool cycle); + const HINSTANCE m_hinstance{}; HKEY m_virtualDesktopsRegKey{ nullptr }; @@ -828,17 +832,43 @@ bool FancyZones::OnSnapHotkey(DWORD vkCode) noexcept auto window = GetForegroundWindow(); if (IsInterestingWindow(window)) { - const HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL); - if (monitor) + const HMONITOR current = MonitorFromWindow(window, MONITOR_DEFAULTTONULL); + if (current) { - std::shared_lock readLock(m_lock); - - auto iter = m_zoneWindowMap.find(monitor); - if (iter != m_zoneWindowMap.end()) + std::vector monitorInfo = GetMonitorsSorted(); + if (monitorInfo.size() > 1) { - const auto& zoneWindowPtr = iter->second; - zoneWindowPtr->MoveWindowIntoZoneByDirection(window, vkCode); - return true; + // Multi monitor environment. + auto currMonitorInfo = std::find(std::begin(monitorInfo), std::end(monitorInfo), current); + do + { + if (MoveWindowIntoZoneByDirection(*currMonitorInfo, window, vkCode, false /* cycle through zones */)) + { + return true; + } + // We iterated through all zones in current monitor zone layout, move on to next one (or previous depending on direction). + if (vkCode == VK_RIGHT) + { + currMonitorInfo = std::next(currMonitorInfo); + if (currMonitorInfo == std::end(monitorInfo)) + { + currMonitorInfo = std::begin(monitorInfo); + } + } + else if (vkCode == VK_LEFT) + { + if (currMonitorInfo == std::begin(monitorInfo)) + { + currMonitorInfo = std::end(monitorInfo); + } + currMonitorInfo = std::prev(currMonitorInfo); + } + } while (*currMonitorInfo != current); + } + else + { + // Single monitor environment. + return MoveWindowIntoZoneByDirection(current, window, vkCode, true /* cycle through zones */); } } } @@ -1111,6 +1141,46 @@ void FancyZones::OnEditorExitEvent() noexcept JSONHelpers::FancyZonesDataInstance().SaveFancyZonesData(); } +std::vector FancyZones::GetMonitorsSorted() noexcept +{ + std::shared_lock readLock(m_lock); + + auto monitorInfo = GetRawMonitorData(); + OrderMonitors(monitorInfo); + std::vector output; + std::transform(std::begin(monitorInfo), std::end(monitorInfo), std::back_inserter(output), [](const auto& info) { return info.first; }); + return output; +} + +std::vector> FancyZones::GetRawMonitorData() noexcept +{ + std::shared_lock readLock(m_lock); + + std::vector> monitorInfo; + for (const auto& [monitor, window] : m_zoneWindowMap) + { + if (window->ActiveZoneSet() != nullptr) + { + MONITORINFOEX mi; + mi.cbSize = sizeof(mi); + GetMonitorInfo(monitor, &mi); + monitorInfo.push_back({ monitor, mi.rcMonitor }); + } + } + return monitorInfo; +} + +bool FancyZones::MoveWindowIntoZoneByDirection(HMONITOR monitor, HWND window, DWORD vkCode, bool cycle) +{ + auto iter = m_zoneWindowMap.find(monitor); + if (iter != std::end(m_zoneWindowMap)) + { + const auto& zoneWindowPtr = iter->second; + return zoneWindowPtr->MoveWindowIntoZoneByDirection(window, vkCode, cycle); + } + return false; +} + winrt::com_ptr MakeFancyZones(HINSTANCE hinstance, const winrt::com_ptr& settings) noexcept { if (!settings) diff --git a/src/modules/fancyzones/lib/ZoneSet.cpp b/src/modules/fancyzones/lib/ZoneSet.cpp index 58c02635daf2..c76051f5a7c0 100644 --- a/src/modules/fancyzones/lib/ZoneSet.cpp +++ b/src/modules/fancyzones/lib/ZoneSet.cpp @@ -130,8 +130,8 @@ struct ZoneSet : winrt::implements GetZones() noexcept { return m_zones; } IFACEMETHODIMP_(void) MoveWindowIntoZoneByIndex(HWND window, HWND zoneWindow, int index) noexcept; - IFACEMETHODIMP_(void) - MoveWindowIntoZoneByDirection(HWND window, HWND zoneWindow, DWORD vkCode) noexcept; + IFACEMETHODIMP_(bool) + MoveWindowIntoZoneByDirection(HWND window, HWND zoneWindow, DWORD vkCode, bool cycle) noexcept; IFACEMETHODIMP_(void) MoveWindowIntoZoneByPoint(HWND window, HWND zoneWindow, POINT ptClient) noexcept; IFACEMETHODIMP_(bool) @@ -240,12 +240,12 @@ ZoneSet::MoveWindowIntoZoneByIndex(HWND window, HWND windowZone, int index) noex } } -IFACEMETHODIMP_(void) -ZoneSet::MoveWindowIntoZoneByDirection(HWND window, HWND windowZone, DWORD vkCode) noexcept +IFACEMETHODIMP_(bool) +ZoneSet::MoveWindowIntoZoneByDirection(HWND window, HWND windowZone, DWORD vkCode, bool cycle) noexcept { if (m_zones.empty()) { - return; + return false; } winrt::com_ptr oldZone = nullptr; @@ -262,6 +262,11 @@ ZoneSet::MoveWindowIntoZoneByDirection(HWND window, HWND windowZone, DWORD vkCod { if (iter == m_zones.begin()) { + if (!cycle) + { + oldZone->RemoveWindowFromZone(window, false); + return false; + } iter = m_zones.end(); } iter--; @@ -271,6 +276,11 @@ ZoneSet::MoveWindowIntoZoneByDirection(HWND window, HWND windowZone, DWORD vkCod iter++; if (iter == m_zones.end()) { + if (!cycle) + { + oldZone->RemoveWindowFromZone(window, false); + return false; + } iter = m_zones.begin(); } } @@ -283,7 +293,9 @@ ZoneSet::MoveWindowIntoZoneByDirection(HWND window, HWND windowZone, DWORD vkCod oldZone->RemoveWindowFromZone(window, false); } newZone->AddWindowToZone(window, windowZone, true); + return true; } + return false; } IFACEMETHODIMP_(void) diff --git a/src/modules/fancyzones/lib/ZoneSet.h b/src/modules/fancyzones/lib/ZoneSet.h index 6d595a82a304..94a7ff6c8b46 100644 --- a/src/modules/fancyzones/lib/ZoneSet.h +++ b/src/modules/fancyzones/lib/ZoneSet.h @@ -57,8 +57,12 @@ interface __declspec(uuid("{E4839EB7-669D-49CF-84A9-71A2DFD851A3}")) IZoneSet : * @param zoneWindow The m_window of a ZoneWindow, it's a hidden window representing the * current monitor desktop work area. * @param vkCode Pressed arrow key. + * @param cycle Whether we should move window to the first zone if we reached last zone in layout. + * + * @returns Boolean which is always true if cycle argument is set, otherwise indicating if there is more + * zones left in the zone layout in which window can move. */ - IFACEMETHOD_(void, MoveWindowIntoZoneByDirection)(HWND window, HWND zoneWindow, DWORD vkCode) = 0; + IFACEMETHOD_(bool, MoveWindowIntoZoneByDirection)(HWND window, HWND zoneWindow, DWORD vkCode, bool cycle) = 0; /** * Assign window to the zone based on cursor coordinates. * @@ -75,7 +79,8 @@ interface __declspec(uuid("{E4839EB7-669D-49CF-84A9-71A2DFD851A3}")) IZoneSet : * @param monitorInfo Information about monitor on which zone layout is applied. * @param zoneCount Number of zones inside zone layout. * @param spacing Spacing between zones in pixels. - * @returns Boolean if calculation was successful. + * + * @returns Boolean indicating if calculation was successful. */ IFACEMETHOD_(bool, CalculateZones)(MONITORINFO monitorInfo, int zoneCount, int spacing) = 0; }; diff --git a/src/modules/fancyzones/lib/ZoneWindow.cpp b/src/modules/fancyzones/lib/ZoneWindow.cpp index 9170d0562c8a..a1fdb4628070 100644 --- a/src/modules/fancyzones/lib/ZoneWindow.cpp +++ b/src/modules/fancyzones/lib/ZoneWindow.cpp @@ -283,8 +283,8 @@ struct ZoneWindow : public winrt::implements IsDragEnabled() noexcept { return m_dragEnabled; } IFACEMETHODIMP_(void) MoveWindowIntoZoneByIndex(HWND window, int index) noexcept; - IFACEMETHODIMP_(void) - MoveWindowIntoZoneByDirection(HWND window, DWORD vkCode) noexcept; + IFACEMETHODIMP_(bool) + MoveWindowIntoZoneByDirection(HWND window, DWORD vkCode, bool cycle) noexcept; IFACEMETHODIMP_(void) CycleActiveZoneSet(DWORD vkCode) noexcept; IFACEMETHODIMP_(std::wstring) @@ -466,14 +466,18 @@ ZoneWindow::MoveWindowIntoZoneByIndex(HWND window, int index) noexcept } } -IFACEMETHODIMP_(void) -ZoneWindow::MoveWindowIntoZoneByDirection(HWND window, DWORD vkCode) noexcept +IFACEMETHODIMP_(bool) +ZoneWindow::MoveWindowIntoZoneByDirection(HWND window, DWORD vkCode, bool cycle) noexcept { if (m_activeZoneSet) { - m_activeZoneSet->MoveWindowIntoZoneByDirection(window, m_window.get(), vkCode); - SaveWindowProcessToZoneIndex(window); + if (m_activeZoneSet->MoveWindowIntoZoneByDirection(window, m_window.get(), vkCode, cycle)) + { + SaveWindowProcessToZoneIndex(window); + return true; + } } + return false; } IFACEMETHODIMP_(void) diff --git a/src/modules/fancyzones/lib/ZoneWindow.h b/src/modules/fancyzones/lib/ZoneWindow.h index d2420e3eecd0..276fb7a7dd81 100644 --- a/src/modules/fancyzones/lib/ZoneWindow.h +++ b/src/modules/fancyzones/lib/ZoneWindow.h @@ -58,8 +58,12 @@ interface __declspec(uuid("{7F017528-8110-4FB3-BE41-F472969C2560}")) IZoneWindow * * @param window Handle of window which should be assigned to zone. * @param vkCode Pressed arrow key. + * @param cycle Whether we should move window to the first zone if we reached last zone in layout. + * + * @returns Boolean which is always true if cycle argument is set, otherwise indicating if there is more + * zones left in the zone layout in which window can move. */ - IFACEMETHOD_(void, MoveWindowIntoZoneByDirection)(HWND window, DWORD vkCode) = 0; + IFACEMETHOD_(bool, MoveWindowIntoZoneByDirection)(HWND window, DWORD vkCode, bool cycle) = 0; /** * Cycle through active zone layouts (giving hints about each layout). * diff --git a/src/modules/fancyzones/lib/util.cpp b/src/modules/fancyzones/lib/util.cpp index aee018f06767..631af7e52841 100644 --- a/src/modules/fancyzones/lib/util.cpp +++ b/src/modules/fancyzones/lib/util.cpp @@ -25,3 +25,86 @@ UINT GetDpiForMonitor(HMONITOR monitor) noexcept return (dpi == 0) ? DPIAware::DEFAULT_DPI : dpi; } + +void OrderMonitors(std::vector>& monitorInfo) +{ + const size_t nMonitors = monitorInfo.size(); + // blocking[i][j] - whether monitor i blocks monitor j in the ordering, i.e. monitor i should go before monitor j + std::vector> blocking(nMonitors, std::vector(nMonitors, false)); + + // blockingCount[j] - the number of monitors which block monitor j + std::vector blockingCount(nMonitors, 0); + + for (size_t i = 0; i < nMonitors; i++) + { + RECT rectI = monitorInfo[i].second; + for (size_t j = 0; j < nMonitors; j++) + { + RECT rectJ = monitorInfo[j].second; + blocking[i][j] = rectI.top < rectJ.bottom && rectI.left < rectJ.right && i != j; + if (blocking[i][j]) + { + blockingCount[j]++; + } + } + } + + // used[i] - whether the sorting algorithm has used monitor i so far + std::vector used(nMonitors, false); + + // the sorted sequence of monitors + std::vector> sortedMonitorInfo; + + for (size_t iteration = 0; iteration < nMonitors; iteration++) + { + // Indices of candidates to become the next monitor in the sequence + std::vector candidates; + + // First, find indices of all unblocked monitors + for (size_t i = 0; i < nMonitors; i++) + { + if (blockingCount[i] == 0 && !used[i]) + { + candidates.push_back(i); + } + } + + // In the unlikely event that there are no unblocked monitors, declare all unused monitors as candidates. + if (candidates.empty()) + { + for (size_t i = 0; i < nMonitors; i++) + { + if (!used[i]) + { + candidates.push_back(i); + } + } + } + + // Pick the lexicographically smallest monitor as the next one + size_t smallest = candidates[0]; + for (size_t j = 1; j < candidates.size(); j++) + { + size_t current = candidates[j]; + + // Compare (top, left) lexicographically + if (std::tie(monitorInfo[current].second.top, monitorInfo[current].second.left) + < std::tie(monitorInfo[smallest].second.top, monitorInfo[smallest].second.left)) + { + smallest = current; + } + } + + used[smallest] = true; + sortedMonitorInfo.push_back(monitorInfo[smallest]); + for (size_t i = 0; i < nMonitors; i++) + { + if (blocking[smallest][i]) + { + blockingCount[i]--; + } + } + } + + monitorInfo = std::move(sortedMonitorInfo); +} diff --git a/src/modules/fancyzones/lib/util.h b/src/modules/fancyzones/lib/util.h index 23a65ed53427..82cad6bc8845 100644 --- a/src/modules/fancyzones/lib/util.h +++ b/src/modules/fancyzones/lib/util.h @@ -146,4 +146,5 @@ inline unsigned char OpacitySettingToAlpha(int opacity) return static_cast(opacity * 2.55); } -UINT GetDpiForMonitor(HMONITOR monitor) noexcept; \ No newline at end of file +UINT GetDpiForMonitor(HMONITOR monitor) noexcept; +void OrderMonitors(std::vector>& monitorInfo); diff --git a/src/modules/fancyzones/tests/UnitTests/Util.Spec.cpp b/src/modules/fancyzones/tests/UnitTests/Util.Spec.cpp index aabc07f8a83b..772bf6e75fcb 100644 --- a/src/modules/fancyzones/tests/UnitTests/Util.Spec.cpp +++ b/src/modules/fancyzones/tests/UnitTests/Util.Spec.cpp @@ -1,32 +1,235 @@ #include "pch.h" +#include "Util.h" #include "lib\util.h" using namespace Microsoft::VisualStudio::CppUnitTestFramework; namespace FancyZonesUnitTests { - TEST_CLASS(UtilUnitTests){ - public: - TEST_METHOD(TestParseDeviceId){ - // We're interested in the unique part between the first and last #'s - // Example input: \\?\DISPLAY#DELA026#5&10a58c63&0&UID16777488#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7} - // Example output: DELA026#5&10a58c63&0&UID16777488 - PCWSTR input = L"\\\\?\\DISPLAY#DELA026#5&10a58c63&0&UID16777488#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}"; - wchar_t output[256]{}; - ParseDeviceId(input, output, ARRAYSIZE(output)); - Assert::AreEqual(0, wcscmp(output, L"DELA026#5&10a58c63&0&UID16777488")); -} + void TestMonitorSetPermutations(const std::vector>& monitorInfo) + { + auto monitorInfoPermutation = monitorInfo; -TEST_METHOD(TestParseInvalidDeviceId) -{ - // We're interested in the unique part between the first and last #'s - // Example input: \\?\DISPLAY#DELA026#5&10a58c63&0&UID16777488#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7} - // Example output: DELA026#5&10a58c63&0&UID16777488 - PCWSTR input = L"AnInvalidDeviceId"; - wchar_t output[256]{}; - ParseDeviceId(input, output, ARRAYSIZE(output)); - Assert::AreEqual(0, wcscmp(output, L"FallbackDevice")); -} -} -; + do { + auto monitorInfoCopy = monitorInfoPermutation; + OrderMonitors(monitorInfoCopy); + CustomAssert::AreEqual(monitorInfo, monitorInfoCopy); + } while (std::next_permutation(monitorInfoPermutation.begin(), monitorInfoPermutation.end(), [](auto x, auto y) { return x.first < y.first; })); + } + + void TestMonitorSetPermutationsOffsets(const std::vector>& monitorInfo) + { + for (int offsetX = -3000; offsetX <= 3000; offsetX += 1000) + { + for (int offsetY = -3000; offsetY <= 3000; offsetY += 1000) + { + auto monitorInfoCopy = monitorInfo; + for (auto& [monitor, rect] : monitorInfoCopy) + { + rect.left += offsetX; + rect.right += offsetX; + rect.top += offsetY; + rect.bottom += offsetY; + } + TestMonitorSetPermutations(monitorInfoCopy); + } + } + } + + TEST_CLASS(UtilUnitTests) + { + TEST_METHOD(TestParseDeviceId) + { + // We're interested in the unique part between the first and last #'s + // Example input: \\?\DISPLAY#DELA026#5&10a58c63&0&UID16777488#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7} + // Example output: DELA026#5&10a58c63&0&UID16777488 + PCWSTR input = L"\\\\?\\DISPLAY#DELA026#5&10a58c63&0&UID16777488#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}"; + wchar_t output[256]{}; + ParseDeviceId(input, output, ARRAYSIZE(output)); + Assert::AreEqual(0, wcscmp(output, L"DELA026#5&10a58c63&0&UID16777488")); + } + + TEST_METHOD(TestParseInvalidDeviceId) + { + // We're interested in the unique part between the first and last #'s + // Example input: \\?\DISPLAY#DELA026#5&10a58c63&0&UID16777488#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7} + // Example output: DELA026#5&10a58c63&0&UID16777488 + PCWSTR input = L"AnInvalidDeviceId"; + wchar_t output[256]{}; + ParseDeviceId(input, output, ARRAYSIZE(output)); + Assert::AreEqual(0, wcscmp(output, L"FallbackDevice")); + } + + TEST_METHOD(TestMonitorOrdering01) + { + // Three horizontally arranged monitors, bottom aligned, with increasing sizes + std::vector> monitorInfo = { + {Mocks::Monitor(), RECT{.left = 0, .top = 200, .right = 1600, .bottom = 1100} }, + {Mocks::Monitor(), RECT{.left = 1600, .top = 100, .right = 3300, .bottom = 1100} }, + {Mocks::Monitor(), RECT{.left = 3300, .top = 0, .right = 5100, .bottom = 1100} }, + }; + + TestMonitorSetPermutationsOffsets(monitorInfo); + } + + TEST_METHOD(TestMonitorOrdering02) + { + // Three horizontally arranged monitors, bottom aligned, with equal sizes + std::vector> monitorInfo = { + {Mocks::Monitor(), RECT{.left = 0, .top = 0, .right = 1600, .bottom = 900} }, + {Mocks::Monitor(), RECT{.left = 1600, .top = 0, .right = 3200, .bottom = 900} }, + {Mocks::Monitor(), RECT{.left = 3200, .top = 0, .right = 4800, .bottom = 900} }, + }; + + TestMonitorSetPermutationsOffsets(monitorInfo); + } + + TEST_METHOD(TestMonitorOrdering03) + { + // Three horizontally arranged monitors, bottom aligned, with decreasing sizes + std::vector> monitorInfo = { + {Mocks::Monitor(), RECT{.left = 0, .top = 0, .right = 1800, .bottom = 1100} }, + {Mocks::Monitor(), RECT{.left = 1800, .top = 100, .right = 3500, .bottom = 1100} }, + {Mocks::Monitor(), RECT{.left = 3500, .top = 200, .right = 5100, .bottom = 1100} }, + }; + + TestMonitorSetPermutationsOffsets(monitorInfo); + } + + TEST_METHOD(TestMonitorOrdering04) + { + // Three horizontally arranged monitors, top aligned, with increasing sizes + std::vector> monitorInfo = { + {Mocks::Monitor(), RECT{.left = 0, .top = 0, .right = 1600, .bottom = 900} }, + {Mocks::Monitor(), RECT{.left = 1600, .top = 0, .right = 3300, .bottom = 1000} }, + {Mocks::Monitor(), RECT{.left = 3300, .top = 0, .right = 5100, .bottom = 1100} }, + }; + + TestMonitorSetPermutationsOffsets(monitorInfo); + } + + TEST_METHOD(TestMonitorOrdering05) + { + // Three horizontally arranged monitors, top aligned, with equal sizes + std::vector> monitorInfo = { + {Mocks::Monitor(), RECT{.left = 0, .top = 0, .right = 1600, .bottom = 900} }, + {Mocks::Monitor(), RECT{.left = 1600, .top = 0, .right = 3200, .bottom = 900} }, + {Mocks::Monitor(), RECT{.left = 3200, .top = 0, .right = 4800, .bottom = 900} }, + }; + + TestMonitorSetPermutationsOffsets(monitorInfo); + } + + TEST_METHOD(TestMonitorOrdering06) + { + // Three horizontally arranged monitors, top aligned, with decreasing sizes + std::vector> monitorInfo = { + {Mocks::Monitor(), RECT{.left = 0, .top = 0, .right = 1800, .bottom = 1100} }, + {Mocks::Monitor(), RECT{.left = 1800, .top = 0, .right = 3500, .bottom = 1000} }, + {Mocks::Monitor(), RECT{.left = 3500, .top = 0, .right = 5100, .bottom = 900} }, + }; + + TestMonitorSetPermutationsOffsets(monitorInfo); + } + + TEST_METHOD(TestMonitorOrdering07) + { + // Three vertically arranged monitors, center aligned, with equal sizes, except the middle monitor is a bit wider + std::vector> monitorInfo = { + {Mocks::Monitor(), RECT{.left = 100, .top = 0, .right = 1700, .bottom = 900} }, + {Mocks::Monitor(), RECT{.left = 0, .top = 900, .right = 1800, .bottom = 1800} }, + {Mocks::Monitor(), RECT{.left = 100, .top = 1800, .right = 1700, .bottom = 2700} }, + }; + + TestMonitorSetPermutationsOffsets(monitorInfo); + } + + TEST_METHOD(TestMonitorOrdering08) + { + // ------------------ + // | || || | + // | || || | + // ------------------ + // | || | + // | || | + // ------------------ + std::vector> monitorInfo = { + {Mocks::Monitor(), RECT{.left = 0, .top = 0, .right = 600, .bottom = 400} }, + {Mocks::Monitor(), RECT{.left = 600, .top = 0, .right = 1200, .bottom = 400} }, + {Mocks::Monitor(), RECT{.left = 1200, .top = 0, .right = 1800, .bottom = 400} }, + {Mocks::Monitor(), RECT{.left = 0, .top = 400, .right = 900, .bottom = 800} }, + {Mocks::Monitor(), RECT{.left = 900, .top = 400, .right = 1800, .bottom = 800} }, + }; + + TestMonitorSetPermutationsOffsets(monitorInfo); + } + + TEST_METHOD(TestMonitorOrdering09) + { + // Regular 3x3 grid + std::vector> monitorInfo = { + {Mocks::Monitor(), RECT{.left = 0, .top = 0, .right = 400, .bottom = 300} }, + {Mocks::Monitor(), RECT{.left = 400, .top = 0, .right = 800, .bottom = 300} }, + {Mocks::Monitor(), RECT{.left = 800, .top = 0, .right = 1200, .bottom = 300} }, + {Mocks::Monitor(), RECT{.left = 0, .top = 300, .right = 400, .bottom = 600} }, + {Mocks::Monitor(), RECT{.left = 400, .top = 300, .right = 800, .bottom = 600} }, + {Mocks::Monitor(), RECT{.left = 800, .top = 300, .right = 1200, .bottom = 600} }, + {Mocks::Monitor(), RECT{.left = 0, .top = 600, .right = 400, .bottom = 900} }, + {Mocks::Monitor(), RECT{.left = 400, .top = 600, .right = 800, .bottom = 900} }, + {Mocks::Monitor(), RECT{.left = 800, .top = 600, .right = 1200, .bottom = 900} }, + }; + + // Reduce running time by testing only rotations + for (int i = 0; i < 9; i++) + { + auto monitorInfoCopy = monitorInfo; + std::rotate(monitorInfoCopy.begin(), monitorInfoCopy.begin() + i, monitorInfoCopy.end()); + OrderMonitors(monitorInfoCopy); + CustomAssert::AreEqual(monitorInfo, monitorInfoCopy); + } + } + + TEST_METHOD(TestMonitorOrdering10) + { + // ------------------ + // | || | + // | || | + // ------------------ + // | || || | + // | || || | + // ------------------ + std::vector> monitorInfo = { + {Mocks::Monitor(), RECT{.left = 0, .top = 0, .right = 900, .bottom = 400} }, + {Mocks::Monitor(), RECT{.left = 900, .top = 0, .right = 1800, .bottom = 400} }, + {Mocks::Monitor(), RECT{.left = 0, .top = 400, .right = 600, .bottom = 800} }, + {Mocks::Monitor(), RECT{.left = 600, .top = 400, .right = 1200, .bottom = 800} }, + {Mocks::Monitor(), RECT{.left = 1200, .top = 400, .right = 1800, .bottom = 800} }, + }; + + TestMonitorSetPermutationsOffsets(monitorInfo); + } + + TEST_METHOD(TestMonitorOrdering11) + { + // Random values, some monitors overlap, don't check order, just ensure it doesn't crash and it's the same every time + std::vector> monitorInfo = { + {Mocks::Monitor(), RECT{.left = 410, .top = 630, .right = 988, .bottom = 631} }, + {Mocks::Monitor(), RECT{.left = 302, .top = 189, .right = 550, .bottom = 714} }, + {Mocks::Monitor(), RECT{.left = 158, .top = 115, .right = 657, .bottom = 499} }, + {Mocks::Monitor(), RECT{.left = 341, .top = 340, .right = 723, .bottom = 655} }, + {Mocks::Monitor(), RECT{.left = 433, .top = 393, .right = 846, .bottom = 544} }, + }; + + auto monitorInfoPermutation = monitorInfo; + auto firstTime = monitorInfo; + OrderMonitors(firstTime); + + do { + auto monitorInfoCopy = monitorInfoPermutation; + OrderMonitors(monitorInfoCopy); + CustomAssert::AreEqual(firstTime, monitorInfoCopy); + } while (next_permutation(monitorInfoPermutation.begin(), monitorInfoPermutation.end(), [](auto x, auto y) { return x.first < y.first; })); + } + }; } + diff --git a/src/modules/fancyzones/tests/UnitTests/Util.h b/src/modules/fancyzones/tests/UnitTests/Util.h index fa55b301e16a..91a9d509c12f 100644 --- a/src/modules/fancyzones/tests/UnitTests/Util.h +++ b/src/modules/fancyzones/tests/UnitTests/Util.h @@ -19,6 +19,15 @@ namespace CustomAssert { Microsoft::VisualStudio::CppUnitTestFramework::Assert::IsTrue(t1 == t2); } + + static void AreEqual(const std::vector>& a1, const std::vector>& a2) + { + Microsoft::VisualStudio::CppUnitTestFramework::Assert::IsTrue(a1.size() == a2.size()); + for (size_t i = 0; i < a1.size(); i++) + { + Microsoft::VisualStudio::CppUnitTestFramework::Assert::IsTrue(a1[i].first == a2[i].first); + } + } } namespace Mocks diff --git a/src/modules/fancyzones/tests/UnitTests/ZoneSet.Spec.cpp b/src/modules/fancyzones/tests/UnitTests/ZoneSet.Spec.cpp index c1cead89e4fe..56e59c325e2a 100644 --- a/src/modules/fancyzones/tests/UnitTests/ZoneSet.Spec.cpp +++ b/src/modules/fancyzones/tests/UnitTests/ZoneSet.Spec.cpp @@ -12,7 +12,7 @@ using TZoneSetLayoutType = JSONHelpers::ZoneSetLayoutType; namespace FancyZonesUnitTests { - TEST_CLASS(ZoneSetUnitTests) + TEST_CLASS (ZoneSetUnitTests) { GUID m_id; const TZoneSetLayoutType m_layoutType = TZoneSetLayoutType::Custom; @@ -21,481 +21,481 @@ namespace FancyZonesUnitTests winrt::com_ptr m_set; TEST_METHOD_INITIALIZE(Init) - { - auto hres = CoCreateGuid(&m_id); - Assert::AreEqual(S_OK, hres); - - ZoneSetConfig m_config = ZoneSetConfig(m_id, m_layoutType, Mocks::Monitor(), m_resolutionKey); - m_set = MakeZoneSet(m_config); - } - - void compareZones(const winrt::com_ptr& expected, const winrt::com_ptr& actual) - { - Assert::AreEqual(expected->Id(), actual->Id()); - Assert::AreEqual(expected->GetZoneRect().left, actual->GetZoneRect().left); - Assert::AreEqual(expected->GetZoneRect().right, actual->GetZoneRect().right); - Assert::AreEqual(expected->GetZoneRect().top, actual->GetZoneRect().top); - Assert::AreEqual(expected->GetZoneRect().bottom, actual->GetZoneRect().bottom); - } - - public: - TEST_METHOD(TestCreateZoneSet) - { - Assert::IsNotNull(&m_set); - CustomAssert::AreEqual(m_set->Id(), m_id); - CustomAssert::AreEqual(m_set->LayoutType(), m_layoutType); - } + { + auto hres = CoCreateGuid(&m_id); + Assert::AreEqual(S_OK, hres); - TEST_METHOD(TestCreateZoneSetGuidEmpty) - { - GUID zoneSetId{}; - ZoneSetConfig config(zoneSetId, m_layoutType, Mocks::Monitor(), m_resolutionKey); - winrt::com_ptr set = MakeZoneSet(config); + ZoneSetConfig m_config = ZoneSetConfig(m_id, m_layoutType, Mocks::Monitor(), m_resolutionKey); + m_set = MakeZoneSet(m_config); + } - Assert::IsNotNull(&set); - CustomAssert::AreEqual(set->Id(), zoneSetId); - CustomAssert::AreEqual(set->LayoutType(), m_layoutType); - } + void compareZones(const winrt::com_ptr& expected, const winrt::com_ptr& actual) + { + Assert::AreEqual(expected->Id(), actual->Id()); + Assert::AreEqual(expected->GetZoneRect().left, actual->GetZoneRect().left); + Assert::AreEqual(expected->GetZoneRect().right, actual->GetZoneRect().right); + Assert::AreEqual(expected->GetZoneRect().top, actual->GetZoneRect().top); + Assert::AreEqual(expected->GetZoneRect().bottom, actual->GetZoneRect().bottom); + } - TEST_METHOD(TestCreateZoneSetMonitorEmpty) - { - ZoneSetConfig config(m_id, m_layoutType, nullptr, m_resolutionKey); - winrt::com_ptr set = MakeZoneSet(config); - Assert::IsNotNull(&set); - CustomAssert::AreEqual(set->Id(), m_id); - CustomAssert::AreEqual(set->LayoutType(), m_layoutType); - } + public: + TEST_METHOD (TestCreateZoneSet) + { + Assert::IsNotNull(&m_set); + CustomAssert::AreEqual(m_set->Id(), m_id); + CustomAssert::AreEqual(m_set->LayoutType(), m_layoutType); + } - TEST_METHOD(TestCreateZoneSetKeyEmpty) - { - ZoneSetConfig config(m_id, m_layoutType, Mocks::Monitor(), nullptr); - winrt::com_ptr set = MakeZoneSet(config); - Assert::IsNotNull(&set); - CustomAssert::AreEqual(set->Id(), m_id); - CustomAssert::AreEqual(set->LayoutType(), m_layoutType); - } + TEST_METHOD (TestCreateZoneSetGuidEmpty) + { + GUID zoneSetId{}; + ZoneSetConfig config(zoneSetId, m_layoutType, Mocks::Monitor(), m_resolutionKey); + winrt::com_ptr set = MakeZoneSet(config); - TEST_METHOD(EmptyZones) - { - auto zones = m_set->GetZones(); - Assert::AreEqual((size_t)0, zones.size()); - } + Assert::IsNotNull(&set); + CustomAssert::AreEqual(set->Id(), zoneSetId); + CustomAssert::AreEqual(set->LayoutType(), m_layoutType); + } - TEST_METHOD(AddOne) - { - winrt::com_ptr zone = MakeZone({ 0, 0, 100, 100 }); - m_set->AddZone(zone); - auto zones = m_set->GetZones(); - Assert::AreEqual((size_t)1, zones.size()); - compareZones(zone, zones[0]); - Assert::AreEqual((size_t)1, zones[0]->Id()); - } + TEST_METHOD (TestCreateZoneSetMonitorEmpty) + { + ZoneSetConfig config(m_id, m_layoutType, nullptr, m_resolutionKey); + winrt::com_ptr set = MakeZoneSet(config); + Assert::IsNotNull(&set); + CustomAssert::AreEqual(set->Id(), m_id); + CustomAssert::AreEqual(set->LayoutType(), m_layoutType); + } - TEST_METHOD(AddManySame) - { - winrt::com_ptr zone = MakeZone({ 0, 0, 100, 100 }); - for (size_t i = 0; i < 1024; i++) + TEST_METHOD (TestCreateZoneSetKeyEmpty) { - m_set->AddZone(zone); - auto zones = m_set->GetZones(); - Assert::AreEqual(i + 1, zones.size()); - compareZones(zone, zones[i]); - Assert::AreEqual(i + 1, zones[i]->Id()); + ZoneSetConfig config(m_id, m_layoutType, Mocks::Monitor(), nullptr); + winrt::com_ptr set = MakeZoneSet(config); + Assert::IsNotNull(&set); + CustomAssert::AreEqual(set->Id(), m_id); + CustomAssert::AreEqual(set->LayoutType(), m_layoutType); } - } - TEST_METHOD(AddManyEqual) - { - for (size_t i = 0; i < 1024; i++) + TEST_METHOD (EmptyZones) { - winrt::com_ptr zone = MakeZone({ 0, 0, 100, 100 }); - m_set->AddZone(zone); auto zones = m_set->GetZones(); - Assert::AreEqual(i + 1, zones.size()); - compareZones(zone, zones[i]); - Assert::AreEqual(i + 1, zones[i]->Id()); + Assert::AreEqual((size_t)0, zones.size()); } - } - TEST_METHOD(AddManyDifferent) - { - for (size_t i = 0; i < 1024; i++) + TEST_METHOD (AddOne) { - winrt::com_ptr zone = MakeZone({ rand() % 10, rand() % 10, rand() % 100, rand() % 100 }); + winrt::com_ptr zone = MakeZone({ 0, 0, 100, 100 }); m_set->AddZone(zone); auto zones = m_set->GetZones(); - Assert::AreEqual(i + 1, zones.size()); - compareZones(zone, zones[i]); - Assert::AreEqual(i + 1, zones[i]->Id()); + Assert::AreEqual((size_t)1, zones.size()); + compareZones(zone, zones[0]); + Assert::AreEqual((size_t)1, zones[0]->Id()); } - } - - TEST_METHOD(ZoneFromPointEmpty) - { - auto actual = m_set->ZoneFromPoint(POINT{ 0, 0 }); - Assert::IsTrue(nullptr == actual); - } - - TEST_METHOD(ZoneFromPointInner) - { - const int left = 0, top = 0, right = 100, bottom = 100; - winrt::com_ptr expected = MakeZone({ left, top, right, bottom }); - m_set->AddZone(expected); - for (int i = left + 1; i < right; i++) + TEST_METHOD (AddManySame) { - for (int j = top + 1; j < bottom; j++) + winrt::com_ptr zone = MakeZone({ 0, 0, 100, 100 }); + for (size_t i = 0; i < 1024; i++) { - auto actual = m_set->ZoneFromPoint(POINT{ i, j }); - Assert::IsTrue(actual != nullptr); - compareZones(expected, actual); + m_set->AddZone(zone); + auto zones = m_set->GetZones(); + Assert::AreEqual(i + 1, zones.size()); + compareZones(zone, zones[i]); + Assert::AreEqual(i + 1, zones[i]->Id()); } } - } - - TEST_METHOD(ZoneFromPointBorder) - { - const int left = 0, top = 0, right = 100, bottom = 100; - winrt::com_ptr expected = MakeZone({ left, top, right, bottom }); - m_set->AddZone(expected); - for (int i = left; i < right; i++) + TEST_METHOD (AddManyEqual) { - auto actual = m_set->ZoneFromPoint(POINT{ i, top }); - Assert::IsTrue(actual != nullptr); - compareZones(expected, actual); + for (size_t i = 0; i < 1024; i++) + { + winrt::com_ptr zone = MakeZone({ 0, 0, 100, 100 }); + m_set->AddZone(zone); + auto zones = m_set->GetZones(); + Assert::AreEqual(i + 1, zones.size()); + compareZones(zone, zones[i]); + Assert::AreEqual(i + 1, zones[i]->Id()); + } } - for (int i = top; i < bottom; i++) + TEST_METHOD (AddManyDifferent) { - auto actual = m_set->ZoneFromPoint(POINT{ left, i }); - Assert::IsTrue(actual != nullptr); - compareZones(expected, actual); + for (size_t i = 0; i < 1024; i++) + { + winrt::com_ptr zone = MakeZone({ rand() % 10, rand() % 10, rand() % 100, rand() % 100 }); + m_set->AddZone(zone); + auto zones = m_set->GetZones(); + Assert::AreEqual(i + 1, zones.size()); + compareZones(zone, zones[i]); + Assert::AreEqual(i + 1, zones[i]->Id()); + } } - //bottom and right borders considered to be outside - for (int i = left; i < right; i++) + TEST_METHOD (ZoneFromPointEmpty) { - auto actual = m_set->ZoneFromPoint(POINT{ i, bottom }); + auto actual = m_set->ZoneFromPoint(POINT{ 0, 0 }); Assert::IsTrue(nullptr == actual); } - for (int i = top; i < bottom; i++) + TEST_METHOD (ZoneFromPointInner) { - auto actual = m_set->ZoneFromPoint(POINT{ right, i }); - Assert::IsTrue(nullptr == actual); - } - } + const int left = 0, top = 0, right = 100, bottom = 100; + winrt::com_ptr expected = MakeZone({ left, top, right, bottom }); + m_set->AddZone(expected); - TEST_METHOD(ZoneFromPointOuter) - { - const int left = 0, top = 0, right = 100, bottom = 100; - winrt::com_ptr zone = MakeZone({ left, top, right, bottom }); - m_set->AddZone(zone); - - auto actual = m_set->ZoneFromPoint(POINT{ 101, 101 }); - Assert::IsTrue(actual == nullptr); - } - - TEST_METHOD(ZoneFromPointOverlapping) - { - winrt::com_ptr zone1 = MakeZone({ 0, 0, 100, 100 }); - m_set->AddZone(zone1); - winrt::com_ptr zone2 = MakeZone({ 10, 10, 90, 90 }); - m_set->AddZone(zone2); - winrt::com_ptr zone3 = MakeZone({ 10, 10, 150, 150 }); - m_set->AddZone(zone3); - winrt::com_ptr zone4 = MakeZone({ 10, 10, 50, 50 }); - m_set->AddZone(zone4); - - auto actual = m_set->ZoneFromPoint(POINT{ 50, 50 }); - Assert::IsTrue(actual != nullptr); - compareZones(zone2, actual); - } + for (int i = left + 1; i < right; i++) + { + for (int j = top + 1; j < bottom; j++) + { + auto actual = m_set->ZoneFromPoint(POINT{ i, j }); + Assert::IsTrue(actual != nullptr); + compareZones(expected, actual); + } + } + } - TEST_METHOD(ZoneFromPointWithNotNormalizedRect) - { - winrt::com_ptr zone = MakeZone({ 100, 100, 0, 0 }); - m_set->AddZone(zone); + TEST_METHOD (ZoneFromPointBorder) + { + const int left = 0, top = 0, right = 100, bottom = 100; + winrt::com_ptr expected = MakeZone({ left, top, right, bottom }); + m_set->AddZone(expected); - auto actual = m_set->ZoneFromPoint(POINT{ 50, 50 }); - Assert::IsTrue(actual == nullptr); - } + for (int i = left; i < right; i++) + { + auto actual = m_set->ZoneFromPoint(POINT{ i, top }); + Assert::IsTrue(actual != nullptr); + compareZones(expected, actual); + } - TEST_METHOD(ZoneFromPointWithZeroRect) - { - winrt::com_ptr zone = MakeZone({ 0, 0, 0, 0 }); - m_set->AddZone(zone); + for (int i = top; i < bottom; i++) + { + auto actual = m_set->ZoneFromPoint(POINT{ left, i }); + Assert::IsTrue(actual != nullptr); + compareZones(expected, actual); + } - auto actual = m_set->ZoneFromPoint(POINT{ 0, 0 }); - Assert::IsTrue(actual == nullptr); - } + //bottom and right borders considered to be outside + for (int i = left; i < right; i++) + { + auto actual = m_set->ZoneFromPoint(POINT{ i, bottom }); + Assert::IsTrue(nullptr == actual); + } - TEST_METHOD(ZoneIndexFromWindow) - { - HWND window = Mocks::Window(); - HWND zoneWindow = Mocks::Window(); + for (int i = top; i < bottom; i++) + { + auto actual = m_set->ZoneFromPoint(POINT{ right, i }); + Assert::IsTrue(nullptr == actual); + } + } - winrt::com_ptr zone1 = MakeZone({ 0, 0, 100, 100 }); - winrt::com_ptr zone2 = MakeZone({ 20, 20, 200, 200 }); - winrt::com_ptr zone3 = MakeZone({ 0, 0, 100, 100 }); - winrt::com_ptr zone4 = MakeZone({ 10, 10, 100, 100 }); - winrt::com_ptr zone5 = MakeZone({ 20, 20, 100, 100 }); + TEST_METHOD (ZoneFromPointOuter) + { + const int left = 0, top = 0, right = 100, bottom = 100; + winrt::com_ptr zone = MakeZone({ left, top, right, bottom }); + m_set->AddZone(zone); - zone3->AddWindowToZone(window, zoneWindow, true); + auto actual = m_set->ZoneFromPoint(POINT{ 101, 101 }); + Assert::IsTrue(actual == nullptr); + } - m_set->AddZone(zone1); - m_set->AddZone(zone2); - m_set->AddZone(zone3); - m_set->AddZone(zone4); - m_set->AddZone(zone5); + TEST_METHOD (ZoneFromPointOverlapping) + { + winrt::com_ptr zone1 = MakeZone({ 0, 0, 100, 100 }); + m_set->AddZone(zone1); + winrt::com_ptr zone2 = MakeZone({ 10, 10, 90, 90 }); + m_set->AddZone(zone2); + winrt::com_ptr zone3 = MakeZone({ 10, 10, 150, 150 }); + m_set->AddZone(zone3); + winrt::com_ptr zone4 = MakeZone({ 10, 10, 50, 50 }); + m_set->AddZone(zone4); + + auto actual = m_set->ZoneFromPoint(POINT{ 50, 50 }); + Assert::IsTrue(actual != nullptr); + compareZones(zone2, actual); + } - const int expected = 2; - auto actual = m_set->GetZoneIndexFromWindow(window); - Assert::AreEqual(expected, actual); - } + TEST_METHOD (ZoneFromPointWithNotNormalizedRect) + { + winrt::com_ptr zone = MakeZone({ 100, 100, 0, 0 }); + m_set->AddZone(zone); - TEST_METHOD(ZoneIndexFromWindowWithEqualWindows) - { - HWND window = Mocks::Window(); - HWND zoneWindow = Mocks::Window(); - - winrt::com_ptr zone1 = MakeZone({ 0, 0, 100, 100 }); - winrt::com_ptr zone2 = MakeZone({ 20, 20, 200, 200 }); - winrt::com_ptr zone3 = MakeZone({ 0, 0, 100, 100 }); - winrt::com_ptr zone4 = MakeZone({ 10, 10, 100, 100 }); - winrt::com_ptr zone5 = MakeZone({ 20, 20, 100, 100 }); - - zone3->AddWindowToZone(window, zoneWindow, true); - zone4->AddWindowToZone(window, zoneWindow, true); - - m_set->AddZone(zone1); - m_set->AddZone(zone2); - m_set->AddZone(zone3); - m_set->AddZone(zone4); - m_set->AddZone(zone5); - - const int expected = 2; - auto actual = m_set->GetZoneIndexFromWindow(window); - Assert::AreEqual(expected, actual); - } + auto actual = m_set->ZoneFromPoint(POINT{ 50, 50 }); + Assert::IsTrue(actual == nullptr); + } - TEST_METHOD(ZoneIndexFromWindowUnknown) - { - winrt::com_ptr zone = MakeZone({ 0, 0, 100, 100 }); - HWND window = Mocks::Window(); - HWND zoneWindow = Mocks::Window(); - zone->AddWindowToZone(window, zoneWindow, true); - m_set->AddZone(zone); + TEST_METHOD (ZoneFromPointWithZeroRect) + { + winrt::com_ptr zone = MakeZone({ 0, 0, 0, 0 }); + m_set->AddZone(zone); - const int expected = -1; - auto actual = m_set->GetZoneIndexFromWindow(Mocks::Window()); - Assert::AreEqual(expected, actual); - } + auto actual = m_set->ZoneFromPoint(POINT{ 0, 0 }); + Assert::IsTrue(actual == nullptr); + } - TEST_METHOD(ZoneIndexFromWindowNull) - { - winrt::com_ptr zone = MakeZone({ 0, 0, 100, 100 }); - HWND window = Mocks::Window(); - HWND zoneWindow = Mocks::Window(); - zone->AddWindowToZone(window, zoneWindow, true); - m_set->AddZone(zone); + TEST_METHOD (ZoneIndexFromWindow) + { + HWND window = Mocks::Window(); + HWND zoneWindow = Mocks::Window(); + + winrt::com_ptr zone1 = MakeZone({ 0, 0, 100, 100 }); + winrt::com_ptr zone2 = MakeZone({ 20, 20, 200, 200 }); + winrt::com_ptr zone3 = MakeZone({ 0, 0, 100, 100 }); + winrt::com_ptr zone4 = MakeZone({ 10, 10, 100, 100 }); + winrt::com_ptr zone5 = MakeZone({ 20, 20, 100, 100 }); + + zone3->AddWindowToZone(window, zoneWindow, true); + + m_set->AddZone(zone1); + m_set->AddZone(zone2); + m_set->AddZone(zone3); + m_set->AddZone(zone4); + m_set->AddZone(zone5); + + const int expected = 2; + auto actual = m_set->GetZoneIndexFromWindow(window); + Assert::AreEqual(expected, actual); + } - const int expected = -1; - auto actual = m_set->GetZoneIndexFromWindow(nullptr); - Assert::AreEqual(expected, actual); - } + TEST_METHOD (ZoneIndexFromWindowWithEqualWindows) + { + HWND window = Mocks::Window(); + HWND zoneWindow = Mocks::Window(); + + winrt::com_ptr zone1 = MakeZone({ 0, 0, 100, 100 }); + winrt::com_ptr zone2 = MakeZone({ 20, 20, 200, 200 }); + winrt::com_ptr zone3 = MakeZone({ 0, 0, 100, 100 }); + winrt::com_ptr zone4 = MakeZone({ 10, 10, 100, 100 }); + winrt::com_ptr zone5 = MakeZone({ 20, 20, 100, 100 }); + + zone3->AddWindowToZone(window, zoneWindow, true); + zone4->AddWindowToZone(window, zoneWindow, true); + + m_set->AddZone(zone1); + m_set->AddZone(zone2); + m_set->AddZone(zone3); + m_set->AddZone(zone4); + m_set->AddZone(zone5); + + const int expected = 2; + auto actual = m_set->GetZoneIndexFromWindow(window); + Assert::AreEqual(expected, actual); + } - TEST_METHOD(MoveWindowIntoZoneByIndex) - { - winrt::com_ptr zone1 = MakeZone({ 0, 0, 100, 100 }); - winrt::com_ptr zone2 = MakeZone({ 0, 0, 100, 100 }); - winrt::com_ptr zone3 = MakeZone({ 0, 0, 100, 100 }); - m_set->AddZone(zone1); - m_set->AddZone(zone2); - m_set->AddZone(zone3); + TEST_METHOD (ZoneIndexFromWindowUnknown) + { + winrt::com_ptr zone = MakeZone({ 0, 0, 100, 100 }); + HWND window = Mocks::Window(); + HWND zoneWindow = Mocks::Window(); + zone->AddWindowToZone(window, zoneWindow, true); + m_set->AddZone(zone); - HWND window = Mocks::Window(); - m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 1); - Assert::IsFalse(zone1->ContainsWindow(window)); - Assert::IsTrue(zone2->ContainsWindow(window)); - Assert::IsFalse(zone3->ContainsWindow(window)); - } + const int expected = -1; + auto actual = m_set->GetZoneIndexFromWindow(Mocks::Window()); + Assert::AreEqual(expected, actual); + } - TEST_METHOD(MoveWindowIntoZoneByIndexWithNoZones) - { - HWND window = Mocks::Window(); - m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0); - } + TEST_METHOD (ZoneIndexFromWindowNull) + { + winrt::com_ptr zone = MakeZone({ 0, 0, 100, 100 }); + HWND window = Mocks::Window(); + HWND zoneWindow = Mocks::Window(); + zone->AddWindowToZone(window, zoneWindow, true); + m_set->AddZone(zone); - TEST_METHOD(MoveWindowIntoZoneByIndexWithInvalidIndex) - { - winrt::com_ptr zone1 = MakeZone({ 0, 0, 100, 100 }); - winrt::com_ptr zone2 = MakeZone({ 0, 0, 100, 100 }); - winrt::com_ptr zone3 = MakeZone({ 0, 0, 100, 100 }); - m_set->AddZone(zone1); - m_set->AddZone(zone2); - m_set->AddZone(zone3); + const int expected = -1; + auto actual = m_set->GetZoneIndexFromWindow(nullptr); + Assert::AreEqual(expected, actual); + } - HWND window = Mocks::Window(); - m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 100); - Assert::IsTrue(zone1->ContainsWindow(window)); - Assert::IsFalse(zone2->ContainsWindow(window)); - Assert::IsFalse(zone3->ContainsWindow(window)); - } + TEST_METHOD (MoveWindowIntoZoneByIndex) + { + winrt::com_ptr zone1 = MakeZone({ 0, 0, 100, 100 }); + winrt::com_ptr zone2 = MakeZone({ 0, 0, 100, 100 }); + winrt::com_ptr zone3 = MakeZone({ 0, 0, 100, 100 }); + m_set->AddZone(zone1); + m_set->AddZone(zone2); + m_set->AddZone(zone3); + + HWND window = Mocks::Window(); + m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 1); + Assert::IsFalse(zone1->ContainsWindow(window)); + Assert::IsTrue(zone2->ContainsWindow(window)); + Assert::IsFalse(zone3->ContainsWindow(window)); + } - TEST_METHOD(MoveWindowIntoZoneByIndexSeveralTimesSameWindow) - { - // Add a couple of zones. - winrt::com_ptr zone1 = MakeZone({ 0, 0, 100, 100 }); - winrt::com_ptr zone2 = MakeZone({ 1, 1, 101, 101 }); - winrt::com_ptr zone3 = MakeZone({ 2, 2, 102, 102 }); - m_set->AddZone(zone1); - m_set->AddZone(zone2); - m_set->AddZone(zone3); + TEST_METHOD (MoveWindowIntoZoneByIndexWithNoZones) + { + HWND window = Mocks::Window(); + m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0); + } - HWND window = Mocks::Window(); - m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0); - Assert::IsTrue(zone1->ContainsWindow(window)); - Assert::IsFalse(zone2->ContainsWindow(window)); - Assert::IsFalse(zone3->ContainsWindow(window)); - - m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 1); - Assert::IsFalse(zone1->ContainsWindow(window)); - Assert::IsTrue(zone2->ContainsWindow(window)); - Assert::IsFalse(zone3->ContainsWindow(window)); - - m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 2); - Assert::IsFalse(zone1->ContainsWindow(window)); - Assert::IsFalse(zone2->ContainsWindow(window)); - Assert::IsTrue(zone3->ContainsWindow(window)); - } + TEST_METHOD (MoveWindowIntoZoneByIndexWithInvalidIndex) + { + winrt::com_ptr zone1 = MakeZone({ 0, 0, 100, 100 }); + winrt::com_ptr zone2 = MakeZone({ 0, 0, 100, 100 }); + winrt::com_ptr zone3 = MakeZone({ 0, 0, 100, 100 }); + m_set->AddZone(zone1); + m_set->AddZone(zone2); + m_set->AddZone(zone3); + + HWND window = Mocks::Window(); + m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 100); + Assert::IsTrue(zone1->ContainsWindow(window)); + Assert::IsFalse(zone2->ContainsWindow(window)); + Assert::IsFalse(zone3->ContainsWindow(window)); + } - TEST_METHOD(MoveWindowIntoZoneByIndexSeveralTimesSameIndex) - { - // Add a couple of zones. - winrt::com_ptr zone1 = MakeZone({ 0, 0, 100, 100 }); - winrt::com_ptr zone2 = MakeZone({ 1, 1, 101, 101 }); - winrt::com_ptr zone3 = MakeZone({ 2, 2, 102, 102 }); - m_set->AddZone(zone1); - m_set->AddZone(zone2); - m_set->AddZone(zone3); + TEST_METHOD (MoveWindowIntoZoneByIndexSeveralTimesSameWindow) + { + // Add a couple of zones. + winrt::com_ptr zone1 = MakeZone({ 0, 0, 100, 100 }); + winrt::com_ptr zone2 = MakeZone({ 1, 1, 101, 101 }); + winrt::com_ptr zone3 = MakeZone({ 2, 2, 102, 102 }); + m_set->AddZone(zone1); + m_set->AddZone(zone2); + m_set->AddZone(zone3); + + HWND window = Mocks::Window(); + m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0); + Assert::IsTrue(zone1->ContainsWindow(window)); + Assert::IsFalse(zone2->ContainsWindow(window)); + Assert::IsFalse(zone3->ContainsWindow(window)); + + m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 1); + Assert::IsFalse(zone1->ContainsWindow(window)); + Assert::IsTrue(zone2->ContainsWindow(window)); + Assert::IsFalse(zone3->ContainsWindow(window)); + + m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 2); + Assert::IsFalse(zone1->ContainsWindow(window)); + Assert::IsFalse(zone2->ContainsWindow(window)); + Assert::IsTrue(zone3->ContainsWindow(window)); + } - HWND window = Mocks::Window(); - m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0); - m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0); - m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0); - Assert::IsTrue(zone1->ContainsWindow(window)); - Assert::IsFalse(zone2->ContainsWindow(window)); - Assert::IsFalse(zone3->ContainsWindow(window)); - } + TEST_METHOD (MoveWindowIntoZoneByIndexSeveralTimesSameIndex) + { + // Add a couple of zones. + winrt::com_ptr zone1 = MakeZone({ 0, 0, 100, 100 }); + winrt::com_ptr zone2 = MakeZone({ 1, 1, 101, 101 }); + winrt::com_ptr zone3 = MakeZone({ 2, 2, 102, 102 }); + m_set->AddZone(zone1); + m_set->AddZone(zone2); + m_set->AddZone(zone3); + + HWND window = Mocks::Window(); + m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0); + m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0); + m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0); + Assert::IsTrue(zone1->ContainsWindow(window)); + Assert::IsFalse(zone2->ContainsWindow(window)); + Assert::IsFalse(zone3->ContainsWindow(window)); + } - TEST_METHOD(MoveWindowIntoZoneByPointEmpty) - { - m_set->MoveWindowIntoZoneByPoint(Mocks::Window(), Mocks::Window(), POINT{ 0, 0 }); - } + TEST_METHOD (MoveWindowIntoZoneByPointEmpty) + { + m_set->MoveWindowIntoZoneByPoint(Mocks::Window(), Mocks::Window(), POINT{ 0, 0 }); + } - TEST_METHOD(MoveWindowIntoZoneByPointOuterPoint) - { - winrt::com_ptr zone1 = MakeZone({ 0, 0, 100, 100 }); - m_set->AddZone(zone1); + TEST_METHOD (MoveWindowIntoZoneByPointOuterPoint) + { + winrt::com_ptr zone1 = MakeZone({ 0, 0, 100, 100 }); + m_set->AddZone(zone1); - auto window = Mocks::Window(); - m_set->MoveWindowIntoZoneByPoint(window, Mocks::Window(), POINT{ 101, 101 }); + auto window = Mocks::Window(); + m_set->MoveWindowIntoZoneByPoint(window, Mocks::Window(), POINT{ 101, 101 }); - Assert::IsFalse(zone1->ContainsWindow(window)); - } + Assert::IsFalse(zone1->ContainsWindow(window)); + } - TEST_METHOD(MoveWindowIntoZoneByPointInnerPoint) - { - winrt::com_ptr zone1 = MakeZone({ 0, 0, 100, 100 }); - m_set->AddZone(zone1); + TEST_METHOD (MoveWindowIntoZoneByPointInnerPoint) + { + winrt::com_ptr zone1 = MakeZone({ 0, 0, 100, 100 }); + m_set->AddZone(zone1); - auto window = Mocks::Window(); - m_set->MoveWindowIntoZoneByPoint(window, Mocks::Window(), POINT{ 50, 50 }); + auto window = Mocks::Window(); + m_set->MoveWindowIntoZoneByPoint(window, Mocks::Window(), POINT{ 50, 50 }); - Assert::IsTrue(zone1->ContainsWindow(window)); - } + Assert::IsTrue(zone1->ContainsWindow(window)); + } - TEST_METHOD(MoveWindowIntoZoneByPointInnerPointOverlappingZones) - { - winrt::com_ptr zone1 = MakeZone({ 0, 0, 100, 100 }); - winrt::com_ptr zone2 = MakeZone({ 10, 10, 90, 90 }); - m_set->AddZone(zone1); - m_set->AddZone(zone2); + TEST_METHOD (MoveWindowIntoZoneByPointInnerPointOverlappingZones) + { + winrt::com_ptr zone1 = MakeZone({ 0, 0, 100, 100 }); + winrt::com_ptr zone2 = MakeZone({ 10, 10, 90, 90 }); + m_set->AddZone(zone1); + m_set->AddZone(zone2); - auto window = Mocks::Window(); - m_set->MoveWindowIntoZoneByPoint(window, Mocks::Window(), POINT{ 50, 50 }); + auto window = Mocks::Window(); + m_set->MoveWindowIntoZoneByPoint(window, Mocks::Window(), POINT{ 50, 50 }); - Assert::IsFalse(zone1->ContainsWindow(window)); - Assert::IsTrue(zone2->ContainsWindow(window)); - } + Assert::IsFalse(zone1->ContainsWindow(window)); + Assert::IsTrue(zone2->ContainsWindow(window)); + } - TEST_METHOD(MoveWindowIntoZoneByPointDropAddWindow) - { - const auto window = Mocks::Window(); - const auto zoneWindow = Mocks::Window(); + TEST_METHOD (MoveWindowIntoZoneByPointDropAddWindow) + { + const auto window = Mocks::Window(); + const auto zoneWindow = Mocks::Window(); - winrt::com_ptr zone1 = MakeZone({ 0, 0, 100, 100 }); - winrt::com_ptr zone2 = MakeZone({ 10, 10, 90, 90 }); + winrt::com_ptr zone1 = MakeZone({ 0, 0, 100, 100 }); + winrt::com_ptr zone2 = MakeZone({ 10, 10, 90, 90 }); - zone1->AddWindowToZone(window, zoneWindow, false); + zone1->AddWindowToZone(window, zoneWindow, false); - m_set->AddZone(zone1); - m_set->AddZone(zone2); + m_set->AddZone(zone1); + m_set->AddZone(zone2); - m_set->MoveWindowIntoZoneByPoint(window, Mocks::Window(), POINT{ 50, 50 }); + m_set->MoveWindowIntoZoneByPoint(window, Mocks::Window(), POINT{ 50, 50 }); - Assert::IsFalse(zone1->ContainsWindow(window)); - Assert::IsTrue(zone2->ContainsWindow(window)); - } + Assert::IsFalse(zone1->ContainsWindow(window)); + Assert::IsTrue(zone2->ContainsWindow(window)); + } - TEST_METHOD(MoveWindowIntoZoneByPointDropAddWindowToSameZone) - { - const auto window = Mocks::Window(); - const auto zoneWindow = Mocks::Window(); + TEST_METHOD (MoveWindowIntoZoneByPointDropAddWindowToSameZone) + { + const auto window = Mocks::Window(); + const auto zoneWindow = Mocks::Window(); - winrt::com_ptr zone1 = MakeZone({ 0, 0, 100, 100 }); - winrt::com_ptr zone2 = MakeZone({ 10, 10, 90, 90 }); + winrt::com_ptr zone1 = MakeZone({ 0, 0, 100, 100 }); + winrt::com_ptr zone2 = MakeZone({ 10, 10, 90, 90 }); - zone2->AddWindowToZone(window, zoneWindow, false); + zone2->AddWindowToZone(window, zoneWindow, false); - m_set->AddZone(zone1); - m_set->AddZone(zone2); + m_set->AddZone(zone1); + m_set->AddZone(zone2); - m_set->MoveWindowIntoZoneByPoint(window, Mocks::Window(), POINT{ 50, 50 }); + m_set->MoveWindowIntoZoneByPoint(window, Mocks::Window(), POINT{ 50, 50 }); - Assert::IsFalse(zone1->ContainsWindow(window)); - Assert::IsTrue(zone2->ContainsWindow(window)); - } + Assert::IsFalse(zone1->ContainsWindow(window)); + Assert::IsTrue(zone2->ContainsWindow(window)); + } - TEST_METHOD(MoveWindowIntoZoneByPointSeveralZonesWithSameWindow) - { - const auto window = Mocks::Window(); - const auto zoneWindow = Mocks::Window(); + TEST_METHOD (MoveWindowIntoZoneByPointSeveralZonesWithSameWindow) + { + const auto window = Mocks::Window(); + const auto zoneWindow = Mocks::Window(); - winrt::com_ptr zone1 = MakeZone({ 0, 0, 100, 100 }); - winrt::com_ptr zone2 = MakeZone({ 10, 10, 90, 90 }); - winrt::com_ptr zone3 = MakeZone({ 20, 20, 80, 80 }); + winrt::com_ptr zone1 = MakeZone({ 0, 0, 100, 100 }); + winrt::com_ptr zone2 = MakeZone({ 10, 10, 90, 90 }); + winrt::com_ptr zone3 = MakeZone({ 20, 20, 80, 80 }); - zone1->AddWindowToZone(window, zoneWindow, false); - zone2->AddWindowToZone(window, zoneWindow, false); - zone3->AddWindowToZone(window, zoneWindow, false); + zone1->AddWindowToZone(window, zoneWindow, false); + zone2->AddWindowToZone(window, zoneWindow, false); + zone3->AddWindowToZone(window, zoneWindow, false); - m_set->AddZone(zone1); - m_set->AddZone(zone2); - m_set->AddZone(zone3); + m_set->AddZone(zone1); + m_set->AddZone(zone2); + m_set->AddZone(zone3); - m_set->MoveWindowIntoZoneByPoint(window, Mocks::Window(), POINT{ 50, 50 }); + m_set->MoveWindowIntoZoneByPoint(window, Mocks::Window(), POINT{ 50, 50 }); - Assert::IsFalse(zone1->ContainsWindow(window)); - Assert::IsFalse(zone2->ContainsWindow(window)); - Assert::IsTrue(zone3->ContainsWindow(window)); - } + Assert::IsFalse(zone1->ContainsWindow(window)); + Assert::IsFalse(zone2->ContainsWindow(window)); + Assert::IsTrue(zone3->ContainsWindow(window)); + } }; // MoveWindowIntoZoneByDirection is complicated enough to warrant it's own test class - TEST_CLASS(ZoneSetsMoveWindowIntoZoneByDirectionUnitTests) + TEST_CLASS (ZoneSetsMoveWindowIntoZoneByDirectionUnitTests) { winrt::com_ptr m_set; winrt::com_ptr m_zone1; @@ -516,66 +516,66 @@ namespace FancyZonesUnitTests m_set->AddZone(m_zone3); } - TEST_METHOD(EmptyZonesLeft) + TEST_METHOD (EmptyZonesLeft) { ZoneSetConfig config({}, TZoneSetLayoutType::Custom, Mocks::Monitor(), L"WorkAreaIn"); auto set = MakeZoneSet(config); - set->MoveWindowIntoZoneByDirection(Mocks::Window(), Mocks::Window(), VK_LEFT); + set->MoveWindowIntoZoneByDirection(Mocks::Window(), Mocks::Window(), VK_LEFT, true); } - TEST_METHOD(EmptyZonesRight) + TEST_METHOD (EmptyZonesRight) { ZoneSetConfig config({}, TZoneSetLayoutType::Custom, Mocks::Monitor(), L"WorkAreaIn"); auto set = MakeZoneSet(config); - set->MoveWindowIntoZoneByDirection(Mocks::Window(), Mocks::Window(), VK_RIGHT); + set->MoveWindowIntoZoneByDirection(Mocks::Window(), Mocks::Window(), VK_RIGHT, true); } - TEST_METHOD(MoveRightNoZones) + TEST_METHOD (MoveRightNoZones) { HWND window = Mocks::Window(); - m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_RIGHT); + m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_RIGHT, true); Assert::IsTrue(m_zone1->ContainsWindow(window)); Assert::IsFalse(m_zone2->ContainsWindow(window)); Assert::IsFalse(m_zone3->ContainsWindow(window)); } - TEST_METHOD(MoveLeftNoZones) + TEST_METHOD (MoveLeftNoZones) { HWND window = Mocks::Window(); - m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_LEFT); + m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_LEFT, true); Assert::IsFalse(m_zone1->ContainsWindow(window)); Assert::IsFalse(m_zone2->ContainsWindow(window)); Assert::IsTrue(m_zone3->ContainsWindow(window)); } - TEST_METHOD(MoveRightTwice) + TEST_METHOD (MoveRightTwice) { HWND window = Mocks::Window(); - m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_RIGHT); - m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_RIGHT); + m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_RIGHT, true); + m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_RIGHT, true); Assert::IsFalse(m_zone1->ContainsWindow(window)); Assert::IsTrue(m_zone2->ContainsWindow(window)); Assert::IsFalse(m_zone3->ContainsWindow(window)); } - TEST_METHOD(MoveLeftTwice) + TEST_METHOD (MoveLeftTwice) { HWND window = Mocks::Window(); - m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_LEFT); - m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_LEFT); + m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_LEFT, true); + m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_LEFT, true); Assert::IsFalse(m_zone1->ContainsWindow(window)); Assert::IsTrue(m_zone2->ContainsWindow(window)); Assert::IsFalse(m_zone3->ContainsWindow(window)); } - TEST_METHOD(MoveRightMoreThanZonesCount) + TEST_METHOD (MoveRightMoreThanZonesCount) { HWND window = Mocks::Window(); for (int i = 0; i <= m_set->GetZones().size(); i++) { - m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_RIGHT); + m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_RIGHT, true); } Assert::IsTrue(m_zone1->ContainsWindow(window)); @@ -583,12 +583,12 @@ namespace FancyZonesUnitTests Assert::IsFalse(m_zone3->ContainsWindow(window)); } - TEST_METHOD(MoveLeftMoreThanZonesCount) + TEST_METHOD (MoveLeftMoreThanZonesCount) { HWND window = Mocks::Window(); for (int i = 0; i <= m_set->GetZones().size(); i++) { - m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_LEFT); + m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_LEFT, true); } Assert::IsFalse(m_zone1->ContainsWindow(window)); @@ -596,22 +596,22 @@ namespace FancyZonesUnitTests Assert::IsTrue(m_zone3->ContainsWindow(window)); } - TEST_METHOD(MoveWindowIntoZoneByDirectionRight) + TEST_METHOD (MoveWindowIntoZoneByDirectionRight) { HWND window = Mocks::Window(); m_zone1->AddWindowToZone(window, Mocks::Window(), false /*stampZone*/); - m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_RIGHT); + m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_RIGHT, true); Assert::IsFalse(m_zone1->ContainsWindow(window)); Assert::IsTrue(m_zone2->ContainsWindow(window)); Assert::IsFalse(m_zone3->ContainsWindow(window)); - m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_RIGHT); + m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_RIGHT, true); Assert::IsFalse(m_zone1->ContainsWindow(window)); Assert::IsFalse(m_zone2->ContainsWindow(window)); Assert::IsTrue(m_zone3->ContainsWindow(window)); } - TEST_METHOD(MoveRightWithSameWindowAdded) + TEST_METHOD (MoveRightWithSameWindowAdded) { HWND window = Mocks::Window(); m_zone1->AddWindowToZone(window, Mocks::Window(), false /*stampZone*/); @@ -621,18 +621,18 @@ namespace FancyZonesUnitTests Assert::IsTrue(m_zone2->ContainsWindow(window)); Assert::IsFalse(m_zone3->ContainsWindow(window)); - m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_RIGHT); + m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_RIGHT, true); Assert::IsFalse(m_zone1->ContainsWindow(window)); Assert::IsTrue(m_zone2->ContainsWindow(window)); Assert::IsFalse(m_zone3->ContainsWindow(window)); - m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_RIGHT); + m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_RIGHT, true); Assert::IsFalse(m_zone1->ContainsWindow(window)); Assert::IsFalse(m_zone2->ContainsWindow(window)); Assert::IsTrue(m_zone3->ContainsWindow(window)); } - TEST_METHOD(MoveRightWithDifferentWindowsAdded) + TEST_METHOD (MoveRightWithDifferentWindowsAdded) { HWND window1 = Mocks::Window(); HWND window2 = Mocks::Window(); @@ -646,7 +646,7 @@ namespace FancyZonesUnitTests Assert::IsTrue(m_zone2->ContainsWindow(window2)); Assert::IsFalse(m_zone3->ContainsWindow(window2)); - m_set->MoveWindowIntoZoneByDirection(window1, Mocks::Window(), VK_RIGHT); + m_set->MoveWindowIntoZoneByDirection(window1, Mocks::Window(), VK_RIGHT, true); Assert::IsFalse(m_zone1->ContainsWindow(window1)); Assert::IsTrue(m_zone2->ContainsWindow(window1)); Assert::IsFalse(m_zone3->ContainsWindow(window1)); @@ -654,7 +654,7 @@ namespace FancyZonesUnitTests Assert::IsTrue(m_zone2->ContainsWindow(window2)); Assert::IsFalse(m_zone3->ContainsWindow(window2)); - m_set->MoveWindowIntoZoneByDirection(window1, Mocks::Window(), VK_RIGHT); + m_set->MoveWindowIntoZoneByDirection(window1, Mocks::Window(), VK_RIGHT, true); Assert::IsFalse(m_zone1->ContainsWindow(window1)); Assert::IsFalse(m_zone2->ContainsWindow(window1)); Assert::IsTrue(m_zone3->ContainsWindow(window1)); @@ -663,22 +663,22 @@ namespace FancyZonesUnitTests Assert::IsFalse(m_zone3->ContainsWindow(window2)); } - TEST_METHOD(MoveWindowIntoZoneByDirectionLeft) + TEST_METHOD (MoveWindowIntoZoneByDirectionLeft) { HWND window = Mocks::Window(); m_zone3->AddWindowToZone(window, Mocks::Window(), false /*stampZone*/); - m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_LEFT); + m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_LEFT, true); Assert::IsFalse(m_zone1->ContainsWindow(window)); Assert::IsTrue(m_zone2->ContainsWindow(window)); Assert::IsFalse(m_zone3->ContainsWindow(window)); - m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_LEFT); + m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_LEFT, true); Assert::IsTrue(m_zone1->ContainsWindow(window)); Assert::IsFalse(m_zone2->ContainsWindow(window)); Assert::IsFalse(m_zone3->ContainsWindow(window)); } - TEST_METHOD(MoveLeftWithSameWindowAdded) + TEST_METHOD (MoveLeftWithSameWindowAdded) { HWND window = Mocks::Window(); m_zone2->AddWindowToZone(window, Mocks::Window(), false /*stampZone*/); @@ -688,18 +688,18 @@ namespace FancyZonesUnitTests Assert::IsTrue(m_zone2->ContainsWindow(window)); Assert::IsTrue(m_zone3->ContainsWindow(window)); - m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_LEFT); + m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_LEFT, true); Assert::IsTrue(m_zone1->ContainsWindow(window)); Assert::IsFalse(m_zone2->ContainsWindow(window)); Assert::IsTrue(m_zone3->ContainsWindow(window)); - m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_LEFT); + m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_LEFT, true); Assert::IsFalse(m_zone1->ContainsWindow(window)); Assert::IsFalse(m_zone2->ContainsWindow(window)); Assert::IsTrue(m_zone3->ContainsWindow(window)); } - TEST_METHOD(MoveLeftWithDifferentWindowsAdded) + TEST_METHOD (MoveLeftWithDifferentWindowsAdded) { HWND window1 = Mocks::Window(); HWND window2 = Mocks::Window(); @@ -713,7 +713,7 @@ namespace FancyZonesUnitTests Assert::IsFalse(m_zone2->ContainsWindow(window2)); Assert::IsTrue(m_zone3->ContainsWindow(window2)); - m_set->MoveWindowIntoZoneByDirection(window2, Mocks::Window(), VK_LEFT); + m_set->MoveWindowIntoZoneByDirection(window2, Mocks::Window(), VK_LEFT, true); Assert::IsFalse(m_zone1->ContainsWindow(window1)); Assert::IsTrue(m_zone2->ContainsWindow(window1)); Assert::IsFalse(m_zone3->ContainsWindow(window1)); @@ -721,7 +721,7 @@ namespace FancyZonesUnitTests Assert::IsTrue(m_zone2->ContainsWindow(window2)); Assert::IsFalse(m_zone3->ContainsWindow(window2)); - m_set->MoveWindowIntoZoneByDirection(window2, Mocks::Window(), VK_LEFT); + m_set->MoveWindowIntoZoneByDirection(window2, Mocks::Window(), VK_LEFT, true); Assert::IsFalse(m_zone1->ContainsWindow(window1)); Assert::IsTrue(m_zone2->ContainsWindow(window1)); Assert::IsFalse(m_zone3->ContainsWindow(window1)); @@ -730,33 +730,33 @@ namespace FancyZonesUnitTests Assert::IsFalse(m_zone3->ContainsWindow(window2)); } - TEST_METHOD(MoveWindowIntoZoneByDirectionWrapAroundRight) + TEST_METHOD (MoveWindowIntoZoneByDirectionWrapAroundRight) { HWND window = Mocks::Window(); m_zone3->AddWindowToZone(window, Mocks::Window(), false /*stampZone*/); - m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_RIGHT); + m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_RIGHT, true); Assert::IsTrue(m_zone1->ContainsWindow(window)); Assert::IsFalse(m_zone2->ContainsWindow(window)); Assert::IsFalse(m_zone3->ContainsWindow(window)); } - TEST_METHOD(MoveWindowIntoZoneByDirectionWrapAroundLeft) + TEST_METHOD (MoveWindowIntoZoneByDirectionWrapAroundLeft) { HWND window = Mocks::Window(); m_zone1->AddWindowToZone(window, Mocks::Window(), false /*stampZone*/); - m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_LEFT); + m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_LEFT, true); Assert::IsFalse(m_zone1->ContainsWindow(window)); Assert::IsFalse(m_zone2->ContainsWindow(window)); Assert::IsTrue(m_zone3->ContainsWindow(window)); } - TEST_METHOD(MoveSecondWindowIntoSameZone) + TEST_METHOD (MoveSecondWindowIntoSameZone) { HWND window1 = Mocks::Window(); m_zone1->AddWindowToZone(window1, Mocks::Window(), false /*stampZone*/); HWND window2 = Mocks::Window(); - m_set->MoveWindowIntoZoneByDirection(window2, Mocks::Window(), VK_RIGHT); + m_set->MoveWindowIntoZoneByDirection(window2, Mocks::Window(), VK_RIGHT, true); Assert::IsTrue(m_zone1->ContainsWindow(window1)); Assert::IsFalse(m_zone2->ContainsWindow(window1)); @@ -766,9 +766,33 @@ namespace FancyZonesUnitTests Assert::IsFalse(m_zone2->ContainsWindow(window2)); Assert::IsFalse(m_zone3->ContainsWindow(window2)); } + + TEST_METHOD (MoveRightMoreThanZoneCountReturnsFalse) + { + HWND window = Mocks::Window(); + m_zone1->AddWindowToZone(window, Mocks::Window(), false /*stampZone*/); + for (size_t i = 0; i < m_set->GetZones().size() - 1; ++i) + { + m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_RIGHT, false); + } + bool moreZonesInLayout = m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_RIGHT, false); + Assert::IsFalse(moreZonesInLayout); + } + + TEST_METHOD (MoveLeftMoreThanZoneCountReturnsFalse) + { + HWND window = Mocks::Window(); + m_zone3->AddWindowToZone(window, Mocks::Window(), false /*stampZone*/); + for (size_t i = 0; i < m_set->GetZones().size() - 1; ++i) + { + m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_LEFT, false); + } + bool moreZonesInLayout = m_set->MoveWindowIntoZoneByDirection(window, Mocks::Window(), VK_LEFT, false); + Assert::IsFalse(moreZonesInLayout); + } }; - TEST_CLASS(ZoneSetCalculateZonesUnitTests) + TEST_CLASS (ZoneSetCalculateZonesUnitTests) { GUID m_id; const TZoneSetLayoutType m_layoutType = TZoneSetLayoutType::Custom; @@ -776,7 +800,7 @@ namespace FancyZonesUnitTests winrt::com_ptr m_set; HMONITOR m_monitor; - const std::array m_popularMonitors { + const std::array m_popularMonitors{ MONITORINFO{ .cbSize = sizeof(MONITORINFO), .rcWork{ .left = 0, .top = 0, .right = 1024, .bottom = 768 } }, MONITORINFO{ .cbSize = sizeof(MONITORINFO), .rcWork{ .left = 0, .top = 0, .right = 1280, .bottom = 720 } }, MONITORINFO{ .cbSize = sizeof(MONITORINFO), .rcWork{ .left = 0, .top = 0, .right = 1280, .bottom = 800 } }, @@ -793,406 +817,406 @@ namespace FancyZonesUnitTests const std::wstring m_path = PTSettingsHelper::get_module_save_folder_location(L"FancyZones") + L"\\" + std::wstring(L"testzones.json"); TEST_METHOD_INITIALIZE(Init) - { - auto hres = CoCreateGuid(&m_id); - Assert::AreEqual(S_OK, hres); - - m_monitor = MonitorFromPoint(POINT{ 0, 0 }, MONITOR_DEFAULTTOPRIMARY); - - ZoneSetConfig m_config = ZoneSetConfig(m_id, m_layoutType, m_monitor, m_resolutionKey); - m_set = MakeZoneSet(m_config); - } - - TEST_METHOD_CLEANUP(Cleanup) - { - std::filesystem::remove(m_path); - } - - void checkZones(const winrt::com_ptr& set, size_t expectedCount, MONITORINFO monitorInfo) - { - auto zones = set->GetZones(); - Assert::AreEqual(expectedCount, zones.size()); - - for (const auto& zone : zones) { - Assert::IsTrue(zone->IsEmpty()); + auto hres = CoCreateGuid(&m_id); + Assert::AreEqual(S_OK, hres); - const auto& zoneRect = zone->GetZoneRect(); - Assert::IsTrue(zoneRect.left >= 0, L"left border is less than zero"); - Assert::IsTrue(zoneRect.top >= 0, L"top border is less than zero"); + m_monitor = MonitorFromPoint(POINT{ 0, 0 }, MONITOR_DEFAULTTOPRIMARY); - Assert::IsTrue(zoneRect.left < zoneRect.right, L"rect.left >= rect.right"); - Assert::IsTrue(zoneRect.top < zoneRect.bottom, L"rect.top >= rect.bottom"); - - Assert::IsTrue(zoneRect.right <= monitorInfo.rcWork.right, L"right border is bigger than monitor work space"); - Assert::IsTrue(zoneRect.bottom <= monitorInfo.rcWork.bottom, L"bottom border is bigger than monitor work space"); + ZoneSetConfig m_config = ZoneSetConfig(m_id, m_layoutType, m_monitor, m_resolutionKey); + m_set = MakeZoneSet(m_config); } - } - - public: - TEST_METHOD(ValidValues) - { - const int spacing = 10; - const int zoneCount = 10; - - for (int type = static_cast(JSONHelpers::ZoneSetLayoutType::Focus); type < static_cast(JSONHelpers::ZoneSetLayoutType::Custom); type++) - { - ZoneSetConfig m_config = ZoneSetConfig(m_id, static_cast(type), m_monitor, m_resolutionKey); - for (const auto& monitorInfo : m_popularMonitors) + TEST_METHOD_CLEANUP(Cleanup) { - auto set = MakeZoneSet(m_config); - auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); - Assert::IsTrue(result); - checkZones(set, zoneCount, monitorInfo); + std::filesystem::remove(m_path); } - } - } - TEST_METHOD(InvalidMonitorInfo) - { - const int spacing = 10; - const int zoneCount = 10; - for (int type = static_cast(JSONHelpers::ZoneSetLayoutType::Focus); type < static_cast(JSONHelpers::ZoneSetLayoutType::Custom); type++) - { - ZoneSetConfig m_config = ZoneSetConfig(m_id, static_cast(type), m_monitor, m_resolutionKey); - auto set = MakeZoneSet(m_config); + void checkZones(const winrt::com_ptr& set, size_t expectedCount, MONITORINFO monitorInfo) + { + auto zones = set->GetZones(); + Assert::AreEqual(expectedCount, zones.size()); - MONITORINFO info{}; - auto result = set->CalculateZones(info, zoneCount, spacing); - Assert::IsFalse(result); - } - } + for (const auto& zone : zones) + { + Assert::IsTrue(zone->IsEmpty()); - TEST_METHOD(ZeroSpacing) - { - const int spacing = 0; - const int zoneCount = 10; + const auto& zoneRect = zone->GetZoneRect(); + Assert::IsTrue(zoneRect.left >= 0, L"left border is less than zero"); + Assert::IsTrue(zoneRect.top >= 0, L"top border is less than zero"); - for (int type = static_cast(JSONHelpers::ZoneSetLayoutType::Focus); type < static_cast(JSONHelpers::ZoneSetLayoutType::Custom); type++) - { - ZoneSetConfig m_config = ZoneSetConfig(m_id, static_cast(type), m_monitor, m_resolutionKey); + Assert::IsTrue(zoneRect.left < zoneRect.right, L"rect.left >= rect.right"); + Assert::IsTrue(zoneRect.top < zoneRect.bottom, L"rect.top >= rect.bottom"); - for (const auto& monitorInfo : m_popularMonitors) - { - auto set = MakeZoneSet(m_config); - auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); - Assert::IsTrue(result); - checkZones(set, zoneCount, monitorInfo); + Assert::IsTrue(zoneRect.right <= monitorInfo.rcWork.right, L"right border is bigger than monitor work space"); + Assert::IsTrue(zoneRect.bottom <= monitorInfo.rcWork.bottom, L"bottom border is bigger than monitor work space"); + } } - } - } - TEST_METHOD(NegativeSpacing) - { - const int spacing = -1; - const int zoneCount = 10; - - for (int type = static_cast(JSONHelpers::ZoneSetLayoutType::Focus); type < static_cast(JSONHelpers::ZoneSetLayoutType::Custom); type++) - { - ZoneSetConfig m_config = ZoneSetConfig(m_id, static_cast(type), m_monitor, m_resolutionKey); - auto set = MakeZoneSet(m_config); - - for (const auto& monitorInfo : m_popularMonitors) + public: + TEST_METHOD (ValidValues) { - auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); - if (type == static_cast(JSONHelpers::ZoneSetLayoutType::Focus)) + const int spacing = 10; + const int zoneCount = 10; + + for (int type = static_cast(JSONHelpers::ZoneSetLayoutType::Focus); type < static_cast(JSONHelpers::ZoneSetLayoutType::Custom); type++) { - //Focus doesn't depends on spacing - Assert::IsTrue(result); + ZoneSetConfig m_config = ZoneSetConfig(m_id, static_cast(type), m_monitor, m_resolutionKey); + + for (const auto& monitorInfo : m_popularMonitors) + { + auto set = MakeZoneSet(m_config); + auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); + Assert::IsTrue(result); + checkZones(set, zoneCount, monitorInfo); + } } - else + } + TEST_METHOD (InvalidMonitorInfo) + { + const int spacing = 10; + const int zoneCount = 10; + + for (int type = static_cast(JSONHelpers::ZoneSetLayoutType::Focus); type < static_cast(JSONHelpers::ZoneSetLayoutType::Custom); type++) { + ZoneSetConfig m_config = ZoneSetConfig(m_id, static_cast(type), m_monitor, m_resolutionKey); + auto set = MakeZoneSet(m_config); + + MONITORINFO info{}; + auto result = set->CalculateZones(info, zoneCount, spacing); Assert::IsFalse(result); } } - } - } - TEST_METHOD(HorizontallyBigSpacing) - { - const int zoneCount = 10; - - for (int type = static_cast(JSONHelpers::ZoneSetLayoutType::Focus); type < static_cast(JSONHelpers::ZoneSetLayoutType::Custom); type++) - { - ZoneSetConfig m_config = ZoneSetConfig(m_id, static_cast(type), m_monitor, m_resolutionKey); - auto set = MakeZoneSet(m_config); - - for (const auto& monitorInfo : m_popularMonitors) + TEST_METHOD (ZeroSpacing) { - const int spacing = monitorInfo.rcWork.right; - auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); - if (type == static_cast(JSONHelpers::ZoneSetLayoutType::Focus)) - { - //Focus doesn't depends on spacing - Assert::IsTrue(result); - } - else + const int spacing = 0; + const int zoneCount = 10; + + for (int type = static_cast(JSONHelpers::ZoneSetLayoutType::Focus); type < static_cast(JSONHelpers::ZoneSetLayoutType::Custom); type++) { - Assert::IsFalse(result); + ZoneSetConfig m_config = ZoneSetConfig(m_id, static_cast(type), m_monitor, m_resolutionKey); + + for (const auto& monitorInfo : m_popularMonitors) + { + auto set = MakeZoneSet(m_config); + auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); + Assert::IsTrue(result); + checkZones(set, zoneCount, monitorInfo); + } } } - } - } - TEST_METHOD(VerticallyBigSpacing) - { - const int zoneCount = 10; - - for (int type = static_cast(JSONHelpers::ZoneSetLayoutType::Focus); type < static_cast(JSONHelpers::ZoneSetLayoutType::Custom); type++) - { - ZoneSetConfig m_config = ZoneSetConfig(m_id, static_cast(type), m_monitor, m_resolutionKey); - auto set = MakeZoneSet(m_config); - - for (const auto& monitorInfo : m_popularMonitors) + TEST_METHOD (NegativeSpacing) { - const int spacing = monitorInfo.rcWork.bottom; - auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); - if (type == static_cast(JSONHelpers::ZoneSetLayoutType::Focus)) + const int spacing = -1; + const int zoneCount = 10; + + for (int type = static_cast(JSONHelpers::ZoneSetLayoutType::Focus); type < static_cast(JSONHelpers::ZoneSetLayoutType::Custom); type++) { - //Focus doesn't depends on spacing - Assert::IsTrue(result); + ZoneSetConfig m_config = ZoneSetConfig(m_id, static_cast(type), m_monitor, m_resolutionKey); + auto set = MakeZoneSet(m_config); + + for (const auto& monitorInfo : m_popularMonitors) + { + auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); + if (type == static_cast(JSONHelpers::ZoneSetLayoutType::Focus)) + { + //Focus doesn't depends on spacing + Assert::IsTrue(result); + } + else + { + Assert::IsFalse(result); + } + } } - else + } + + TEST_METHOD (HorizontallyBigSpacing) + { + const int zoneCount = 10; + + for (int type = static_cast(JSONHelpers::ZoneSetLayoutType::Focus); type < static_cast(JSONHelpers::ZoneSetLayoutType::Custom); type++) { - Assert::IsFalse(result); + ZoneSetConfig m_config = ZoneSetConfig(m_id, static_cast(type), m_monitor, m_resolutionKey); + auto set = MakeZoneSet(m_config); + + for (const auto& monitorInfo : m_popularMonitors) + { + const int spacing = monitorInfo.rcWork.right; + auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); + if (type == static_cast(JSONHelpers::ZoneSetLayoutType::Focus)) + { + //Focus doesn't depends on spacing + Assert::IsTrue(result); + } + else + { + Assert::IsFalse(result); + } + } } } - } - } - TEST_METHOD(ZeroZoneCount) - { - const int spacing = 10; - const int zoneCount = 0; + TEST_METHOD (VerticallyBigSpacing) + { + const int zoneCount = 10; - for (int type = static_cast(JSONHelpers::ZoneSetLayoutType::Focus); type < static_cast(JSONHelpers::ZoneSetLayoutType::Custom); type++) - { - ZoneSetConfig m_config = ZoneSetConfig(m_id, static_cast(type), m_monitor, m_resolutionKey); - auto set = MakeZoneSet(m_config); + for (int type = static_cast(JSONHelpers::ZoneSetLayoutType::Focus); type < static_cast(JSONHelpers::ZoneSetLayoutType::Custom); type++) + { + ZoneSetConfig m_config = ZoneSetConfig(m_id, static_cast(type), m_monitor, m_resolutionKey); + auto set = MakeZoneSet(m_config); + + for (const auto& monitorInfo : m_popularMonitors) + { + const int spacing = monitorInfo.rcWork.bottom; + auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); + if (type == static_cast(JSONHelpers::ZoneSetLayoutType::Focus)) + { + //Focus doesn't depends on spacing + Assert::IsTrue(result); + } + else + { + Assert::IsFalse(result); + } + } + } + } - for (const auto& monitorInfo : m_popularMonitors) + TEST_METHOD (ZeroZoneCount) { - auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); - Assert::IsFalse(result); + const int spacing = 10; + const int zoneCount = 0; + + for (int type = static_cast(JSONHelpers::ZoneSetLayoutType::Focus); type < static_cast(JSONHelpers::ZoneSetLayoutType::Custom); type++) + { + ZoneSetConfig m_config = ZoneSetConfig(m_id, static_cast(type), m_monitor, m_resolutionKey); + auto set = MakeZoneSet(m_config); + + for (const auto& monitorInfo : m_popularMonitors) + { + auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); + Assert::IsFalse(result); + } + } } - } - } - TEST_METHOD(BigZoneCount) - { - const int spacing = 1; + TEST_METHOD (BigZoneCount) + { + const int spacing = 1; - for (int type = static_cast(JSONHelpers::ZoneSetLayoutType::Focus); type < static_cast(JSONHelpers::ZoneSetLayoutType::Custom); type++) - { - const int spacing = 10; - const int zoneCount = 40; //editor limit + for (int type = static_cast(JSONHelpers::ZoneSetLayoutType::Focus); type < static_cast(JSONHelpers::ZoneSetLayoutType::Custom); type++) + { + const int spacing = 10; + const int zoneCount = 40; //editor limit + + ZoneSetConfig m_config = ZoneSetConfig(m_id, static_cast(type), m_monitor, m_resolutionKey); + + for (const auto& monitorInfo : m_popularMonitors) + { + auto set = MakeZoneSet(m_config); + auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); + Assert::IsTrue(result); + checkZones(set, zoneCount, monitorInfo); + } + } + } - ZoneSetConfig m_config = ZoneSetConfig(m_id, static_cast(type), m_monitor, m_resolutionKey); - - for (const auto& monitorInfo : m_popularMonitors) + TEST_METHOD (CustomZonesFromUnexistedFile) { - auto set = MakeZoneSet(m_config); - auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); - Assert::IsTrue(result); - checkZones(set, zoneCount, monitorInfo); - } - } - } + const int spacing = 10; + const int zoneCount = 0; - TEST_METHOD(CustomZonesFromUnexistedFile) - { - const int spacing = 10; - const int zoneCount = 0; + //be sure that file does not exist + if (std::filesystem::exists(m_path)) + { + std::filesystem::remove(m_path); + } - //be sure that file does not exist - if (std::filesystem::exists(m_path)) - { - std::filesystem::remove(m_path); - } + ZoneSetConfig m_config = ZoneSetConfig(m_id, TZoneSetLayoutType::Custom, m_monitor, m_resolutionKey); + auto set = MakeZoneSet(m_config); - ZoneSetConfig m_config = ZoneSetConfig(m_id, TZoneSetLayoutType::Custom, m_monitor, m_resolutionKey); - auto set = MakeZoneSet(m_config); + for (const auto& monitorInfo : m_popularMonitors) + { + auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); + Assert::IsFalse(result); + } + } - for (const auto& monitorInfo : m_popularMonitors) - { - auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); - Assert::IsFalse(result); - } - } + TEST_METHOD (CustomZoneFromEmptyFile) + { + const int spacing = 10; + const int zoneCount = 0; - TEST_METHOD(CustomZoneFromEmptyFile) - { - const int spacing = 10; - const int zoneCount = 0; + Assert::IsTrue(std::filesystem::create_directories(m_path)); + Assert::IsTrue(std::filesystem::exists(m_path)); - Assert::IsTrue(std::filesystem::create_directories(m_path)); - Assert::IsTrue(std::filesystem::exists(m_path)); + ZoneSetConfig m_config = ZoneSetConfig(m_id, TZoneSetLayoutType::Custom, m_monitor, m_resolutionKey); + auto set = MakeZoneSet(m_config); - ZoneSetConfig m_config = ZoneSetConfig(m_id, TZoneSetLayoutType::Custom, m_monitor, m_resolutionKey); - auto set = MakeZoneSet(m_config); + for (const auto& monitorInfo : m_popularMonitors) + { + auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); + Assert::IsFalse(result); + } + } - for (const auto& monitorInfo : m_popularMonitors) - { - auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); - Assert::IsFalse(result); - } - } + TEST_METHOD (CustomZoneFromInvalidCanvasLayoutInfo) + { + using namespace JSONHelpers; - TEST_METHOD(CustomZoneFromInvalidCanvasLayoutInfo) - { - using namespace JSONHelpers; + const std::wstring uuid = L"uuid"; + const CanvasLayoutInfo info{ -1, 100, { CanvasLayoutInfo::Rect{ -10, -10, 100, 100 }, CanvasLayoutInfo::Rect{ 50, 50, 150, 150 } } }; + CustomZoneSetJSON expected{ uuid, CustomZoneSetData{ L"name", CustomLayoutType::Canvas, info } }; + json::to_file(m_path, CustomZoneSetJSON::ToJson(expected)); + Assert::IsTrue(std::filesystem::exists(m_path)); - const std::wstring uuid = L"uuid"; - const CanvasLayoutInfo info{ -1, 100, { CanvasLayoutInfo::Rect{ -10, -10, 100, 100 }, CanvasLayoutInfo::Rect{ 50, 50, 150, 150 } } }; - CustomZoneSetJSON expected{ uuid, CustomZoneSetData{ L"name", CustomLayoutType::Canvas, info } }; - json::to_file(m_path, CustomZoneSetJSON::ToJson(expected)); - Assert::IsTrue(std::filesystem::exists(m_path)); + const int spacing = 10; + const int zoneCount = static_cast(info.zones.size()); - const int spacing = 10; - const int zoneCount = static_cast(info.zones.size()); + ZoneSetConfig m_config = ZoneSetConfig(m_id, TZoneSetLayoutType::Custom, m_monitor, m_resolutionKey); + auto set = MakeZoneSet(m_config); - ZoneSetConfig m_config = ZoneSetConfig(m_id, TZoneSetLayoutType::Custom, m_monitor, m_resolutionKey); - auto set = MakeZoneSet(m_config); + for (const auto& monitorInfo : m_popularMonitors) + { + auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); + Assert::IsFalse(result); + } + } - for (const auto& monitorInfo : m_popularMonitors) - { - auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); - Assert::IsFalse(result); - } - } + TEST_METHOD (CustomZoneFromInvalidGridLayoutInfo) + { + using namespace JSONHelpers; + + const std::wstring uuid = L"uuid"; + const GridLayoutInfo grid(GridLayoutInfo(JSONHelpers::GridLayoutInfo::Full{ + .rows = 1, + .columns = 3, + .rowsPercents = { -100 }, //rows percents are negative + .columnsPercents = { 2500, 2500 }, //column percents count is invalid + .cellChildMap = { { 0, 1, 2 } } })); + CustomZoneSetJSON expected{ uuid, CustomZoneSetData{ L"name", CustomLayoutType::Grid, grid } }; + json::to_file(m_path, CustomZoneSetJSON::ToJson(expected)); + Assert::IsTrue(std::filesystem::exists(m_path)); + + const int spacing = 0; + const int zoneCount = grid.rows() * grid.columns(); + + ZoneSetConfig m_config = ZoneSetConfig(m_id, TZoneSetLayoutType::Custom, m_monitor, m_resolutionKey); + auto set = MakeZoneSet(m_config); - TEST_METHOD(CustomZoneFromInvalidGridLayoutInfo) - { - using namespace JSONHelpers; - - const std::wstring uuid = L"uuid"; - const GridLayoutInfo grid(GridLayoutInfo(JSONHelpers::GridLayoutInfo::Full{ - .rows = 1, - .columns = 3, - .rowsPercents = { -100 }, //rows percents are negative - .columnsPercents = { 2500, 2500 }, //column percents count is invalid - .cellChildMap = { { 0, 1, 2 } } })); - CustomZoneSetJSON expected{ uuid, CustomZoneSetData{ L"name", CustomLayoutType::Grid, grid } }; - json::to_file(m_path, CustomZoneSetJSON::ToJson(expected)); - Assert::IsTrue(std::filesystem::exists(m_path)); - - const int spacing = 0; - const int zoneCount = grid.rows() * grid.columns(); - - ZoneSetConfig m_config = ZoneSetConfig(m_id, TZoneSetLayoutType::Custom, m_monitor, m_resolutionKey); - auto set = MakeZoneSet(m_config); - - for (const auto& monitorInfo : m_popularMonitors) - { - auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); - Assert::IsFalse(result); - } - } + for (const auto& monitorInfo : m_popularMonitors) + { + auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); + Assert::IsFalse(result); + } + } - TEST_METHOD(CustomZoneFromValidCanvasLayoutInfo) - { - using namespace JSONHelpers; + TEST_METHOD (CustomZoneFromValidCanvasLayoutInfo) + { + using namespace JSONHelpers; - //prepare device data - { - const std::wstring zoneUuid = L"default_device_id"; - DeviceInfoJSON deviceInfo{ zoneUuid, DeviceInfoData{ ZoneSetData{ L"uuid", ZoneSetLayoutType::Custom }, true, 16, 3 } }; - const std::wstring deviceInfoPath = FancyZonesDataInstance().GetPersistFancyZonesJSONPath() + L".device_info_tmp"; - FancyZonesDataInstance().SerializeDeviceInfoToTmpFile(deviceInfo, deviceInfoPath); + //prepare device data + { + const std::wstring zoneUuid = L"default_device_id"; + DeviceInfoJSON deviceInfo{ zoneUuid, DeviceInfoData{ ZoneSetData{ L"uuid", ZoneSetLayoutType::Custom }, true, 16, 3 } }; + const std::wstring deviceInfoPath = FancyZonesDataInstance().GetPersistFancyZonesJSONPath() + L".device_info_tmp"; + FancyZonesDataInstance().SerializeDeviceInfoToTmpFile(deviceInfo, deviceInfoPath); - FancyZonesDataInstance().ParseDeviceInfoFromTmpFile(deviceInfoPath); - std::filesystem::remove(deviceInfoPath); - } + FancyZonesDataInstance().ParseDeviceInfoFromTmpFile(deviceInfoPath); + std::filesystem::remove(deviceInfoPath); + } - //prepare expected data - wil::unique_cotaskmem_string uuid; - Assert::AreEqual(S_OK, StringFromCLSID(m_id, &uuid)); - const CanvasLayoutInfo info{ 123, 321, { CanvasLayoutInfo::Rect{ 0, 0, 100, 100 }, CanvasLayoutInfo::Rect{ 50, 50, 150, 150 } } }; - CustomZoneSetJSON expected{ uuid.get(), CustomZoneSetData{ L"name", CustomLayoutType::Canvas, info } }; - json::to_file(m_path, CustomZoneSetJSON::ToJson(expected)); - Assert::IsTrue(std::filesystem::exists(m_path)); - FancyZonesDataInstance().ParseCustomZoneSetFromTmpFile(m_path); - - //test - const int spacing = 10; - const int zoneCount = static_cast(info.zones.size()); - ZoneSetConfig m_config = ZoneSetConfig(m_id, TZoneSetLayoutType::Custom, m_monitor, m_resolutionKey); - for (const auto& monitorInfo : m_popularMonitors) - { - auto set = MakeZoneSet(m_config); - auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); - Assert::IsTrue(result); - checkZones(set, zoneCount, monitorInfo); - } - } + //prepare expected data + wil::unique_cotaskmem_string uuid; + Assert::AreEqual(S_OK, StringFromCLSID(m_id, &uuid)); + const CanvasLayoutInfo info{ 123, 321, { CanvasLayoutInfo::Rect{ 0, 0, 100, 100 }, CanvasLayoutInfo::Rect{ 50, 50, 150, 150 } } }; + CustomZoneSetJSON expected{ uuid.get(), CustomZoneSetData{ L"name", CustomLayoutType::Canvas, info } }; + json::to_file(m_path, CustomZoneSetJSON::ToJson(expected)); + Assert::IsTrue(std::filesystem::exists(m_path)); + FancyZonesDataInstance().ParseCustomZoneSetFromTmpFile(m_path); + + //test + const int spacing = 10; + const int zoneCount = static_cast(info.zones.size()); + ZoneSetConfig m_config = ZoneSetConfig(m_id, TZoneSetLayoutType::Custom, m_monitor, m_resolutionKey); + for (const auto& monitorInfo : m_popularMonitors) + { + auto set = MakeZoneSet(m_config); + auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); + Assert::IsTrue(result); + checkZones(set, zoneCount, monitorInfo); + } + } - TEST_METHOD(CustomZoneFromValidGridFullLayoutInfo) - { - using namespace JSONHelpers; + TEST_METHOD (CustomZoneFromValidGridFullLayoutInfo) + { + using namespace JSONHelpers; - //prepare device data - { - const std::wstring zoneUuid = L"default_device_id"; - DeviceInfoJSON deviceInfo{ zoneUuid, DeviceInfoData{ ZoneSetData{ L"uuid", ZoneSetLayoutType::Custom }, true, 16, 3 } }; - const std::wstring deviceInfoPath = FancyZonesDataInstance().GetPersistFancyZonesJSONPath() + L".device_info_tmp"; - FancyZonesDataInstance().SerializeDeviceInfoToTmpFile(deviceInfo, deviceInfoPath); + //prepare device data + { + const std::wstring zoneUuid = L"default_device_id"; + DeviceInfoJSON deviceInfo{ zoneUuid, DeviceInfoData{ ZoneSetData{ L"uuid", ZoneSetLayoutType::Custom }, true, 16, 3 } }; + const std::wstring deviceInfoPath = FancyZonesDataInstance().GetPersistFancyZonesJSONPath() + L".device_info_tmp"; + FancyZonesDataInstance().SerializeDeviceInfoToTmpFile(deviceInfo, deviceInfoPath); - FancyZonesDataInstance().ParseDeviceInfoFromTmpFile(deviceInfoPath); - std::filesystem::remove(deviceInfoPath); - } + FancyZonesDataInstance().ParseDeviceInfoFromTmpFile(deviceInfoPath); + std::filesystem::remove(deviceInfoPath); + } - //prepare expected data - wil::unique_cotaskmem_string uuid; - Assert::AreEqual(S_OK, StringFromCLSID(m_id, &uuid)); - const GridLayoutInfo grid(GridLayoutInfo(JSONHelpers::GridLayoutInfo::Full{ - .rows = 1, - .columns = 3, - .rowsPercents = { 10000 }, - .columnsPercents = { 2500, 5000, 2500 }, - .cellChildMap = { { 0, 1, 2 } } })); - CustomZoneSetJSON expected{ uuid.get(), CustomZoneSetData{ L"name", CustomLayoutType::Grid, grid } }; - json::to_file(m_path, CustomZoneSetJSON::ToJson(expected)); - Assert::IsTrue(std::filesystem::exists(m_path)); - FancyZonesDataInstance().ParseCustomZoneSetFromTmpFile(m_path); - - const int spacing = 10; - const int zoneCount = grid.rows() * grid.columns(); - - ZoneSetConfig m_config = ZoneSetConfig(m_id, TZoneSetLayoutType::Custom, m_monitor, m_resolutionKey); - - for (const auto& monitorInfo : m_popularMonitors) - { - auto set = MakeZoneSet(m_config); - auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); - Assert::IsTrue(result); - checkZones(set, zoneCount, monitorInfo); - } - } + //prepare expected data + wil::unique_cotaskmem_string uuid; + Assert::AreEqual(S_OK, StringFromCLSID(m_id, &uuid)); + const GridLayoutInfo grid(GridLayoutInfo(JSONHelpers::GridLayoutInfo::Full{ + .rows = 1, + .columns = 3, + .rowsPercents = { 10000 }, + .columnsPercents = { 2500, 5000, 2500 }, + .cellChildMap = { { 0, 1, 2 } } })); + CustomZoneSetJSON expected{ uuid.get(), CustomZoneSetData{ L"name", CustomLayoutType::Grid, grid } }; + json::to_file(m_path, CustomZoneSetJSON::ToJson(expected)); + Assert::IsTrue(std::filesystem::exists(m_path)); + FancyZonesDataInstance().ParseCustomZoneSetFromTmpFile(m_path); + + const int spacing = 10; + const int zoneCount = grid.rows() * grid.columns(); + + ZoneSetConfig m_config = ZoneSetConfig(m_id, TZoneSetLayoutType::Custom, m_monitor, m_resolutionKey); + + for (const auto& monitorInfo : m_popularMonitors) + { + auto set = MakeZoneSet(m_config); + auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); + Assert::IsTrue(result); + checkZones(set, zoneCount, monitorInfo); + } + } - TEST_METHOD(CustomZoneFromValidGridMinimalLayoutInfo) - { - using namespace JSONHelpers; + TEST_METHOD (CustomZoneFromValidGridMinimalLayoutInfo) + { + using namespace JSONHelpers; - const std::wstring uuid = L"uuid"; - const GridLayoutInfo grid(GridLayoutInfo(JSONHelpers::GridLayoutInfo::Minimal{ - .rows = 1, - .columns = 3 })); - CustomZoneSetJSON expected{ uuid, CustomZoneSetData{ L"name", CustomLayoutType::Grid, grid } }; - json::to_file(m_path, CustomZoneSetJSON::ToJson(expected)); - Assert::IsTrue(std::filesystem::exists(m_path)); + const std::wstring uuid = L"uuid"; + const GridLayoutInfo grid(GridLayoutInfo(JSONHelpers::GridLayoutInfo::Minimal{ + .rows = 1, + .columns = 3 })); + CustomZoneSetJSON expected{ uuid, CustomZoneSetData{ L"name", CustomLayoutType::Grid, grid } }; + json::to_file(m_path, CustomZoneSetJSON::ToJson(expected)); + Assert::IsTrue(std::filesystem::exists(m_path)); - const int spacing = 0; - const int zoneCount = grid.rows() * grid.columns(); + const int spacing = 0; + const int zoneCount = grid.rows() * grid.columns(); - ZoneSetConfig m_config = ZoneSetConfig(m_id, TZoneSetLayoutType::Custom, m_monitor, m_resolutionKey); - auto set = MakeZoneSet(m_config); + ZoneSetConfig m_config = ZoneSetConfig(m_id, TZoneSetLayoutType::Custom, m_monitor, m_resolutionKey); + auto set = MakeZoneSet(m_config); - for (const auto& monitorInfo : m_popularMonitors) - { - auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); - Assert::IsFalse(result); - } - } + for (const auto& monitorInfo : m_popularMonitors) + { + auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); + Assert::IsFalse(result); + } + } }; } diff --git a/src/modules/fancyzones/tests/UnitTests/ZoneWindow.Spec.cpp b/src/modules/fancyzones/tests/UnitTests/ZoneWindow.Spec.cpp index 9d3eb3b75225..13408dfc3a99 100644 --- a/src/modules/fancyzones/tests/UnitTests/ZoneWindow.Spec.cpp +++ b/src/modules/fancyzones/tests/UnitTests/ZoneWindow.Spec.cpp @@ -523,7 +523,7 @@ namespace FancyZonesUnitTests Assert::IsNotNull(m_zoneWindow->ActiveZoneSet()); const auto window = Mocks::WindowCreate(m_hInst); - m_zoneWindow->MoveWindowIntoZoneByDirection(window, VK_RIGHT); + m_zoneWindow->MoveWindowIntoZoneByDirection(window, VK_RIGHT, true); const auto actualAppZoneHistory = m_fancyZonesData.GetAppZoneHistoryMap(); Assert::AreEqual((size_t)1, actualAppZoneHistory.size()); @@ -537,9 +537,9 @@ namespace FancyZonesUnitTests Assert::IsNotNull(m_zoneWindow->ActiveZoneSet()); const auto window = Mocks::WindowCreate(m_hInst); - m_zoneWindow->MoveWindowIntoZoneByDirection(window, VK_RIGHT); - m_zoneWindow->MoveWindowIntoZoneByDirection(window, VK_RIGHT); - m_zoneWindow->MoveWindowIntoZoneByDirection(window, VK_RIGHT); + m_zoneWindow->MoveWindowIntoZoneByDirection(window, VK_RIGHT, true); + m_zoneWindow->MoveWindowIntoZoneByDirection(window, VK_RIGHT, true); + m_zoneWindow->MoveWindowIntoZoneByDirection(window, VK_RIGHT, true); const auto actualAppZoneHistory = m_fancyZonesData.GetAppZoneHistoryMap(); Assert::AreEqual((size_t)1, actualAppZoneHistory.size());