diff --git a/src/modules/fancyzones/lib/FancyZones.cpp b/src/modules/fancyzones/lib/FancyZones.cpp index 39d73736a4ea..2f591d222ead 100644 --- a/src/modules/fancyzones/lib/FancyZones.cpp +++ b/src/modules/fancyzones/lib/FancyZones.cpp @@ -333,10 +333,10 @@ FancyZones::WindowCreated(HWND window) noexcept std::vector zoneIndexSet = fancyZonesData.GetAppLastZoneIndexSet(window, zoneWindow->UniqueId(), guidString.get()); if (zoneIndexSet.size() && !IsSplashScreen(window) && - !fancyZonesData.IsAnotherWindowOfApplicationInstanceZoned(window)) + !fancyZonesData.IsAnotherWindowOfApplicationInstanceZoned(window, zoneWindow->UniqueId())) { m_windowMoveHandler.MoveWindowIntoZoneByIndexSet(window, zoneIndexSet, zoneWindow); - fancyZonesData.UpdateProcessIdToHandleMap(window); + fancyZonesData.UpdateProcessIdToHandleMap(window, zoneWindow->UniqueId()); } } } @@ -849,21 +849,11 @@ void FancyZones::RegisterVirtualDesktopUpdates(std::vector& ids) noexcept { std::unique_lock writeLock(m_lock); - std::vector deleted{}; - m_workAreaHandler.RegisterUpdates(ids, deleted); - - bool modified{ false }; - for (const auto& id : deleted) - { - wil::unique_cotaskmem_string virtualDesktopId; - if (SUCCEEDED(StringFromCLSID(id, &virtualDesktopId))) - { - modified |= JSONHelpers::FancyZonesDataInstance().RemoveDevicesByVirtualDesktopId(virtualDesktopId.get()); - } - } - if (modified) + m_workAreaHandler.RegisterUpdates(ids); + std::vector active{}; + if (VirtualDesktopUtils::GetVirtualDesktopIds(active)) { - JSONHelpers::FancyZonesDataInstance().SaveFancyZonesData(); + JSONHelpers::FancyZonesDataInstance().RemoveDeletedDesktops(active); } } diff --git a/src/modules/fancyzones/lib/JsonHelpers.cpp b/src/modules/fancyzones/lib/JsonHelpers.cpp index 094a2d9cf15a..0fa07f82c7b4 100644 --- a/src/modules/fancyzones/lib/JsonHelpers.cpp +++ b/src/modules/fancyzones/lib/JsonHelpers.cpp @@ -39,7 +39,7 @@ namespace JSONHelpers bool isValidGuid(const std::wstring& str) { GUID id; - return SUCCEEDED_LOG(CLSIDFromString(str.c_str(), &id)); + return SUCCEEDED(CLSIDFromString(str.c_str(), &id)); } bool isValidDeviceId(const std::wstring& str) @@ -278,25 +278,6 @@ namespace JSONHelpers } } - bool FancyZonesData::RemoveDevicesByVirtualDesktopId(const std::wstring& virtualDesktopId) - { - std::scoped_lock lock{ dataLock }; - bool modified{ false }; - for (auto it = deviceInfoMap.begin(); it != deviceInfoMap.end();) - { - if (ExtractVirtualDesktopId(it->first) == virtualDesktopId) - { - it = deviceInfoMap.erase(it); - modified = true; - } - else - { - ++it; - } - } - return modified; - } - void FancyZonesData::CloneDeviceInfo(const std::wstring& source, const std::wstring& destination) { if (source == destination) @@ -331,11 +312,14 @@ namespace JSONHelpers return deviceId.substr(0, deviceId.rfind('_') + 1) + desktopId; }; std::scoped_lock lock{ dataLock }; - for (auto& [path, data] : appZoneHistoryMap) + for (auto& [path, perDesktopData] : appZoneHistoryMap) { - if (ExtractVirtualDesktopId(data.deviceId) == DEFAULT_GUID) + for (auto& data : perDesktopData) { - data.deviceId = replaceDesktopId(data.deviceId); + if (ExtractVirtualDesktopId(data.deviceId) == DEFAULT_GUID) + { + data.deviceId = replaceDesktopId(data.deviceId); + } } } std::vector toReplace{}; @@ -361,9 +345,11 @@ namespace JSONHelpers std::scoped_lock lock{ dataLock }; for (auto it = std::begin(deviceInfoMap); it != std::end(deviceInfoMap);) { - auto foundId = active.find(ExtractVirtualDesktopId(it->first)); + std::wstring desktopId = ExtractVirtualDesktopId(it->first); + auto foundId = active.find(desktopId); if (foundId == std::end(active)) { + RemoveDesktopAppZoneHistory(desktopId); it = deviceInfoMap.erase(it); } else @@ -374,27 +360,34 @@ namespace JSONHelpers SaveFancyZonesData(); } - bool FancyZonesData::IsAnotherWindowOfApplicationInstanceZoned(HWND window) const + bool FancyZonesData::IsAnotherWindowOfApplicationInstanceZoned(HWND window, const std::wstring_view& deviceId) const { std::scoped_lock lock{ dataLock }; auto processPath = get_process_path(window); if (!processPath.empty()) { auto history = appZoneHistoryMap.find(processPath); - if (history != appZoneHistoryMap.end()) + if (history != std::end(appZoneHistoryMap)) { - DWORD processId = 0; - GetWindowThreadProcessId(window, &processId); + auto& perDesktopData = history->second; + for (auto& data : perDesktopData) + { + if (data.deviceId == deviceId) + { + DWORD processId = 0; + GetWindowThreadProcessId(window, &processId); - auto processIdIt = history->second.processIdToHandleMap.find(processId); + auto processIdIt = data.processIdToHandleMap.find(processId); - if (processIdIt == history->second.processIdToHandleMap.end()) - { - return false; - } - else if (processIdIt->second != window && IsWindow(processIdIt->second)) - { - return true; + if (processIdIt == std::end(data.processIdToHandleMap)) + { + return false; + } + else if (processIdIt->second != window && IsWindow(processIdIt->second)) + { + return true; + } + } } } } @@ -402,19 +395,26 @@ namespace JSONHelpers return false; } - void FancyZonesData::UpdateProcessIdToHandleMap(HWND window) + void FancyZonesData::UpdateProcessIdToHandleMap(HWND window, const std::wstring_view& deviceId) { std::scoped_lock lock{ dataLock }; auto processPath = get_process_path(window); if (!processPath.empty()) { auto history = appZoneHistoryMap.find(processPath); - if (history != appZoneHistoryMap.end()) + if (history != std::end(appZoneHistoryMap)) { - DWORD processId = 0; - GetWindowThreadProcessId(window, &processId); - - history->second.processIdToHandleMap[processId] = window; + auto& perDesktopData = history->second; + for (auto& data : perDesktopData) + { + if (data.deviceId == deviceId) + { + DWORD processId = 0; + GetWindowThreadProcessId(window, &processId); + data.processIdToHandleMap[processId] = window; + break; + } + } } } } @@ -426,12 +426,15 @@ namespace JSONHelpers if (!processPath.empty()) { auto history = appZoneHistoryMap.find(processPath); - if (history != appZoneHistoryMap.end()) + if (history != std::end(appZoneHistoryMap)) { - const auto& data = history->second; - if (data.zoneSetUuid == zoneSetId && data.deviceId == deviceId) + const auto& perDesktopData = history->second; + for (const auto& data : perDesktopData) { - return history->second.zoneIndexSet; + if (data.zoneSetUuid == zoneSetId && data.deviceId == deviceId) + { + return data.zoneIndexSet; + } } } } @@ -446,31 +449,42 @@ namespace JSONHelpers if (!processPath.empty()) { auto history = appZoneHistoryMap.find(processPath); - if (history != appZoneHistoryMap.end()) + if (history != std::end(appZoneHistoryMap)) { - auto& data = history->second; - if (data.zoneSetUuid == zoneSetId && data.deviceId == deviceId) + auto& perDesktopData = history->second; + for (auto data = std::begin(perDesktopData); data != std::end(perDesktopData);) { - if (!IsAnotherWindowOfApplicationInstanceZoned(window)) + if (data->deviceId == deviceId && data->zoneSetUuid == zoneSetId) { - DWORD processId = 0; - GetWindowThreadProcessId(window, &processId); + if (!IsAnotherWindowOfApplicationInstanceZoned(window, deviceId)) + { + DWORD processId = 0; + GetWindowThreadProcessId(window, &processId); - data.processIdToHandleMap.erase(processId); - } + data->processIdToHandleMap.erase(processId); + } - // if there is another instance placed don't erase history - for (auto placedWindow : data.processIdToHandleMap) - { - if (IsWindow(placedWindow.second)) + // if there is another instance placed don't erase history + for (auto placedWindow : data->processIdToHandleMap) { - return false; + if (IsWindow(placedWindow.second)) + { + return false; + } } - } - appZoneHistoryMap.erase(processPath); - SaveFancyZonesData(); - return true; + data = perDesktopData.erase(data); + if (perDesktopData.empty()) + { + appZoneHistoryMap.erase(processPath); + } + SaveFancyZonesData(); + return true; + } + else + { + ++data; + } } } } @@ -482,7 +496,7 @@ namespace JSONHelpers { std::scoped_lock lock{ dataLock }; - if (IsAnotherWindowOfApplicationInstanceZoned(window)) + if (IsAnotherWindowOfApplicationInstanceZoned(window, deviceId)) { return false; } @@ -497,23 +511,48 @@ namespace JSONHelpers GetWindowThreadProcessId(window, &processId); auto history = appZoneHistoryMap.find(processPath); - - if (history != appZoneHistoryMap.end()) + if (history != std::end(appZoneHistoryMap)) { - auto& data = history->second; - - for (auto placedWindow : data.processIdToHandleMap) + auto& perDesktopData = history->second; + for (auto& data : perDesktopData) { - if (IsWindow(placedWindow.second) && processId != placedWindow.first) + if (data.deviceId == deviceId) { - return false; + for (auto placedWindow : data.processIdToHandleMap) + { + if (IsWindow(placedWindow.second) && processId != placedWindow.first) + { + return false; + } + } + // application already has history on this desktop, but zone (or zone layout) has changed + data.processIdToHandleMap[processId] = window; + data.zoneSetUuid = zoneSetId; + data.zoneIndexSet = zoneIndexSet; + SaveFancyZonesData(); + return true; } } } - auto windowMap = appZoneHistoryMap[processPath].processIdToHandleMap; - windowMap[processId] = window; - appZoneHistoryMap[processPath] = AppZoneHistoryData{ .processIdToHandleMap = windowMap, .zoneSetUuid = zoneSetId, .deviceId = deviceId, .zoneIndexSet = zoneIndexSet }; + std::map processIdToHandleMap{}; + processIdToHandleMap[processId] = window; + AppZoneHistoryData data{ .processIdToHandleMap = processIdToHandleMap, + .zoneSetUuid = zoneSetId, + .deviceId = deviceId, + .zoneIndexSet = zoneIndexSet }; + + if (appZoneHistoryMap.contains(processPath)) + { + // application already has history but on other desktop, add with new desktop info + appZoneHistoryMap[processPath].push_back(data); + } + else + { + // new application, create entry in app zone history map + appZoneHistoryMap[processPath] = std::vector{ data }; + } + SaveFancyZonesData(); return true; } @@ -874,6 +913,34 @@ namespace JSONHelpers } } + void FancyZonesData::RemoveDesktopAppZoneHistory(const std::wstring& desktopId) + { + for (auto it = std::begin(appZoneHistoryMap); it != std::end(appZoneHistoryMap);) + { + auto& perDesktopData = it->second; + for (auto desktopIt = std::begin(perDesktopData); desktopIt != std::end(perDesktopData);) + { + if (ExtractVirtualDesktopId(desktopIt->deviceId) == desktopId) + { + desktopIt = perDesktopData.erase(desktopIt); + } + else + { + ++desktopIt; + } + } + + if (perDesktopData.empty()) + { + it = appZoneHistoryMap.erase(it); + } + else + { + ++it; + } + } + } + json::JsonObject ZoneSetData::ToJson(const ZoneSetData& zoneSet) { json::JsonObject result{}; @@ -911,19 +978,55 @@ namespace JSONHelpers result.SetNamedValue(L"app-path", json::value(appZoneHistory.appPath)); - json::JsonArray jsonIndexSet; - for (int index : appZoneHistory.data.zoneIndexSet) + json::JsonArray appHistoryArray; + for (const auto& data : appZoneHistory.data) { - jsonIndexSet.Append(json::value(index)); + json::JsonObject desktopData; + json::JsonArray jsonIndexSet; + for (int index : data.zoneIndexSet) + { + jsonIndexSet.Append(json::value(index)); + } + + desktopData.SetNamedValue(L"zone-index-set", jsonIndexSet); + desktopData.SetNamedValue(L"device-id", json::value(data.deviceId)); + desktopData.SetNamedValue(L"zoneset-uuid", json::value(data.zoneSetUuid)); + + appHistoryArray.Append(desktopData); } - result.SetNamedValue(L"zone-index-set", jsonIndexSet); - result.SetNamedValue(L"device-id", json::value(appZoneHistory.data.deviceId)); - result.SetNamedValue(L"zoneset-uuid", json::value(appZoneHistory.data.zoneSetUuid)); + result.SetNamedValue(L"history", appHistoryArray); return result; } + std::optional ParseSingleAppZoneHistoryItem(const json::JsonObject& json) + { + AppZoneHistoryData data; + if (json.HasKey(L"zone-index-set")) + { + data.zoneIndexSet = {}; + for (auto& value : json.GetNamedArray(L"zone-index-set")) + { + data.zoneIndexSet.push_back(static_cast(value.GetNumber())); + } + } + else if (json.HasKey(L"zone-index")) + { + data.zoneIndexSet = { static_cast(json.GetNamedNumber(L"zone-index")) }; + } + + data.deviceId = json.GetNamedString(L"device-id"); + data.zoneSetUuid = json.GetNamedString(L"zoneset-uuid"); + + if (!isValidGuid(data.zoneSetUuid) || !isValidDeviceId(data.deviceId)) + { + return std::nullopt; + } + + return data; + } + std::optional AppZoneHistoryJSON::FromJson(const json::JsonObject& zoneSet) { try @@ -931,23 +1034,27 @@ namespace JSONHelpers AppZoneHistoryJSON result; result.appPath = zoneSet.GetNamedString(L"app-path"); - if (zoneSet.HasKey(L"zone-index-set")) + if (zoneSet.HasKey(L"history")) { - result.data.zoneIndexSet = {}; - for (auto& value : zoneSet.GetNamedArray(L"zone-index-set")) + auto appHistoryArray = zoneSet.GetNamedArray(L"history"); + for (uint32_t i = 0; i < appHistoryArray.Size(); ++i) { - result.data.zoneIndexSet.push_back(static_cast(value.GetNumber())); + json::JsonObject json = appHistoryArray.GetObjectAt(i); + if (auto data = ParseSingleAppZoneHistoryItem(json); data.has_value()) + { + result.data.push_back(std::move(data.value())); + } } } - else if (zoneSet.HasKey(L"zone-index")) + else { - result.data.zoneIndexSet = { static_cast(zoneSet.GetNamedNumber(L"zone-index")) }; + // handle previous file format, with single desktop layout information per application + if (auto data = ParseSingleAppZoneHistoryItem(zoneSet); data.has_value()) + { + result.data.push_back(std::move(data.value())); + } } - - result.data.deviceId = zoneSet.GetNamedString(L"device-id"); - result.data.zoneSetUuid = zoneSet.GetNamedString(L"zoneset-uuid"); - - if (!isValidGuid(result.data.zoneSetUuid) || !isValidDeviceId(result.data.deviceId)) + if (result.data.empty()) { return std::nullopt; } diff --git a/src/modules/fancyzones/lib/JsonHelpers.h b/src/modules/fancyzones/lib/JsonHelpers.h index 08cfb3c80d2e..bc07083e9598 100644 --- a/src/modules/fancyzones/lib/JsonHelpers.h +++ b/src/modules/fancyzones/lib/JsonHelpers.h @@ -143,7 +143,7 @@ namespace JSONHelpers struct AppZoneHistoryJSON { std::wstring appPath; - AppZoneHistoryData data; + std::vector data; static json::JsonObject ToJson(const AppZoneHistoryJSON& appZoneHistory); static std::optional FromJson(const json::JsonObject& zoneSet); @@ -201,7 +201,7 @@ namespace JSONHelpers return customZoneSetsMap; } - inline const std::unordered_map& GetAppZoneHistoryMap() const + inline const std::unordered_map>& GetAppZoneHistoryMap() const { std::scoped_lock lock{ dataLock }; return appZoneHistoryMap; @@ -233,13 +233,12 @@ namespace JSONHelpers } void AddDevice(const std::wstring& deviceId); - bool RemoveDevicesByVirtualDesktopId(const std::wstring& virtualDesktopId); void CloneDeviceInfo(const std::wstring& source, const std::wstring& destination); void UpdatePrimaryDesktopData(const std::wstring& desktopId); void RemoveDeletedDesktops(const std::vector& activeDesktops); - bool IsAnotherWindowOfApplicationInstanceZoned(HWND window) const; - void UpdateProcessIdToHandleMap(HWND window); + bool IsAnotherWindowOfApplicationInstanceZoned(HWND window, const std::wstring_view& deviceId) const; + void UpdateProcessIdToHandleMap(HWND window, const std::wstring_view& deviceId); std::vector GetAppLastZoneIndexSet(HWND window, const std::wstring_view& deviceId, const std::wstring_view& zoneSetId) const; bool RemoveAppLastZone(HWND window, const std::wstring_view& deviceId, const std::wstring_view& zoneSetId); bool SetAppLastZones(HWND window, const std::wstring& deviceId, const std::wstring& zoneSetId, const std::vector& zoneIndexSet); @@ -265,8 +264,9 @@ namespace JSONHelpers private: void MigrateCustomZoneSetsFromRegistry(); + void RemoveDesktopAppZoneHistory(const std::wstring& desktopId); - std::unordered_map appZoneHistoryMap{}; + std::unordered_map> appZoneHistoryMap{}; std::unordered_map deviceInfoMap{}; std::unordered_map customZoneSetsMap{}; diff --git a/src/modules/fancyzones/lib/MonitorWorkAreaHandler.cpp b/src/modules/fancyzones/lib/MonitorWorkAreaHandler.cpp index 9b51dc26fcdc..f8cad1adcc53 100644 --- a/src/modules/fancyzones/lib/MonitorWorkAreaHandler.cpp +++ b/src/modules/fancyzones/lib/MonitorWorkAreaHandler.cpp @@ -73,7 +73,7 @@ bool MonitorWorkAreaHandler::IsNewWorkArea(const GUID& desktopId, HMONITOR monit return true; } -void MonitorWorkAreaHandler::RegisterUpdates(const std::vector& active, std::vector& deleted) +void MonitorWorkAreaHandler::RegisterUpdates(const std::vector& active) { std::unordered_set activeVirtualDesktops(std::begin(active), std::end(active)); for (auto desktopIt = std::begin(workAreaMap); desktopIt != std::end(workAreaMap);) @@ -81,8 +81,7 @@ void MonitorWorkAreaHandler::RegisterUpdates(const std::vector& active, st auto activeIt = activeVirtualDesktops.find(desktopIt->first); if (activeIt == std::end(activeVirtualDesktops)) { - // register deleted virtual desktop - deleted.push_back(desktopIt->first); + // virtual desktop deleted, remove entry from the map desktopIt = workAreaMap.erase(desktopIt); } else diff --git a/src/modules/fancyzones/lib/MonitorWorkAreaHandler.h b/src/modules/fancyzones/lib/MonitorWorkAreaHandler.h index 7b00f377bdbf..10f9df7dd957 100644 --- a/src/modules/fancyzones/lib/MonitorWorkAreaHandler.h +++ b/src/modules/fancyzones/lib/MonitorWorkAreaHandler.h @@ -77,10 +77,8 @@ class MonitorWorkAreaHandler * Register changes in current virtual desktop layout. * * @param[in] active Array of currently active virtual desktop identifiers. - * @param[out] deleted Array of virtual desktop identifiers belonging to previously registered but now deleted - * work areas. */ - void RegisterUpdates(const std::vector& active, std::vector& deleted); + void RegisterUpdates(const std::vector& active); /** * Clear all persisted work area related data. diff --git a/src/modules/fancyzones/tests/UnitTests/JsonHelpers.Tests.cpp b/src/modules/fancyzones/tests/UnitTests/JsonHelpers.Tests.cpp index b660e22b8fa8..affece05657a 100644 --- a/src/modules/fancyzones/tests/UnitTests/JsonHelpers.Tests.cpp +++ b/src/modules/fancyzones/tests/UnitTests/JsonHelpers.Tests.cpp @@ -715,8 +715,11 @@ namespace FancyZonesUnitTests { TEST_METHOD (ToJson) { - AppZoneHistoryJSON appZoneHistory{ L"appPath", AppZoneHistoryData{ .zoneSetUuid = L"zoneset-uuid", .deviceId = L"device-id", .zoneIndexSet = { 54321 } } }; - json::JsonObject expected = json::JsonObject::Parse(L"{\"app-path\": \"appPath\", \"device-id\": \"device-id\", \"zoneset-uuid\": \"zoneset-uuid\", \"zone-index-set\": [54321]}"); + AppZoneHistoryData data{ + .zoneSetUuid = L"zoneset-uuid", .deviceId = L"device-id", .zoneIndexSet = { 54321 } + }; + AppZoneHistoryJSON appZoneHistory{ L"appPath", std::vector{ data } }; + json::JsonObject expected = json::JsonObject::Parse(L"{\"app-path\": \"appPath\", \"history\":[{\"zone-index-set\": [54321], \"device-id\": \"device-id\", \"zoneset-uuid\": \"zoneset-uuid\"}]}"); auto actual = AppZoneHistoryJSON::ToJson(appZoneHistory); compareJsonObjects(expected, actual); @@ -724,35 +727,42 @@ namespace FancyZonesUnitTests TEST_METHOD (FromJson) { - AppZoneHistoryJSON expected{ L"appPath", AppZoneHistoryData{ .zoneSetUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502906}", .deviceId = L"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1539}", .zoneIndexSet = { 54321 } } }; - json::JsonObject json = json::JsonObject::Parse(L"{\"app-path\": \"appPath\", \"device-id\": \"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1539}\", \"zoneset-uuid\": \"{33A2B101-06E0-437B-A61E-CDBECF502906}\", \"zone-index\": 54321}"); + AppZoneHistoryData data{ + .zoneSetUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502906}", .deviceId = L"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1539}", .zoneIndexSet = { 54321 } + }; + AppZoneHistoryJSON expected{ L"appPath", std::vector{ data } }; + json::JsonObject json = json::JsonObject::Parse(L"{\"app-path\": \"appPath\", \"history\": [{\"device-id\": \"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1539}\", \"zoneset-uuid\": \"{33A2B101-06E0-437B-A61E-CDBECF502906}\", \"zone-index\": 54321}]}"); auto actual = AppZoneHistoryJSON::FromJson(json); Assert::IsTrue(actual.has_value()); Assert::AreEqual(expected.appPath.c_str(), actual->appPath.c_str()); - Assert::AreEqual(expected.data.zoneIndexSet, actual->data.zoneIndexSet); - Assert::AreEqual(expected.data.deviceId.c_str(), actual->data.deviceId.c_str()); - Assert::AreEqual(expected.data.zoneSetUuid.c_str(), actual->data.zoneSetUuid.c_str()); + Assert::AreEqual(expected.data.size(), actual->data.size()); + Assert::AreEqual(expected.data[0].zoneIndexSet, actual->data[0].zoneIndexSet); + Assert::AreEqual(expected.data[0].deviceId.c_str(), actual->data[0].deviceId.c_str()); + Assert::AreEqual(expected.data[0].zoneSetUuid.c_str(), actual->data[0].zoneSetUuid.c_str()); } TEST_METHOD (FromJsonInvalidUuid) { - json::JsonObject json = json::JsonObject::Parse(L"{\"app-path\": \"appPath\", \"device-id\": \"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1539}\", \"zoneset-uuid\": \"zoneset-uuid\", \"zone-index\": 54321}"); + json::JsonObject json = json::JsonObject::Parse(L"{\"app-path\": \"appPath\", \"history\": [{\"device-id\": \"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1539}\", \"zoneset-uuid\": \"zoneset-uuid\", \"zone-index\": 54321}]}"); auto actual = AppZoneHistoryJSON::FromJson(json); Assert::IsFalse(actual.has_value()); } TEST_METHOD (FromJsonInvalidDeviceId) { - json::JsonObject json = json::JsonObject::Parse(L"{\"app-path\": \"appPath\", \"device-id\": \"device-id\", \"zoneset-uuid\": \"{33A2B101-06E0-437B-A61E-CDBECF502906}\", \"zone-index\": 54321}"); + json::JsonObject json = json::JsonObject::Parse(L"{\"app-path\": \"appPath\", \"history\": [{\"device-id\": \"device-id\", \"zoneset-uuid\": \"{33A2B101-06E0-437B-A61E-CDBECF502906}\", \"zone-index\": 54321}]}"); auto actual = AppZoneHistoryJSON::FromJson(json); Assert::IsFalse(actual.has_value()); } TEST_METHOD (FromJsonMissingKeys) { - AppZoneHistoryJSON appZoneHistory{ L"appPath", AppZoneHistoryData{ .zoneSetUuid = L"zoneset-uuid", .deviceId = L"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1539}", .zoneIndexSet = { 54321 } } }; + AppZoneHistoryData data{ + .zoneSetUuid = L"zoneset-uuid", .deviceId = L"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1539}", .zoneIndexSet = { 54321 } + }; + AppZoneHistoryJSON appZoneHistory{ L"appPath", std::vector{ data } }; const auto json = AppZoneHistoryJSON::ToJson(appZoneHistory); auto iter = json.First(); @@ -770,9 +780,54 @@ namespace FancyZonesUnitTests TEST_METHOD (FromJsonInvalidTypes) { - json::JsonObject json = json::JsonObject::Parse(L"{\"app-path\": false, \"device-id\": [], \"zoneset-uuid\": {}, \"zone-index\": \"54321\"}"); + json::JsonObject json = json::JsonObject::Parse(L"{\"app-path\": false, \"history\": [{\"device-id\": [], \"zoneset-uuid\": {}, \"zone-index\": \"54321\"}]}"); Assert::IsFalse(AppZoneHistoryJSON::FromJson(json).has_value()); } + + TEST_METHOD (ToJsonMultipleDesktopAppHistory) + { + AppZoneHistoryData data1{ + .zoneSetUuid = L"zoneset-uuid1", .deviceId = L"device-id1", .zoneIndexSet = { 54321 } + }; + AppZoneHistoryData data2{ + .zoneSetUuid = L"zoneset-uuid2", .deviceId = L"device-id2", .zoneIndexSet = { 12345 } + }; + AppZoneHistoryJSON appZoneHistory{ + L"appPath", std::vector{ data1, data2 } + }; + json::JsonObject expected = json::JsonObject::Parse(L"{\"app-path\": \"appPath\", \"history\": [{\"zone-index-set\": [54321], \"device-id\": \"device-id1\", \"zoneset-uuid\": \"zoneset-uuid1\"}, {\"zone-index-set\": [12345], \"device-id\": \"device-id2\", \"zoneset-uuid\": \"zoneset-uuid2\"}]}"); + + auto actual = AppZoneHistoryJSON::ToJson(appZoneHistory); + std::wstring s = actual.Stringify().c_str(); + compareJsonObjects(expected, actual); + } + + TEST_METHOD (FromJsonMultipleDesktopAppHistory) + { + AppZoneHistoryData data1{ + .zoneSetUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502906}", .deviceId = L"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1539}", .zoneIndexSet = { 54321 } + }; + AppZoneHistoryData data2{ + .zoneSetUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502906}", .deviceId = L"AOC2460#4&fe3a015&0&UID65793_1920_1200_{8a0b9205-6128-45a2-934a-b97f5b271235}", .zoneIndexSet = { 12345 } + }; + AppZoneHistoryJSON expected{ + L"appPath", std::vector{ data1, data2 } + }; + json::JsonObject json = json::JsonObject::Parse(L"{\"app-path\": \"appPath\", \"history\": [{\"device-id\": \"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1539}\", \"zoneset-uuid\": \"{33A2B101-06E0-437B-A61E-CDBECF502906}\", \"zone-index-set\": [54321]}, {\"device-id\": \"AOC2460#4&fe3a015&0&UID65793_1920_1200_{8a0b9205-6128-45a2-934a-b97f5b271235}\", \"zoneset-uuid\": \"{33A2B101-06E0-437B-A61E-CDBECF502906}\", \"zone-index-set\": [12345]}]}"); + + auto actual = AppZoneHistoryJSON::FromJson(json); + Assert::IsTrue(actual.has_value()); + + Assert::AreEqual(expected.appPath.c_str(), actual->appPath.c_str()); + Assert::AreEqual(expected.data.size(), actual->data.size()); + + for (size_t i = 0; i < expected.data.size(); ++i) + { + Assert::AreEqual(expected.data[i].zoneIndexSet, actual->data[i].zoneIndexSet); + Assert::AreEqual(expected.data[i].deviceId.c_str(), actual->data[i].deviceId.c_str()); + Assert::AreEqual(expected.data[i].zoneSetUuid.c_str(), actual->data[i].zoneSetUuid.c_str()); + } + } }; TEST_CLASS (DeviceInfoUnitTests) @@ -1153,47 +1208,60 @@ namespace FancyZonesUnitTests const std::wstring expectedZoneSetId = L"{33A2B101-06E0-437B-A61E-CDBECF502906}"; const int expectedIndex = 54321; - json::JsonObject json; - AppZoneHistoryJSON expected{ expectedAppPath, AppZoneHistoryData{ .zoneSetUuid = expectedZoneSetId, .deviceId = expectedDeviceId, .zoneIndexSet = { expectedIndex } } }; + AppZoneHistoryData data{ + .zoneSetUuid = expectedZoneSetId, .deviceId = expectedDeviceId, .zoneIndexSet = { expectedIndex } + }; + AppZoneHistoryJSON expected{ expectedAppPath, std::vector{ data } }; json::JsonArray zoneHistoryArray; zoneHistoryArray.Append(AppZoneHistoryJSON::ToJson(expected)); + json::JsonObject json; json.SetNamedValue(L"app-zone-history", json::JsonValue::Parse(zoneHistoryArray.Stringify())); - FancyZonesData data; - data.SetSettingsModulePath(m_moduleName); - data.ParseAppZoneHistory(json); + FancyZonesData fancyZonesData; + fancyZonesData.SetSettingsModulePath(m_moduleName); + fancyZonesData.ParseAppZoneHistory(json); - const auto actualProcessHistoryMap = data.GetAppZoneHistoryMap(); + const auto actualProcessHistoryMap = fancyZonesData.GetAppZoneHistoryMap(); Assert::AreEqual((size_t)zoneHistoryArray.Size(), actualProcessHistoryMap.size()); const auto actualProcessHistory = actualProcessHistoryMap.begin(); Assert::AreEqual(expectedAppPath.c_str(), actualProcessHistory->first.c_str()); const auto actualAppZoneHistory = actualProcessHistory->second; - Assert::AreEqual(expectedZoneSetId.c_str(), actualAppZoneHistory.zoneSetUuid.c_str()); - Assert::AreEqual(expectedDeviceId.c_str(), actualAppZoneHistory.deviceId.c_str()); - Assert::AreEqual({ expectedIndex }, actualAppZoneHistory.zoneIndexSet); + Assert::AreEqual(expected.data.size(), actualAppZoneHistory.size()); + Assert::AreEqual(expectedZoneSetId.c_str(), actualAppZoneHistory[0].zoneSetUuid.c_str()); + Assert::AreEqual(expectedDeviceId.c_str(), actualAppZoneHistory[0].deviceId.c_str()); + Assert::AreEqual({ expectedIndex }, actualAppZoneHistory[0].zoneIndexSet); } TEST_METHOD (AppZoneHistoryParseManyApps) { json::JsonObject json; json::JsonArray zoneHistoryArray; - zoneHistoryArray.Append(AppZoneHistoryJSON::ToJson(AppZoneHistoryJSON{ L"app-path-1", AppZoneHistoryData{ .zoneSetUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502900}", .deviceId = L"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1530}", .zoneIndexSet = { 1 } } })); - zoneHistoryArray.Append(AppZoneHistoryJSON::ToJson(AppZoneHistoryJSON{ L"app-path-2", AppZoneHistoryData{ .zoneSetUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502901}", .deviceId = L"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1531}", .zoneIndexSet = { 2 } } })); - zoneHistoryArray.Append(AppZoneHistoryJSON::ToJson(AppZoneHistoryJSON{ L"app-path-3", AppZoneHistoryData{ .zoneSetUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502902}", .deviceId = L"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1532}", .zoneIndexSet = { 3 } } })); - zoneHistoryArray.Append(AppZoneHistoryJSON::ToJson(AppZoneHistoryJSON{ L"app-path-4", AppZoneHistoryData{ .zoneSetUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502903}", .deviceId = L"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1533}", .zoneIndexSet = { 4 } } })); + AppZoneHistoryData data1{ + .zoneSetUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502900}", .deviceId = L"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1530}", .zoneIndexSet = { 1 } + }; + AppZoneHistoryData data2{ + .zoneSetUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502901}", .deviceId = L"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1531}", .zoneIndexSet = { 2 } + }; + AppZoneHistoryData data3{ + .zoneSetUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502902}", .deviceId = L"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1532}", .zoneIndexSet = { 3 } + }; + AppZoneHistoryData data4{ + .zoneSetUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502903}", .deviceId = L"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1533}", .zoneIndexSet = { 4 } + }; + zoneHistoryArray.Append(AppZoneHistoryJSON::ToJson(AppZoneHistoryJSON{ L"app-path-1", std::vector{ data1 } })); + zoneHistoryArray.Append(AppZoneHistoryJSON::ToJson(AppZoneHistoryJSON{ L"app-path-2", std::vector{ data2 } })); + zoneHistoryArray.Append(AppZoneHistoryJSON::ToJson(AppZoneHistoryJSON{ L"app-path-3", std::vector{ data3 } })); + zoneHistoryArray.Append(AppZoneHistoryJSON::ToJson(AppZoneHistoryJSON{ L"app-path-4", std::vector{ data4 } })); json.SetNamedValue(L"app-zone-history", json::JsonValue::Parse(zoneHistoryArray.Stringify())); - FancyZonesData data; - data.SetSettingsModulePath(m_moduleName); - data.ParseAppZoneHistory(json); - - auto actualMap = data.GetAppZoneHistoryMap(); - Assert::AreEqual((size_t)zoneHistoryArray.Size(), actualMap.size()); + FancyZonesData fancyZonesData; + fancyZonesData.SetSettingsModulePath(m_moduleName); + fancyZonesData.ParseAppZoneHistory(json); - const auto actualProcessHistoryMap = data.GetAppZoneHistoryMap(); + const auto actualProcessHistoryMap = fancyZonesData.GetAppZoneHistoryMap(); Assert::AreEqual((size_t)zoneHistoryArray.Size(), actualProcessHistoryMap.size()); auto iter = zoneHistoryArray.First(); @@ -1201,10 +1269,11 @@ namespace FancyZonesUnitTests { auto expected = AppZoneHistoryJSON::FromJson(json::JsonObject::Parse(iter.Current().Stringify())); - const auto actual = actualProcessHistoryMap.at(expected->appPath); - Assert::AreEqual(expected->data.deviceId.c_str(), actual.deviceId.c_str()); - Assert::AreEqual(expected->data.zoneSetUuid.c_str(), actual.zoneSetUuid.c_str()); - Assert::AreEqual(expected->data.zoneIndexSet, actual.zoneIndexSet); + const auto& actual = actualProcessHistoryMap.at(expected->appPath); + Assert::AreEqual(expected->data.size(), actual.size()); + Assert::AreEqual(expected->data[0].deviceId.c_str(), actual[0].deviceId.c_str()); + Assert::AreEqual(expected->data[0].zoneSetUuid.c_str(), actual[0].zoneSetUuid.c_str()); + Assert::AreEqual(expected->data[0].zoneIndexSet, actual[0].zoneIndexSet); iter.MoveNext(); } @@ -1216,24 +1285,36 @@ namespace FancyZonesUnitTests json::JsonArray zoneHistoryArray; const auto appPath = L"app-path"; - zoneHistoryArray.Append(AppZoneHistoryJSON::ToJson(AppZoneHistoryJSON{ appPath, AppZoneHistoryData{ .zoneSetUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502900}", .deviceId = L"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1530}", .zoneIndexSet = { 1 } } })); - zoneHistoryArray.Append(AppZoneHistoryJSON::ToJson(AppZoneHistoryJSON{ appPath, AppZoneHistoryData{ .zoneSetUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502901}", .deviceId = L"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1531}", .zoneIndexSet = { 2 } } })); - zoneHistoryArray.Append(AppZoneHistoryJSON::ToJson(AppZoneHistoryJSON{ appPath, AppZoneHistoryData{ .zoneSetUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502902}", .deviceId = L"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1532}", .zoneIndexSet = { 3 } } })); - const auto expected = AppZoneHistoryData{ .zoneSetUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502903}", .deviceId = L"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1533}", .zoneIndexSet = { 4 } }; - zoneHistoryArray.Append(AppZoneHistoryJSON::ToJson(AppZoneHistoryJSON{ appPath, expected })); + AppZoneHistoryData data1{ + .zoneSetUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502900}", .deviceId = L"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1530}", .zoneIndexSet = { 1 } + }; + zoneHistoryArray.Append(AppZoneHistoryJSON::ToJson(AppZoneHistoryJSON{ appPath, std::vector{ data1 } })); + AppZoneHistoryData data2{ + .zoneSetUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502901}", .deviceId = L"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1531}", .zoneIndexSet = { 2 } + }; + zoneHistoryArray.Append(AppZoneHistoryJSON::ToJson(AppZoneHistoryJSON{ appPath, std::vector{ data2 } })); + AppZoneHistoryData data3{ + .zoneSetUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502902}", .deviceId = L"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1532}", .zoneIndexSet = { 3 } + }; + zoneHistoryArray.Append(AppZoneHistoryJSON::ToJson(AppZoneHistoryJSON{ appPath, std::vector{ data3 } })); + AppZoneHistoryData expected{ + .zoneSetUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502903}", .deviceId = L"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1533}", .zoneIndexSet = { 4 } + }; + zoneHistoryArray.Append(AppZoneHistoryJSON::ToJson(AppZoneHistoryJSON{ appPath, std::vector{ expected } })); json.SetNamedValue(L"app-zone-history", json::JsonValue::Parse(zoneHistoryArray.Stringify())); - FancyZonesData data; - data.SetSettingsModulePath(m_moduleName); - data.ParseAppZoneHistory(json); + FancyZonesData fancyZonesData; + fancyZonesData.SetSettingsModulePath(m_moduleName); + fancyZonesData.ParseAppZoneHistory(json); - const auto actualProcessHistoryMap = data.GetAppZoneHistoryMap(); + const auto& actualProcessHistoryMap = fancyZonesData.GetAppZoneHistoryMap(); Assert::AreEqual((size_t)1, actualProcessHistoryMap.size()); - const auto actual = actualProcessHistoryMap.at(appPath); - Assert::AreEqual(expected.deviceId.c_str(), actual.deviceId.c_str()); - Assert::AreEqual(expected.zoneSetUuid.c_str(), actual.zoneSetUuid.c_str()); - Assert::AreEqual(expected.zoneIndexSet, actual.zoneIndexSet); + const auto& actual = actualProcessHistoryMap.at(appPath); + Assert::AreEqual((size_t)1, actual.size()); + Assert::AreEqual(expected.deviceId.c_str(), actual[0].deviceId.c_str()); + Assert::AreEqual(expected.zoneSetUuid.c_str(), actual[0].zoneSetUuid.c_str()); + Assert::AreEqual(expected.zoneIndexSet, actual[0].zoneIndexSet); } TEST_METHOD (AppZoneHistoryParseEmpty) @@ -1250,12 +1331,15 @@ namespace FancyZonesUnitTests { const std::wstring appPath = L"appPath"; json::JsonObject json; - AppZoneHistoryJSON expected{ appPath, AppZoneHistoryData{ .zoneSetUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502906}", .deviceId = L"device-id", .zoneIndexSet = { 54321 } } }; + AppZoneHistoryData data{ + .zoneSetUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502906}", .deviceId = L"device-id", .zoneIndexSet = { 54321 } + }; + AppZoneHistoryJSON expected{ appPath, std::vector{ data } }; json.SetNamedValue(L"app-zone-history", json::JsonValue::Parse(AppZoneHistoryJSON::ToJson(expected).Stringify())); - FancyZonesData data; - data.SetSettingsModulePath(m_moduleName); - bool actual = data.ParseAppZoneHistory(json); + FancyZonesData fancyZonesData; + fancyZonesData.SetSettingsModulePath(m_moduleName); + bool actual = fancyZonesData.ParseAppZoneHistory(json); Assert::IsFalse(actual); } @@ -1264,12 +1348,15 @@ namespace FancyZonesUnitTests { const std::wstring appPath = L"appPath"; json::JsonObject json; - AppZoneHistoryJSON expected{ appPath, AppZoneHistoryData{ .zoneSetUuid = L"zoneset-uuid", .deviceId = L"device-id", .zoneIndexSet = { 54321 } } }; + AppZoneHistoryData data{ + .zoneSetUuid = L"zoneset-uuid", .deviceId = L"device-id", .zoneIndexSet = { 54321 } + }; + AppZoneHistoryJSON expected{ appPath, std::vector{ data } }; json.SetNamedValue(L"app-zone-history", json::JsonValue::Parse(AppZoneHistoryJSON::ToJson(expected).Stringify())); - FancyZonesData data; - data.SetSettingsModulePath(m_moduleName); - bool actual = data.ParseAppZoneHistory(json); + FancyZonesData fancyZonesData; + fancyZonesData.SetSettingsModulePath(m_moduleName); + bool actual = fancyZonesData.ParseAppZoneHistory(json); Assert::IsFalse(actual); } @@ -1278,15 +1365,21 @@ namespace FancyZonesUnitTests { const std::wstring appPath = L"appPath"; json::JsonArray expected; - expected.Append(AppZoneHistoryJSON::ToJson(AppZoneHistoryJSON{ appPath, AppZoneHistoryData{ .zoneSetUuid = L"{39B25DD2-130D-4B5D-8851-4791D66B1539}", .deviceId = m_defaultDeviceId, .zoneIndexSet = { 54321 } } })); + AppZoneHistoryData data{ + .zoneSetUuid = L"{39B25DD2-130D-4B5D-8851-4791D66B1539}", .deviceId = m_defaultDeviceId, .zoneIndexSet = { 54321 } + }; + AppZoneHistoryJSON appZoneHistory{ + appPath, std::vector{ data } + }; + expected.Append(AppZoneHistoryJSON::ToJson(appZoneHistory)); json::JsonObject json; json.SetNamedValue(L"app-zone-history", json::JsonValue::Parse(expected.Stringify())); - FancyZonesData data; - data.SetSettingsModulePath(m_moduleName); - data.ParseAppZoneHistory(json); + FancyZonesData fancyZonesData; + fancyZonesData.SetSettingsModulePath(m_moduleName); + fancyZonesData.ParseAppZoneHistory(json); - auto actual = data.SerializeAppZoneHistory(); + auto actual = fancyZonesData.SerializeAppZoneHistory(); compareJsonArrays(expected, actual); } @@ -1294,17 +1387,41 @@ namespace FancyZonesUnitTests { json::JsonObject json; json::JsonArray expected; - expected.Append(AppZoneHistoryJSON::ToJson(AppZoneHistoryJSON{ L"app-path-1", AppZoneHistoryData{ .zoneSetUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502906}", .deviceId = m_defaultDeviceId, .zoneIndexSet = { 54321 } } })); - expected.Append(AppZoneHistoryJSON::ToJson(AppZoneHistoryJSON{ L"app-path-2", AppZoneHistoryData{ .zoneSetUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502906}", .deviceId = m_defaultDeviceId, .zoneIndexSet = { 54321 } } })); - expected.Append(AppZoneHistoryJSON::ToJson(AppZoneHistoryJSON{ L"app-path-3", AppZoneHistoryData{ .zoneSetUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502906}", .deviceId = m_defaultDeviceId, .zoneIndexSet = { 54321 } } })); - expected.Append(AppZoneHistoryJSON::ToJson(AppZoneHistoryJSON{ L"app-path-4", AppZoneHistoryData{ .zoneSetUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502906}", .deviceId = m_defaultDeviceId, .zoneIndexSet = { 54321 } } })); + AppZoneHistoryData data1{ + .zoneSetUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502906}", .deviceId = m_defaultDeviceId, .zoneIndexSet = { 54321 } + }; + AppZoneHistoryJSON appZoneHistory1{ + L"app-path-1", std::vector{ data1 } + }; + AppZoneHistoryData data2{ + .zoneSetUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502906}", .deviceId = m_defaultDeviceId, .zoneIndexSet = { 54321 } + }; + AppZoneHistoryJSON appZoneHistory2{ + L"app-path-2", std::vector{ data2 } + }; + AppZoneHistoryData data3{ + .zoneSetUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502906}", .deviceId = m_defaultDeviceId, .zoneIndexSet = { 54321 } + }; + AppZoneHistoryJSON appZoneHistory3{ + L"app-path-3", std::vector{ data3 } + }; + AppZoneHistoryData data4{ + .zoneSetUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502906}", .deviceId = m_defaultDeviceId, .zoneIndexSet = { 54321 } + }; + AppZoneHistoryJSON appZoneHistory4{ + L"app-path-4", std::vector{ data4 } + }; + expected.Append(AppZoneHistoryJSON::ToJson(appZoneHistory1)); + expected.Append(AppZoneHistoryJSON::ToJson(appZoneHistory2)); + expected.Append(AppZoneHistoryJSON::ToJson(appZoneHistory3)); + expected.Append(AppZoneHistoryJSON::ToJson(appZoneHistory4)); json.SetNamedValue(L"app-zone-history", json::JsonValue::Parse(expected.Stringify())); - FancyZonesData data; - data.SetSettingsModulePath(m_moduleName); - data.ParseAppZoneHistory(json); + FancyZonesData fancyZonesData; + fancyZonesData.SetSettingsModulePath(m_moduleName); + fancyZonesData.ParseAppZoneHistory(json); - auto actual = data.SerializeAppZoneHistory(); + auto actual = fancyZonesData.SerializeAppZoneHistory(); compareJsonArrays(expected, actual); } @@ -1625,9 +1742,9 @@ namespace FancyZonesUnitTests TEST_METHOD (LoadFancyZonesDataFromJson) { - FancyZonesData data; - data.SetSettingsModulePath(m_moduleName); - const auto jsonPath = data.GetPersistFancyZonesJSONPath(); + FancyZonesData fancyZonesData; + fancyZonesData.SetSettingsModulePath(m_moduleName); + const auto jsonPath = fancyZonesData.GetPersistFancyZonesJSONPath(); auto savedJson = json::from_file(jsonPath); if (std::filesystem::exists(jsonPath)) @@ -1642,7 +1759,10 @@ namespace FancyZonesUnitTests .columnsPercents = { 2500, 5000, 2500 }, .cellChildMap = { { 0, 1, 2 } } })); CustomZoneSetJSON zoneSets{ L"{33A2B101-06E0-437B-A61E-CDBECF502906}", CustomZoneSetData{ L"name", CustomLayoutType::Grid, grid } }; - AppZoneHistoryJSON appZoneHistory{ L"app-path", AppZoneHistoryData{ .zoneSetUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502906}", .deviceId = L"device-id", .zoneIndexSet = { 54321 } } }; + AppZoneHistoryData data{ + .zoneSetUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502906}", .deviceId = L"device-id", .zoneIndexSet = { 54321 } + }; + AppZoneHistoryJSON appZoneHistory{ L"app-path", std::vector{ data } }; DeviceInfoJSON deviceInfo{ L"{33A2B101-06E0-437B-A61E-CDBECF502906}", DeviceInfoData{ ZoneSetData{ L"uuid", ZoneSetLayoutType::Custom }, true, 16, 3 } }; json::JsonArray zoneSetsArray, appZonesArray, deviceInfoArray; zoneSetsArray.Append(CustomZoneSetJSON::ToJson(zoneSets)); @@ -1655,7 +1775,7 @@ namespace FancyZonesUnitTests json::to_file(jsonPath, fancyZones); - data.LoadFancyZonesData(); + fancyZonesData.LoadFancyZonesData(); if (savedJson) { json::to_file(jsonPath, *savedJson); @@ -1665,9 +1785,9 @@ namespace FancyZonesUnitTests std::filesystem::remove(jsonPath); } - Assert::IsFalse(data.GetCustomZoneSetsMap().empty()); - Assert::IsFalse(data.GetCustomZoneSetsMap().empty()); - Assert::IsFalse(data.GetCustomZoneSetsMap().empty()); + Assert::IsFalse(fancyZonesData.GetCustomZoneSetsMap().empty()); + Assert::IsFalse(fancyZonesData.GetCustomZoneSetsMap().empty()); + Assert::IsFalse(fancyZonesData.GetCustomZoneSetsMap().empty()); } TEST_METHOD (LoadFancyZonesDataFromCroppedJson) diff --git a/src/modules/fancyzones/tests/UnitTests/ZoneWindow.Spec.cpp b/src/modules/fancyzones/tests/UnitTests/ZoneWindow.Spec.cpp index 003309825ef7..821f1c6ad314 100644 --- a/src/modules/fancyzones/tests/UnitTests/ZoneWindow.Spec.cpp +++ b/src/modules/fancyzones/tests/UnitTests/ZoneWindow.Spec.cpp @@ -607,10 +607,11 @@ namespace FancyZonesUnitTests const auto window = Mocks::WindowCreate(m_hInst); m_zoneWindow->MoveWindowIntoZoneByDirection(window, VK_RIGHT, true); - const auto actualAppZoneHistory = m_fancyZonesData.GetAppZoneHistoryMap(); + const auto& actualAppZoneHistory = m_fancyZonesData.GetAppZoneHistoryMap(); Assert::AreEqual((size_t)1, actualAppZoneHistory.size()); - const auto actual = actualAppZoneHistory.begin()->second; - Assert::AreEqual({ 0 }, actual.zoneIndexSet); + const auto& appHistoryArray = actualAppZoneHistory.begin()->second; + Assert::AreEqual((size_t)1, appHistoryArray.size()); + Assert::AreEqual({ 0 }, appHistoryArray[0].zoneIndexSet); } TEST_METHOD(MoveWindowIntoZoneByDirectionManyTimes) @@ -623,10 +624,11 @@ namespace FancyZonesUnitTests m_zoneWindow->MoveWindowIntoZoneByDirection(window, VK_RIGHT, true); m_zoneWindow->MoveWindowIntoZoneByDirection(window, VK_RIGHT, true); - const auto actualAppZoneHistory = m_fancyZonesData.GetAppZoneHistoryMap(); + const auto& actualAppZoneHistory = m_fancyZonesData.GetAppZoneHistoryMap(); Assert::AreEqual((size_t)1, actualAppZoneHistory.size()); - const auto actual = actualAppZoneHistory.begin()->second; - Assert::AreEqual({ 2 }, actual.zoneIndexSet); + const auto& appHistoryArray = actualAppZoneHistory.begin()->second; + Assert::AreEqual((size_t)1, appHistoryArray.size()); + Assert::AreEqual({ 2 }, appHistoryArray[0].zoneIndexSet); } TEST_METHOD(SaveWindowProcessToZoneIndexNoActiveZoneSet) @@ -676,18 +678,22 @@ namespace FancyZonesUnitTests const auto deviceId = m_zoneWindow->UniqueId(); const auto zoneSetId = m_zoneWindow->ActiveZoneSet()->Id(); - //fill app zone history map + // fill app zone history map Assert::IsTrue(m_fancyZonesData.SetAppLastZones(window, deviceId, Helpers::GuidToString(zoneSetId), { 0 })); Assert::AreEqual((size_t)1, m_fancyZonesData.GetAppZoneHistoryMap().size()); - Assert::AreEqual({ 0 }, m_fancyZonesData.GetAppZoneHistoryMap().at(processPath).zoneIndexSet); + const auto& appHistoryArray1 = m_fancyZonesData.GetAppZoneHistoryMap().at(processPath); + Assert::AreEqual((size_t)1, appHistoryArray1.size()); + Assert::AreEqual({ 0 }, appHistoryArray1[0].zoneIndexSet); - //add zone without window + // add zone without window const auto zone = MakeZone(RECT{ 0, 0, 100, 100 }); m_zoneWindow->ActiveZoneSet()->AddZone(zone); m_zoneWindow->SaveWindowProcessToZoneIndex(window); Assert::AreEqual((size_t)1, m_fancyZonesData.GetAppZoneHistoryMap().size()); - Assert::AreEqual({ 0 }, m_fancyZonesData.GetAppZoneHistoryMap().at(processPath).zoneIndexSet); + const auto& appHistoryArray2 = m_fancyZonesData.GetAppZoneHistoryMap().at(processPath); + Assert::AreEqual((size_t)1, appHistoryArray2.size()); + Assert::AreEqual({ 0 }, appHistoryArray2[0].zoneIndexSet); } TEST_METHOD(SaveWindowProcessToZoneIndexWindowAdded) @@ -707,18 +713,20 @@ namespace FancyZonesUnitTests //fill app zone history map Assert::IsTrue(m_fancyZonesData.SetAppLastZones(window, deviceId, Helpers::GuidToString(zoneSetId), { 2 })); Assert::AreEqual((size_t)1, m_fancyZonesData.GetAppZoneHistoryMap().size()); - Assert::AreEqual({ 2 }, m_fancyZonesData.GetAppZoneHistoryMap().at(processPath).zoneIndexSet); + const auto& appHistoryArray = m_fancyZonesData.GetAppZoneHistoryMap().at(processPath); + Assert::AreEqual((size_t)1, appHistoryArray.size()); + Assert::AreEqual({ 2 }, appHistoryArray[0].zoneIndexSet); m_zoneWindow->SaveWindowProcessToZoneIndex(window); - const auto actualAppZoneHistory = m_fancyZonesData.GetAppZoneHistoryMap(); + const auto& actualAppZoneHistory = m_fancyZonesData.GetAppZoneHistoryMap(); Assert::AreEqual((size_t)1, actualAppZoneHistory.size()); - const auto expected = m_zoneWindow->ActiveZoneSet()->GetZoneIndexSetFromWindow(window); - const auto actual = m_fancyZonesData.GetAppZoneHistoryMap().at(processPath).zoneIndexSet; + const auto& expected = m_zoneWindow->ActiveZoneSet()->GetZoneIndexSetFromWindow(window); + const auto& actual = appHistoryArray[0].zoneIndexSet; Assert::AreEqual(expected, actual); } - TEST_METHOD (WhenWindowIsNotResizablePlacingItIntoTheZoneShouldNotResizeIt) + TEST_METHOD(WhenWindowIsNotResizablePlacingItIntoTheZoneShouldNotResizeIt) { m_zoneWindow = InitZoneWindowWithActiveZoneSet(); Assert::IsNotNull(m_zoneWindow->ActiveZoneSet());