Files
PowerToys/src/common/UnitTests-CommonUtils/ProcessApi.Tests.cpp
Kai Tao 27ba536872 UT: Add ut to protect common utils codes (#45290)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
As title

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Tests should be picked up and run and pass
2026-02-03 15:12:45 +08:00

137 lines
4.7 KiB
C++

#include "pch.h"
#include "TestHelpers.h"
#include <processApi.h>
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace UnitTestsCommonUtils
{
TEST_CLASS(ProcessApiTests)
{
public:
TEST_METHOD(GetProcessHandlesByName_CurrentProcess_ReturnsHandles)
{
// Get current process executable name
wchar_t path[MAX_PATH];
GetModuleFileNameW(nullptr, path, MAX_PATH);
// Extract just the filename
std::wstring fullPath(path);
auto lastSlash = fullPath.rfind(L'\\');
std::wstring exeName = (lastSlash != std::wstring::npos) ?
fullPath.substr(lastSlash + 1) : fullPath;
auto handles = getProcessHandlesByName(exeName, PROCESS_QUERY_LIMITED_INFORMATION);
// Should find at least our own process
Assert::IsFalse(handles.empty());
// Handles are RAII-managed
}
TEST_METHOD(GetProcessHandlesByName_NonExistentProcess_ReturnsEmpty)
{
auto handles = getProcessHandlesByName(L"NonExistentProcess12345.exe", PROCESS_QUERY_LIMITED_INFORMATION);
Assert::IsTrue(handles.empty());
}
TEST_METHOD(GetProcessHandlesByName_EmptyName_ReturnsEmpty)
{
auto handles = getProcessHandlesByName(L"", PROCESS_QUERY_LIMITED_INFORMATION);
Assert::IsTrue(handles.empty());
}
TEST_METHOD(GetProcessHandlesByName_Explorer_ReturnsHandles)
{
// Explorer.exe should typically be running
auto handles = getProcessHandlesByName(L"explorer.exe", PROCESS_QUERY_LIMITED_INFORMATION);
// Handles are RAII-managed
// May or may not find explorer depending on system state
// Just verify it doesn't crash
Assert::IsTrue(true);
}
TEST_METHOD(GetProcessHandlesByName_CaseInsensitive_Works)
{
// Get current process name in uppercase
wchar_t path[MAX_PATH];
GetModuleFileNameW(nullptr, path, MAX_PATH);
std::wstring fullPath(path);
auto lastSlash = fullPath.rfind(L'\\');
std::wstring exeName = (lastSlash != std::wstring::npos) ?
fullPath.substr(lastSlash + 1) : fullPath;
// Convert to uppercase
std::wstring upperName = exeName;
std::transform(upperName.begin(), upperName.end(), upperName.begin(), ::towupper);
auto handles = getProcessHandlesByName(upperName, PROCESS_QUERY_LIMITED_INFORMATION);
// Handles are RAII-managed
// The function may or may not be case insensitive - just don't crash
Assert::IsTrue(true);
}
TEST_METHOD(GetProcessHandlesByName_DifferentAccessRights_Works)
{
wchar_t path[MAX_PATH];
GetModuleFileNameW(nullptr, path, MAX_PATH);
std::wstring fullPath(path);
auto lastSlash = fullPath.rfind(L'\\');
std::wstring exeName = (lastSlash != std::wstring::npos) ?
fullPath.substr(lastSlash + 1) : fullPath;
// Try with different access rights
auto handles1 = getProcessHandlesByName(exeName, PROCESS_QUERY_INFORMATION);
auto handles2 = getProcessHandlesByName(exeName, PROCESS_VM_READ);
// Handles are RAII-managed
// Just verify no crashes
Assert::IsTrue(true);
}
TEST_METHOD(GetProcessHandlesByName_SystemProcess_MayRequireElevation)
{
// System processes might require elevation
auto handles = getProcessHandlesByName(L"System", PROCESS_QUERY_LIMITED_INFORMATION);
// Handles are RAII-managed
// Just verify no crashes
Assert::IsTrue(true);
}
TEST_METHOD(GetProcessHandlesByName_ValidHandles_AreUsable)
{
wchar_t path[MAX_PATH];
GetModuleFileNameW(nullptr, path, MAX_PATH);
std::wstring fullPath(path);
auto lastSlash = fullPath.rfind(L'\\');
std::wstring exeName = (lastSlash != std::wstring::npos) ?
fullPath.substr(lastSlash + 1) : fullPath;
auto handles = getProcessHandlesByName(exeName, PROCESS_QUERY_LIMITED_INFORMATION);
bool foundValidHandle = false;
for (auto& handle : handles)
{
// Try to use the handle
DWORD exitCode;
if (GetExitCodeProcess(handle.get(), &exitCode))
{
foundValidHandle = true;
}
}
Assert::IsTrue(foundValidHandle || handles.empty());
}
};
}