mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
[USER32_APITEST] Add tests for CharPrev/Next/Ex/A/W
CORE-18415 CORE-18452
This commit is contained in:
parent
bd40c13f6f
commit
4b10fdbce9
3 changed files with 820 additions and 0 deletions
|
@ -2,6 +2,7 @@
|
|||
list(APPEND SOURCE
|
||||
AttachThreadInput.c
|
||||
../include/msgtrace.c
|
||||
CharFuncs.c
|
||||
CloseWindow.c
|
||||
CreateDialog.c
|
||||
CreateIconFromResourceEx.c
|
||||
|
|
817
modules/rostests/apitests/user32/CharFuncs.c
Normal file
817
modules/rostests/apitests/user32/CharFuncs.c
Normal file
|
@ -0,0 +1,817 @@
|
|||
/*
|
||||
* PROJECT: ReactOS API tests
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* PURPOSE: Tests for Char* functions
|
||||
* COPYRIGHT: Copyright 2022 Stanislav Motylkov <x86corez@gmail.com>
|
||||
*/
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
#include <winnls.h>
|
||||
#include <ndk/rtlfuncs.h>
|
||||
#include <pseh/pseh2.h>
|
||||
#include <strsafe.h>
|
||||
#include <versionhelpers.h>
|
||||
|
||||
#define INVALID_PTR_OFF(x) ((PVOID)(ULONG_PTR)(0xdeadbeefdeadbeefULL + x))
|
||||
#define INVALID_PTR INVALID_PTR_OFF(0)
|
||||
|
||||
/* Default code page to be tested */
|
||||
#define TEST_ACP 1252
|
||||
|
||||
typedef enum
|
||||
{
|
||||
testLen,
|
||||
testOffs,
|
||||
testBoth,
|
||||
} TEST_TYPE;
|
||||
|
||||
/* Dynamic allocation tests */
|
||||
typedef struct
|
||||
{
|
||||
TEST_TYPE testType;
|
||||
LPWSTR lpszStart; /* Specified string for szStart */
|
||||
LPWSTR lpszCurrent; /* Specified string for szCurrent (only when testType == testBoth) */
|
||||
INT iOffset; /* Specified offset to test (only when testType == testOffs) */
|
||||
INT iResOffset; /* Expected offset when szCurrent >= szStart */
|
||||
INT iResOffsetNeg; /* Expected offset when szCurrent < szStart */
|
||||
BOOL bWithinStart; /* TRUE for pointer expected to be within szStart, FALSE for within szCurrent */
|
||||
BOOL bWideOnly; /* Perform test only for Unicode case */
|
||||
} TESTS_CHARPREV;
|
||||
|
||||
TESTS_CHARPREV TestCharPrev[] =
|
||||
{
|
||||
{testLen, L"C:\\ReactOS", NULL, 0, 9, 9, TRUE, FALSE},
|
||||
{testOffs, L"abcdefghijk", NULL, 11, 10, 10, TRUE, FALSE},
|
||||
{testOffs, L"test a´^~¯", NULL, 10, 9, 9, TRUE, FALSE},
|
||||
{testOffs, L"test å", NULL, 6, 5, 5, TRUE, FALSE},
|
||||
{testBoth, L"C:\\ReactOS", L"", 0, -1, 0, FALSE, FALSE},
|
||||
{testBoth, L"C:\\ReactOS\\", L"C:\\ReactOS", 0, -1, 0, FALSE, FALSE},
|
||||
{testBoth, L"C:\\ReactOS\\", L"ReactOS", 0, -1, 0, FALSE, FALSE},
|
||||
};
|
||||
|
||||
TESTS_CHARPREV TestCharPrev_XP[] =
|
||||
{
|
||||
/* XP/2003 treat diacritics as normal characters */
|
||||
{testOffs, L"test a\x030a", NULL, 7, 6, 6, TRUE, TRUE},
|
||||
{testOffs, L"test a\x0301\x0302\x0303\x0304", NULL, 10, 9, 9, TRUE, TRUE},
|
||||
{testOffs, L"test a\x0301\x0302\x0303\x0304", NULL, 9, 8, 8, TRUE, TRUE},
|
||||
{testOffs, L"test a\x0301\x0302\x0303\x0304", NULL, 8, 7, 7, TRUE, TRUE},
|
||||
{testOffs, L"test a\x0301\x0302\x0303\x0304", NULL, 7, 6, 6, TRUE, TRUE},
|
||||
};
|
||||
|
||||
TESTS_CHARPREV TestCharPrev_Vista[] =
|
||||
{
|
||||
/* Vista+ does respect diacritics and skip them */
|
||||
{testOffs, L"test a\x030a", NULL, 7, 5, 5, TRUE, TRUE},
|
||||
{testOffs, L"test a\x0301\x0302\x0303\x0304", NULL, 10, 5, 5, TRUE, TRUE},
|
||||
{testOffs, L"test a\x0301\x0302\x0303\x0304", NULL, 9, 5, 5, TRUE, TRUE},
|
||||
{testOffs, L"test a\x0301\x0302\x0303\x0304", NULL, 8, 5, 5, TRUE, TRUE},
|
||||
{testOffs, L"test a\x0301\x0302\x0303\x0304", NULL, 7, 5, 5, TRUE, TRUE},
|
||||
};
|
||||
|
||||
/* Static tests */
|
||||
static const WCHAR wszReactOS[] = L"C:\\ReactOS";
|
||||
static const CHAR szReactOS[] = "C:\\ReactOS";
|
||||
static const WCHAR wszSpecial[] = L"test\0\0\0\0\0\0aa\t\t\t\r\n\r\n";
|
||||
static const CHAR szSpecial[] = "test\0\0\0\0\0\0aa\t\t\t\r\n\r\n";
|
||||
static const WCHAR wszMagic1[] = L"test a\x030a";
|
||||
static const WCHAR wszMagic2[] = L"test a\x0301\x0302\x0303\x0304";
|
||||
|
||||
static const CHAR szUTF8Cyril[] = "test \xD1\x82\xD0\xB5\xD1\x81\xD1\x82"; /* UTF8(L"test тест") */
|
||||
static const CHAR szUTF8Greek[] = "test \xCF\x84\xCE\xB5\xCF\x83\xCF\x84"; /* UTF8(L"test τεστ") */
|
||||
static const CHAR szUTF8Japan[] = "test \xE3\x83\x86\xE3\x82\xB9\xE3\x83\x88"; /* UTF8(L"test テスト") */
|
||||
static const CHAR szCP932Japan[] = "test \x83\x65\x83\x58\x83\x67"; /* CP932(L"test テスト") */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LPCWSTR wszStart;
|
||||
LPCWSTR wszCurrent;
|
||||
LPCWSTR wszResult;
|
||||
LPCSTR szStart;
|
||||
LPCSTR szCurrent;
|
||||
LPCSTR szResult;
|
||||
} ST_TESTS_CHARPREV;
|
||||
|
||||
ST_TESTS_CHARPREV TestStaticCharPrev[] =
|
||||
{
|
||||
{wszReactOS, wszReactOS, wszReactOS,
|
||||
szReactOS, szReactOS, szReactOS},
|
||||
{wszReactOS, wszReactOS + 1, wszReactOS,
|
||||
szReactOS, szReactOS + 1, szReactOS},
|
||||
{wszReactOS, wszReactOS + 2, wszReactOS + 1,
|
||||
szReactOS, szReactOS + 2, szReactOS + 1},
|
||||
{wszReactOS, wszReactOS + 3, wszReactOS + 2,
|
||||
szReactOS, szReactOS + 3, szReactOS + 2},
|
||||
{wszReactOS, wszReactOS + 10, wszReactOS + 9,
|
||||
szReactOS, szReactOS + 10, szReactOS + 9},
|
||||
|
||||
{wszReactOS + 2, wszReactOS, wszReactOS,
|
||||
szReactOS + 2, szReactOS, szReactOS},
|
||||
{wszReactOS + 2, wszReactOS + 1, wszReactOS + 1,
|
||||
szReactOS + 2, szReactOS + 1, szReactOS + 1},
|
||||
{wszReactOS + 2, wszReactOS + 2, wszReactOS + 2,
|
||||
szReactOS + 2, szReactOS + 2, szReactOS + 2},
|
||||
{wszReactOS + 2, wszReactOS + 3, wszReactOS + 2,
|
||||
szReactOS + 2, szReactOS + 3, szReactOS + 2},
|
||||
{wszReactOS + 2, wszReactOS + 4, wszReactOS + 3,
|
||||
szReactOS + 2, szReactOS + 4, szReactOS + 3},
|
||||
|
||||
/* Test null-terminators */
|
||||
{wszSpecial, wszSpecial + 8, wszSpecial + 7,
|
||||
szSpecial, szSpecial + 8, szSpecial + 7},
|
||||
|
||||
/* Test tabulation */
|
||||
{wszSpecial, wszSpecial + 13, wszSpecial + 12,
|
||||
szSpecial, szSpecial + 13, szSpecial + 12},
|
||||
|
||||
/* Test linebreak */
|
||||
{wszSpecial, wszSpecial + 17, wszSpecial + 16,
|
||||
szSpecial, szSpecial + 17, szSpecial + 16},
|
||||
{wszSpecial, wszSpecial + 18, wszSpecial + 17,
|
||||
szSpecial, szSpecial + 18, szSpecial + 17},
|
||||
};
|
||||
|
||||
ST_TESTS_CHARPREV TestStaticCharPrev_XP[] =
|
||||
{
|
||||
/* XP/2003 treat diacritics as normal characters */
|
||||
{wszMagic1, wszMagic1 + 7, wszMagic1 + 6,
|
||||
NULL, NULL, NULL},
|
||||
{wszMagic2, wszMagic2 + 10, wszMagic2 + 9,
|
||||
NULL, NULL, NULL},
|
||||
{wszMagic2, wszMagic2 + 9, wszMagic2 + 8,
|
||||
NULL, NULL, NULL},
|
||||
{wszMagic2, wszMagic2 + 8, wszMagic2 + 7,
|
||||
NULL, NULL, NULL},
|
||||
{wszMagic2, wszMagic2 + 7, wszMagic2 + 6,
|
||||
NULL, NULL, NULL},
|
||||
};
|
||||
|
||||
ST_TESTS_CHARPREV TestStaticCharPrev_Vista[] =
|
||||
{
|
||||
/* Vista+ does respect diacritics and skip them */
|
||||
{wszMagic1, wszMagic1 + 7, wszMagic1 + 5,
|
||||
NULL, NULL, NULL},
|
||||
{wszMagic2, wszMagic2 + 10, wszMagic2 + 5,
|
||||
NULL, NULL, NULL},
|
||||
{wszMagic2, wszMagic2 + 9, wszMagic2 + 5,
|
||||
NULL, NULL, NULL},
|
||||
{wszMagic2, wszMagic2 + 8, wszMagic2 + 5,
|
||||
NULL, NULL, NULL},
|
||||
{wszMagic2, wszMagic2 + 7, wszMagic2 + 5,
|
||||
NULL, NULL, NULL},
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT uCodePage;
|
||||
LPCSTR szStart;
|
||||
LPCSTR szCurrent;
|
||||
LPCSTR szResult;
|
||||
} ST_CODEPAGE_TESTS_CHARPREV;
|
||||
|
||||
ST_CODEPAGE_TESTS_CHARPREV TestStaticCodePageCharPrev[] =
|
||||
{
|
||||
/* UTF-8 characters are not properly counted */
|
||||
{CP_UTF8, szUTF8Cyril, szUTF8Cyril + 2, szUTF8Cyril + 1},
|
||||
{CP_UTF8, szUTF8Cyril, szUTF8Cyril + 7, szUTF8Cyril + 6},
|
||||
{CP_UTF8, szUTF8Cyril, szUTF8Cyril + 9, szUTF8Cyril + 8},
|
||||
|
||||
{CP_UTF8, szUTF8Greek, szUTF8Greek + 7, szUTF8Greek + 6},
|
||||
{CP_UTF8, szUTF8Greek, szUTF8Greek + 9, szUTF8Greek + 8},
|
||||
|
||||
{CP_UTF8, szUTF8Japan, szUTF8Japan + 8, szUTF8Japan + 7},
|
||||
{CP_UTF8, szUTF8Japan, szUTF8Japan + 11, szUTF8Japan + 10},
|
||||
|
||||
/* Code Page 932 / Shift-JIS characters are properly counted */
|
||||
{932, szCP932Japan, szCP932Japan + 2, szCP932Japan + 1},
|
||||
{932, szCP932Japan, szCP932Japan + 7, szCP932Japan + 5},
|
||||
{932, szCP932Japan, szCP932Japan + 9, szCP932Japan + 7},
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LPCWSTR wszString;
|
||||
LPCWSTR wszResult;
|
||||
LPCSTR szString;
|
||||
LPCSTR szResult;
|
||||
} ST_TESTS_CHARNEXT;
|
||||
|
||||
ST_TESTS_CHARNEXT TestStaticCharNext[] =
|
||||
{
|
||||
{wszReactOS, wszReactOS + 1,
|
||||
szReactOS, szReactOS + 1},
|
||||
{wszReactOS + 1, wszReactOS + 2,
|
||||
szReactOS + 1, szReactOS + 2},
|
||||
{wszReactOS + 2, wszReactOS + 3,
|
||||
szReactOS + 2, szReactOS + 3},
|
||||
{wszReactOS + 9, wszReactOS + 10,
|
||||
szReactOS + 9, szReactOS + 10},
|
||||
{wszReactOS + 10, wszReactOS + 10,
|
||||
szReactOS + 10, szReactOS + 10},
|
||||
|
||||
/* Test null-terminators */
|
||||
{wszSpecial + 3, wszSpecial + 4,
|
||||
szSpecial + 3, szSpecial + 4},
|
||||
{wszSpecial + 4, wszSpecial + 4,
|
||||
szSpecial + 4, szSpecial + 4},
|
||||
{wszSpecial + 5, wszSpecial + 5,
|
||||
szSpecial + 5, szSpecial + 5},
|
||||
|
||||
/* Test tabulation */
|
||||
{wszSpecial + 12, wszSpecial + 13,
|
||||
szSpecial + 12, szSpecial + 13},
|
||||
|
||||
/* Test linebreak */
|
||||
{wszSpecial + 15, wszSpecial + 16,
|
||||
szSpecial + 15, szSpecial + 16},
|
||||
{wszSpecial + 16, wszSpecial + 17,
|
||||
szSpecial + 16, szSpecial + 17},
|
||||
};
|
||||
|
||||
ST_TESTS_CHARNEXT TestStaticCharNext_XP[] =
|
||||
{
|
||||
/* XP/2003 treat diacritics as normal characters */
|
||||
{wszMagic1 + 5, wszMagic1 + 6,
|
||||
NULL, NULL},
|
||||
{wszMagic2 + 5, wszMagic2 + 6,
|
||||
NULL, NULL},
|
||||
{wszMagic2 + 6, wszMagic2 + 7,
|
||||
NULL, NULL},
|
||||
{wszMagic2 + 7, wszMagic2 + 8,
|
||||
NULL, NULL},
|
||||
{wszMagic2 + 8, wszMagic2 + 9,
|
||||
NULL, NULL},
|
||||
};
|
||||
|
||||
ST_TESTS_CHARNEXT TestStaticCharNext_Vista[] =
|
||||
{
|
||||
/* Vista+ does respect diacritics and skip them */
|
||||
{wszMagic1 + 5, wszMagic1 + 7,
|
||||
NULL, NULL},
|
||||
{wszMagic2 + 5, wszMagic2 + 10,
|
||||
NULL, NULL},
|
||||
{wszMagic2 + 6, wszMagic2 + 10,
|
||||
NULL, NULL},
|
||||
{wszMagic2 + 7, wszMagic2 + 10,
|
||||
NULL, NULL},
|
||||
{wszMagic2 + 8, wszMagic2 + 10,
|
||||
NULL, NULL},
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT uCodePage;
|
||||
LPCSTR szString;
|
||||
LPCSTR szResult;
|
||||
} ST_CODEPAGE_TESTS_CHARNEXT;
|
||||
|
||||
ST_CODEPAGE_TESTS_CHARNEXT TestStaticCodePageCharNext[] =
|
||||
{
|
||||
/* UTF-8 characters are not properly counted */
|
||||
{CP_UTF8, szUTF8Cyril, szUTF8Cyril + 1},
|
||||
{CP_UTF8, szUTF8Cyril + 4, szUTF8Cyril + 5},
|
||||
{CP_UTF8, szUTF8Cyril + 5, szUTF8Cyril + 6},
|
||||
{CP_UTF8, szUTF8Cyril + 7, szUTF8Cyril + 8},
|
||||
|
||||
{CP_UTF8, szUTF8Greek + 5, szUTF8Greek + 6},
|
||||
{CP_UTF8, szUTF8Greek + 7, szUTF8Greek + 8},
|
||||
|
||||
{CP_UTF8, szUTF8Japan + 5, szUTF8Japan + 6},
|
||||
{CP_UTF8, szUTF8Japan + 8, szUTF8Japan + 9},
|
||||
|
||||
/* Code Page 932 / Shift-JIS characters are properly counted */
|
||||
{932, szCP932Japan, szCP932Japan + 1},
|
||||
{932, szCP932Japan + 5, szCP932Japan + 7},
|
||||
{932, szCP932Japan + 7, szCP932Japan + 9},
|
||||
};
|
||||
|
||||
/* Exception tests (corner cases) */
|
||||
typedef struct
|
||||
{
|
||||
LPCWSTR wszStart;
|
||||
LPCWSTR wszCurrent;
|
||||
LPCWSTR wszResult;
|
||||
LPCSTR szStart;
|
||||
LPCSTR szCurrent;
|
||||
LPCSTR szResult;
|
||||
LPCSTR szExResult;
|
||||
NTSTATUS resStatus;
|
||||
} EX_TESTS_CHARPREV;
|
||||
|
||||
EX_TESTS_CHARPREV TestExceptionCharPrev[] =
|
||||
{
|
||||
{wszReactOS, NULL, NULL,
|
||||
szReactOS, NULL, NULL, NULL,
|
||||
STATUS_SUCCESS},
|
||||
{NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL,
|
||||
STATUS_SUCCESS},
|
||||
{NULL, wszReactOS, wszReactOS - 1,
|
||||
NULL, szReactOS, szReactOS - 1, szReactOS - 1,
|
||||
STATUS_SUCCESS},
|
||||
|
||||
{INVALID_PTR, NULL, NULL,
|
||||
INVALID_PTR, NULL, NULL, NULL,
|
||||
STATUS_SUCCESS},
|
||||
{NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL,
|
||||
STATUS_SUCCESS},
|
||||
{NULL, INVALID_PTR, NULL,
|
||||
NULL, INVALID_PTR, INVALID_PTR_OFF(-1) /* NULL on Win7 with updates */, NULL,
|
||||
STATUS_ACCESS_VIOLATION},
|
||||
|
||||
{wszReactOS, INVALID_PTR, NULL,
|
||||
szReactOS, INVALID_PTR, INVALID_PTR_OFF(-1) /* NULL on Win7 with updates */, NULL,
|
||||
STATUS_ACCESS_VIOLATION},
|
||||
{INVALID_PTR, INVALID_PTR, INVALID_PTR,
|
||||
INVALID_PTR, INVALID_PTR, INVALID_PTR, INVALID_PTR,
|
||||
STATUS_SUCCESS},
|
||||
{INVALID_PTR, wszReactOS, wszReactOS,
|
||||
INVALID_PTR, szReactOS, szReactOS, szReactOS,
|
||||
STATUS_SUCCESS},
|
||||
|
||||
{INVALID_PTR_OFF(-2), INVALID_PTR, NULL,
|
||||
INVALID_PTR_OFF(-2), INVALID_PTR, INVALID_PTR_OFF(-1) /* NULL on Win7 with updates */, NULL,
|
||||
STATUS_ACCESS_VIOLATION},
|
||||
{INVALID_PTR, INVALID_PTR_OFF(2), NULL,
|
||||
INVALID_PTR, INVALID_PTR_OFF(2), INVALID_PTR_OFF(1) /* NULL on Win7 with updates */, NULL,
|
||||
STATUS_ACCESS_VIOLATION},
|
||||
{INVALID_PTR, INVALID_PTR_OFF(-2), INVALID_PTR_OFF(-2),
|
||||
INVALID_PTR, INVALID_PTR_OFF(-2), INVALID_PTR_OFF(-2), INVALID_PTR_OFF(-2),
|
||||
STATUS_SUCCESS},
|
||||
{INVALID_PTR_OFF(2), INVALID_PTR, INVALID_PTR,
|
||||
INVALID_PTR_OFF(2), INVALID_PTR, INVALID_PTR, INVALID_PTR,
|
||||
STATUS_SUCCESS},
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LPCWSTR wszString;
|
||||
LPCWSTR wszResult;
|
||||
LPCSTR szString;
|
||||
LPCSTR szResult;
|
||||
NTSTATUS resStatus;
|
||||
} EX_TESTS_CHARNEXT;
|
||||
|
||||
EX_TESTS_CHARNEXT TestExceptionCharNext[] =
|
||||
{
|
||||
{wszReactOS, wszReactOS + 1,
|
||||
szReactOS, szReactOS + 1,
|
||||
STATUS_SUCCESS},
|
||||
{NULL, NULL,
|
||||
NULL, NULL,
|
||||
STATUS_ACCESS_VIOLATION},
|
||||
{INVALID_PTR, NULL,
|
||||
INVALID_PTR, NULL,
|
||||
STATUS_ACCESS_VIOLATION},
|
||||
|
||||
{INVALID_PTR_OFF(-2), NULL,
|
||||
INVALID_PTR_OFF(-2), NULL,
|
||||
STATUS_ACCESS_VIOLATION},
|
||||
{INVALID_PTR_OFF(2), NULL,
|
||||
INVALID_PTR_OFF(2), NULL,
|
||||
STATUS_ACCESS_VIOLATION},
|
||||
};
|
||||
|
||||
static LPWSTR AllocStringW(LPWSTR lpszStr, SIZE_T len)
|
||||
{
|
||||
LPWSTR str;
|
||||
SIZE_T sz;
|
||||
|
||||
if (!lpszStr)
|
||||
return NULL;
|
||||
|
||||
sz = (len + 1) * sizeof(lpszStr[0]);
|
||||
str = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz);
|
||||
if (!str)
|
||||
{
|
||||
trace("HeapAlloc failed (error %ld)\n", GetLastError());
|
||||
goto Skip;
|
||||
}
|
||||
StringCbCopyW(str, sz, lpszStr);
|
||||
Skip:
|
||||
return str;
|
||||
}
|
||||
|
||||
static LPSTR AllocStringA(LPWSTR lpszStr, SIZE_T len)
|
||||
{
|
||||
LPSTR str;
|
||||
SIZE_T sz, mbs;
|
||||
|
||||
if (!lpszStr)
|
||||
return NULL;
|
||||
|
||||
sz = len + 1;
|
||||
str = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz);
|
||||
if (!str)
|
||||
{
|
||||
trace("HeapAlloc failed (error %ld)\n", GetLastError());
|
||||
goto Skip;
|
||||
}
|
||||
|
||||
mbs = WideCharToMultiByte(TEST_ACP, 0, lpszStr, -1, NULL, 0, NULL, NULL);
|
||||
if (!mbs || mbs > sz)
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, str);
|
||||
str = NULL;
|
||||
trace("WideCharToMultiByte returned %lu (error %ld)\n", mbs, GetLastError());
|
||||
goto Skip;
|
||||
}
|
||||
|
||||
WideCharToMultiByte(TEST_ACP, 0, lpszStr, -1, str, mbs, NULL, NULL);
|
||||
Skip:
|
||||
return str;
|
||||
}
|
||||
|
||||
static void testCharPrevW(const TESTS_CHARPREV *pEntry, SIZE_T len, UINT i)
|
||||
{
|
||||
LPWSTR wszStart, wszCurrent;
|
||||
LPWSTR pchW;
|
||||
INT iRealOffset;
|
||||
BOOL b;
|
||||
|
||||
wszStart = AllocStringW(pEntry->lpszStart, len);
|
||||
if (!wszStart && pEntry->lpszStart)
|
||||
{
|
||||
skip("[%u] AllocStringW for wszStart failed\n", i);
|
||||
goto Cleanup;
|
||||
}
|
||||
if (pEntry->testType == testLen)
|
||||
wszCurrent = wszStart + len;
|
||||
else if (pEntry->testType == testOffs)
|
||||
wszCurrent = wszStart + pEntry->iOffset;
|
||||
else
|
||||
{
|
||||
wszCurrent = AllocStringW(pEntry->lpszCurrent, wcslen(pEntry->lpszCurrent));
|
||||
if (!wszCurrent && pEntry->lpszCurrent)
|
||||
{
|
||||
skip("[%u] AllocStringW for wszCurrent failed\n", i);
|
||||
goto Cleanup;
|
||||
}
|
||||
}
|
||||
pchW = CharPrevW(wszStart, wszCurrent);
|
||||
if (wszCurrent - wszStart >= 0)
|
||||
iRealOffset = pEntry->iResOffset;
|
||||
else
|
||||
iRealOffset = pEntry->iResOffsetNeg;
|
||||
if (pEntry->bWithinStart)
|
||||
{
|
||||
b = pchW >= wszStart && pchW <= wszStart + len;
|
||||
if (iRealOffset >= 0)
|
||||
ok(b, "[%u] CharPrevW: pchW (0x%p) is expected to be within wszStart (0x%p)\n", i, pchW, wszStart);
|
||||
else
|
||||
ok(!b, "[%u] CharPrevW: pchW (0x%p) is expected to be outside wszStart (0x%p)\n", i, pchW, wszStart);
|
||||
ok(pchW == wszStart + iRealOffset, "[%u] CharPrevW: pchW is 0x%p (offset %d)\n", i, pchW, pchW - wszStart);
|
||||
}
|
||||
else
|
||||
{
|
||||
b = pchW >= wszCurrent && pchW <= wszCurrent + wcslen(pEntry->lpszCurrent);
|
||||
if (iRealOffset >= 0)
|
||||
ok(b, "[%u] CharPrevW: pchW (0x%p) is expected to be within wszCurrent (0x%p)\n", i, pchW, wszCurrent);
|
||||
else
|
||||
ok(!b, "[%u] CharPrevW: pchW (0x%p) is expected to be outside wszCurrent (0x%p)\n", i, pchW, wszCurrent);
|
||||
ok(pchW == wszCurrent + iRealOffset, "[%u] CharPrevW: pchW is 0x%p (offset %d)\n", i, pchW, pchW - wszCurrent);
|
||||
}
|
||||
|
||||
Cleanup:
|
||||
if (pEntry->testType != testBoth)
|
||||
wszCurrent = NULL;
|
||||
HeapFree(GetProcessHeap(), 0, wszStart);
|
||||
HeapFree(GetProcessHeap(), 0, wszCurrent);
|
||||
}
|
||||
|
||||
static void testCharPrevA(const TESTS_CHARPREV *pEntry, SIZE_T len, UINT i)
|
||||
{
|
||||
LPSTR szStart, szCurrent;
|
||||
LPSTR pchA, pchEx;
|
||||
INT iRealOffset;
|
||||
BOOL b;
|
||||
|
||||
szStart = AllocStringA(pEntry->lpszStart, len);
|
||||
if (!szStart && pEntry->lpszStart)
|
||||
{
|
||||
skip("[%u] AllocStringA for szStart failed\n", i);
|
||||
goto Cleanup;
|
||||
}
|
||||
if (pEntry->testType == testLen)
|
||||
szCurrent = szStart + len;
|
||||
else if (pEntry->testType == testOffs)
|
||||
szCurrent = szStart + pEntry->iOffset;
|
||||
else
|
||||
{
|
||||
szCurrent = AllocStringA(pEntry->lpszCurrent, wcslen(pEntry->lpszCurrent));
|
||||
if (!szCurrent && pEntry->lpszCurrent)
|
||||
{
|
||||
skip("[%u] AllocStringA for szCurrent failed\n", i);
|
||||
goto Cleanup;
|
||||
}
|
||||
}
|
||||
pchA = CharPrevA(szStart, szCurrent);
|
||||
pchEx = CharPrevExA(TEST_ACP, szStart, szCurrent, 0);
|
||||
if (szCurrent - szStart >= 0)
|
||||
iRealOffset = pEntry->iResOffset;
|
||||
else
|
||||
iRealOffset = pEntry->iResOffsetNeg;
|
||||
if (pEntry->bWithinStart)
|
||||
{
|
||||
b = pchA >= szStart && pchA <= szStart + len;
|
||||
if (iRealOffset >= 0)
|
||||
ok(b, "[%u] CharPrevA: pchA (0x%p) is expected to be within szStart (0x%p)\n", i, pchA, szStart);
|
||||
else
|
||||
ok(!b, "[%u] CharPrevA: pchA (0x%p) is expected to be outside szStart (0x%p)\n", i, pchA, szStart);
|
||||
ok(pchA == szStart + iRealOffset, "[%u] CharPrevA: pchA is 0x%p (offset %d)\n", i, pchA, pchA - szStart);
|
||||
}
|
||||
else
|
||||
{
|
||||
b = pchA >= szCurrent && pchA <= szCurrent + wcslen(pEntry->lpszCurrent);
|
||||
if (iRealOffset >= 0)
|
||||
ok(b, "[%u] CharPrevA: pchA (0x%p) is expected to be within szCurrent (0x%p)\n", i, pchA, szCurrent);
|
||||
else
|
||||
ok(!b, "[%u] CharPrevA: pchA (0x%p) is expected to be outside szCurrent (0x%p)\n", i, pchA, szCurrent);
|
||||
ok(pchA == szCurrent + iRealOffset, "[%u] CharPrevA: pchA is 0x%p (offset %d)\n", i, pchA, pchA - szCurrent);
|
||||
}
|
||||
ok(pchA == pchEx, "[%u] CharPrevExA: pchA (0x%p) is not equal to pchEx (0x%p)\n", i, pchA, pchEx);
|
||||
|
||||
Cleanup:
|
||||
if (pEntry->testType != testBoth)
|
||||
szCurrent = NULL;
|
||||
HeapFree(GetProcessHeap(), 0, szStart);
|
||||
HeapFree(GetProcessHeap(), 0, szCurrent);
|
||||
}
|
||||
|
||||
static void testDynCharPrev(const TESTS_CHARPREV *pEntry, UINT i)
|
||||
{
|
||||
SIZE_T len;
|
||||
|
||||
len = wcslen(pEntry->lpszStart);
|
||||
testCharPrevW(pEntry, len, i);
|
||||
|
||||
if (pEntry->bWideOnly)
|
||||
return;
|
||||
|
||||
testCharPrevA(pEntry, len, i);
|
||||
}
|
||||
|
||||
static void testStatCharPrev(const ST_TESTS_CHARPREV *pEntry, UINT i)
|
||||
{
|
||||
LPWSTR pchW;
|
||||
LPSTR pchA;
|
||||
|
||||
pchW = CharPrevW(pEntry->wszStart, pEntry->wszCurrent);
|
||||
ok(pchW == pEntry->wszResult, "[%u] CharPrevW: pchW is 0x%p (expected 0x%p)\n", i, pchW, pEntry->wszResult);
|
||||
|
||||
if (!pEntry->szStart)
|
||||
return;
|
||||
|
||||
pchA = CharPrevA(pEntry->szStart, pEntry->szCurrent);
|
||||
ok(pchA == pEntry->szResult, "[%u] CharPrevA: pchA is 0x%p (expected 0x%p)\n", i, pchA, pEntry->szResult);
|
||||
|
||||
pchA = CharPrevExA(TEST_ACP, pEntry->szStart, pEntry->szCurrent, 0);
|
||||
ok(pchA == pEntry->szResult, "[%u] CharPrevExA: pchA is 0x%p (expected 0x%p)\n", i, pchA, pEntry->szResult);
|
||||
}
|
||||
|
||||
static void testStatCodePageCharPrev(const ST_CODEPAGE_TESTS_CHARPREV *pEntry, UINT i)
|
||||
{
|
||||
LPSTR pchA;
|
||||
|
||||
pchA = CharPrevExA(pEntry->uCodePage, pEntry->szStart, pEntry->szCurrent, 0);
|
||||
ok(pchA == pEntry->szResult, "[%u] CharPrevExA(%u): pchA is 0x%p (expected 0x%p)\n", i, pEntry->uCodePage, pchA, pEntry->szResult);
|
||||
}
|
||||
|
||||
static void testStatCharNext(const ST_TESTS_CHARNEXT *pEntry, UINT i)
|
||||
{
|
||||
LPWSTR pchW;
|
||||
LPSTR pchA;
|
||||
|
||||
pchW = CharNextW(pEntry->wszString);
|
||||
ok(pchW == pEntry->wszResult, "[%u] CharNextW: pchW is 0x%p (expected 0x%p)\n", i, pchW, pEntry->wszResult);
|
||||
|
||||
if (!pEntry->szString)
|
||||
return;
|
||||
|
||||
pchA = CharNextA(pEntry->szString);
|
||||
ok(pchA == pEntry->szResult, "[%u] CharNextA: pchA is 0x%p (expected 0x%p)\n", i, pchA, pEntry->szResult);
|
||||
|
||||
pchA = CharNextExA(TEST_ACP, pEntry->szString, 0);
|
||||
ok(pchA == pEntry->szResult, "[%u] CharNextExA: pchA is 0x%p (expected 0x%p)\n", i, pchA, pEntry->szResult);
|
||||
}
|
||||
|
||||
static void testStatCodePageCharNext(const ST_CODEPAGE_TESTS_CHARNEXT *pEntry, UINT i)
|
||||
{
|
||||
LPSTR pchA;
|
||||
|
||||
pchA = CharNextExA(pEntry->uCodePage, pEntry->szString, 0);
|
||||
ok(pchA == pEntry->szResult, "[%u] CharNextExA(%u): pchA is 0x%p (expected 0x%p)\n", i, pEntry->uCodePage, pchA, pEntry->szResult);
|
||||
}
|
||||
|
||||
static void testCharPrev(void)
|
||||
{
|
||||
UINT i;
|
||||
|
||||
/* Perform dynamic allocation tests */
|
||||
for (i = 0; i < _countof(TestCharPrev); i++)
|
||||
{
|
||||
testDynCharPrev(&TestCharPrev[i], i);
|
||||
}
|
||||
|
||||
if (!IsWindowsVistaOrGreater())
|
||||
{
|
||||
for (i = 0; i < _countof(TestCharPrev_XP); i++)
|
||||
{
|
||||
testDynCharPrev(&TestCharPrev_XP[i], i);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < _countof(TestCharPrev_Vista); i++)
|
||||
{
|
||||
testDynCharPrev(&TestCharPrev_Vista[i], i);
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform static tests */
|
||||
for (i = 0; i < _countof(TestStaticCharPrev); i++)
|
||||
{
|
||||
testStatCharPrev(&TestStaticCharPrev[i], i);
|
||||
}
|
||||
|
||||
if (!IsWindowsVistaOrGreater())
|
||||
{
|
||||
for (i = 0; i < _countof(TestStaticCharPrev_XP); i++)
|
||||
{
|
||||
testStatCharPrev(&TestStaticCharPrev_XP[i], i);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < _countof(TestStaticCharPrev_Vista); i++)
|
||||
{
|
||||
testStatCharPrev(&TestStaticCharPrev_Vista[i], i);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < _countof(TestStaticCodePageCharPrev); i++)
|
||||
{
|
||||
testStatCodePageCharPrev(&TestStaticCodePageCharPrev[i], i);
|
||||
}
|
||||
|
||||
/* Perform exception tests (check corner cases) */
|
||||
if (INVALID_PTR < (PVOID)wszReactOS)
|
||||
{
|
||||
ok(FALSE, "testCharPrev: unexpected INVALID PTR < wszReactOS\n");
|
||||
return;
|
||||
}
|
||||
if (INVALID_PTR < (PVOID)szReactOS)
|
||||
{
|
||||
ok(FALSE, "testCharPrev: unexpected INVALID PTR < szReactOS\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < _countof(TestExceptionCharPrev); i++)
|
||||
{
|
||||
LPWSTR pchW;
|
||||
LPSTR pchA;
|
||||
const EX_TESTS_CHARPREV *pEntry = &TestExceptionCharPrev[i];
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
|
||||
//trace("0x%p 0x%p\n", pEntry->wszStart, pEntry->wszCurrent);
|
||||
pchW = NULL;
|
||||
_SEH2_TRY
|
||||
{
|
||||
pchW = CharPrevW(pEntry->wszStart, pEntry->wszCurrent);
|
||||
}
|
||||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
Status = _SEH2_GetExceptionCode();
|
||||
}
|
||||
_SEH2_END;
|
||||
ok(Status == pEntry->resStatus, "[%u] CharPrevW: Status is 0x%lX, expected 0x%lX\n", i, Status, pEntry->resStatus);
|
||||
ok(pchW == pEntry->wszResult, "[%u] CharPrevW: pchW is 0x%p, expected 0x%p\n", i, pchW, pEntry->wszResult);
|
||||
|
||||
//trace("0x%p 0x%p\n", pEntry->szStart, pEntry->szCurrent);
|
||||
pchA = NULL;
|
||||
_SEH2_TRY
|
||||
{
|
||||
pchA = CharPrevA(pEntry->szStart, pEntry->szCurrent);
|
||||
}
|
||||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
Status = _SEH2_GetExceptionCode();
|
||||
}
|
||||
_SEH2_END;
|
||||
ok(Status == pEntry->resStatus, "[%u] CharPrevA: Status is 0x%lX, expected 0x%lX\n", i, Status, pEntry->resStatus);
|
||||
ok(pchA == pEntry->szResult, "[%u] CharPrevA: pchA is 0x%p, expected 0x%p\n", i, pchA, pEntry->szResult);
|
||||
|
||||
pchA = NULL;
|
||||
_SEH2_TRY
|
||||
{
|
||||
pchA = CharPrevExA(TEST_ACP, pEntry->szStart, pEntry->szCurrent, 0);
|
||||
}
|
||||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
Status = _SEH2_GetExceptionCode();
|
||||
}
|
||||
_SEH2_END;
|
||||
ok(Status == pEntry->resStatus, "[%u] CharPrevExA: Status is 0x%lX, expected 0x%lX\n", i, Status, pEntry->resStatus);
|
||||
ok(pchA == pEntry->szExResult, "[%u] CharPrevExA: pchA is 0x%p, expected 0x%p\n", i, pchA, pEntry->szExResult);
|
||||
}
|
||||
}
|
||||
|
||||
static void testCharNext(void)
|
||||
{
|
||||
UINT i;
|
||||
|
||||
/* Perform static tests */
|
||||
for (i = 0; i < _countof(TestStaticCharNext); i++)
|
||||
{
|
||||
testStatCharNext(&TestStaticCharNext[i], i);
|
||||
}
|
||||
|
||||
if (!IsWindowsVistaOrGreater())
|
||||
{
|
||||
for (i = 0; i < _countof(TestStaticCharNext_XP); i++)
|
||||
{
|
||||
testStatCharNext(&TestStaticCharNext_XP[i], i);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < _countof(TestStaticCharNext_Vista); i++)
|
||||
{
|
||||
testStatCharNext(&TestStaticCharNext_Vista[i], i);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < _countof(TestStaticCodePageCharNext); i++)
|
||||
{
|
||||
testStatCodePageCharNext(&TestStaticCodePageCharNext[i], i);
|
||||
}
|
||||
|
||||
/* Perform exception tests (check corner cases) */
|
||||
if (INVALID_PTR < (PVOID)wszReactOS)
|
||||
{
|
||||
ok(FALSE, "testCharNext: unexpected INVALID PTR < wszReactOS\n");
|
||||
return;
|
||||
}
|
||||
if (INVALID_PTR < (PVOID)szReactOS)
|
||||
{
|
||||
ok(FALSE, "testCharNext: unexpected INVALID PTR < szReactOS\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < _countof(TestExceptionCharNext); i++)
|
||||
{
|
||||
LPWSTR pchW;
|
||||
LPSTR pchA;
|
||||
const EX_TESTS_CHARNEXT *pEntry = &TestExceptionCharNext[i];
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
|
||||
//trace("0x%p\n", pEntry->wszString);
|
||||
pchW = NULL;
|
||||
_SEH2_TRY
|
||||
{
|
||||
pchW = CharNextW(pEntry->wszString);
|
||||
}
|
||||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
Status = _SEH2_GetExceptionCode();
|
||||
}
|
||||
_SEH2_END;
|
||||
ok(Status == pEntry->resStatus, "[%u] CharNextW: Status is 0x%lX, expected 0x%lX\n", i, Status, pEntry->resStatus);
|
||||
ok(pchW == pEntry->wszResult, "[%u] CharNextW: pchW is 0x%p, expected 0x%p\n", i, pchW, pEntry->wszResult);
|
||||
|
||||
//trace("0x%p 0x%p\n", pEntry->szString);
|
||||
pchA = NULL;
|
||||
_SEH2_TRY
|
||||
{
|
||||
pchA = CharNextA(pEntry->szString);
|
||||
}
|
||||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
Status = _SEH2_GetExceptionCode();
|
||||
}
|
||||
_SEH2_END;
|
||||
ok(Status == pEntry->resStatus, "[%u] CharNextA: Status is 0x%lX, expected 0x%lX\n", i, Status, pEntry->resStatus);
|
||||
ok(pchA == pEntry->szResult, "[%u] CharNextA: pchA is 0x%p, expected 0x%p\n", i, pchA, pEntry->szResult);
|
||||
|
||||
pchA = NULL;
|
||||
_SEH2_TRY
|
||||
{
|
||||
pchA = CharNextExA(TEST_ACP, pEntry->szString, 0);
|
||||
}
|
||||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
Status = _SEH2_GetExceptionCode();
|
||||
}
|
||||
_SEH2_END;
|
||||
ok(Status == pEntry->resStatus, "[%u] CharNextExA: Status is 0x%lX, expected 0x%lX\n", i, Status, pEntry->resStatus);
|
||||
ok(pchA == pEntry->szResult, "[%u] CharNextExA: pchA is 0x%p, expected 0x%p\n", i, pchA, pEntry->szResult);
|
||||
}
|
||||
}
|
||||
|
||||
START_TEST(CharFuncs)
|
||||
{
|
||||
testCharPrev();
|
||||
testCharNext();
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
#include <apitest.h>
|
||||
|
||||
extern void func_AttachThreadInput(void);
|
||||
extern void func_CharFuncs(void);
|
||||
extern void func_CloseWindow(void);
|
||||
extern void func_CreateDialog(void);
|
||||
extern void func_CreateIconFromResourceEx(void);
|
||||
|
@ -58,6 +59,7 @@ extern void func_wsprintf(void);
|
|||
const struct test winetest_testlist[] =
|
||||
{
|
||||
{ "AttachThreadInput", func_AttachThreadInput },
|
||||
{ "CharFuncs", func_CharFuncs },
|
||||
{ "CloseWindow", func_CloseWindow },
|
||||
{ "CreateDialog", func_CreateDialog },
|
||||
{ "CreateIconFromResourceEx", func_CreateIconFromResourceEx },
|
||||
|
|
Loading…
Reference in a new issue