1 /* 2 * PROJECT: ReactOS api tests 3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) 4 * PURPOSE: Test for IACLCustomMRU objects 5 * COPYRIGHT: Copyright 2017 Mark Jansen (mark.jansen@reactos.org) 6 */ 7 8 #define _UNICODE 9 #define UNICODE 10 #include <apitest.h> 11 #include <shlobj.h> 12 #include <atlbase.h> 13 #include <atlstr.h> 14 #include <atlcom.h> 15 #include <atlwin.h> 16 17 // Yes, gcc at it again, let's validate everything found inside unused templates! 18 ULONG DbgPrint(PCH Format,...); 19 20 #include <shellutils.h> 21 #include <shlwapi.h> 22 #include <strsafe.h> 23 #include <initguid.h> 24 25 #define ok_hex_(file, line, key, expression, result) \ 26 do { \ 27 int _value = (expression); \ 28 ok_(file, line)(_value == (result), "Wrong value for '%s', expected: " #result " (0x%x), got: 0x%x for %c\n", \ 29 #expression, (int)(result), _value, (char)key); \ 30 } while (0) 31 32 33 34 struct CCoInit 35 { 36 CCoInit() { hres = CoInitialize(NULL); } 37 ~CCoInit() { if (SUCCEEDED(hres)) { CoUninitialize(); } } 38 HRESULT hres; 39 }; 40 41 42 DEFINE_GUID(IID_IACLCustomMRU, 0xf729fc5e, 0x8769, 0x4f3e, 0xbd, 0xb2, 0xd7, 0xb5, 0x0f, 0xd2, 0x27, 0x5b); 43 static const WCHAR szTestPath[] = L"TESTPATH_BROWSEUI_APITEST"; 44 45 #undef INTERFACE 46 #define INTERFACE IACLCustomMRU 47 48 /* based on https://msdn.microsoft.com/en-gb/library/windows/desktop/bb776380(v=vs.85).aspx */ 49 DECLARE_INTERFACE_IID_(IACLCustomMRU, IUnknown, "F729FC5E-8769-4F3E-BDB2-D7B50FD2275B") 50 { 51 // *** IUnknown methods *** 52 STDMETHOD(QueryInterface) (THIS_ REFIID riid, void **ppv) PURE; 53 STDMETHOD_(ULONG, AddRef) (THIS)PURE; 54 STDMETHOD_(ULONG, Release) (THIS)PURE; 55 56 // *** IACLCustomMRU methods *** 57 STDMETHOD(Initialize) (THIS_ LPCWSTR pwszMRURegKey, DWORD dwMax) PURE; 58 STDMETHOD(AddMRUString) (THIS_ LPCWSTR pwszEntry) PURE; 59 }; 60 61 62 static void Cleanup_Testdata() 63 { 64 CRegKey tmp; 65 if (!tmp.Open(HKEY_CURRENT_USER, NULL, KEY_READ | KEY_WRITE)) 66 tmp.DeleteSubKey(szTestPath); 67 } 68 69 #define verify_mru(mru, ...) verify_mru_(__FILE__, __LINE__, mru, __VA_ARGS__, NULL) 70 static void verify_mru_(const char* file, int line, IACLCustomMRU* mru, PCWSTR MRUString, ...) 71 { 72 73 CRegKey key; 74 key.Open(HKEY_CURRENT_USER, szTestPath); 75 76 va_list args; 77 va_start(args, MRUString); 78 PCWSTR Entry; 79 WCHAR Key = L'a'; 80 while ((Entry = va_arg(args, PCWSTR))) 81 { 82 WCHAR Value[MAX_PATH]; 83 ULONG nChars = _countof(Value); 84 CStringW tmp; 85 tmp += Key; 86 LSTATUS Status = key.QueryStringValue(tmp, Value, &nChars); 87 ok_hex_(file, line, Key, Status, ERROR_SUCCESS); 88 if (Status == ERROR_SUCCESS) 89 { 90 ok_(file, line)(!wcscmp(Value, Entry), "Expected value %c to be %S, was %S\n", (char)Key, Entry, Value); 91 } 92 Key++; 93 } 94 va_end(args); 95 96 if (Key != L'a') 97 { 98 WCHAR Value[MAX_PATH]; 99 ULONG nChars = _countof(Value); 100 LSTATUS Status = key.QueryStringValue(L"MRUList", Value, &nChars); 101 ok_hex_(file, line, Key, Status, ERROR_SUCCESS); 102 if (Status == ERROR_SUCCESS) 103 { 104 ok_(file, line)(!wcscmp(Value, MRUString), "Expected MRUList to be %S, was %S\n", MRUString, Value); 105 } 106 } 107 } 108 109 110 static void 111 test_IACLCustomMRU_Basics() 112 { 113 CComPtr<IACLCustomMRU> CustomMRU; 114 HRESULT hr = CoCreateInstance(CLSID_ACLCustomMRU, NULL, CLSCTX_ALL, IID_PPV_ARG(IACLCustomMRU, &CustomMRU)); 115 ok_hex(hr, S_OK); 116 if (!SUCCEEDED(hr)) 117 return; 118 119 Cleanup_Testdata(); 120 121 /* Initialize with a NULL name will cause an AV */ 122 //hr = CustomMRU->Initialize(NULL, 0); 123 124 hr = CustomMRU->Initialize(szTestPath, 0); 125 ok_hex(hr, S_OK); 126 /* Adding an entry with a dwMax of 0 will cause an AV */ 127 128 /* Calling it again will resize */ 129 hr = CustomMRU->Initialize(szTestPath, 3); 130 ok_hex(hr, S_OK); 131 verify_mru(CustomMRU, L""); 132 133 hr = CustomMRU->AddMRUString(L"FIRST_ENTRY"); 134 ok_hex(hr, S_OK); 135 verify_mru(CustomMRU, L"a", L"FIRST_ENTRY"); 136 137 hr = CustomMRU->AddMRUString(L"SECOND_ENTRY"); 138 ok_hex(hr, S_OK); 139 verify_mru(CustomMRU, L"ba", L"FIRST_ENTRY", L"SECOND_ENTRY"); 140 141 hr = CustomMRU->AddMRUString(L"THIRD_ENTRY"); 142 ok_hex(hr, S_OK); 143 verify_mru(CustomMRU, L"cba", L"FIRST_ENTRY", L"SECOND_ENTRY", L"THIRD_ENTRY"); 144 145 /* First entry is replaced */ 146 hr = CustomMRU->AddMRUString(L"FOURTH_ENTRY"); 147 ok_hex(hr, S_OK); 148 verify_mru(CustomMRU, L"acb", L"FOURTH_ENTRY", L"SECOND_ENTRY", L"THIRD_ENTRY"); 149 150 /* Second entry is replaced */ 151 hr = CustomMRU->AddMRUString(L"FIFTH_ENTRY"); 152 ok_hex(hr, S_OK); 153 verify_mru(CustomMRU, L"bac", L"FOURTH_ENTRY", L"FIFTH_ENTRY", L"THIRD_ENTRY"); 154 } 155 156 157 static void FillDefault(IACLCustomMRU* CustomMRU) 158 { 159 Cleanup_Testdata(); 160 HRESULT hr = CustomMRU->Initialize(szTestPath, 3); 161 ok_hex(hr, S_OK); 162 hr = CustomMRU->AddMRUString(L"FIRST_ENTRY"); 163 ok_hex(hr, S_OK); 164 hr = CustomMRU->AddMRUString(L"SECOND_ENTRY"); 165 ok_hex(hr, S_OK); 166 hr = CustomMRU->AddMRUString(L"THIRD_ENTRY"); 167 ok_hex(hr, S_OK); 168 } 169 170 static void 171 test_IACLCustomMRU_UpdateOrder() 172 { 173 CComPtr<IACLCustomMRU> CustomMRU; 174 HRESULT hr = CoCreateInstance(CLSID_ACLCustomMRU, NULL, CLSCTX_ALL, IID_PPV_ARG(IACLCustomMRU, &CustomMRU)); 175 ok_hex(hr, S_OK); 176 if (!SUCCEEDED(hr)) 177 return; 178 179 Cleanup_Testdata(); 180 FillDefault(CustomMRU); 181 verify_mru(CustomMRU, L"cba", L"FIRST_ENTRY", L"SECOND_ENTRY", L"THIRD_ENTRY"); 182 183 /* Add the first entry again */ 184 hr = CustomMRU->AddMRUString(L"FIRST_ENTRY"); 185 ok_hex(hr, S_OK); 186 /* No change */ 187 verify_mru(CustomMRU, L"cba", L"FIRST_ENTRY", L"SECOND_ENTRY", L"THIRD_ENTRY"); 188 189 CustomMRU.Release(); 190 /* Now the order is updated */ 191 verify_mru(NULL, L"acb", L"FIRST_ENTRY", L"SECOND_ENTRY", L"THIRD_ENTRY"); 192 193 194 hr = CoCreateInstance(CLSID_ACLCustomMRU, NULL, CLSCTX_ALL, IID_PPV_ARG(IACLCustomMRU, &CustomMRU)); 195 ok_hex(hr, S_OK); 196 if (!SUCCEEDED(hr)) 197 return; 198 199 Cleanup_Testdata(); 200 FillDefault(CustomMRU); 201 verify_mru(CustomMRU, L"cba", L"FIRST_ENTRY", L"SECOND_ENTRY", L"THIRD_ENTRY"); 202 203 204 /* Add the first entry again */ 205 hr = CustomMRU->AddMRUString(L"FIRST_ENTRY"); 206 ok_hex(hr, S_OK); 207 /* No change */ 208 verify_mru(CustomMRU, L"cba", L"FIRST_ENTRY", L"SECOND_ENTRY", L"THIRD_ENTRY"); 209 210 hr = CustomMRU->AddMRUString(L"SOMETHING_ELSE"); 211 ok_hex(hr, S_OK); 212 /* Now all changes are persisted */ 213 verify_mru(CustomMRU, L"bac", L"FIRST_ENTRY", L"SOMETHING_ELSE", L"THIRD_ENTRY"); 214 } 215 216 static void 217 test_IACLCustomMRU_ExtraChars() 218 { 219 CComPtr<IACLCustomMRU> CustomMRU; 220 HRESULT hr = CoCreateInstance(CLSID_ACLCustomMRU, NULL, CLSCTX_ALL, IID_PPV_ARG(IACLCustomMRU, &CustomMRU)); 221 ok_hex(hr, S_OK); 222 if (!SUCCEEDED(hr)) 223 return; 224 225 Cleanup_Testdata(); 226 227 /* Still returnes success */ 228 hr = CustomMRU->Initialize(szTestPath, 30); 229 ok_hex(hr, S_OK); 230 231 for (int n = 0; n < 30; ++n) 232 { 233 CStringW tmp; 234 tmp.Format(L"%d", n); 235 236 hr = CustomMRU->AddMRUString(tmp); 237 ok_hex(hr, S_OK); 238 } 239 /* But is starting to wrap around */ 240 verify_mru(CustomMRU, L"a}|{zyxwvutsrqponmlkjihgfedcb", L"29", 241 L"1", L"2", L"3", L"4", L"5", L"6", L"7", L"8", L"9", 242 L"10", L"11", L"12", L"13", L"14", L"15", L"16", L"17", L"18", L"19", 243 L"20", L"21", L"22", L"23", L"24", L"25", L"26", L"27", L"28"); 244 245 Cleanup_Testdata(); 246 } 247 248 static void 249 test_IACLCustomMRU_Continue() 250 { 251 CComPtr<IACLCustomMRU> CustomMRU; 252 HRESULT hr = CoCreateInstance(CLSID_ACLCustomMRU, NULL, CLSCTX_ALL, IID_PPV_ARG(IACLCustomMRU, &CustomMRU)); 253 ok_hex(hr, S_OK); 254 if (!SUCCEEDED(hr)) 255 return; 256 257 Cleanup_Testdata(); 258 FillDefault(CustomMRU); 259 verify_mru(CustomMRU, L"cba", L"FIRST_ENTRY", L"SECOND_ENTRY", L"THIRD_ENTRY"); 260 261 CustomMRU.Release(); 262 263 hr = CoCreateInstance(CLSID_ACLCustomMRU, NULL, CLSCTX_ALL, IID_PPV_ARG(IACLCustomMRU, &CustomMRU)); 264 ok_hex(hr, S_OK); 265 if (!SUCCEEDED(hr)) 266 return; 267 268 hr = CustomMRU->Initialize(szTestPath, 3); 269 ok_hex(hr, S_OK); 270 271 /* First entry is replaced */ 272 hr = CustomMRU->AddMRUString(L"FOURTH_ENTRY"); 273 ok_hex(hr, S_OK); 274 verify_mru(CustomMRU, L"acb", L"FOURTH_ENTRY", L"SECOND_ENTRY", L"THIRD_ENTRY"); 275 276 CustomMRU.Release(); 277 278 hr = CoCreateInstance(CLSID_ACLCustomMRU, NULL, CLSCTX_ALL, IID_PPV_ARG(IACLCustomMRU, &CustomMRU)); 279 ok_hex(hr, S_OK); 280 if (!SUCCEEDED(hr)) 281 return; 282 283 hr = CustomMRU->Initialize(szTestPath, 3); 284 ok_hex(hr, S_OK); 285 286 /* Second entry is replaced */ 287 hr = CustomMRU->AddMRUString(L"FIFTH_ENTRY"); 288 ok_hex(hr, S_OK); 289 verify_mru(CustomMRU, L"bac", L"FOURTH_ENTRY", L"FIFTH_ENTRY", L"THIRD_ENTRY"); 290 291 CustomMRU.Release(); 292 293 hr = CoCreateInstance(CLSID_ACLCustomMRU, NULL, CLSCTX_ALL, IID_PPV_ARG(IACLCustomMRU, &CustomMRU)); 294 ok_hex(hr, S_OK); 295 if (!SUCCEEDED(hr)) 296 return; 297 298 299 /* Save some garbage */ 300 CRegKey key; 301 key.Open(HKEY_CURRENT_USER, szTestPath); 302 key.SetStringValue(L"MRUList", L"b**"); 303 key.Close(); 304 305 hr = CustomMRU->Initialize(szTestPath, 3); 306 ok_hex(hr, S_OK); 307 308 CustomMRU.Release(); 309 310 /* Not cleaned up */ 311 verify_mru(CustomMRU, L"b**", L"FOURTH_ENTRY", L"FIFTH_ENTRY", L"THIRD_ENTRY"); 312 313 hr = CoCreateInstance(CLSID_ACLCustomMRU, NULL, CLSCTX_ALL, IID_PPV_ARG(IACLCustomMRU, &CustomMRU)); 314 ok_hex(hr, S_OK); 315 if (!SUCCEEDED(hr)) 316 return; 317 318 hr = CustomMRU->Initialize(szTestPath, 3); 319 ok_hex(hr, S_OK); 320 321 /* Now it's just cleaned up */ 322 hr = CustomMRU->AddMRUString(L"SIXTH_ENTRY"); 323 ok_hex(hr, S_OK); 324 verify_mru(CustomMRU, L"ab", L"SIXTH_ENTRY"); 325 326 CustomMRU.Release(); 327 328 hr = CoCreateInstance(CLSID_ACLCustomMRU, NULL, CLSCTX_ALL, IID_PPV_ARG(IACLCustomMRU, &CustomMRU)); 329 ok_hex(hr, S_OK); 330 if (!SUCCEEDED(hr)) 331 return; 332 333 Cleanup_Testdata(); 334 FillDefault(CustomMRU); 335 verify_mru(CustomMRU, L"cba", L"FIRST_ENTRY", L"SECOND_ENTRY", L"THIRD_ENTRY"); 336 337 CustomMRU.Release(); 338 339 hr = CoCreateInstance(CLSID_ACLCustomMRU, NULL, CLSCTX_ALL, IID_PPV_ARG(IACLCustomMRU, &CustomMRU)); 340 ok_hex(hr, S_OK); 341 if (!SUCCEEDED(hr)) 342 return; 343 344 key.Open(HKEY_CURRENT_USER, szTestPath); 345 key.SetStringValue(L"MRUList", L"baccccc"); 346 key.Close(); 347 348 hr = CustomMRU->Initialize(szTestPath, 3); 349 ok_hex(hr, S_OK); 350 CustomMRU.Release(); 351 352 verify_mru(CustomMRU, L"baccccc", L"FIRST_ENTRY", L"SECOND_ENTRY", L"THIRD_ENTRY"); 353 354 hr = CoCreateInstance(CLSID_ACLCustomMRU, NULL, CLSCTX_ALL, IID_PPV_ARG(IACLCustomMRU, &CustomMRU)); 355 ok_hex(hr, S_OK); 356 if (!SUCCEEDED(hr)) 357 return; 358 359 hr = CustomMRU->Initialize(szTestPath, 3); 360 ok_hex(hr, S_OK); 361 362 hr = CustomMRU->AddMRUString(L"FOURTH_ENTRY"); 363 ok_hex(hr, S_OK); 364 verify_mru(CustomMRU, L"a", L"FOURTH_ENTRY", L"SECOND_ENTRY", L"THIRD_ENTRY"); 365 366 CustomMRU.Release(); 367 Cleanup_Testdata(); 368 369 hr = CoCreateInstance(CLSID_ACLCustomMRU, NULL, CLSCTX_ALL, IID_PPV_ARG(IACLCustomMRU, &CustomMRU)); 370 ok_hex(hr, S_OK); 371 if (!SUCCEEDED(hr)) 372 return; 373 374 hr = CustomMRU->Initialize(szTestPath, 3); 375 ok_hex(hr, S_OK); 376 if (!SUCCEEDED(hr)) 377 return; 378 379 hr = CustomMRU->AddMRUString(L"FIRST_ENTRY"); 380 ok_hex(hr, S_OK); 381 verify_mru(CustomMRU, L"a", L"FIRST_ENTRY"); 382 383 CustomMRU.Release(); 384 385 key.Open(HKEY_CURRENT_USER, szTestPath); 386 key.SetStringValue(L"MRUList", L"aaa"); 387 key.Close(); 388 389 hr = CoCreateInstance(CLSID_ACLCustomMRU, NULL, CLSCTX_ALL, IID_PPV_ARG(IACLCustomMRU, &CustomMRU)); 390 ok_hex(hr, S_OK); 391 if (!SUCCEEDED(hr)) 392 return; 393 394 hr = CustomMRU->Initialize(szTestPath, 3); 395 ok_hex(hr, S_OK); 396 if (!SUCCEEDED(hr)) 397 return; 398 399 hr = CustomMRU->AddMRUString(L"SECOND_ENTRY"); 400 ok_hex(hr, S_OK); 401 verify_mru(CustomMRU, L"ba", L"FIRST_ENTRY", L"SECOND_ENTRY"); 402 } 403 404 START_TEST(IACLCustomMRU) 405 { 406 CCoInit init; 407 ok_hex(init.hres, S_OK); 408 if (!SUCCEEDED(init.hres)) 409 return; 410 411 test_IACLCustomMRU_Basics(); 412 test_IACLCustomMRU_UpdateOrder(); 413 test_IACLCustomMRU_ExtraChars(); 414 test_IACLCustomMRU_Continue(); 415 416 Cleanup_Testdata(); 417 } 418