From 126af8653e403219f015211aa4dcba8be82b69f8 Mon Sep 17 00:00:00 2001 From: Felix Nawothnig Date: Sun, 3 Jul 2005 12:02:09 +0000 Subject: [PATCH] Rewrote the DPA testsuite. --- dlls/comctl32/tests/Makefile.in | 2 +- dlls/comctl32/tests/dpa.c | 512 +++++++++++++++++++++++++++++++++------- 2 files changed, 432 insertions(+), 82 deletions(-) rewrite dlls/comctl32/tests/dpa.c (63%) diff --git a/dlls/comctl32/tests/Makefile.in b/dlls/comctl32/tests/Makefile.in index 14ed981369e..cd4e90fd3df 100644 --- a/dlls/comctl32/tests/Makefile.in +++ b/dlls/comctl32/tests/Makefile.in @@ -3,7 +3,7 @@ TOPOBJDIR = ../../.. SRCDIR = @srcdir@ VPATH = @srcdir@ TESTDLL = comctl32.dll -IMPORTS = comctl32 shlwapi user32 gdi32 advapi32 +IMPORTS = comctl32 ole32 shlwapi user32 gdi32 advapi32 CTESTS = \ dpa.c \ diff --git a/dlls/comctl32/tests/dpa.c b/dlls/comctl32/tests/dpa.c dissimilarity index 63% index ca93a91855f..cead66506ee 100644 --- a/dlls/comctl32/tests/dpa.c +++ b/dlls/comctl32/tests/dpa.c @@ -1,81 +1,431 @@ -/* - * Unit tests for DPA functions - * - * Copyright 2003 Uwe Bonnes - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include - -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "commctrl.h" - -#include "wine/test.h" - -static HDPA (WINAPI *pDPA_Create)(int); -static BOOL (WINAPI *pDPA_Grow)(const HDPA hdpa, INT nGrow); -static BOOL (WINAPI *pDPA_Destroy)(const HDPA hdpa); -static INT (WINAPI *pDPA_Search)(HDPA, LPVOID, INT, PFNDPACOMPARE, LPARAM, UINT); -static BOOL (WINAPI *pDPA_SetPtr)(const HDPA hdpa, INT i, LPVOID p); - -static INT CALLBACK dpa_strcmp(LPVOID pvstr1, LPVOID pvstr2, LPARAM flags) -{ - LPCSTR str1 = (LPCSTR)pvstr1; - LPCSTR str2 = (LPCSTR)pvstr2; - - return lstrcmpA (str1, str2); -} - -static void DPA_test(void) -{ - HDPA dpa_ret; - INT int_ret; - CHAR test_str0[]="test0"; - - if (!pDPA_Create) - return; - - dpa_ret = pDPA_Create(0); - ok((dpa_ret !=0), "DPA_Create failed\n"); - int_ret = pDPA_Search(dpa_ret,test_str0,0, dpa_strcmp,0, DPAS_SORTED); - ok((int_ret == -1), "DPA_Search found invalid item\n"); - int_ret = pDPA_Search(dpa_ret,test_str0,0, dpa_strcmp,0, DPAS_SORTED|DPAS_INSERTBEFORE); - ok((int_ret == 0), "DPA_Search proposed bad item\n"); - int_ret = pDPA_Search(dpa_ret,test_str0,0, dpa_strcmp,0, DPAS_SORTED|DPAS_INSERTAFTER); - ok((int_ret == 0), "DPA_Search proposed bad item\n"); - int_ret = pDPA_Grow(dpa_ret,0); - ok(int_ret != 0, "DPA_Grow failed\n"); - int_ret = pDPA_SetPtr(dpa_ret, 0, (void*)0xdeadbeef); - ok(int_ret != 0, "DPA_SetPtr failed\n"); - int_ret = pDPA_Destroy(dpa_ret); - ok(int_ret != 0, "DPA_Destory failed\n"); -} - -START_TEST(dpa) -{ - HMODULE hdll; - - hdll=GetModuleHandleA("comctl32.dll"); - pDPA_Create=(void*)GetProcAddress(hdll,(LPCSTR)328); - pDPA_Destroy=(void*)GetProcAddress(hdll,(LPCSTR)329); - pDPA_Grow=(void*)GetProcAddress(hdll,(LPCSTR)330); - pDPA_Search=(void*)GetProcAddress(hdll,(LPCSTR)339); - pDPA_SetPtr=(void*)GetProcAddress(hdll,(LPCSTR)335); - - DPA_test(); -} +/* + * Unit tests for DPA functions + * + * Copyright 2003 Uwe Bonnes + * Copyright 2005 Felix Nawothnig + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define COBJMACROS + +#include + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "commctrl.h" +#include "objidl.h" + +#include "wine/test.h" + +#define DPAM_NOSORT 0x1 +#define DPAM_INSERT 0x4 +#define DPAM_DELETE 0x8 + +typedef struct _ITEMDATA +{ + INT iPos; + PVOID pvData; +} ITEMDATA, *LPITEMDATA; + +typedef PVOID (CALLBACK *PFNDPAMERGE)(UINT,PVOID,PVOID,LPARAM); +typedef HRESULT (CALLBACK *PFNDPASTM)(LPITEMDATA,IStream*,LPARAM); + +static HDPA (WINAPI *pDPA_Clone)(const HDPA,const HDPA); +static HDPA (WINAPI *pDPA_Create)(INT); +static HDPA (WINAPI *pDPA_CreateEx)(INT,HANDLE); +static PVOID (WINAPI *pDPA_DeleteAllPtrs)(const HDPA); +static PVOID (WINAPI *pDPA_DeletePtr)(const HDPA,INT); +static BOOL (WINAPI *pDPA_Destroy)(const HDPA); +static VOID (WINAPI *pDPA_DestroyCallback)(HDPA,PFNDPAENUMCALLBACK,PVOID); +static VOID (WINAPI *pDPA_EnumCallback)(HDPA,PFNDPAENUMCALLBACK,PVOID); +static INT (WINAPI *pDPA_GetPtr)(const HDPA,INT); +static INT (WINAPI *pDPA_GetPtrIndex)(const HDPA,PVOID); +static BOOL (WINAPI *pDPA_Grow)(HDPA,INT); +static INT (WINAPI *pDPA_InsertPtr)(const HDPA,INT,PVOID); +static HRESULT (WINAPI *pDPA_LoadStream)(HDPA*,PFNDPASTM,IStream*,LPARAM); +static BOOL (WINAPI *pDPA_Merge)(const HDPA,const HDPA,DWORD,PFNDPACOMPARE,PFNDPAMERGE,LPARAM); +static HRESULT (WINAPI *pDPA_SaveStream)(HDPA,PFNDPASTM,IStream*,LPARAM); +static INT (WINAPI *pDPA_Search)(HDPA,PVOID,INT,PFNDPACOMPARE,LPARAM,UINT); +static BOOL (WINAPI *pDPA_SetPtr)(const HDPA,INT,PVOID); +static BOOL (WINAPI *pDPA_Sort)(const HDPA,PFNDPACOMPARE,LPARAM); + +#define COMCTL32_GET_PROC(func, ord) \ + ((p ## func = (PVOID)GetProcAddress(hcomctl32,(LPCSTR)ord)) ? 1 \ + : (trace( #func " not exported\n"), 0)) + +static BOOL InitFunctionPtrs(HMODULE hcomctl32) +{ + /* 4.00+ */ + if(COMCTL32_GET_PROC(DPA_Clone, 331) && + COMCTL32_GET_PROC(DPA_Create, 328) && + COMCTL32_GET_PROC(DPA_CreateEx, 340) && + COMCTL32_GET_PROC(DPA_DeleteAllPtrs, 337) && + COMCTL32_GET_PROC(DPA_DeletePtr, 336) && + COMCTL32_GET_PROC(DPA_Destroy, 329) && + COMCTL32_GET_PROC(DPA_GetPtr, 332) && + COMCTL32_GET_PROC(DPA_GetPtrIndex, 333) && + COMCTL32_GET_PROC(DPA_Grow, 330) && + COMCTL32_GET_PROC(DPA_InsertPtr, 334) && + COMCTL32_GET_PROC(DPA_Search, 339) && + COMCTL32_GET_PROC(DPA_SetPtr, 335) && + COMCTL32_GET_PROC(DPA_Sort, 338)) + { + /* 4.71+ */ + COMCTL32_GET_PROC(DPA_DestroyCallback, 386) && + COMCTL32_GET_PROC(DPA_EnumCallback, 385) && + COMCTL32_GET_PROC(DPA_LoadStream, 9); + COMCTL32_GET_PROC(DPA_Merge, 11); + COMCTL32_GET_PROC(DPA_SaveStream, 10); + + return TRUE; + } + + return FALSE; +} + +/* Callbacks */ +static INT CALLBACK CB_CmpLT(PVOID p1, PVOID p2, LPARAM lp) +{ + ok(lp == 0xdeadbeef, "lp=%ld\n", lp); + return p1 < p2 ? -1 : p1 > p2 ? 1 : 0; +} + +static INT CALLBACK CB_CmpGT(PVOID p1, PVOID p2, LPARAM lp) +{ + ok(lp == 0xdeadbeef, "lp=%ld\n", lp); + return p1 > p2 ? -1 : p1 < p2 ? 1 : 0; +} + +static PVOID CALLBACK CB_MergeInsertSrc(UINT op, PVOID p1, PVOID p2, LPARAM lp) +{ + ok(lp == 0xdeadbeef, "lp=%ld\n", lp); + return p1; +} + +static PVOID CALLBACK CB_MergeDeleteOddSrc(UINT op, PVOID p1, PVOID p2, LPARAM lp) +{ + ok(lp == 0xdeadbeef, "lp=%ld\n", lp); + return ((PCHAR)p2)+1; +} + +static INT nEnum; + +static INT CALLBACK CB_EnumFirstThree(PVOID pItem, PVOID lp) +{ + INT i; + + i = pDPA_GetPtrIndex(lp, pItem); + ok(i == nEnum, "i=%d nEnum=%d\n", i, nEnum); + nEnum++; + pDPA_SetPtr(lp, i, (PVOID)7); + return pItem != (PVOID)3; +} + +static HRESULT CALLBACK CB_Save(LPITEMDATA pInfo, IStream *pStm, LPARAM lp) +{ + HRESULT hRes; + + ok(lp == 0xdeadbeef, "lp=%ld\n", lp); + hRes = IStream_Write(pStm, &pInfo->iPos, sizeof(INT), NULL); + ok(hRes == S_OK, "hRes=0x%lx\n", hRes); + hRes = IStream_Write(pStm, &pInfo->pvData, sizeof(PVOID), NULL); + ok(hRes == S_OK, "hRes=0x%lx\n", hRes); + return S_OK; +} + +static HRESULT CALLBACK CB_Load(LPITEMDATA pInfo, IStream *pStm, LPARAM lp) +{ + HRESULT hRes; + INT iOldPos; + + iOldPos = pInfo->iPos; + ok(lp == 0xdeadbeef, "lp=%ld\n", lp); + hRes = IStream_Read(pStm, &pInfo->iPos, sizeof(INT), NULL); + ok(hRes == S_OK, "hRes=0x%lx\n", hRes); + ok(pInfo->iPos == iOldPos, "iPos=%d iOldPos=%d\n", pInfo->iPos, iOldPos); + hRes = IStream_Read(pStm, &pInfo->pvData, sizeof(PVOID), NULL); + ok(hRes == S_OK, "hRes=0x%lx\n", hRes); + return S_OK; +} + +static BOOL CheckDPA(HDPA dpa, DWORD dwIn, PDWORD pdwOut) +{ + DWORD dwOut = 0; + INT i; + + for(i = 0; i < 8;) + { + ULONG_PTR ulItem = (ULONG_PTR)pDPA_GetPtr(dpa, i++); + if(!ulItem) break; + dwOut = dwOut << 4 | (ulItem & 0xf); + } + + *pdwOut = dwOut; + + if(dwOut != dwIn) + { + pDPA_DeleteAllPtrs(dpa); + + do + { + pDPA_InsertPtr(dpa, 0, (PVOID)(dwIn & 0xf)); + dwIn >>= 4; + } + while(dwIn); + + return FALSE; + } + + return TRUE; +} + +static void test_dpa(void) +{ + SYSTEM_INFO si; + HANDLE hHeap; + HDPA dpa, dpa2, dpa3; + INT ret, i; + PVOID p; + DWORD dw, dw2, dw3; + HRESULT hRes; + + GetSystemInfo(&si); + hHeap = HeapCreate(0, 1, 2); + ok(hHeap != NULL, "error=%ld\n", GetLastError()); + dpa3 = pDPA_CreateEx(0, hHeap); + ok(dpa3 != NULL, "\n"); + ret = pDPA_Grow(dpa3, si.dwPageSize + 1); + todo_wine ok(!ret && GetLastError() == ERROR_NOT_ENOUGH_MEMORY, + "ret=%d error=%ld\n", ret, GetLastError()); + + dpa = pDPA_Create(0); + ok(dpa != NULL, "\n"); + + /* Set item with out of bound index */ + ok(pDPA_SetPtr(dpa, 1, (PVOID)6), "\n"); + /* Fill the greated gap */ + ok(pDPA_SetPtr(dpa, 0, (PVOID)5), "\n"); + ok(CheckDPA(dpa, 0x56, &dw), "dw=0x%lx\n", dw); + + /* Prepend item */ + ret = pDPA_InsertPtr(dpa, 1, (PVOID)1); + ok(ret == 1, "ret=%d\n", ret); + /* Append item using correct index */ + ret = pDPA_InsertPtr(dpa, 3, (PVOID)3); + ok(ret == 3, "ret=%d\n", ret); + /* Append item using out of bound index */ + ret = pDPA_InsertPtr(dpa, 5, (PVOID)2); + todo_wine ok(ret == 4, "ret=%d\n", ret); + /* Append item using DPA_APPEND */ + ret = pDPA_InsertPtr(dpa, DPA_APPEND, (PVOID)4); + todo_wine ok(ret == 5, "ret=%d\n", ret); + + todo_wine ok(CheckDPA(dpa, 0x516324, &dw), "dw=0x%lx\n", dw); + + for(i = 1; i <= 6; i++) + { + INT j, k; + k = pDPA_GetPtrIndex(dpa, (PVOID)i); + /* Linear searches should work on unsorted DPAs */ + j = pDPA_Search(dpa, (PVOID)i, 0, CB_CmpLT, 0xdeadbeef, 0); + ok(j == k, "j=%d k=%d\n", j, k); + } + + /* Sort DPA */ + ok(pDPA_Sort(dpa, CB_CmpGT, 0xdeadbeef), "\n"); + ok(CheckDPA(dpa, 0x654321, &dw), "dw=0x%lx\n", dw); + + /* Clone into a new DPA */ + dpa2 = pDPA_Clone(dpa, NULL); + ok(dpa2 != NULL, "\n"); + /* The old data should have been preserved */ + ok(CheckDPA(dpa2, 0x654321, &dw2), "dw=0x%lx\n", dw2); + ok(pDPA_Sort(dpa, CB_CmpLT, 0xdeadbeef), "\n"); + + /* Test if the DPA itself was really copied */ + ok(CheckDPA(dpa, 0x123456, &dw), "dw=0x%lx\n", dw ); + ok(CheckDPA(dpa2, 0x654321, &dw2), "dw2=0x%lx\n", dw2); + + /* Clone into an old DPA */ + p = NULL; SetLastError(ERROR_SUCCESS); + p = pDPA_Clone(dpa, dpa3); + ok(p == dpa3, "p=%p\n", p); + ok(CheckDPA(dpa3, 0x123456, &dw3), "dw3=0x%lx\n", dw3); + + for(i = 1; i <= 6; i++) + { + INT j; + + /* The array is in order so ptr == index+1 */ + j = pDPA_GetPtrIndex(dpa, (PVOID)i); + ok(j+1 == i, "j=%d i=%d\n", j, i); + j = pDPA_Search(dpa, (PVOID)i, 0, CB_CmpLT, 0xdeadbeef, DPAS_SORTED); + if(i > 1) todo_wine ok(j+1 == i, "j=%d i=%d\n", j, i); + + /* Linear searches respect iStart ... */ + j = pDPA_Search(dpa, (PVOID)i, i+1, CB_CmpLT, 0xdeadbeef, 0); + ok(j == DPA_ERR, "j=%d\n", j); + /* ... but for a binary search it's ignored */ + j = pDPA_Search(dpa, (PVOID)i, i+1, CB_CmpLT, 0xdeadbeef, DPAS_SORTED); + todo_wine ok(j+1 == i, "j=%d i=%d\n", j, i); + } + + /* Try to get the index of a non-existent item */ + i = pDPA_GetPtrIndex(dpa, (PVOID)7); + ok(i == DPA_ERR, "i=%d\n", i); + + /* Try to delete out of bound indexes */ + p = pDPA_DeletePtr(dpa, -1); + ok(p == NULL, "p=%p\n", p); + p = pDPA_DeletePtr(dpa, 6); + ok(p == NULL, "p=%p\n", p); + + /* Delete the third item */ + p = pDPA_DeletePtr(dpa, 2); + ok(p == (PVOID)3, "p=%p\n", p); + ok(CheckDPA(dpa, 0x12456, &dw), "dw=0x%lx\n", dw); + + /* Check where to re-insert the deleted item */ + i = pDPA_Search(dpa, (PVOID)3, 0, + CB_CmpLT, 0xdeadbeef, DPAS_SORTED|DPAS_INSERTAFTER); + ok(i == 2, "i=%d\n", i); + /* DPAS_INSERTBEFORE works just like DPAS_INSERTAFTER */ + i = pDPA_Search(dpa, (PVOID)3, 0, + CB_CmpLT, 0xdeadbeef, DPAS_SORTED|DPAS_INSERTBEFORE); + todo_wine ok(i == 2, "i=%d\n", i); + + /* Re-insert the item */ + ret = pDPA_InsertPtr(dpa, 2, (PVOID)3); + ok(ret == 2, "ret=%d i=%d\n", ret, 2); + ok(CheckDPA(dpa, 0x123456, &dw), "dw=0x%lx\n", dw); + + /* When doing a binary search while claiming reverse order all indexes + * should be bogus */ + for(i = 0; i < 6; i++) + { + INT j = pDPA_Search(dpa, (PVOID)i, 0, CB_CmpGT, 0xdeadbeef, + DPAS_SORTED|DPAS_INSERTBEFORE); + ok(j != i, "i=%d\n", i); + } + + if(pDPA_Merge) + { + /* Delete all even entries from dpa */ + p = pDPA_DeletePtr(dpa, 1); + p = pDPA_DeletePtr(dpa, 2); + p = pDPA_DeletePtr(dpa, 3); + ok(CheckDPA(dpa, 0x135, &dw), "dw=0x%lx\n", dw); + + /* Delete all odd entries from dpa2 */ + pDPA_Merge(dpa2, dpa, DPAM_DELETE, + CB_CmpLT, CB_MergeDeleteOddSrc, 0xdeadbeef); + todo_wine ok(CheckDPA(dpa2, 0x246, &dw2), "dw=0x%lx\n", dw2); + + /* Merge dpa3 into dpa2 and dpa */ + pDPA_Merge(dpa, dpa3, DPAM_INSERT|DPAM_NOSORT, + CB_CmpLT, CB_MergeInsertSrc, 0xdeadbeef); + pDPA_Merge(dpa2, dpa3, DPAM_INSERT|DPAM_NOSORT, + CB_CmpLT, CB_MergeInsertSrc, 0xdeadbeef); + + ok(CheckDPA(dpa, 0x123456, &dw ), "dw=0x%lx\n", dw); + ok(CheckDPA(dpa2, 0x123456, &dw2), "dw2=0x%lx\n", dw2); + ok(CheckDPA(dpa3, 0x123456, &dw3), "dw3=0x%lx\n", dw3); + } + + if(pDPA_EnumCallback) + { + nEnum = 0; + pDPA_EnumCallback(dpa2, CB_EnumFirstThree, (PVOID)dpa2); + ok(CheckDPA(dpa2, 0x777456, &dw2), "dw=0x%lx\n", dw2); + ok(nEnum == 3, "nEnum=%d\n", nEnum); + } + pDPA_DeleteAllPtrs(dpa2); + ok(CheckDPA(dpa2, 0, &dw2), "dw2=0x%lx\n", dw2); + pDPA_Destroy(dpa2); + + if(pDPA_DestroyCallback) + { + nEnum = 0; + pDPA_DestroyCallback(dpa3, CB_EnumFirstThree, dpa3); + ok(nEnum == 3, "nEnum=%d\n", nEnum); + } + else pDPA_Destroy(dpa3); + + if(!pDPA_SaveStream) + goto skip_stream_tests; + + hRes = CoInitialize(NULL); + if(hRes == S_OK) + { + static const WCHAR szStg[] = { 'S','t','g',0 }; + IStorage* pStg = NULL; + IStream* pStm = NULL; + LARGE_INTEGER liZero; + DWORD dwMode; + liZero.QuadPart = 0; + + dwMode = STGM_DIRECT|STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE; + hRes = StgCreateDocfile(NULL, dwMode|STGM_DELETEONRELEASE, 0, &pStg); + ok(hRes == S_OK, "hRes=0x%lx\n", hRes); + + hRes = IStorage_CreateStream(pStg, szStg, dwMode, 0, 0, &pStm); + ok(hRes == S_OK, "hRes=0x%lx\n", hRes); + + hRes = pDPA_SaveStream(dpa, CB_Save, pStm, 0xdeadbeef); + todo_wine ok(hRes == S_OK, "hRes=0x%lx\n", hRes); + pDPA_Destroy(dpa); + + hRes = IStream_Seek(pStm, liZero, STREAM_SEEK_SET, NULL); + ok(hRes == S_OK, "hRes=0x%lx\n", hRes); + hRes = pDPA_LoadStream(&dpa, CB_Load, pStm, 0xdeadbeef); + todo_wine ok(hRes == S_OK, "hRes=0x%lx\n", hRes); + todo_wine ok(CheckDPA(dpa, 0x123456, &dw), "dw=0x%lx\n", dw); + pDPA_Destroy(dpa); + + ret = IStream_Release(pStm); + ok(!ret, "ret=%d\n", ret); + + ret = IStorage_Release(pStg); + ok(!ret, "ret=%d\n", ret); + + CoUninitialize(); + } + else ok(0, "hResult: %ld\n", hRes); + +skip_stream_tests: + pDPA_Destroy(dpa); +} + +START_TEST(dpa) +{ + HMODULE hcomctl32; + + hcomctl32 = GetModuleHandleA("comctl32.dll"); + + if(!hcomctl32) + { + ok(0, "error=%ld\n", GetLastError()); + return; + } + + if(InitFunctionPtrs(hcomctl32)) + test_dpa(); + else + trace("skipping tests\n"); + + FreeLibrary(hcomctl32); +} -- 2.11.4.GIT