mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-02-23 19:49:43 +01:00
<!-- 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
211 lines
7.4 KiB
C++
211 lines
7.4 KiB
C++
#include "pch.h"
|
|
#include "TestHelpers.h"
|
|
#include <UnhandledExceptionHandler.h>
|
|
|
|
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
|
|
|
namespace UnitTestsCommonUtils
|
|
{
|
|
TEST_CLASS(UnhandledExceptionTests)
|
|
{
|
|
public:
|
|
// exceptionDescription tests
|
|
TEST_METHOD(ExceptionDescription_AccessViolation_ReturnsDescription)
|
|
{
|
|
auto result = exceptionDescription(EXCEPTION_ACCESS_VIOLATION);
|
|
Assert::IsTrue(result && *result != '\0');
|
|
// Should contain meaningful description
|
|
std::string desc{ result };
|
|
Assert::IsTrue(desc.find("ACCESS") != std::string::npos ||
|
|
desc.find("access") != std::string::npos ||
|
|
desc.find("violation") != std::string::npos ||
|
|
desc.length() > 0);
|
|
}
|
|
|
|
TEST_METHOD(ExceptionDescription_StackOverflow_ReturnsDescription)
|
|
{
|
|
auto result = exceptionDescription(EXCEPTION_STACK_OVERFLOW);
|
|
Assert::IsTrue(result && *result != '\0');
|
|
}
|
|
|
|
TEST_METHOD(ExceptionDescription_DivideByZero_ReturnsDescription)
|
|
{
|
|
auto result = exceptionDescription(EXCEPTION_INT_DIVIDE_BY_ZERO);
|
|
Assert::IsTrue(result && *result != '\0');
|
|
}
|
|
|
|
TEST_METHOD(ExceptionDescription_IllegalInstruction_ReturnsDescription)
|
|
{
|
|
auto result = exceptionDescription(EXCEPTION_ILLEGAL_INSTRUCTION);
|
|
Assert::IsTrue(result && *result != '\0');
|
|
}
|
|
|
|
TEST_METHOD(ExceptionDescription_ArrayBoundsExceeded_ReturnsDescription)
|
|
{
|
|
auto result = exceptionDescription(EXCEPTION_ARRAY_BOUNDS_EXCEEDED);
|
|
Assert::IsTrue(result && *result != '\0');
|
|
}
|
|
|
|
TEST_METHOD(ExceptionDescription_Breakpoint_ReturnsDescription)
|
|
{
|
|
auto result = exceptionDescription(EXCEPTION_BREAKPOINT);
|
|
Assert::IsTrue(result && *result != '\0');
|
|
}
|
|
|
|
TEST_METHOD(ExceptionDescription_SingleStep_ReturnsDescription)
|
|
{
|
|
auto result = exceptionDescription(EXCEPTION_SINGLE_STEP);
|
|
Assert::IsTrue(result && *result != '\0');
|
|
}
|
|
|
|
TEST_METHOD(ExceptionDescription_FloatDivideByZero_ReturnsDescription)
|
|
{
|
|
auto result = exceptionDescription(EXCEPTION_FLT_DIVIDE_BY_ZERO);
|
|
Assert::IsTrue(result && *result != '\0');
|
|
}
|
|
|
|
TEST_METHOD(ExceptionDescription_FloatOverflow_ReturnsDescription)
|
|
{
|
|
auto result = exceptionDescription(EXCEPTION_FLT_OVERFLOW);
|
|
Assert::IsTrue(result && *result != '\0');
|
|
}
|
|
|
|
TEST_METHOD(ExceptionDescription_FloatUnderflow_ReturnsDescription)
|
|
{
|
|
auto result = exceptionDescription(EXCEPTION_FLT_UNDERFLOW);
|
|
Assert::IsTrue(result && *result != '\0');
|
|
}
|
|
|
|
TEST_METHOD(ExceptionDescription_FloatInvalidOperation_ReturnsDescription)
|
|
{
|
|
auto result = exceptionDescription(EXCEPTION_FLT_INVALID_OPERATION);
|
|
Assert::IsTrue(result && *result != '\0');
|
|
}
|
|
|
|
TEST_METHOD(ExceptionDescription_PrivilegedInstruction_ReturnsDescription)
|
|
{
|
|
auto result = exceptionDescription(EXCEPTION_PRIV_INSTRUCTION);
|
|
Assert::IsTrue(result && *result != '\0');
|
|
}
|
|
|
|
TEST_METHOD(ExceptionDescription_InPageError_ReturnsDescription)
|
|
{
|
|
auto result = exceptionDescription(EXCEPTION_IN_PAGE_ERROR);
|
|
Assert::IsTrue(result && *result != '\0');
|
|
}
|
|
|
|
TEST_METHOD(ExceptionDescription_UnknownCode_ReturnsDescription)
|
|
{
|
|
auto result = exceptionDescription(0x12345678);
|
|
// Should return something (possibly "Unknown exception" or similar)
|
|
Assert::IsTrue(result && *result != '\0');
|
|
}
|
|
|
|
TEST_METHOD(ExceptionDescription_ZeroCode_ReturnsDescription)
|
|
{
|
|
auto result = exceptionDescription(0);
|
|
// Should handle zero gracefully
|
|
Assert::IsTrue(result && *result != '\0');
|
|
}
|
|
|
|
// GetFilenameStart tests (if accessible)
|
|
TEST_METHOD(GetFilenameStart_ValidPath_ReturnsFilename)
|
|
{
|
|
wchar_t path[] = L"C:\\folder\\subfolder\\file.exe";
|
|
int start = GetFilenameStart(path);
|
|
|
|
Assert::IsTrue(start >= 0);
|
|
Assert::AreEqual(std::wstring(L"file.exe"), std::wstring(path + start));
|
|
}
|
|
|
|
TEST_METHOD(GetFilenameStart_NoPath_ReturnsOriginal)
|
|
{
|
|
wchar_t path[] = L"file.exe";
|
|
int start = GetFilenameStart(path);
|
|
|
|
Assert::IsTrue(start >= 0);
|
|
Assert::AreEqual(std::wstring(L"file.exe"), std::wstring(path + start));
|
|
}
|
|
|
|
TEST_METHOD(GetFilenameStart_TrailingBackslash_ReturnsEmpty)
|
|
{
|
|
wchar_t path[] = L"C:\\folder\\";
|
|
int start = GetFilenameStart(path);
|
|
|
|
// Should point to empty string after last backslash
|
|
Assert::IsTrue(start >= 0);
|
|
}
|
|
|
|
TEST_METHOD(GetFilenameStart_NullPath_HandlesGracefully)
|
|
{
|
|
// This might crash or return null depending on implementation
|
|
// Just document the behavior
|
|
int start = GetFilenameStart(nullptr);
|
|
(void)start;
|
|
// Result is implementation-defined for null input
|
|
Assert::IsTrue(true);
|
|
}
|
|
|
|
// Thread safety tests
|
|
TEST_METHOD(ExceptionDescription_ThreadSafe)
|
|
{
|
|
std::vector<std::thread> threads;
|
|
std::atomic<int> successCount{ 0 };
|
|
|
|
for (int i = 0; i < 10; ++i)
|
|
{
|
|
threads.emplace_back([&successCount]() {
|
|
for (int j = 0; j < 10; ++j)
|
|
{
|
|
auto desc = exceptionDescription(EXCEPTION_ACCESS_VIOLATION);
|
|
if (desc && *desc != '\0')
|
|
{
|
|
successCount++;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
for (auto& t : threads)
|
|
{
|
|
t.join();
|
|
}
|
|
|
|
Assert::AreEqual(100, successCount.load());
|
|
}
|
|
|
|
// All exception codes test
|
|
TEST_METHOD(ExceptionDescription_AllCommonCodes_ReturnDescriptions)
|
|
{
|
|
std::vector<DWORD> codes = {
|
|
EXCEPTION_ACCESS_VIOLATION,
|
|
EXCEPTION_ARRAY_BOUNDS_EXCEEDED,
|
|
EXCEPTION_BREAKPOINT,
|
|
EXCEPTION_DATATYPE_MISALIGNMENT,
|
|
EXCEPTION_FLT_DENORMAL_OPERAND,
|
|
EXCEPTION_FLT_DIVIDE_BY_ZERO,
|
|
EXCEPTION_FLT_INEXACT_RESULT,
|
|
EXCEPTION_FLT_INVALID_OPERATION,
|
|
EXCEPTION_FLT_OVERFLOW,
|
|
EXCEPTION_FLT_STACK_CHECK,
|
|
EXCEPTION_FLT_UNDERFLOW,
|
|
EXCEPTION_ILLEGAL_INSTRUCTION,
|
|
EXCEPTION_IN_PAGE_ERROR,
|
|
EXCEPTION_INT_DIVIDE_BY_ZERO,
|
|
EXCEPTION_INT_OVERFLOW,
|
|
EXCEPTION_INVALID_DISPOSITION,
|
|
EXCEPTION_NONCONTINUABLE_EXCEPTION,
|
|
EXCEPTION_PRIV_INSTRUCTION,
|
|
EXCEPTION_SINGLE_STEP,
|
|
EXCEPTION_STACK_OVERFLOW
|
|
};
|
|
|
|
for (DWORD code : codes)
|
|
{
|
|
auto desc = exceptionDescription(code);
|
|
Assert::IsTrue(desc && *desc != '\0', (L"Empty description for code: " + std::to_wstring(code)).c_str());
|
|
}
|
|
}
|
|
};
|
|
}
|