dxdiagn: Simplify the root container initialization.
[wine] / dlls / dxdiagn / tests / container.c
1 /*
2  * Unit tests for IDxDiagContainer
3  *
4  * Copyright 2010 Andrew Nguyen
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #define COBJMACROS
22
23 #include <stdio.h>
24 #include "dxdiag.h"
25 #include "oleauto.h"
26 #include "wine/test.h"
27
28 static IDxDiagProvider *pddp;
29 static IDxDiagContainer *pddc;
30
31 static BOOL create_root_IDxDiagContainer(void)
32 {
33     HRESULT hr;
34     DXDIAG_INIT_PARAMS params;
35
36     hr = CoCreateInstance(&CLSID_DxDiagProvider, NULL, CLSCTX_INPROC_SERVER,
37                           &IID_IDxDiagProvider, (LPVOID*)&pddp);
38     if (SUCCEEDED(hr))
39     {
40         params.dwSize = sizeof(params);
41         params.dwDxDiagHeaderVersion = DXDIAG_DX9_SDK_VERSION;
42         params.bAllowWHQLChecks = FALSE;
43         params.pReserved = NULL;
44         hr = IDxDiagProvider_Initialize(pddp, &params);
45         if (SUCCEEDED(hr))
46         {
47             hr = IDxDiagProvider_GetRootContainer(pddp, &pddc);
48             if (SUCCEEDED(hr))
49                 return TRUE;
50         }
51         IDxDiagProvider_Release(pddp);
52     }
53     return FALSE;
54 }
55
56 static void test_GetNumberOfChildContainers(void)
57 {
58     HRESULT hr;
59     DWORD count;
60
61     if (!create_root_IDxDiagContainer())
62     {
63         skip("Unable to create the root IDxDiagContainer\n");
64         return;
65     }
66
67     hr = IDxDiagContainer_GetNumberOfChildContainers(pddc, NULL);
68     ok(hr == E_INVALIDARG,
69        "Expected IDxDiagContainer::GetNumberOfChildContainers to return E_INVALIDARG, got 0x%08x\n", hr);
70
71     hr = IDxDiagContainer_GetNumberOfChildContainers(pddc, &count);
72     ok(hr == S_OK,
73        "Expected IDxDiagContainer::GetNumberOfChildContainers to return S_OK, got 0x%08x\n", hr);
74     if (hr == S_OK)
75         ok(count != 0, "Expected the number of child containers for the root container to be non-zero\n");
76
77     IDxDiagContainer_Release(pddc);
78     IDxDiagProvider_Release(pddp);
79 }
80
81 static void test_GetNumberOfProps(void)
82 {
83     HRESULT hr;
84     DWORD count;
85
86     if (!create_root_IDxDiagContainer())
87     {
88         skip("Unable to create the root IDxDiagContainer\n");
89         return;
90     }
91
92     hr = IDxDiagContainer_GetNumberOfProps(pddc, NULL);
93     ok(hr == E_INVALIDARG, "Expected IDxDiagContainer::GetNumberOfProps to return E_INVALIDARG, got 0x%08x\n", hr);
94
95     hr = IDxDiagContainer_GetNumberOfProps(pddc, &count);
96     ok(hr == S_OK, "Expected IDxDiagContainer::GetNumberOfProps to return S_OK, got 0x%08x\n", hr);
97     if (hr == S_OK)
98         ok(count == 0, "Expected the number of properties for the root container to be zero\n");
99
100     IDxDiagContainer_Release(pddc);
101     IDxDiagProvider_Release(pddp);
102 }
103
104 static void test_EnumChildContainerNames(void)
105 {
106     HRESULT hr;
107     WCHAR container[256];
108     DWORD maxcount, index;
109     static const WCHAR testW[] = {'t','e','s','t',0};
110     static const WCHAR zerotestW[] = {0,'e','s','t',0};
111
112     if (!create_root_IDxDiagContainer())
113     {
114         skip("Unable to create the root IDxDiagContainer\n");
115         return;
116     }
117
118     /* Test various combinations of invalid parameters. */
119     hr = IDxDiagContainer_EnumChildContainerNames(pddc, 0, NULL, 0);
120     ok(hr == E_INVALIDARG,
121        "Expected IDxDiagContainer::EnumChildContainerNames to return E_INVALIDARG, got 0x%08x\n", hr);
122
123     hr = IDxDiagContainer_EnumChildContainerNames(pddc, 0, NULL, sizeof(container)/sizeof(WCHAR));
124     ok(hr == E_INVALIDARG,
125        "Expected IDxDiagContainer::EnumChildContainerNames to return E_INVALIDARG, got 0x%08x\n", hr);
126
127     /* Test the conditions in which the output buffer can be modified. */
128     memcpy(container, testW, sizeof(testW));
129     hr = IDxDiagContainer_EnumChildContainerNames(pddc, 0, container, 0);
130     ok(hr == E_INVALIDARG,
131        "Expected IDxDiagContainer::EnumChildContainerNames to return E_INVALIDARG, got 0x%08x\n", hr);
132     ok(!memcmp(container, testW, sizeof(testW)),
133        "Expected the container buffer to be untouched, got %s\n", wine_dbgstr_w(container));
134
135     memcpy(container, testW, sizeof(testW));
136     hr = IDxDiagContainer_EnumChildContainerNames(pddc, ~0, container, 0);
137     ok(hr == E_INVALIDARG,
138        "Expected IDxDiagContainer::EnumChildContainerNames to return E_INVALIDARG, got 0x%08x\n", hr);
139     ok(!memcmp(container, testW, sizeof(testW)),
140        "Expected the container buffer to be untouched, got %s\n", wine_dbgstr_w(container));
141
142     memcpy(container, testW, sizeof(testW));
143     hr = IDxDiagContainer_EnumChildContainerNames(pddc, ~0, container, sizeof(container)/sizeof(WCHAR));
144     ok(hr == E_INVALIDARG,
145        "Expected IDxDiagContainer::EnumChildContainerNames to return E_INVALIDARG, got 0x%08x\n", hr);
146     ok(!memcmp(container, zerotestW, sizeof(zerotestW)),
147        "Expected the container buffer string to be empty, got %s\n", wine_dbgstr_w(container));
148
149     hr = IDxDiagContainer_GetNumberOfChildContainers(pddc, &maxcount);
150     ok(hr == S_OK, "Expected IDxDiagContainer::GetNumberOfChildContainers to return S_OK, got 0x%08x\n", hr);
151     if (FAILED(hr))
152     {
153         skip("IDxDiagContainer::GetNumberOfChildContainers failed\n");
154         goto cleanup;
155     }
156
157     trace("Starting child container enumeration of the root container:\n");
158
159     /* We should be able to enumerate as many child containers as the value
160      * that IDxDiagContainer::GetNumberOfChildContainers returns. */
161     for (index = 0; index <= maxcount; index++)
162     {
163         /* A buffer size of 1 is unlikely to be valid, as only a null terminator
164          * could be stored, and it is unlikely that a container name could be empty. */
165         DWORD buffersize = 1;
166         memcpy(container, testW, sizeof(testW));
167         hr = IDxDiagContainer_EnumChildContainerNames(pddc, index, container, buffersize);
168         if (hr == E_INVALIDARG)
169         {
170             /* We should get here when index is one more than the maximum index value. */
171             ok(maxcount == index,
172                "Expected IDxDiagContainer::EnumChildContainerNames to return E_INVALIDARG "
173                "on the last index %d, got 0x%08x\n", index, hr);
174             ok(container[0] == '\0',
175                "Expected the container buffer string to be empty, got %s\n", wine_dbgstr_w(container));
176             break;
177         }
178         else if (hr == DXDIAG_E_INSUFFICIENT_BUFFER)
179         {
180             WCHAR temp[256];
181
182             ok(container[0] == '\0',
183                "Expected the container buffer string to be empty, got %s\n", wine_dbgstr_w(container));
184
185             /* Get the container name to compare against. */
186             hr = IDxDiagContainer_EnumChildContainerNames(pddc, index, temp, sizeof(temp)/sizeof(WCHAR));
187             ok(hr == S_OK,
188                "Expected IDxDiagContainer::EnumChildContainerNames to return S_OK, got 0x%08x\n", hr);
189
190             /* Show that the DirectX SDK's stipulation that the buffer be at
191              * least 256 characters long is a mere suggestion, and smaller sizes
192              * can be acceptable also. IDxDiagContainer::EnumChildContainerNames
193              * doesn't provide a way of getting the exact size required, so the
194              * buffersize value will be iterated to at most 256 characters. */
195             for (buffersize = 2; buffersize <= 256; buffersize++)
196             {
197                 memcpy(container, testW, sizeof(testW));
198                 hr = IDxDiagContainer_EnumChildContainerNames(pddc, index, container, buffersize);
199                 if (hr != DXDIAG_E_INSUFFICIENT_BUFFER)
200                     break;
201
202                 ok(!memcmp(temp, container, sizeof(WCHAR)*(buffersize - 1)),
203                    "Expected truncated container name string, got %s\n", wine_dbgstr_w(container));
204             }
205
206             ok(hr == S_OK,
207                "Expected IDxDiagContainer::EnumChildContainerNames to return S_OK, "
208                "got hr = 0x%08x, buffersize = %d\n", hr, buffersize);
209             if (hr == S_OK)
210                 trace("pddc[%d] = %s, length = %d\n", index, wine_dbgstr_w(container), buffersize);
211         }
212         else
213         {
214             ok(0, "IDxDiagContainer::EnumChildContainerNames unexpectedly returned 0x%08x\n", hr);
215             break;
216         }
217     }
218
219 cleanup:
220     IDxDiagContainer_Release(pddc);
221     IDxDiagProvider_Release(pddp);
222 }
223
224 static void test_GetChildContainer(void)
225 {
226     HRESULT hr;
227     WCHAR container[256] = {0};
228     IDxDiagContainer *child;
229
230     if (!create_root_IDxDiagContainer())
231     {
232         skip("Unable to create the root IDxDiagContainer\n");
233         return;
234     }
235
236     /* Test various combinations of invalid parameters. */
237     hr = IDxDiagContainer_GetChildContainer(pddc, NULL, NULL);
238     ok(hr == E_INVALIDARG,
239        "Expected IDxDiagContainer::GetChildContainer to return E_INVALIDARG, got 0x%08x\n", hr);
240
241     child = (void*)0xdeadbeef;
242     hr = IDxDiagContainer_GetChildContainer(pddc, NULL, &child);
243     ok(hr == E_INVALIDARG,
244        "Expected IDxDiagContainer::GetChildContainer to return E_INVALIDARG, got 0x%08x\n", hr);
245     ok(child == (void*)0xdeadbeef, "Expected output pointer to be unchanged, got %p\n", child);
246
247     hr = IDxDiagContainer_GetChildContainer(pddc, container, NULL);
248     ok(hr == E_INVALIDARG,
249        "Expected IDxDiagContainer::GetChildContainer to return E_INVALIDARG, got 0x%08x\n", hr);
250
251     child = (void*)0xdeadbeef;
252     hr = IDxDiagContainer_GetChildContainer(pddc, container, &child);
253     ok(hr == E_INVALIDARG,
254        "Expected IDxDiagContainer::GetChildContainer to return E_INVALIDARG, got 0x%08x\n", hr);
255     ok(child == NULL, "Expected output pointer to be NULL, got %p\n", child);
256
257     /* Get the name of a suitable child container. */
258     hr = IDxDiagContainer_EnumChildContainerNames(pddc, 0, container, sizeof(container)/sizeof(WCHAR));
259     ok(hr == S_OK,
260        "Expected IDxDiagContainer::EnumChildContainerNames to return S_OK, got 0x%08x\n", hr);
261     if (FAILED(hr))
262     {
263         skip("IDxDiagContainer::EnumChildContainerNames failed\n");
264         goto cleanup;
265     }
266
267     child = (void*)0xdeadbeef;
268     hr = IDxDiagContainer_GetChildContainer(pddc, container, &child);
269     ok(hr == S_OK,
270        "Expected IDxDiagContainer::GetChildContainer to return S_OK, got 0x%08x\n", hr);
271     ok(child != NULL && child != (void*)0xdeadbeef, "Expected a valid output pointer, got %p\n", child);
272
273     if (SUCCEEDED(hr))
274     {
275         IDxDiagContainer *ptr;
276
277         /* Show that IDxDiagContainer::GetChildContainer returns a different pointer
278          * for multiple calls for the same container name. */
279         hr = IDxDiagContainer_GetChildContainer(pddc, container, &ptr);
280         ok(hr == S_OK,
281            "Expected IDxDiagContainer::GetChildContainer to return S_OK, got 0x%08x\n", hr);
282         if (SUCCEEDED(hr))
283             todo_wine ok(ptr != child, "Expected the two pointers (%p vs. %p) to be unequal\n", child, ptr);
284
285         IDxDiagContainer_Release(ptr);
286         IDxDiagContainer_Release(child);
287     }
288
289 cleanup:
290     IDxDiagContainer_Release(pddc);
291     IDxDiagProvider_Release(pddp);
292 }
293
294 static void test_dot_parsing(void)
295 {
296     HRESULT hr;
297     WCHAR containerbufW[256] = {0}, childbufW[256] = {0};
298     DWORD count, index;
299     size_t i;
300     static const struct
301     {
302         const char *format;
303         const HRESULT expect;
304     } test_strings[] = {
305         { "%s.%s",   S_OK },
306         { "%s.%s.",  S_OK },
307         { ".%s.%s",  E_INVALIDARG },
308         { "%s.%s..", E_INVALIDARG },
309         { ".%s.%s.", E_INVALIDARG },
310         { "..%s.%s", E_INVALIDARG },
311     };
312
313     if (!create_root_IDxDiagContainer())
314     {
315         skip("Unable to create the root IDxDiagContainer\n");
316         return;
317     }
318
319     /* Find a container with a child container of its own. */
320     hr = IDxDiagContainer_GetNumberOfChildContainers(pddc, &count);
321     ok(hr == S_OK, "Expected IDxDiagContainer::GetNumberOfChildContainers to return S_OK, got 0x%08x\n", hr);
322     if (FAILED(hr))
323     {
324         skip("IDxDiagContainer::GetNumberOfChildContainers failed\n");
325         goto cleanup;
326     }
327
328     for (index = 0; index < count; index++)
329     {
330         IDxDiagContainer *child;
331
332         hr = IDxDiagContainer_EnumChildContainerNames(pddc, index, containerbufW, sizeof(containerbufW)/sizeof(WCHAR));
333         ok(hr == S_OK, "Expected IDxDiagContainer_EnumChildContainerNames to return S_OK, got 0x%08x\n", hr);
334         if (FAILED(hr))
335         {
336             skip("IDxDiagContainer::EnumChildContainerNames failed\n");
337             goto cleanup;
338         }
339
340         hr = IDxDiagContainer_GetChildContainer(pddc, containerbufW, &child);
341         ok(hr == S_OK, "Expected IDxDiagContainer::GetChildContainer to return S_OK, got 0x%08x\n", hr);
342
343         if (SUCCEEDED(hr))
344         {
345             hr = IDxDiagContainer_EnumChildContainerNames(child, 0, childbufW, sizeof(childbufW)/sizeof(WCHAR));
346             ok(hr == S_OK || hr == E_INVALIDARG,
347                "Expected IDxDiagContainer::EnumChildContainerNames to return S_OK or E_INVALIDARG, got 0x%08x\n", hr);
348             IDxDiagContainer_Release(child);
349
350             if (SUCCEEDED(hr))
351                 break;
352         }
353     }
354
355     if (!*containerbufW || !*childbufW)
356     {
357         skip("Unable to find a suitable container\n");
358         goto cleanup;
359     }
360
361     trace("Testing IDxDiagContainer::GetChildContainer dot parsing with container %s and child container %s.\n",
362           wine_dbgstr_w(containerbufW), wine_dbgstr_w(childbufW));
363
364     for (i = 0; i < sizeof(test_strings)/sizeof(test_strings[0]); i++)
365     {
366         IDxDiagContainer *child;
367         char containerbufA[256];
368         char childbufA[256];
369         char dotbufferA[255 + 255 + 3 + 1];
370         WCHAR dotbufferW[255 + 255 + 3 + 1]; /* containerbuf + childbuf + dots + null terminator */
371
372         WideCharToMultiByte(CP_ACP, 0, containerbufW, -1, containerbufA, sizeof(containerbufA), NULL, NULL);
373         WideCharToMultiByte(CP_ACP, 0, childbufW, -1, childbufA, sizeof(childbufA), NULL, NULL);
374         sprintf(dotbufferA, test_strings[i].format, containerbufA, childbufA);
375         MultiByteToWideChar(CP_ACP, 0, dotbufferA, -1, dotbufferW, sizeof(dotbufferW)/sizeof(WCHAR));
376
377         trace("Trying container name %s\n", wine_dbgstr_w(dotbufferW));
378         hr = IDxDiagContainer_GetChildContainer(pddc, dotbufferW, &child);
379         ok(hr == test_strings[i].expect,
380            "Expected IDxDiagContainer::GetChildContainer to return 0x%08x for %s, got 0x%08x\n",
381            test_strings[i].expect, wine_dbgstr_w(dotbufferW), hr);
382         if (SUCCEEDED(hr))
383             IDxDiagContainer_Release(child);
384     }
385
386 cleanup:
387     IDxDiagContainer_Release(pddc);
388     IDxDiagProvider_Release(pddp);
389 }
390
391 static void test_EnumPropNames(void)
392 {
393     HRESULT hr;
394     WCHAR container[256], property[256];
395     IDxDiagContainer *child = NULL;
396     DWORD count, index, propcount;
397     static const WCHAR testW[] = {'t','e','s','t',0};
398
399     if (!create_root_IDxDiagContainer())
400     {
401         skip("Unable to create the root IDxDiagContainer\n");
402         return;
403     }
404
405     /* Find a container with a non-zero number of properties. */
406     hr = IDxDiagContainer_GetNumberOfChildContainers(pddc, &count);
407     ok(hr == S_OK, "Expected IDxDiagContainer::GetNumberOfChildContainers to return S_OK, got 0x%08x\n", hr);
408     if (FAILED(hr))
409     {
410         skip("IDxDiagContainer::GetNumberOfChildContainers failed\n");
411         goto cleanup;
412     }
413
414     for (index = 0; index < count; index++)
415     {
416         hr = IDxDiagContainer_EnumChildContainerNames(pddc, index, container, sizeof(container)/sizeof(WCHAR));
417         ok(hr == S_OK, "Expected IDxDiagContainer_EnumChildContainerNames to return S_OK, got 0x%08x\n", hr);
418         if (FAILED(hr))
419         {
420             skip("IDxDiagContainer::EnumChildContainerNames failed\n");
421             goto cleanup;
422         }
423
424         hr = IDxDiagContainer_GetChildContainer(pddc, container, &child);
425         ok(hr == S_OK, "Expected IDxDiagContainer::GetChildContainer to return S_OK, got 0x%08x\n", hr);
426
427         if (SUCCEEDED(hr))
428         {
429             hr = IDxDiagContainer_GetNumberOfProps(child, &propcount);
430             ok(hr == S_OK, "Expected IDxDiagContainer::GetNumberOfProps to return S_OK, got 0x%08x\n", hr);
431
432             if (!propcount)
433             {
434                 IDxDiagContainer_Release(child);
435                 child = NULL;
436             }
437             else
438                 break;
439         }
440     }
441
442     if (!child)
443     {
444         skip("Unable to find a container with non-zero property count\n");
445         goto cleanup;
446     }
447
448     hr = IDxDiagContainer_EnumPropNames(child, ~0, NULL, 0);
449     ok(hr == E_INVALIDARG, "Expected IDxDiagContainer::EnumPropNames to return E_INVALIDARG, got 0x%08x\n", hr);
450
451     memcpy(property, testW, sizeof(testW));
452     hr = IDxDiagContainer_EnumPropNames(child, ~0, property, 0);
453     ok(hr == E_INVALIDARG, "Expected IDxDiagContainer::EnumPropNames to return E_INVALIDARG, got 0x%08x\n", hr);
454     ok(!memcmp(property, testW, sizeof(testW)),
455        "Expected the property buffer to be unchanged, got %s\n", wine_dbgstr_w(property));
456
457     memcpy(property, testW, sizeof(testW));
458     hr = IDxDiagContainer_EnumPropNames(child, ~0, property, sizeof(property)/sizeof(WCHAR));
459     ok(hr == E_INVALIDARG, "Expected IDxDiagContainer::EnumPropNames to return E_INVALIDARG, got 0x%08x\n", hr);
460     ok(!memcmp(property, testW, sizeof(testW)),
461        "Expected the property buffer to be unchanged, got %s\n", wine_dbgstr_w(property));
462
463     trace("Starting property enumeration of the %s container:\n", wine_dbgstr_w(container));
464
465     /* We should be able to enumerate as many properties as the value that
466      * IDxDiagContainer::GetNumberOfProps returns. */
467     for (index = 0; index <= propcount; index++)
468     {
469         /* A buffer size of 1 is unlikely to be valid, as only a null terminator
470          * could be stored, and it is unlikely that a property name could be empty. */
471         DWORD buffersize = 1;
472
473         memcpy(property, testW, sizeof(testW));
474         hr = IDxDiagContainer_EnumPropNames(child, index, property, buffersize);
475         if (hr == E_INVALIDARG)
476         {
477             /* We should get here when index is one more than the maximum index value. */
478             ok(propcount == index,
479                "Expected IDxDiagContainer::EnumPropNames to return E_INVALIDARG "
480                "on the last index %d, got 0x%08x\n", index, hr);
481             ok(!memcmp(property, testW, sizeof(testW)),
482                "Expected the property buffer to be unchanged, got %s\n", wine_dbgstr_w(property));
483             break;
484         }
485         else if (hr == DXDIAG_E_INSUFFICIENT_BUFFER)
486         {
487             WCHAR temp[256];
488
489             ok(property[0] == '\0',
490                "Expected the property buffer string to be empty, got %s\n", wine_dbgstr_w(property));
491             hr = IDxDiagContainer_EnumPropNames(child, index, temp, sizeof(temp)/sizeof(WCHAR));
492             ok(hr == S_OK,
493                "Expected IDxDiagContainer::EnumPropNames to return S_OK, got 0x%08x\n", hr);
494
495             /* Show that the DirectX SDK's stipulation that the buffer be at
496              * least 256 characters long is a mere suggestion, and smaller sizes
497              * can be acceptable also. IDxDiagContainer::EnumPropNames doesn't
498              * provide a way of getting the exact size required, so the buffersize
499              * value will be iterated to at most 256 characters. */
500             for (buffersize = 2; buffersize <= 256; buffersize++)
501             {
502                 memcpy(property, testW, sizeof(testW));
503                 hr = IDxDiagContainer_EnumPropNames(child, index, property, buffersize);
504                 if (hr != DXDIAG_E_INSUFFICIENT_BUFFER)
505                     break;
506
507                 ok(!memcmp(temp, property, sizeof(WCHAR)*(buffersize - 1)),
508                    "Expected truncated property name string, got %s\n", wine_dbgstr_w(property));
509             }
510
511             ok(hr == S_OK,
512                "Expected IDxDiagContainer::EnumPropNames to return S_OK, "
513                "got hr = 0x%08x, buffersize = %d\n", hr, buffersize);
514             if (hr == S_OK)
515                 trace("child[%d] = %s, length = %d\n", index, wine_dbgstr_w(property), buffersize);
516         }
517         else
518         {
519             ok(0, "IDxDiagContainer::EnumPropNames unexpectedly returned 0x%08x\n", hr);
520             break;
521         }
522     }
523
524     IDxDiagContainer_Release(child);
525
526 cleanup:
527     IDxDiagContainer_Release(pddc);
528     IDxDiagProvider_Release(pddp);
529 }
530
531 static void test_GetProp(void)
532 {
533     HRESULT hr;
534     WCHAR container[256], property[256];
535     IDxDiagContainer *child = NULL;
536     DWORD count, index;
537     VARIANT var;
538     SAFEARRAY *sa;
539     SAFEARRAYBOUND bound;
540     static const WCHAR emptyW[] = {0};
541     static const WCHAR testW[] = {'t','e','s','t',0};
542
543     if (!create_root_IDxDiagContainer())
544     {
545         skip("Unable to create the root IDxDiagContainer\n");
546         return;
547     }
548
549     /* Find a container with a property. */
550     hr = IDxDiagContainer_GetNumberOfChildContainers(pddc, &count);
551     ok(hr == S_OK, "Expected IDxDiagContainer::GetNumberOfChildContainers to return S_OK, got 0x%08x\n", hr);
552     if (FAILED(hr))
553     {
554         skip("IDxDiagContainer::GetNumberOfChildContainers failed\n");
555         goto cleanup;
556     }
557
558     for (index = 0; index < count; index++)
559     {
560         hr = IDxDiagContainer_EnumChildContainerNames(pddc, index, container, sizeof(container)/sizeof(WCHAR));
561         ok(hr == S_OK, "Expected IDxDiagContainer_EnumChildContainerNames to return S_OK, got 0x%08x\n", hr);
562         if (FAILED(hr))
563         {
564             skip("IDxDiagContainer::EnumChildContainerNames failed\n");
565             goto cleanup;
566         }
567
568         hr = IDxDiagContainer_GetChildContainer(pddc, container, &child);
569         ok(hr == S_OK, "Expected IDxDiagContainer::GetChildContainer to return S_OK, got 0x%08x\n", hr);
570
571         if (SUCCEEDED(hr))
572         {
573             hr = IDxDiagContainer_EnumPropNames(child, 0, property, sizeof(property)/sizeof(WCHAR));
574             ok(hr == S_OK || hr == E_INVALIDARG,
575                "Expected IDxDiagContainer::EnumPropNames to return S_OK or E_INVALIDARG, got 0x%08x\n", hr);
576
577             if (SUCCEEDED(hr))
578                 break;
579             else
580             {
581                 IDxDiagContainer_Release(child);
582                 child = NULL;
583             }
584         }
585     }
586
587     if (!child)
588     {
589         skip("Unable to find a suitable container\n");
590         goto cleanup;
591     }
592
593     hr = IDxDiagContainer_GetProp(child, NULL, NULL);
594     ok(hr == E_INVALIDARG, "Expected IDxDiagContainer::GetProp to return E_INVALIDARG, got 0x%08x\n", hr);
595
596     V_VT(&var) = 0xdead;
597     hr = IDxDiagContainer_GetProp(child, NULL, &var);
598     ok(hr == E_INVALIDARG, "Expected IDxDiagContainer::GetProp to return E_INVALIDARG, got 0x%08x\n", hr);
599     ok(V_VT(&var) == 0xdead, "Expected the variant to be untouched, got %u\n", V_VT(&var));
600
601     hr = IDxDiagContainer_GetProp(child, emptyW, NULL);
602     ok(hr == E_INVALIDARG, "Expected IDxDiagContainer::GetProp to return E_INVALIDARG, got 0x%08x\n", hr);
603
604     V_VT(&var) = 0xdead;
605     hr = IDxDiagContainer_GetProp(child, emptyW, &var);
606     ok(hr == E_INVALIDARG, "Expected IDxDiagContainer::GetProp to return E_INVALIDARG, got 0x%08x\n", hr);
607     ok(V_VT(&var) == 0xdead, "Expected the variant to be untouched, got %u\n", V_VT(&var));
608
609     hr = IDxDiagContainer_GetProp(child, testW, NULL);
610     ok(hr == E_INVALIDARG, "Expected IDxDiagContainer::GetProp to return E_INVALIDARG, got 0x%08x\n", hr);
611
612     V_VT(&var) = 0xdead;
613     hr = IDxDiagContainer_GetProp(child, testW, &var);
614     ok(hr == E_INVALIDARG, "Expected IDxDiagContainer::GetProp to return E_INVALIDARG, got 0x%08x\n", hr);
615     ok(V_VT(&var) == 0xdead, "Expected the variant to be untouched, got %u\n", V_VT(&var));
616
617     VariantInit(&var);
618     hr = IDxDiagContainer_GetProp(child, property, &var);
619     ok(hr == S_OK, "Expected IDxDiagContainer::GetProp to return S_OK, got 0x%08x\n", hr);
620     ok(V_VT(&var) != VT_EMPTY, "Expected the variant to be modified, got %d\n", V_VT(&var));
621
622     /* Since the documentation for IDxDiagContainer::GetProp claims that the
623      * function reports return values from VariantCopy, try to exercise failure
624      * paths in handling the destination variant. */
625
626     /* Try an invalid variant type. */
627     V_VT(&var) = 0xdead;
628     hr = IDxDiagContainer_GetProp(child, property, &var);
629     ok(hr == S_OK, "Expected IDxDiagContainer::GetProp to return S_OK, got 0x%08x\n", hr);
630     ok(V_VT(&var) != 0xdead, "Expected the variant to be modified, got %d\n", V_VT(&var));
631
632     /* Try passing a variant with a locked SAFEARRAY. */
633     bound.cElements = 1;
634     bound.lLbound = 0;
635     sa = SafeArrayCreate(VT_UI1, 1, &bound);
636     ok(sa != NULL, "Expected SafeArrayCreate to return a valid pointer\n");
637
638     V_VT(&var) = (VT_ARRAY | VT_UI1);
639     V_ARRAY(&var) = sa;
640
641     hr = SafeArrayLock(sa);
642     ok(hr == S_OK, "Expected SafeArrayLock to return S_OK, got 0x%08x\n", hr);
643
644     hr = IDxDiagContainer_GetProp(child, property, &var);
645     ok(hr == S_OK, "Expected IDxDiagContainer::GetProp to return S_OK, got 0x%08x\n", hr);
646     ok(V_VT(&var) != (VT_ARRAY | VT_UI1), "Expected the variant to be modified\n");
647
648     hr = SafeArrayUnlock(sa);
649     ok(hr == S_OK, "Expected SafeArrayUnlock to return S_OK, got 0x%08x\n", hr);
650     hr = SafeArrayDestroy(sa);
651     ok(hr == S_OK, "Expected SafeArrayDestroy to return S_OK, got 0x%08x\n", hr);
652     IDxDiagContainer_Release(child);
653
654 cleanup:
655     IDxDiagContainer_Release(pddc);
656     IDxDiagProvider_Release(pddp);
657 }
658
659 static void test_root_children(void)
660 {
661     static const WCHAR DxDiag_SystemInfo[] = {'D','x','D','i','a','g','_','S','y','s','t','e','m','I','n','f','o',0};
662     static const WCHAR DxDiag_DisplayDevices[] = {'D','x','D','i','a','g','_','D','i','s','p','l','a','y','D','e','v','i','c','e','s',0};
663     static const WCHAR DxDiag_DirectSound[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','S','o','u','n','d',0};
664     static const WCHAR DxDiag_DirectMusic[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','M','u','s','i','c',0};
665     static const WCHAR DxDiag_DirectInput[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','I','n','p','u','t',0};
666     static const WCHAR DxDiag_DirectPlay[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','P','l','a','y',0};
667     static const WCHAR DxDiag_SystemDevices[] = {'D','x','D','i','a','g','_','S','y','s','t','e','m','D','e','v','i','c','e','s',0};
668     static const WCHAR DxDiag_DirectXFiles[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','X','F','i','l','e','s',0};
669     static const WCHAR DxDiag_DirectShowFilters[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','S','h','o','w','F','i','l','t','e','r','s',0};
670     static const WCHAR DxDiag_LogicalDisks[] = {'D','x','D','i','a','g','_','L','o','g','i','c','a','l','D','i','s','k','s',0};
671
672     HRESULT hr;
673     DWORD count, index;
674
675     static const WCHAR *root_children[] = {
676         DxDiag_SystemInfo, DxDiag_DisplayDevices, DxDiag_DirectSound,
677         DxDiag_DirectMusic, DxDiag_DirectInput, DxDiag_DirectPlay,
678         DxDiag_SystemDevices, DxDiag_DirectXFiles, DxDiag_DirectShowFilters,
679         DxDiag_LogicalDisks
680     };
681
682     if (!create_root_IDxDiagContainer())
683     {
684         skip("Unable to create the root IDxDiagContainer\n");
685         return;
686     }
687
688     /* Verify the identity and ordering of the root container's children. */
689     hr = IDxDiagContainer_GetNumberOfChildContainers(pddc, &count);
690     ok(hr == S_OK, "Expected IDxDiagContainer::GetNumberOfChildContainers to return S_OK, got 0x%08x\n", hr);
691     if (FAILED(hr))
692     {
693         skip("IDxDiagContainer::GetNumberOfChildContainers failed\n");
694         goto cleanup;
695     }
696
697     ok(count == sizeof(root_children)/sizeof(root_children[0]),
698        "Got unexpected count %u for the number of child containers\n", count);
699
700     if (count != sizeof(root_children)/sizeof(root_children[0]))
701     {
702         skip("Received unexpected number of child containers\n");
703         goto cleanup;
704     }
705
706     for (index = 0; index <= count; index++)
707     {
708         WCHAR container[256];
709
710         hr = IDxDiagContainer_EnumChildContainerNames(pddc, index, container, sizeof(container)/sizeof(WCHAR));
711         if (hr == E_INVALIDARG)
712         {
713             ok(index == count,
714                "Expected IDxDiagContainer::EnumChildContainerNames to return "
715                "E_INVALIDARG on the last index %u\n", count);
716             break;
717         }
718         else if (hr == S_OK)
719         {
720             ok(!lstrcmpW(container, root_children[index]),
721                "Expected container %s for index %u, got %s\n",
722                wine_dbgstr_w(root_children[index]), index, wine_dbgstr_w(container));
723         }
724         else
725         {
726             ok(0, "IDxDiagContainer::EnumChildContainerNames unexpectedly returned 0x%08x\n", hr);
727             break;
728         }
729     }
730
731 cleanup:
732     IDxDiagContainer_Release(pddc);
733     IDxDiagProvider_Release(pddp);
734 }
735
736 START_TEST(container)
737 {
738     CoInitialize(NULL);
739     test_GetNumberOfChildContainers();
740     test_GetNumberOfProps();
741     test_EnumChildContainerNames();
742     test_GetChildContainer();
743     test_dot_parsing();
744     test_EnumPropNames();
745     test_GetProp();
746
747     test_root_children();
748     CoUninitialize();
749 }