Enabling static analysis on indexer plugin and fixing errors (#5220)

* Enabling code analysis, and treating warnings as errors

* Error CA1724 The type name Settings conflicts in whole or in part with the namespace name 'Microsoft.PowerToys.Settings'. Change either name to eliminate the conflict. Microsoft.Plugin.Indexer C:\repos\powertoys\src\modules\launcher\Plugins\Microsoft.Plugin.Indexer\Settings.cs 9 Active

* Removing keyword "Interface" from namespace to fix fxcop warnings

* Fixing static analysis warnings on ContextMenuLoader

* Fixing general exception warnings for static analysis

* Fixing public list variables, non static methods, and general exception warning

* Implementing IDisposable on OleDBSearch although in practice these objects were already being disposed.

Also Validated we were not using user input directly for sql strings.

* Removing VS generated comments from dispose methods as per PR feedback.

* Setting translated text to use current culture as per PR feedback.

* Explicity specifying 'internal' access modifier for Indexer 'Main' class, as per PR feedback

* Updating to FxCop 3.0.0
This commit is contained in:
ryanbodrug-microsoft 2020-07-30 16:39:47 -07:00 committed by GitHub
parent aa8c31e79b
commit 8f17f7297d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 287 additions and 215 deletions

View file

@ -29,8 +29,9 @@ namespace Microsoft.Plugin.Indexer
public ContextMenuLoader(PluginInitContext context)
{
_context = context;
}
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "We want to keep the process alive, and instead log and show an error message")]
public List<ContextMenuResult> LoadContextMenus(Result selectedResult)
{
var contextMenus = new List<ContextMenuResult>();
@ -111,6 +112,7 @@ namespace Microsoft.Plugin.Indexer
}
// Function to add the context menu item to run as admin
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "We want to keep the process alive, and instead log the exeption message")]
private ContextMenuResult CreateRunAsAdminContextMenu(SearchResult record)
{
return new ContextMenuResult
@ -152,7 +154,7 @@ namespace Microsoft.Plugin.Indexer
return false;
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "We want to keep the process alive, and instead log and show an error message")]
private ContextMenuResult CreateOpenContainingFolderResult(SearchResult record)
{
return new ContextMenuResult
@ -182,7 +184,7 @@ namespace Microsoft.Plugin.Indexer
};
}
public void LogException(string message, Exception e)
public static void LogException(string message, Exception e)
{
Log.Exception($"|Microsoft.Plugin.Folder.ContextMenu|{message}", e);
}

View file

