From 0d4f3d851e47fb7bf479feb79d9cb4321bcaa5ef Mon Sep 17 00:00:00 2001
From: Jeremy Sinclair <4016293+snickler@users.noreply.github.com>
Date: Thu, 7 Aug 2025 17:28:01 -0700
Subject: [PATCH 1/8] [Deps] Update .NET packages from 9.0.7 to 9.0.8 (#41039)
## Summary of the Pull Request
Updates .NET 9 Runtime / Library packages to the latest 9.0.8 servicing
release.
## PR Checklist
- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx
## Detailed Description of the Pull Request / Additional comments
## Validation Steps Performed
---
Directory.Packages.props | 42 +++++++++----------
NOTICE.md | 42 +++++++++----------
.../Directory.Packages.props | 2 +-
3 files changed, 43 insertions(+), 43 deletions(-)
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 3487098f08..71bbda5042 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -34,22 +34,22 @@
-
+
-
+
-
-
-
-
-
+
+
+
+
+
-
+
-
+
-
+
-
-
-
+
+
+
-
+
-
-
+
+
-
+
-
-
-
-
+
+
+
+
diff --git a/NOTICE.md b/NOTICE.md
index 4dcc82579d..d75fe99522 100644
--- a/NOTICE.md
+++ b/NOTICE.md
@@ -1519,23 +1519,23 @@ SOFTWARE.
- Mages 3.0.0
- Markdig.Signed 0.34.0
- MessagePack 3.1.3
-- Microsoft.Bcl.AsyncInterfaces 9.0.7
+- Microsoft.Bcl.AsyncInterfaces 9.0.8
- Microsoft.Bot.AdaptiveExpressions.Core 4.23.0
- Microsoft.CodeAnalysis.NetAnalyzers 9.0.0
-- Microsoft.Data.Sqlite 9.0.7
+- Microsoft.Data.Sqlite 9.0.8
- Microsoft.Diagnostics.Tracing.TraceEvent 3.1.16
- Microsoft.DotNet.ILCompiler (A)
-- Microsoft.Extensions.DependencyInjection 9.0.7
-- Microsoft.Extensions.Hosting 9.0.7
-- Microsoft.Extensions.Hosting.WindowsServices 9.0.7
-- Microsoft.Extensions.Logging 9.0.7
-- Microsoft.Extensions.Logging.Abstractions 9.0.7
+- Microsoft.Extensions.DependencyInjection 9.0.8
+- Microsoft.Extensions.Hosting 9.0.8
+- Microsoft.Extensions.Hosting.WindowsServices 9.0.8
+- Microsoft.Extensions.Logging 9.0.8
+- Microsoft.Extensions.Logging.Abstractions 9.0.8
- Microsoft.NET.ILLink.Tasks (A)
- Microsoft.SemanticKernel 1.15.0
- Microsoft.Toolkit.Uwp.Notifications 7.1.2
- Microsoft.Web.WebView2 1.0.2903.40
-- Microsoft.Win32.SystemEvents 9.0.7
-- Microsoft.Windows.Compatibility 9.0.7
+- Microsoft.Win32.SystemEvents 9.0.8
+- Microsoft.Windows.Compatibility 9.0.8
- Microsoft.Windows.CsWin32 0.3.183
- Microsoft.Windows.CsWinRT 2.2.0
- Microsoft.Windows.SDK.BuildTools 10.0.26100.4188
@@ -1555,25 +1555,25 @@ SOFTWARE.
- SkiaSharp.Views.WinUI 2.88.9
- StreamJsonRpc 2.21.69
- StyleCop.Analyzers 1.2.0-beta.556
-- System.CodeDom 9.0.7
+- System.CodeDom 9.0.8
- System.CommandLine 2.0.0-beta4.22272.1
-- System.ComponentModel.Composition 9.0.7
-- System.Configuration.ConfigurationManager 9.0.7
-- System.Data.OleDb 9.0.7
+- System.ComponentModel.Composition 9.0.8
+- System.Configuration.ConfigurationManager 9.0.8
+- System.Data.OleDb 9.0.8
- System.Data.SqlClient 4.9.0
-- System.Diagnostics.EventLog 9.0.7
-- System.Diagnostics.PerformanceCounter 9.0.7
-- System.Drawing.Common 9.0.7
+- System.Diagnostics.EventLog 9.0.8
+- System.Diagnostics.PerformanceCounter 9.0.8
+- System.Drawing.Common 9.0.8
- System.IO.Abstractions 22.0.13
- System.IO.Abstractions.TestingHelpers 22.0.13
-- System.Management 9.0.7
+- System.Management 9.0.8
- System.Net.Http 4.3.4
- System.Private.Uri 4.3.2
- System.Reactive 6.0.1
-- System.Runtime.Caching 9.0.7
-- System.ServiceProcess.ServiceController 9.0.7
-- System.Text.Encoding.CodePages 9.0.7
-- System.Text.Json 9.0.7
+- System.Runtime.Caching 9.0.8
+- System.ServiceProcess.ServiceController 9.0.8
+- System.Text.Encoding.CodePages 9.0.8
+- System.Text.Json 9.0.8
- System.Text.RegularExpressions 4.3.1
- UnicodeInformation 2.6.0
- UnitsNet 5.56.0
diff --git a/src/modules/cmdpal/ExtensionTemplate/TemplateCmdPalExtension/Directory.Packages.props b/src/modules/cmdpal/ExtensionTemplate/TemplateCmdPalExtension/Directory.Packages.props
index 664b2d678a..d364f7da8b 100644
--- a/src/modules/cmdpal/ExtensionTemplate/TemplateCmdPalExtension/Directory.Packages.props
+++ b/src/modules/cmdpal/ExtensionTemplate/TemplateCmdPalExtension/Directory.Packages.props
@@ -12,6 +12,6 @@
-
+
From 062234c295339f9fc5c3f63cc89421927b8e9463 Mon Sep 17 00:00:00 2001
From: Kai Tao <69313318+vanzue@users.noreply.github.com>
Date: Fri, 8 Aug 2025 16:38:46 +0800
Subject: [PATCH 2/8] Settings: Mouse utils setting crash (#41050)
## Summary of the Pull Request
Fix a crash in settings page due to not found converter
## AI Summary
This pull request makes a small update to the `MouseUtilsPage.xaml` file
to use the correct resource for converting boolean values to visibility
states in the UI.
- Updated the `Visibility` binding on an `InfoBar` to use the
`ReverseBoolToVisibilityConverter` instead of the incorrect
`BoolToReverseVisibilityConverter` resource.
## PR Checklist
- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx
## Detailed Description of the Pull Request / Additional comments
Regression caused by https://github.com/microsoft/PowerToys/pull/40214
## Validation Steps Performed
---
.../Settings.UI/SettingsXAML/Views/MouseUtilsPage.xaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/settings-ui/Settings.UI/SettingsXAML/Views/MouseUtilsPage.xaml b/src/settings-ui/Settings.UI/SettingsXAML/Views/MouseUtilsPage.xaml
index e8ebc76f66..0ba74ca164 100644
--- a/src/settings-ui/Settings.UI/SettingsXAML/Views/MouseUtilsPage.xaml
+++ b/src/settings-ui/Settings.UI/SettingsXAML/Views/MouseUtilsPage.xaml
@@ -149,7 +149,7 @@
IsClosable="False"
IsOpen="True"
Severity="Informational"
- Visibility="{x:Bind ViewModel.IsAnimationEnabledBySystem, Mode=OneWay, Converter={StaticResource BoolToReverseVisibilityConverter}}">
+ Visibility="{x:Bind ViewModel.IsAnimationEnabledBySystem, Mode=OneWay, Converter={StaticResource ReverseBoolToVisibilityConverter}}">
From d72e0ab20d6ca3738b63d087e47525ada66df606 Mon Sep 17 00:00:00 2001
From: Shawn Yuan <128874481+shuaiyuanxx@users.noreply.github.com>
Date: Fri, 8 Aug 2025 22:55:00 +0800
Subject: [PATCH 3/8] Fixed toggle switch not working issue. (#41049)
## Summary of the Pull Request
Fixed toggle switch not working issue.
## AI Summary
This pull request refactors how `DashboardListItem` objects are created
and added to collections in the `DashboardViewModel`. The main
improvement is to separate the instantiation of each `DashboardListItem`
from the assignment of its `EnabledChangedCallback` property, which is
now set after the object is added to the relevant collection. This
change improves clarity and may help prevent issues related to object
initialization order.
Refactoring of `DashboardListItem` creation and initialization:
* In the `AddDashboardListItem` method, the `DashboardListItem` object
is now created and added to `AllModules` before its
`EnabledChangedCallback` property is set, instead of setting this
property during object initialization.
* In the `GetShortcutModules` method, both `ShortcutModules` and
`ActionModules` collections now receive `DashboardListItem` objects that
are instantiated first, added to the collection, and then have their
`EnabledChangedCallback` property set. This replaces the previous
pattern of setting the callback during object creation.
[[1]](diffhunk://#diff-aea3404667e7a3de2750bf9ab7ee8ff5e717892caa68ee1de86713cf8e21b44cL123-R136)
[[2]](diffhunk://#diff-aea3404667e7a3de2750bf9ab7ee8ff5e717892caa68ee1de86713cf8e21b44cL144-R159)
*
## PR Checklist
- [x] Closes: #41046
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx
## Detailed Description of the Pull Request / Additional comments
It is an regression from
https://github.com/microsoft/PowerToys/pull/40214
## Validation Steps Performed
---------
Signed-off-by: Shuai Yuan
---
.../ViewModels/DashboardViewModel.cs | 24 ++++++++++++-------
1 file changed, 15 insertions(+), 9 deletions(-)
diff --git a/src/settings-ui/Settings.UI/ViewModels/DashboardViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/DashboardViewModel.cs
index 6e2bb2d432..8dd97c85fa 100644
--- a/src/settings-ui/Settings.UI/ViewModels/DashboardViewModel.cs
+++ b/src/settings-ui/Settings.UI/ViewModels/DashboardViewModel.cs
@@ -69,16 +69,18 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
private void AddDashboardListItem(ModuleType moduleType)
{
GpoRuleConfigured gpo = ModuleHelper.GetModuleGpoConfiguration(moduleType);
- AllModules.Add(new DashboardListItem()
+ var newItem = new DashboardListItem()
{
Tag = moduleType,
Label = resourceLoader.GetString(ModuleHelper.GetModuleLabelResourceName(moduleType)),
IsEnabled = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && ModuleHelper.GetIsModuleEnabled(generalSettingsConfig, moduleType)),
IsLocked = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled,
Icon = ModuleHelper.GetModuleTypeFluentIconName(moduleType),
- EnabledChangedCallback = EnabledChangedOnUI,
DashboardModuleItems = GetModuleItems(moduleType),
- });
+ };
+
+ AllModules.Add(newItem);
+ newItem.EnabledChangedCallback = EnabledChangedOnUI;
}
private void EnabledChangedOnUI(DashboardListItem dashboardListItem)
@@ -120,16 +122,18 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
if (filteredItems.Count != 0)
{
- ShortcutModules.Add(new DashboardListItem
+ var newItem = new DashboardListItem
{
- EnabledChangedCallback = x.EnabledChangedCallback,
Icon = x.Icon,
IsLocked = x.IsLocked,
Label = x.Label,
Tag = x.Tag,
IsEnabled = x.IsEnabled,
DashboardModuleItems = new ObservableCollection(filteredItems),
- });
+ };
+
+ ShortcutModules.Add(newItem);
+ newItem.EnabledChangedCallback = x.EnabledChangedCallback;
}
}
@@ -141,16 +145,18 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
if (filteredItems.Count != 0)
{
- ActionModules.Add(new DashboardListItem
+ var newItem = new DashboardListItem
{
- EnabledChangedCallback = x.EnabledChangedCallback,
Icon = x.Icon,
IsLocked = x.IsLocked,
Label = x.Label,
Tag = x.Tag,
IsEnabled = x.IsEnabled,
DashboardModuleItems = new ObservableCollection(filteredItems),
- });
+ };
+
+ ActionModules.Add(newItem);
+ newItem.EnabledChangedCallback = x.EnabledChangedCallback;
}
}
}
From 04b8234192593d7a0efe2801d657dc85a8db1e79 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ji=C5=99=C3=AD=20Pol=C3=A1=C5=A1ek?=
Date: Tue, 12 Aug 2025 01:12:05 +0200
Subject: [PATCH 4/8] CmdPal: Fix styles applied to MoreCommandsButton (#41059)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## Summary of the Pull Request
- Apply the same padding to the button as used for primary and secondary
command buttons.
- Use consistent spacing between keycap blocks.
- Match keycap border style and inner text brush with other command
buttons.
- Add min width constraint to shortcut keycap element to make it at
least square.
## PR Checklist
- [x] Closes: #41052
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx
## Detailed Description of the Pull Request / Additional comments
## Validation Steps Performed
👀
---
.../Controls/CommandBar.xaml | 68 +++++++------------
1 file changed, 25 insertions(+), 43 deletions(-)
diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI/Controls/CommandBar.xaml b/src/modules/cmdpal/Microsoft.CmdPal.UI/Controls/CommandBar.xaml
index 9fb047641f..107db49939 100644
--- a/src/modules/cmdpal/Microsoft.CmdPal.UI/Controls/CommandBar.xaml
+++ b/src/modules/cmdpal/Microsoft.CmdPal.UI/Controls/CommandBar.xaml
@@ -59,8 +59,24 @@
+
+
+
+
+
@@ -155,12 +171,7 @@
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind ViewModel.PrimaryCommand.Name, Mode=OneWay}" />
-
+
@@ -179,19 +190,10 @@
Text="{x:Bind ViewModel.SecondaryCommand.Name, Mode=OneWay}" />
-
+
-
+
@@ -199,7 +201,7 @@
-
-
-
+
+
+
-
-
+
+
From bc134b344bcc0e2aeddaa629233423099fac6a7a Mon Sep 17 00:00:00 2001
From: Mike Griese
Date: Mon, 11 Aug 2025 18:43:08 -0500
Subject: [PATCH 5/8] CmdPal: Make sure to include apps in the ctor (#41081)
A regression from #40132
We need to set the value of `_includeApps` in the `MainListPage` ctor.
Without it, if the user doesn't have any extensions installed, the value
is never updated.
---
.../Microsoft.CmdPal.UI.ViewModels/Commands/MainListPage.cs | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Commands/MainListPage.cs b/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Commands/MainListPage.cs
index 71c0a4e810..f877afa9c5 100644
--- a/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Commands/MainListPage.cs
+++ b/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Commands/MainListPage.cs
@@ -60,6 +60,7 @@ public partial class MainListPage : DynamicListPage,
var settings = _serviceProvider.GetService()!;
settings.SettingsChanged += SettingsChangedHandler;
HotReloadSettings(settings);
+ _includeApps = _tlcManager.IsProviderActive(AllAppsCommandProvider.WellKnownId);
IsLoading = true;
}
From 1eae1d9a12e8c7c33cd864da4799ea4c1d6f2001 Mon Sep 17 00:00:00 2001
From: Yu Leng <42196638+moooyo@users.noreply.github.com>
Date: Tue, 12 Aug 2025 07:44:23 +0800
Subject: [PATCH 6/8] [AOT] Remove rd.xml from CmdPal (#41031)
## Summary of the Pull Request
Actually, we don't need to use rd.xml to preserve type. We can add
attribute to do the same things.
Tested in this build:
https://microsoft.visualstudio.com/Dart/_build/results?buildId=127875892&view=artifacts&pathAsName=false&type=publishedArtifacts
## PR Checklist
- [x] Closes: #40633
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx
## Detailed Description of the Pull Request / Additional comments
## Validation Steps Performed
---------
Co-authored-by: Yu Leng (from Dev Box)
---
.../CommandContextItemViewModel.cs | 3 ++
.../CommandItemViewModel.cs | 2 +
.../IContextItemViewModel.cs | 2 +
.../SeparatorContextItemViewModel.cs | 2 +
.../cmdpal/Microsoft.CmdPal.UI/App.xaml.cs | 3 ++
.../Converters/ContextItemTemplateSelector.cs | 2 +
.../Microsoft.CmdPal.UI.csproj | 4 --
.../Microsoft.CmdPal.UI/TypePreservation.cs | 40 +++++++++++++++++++
src/modules/cmdpal/Microsoft.CmdPal.UI/rd.xml | 23 -----------
9 files changed, 54 insertions(+), 27 deletions(-)
create mode 100644 src/modules/cmdpal/Microsoft.CmdPal.UI/TypePreservation.cs
delete mode 100644 src/modules/cmdpal/Microsoft.CmdPal.UI/rd.xml
diff --git a/src/modules/cmdpal/Microsoft.CmdPal.Core.ViewModels/CommandContextItemViewModel.cs b/src/modules/cmdpal/Microsoft.CmdPal.Core.ViewModels/CommandContextItemViewModel.cs
index 60fc815a52..f2060efe88 100644
--- a/src/modules/cmdpal/Microsoft.CmdPal.Core.ViewModels/CommandContextItemViewModel.cs
+++ b/src/modules/cmdpal/Microsoft.CmdPal.Core.ViewModels/CommandContextItemViewModel.cs
@@ -2,11 +2,14 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Diagnostics.CodeAnalysis;
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
+using Microsoft.CommandPalette.Extensions.Toolkit;
namespace Microsoft.CmdPal.Core.ViewModels;
+[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
public partial class CommandContextItemViewModel(ICommandContextItem contextItem, WeakReference context) : CommandItemViewModel(new(contextItem), context), IContextItemViewModel
{
private readonly KeyChord nullKeyChord = new(0, 0, 0);
diff --git a/src/modules/cmdpal/Microsoft.CmdPal.Core.ViewModels/CommandItemViewModel.cs b/src/modules/cmdpal/Microsoft.CmdPal.Core.ViewModels/CommandItemViewModel.cs
index 1861b53ef7..1b9dcf211a 100644
--- a/src/modules/cmdpal/Microsoft.CmdPal.Core.ViewModels/CommandItemViewModel.cs
+++ b/src/modules/cmdpal/Microsoft.CmdPal.Core.ViewModels/CommandItemViewModel.cs
@@ -2,6 +2,7 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Diagnostics.CodeAnalysis;
using Microsoft.CmdPal.Core.ViewModels.Messages;
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
@@ -9,6 +10,7 @@ using Microsoft.CommandPalette.Extensions.Toolkit;
namespace Microsoft.CmdPal.Core.ViewModels;
+[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBarContext
{
public ExtensionObject Model => _commandItemModel;
diff --git a/src/modules/cmdpal/Microsoft.CmdPal.Core.ViewModels/IContextItemViewModel.cs b/src/modules/cmdpal/Microsoft.CmdPal.Core.ViewModels/IContextItemViewModel.cs
index 704947c3a8..cad1af9d4d 100644
--- a/src/modules/cmdpal/Microsoft.CmdPal.Core.ViewModels/IContextItemViewModel.cs
+++ b/src/modules/cmdpal/Microsoft.CmdPal.Core.ViewModels/IContextItemViewModel.cs
@@ -4,12 +4,14 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.CmdPal.Core.ViewModels;
+[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
public interface IContextItemViewModel
{
}
diff --git a/src/modules/cmdpal/Microsoft.CmdPal.Core.ViewModels/SeparatorContextItemViewModel.cs b/src/modules/cmdpal/Microsoft.CmdPal.Core.ViewModels/SeparatorContextItemViewModel.cs
index c6858f490d..8d896bd341 100644
--- a/src/modules/cmdpal/Microsoft.CmdPal.Core.ViewModels/SeparatorContextItemViewModel.cs
+++ b/src/modules/cmdpal/Microsoft.CmdPal.Core.ViewModels/SeparatorContextItemViewModel.cs
@@ -2,11 +2,13 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Diagnostics.CodeAnalysis;
using Microsoft.CmdPal.Core.ViewModels;
using Microsoft.CommandPalette.Extensions;
namespace Microsoft.CmdPal.Core.ViewModels;
+[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
public partial class SeparatorContextItemViewModel() : IContextItemViewModel, ISeparatorContextItem
{
}
diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI/App.xaml.cs b/src/modules/cmdpal/Microsoft.CmdPal.UI/App.xaml.cs
index 03b40bf8d8..ec3604621d 100644
--- a/src/modules/cmdpal/Microsoft.CmdPal.UI/App.xaml.cs
+++ b/src/modules/cmdpal/Microsoft.CmdPal.UI/App.xaml.cs
@@ -64,6 +64,9 @@ public partial class App : Application
this.InitializeComponent();
+ // Ensure types used in XAML are preserved for AOT compilation
+ TypePreservation.PreserveTypes();
+
NativeEventWaiter.WaitForEventLoop(
"Local\\PowerToysCmdPal-ExitEvent-eb73f6be-3f22-4b36-aee3-62924ba40bfd", () =>
{
diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI/Converters/ContextItemTemplateSelector.cs b/src/modules/cmdpal/Microsoft.CmdPal.UI/Converters/ContextItemTemplateSelector.cs
index aec50163db..3ab4dd1c0b 100644
--- a/src/modules/cmdpal/Microsoft.CmdPal.UI/Converters/ContextItemTemplateSelector.cs
+++ b/src/modules/cmdpal/Microsoft.CmdPal.UI/Converters/ContextItemTemplateSelector.cs
@@ -2,6 +2,7 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Diagnostics.CodeAnalysis;
using Microsoft.CmdPal.Core.ViewModels;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
@@ -10,6 +11,7 @@ using Microsoft.UI.Xaml.Data;
namespace Microsoft.CmdPal.UI;
+[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
internal sealed partial class ContextItemTemplateSelector : DataTemplateSelector
{
public DataTemplate? Default { get; set; }
diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI/Microsoft.CmdPal.UI.csproj b/src/modules/cmdpal/Microsoft.CmdPal.UI/Microsoft.CmdPal.UI.csproj
index 44ef3483e2..97ad65dddd 100644
--- a/src/modules/cmdpal/Microsoft.CmdPal.UI/Microsoft.CmdPal.UI.csproj
+++ b/src/modules/cmdpal/Microsoft.CmdPal.UI/Microsoft.CmdPal.UI.csproj
@@ -109,10 +109,6 @@
-
-
-
-
diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI/TypePreservation.cs b/src/modules/cmdpal/Microsoft.CmdPal.UI/TypePreservation.cs
new file mode 100644
index 0000000000..c358c708ae
--- /dev/null
+++ b/src/modules/cmdpal/Microsoft.CmdPal.UI/TypePreservation.cs
@@ -0,0 +1,40 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics.CodeAnalysis;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+
+namespace Microsoft.CmdPal.UI;
+
+///
+/// This class ensures types used in XAML are preserved during AOT compilation.
+/// Framework types cannot have attributes added directly to their definitions since they're external types.
+/// Application types that require runtime type checking should also be preserved here if needed.
+///
+internal static class TypePreservation
+{
+ ///
+ /// This method ensures critical types are preserved for AOT compilation.
+ /// These types are used dynamically in XAML and would otherwise be trimmed.
+ ///
+ [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(Microsoft.UI.Xaml.Controls.FontIconSource))]
+ [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(Microsoft.UI.Xaml.Controls.PathIcon))]
+ [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(Microsoft.UI.Xaml.DataTemplate))]
+ [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(Microsoft.UI.Xaml.Controls.DataTemplateSelector))]
+ [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(Microsoft.UI.Xaml.Controls.ListViewItem))]
+ public static void PreserveTypes()
+ {
+ // This method exists only to hold the DynamicDependency attributes above.
+ // It must be called to ensure the types are not trimmed during AOT compilation.
+
+ // Note: We cannot add [DynamicallyAccessedMembers] directly to framework types
+ // since we don't own their source code. DynamicDependency is the correct approach
+ // for preserving external types that are used dynamically (e.g., in XAML).
+
+ // For application types that require runtime type checking (e.g., in template selectors),
+ // prefer adding [DynamicallyAccessedMembers] attributes directly on the type definitions.
+ // Only use DynamicDependency here for types we cannot modify directly.
+ }
+}
diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI/rd.xml b/src/modules/cmdpal/Microsoft.CmdPal.UI/rd.xml
deleted file mode 100644
index 86331f360d..0000000000
--- a/src/modules/cmdpal/Microsoft.CmdPal.UI/rd.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
From 3682f186e3596b1e62fe9f1f331f28f74fc66830 Mon Sep 17 00:00:00 2001
From: Kai Tao <69313318+vanzue@users.noreply.github.com>
Date: Tue, 12 Aug 2025 10:55:24 +0800
Subject: [PATCH 7/8] Mouse highlighter spotlight mode, fix the gpu perf issue
(#41079)
## Summary of the Pull Request
The big border solution for implementing the spotlight mode is gpu
consuming, switch to a resource friendly implementation.
## PR Checklist
- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx
## Detailed Description of the Pull Request / Additional comments
## Validation Steps Performed
| Before | After |
|----------|----------|
|
|
|
---
.../MouseHighlighter/MouseHighlighter.cpp | 120 +++++++++++++++---
1 file changed, 100 insertions(+), 20 deletions(-)
diff --git a/src/modules/MouseUtils/MouseHighlighter/MouseHighlighter.cpp b/src/modules/MouseUtils/MouseHighlighter/MouseHighlighter.cpp
index 25a95f4d39..05670742ec 100644
--- a/src/modules/MouseUtils/MouseHighlighter/MouseHighlighter.cpp
+++ b/src/modules/MouseUtils/MouseHighlighter/MouseHighlighter.cpp
@@ -5,6 +5,7 @@
#include "MouseHighlighter.h"
#include "trace.h"
#include
+#include
#ifdef COMPOSITION
namespace winrt
@@ -49,6 +50,9 @@ private:
void BringToFront();
HHOOK m_mouseHook = NULL;
static LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) noexcept;
+ // Helpers for spotlight overlay
+ float GetDpiScale() const;
+ void UpdateSpotlightMask(float cx, float cy, float radius, bool show);
static constexpr auto m_className = L"MouseHighlighter";
static constexpr auto m_windowTitle = L"PowerToys Mouse Highlighter";
@@ -67,7 +71,14 @@ private:
winrt::CompositionSpriteShape m_leftPointer{ nullptr };
winrt::CompositionSpriteShape m_rightPointer{ nullptr };
winrt::CompositionSpriteShape m_alwaysPointer{ nullptr };
- winrt::CompositionSpriteShape m_spotlightPointer{ nullptr };
+ // Spotlight overlay (mask with soft feathered edge)
+ winrt::SpriteVisual m_overlay{ nullptr };
+ winrt::CompositionMaskBrush m_spotlightMask{ nullptr };
+ winrt::CompositionRadialGradientBrush m_spotlightMaskGradient{ nullptr };
+ winrt::CompositionColorBrush m_spotlightSource{ nullptr };
+ winrt::CompositionColorGradientStop m_maskStopCenter{ nullptr };
+ winrt::CompositionColorGradientStop m_maskStopInner{ nullptr };
+ winrt::CompositionColorGradientStop m_maskStopOuter{ nullptr };
bool m_leftPointerEnabled = true;
bool m_rightPointerEnabled = true;
@@ -123,6 +134,35 @@ bool Highlighter::CreateHighlighter()
m_shape.RelativeSizeAdjustment({ 1.0f, 1.0f });
m_root.Children().InsertAtTop(m_shape);
+ // Create spotlight overlay (soft feather, DPI-aware)
+ m_overlay = m_compositor.CreateSpriteVisual();
+ m_overlay.RelativeSizeAdjustment({ 1.0f, 1.0f });
+ m_spotlightSource = m_compositor.CreateColorBrush(m_alwaysColor);
+ m_spotlightMaskGradient = m_compositor.CreateRadialGradientBrush();
+ m_spotlightMaskGradient.MappingMode(winrt::CompositionMappingMode::Absolute);
+ // Center region fully transparent
+ m_maskStopCenter = m_compositor.CreateColorGradientStop();
+ m_maskStopCenter.Offset(0.0f);
+ m_maskStopCenter.Color(winrt::Windows::UI::ColorHelper::FromArgb(0, 0, 0, 0));
+ // Inner edge of feather (still transparent)
+ m_maskStopInner = m_compositor.CreateColorGradientStop();
+ m_maskStopInner.Offset(0.995f); // will be updated per-radius
+ m_maskStopInner.Color(winrt::Windows::UI::ColorHelper::FromArgb(0, 0, 0, 0));
+ // Outer edge (opaque mask -> overlay visible)
+ m_maskStopOuter = m_compositor.CreateColorGradientStop();
+ m_maskStopOuter.Offset(1.0f);
+ m_maskStopOuter.Color(winrt::Windows::UI::ColorHelper::FromArgb(255, 255, 255, 255));
+ m_spotlightMaskGradient.ColorStops().Append(m_maskStopCenter);
+ m_spotlightMaskGradient.ColorStops().Append(m_maskStopInner);
+ m_spotlightMaskGradient.ColorStops().Append(m_maskStopOuter);
+
+ m_spotlightMask = m_compositor.CreateMaskBrush();
+ m_spotlightMask.Source(m_spotlightSource);
+ m_spotlightMask.Mask(m_spotlightMaskGradient);
+ m_overlay.Brush(m_spotlightMask);
+ m_overlay.IsVisible(false);
+ m_root.Children().InsertAtTop(m_overlay);
+
return true;
}
catch (...)
@@ -165,12 +205,8 @@ void Highlighter::AddDrawingPoint(MouseButton button)
// always
if (m_spotlightMode)
{
- float borderThickness = static_cast(std::hypot(GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN)));
- circleGeometry.Radius({ static_cast(borderThickness / 2.0 + m_radius), static_cast(borderThickness / 2.0 + m_radius) });
- circleShape.FillBrush(nullptr);
- circleShape.StrokeBrush(m_compositor.CreateColorBrush(m_alwaysColor));
- circleShape.StrokeThickness(borderThickness);
- m_spotlightPointer = circleShape;
+ UpdateSpotlightMask(static_cast(pt.x), static_cast(pt.y), m_radius, true);
+ return;
}
else
{
@@ -209,20 +245,14 @@ void Highlighter::UpdateDrawingPointPosition(MouseButton button)
}
else
{
- // always
+ // always / spotlight idle
if (m_spotlightMode)
{
- if (m_spotlightPointer)
- {
- m_spotlightPointer.Offset({ static_cast(pt.x), static_cast(pt.y) });
- }
+ UpdateSpotlightMask(static_cast(pt.x), static_cast(pt.y), m_radius, true);
}
- else
+ else if (m_alwaysPointer)
{
- if (m_alwaysPointer)
- {
- m_alwaysPointer.Offset({ static_cast(pt.x), static_cast(pt.y) });
- }
+ m_alwaysPointer.Offset({ static_cast(pt.x), static_cast(pt.y) });
}
}
}
@@ -266,9 +296,9 @@ void Highlighter::ClearDrawingPoint()
{
if (m_spotlightMode)
{
- if (m_spotlightPointer)
+ if (m_overlay)
{
- m_spotlightPointer.StrokeBrush().as().Color(winrt::Windows::UI::ColorHelper::FromArgb(0, 0, 0, 0));
+ m_overlay.IsVisible(false);
}
}
else
@@ -421,7 +451,10 @@ void Highlighter::StopDrawing()
m_leftPointer = nullptr;
m_rightPointer = nullptr;
m_alwaysPointer = nullptr;
- m_spotlightPointer = nullptr;
+ if (m_overlay)
+ {
+ m_overlay.IsVisible(false);
+ }
ShowWindow(m_hwnd, SW_HIDE);
UnhookWindowsHookEx(m_mouseHook);
ClearDrawing();
@@ -452,6 +485,16 @@ void Highlighter::ApplySettings(MouseHighlighterSettings settings)
m_rightPointerEnabled = false;
}
+ // Keep spotlight overlay color updated
+ if (m_spotlightSource)
+ {
+ m_spotlightSource.Color(m_alwaysColor);
+ }
+ if (!m_spotlightMode && m_overlay)
+ {
+ m_overlay.IsVisible(false);
+ }
+
if (instance->m_visible)
{
instance->StopDrawing();
@@ -563,6 +606,43 @@ void Highlighter::Terminate()
}
}
+float Highlighter::GetDpiScale() const
+{
+ return static_cast(GetDpiForWindow(m_hwnd)) / 96.0f;
+}
+
+// Update spotlight radial mask center/radius with DPI-aware feather
+void Highlighter::UpdateSpotlightMask(float cx, float cy, float radius, bool show)
+{
+ if (!m_spotlightMaskGradient)
+ {
+ return;
+ }
+
+ m_spotlightMaskGradient.EllipseCenter({ cx, cy });
+ m_spotlightMaskGradient.EllipseRadius({ radius, radius });
+
+ const float dpiScale = GetDpiScale();
+ // Target a very fine edge: ~1 physical pixel, convert to DIPs: 1 / dpiScale
+ const float featherDip = 1.0f / (dpiScale > 0.0f ? dpiScale : 1.0f);
+ const float safeRadius = (std::max)(radius, 1.0f);
+ const float featherRel = (std::min)(0.25f, featherDip / safeRadius);
+
+ if (m_maskStopInner)
+ {
+ m_maskStopInner.Offset((std::max)(0.0f, 1.0f - featherRel));
+ }
+
+ if (m_spotlightSource)
+ {
+ m_spotlightSource.Color(m_alwaysColor);
+ }
+ if (m_overlay)
+ {
+ m_overlay.IsVisible(show);
+ }
+}
+
#pragma region MouseHighlighter_API
void MouseHighlighterApplySettings(MouseHighlighterSettings settings)
From c23dcb0c5aec2e08d652049187c9fa552d0d73bc Mon Sep 17 00:00:00 2001
From: Yu Leng <42196638+moooyo@users.noreply.github.com>
Date: Tue, 12 Aug 2025 18:27:10 +0800
Subject: [PATCH 8/8] [CmdPal][UT] Refactor some cmdpal ext's ut and improve
the test case (#40896)
## Summary of the Pull Request
1. Remove some AI generated nonsense case
2. Add ISettingsInterface for those ext for testing purpose.
3. Add query test.
## PR Checklist
- [x] Closes: #40897
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx
## Detailed Description of the Pull Request / Additional comments
## Validation Steps Performed
---------
Co-authored-by: Yu Leng
---
.../ExtendedCalculatorParserTests.cs | 21 +-
...Microsoft.CmdPal.Ext.Calc.UnitTests.csproj | 1 +
.../QueryTests.cs | 86 ++++++
.../Settings.cs | 35 +++
.../SettingsManagerTests.cs | 55 ++++
...osoft.CmdPal.Ext.Registry.UnitTests.csproj | 1 +
.../QueryTests.cs | 74 +++++
.../Settings.cs | 15 +
.../QueryTests.cs | 8 +-
.../AvailableResultsListTests.cs | 10 +-
.../BasicTests.cs | 28 --
.../FallbackTimeDateItemTests.cs | 26 +-
.../IconTests.cs | 127 ---------
...osoft.CmdPal.Ext.TimeDate.UnitTests.csproj | 1 +
.../QueryTests.cs | 268 +++++-------------
.../Settings.cs | 46 +++
.../SettingsManagerTests.cs | 85 ------
...t.CmdPal.Ext.WindowWalker.UnitTests.csproj | 1 +
.../PluginSettingsTests.cs | 60 ----
.../Settings.cs | 60 ++++
.../CalculatorCommandProvider.cs | 6 +-
.../Helper/CalculateEngine.cs | 2 +-
.../Helper/ISettingsInterface.cs | 18 ++
.../Helper/QueryHelper.cs | 2 +-
.../Helper/ResultHelper.cs | 2 +-
.../Helper/SettingsManager.cs | 2 +-
.../Pages/CalculatorListPage.cs | 4 +-
.../Pages/FallbackCalculatorItem.cs | 4 +-
.../Helpers/ISettingsInterface.cs | 17 ++
.../Helpers/SettingsManager.cs | 37 +++
.../Pages/RegistryListPage.cs | 4 +-
.../RegistryCommandsProvider.cs | 5 +-
.../FallbackTimeDateItem.cs | 4 +-
.../Helpers/AvailableResultsList.cs | 2 +-
.../Helpers/ISettingsInterface.cs | 26 ++
.../Helpers/SettingsManager.cs | 2 +-
.../Helpers/TimeDateCalculator.cs | 2 +-
.../Pages/TimeDateExtensionPage.cs | 4 +-
.../TimeDateCommandsProvider.cs | 2 +-
.../Helpers/ISettingsInterface.cs | 26 ++
.../Helpers/SettingsManager.cs | 2 +-
41 files changed, 639 insertions(+), 542 deletions(-)
create mode 100644 src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.Calc.UnitTests/QueryTests.cs
create mode 100644 src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.Calc.UnitTests/Settings.cs
create mode 100644 src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.Calc.UnitTests/SettingsManagerTests.cs
create mode 100644 src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.Registry.UnitTests/QueryTests.cs
create mode 100644 src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.Registry.UnitTests/Settings.cs
delete mode 100644 src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.TimeDate.UnitTests/BasicTests.cs
delete mode 100644 src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.TimeDate.UnitTests/IconTests.cs
create mode 100644 src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.TimeDate.UnitTests/Settings.cs
delete mode 100644 src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.TimeDate.UnitTests/SettingsManagerTests.cs
delete mode 100644 src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.WindowWalker.UnitTests/PluginSettingsTests.cs
create mode 100644 src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.WindowWalker.UnitTests/Settings.cs
create mode 100644 src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Calc/Helper/ISettingsInterface.cs
create mode 100644 src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Registry/Helpers/ISettingsInterface.cs
create mode 100644 src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Registry/Helpers/SettingsManager.cs
create mode 100644 src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.TimeDate/Helpers/ISettingsInterface.cs
create mode 100644 src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowWalker/Helpers/ISettingsInterface.cs
diff --git a/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.Calc.UnitTests/ExtendedCalculatorParserTests.cs b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.Calc.UnitTests/ExtendedCalculatorParserTests.cs
index e5929de717..b631f59be7 100644
--- a/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.Calc.UnitTests/ExtendedCalculatorParserTests.cs
+++ b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.Calc.UnitTests/ExtendedCalculatorParserTests.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Microsoft Corporation
+// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
@@ -6,12 +6,15 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using Microsoft.CmdPal.Ext.Calc.Helper;
+using Microsoft.CmdPal.Ext.UnitTestBase;
+using Microsoft.CommandPalette.Extensions;
+using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Microsoft.CmdPal.Ext.Calc.UnitTests;
[TestClass]
-public class ExtendedCalculatorParserTests
+public class ExtendedCalculatorParserTests : CommandPaletteUnitTestBase
{
[DataTestMethod]
[DataRow(null)]
@@ -28,7 +31,7 @@ public class ExtendedCalculatorParserTests
[DataRow("[10,10]")] // '[10,10]' is interpreted as array by mages engine
public void Interpret_NoResult_WhenCalled(string input)
{
- var settings = new SettingsManager();
+ var settings = new Settings();
var result = CalculateEngine.Interpret(settings, input, CultureInfo.CurrentCulture, out _);
@@ -68,7 +71,7 @@ public class ExtendedCalculatorParserTests
[DynamicData(nameof(Interpret_NoErrors_WhenCalledWithRounding_Data))]
public void Interpret_NoErrors_WhenCalledWithRounding(string input, decimal expectedResult)
{
- var settings = new SettingsManager();
+ var settings = new Settings();
// Act
// Using InvariantCulture since this is internal
@@ -90,7 +93,7 @@ public class ExtendedCalculatorParserTests
public void Interpret_GreaterPrecision_WhenCalled(string input, decimal expectedResult)
{
// Arrange
- var settings = new SettingsManager();
+ var settings = new Settings();
// Act
// Using InvariantCulture since this is internal
@@ -114,7 +117,7 @@ public class ExtendedCalculatorParserTests
{
// Arrange
var cultureInfo = CultureInfo.GetCultureInfo(cultureName);
- var settings = new SettingsManager();
+ var settings = new Settings();
// Act
var result = CalculateEngine.Interpret(settings, input, cultureInfo, out _);
@@ -175,7 +178,7 @@ public class ExtendedCalculatorParserTests
public void Interpret_MustReturnResult_WhenResultIsZero(string input)
{
// Arrange
- var settings = new SettingsManager();
+ var settings = new Settings();
// Act
// Using InvariantCulture since this is internal
@@ -203,7 +206,7 @@ public class ExtendedCalculatorParserTests
public void Interpret_MustReturnExpectedResult_WhenCalled(string input, decimal expectedResult)
{
// Arrange
- var settings = new SettingsManager();
+ var settings = new Settings();
// Act
// Using en-us culture to have a fixed number style
@@ -226,7 +229,7 @@ public class ExtendedCalculatorParserTests
{
// Arrange
var translator = NumberTranslator.Create(new CultureInfo(sourceCultureName, false), new CultureInfo("en-US", false));
- var settings = new SettingsManager();
+ var settings = new Settings();
// Act
// Using en-us culture to have a fixed number style
diff --git a/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.Calc.UnitTests/Microsoft.CmdPal.Ext.Calc.UnitTests.csproj b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.Calc.UnitTests/Microsoft.CmdPal.Ext.Calc.UnitTests.csproj
index 7144678183..d3f9adeeab 100644
--- a/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.Calc.UnitTests/Microsoft.CmdPal.Ext.Calc.UnitTests.csproj
+++ b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.Calc.UnitTests/Microsoft.CmdPal.Ext.Calc.UnitTests.csproj
@@ -14,5 +14,6 @@
+
\ No newline at end of file
diff --git a/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.Calc.UnitTests/QueryTests.cs b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.Calc.UnitTests/QueryTests.cs
new file mode 100644
index 0000000000..73927849a1
--- /dev/null
+++ b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.Calc.UnitTests/QueryTests.cs
@@ -0,0 +1,86 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Linq;
+using Microsoft.CmdPal.Ext.Calc.Helper;
+using Microsoft.CmdPal.Ext.Calc.Pages;
+using Microsoft.CmdPal.Ext.UnitTestBase;
+using Microsoft.CommandPalette.Extensions.Toolkit;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace Microsoft.CmdPal.Ext.Calc.UnitTests;
+
+[TestClass]
+public class QueryTests : CommandPaletteUnitTestBase
+{
+ [DataTestMethod]
+ [DataRow("2+2", "4")]
+ [DataRow("5*3", "15")]
+ [DataRow("10/2", "5")]
+ [DataRow("sqrt(16)", "4")]
+ [DataRow("2^3", "8")]
+ public void TopLevelPageQueryTest(string input, string expectedResult)
+ {
+ var settings = new Settings();
+ var page = new CalculatorListPage(settings);
+
+ // Simulate query execution
+ page.UpdateSearchText(string.Empty, input);
+ var result = page.GetItems();
+
+ Assert.IsTrue(result.Length == 1, "Valid input should always return result");
+
+ var firstResult = result.FirstOrDefault();
+
+ Assert.IsNotNull(result);
+ Assert.IsTrue(
+ firstResult.Title.Contains(expectedResult),
+ $"Expected result to contain '{expectedResult}' but got '{firstResult.Title}'");
+ }
+
+ [TestMethod]
+ public void EmptyQueryTest()
+ {
+ var settings = new Settings();
+ var page = new CalculatorListPage(settings);
+ page.UpdateSearchText("abc", string.Empty);
+ var results = page.GetItems();
+ Assert.IsNotNull(results);
+
+ var firstItem = results.FirstOrDefault();
+ Assert.AreEqual("Type an equation...", firstItem.Title);
+ }
+
+ [TestMethod]
+ public void InvalidExpressionTest()
+ {
+ var settings = new Settings();
+
+ var page = new CalculatorListPage(settings);
+
+ // Simulate query execution
+ page.UpdateSearchText(string.Empty, "invalid expression");
+ var result = page.GetItems().FirstOrDefault();
+
+ Assert.AreEqual("Type an equation...", result.Title);
+ }
+
+ [DataTestMethod]
+ [DataRow("sin(60)", "-0.30481", CalculateEngine.TrigMode.Radians)]
+ [DataRow("sin(60)", "0.866025", CalculateEngine.TrigMode.Degrees)]
+ [DataRow("sin(60)", "0.809016", CalculateEngine.TrigMode.Gradians)]
+ public void TrigModeSettingsTest(string input, string expected, CalculateEngine.TrigMode trigMode)
+ {
+ var settings = new Settings(trigUnit: trigMode);
+
+ var page = new CalculatorListPage(settings);
+
+ page.UpdateSearchText(string.Empty, input);
+ var result = page.GetItems().FirstOrDefault();
+
+ Assert.IsNotNull(result);
+
+ Assert.IsTrue(result.Title.Contains(expected, System.StringComparison.Ordinal), $"Calc trigMode convert result isn't correct. Current result: {result.Title}");
+ }
+}
diff --git a/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.Calc.UnitTests/Settings.cs b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.Calc.UnitTests/Settings.cs
new file mode 100644
index 0000000000..ccd231767d
--- /dev/null
+++ b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.Calc.UnitTests/Settings.cs
@@ -0,0 +1,35 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.CmdPal.Ext.Calc.Helper;
+
+namespace Microsoft.CmdPal.Ext.Calc.UnitTests;
+
+public class Settings : ISettingsInterface
+{
+ private readonly CalculateEngine.TrigMode trigUnit;
+ private readonly bool inputUseEnglishFormat;
+ private readonly bool outputUseEnglishFormat;
+ private readonly bool closeOnEnter;
+
+ public Settings(
+ CalculateEngine.TrigMode trigUnit = CalculateEngine.TrigMode.Radians,
+ bool inputUseEnglishFormat = false,
+ bool outputUseEnglishFormat = false,
+ bool closeOnEnter = true)
+ {
+ this.trigUnit = trigUnit;
+ this.inputUseEnglishFormat = inputUseEnglishFormat;
+ this.outputUseEnglishFormat = outputUseEnglishFormat;
+ this.closeOnEnter = closeOnEnter;
+ }
+
+ public CalculateEngine.TrigMode TrigUnit => trigUnit;
+
+ public bool InputUseEnglishFormat => inputUseEnglishFormat;
+
+ public bool OutputUseEnglishFormat => outputUseEnglishFormat;
+
+ public bool CloseOnEnter => closeOnEnter;
+}
diff --git a/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.Calc.UnitTests/SettingsManagerTests.cs b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.Calc.UnitTests/SettingsManagerTests.cs
new file mode 100644
index 0000000000..a59fda15d4
--- /dev/null
+++ b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.Calc.UnitTests/SettingsManagerTests.cs
@@ -0,0 +1,55 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.CmdPal.Ext.Calc.Helper;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace Microsoft.CmdPal.Ext.Calc.UnitTests;
+
+[TestClass]
+public class SettingsManagerTests
+{
+ [TestMethod]
+ public void SettingsManagerInitializationTest()
+ {
+ // Act
+ var settingsManager = new SettingsManager();
+
+ // Assert
+ Assert.IsNotNull(settingsManager);
+ Assert.IsNotNull(settingsManager.Settings);
+ }
+
+ [TestMethod]
+ public void SettingsInterfaceTest()
+ {
+ // Act
+ ISettingsInterface settings = new SettingsManager();
+
+ // Assert
+ Assert.IsNotNull(settings);
+ Assert.IsTrue(settings.TrigUnit == CalculateEngine.TrigMode.Radians);
+ Assert.IsFalse(settings.InputUseEnglishFormat);
+ Assert.IsFalse(settings.OutputUseEnglishFormat);
+ Assert.IsTrue(settings.CloseOnEnter);
+ }
+
+ [TestMethod]
+ public void MockSettingsTest()
+ {
+ // Act
+ var settings = new Settings(
+ trigUnit: CalculateEngine.TrigMode.Degrees,
+ inputUseEnglishFormat: true,
+ outputUseEnglishFormat: true,
+ closeOnEnter: false);
+
+ // Assert
+ Assert.IsNotNull(settings);
+ Assert.AreEqual(CalculateEngine.TrigMode.Degrees, settings.TrigUnit);
+ Assert.IsTrue(settings.InputUseEnglishFormat);
+ Assert.IsTrue(settings.OutputUseEnglishFormat);
+ Assert.IsFalse(settings.CloseOnEnter);
+ }
+}
diff --git a/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.Registry.UnitTests/Microsoft.CmdPal.Ext.Registry.UnitTests.csproj b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.Registry.UnitTests/Microsoft.CmdPal.Ext.Registry.UnitTests.csproj
index 951ad696a5..6bcc7bd5da 100644
--- a/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.Registry.UnitTests/Microsoft.CmdPal.Ext.Registry.UnitTests.csproj
+++ b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.Registry.UnitTests/Microsoft.CmdPal.Ext.Registry.UnitTests.csproj
@@ -18,5 +18,6 @@
+
diff --git a/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.Registry.UnitTests/QueryTests.cs b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.Registry.UnitTests/QueryTests.cs
new file mode 100644
index 0000000000..796b3b1b32
--- /dev/null
+++ b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.Registry.UnitTests/QueryTests.cs
@@ -0,0 +1,74 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Linq;
+using Microsoft.CmdPal.Ext.Registry.Helpers;
+using Microsoft.CmdPal.Ext.UnitTestBase;
+using Microsoft.CommandPalette.Extensions;
+using Microsoft.CommandPalette.Extensions.Toolkit;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace Microsoft.CmdPal.Ext.Registry.UnitTests;
+
+[TestClass]
+public class QueryTests : CommandPaletteUnitTestBase
+{
+ [DataTestMethod]
+ [DataRow("HKLM", "HKEY_LOCAL_MACHINE")]
+ [DataRow("HKCU", "HKEY_CURRENT_USER")]
+ [DataRow("HKCR", "HKEY_CLASSES_ROOT")]
+ [DataRow("HKU", "HKEY_USERS")]
+ [DataRow("HKCC", "HKEY_CURRENT_CONFIG")]
+ public void TopLevelPageQueryTest(string input, string expectedKeyName)
+ {
+ var settings = new Settings();
+ var page = new RegistryListPage(settings);
+ var results = page.Query(input);
+
+ Assert.IsNotNull(results);
+ Assert.IsTrue(results.Count > 0, "No items matched the query.");
+
+ var firstItem = results.FirstOrDefault();
+ Assert.IsNotNull(firstItem, "No items matched the query.");
+ Assert.IsTrue(
+ firstItem.Title.Contains(expectedKeyName, System.StringComparison.OrdinalIgnoreCase),
+ $"Expected to match '{expectedKeyName}' but got '{firstItem.Title}'");
+ }
+
+ [TestMethod]
+ public void EmptyQueryTest()
+ {
+ var settings = new Settings();
+ var page = new RegistryListPage(settings);
+ var results = page.Query(string.Empty);
+
+ Assert.IsNotNull(results);
+
+ // Empty query should return all base keys
+ Assert.IsTrue(results.Count >= 5, "Expected at least 5 base registry keys.");
+ }
+
+ [TestMethod]
+ public void NullQueryTest()
+ {
+ var settings = new Settings();
+ var page = new RegistryListPage(settings);
+ var results = page.Query(null);
+
+ Assert.IsNotNull(results);
+ Assert.AreEqual(0, results.Count, "Null query should return empty results.");
+ }
+
+ [TestMethod]
+ public void InvalidBaseKeyTest()
+ {
+ var settings = new Settings();
+ var page = new RegistryListPage(settings);
+ var results = page.Query("INVALID_KEY");
+
+ Assert.IsNotNull(results);
+
+ Assert.AreEqual(0, results.Count, "Invalid query should return empty results.");
+ }
+}
diff --git a/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.Registry.UnitTests/Settings.cs b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.Registry.UnitTests/Settings.cs
new file mode 100644
index 0000000000..f999dd4c29
--- /dev/null
+++ b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.Registry.UnitTests/Settings.cs
@@ -0,0 +1,15 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.CmdPal.Ext.Registry.Helpers;
+
+namespace Microsoft.CmdPal.Ext.Registry.UnitTests;
+
+public class Settings : ISettingsInterface
+{
+ public Settings()
+ {
+ // Currently no specific settings for Registry extension
+ }
+}
diff --git a/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.System.UnitTests/QueryTests.cs b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.System.UnitTests/QueryTests.cs
index dc455dd0e4..5b11ba6e05 100644
--- a/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.System.UnitTests/QueryTests.cs
+++ b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.System.UnitTests/QueryTests.cs
@@ -142,11 +142,7 @@ public class QueryTests : CommandPaletteUnitTestBase
// UEFI Firmware Settings command should exist
Assert.IsNotNull(result);
var firstItem = result.FirstOrDefault();
- Assert.IsNotNull(firstItem, "No items matched the query.");
- var containsFirmwareSettings = firstItem.Title.Contains("UEFI Firmware Settings", StringComparison.OrdinalIgnoreCase);
-
- Assert.IsTrue(
- containsFirmwareSettings == hasCommand,
- $"Expected to match 'UEFI Firmware Settings' but got '{firstItem.Title}'");
+ var firstItemIsUefiCommand = firstItem?.Title.Contains("UEFI", StringComparison.OrdinalIgnoreCase) ?? false;
+ Assert.AreEqual(hasCommand, firstItemIsUefiCommand, $"Expected to match (or not match) 'UEFI Firmware Settings' but got '{firstItem?.Title}'");
}
}
diff --git a/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.TimeDate.UnitTests/AvailableResultsListTests.cs b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.TimeDate.UnitTests/AvailableResultsListTests.cs
index 54004680b4..1c5b7a981c 100644
--- a/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.TimeDate.UnitTests/AvailableResultsListTests.cs
+++ b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.TimeDate.UnitTests/AvailableResultsListTests.cs
@@ -367,7 +367,7 @@ public class AvailableResultsListTests
public void UnixTimestampSecondsFormat()
{
// Setup
- string formatLabel = "Unix epoch time";
+ var formatLabel = "Unix epoch time";
DateTime timeValue = DateTime.Now.ToUniversalTime();
var settings = new SettingsManager();
var helperResults = AvailableResultsList.GetList(true, settings, null, null, timeValue);
@@ -384,7 +384,7 @@ public class AvailableResultsListTests
public void UnixTimestampMillisecondsFormat()
{
// Setup
- string formatLabel = "Unix epoch time in milliseconds";
+ var formatLabel = "Unix epoch time in milliseconds";
DateTime timeValue = DateTime.Now.ToUniversalTime();
var settings = new SettingsManager();
var helperResults = AvailableResultsList.GetList(true, settings, null, null, timeValue);
@@ -401,7 +401,7 @@ public class AvailableResultsListTests
public void WindowsFileTimeFormat()
{
// Setup
- string formatLabel = "Windows file time (Int64 number)";
+ var formatLabel = "Windows file time (Int64 number)";
DateTime timeValue = DateTime.Now;
var settings = new SettingsManager();
var helperResults = AvailableResultsList.GetList(true, settings, null, null, timeValue);
@@ -418,7 +418,7 @@ public class AvailableResultsListTests
public void ValidateEraResult()
{
// Setup
- string formatLabel = "Era";
+ var formatLabel = "Era";
DateTime timeValue = DateTime.Now;
var settings = new SettingsManager();
var helperResults = AvailableResultsList.GetList(true, settings, null, null, timeValue);
@@ -435,7 +435,7 @@ public class AvailableResultsListTests
public void ValidateEraAbbreviationResult()
{
// Setup
- string formatLabel = "Era abbreviation";
+ var formatLabel = "Era abbreviation";
DateTime timeValue = DateTime.Now;
var settings = new SettingsManager();
var helperResults = AvailableResultsList.GetList(true, settings, null, null, timeValue);
diff --git a/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.TimeDate.UnitTests/BasicTests.cs b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.TimeDate.UnitTests/BasicTests.cs
deleted file mode 100644
index a6dd74db3f..0000000000
--- a/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.TimeDate.UnitTests/BasicTests.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (c) Microsoft Corporation
-// The Microsoft Corporation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-
-namespace Microsoft.CmdPal.Ext.TimeDate.UnitTests;
-
-[TestClass]
-public class BasicTests
-{
- [TestMethod]
- public void BasicTest()
- {
- // This is a basic test to verify the test project can run
- Assert.IsTrue(true);
- }
-
- [TestMethod]
- public void DateTimeTest()
- {
- // Test basic DateTime functionality
- var now = DateTime.Now;
- Assert.IsNotNull(now);
- Assert.IsTrue(now > DateTime.MinValue);
- }
-}
diff --git a/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.TimeDate.UnitTests/FallbackTimeDateItemTests.cs b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.TimeDate.UnitTests/FallbackTimeDateItemTests.cs
index 596a0af97c..3f13336b0b 100644
--- a/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.TimeDate.UnitTests/FallbackTimeDateItemTests.cs
+++ b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.TimeDate.UnitTests/FallbackTimeDateItemTests.cs
@@ -40,7 +40,7 @@ public class FallbackTimeDateItemTests
public void FallbackQueryTests(string query, string expectedTitle)
{
// Setup
- var settingsManager = new SettingsManager();
+ var settingsManager = new Settings();
DateTime now = new DateTime(2025, 7, 1, 12, 0, 0); // Fixed date for testing
var fallbackItem = new FallbackTimeDateItem(settingsManager, now);
@@ -66,7 +66,7 @@ public class FallbackTimeDateItemTests
public void InvalidQueryTests(string query)
{
// Setup
- var settingsManager = new SettingsManager();
+ var settingsManager = new Settings();
DateTime now = new DateTime(2025, 7, 1, 12, 0, 0); // Fixed date for testing
var fallbackItem = new FallbackTimeDateItem(settingsManager, now);
@@ -83,4 +83,26 @@ public class FallbackTimeDateItemTests
Assert.Fail($"UpdateQuery should not throw exceptions: {ex.Message}");
}
}
+
+ [DataTestMethod]
+ public void DisableFallbackItemTest()
+ {
+ // Setup
+ var settingsManager = new Settings(enableFallbackItems: false);
+ DateTime now = new DateTime(2025, 7, 1, 12, 0, 0); // Fixed date for testing
+ var fallbackItem = new FallbackTimeDateItem(settingsManager, now);
+
+ // Act & Assert - Test that UpdateQuery doesn't throw exceptions
+ try
+ {
+ fallbackItem.UpdateQuery("now");
+
+ Assert.AreEqual(string.Empty, fallbackItem.Title, "Title should be empty when disable fallback item");
+ Assert.AreEqual(string.Empty, fallbackItem.Subtitle, "Subtitle should be empty when disable fallback item");
+ }
+ catch (Exception ex)
+ {
+ Assert.Fail($"UpdateQuery should not throw exceptions: {ex.Message}");
+ }
+ }
}
diff --git a/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.TimeDate.UnitTests/IconTests.cs b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.TimeDate.UnitTests/IconTests.cs
deleted file mode 100644
index 9dcbfd6f96..0000000000
--- a/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.TimeDate.UnitTests/IconTests.cs
+++ /dev/null
@@ -1,127 +0,0 @@
-// Copyright (c) Microsoft Corporation
-// The Microsoft Corporation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Globalization;
-using Microsoft.CmdPal.Ext.TimeDate.Helpers;
-using Microsoft.CommandPalette.Extensions.Toolkit;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-
-namespace Microsoft.CmdPal.Ext.TimeDate.UnitTests;
-
-[TestClass]
-public class IconTests
-{
- private CultureInfo originalCulture;
- private CultureInfo originalUiCulture;
-
- [TestInitialize]
- public void Setup()
- {
- // Set culture to 'en-us'
- originalCulture = CultureInfo.CurrentCulture;
- CultureInfo.CurrentCulture = new CultureInfo("en-us", false);
- originalUiCulture = CultureInfo.CurrentUICulture;
- CultureInfo.CurrentUICulture = new CultureInfo("en-us", false);
- }
-
- [TestCleanup]
- public void CleanUp()
- {
- // Set culture to original value
- CultureInfo.CurrentCulture = originalCulture;
- CultureInfo.CurrentUICulture = originalUiCulture;
- }
-
- [TestMethod]
- public void TimeDateCommandsProvider_HasIcon()
- {
- // Setup
- var provider = new TimeDateCommandsProvider();
-
- // Act
- var icon = provider.Icon;
-
- // Assert
- Assert.IsNotNull(icon, "Provider should have an icon");
- }
-
- [TestMethod]
- public void TimeDateCommandsProvider_TopLevelCommands_HaveIcons()
- {
- // Setup
- var provider = new TimeDateCommandsProvider();
-
- // Act
- var commands = provider.TopLevelCommands();
-
- // Assert
- Assert.IsNotNull(commands);
- Assert.IsTrue(commands.Length > 0, "Should have at least one top-level command");
-
- foreach (var command in commands)
- {
- Assert.IsNotNull(command.Icon, "Each command should have an icon");
- }
- }
-
- [TestMethod]
- public void AvailableResults_HaveIcons()
- {
- // Setup
- var settings = new SettingsManager();
-
- // Act
- var results = AvailableResultsList.GetList(true, settings);
-
- // Assert
- Assert.IsNotNull(results);
- Assert.IsTrue(results.Count > 0, "Should have results");
-
- foreach (var result in results)
- {
- Assert.IsNotNull(result.GetIconInfo(), $"Result '{result.Label}' should have an icon");
- }
- }
-
- [DataTestMethod]
- [DataRow(ResultIconType.Time, "\uE823")]
- [DataRow(ResultIconType.Date, "\uE787")]
- [DataRow(ResultIconType.DateTime, "\uEC92")]
- public void ResultHelper_CreateListItem_PreservesIcon(ResultIconType resultIconType, string expectedIcon)
- {
- // Setup
- var availableResult = new AvailableResult
- {
- Label = "Test Label",
- Value = "Test Value",
- IconType = resultIconType,
- };
-
- // Act
- var listItem = availableResult.ToListItem();
-
- var icon = listItem.Icon;
-
- // Assert
- Assert.IsNotNull(listItem);
- Assert.IsNotNull(listItem.Icon, "ListItem should preserve the icon from AvailableResult");
- Assert.AreEqual(expectedIcon, icon.Dark.Icon, $"Icon for {resultIconType} should match expected value");
- }
-
- [TestMethod]
- public void Icons_AreNotEmpty()
- {
- // Setup
- var settings = new SettingsManager();
- var results = AvailableResultsList.GetList(true, settings);
-
- // Act & Assert
- foreach (var result in results)
- {
- Assert.IsNotNull(result.GetIconInfo(), $"Result '{result.Label}' should have an icon");
- Assert.IsFalse(string.IsNullOrWhiteSpace(result.GetIconInfo().ToString()), $"Icon for '{result.Label}' should not be empty");
- }
- }
-}
diff --git a/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.TimeDate.UnitTests/Microsoft.CmdPal.Ext.TimeDate.UnitTests.csproj b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.TimeDate.UnitTests/Microsoft.CmdPal.Ext.TimeDate.UnitTests.csproj
index c9eb4eb904..b19c5348eb 100644
--- a/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.TimeDate.UnitTests/Microsoft.CmdPal.Ext.TimeDate.UnitTests.csproj
+++ b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.TimeDate.UnitTests/Microsoft.CmdPal.Ext.TimeDate.UnitTests.csproj
@@ -19,5 +19,6 @@
+
diff --git a/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.TimeDate.UnitTests/QueryTests.cs b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.TimeDate.UnitTests/QueryTests.cs
index b6d2b69050..cba7614044 100644
--- a/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.TimeDate.UnitTests/QueryTests.cs
+++ b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.TimeDate.UnitTests/QueryTests.cs
@@ -6,13 +6,14 @@ using System;
using System.Globalization;
using System.Linq;
using Microsoft.CmdPal.Ext.TimeDate.Helpers;
-using Microsoft.CommandPalette.Extensions.Toolkit;
+using Microsoft.CmdPal.Ext.TimeDate.Pages;
+using Microsoft.CmdPal.Ext.UnitTestBase;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Microsoft.CmdPal.Ext.TimeDate.UnitTests;
[TestClass]
-public class QueryTests
+public class QueryTests : CommandPaletteUnitTestBase
{
private CultureInfo originalCulture;
private CultureInfo originalUiCulture;
@@ -46,7 +47,7 @@ public class QueryTests
public void CountBasicQueries(string query, int expectedMinResultCount)
{
// Setup
- var settings = new SettingsManager();
+ var settings = new Settings();
// Act
var results = TimeDateCalculator.ExecuteSearch(settings, query);
@@ -58,30 +59,32 @@ public class QueryTests
}
[DataTestMethod]
- [DataRow("time")]
- [DataRow("date")]
- [DataRow("year")]
- [DataRow("now")]
- [DataRow("current")]
- [DataRow("")]
- [DataRow("now::10:10:10")] // Windows file time
- public void AllQueriesReturnResults(string query)
+ [DataRow("time", "time")]
+ [DataRow("date", "date")]
+ [DataRow("year", "year")]
+ [DataRow("now", "now")]
+ [DataRow("year", "year")]
+ public void BasicQueryTest(string input, string expectedMatchTerm)
{
- // Setup
- var settings = new SettingsManager();
+ var settings = new Settings();
+ var page = new TimeDateExtensionPage(settings);
+ page.UpdateSearchText(string.Empty, input);
+ var resultLists = page.GetItems();
- // Act
- var results = TimeDateCalculator.ExecuteSearch(settings, query);
+ var result = Query(input, resultLists);
- // Assert
- Assert.IsNotNull(results);
- Assert.IsTrue(results.Count > 0, $"Query '{query}' should return at least one result");
+ Assert.IsNotNull(result);
+ Assert.IsTrue(result.Length > 0, "No items matched the query.");
+
+ var firstItem = result.FirstOrDefault();
+ Assert.IsNotNull(firstItem, "No items matched the query.");
+ Assert.IsTrue(
+ firstItem.Title.Contains(expectedMatchTerm, System.StringComparison.OrdinalIgnoreCase) ||
+ firstItem.Subtitle.Contains(expectedMatchTerm, System.StringComparison.OrdinalIgnoreCase),
+ $"Expected to match '{expectedMatchTerm}' in title or subtitle but got '{firstItem.Title}' - '{firstItem.Subtitle}'");
}
[DataTestMethod]
- [DataRow("time", "Time")]
- [DataRow("date", "Date")]
- [DataRow("now", "Now")]
[DataRow("unix", "Unix epoch time")]
[DataRow("unix epoch time in milli", "Unix epoch time in milliseconds")]
[DataRow("file", "Windows file time (Int64 number)")]
@@ -98,12 +101,8 @@ public class QueryTests
[DataRow("month", "Month")]
[DataRow("month of year", "Month of the year")]
[DataRow("month and d", "Month and day")]
- [DataRow("month and y", "Month and year")]
[DataRow("year", "Year")]
- [DataRow("era", "Era")]
- [DataRow("era a", "Era abbreviation")]
[DataRow("universal", "Universal time format: YYYY-MM-DD hh:mm:ss")]
- [DataRow("iso", "ISO 8601")]
[DataRow("rfc", "RFC1123")]
[DataRow("time::12:30", "Time")]
[DataRow("date::10.10.2022", "Date")]
@@ -114,40 +113,19 @@ public class QueryTests
[DataRow("week num", "Week of the year (Calendar week, Week number)")]
[DataRow("days in mo", "Days in month")]
[DataRow("Leap y", "Leap year")]
- public void CanFindFormatResult(string query, string expectedSubtitle)
+ public void FormatDateQueryTest(string input, string expectedMatchTerm)
{
- // Setup
- var settings = new SettingsManager();
+ var settings = new Settings();
+ var page = new TimeDateExtensionPage(settings);
+ page.UpdateSearchText(string.Empty, input);
+ var resultLists = page.GetItems();
- // Act
- var results = TimeDateCalculator.ExecuteSearch(settings, query);
-
- // Assert
- var matchingResult = results.FirstOrDefault(x => x.Subtitle?.StartsWith(expectedSubtitle, StringComparison.CurrentCulture) == true);
- Assert.IsNotNull(matchingResult, $"Could not find result with subtitle starting with '{expectedSubtitle}' for query '{query}'");
- }
-
- [DataTestMethod]
- [DataRow("12:30", "Time")]
- [DataRow("10.10.2022", "Date")]
- [DataRow("u1646408119", "Date and time")]
- [DataRow("u+1646408119", "Date and time")]
- [DataRow("u-1646408119", "Date and time")]
- [DataRow("ums1646408119", "Date and time")]
- [DataRow("ums+1646408119", "Date and time")]
- [DataRow("ums-1646408119", "Date and time")]
- [DataRow("ft637820085517321977", "Date and time")]
- public void DateTimeNumberOnlyInput(string query, string expectedSubtitle)
- {
- // Setup
- var settings = new SettingsManager();
-
- // Act
- var results = TimeDateCalculator.ExecuteSearch(settings, query);
-
- // Assert
- var matchingResult = results.FirstOrDefault(x => x.Subtitle?.StartsWith(expectedSubtitle, StringComparison.CurrentCulture) == true);
- Assert.IsNotNull(matchingResult, $"Could not find result with subtitle starting with '{expectedSubtitle}' for query '{query}'");
+ var firstItem = resultLists.FirstOrDefault();
+ Assert.IsNotNull(firstItem, "No items matched the query.");
+ Assert.IsTrue(
+ firstItem.Title.Contains(expectedMatchTerm, System.StringComparison.OrdinalIgnoreCase) ||
+ firstItem.Subtitle.Contains(expectedMatchTerm, System.StringComparison.OrdinalIgnoreCase),
+ $"Expected to match '{expectedMatchTerm}' in title or subtitle but got '{firstItem.Title}' - '{firstItem.Subtitle}'");
}
[DataTestMethod]
@@ -157,24 +135,6 @@ public class QueryTests
[DataRow("time:eeee")]
[DataRow("time::eeee")]
[DataRow("time//eeee")]
- public void InvalidInputShowsErrorResults(string query)
- {
- // Setup
- var settings = new SettingsManager();
-
- // Act
- var results = TimeDateCalculator.ExecuteSearch(settings, query);
-
- // Assert
- Assert.IsNotNull(results, $"Results should not be null for query '{query}'");
- Assert.IsTrue(results.Count > 0, $"Query '{query}' should return at least one result");
-
- // For invalid input, cmdpal returns an error result
- var hasErrorResult = results.Any(r => r.Title?.StartsWith("Error: Invalid input", StringComparison.CurrentCulture) == true);
- Assert.IsTrue(hasErrorResult, $"Query '{query}' should return an error result for invalid input");
- }
-
- [DataTestMethod]
[DataRow("ug1646408119")] // Invalid prefix
[DataRow("u9999999999999")] // Unix number + prefix is longer than 12 characters
[DataRow("ums999999999999999")] // Unix number in milliseconds + prefix is longer than 17 characters
@@ -194,116 +154,33 @@ public class QueryTests
[DataRow("10.aa.22")]
[DataRow("12::55")]
[DataRow("12:aa:55")]
- public void InvalidNumberInputShowsErrorMessage(string query)
+ public void InvalidInputShowsErrorResults(string query)
{
- // Setup
- var settings = new SettingsManager();
-
- // Act
- var results = TimeDateCalculator.ExecuteSearch(settings, query);
+ var settings = new Settings();
+ var page = new TimeDateExtensionPage(settings);
+ page.UpdateSearchText(string.Empty, query);
+ var results = page.GetItems();
// Assert
Assert.IsNotNull(results, $"Results should not be null for query '{query}'");
- Assert.IsTrue(results.Count > 0, $"Should return at least one result (error message) for invalid query '{query}'");
+ Assert.IsTrue(results.Length > 0, $"Query '{query}' should return at least one result");
- // Check if we get an error result
- var errorResult = results.FirstOrDefault(r => r.Title?.StartsWith("Error: Invalid input", StringComparison.CurrentCulture) == true);
- Assert.IsNotNull(errorResult, $"Should return an error result for invalid query '{query}'");
+ var firstItem = results.FirstOrDefault();
+ Assert.IsTrue(firstItem.Title.StartsWith("Error: Invalid input", StringComparison.CurrentCulture), $"Query '{query}' should return an error result for invalid input");
}
[DataTestMethod]
- [DataRow("10.10aa")] // Input contains . (Can be part of a date.)
- [DataRow("10:10aa")] // Input contains : (Can be part of a time.)
- [DataRow("10/10aa")] // Input contains / (Can be part of a date.)
- public void InvalidInputNotShowsErrorMessage(string query)
+ [DataRow("")]
+ [DataRow(null)]
+ public void EmptyQueryReturnsAllResults(string input)
{
- // Setup
- var settings = new SettingsManager();
-
- // Act
- var results = TimeDateCalculator.ExecuteSearch(settings, query);
+ var settings = new Settings();
+ var page = new TimeDateExtensionPage(settings);
+ page.UpdateSearchText("abc", input);
+ var results = page.GetItems();
// Assert
- Assert.IsNotNull(results, $"Results should not be null for query '{query}'");
-
- // These queries are ambiguous and cmdpal returns an error for them
- // This test might need to be adjusted based on actual cmdpal behavior
- if (results.Count > 0)
- {
- var hasErrorResult = results.Any(r => r.Title?.StartsWith("Error: Invalid input", StringComparison.CurrentCulture) == true);
-
- // For these ambiguous inputs, cmdpal may return error results, which is acceptable
- // We just verify that the system handles them gracefully (doesn't crash)
- Assert.IsTrue(true, $"Query '{query}' handled gracefully");
- }
- }
-
- [DataTestMethod]
- [DataRow("time", "time", true)] // Full word match should work
- [DataRow("date", "date", true)] // Full word match should work
- [DataRow("now", "now", true)] // Full word match should work
- [DataRow("year", "year", true)] // Full word match should work
- [DataRow("abcdefg", "", false)] // Invalid query should return error
- public void ValidateBehaviorOnSearchQueries(string query, string expectedMatchTerm, bool shouldHaveValidResults)
- {
- // Setup
- var settings = new SettingsManager();
-
- // Act
- var results = TimeDateCalculator.ExecuteSearch(settings, query);
-
- // Assert
- Assert.IsNotNull(results, $"Results should not be null for query '{query}'");
- Assert.IsTrue(results.Count > 0, $"Query '{query}' should return at least one result");
-
- if (shouldHaveValidResults)
- {
- // Should have non-error results
- var hasValidResult = results.Any(r => !r.Title?.StartsWith("Error: Invalid input", StringComparison.CurrentCulture) == true);
- Assert.IsTrue(hasValidResult, $"Query '{query}' should return valid (non-error) results");
-
- if (!string.IsNullOrEmpty(expectedMatchTerm))
- {
- var hasMatchingResult = results.Any(r =>
- r.Title?.Contains(expectedMatchTerm, StringComparison.CurrentCultureIgnoreCase) == true ||
- r.Subtitle?.Contains(expectedMatchTerm, StringComparison.CurrentCultureIgnoreCase) == true);
- Assert.IsTrue(hasMatchingResult, $"Query '{query}' should return results containing '{expectedMatchTerm}'");
- }
- }
- else
- {
- // Should have error results
- var hasErrorResult = results.Any(r => r.Title?.StartsWith("Error: Invalid input", StringComparison.CurrentCulture) == true);
- Assert.IsTrue(hasErrorResult, $"Query '{query}' should return error results for invalid input");
- }
- }
-
- [TestMethod]
- public void EmptyQueryReturnsAllResults()
- {
- // Setup
- var settings = new SettingsManager();
-
- // Act
- var results = TimeDateCalculator.ExecuteSearch(settings, string.Empty);
-
- // Assert
- Assert.IsNotNull(results);
- Assert.IsTrue(results.Count > 0, "Empty query should return all available results");
- }
-
- [TestMethod]
- public void NullQueryReturnsAllResults()
- {
- // Setup
- var settings = new SettingsManager();
-
- // Act
- var results = TimeDateCalculator.ExecuteSearch(settings, null);
-
- // Assert
- Assert.IsNotNull(results);
- Assert.IsTrue(results.Count > 0, "Null query should return all available results");
+ Assert.IsTrue(results.Length > 0, $"Empty query should return results");
}
[DataTestMethod]
@@ -312,39 +189,34 @@ public class QueryTests
[DataRow("iso utc", "ISO 8601 UTC")]
[DataRow("iso zone", "ISO 8601 with time zone")]
[DataRow("iso utc zone", "ISO 8601 UTC with time zone")]
- public void UTCRelatedQueries(string query, string expectedSubtitle)
+ public void TimeZoneQuery(string query, string expectedSubtitle)
{
- // Setup
- var settings = new SettingsManager();
-
- // Act
- var results = TimeDateCalculator.ExecuteSearch(settings, query);
+ var settings = new Settings();
+ var page = new TimeDateExtensionPage(settings);
+ page.UpdateSearchText(string.Empty, query);
+ var resultsList = page.GetItems();
+ var results = Query(query, resultsList);
// Assert
Assert.IsNotNull(results);
- Assert.IsTrue(results.Count > 0, $"Query '{query}' should return results");
-
- var matchingResult = results.FirstOrDefault(x => x.Subtitle?.StartsWith(expectedSubtitle, StringComparison.CurrentCulture) == true);
- Assert.IsNotNull(matchingResult, $"Could not find result with subtitle starting with '{expectedSubtitle}' for query '{query}'");
+ var firstResult = results.FirstOrDefault();
+ Assert.IsTrue(firstResult.Subtitle.StartsWith(expectedSubtitle, StringComparison.CurrentCulture), $"Could not find result with subtitle starting with '{expectedSubtitle}' for query '{query}'");
}
[DataTestMethod]
- [DataRow("time::12:30:45")]
- [DataRow("date::2023-12-25")]
- [DataRow("now::u1646408119")]
- [DataRow("current::ft637820085517321977")]
- public void DelimiterQueriesReturnResults(string query)
+ [DataRow("time::12:30:45", "12:30 PM")]
+ [DataRow("date::2023-12-25", "12/25/2023")]
+ [DataRow("now::u1646408119", "132908817190000000")]
+ public void DelimiterQueriesReturnResults(string query, string expectedResult)
{
- // Setup
- var settings = new SettingsManager();
-
- // Act
- var results = TimeDateCalculator.ExecuteSearch(settings, query);
+ var settings = new Settings();
+ var page = new TimeDateExtensionPage(settings);
+ page.UpdateSearchText(string.Empty, query);
+ var resultsList = page.GetItems();
// Assert
- Assert.IsNotNull(results);
-
- // Delimiter queries should return results even if parsing fails (error results)
- Assert.IsTrue(results.Count > 0, $"Delimiter query '{query}' should return at least one result");
+ Assert.IsNotNull(resultsList);
+ var firstResult = resultsList.FirstOrDefault();
+ Assert.IsTrue(firstResult.Title.Contains(expectedResult, StringComparison.CurrentCulture), $"Delimiter query '{query}' result not match {expectedResult} current result {firstResult.Title}");
}
}
diff --git a/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.TimeDate.UnitTests/Settings.cs b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.TimeDate.UnitTests/Settings.cs
new file mode 100644
index 0000000000..ce412a7377
--- /dev/null
+++ b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.TimeDate.UnitTests/Settings.cs
@@ -0,0 +1,46 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using Microsoft.CmdPal.Ext.TimeDate.Helpers;
+
+namespace Microsoft.CmdPal.Ext.TimeDate.UnitTests;
+
+public class Settings : ISettingsInterface
+{
+ private readonly int firstWeekOfYear;
+ private readonly int firstDayOfWeek;
+ private readonly bool enableFallbackItems;
+ private readonly bool timeWithSecond;
+ private readonly bool dateWithWeekday;
+ private readonly List customFormats;
+
+ public Settings(
+ int firstWeekOfYear = -1,
+ int firstDayOfWeek = -1,
+ bool enableFallbackItems = true,
+ bool timeWithSecond = false,
+ bool dateWithWeekday = false,
+ List customFormats = null)
+ {
+ this.firstWeekOfYear = firstWeekOfYear;
+ this.firstDayOfWeek = firstDayOfWeek;
+ this.enableFallbackItems = enableFallbackItems;
+ this.timeWithSecond = timeWithSecond;
+ this.dateWithWeekday = dateWithWeekday;
+ this.customFormats = customFormats ?? new List();
+ }
+
+ public int FirstWeekOfYear => firstWeekOfYear;
+
+ public int FirstDayOfWeek => firstDayOfWeek;
+
+ public bool EnableFallbackItems => enableFallbackItems;
+
+ public bool TimeWithSecond => timeWithSecond;
+
+ public bool DateWithWeekday => dateWithWeekday;
+
+ public List CustomFormats => customFormats;
+}
diff --git a/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.TimeDate.UnitTests/SettingsManagerTests.cs b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.TimeDate.UnitTests/SettingsManagerTests.cs
deleted file mode 100644
index 70e3c07e0d..0000000000
--- a/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.TimeDate.UnitTests/SettingsManagerTests.cs
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright (c) Microsoft Corporation
-// The Microsoft Corporation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Globalization;
-using Microsoft.CmdPal.Ext.TimeDate.Helpers;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-
-namespace Microsoft.CmdPal.Ext.TimeDate.UnitTests;
-
-[TestClass]
-public class SettingsManagerTests
-{
- private CultureInfo originalCulture;
- private CultureInfo originalUiCulture;
-
- [TestInitialize]
- public void Setup()
- {
- // Set culture to 'en-us'
- originalCulture = CultureInfo.CurrentCulture;
- CultureInfo.CurrentCulture = new CultureInfo("en-us", false);
- originalUiCulture = CultureInfo.CurrentUICulture;
- CultureInfo.CurrentUICulture = new CultureInfo("en-us", false);
- }
-
- [TestCleanup]
- public void Cleanup()
- {
- // Restore original culture
- CultureInfo.CurrentCulture = originalCulture;
- CultureInfo.CurrentUICulture = originalUiCulture;
- }
-
- [TestMethod]
- public void SettingsManagerInitializationTest()
- {
- // Act
- var settingsManager = new SettingsManager();
-
- // Assert
- Assert.IsNotNull(settingsManager);
- Assert.IsNotNull(settingsManager.Settings);
- }
-
- [TestMethod]
- public void DefaultSettingsValidation()
- {
- // Act
- var settingsManager = new SettingsManager();
-
- // Assert - Check that properties are accessible
- var enableFallback = settingsManager.EnableFallbackItems;
- var timeWithSecond = settingsManager.TimeWithSecond;
- var dateWithWeekday = settingsManager.DateWithWeekday;
- var firstWeekOfYear = settingsManager.FirstWeekOfYear;
- var firstDayOfWeek = settingsManager.FirstDayOfWeek;
- var customFormats = settingsManager.CustomFormats;
-
- Assert.IsNotNull(customFormats);
- }
-
- [TestMethod]
- public void SettingsPropertiesAccessibilityTest()
- {
- // Setup
- var settingsManager = new SettingsManager();
-
- // Act & Assert - Verify all properties are accessible without exception
- try
- {
- _ = settingsManager.EnableFallbackItems;
- _ = settingsManager.TimeWithSecond;
- _ = settingsManager.DateWithWeekday;
- _ = settingsManager.FirstWeekOfYear;
- _ = settingsManager.FirstDayOfWeek;
- _ = settingsManager.CustomFormats;
- }
- catch (Exception ex)
- {
- Assert.Fail($"Settings properties should be accessible: {ex.Message}");
- }
- }
-}
diff --git a/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.WindowWalker.UnitTests/Microsoft.CmdPal.Ext.WindowWalker.UnitTests.csproj b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.WindowWalker.UnitTests/Microsoft.CmdPal.Ext.WindowWalker.UnitTests.csproj
index 8019cfff91..8fde8f6f39 100644
--- a/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.WindowWalker.UnitTests/Microsoft.CmdPal.Ext.WindowWalker.UnitTests.csproj
+++ b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.WindowWalker.UnitTests/Microsoft.CmdPal.Ext.WindowWalker.UnitTests.csproj
@@ -20,5 +20,6 @@
+
diff --git a/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.WindowWalker.UnitTests/PluginSettingsTests.cs b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.WindowWalker.UnitTests/PluginSettingsTests.cs
deleted file mode 100644
index fd8e103140..0000000000
--- a/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.WindowWalker.UnitTests/PluginSettingsTests.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright (c) Microsoft Corporation
-// The Microsoft Corporation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Reflection;
-
-using Microsoft.CmdPal.Ext.WindowWalker.Helpers;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-
-namespace Microsoft.CmdPal.Ext.WindowWalker.UnitTests;
-
-[TestClass]
-public class PluginSettingsTests
-{
- [DataTestMethod]
- [DataRow("ResultsFromVisibleDesktopOnly")]
- [DataRow("SubtitleShowPid")]
- [DataRow("SubtitleShowDesktopName")]
- [DataRow("ConfirmKillProcess")]
- [DataRow("KillProcessTree")]
- [DataRow("OpenAfterKillAndClose")]
- [DataRow("HideKillProcessOnElevatedProcesses")]
- [DataRow("HideExplorerSettingInfo")]
- [DataRow("InMruOrder")]
- public void DoesSettingExist(string name)
- {
- // Setup
- Type settings = SettingsManager.Instance?.GetType();
-
- // Act
- var result = settings?.GetProperty(name, BindingFlags.Public | BindingFlags.Instance);
-
- // Assert
- Assert.IsNotNull(result);
- }
-
- [DataTestMethod]
- [DataRow("ResultsFromVisibleDesktopOnly", false)]
- [DataRow("SubtitleShowPid", false)]
- [DataRow("SubtitleShowDesktopName", true)]
- [DataRow("ConfirmKillProcess", true)]
- [DataRow("KillProcessTree", false)]
- [DataRow("OpenAfterKillAndClose", false)]
- [DataRow("HideKillProcessOnElevatedProcesses", false)]
- [DataRow("HideExplorerSettingInfo", true)]
- [DataRow("InMruOrder", true)]
- public void DefaultValues(string name, bool valueExpected)
- {
- // Setup
- SettingsManager setting = SettingsManager.Instance;
-
- // Act
- PropertyInfo propertyInfo = setting?.GetType()?.GetProperty(name, BindingFlags.Public | BindingFlags.Instance);
- var result = propertyInfo?.GetValue(setting);
-
- // Assert
- Assert.AreEqual(valueExpected, result);
- }
-}
diff --git a/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.WindowWalker.UnitTests/Settings.cs b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.WindowWalker.UnitTests/Settings.cs
new file mode 100644
index 0000000000..e8271da371
--- /dev/null
+++ b/src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.WindowWalker.UnitTests/Settings.cs
@@ -0,0 +1,60 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.CmdPal.Ext.WindowWalker.Helpers;
+
+namespace Microsoft.CmdPal.Ext.WindowWalker.UnitTests;
+
+public class Settings : ISettingsInterface
+{
+ private readonly bool resultsFromVisibleDesktopOnly;
+ private readonly bool subtitleShowPid;
+ private readonly bool subtitleShowDesktopName;
+ private readonly bool confirmKillProcess;
+ private readonly bool killProcessTree;
+ private readonly bool openAfterKillAndClose;
+ private readonly bool hideKillProcessOnElevatedProcesses;
+ private readonly bool hideExplorerSettingInfo;
+ private readonly bool inMruOrder;
+
+ public Settings(
+ bool resultsFromVisibleDesktopOnly = false,
+ bool subtitleShowPid = false,
+ bool subtitleShowDesktopName = true,
+ bool confirmKillProcess = true,
+ bool killProcessTree = false,
+ bool openAfterKillAndClose = false,
+ bool hideKillProcessOnElevatedProcesses = false,
+ bool hideExplorerSettingInfo = true,
+ bool inMruOrder = true)
+ {
+ this.resultsFromVisibleDesktopOnly = resultsFromVisibleDesktopOnly;
+ this.subtitleShowPid = subtitleShowPid;
+ this.subtitleShowDesktopName = subtitleShowDesktopName;
+ this.confirmKillProcess = confirmKillProcess;
+ this.killProcessTree = killProcessTree;
+ this.openAfterKillAndClose = openAfterKillAndClose;
+ this.hideKillProcessOnElevatedProcesses = hideKillProcessOnElevatedProcesses;
+ this.hideExplorerSettingInfo = hideExplorerSettingInfo;
+ this.inMruOrder = inMruOrder;
+ }
+
+ public bool ResultsFromVisibleDesktopOnly => resultsFromVisibleDesktopOnly;
+
+ public bool SubtitleShowPid => subtitleShowPid;
+
+ public bool SubtitleShowDesktopName => subtitleShowDesktopName;
+
+ public bool ConfirmKillProcess => confirmKillProcess;
+
+ public bool KillProcessTree => killProcessTree;
+
+ public bool OpenAfterKillAndClose => openAfterKillAndClose;
+
+ public bool HideKillProcessOnElevatedProcesses => hideKillProcessOnElevatedProcesses;
+
+ public bool HideExplorerSettingInfo => hideExplorerSettingInfo;
+
+ public bool InMruOrder => inMruOrder;
+}
diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Calc/CalculatorCommandProvider.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Calc/CalculatorCommandProvider.cs
index 0f4a8b0d9b..cdf0ccfa47 100644
--- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Calc/CalculatorCommandProvider.cs
+++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Calc/CalculatorCommandProvider.cs
@@ -12,21 +12,21 @@ namespace Microsoft.CmdPal.Ext.Calc;
public partial class CalculatorCommandProvider : CommandProvider
{
+ private static ISettingsInterface settings = new SettingsManager();
private readonly ListItem _listItem = new(new CalculatorListPage(settings))
{
Subtitle = Resources.calculator_top_level_subtitle,
- MoreCommands = [new CommandContextItem(settings.Settings.SettingsPage)],
+ MoreCommands = [new CommandContextItem(((SettingsManager)settings).Settings.SettingsPage)],
};
private readonly FallbackCalculatorItem _fallback = new(settings);
- private static SettingsManager settings = new();
public CalculatorCommandProvider()
{
Id = "Calculator";
DisplayName = Resources.calculator_display_name;
Icon = Icons.CalculatorIcon;
- Settings = settings.Settings;
+ Settings = ((SettingsManager)settings).Settings;
}
public override ICommandItem[] TopLevelCommands() => [_listItem];
diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Calc/Helper/CalculateEngine.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Calc/Helper/CalculateEngine.cs
index ca2e1d1ea8..a927e07499 100644
--- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Calc/Helper/CalculateEngine.cs
+++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Calc/Helper/CalculateEngine.cs
@@ -34,7 +34,7 @@ public static class CalculateEngine
/// Interpret
///
/// Use CultureInfo.CurrentCulture if something is user facing
- public static CalculateResult Interpret(SettingsManager settings, string input, CultureInfo cultureInfo, out string error)
+ public static CalculateResult Interpret(ISettingsInterface settings, string input, CultureInfo cultureInfo, out string error)
{
error = default;
diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Calc/Helper/ISettingsInterface.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Calc/Helper/ISettingsInterface.cs
new file mode 100644
index 0000000000..f4b7a50644
--- /dev/null
+++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Calc/Helper/ISettingsInterface.cs
@@ -0,0 +1,18 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.CmdPal.Ext.Calc.Helper;
+
+namespace Microsoft.CmdPal.Ext.Calc.Helper;
+
+public interface ISettingsInterface
+{
+ public CalculateEngine.TrigMode TrigUnit { get; }
+
+ public bool InputUseEnglishFormat { get; }
+
+ public bool OutputUseEnglishFormat { get; }
+
+ public bool CloseOnEnter { get; }
+}
diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Calc/Helper/QueryHelper.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Calc/Helper/QueryHelper.cs
index b6c41f3831..99f782d714 100644
--- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Calc/Helper/QueryHelper.cs
+++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Calc/Helper/QueryHelper.cs
@@ -12,7 +12,7 @@ namespace Microsoft.CmdPal.Ext.Calc.Helper;
public static partial class QueryHelper
{
- public static ListItem Query(string query, SettingsManager settings, bool isFallbackSearch, TypedEventHandler