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 "precomp.h"
20 
21 static const WCHAR wszTestProperty1[] = {'P','r','o','p','e','r','t','y','1',0};
22 static const WCHAR wszTestProperty2[] = {'P','r','o','p','e','r','t','y','2',0};
23 static const WCHAR wszTestInvalidProperty[] = {'I','n','v','a','l','i','d',0};
24 
25 static void test_propertybag_getpropertyinfo(IPropertyBag2 *property, ULONG expected_count)
26 {
27     HRESULT hr;
28     PROPBAG2 pb[2];
29     ULONG out_count;
30 
31     /* iProperty: Out of bounce */
32     hr = IPropertyBag2_GetPropertyInfo(property, expected_count, 1, pb, &out_count);
33     ok(hr == WINCODEC_ERR_VALUEOUTOFRANGE,
34        "GetPropertyInfo handled iProperty out of bounce wrong, hr=%x\n", hr);
35 
36     /* cProperty: Out of bounce */
37     hr = IPropertyBag2_GetPropertyInfo(property, 0, expected_count+1, pb, &out_count);
38     ok(hr == WINCODEC_ERR_VALUEOUTOFRANGE,
39        "GetPropertyInfo handled cProperty out of bounce wrong, hr=%x\n", hr);
40 
41     /* GetPropertyInfo can be called for zero items on Windows 8 but not on Windows 7 (wine behaves like Win8) */
42     if (expected_count == 0)
43         return;
44 
45     hr = IPropertyBag2_GetPropertyInfo(property, 0, expected_count, pb, &out_count);
46     ok(hr == S_OK, "GetPropertyInfo failed, hr=%x\n", hr);
47     if (FAILED(hr))
48         return;
49 
50     ok(expected_count == out_count,
51        "GetPropertyInfo returned unexpected property count, %i != %i)\n",
52        expected_count, out_count);
53 
54     if(expected_count != 2)
55         return;
56 
57     ok(pb[0].vt == VT_UI1, "Invalid variant type, pb[0].vt=%x\n", pb[0].vt);
58     ok(pb[0].dwType == PROPBAG2_TYPE_DATA, "Invalid variant type, pb[0].dwType=%x\n", pb[0].dwType);
59     ok(lstrcmpW(pb[0].pstrName, wszTestProperty1) == 0, "Invalid property name, pb[0].pstrName=%s\n", wine_dbgstr_w(pb[0].pstrName));
60     CoTaskMemFree(pb[0].pstrName);
61 
62     ok(pb[1].vt == VT_R4, "Invalid variant type, pb[1].vt=%x\n", pb[1].vt);
63     ok(pb[1].dwType == PROPBAG2_TYPE_DATA, "Invalid variant type, pb[1].dwType=%x\n", pb[1].dwType);
64     ok(lstrcmpW(pb[1].pstrName, wszTestProperty2) == 0, "Invalid property name, pb[1].pstrName=%s\n", wine_dbgstr_w(pb[1].pstrName));
65     CoTaskMemFree(pb[1].pstrName);
66 }
67 
68 static void test_propertybag_countproperties(IPropertyBag2 *property, ULONG expected_count)
69 {
70     ULONG count = (ULONG)-1;
71     HRESULT hr;
72 
73     hr = IPropertyBag2_CountProperties(property, NULL);
74     ok(hr == E_INVALIDARG, "CountProperties returned unexpected result, hr=%x\n", hr);
75 
76     hr = IPropertyBag2_CountProperties(property, &count);
77     ok(hr == S_OK, "CountProperties failed, hr=%x\n", hr);
78 
79     if (FAILED(hr))
80         return;
81 
82     ok(count == expected_count, "CountProperties returned invalid value, count=%i\n", count);
83 }
84 
85 static void test_propertybag_read(IPropertyBag2 *property)
86 {
87     HRESULT hr;
88     PROPBAG2 options[3] = {{0}};
89     VARIANT values[3];
90     HRESULT itm_hr[3] = {S_OK, S_OK, S_OK};
91 
92     /* 1. One unknown property */
93     options[0].pstrName = (LPOLESTR)wszTestInvalidProperty;
94     hr = IPropertyBag2_Read(property, 1, options, NULL, values, itm_hr);
95     ok(hr == E_FAIL,
96        "Read for an unknown property did not fail with expected code, hr=%x\n", hr);
97 
98     /* 2. One known property */
99     options[0].pstrName = (LPOLESTR)wszTestProperty1;
100     itm_hr[0] = E_FAIL;
101     hr = IPropertyBag2_Read(property, 1, options, NULL, values, itm_hr);
102     ok(hr == S_OK, "Read failed, hr=%x\n", hr);
103     if (SUCCEEDED(hr))
104     {
105         ok(itm_hr[0] == S_OK,
106            "Read failed, itm_hr[0]=%x\n", itm_hr[0]);
107         ok(V_VT(&values[0]) == VT_UI1,
108            "Read failed, V_VT(&values[0])=%x\n", V_VT(&values[0]));
109         ok(V_UNION(&values[0], bVal) == 12,
110            "Read failed, &values[0]=%i\n", V_UNION(&values[0], bVal));
111 
112         VariantClear(&values[0]);
113     }
114 
115     /* 3. Two known properties */
116     options[0].pstrName = (LPOLESTR)wszTestProperty1;
117     options[1].pstrName = (LPOLESTR)wszTestProperty2;
118     itm_hr[0] = E_FAIL;
119     itm_hr[1] = E_FAIL;
120     hr = IPropertyBag2_Read(property, 2, options, NULL, values, itm_hr);
121     ok(hr == S_OK, "Read failed, hr=%x\n", hr);
122     if (SUCCEEDED(hr))
123     {
124         ok(itm_hr[0] == S_OK, "Read failed, itm_hr[0]=%x\n", itm_hr[0]);
125         ok(V_VT(&values[0]) == VT_UI1, "Read failed, V_VT(&values[0])=%x\n", V_VT(&values[0]));
126         ok(V_UNION(&values[0], bVal) == 12, "Read failed, &values[0]=%i\n", V_UNION(&values[0], bVal));
127 
128         ok(itm_hr[1] == S_OK, "Read failed, itm_hr[1]=%x\n", itm_hr[1]);
129         ok(V_VT(&values[1]) == VT_R4, "Read failed, V_VT(&values[1])=%x\n", V_VT(&values[1]));
130         ok(V_UNION(&values[1], fltVal) == (float)3.14, "Read failed, &values[1]=%f\n", V_UNION(&values[1], fltVal));
131 
132         VariantClear(&values[0]);
133         VariantClear(&values[1]);
134     }
135 
136 
137     /* 4. One unknown property between two valid */
138 
139     /* Exotic initializations so we can detect what is unchanged */
140     itm_hr[0] = -1; itm_hr[1] = -1; itm_hr[2] = -1;
141     V_VT(&values[0]) = VT_NULL;
142     V_VT(&values[1]) = VT_NULL;
143     V_VT(&values[2]) = VT_NULL;
144     V_UNION(&values[0], bVal) = 254;
145     V_UNION(&values[1], bVal) = 254;
146     V_UNION(&values[2], bVal) = 254;
147 
148     options[0].pstrName = (LPOLESTR)wszTestProperty1;
149     options[1].pstrName = (LPOLESTR)wszTestInvalidProperty;
150     options[2].pstrName = (LPOLESTR)wszTestProperty2;
151 
152     hr = IPropertyBag2_Read(property, 3, options, NULL, values, itm_hr);
153     ok(hr == E_FAIL, "Read failed, hr=%x\n", hr);
154     if (hr == E_FAIL)
155     {
156         ok(itm_hr[0] == S_OK, "Read error code has unexpected value, itm_hr[0]=%x\n", itm_hr[0]);
157         ok(itm_hr[1] == -1,   "Read error code has unexpected value, itm_hr[1]=%x\n", itm_hr[1]);
158         ok(itm_hr[2] == -1,   "Read error code has unexpected value, itm_hr[2]=%x\n", itm_hr[2]);
159 
160         ok(V_VT(&values[0]) == VT_UI1,  "Read variant has unexpected type, V_VT(&values[0])=%x\n", V_VT(&values[0]));
161         ok(V_VT(&values[1]) == VT_NULL, "Read variant has unexpected type, V_VT(&values[1])=%x\n", V_VT(&values[1]));
162         ok(V_VT(&values[2]) == VT_NULL, "Read variant has unexpected type, V_VT(&values[2])=%x\n", V_VT(&values[2]));
163 
164         ok(V_UNION(&values[0], bVal) == 12,  "Read variant has unexpected value, V_UNION(&values[0])=%i\n", V_UNION(&values[0], bVal));
165         ok(V_UNION(&values[1], bVal) == 254, "Read variant has unexpected value, V_UNION(&values[1])=%i\n", V_UNION(&values[1], bVal));
166         ok(V_UNION(&values[2], bVal) == 254, "Read variant has unexpected value, V_UNION(&values[2])=%i\n", V_UNION(&values[2], bVal));
167     }
168 }
169 
170 static void test_propertybag_write(IPropertyBag2 *property)
171 {
172     HRESULT hr;
173     PROPBAG2 options[2] = {{0}};
174     VARIANT values[2];
175 
176     VariantInit(&values[0]);
177     VariantInit(&values[1]);
178 
179     /* 1. One unknown property */
180     options[0].pstrName = (LPOLESTR)wszTestInvalidProperty;
181     hr = IPropertyBag2_Write(property, 1, options, values);
182     ok(hr == E_FAIL, "Write for an unknown property did not fail with expected code, hr=%x\n", hr);
183 
184     /* 2. One property without correct type */
185     options[0].pstrName = (LPOLESTR)wszTestProperty1;
186     V_VT(&values[0]) = VT_UI1;
187     V_UNION(&values[0], bVal) = 1;
188     hr = IPropertyBag2_Write(property, 1, options, values);
189     ok(hr == S_OK, "Write for one property failed, hr=%x\n", hr);
190 
191     /* 3. One property with mismatching type */
192     options[0].pstrName = (LPOLESTR)wszTestProperty1;
193     V_VT(&values[0]) = VT_I1;
194     V_UNION(&values[0], bVal) = 2;
195     hr = IPropertyBag2_Write(property, 1, options, values);
196     ok(hr == WINCODEC_ERR_PROPERTYUNEXPECTEDTYPE,
197        "Write with mismatching type did not fail with expected code hr=%x\n", hr);
198 
199     /* 4. Reset one property to empty */
200     options[0].pstrName = (LPOLESTR)wszTestProperty1;
201     VariantClear(&values[0]);
202     hr = IPropertyBag2_Write(property, 1, options, values);
203     ok(hr == WINCODEC_ERR_PROPERTYUNEXPECTEDTYPE,
204        "Write to reset to empty value does not fail with expected code, hr=%x\n", hr);
205 
206     /* 5. Set two properties */
207     options[0].pstrName = (LPOLESTR)wszTestProperty1;
208     V_VT(&values[0]) = VT_UI1;
209     V_UNION(&values[0], bVal) = 12;
210     options[1].pstrName = (LPOLESTR)wszTestProperty2;
211     V_VT(&values[1]) = VT_R4;
212     V_UNION(&values[1], fltVal) = (float)3.14;
213     hr = IPropertyBag2_Write(property, 2, options, values);
214     ok(hr == S_OK, "Write for two properties failed, hr=%x\n", hr);
215 }
216 
217 static void test_empty_propertybag(void)
218 {
219     HRESULT hr;
220     IWICComponentFactory *factory;
221     IPropertyBag2 *property;
222 
223     hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
224                           &IID_IWICComponentFactory, (void**)&factory);
225     ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
226 
227     hr = IWICComponentFactory_CreateEncoderPropertyBag(factory, NULL, 0, &property);
228 
229     ok(hr == S_OK, "Creating EncoderPropertyBag failed, hr=%x\n", hr);
230     if (FAILED(hr)) return;
231 
232     test_propertybag_countproperties(property, 0);
233 
234     test_propertybag_getpropertyinfo(property, 0);
235 
236     IPropertyBag2_Release(property);
237 
238     IWICComponentFactory_Release(factory);
239 }
240 
241 static void test_filled_propertybag(void)
242 {
243     HRESULT hr;
244     IWICComponentFactory *factory;
245     IPropertyBag2 *property;
246     PROPBAG2 opts[2]= {
247         {PROPBAG2_TYPE_DATA, VT_UI1, 0, 0, (LPOLESTR)wszTestProperty1, {0}},
248         {PROPBAG2_TYPE_DATA, VT_R4, 0, 0, (LPOLESTR)wszTestProperty2, {0}}
249     };
250 
251     hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
252                           &IID_IWICComponentFactory, (void**)&factory);
253     ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
254 
255     hr = IWICComponentFactory_CreateEncoderPropertyBag(factory, opts, 2, &property);
256 
257     ok(hr == S_OK, "Creating EncoderPropertyBag failed, hr=%x\n", hr);
258     if (FAILED(hr)) return;
259 
260     test_propertybag_countproperties(property, 2);
261 
262     test_propertybag_getpropertyinfo(property, 2);
263 
264     test_propertybag_write(property);
265 
266     test_propertybag_read(property);
267 
268     IPropertyBag2_Release(property);
269 
270     IWICComponentFactory_Release(factory);
271 }
272 
273 START_TEST(propertybag)
274 {
275     CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
276 
277     test_empty_propertybag();
278 
279     test_filled_propertybag();
280 
281     CoUninitialize();
282 }
283