Fix for File explorer not showing up and multiple notepads (#3969)

* reverted the dedup code, file explorer shows up but so do duplicates

* Fixed file explorer and dedup

* Formatting

* Added tests for all the cases

* Formatting

* Tests

* take name and exe into consideration while calculating hash

* unique primes while calculating hash code
This commit is contained in:
Alekhya 2020-06-02 14:36:32 -07:00 committed by GitHub
parent 96b79d5f06
commit 8cddd595d4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 200 additions and 11 deletions

View File

@ -444,6 +444,46 @@ namespace Microsoft.Plugin.Program.Programs
return entry;
}
public class removeDuplicatesComparer : IEqualityComparer<Win32>
{
public bool Equals(Win32 app1, Win32 app2)
{
if(!string.IsNullOrEmpty(app1.Name) && !string.IsNullOrEmpty(app2.Name)
&& !string.IsNullOrEmpty(app1.ExecutableName) && !string.IsNullOrEmpty(app2.ExecutableName)
&& !string.IsNullOrEmpty(app1.FullPath) && !string.IsNullOrEmpty(app2.FullPath))
{
return app1.Name.Equals(app2.Name, StringComparison.OrdinalIgnoreCase)
&& app1.ExecutableName.Equals(app2.ExecutableName, StringComparison.OrdinalIgnoreCase)
&& app1.FullPath.Equals(app2.FullPath, StringComparison.OrdinalIgnoreCase);
}
return false;
}
// Ref : https://stackoverflow.com/questions/2730865/how-do-i-calculate-a-good-hash-code-for-a-list-of-strings
public int GetHashCode(Win32 obj)
{
int namePrime = 13;
int executablePrime = 17;
int fullPathPrime = 31;
int result = 1;
result = result * namePrime + obj.Name.GetHashCode();
result = result * executablePrime + obj.ExecutableName.GetHashCode();
result = result * fullPathPrime + obj.FullPath.GetHashCode();
return result;
}
}
// Deduplication code
public static Func<ParallelQuery<Win32>, Win32[]> DeduplicatePrograms = (programs) =>
{
var uniqueExePrograms = programs.Where(x => !string.IsNullOrEmpty(x.LnkResolvedPath) || Extension(x.FullPath) != ExeExtension);
var uniquePrograms = uniqueExePrograms.Distinct(new removeDuplicatesComparer());
return uniquePrograms.ToArray();
};
public static Win32[] All(Settings settings)
{
try
@ -465,15 +505,7 @@ namespace Microsoft.Plugin.Program.Programs
programs = programs.Concat(startMenu);
}
var programsWithoutLnk = programs.Where(x => string.IsNullOrEmpty(x.LnkResolvedPath));
var programsAsList = programs.ToList();
foreach(var app in programsWithoutLnk)
{
programsAsList.RemoveAll(x => (x.FullPath == app.FullPath) && string.IsNullOrEmpty(x.LnkResolvedPath));
}
return programsAsList.ToArray();
return DeduplicatePrograms(programs);
}
#if DEBUG //This is to make developer aware of any unhandled exception and add in handling.
catch (Exception e)

View File

@ -187,8 +187,6 @@ namespace Wox.Test
[TestCase("sql manag", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)]
[TestCase("sql", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)]
[TestCase("sql serv", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)]
[TestCase("sqlserv", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, false)]
[TestCase("sql servman", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, false)]
[TestCase("sql serv man", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)]
[TestCase("sql studio", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)]
[TestCase("mic", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)]
@ -224,5 +222,20 @@ namespace Wox.Test
$"Raw Score: {matchResult.RawScore}{Environment.NewLine}" +
$"Precision Score: {(int)expectedPrecisionScore}");
}
[TestCase("Windows Terminal", "Windows_Terminal", "term")]
[TestCase("Windows Terminal", "WindowsTerminal", "term")]
public void FuzzyMatchingScore_ShouldBeHigher_WhenPreceedingCharacterIsSpace(string firstCompareStr, string secondCompareStr, string query)
{
// Arrange
var matcher = new StringMatcher();
// Act
var firstScore = matcher.FuzzyMatch(query, firstCompareStr).Score;
var secondScore = matcher.FuzzyMatch(query, secondCompareStr).Score;
// Assert
Assert.IsTrue(firstScore > secondScore);
}
}
}

View File