@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Plugin.Indexer.DriveDetection;
using Microsoft.Plugin.Indexer.Interface;
namespace Microsoft.Plugin.Indexer.DriveDetection
namespace Microsoft.Plugin.Indexer.DriveDetection
{
public class IndexerDriveDetection
{

View file

@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Text;
using System.Windows.Input;
using Microsoft.Plugin.Indexer.Interface;
using Microsoft.Plugin.Indexer;
using Microsoft.Win32;
namespace Microsoft.Plugin.Indexer.DriveDetection

View file

@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Text;
namespace Microsoft.Plugin.Indexer.Interface
namespace Microsoft.Plugin.Indexer
{
public interface IRegistryWrapper
{

View file

@ -1,7 +1,7 @@
using Microsoft.Plugin.Indexer.SearchHelper;
using System.Collections.Generic;
namespace Microsoft.Plugin.Indexer.Interface
namespace Microsoft.Plugin.Indexer
{
public interface ISearch
{

View file

@ -1,37 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.Text;
using System.Threading.Tasks;
using Wox.Plugin;
using System.IO;
using System.ComponentModel;
using Wox.Infrastructure.Storage;
using Microsoft.Plugin.Indexer.SearchHelper;
using Microsoft.Search.Interop;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.Text;
using System.Threading.Tasks;
using Wox.Plugin;
using System.IO;
using System.ComponentModel;
using Wox.Infrastructure.Storage;
using Microsoft.Plugin.Indexer.SearchHelper;
using Microsoft.Search.Interop;
using Microsoft.PowerToys.Settings.UI.Lib;
using System.Windows.Controls;
using Wox.Infrastructure.Logger;
using System.Text.RegularExpressions;
using Microsoft.Plugin.Indexer.DriveDetection;
using System.Globalization;
namespace Microsoft.Plugin.Indexer
{
class Main : ISettingProvider, IPlugin, ISavable, IPluginI18n, IContextMenu
{
// This variable contains metadata about the Plugin
private PluginInitContext _context;
// This variable contains information about the context menus
private Settings _settings;
// Contains information about the plugin stored in json format
private PluginJsonStorage<Settings> _storage;
// To access Windows Search functionalities
private readonly WindowsSearchAPI _api = new WindowsSearchAPI(new OleDBSearch());
namespace Microsoft.Plugin.Indexer
{
internal class Main : ISettingProvider, IPlugin, ISavable, IPluginI18n, IContextMenu, IDisposable
{
// This variable contains metadata about the Plugin
private PluginInitContext _context;
// This variable contains information about the context menus
private IndexerSettings _settings;
// Contains information about the plugin stored in json format
private PluginJsonStorage<IndexerSettings> _storage;
// To access Windows Search functionalities
private static readonly OleDBSearch _search = new OleDBSearch();
private readonly WindowsSearchAPI _api = new WindowsSearchAPI(_search);
// To obtain information regarding the drives that are indexed
private readonly IndexerDriveDetection _driveDetection = new IndexerDriveDetection(new RegistryWrapper());
@ -39,129 +41,132 @@ namespace Microsoft.Plugin.Indexer
// Reserved keywords in oleDB
private string ReservedStringPattern = @"^[\/\\\$\%]+$";
private string WarningIconPath { get; set; }
private IContextMenu _contextMenuLoader;
private IContextMenu _contextMenuLoader;
private bool disposedValue;
// To save the configurations of plugins
public void Save()
{
_storage.Save();
}
// This function uses the Windows indexer and returns the list of results obtained
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "We want to keep the process alive but will log the exception")]
public List<Result> Query(Query query)
{
var results = new List<Result>();
if (!string.IsNullOrEmpty(query.Search))
{
var searchQuery = query.Search;
if (_settings.MaxSearchCount <= 0)
{
_settings.MaxSearchCount = 50;
}
// To save the configurations of plugins
public void Save()
{
_storage.Save();
}
var regexMatch = Regex.Match(searchQuery, ReservedStringPattern);
// This function uses the Windows indexer and returns the list of results obtained
public List<Result> Query(Query query)
{
var results = new List<Result>();
if (!regexMatch.Success)
{
try
{
if(_driveDetection.DisplayWarning())
{
results.Add(new Result
{
Title = _context.API.GetTranslation("Microsoft_plugin_indexer_drivedetectionwarning"),
SubTitle = _context.API.GetTranslation("Microsoft_plugin_indexer_disable_warning_in_settings"),
IcoPath = WarningIconPath,
Action = e =>
{
try
{
Process.Start(GetWindowsSearchSettingsProcessInfo());
}
catch (Exception ex)
{
Log.Exception("Microsoft.Plugin.Indexer", $"Unable to launch Windows Search Settings: {ex.Message}", ex, "Query");
}
return true;
}
});
}
if (!string.IsNullOrEmpty(query.Search))
{
var searchQuery = query.Search;
if (_settings.MaxSearchCount <= 0)
{
_settings.MaxSearchCount = 50;
}
var regexMatch = Regex.Match(searchQuery, ReservedStringPattern);
if (!regexMatch.Success)
{
try
{
if(_driveDetection.DisplayWarning())
{
results.Add(new Result
{
Title = _context.API.GetTranslation("Microsoft_plugin_indexer_drivedetectionwarning"),
SubTitle = _context.API.GetTranslation("Microsoft_plugin_indexer_disable_warning_in_settings"),
IcoPath = WarningIconPath,
Action = e =>
{
try
{
Process.Start(GetWindowsSearchSettingsProcessInfo());
}
catch (Exception ex)
{
Log.Exception("Microsoft.Plugin.Indexer", $"Unable to launch Windows Search Settings: {ex.Message}", ex, "Query");
}
return true;
}
});
}
var searchResultsList = _api.Search(searchQuery, maxCount: _settings.MaxSearchCount).ToList();
foreach (var searchResult in searchResultsList)
{
var path = searchResult.Path;
var toolTipTitle = string.Format("{0} : {1}", _context.API.GetTranslation("Microsoft_plugin_indexer_name"), searchResult.Title);
var toolTipText = string.Format("{0} : {1}", _context.API.GetTranslation("Microsoft_plugin_indexer_path"), path);
string workingDir = null;
if (_settings.UseLocationAsWorkingDir)
workingDir = Path.GetDirectoryName(path);
Result r = new Result();
r.Title = searchResult.Title;
r.SubTitle = "Search: " + path;
r.IcoPath = path;
r.ToolTipData = new ToolTipData(toolTipTitle, toolTipText);
r.Action = c =>
{
bool hide;
try
{
Process.Start(new ProcessStartInfo
{
FileName = path,
UseShellExecute = true,
WorkingDirectory = workingDir
});
hide = true;
}
catch (Win32Exception)
{
var name = $"Plugin: {_context.CurrentPluginMetadata.Name}";
var msg = "Can't Open this file";
_context.API.ShowMsg(name, msg, string.Empty);
hide = false;
}
return hide;
};
r.ContextData = searchResult;
//If the result is a directory, then it's display should show a directory.
if (Directory.Exists(path))
{
r.QueryTextDisplay = path;
}
results.Add(r);
}
}
catch (InvalidOperationException)
{
//The connection has closed, internal error of ExecuteReader()
//Not showing this exception to the users
}
catch (Exception ex)
{
Log.Info(ex.ToString());
var searchResultsList = _api.Search(searchQuery, maxCount: _settings.MaxSearchCount).ToList();
foreach (var searchResult in searchResultsList)
{
var path = searchResult.Path;
var toolTipTitle = string.Format(CultureInfo.CurrentCulture, "{0} : {1}", _context.API.GetTranslation("Microsoft_plugin_indexer_name"), searchResult.Title);
var toolTipText = string.Format(CultureInfo.CurrentCulture, "{0} : {1}", _context.API.GetTranslation("Microsoft_plugin_indexer_path"), path);
string workingDir = null;
if (_settings.UseLocationAsWorkingDir)
workingDir = Path.GetDirectoryName(path);
Result r = new Result();
r.Title = searchResult.Title;
r.SubTitle = "Search: " + path;
r.IcoPath = path;
r.ToolTipData = new ToolTipData(toolTipTitle, toolTipText);
r.Action = c =>
{
bool hide;
try
{
Process.Start(new ProcessStartInfo
{
FileName = path,
UseShellExecute = true,
WorkingDirectory = workingDir
});
hide = true;
}
catch (Win32Exception)
{
var name = $"Plugin: {_context.CurrentPluginMetadata.Name}";
var msg = "Can't Open this file";
_context.API.ShowMsg(name, msg, string.Empty);
hide = false;
}
return hide;
};
r.ContextData = searchResult;
//If the result is a directory, then it's display should show a directory.
if (Directory.Exists(path))
{
r.QueryTextDisplay = path;
}
results.Add(r);
}
}
catch (InvalidOperationException)
{
//The connection has closed, internal error of ExecuteReader()
//Not showing this exception to the users
}
catch (Exception ex)
{
Log.Info(ex.ToString());
}
}
}
return results;
}
public void Init(PluginInitContext context)
{
// initialize the context of the plugin
_context = context;
_contextMenuLoader = new ContextMenuLoader(context);
_storage = new PluginJsonStorage<Settings>();
_settings = _storage.Load();
}
return results;
}
public void Init(PluginInitContext context)
{
// initialize the context of the plugin
_context = context;
_contextMenuLoader = new ContextMenuLoader(context);
_storage = new PluginJsonStorage<IndexerSettings>();
_settings = _storage.Load();
_context.API.ThemeChanged += OnThemeChanged;
UpdateIconPath(_context.API.GetCurrentTheme());
}
UpdateIconPath(_context.API.GetCurrentTheme());
}
// Todo : Update with theme based IconPath
private void UpdateIconPath(Theme theme)
{
@ -178,25 +183,25 @@ namespace Microsoft.Plugin.Indexer
private void OnThemeChanged(Theme _, Theme newTheme)
{
UpdateIconPath(newTheme);
}
// TODO: Localize the strings
// Set the Plugin Title
public string GetTranslatedPluginTitle()
{
return "Windows Indexer Plugin";
}
// TODO: Localize the string
// Set the plugin Description
public string GetTranslatedPluginDescription()
{
return "Returns files and folders";
}
public List<ContextMenuResult> LoadContextMenus(Result selectedResult)
{
return _contextMenuLoader.LoadContextMenus(selectedResult);
// TODO: Localize the strings
// Set the Plugin Title
public string GetTranslatedPluginTitle()
{
return "Windows Indexer Plugin";
}
// TODO: Localize the string
// Set the plugin Description
public string GetTranslatedPluginDescription()
{
return "Returns files and folders";
}
public List<ContextMenuResult> LoadContextMenus(Result selectedResult)
{
return _contextMenuLoader.LoadContextMenus(selectedResult);
}
public void UpdateSettings(PowerLauncherSettings settings)
{
@ -209,7 +214,7 @@ namespace Microsoft.Plugin.Indexer
}
// Returns the Process Start Information for the new Windows Search Settings
public ProcessStartInfo GetWindowsSearchSettingsProcessInfo()
public static ProcessStartInfo GetWindowsSearchSettingsProcessInfo()
{
var ps = new ProcessStartInfo("ms-settings:cortana-windowssearch")
{
@ -218,7 +223,26 @@ namespace Microsoft.Plugin.Indexer
};
return ps;
}
}
}
}
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
_search.Dispose();
}
disposedValue = true;
}
}
public void Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
}

View file

@ -23,6 +23,7 @@
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<WarningLevel>4</WarningLevel>
<Optimize>false</Optimize>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@ -38,6 +39,10 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="System.Data.OleDb" Version="4.7.1" />
<PackageReference Include="tlbimp-Microsoft.Search.Interop" Version="1.0.0">
<NoWarn>NU1701</NoWarn>

View file

@ -8,11 +8,11 @@ namespace Microsoft.Plugin.Indexer.SearchHelper
{
public class OleDBResult
{
public List<object> fieldData;
public List<object> FieldData { get; }
public OleDBResult(List<object> fieldData)
{
this.fieldData = fieldData;
FieldData = fieldData;
}
}
}

View file

@ -1,16 +1,19 @@
using Microsoft.Plugin.Indexer.Interface;
using System;
using System;
using System.Collections.Generic;
using System.Data.OleDb;
namespace Microsoft.Plugin.Indexer.SearchHelper
{
public class OleDBSearch : ISearch
public class OleDBSearch : ISearch, IDisposable
{
private OleDbCommand command;
private OleDbConnection conn;
private OleDbDataReader WDSResults;
private OleDbDataReader WDSResults;
private bool disposedValue;
[System.Diagnostics.CodeAnalysis.SuppressMessage("Security", "CA2100:Review SQL queries for security vulnerabilities",
Justification = "sqlQuery does not come from user input but is generated via the ISearchQueryHelper::GenerateSqlFromUserQuery " +
" see: https://docs.microsoft.com/en-us/windows/win32/search/-search-3x-wds-qryidx-searchqueryhelper#using-the-generatesqlfromuserquery-method")]
public List<OleDBResult> Query(string connectionString, string sqlQuery)
{
List<OleDBResult> result = new List<OleDBResult>();
@ -75,6 +78,37 @@ namespace Microsoft.Plugin.Indexer.SearchHelper
}
return commandDisposed && resultDisposed && connDisposed;
}
}
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
command?.Dispose();
conn?.Dispose();
WDSResults?.Dispose();
}
// TODO: free unmanaged resources (unmanaged objects) and override finalizer
// TODO: set large fields to null
disposedValue = true;
}
}
// // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources
// ~OleDBSearch()
// {
// // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
// Dispose(disposing: false);
// }
public void Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
}

View file

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using Microsoft.Plugin.Indexer.Interface;
using Microsoft.Search.Interop;
namespace Microsoft.Plugin.Indexer.SearchHelper
@ -21,6 +20,11 @@ namespace Microsoft.Plugin.Indexer.SearchHelper
public List<SearchResult> ExecuteQuery(ISearchQueryHelper queryHelper, string keyword)
{
if(queryHelper == null)
{
throw new ArgumentNullException(paramName: nameof(queryHelper));
}
List<SearchResult> _Result = new List<SearchResult>();
// Generate SQL from our parameters, converting the userQuery from AQS->WHERE clause
@ -32,21 +36,21 @@ namespace Microsoft.Plugin.Indexer.SearchHelper
// Loop over all records from the database
foreach (OleDBResult oleDBResult in oleDBResults)
{
if (oleDBResult.fieldData[0] == DBNull.Value || oleDBResult.fieldData[1] == DBNull.Value || oleDBResult.fieldData[2] == DBNull.Value)
if (oleDBResult.FieldData[0] == DBNull.Value || oleDBResult.FieldData[1] == DBNull.Value || oleDBResult.FieldData[2] == DBNull.Value)
{
continue;
}
UInt32 fileAttributes = (UInt32)((Int64)oleDBResult.fieldData[2]);
UInt32 fileAttributes = (UInt32)((Int64)oleDBResult.FieldData[2]);
bool isFileHidden = (fileAttributes & FILE_ATTRIBUTE_HIDDEN) == FILE_ATTRIBUTE_HIDDEN;
if (DisplayHiddenFiles || !isFileHidden)
{
var uri_path = new Uri((string)oleDBResult.fieldData[0]);
var uri_path = new Uri((string)oleDBResult.FieldData[0]);
var result = new SearchResult
{
Path = uri_path.LocalPath,
Title = (string)oleDBResult.fieldData[1]
Title = (string)oleDBResult.FieldData[1]
};
_Result.Add(result);
}
@ -56,15 +60,25 @@ namespace Microsoft.Plugin.Indexer.SearchHelper
}
public void ModifyQueryHelper(ref ISearchQueryHelper queryHelper, string pattern)
public static void ModifyQueryHelper(ref ISearchQueryHelper queryHelper, string pattern)
{
if(pattern == null)
{
throw new ArgumentNullException(paramName: nameof(pattern));
}
if (queryHelper == null)
{
throw new ArgumentNullException(paramName: nameof(queryHelper));
}
// convert file pattern if it is not '*'. Don't create restriction for '*' as it includes all files.
if (pattern != "*")
{
pattern = pattern.Replace("*", "%");
pattern = pattern.Replace("?", "_");
pattern = pattern.Replace("*", "%", StringComparison.InvariantCulture);
pattern = pattern.Replace("?", "_", StringComparison.InvariantCulture);
if (pattern.Contains("%") || pattern.Contains("_"))
if (pattern.Contains("%", StringComparison.InvariantCulture) || pattern.Contains("_", StringComparison.InvariantCulture))
{
queryHelper.QueryWhereRestrictions += " AND System.FileName LIKE '" + pattern + "' ";
}
@ -76,7 +90,7 @@ namespace Microsoft.Plugin.Indexer.SearchHelper
}
}
public void InitQueryHelper(out ISearchQueryHelper queryHelper, int maxCount)
public static void InitQueryHelper(out ISearchQueryHelper queryHelper, int maxCount)
{
// This uses the Microsoft.Search.Interop assembly
CSearchManager manager = new CSearchManager();

View file

@ -6,9 +6,9 @@ using System.Threading.Tasks;
namespace Microsoft.Plugin.Indexer
{
public class Settings
public class IndexerSettings
{
public List<ContextMenu> ContextMenus = new List<ContextMenu>();
public List<ContextMenu> ContextMenus { get; } = new List<ContextMenu>();
public int MaxSearchCount { get; set; } = 100;
public bool UseLocationAsWorkingDir { get; set; } = false;
}

View file

@ -3,7 +3,6 @@ using System;
using System.Collections.Generic;
using Microsoft.Search.Interop;
using Microsoft.Plugin.Indexer.SearchHelper;
using Microsoft.Plugin.Indexer.Interface;
using Microsoft.Plugin.Indexer;
using Moq;
using Wox.Plugin;
@ -33,7 +32,7 @@ namespace Wox.Test.Plugins
ISearchQueryHelper queryHelper = null;
// Act
_api.InitQueryHelper(out queryHelper, maxCount);
WindowsSearchAPI.InitQueryHelper(out queryHelper, maxCount);
// Assert
Assert.IsNotNull(queryHelper);
@ -47,10 +46,10 @@ namespace Wox.Test.Plugins
ISearchQueryHelper queryHelper;
String pattern = "*";
WindowsSearchAPI _api = GetWindowsSearchAPI();
_api.InitQueryHelper(out queryHelper, 10);
WindowsSearchAPI.InitQueryHelper(out queryHelper, 10);
// Act
_api.ModifyQueryHelper(ref queryHelper, pattern);
WindowsSearchAPI.ModifyQueryHelper(ref queryHelper, pattern);
// Assert
Assert.IsFalse(queryHelper.QueryWhereRestrictions.Contains("LIKE"));
@ -64,10 +63,10 @@ namespace Wox.Test.Plugins
ISearchQueryHelper queryHelper;
String pattern = "tt*^&)";
WindowsSearchAPI _api = GetWindowsSearchAPI();
_api.InitQueryHelper(out queryHelper, 10);
WindowsSearchAPI.InitQueryHelper(out queryHelper, 10);
// Act
_api.ModifyQueryHelper(ref queryHelper, pattern);
WindowsSearchAPI.ModifyQueryHelper(ref queryHelper, pattern);
// Assert
Assert.IsTrue(queryHelper.QueryWhereRestrictions.Contains("LIKE"));
@ -81,10 +80,10 @@ namespace Wox.Test.Plugins
ISearchQueryHelper queryHelper;
String pattern = "tt%^&)";
WindowsSearchAPI _api = GetWindowsSearchAPI();
_api.InitQueryHelper(out queryHelper, 10);
WindowsSearchAPI.InitQueryHelper(out queryHelper, 10);
// Act
_api.ModifyQueryHelper(ref queryHelper, pattern);
WindowsSearchAPI.ModifyQueryHelper(ref queryHelper, pattern);
// Assert
Assert.IsTrue(queryHelper.QueryWhereRestrictions.Contains("LIKE"));
@ -98,10 +97,10 @@ namespace Wox.Test.Plugins
ISearchQueryHelper queryHelper;
String pattern = "tt_^&)";
WindowsSearchAPI _api = GetWindowsSearchAPI();
_api.InitQueryHelper(out queryHelper, 10);
WindowsSearchAPI.InitQueryHelper(out queryHelper, 10);
// Act
_api.ModifyQueryHelper(ref queryHelper, pattern);
WindowsSearchAPI.ModifyQueryHelper(ref queryHelper, pattern);
// Assert
Assert.IsTrue(queryHelper.QueryWhereRestrictions.Contains("LIKE"));
@ -115,10 +114,10 @@ namespace Wox.Test.Plugins
ISearchQueryHelper queryHelper;
String pattern = "tt?^&)";
WindowsSearchAPI _api = GetWindowsSearchAPI();
_api.InitQueryHelper(out queryHelper, 10);
WindowsSearchAPI.InitQueryHelper(out queryHelper, 10);
// Act
_api.ModifyQueryHelper(ref queryHelper, pattern);
WindowsSearchAPI.ModifyQueryHelper(ref queryHelper, pattern);
// Assert
Assert.IsTrue(queryHelper.QueryWhereRestrictions.Contains("LIKE"));
@ -132,10 +131,10 @@ namespace Wox.Test.Plugins
ISearchQueryHelper queryHelper;
String pattern = "tt^&)bc";
WindowsSearchAPI _api = GetWindowsSearchAPI();
_api.InitQueryHelper(out queryHelper, 10);
WindowsSearchAPI.InitQueryHelper(out queryHelper, 10);
// Act
_api.ModifyQueryHelper(ref queryHelper, pattern);
WindowsSearchAPI.ModifyQueryHelper(ref queryHelper, pattern);
// Assert
Assert.IsFalse(queryHelper.QueryWhereRestrictions.Contains("LIKE"));