include: Move some documented DPA definitions to public header, use PSDK names.
[wine] / dlls / comctl32 / tests / dpa.c
1 /*
2  * Unit tests for DPA functions
3  *
4  * Copyright 2003 Uwe Bonnes
5  * Copyright 2005 Felix Nawothnig
6  *
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.
11  *
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.
16  *
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
20  */
21
22 #define COBJMACROS
23
24 #include <stdarg.h>
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "commctrl.h"
30 #include "objidl.h"
31
32 #include "wine/test.h"
33
34 typedef struct _ITEMDATA
35 {
36     INT   iPos;
37     PVOID pvData;
38 } ITEMDATA, *LPITEMDATA;
39
40 typedef HRESULT (CALLBACK *PFNDPASTM)(LPITEMDATA,IStream*,LPARAM);
41
42 static HDPA    (WINAPI *pDPA_Clone)(const HDPA,const HDPA);
43 static HDPA    (WINAPI *pDPA_Create)(INT);
44 static HDPA    (WINAPI *pDPA_CreateEx)(INT,HANDLE);
45 static PVOID   (WINAPI *pDPA_DeleteAllPtrs)(const HDPA);
46 static PVOID   (WINAPI *pDPA_DeletePtr)(const HDPA,INT);
47 static BOOL    (WINAPI *pDPA_Destroy)(const HDPA);
48 static VOID    (WINAPI *pDPA_DestroyCallback)(HDPA,PFNDPAENUMCALLBACK,PVOID);
49 static VOID    (WINAPI *pDPA_EnumCallback)(HDPA,PFNDPAENUMCALLBACK,PVOID); 
50 static INT     (WINAPI *pDPA_GetPtr)(const HDPA,INT);
51 static INT     (WINAPI *pDPA_GetPtrIndex)(const HDPA,PVOID);
52 static BOOL    (WINAPI *pDPA_Grow)(HDPA,INT);
53 static INT     (WINAPI *pDPA_InsertPtr)(const HDPA,INT,PVOID);
54 static HRESULT (WINAPI *pDPA_LoadStream)(HDPA*,PFNDPASTM,IStream*,LPARAM);
55 static BOOL    (WINAPI *pDPA_Merge)(const HDPA,const HDPA,DWORD,PFNDPACOMPARE,PFNDPAMERGE,LPARAM);
56 static HRESULT (WINAPI *pDPA_SaveStream)(HDPA,PFNDPASTM,IStream*,LPARAM);
57 static INT     (WINAPI *pDPA_Search)(HDPA,PVOID,INT,PFNDPACOMPARE,LPARAM,UINT);
58 static BOOL    (WINAPI *pDPA_SetPtr)(const HDPA,INT,PVOID);
59 static BOOL    (WINAPI *pDPA_Sort)(const HDPA,PFNDPACOMPARE,LPARAM);
60
61 #define COMCTL32_GET_PROC(func, ord) \
62   ((p ## func = (PVOID)GetProcAddress(hcomctl32,(LPCSTR)ord)) ? 1 \
63    : (trace( #func " not exported\n"), 0)) 
64
65 static BOOL InitFunctionPtrs(HMODULE hcomctl32)
66 {
67     /* 4.00+ */
68     if(COMCTL32_GET_PROC(DPA_Clone, 331) &&
69        COMCTL32_GET_PROC(DPA_Create, 328) &&
70        COMCTL32_GET_PROC(DPA_CreateEx, 340) &&
71        COMCTL32_GET_PROC(DPA_DeleteAllPtrs, 337) &&
72        COMCTL32_GET_PROC(DPA_DeletePtr, 336) &&
73        COMCTL32_GET_PROC(DPA_Destroy, 329) &&
74        COMCTL32_GET_PROC(DPA_GetPtr, 332) &&
75        COMCTL32_GET_PROC(DPA_GetPtrIndex, 333) &&
76        COMCTL32_GET_PROC(DPA_Grow, 330) &&
77        COMCTL32_GET_PROC(DPA_InsertPtr, 334) &&
78        COMCTL32_GET_PROC(DPA_Search, 339) &&
79        COMCTL32_GET_PROC(DPA_SetPtr, 335) &&
80        COMCTL32_GET_PROC(DPA_Sort, 338))
81     {
82         /* 4.71+ */
83         COMCTL32_GET_PROC(DPA_DestroyCallback, 386) &&
84         COMCTL32_GET_PROC(DPA_EnumCallback, 385) &&
85         COMCTL32_GET_PROC(DPA_LoadStream, 9) &&
86         COMCTL32_GET_PROC(DPA_Merge, 11) &&
87         COMCTL32_GET_PROC(DPA_SaveStream, 10);
88
89         return TRUE;
90     }
91
92     return FALSE;
93 }
94
95 /* Callbacks */
96 static INT CALLBACK CB_CmpLT(PVOID p1, PVOID p2, LPARAM lp)
97 {
98     ok(lp == 0xdeadbeef, "lp=%ld\n", lp);
99     return p1 < p2 ? -1 : p1 > p2 ? 1 : 0;
100 }
101
102 static INT CALLBACK CB_CmpGT(PVOID p1, PVOID p2, LPARAM lp)
103 {
104     ok(lp == 0xdeadbeef, "lp=%ld\n", lp);
105     return p1 > p2 ? -1 : p1 < p2 ? 1 : 0;
106 }
107
108 static PVOID CALLBACK CB_MergeInsertSrc(UINT op, PVOID p1, PVOID p2, LPARAM lp)
109 {
110     ok(lp == 0xdeadbeef, "lp=%ld\n", lp);
111     return p1;
112 }        
113
114 static PVOID CALLBACK CB_MergeDeleteOddSrc(UINT op, PVOID p1, PVOID p2, LPARAM lp)
115 {
116     ok(lp == 0xdeadbeef, "lp=%ld\n", lp);
117     return ((PCHAR)p2)+1;
118 }
119
120 static INT nEnum;
121
122 static INT CALLBACK CB_EnumFirstThree(PVOID pItem, PVOID lp)
123 {   
124     INT i;
125
126     i = pDPA_GetPtrIndex(lp, pItem);
127     ok(i == nEnum, "i=%d nEnum=%d\n", i, nEnum);
128     nEnum++;
129     pDPA_SetPtr(lp, i, (PVOID)7);
130     return pItem != (PVOID)3;
131 }
132
133 static HRESULT CALLBACK CB_Save(LPITEMDATA pInfo, IStream *pStm, LPARAM lp)
134 {
135     HRESULT hRes;
136     
137     ok(lp == 0xdeadbeef, "lp=%ld\n", lp);
138     hRes = IStream_Write(pStm, &pInfo->iPos, sizeof(INT), NULL);
139     ok(hRes == S_OK, "hRes=0x%x\n", hRes);
140     hRes = IStream_Write(pStm, &pInfo->pvData, sizeof(PVOID), NULL);
141     ok(hRes == S_OK, "hRes=0x%x\n", hRes);
142     return S_OK;
143 }
144
145 static HRESULT CALLBACK CB_Load(LPITEMDATA pInfo, IStream *pStm, LPARAM lp)
146 {
147     HRESULT hRes;
148     INT iOldPos;
149     
150     iOldPos = pInfo->iPos;
151     ok(lp == 0xdeadbeef, "lp=%ld\n", lp);
152     hRes = IStream_Read(pStm, &pInfo->iPos, sizeof(INT), NULL);
153     ok(hRes == S_OK, "hRes=0x%x\n", hRes);
154     ok(pInfo->iPos == iOldPos, "iPos=%d iOldPos=%d\n", pInfo->iPos, iOldPos);
155     hRes = IStream_Read(pStm, &pInfo->pvData, sizeof(PVOID), NULL);
156     ok(hRes == S_OK, "hRes=0x%x\n", hRes);
157     return S_OK;
158 }
159
160 static BOOL CheckDPA(HDPA dpa, DWORD dwIn, PDWORD pdwOut)
161 {
162     DWORD dwOut = 0;
163     INT i;
164
165     for(i = 0; i < 8;)
166     {
167         ULONG_PTR ulItem = (ULONG_PTR)pDPA_GetPtr(dpa, i++);
168         if(!ulItem) break;
169         dwOut = dwOut << 4 | (ulItem & 0xf);
170     }
171     
172     *pdwOut = dwOut;
173
174     if(dwOut != dwIn)
175     {
176         pDPA_DeleteAllPtrs(dpa);
177         
178         do
179         {
180             pDPA_InsertPtr(dpa, 0, (PVOID)(ULONG_PTR)(dwIn & 0xf));
181             dwIn >>= 4;
182         }
183         while(dwIn);
184         
185         return FALSE;
186     }
187     
188     return TRUE;
189 }
190
191 static void test_dpa(void)
192 {
193     SYSTEM_INFO si;
194     HANDLE hHeap;
195     HDPA dpa, dpa2, dpa3;
196     INT ret, i;
197     PVOID p;
198     DWORD dw, dw2, dw3;
199     BOOL rc;
200     
201     GetSystemInfo(&si);
202     hHeap = HeapCreate(0, 1, 2);
203     ok(hHeap != NULL, "error=%d\n", GetLastError());
204     dpa3 = pDPA_CreateEx(0, hHeap);
205     ok(dpa3 != NULL, "\n");
206     ret = pDPA_Grow(dpa3, si.dwPageSize + 1);
207     todo_wine ok(!ret && GetLastError() == ERROR_NOT_ENOUGH_MEMORY, 
208        "ret=%d error=%d\n", ret, GetLastError());
209         
210     dpa = pDPA_Create(0);
211     ok(dpa != NULL, "\n");
212
213     /* Set item with out of bound index */
214     ok(pDPA_SetPtr(dpa, 1, (PVOID)6), "\n");
215     /* Fill the created gap */
216     ok(pDPA_SetPtr(dpa, 0, (PVOID)5), "\n");
217     rc=CheckDPA(dpa, 0x56, &dw);
218     ok(rc, "dw=0x%x\n", dw);
219     
220     /* Prepend item */
221     ret = pDPA_InsertPtr(dpa, 1, (PVOID)1);
222     ok(ret == 1, "ret=%d\n", ret);
223     /* Append item using correct index */
224     ret = pDPA_InsertPtr(dpa, 3, (PVOID)3);
225     ok(ret == 3, "ret=%d\n", ret);
226     /* Append item using out of bound index */
227     ret = pDPA_InsertPtr(dpa, 5, (PVOID)2);
228     ok(ret == 4, "ret=%d\n", ret);
229     /* Append item using DPA_APPEND */ 
230     ret = pDPA_InsertPtr(dpa, DPA_APPEND, (PVOID)4);
231     ok(ret == 5, "ret=%d\n", ret);
232
233     rc=CheckDPA(dpa, 0x516324, &dw);
234     ok(rc, "dw=0x%x\n", dw);
235
236     for(i = 1; i <= 6; i++)
237     {
238         INT j, k;
239         k = pDPA_GetPtrIndex(dpa, (PVOID)(INT_PTR)i);
240         /* Linear searches should work on unsorted DPAs */
241         j = pDPA_Search(dpa, (PVOID)(INT_PTR)i, 0, CB_CmpLT, 0xdeadbeef, 0);
242         ok(j == k, "j=%d k=%d\n", j, k);
243     }
244
245     /* Sort DPA */
246     ok(pDPA_Sort(dpa, CB_CmpGT, 0xdeadbeef), "\n");
247     rc=CheckDPA(dpa, 0x654321, &dw);
248     ok(rc, "dw=0x%x\n", dw);
249     
250     /* Clone into a new DPA */
251     dpa2 = pDPA_Clone(dpa, NULL);
252     ok(dpa2 != NULL, "\n");
253     /* The old data should have been preserved */
254     rc=CheckDPA(dpa2, 0x654321, &dw2);
255     ok(rc, "dw=0x%x\n", dw2);
256     ok(pDPA_Sort(dpa, CB_CmpLT, 0xdeadbeef), "\n");
257     
258     /* Test if the DPA itself was really copied */
259     rc=CheckDPA(dpa,  0x123456, &dw);
260     ok(rc, "dw=0x%x\n",  dw );
261     rc=CheckDPA(dpa2, 0x654321, &dw2);
262     ok(rc, "dw2=0x%x\n", dw2);
263
264     /* Clone into an old DPA */
265     p = NULL; SetLastError(ERROR_SUCCESS);
266     p = pDPA_Clone(dpa, dpa3);
267     ok(p == dpa3, "p=%p\n", p);
268     rc=CheckDPA(dpa3, 0x123456, &dw3);
269     ok(rc, "dw3=0x%x\n", dw3);
270
271     for(i = 1; i <= 6; i++)
272     {
273         INT j;
274
275         /* The array is in order so ptr == index+1 */
276         j = pDPA_GetPtrIndex(dpa, (PVOID)(INT_PTR)i);
277         ok(j+1 == i, "j=%d i=%d\n", j, i);
278         j = pDPA_Search(dpa, (PVOID)(INT_PTR)i, 0, CB_CmpLT, 0xdeadbeef, DPAS_SORTED);
279         ok(j+1 == i, "j=%d i=%d\n", j, i);
280
281         /* Linear searches respect iStart ... */
282         j = pDPA_Search(dpa, (PVOID)(INT_PTR)i, i+1, CB_CmpLT, 0xdeadbeef, 0);
283         ok(j == DPA_ERR, "j=%d\n", j);
284         /* ... but for a binary search it's ignored */
285         j = pDPA_Search(dpa, (PVOID)(INT_PTR)i, i+1, CB_CmpLT, 0xdeadbeef, DPAS_SORTED);
286         ok(j+1 == i, "j=%d i=%d\n", j, i);
287     }
288
289     /* Try to get the index of a nonexistent item */
290     i = pDPA_GetPtrIndex(dpa, (PVOID)7);
291     ok(i == DPA_ERR, "i=%d\n", i);
292     
293     /* Try to delete out of bound indexes */
294     p = pDPA_DeletePtr(dpa, -1);
295     ok(p == NULL, "p=%p\n", p);
296     p = pDPA_DeletePtr(dpa, 6);
297     ok(p == NULL, "p=%p\n", p);
298
299     /* Delete the third item */
300     p = pDPA_DeletePtr(dpa, 2);
301     ok(p == (PVOID)3, "p=%p\n", p);
302     rc=CheckDPA(dpa, 0x12456, &dw);
303     ok(rc, "dw=0x%x\n", dw);
304
305     /* Check where to re-insert the deleted item */
306     i = pDPA_Search(dpa, (PVOID)3, 0, 
307                     CB_CmpLT, 0xdeadbeef, DPAS_SORTED|DPAS_INSERTAFTER);
308     ok(i == 2, "i=%d\n", i);
309     /* DPAS_INSERTBEFORE works just like DPAS_INSERTAFTER */
310     i = pDPA_Search(dpa, (PVOID)3, 0,
311                     CB_CmpLT, 0xdeadbeef, DPAS_SORTED|DPAS_INSERTBEFORE);
312     ok(i == 2, "i=%d\n", i);
313     /* without DPAS_INSERTBEFORE/AFTER */
314     i = pDPA_Search(dpa, (PVOID)3, 0,
315                     CB_CmpLT, 0xdeadbeef, DPAS_SORTED);
316     ok(i == -1, "i=%d\n", i);
317
318     /* Re-insert the item */
319     ret = pDPA_InsertPtr(dpa, 2, (PVOID)3);
320     ok(ret == 2, "ret=%d i=%d\n", ret, 2);
321     rc=CheckDPA(dpa, 0x123456, &dw);
322     ok(rc, "dw=0x%x\n", dw);
323     
324     /* When doing a binary search while claiming reverse order all indexes
325      * should be bogus */
326     for(i = 0; i < 6; i++)
327     {
328         INT j = pDPA_Search(dpa, (PVOID)(INT_PTR)i, 0, CB_CmpGT, 0xdeadbeef,
329                             DPAS_SORTED|DPAS_INSERTBEFORE);
330         ok(j != i, "i=%d\n", i);
331     }
332
333     /* Setting item with huge index should work */
334     ok(pDPA_SetPtr(dpa2, 0x12345, (PVOID)0xdeadbeef), "\n");
335     ret = pDPA_GetPtrIndex(dpa2, (PVOID)0xdeadbeef);
336     ok(ret == 0x12345, "ret=%d\n", ret);
337           
338     pDPA_DeleteAllPtrs(dpa2);
339     rc=CheckDPA(dpa2, 0, &dw2);
340     ok(rc, "dw2=0x%x\n", dw2);
341     pDPA_Destroy(dpa2);
342     pDPA_Destroy(dpa3);
343 }
344
345 static void test_DPA_Merge(void)
346 {
347     HDPA dpa, dpa2, dpa3;
348     INT ret, i;
349     DWORD dw;
350     BOOL rc;
351
352     if(!pDPA_Merge)
353     {
354         win_skip("DPA_Merge() not available\n");
355         return;
356     }
357
358     dpa  = pDPA_Create(0);
359     dpa2 = pDPA_Create(0);
360     dpa3 = pDPA_Create(0);
361
362     ret = pDPA_InsertPtr(dpa, 0, (PVOID)1);
363     ok(ret == 0, "ret=%d\n", ret);
364     ret = pDPA_InsertPtr(dpa, 1, (PVOID)3);
365     ok(ret == 1, "ret=%d\n", ret);
366     ret = pDPA_InsertPtr(dpa, 2, (PVOID)5);
367     ok(ret == 2, "ret=%d\n", ret);
368
369     rc = CheckDPA(dpa, 0x135, &dw);
370     ok(rc, "dw=0x%x\n", dw);
371
372     for (i = 0; i < 6; i++)
373     {
374         ret = pDPA_InsertPtr(dpa2, i, (PVOID)(6-i));
375         ok(ret == i, "ret=%d\n", ret);
376         ret = pDPA_InsertPtr(dpa3, i, (PVOID)(i+1));
377         ok(ret == i, "ret=%d\n", ret);
378     }
379
380     rc = CheckDPA(dpa2, 0x654321, &dw);
381     ok(rc, "dw=0x%x\n", dw);
382     rc = CheckDPA(dpa3, 0x123456, &dw);
383     ok(rc, "dw=0x%x\n", dw);
384
385     /* Delete all odd entries from dpa2 */
386     pDPA_Merge(dpa2, dpa, DPAM_INTERSECT,
387                CB_CmpLT, CB_MergeDeleteOddSrc, 0xdeadbeef);
388     todo_wine
389     {
390         rc = CheckDPA(dpa2, 0x246, &dw);
391         ok(rc, "dw=0x%x\n", dw);
392     }
393
394     /* Merge dpa3 into dpa2 and dpa */
395     pDPA_Merge(dpa, dpa3, DPAM_UNION|DPAM_SORTED,
396                CB_CmpLT, CB_MergeInsertSrc, 0xdeadbeef);
397     pDPA_Merge(dpa2, dpa3, DPAM_UNION|DPAM_SORTED,
398                CB_CmpLT, CB_MergeInsertSrc, 0xdeadbeef);
399
400     rc = CheckDPA(dpa,  0x123456, &dw);
401     ok(rc, "dw=0x%x\n",  dw);
402     rc = CheckDPA(dpa2, 0x123456, &dw);
403     ok(rc ||
404        broken(!rc), /* win98 */
405        "dw=0x%x\n", dw);
406     rc = CheckDPA(dpa3, 0x123456, &dw);
407     ok(rc, "dw=0x%x\n", dw);
408
409     pDPA_Destroy(dpa);
410     pDPA_Destroy(dpa2);
411     pDPA_Destroy(dpa3);
412 }
413
414 static void test_DPA_EnumCallback(void)
415 {
416     HDPA dpa;
417     BOOL rc;
418     DWORD dw;
419     INT i, ret;
420
421     if(!pDPA_EnumCallback)
422     {
423         win_skip("DPA_EnumCallback() not available\n");
424         return;
425     }
426
427     dpa = pDPA_Create(0);
428
429     for (i = 0; i < 6; i++)
430     {
431         ret = pDPA_InsertPtr(dpa, i, (PVOID)(i+1));
432         ok(ret == i, "ret=%d\n", ret);
433     }
434
435     rc = CheckDPA(dpa, 0x123456, &dw);
436     ok(rc, "dw=0x%x\n", dw);
437
438     nEnum = 0;
439     /* test callback sets first 3 items to 7 */
440     pDPA_EnumCallback(dpa, CB_EnumFirstThree, dpa);
441     rc = CheckDPA(dpa, 0x777456, &dw);
442     ok(rc, "dw=0x%x\n", dw);
443     ok(nEnum == 3, "nEnum=%d\n", nEnum);
444
445     pDPA_Destroy(dpa);
446 }
447
448 static void test_DPA_DestroyCallback(void)
449 {
450     HDPA dpa;
451     INT i, ret;
452
453     if(!pDPA_DestroyCallback)
454     {
455         win_skip("DPA_DestroyCallback() not available\n");
456         return;
457     }
458
459     dpa = pDPA_Create(0);
460
461     for (i = 0; i < 3; i++)
462     {
463         ret = pDPA_InsertPtr(dpa, i, (PVOID)(i+1));
464         ok(ret == i, "ret=%d\n", ret);
465     }
466
467     nEnum = 0;
468     pDPA_DestroyCallback(dpa, CB_EnumFirstThree, dpa);
469     ok(nEnum == 3, "nEnum=%d\n", nEnum);
470 }
471
472 static void test_dpa_stream(void)
473 {
474     HDPA dpa;
475     HRESULT hRes;
476     INT ret, i;
477     BOOL rc;
478
479     static const WCHAR szStg[] = { 'S','t','g',0 };
480     IStorage* pStg = NULL;
481     IStream* pStm = NULL;
482     LARGE_INTEGER liZero;
483     DWORD dwMode, dw;
484
485     if(!pDPA_SaveStream)
486     {
487         win_skip("DPA_SaveStream() not available. Skipping stream tests.\n");
488         return;
489     }
490
491     hRes = CoInitialize(NULL);
492     if (hRes != S_OK)
493     {
494         ok(0, "hResult: %d\n", hRes);
495         return;
496     }
497
498     dpa = pDPA_Create(0);
499
500     for (i = 0; i < 6; i++)
501     {
502         ret = pDPA_InsertPtr(dpa, i, (PVOID)(i+1));
503         ok(ret == i, "ret=%d\n", ret);
504     }
505
506     dwMode = STGM_DIRECT|STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE;
507     hRes = StgCreateDocfile(NULL, dwMode|STGM_DELETEONRELEASE, 0, &pStg);
508     ok(hRes == S_OK, "hRes=0x%x\n", hRes);
509
510     hRes = IStorage_CreateStream(pStg, szStg, dwMode, 0, 0, &pStm);
511     ok(hRes == S_OK, "hRes=0x%x\n", hRes);
512
513     hRes = pDPA_SaveStream(dpa, CB_Save, pStm, 0xdeadbeef);
514     todo_wine ok(hRes == S_OK, "hRes=0x%x\n", hRes);
515     pDPA_Destroy(dpa);
516
517     liZero.QuadPart = 0;
518     hRes = IStream_Seek(pStm, liZero, STREAM_SEEK_SET, NULL);
519     ok(hRes == S_OK, "hRes=0x%x\n", hRes);
520     hRes = pDPA_LoadStream(&dpa, CB_Load, pStm, 0xdeadbeef);
521     todo_wine
522     {
523         ok(hRes == S_OK, "hRes=0x%x\n", hRes);
524         rc = CheckDPA(dpa, 0x123456, &dw);
525         ok(rc, "dw=0x%x\n", dw);
526     }
527     pDPA_Destroy(dpa);
528
529     ret = IStream_Release(pStm);
530     ok(!ret, "ret=%d\n", ret);
531
532     ret = IStorage_Release(pStg);
533     ok(!ret, "ret=%d\n", ret);
534
535     CoUninitialize();
536 }
537
538 START_TEST(dpa)
539 {
540     HMODULE hcomctl32;
541
542     hcomctl32 = GetModuleHandleA("comctl32.dll");
543
544     if(!InitFunctionPtrs(hcomctl32))
545     {
546         win_skip("Needed functions are not available\n");
547         return;
548     }
549
550     test_dpa();
551     test_DPA_Merge();
552     test_DPA_EnumCallback();
553     test_DPA_DestroyCallback();
554     test_dpa_stream();
555 }