ThemeHelperTest.cs
1 // Copyright (c) Microsoft Corporation 2 // The Microsoft Corporation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System; 6 using System.Linq.Expressions; 7 using ManagedCommon; 8 using Microsoft.VisualStudio.TestTools.UnitTesting; 9 using Moq; 10 using PowerLauncher.Helper; 11 using PowerLauncher.Services; 12 13 namespace Wox.Test; 14 15 [TestClass] 16 public class ThemeHelperTest 17 { 18 // Registry key paths. 19 private const string ThemesKey = @"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes"; 20 private const string PersonalizeKey = ThemesKey + "\\Personalize"; 21 22 // Theme paths. 23 private const string HighContrastThemePath = @"C:\WINDOWS\resources\Ease of Access Themes\hcwhite.theme"; 24 private const string NonHighContrastThemePath = @"C:\Users\Test\AppData\Local\Microsoft\Windows\Themes\Custom.theme"; 25 26 /// <summary> 27 /// The expected High Contrast theme when the <see cref="HighContrastThemePath"/> is returned 28 /// from the registry. 29 /// </summary> 30 private const Theme HighContrastTheme = Theme.HighContrastWhite; 31 32 /// <summary> 33 /// Mock <see cref="IRegistryService.GetValue"/>, to return the value of the AppsUseLightTheme 34 /// key. 35 /// </summary> 36 private static readonly Expression<Func<IRegistryService, object>> _mockAppsUseLightTheme = (service) => 37 service.GetValue(PersonalizeKey, "AppsUseLightTheme", ThemeHelper.AppsUseLightThemeDefault); 38 39 /// <summary> 40 /// Mock <see cref="IRegistryService.GetValue"/> to return the value of the CurrentTheme key. 41 /// </summary> 42 /// <remarks> 43 /// The default value given here - string.Empty - must be the same as the default value in the 44 /// actual code for tests using this mock to be valid. 45 /// </remarks> 46 private static readonly Expression<Func<IRegistryService, object>> _mockCurrentTheme = (service) => 47 service.GetValue(ThemesKey, "CurrentTheme", string.Empty); 48 49 /// <summary> 50 /// Test GetAppsTheme method. 51 /// </summary> 52 /// <param name="registryValue">The mocked value for the AppsUseLightTheme registry key.</param> 53 /// <param name="expectedTheme">The expected <see cref="Theme"/> output from the call to 54 /// <see cref="ThemeHelper.GetAppsTheme"/>.</param> 55 [DataTestMethod] 56 [DataRow(ThemeHelper.AppsUseLightThemeLight, Theme.Light)] 57 [DataRow(ThemeHelper.AppsUseLightThemeDark, Theme.Dark)] 58 [DataRow(int.MaxValue, Theme.Light)] // Out of range values should default to Light 59 [DataRow(null, Theme.Light)] // Missing keys or values should default to Light 60 [DataRow("RandomString", Theme.Light)] // Invalid string values should default to Light 61 public void GetAppsTheme_ReturnsExpectedTheme(object registryValue, Theme expectedTheme) 62 { 63 var mockService = new Mock<IRegistryService>(); 64 mockService.Setup(_mockAppsUseLightTheme).Returns(registryValue); 65 66 var helper = new ThemeHelper(mockService.Object); 67 68 Assert.AreEqual(expectedTheme, helper.GetAppsTheme()); 69 } 70 71 /// <summary> 72 /// Test <see cref="ThemeHelper.GetHighContrastTheme"/>. 73 /// </summary> 74 /// <param name="registryValue">The mocked value for the CurrentTheme registry key.</param> 75 /// <param name="expectedTheme">The expected <see cref="Theme"/> output from the call to 76 /// <see cref="ThemeHelper.GetHighContrastTheme"/>.</param> 77 [DataTestMethod] 78 [DataRow(HighContrastThemePath, HighContrastTheme)] // Valid High Contrast theme 79 [DataRow(NonHighContrastThemePath, null)] // Non-High Contrast theme should return null 80 [DataRow(null, null)] // Missing keys or values should default to null 81 [DataRow("", null)] // Empty string values should default to null 82 public void GetHighContrastTheme_ReturnsExpectedTheme(string registryValue, Theme? expectedTheme) 83 { 84 var mockService = new Mock<IRegistryService>(); 85 mockService.Setup(_mockCurrentTheme).Returns(registryValue); 86 87 var helper = new ThemeHelper(mockService.Object); 88 89 Assert.AreEqual(expectedTheme, helper.GetHighContrastTheme()); 90 } 91 92 /// <summary> 93 /// Test <see cref="ThemeHelper.DetermineTheme"/>. 94 /// </summary> 95 /// <param name="registryTheme">The mocked value for the CurrentTheme registry key.</param> 96 /// <param name="requestedTheme">The <see cref="Theme"/> value from the application's settings. 97 /// </param> 98 /// <param name="expectedTheme">The expected <see cref="Theme"/> output from the call to 99 /// <see cref="ThemeHelper.DetermineTheme"/>.</param> 100 /// <param name="appsUseLightTheme">The mocked value for the AppsUseLightTheme registry key, 101 /// representing the system preference for Light or Dark mode.</param> 102 [DataTestMethod] 103 [DataRow(HighContrastThemePath, Theme.System, HighContrastTheme)] // High Contrast theme active 104 [DataRow(HighContrastThemePath, Theme.Light, HighContrastTheme)] // High Contrast theme active - Light mode override ignored 105 [DataRow(HighContrastThemePath, Theme.Dark, HighContrastTheme)] // High Contrast theme active - Dark mode override ignored 106 [DataRow(NonHighContrastThemePath, Theme.System, Theme.Light)] // System preference with default light theme 107 [DataRow(NonHighContrastThemePath, Theme.System, Theme.Dark, ThemeHelper.AppsUseLightThemeDark)] // System preference with dark mode 108 [DataRow(NonHighContrastThemePath, Theme.Light, Theme.Light, ThemeHelper.AppsUseLightThemeDark)] // Light mode override 109 [DataRow(NonHighContrastThemePath, Theme.Dark, Theme.Dark, ThemeHelper.AppsUseLightThemeLight)] // Dark mode override 110 [DataRow(null, Theme.System, Theme.Light)] // Missing keys or values should default to Light 111 [DataRow("", Theme.System, Theme.Light)] // Empty current theme paths should default to Light 112 [DataRow("RandomString", Theme.System, Theme.Light)] // Invalid current theme paths should default to Light 113 [DataRow(NonHighContrastThemePath, (Theme)int.MaxValue, Theme.Light)] // Invalid theme values should default to Light 114 public void DetermineTheme_ReturnsExpectedTheme(string registryTheme, Theme requestedTheme, Theme expectedTheme, int? appsUseLightTheme = 1) 115 { 116 var mockService = new Mock<IRegistryService>(); 117 mockService.Setup(_mockCurrentTheme).Returns(registryTheme); 118 mockService.Setup(_mockAppsUseLightTheme).Returns(appsUseLightTheme); 119 120 var helper = new ThemeHelper(mockService.Object); 121 122 Assert.AreEqual(expectedTheme, helper.DetermineTheme(requestedTheme)); 123 } 124 }