@ -0,0 +1,143 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using NUnit.Framework;
using Wox.Infrastructure;
using Wox.Plugin;
using Microsoft.Plugin.Program.Programs;
using Moq;
using System.IO;
namespace Wox.Test.Plugins
{
[TestFixture]
public class ProgramPluginTest
{
Win32 notepad_appdata = new Win32
{
Name = "Notepad",
ExecutableName = "notepad.exe",
FullPath = "c:\\windows\\system32\\notepad.exe",
LnkResolvedPath = "c:\\users\\powertoys\\appdata\\roaming\\microsoft\\windows\\start menu\\programs\\accessories\\notepad.lnk"
};
Win32 notepad_users = new Win32
{
Name = "Notepad",
ExecutableName = "notepad.exe",
FullPath = "c:\\windows\\system32\\notepad.exe",
LnkResolvedPath = "c:\\programdata\\microsoft\\windows\\start menu\\programs\\accessories\\notepad.lnk"
};
Win32 azure_command_prompt = new Win32
{
Name = "Microsoft Azure Command Prompt - v2.9",
ExecutableName = "cmd.exe",
FullPath = "c:\\windows\\system32\\cmd.exe",
LnkResolvedPath = "c:\\programdata\\microsoft\\windows\\start menu\\programs\\microsoft azure\\microsoft azure sdk for .net\\v2.9\\microsoft azure command prompt - v2.9.lnk"
};
Win32 visual_studio_command_prompt = new Win32
{
Name = "x64 Native Tools Command Prompt for VS 2019",
ExecutableName = "cmd.exe",
FullPath = "c:\\windows\\system32\\cmd.exe",
LnkResolvedPath = "c:\\programdata\\microsoft\\windows\\start menu\\programs\\visual studio 2019\\visual studio tools\\vc\\x64 native tools command prompt for vs 2019.lnk"
};
Win32 command_prompt = new Win32
{
Name = "Command Prompt",
ExecutableName = "cmd.exe",
FullPath = "c:\\windows\\system32\\cmd.exe",
LnkResolvedPath ="c:\\users\\powertoys\\appdata\\roaming\\microsoft\\windows\\start menu\\programs\\system tools\\command prompt.lnk"
};
Win32 file_explorer = new Win32
{
Name = "File Explorer",
ExecutableName = "File Explorer.lnk",
FullPath = "c:\\users\\powertoys\\appdata\\roaming\\microsoft\\windows\\start menu\\programs\\system tools\\file explorer.lnk",
LnkResolvedPath = null
};
Win32 wordpad = new Win32
{
Name = "Wordpad",
ExecutableName = "wordpad.exe",
FullPath = "c:\\program files\\windows nt\\accessories\\wordpad.exe",
LnkResolvedPath = "c:\\programdata\\microsoft\\windows\\start menu\\programs\\accessories\\wordpad.lnk"
};
Win32 wordpad_duplicate = new Win32
{
Name = "WORDPAD",
ExecutableName = "WORDPAD.EXE",
FullPath = "c:\\program files\\windows nt\\accessories\\wordpad.exe",
LnkResolvedPath = null
};
[Test]
public void DedupFunction_whenCalled_mustRemoveDuplicateNotepads()
{
// Arrange
List<Win32> prgms = new List<Win32>();
prgms.Add(notepad_appdata);
prgms.Add(notepad_users);
// Act
Win32[] apps = Win32.DeduplicatePrograms(prgms.AsParallel());
// Assert
Assert.AreEqual(apps.Length, 1);
}
[Test]
public void DedupFunction_whenCalled_mustNotRemovelnkWhichdoesNotHaveExe()
{
// Arrange
List<Win32> prgms = new List<Win32>();
prgms.Add(file_explorer);
// Act
Win32[] apps = Win32.DeduplicatePrograms(prgms.AsParallel());
// Assert
Assert.AreEqual(apps.Length, 1);
}
[Test]
public void DedupFunction_mustRemoveDuplicates_forExeExtensionsWithoutLnkResolvedPath()
{
// Arrange
List<Win32> prgms = new List<Win32>();
prgms.Add(wordpad);
prgms.Add(wordpad_duplicate);
// Act
Win32[] apps = Win32.DeduplicatePrograms(prgms.AsParallel());
// Assert
Assert.AreEqual(apps.Length, 1);
Assert.IsTrue(!string.IsNullOrEmpty(apps[0].LnkResolvedPath));
}
[Test]
public void DedupFunction_mustNotRemovePrograms_withSameExeNameAndFullPath()
{
// Arrange
List<Win32> prgms = new List<Win32>();
prgms.Add(azure_command_prompt);
prgms.Add(visual_studio_command_prompt);
prgms.Add(command_prompt);
// Act
Win32[] apps = Win32.DeduplicatePrograms(prgms.AsParallel());
// Assert
Assert.AreEqual(apps.Length, 3);
}
}
}

View File

@ -40,6 +40,7 @@
<ItemGroup>
<ProjectReference Include="..\Plugins\Microsoft.Plugin.Indexer\Microsoft.Plugin.Indexer.csproj" />
<ProjectReference Include="..\Plugins\Microsoft.Plugin.Program\Microsoft.Plugin.Program.csproj" />
<ProjectReference Include="..\Wox.Core\Wox.Core.csproj" />
<ProjectReference Include="..\Wox.Infrastructure\Wox.Infrastructure.csproj" />
<ProjectReference Include="..\Wox.Plugin\Wox.Plugin.csproj" />