/ src / common / UnitTests-CommonUtils / UnhandledException.Tests.cpp
UnhandledException.Tests.cpp
  1  #include "pch.h"
  2  #include "TestHelpers.h"
  3  #include <UnhandledExceptionHandler.h>
  4  
  5  using namespace Microsoft::VisualStudio::CppUnitTestFramework;
  6  
  7  namespace UnitTestsCommonUtils
  8  {
  9      TEST_CLASS(UnhandledExceptionTests)
 10      {
 11      public:
 12          // exceptionDescription tests
 13          TEST_METHOD(ExceptionDescription_AccessViolation_ReturnsDescription)
 14          {
 15              auto result = exceptionDescription(EXCEPTION_ACCESS_VIOLATION);
 16              Assert::IsTrue(result && *result != '\0');
 17              // Should contain meaningful description
 18              std::string desc{ result };
 19              Assert::IsTrue(desc.find("ACCESS") != std::string::npos ||
 20                            desc.find("access") != std::string::npos ||
 21                            desc.find("violation") != std::string::npos ||
 22                            desc.length() > 0);
 23          }
 24  
 25          TEST_METHOD(ExceptionDescription_StackOverflow_ReturnsDescription)
 26          {
 27              auto result = exceptionDescription(EXCEPTION_STACK_OVERFLOW);
 28              Assert::IsTrue(result && *result != '\0');
 29          }
 30  
 31          TEST_METHOD(ExceptionDescription_DivideByZero_ReturnsDescription)
 32          {
 33              auto result = exceptionDescription(EXCEPTION_INT_DIVIDE_BY_ZERO);
 34              Assert::IsTrue(result && *result != '\0');
 35          }
 36  
 37          TEST_METHOD(ExceptionDescription_IllegalInstruction_ReturnsDescription)
 38          {
 39              auto result = exceptionDescription(EXCEPTION_ILLEGAL_INSTRUCTION);
 40              Assert::IsTrue(result && *result != '\0');
 41          }
 42  
 43          TEST_METHOD(ExceptionDescription_ArrayBoundsExceeded_ReturnsDescription)
 44          {
 45              auto result = exceptionDescription(EXCEPTION_ARRAY_BOUNDS_EXCEEDED);
 46              Assert::IsTrue(result && *result != '\0');
 47          }
 48  
 49          TEST_METHOD(ExceptionDescription_Breakpoint_ReturnsDescription)
 50          {
 51              auto result = exceptionDescription(EXCEPTION_BREAKPOINT);
 52              Assert::IsTrue(result && *result != '\0');
 53          }
 54  
 55          TEST_METHOD(ExceptionDescription_SingleStep_ReturnsDescription)
 56          {
 57              auto result = exceptionDescription(EXCEPTION_SINGLE_STEP);
 58              Assert::IsTrue(result && *result != '\0');
 59          }
 60  
 61          TEST_METHOD(ExceptionDescription_FloatDivideByZero_ReturnsDescription)
 62          {
 63              auto result = exceptionDescription(EXCEPTION_FLT_DIVIDE_BY_ZERO);
 64              Assert::IsTrue(result && *result != '\0');
 65          }
 66  
 67          TEST_METHOD(ExceptionDescription_FloatOverflow_ReturnsDescription)
 68          {
 69              auto result = exceptionDescription(EXCEPTION_FLT_OVERFLOW);
 70              Assert::IsTrue(result && *result != '\0');
 71          }
 72  
 73          TEST_METHOD(ExceptionDescription_FloatUnderflow_ReturnsDescription)
 74          {
 75              auto result = exceptionDescription(EXCEPTION_FLT_UNDERFLOW);
 76              Assert::IsTrue(result && *result != '\0');
 77          }
 78  
 79          TEST_METHOD(ExceptionDescription_FloatInvalidOperation_ReturnsDescription)
 80          {
 81              auto result = exceptionDescription(EXCEPTION_FLT_INVALID_OPERATION);
 82              Assert::IsTrue(result && *result != '\0');
 83          }
 84  
 85          TEST_METHOD(ExceptionDescription_PrivilegedInstruction_ReturnsDescription)
 86          {
 87              auto result = exceptionDescription(EXCEPTION_PRIV_INSTRUCTION);
 88              Assert::IsTrue(result && *result != '\0');
 89          }
 90  
 91          TEST_METHOD(ExceptionDescription_InPageError_ReturnsDescription)
 92          {
 93              auto result = exceptionDescription(EXCEPTION_IN_PAGE_ERROR);
 94              Assert::IsTrue(result && *result != '\0');
 95          }
 96  
 97          TEST_METHOD(ExceptionDescription_UnknownCode_ReturnsDescription)
 98          {
 99              auto result = exceptionDescription(0x12345678);
100              // Should return something (possibly "Unknown exception" or similar)
101              Assert::IsTrue(result && *result != '\0');
102          }
103  
104          TEST_METHOD(ExceptionDescription_ZeroCode_ReturnsDescription)
105          {
106              auto result = exceptionDescription(0);
107              // Should handle zero gracefully
108              Assert::IsTrue(result && *result != '\0');
109          }
110  
111          // GetFilenameStart tests (if accessible)
112          TEST_METHOD(GetFilenameStart_ValidPath_ReturnsFilename)
113          {
114              wchar_t path[] = L"C:\\folder\\subfolder\\file.exe";
115              int start = GetFilenameStart(path);
116  
117              Assert::IsTrue(start >= 0);
118              Assert::AreEqual(std::wstring(L"file.exe"), std::wstring(path + start));
119          }
120  
121          TEST_METHOD(GetFilenameStart_NoPath_ReturnsOriginal)
122          {
123              wchar_t path[] = L"file.exe";
124              int start = GetFilenameStart(path);
125  
126              Assert::IsTrue(start >= 0);
127              Assert::AreEqual(std::wstring(L"file.exe"), std::wstring(path + start));
128          }
129  
130          TEST_METHOD(GetFilenameStart_TrailingBackslash_ReturnsEmpty)
131          {
132              wchar_t path[] = L"C:\\folder\\";
133              int start = GetFilenameStart(path);
134  
135              // Should point to empty string after last backslash
136              Assert::IsTrue(start >= 0);
137          }
138  
139          TEST_METHOD(GetFilenameStart_NullPath_HandlesGracefully)
140          {
141              // This might crash or return null depending on implementation
142              // Just document the behavior
143              int start = GetFilenameStart(nullptr);
144              (void)start;
145              // Result is implementation-defined for null input
146              Assert::IsTrue(true);
147          }
148  
149          // Thread safety tests
150          TEST_METHOD(ExceptionDescription_ThreadSafe)
151          {
152              std::vector<std::thread> threads;
153              std::atomic<int> successCount{ 0 };
154  
155              for (int i = 0; i < 10; ++i)
156              {
157                  threads.emplace_back([&successCount]() {
158                      for (int j = 0; j < 10; ++j)
159                      {
160                          auto desc = exceptionDescription(EXCEPTION_ACCESS_VIOLATION);
161                          if (desc && *desc != '\0')
162                          {
163                              successCount++;
164                          }
165                      }
166                  });
167              }
168  
169              for (auto& t : threads)
170              {
171                  t.join();
172              }
173  
174              Assert::AreEqual(100, successCount.load());
175          }
176  
177          // All exception codes test
178          TEST_METHOD(ExceptionDescription_AllCommonCodes_ReturnDescriptions)
179          {
180              std::vector<DWORD> codes = {
181                  EXCEPTION_ACCESS_VIOLATION,
182                  EXCEPTION_ARRAY_BOUNDS_EXCEEDED,
183                  EXCEPTION_BREAKPOINT,
184                  EXCEPTION_DATATYPE_MISALIGNMENT,
185                  EXCEPTION_FLT_DENORMAL_OPERAND,
186                  EXCEPTION_FLT_DIVIDE_BY_ZERO,
187                  EXCEPTION_FLT_INEXACT_RESULT,
188                  EXCEPTION_FLT_INVALID_OPERATION,
189                  EXCEPTION_FLT_OVERFLOW,
190                  EXCEPTION_FLT_STACK_CHECK,
191                  EXCEPTION_FLT_UNDERFLOW,
192                  EXCEPTION_ILLEGAL_INSTRUCTION,
193                  EXCEPTION_IN_PAGE_ERROR,
194                  EXCEPTION_INT_DIVIDE_BY_ZERO,
195                  EXCEPTION_INT_OVERFLOW,
196                  EXCEPTION_INVALID_DISPOSITION,
197                  EXCEPTION_NONCONTINUABLE_EXCEPTION,
198                  EXCEPTION_PRIV_INSTRUCTION,
199                  EXCEPTION_SINGLE_STEP,
200                  EXCEPTION_STACK_OVERFLOW
201              };
202  
203              for (DWORD code : codes)
204              {
205                  auto desc = exceptionDescription(code);
206                  Assert::IsTrue(desc && *desc != '\0', (L"Empty description for code: " + std::to_wstring(code)).c_str());
207              }
208          }
209      };
210  }