1 /* 2 * PROJECT: ReactOS API tests 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Tests for Char* functions 5 * COPYRIGHT: Copyright 2022 Stanislav Motylkov <x86corez@gmail.com> 6 */ 7 8 #include "precomp.h" 9 10 #include <winnls.h> 11 #include <ndk/rtlfuncs.h> 12 #include <pseh/pseh2.h> 13 #include <strsafe.h> 14 #include <versionhelpers.h> 15 16 #define INVALID_PTR_OFF(x) ((PVOID)(ULONG_PTR)(0xdeadbeefdeadbeefULL + x)) 17 #define INVALID_PTR INVALID_PTR_OFF(0) 18 19 /* Default code page to be tested */ 20 #define TEST_ACP 1252 21 22 typedef enum 23 { 24 testLen, 25 testOffs, 26 testBoth, 27 } TEST_TYPE; 28 29 /* Dynamic allocation tests */ 30 typedef struct 31 { 32 TEST_TYPE testType; 33 LPWSTR lpszStart; /* Specified string for szStart */ 34 LPWSTR lpszCurrent; /* Specified string for szCurrent (only when testType == testBoth) */ 35 INT iOffset; /* Specified offset to test (only when testType == testOffs) */ 36 INT iResOffset; /* Expected offset when szCurrent >= szStart */ 37 INT iResOffsetNeg; /* Expected offset when szCurrent < szStart */ 38 BOOL bWithinStart; /* TRUE for pointer expected to be within szStart, FALSE for within szCurrent */ 39 BOOL bWideOnly; /* Perform test only for Unicode case */ 40 } TESTS_CHARPREV; 41 42 TESTS_CHARPREV TestCharPrev[] = 43 { 44 {testLen, L"C:\\ReactOS", NULL, 0, 9, 9, TRUE, FALSE}, 45 {testOffs, L"abcdefghijk", NULL, 11, 10, 10, TRUE, FALSE}, 46 {testOffs, L"test a´^~¯", NULL, 10, 9, 9, TRUE, FALSE}, 47 {testOffs, L"test å", NULL, 6, 5, 5, TRUE, FALSE}, 48 {testBoth, L"C:\\ReactOS", L"", 0, -1, 0, FALSE, FALSE}, 49 {testBoth, L"C:\\ReactOS\\", L"C:\\ReactOS", 0, -1, 0, FALSE, FALSE}, 50 {testBoth, L"C:\\ReactOS\\", L"ReactOS", 0, -1, 0, FALSE, FALSE}, 51 }; 52 53 TESTS_CHARPREV TestCharPrev_XP[] = 54 { 55 /* XP/2003 treat diacritics as normal characters */ 56 {testOffs, L"test a\x030a", NULL, 7, 6, 6, TRUE, TRUE}, 57 {testOffs, L"test a\x0301\x0302\x0303\x0304", NULL, 10, 9, 9, TRUE, TRUE}, 58 {testOffs, L"test a\x0301\x0302\x0303\x0304", NULL, 9, 8, 8, TRUE, TRUE}, 59 {testOffs, L"test a\x0301\x0302\x0303\x0304", NULL, 8, 7, 7, TRUE, TRUE}, 60 {testOffs, L"test a\x0301\x0302\x0303\x0304", NULL, 7, 6, 6, TRUE, TRUE}, 61 }; 62 63 TESTS_CHARPREV TestCharPrev_Vista[] = 64 { 65 /* Vista+ does respect diacritics and skip them */ 66 {testOffs, L"test a\x030a", NULL, 7, 5, 5, TRUE, TRUE}, 67 {testOffs, L"test a\x0301\x0302\x0303\x0304", NULL, 10, 5, 5, TRUE, TRUE}, 68 {testOffs, L"test a\x0301\x0302\x0303\x0304", NULL, 9, 5, 5, TRUE, TRUE}, 69 {testOffs, L"test a\x0301\x0302\x0303\x0304", NULL, 8, 5, 5, TRUE, TRUE}, 70 {testOffs, L"test a\x0301\x0302\x0303\x0304", NULL, 7, 5, 5, TRUE, TRUE}, 71 }; 72 73 /* Static tests */ 74 static const WCHAR wszReactOS[] = L"C:\\ReactOS"; 75 static const CHAR szReactOS[] = "C:\\ReactOS"; 76 static const WCHAR wszSpecial[] = L"test\0\0\0\0\0\0aa\t\t\t\r\n\r\n"; 77 static const CHAR szSpecial[] = "test\0\0\0\0\0\0aa\t\t\t\r\n\r\n"; 78 static const WCHAR wszMagic1[] = L"test a\x030a"; 79 static const WCHAR wszMagic2[] = L"test a\x0301\x0302\x0303\x0304"; 80 81 static const CHAR szUTF8Cyril[] = "test \xD1\x82\xD0\xB5\xD1\x81\xD1\x82"; /* UTF8(L"test тест") */ 82 static const CHAR szUTF8Greek[] = "test \xCF\x84\xCE\xB5\xCF\x83\xCF\x84"; /* UTF8(L"test τεστ") */ 83 static const CHAR szUTF8Japan[] = "test \xE3\x83\x86\xE3\x82\xB9\xE3\x83\x88"; /* UTF8(L"test テスト") */ 84 static const CHAR szCP932Japan[] = "test \x83\x65\x83\x58\x83\x67"; /* CP932(L"test テスト") */ 85 86 typedef struct 87 { 88 LPCWSTR wszStart; 89 LPCWSTR wszCurrent; 90 LPCWSTR wszResult; 91 LPCSTR szStart; 92 LPCSTR szCurrent; 93 LPCSTR szResult; 94 } ST_TESTS_CHARPREV; 95 96 ST_TESTS_CHARPREV TestStaticCharPrev[] = 97 { 98 {wszReactOS, wszReactOS, wszReactOS, 99 szReactOS, szReactOS, szReactOS}, 100 {wszReactOS, wszReactOS + 1, wszReactOS, 101 szReactOS, szReactOS + 1, szReactOS}, 102 {wszReactOS, wszReactOS + 2, wszReactOS + 1, 103 szReactOS, szReactOS + 2, szReactOS + 1}, 104 {wszReactOS, wszReactOS + 3, wszReactOS + 2, 105 szReactOS, szReactOS + 3, szReactOS + 2}, 106 {wszReactOS, wszReactOS + 10, wszReactOS + 9, 107 szReactOS, szReactOS + 10, szReactOS + 9}, 108 109 {wszReactOS + 2, wszReactOS, wszReactOS, 110 szReactOS + 2, szReactOS, szReactOS}, 111 {wszReactOS + 2, wszReactOS + 1, wszReactOS + 1, 112 szReactOS + 2, szReactOS + 1, szReactOS + 1}, 113 {wszReactOS + 2, wszReactOS + 2, wszReactOS + 2, 114 szReactOS + 2, szReactOS + 2, szReactOS + 2}, 115 {wszReactOS + 2, wszReactOS + 3, wszReactOS + 2, 116 szReactOS + 2, szReactOS + 3, szReactOS + 2}, 117 {wszReactOS + 2, wszReactOS + 4, wszReactOS + 3, 118 szReactOS + 2, szReactOS + 4, szReactOS + 3}, 119 120 /* Test null-terminators */ 121 {wszSpecial, wszSpecial + 8, wszSpecial + 7, 122 szSpecial, szSpecial + 8, szSpecial + 7}, 123 124 /* Test tabulation */ 125 {wszSpecial, wszSpecial + 13, wszSpecial + 12, 126 szSpecial, szSpecial + 13, szSpecial + 12}, 127 128 /* Test linebreak */ 129 {wszSpecial, wszSpecial + 17, wszSpecial + 16, 130 szSpecial, szSpecial + 17, szSpecial + 16}, 131 {wszSpecial, wszSpecial + 18, wszSpecial + 17, 132 szSpecial, szSpecial + 18, szSpecial + 17}, 133 }; 134 135 ST_TESTS_CHARPREV TestStaticCharPrev_XP[] = 136 { 137 /* XP/2003 treat diacritics as normal characters */ 138 {wszMagic1, wszMagic1 + 7, wszMagic1 + 6, 139 NULL, NULL, NULL}, 140 {wszMagic2, wszMagic2 + 10, wszMagic2 + 9, 141 NULL, NULL, NULL}, 142 {wszMagic2, wszMagic2 + 9, wszMagic2 + 8, 143 NULL, NULL, NULL}, 144 {wszMagic2, wszMagic2 + 8, wszMagic2 + 7, 145 NULL, NULL, NULL}, 146 {wszMagic2, wszMagic2 + 7, wszMagic2 + 6, 147 NULL, NULL, NULL}, 148 }; 149 150 ST_TESTS_CHARPREV TestStaticCharPrev_Vista[] = 151 { 152 /* Vista+ does respect diacritics and skip them */ 153 {wszMagic1, wszMagic1 + 7, wszMagic1 + 5, 154 NULL, NULL, NULL}, 155 {wszMagic2, wszMagic2 + 10, wszMagic2 + 5, 156 NULL, NULL, NULL}, 157 {wszMagic2, wszMagic2 + 9, wszMagic2 + 5, 158 NULL, NULL, NULL}, 159 {wszMagic2, wszMagic2 + 8, wszMagic2 + 5, 160 NULL, NULL, NULL}, 161 {wszMagic2, wszMagic2 + 7, wszMagic2 + 5, 162 NULL, NULL, NULL}, 163 }; 164 165 typedef struct 166 { 167 UINT uCodePage; 168 LPCSTR szStart; 169 LPCSTR szCurrent; 170 LPCSTR szResult; 171 } ST_CODEPAGE_TESTS_CHARPREV; 172 173 ST_CODEPAGE_TESTS_CHARPREV TestStaticCodePageCharPrev[] = 174 { 175 /* UTF-8 characters are not properly counted */ 176 {CP_UTF8, szUTF8Cyril, szUTF8Cyril + 2, szUTF8Cyril + 1}, 177 {CP_UTF8, szUTF8Cyril, szUTF8Cyril + 7, szUTF8Cyril + 6}, 178 {CP_UTF8, szUTF8Cyril, szUTF8Cyril + 9, szUTF8Cyril + 8}, 179 180 {CP_UTF8, szUTF8Greek, szUTF8Greek + 7, szUTF8Greek + 6}, 181 {CP_UTF8, szUTF8Greek, szUTF8Greek + 9, szUTF8Greek + 8}, 182 183 {CP_UTF8, szUTF8Japan, szUTF8Japan + 8, szUTF8Japan + 7}, 184 {CP_UTF8, szUTF8Japan, szUTF8Japan + 11, szUTF8Japan + 10}, 185 186 /* Code Page 932 / Shift-JIS characters are properly counted */ 187 {932, szCP932Japan, szCP932Japan + 2, szCP932Japan + 1}, 188 {932, szCP932Japan, szCP932Japan + 7, szCP932Japan + 5}, 189 {932, szCP932Japan, szCP932Japan + 9, szCP932Japan + 7}, 190 }; 191 192 typedef struct 193 { 194 LPCWSTR wszString; 195 LPCWSTR wszResult; 196 LPCSTR szString; 197 LPCSTR szResult; 198 } ST_TESTS_CHARNEXT; 199 200 ST_TESTS_CHARNEXT TestStaticCharNext[] = 201 { 202 {wszReactOS, wszReactOS + 1, 203 szReactOS, szReactOS + 1}, 204 {wszReactOS + 1, wszReactOS + 2, 205 szReactOS + 1, szReactOS + 2}, 206 {wszReactOS + 2, wszReactOS + 3, 207 szReactOS + 2, szReactOS + 3}, 208 {wszReactOS + 9, wszReactOS + 10, 209 szReactOS + 9, szReactOS + 10}, 210 {wszReactOS + 10, wszReactOS + 10, 211 szReactOS + 10, szReactOS + 10}, 212 213 /* Test null-terminators */ 214 {wszSpecial + 3, wszSpecial + 4, 215 szSpecial + 3, szSpecial + 4}, 216 {wszSpecial + 4, wszSpecial + 4, 217 szSpecial + 4, szSpecial + 4}, 218 {wszSpecial + 5, wszSpecial + 5, 219 szSpecial + 5, szSpecial + 5}, 220 221 /* Test tabulation */ 222 {wszSpecial + 12, wszSpecial + 13, 223 szSpecial + 12, szSpecial + 13}, 224 225 /* Test linebreak */ 226 {wszSpecial + 15, wszSpecial + 16, 227 szSpecial + 15, szSpecial + 16}, 228 {wszSpecial + 16, wszSpecial + 17, 229 szSpecial + 16, szSpecial + 17}, 230 }; 231 232 ST_TESTS_CHARNEXT TestStaticCharNext_XP[] = 233 { 234 /* XP/2003 treat diacritics as normal characters */ 235 {wszMagic1 + 5, wszMagic1 + 6, 236 NULL, NULL}, 237 {wszMagic2 + 5, wszMagic2 + 6, 238 NULL, NULL}, 239 {wszMagic2 + 6, wszMagic2 + 7, 240 NULL, NULL}, 241 {wszMagic2 + 7, wszMagic2 + 8, 242 NULL, NULL}, 243 {wszMagic2 + 8, wszMagic2 + 9, 244 NULL, NULL}, 245 }; 246 247 ST_TESTS_CHARNEXT TestStaticCharNext_Vista[] = 248 { 249 /* Vista+ does respect diacritics and skip them */ 250 {wszMagic1 + 5, wszMagic1 + 7, 251 NULL, NULL}, 252 {wszMagic2 + 5, wszMagic2 + 10, 253 NULL, NULL}, 254 {wszMagic2 + 6, wszMagic2 + 10, 255 NULL, NULL}, 256 {wszMagic2 + 7, wszMagic2 + 10, 257 NULL, NULL}, 258 {wszMagic2 + 8, wszMagic2 + 10, 259 NULL, NULL}, 260 }; 261 262 typedef struct 263 { 264 UINT uCodePage; 265 LPCSTR szString; 266 LPCSTR szResult; 267 } ST_CODEPAGE_TESTS_CHARNEXT; 268 269 ST_CODEPAGE_TESTS_CHARNEXT TestStaticCodePageCharNext[] = 270 { 271 /* UTF-8 characters are not properly counted */ 272 {CP_UTF8, szUTF8Cyril, szUTF8Cyril + 1}, 273 {CP_UTF8, szUTF8Cyril + 4, szUTF8Cyril + 5}, 274 {CP_UTF8, szUTF8Cyril + 5, szUTF8Cyril + 6}, 275 {CP_UTF8, szUTF8Cyril + 7, szUTF8Cyril + 8}, 276 277 {CP_UTF8, szUTF8Greek + 5, szUTF8Greek + 6}, 278 {CP_UTF8, szUTF8Greek + 7, szUTF8Greek + 8}, 279 280 {CP_UTF8, szUTF8Japan + 5, szUTF8Japan + 6}, 281 {CP_UTF8, szUTF8Japan + 8, szUTF8Japan + 9}, 282 283 /* Code Page 932 / Shift-JIS characters are properly counted */ 284 {932, szCP932Japan, szCP932Japan + 1}, 285 {932, szCP932Japan + 5, szCP932Japan + 7}, 286 {932, szCP932Japan + 7, szCP932Japan + 9}, 287 }; 288 289 /* Exception tests (corner cases) */ 290 typedef struct 291 { 292 LPCWSTR wszStart; 293 LPCWSTR wszCurrent; 294 LPCWSTR wszResult; 295 LPCSTR szStart; 296 LPCSTR szCurrent; 297 LPCSTR szResult; 298 LPCSTR szExResult; 299 NTSTATUS resStatus; 300 } EX_TESTS_CHARPREV; 301 302 EX_TESTS_CHARPREV TestExceptionCharPrev[] = 303 { 304 {wszReactOS, NULL, NULL, 305 szReactOS, NULL, NULL, NULL, 306 STATUS_SUCCESS}, 307 {NULL, NULL, NULL, 308 NULL, NULL, NULL, NULL, 309 STATUS_SUCCESS}, 310 {NULL, wszReactOS, wszReactOS - 1, 311 NULL, szReactOS, szReactOS - 1, szReactOS - 1, 312 STATUS_SUCCESS}, 313 314 {INVALID_PTR, NULL, NULL, 315 INVALID_PTR, NULL, NULL, NULL, 316 STATUS_SUCCESS}, 317 {NULL, NULL, NULL, 318 NULL, NULL, NULL, NULL, 319 STATUS_SUCCESS}, 320 {NULL, INVALID_PTR, NULL, 321 NULL, INVALID_PTR, INVALID_PTR_OFF(-1) /* NULL on Win7 with updates */, NULL, 322 STATUS_ACCESS_VIOLATION}, 323 324 {wszReactOS, INVALID_PTR, NULL, 325 szReactOS, INVALID_PTR, INVALID_PTR_OFF(-1) /* NULL on Win7 with updates */, NULL, 326 STATUS_ACCESS_VIOLATION}, 327 {INVALID_PTR, INVALID_PTR, INVALID_PTR, 328 INVALID_PTR, INVALID_PTR, INVALID_PTR, INVALID_PTR, 329 STATUS_SUCCESS}, 330 {INVALID_PTR, wszReactOS, wszReactOS, 331 INVALID_PTR, szReactOS, szReactOS, szReactOS, 332 STATUS_SUCCESS}, 333 334 {INVALID_PTR_OFF(-2), INVALID_PTR, NULL, 335 INVALID_PTR_OFF(-2), INVALID_PTR, INVALID_PTR_OFF(-1) /* NULL on Win7 with updates */, NULL, 336 STATUS_ACCESS_VIOLATION}, 337 {INVALID_PTR, INVALID_PTR_OFF(2), NULL, 338 INVALID_PTR, INVALID_PTR_OFF(2), INVALID_PTR_OFF(1) /* NULL on Win7 with updates */, NULL, 339 STATUS_ACCESS_VIOLATION}, 340 {INVALID_PTR, INVALID_PTR_OFF(-2), INVALID_PTR_OFF(-2), 341 INVALID_PTR, INVALID_PTR_OFF(-2), INVALID_PTR_OFF(-2), INVALID_PTR_OFF(-2), 342 STATUS_SUCCESS}, 343 {INVALID_PTR_OFF(2), INVALID_PTR, INVALID_PTR, 344 INVALID_PTR_OFF(2), INVALID_PTR, INVALID_PTR, INVALID_PTR, 345 STATUS_SUCCESS}, 346 }; 347 348 typedef struct 349 { 350 LPCWSTR wszString; 351 LPCWSTR wszResult; 352 LPCSTR szString; 353 LPCSTR szResult; 354 NTSTATUS resStatus; 355 } EX_TESTS_CHARNEXT; 356 357 EX_TESTS_CHARNEXT TestExceptionCharNext[] = 358 { 359 {wszReactOS, wszReactOS + 1, 360 szReactOS, szReactOS + 1, 361 STATUS_SUCCESS}, 362 {NULL, NULL, 363 NULL, NULL, 364 STATUS_ACCESS_VIOLATION}, 365 {INVALID_PTR, NULL, 366 INVALID_PTR, NULL, 367 STATUS_ACCESS_VIOLATION}, 368 369 {INVALID_PTR_OFF(-2), NULL, 370 INVALID_PTR_OFF(-2), NULL, 371 STATUS_ACCESS_VIOLATION}, 372 {INVALID_PTR_OFF(2), NULL, 373 INVALID_PTR_OFF(2), NULL, 374 STATUS_ACCESS_VIOLATION}, 375 }; 376 377 static LPWSTR AllocStringW(LPWSTR lpszStr, SIZE_T len) 378 { 379 LPWSTR str; 380 SIZE_T sz; 381 382 if (!lpszStr) 383 return NULL; 384 385 sz = (len + 1) * sizeof(lpszStr[0]); 386 str = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz); 387 if (!str) 388 { 389 trace("HeapAlloc failed (error %ld)\n", GetLastError()); 390 goto Skip; 391 } 392 StringCbCopyW(str, sz, lpszStr); 393 Skip: 394 return str; 395 } 396 397 static LPSTR AllocStringA(LPWSTR lpszStr, SIZE_T len) 398 { 399 LPSTR str; 400 SIZE_T sz, mbs; 401 402 if (!lpszStr) 403 return NULL; 404 405 sz = len + 1; 406 str = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz); 407 if (!str) 408 { 409 trace("HeapAlloc failed (error %ld)\n", GetLastError()); 410 goto Skip; 411 } 412 413 mbs = WideCharToMultiByte(TEST_ACP, 0, lpszStr, -1, NULL, 0, NULL, NULL); 414 if (!mbs || mbs > sz) 415 { 416 HeapFree(GetProcessHeap(), 0, str); 417 str = NULL; 418 trace("WideCharToMultiByte returned %lu (error %ld)\n", mbs, GetLastError()); 419 goto Skip; 420 } 421 422 WideCharToMultiByte(TEST_ACP, 0, lpszStr, -1, str, mbs, NULL, NULL); 423 Skip: 424 return str; 425 } 426 427 static void testCharPrevW(const TESTS_CHARPREV *pEntry, SIZE_T len, UINT i) 428 { 429 LPWSTR wszStart, wszCurrent; 430 LPWSTR pchW; 431 INT iRealOffset; 432 BOOL b; 433 434 wszStart = AllocStringW(pEntry->lpszStart, len); 435 if (!wszStart && pEntry->lpszStart) 436 { 437 skip("[%u] AllocStringW for wszStart failed\n", i); 438 goto Cleanup; 439 } 440 if (pEntry->testType == testLen) 441 wszCurrent = wszStart + len; 442 else if (pEntry->testType == testOffs) 443 wszCurrent = wszStart + pEntry->iOffset; 444 else 445 { 446 wszCurrent = AllocStringW(pEntry->lpszCurrent, wcslen(pEntry->lpszCurrent)); 447 if (!wszCurrent && pEntry->lpszCurrent) 448 { 449 skip("[%u] AllocStringW for wszCurrent failed\n", i); 450 goto Cleanup; 451 } 452 } 453 pchW = CharPrevW(wszStart, wszCurrent); 454 if (wszCurrent - wszStart >= 0) 455 iRealOffset = pEntry->iResOffset; 456 else 457 iRealOffset = pEntry->iResOffsetNeg; 458 if (pEntry->bWithinStart) 459 { 460 b = pchW >= wszStart && pchW <= wszStart + len; 461 if (iRealOffset >= 0) 462 ok(b, "[%u] CharPrevW: pchW (0x%p) is expected to be within wszStart (0x%p)\n", i, pchW, wszStart); 463 else 464 ok(!b, "[%u] CharPrevW: pchW (0x%p) is expected to be outside wszStart (0x%p)\n", i, pchW, wszStart); 465 ok(pchW == wszStart + iRealOffset, "[%u] CharPrevW: pchW is 0x%p (offset %d)\n", i, pchW, pchW - wszStart); 466 } 467 else 468 { 469 b = pchW >= wszCurrent && pchW <= wszCurrent + wcslen(pEntry->lpszCurrent); 470 if (iRealOffset >= 0) 471 ok(b, "[%u] CharPrevW: pchW (0x%p) is expected to be within wszCurrent (0x%p)\n", i, pchW, wszCurrent); 472 else 473 ok(!b, "[%u] CharPrevW: pchW (0x%p) is expected to be outside wszCurrent (0x%p)\n", i, pchW, wszCurrent); 474 ok(pchW == wszCurrent + iRealOffset, "[%u] CharPrevW: pchW is 0x%p (offset %d)\n", i, pchW, pchW - wszCurrent); 475 } 476 477 Cleanup: 478 if (pEntry->testType != testBoth) 479 wszCurrent = NULL; 480 HeapFree(GetProcessHeap(), 0, wszStart); 481 HeapFree(GetProcessHeap(), 0, wszCurrent); 482 } 483 484 static void testCharPrevA(const TESTS_CHARPREV *pEntry, SIZE_T len, UINT i) 485 { 486 LPSTR szStart, szCurrent; 487 LPSTR pchA, pchEx; 488 INT iRealOffset; 489 BOOL b; 490 491 szStart = AllocStringA(pEntry->lpszStart, len); 492 if (!szStart && pEntry->lpszStart) 493 { 494 skip("[%u] AllocStringA for szStart failed\n", i); 495 goto Cleanup; 496 } 497 if (pEntry->testType == testLen) 498 szCurrent = szStart + len; 499 else if (pEntry->testType == testOffs) 500 szCurrent = szStart + pEntry->iOffset; 501 else 502 { 503 szCurrent = AllocStringA(pEntry->lpszCurrent, wcslen(pEntry->lpszCurrent)); 504 if (!szCurrent && pEntry->lpszCurrent) 505 { 506 skip("[%u] AllocStringA for szCurrent failed\n", i); 507 goto Cleanup; 508 } 509 } 510 pchA = CharPrevA(szStart, szCurrent); 511 pchEx = CharPrevExA(TEST_ACP, szStart, szCurrent, 0); 512 if (szCurrent - szStart >= 0) 513 iRealOffset = pEntry->iResOffset; 514 else 515 iRealOffset = pEntry->iResOffsetNeg; 516 if (pEntry->bWithinStart) 517 { 518 b = pchA >= szStart && pchA <= szStart + len; 519 if (iRealOffset >= 0) 520 ok(b, "[%u] CharPrevA: pchA (0x%p) is expected to be within szStart (0x%p)\n", i, pchA, szStart); 521 else 522 ok(!b, "[%u] CharPrevA: pchA (0x%p) is expected to be outside szStart (0x%p)\n", i, pchA, szStart); 523 ok(pchA == szStart + iRealOffset, "[%u] CharPrevA: pchA is 0x%p (offset %d)\n", i, pchA, pchA - szStart); 524 } 525 else 526 { 527 b = pchA >= szCurrent && pchA <= szCurrent + wcslen(pEntry->lpszCurrent); 528 if (iRealOffset >= 0) 529 ok(b, "[%u] CharPrevA: pchA (0x%p) is expected to be within szCurrent (0x%p)\n", i, pchA, szCurrent); 530 else 531 ok(!b, "[%u] CharPrevA: pchA (0x%p) is expected to be outside szCurrent (0x%p)\n", i, pchA, szCurrent); 532 ok(pchA == szCurrent + iRealOffset, "[%u] CharPrevA: pchA is 0x%p (offset %d)\n", i, pchA, pchA - szCurrent); 533 } 534 ok(pchA == pchEx, "[%u] CharPrevExA: pchA (0x%p) is not equal to pchEx (0x%p)\n", i, pchA, pchEx); 535 536 Cleanup: 537 if (pEntry->testType != testBoth) 538 szCurrent = NULL; 539 HeapFree(GetProcessHeap(), 0, szStart); 540 HeapFree(GetProcessHeap(), 0, szCurrent); 541 } 542 543 static void testDynCharPrev(const TESTS_CHARPREV *pEntry, UINT i) 544 { 545 SIZE_T len; 546 547 len = wcslen(pEntry->lpszStart); 548 testCharPrevW(pEntry, len, i); 549 550 if (pEntry->bWideOnly) 551 return; 552 553 testCharPrevA(pEntry, len, i); 554 } 555 556 static void testStatCharPrev(const ST_TESTS_CHARPREV *pEntry, UINT i) 557 { 558 LPWSTR pchW; 559 LPSTR pchA; 560 561 pchW = CharPrevW(pEntry->wszStart, pEntry->wszCurrent); 562 ok(pchW == pEntry->wszResult, "[%u] CharPrevW: pchW is 0x%p (expected 0x%p)\n", i, pchW, pEntry->wszResult); 563 564 if (!pEntry->szStart) 565 return; 566 567 pchA = CharPrevA(pEntry->szStart, pEntry->szCurrent); 568 ok(pchA == pEntry->szResult, "[%u] CharPrevA: pchA is 0x%p (expected 0x%p)\n", i, pchA, pEntry->szResult); 569 570 pchA = CharPrevExA(TEST_ACP, pEntry->szStart, pEntry->szCurrent, 0); 571 ok(pchA == pEntry->szResult, "[%u] CharPrevExA: pchA is 0x%p (expected 0x%p)\n", i, pchA, pEntry->szResult); 572 } 573 574 static void testStatCodePageCharPrev(const ST_CODEPAGE_TESTS_CHARPREV *pEntry, UINT i) 575 { 576 LPSTR pchA; 577 578 pchA = CharPrevExA(pEntry->uCodePage, pEntry->szStart, pEntry->szCurrent, 0); 579 ok(pchA == pEntry->szResult, "[%u] CharPrevExA(%u): pchA is 0x%p (expected 0x%p)\n", i, pEntry->uCodePage, pchA, pEntry->szResult); 580 } 581 582 static void testStatCharNext(const ST_TESTS_CHARNEXT *pEntry, UINT i) 583 { 584 LPWSTR pchW; 585 LPSTR pchA; 586 587 pchW = CharNextW(pEntry->wszString); 588 ok(pchW == pEntry->wszResult, "[%u] CharNextW: pchW is 0x%p (expected 0x%p)\n", i, pchW, pEntry->wszResult); 589 590 if (!pEntry->szString) 591 return; 592 593 pchA = CharNextA(pEntry->szString); 594 ok(pchA == pEntry->szResult, "[%u] CharNextA: pchA is 0x%p (expected 0x%p)\n", i, pchA, pEntry->szResult); 595 596 pchA = CharNextExA(TEST_ACP, pEntry->szString, 0); 597 ok(pchA == pEntry->szResult, "[%u] CharNextExA: pchA is 0x%p (expected 0x%p)\n", i, pchA, pEntry->szResult); 598 } 599 600 static void testStatCodePageCharNext(const ST_CODEPAGE_TESTS_CHARNEXT *pEntry, UINT i) 601 { 602 LPSTR pchA; 603 604 pchA = CharNextExA(pEntry->uCodePage, pEntry->szString, 0); 605 ok(pchA == pEntry->szResult, "[%u] CharNextExA(%u): pchA is 0x%p (expected 0x%p)\n", i, pEntry->uCodePage, pchA, pEntry->szResult); 606 } 607 608 static void testCharPrev(void) 609 { 610 UINT i; 611 612 /* Perform dynamic allocation tests */ 613 for (i = 0; i < _countof(TestCharPrev); i++) 614 { 615 testDynCharPrev(&TestCharPrev[i], i); 616 } 617 618 if (!IsWindowsVistaOrGreater()) 619 { 620 for (i = 0; i < _countof(TestCharPrev_XP); i++) 621 { 622 testDynCharPrev(&TestCharPrev_XP[i], i); 623 } 624 } 625 else 626 { 627 for (i = 0; i < _countof(TestCharPrev_Vista); i++) 628 { 629 testDynCharPrev(&TestCharPrev_Vista[i], i); 630 } 631 } 632 633 /* Perform static tests */ 634 for (i = 0; i < _countof(TestStaticCharPrev); i++) 635 { 636 testStatCharPrev(&TestStaticCharPrev[i], i); 637 } 638 639 if (!IsWindowsVistaOrGreater()) 640 { 641 for (i = 0; i < _countof(TestStaticCharPrev_XP); i++) 642 { 643 testStatCharPrev(&TestStaticCharPrev_XP[i], i); 644 } 645 } 646 else 647 { 648 for (i = 0; i < _countof(TestStaticCharPrev_Vista); i++) 649 { 650 testStatCharPrev(&TestStaticCharPrev_Vista[i], i); 651 } 652 } 653 654 for (i = 0; i < _countof(TestStaticCodePageCharPrev); i++) 655 { 656 testStatCodePageCharPrev(&TestStaticCodePageCharPrev[i], i); 657 } 658 659 /* Perform exception tests (check corner cases) */ 660 if (INVALID_PTR < (PVOID)wszReactOS) 661 { 662 ok(FALSE, "testCharPrev: unexpected INVALID PTR < wszReactOS\n"); 663 return; 664 } 665 if (INVALID_PTR < (PVOID)szReactOS) 666 { 667 ok(FALSE, "testCharPrev: unexpected INVALID PTR < szReactOS\n"); 668 return; 669 } 670 671 for (i = 0; i < _countof(TestExceptionCharPrev); i++) 672 { 673 LPWSTR pchW; 674 LPSTR pchA; 675 const EX_TESTS_CHARPREV *pEntry = &TestExceptionCharPrev[i]; 676 NTSTATUS Status = STATUS_SUCCESS; 677 678 //trace("0x%p 0x%p\n", pEntry->wszStart, pEntry->wszCurrent); 679 pchW = NULL; 680 _SEH2_TRY 681 { 682 pchW = CharPrevW(pEntry->wszStart, pEntry->wszCurrent); 683 } 684 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 685 { 686 Status = _SEH2_GetExceptionCode(); 687 } 688 _SEH2_END; 689 ok(Status == pEntry->resStatus, "[%u] CharPrevW: Status is 0x%lX, expected 0x%lX\n", i, Status, pEntry->resStatus); 690 ok(pchW == pEntry->wszResult, "[%u] CharPrevW: pchW is 0x%p, expected 0x%p\n", i, pchW, pEntry->wszResult); 691 692 //trace("0x%p 0x%p\n", pEntry->szStart, pEntry->szCurrent); 693 pchA = NULL; 694 _SEH2_TRY 695 { 696 pchA = CharPrevA(pEntry->szStart, pEntry->szCurrent); 697 } 698 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 699 { 700 Status = _SEH2_GetExceptionCode(); 701 } 702 _SEH2_END; 703 ok(Status == pEntry->resStatus, "[%u] CharPrevA: Status is 0x%lX, expected 0x%lX\n", i, Status, pEntry->resStatus); 704 ok(pchA == pEntry->szResult, "[%u] CharPrevA: pchA is 0x%p, expected 0x%p\n", i, pchA, pEntry->szResult); 705 706 pchA = NULL; 707 _SEH2_TRY 708 { 709 pchA = CharPrevExA(TEST_ACP, pEntry->szStart, pEntry->szCurrent, 0); 710 } 711 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 712 { 713 Status = _SEH2_GetExceptionCode(); 714 } 715 _SEH2_END; 716 ok(Status == pEntry->resStatus, "[%u] CharPrevExA: Status is 0x%lX, expected 0x%lX\n", i, Status, pEntry->resStatus); 717 ok(pchA == pEntry->szExResult, "[%u] CharPrevExA: pchA is 0x%p, expected 0x%p\n", i, pchA, pEntry->szExResult); 718 } 719 } 720 721 static void testCharNext(void) 722 { 723 UINT i; 724 725 /* Perform static tests */ 726 for (i = 0; i < _countof(TestStaticCharNext); i++) 727 { 728 testStatCharNext(&TestStaticCharNext[i], i); 729 } 730 731 if (!IsWindowsVistaOrGreater()) 732 { 733 for (i = 0; i < _countof(TestStaticCharNext_XP); i++) 734 { 735 testStatCharNext(&TestStaticCharNext_XP[i], i); 736 } 737 } 738 else 739 { 740 for (i = 0; i < _countof(TestStaticCharNext_Vista); i++) 741 { 742 testStatCharNext(&TestStaticCharNext_Vista[i], i); 743 } 744 } 745 746 for (i = 0; i < _countof(TestStaticCodePageCharNext); i++) 747 { 748 testStatCodePageCharNext(&TestStaticCodePageCharNext[i], i); 749 } 750 751 /* Perform exception tests (check corner cases) */ 752 if (INVALID_PTR < (PVOID)wszReactOS) 753 { 754 ok(FALSE, "testCharNext: unexpected INVALID PTR < wszReactOS\n"); 755 return; 756 } 757 if (INVALID_PTR < (PVOID)szReactOS) 758 { 759 ok(FALSE, "testCharNext: unexpected INVALID PTR < szReactOS\n"); 760 return; 761 } 762 763 for (i = 0; i < _countof(TestExceptionCharNext); i++) 764 { 765 LPWSTR pchW; 766 LPSTR pchA; 767 const EX_TESTS_CHARNEXT *pEntry = &TestExceptionCharNext[i]; 768 NTSTATUS Status = STATUS_SUCCESS; 769 770 //trace("0x%p\n", pEntry->wszString); 771 pchW = NULL; 772 _SEH2_TRY 773 { 774 pchW = CharNextW(pEntry->wszString); 775 } 776 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 777 { 778 Status = _SEH2_GetExceptionCode(); 779 } 780 _SEH2_END; 781 ok(Status == pEntry->resStatus, "[%u] CharNextW: Status is 0x%lX, expected 0x%lX\n", i, Status, pEntry->resStatus); 782 ok(pchW == pEntry->wszResult, "[%u] CharNextW: pchW is 0x%p, expected 0x%p\n", i, pchW, pEntry->wszResult); 783 784 //trace("0x%p 0x%p\n", pEntry->szString); 785 pchA = NULL; 786 _SEH2_TRY 787 { 788 pchA = CharNextA(pEntry->szString); 789 } 790 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 791 { 792 Status = _SEH2_GetExceptionCode(); 793 } 794 _SEH2_END; 795 ok(Status == pEntry->resStatus, "[%u] CharNextA: Status is 0x%lX, expected 0x%lX\n", i, Status, pEntry->resStatus); 796 ok(pchA == pEntry->szResult, "[%u] CharNextA: pchA is 0x%p, expected 0x%p\n", i, pchA, pEntry->szResult); 797 798 pchA = NULL; 799 _SEH2_TRY 800 { 801 pchA = CharNextExA(TEST_ACP, pEntry->szString, 0); 802 } 803 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 804 { 805 Status = _SEH2_GetExceptionCode(); 806 } 807 _SEH2_END; 808 ok(Status == pEntry->resStatus, "[%u] CharNextExA: Status is 0x%lX, expected 0x%lX\n", i, Status, pEntry->resStatus); 809 ok(pchA == pEntry->szResult, "[%u] CharNextExA: pchA is 0x%p, expected 0x%p\n", i, pchA, pEntry->szResult); 810 } 811 } 812 813 START_TEST(CharFuncs) 814 { 815 testCharPrev(); 816 testCharNext(); 817 } 818