/ src / modules / powerrename / unittests / PowerRenameManagerTests.cpp
PowerRenameManagerTests.cpp
  1  #include "pch.h"
  2  #include <PowerRenameInterfaces.h>
  3  #include <PowerRenameManager.h>
  4  #include <PowerRenameItem.h>
  5  #include "MockPowerRenameItem.h"
  6  #include "MockPowerRenameManagerEvents.h"
  7  #include "TestFileHelper.h"
  8  #include "Helpers.h"
  9  
 10  #define DEFAULT_FLAGS 0
 11  
 12  using namespace Microsoft::VisualStudio::CppUnitTestFramework;
 13  
 14  EXTERN_C IMAGE_DOS_HEADER __ImageBase;
 15  
 16  #define HINST_THISCOMPONENT ((HINSTANCE)&__ImageBase)
 17  
 18  HINSTANCE g_hostHInst = HINST_THISCOMPONENT;
 19  
 20  namespace PowerRenameManagerTests
 21  {
 22      TEST_CLASS (SimpleTests)
 23      {
 24      public:
 25          struct rename_pairs
 26          {
 27              std::wstring originalName;
 28              std::wstring newName;
 29              bool isFile;
 30              bool shouldRename;
 31              int depth;
 32          };
 33  
 34          void RenameHelper(_In_ rename_pairs * renamePairs, _In_ int numPairs, _In_ std::wstring searchTerm, _In_ std::wstring replaceTerm, SYSTEMTIME fileTime, _In_ DWORD flags)
 35          {
 36              // Create a single item (in a temp directory) and verify rename works as expected
 37              CTestFileHelper testFileHelper;
 38              for (int i = 0; i < numPairs; i++)
 39              {
 40                  if (renamePairs[i].isFile)
 41                  {
 42                      Assert::IsTrue(testFileHelper.AddFile(renamePairs[i].originalName));
 43                  }
 44                  else
 45                  {
 46                      Assert::IsTrue(testFileHelper.AddFolder(renamePairs[i].originalName));
 47                  }
 48              }
 49  
 50              CComPtr<IPowerRenameManager> mgr;
 51              Assert::IsTrue(CPowerRenameManager::s_CreateInstance(&mgr) == S_OK);
 52              CMockPowerRenameManagerEvents* mockMgrEvents = new CMockPowerRenameManagerEvents();
 53              CComPtr<IPowerRenameManagerEvents> mgrEvents;
 54              Assert::IsTrue(mockMgrEvents->QueryInterface(IID_PPV_ARGS(&mgrEvents)) == S_OK);
 55              DWORD cookie = 0;
 56              Assert::IsTrue(mgr->Advise(mgrEvents, &cookie) == S_OK);
 57  
 58              for (int i = 0; i < numPairs; i++)
 59              {
 60                  CComPtr<IPowerRenameItem> item;
 61                  CMockPowerRenameItem::CreateInstance(testFileHelper.GetFullPath(renamePairs[i].originalName).c_str(),
 62                                                       renamePairs[i].originalName.c_str(),
 63                                                       renamePairs[i].depth,
 64                                                       !renamePairs[i].isFile,
 65                                                       fileTime,
 66                                                       &item);
 67  
 68                  int itemId = 0;
 69                  Assert::IsTrue(item->GetId(&itemId) == S_OK);
 70                  mgr->AddItem(item);
 71              }
 72  
 73              // TODO: Setup match and replace parameters
 74              CComPtr<IPowerRenameRegEx> renRegEx;
 75              Assert::IsTrue(mgr->GetRenameRegEx(&renRegEx) == S_OK);
 76              renRegEx->PutFlags(flags);
 77              renRegEx->PutSearchTerm(searchTerm.c_str());
 78              renRegEx->PutReplaceTerm(replaceTerm.c_str());
 79  
 80              // Perform the rename
 81              bool replaceSuccess = false;
 82              for (int step = 0; step < 20; step++)
 83              {
 84                  replaceSuccess = mgr->Rename(0, true) == S_OK;
 85                  if (replaceSuccess)
 86                  {
 87                      break;
 88                  }
 89                  Sleep(10);
 90              }
 91  
 92              Assert::IsTrue(replaceSuccess);
 93  
 94              std::vector<std::wstring> shouldRename = { L"not ", L"" };
 95  
 96              // Verify the rename occurred
 97              for (int i = 0; i < numPairs; i++)
 98              {
 99                  Assert::IsTrue(testFileHelper.PathExistsCaseSensitive(renamePairs[i].originalName) == !renamePairs[i].shouldRename, 
100                                 (std::wstring(L"The path: [" +  renamePairs[i].originalName + L"] should ") + shouldRename[!renamePairs[i].shouldRename] + L"exist.").c_str());
101                  Assert::IsTrue(testFileHelper.PathExistsCaseSensitive(renamePairs[i].newName) == renamePairs[i].shouldRename,
102                                 (std::wstring(L"The path: [" + renamePairs[i].newName + L"] should ") + shouldRename[renamePairs[i].shouldRename] + L"exist.").c_str());
103              }
104  
105              Assert::IsTrue(mgr->Shutdown() == S_OK);
106  
107              mockMgrEvents->Release();
108          }
109          TEST_METHOD (CreateTest)
110          {
111              CComPtr<IPowerRenameManager> mgr;
112              Assert::IsTrue(CPowerRenameManager::s_CreateInstance(&mgr) == S_OK);
113          }
114  
115          TEST_METHOD (CreateAndShutdownTest)
116          {
117              CComPtr<IPowerRenameManager> mgr;
118              Assert::IsTrue(CPowerRenameManager::s_CreateInstance(&mgr) == S_OK);
119              Assert::IsTrue(mgr->Shutdown() == S_OK);
120          }
121  
122          TEST_METHOD (AddItemTest)
123          {
124              CComPtr<IPowerRenameManager> mgr;
125              Assert::IsTrue(CPowerRenameManager::s_CreateInstance(&mgr) == S_OK);
126              CComPtr<IPowerRenameItem> item;
127              CMockPowerRenameItem::CreateInstance(L"foo", L"foo", 0, false, SYSTEMTIME{ 0 }, &item);
128              mgr->AddItem(item);
129              Assert::IsTrue(mgr->Shutdown() == S_OK);
130          }
131  
132          TEST_METHOD (VerifyRenameManagerEvents)
133          {
134              CComPtr<IPowerRenameManager> mgr;
135              Assert::IsTrue(CPowerRenameManager::s_CreateInstance(&mgr) == S_OK);
136              CMockPowerRenameManagerEvents* mockMgrEvents = new CMockPowerRenameManagerEvents();
137              CComPtr<IPowerRenameManagerEvents> mgrEvents;
138              Assert::IsTrue(mockMgrEvents->QueryInterface(IID_PPV_ARGS(&mgrEvents)) == S_OK);
139              DWORD cookie = 0;
140              Assert::IsTrue(mgr->Advise(mgrEvents, &cookie) == S_OK);
141              CComPtr<IPowerRenameItem> item;
142              CMockPowerRenameItem::CreateInstance(L"foo", L"foo", 0, false, SYSTEMTIME{ 0 }, &item);
143              int itemId = 0;
144              Assert::IsTrue(item->GetId(&itemId) == S_OK);
145              mgr->AddItem(item);
146  
147              Assert::IsTrue(mgr->Shutdown() == S_OK);
148  
149              mockMgrEvents->Release();
150          }
151  
152          TEST_METHOD (VerifySingleRename)
153          {
154              // Create a single item and verify rename works as expected
155              rename_pairs renamePairs[] = {
156                  { L"foo.txt", L"bar.txt", true, true }
157              };
158  
159              RenameHelper(renamePairs, ARRAYSIZE(renamePairs), L"foo", L"bar", SYSTEMTIME{ 2020, 7, 3, 22, 15, 6, 42, 453 }, DEFAULT_FLAGS);
160          }
161  
162          TEST_METHOD (VerifyMultiRename)
163          {
164              // Create a single item and verify rename works as expected
165              rename_pairs renamePairs[] = {
166                  { L"foo1.txt", L"bar1.txt", true, true, 0 },
167                  { L"foo2.txt", L"bar2.txt", true, true, 0 },
168                  { L"foo3.txt", L"bar3.txt", true, true, 0 },
169                  { L"foo4.txt", L"bar4.txt", true, true, 0 },
170                  { L"foo5.txt", L"bar5.txt", true, true, 0 },
171                  { L"baa.txt", L"baa_norename.txt", true, false, 0 }
172              };
173  
174              RenameHelper(renamePairs, ARRAYSIZE(renamePairs), L"foo", L"bar", SYSTEMTIME{ 2020, 7, 3, 22, 15, 6, 42, 453 }, DEFAULT_FLAGS);
175          }
176  
177          TEST_METHOD (VerifyFilesOnlyRename)
178          {
179              // Verify only files are renamed when folders match too
180              rename_pairs renamePairs[] = {
181                  { L"foo.txt", L"bar.txt", true, true, 0 },
182                  { L"foo", L"foo_norename", false, false, 0 }
183              };
184  
185              RenameHelper(renamePairs, ARRAYSIZE(renamePairs), L"foo", L"bar", SYSTEMTIME{ 2020, 7, 3, 22, 15, 6, 42, 453 }, DEFAULT_FLAGS | ExcludeFolders);
186          }
187  
188          TEST_METHOD (VerifyFoldersOnlyRename)
189          {
190              // Verify only folders are renamed when files match too
191              rename_pairs renamePairs[] = {
192                  { L"foo.txt", L"foo_norename.txt", true, false, 0 },
193                  { L"foo", L"bar", false, true, 0 }
194              };
195  
196              RenameHelper(renamePairs, ARRAYSIZE(renamePairs), L"foo", L"bar", SYSTEMTIME{ 2020, 7, 3, 22, 15, 6, 42, 453 }, DEFAULT_FLAGS | ExcludeFiles);
197          }
198  
199          TEST_METHOD (VerifyFileNameOnlyRename)
200          {
201              // Verify only file name is renamed, not extension
202              rename_pairs renamePairs[] = {
203                  { L"foo.foo", L"bar.foo", true, true, 0 },
204                  { L"test.foo", L"test.foo_norename", true, false, 0 }
205              };
206  
207              RenameHelper(renamePairs, ARRAYSIZE(renamePairs), L"foo", L"bar", SYSTEMTIME{ 2020, 7, 3, 22, 15, 6, 42, 453 }, DEFAULT_FLAGS | NameOnly);
208          }
209  
210          TEST_METHOD (VerifyFileExtensionOnlyRename)
211          {
212              // Verify only file extension is renamed, not name
213              rename_pairs renamePairs[] = {
214                  { L"foo.foo", L"foo.bar", true, true, 0 },
215                  { L"test.foo", L"test.bar", true, true, 0 }
216              };
217  
218              RenameHelper(renamePairs, ARRAYSIZE(renamePairs), L"foo", L"bar", SYSTEMTIME{ 2020, 7, 3, 22, 15, 6, 42, 453 }, DEFAULT_FLAGS | ExtensionOnly);
219          }
220  
221          TEST_METHOD (VerifySubFoldersRename)
222          {
223              // Verify subfolders do not get renamed
224              rename_pairs renamePairs[] = {
225                  { L"foo1", L"bar1", false, true, 0 },
226                  { L"foo2", L"foo2_norename", false, false, 1 }
227              };
228  
229              RenameHelper(renamePairs, ARRAYSIZE(renamePairs), L"foo", L"bar", SYSTEMTIME{ 2020, 7, 3, 22, 15, 6, 42, 453 }, DEFAULT_FLAGS | ExcludeSubfolders);
230          }
231  
232          TEST_METHOD (VerifyUppercaseTransform)
233          {
234              rename_pairs renamePairs[] = {
235                  { L"foo", L"BAR", true, true, 0 },
236                  { L"foo.test", L"BAR.TEST", true, true, 0 },
237                  { L"TEST", L"TEST_norename", true, false, 0 }
238              };
239  
240              RenameHelper(renamePairs, ARRAYSIZE(renamePairs), L"foo", L"bar", SYSTEMTIME{ 2020, 7, 3, 22, 15, 6, 42, 453 }, DEFAULT_FLAGS | Uppercase);
241          }
242  
243          TEST_METHOD (VerifyLowercaseTransform)
244          {
245              rename_pairs renamePairs[] = {
246                  { L"Foo", L"bar", false, true, 0 },
247                  { L"Foo.teST", L"bar.test", false, true, 0 },
248                  { L"test", L"test_norename", false, false, 0 }
249              };
250  
251              RenameHelper(renamePairs, ARRAYSIZE(renamePairs), L"foo", L"bar", SYSTEMTIME{ 2020, 7, 3, 22, 15, 6, 42, 453 }, DEFAULT_FLAGS | Lowercase);
252          }
253  
254          TEST_METHOD (VerifyTitlecaseTransform)
255          {
256              rename_pairs renamePairs[] = {
257                  { L"foo And The To", L"Bar and the To", false, true, 0 },
258                  { L"foo And The To.txt", L"Bar and the To.txt", true, true, 0 },
259                  { L"Test", L"Test_norename", false, false, 0 }
260              };
261  
262              RenameHelper(renamePairs, ARRAYSIZE(renamePairs), L"foo", L"bar", SYSTEMTIME{ 2020, 7, 3, 22, 15, 6, 42, 453 }, DEFAULT_FLAGS | Titlecase);
263          }      
264  
265          TEST_METHOD (VerifyTitlecaseWithApostropheTransform)
266          {
267              rename_pairs renamePairs[] = {
268                  { L"the foo i'll and i've you're dogs' the i'd it's i'm don't to y'all", L"The Bar I'll and I've You're Dogs' the I'd It's I'm Don't to Y'all", false, true, 0 },
269                  { L"'the 'foo' 'i'll' and i've you're dogs' the 'i'd' it's i'm don't to y'all.txt", L"'The 'Bar' 'I'll' and I've You're Dogs' the 'I'd' It's I'm Don't to Y'all.txt", true, true, 0 },
270                  { L"Test", L"Test_norename", false, false, 0 }
271              };
272  
273              RenameHelper(renamePairs, ARRAYSIZE(renamePairs), L"foo", L"bar", SYSTEMTIME{ 2020, 7, 3, 22, 15, 6, 42, 453 }, DEFAULT_FLAGS | Titlecase);
274          }
275  
276          TEST_METHOD (VerifyCapitalizedTransform)
277          {
278              rename_pairs renamePairs[] = {
279                  { L"foo and the to", L"Bar And The To", false, true, 0 },
280                  { L"Test", L"Test_norename", false, false, 0 }
281              };
282  
283              RenameHelper(renamePairs, ARRAYSIZE(renamePairs), L"foo", L"bar", SYSTEMTIME{ 2020, 7, 3, 22, 15, 6, 42, 453 }, DEFAULT_FLAGS | Capitalized);
284          }
285  
286          TEST_METHOD (VerifyCapitalizedWithApostropheTransform)
287          {
288              rename_pairs renamePairs[] = {
289                  { L"foo i'll and i've you're dogs' the i'd it's i'm don't to y'all", L"Bar I'll And I've You're Dogs' The I'd It's I'm Don't To Y'all", false, true, 0 },
290                  { L"'foo i'll 'and' i've you're dogs' the i'd it's i'm don't to y'all.txt", L"'Bar I'll 'And' I've You're Dogs' The I'd It's I'm Don't To Y'all.txt", true, true, 0 },
291                  { L"Test", L"Test_norename", false, false, 0 }
292              };
293  
294              RenameHelper(renamePairs, ARRAYSIZE(renamePairs), L"foo", L"bar", SYSTEMTIME{ 2020, 7, 3, 22, 15, 6, 42, 453 }, DEFAULT_FLAGS | Capitalized);
295          }
296  
297          TEST_METHOD (VerifyNameOnlyTransform)
298          {
299              rename_pairs renamePairs[] = {
300                  { L"foo.foo", L"BAR.foo", true, true, 0 },
301                  { L"foo.txt", L"BAR.TXT", false, true, 0 },
302                  { L"TEST", L"TEST_norename", false, false, 1 }
303              };
304  
305              RenameHelper(renamePairs, ARRAYSIZE(renamePairs), L"foo", L"bar", SYSTEMTIME{ 2020, 7, 3, 22, 15, 6, 42, 453 }, DEFAULT_FLAGS | Uppercase | NameOnly);
306          }
307  
308          TEST_METHOD (VerifyExtensionOnlyTransform)
309          {
310              rename_pairs renamePairs[] = {
311                  { L"foo.FOO", L"foo.bar", true, true, 0 },
312                  { L"bar.FOO", L"bar.FOO_norename", false, false, 0 },
313                  { L"foo.bar", L"foo.bar_norename", true, false, 0 }
314              };
315  
316              RenameHelper(renamePairs, ARRAYSIZE(renamePairs), L"foo", L"bar", SYSTEMTIME{ 2020, 7, 3, 22, 15, 6, 42, 453 }, DEFAULT_FLAGS | Lowercase | ExtensionOnly);
317          }
318  
319          TEST_METHOD (VerifyFileAttributesNoPadding)
320          {
321              rename_pairs renamePairs[] = {
322                  { L"foo", L"bar20-7-22-15-6-42-4", true, true, 0 },
323              };
324  
325              RenameHelper(renamePairs, ARRAYSIZE(renamePairs), L"foo", L"bar$YY-$M-$D-$h-$m-$s-$f", SYSTEMTIME{ 2020, 7, 3, 22, 15, 6, 42, 453 }, DEFAULT_FLAGS);
326          }
327  
328          TEST_METHOD (VerifyFileAttributesPadding)
329          {
330              rename_pairs renamePairs[] = {
331                  { L"foo", L"bar2020-07-22-15-06-42-453", true, true, 0 },
332              };
333  
334              RenameHelper(renamePairs, ARRAYSIZE(renamePairs), L"foo", L"bar$YYYY-$MM-$DD-$hh-$mm-$ss-$fff", SYSTEMTIME{ 2020, 7, 3, 22, 15, 6, 42, 453 }, DEFAULT_FLAGS);
335          }
336  
337          TEST_METHOD (VerifyFileAttributesMonthAndDayNames)
338          {
339              std::locale::global(std::locale(""));
340              SYSTEMTIME fileTime = { 2020, 1, 3, 1, 15, 6, 42, 453 };
341              wchar_t localeName[LOCALE_NAME_MAX_LENGTH];
342              wchar_t result[MAX_PATH] = L"bar";
343              wchar_t formattedDate[MAX_PATH];
344              if (GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH) == 0)
345                  StringCchCopy(localeName, LOCALE_NAME_MAX_LENGTH, L"en_US");
346  
347              GetDateFormatEx(localeName, NULL, &fileTime, L"MMM", formattedDate, MAX_PATH, NULL);
348              formattedDate[0] = towupper(formattedDate[0]);
349              StringCchPrintf(result, MAX_PATH, TEXT("%s%s"), result, formattedDate);
350  
351              GetDateFormatEx(localeName, NULL, &fileTime, L"MMMM", formattedDate, MAX_PATH, NULL);
352              formattedDate[0] = towupper(formattedDate[0]);
353              StringCchPrintf(result, MAX_PATH, TEXT("%s-%s"), result, formattedDate);
354  
355              GetDateFormatEx(localeName, NULL, &fileTime, L"ddd", formattedDate, MAX_PATH, NULL);
356              formattedDate[0] = towupper(formattedDate[0]);
357              StringCchPrintf(result, MAX_PATH, TEXT("%s-%s"), result, formattedDate);
358  
359              GetDateFormatEx(localeName, NULL, &fileTime, L"dddd", formattedDate, MAX_PATH, NULL);
360              formattedDate[0] = towupper(formattedDate[0]);
361              StringCchPrintf(result, MAX_PATH, TEXT("%s-%s"), result, formattedDate);
362  
363              rename_pairs renamePairs[] = {
364                  { L"foo", result, true, true, 0 },
365              };
366  
367              RenameHelper(renamePairs, ARRAYSIZE(renamePairs), L"foo", L"bar$MMM-$MMMM-$DDD-$DDDD", SYSTEMTIME{ 2020, 1, 3, 1, 15, 6, 42, 453 }, DEFAULT_FLAGS);
368          }
369      };
370  }