Skip to content

Commit 061d53c

Browse files
authored
Merge branch 'dev' into feature/query-command-line-arg
2 parents ab882e6 + 07a958d commit 061d53c

3 files changed

Lines changed: 523 additions & 127 deletions

File tree

Flow.Launcher.Infrastructure/UserSettings/Settings.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ public bool UseSound
173173
}
174174
}
175175
public double SoundVolume { get; set; } = 50;
176-
public bool ShowBadges { get; set; } = false;
176+
public bool ShowBadges { get; set; } = true;
177177
public bool ShowBadgesGlobalOnly { get; set; } = false;
178178

179179
private string _settingWindowFont { get; set; } = Win32Helper.GetSystemDefaultFont(false);
Lines changed: 335 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,358 @@
1+
using System;
12
using System.Diagnostics;
3+
using System.Linq;
4+
using Flow.Launcher.Plugin;
25
using Flow.Launcher.Plugin.Shell;
36
using NUnit.Framework;
4-
using NUnit.Framework.Legacy;
57

68
namespace Flow.Launcher.Test.Plugins
79
{
810
[TestFixture]
911
public class ShellPluginTest
1012
{
13+
private const string ClosePrompt = "Press any key to close...";
14+
15+
private static ProcessStartInfo Create(
16+
string command = "test",
17+
Shell shell = Shell.Cmd,
18+
bool leaveShellOpen = false,
19+
bool closeShellAfterPress = false,
20+
bool useWindowsTerminal = false,
21+
bool runAsAdmin = false)
22+
=> Main.CreateProcessStartInfo(
23+
command,
24+
shell,
25+
leaveShellOpen,
26+
closeShellAfterPress,
27+
useWindowsTerminal,
28+
runAsAdmin,
29+
ClosePrompt);
30+
31+
#region CMD
32+
33+
[Test]
34+
public void Cmd_ShouldPreserveQuotedCommands()
35+
{
36+
var info = Create(
37+
command: "\"cmd.exe\"",
38+
shell: Shell.Cmd);
39+
40+
Assert.That(info.FileName, Is.EqualTo("cmd.exe"));
41+
Assert.That(info.Arguments, Is.EqualTo("/c \"cmd.exe\""));
42+
Assert.That(info.ArgumentList, Is.Empty);
43+
}
44+
45+
[Test]
46+
public void Cmd_ShouldUseArgumentListForWindowsTerminal()
47+
{
48+
var info = Create(
49+
command: "\"cmd.exe\"",
50+
shell: Shell.Cmd,
51+
useWindowsTerminal: true);
52+
53+
Assert.That(info.FileName, Is.EqualTo("wt.exe"));
54+
Assert.That(info.ArgumentList, Is.EqualTo(["cmd", "/c", "\"cmd.exe\""]));
55+
Assert.That(info.Arguments, Is.Empty);
56+
}
57+
58+
[TestCase(true, "/k")]
59+
[TestCase(false, "/c")]
60+
public void Cmd_UsesCorrectShellSwitch(bool leaveShellOpen, string expectedSwitch)
61+
{
62+
const string command = "test";
63+
var info = Create(
64+
command: command,
65+
leaveShellOpen: leaveShellOpen,
66+
shell: Shell.Cmd);
67+
68+
Assert.That(info.Arguments, Is.EqualTo($"{expectedSwitch} {command}"));
69+
}
70+
71+
[Test]
72+
public void Cmd_CloseShellAfterPress_AppendsPause()
73+
{
74+
const string command = "test";
75+
var info = Create(
76+
command: command,
77+
closeShellAfterPress: true,
78+
shell: Shell.Cmd);
79+
80+
Assert.That(info.Arguments, Is.EqualTo($"/c {command} && echo {ClosePrompt} && pause > nul"));
81+
}
82+
1183
[Test]
12-
public void ConfigureCmdProcessStartInfo_ShouldPreserveQuotedCommands()
84+
public void Cmd_TrimsCommandWhitespace()
1385
{
14-
var info = new ProcessStartInfo();
86+
var info = Create(
87+
command: " dir ",
88+
shell: Shell.Cmd);
89+
90+
Assert.That(info.Arguments, Is.EqualTo("/c dir"));
91+
}
1592

16-
Main.ConfigureCmdProcessStartInfo(
17-
info,
18-
"\"cmd.exe\"",
19-
leaveShellOpen: false,
20-
closeShellAfterPress: false,
21-
notifyStr: "Press any key to close",
22-
useWindowsTerminal: false);
93+
[Test]
94+
public void Cmd_WithSpacesAndQuotes_PassesThroughUnchanged()
95+
{
96+
var info = Create(
97+
command: "\"C:\\Program Files\\app.exe\" --flag",
98+
shell: Shell.Cmd);
2399

24-
ClassicAssert.AreEqual("cmd.exe", info.FileName);
25-
ClassicAssert.AreEqual("/c \"cmd.exe\"", info.Arguments);
26-
ClassicAssert.IsEmpty(info.ArgumentList);
100+
Assert.That(info.Arguments, Is.EqualTo("/c \"C:\\Program Files\\app.exe\" --flag"));
27101
}
28102

103+
#endregion
104+
105+
#region PowerShell
106+
29107
[Test]
30-
public void ConfigureCmdProcessStartInfo_ShouldKeepArgumentListForWindowsTerminal()
108+
public void Powershell_DirectExecution()
31109
{
32-
var info = new ProcessStartInfo();
110+
var info = Create(shell: Shell.Powershell);
111+
112+
Assert.That(info.FileName, Is.EqualTo("powershell.exe"));
113+
Assert.That(info.ArgumentList, Is.EqualTo(["-Command", "test;"]));
114+
}
33115

34-
Main.ConfigureCmdProcessStartInfo(
35-
info,
36-
"\"cmd.exe\"",
37-
leaveShellOpen: false,
38-
closeShellAfterPress: false,
39-
notifyStr: "Press any key to close",
116+
[Test]
117+
public void Powershell_WithSpecialCharacters_PassesThrough()
118+
{
119+
var info = Create(
120+
command: "$env:USERNAME",
121+
shell: Shell.Powershell);
122+
123+
Assert.That(info.ArgumentList, Is.EqualTo(["-Command", "$env:USERNAME;"]));
124+
}
125+
126+
[Test]
127+
public void Powershell_CloseShellAfterPress_AppendsPrompt()
128+
{
129+
var info = Create(
130+
shell: Shell.Powershell,
131+
closeShellAfterPress: true);
132+
133+
var commandArg = info.ArgumentList.Last();
134+
Assert.That(commandArg, Does.Contain($"Write-Host '{ClosePrompt}'"));
135+
}
136+
137+
[Test]
138+
public void Powershell_WT_UsesWindowsTerminal()
139+
{
140+
var info = Create(
141+
shell: Shell.Powershell,
40142
useWindowsTerminal: true);
41143

42-
ClassicAssert.AreEqual("wt.exe", info.FileName);
43-
CollectionAssert.AreEqual(new[] { "cmd", "/c", "\"cmd.exe\"" }, info.ArgumentList);
44-
ClassicAssert.IsEmpty(info.Arguments);
144+
Assert.That(info.FileName, Is.EqualTo("wt.exe"));
145+
Assert.That(info.ArgumentList, Does.Contain("powershell"));
146+
}
147+
148+
[TestCase(false)]
149+
[TestCase(true)]
150+
public void Powershell_AddsNoExitOnlyWhenLeaveShellOpen(bool leaveShellOpen)
151+
{
152+
var info = Create(
153+
shell: Shell.Powershell,
154+
leaveShellOpen: leaveShellOpen);
155+
156+
Assert.That(info.ArgumentList, leaveShellOpen
157+
? Does.Contain("-NoExit")
158+
: Does.Not.Contain("-NoExit"));
159+
}
160+
161+
[Test]
162+
public void Powershell_LeaveShellOpen_OmitsCommandSwitch()
163+
{
164+
var info = Create(
165+
shell: Shell.Powershell,
166+
leaveShellOpen: true);
167+
168+
Assert.That(info.ArgumentList, Does.Not.Contain("-Command"));
169+
}
170+
171+
#endregion
172+
173+
#region Pwsh
174+
175+
[Test]
176+
public void Pwsh_AlwaysAddsCommandSwitch()
177+
{
178+
var info = Create(shell: Shell.Pwsh);
179+
180+
Assert.That(info.FileName, Is.EqualTo("pwsh.exe"));
181+
Assert.That(info.ArgumentList, Does.Contain("-Command"));
182+
}
183+
184+
[TestCase(false)]
185+
[TestCase(true)]
186+
public void Pwsh_AddsNoExitOnlyWhenLeaveShellOpen(bool leaveShellOpen)
187+
{
188+
var info = Create(
189+
shell: Shell.Pwsh,
190+
leaveShellOpen: leaveShellOpen);
191+
192+
Assert.That(
193+
info.ArgumentList,
194+
leaveShellOpen
195+
? Does.Contain("-NoExit")
196+
: Does.Not.Contain("-NoExit")
197+
);
45198
}
199+
200+
[Test]
201+
public void Pwsh_CloseShellAfterPress_AppendsPrompt()
202+
{
203+
var info = Create(
204+
shell: Shell.Pwsh,
205+
closeShellAfterPress: true);
206+
207+
var commandArg = info.ArgumentList.Last();
208+
Assert.That(commandArg, Does.Contain($"Write-Host '{ClosePrompt}'"));
209+
}
210+
211+
#endregion
212+
213+
#region RunCommand
214+
215+
[Test]
216+
public void RunCommand_SingleWord_SetsFileName()
217+
{
218+
var info = Create(
219+
command: "notepad",
220+
shell: Shell.RunCommand);
221+
222+
Assert.That(info.FileName, Is.EqualTo("notepad"));
223+
Assert.That(info.Arguments, Is.Empty);
224+
}
225+
226+
[Test]
227+
public void RunCommand_UnknownExecutable_SetsWholeCommandAsFileName()
228+
{
229+
var info = Create(
230+
command: "nonexistentapp123 argument",
231+
shell: Shell.RunCommand);
232+
233+
Assert.That(info.FileName, Is.EqualTo("nonexistentapp123 argument"));
234+
}
235+
236+
[Test]
237+
public void RunCommand_UnknownQuotedExecutable_SetsWholeCommandAsFileName()
238+
{
239+
var info = Create(
240+
command: "\"C:\\nonexistent\\app.exe\" --flag",
241+
shell: Shell.RunCommand);
242+
243+
Assert.That(info.FileName, Is.EqualTo("\"C:\\nonexistent\\app.exe\" --flag"));
244+
}
245+
246+
[Test]
247+
public void RunCommand_QuotedPathNoArgs_ExtractsFileName()
248+
{
249+
var systemDir = Environment.SystemDirectory;
250+
var info = Create(
251+
command: $"\"{systemDir}\\cmd.exe\"",
252+
shell: Shell.RunCommand);
253+
254+
Assert.That(info.FileName, Is.EqualTo($"{systemDir}\\cmd.exe"));
255+
Assert.That(info.Arguments, Is.Empty);
256+
}
257+
258+
[Test]
259+
public void RunCommand_QuotedPath_WithQuotedArgs_Preserved()
260+
{
261+
var systemDir = Environment.SystemDirectory;
262+
var info = Create(
263+
command: $"\"{systemDir}\\cmd.exe\" /c echo \"hello world\"",
264+
shell: Shell.RunCommand);
265+
266+
Assert.That(info.FileName, Is.EqualTo($"{systemDir}\\cmd.exe"));
267+
Assert.That(info.Arguments, Is.EqualTo("/c echo \"hello world\""));
268+
}
269+
270+
[Test]
271+
public void RunCommand_UsesArgumentsForCommandTail()
272+
{
273+
var info = Create(
274+
command: "cmd /c echo hello",
275+
shell: Shell.RunCommand);
276+
277+
Assert.That(info.FileName, Is.EqualTo("cmd"));
278+
Assert.That(info.Arguments, Is.EqualTo("/c echo hello"));
279+
}
280+
281+
[Test]
282+
public void RunCommand_QuotedExecutablePath_ExtractsFileName()
283+
{
284+
var systemDir = Environment.SystemDirectory;
285+
var info = Create(
286+
command: $"\"{systemDir}\\cmd.exe\" /c echo hello",
287+
shell: Shell.RunCommand);
288+
289+
Assert.That(info.FileName, Is.EqualTo($"{systemDir}\\cmd.exe"));
290+
Assert.That(info.Arguments, Is.EqualTo("/c echo hello"));
291+
}
292+
293+
#endregion
294+
295+
#region Common
296+
297+
[TestCase(false, "")]
298+
[TestCase(true, "runas")]
299+
public void SetsRunAsAdminVerb(bool runAsAdmin, string expectedVerb)
300+
{
301+
var info = Create(runAsAdmin: runAsAdmin);
302+
303+
Assert.That(info.Verb, Is.EqualTo(expectedVerb));
304+
}
305+
306+
[TestCase(Shell.Cmd)]
307+
[TestCase(Shell.Powershell)]
308+
[TestCase(Shell.Pwsh)]
309+
[TestCase(Shell.RunCommand)]
310+
public void SetsWorkingDirectory(Shell shell)
311+
{
312+
var info = Create(shell: shell);
313+
314+
var expected = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
315+
Assert.That(info.WorkingDirectory, Is.EqualTo(expected));
316+
}
317+
318+
[TestCase(Shell.Cmd)]
319+
[TestCase(Shell.Powershell)]
320+
[TestCase(Shell.Pwsh)]
321+
[TestCase(Shell.RunCommand)]
322+
public void SetsUseShellExecute(Shell shell)
323+
{
324+
var info = Create(shell: shell);
325+
326+
Assert.That(info.UseShellExecute, Is.True);
327+
}
328+
329+
[TestCase(Shell.Cmd)]
330+
[TestCase(Shell.Powershell)]
331+
[TestCase(Shell.Pwsh)]
332+
[TestCase(Shell.RunCommand)]
333+
public void ExpandsEnvironmentVariables(Shell shell)
334+
{
335+
var info = Create(
336+
command: "%USERPROFILE%\\test",
337+
shell: shell);
338+
339+
var expandedPath = Environment.ExpandEnvironmentVariables("%USERPROFILE%\\test");
340+
341+
switch (shell)
342+
{
343+
case Shell.Cmd:
344+
Assert.That(info.Arguments, Is.EqualTo($"/c {expandedPath}"));
345+
break;
346+
case Shell.Powershell:
347+
case Shell.Pwsh:
348+
Assert.That(info.ArgumentList, Does.Contain(expandedPath + ";"));
349+
break;
350+
case Shell.RunCommand:
351+
Assert.That(info.FileName, Is.EqualTo(expandedPath));
352+
break;
353+
}
354+
}
355+
356+
#endregion
46357
}
47358
}

0 commit comments

Comments
 (0)