Release 1.5.29.
[wine] / dlls / windowscodecs / tests / propertybag.c
1 /*
2  * Copyright 2013 Ludger Sprenker
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include <stdarg.h>
20 #include <math.h>
21
22 #define COBJMACROS
23 #define CONST_VTABLE
24
25 #include "windef.h"
26 #include "objbase.h"
27 #include "wincodec.h"
28 #include "wincodecsdk.h"
29 #include "wine/test.h"
30
31 static const WCHAR wszTestProperty1[] = {'P','r','o','p','e','r','t','y','1',0};
32 static const WCHAR wszTestProperty2[] = {'P','r','o','p','e','r','t','y','2',0};
33 static const WCHAR wszTestInvalidProperty[] = {'I','n','v','a','l','i','d',0};
34
35 static void test_propertybag_getpropertyinfo(IPropertyBag2 *property, ULONG expected_count)
36 {
37     HRESULT hr;
38     PROPBAG2 pb[2];
39     ULONG out_count;
40
41     /* iProperty: Out of bounce */
42     hr = IPropertyBag2_GetPropertyInfo(property, expected_count, 1, pb, &out_count);
43     ok(hr == WINCODEC_ERR_VALUEOUTOFRANGE,
44        "GetPropertyInfo handled iProperty out of bounce wrong, hr=%x\n", hr);
45
46     /* cProperty: Out of bounce */
47     hr = IPropertyBag2_GetPropertyInfo(property, 0, expected_count+1, pb, &out_count);
48     ok(hr == WINCODEC_ERR_VALUEOUTOFRANGE,
49        "GetPropertyInfo handled cProperty out of bounce wrong, hr=%x\n", hr);
50
51     /* GetPropertyInfo can be called for zero items on Windows 8 but not on Windows 7 (wine behaves like Win8) */
52     if (expected_count == 0)
53         return;
54
55     hr = IPropertyBag2_GetPropertyInfo(property, 0, expected_count, pb, &out_count);
56     ok(hr == S_OK, "GetPropertyInfo failed, hr=%x\n", hr);
57     if (FAILED(hr))
58         return;
59
60     ok(expected_count == out_count,
61        "GetPropertyInfo returned unexpected property count, %i != %i)\n",
62        expected_count, out_count);
63
64     if(expected_count != 2)
65         return;
66
67     ok(pb[0].vt == VT_UI1, "Invalid variant type, pb[0].vt=%x\n", pb[0].vt);
68     ok(pb[0].dwType == PROPBAG2_TYPE_DATA, "Invalid variant type, pb[0].dwType=%x\n", pb[0].dwType);
69     ok(lstrcmpW(pb[0].pstrName, wszTestProperty1) == 0, "Invalid property name, pb[0].pstrName=%s\n", wine_dbgstr_w(pb[0].pstrName));
70
71     ok(pb[1].vt == VT_R4, "Invalid variant type, pb[1].vt=%x\n", pb[1].vt);
72     ok(pb[1].dwType == PROPBAG2_TYPE_DATA, "Invalid variant type, pb[1].dwType=%x\n", pb[1].dwType);
73     ok(lstrcmpW(pb[1].pstrName, wszTestProperty2) == 0, "Invalid property name, pb[1].pstrName=%s\n", wine_dbgstr_w(pb[1].pstrName));
74 }
75
76 static void test_propertybag_countproperties(IPropertyBag2 *property, ULONG expected_count)
77 {
78     ULONG count = (ULONG)-1;
79     HRESULT hr;
80
81     hr = IPropertyBag2_CountProperties(property, NULL);
82     ok(hr == E_INVALIDARG, "CountProperties returned unexpected result, hr=%x\n", hr);
83
84     hr = IPropertyBag2_CountProperties(property, &count);
85     ok(hr == S_OK, "CountProperties failed, hr=%x\n", hr);
86
87     if (FAILED(hr))
88         return;
89
90     ok(count == expected_count, "CountProperties returned invalid value, count=%i\n", count);
91 }
92
93 static void test_propertybag_read(IPropertyBag2 *property)
94 {
95     HRESULT hr;
96     PROPBAG2 options[3] = {{0}};
97     VARIANT values[3];
98     HRESULT itm_hr[3] = {S_OK, S_OK, S_OK};
99
100     /* 1. One unknown property */
101     options[0].pstrName = (LPOLESTR)wszTestInvalidProperty;
102     hr = IPropertyBag2_Read(property, 1, options, NULL, values, itm_hr);
103     ok(hr == E_FAIL,
104        "Read for an unknown property did not fail with expected code, hr=%x\n", hr);
105
106     /* 2. One known property */
107     options[0].pstrName = (LPOLESTR)wszTestProperty1;
108     itm_hr[0] = E_FAIL;
109     hr = IPropertyBag2_Read(property, 1, options, NULL, values, itm_hr);
110     ok(hr == S_OK, "Read failed, hr=%x\n", hr);
111     if (SUCCEEDED(hr))
112     {
113         ok(itm_hr[0] == S_OK,
114            "Read failed, itm_hr[0]=%x\n", itm_hr[0]);
115         ok(V_VT(&values[0]) == VT_UI1,
116            "Read failed, V_VT(&values[0])=%x\n", V_VT(&values[0]));
117         ok(V_UNION(&values[0], bVal) == 12,
118            "Read failed, &values[0]=%i\n", V_UNION(&values[0], bVal));
119
120         VariantClear(&values[0]);
121     }
122
123     /* 3. Two known properties */
124     options[0].pstrName = (LPOLESTR)wszTestProperty1;
125     options[1].pstrName = (LPOLESTR)wszTestProperty2;
126     itm_hr[0] = E_FAIL;
127     itm_hr[1] = E_FAIL;
128     hr = IPropertyBag2_Read(property, 2, options, NULL, values, itm_hr);
129     ok(hr == S_OK, "Read failed, hr=%x\n", hr);
130     if (SUCCEEDED(hr))
131     {
132         ok(itm_hr[0] == S_OK, "Read failed, itm_hr[0]=%x\n", itm_hr[0]);
133         ok(V_VT(&values[0]) == VT_UI1, "Read failed, V_VT(&values[0])=%x\n", V_VT(&values[0]));
134         ok(V_UNION(&values[0], bVal) == 12, "Read failed, &values[0]=%i\n", V_UNION(&values[0], bVal));
135
136         ok(itm_hr[1] == S_OK, "Read failed, itm_hr[1]=%x\n", itm_hr[1]);
137         ok(V_VT(&values[1]) == VT_R4, "Read failed, V_VT(&values[1])=%x\n", V_VT(&values[1]));
138         ok(V_UNION(&values[1], fltVal) == (float)3.14, "Read failed, &values[1]=%f\n", V_UNION(&values[1], fltVal));
139
140         VariantClear(&values[0]);
141         VariantClear(&values[1]);
142     }
143
144
145     /* 4. One unknown property between two valid */
146
147     /* Exotic initializations so we can detect what is unchanged */
148     itm_hr[0] = -1; itm_hr[1] = -1; itm_hr[2] = -1;
149     V_VT(&values[0]) = VT_NULL;
150     V_VT(&values[1]) = VT_NULL;
151     V_VT(&values[2]) = VT_NULL;
152     V_UNION(&values[0], bVal) = 254;
153     V_UNION(&values[1], bVal) = 254;
154     V_UNION(&values[2], bVal) = 254;
155
156     options[0].pstrName = (LPOLESTR)wszTestProperty1;
157     options[1].pstrName = (LPOLESTR)wszTestInvalidProperty;
158     options[2].pstrName = (LPOLESTR)wszTestProperty2;
159
160     hr = IPropertyBag2_Read(property, 3, options, NULL, values, itm_hr);
161     ok(hr == E_FAIL, "Read failed, hr=%x\n", hr);
162     if (hr == E_FAIL)
163     {
164         ok(itm_hr[0] == S_OK, "Read error code has unexpected value, itm_hr[0]=%x\n", itm_hr[0]);
165         ok(itm_hr[1] == -1,   "Read error code has unexpected value, itm_hr[1]=%x\n", itm_hr[1]);
166         ok(itm_hr[2] == -1,   "Read error code has unexpected value, itm_hr[2]=%x\n", itm_hr[2]);
167
168         ok(V_VT(&values[0]) == VT_UI1,  "Read variant has unexpected type, V_VT(&values[0])=%x\n", V_VT(&values[0]));
169         ok(V_VT(&values[1]) == VT_NULL, "Read variant has unexpected type, V_VT(&values[1])=%x\n", V_VT(&values[1]));
170         ok(V_VT(&values[2]) == VT_NULL, "Read variant has unexpected type, V_VT(&values[2])=%x\n", V_VT(&values[2]));
171
172         ok(V_UNION(&values[0], bVal) == 12,  "Read variant has unexpected value, V_UNION(&values[0])=%i\n", V_UNION(&values[0], bVal));
173         ok(V_UNION(&values[1], bVal) == 254, "Read variant has unexpected value, V_UNION(&values[1])=%i\n", V_UNION(&values[1], bVal));
174         ok(V_UNION(&values[2], bVal) == 254, "Read variant has unexpected value, V_UNION(&values[2])=%i\n", V_UNION(&values[2], bVal));
175     }
176 }
177
178 static void test_propertybag_write(IPropertyBag2 *property)
179 {
180     HRESULT hr;
181     PROPBAG2 options[2] = {{0}};
182     VARIANT values[2];
183
184     VariantInit(&values[0]);
185     VariantInit(&values[1]);
186
187     /* 1. One unknown property */
188     options[0].pstrName = (LPOLESTR)wszTestInvalidProperty;
189     hr = IPropertyBag2_Write(property, 1, options, values);
190     ok(hr == E_FAIL, "Write for an unknown property did not fail with expected code, hr=%x\n", hr);
191
192     /* 2. One property without correct type */
193     options[0].pstrName = (LPOLESTR)wszTestProperty1;
194     V_VT(&values[0]) = VT_UI1;
195     V_UNION(&values[0], bVal) = 1;
196     hr = IPropertyBag2_Write(property, 1, options, values);
197     ok(hr == S_OK, "Write for one property failed, hr=%x\n", hr);
198
199     /* 3. One property with mismatching type */
200     options[0].pstrName = (LPOLESTR)wszTestProperty1;
201     V_VT(&values[0]) = VT_I1;
202     V_UNION(&values[0], bVal) = 2;
203     hr = IPropertyBag2_Write(property, 1, options, values);
204     ok(hr == WINCODEC_ERR_PROPERTYUNEXPECTEDTYPE,
205        "Write with mismatching type did not fail with expected code hr=%x\n", hr);
206
207     /* 4. Reset one property to empty */
208     options[0].pstrName = (LPOLESTR)wszTestProperty1;
209     VariantClear(&values[0]);
210     hr = IPropertyBag2_Write(property, 1, options, values);
211     ok(hr == WINCODEC_ERR_PROPERTYUNEXPECTEDTYPE,
212        "Write to reset to empty value does not fail with expected code, hr=%x\n", hr);
213
214     /* 5. Set two properties */
215     options[0].pstrName = (LPOLESTR)wszTestProperty1;
216     V_VT(&values[0]) = VT_UI1;
217     V_UNION(&values[0], bVal) = 12;
218     options[1].pstrName = (LPOLESTR)wszTestProperty2;
219     V_VT(&values[1]) = VT_R4;
220     V_UNION(&values[1], fltVal) = (float)3.14;
221     hr = IPropertyBag2_Write(property, 2, options, values);
222     ok(hr == S_OK, "Write for two properties failed, hr=%x\n", hr);
223 }
224
225 static void test_empty_propertybag(void)
226 {
227     HRESULT hr;
228     IWICComponentFactory *factory;
229     IPropertyBag2 *property;
230
231     hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
232                           &IID_IWICComponentFactory, (void**)&factory);
233     ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
234
235     hr = IWICComponentFactory_CreateEncoderPropertyBag(factory, NULL, 0, &property);
236
237     ok(hr == S_OK, "Creating EncoderPropertyBag failed, hr=%x\n", hr);
238     if (FAILED(hr)) return;
239
240     test_propertybag_countproperties(property, 0);
241
242     test_propertybag_getpropertyinfo(property, 0);
243
244     IPropertyBag2_Release(property);
245
246     IWICComponentFactory_Release(factory);
247 }
248
249 static void test_filled_propertybag(void)
250 {
251     HRESULT hr;
252     IWICComponentFactory *factory;
253     IPropertyBag2 *property;
254     PROPBAG2 opts[2]= {
255         {.pstrName = (LPOLESTR)wszTestProperty1, .vt=VT_UI1, .dwType=PROPBAG2_TYPE_DATA},
256         {.pstrName = (LPOLESTR)wszTestProperty2, .vt=VT_R4,  .dwType=PROPBAG2_TYPE_DATA}
257     };
258
259     hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
260                           &IID_IWICComponentFactory, (void**)&factory);
261     ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
262
263     hr = IWICComponentFactory_CreateEncoderPropertyBag(factory, opts, 2, &property);
264
265     ok(hr == S_OK, "Creating EncoderPropertyBag failed, hr=%x\n", hr);
266     if (FAILED(hr)) return;
267
268     test_propertybag_countproperties(property, 2);
269
270     test_propertybag_getpropertyinfo(property, 2);
271
272     test_propertybag_write(property);
273
274     test_propertybag_read(property);
275
276     IPropertyBag2_Release(property);
277
278     IWICComponentFactory_Release(factory);
279 }
280
281 START_TEST(propertybag)
282 {
283     CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
284
285     test_empty_propertybag();
286
287     test_filled_propertybag();
288
289     CoUninitialize();
290 }