QueryTests.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.Collections.Generic; 6 using System.IO; 7 using System.Linq; 8 using System.Threading.Tasks; 9 using Microsoft.CmdPal.Core.Common.Services; 10 using Microsoft.CmdPal.Ext.Shell.Pages; 11 using Microsoft.CmdPal.Ext.UnitTestBase; 12 using Microsoft.CommandPalette.Extensions; 13 using Microsoft.VisualStudio.TestTools.UnitTesting; 14 using Moq; 15 16 namespace Microsoft.CmdPal.Ext.Shell.UnitTests; 17 18 [TestClass] 19 public class QueryTests : CommandPaletteUnitTestBase 20 { 21 private static Mock<IRunHistoryService> CreateMockHistoryService(IList<string> historyItems = null) 22 { 23 var mockHistoryService = new Mock<IRunHistoryService>(); 24 var history = historyItems ?? new List<string>(); 25 26 mockHistoryService.Setup(x => x.GetRunHistory()) 27 .Returns(() => history.ToList().AsReadOnly()); 28 29 mockHistoryService.Setup(x => x.AddRunHistoryItem(It.IsAny<string>())) 30 .Callback<string>(item => 31 { 32 if (!string.IsNullOrWhiteSpace(item)) 33 { 34 history.Remove(item); 35 history.Insert(0, item); 36 } 37 }); 38 39 mockHistoryService.Setup(x => x.ClearRunHistory()) 40 .Callback(() => history.Clear()); 41 42 return mockHistoryService; 43 } 44 45 private static Mock<IRunHistoryService> CreateMockHistoryServiceWithCommonCommands() 46 { 47 var commonCommands = new List<string> 48 { 49 "ping google.com", 50 "ipconfig /all", 51 "curl https://api.github.com", 52 "dir", 53 "cd ..", 54 "git status", 55 "npm install", 56 "python --version", 57 }; 58 59 return CreateMockHistoryService(commonCommands); 60 } 61 62 [TestMethod] 63 public void ValidateHistoryFunctionality() 64 { 65 // Setup 66 var settings = Settings.CreateDefaultSettings(); 67 68 // Act 69 settings.AddCmdHistory("test-command"); 70 71 // Assert 72 Assert.AreEqual(1, settings.Count["test-command"]); 73 } 74 75 [TestMethod] 76 [DataRow("ping bing.com", "ping.exe")] 77 [DataRow("curl bing.com", "curl.exe")] 78 [DataRow("ipconfig /all", "ipconfig.exe")] 79 [DataRow("\"C:\\Program Files\\Windows Defender\\MsMpEng.exe\"", "MsMpEng.exe")] 80 [DataRow("C:\\Program Files\\Windows Defender\\MsMpEng.exe", "MsMpEng.exe")] 81 public async Task QueryWithoutHistoryCommand(string command, string exeName) 82 { 83 // Setup 84 var settings = Settings.CreateDefaultSettings(); 85 var mockHistory = CreateMockHistoryService(); 86 87 var pages = new ShellListPage(settings, mockHistory.Object, telemetryService: null); 88 89 await UpdatePageAndWaitForItems(pages, () => 90 { 91 // Test: Search for a command that exists in history 92 pages.UpdateSearchText(string.Empty, command); 93 }); 94 95 var commandList = pages.GetItems(); 96 97 Assert.AreEqual(1, commandList.Length); 98 99 var listItem = commandList.FirstOrDefault(); 100 Assert.IsNotNull(listItem); 101 102 var runExeListItem = listItem as RunExeItem; 103 Assert.IsNotNull(runExeListItem); 104 Assert.AreEqual(exeName, runExeListItem.Exe); 105 Assert.IsTrue(listItem.Title.Contains(exeName), $"expect ${exeName} but got ${listItem.Title}"); 106 Assert.IsNotNull(listItem.Icon); 107 } 108 109 [TestMethod] 110 [DataRow("ping bing.com", "ping.exe")] 111 [DataRow("curl bing.com", "curl.exe")] 112 [DataRow("ipconfig /all", "ipconfig.exe")] 113 public async Task QueryWithHistoryCommands(string command, string exeName) 114 { 115 // Setup 116 var settings = Settings.CreateDefaultSettings(); 117 var mockHistoryService = CreateMockHistoryServiceWithCommonCommands(); 118 119 var pages = new ShellListPage(settings, mockHistoryService.Object, telemetryService: null); 120 121 await UpdatePageAndWaitForItems(pages, () => 122 { 123 // Test: Search for a command that exists in history 124 pages.UpdateSearchText(string.Empty, command); 125 }); 126 127 var commandList = pages.GetItems(); 128 129 // Should find at least the ping command from history 130 Assert.IsTrue(commandList.Length > 1); 131 132 var expectedCommand = commandList.FirstOrDefault(); 133 Assert.IsNotNull(expectedCommand); 134 Assert.IsNotNull(expectedCommand.Icon); 135 Assert.IsTrue(expectedCommand.Title.Contains(exeName), $"expect ${exeName} but got ${expectedCommand.Title}"); 136 } 137 138 [TestMethod] 139 public async Task EmptyQueryWithHistoryCommands() 140 { 141 // Setup 142 var settings = Settings.CreateDefaultSettings(); 143 var mockHistoryService = CreateMockHistoryServiceWithCommonCommands(); 144 145 var pages = new ShellListPage(settings, mockHistoryService.Object, telemetryService: null); 146 147 await UpdatePageAndWaitForItems(pages, () => 148 { 149 // Test: Search for a command that exists in history 150 pages.UpdateSearchText("abcdefg", string.Empty); 151 }); 152 153 var commandList = pages.GetItems(); 154 155 // Should find at least the ping command from history 156 Assert.IsTrue(commandList.Length > 1); 157 } 158 159 [TestMethod] 160 public async Task TestCacheBackToSameDirectory() 161 { 162 // Setup 163 var settings = Settings.CreateDefaultSettings(); 164 var mockHistoryService = CreateMockHistoryService(); 165 166 var page = new ShellListPage(settings, mockHistoryService.Object, telemetryService: null); 167 168 // Load up everything in c:\, for the sake of comparing: 169 var filesInC = Directory.EnumerateFileSystemEntries("C:\\"); 170 171 await UpdatePageAndWaitForItems(page, () => { page.SearchText = "c:\\"; }); 172 173 var commandList = page.GetItems(); 174 175 // Should find only items for what's in c:\ 176 Assert.IsTrue(commandList.Length == filesInC.Count()); 177 178 await UpdatePageAndWaitForItems(page, () => { page.SearchText = "c:\\Win"; }); 179 await UpdatePageAndWaitForItems(page, () => { page.SearchText = "c:\\Windows"; }); 180 await UpdatePageAndWaitForItems(page, () => { page.SearchText = "c:\\"; }); 181 182 commandList = page.GetItems(); 183 184 // Should still find everything 185 Assert.IsTrue(commandList.Length == filesInC.Count()); 186 187 await TypeStringIntoPage(page, "c:\\Windows\\Pro"); 188 await BackspaceSearchText(page, "c:\\Windows\\Pro", 3); // 3 characters for c:\ 189 190 commandList = page.GetItems(); 191 192 // Should still find everything 193 Assert.IsTrue(commandList.Length == filesInC.Count()); 194 } 195 196 private async Task TypeStringIntoPage(IDynamicListPage page, string searchText) 197 { 198 // type the string one character at a time 199 for (var i = 0; i < searchText.Length; i++) 200 { 201 var substr = searchText[..i]; 202 await UpdatePageAndWaitForItems(page, () => { page.SearchText = substr; }); 203 } 204 } 205 206 private async Task BackspaceSearchText(IDynamicListPage page, string originalSearchText, int finalStringLength) 207 { 208 var originalLength = originalSearchText.Length; 209 for (var i = originalLength; i >= finalStringLength; i--) 210 { 211 var substr = originalSearchText[..i]; 212 await UpdatePageAndWaitForItems(page, () => { page.SearchText = substr; }); 213 } 214 } 215 216 [TestMethod] 217 public async Task TestCacheSameDirectorySlashy() 218 { 219 // Setup 220 var settings = Settings.CreateDefaultSettings(); 221 var mockHistoryService = CreateMockHistoryService(); 222 223 var page = new ShellListPage(settings, mockHistoryService.Object, telemetryService: null); 224 225 // Load up everything in c:\, for the sake of comparing: 226 var filesInC = Directory.EnumerateFileSystemEntries("C:\\"); 227 var filesInWindows = Directory.EnumerateFileSystemEntries("C:\\Windows"); 228 await UpdatePageAndWaitForItems(page, () => { page.SearchText = "c:\\"; }); 229 230 var commandList = page.GetItems(); 231 Assert.IsTrue(commandList.Length == filesInC.Count()); 232 233 // First navigate to c:\Windows. This should match everything that matches "windows" inside of C:\ 234 await UpdatePageAndWaitForItems(page, () => { page.SearchText = "c:\\Windows"; }); 235 var cWindowsCommandsPre = page.GetItems(); 236 237 // Then go into c:\windows\. This will only have the results in c:\windows\ 238 await UpdatePageAndWaitForItems(page, () => { page.SearchText = "c:\\Windows\\"; }); 239 var windowsCommands = page.GetItems(); 240 Assert.IsTrue(windowsCommands.Length != cWindowsCommandsPre.Length); 241 242 // now go back to c:\windows. This should match the results from the last time we entered this string 243 await UpdatePageAndWaitForItems(page, () => { page.SearchText = "c:\\Windows"; }); 244 var cWindowsCommandsPost = page.GetItems(); 245 Assert.IsTrue(cWindowsCommandsPre.Length == cWindowsCommandsPost.Length); 246 } 247 248 [TestMethod] 249 public async Task TestPathWithSpaces() 250 { 251 // Setup 252 var settings = Settings.CreateDefaultSettings(); 253 var mockHistoryService = CreateMockHistoryService(); 254 255 var page = new ShellListPage(settings, mockHistoryService.Object, telemetryService: null); 256 257 // Load up everything in c:\, for the sake of comparing: 258 var filesInC = Directory.EnumerateFileSystemEntries("C:\\"); 259 var filesInProgramFiles = Directory.EnumerateFileSystemEntries("C:\\Program Files"); 260 await UpdatePageAndWaitForItems(page, () => { page.SearchText = "c:\\Program Files\\"; }); 261 262 var commandList = page.GetItems(); 263 Assert.IsTrue(commandList.Length == filesInProgramFiles.Count()); 264 } 265 266 [TestMethod] 267 public async Task TestNoWrapSuggestionsWithSpaces() 268 { 269 // Setup 270 var settings = Settings.CreateDefaultSettings(); 271 var mockHistoryService = CreateMockHistoryService(); 272 273 var page = new ShellListPage(settings, mockHistoryService.Object, telemetryService: null); 274 275 await UpdatePageAndWaitForItems(page, () => { page.SearchText = "c:\\Program Files\\"; }); 276 277 var commandList = page.GetItems(); 278 279 foreach (var item in commandList) 280 { 281 Assert.IsTrue(!string.IsNullOrEmpty(item.TextToSuggest)); 282 Assert.IsFalse(item.TextToSuggest.StartsWith('"')); 283 } 284 } 285 }