2 * Unit tests for DPA functions
4 * Copyright 2003 Uwe Bonnes
5 * Copyright 2005 Felix Nawothnig
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
32 #include "wine/test.h"
34 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
36 static HDPA (WINAPI *pDPA_Clone)(const HDPA,const HDPA);
37 static HDPA (WINAPI *pDPA_Create)(INT);
38 static HDPA (WINAPI *pDPA_CreateEx)(INT,HANDLE);
39 static PVOID (WINAPI *pDPA_DeleteAllPtrs)(const HDPA);
40 static PVOID (WINAPI *pDPA_DeletePtr)(const HDPA,INT);
41 static BOOL (WINAPI *pDPA_Destroy)(const HDPA);
42 static VOID (WINAPI *pDPA_DestroyCallback)(HDPA,PFNDPAENUMCALLBACK,PVOID);
43 static VOID (WINAPI *pDPA_EnumCallback)(HDPA,PFNDPAENUMCALLBACK,PVOID);
44 static INT (WINAPI *pDPA_GetPtr)(const HDPA,INT);
45 static INT (WINAPI *pDPA_GetPtrIndex)(const HDPA,PVOID);
46 static BOOL (WINAPI *pDPA_Grow)(HDPA,INT);
47 static INT (WINAPI *pDPA_InsertPtr)(const HDPA,INT,PVOID);
48 static HRESULT (WINAPI *pDPA_LoadStream)(HDPA*,PFNDPASTREAM,IStream*,LPARAM);
49 static BOOL (WINAPI *pDPA_Merge)(const HDPA,const HDPA,DWORD,PFNDPACOMPARE,PFNDPAMERGE,LPARAM);
50 static HRESULT (WINAPI *pDPA_SaveStream)(HDPA,PFNDPASTREAM,IStream*,LPARAM);
51 static INT (WINAPI *pDPA_Search)(HDPA,PVOID,INT,PFNDPACOMPARE,LPARAM,UINT);
52 static BOOL (WINAPI *pDPA_SetPtr)(const HDPA,INT,PVOID);
53 static BOOL (WINAPI *pDPA_Sort)(const HDPA,PFNDPACOMPARE,LPARAM);
55 #define COMCTL32_GET_PROC(func, ord) \
56 ((p ## func = (PVOID)GetProcAddress(hcomctl32,(LPCSTR)ord)) ? 1 \
57 : (trace( #func " not exported\n"), 0))
59 static BOOL InitFunctionPtrs(HMODULE hcomctl32)
62 if(COMCTL32_GET_PROC(DPA_Clone, 331) &&
63 COMCTL32_GET_PROC(DPA_Create, 328) &&
64 COMCTL32_GET_PROC(DPA_CreateEx, 340) &&
65 COMCTL32_GET_PROC(DPA_DeleteAllPtrs, 337) &&
66 COMCTL32_GET_PROC(DPA_DeletePtr, 336) &&
67 COMCTL32_GET_PROC(DPA_Destroy, 329) &&
68 COMCTL32_GET_PROC(DPA_GetPtr, 332) &&
69 COMCTL32_GET_PROC(DPA_GetPtrIndex, 333) &&
70 COMCTL32_GET_PROC(DPA_Grow, 330) &&
71 COMCTL32_GET_PROC(DPA_InsertPtr, 334) &&
72 COMCTL32_GET_PROC(DPA_Search, 339) &&
73 COMCTL32_GET_PROC(DPA_SetPtr, 335) &&
74 COMCTL32_GET_PROC(DPA_Sort, 338))
77 COMCTL32_GET_PROC(DPA_DestroyCallback, 386) &&
78 COMCTL32_GET_PROC(DPA_EnumCallback, 385) &&
79 COMCTL32_GET_PROC(DPA_LoadStream, 9) &&
80 COMCTL32_GET_PROC(DPA_Merge, 11) &&
81 COMCTL32_GET_PROC(DPA_SaveStream, 10);
90 static INT CALLBACK CB_CmpLT(PVOID p1, PVOID p2, LPARAM lp)
92 ok(lp == 0xdeadbeef, "lp=%ld\n", lp);
93 return p1 < p2 ? -1 : p1 > p2 ? 1 : 0;
96 static INT CALLBACK CB_CmpGT(PVOID p1, PVOID p2, LPARAM lp)
98 ok(lp == 0xdeadbeef, "lp=%ld\n", lp);
99 return p1 > p2 ? -1 : p1 < p2 ? 1 : 0;
102 /* merge callback messages counter
106 static INT nMessages[4];
108 static PVOID CALLBACK CB_MergeInsertSrc(UINT op, PVOID p1, PVOID p2, LPARAM lp)
111 ok(lp == 0xdeadbeef, "lp=%ld\n", lp);
115 static PVOID CALLBACK CB_MergeDeleteOddSrc(UINT op, PVOID p1, PVOID p2, LPARAM lp)
118 ok(lp == 0xdeadbeef, "lp=%ld\n", lp);
119 return ((PCHAR)p2)+1;
124 static INT CALLBACK CB_EnumFirstThree(PVOID pItem, PVOID lp)
128 i = pDPA_GetPtrIndex(lp, pItem);
129 ok(i == nEnum, "i=%d nEnum=%d\n", i, nEnum);
131 pDPA_SetPtr(lp, i, (PVOID)7);
132 return pItem != (PVOID)3;
135 static HRESULT CALLBACK CB_Save(DPASTREAMINFO *pInfo, IStream *pStm, LPVOID lp)
139 ok(lp == (LPVOID)0xdeadbeef, "lp=%p\n", lp);
140 hRes = IStream_Write(pStm, &pInfo->iPos, sizeof(INT), NULL);
141 ok(hRes == S_OK, "hRes=0x%x\n", hRes);
142 hRes = IStream_Write(pStm, &pInfo->pvItem, sizeof(PVOID), NULL);
143 ok(hRes == S_OK, "hRes=0x%x\n", hRes);
147 static HRESULT CALLBACK CB_Load(DPASTREAMINFO *pInfo, IStream *pStm, LPVOID lp)
152 iOldPos = pInfo->iPos;
153 ok(lp == (LPVOID)0xdeadbeef, "lp=%p\n", lp);
154 hRes = IStream_Read(pStm, &pInfo->iPos, sizeof(INT), NULL);
155 ok(hRes == S_OK, "hRes=0x%x\n", hRes);
156 ok(pInfo->iPos == iOldPos, "iPos=%d iOldPos=%d\n", pInfo->iPos, iOldPos);
157 hRes = IStream_Read(pStm, &pInfo->pvItem, sizeof(PVOID), NULL);
158 ok(hRes == S_OK, "hRes=0x%x\n", hRes);
162 static BOOL CheckDPA(HDPA dpa, DWORD dwIn, PDWORD pdwOut)
169 ULONG_PTR ulItem = (ULONG_PTR)pDPA_GetPtr(dpa, i++);
171 dwOut = dwOut << 4 | (ulItem & 0xf);
178 pDPA_DeleteAllPtrs(dpa);
182 pDPA_InsertPtr(dpa, 0, (PVOID)(ULONG_PTR)(dwIn & 0xf));
193 static void test_dpa(void)
197 HDPA dpa, dpa2, dpa3;
204 hHeap = HeapCreate(0, 1, 2);
205 ok(hHeap != NULL, "error=%d\n", GetLastError());
206 dpa3 = pDPA_CreateEx(0, hHeap);
207 ok(dpa3 != NULL, "\n");
208 ret = pDPA_Grow(dpa3, si.dwPageSize + 1);
209 todo_wine ok(!ret && GetLastError() == ERROR_NOT_ENOUGH_MEMORY,
210 "ret=%d error=%d\n", ret, GetLastError());
212 dpa = pDPA_Create(0);
213 ok(dpa != NULL, "\n");
215 /* Set item with out of bound index */
216 ok(pDPA_SetPtr(dpa, 1, (PVOID)6), "\n");
217 /* Fill the created gap */
218 ok(pDPA_SetPtr(dpa, 0, (PVOID)5), "\n");
219 rc=CheckDPA(dpa, 0x56, &dw);
220 ok(rc, "dw=0x%x\n", dw);
223 ret = pDPA_InsertPtr(dpa, 1, (PVOID)1);
224 ok(ret == 1, "ret=%d\n", ret);
225 /* Append item using correct index */
226 ret = pDPA_InsertPtr(dpa, 3, (PVOID)3);
227 ok(ret == 3, "ret=%d\n", ret);
228 /* Append item using out of bound index */
229 ret = pDPA_InsertPtr(dpa, 5, (PVOID)2);
230 ok(ret == 4, "ret=%d\n", ret);
231 /* Append item using DPA_APPEND */
232 ret = pDPA_InsertPtr(dpa, DPA_APPEND, (PVOID)4);
233 ok(ret == 5, "ret=%d\n", ret);
235 rc=CheckDPA(dpa, 0x516324, &dw);
236 ok(rc, "dw=0x%x\n", dw);
238 for(i = 1; i <= 6; i++)
241 k = pDPA_GetPtrIndex(dpa, (PVOID)(INT_PTR)i);
242 /* Linear searches should work on unsorted DPAs */
243 j = pDPA_Search(dpa, (PVOID)(INT_PTR)i, 0, CB_CmpLT, 0xdeadbeef, 0);
244 ok(j == k, "j=%d k=%d\n", j, k);
248 ok(pDPA_Sort(dpa, CB_CmpGT, 0xdeadbeef), "\n");
249 rc=CheckDPA(dpa, 0x654321, &dw);
250 ok(rc, "dw=0x%x\n", dw);
252 /* Clone into a new DPA */
253 dpa2 = pDPA_Clone(dpa, NULL);
254 ok(dpa2 != NULL, "\n");
255 /* The old data should have been preserved */
256 rc=CheckDPA(dpa2, 0x654321, &dw2);
257 ok(rc, "dw=0x%x\n", dw2);
258 ok(pDPA_Sort(dpa, CB_CmpLT, 0xdeadbeef), "\n");
260 /* Test if the DPA itself was really copied */
261 rc=CheckDPA(dpa, 0x123456, &dw);
262 ok(rc, "dw=0x%x\n", dw );
263 rc=CheckDPA(dpa2, 0x654321, &dw2);
264 ok(rc, "dw2=0x%x\n", dw2);
266 /* Clone into an old DPA */
267 p = NULL; SetLastError(ERROR_SUCCESS);
268 p = pDPA_Clone(dpa, dpa3);
269 ok(p == dpa3, "p=%p\n", p);
270 rc=CheckDPA(dpa3, 0x123456, &dw3);
271 ok(rc, "dw3=0x%x\n", dw3);
273 for(i = 1; i <= 6; i++)
277 /* The array is in order so ptr == index+1 */
278 j = pDPA_GetPtrIndex(dpa, (PVOID)(INT_PTR)i);
279 ok(j+1 == i, "j=%d i=%d\n", j, i);
280 j = pDPA_Search(dpa, (PVOID)(INT_PTR)i, 0, CB_CmpLT, 0xdeadbeef, DPAS_SORTED);
281 ok(j+1 == i, "j=%d i=%d\n", j, i);
283 /* Linear searches respect iStart ... */
284 j = pDPA_Search(dpa, (PVOID)(INT_PTR)i, i+1, CB_CmpLT, 0xdeadbeef, 0);
285 ok(j == DPA_ERR, "j=%d\n", j);
286 /* ... but for a binary search it's ignored */
287 j = pDPA_Search(dpa, (PVOID)(INT_PTR)i, i+1, CB_CmpLT, 0xdeadbeef, DPAS_SORTED);
288 ok(j+1 == i, "j=%d i=%d\n", j, i);
291 /* Try to get the index of a nonexistent item */
292 i = pDPA_GetPtrIndex(dpa, (PVOID)7);
293 ok(i == DPA_ERR, "i=%d\n", i);
295 /* Try to delete out of bound indexes */
296 p = pDPA_DeletePtr(dpa, -1);
297 ok(p == NULL, "p=%p\n", p);
298 p = pDPA_DeletePtr(dpa, 6);
299 ok(p == NULL, "p=%p\n", p);
301 /* Delete the third item */
302 p = pDPA_DeletePtr(dpa, 2);
303 ok(p == (PVOID)3, "p=%p\n", p);
304 rc=CheckDPA(dpa, 0x12456, &dw);
305 ok(rc, "dw=0x%x\n", dw);
307 /* Check where to re-insert the deleted item */
308 i = pDPA_Search(dpa, (PVOID)3, 0,
309 CB_CmpLT, 0xdeadbeef, DPAS_SORTED|DPAS_INSERTAFTER);
310 ok(i == 2, "i=%d\n", i);
311 /* DPAS_INSERTBEFORE works just like DPAS_INSERTAFTER */
312 i = pDPA_Search(dpa, (PVOID)3, 0,
313 CB_CmpLT, 0xdeadbeef, DPAS_SORTED|DPAS_INSERTBEFORE);
314 ok(i == 2, "i=%d\n", i);
315 /* without DPAS_INSERTBEFORE/AFTER */
316 i = pDPA_Search(dpa, (PVOID)3, 0,
317 CB_CmpLT, 0xdeadbeef, DPAS_SORTED);
318 ok(i == -1, "i=%d\n", i);
320 /* Re-insert the item */
321 ret = pDPA_InsertPtr(dpa, 2, (PVOID)3);
322 ok(ret == 2, "ret=%d i=%d\n", ret, 2);
323 rc=CheckDPA(dpa, 0x123456, &dw);
324 ok(rc, "dw=0x%x\n", dw);
326 /* When doing a binary search while claiming reverse order all indexes
328 for(i = 0; i < 6; i++)
330 INT j = pDPA_Search(dpa, (PVOID)(INT_PTR)i, 0, CB_CmpGT, 0xdeadbeef,
331 DPAS_SORTED|DPAS_INSERTBEFORE);
332 ok(j != i, "i=%d\n", i);
335 /* Setting item with huge index should work */
336 ok(pDPA_SetPtr(dpa2, 0x12345, (PVOID)0xdeadbeef), "\n");
337 ret = pDPA_GetPtrIndex(dpa2, (PVOID)0xdeadbeef);
338 ok(ret == 0x12345, "ret=%d\n", ret);
340 pDPA_DeleteAllPtrs(dpa2);
341 rc=CheckDPA(dpa2, 0, &dw2);
342 ok(rc, "dw2=0x%x\n", dw2);
347 static void test_DPA_Merge(void)
349 HDPA dpa, dpa2, dpa3;
356 win_skip("DPA_Merge() not available\n");
360 dpa = pDPA_Create(0);
361 dpa2 = pDPA_Create(0);
362 dpa3 = pDPA_Create(0);
364 ret = pDPA_InsertPtr(dpa, 0, (PVOID)1);
365 ok(ret == 0, "ret=%d\n", ret);
366 ret = pDPA_InsertPtr(dpa, 1, (PVOID)3);
367 ok(ret == 1, "ret=%d\n", ret);
368 ret = pDPA_InsertPtr(dpa, 2, (PVOID)5);
369 ok(ret == 2, "ret=%d\n", ret);
371 rc = CheckDPA(dpa, 0x135, &dw);
372 ok(rc, "dw=0x%x\n", dw);
374 for (i = 0; i < 6; i++)
376 ret = pDPA_InsertPtr(dpa2, i, (PVOID)(6-i));
377 ok(ret == i, "ret=%d\n", ret);
378 ret = pDPA_InsertPtr(dpa3, i, (PVOID)(i+1));
379 ok(ret == i, "ret=%d\n", ret);
382 rc = CheckDPA(dpa2, 0x654321, &dw);
383 ok(rc, "dw=0x%x\n", dw);
384 rc = CheckDPA(dpa3, 0x123456, &dw);
385 ok(rc, "dw=0x%x\n", dw);
387 /* Delete all odd entries from dpa2 */
388 memset(nMessages, 0, sizeof(nMessages));
389 pDPA_Merge(dpa2, dpa, DPAM_INTERSECT,
390 CB_CmpLT, CB_MergeDeleteOddSrc, 0xdeadbeef);
391 rc = CheckDPA(dpa2, 0x246, &dw);
392 ok(rc, "dw=0x%x\n", dw);
394 expect(3, nMessages[DPAMM_MERGE]);
395 expect(3, nMessages[DPAMM_DELETE]);
396 expect(0, nMessages[DPAMM_INSERT]);
398 for (i = 0; i < 6; i++)
400 ret = pDPA_InsertPtr(dpa2, i, (PVOID)(6-i));
401 ok(ret == i, "ret=%d\n", ret);
404 /* DPAM_INTERSECT - returning source while merging */
405 memset(nMessages, 0, sizeof(nMessages));
406 pDPA_Merge(dpa2, dpa, DPAM_INTERSECT,
407 CB_CmpLT, CB_MergeInsertSrc, 0xdeadbeef);
408 rc = CheckDPA(dpa2, 0x135, &dw);
409 ok(rc, "dw=0x%x\n", dw);
411 expect(3, nMessages[DPAMM_MERGE]);
412 expect(6, nMessages[DPAMM_DELETE]);
413 expect(0, nMessages[DPAMM_INSERT]);
416 pDPA_DeleteAllPtrs(dpa);
417 pDPA_InsertPtr(dpa, 0, (PVOID)1);
418 pDPA_InsertPtr(dpa, 1, (PVOID)3);
419 pDPA_InsertPtr(dpa, 2, (PVOID)5);
420 pDPA_DeleteAllPtrs(dpa2);
421 pDPA_InsertPtr(dpa2, 0, (PVOID)2);
422 pDPA_InsertPtr(dpa2, 1, (PVOID)4);
423 pDPA_InsertPtr(dpa2, 2, (PVOID)6);
425 memset(nMessages, 0, sizeof(nMessages));
426 pDPA_Merge(dpa2, dpa, DPAM_UNION,
427 CB_CmpLT, CB_MergeInsertSrc, 0xdeadbeef);
428 rc = CheckDPA(dpa2, 0x123456, &dw);
429 ok(rc, "dw=0x%x\n", dw);
431 expect(0, nMessages[DPAMM_MERGE]);
432 expect(0, nMessages[DPAMM_DELETE]);
433 expect(3, nMessages[DPAMM_INSERT]);
435 /* Merge dpa3 into dpa2 and dpa */
436 memset(nMessages, 0, sizeof(nMessages));
437 pDPA_Merge(dpa, dpa3, DPAM_UNION|DPAM_SORTED,
438 CB_CmpLT, CB_MergeInsertSrc, 0xdeadbeef);
439 expect(3, nMessages[DPAMM_MERGE]);
440 expect(0, nMessages[DPAMM_DELETE]);
441 expect(3, nMessages[DPAMM_INSERT]);
444 pDPA_DeleteAllPtrs(dpa2);
445 pDPA_InsertPtr(dpa2, 0, (PVOID)2);
446 pDPA_InsertPtr(dpa2, 1, (PVOID)4);
447 pDPA_InsertPtr(dpa2, 2, (PVOID)6);
449 memset(nMessages, 0, sizeof(nMessages));
450 pDPA_Merge(dpa2, dpa3, DPAM_UNION|DPAM_SORTED,
451 CB_CmpLT, CB_MergeInsertSrc, 0xdeadbeef);
452 expect(3, nMessages[DPAMM_MERGE]);
453 expect(0, nMessages[DPAMM_DELETE]);
454 expect(3, nMessages[DPAMM_INSERT]);
456 rc = CheckDPA(dpa, 0x123456, &dw);
457 ok(rc, "dw=0x%x\n", dw);
458 rc = CheckDPA(dpa2, 0x123456, &dw);
460 broken(!rc), /* win98 */
462 rc = CheckDPA(dpa3, 0x123456, &dw);
463 ok(rc, "dw=0x%x\n", dw);
470 static void test_DPA_EnumCallback(void)
477 if(!pDPA_EnumCallback)
479 win_skip("DPA_EnumCallback() not available\n");
483 dpa = pDPA_Create(0);
485 for (i = 0; i < 6; i++)
487 ret = pDPA_InsertPtr(dpa, i, (PVOID)(i+1));
488 ok(ret == i, "ret=%d\n", ret);
491 rc = CheckDPA(dpa, 0x123456, &dw);
492 ok(rc, "dw=0x%x\n", dw);
495 /* test callback sets first 3 items to 7 */
496 pDPA_EnumCallback(dpa, CB_EnumFirstThree, dpa);
497 rc = CheckDPA(dpa, 0x777456, &dw);
498 ok(rc, "dw=0x%x\n", dw);
499 ok(nEnum == 3, "nEnum=%d\n", nEnum);
504 static void test_DPA_DestroyCallback(void)
509 if(!pDPA_DestroyCallback)
511 win_skip("DPA_DestroyCallback() not available\n");
515 dpa = pDPA_Create(0);
517 for (i = 0; i < 3; i++)
519 ret = pDPA_InsertPtr(dpa, i, (PVOID)(i+1));
520 ok(ret == i, "ret=%d\n", ret);
524 pDPA_DestroyCallback(dpa, CB_EnumFirstThree, dpa);
525 ok(nEnum == 3, "nEnum=%d\n", nEnum);
528 static void test_dpa_stream(void)
535 static const WCHAR szStg[] = { 'S','t','g',0 };
536 IStorage* pStg = NULL;
537 IStream* pStm = NULL;
538 LARGE_INTEGER liZero;
543 win_skip("DPA_SaveStream() not available. Skipping stream tests.\n");
547 hRes = CoInitialize(NULL);
550 ok(0, "hResult: %d\n", hRes);
554 dpa = pDPA_Create(0);
556 for (i = 0; i < 6; i++)
558 ret = pDPA_InsertPtr(dpa, i, (PVOID)(i+1));
559 ok(ret == i, "ret=%d\n", ret);
562 dwMode = STGM_DIRECT|STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE;
563 hRes = StgCreateDocfile(NULL, dwMode|STGM_DELETEONRELEASE, 0, &pStg);
564 ok(hRes == S_OK, "hRes=0x%x\n", hRes);
566 hRes = IStorage_CreateStream(pStg, szStg, dwMode, 0, 0, &pStm);
567 ok(hRes == S_OK, "hRes=0x%x\n", hRes);
569 hRes = pDPA_SaveStream(dpa, CB_Save, pStm, 0xdeadbeef);
570 todo_wine ok(hRes == S_OK, "hRes=0x%x\n", hRes);
574 hRes = IStream_Seek(pStm, liZero, STREAM_SEEK_SET, NULL);
575 ok(hRes == S_OK, "hRes=0x%x\n", hRes);
576 hRes = pDPA_LoadStream(&dpa, CB_Load, pStm, 0xdeadbeef);
579 ok(hRes == S_OK, "hRes=0x%x\n", hRes);
580 rc = CheckDPA(dpa, 0x123456, &dw);
581 ok(rc, "dw=0x%x\n", dw);
585 ret = IStream_Release(pStm);
586 ok(!ret, "ret=%d\n", ret);
588 ret = IStorage_Release(pStg);
589 ok(!ret, "ret=%d\n", ret);
598 hcomctl32 = GetModuleHandleA("comctl32.dll");
600 if(!InitFunctionPtrs(hcomctl32))
602 win_skip("Needed functions are not available\n");
608 test_DPA_EnumCallback();
609 test_DPA_DestroyCallback();