Skip to content

Commit db2b856

Browse files
authored
Merge pull request #1817 from VictoriousRaptor/FixExplorer
Fix bugs in explorer plugin
2 parents d2cc576 + dd02ad3 commit db2b856

File tree

10 files changed

+263
-120
lines changed

10 files changed

+263
-120
lines changed

Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
using System;
22
using System.Diagnostics;
33
using System.IO;
4+
#pragma warning disable IDE0005
45
using System.Windows;
6+
#pragma warning restore IDE0005
57

68
namespace Flow.Launcher.Plugin.SharedCommands
79
{
@@ -206,22 +208,16 @@ public static bool IsLocationPathString(this string querySearchString)
206208
///</summary>
207209
public static string GetPreviousExistingDirectory(Func<string, bool> locationExists, string path)
208210
{
209-
var previousDirectoryPath = "";
210211
var index = path.LastIndexOf('\\');
211212
if (index > 0 && index < (path.Length - 1))
212213
{
213-
previousDirectoryPath = path.Substring(0, index + 1);
214-
if (!locationExists(previousDirectoryPath))
215-
{
216-
return "";
217-
}
214+
string previousDirectoryPath = path.Substring(0, index + 1);
215+
return locationExists(previousDirectoryPath) ? previousDirectoryPath : "";
218216
}
219217
else
220218
{
221219
return "";
222220
}
223-
224-
return previousDirectoryPath;
225221
}
226222

227223
///<summary>
@@ -241,5 +237,33 @@ public static string ReturnPreviousDirectoryIfIncompleteString(string path)
241237

242238
return path;
243239
}
240+
241+
/// <summary>
242+
/// Returns if <paramref name="parentPath"/> contains <paramref name="subPath"/>.
243+
/// From https://stackoverflow.com/a/66877016
244+
/// </summary>
245+
/// <param name="parentPath">Parent path</param>
246+
/// <param name="subPath">Sub path</param>
247+
/// <param name="allowEqual">If <see langword="true"/>, when <paramref name="parentPath"/> and <paramref name="subPath"/> are equal, returns <see langword="true"/></param>
248+
/// <returns></returns>
249+
public static bool PathContains(string parentPath, string subPath, bool allowEqual = false)
250+
{
251+
var rel = Path.GetRelativePath(parentPath.EnsureTrailingSlash(), subPath);
252+
return (rel != "." || allowEqual)
253+
&& rel != ".."
254+
&& !rel.StartsWith("../")
255+
&& !rel.StartsWith(@"..\")
256+
&& !Path.IsPathRooted(rel);
257+
}
258+
259+
/// <summary>
260+
/// Returns path ended with "\"
261+
/// </summary>
262+
/// <param name="path"></param>
263+
/// <returns></returns>
264+
public static string EnsureTrailingSlash(this string path)
265+
{
266+
return path.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar;
267+
}
244268
}
245269
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
using Flow.Launcher.Plugin.SharedCommands;
2+
using NUnit.Framework;
3+
4+
namespace Flow.Launcher.Test
5+
{
6+
[TestFixture]
7+
8+
public class FilesFoldersTest
9+
{
10+
// Testcases from https://stackoverflow.com/a/31941905/20703207
11+
// Disk
12+
[TestCase(@"c:", @"c:\foo", true)]
13+
[TestCase(@"c:\", @"c:\foo", true)]
14+
// Slash
15+
[TestCase(@"c:\foo\bar\", @"c:\foo\", false)]
16+
[TestCase(@"c:\foo\bar", @"c:\foo\", false)]
17+
[TestCase(@"c:\foo", @"c:\foo\bar", true)]
18+
[TestCase(@"c:\foo\", @"c:\foo\bar", true)]
19+
// File
20+
[TestCase(@"c:\foo", @"c:\foo\a.txt", true)]
21+
[TestCase(@"c:\foo", @"c:/foo/a.txt", true)]
22+
[TestCase(@"c:\FOO\a.txt", @"c:\foo", false)]
23+
[TestCase(@"c:\foo\a.txt", @"c:\foo\", false)]
24+
[TestCase(@"c:\foobar\a.txt", @"c:\foo", false)]
25+
[TestCase(@"c:\foobar\a.txt", @"c:\foo\", false)]
26+
[TestCase(@"c:\foo\", @"c:\foo.txt", false)]
27+
// Prefix
28+
[TestCase(@"c:\foo", @"c:\foobar", false)]
29+
[TestCase(@"C:\Program", @"C:\Program Files\", false)]
30+
[TestCase(@"c:\foobar", @"c:\foo\a.txt", false)]
31+
[TestCase(@"c:\foobar\", @"c:\foo\a.txt", false)]
32+
// Edge case
33+
[TestCase(@"c:\foo", @"c:\foo\..\bar\baz", false)]
34+
[TestCase(@"c:\bar", @"c:\foo\..\bar\baz", true)]
35+
[TestCase(@"c:\barr", @"c:\foo\..\bar\baz", false)]
36+
// Equality
37+
[TestCase(@"c:\foo", @"c:\foo", false)]
38+
[TestCase(@"c:\foo\", @"c:\foo", false)]
39+
[TestCase(@"c:\foo", @"c:\foo\", false)]
40+
public void GivenTwoPaths_WhenCheckPathContains_ThenShouldBeExpectedResult(string parentPath, string path, bool expectedResult)
41+
{
42+
Assert.AreEqual(expectedResult, FilesFolders.PathContains(parentPath, path));
43+
}
44+
45+
[TestCase(@"c:\foo", @"c:\foo", true)]
46+
[TestCase(@"c:\foo\", @"c:\foo", true)]
47+
[TestCase(@"c:\foo", @"c:\foo\", true)]
48+
public void GivenTwoPathsAreTheSame_WhenCheckPathContains_ThenShouldBeTrue(string parentPath, string path, bool expectedResult)
49+
{
50+
Assert.AreEqual(expectedResult, FilesFolders.PathContains(parentPath, path, true));
51+
}
52+
}
53+
}

Flow.Launcher.Test/Plugins/ExplorerTest.cs

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@
77
using NUnit.Framework;
88
using System;
99
using System.Collections.Generic;
10+
using System.IO;
1011
using System.Runtime.Versioning;
1112
using System.Threading;
1213
using System.Threading.Tasks;
14+
using static Flow.Launcher.Plugin.Explorer.Search.SearchManager;
1315

1416
namespace Flow.Launcher.Test.Plugins
1517
{
@@ -176,7 +178,7 @@ public void GivenQuery_WhenActionKeywordForFileContentSearchExists_ThenFileConte
176178
var searchManager = new SearchManager(new Settings(), new PluginInitContext());
177179

178180
// When
179-
var result = SearchManager.IsFileContentSearch(query.ActionKeyword);
181+
var result = searchManager.IsFileContentSearch(query.ActionKeyword);
180182

181183
// Then
182184
Assert.IsTrue(result,
@@ -193,6 +195,7 @@ public void GivenQuery_WhenActionKeywordForFileContentSearchExists_ThenFileConte
193195
[TestCase(@"c:\>*", true)]
194196
[TestCase(@"c:\>", true)]
195197
[TestCase(@"c:\SomeLocation\SomeOtherLocation\>", true)]
198+
[TestCase(@"c:\SomeLocation\SomeOtherLocation", true)]
196199
public void WhenGivenQuerySearchString_ThenShouldIndicateIfIsLocationPathString(string querySearchString, bool expectedResult)
197200
{
198201
// When, Given
@@ -393,5 +396,68 @@ public void GivenQueryWithFileTypeResult_WhenGetAutoComplete_ThenResultShouldBeE
393396
// Then
394397
Assert.AreEqual(result, expectedResult);
395398
}
399+
400+
[TestCase(@"c:\foo", @"c:\foo", true)]
401+
[TestCase(@"C:\Foo\", @"c:\foo\", true)]
402+
[TestCase(@"c:\foo", @"c:\foo\", false)]
403+
public void GivenTwoPaths_WhenCompared_ThenShouldBeExpectedSameOrDifferent(string path1, string path2, bool expectedResult)
404+
{
405+
// Given
406+
var comparator = PathEqualityComparator.Instance;
407+
var result1 = new Result
408+
{
409+
Title = Path.GetFileName(path1),
410+
SubTitle = path1
411+
};
412+
var result2 = new Result
413+
{
414+
Title = Path.GetFileName(path2),
415+
SubTitle = path2
416+
};
417+
418+
// When, Then
419+
Assert.AreEqual(expectedResult, comparator.Equals(result1, result2));
420+
}
421+
422+
[TestCase(@"c:\foo\", @"c:\foo\")]
423+
[TestCase(@"C:\Foo\", @"c:\foo\")]
424+
public void GivenTwoPaths_WhenComparedHasCode_ThenShouldBeSame(string path1, string path2)
425+
{
426+
// Given
427+
var comparator = PathEqualityComparator.Instance;
428+
var result1 = new Result
429+
{
430+
Title = Path.GetFileName(path1),
431+
SubTitle = path1
432+
};
433+
var result2 = new Result
434+
{
435+
Title = Path.GetFileName(path2),
436+
SubTitle = path2
437+
};
438+
439+
var hash1 = comparator.GetHashCode(result1);
440+
var hash2 = comparator.GetHashCode(result2);
441+
442+
// When, Then
443+
Assert.IsTrue(hash1 == hash2);
444+
}
445+
446+
[TestCase(@"%appdata%", true)]
447+
[TestCase(@"%appdata%\123", true)]
448+
[TestCase(@"c:\foo %appdata%\", false)]
449+
[TestCase(@"c:\users\%USERNAME%\downloads", true)]
450+
[TestCase(@"c:\downloads", false)]
451+
[TestCase(@"%", false)]
452+
[TestCase(@"%%", false)]
453+
[TestCase(@"%bla%blabla%", false)]
454+
public void GivenPath_WhenHavingEnvironmentVariableOrNot_ThenShouldBeExpected(string path, bool expectedResult)
455+
{
456+
// When
457+
var result = EnvironmentVariables.HasEnvironmentVar(path);
458+
459+
// Then
460+
Assert.AreEqual(result, expectedResult);
461+
}
396462
}
397463
}

Plugins/Flow.Launcher.Plugin.Explorer/Exceptions/EngineNotAvailableException.cs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
using System;
44
using System.Threading.Tasks;
55
using System.Windows;
6-
using Flow.Launcher.Plugin.Explorer.Search.IProvider;
7-
using JetBrains.Annotations;
86

97
namespace Flow.Launcher.Plugin.Explorer.Exceptions;
108

@@ -20,7 +18,7 @@ public EngineNotAvailableException(
2018
string engineName,
2119
string resolution,
2220
string message,
23-
Func<ActionContext, ValueTask<bool>> action = null) : base(message)
21+
Func<ActionContext, ValueTask<bool>>? action = null) : base(message)
2422
{
2523
EngineName = engineName;
2624
Resolution = resolution;
@@ -40,6 +38,23 @@ public EngineNotAvailableException(
4038
EngineName = engineName;
4139
Resolution = resolution;
4240
}
41+
42+
public EngineNotAvailableException(
43+
string engineName,
44+
string resolution,
45+
string message,
46+
string errorIconPath,
47+
Func<ActionContext, ValueTask<bool>>? action = null) : base(message)
48+
{
49+
EngineName = engineName;
50+
Resolution = resolution;
51+
ErrorIcon = errorIconPath;
52+
Action = action ?? (_ =>
53+
{
54+
Clipboard.SetDataObject(this.ToString());
55+
return ValueTask.FromResult(true);
56+
});
57+
}
4358

4459
public override string ToString()
4560
{

0 commit comments

Comments
 (0)