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;
  6  using System.Globalization;
  7  using System.Linq;
  8  using Microsoft.CmdPal.Ext.TimeDate.Helpers;
  9  using Microsoft.CmdPal.Ext.TimeDate.Pages;
 10  using Microsoft.CmdPal.Ext.UnitTestBase;
 11  using Microsoft.VisualStudio.TestTools.UnitTesting;
 12  
 13  namespace Microsoft.CmdPal.Ext.TimeDate.UnitTests;
 14  
 15  [TestClass]
 16  public class QueryTests : CommandPaletteUnitTestBase
 17  {
 18      private CultureInfo originalCulture;
 19      private CultureInfo originalUiCulture;
 20  
 21      [TestInitialize]
 22      public void Setup()
 23      {
 24          // Set culture to 'en-us'
 25          originalCulture = CultureInfo.CurrentCulture;
 26          CultureInfo.CurrentCulture = new CultureInfo("en-us", false);
 27          originalUiCulture = CultureInfo.CurrentUICulture;
 28          CultureInfo.CurrentUICulture = new CultureInfo("en-us", false);
 29      }
 30  
 31      [TestCleanup]
 32      public void CleanUp()
 33      {
 34          // Set culture to original value
 35          CultureInfo.CurrentCulture = originalCulture;
 36          CultureInfo.CurrentUICulture = originalUiCulture;
 37      }
 38  
 39      [DataTestMethod]
 40      [DataRow("time", 1)] // Common time queries should return results
 41      [DataRow("date", 1)] // Common date queries should return results
 42      [DataRow("now", 1)] // Now should return multiple results
 43      [DataRow("current", 1)] // Current should return multiple results
 44      [DataRow("year", 1)] // Year-related queries should return results
 45      [DataRow("time::10:10:10", 1)] // Specific time format should return results
 46      [DataRow("date::10/10/10", 1)] // Specific date format should return results
 47      public void CountBasicQueries(string query, int expectedMinResultCount)
 48      {
 49          // Setup
 50          var settings = new Settings();
 51  
 52          // Act
 53          var results = TimeDateCalculator.ExecuteSearch(settings, query);
 54  
 55          // Assert
 56          Assert.IsTrue(
 57              results.Count >= expectedMinResultCount,
 58              $"Expected at least {expectedMinResultCount} results for query '{query}', but got {results.Count}");
 59      }
 60  
 61      [DataTestMethod]
 62      [DataRow("time", "time")]
 63      [DataRow("date", "date")]
 64      [DataRow("year", "year")]
 65      [DataRow("now", "now")]
 66      [DataRow("year", "year")]
 67      public void BasicQueryTest(string input, string expectedMatchTerm)
 68      {
 69          var settings = new Settings();
 70          var page = new TimeDateExtensionPage(settings);
 71          page.UpdateSearchText(string.Empty, input);
 72          var resultLists = page.GetItems();
 73  
 74          var result = Query(input, resultLists);
 75  
 76          Assert.IsNotNull(result);
 77          Assert.IsTrue(result.Length > 0, "No items matched the query.");
 78  
 79          var firstItem = result.FirstOrDefault();
 80          Assert.IsNotNull(firstItem, "No items matched the query.");
 81          Assert.IsTrue(
 82              firstItem.Title.Contains(expectedMatchTerm, System.StringComparison.OrdinalIgnoreCase) ||
 83              firstItem.Subtitle.Contains(expectedMatchTerm, System.StringComparison.OrdinalIgnoreCase),
 84              $"Expected to match '{expectedMatchTerm}' in title or subtitle but got '{firstItem.Title}' - '{firstItem.Subtitle}'");
 85      }
 86  
 87      [DataTestMethod]
 88      [DataRow("unix", "Unix epoch time")]
 89      [DataRow("unix epoch time in milli", "Unix epoch time in milliseconds")]
 90      [DataRow("file", "Windows file time (Int64 number)")]
 91      [DataRow("hour", "Hour")]
 92      [DataRow("minute", "Minute")]
 93      [DataRow("second", "Second")]
 94      [DataRow("millisecond", "Millisecond")]
 95      [DataRow("day", "Day (Week day)")]
 96      [DataRow("day of week", "Day of the week (Week day)")]
 97      [DataRow("day of month", "Day of the month")]
 98      [DataRow("day of year", "Day of the year")]
 99      [DataRow("week of month", "Week of the month")]
100      [DataRow("week of year", "Week of the year (Calendar week, Week number)")]
101      [DataRow("month", "Month")]
102      [DataRow("month of year", "Month of the year")]
103      [DataRow("month and d", "Month and day")]
104      [DataRow("year", "Year")]
105      [DataRow("universal", "Universal time format: YYYY-MM-DD hh:mm:ss")]
106      [DataRow("rfc", "RFC1123")]
107      [DataRow("time::12:30", "Time")]
108      [DataRow("date::10.10.2022", "Date")]
109      [DataRow("time::u1646408119", "Time")]
110      [DataRow("time::ft637820085517321977", "Time")]
111      [DataRow("week day", "Day (Week day)")]
112      [DataRow("cal week", "Week of the year (Calendar week, Week number)")]
113      [DataRow("week num", "Week of the year (Calendar week, Week number)")]
114      [DataRow("days in mo", "Days in month")]
115      [DataRow("Leap y", "Leap year")]
116      public void FormatDateQueryTest(string input, string expectedMatchTerm)
117      {
118          var settings = new Settings();
119          var page = new TimeDateExtensionPage(settings);
120          page.UpdateSearchText(string.Empty, input);
121          var resultLists = page.GetItems();
122  
123          var firstItem = resultLists.FirstOrDefault();
124          Assert.IsNotNull(firstItem, "No items matched the query.");
125          Assert.IsTrue(
126              firstItem.Title.Contains(expectedMatchTerm, System.StringComparison.OrdinalIgnoreCase) ||
127              firstItem.Subtitle.Contains(expectedMatchTerm, System.StringComparison.OrdinalIgnoreCase),
128              $"Expected to match '{expectedMatchTerm}' in title or subtitle but got '{firstItem.Title}' - '{firstItem.Subtitle}'");
129      }
130  
131      [DataTestMethod]
132      [DataRow("abcdefg")]
133      [DataRow("timmmmeeee")]
134      [DataRow("timtaaaetetaae::u1646408119")]
135      [DataRow("time:eeee")]
136      [DataRow("time::eeee")]
137      [DataRow("time//eeee")]
138      [DataRow("ug1646408119")] // Invalid prefix
139      [DataRow("u9999999999999")] // Unix number + prefix is longer than 12 characters
140      [DataRow("ums999999999999999")] // Unix number in milliseconds + prefix is longer than 17 characters
141      [DataRow("-u99999999999")] // Unix number with wrong placement of - sign
142      [DataRow("+ums9999999999")] // Unix number in milliseconds with wrong placement of + sign
143      [DataRow("0123456")] // Missing prefix
144      [DataRow("ft63782008ab55173dasdas21977")] // Number contains letters
145      [DataRow("ft63782008ab55173dasdas")] // Number contains letters at the end
146      [DataRow("ft12..548")] // Number contains wrong punctuation
147      [DataRow("ft12..54//8")] // Number contains wrong punctuation and other characters
148      [DataRow("time::ft12..54//8")] // Number contains wrong punctuation and other characters
149      [DataRow("ut2ed.5555")] // Number contains letters
150      [DataRow("12..54//8")] // Number contains punctuation and other characters, but no special prefix
151      [DataRow("ft::1288gg8888")] // Number contains delimiter and letters, but no special prefix
152      [DataRow("date::12::55")]
153      [DataRow("date::12:aa:55")]
154      [DataRow("10.aa.22")]
155      [DataRow("12::55")]
156      [DataRow("12:aa:55")]
157      public void InvalidInputShowsErrorResults(string query)
158      {
159          var settings = new Settings();
160          var page = new TimeDateExtensionPage(settings);
161          page.UpdateSearchText(string.Empty, query);
162          var results = page.GetItems();
163  
164          // Assert
165          Assert.IsNotNull(results, $"Results should not be null for query '{query}'");
166          Assert.IsTrue(results.Length > 0, $"Query '{query}' should return at least one result");
167  
168          var firstItem = results.FirstOrDefault();
169          Assert.IsTrue(firstItem.Title.StartsWith("Error: Invalid input", StringComparison.CurrentCulture), $"Query '{query}' should return an error result for invalid input");
170      }
171  
172      [DataTestMethod]
173      [DataRow("")]
174      [DataRow(null)]
175      public void EmptyQueryReturnsAllResults(string input)
176      {
177          var settings = new Settings();
178          var page = new TimeDateExtensionPage(settings);
179          page.UpdateSearchText("abc", input);
180          var results = page.GetItems();
181  
182          // Assert
183          Assert.IsTrue(results.Length > 0, $"Empty query should return results");
184      }
185  
186      [DataTestMethod]
187      [DataRow("time u", "Time UTC")]
188      [DataRow("now u", "Now UTC")]
189      [DataRow("iso utc", "ISO 8601 UTC")]
190      [DataRow("iso zone", "ISO 8601 with time zone")]
191      [DataRow("iso utc zone", "ISO 8601 UTC with time zone")]
192      public void TimeZoneQuery(string query, string expectedSubtitle)
193      {
194          var settings = new Settings();
195          var page = new TimeDateExtensionPage(settings);
196          page.UpdateSearchText(string.Empty, query);
197          var resultsList = page.GetItems();
198          var results = Query(query, resultsList);
199  
200          // Assert
201          Assert.IsNotNull(results);
202          var firstResult = results.FirstOrDefault();
203          Assert.IsTrue(firstResult.Subtitle.StartsWith(expectedSubtitle, StringComparison.CurrentCulture), $"Could not find result with subtitle starting with '{expectedSubtitle}' for query '{query}'");
204      }
205  
206      [DataTestMethod]
207      [DataRow("time::12:30:45", "12:30 PM")]
208      [DataRow("date::2023-12-25", "12/25/2023")]
209      [DataRow("now::u1646408119", "132908817190000000")]
210      public void DelimiterQueriesReturnResults(string query, string expectedResult)
211      {
212          var settings = new Settings();
213          var page = new TimeDateExtensionPage(settings);
214          page.UpdateSearchText(string.Empty, query);
215          var resultsList = page.GetItems();
216  
217          // Assert
218          Assert.IsNotNull(resultsList);
219          var firstResult = resultsList.FirstOrDefault();
220          Assert.IsTrue(firstResult.Title.Contains(expectedResult, StringComparison.CurrentCulture), $"Delimiter query '{query}' result not match {expectedResult} current result {firstResult.Title}");
221      }
222  }