Skip to content

Commit 319f594

Browse files
committed
Modified tests that starts processes to use the new console attribute set to false to prevent window flicker while running tests.
Modified tests that started/killed notepad.exe to use calc.exe instead. This change prevents killing potentially open/unsaved documents.
1 parent 0bbeb19 commit 319f594

File tree

7 files changed

+173
-27
lines changed

7 files changed

+173
-27
lines changed

src/tests/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ add_executable(sa.tests
149149

150150
# Group external files as filter for Visual Studio
151151
source_group("Test Data Files" FILES ${CONFIGURATION_TEST_FILES})
152-
source_group("Test Source Files" FILES ${HEADER_AND_SOURCE_TEST_FILES})
152+
source_group("Test Source Files" FILES ${HEADER_AND_SOURCE_TEST_FILES} ${PLUGINS_TEST_FILES})
153153

154154
# Unit test projects requires to link with pthread if also linking with gtest
155155
if(NOT WIN32)

src/tests/TestActionExecute.cpp

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "rapidassist/environment.h"
3939
#include "rapidassist/process.h"
4040
#include "rapidassist/cli.h"
41+
#include "rapidassist/random.h"
4142

4243
#ifndef WIN32_LEAN_AND_MEAN
4344
#define WIN32_LEAN_AND_MEAN 1
@@ -55,14 +56,160 @@ namespace shellanything
5556
{
5657
namespace test
5758
{
59+
ra::strings::StringVector RunProcesAndCaptureOutput(const std::string& base_command)
60+
{
61+
static const ra::strings::StringVector EMPTY_LIST;
62+
63+
std::string random_value = ra::strings::ToString(ra::random::GetRandomInt(0, 32767) + 10000);
64+
std::string temp_file = ra::filesystem::GetTemporaryDirectory() + "\\" + __FUNCTION__ + "." + random_value + ".tmp";
65+
ra::strings::Replace(temp_file, "::", ".");
66+
67+
// Execute
68+
std::string full_command = base_command + ">" + temp_file;
69+
int exit_code = system(full_command.c_str());
70+
71+
if (exit_code != 0)
72+
return EMPTY_LIST; // error
73+
74+
ra::strings::StringVector output;
75+
bool success_read = ra::filesystem::ReadTextFile(temp_file, output);
76+
if (!success_read)
77+
return EMPTY_LIST;
78+
79+
return output;
80+
}
81+
82+
size_t FindValue(const ra::strings::StringVector& list_values, const std::string& query_value)
83+
{
84+
for (size_t i = 0; i < list_values.size(); i++)
85+
{
86+
const std::string& list_value = list_values[i];
87+
if (query_value == list_value)
88+
return i;
89+
}
90+
return std::string::npos;
91+
}
92+
93+
ra::strings::StringVector FindNewValues(const ra::strings::StringVector& baseline_values, const ra::strings::StringVector& current_values)
94+
{
95+
ra::strings::StringVector new_values;
96+
97+
for (size_t i = 0; i < current_values.size(); i++)
98+
{
99+
const std::string& current_value = current_values[i];
100+
size_t find_pos = FindValue(baseline_values, current_value);
101+
if (find_pos == std::string::npos)
102+
{
103+
// This is a new value
104+
new_values.push_back(current_value);
105+
}
106+
}
107+
108+
return new_values;
109+
}
110+
58111
void KillCalculatorProcess()
59112
{
113+
printf("Killing all calculator processes...\n");
114+
60115
system("cmd.exe /c taskkill /IM calc.exe >NUL 2>NUL");
61116

62117
// On Windows 10, calc.exe launches Calculator which is an application in the Microsoft App Store.
63118
//The executable path is something similar to C:\Program Files\WindowsApps\Microsoft.WindowsCalculator_10.2103.8.0_x64__8wbfmf6g6wwcr\Calculator.exe
64119
system("cmd.exe /c WMIC PROCESS WHERE \"ExecutablePath like '%%Microsoft.WindowsCalculator%%Calculator.exe'\" DELETE >NUL 2>NUL");
65120
system("cmd.exe /c WMIC PROCESS WHERE \"ExecutablePath like '%%Microsoft.WindowsCalculator%%CalculatorApp.exe'\" DELETE >NUL 2>NUL");
121+
122+
ra::timing::Millisleep(1000);
123+
124+
printf("killed.\n");
125+
}
126+
127+
bool StartCalculatorProcess(ra::process::processid_t & pId)
128+
{
129+
// https://stackoverflow.com/questions/63990787/the-process-id-returned-by-the-createprocess-function-is-different-from-the-task
130+
// calc.exe is a stub/proxy which will launch the actual CalculatorApp.exe.
131+
// For my system, thats is "C:\Program Files\WindowsApps\Microsoft.WindowsCalculator_11.2405.2.0_x64__8wekyb3d8bbwe\CalculatorApp.exe"
132+
// However, a normal user cannot launch this process:
133+
// Windows cannot access the specified device, path, or file.You may not have the appropriate permissions to access the item.
134+
// So we hack our way and try our best to detect it...
135+
//
136+
137+
138+
/*
139+
PropertyManager& pmgr = PropertyManager::GetInstance();
140+
printf("Starting calc.exe...\n");
141+
142+
SelectionContext c;
143+
{
144+
StringList elements;
145+
elements.push_back("C:\\Windows\\System32\\cmd.exe");
146+
c.SetElements(elements);
147+
}
148+
149+
ActionExecute ae;
150+
ae.SetPath("C:\\Windows\\System32\\calc.exe");
151+
ae.SetPid("tmp.pid");
152+
153+
bool executed = ae.Execute(c);
154+
if (!executed)
155+
{
156+
printf("error: not started.\n");
157+
return false;
158+
}
159+
160+
ra::timing::Millisleep(2000);
161+
162+
bool parsed = ra::strings::Parse(pmgr.GetProperty("tmp.pid"), pId);
163+
if (!parsed)
164+
{
165+
printf("error: unknown pid.\n");
166+
return false;
167+
}
168+
169+
printf("started.\n");
170+
return true;
171+
*/
172+
173+
printf("Starting calc.exe...\n");
174+
175+
static const std::string base_command = "powershell -ExecutionPolicy bypass -Command \"Get-Process | Where{ $_.ProcessName -eq 'CalculatorApp' } | Select -ExpandProperty 'Id'\"";
176+
ra::strings::StringVector baseline_processes = RunProcesAndCaptureOutput(base_command);
177+
178+
system("start \"\" calc.exe >NUL 2>NUL");
179+
180+
double start = ra::timing::GetMillisecondsTimer();
181+
double elapsed_ms = ra::timing::GetMillisecondsTimer() - start;
182+
while (pId == 0 && elapsed_ms < 2500)
183+
{
184+
ra::timing::Millisleep(250);
185+
186+
// Search for a new process
187+
ra::strings::StringVector new_processes = RunProcesAndCaptureOutput(base_command);
188+
189+
// Check for new values
190+
ra::strings::StringVector new_values = FindNewValues(baseline_processes, new_processes);
191+
if (new_values.size() >= 1)
192+
{
193+
// This is the one
194+
std::string pid_str = new_values[0];
195+
196+
bool parsed = ra::strings::Parse(pid_str, pId);
197+
if (parsed)
198+
{
199+
printf("started.\n");
200+
return true;
201+
}
202+
203+
// We failed parsing, ignore this value for the next pass.
204+
baseline_processes.push_back(pid_str);
205+
}
206+
207+
// refresh timers
208+
elapsed_ms = ra::timing::GetMillisecondsTimer() - start;
209+
}
210+
211+
printf("error: not running.\n");
212+
return false;
66213
}
67214

68215
namespace FindProcessWindows

src/tests/TestPlugins.cpp

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "PropertyManager.h"
2929
#include "SelectionContext.h"
3030
#include "SelectionContext.h"
31+
#include "ActionExecute.h"
3132

3233
#include "rapidassist/testing.h"
3334
#include "rapidassist/filesystem.h"
@@ -39,6 +40,9 @@ namespace shellanything
3940
{
4041
namespace test
4142
{
43+
extern void KillCalculatorProcess();
44+
extern bool StartCalculatorProcess(ra::process::processid_t& pId);
45+
4246
static const ConfigFile* INVALID_CONFIGURATION = NULL;
4347

4448
//--------------------------------------------------------------------------------------------------
@@ -160,10 +164,8 @@ namespace shellanything
160164
//Disable process id property
161165
pmgr.SetProperty("sa_plugin_process.pid", "");
162166

163-
//Kill all instances of notepad.exe
164-
printf("Killing notepad.exe processes...\n");
165-
system("taskkill /F /IM notepad.exe");
166-
printf("done.\n");
167+
//Kill all instances of calc.exe
168+
KillCalculatorProcess();
167169

168170
//Set all menus visible
169171
for (size_t i = 0; i < menus.size(); i++)
@@ -192,12 +194,9 @@ namespace shellanything
192194
ASSERT_FALSE(menu->IsVisible()) << "menu[" << i << "] named '" << menu->GetName() << "' should be invisible";
193195
}
194196

195-
//Start notepad
196-
printf("Starting notepad.exe...\n");
197-
ra::process::processid_t notepad_pid = ra::process::StartProcess("C:\\Windows\\System32\\notepad.exe");
198-
ra::timing::Millisleep(2000);
199-
ASSERT_NE(0, notepad_pid);
200-
printf("done.\n");
197+
//Start calc
198+
ra::process::processid_t pId = 0;
199+
ASSERT_TRUE( StartCalculatorProcess(pId) );
201200

202201
//Set all menus visible
203202
for (size_t i = 0; i < menus.size(); i++)
@@ -222,8 +221,8 @@ namespace shellanything
222221
menu->SetVisible(false);
223222
}
224223

225-
std::string notepad_pid_str = ra::strings::ToString(notepad_pid);
226-
pmgr.SetProperty("sa_plugin_process.pid", notepad_pid_str);
224+
// Change a property which is used by menus to filter visibility by pid
225+
pmgr.SetProperty("sa_plugin_process.pid", ra::strings::ToString(pId));
227226

228227
//Update menus again
229228
config0->Update(c);
@@ -236,7 +235,7 @@ namespace shellanything
236235
}
237236

238237
//Cleanup
239-
ra::process::Kill(notepad_pid);
238+
KillCalculatorProcess();
240239
ASSERT_TRUE(workspace.Cleanup()) << "Failed deleting workspace directory '" << workspace.GetBaseDirectory() << "'.";
241240
}
242241
//--------------------------------------------------------------------------------------------------

src/tests/test_files/TestActionExecute.testWaitInfinite.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
<menu name="menu">
66
<actions>
7-
<exec path="powershell.exe" arguments="-nologo -executionpolicy bypass -Command &quot;Start-Sleep -Seconds 10&quot;" wait="true" />
7+
<exec path="powershell.exe" arguments="-nologo -executionpolicy bypass -Command &quot;Start-Sleep -Seconds 10&quot;" wait="true" console="false" />
88
</actions>
99
</menu>
1010

src/tests/test_files/TestActionExecute.testWaitTimeout.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
<menu name="expected_exec_timeout">
66
<actions>
7-
<exec path="powershell.exe" arguments="-nologo -executionpolicy bypass -Command &quot;Start-Sleep -Seconds 30&quot;" wait="true" timeout="10" />
7+
<exec path="powershell.exe" arguments="-nologo -executionpolicy bypass -Command &quot;Start-Sleep -Seconds 30&quot;" wait="true" timeout="10" console="false" />
88
</actions>
99
</menu>
1010

src/tests/test_files/TestActionProperty.testLiveProperties.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,23 @@
55
<menu name="Test">
66
<actions>
77
<!-- Setting the clipboard from outside of the scope of ShellAnything -->
8-
<exec path="powershell.exe" arguments="Set-Clipboard -Value &quot;Luke&quot;" wait="true" timeout="10" />
8+
<exec path="powershell.exe" arguments="Set-Clipboard -Value &quot;Luke&quot;" wait="true" timeout="10" console="false" />
99

1010
<!-- Expect the live property `clipboard` is updated -->
1111
<property name="character1" value="${clipboard}" />
1212

1313

1414

1515
<!-- Setting the clipboard from outside of the scope of ShellAnything -->
16-
<exec path="powershell.exe" arguments="Set-Clipboard -Value &quot;Leia&quot;" wait="true" timeout="10" />
16+
<exec path="powershell.exe" arguments="Set-Clipboard -Value &quot;Leia&quot;" wait="true" timeout="10" console="false" />
1717

1818
<!-- Expect the live property `clipboard` is updated -->
1919
<property name="character2" value="${clipboard}" />
2020

2121

2222

2323
<!-- Setting the clipboard from outside of the scope of ShellAnything -->
24-
<exec path="powershell.exe" arguments="Set-Clipboard -Value &quot;Han&quot;" wait="true" timeout="10" />
24+
<exec path="powershell.exe" arguments="Set-Clipboard -Value &quot;Han&quot;" wait="true" timeout="10" console="false" />
2525

2626
<!-- Expect the live property `clipboard` is updated -->
2727
<property name="character3" value="${clipboard}" />

src/tests/test_files/TestPlugins.testProcess.xml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,28 +14,28 @@
1414
</plugins>
1515
<shell>
1616

17-
<menu name="Terminate Notepad (by filename)">
18-
<visibility process_filename="notepad.exe" />
17+
<menu name="Terminate Calc (by filename)">
18+
<visibility process_filename="CalculatorApp.exe" />
1919
<actions>
20-
<terminateprocess filename="notepad.exe" />
20+
<terminateprocess filename="CalculatorApp.exe" />
2121
</actions>
2222
</menu>
2323

24-
<menu name="Terminate Notepad (by pid)">
24+
<menu name="Terminate Calc (by pid)">
2525
<visibility process_pid="${sa_plugin_process.pid}" />
2626
<actions>
2727
<terminateprocess pid="${sa_plugin_process.pid}" />
2828
</actions>
2929
</menu>
3030

31-
<menu name="Kill Notepad (by filename)">
32-
<visibility process_filename="notepad.exe" />
31+
<menu name="Kill Calc (by filename)">
32+
<visibility process_filename="CalculatorApp.exe" />
3333
<actions>
34-
<killprocess filename="notepad.exe" />
34+
<killprocess filename="CalculatorApp.exe" />
3535
</actions>
3636
</menu>
3737

38-
<menu name="Kill Notepad (by pid)">
38+
<menu name="Kill Calc (by pid)">
3939
<visibility process_pid="${sa_plugin_process.pid}" />
4040
<actions>
4141
<killprocess pid="${sa_plugin_process.pid}" />

0 commit comments

Comments
 (0)