diff --git a/src/core/Microsoft.PowerToys.Settings.UI.Lib/Helpers/Observable.cs b/src/core/Microsoft.PowerToys.Settings.UI.Lib/Helpers/Observable.cs new file mode 100644 index 0000000000..918c5c531b --- /dev/null +++ b/src/core/Microsoft.PowerToys.Settings.UI.Lib/Helpers/Observable.cs @@ -0,0 +1,27 @@ +// 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.ComponentModel; +using System.Runtime.CompilerServices; + +namespace Microsoft.PowerToys.Settings.UI.Lib.Helpers +{ + public class Observable : INotifyPropertyChanged + { + public event PropertyChangedEventHandler PropertyChanged; + + protected void Set(ref T storage, T value, [CallerMemberName] string propertyName = null) + { + if (Equals(storage, value)) + { + return; + } + + storage = value; + OnPropertyChanged(propertyName); + } + + protected void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } +} diff --git a/src/core/Microsoft.PowerToys.Settings.UI.Lib/ViewModels/Commands/ButtonClickCommand.cs b/src/core/Microsoft.PowerToys.Settings.UI.Lib/ViewModels/Commands/ButtonClickCommand.cs new file mode 100644 index 0000000000..c31b17494e --- /dev/null +++ b/src/core/Microsoft.PowerToys.Settings.UI.Lib/ViewModels/Commands/ButtonClickCommand.cs @@ -0,0 +1,34 @@ +// 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.Windows.Input; + +namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels.Commands +{ + public class ButtonClickCommand : ICommand + { + private readonly Action _execute; + + public ButtonClickCommand(Action execute) + { + this._execute = execute; + } + + // Occurs when changes occur that affect whether or not the command should execute. + public event EventHandler CanExecuteChanged; + + // Defines the method that determines whether the command can execute in its current state. + public bool CanExecute(object parameter) + { + return true; + } + + // Defines the method to be called when the command is invoked. + public void Execute(object parameter) + { + _execute(); + } + } +} diff --git a/src/core/Microsoft.PowerToys.Settings.UI.Lib/ViewModels/Commands/RelayCommand.cs b/src/core/Microsoft.PowerToys.Settings.UI.Lib/ViewModels/Commands/RelayCommand.cs new file mode 100644 index 0000000000..0c2b5ef79f --- /dev/null +++ b/src/core/Microsoft.PowerToys.Settings.UI.Lib/ViewModels/Commands/RelayCommand.cs @@ -0,0 +1,34 @@ +// 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.Windows.Input; + +namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels.Commands +{ + public class RelayCommand : ICommand + { + private readonly Action _execute; + private readonly Func _canExecute; + + public event EventHandler CanExecuteChanged; + + public RelayCommand(Action execute) + : this(execute, null) + { + } + + public RelayCommand(Action execute, Func canExecute) + { + _execute = execute ?? throw new ArgumentNullException(nameof(execute)); + _canExecute = canExecute; + } + + public bool CanExecute(object parameter) => _canExecute == null || _canExecute(); + + public void Execute(object parameter) => _execute(); + + public void OnCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty); + } +} diff --git a/src/core/Microsoft.PowerToys.Settings.UI.Lib/ViewModels/Commands/RelayCommand`1.cs b/src/core/Microsoft.PowerToys.Settings.UI.Lib/ViewModels/Commands/RelayCommand`1.cs new file mode 100644 index 0000000000..41f7f3e648 --- /dev/null +++ b/src/core/Microsoft.PowerToys.Settings.UI.Lib/ViewModels/Commands/RelayCommand`1.cs @@ -0,0 +1,36 @@ +// 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.Windows.Input; + +namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels.Commands +{ + + public class RelayCommand : ICommand + { + private readonly Action execute; + + private readonly Func canExecute; + + public event EventHandler CanExecuteChanged; + + public RelayCommand(Action execute) + : this(execute, null) + { + } + + public RelayCommand(Action execute, Func canExecute) + { + this.execute = execute ?? throw new ArgumentNullException(nameof(execute)); + this.canExecute = canExecute; + } + + public bool CanExecute(object parameter) => canExecute == null || canExecute((T)parameter); + + public void Execute(object parameter) => execute((T)parameter); + + public void OnCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty); + } +} diff --git a/src/core/Microsoft.PowerToys.Settings.UI/ViewModels/GeneralViewModel.cs b/src/core/Microsoft.PowerToys.Settings.UI.Lib/ViewModels/GeneralViewModel.cs similarity index 78% rename from src/core/Microsoft.PowerToys.Settings.UI/ViewModels/GeneralViewModel.cs rename to src/core/Microsoft.PowerToys.Settings.UI.Lib/ViewModels/GeneralViewModel.cs index 4c71e583ac..f2975d50dc 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI/ViewModels/GeneralViewModel.cs +++ b/src/core/Microsoft.PowerToys.Settings.UI.Lib/ViewModels/GeneralViewModel.cs @@ -5,15 +5,12 @@ using System; using System.Diagnostics; using System.Runtime.CompilerServices; -using Microsoft.PowerToys.Settings.UI.Helpers; -using Microsoft.PowerToys.Settings.UI.Lib; +using System.Text.Json; +using Microsoft.PowerToys.Settings.UI.Lib.Helpers; using Microsoft.PowerToys.Settings.UI.Lib.Utilities; -using Microsoft.PowerToys.Settings.UI.ViewModels.Commands; -using Microsoft.PowerToys.Settings.UI.Views; -using Windows.ApplicationModel.Resources; -using Windows.UI.Xaml; +using Microsoft.PowerToys.Settings.UI.Lib.ViewModels.Commands; -namespace Microsoft.PowerToys.Settings.UI.ViewModels +namespace Microsoft.PowerToys.Settings.UI.Lib.ViewModels { public class GeneralViewModel : Observable { @@ -23,26 +20,25 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels public ButtonClickCommand RestartElevatedButtonEventHandler { get; set; } - private ResourceLoader loader = ResourceLoader.GetForViewIndependentUse(); - public string RunningAsUserDefaultText { get; private set; } + public Func UpdateUIThemeCallBack { get; } - public string RunningAsAdminDefaultText { get; private set; } + public Func SendConfigMSG { get; } - private bool _packaged = false; - private bool _startup = false; - private bool _isElevated = false; - private bool _runElevated = false; - private bool _isAdmin = false; - private bool _isDarkThemeRadioButtonChecked = false; - private bool _isLightThemeRadioButtonChecked = false; - private bool _isSystemThemeRadioButtonChecked = false; - private bool _autoDownloadUpdates = false; + public Func SendRestartAsAdminConfigMSG { get; } - public GeneralViewModel() + public Func SendCheckForUpdatesConfigMSG { get; } + + public readonly string RunningAsUserDefaultText; + + public readonly string RunningAsAdminDefaultText; + + public string SettingsConfigFileFolder = string.Empty; + + public GeneralViewModel(string runAsAdminText, string runAsUserText, bool isElevated, bool isAdmin, Func updateTheme, Func ipcMSGCallBackFunc, Func ipcMSGRestartAsAdminMSGCallBackFunc, Func ipcMSGCheckForUpdatesCallBackFunc, string configFileSubfolder = "") { - CheckFoUpdatesEventHandler = new ButtonClickCommand(CheckForUpdates_Click); - RestartElevatedButtonEventHandler = new ButtonClickCommand(Restart_Elevated); + this.CheckFoUpdatesEventHandler = new ButtonClickCommand(CheckForUpdates_Click); + this.RestartElevatedButtonEventHandler = new ButtonClickCommand(Restart_Elevated); try { @@ -66,54 +62,52 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels SettingsUtils.SaveSettings(GeneralSettingsConfigs.ToJsonString(), string.Empty); } + // set the callback functions value to hangle outgoing IPC message. + SendConfigMSG = ipcMSGCallBackFunc; + SendCheckForUpdatesConfigMSG = ipcMSGCheckForUpdatesCallBackFunc; + SendRestartAsAdminConfigMSG = ipcMSGRestartAsAdminMSGCallBackFunc; + + // set the callback function value to update the UI theme. + UpdateUIThemeCallBack = updateTheme; + UpdateUIThemeCallBack(GeneralSettingsConfigs.Theme.ToLower()); + + // Update Settings file folder: + SettingsConfigFileFolder = configFileSubfolder; + switch (GeneralSettingsConfigs.Theme.ToLower()) { case "light": _isLightThemeRadioButtonChecked = true; - try - { - ShellPage.ShellHandler.RequestedTheme = ElementTheme.Light; - } - catch - { - } - break; case "dark": _isDarkThemeRadioButtonChecked = true; - try - { - ShellPage.ShellHandler.RequestedTheme = ElementTheme.Dark; - } - catch - { - } - break; case "system": _isSystemThemeRadioButtonChecked = true; - try - { - ShellPage.ShellHandler.RequestedTheme = ElementTheme.Default; - } - catch - { - } - break; } _startup = GeneralSettingsConfigs.Startup; _autoDownloadUpdates = GeneralSettingsConfigs.AutoDownloadUpdates; - _isElevated = ShellPage.IsElevated; + _isElevated = isElevated; _runElevated = GeneralSettingsConfigs.RunElevated; - RunningAsUserDefaultText = loader.GetString("GeneralSettings_RunningAsUserText"); - RunningAsAdminDefaultText = loader.GetString("GeneralSettings_RunningAsAdminText"); + RunningAsUserDefaultText = runAsUserText; + RunningAsAdminDefaultText = runAsAdminText; - _isAdmin = ShellPage.IsUserAnAdmin; + _isAdmin = isAdmin; } + private bool _packaged = false; + private bool _startup = false; + private bool _isElevated = false; + private bool _runElevated = false; + private bool _isAdmin = false; + private bool _isDarkThemeRadioButtonChecked = false; + private bool _isLightThemeRadioButtonChecked = false; + private bool _isSystemThemeRadioButtonChecked = false; + private bool _autoDownloadUpdates = false; + // Gets or sets a value indicating whether packaged. public bool Packaged { @@ -265,7 +259,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels _isDarkThemeRadioButtonChecked = value; try { - ShellPage.ShellHandler.RequestedTheme = ElementTheme.Dark; + UpdateUIThemeCallBack(GeneralSettingsConfigs.Theme); } catch { @@ -291,7 +285,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels _isLightThemeRadioButtonChecked = value; try { - ShellPage.ShellHandler.RequestedTheme = ElementTheme.Light; + UpdateUIThemeCallBack(GeneralSettingsConfigs.Theme); } catch { @@ -317,7 +311,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels _isSystemThemeRadioButtonChecked = value; try { - ShellPage.ShellHandler.RequestedTheme = ElementTheme.Default; + UpdateUIThemeCallBack(GeneralSettingsConfigs.Theme); } catch { @@ -343,30 +337,30 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels OutGoingGeneralSettings outsettings = new OutGoingGeneralSettings(GeneralSettingsConfigs); - ShellPage.DefaultSndMSGCallback(outsettings.ToString()); + SendConfigMSG(outsettings.ToString()); } // callback function to launch the URL to check for updates. - private void CheckForUpdates_Click() + private async void CheckForUpdates_Click() { - GeneralSettings settings = SettingsUtils.GetSettings(string.Empty); + GeneralSettings settings = SettingsUtils.GetSettings(SettingsConfigFileFolder); settings.CustomActionName = "check_for_updates"; OutGoingGeneralSettings outsettings = new OutGoingGeneralSettings(settings); GeneralSettingsCustomAction customaction = new GeneralSettingsCustomAction(outsettings); - ShellPage.CheckForUpdatesMsgCallback?.Invoke(customaction.ToString()); + SendCheckForUpdatesConfigMSG(customaction.ToString()); } public void Restart_Elevated() { - GeneralSettings settings = SettingsUtils.GetSettings(string.Empty); + GeneralSettings settings = SettingsUtils.GetSettings(SettingsConfigFileFolder); settings.CustomActionName = "restart_elevation"; OutGoingGeneralSettings outsettings = new OutGoingGeneralSettings(settings); GeneralSettingsCustomAction customaction = new GeneralSettingsCustomAction(outsettings); - ShellPage.SndRestartAsAdminMsgCallback?.Invoke(customaction.ToString()); + SendRestartAsAdminConfigMSG(customaction.ToString()); } } } diff --git a/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ModelsTests/BasePTModuleSettingsTest.cs b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ModelsTests/BasePTModuleSettingsTest.cs new file mode 100644 index 0000000000..84bba538c8 --- /dev/null +++ b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ModelsTests/BasePTModuleSettingsTest.cs @@ -0,0 +1,53 @@ +// 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.PowerToys.Settings.UI.Lib; +using Microsoft.PowerToys.Settings.UnitTest; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Schema; + +namespace CommonLibTest +{ + [TestClass] + public class BasePTModuleSettingsTest + { + // Work around for System.JSON required properties: + // https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to. + // Test also fails when the attributes are not initialized i.e they have null values. + [TestMethod] + [Obsolete] + public void ToJsonString_ShouldReturnValidJSONOfModel_WhenSuccessful() + { + // Arrange + string file_name = "test\\BasePTModuleSettingsTest"; + string expectedSchemaText = @" + { + '$schema': 'http://json-schema.org/draft-04/schema#', + 'type': 'object', + 'properties': { + 'name': { + 'type': 'string' + }, + 'version': { + 'type': 'string' + } + }, + 'additionalProperties': false + }"; + + string testSettingsConfigs = new BasePTSettingsTest().ToJsonString(); + SettingsUtils.SaveSettings(testSettingsConfigs, file_name); + JsonSchema expectedSchema = JsonSchema.Parse(expectedSchemaText); + + // Act + JObject actualSchema = JObject.Parse(SettingsUtils.GetSettings(file_name).ToJsonString()); + bool valid = actualSchema.IsValid(expectedSchema); + + // Assert + Assert.IsTrue(valid); + } + } +} diff --git a/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ModelsTests/BasePTSettingsTest.cs b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ModelsTests/BasePTSettingsTest.cs new file mode 100644 index 0000000000..2bec4be724 --- /dev/null +++ b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ModelsTests/BasePTSettingsTest.cs @@ -0,0 +1,17 @@ +// 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.PowerToys.Settings.UI.Lib; + +namespace Microsoft.PowerToys.Settings.UnitTest +{ + public class BasePTSettingsTest : BasePTModuleSettings + { + public BasePTSettingsTest() + { + Name = string.Empty; + Version = string.Empty; + } + } +} diff --git a/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ModelsTests/HelperTest.cs b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ModelsTests/HelperTest.cs new file mode 100644 index 0000000000..421d044e4a --- /dev/null +++ b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ModelsTests/HelperTest.cs @@ -0,0 +1,76 @@ +// 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.PowerToys.Settings.UI.Lib.Utilities; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace CommonLibTest +{ + [TestClass] + public class HelperTest + { + public static void TestStringIsSmaller(string v1, string v2) + { + var res = Helper.CompareVersions(v1, v2); + Assert.IsTrue(res < 0); + } + + public static void TestStringsAreEqual(string v1, string v2) + { + var res = Helper.CompareVersions(v1, v2); + Assert.IsTrue(res == 0); + } + + [TestMethod] + public void Helper_CompareVersions_ShouldBeEqual_WhenSuccessful() + { + TestStringsAreEqual("v0.0.0", "v0.0.0"); + TestStringsAreEqual("v0.1.1", "v0.1.1"); + TestStringsAreEqual("v1.1.1", "v1.1.1"); + TestStringsAreEqual("v1.999.99", "v1.999.99"); + } + + [TestMethod] + public void Helper_CompareVersions_ShouldBeSmaller_WhenSuccessful() + { + TestStringIsSmaller("v0.0.0", "v0.0.1"); + TestStringIsSmaller("v0.0.0", "v0.1.0"); + TestStringIsSmaller("v0.0.0", "v1.0.0"); + TestStringIsSmaller("v1.0.1", "v1.0.2"); + TestStringIsSmaller("v1.1.1", "v1.1.2"); + TestStringIsSmaller("v1.1.1", "v1.2.0"); + TestStringIsSmaller("v1.999.99", "v2.0.0"); + TestStringIsSmaller("v1.0.99", "v1.2.0"); + } + + [TestMethod] + [ExpectedException(typeof(FormatException))] + public void Helper_CompareVersions_ShouldThrowBadFormat_WhenNoVersionString() + { + Helper.CompareVersions("v0.0.1", string.Empty); + } + + [TestMethod] + [ExpectedException(typeof(FormatException))] + public void Helper_CompareVersions_ShouldThrowBadFormat_WhenShortVersionString() + { + Helper.CompareVersions("v0.0.1", "v0.1"); + } + + [TestMethod] + [ExpectedException(typeof(FormatException))] + public void Helper_CompareVersions_ShouldThrowBadFormat_WhenLongVersionString() + { + Helper.CompareVersions("v0.0.1", "v0.0.0.1"); + } + + [TestMethod] + [ExpectedException(typeof(FormatException))] + public void Helper_CompareVersions_ShouldThrowBadFormat_WhenItIsNotAVersionString() + { + Helper.CompareVersions("v0.0.1", "HelloWorld"); + } + } +} diff --git a/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ModelsTests/SettingsUtilsTests.cs b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ModelsTests/SettingsUtilsTests.cs new file mode 100644 index 0000000000..dcb83fcba8 --- /dev/null +++ b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ModelsTests/SettingsUtilsTests.cs @@ -0,0 +1,123 @@ +// 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.IO; +using System.Linq; +using System.Text.Json; +using Microsoft.PowerToys.Settings.UI.Lib; +using Microsoft.PowerToys.Settings.UnitTest; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace CommonLibTest +{ + [TestClass] + public class SettingsUtilsTests + { + public SettingsUtilsTests() + { + string file_name = "\\test"; + if (SettingsUtils.SettingsFolderExists(file_name)) + { + DeleteFolder(file_name); + } + } + + [TestCleanup] + public void Cleanup() + { + string file_name = "\\test"; + if (SettingsUtils.SettingsFolderExists(file_name)) + { + DeleteFolder(file_name); + } + } + + [TestMethod] + public void SaveSettings_SaveSettingsToFile_WhenFilePathExists() + { + // Arrange + string file_name = "\\test"; + string file_contents_correct_json_content = "{\"name\":\"powertoy module name\",\"version\":\"powertoy version\"}"; + + BasePTSettingsTest expected_json = JsonSerializer.Deserialize(file_contents_correct_json_content); + + // Act + SettingsUtils.SaveSettings(file_contents_correct_json_content, file_name); + BasePTSettingsTest actual_json = SettingsUtils.GetSettings(file_name); + + // Assert + Assert.IsTrue(actual_json.Equals(actual_json)); + } + + [TestMethod] + public void SaveSettings_ShouldCreateFile_WhenFilePathIsNotFound() + { + // Arrange + string file_name = "test\\Test Folder"; + string file_contents_correct_json_content = "{\"name\":\"powertoy module name\",\"version\":\"powertoy version\"}"; + + BasePTSettingsTest expected_json = JsonSerializer.Deserialize(file_contents_correct_json_content); + + // Act + if (SettingsUtils.SettingsFolderExists(file_name)) + { + DeleteFolder(file_name); + } + + SettingsUtils.SaveSettings(file_contents_correct_json_content, file_name); + BasePTSettingsTest actual_json = SettingsUtils.GetSettings(file_name); + + // Assert + Assert.IsTrue(actual_json.Equals(actual_json)); + } + + [TestMethod] + public void SettingsFolderExists_ShouldReturnFalse_WhenFilePathIsNotFound() + { + // Arrange + string file_name_random = "test\\" + RandomString(); + string file_name_exists = "test\\exists"; + string file_contents_correct_json_content = "{\"name\":\"powertoy module name\",\"version\":\"powertoy version\"}"; + + // Act + bool pathNotFound = SettingsUtils.SettingsFolderExists(file_name_random); + + SettingsUtils.SaveSettings(file_contents_correct_json_content, file_name_exists); + bool pathFound = SettingsUtils.SettingsFolderExists(file_name_exists); + + // Assert + Assert.IsFalse(pathNotFound); + Assert.IsTrue(pathFound); + } + + [TestMethod] + public void CreateSettingsFolder_ShouldCreateFolder_WhenSuccessful() + { + // Arrange + string file_name = "test\\" + RandomString(); + + // Act + SettingsUtils.CreateSettingsFolder(file_name); + + // Assert + Assert.IsTrue(SettingsUtils.SettingsFolderExists(file_name)); + } + + public void DeleteFolder(string powertoy) + { + Directory.Delete(Path.Combine(SettingsUtils.LocalApplicationDataFolder(), $"Microsoft\\PowerToys\\{powertoy}"), true); + } + + public static string RandomString() + { + Random random = new Random(); + int length = 20; + const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + + return new string(Enumerable.Repeat(chars, length) + .Select(s => s[random.Next(s.Length)]).ToArray()); + } + } +} diff --git a/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/General.cs b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/General.cs new file mode 100644 index 0000000000..45e4660f85 --- /dev/null +++ b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/General.cs @@ -0,0 +1,201 @@ +// 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.IO; +using System.Text.Json; +using Microsoft.PowerToys.Settings.UI.Lib; +using Microsoft.PowerToys.Settings.UI.Lib.ViewModels; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace ViewModelTests +{ + [TestClass] + public class General + { + public const string generalSettings_file_name = "Test\\GenealSettings"; + + [TestInitialize] + public void Setup() + { + // initialize creation of test settings file. + GeneralSettings generalSettings = new GeneralSettings(); + SettingsUtils.SaveSettings(generalSettings.ToJsonString(), generalSettings_file_name); + } + + [TestCleanup] + public void CleanUp() + { + // delete folder created. + if (SettingsUtils.SettingsFolderExists(generalSettings_file_name)) + { + DeleteFolder(generalSettings_file_name); + } + } + + public void DeleteFolder(string powertoy) + { + Directory.Delete(Path.Combine(SettingsUtils.LocalApplicationDataFolder(), $"Microsoft\\PowerToys\\{powertoy}"), true); + } + + [TestMethod] + public void IsElevated_ShouldUpdateRunasAdminStatusAttrs_WhenSuccessful() + { + // Arrange + Func SendMockIPCConfigMSG = msg => { return 0; }; + Func SendRestartAdminIPCMessage = msg => { return 0; }; + Func SendCheckForUpdatesIPCMessage = msg => { return 0; }; + GeneralViewModel viewModel = new GeneralViewModel( + "GeneralSettings_RunningAsAdminText", + "GeneralSettings_RunningAsUserText", + false, + false, + UpdateUIThemeMethod, + SendMockIPCConfigMSG, + SendRestartAdminIPCMessage, + SendCheckForUpdatesIPCMessage, + generalSettings_file_name); + + Assert.AreEqual(viewModel.RunningAsUserDefaultText, viewModel.RunningAsText); + Assert.IsFalse(viewModel.IsElevated); + + // Act + viewModel.IsElevated = true; + + // Assert + Assert.AreEqual(viewModel.RunningAsAdminDefaultText, viewModel.RunningAsText); + Assert.IsTrue(viewModel.IsElevated); + } + + [TestMethod] + public void Startup_ShouldEnableRunOnStartUp_WhenSuccessful() + { + // Assert + Func SendMockIPCConfigMSG = msg => + { + OutGoingGeneralSettings snd = JsonSerializer.Deserialize(msg); + Assert.IsTrue(snd.GeneralSettings.Startup); + return 0; + }; + + // Arrange + Func SendRestartAdminIPCMessage = msg => { return 0; }; + Func SendCheckForUpdatesIPCMessage = msg => { return 0; }; + GeneralViewModel viewModel = new GeneralViewModel( + "GeneralSettings_RunningAsAdminText", + "GeneralSettings_RunningAsUserText", + false, + false, + UpdateUIThemeMethod, + SendMockIPCConfigMSG, + SendRestartAdminIPCMessage, + SendCheckForUpdatesIPCMessage, + generalSettings_file_name); + Assert.IsFalse(viewModel.Startup); + + // act + viewModel.Startup = true; + } + + [TestMethod] + public void RunElevated_ShouldEnableAlwaysRunElevated_WhenSuccessful() + { + // Assert + Func SendMockIPCConfigMSG = msg => + { + OutGoingGeneralSettings snd = JsonSerializer.Deserialize(msg); + Assert.IsTrue(snd.GeneralSettings.RunElevated); + return 0; + }; + + Func SendRestartAdminIPCMessage = msg => { return 0; }; + Func SendCheckForUpdatesIPCMessage = msg => { return 0; }; + + // Arrange + GeneralViewModel viewModel = new GeneralViewModel( + "GeneralSettings_RunningAsAdminText", + "GeneralSettings_RunningAsUserText", + false, + false, + UpdateUIThemeMethod, + SendMockIPCConfigMSG, + SendRestartAdminIPCMessage, + SendCheckForUpdatesIPCMessage, + generalSettings_file_name); + + Assert.IsFalse(viewModel.RunElevated); + + // act + viewModel.RunElevated = true; + } + + [TestMethod] + public void IsLightThemeRadioButtonChecked_ShouldThemeToLight_WhenSuccessful() + { + // Arrange + GeneralViewModel viewModel = null; + // Assert + Func SendMockIPCConfigMSG = msg => + { + OutGoingGeneralSettings snd = JsonSerializer.Deserialize(msg); + Assert.AreEqual("light", snd.GeneralSettings.Theme); + return 0; + }; + + Func SendRestartAdminIPCMessage = msg => { return 0; }; + Func SendCheckForUpdatesIPCMessage = msg => { return 0; }; + viewModel = new GeneralViewModel( + "GeneralSettings_RunningAsAdminText", + "GeneralSettings_RunningAsUserText", + false, + false, + UpdateUIThemeMethod, + SendMockIPCConfigMSG, + SendRestartAdminIPCMessage, + SendCheckForUpdatesIPCMessage, + generalSettings_file_name); + Assert.IsFalse(viewModel.IsLightThemeRadioButtonChecked); + + // act + viewModel.IsLightThemeRadioButtonChecked = true; + } + + [TestMethod] + public void IsDarkThemeRadioButtonChecked_ShouldThemeToDark_WhenSuccessful() + { + // Arrange + // Assert + Func SendMockIPCConfigMSG = msg => + { + OutGoingGeneralSettings snd = JsonSerializer.Deserialize(msg); + Assert.AreEqual("dark", snd.GeneralSettings.Theme); + return 0; + }; + + Func SendRestartAdminIPCMessage = msg => { return 0; }; + Func SendCheckForUpdatesIPCMessage = msg => { return 0; }; + GeneralViewModel viewModel = new GeneralViewModel( + "GeneralSettings_RunningAsAdminText", + "GeneralSettings_RunningAsUserText", + false, + false, + UpdateUIThemeMethod, + SendMockIPCConfigMSG, + SendRestartAdminIPCMessage, + SendCheckForUpdatesIPCMessage, + generalSettings_file_name); + Assert.IsFalse(viewModel.IsDarkThemeRadioButtonChecked); + + + + // act + viewModel.IsDarkThemeRadioButtonChecked = true; + } + + public int UpdateUIThemeMethod(string themeName) + { + return 0; + } + } +} diff --git a/src/core/Microsoft.PowerToys.Settings.UI/Microsoft.PowerToys.Settings.UI.csproj b/src/core/Microsoft.PowerToys.Settings.UI/Microsoft.PowerToys.Settings.UI.csproj index ec5dc1001a..69d2c51208 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI/Microsoft.PowerToys.Settings.UI.csproj +++ b/src/core/Microsoft.PowerToys.Settings.UI/Microsoft.PowerToys.Settings.UI.csproj @@ -110,7 +110,6 @@ - diff --git a/src/core/Microsoft.PowerToys.Settings.UI/Views/GeneralPage.xaml b/src/core/Microsoft.PowerToys.Settings.UI/Views/GeneralPage.xaml index 0016a71b80..d4e0ca8a1f 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI/Views/GeneralPage.xaml +++ b/src/core/Microsoft.PowerToys.Settings.UI/Views/GeneralPage.xaml @@ -3,7 +3,6 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:Microsoft.PowerToys.Settings.UI.Views" - xmlns:viewModel="using:Microsoft.PowerToys.Settings.UI.ViewModels" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:converters="using:Microsoft.Toolkit.Uwp.UI.Converters" @@ -14,7 +13,6 @@ - @@ -56,25 +54,25 @@ -