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  
  9  using Microsoft.VisualStudio.TestTools.UnitTesting;
 10  using Moq;
 11  using Wox.Infrastructure;
 12  using Wox.Plugin;
 13  
 14  namespace Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests
 15  {
 16      [TestClass]
 17      public class QueryTests
 18      {
 19          private CultureInfo originalCulture;
 20          private CultureInfo originalUiCulture;
 21  
 22          [TestInitialize]
 23          public void Setup()
 24          {
 25              StringMatcher.Instance = new StringMatcher();
 26  
 27              // Set culture to 'en-us'
 28              originalCulture = CultureInfo.CurrentCulture;
 29              CultureInfo.CurrentCulture = new CultureInfo("en-us", false);
 30              originalUiCulture = CultureInfo.CurrentUICulture;
 31              CultureInfo.CurrentUICulture = new CultureInfo("en-us", false);
 32          }
 33  
 34          [DataTestMethod]
 35          [DataRow("time", 2)] // Setting 'Only Date, Time, Now on global results' is default on
 36          [DataRow("date", 2)] // Setting 'Only Date, Time, Now on global results' is default on
 37          [DataRow("now", 3)] // Setting 'Only Date, Time, Now on global results' is default on
 38          [DataRow("current", 3)] // Setting 'Only Date, Time, Now on global results' is default on
 39          [DataRow("year", 0)] // Setting 'Only Date, Time, Now on global results' is default on
 40          [DataRow("time::10:10:10", 0)] // Setting 'Only Date, Time, Now on global results' is default on
 41          [DataRow("date::10/10/10", 0)] // Setting 'Only Date, Time, Now on global results' is default on
 42          public void CountWithoutPluginKeyword(string typedString, int expectedResultCount)
 43          {
 44              // Setup
 45              Mock<Main> main = new();
 46              Query expectedQuery = new(typedString);
 47  
 48              // Act
 49              var result = main.Object.Query(expectedQuery).Count;
 50  
 51              // Assert
 52              Assert.AreEqual(expectedResultCount, result, "Result depends on default plugin settings!");
 53          }
 54  
 55          [DataTestMethod]
 56          [DataRow("(time", 18)]
 57          [DataRow("(date", 28)]
 58          [DataRow("(year", 8)]
 59          [DataRow("(now", 34)]
 60          [DataRow("(current", 34)]
 61          [DataRow("(", 34)]
 62          [DataRow("(now::10:10:10", 1)] // Windows file time
 63          [DataRow("(current::10:10:10", 0)]
 64          public void CountWithPluginKeyword(string typedString, int expectedResultCount)
 65          {
 66              // Setup
 67              Mock<Main> main = new();
 68              Query expectedQuery = new(typedString, "(");
 69  
 70              // Act
 71              var result = main.Object.Query(expectedQuery);
 72  
 73              // Assert
 74              Assert.AreEqual(expectedResultCount, result.Count, result.ToString());
 75          }
 76  
 77          [DataTestMethod]
 78          [DataRow("time", 2)] // Match if first word is a full word match
 79          [DataRow("ime", 0)] // Don't match if first word is not a full match
 80          [DataRow("and", 0)] // Don't match for only conjunctions
 81          [DataRow("and time", 1)] // match if term is conjunction and other words
 82          [DataRow("date and time", 1)] // Match if first word is a full word match
 83          [DataRow("ate and time", 0)] // Don't match if first word is not a full word match
 84          [DataRow("10/10/10", 0)] // Don't match number only input (Setting 'Only Date, Time, Now on global results' is default on)
 85          [DataRow("10:10:10", 0)] // Don't match number only input (Setting 'Only Date, Time, Now on global results' is default on)
 86          [DataRow("10 10 10", 0)] // Don't match number only input (Setting 'Only Date, Time, Now on global results' is default on)
 87          [DataRow("ft10", 1)] // Don't match number input with prefix (Setting 'Only Date, Time, Now on global results' is default on) => Test behave strange here.
 88          public void ValidateBehaviorOnGlobalQueries(string typedString, int expectedResultCount)
 89          {
 90              // Setup
 91              Mock<Main> main = new();
 92              Query expectedQuery = new(typedString);
 93  
 94              // Act
 95              var result = main.Object.Query(expectedQuery);
 96  
 97              // Assert
 98              Assert.AreEqual(expectedResultCount, result.Count, result.ToString());
 99          }
100  
101          [DataTestMethod]
102          [DataRow("(time", "Time -")]
103          [DataRow("(time u", "Time UTC -")]
104          [DataRow("(date", "Date -")]
105          [DataRow("(now", "Now -")]
106          [DataRow("(now u", "Now UTC -")]
107          [DataRow("(unix", "Unix epoch time -")]
108          [DataRow("(unix epoch time in milli", "Unix epoch time in milliseconds -")]
109          [DataRow("(file", "Windows file time (Int64 number) ")]
110          [DataRow("(hour", "Hour -")]
111          [DataRow("(minute", "Minute -")]
112          [DataRow("(second", "Second -")]
113          [DataRow("(millisecond", "Millisecond -")]
114          [DataRow("(day", "Day (Week day) -")]
115          [DataRow("(day of week", "Day of the week (Week day) -")]
116          [DataRow("(day of month", "Day of the month -")]
117          [DataRow("(day of year", "Day of the year -")]
118          [DataRow("(week of month", "Week of the month -")]
119          [DataRow("(week of year", "Week of the year (Calendar week, Week number) -")]
120          [DataRow("(month", "Month -")]
121          [DataRow("(month of year", "Month of the year -")]
122          [DataRow("(month and d", "Month and day -")]
123          [DataRow("(month and y", "Month and year -")]
124          [DataRow("(year", "Year -")]
125          [DataRow("(era", "Era -")]
126          [DataRow("(era a", "Era abbreviation -")]
127          [DataRow("(universal", "Universal time format: YYYY-MM-DD hh:mm:ss -")]
128          [DataRow("(iso", "ISO 8601 -")]
129          [DataRow("(iso utc", "ISO 8601 UTC -")]
130          [DataRow("(iso zone", "ISO 8601 with time zone - ")]
131          [DataRow("(iso utc zone", "ISO 8601 UTC with time zone -")]
132          [DataRow("(rfc", "RFC1123 -")]
133          [DataRow("(time::12:30", "Time -")]
134          [DataRow("(date::10.10.2022", "Date -")]
135          [DataRow("(time::u1646408119", "Time -")]
136          [DataRow("(time::ft637820085517321977", "Time -")]
137          [DataRow("(year", "Era -")]
138          [DataRow("(date", "Era -")]
139          [DataRow("(week day", "Day (Week day) -")]
140          [DataRow("(week day", "Day of the week (Week day) -")]
141          [DataRow("(cal week", "Week of the year (Calendar week, Week number) -")]
142          [DataRow("(week num", "Week of the year (Calendar week, Week number) -")]
143          [DataRow("(days in mo", "Days in month -")]
144          [DataRow("(Leap y", "Leap year -")]
145          public void CanFindFormatResult(string typedString, string expectedResult)
146          {
147              // Setup
148              Mock<Main> main = new();
149              Query expectedQuery = new(typedString, "(");
150  
151              // Act
152              var result = main.Object.Query(expectedQuery).FirstOrDefault(x => x.SubTitle.StartsWith(expectedResult, StringComparison.CurrentCulture));
153  
154              // Assert
155              Assert.IsNotNull(result);
156              Assert.IsTrue(result?.Score >= 1, $"Score: {result?.Score}");
157          }
158  
159          [DataTestMethod]
160          [DataRow("(12:30", "Time -")]
161          [DataRow("(10.10.2022", "Date -")]
162          [DataRow("(u1646408119", "Date and time -")]
163          [DataRow("(u+1646408119", "Date and time -")]
164          [DataRow("(u-1646408119", "Date and time -")]
165          [DataRow("(ums1646408119", "Date and time -")]
166          [DataRow("(ums+1646408119", "Date and time -")]
167          [DataRow("(ums-1646408119", "Date and time -")]
168          [DataRow("(ft637820085517321977", "Date and time -")]
169          public void DateTimeNumberOnlyInput(string typedString, string expectedResult)
170          {
171              // Setup
172              Mock<Main> main = new();
173              Query expectedQuery = new(typedString, "(");
174  
175              // Act
176              var result = main.Object.Query(expectedQuery).FirstOrDefault(x => x.SubTitle.StartsWith(expectedResult, StringComparison.CurrentCulture));
177  
178              // Assert
179              Assert.IsNotNull(result);
180          }
181  
182          // [DataRow("(::")] -> Behaves different to PT Run user interface
183          // [DataRow("(time::")] -> Behaves different to PT Run user interface
184          // [DataRow("(::time")] -> Behaves different to PT Run user interface
185          [DataTestMethod]
186          [DataRow("(abcdefg")]
187          [DataRow("(timmmmeeee")]
188          [DataRow("(timtaaaetetaae::u1646408119")]
189          [DataRow("(time:eeee")]
190          [DataRow("(time::eeee")]
191          [DataRow("(time//eeee")]
192          public void InvalidInputNotShowsResults(string typedString)
193          {
194              // Setup
195              Mock<Main> main = new();
196              Query expectedQuery = new(typedString, "(");
197  
198              // Act
199              var result = main.Object.Query(expectedQuery).FirstOrDefault();
200  
201              // Assert
202              Assert.IsNull(result, result?.ToString());
203          }
204  
205          [DataTestMethod]
206          [DataRow("(ug1646408119")] // Invalid prefix
207          [DataRow("(u9999999999999")] // Unix number + prefix is longer than 12 characters
208          [DataRow("(ums999999999999999")] // Unix number in milliseconds + prefix is longer than 17 characters
209          [DataRow("(-u99999999999")] // Unix number with wrong placement of - sign
210          [DataRow("(+ums9999999999")] // Unix number in milliseconds with wrong placement of + sign
211          [DataRow("(0123456")] // Missing prefix
212          [DataRow("(ft63782008ab55173dasdas21977")] // Number contains letters
213          [DataRow("(ft63782008ab55173dasdas")] // Number contains letters at the end
214          [DataRow("(ft12..548")] // Number contains wrong punctuation
215          [DataRow("(ft12..54//8")] // Number contains wrong punctuation and other characters
216          [DataRow("(time::ft12..54//8")] // Number contains wrong punctuation and other characters
217          [DataRow("(ut2ed.5555")] // Number contains letters
218          [DataRow("(12..54//8")] // Number contains punctuation and other characters, but no special prefix
219          [DataRow("(ft::1288gg8888")] // Number contains delimiter and letters, but no special prefix
220          [DataRow("(date::12::55")]
221          [DataRow("(date::12:aa:55")]
222          [DataRow("(10.aa.22")]
223          [DataRow("(12::55")]
224          [DataRow("(12:aa:55")]
225          public void InvalidNumberInputShowsErrorMessage(string typedString)
226          {
227              // Setup
228              Mock<Main> main = new();
229              Query expectedQuery = new(typedString, "(");
230  
231              // Act
232              var result = main.Object.Query(expectedQuery).FirstOrDefault().Title;
233  
234              // Assert
235              Assert.IsTrue(result.StartsWith("Error:", StringComparison.CurrentCulture));
236          }
237  
238          [DataTestMethod]
239          [DataRow("(ft1 2..548")] // Input contains space
240          [DataRow("(ft12..54 //8")] // Input contains space
241          [DataRow("(time::ft12..54 //8")] // Input contains space
242          [DataRow("(10.10aa")] // Input contains <Number>.<Number> (Can be part of a date.)
243          [DataRow("(10:10aa")] // Input contains <Number>:<Number> (Can be part of a time.)
244          [DataRow("(10/10aa")] // Input contains <Number>/<Number> (Can be part of a date.)
245          public void InvalidInputNotShowsErrorMessage(string typedString)
246          {
247              // Setup
248              Mock<Main> main = new();
249              Query expectedQuery = new(typedString, "(");
250  
251              // Act
252              var result = main.Object.Query(expectedQuery).FirstOrDefault();
253  
254              // Assert
255              Assert.IsNull(result);
256          }
257  
258          [TestCleanup]
259          public void CleanUp()
260          {
261              // Set culture to original value
262              CultureInfo.CurrentCulture = originalCulture;
263              CultureInfo.CurrentUICulture = originalUiCulture;
264          }
265      }
266  }