1 /*
2  * PROJECT:     ReactOS api tests
3  * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4  * PURPOSE:     Tests for SHPropertyBag Read/Write
5  * COPYRIGHT:   Copyright 2023 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
6  */
7 
8 #include <apitest.h>
9 #include <shlwapi.h>
10 #include <shlobj.h>
11 #include <shlwapi_undoc.h>
12 
13 #include <pseh/pseh2.h>
14 
15 static LPCWSTR s_pszPropNames[4] = { NULL, NULL, NULL, NULL };
16 static VARTYPE s_vt;
17 static INT s_cRead = 0;
18 static INT s_cWrite = 0;
19 
20 static void ResetTest(VARTYPE vt,
21                   LPCWSTR pszName0 = NULL, LPCWSTR pszName1 = NULL,
22                   LPCWSTR pszName2 = NULL, LPCWSTR pszName3 = NULL)
23 {
24     s_vt = vt;
25     s_cRead = s_cWrite = 0;
26     s_pszPropNames[0] = pszName0;
27     s_pszPropNames[1] = pszName1;
28     s_pszPropNames[2] = pszName2;
29     s_pszPropNames[3] = pszName3;
30 }
31 
32 class CDummyPropertyBag : public IPropertyBag
33 {
34 public:
35     CDummyPropertyBag()
36     {
37     }
38 
39     // IUnknown
40     STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject) override
41     {
42         ok_int(0, 1);
43         return S_OK;
44     }
45     STDMETHODIMP_(ULONG) AddRef() override
46     {
47         ok_int(0, 1);
48         return S_OK;
49     }
50     STDMETHODIMP_(ULONG) Release() override
51     {
52         ok_int(0, 1);
53         return S_OK;
54     }
55 
56     // IPropertyBag
57     STDMETHODIMP Read(LPCWSTR pszPropName, VARIANT *pvari, IErrorLog *pErrorLog) override
58     {
59         ++s_cRead;
60         ok_int(s_vt, V_VT(pvari));
61         for (size_t i = 0; i < _countof(s_pszPropNames); ++i)
62         {
63             if (s_pszPropNames[i])
64             {
65                 ok_wstr(pszPropName, s_pszPropNames[i]);
66                 s_pszPropNames[i] = NULL;
67                 if (lstrcmpiW(pszPropName, L"RECTL2.top") == 0)
68                     return E_FAIL;
69 
70                 goto Skip1;
71             }
72         }
73         ok_int(0, 1);
74 Skip1:
75         return S_OK;
76     }
77 
78     STDMETHODIMP Write(LPCWSTR pszPropName, VARIANT *pvari) override
79     {
80         ++s_cWrite;
81         ok_int(s_vt, V_VT(pvari));
82         for (size_t i = 0; i < _countof(s_pszPropNames); ++i)
83         {
84             if (s_pszPropNames[i])
85             {
86                 ok_wstr(pszPropName, s_pszPropNames[i]);
87                 s_pszPropNames[i] = NULL;
88                 if (lstrcmpiW(pszPropName, L"RECTL2.bottom") == 0)
89                 {
90                     s_vt = VT_EMPTY;
91                     ZeroMemory(&s_pszPropNames, sizeof(s_pszPropNames));
92                     s_pszPropNames[0] = L"RECTL2.right";
93                     return E_FAIL;
94                 }
95                 goto Skip2;
96             }
97         }
98         ok_int(0, 1);
99 Skip2:
100         return S_OK;
101     }
102 };
103 
104 static void SHPropertyBag_ReadTest(void)
105 {
106     HRESULT hr;
107     CDummyPropertyBag dummy;
108     BOOL bValue = 0xDEADFACE;
109     SHORT sValue = 0xDEAD;
110     LONG lValue = 0xDEADDEAD;
111     DWORD dwValue = 0xFEEDF00D;
112     BSTR bstr = NULL;
113     POINTL ptl = { 0xEEEE, 0xDDDD };
114     POINTS pts = { 0x2222, 0x3333 };
115     RECTL rcl = { 123, 456, 789, 101112 };
116 
117     ResetTest(VT_BOOL, L"BOOL1");
118     hr = SHPropertyBag_ReadBOOL(&dummy, s_pszPropNames[0], &bValue);
119     ok_long(hr, S_OK);
120     ok_int(s_cRead, 1);
121     ok_int(s_cWrite, 0);
122 
123     ResetTest(VT_UI2, L"SHORT1");
124     hr = SHPropertyBag_ReadSHORT(&dummy, s_pszPropNames[0], &sValue);
125     ok_long(hr, S_OK);
126     ok_int(s_cRead, 1);
127     ok_int(s_cWrite, 0);
128 
129     ResetTest(VT_I4, L"LONG1");
130     hr = SHPropertyBag_ReadLONG(&dummy, s_pszPropNames[0], &lValue);
131     ok_long(hr, S_OK);
132     ok_int(s_cRead, 1);
133     ok_int(s_cWrite, 0);
134 
135     ResetTest(VT_UI4, L"DWORD1");
136     hr = SHPropertyBag_ReadDWORD(&dummy, s_pszPropNames[0], &dwValue);
137     ok_long(hr, S_OK);
138     ok_int(s_cRead, 1);
139     ok_int(s_cWrite, 0);
140 
141     ResetTest(VT_BSTR, L"Str1");
142     hr = SHPropertyBag_ReadBSTR(&dummy, s_pszPropNames[0], &bstr);
143     ok_long(hr, S_OK);
144     ok_int(s_cRead, 1);
145     ok_int(s_cWrite, 0);
146     SysFreeString(bstr);
147 
148     ResetTest(VT_I4, L"POINTL1.x", L"POINTL1.y");
149     hr = SHPropertyBag_ReadPOINTL(&dummy, L"POINTL1", &ptl);
150     ok_long(hr, S_OK);
151     ok_int(s_cRead, 2);
152     ok_int(s_cWrite, 0);
153 
154     ResetTest(VT_I4, L"POINTS1.x", L"POINTS1.y");
155     hr = SHPropertyBag_ReadPOINTS(&dummy, L"POINTS1", &pts);
156     ok_long(hr, S_OK);
157     ok_int(s_cRead, 2);
158     ok_int(s_cWrite, 0);
159 
160     ResetTest(VT_I4, L"RECTL1.left", L"RECTL1.top", L"RECTL1.right", L"RECTL1.bottom");
161     hr = SHPropertyBag_ReadRECTL(&dummy, L"RECTL1", &rcl);
162     ok_long(hr, S_OK);
163     ok_int(s_cRead, 4);
164     ok_int(s_cWrite, 0);
165 
166     ResetTest(VT_I4, L"RECTL2.left", L"RECTL2.top", L"RECTL2.right", L"RECTL2.bottom");
167     hr = SHPropertyBag_ReadRECTL(&dummy, L"RECTL2", &rcl);
168     ok_long(hr, E_FAIL);
169     ok_int(s_cRead, 2);
170     ok_int(s_cWrite, 0);
171 }
172 
173 static void SHPropertyBag_WriteTest(void)
174 {
175     HRESULT hr;
176     CDummyPropertyBag dummy;
177 
178     ResetTest(VT_EMPTY, L"EMPTY1");
179     hr = SHPropertyBag_Delete(&dummy, s_pszPropNames[0]);
180     ok_long(hr, S_OK);
181     ok_int(s_cRead, 0);
182     ok_int(s_cWrite, 1);
183 
184     ResetTest(VT_BOOL, L"BOOL1");
185     hr = SHPropertyBag_WriteBOOL(&dummy, s_pszPropNames[0], TRUE);
186     ok_long(hr, S_OK);
187     ok_int(s_cRead, 0);
188     ok_int(s_cWrite, 1);
189 
190     ResetTest(VT_UI2, L"SHORT1");
191     hr = SHPropertyBag_WriteSHORT(&dummy, s_pszPropNames[0], 1);
192     ok_long(hr, S_OK);
193     ok_int(s_cRead, 0);
194     ok_int(s_cWrite, 1);
195 
196     ResetTest(VT_I4, L"LONG1");
197     hr = SHPropertyBag_WriteLONG(&dummy, s_pszPropNames[0], 1);
198     ok_long(hr, S_OK);
199     ok_int(s_cRead, 0);
200     ok_int(s_cWrite, 1);
201 
202     ResetTest(VT_UI4, L"DWORD1");
203     hr = SHPropertyBag_WriteDWORD(&dummy, s_pszPropNames[0], 1);
204     ok_long(hr, S_OK);
205     ok_int(s_cRead, 0);
206     ok_int(s_cWrite, 1);
207 
208     ResetTest(VT_BSTR, L"Str1");
209     hr = SHPropertyBag_WriteStr(&dummy, s_pszPropNames[0], L"1");
210     ok_long(hr, S_OK);
211     ok_int(s_cRead, 0);
212     ok_int(s_cWrite, 1);
213 
214     ResetTest(VT_I4, L"POINTL1.x", L"POINTL1.y");
215     POINTL ptl = { 0xEEEE, 0xDDDD };
216     hr = SHPropertyBag_WritePOINTL(&dummy, L"POINTL1", &ptl);
217     ok_long(hr, S_OK);
218     ok_int(s_cRead, 0);
219     ok_int(s_cWrite, 2);
220 
221     ResetTest(VT_I4, L"POINTS1.x", L"POINTS1.y");
222     POINTS pts = { 0x2222, 0x3333 };
223     hr = SHPropertyBag_WritePOINTS(&dummy, L"POINTS1", &pts);
224     ok_long(hr, S_OK);
225     ok_int(s_cRead, 0);
226     ok_int(s_cWrite, 2);
227 
228     ResetTest(VT_I4, L"RECTL1.left", L"RECTL1.top", L"RECTL1.right", L"RECTL1.bottom");
229     RECTL rcl = { 123, 456, 789, 101112 };
230     hr = SHPropertyBag_WriteRECTL(&dummy, L"RECTL1", &rcl);
231     ok_long(hr, S_OK);
232     ok_int(s_cRead, 0);
233     ok_int(s_cWrite, 4);
234 
235     ResetTest(VT_I4, L"RECTL2.left", L"RECTL2.top", L"RECTL2.right", L"RECTL2.bottom");
236     hr = SHPropertyBag_WriteRECTL(&dummy, L"RECTL2", &rcl);
237     ok_long(hr, S_OK);
238     ok_int(s_cRead, 0);
239     ok_int(s_cWrite, 5);
240 
241     GUID guid;
242     ZeroMemory(&guid, sizeof(guid));
243     ResetTest(VT_BSTR, L"GUID1");
244     hr = SHPropertyBag_WriteGUID(&dummy, L"GUID1", &guid);
245     ok_long(hr, S_OK);
246     ok_int(s_cRead, 0);
247     ok_int(s_cWrite, 1);
248 }
249 
250 START_TEST(SHPropertyBag)
251 {
252     SHPropertyBag_ReadTest();
253     SHPropertyBag_WriteTest();
254 }
255