PowerRenameRegExTests.cpp
1 #include "pch.h" 2 #include "powerrename/lib/Settings.h" 3 #include <PowerRenameInterfaces.h> 4 #include <PowerRenameRegEx.h> 5 #include "MockPowerRenameRegExEvents.h" 6 7 using namespace Microsoft::VisualStudio::CppUnitTestFramework; 8 9 namespace PowerRenameRegExTests 10 { 11 TEST_CLASS(SimpleTests){ 12 public: 13 TEST_CLASS_INITIALIZE(ClassInitialize) 14 { 15 CSettingsInstance().SetUseBoostLib(false); 16 } 17 18 #define TESTS_PARTIAL 19 #include "CommonRegExTests.h" 20 21 TEST_METHOD(VerifyMatchAllWildcardUseRegEx) 22 { 23 CComPtr<IPowerRenameRegEx> renameRegEx; 24 Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK); 25 DWORD flags = MatchAllOccurrences | UseRegularExpressions; 26 Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK); 27 28 SearchReplaceExpected sreTable[] = { 29 { L".*", L"Foo", L"AAAAAA", L"Foo" }, 30 }; 31 32 for (int i = 0; i < ARRAYSIZE(sreTable); i++) 33 { 34 PWSTR result = nullptr; 35 Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK); 36 Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK); 37 unsigned long index = {}; 38 Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result, index) == S_OK); 39 Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0); 40 CoTaskMemFree(result); 41 } 42 } 43 44 TEST_METHOD(VerifyReplaceFirstWildCardUseRegexMatchAllOccurrences) 45 { 46 SearchReplaceExpected sreTable[] = { 47 //search, replace, test, result 48 { L".*", L"Foo", L"AAAAAA", L"Foo" }, 49 }; 50 VerifyReplaceFirstWildcard(sreTable, ARRAYSIZE(sreTable), UseRegularExpressions | MatchAllOccurrences); 51 } 52 53 TEST_METHOD(VerifyHandleCapturingGroups) 54 { 55 CComPtr<IPowerRenameRegEx> renameRegEx; 56 Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK); 57 DWORD flags = MatchAllOccurrences | UseRegularExpressions | CaseSensitive; 58 Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK); 59 60 SearchReplaceExpected sreTable[] = { 61 //search, replace, test, result 62 { L"(foo)(bar)", L"$1_$002_$223_$001021_$00001", L"foobar", L"foo_$002_bar23_$001021_$00001" }, 63 { L"(foo)(bar)", L"_$1$2_$123$040", L"foobar", L"_foobar_foo23$040" }, 64 { L"(foo)(bar)", L"$$$1", L"foobar", L"$foo" }, 65 { L"(foo)(bar)", L"$$1", L"foobar", L"$1" }, 66 { L"(foo)(bar)", L"$12", L"foobar", L"foo2" }, 67 { L"(foo)(bar)", L"$10", L"foobar", L"foo0" }, 68 { L"(foo)(bar)", L"$01", L"foobar", L"$01" }, 69 { L"(foo)(bar)", L"$$$11", L"foobar", L"$foo1" }, 70 { L"(foo)(bar)", L"$$$$113a", L"foobar", L"$$113a" }, 71 }; 72 73 for (int i = 0; i < ARRAYSIZE(sreTable); i++) 74 { 75 PWSTR result = nullptr; 76 Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK); 77 Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK); 78 unsigned long index = {}; 79 Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result, index) == S_OK); 80 Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0); 81 CoTaskMemFree(result); 82 } 83 } 84 85 TEST_METHOD (VerifyFileAttributesNoPadding) 86 { 87 CComPtr<IPowerRenameRegEx> renameRegEx; 88 Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK); 89 DWORD flags = MatchAllOccurrences | UseRegularExpressions ; 90 SYSTEMTIME fileTime = SYSTEMTIME{ 2020, 7, 3, 22, 15, 6, 42, 453 }; 91 Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK); 92 93 SearchReplaceExpected sreTable[] = { 94 //search, replace, test, result 95 { L"foo", L"bar$YY-$M-$D-$h-$m-$s-$f", L"foo", L"bar20-7-22-15-6-42-4" }, 96 }; 97 98 for (int i = 0; i < ARRAYSIZE(sreTable); i++) 99 { 100 PWSTR result = nullptr; 101 Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK); 102 Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK); 103 Assert::IsTrue(renameRegEx->PutFileTime(fileTime) == S_OK); 104 unsigned long index = {}; 105 Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result, index) == S_OK); 106 Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0); 107 CoTaskMemFree(result); 108 } 109 } 110 111 TEST_METHOD (VerifyFileAttributesPadding) 112 { 113 CComPtr<IPowerRenameRegEx> renameRegEx; 114 Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK); 115 DWORD flags = MatchAllOccurrences | UseRegularExpressions; 116 Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK); 117 SYSTEMTIME fileTime = SYSTEMTIME{ 2020, 7, 3, 22, 15, 6, 42, 453 }; 118 SearchReplaceExpected sreTable[] = { 119 //search, replace, test, result 120 { L"foo", L"bar$YYYY-$MM-$DD-$hh-$mm-$ss-$fff", L"foo", L"bar2020-07-22-15-06-42-453" }, 121 }; 122 123 for (int i = 0; i < ARRAYSIZE(sreTable); i++) 124 { 125 PWSTR result = nullptr; 126 Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK); 127 Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK); 128 Assert::IsTrue(renameRegEx->PutFileTime(fileTime) == S_OK); 129 unsigned long index = {}; 130 Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result, index) == S_OK); 131 Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0); 132 CoTaskMemFree(result); 133 } 134 } 135 136 TEST_METHOD (VerifyFileAttributesMonthAndDayNames) 137 { 138 CComPtr<IPowerRenameRegEx> renameRegEx; 139 Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK); 140 DWORD flags = MatchAllOccurrences | UseRegularExpressions; 141 Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK); 142 143 std::locale::global(std::locale("")); 144 SYSTEMTIME fileTime = { 2020, 1, 3, 1, 15, 6, 42, 453 }; 145 wchar_t localeName[LOCALE_NAME_MAX_LENGTH]; 146 wchar_t dest[MAX_PATH] = L"bar"; 147 wchar_t formattedDate[MAX_PATH]; 148 if (GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH) == 0) 149 StringCchCopy(localeName, LOCALE_NAME_MAX_LENGTH, L"en_US"); 150 151 GetDateFormatEx(localeName, NULL, &fileTime, L"MMM", formattedDate, MAX_PATH, NULL); 152 formattedDate[0] = towupper(formattedDate[0]); 153 StringCchPrintf(dest, MAX_PATH, TEXT("%s%s"), dest, formattedDate); 154 155 GetDateFormatEx(localeName, NULL, &fileTime, L"MMMM", formattedDate, MAX_PATH, NULL); 156 formattedDate[0] = towupper(formattedDate[0]); 157 StringCchPrintf(dest, MAX_PATH, TEXT("%s-%s"), dest, formattedDate); 158 159 GetDateFormatEx(localeName, NULL, &fileTime, L"ddd", formattedDate, MAX_PATH, NULL); 160 formattedDate[0] = towupper(formattedDate[0]); 161 StringCchPrintf(dest, MAX_PATH, TEXT("%s-%s"), dest, formattedDate); 162 163 GetDateFormatEx(localeName, NULL, &fileTime, L"dddd", formattedDate, MAX_PATH, NULL); 164 formattedDate[0] = towupper(formattedDate[0]); 165 StringCchPrintf(dest, MAX_PATH, TEXT("%s-%s"), dest, formattedDate); 166 167 SearchReplaceExpected sreTable[] = { 168 //search, replace, test, result 169 { L"foo", L"bar$MMM-$MMMM-$DDD-$DDDD", L"foo", dest }, 170 }; 171 172 for (int i = 0; i < ARRAYSIZE(sreTable); i++) 173 { 174 PWSTR result = nullptr; 175 Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK); 176 Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK); 177 Assert::IsTrue(renameRegEx->PutFileTime(fileTime) == S_OK); 178 unsigned long index = {}; 179 Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result, index) == S_OK); 180 Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0); 181 CoTaskMemFree(result); 182 } 183 } 184 185 TEST_METHOD(VerifyLookbehindFails) 186 { 187 // Standard Library Regex Engine does not support lookbehind, thus test should fail. 188 SearchReplaceExpected sreTable[] = { 189 //search, replace, test, result 190 { L"(?<=E12).*", L"Foo", L"AAAAAA", nullptr }, 191 { L"(?<!E12).*", L"Foo", L"AAAAAA", nullptr }, 192 }; 193 194 CComPtr<IPowerRenameRegEx> renameRegEx; 195 Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK); 196 Assert::IsTrue(renameRegEx->PutFlags(UseRegularExpressions) == S_OK); 197 198 for (int i = 0; i < ARRAYSIZE(sreTable); i++) 199 { 200 PWSTR result = nullptr; 201 Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK); 202 Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK); 203 unsigned long index = {}; 204 Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result, index) == E_FAIL); 205 Assert::AreEqual(sreTable[i].expected, result); 206 CoTaskMemFree(result); 207 } 208 } 209 210 TEST_METHOD (Verify12and24HourTimeFormats) 211 { 212 CComPtr<IPowerRenameRegEx> renameRegEx; 213 Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK); 214 DWORD flags = MatchAllOccurrences | UseRegularExpressions; 215 Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK); 216 217 struct TimeTestCase { 218 SYSTEMTIME time; // Input time 219 PCWSTR formatString; // Format pattern 220 PCWSTR expectedResult; // Expected output 221 PCWSTR description; // Description of what we're testing 222 }; 223 224 struct TimeTestCase testCases[] = { 225 // Midnight (00:00 / 12:00 AM) 226 { { 2025, 4, 4, 10, 0, 0, 0, 0 }, L"[$hh:$mm] [$H:$mm $tt]", L"[00:00] [12:00 am]", L"Midnight formatting" }, 227 228 // Noon (12:00 / 12:00 PM) 229 { { 2025, 4, 4, 10, 12, 0, 0, 0 }, L"[$hh:$mm] [$H:$mm $tt]", L"[12:00] [12:00 pm]", L"Noon formatting" }, 230 231 // 1:05 AM 232 { { 2025, 4, 4, 10, 1, 5, 0, 0 }, L"[$h:$m] [$H:$m $tt] [$hh:$mm] [$HH:$mm $TT]", 233 L"[1:5] [1:5 am] [01:05] [01:05 AM]", L"1 AM with various formats" }, 234 235 // 11 PM 236 { { 2025, 4, 4, 10, 23, 45, 0, 0 }, L"[$h:$m] [$H:$m $tt] [$hh:$mm] [$HH:$mm $TT]", 237 L"[23:45] [11:45 pm] [23:45] [11:45 PM]", L"11 PM with various formats" }, 238 239 // Mixed formats in complex pattern 240 { { 2025, 4, 4, 10, 14, 30, 0, 0 }, L"Date: $YYYY-$MM-$DD Time: $hh:$mm (24h) / $H:$mm $tt (12h)", 241 L"Date: 2025-04-10 Time: 14:30 (24h) / 2:30 pm (12h)", L"Complex combined format" }, 242 }; 243 244 for (int i = 0; i < ARRAYSIZE(testCases); i++) 245 { 246 PWSTR result = nullptr; 247 Assert::IsTrue(renameRegEx->PutSearchTerm(L"test") == S_OK); 248 Assert::IsTrue(renameRegEx->PutReplaceTerm(testCases[i].formatString) == S_OK); 249 Assert::IsTrue(renameRegEx->PutFileTime(testCases[i].time) == S_OK); 250 unsigned long index = {}; 251 Assert::IsTrue(renameRegEx->Replace(L"test", &result, index) == S_OK); 252 Assert::IsTrue(wcscmp(result, testCases[i].expectedResult) == 0, 253 (std::wstring(L"Failed test case: ") + testCases[i].description).c_str()); 254 CoTaskMemFree(result); 255 } 256 } 257 258 }; 259 }