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
AllocStringW(LPWSTR lpszStr,SIZE_T len)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
AllocStringA(LPWSTR lpszStr,SIZE_T len)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
testCharPrevW(const TESTS_CHARPREV * pEntry,SIZE_T len,UINT i)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
testCharPrevA(const TESTS_CHARPREV * pEntry,SIZE_T len,UINT i)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
testDynCharPrev(const TESTS_CHARPREV * pEntry,UINT i)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
testStatCharPrev(const ST_TESTS_CHARPREV * pEntry,UINT i)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
testStatCodePageCharPrev(const ST_CODEPAGE_TESTS_CHARPREV * pEntry,UINT i)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
testStatCharNext(const ST_TESTS_CHARNEXT * pEntry,UINT i)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
testStatCodePageCharNext(const ST_CODEPAGE_TESTS_CHARNEXT * pEntry,UINT i)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
testCharPrev(void)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
testCharNext(void)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
START_TEST(CharFuncs)813 START_TEST(CharFuncs)
814 {
815 testCharPrev();
816 testCharNext();
817 }
818