Fix some gcc 4.0 warnings.
[wine] / dlls / ntdll / tests / atom.c
1 /* Unit test suite for Ntdll atom API functions
2  *
3  * Copyright 2003 Gyorgy 'Nog' Jeney
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  * NOTES
20  * We use function pointers here as there is no import library for NTDLL on
21  * windows.
22  */
23
24 #include <stdio.h>
25 #include <stdarg.h>
26
27 #include "ntstatus.h"
28 /* Define WIN32_NO_STATUS so MSVC does not give us duplicate macro 
29  * definition errors when we get to winnt.h
30  */
31 #define WIN32_NO_STATUS
32
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winreg.h"
36 #include "winnls.h"
37 #include "wine/test.h"
38 #include "wine/unicode.h"
39 #include "winternl.h"
40
41 #ifndef __WINE_WINTERNL_H
42 typedef unsigned short RTL_ATOM, *PRTL_ATOM;
43 typedef struct atom_table *RTL_ATOM_TABLE, **PRTL_ATOM_TABLE;
44 #endif
45
46 /* Function pointers for ntdll calls */
47 static HMODULE hntdll = 0;
48 static NTSTATUS (WINAPI *pRtlCreateAtomTable)(ULONG,PRTL_ATOM_TABLE);
49 static NTSTATUS (WINAPI *pRtlDestroyAtomTable)(RTL_ATOM_TABLE);
50 static NTSTATUS (WINAPI *pRtlEmptyAtomTable)(RTL_ATOM_TABLE,BOOLEAN);
51 static NTSTATUS (WINAPI *pRtlAddAtomToAtomTable)(RTL_ATOM_TABLE,PCWSTR,PRTL_ATOM);
52 static NTSTATUS (WINAPI *pRtlDeleteAtomFromAtomTable)(RTL_ATOM_TABLE,RTL_ATOM);
53 static NTSTATUS (WINAPI *pRtlLookupAtomInAtomTable)(RTL_ATOM_TABLE,PCWSTR,PRTL_ATOM);
54 static NTSTATUS (WINAPI *pRtlPinAtomInAtomTable)(RTL_ATOM_TABLE,RTL_ATOM);
55 static NTSTATUS (WINAPI *pRtlQueryAtomInAtomTable)(RTL_ATOM_TABLE,RTL_ATOM,PULONG,PULONG,PWSTR,PULONG);
56
57 static const WCHAR EmptyAtom[] = {0};
58 static const WCHAR testAtom1[] = {'H','e','l','l','o',' ','W','o','r','l','d',0};
59 static const WCHAR testAtom2[] = {'H','e','l','l','o',' ','W','o','r','l','d','2',0};
60 static const WCHAR testAtom3[] = {'H','e','l','l','o',' ','W','o','r','l','d','3',0};
61
62 static const WCHAR testAtom1Cap[] = {'H','E','L','L','O',' ','W','O','R','L','D',0};
63 static const WCHAR testAtom1Low[] = {'h','e','l','l','o',' ','w','o','r','l','d',0};
64
65 static const WCHAR testAtomInt[] = {'#','1','3','2',0};
66 static const WCHAR testAtomIntInv[] = {'#','2','3','4','z',0};
67 static const WCHAR testAtomOTT[] = {'#','1','2','3',0};
68
69 static void InitFunctionPtr(void)
70 {
71     hntdll = LoadLibraryA("ntdll.dll");
72     ok(hntdll != 0, "Unable to load ntdll.dll\n");
73
74     if (hntdll)
75     {
76         pRtlCreateAtomTable = (void *)GetProcAddress(hntdll, "RtlCreateAtomTable");
77         pRtlDestroyAtomTable = (void *)GetProcAddress(hntdll, "RtlDestroyAtomTable");
78         pRtlEmptyAtomTable = (void *)GetProcAddress(hntdll, "RtlEmptyAtomTable");
79         pRtlAddAtomToAtomTable = (void *)GetProcAddress(hntdll, "RtlAddAtomToAtomTable");
80         pRtlDeleteAtomFromAtomTable = (void *)GetProcAddress(hntdll, "RtlDeleteAtomFromAtomTable");
81         pRtlLookupAtomInAtomTable = (void *)GetProcAddress(hntdll, "RtlLookupAtomInAtomTable");
82         pRtlPinAtomInAtomTable = (void *)GetProcAddress(hntdll, "RtlPinAtomInAtomTable");
83         pRtlQueryAtomInAtomTable = (void *)GetProcAddress(hntdll, "RtlQueryAtomInAtomTable");
84     }
85 }
86
87 static DWORD RtlAtomTestThread(LPVOID Table)
88 {
89     RTL_ATOM_TABLE AtomTable = *(PRTL_ATOM_TABLE)Table;
90     RTL_ATOM Atom;
91     NTSTATUS res;
92     ULONG RefCount = 0, PinCount = 0, Len = 0;
93     WCHAR Name[64];
94
95     res = pRtlLookupAtomInAtomTable(AtomTable, testAtom1, &Atom);
96     ok(!res, "Unable to find atom from another thread, retval: %lx\n", res);
97
98     res = pRtlLookupAtomInAtomTable(AtomTable, testAtom2, &Atom);
99     ok(!res, "Unable to lookup pinned atom in table, retval: %lx\n", res);
100
101     res = pRtlQueryAtomInAtomTable(AtomTable, Atom, &RefCount, &PinCount, Name, &Len);
102     ok(res == STATUS_BUFFER_TOO_SMALL, "We got wrong retval: %lx\n", res);
103
104     Len = 64;
105     res = pRtlQueryAtomInAtomTable(AtomTable, Atom, &RefCount, &PinCount, Name, &Len);
106     ok(!res, "Failed with longenough buffer, retval: %lx\n", res);
107     ok(RefCount == 1, "Refcount was not 1 but %lx\n", RefCount);
108     ok(PinCount == 1, "Pincount was not 1 but %lx\n", PinCount);
109     ok(!strcmpW(Name, testAtom2), "We found wrong atom!!\n");
110     ok((strlenW(testAtom2) * sizeof(WCHAR)) == Len, "Returned wrong length %ld\n", Len);
111
112     Len = 64;
113     res = pRtlQueryAtomInAtomTable(AtomTable, Atom, NULL, NULL, Name, &Len);
114     ok(!res, "RtlQueryAtomInAtomTable with optional args invalid failed, retval: %lx\n", res);
115     ok(!strcmpW(Name, testAtom2), "Found Wrong atom!\n");
116     ok((strlenW(testAtom2) * sizeof(WCHAR)) == Len, "Returned wrong length %ld\n", Len);
117
118     res = pRtlPinAtomInAtomTable(AtomTable, Atom);
119     ok(!res, "Unable to pin atom in atom table, retval: %lx\n", res);
120
121     return 0;
122 }
123
124 static void test_NtAtom(void)
125 {
126     RTL_ATOM_TABLE AtomTable = NULL;
127     NTSTATUS res;
128     RTL_ATOM Atom1, Atom2, Atom3, testEAtom, testAtom;
129     HANDLE testThread;
130     ULONG RefCount = 0, PinCount = 0, Len = 0;
131     WCHAR Name[64];
132
133     /* If we pass a non-null string to create atom table, then it thinks that we
134      * have passed it an already allocated atom table */
135     res = pRtlCreateAtomTable(0, &AtomTable);
136     ok(!res, "RtlCreateAtomTable should succeed with an atom table size of 0\n");
137
138     if (!res)
139     {
140         res = pRtlDestroyAtomTable(AtomTable);
141         ok(!res, "We could create the atom table, but we couldn't destroy it! retval: %lx\n", res);
142     }
143
144     AtomTable = NULL;
145     res = pRtlCreateAtomTable(37, &AtomTable);
146     ok(!res, "We're unable to create an atom table with a valid table size retval: %lx\n", res);
147     if (!res)
148     {
149         res = pRtlAddAtomToAtomTable(AtomTable, testAtom1, &Atom1);
150         ok(!res, "We were unable to add a simple atom to the atom table, retval: %lx\n", res);
151
152         res = pRtlLookupAtomInAtomTable(AtomTable, testAtom1Cap, &testAtom);
153         ok(!res, "We were unable to find capital version of the atom, retval: %lx\n", res);
154         ok(Atom1 == testAtom, "Found wrong atom in table when querying capital atom\n");
155
156         res = pRtlLookupAtomInAtomTable(AtomTable, testAtom1Low, &testAtom);
157         ok(!res, "Unable to find lowercase version of the atom, retval: %lx\n", res);
158         ok(testAtom == Atom1, "Found wrong atom when querying lowercase atom\n");
159
160         res = pRtlAddAtomToAtomTable(AtomTable, EmptyAtom, &testEAtom);
161         ok(res == STATUS_OBJECT_NAME_INVALID, "Got wrong retval, retval: %lx\n", res);
162
163         res = pRtlLookupAtomInAtomTable(AtomTable, testAtom1, &testAtom);
164         ok(!res, "Failed to find totally legitimate atom, retval: %lx\n", res);
165         ok(testAtom == Atom1, "Found wrong atom!\n");
166
167         res = pRtlAddAtomToAtomTable(AtomTable, testAtom2, &Atom2);
168         ok(!res, "Unable to add other legitimate atom to table, retval: %lx\n", res);
169
170         res = pRtlPinAtomInAtomTable(AtomTable, Atom2);
171         ok(!res, "Unable to pin atom in atom table, retval: %lx\n", res);
172
173         testThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)RtlAtomTestThread, &AtomTable, 0, NULL);
174         WaitForSingleObject(testThread, INFINITE);
175
176         Len = 64;
177         res = pRtlQueryAtomInAtomTable(AtomTable, Atom2, &RefCount, &PinCount, Name, &Len);
178         ok(!res, "Unable to query atom in atom table, retval: %lx\n", res);
179         ok(RefCount == 1, "RefCount is not 1 but %lx\n", RefCount);
180         ok(PinCount == 1, "PinCount is not 1 but %lx\n", PinCount);
181         ok(!strcmpW(Name, testAtom2), "We found wrong atom\n");
182         ok((strlenW(testAtom2) * sizeof(WCHAR)) == Len, "Returned wrong length %ld\n", Len);
183
184         res = pRtlEmptyAtomTable(AtomTable, FALSE);
185         ok(!res, "Unable to empty atom table, retval %lx\n", res);
186
187         Len = 64;
188         res = pRtlQueryAtomInAtomTable(AtomTable, Atom2, &RefCount, &PinCount, Name, &Len);
189         ok(!res, "It seems RtlEmptyAtomTable deleted our pinned atom eaven though we asked it not to, retval: %lx\n", res);
190         ok(RefCount == 1, "RefCount is not 1 but %lx\n", RefCount);
191         ok(PinCount == 1, "PinCount is not 1 but %lx\n", PinCount);
192         ok(!strcmpW(Name, testAtom2), "We found wrong atom\n");
193         ok((strlenW(testAtom2) * sizeof(WCHAR)) == Len, "Returned wrong length %ld\n", Len);
194
195         res = pRtlLookupAtomInAtomTable(AtomTable, testAtom2, &testAtom);
196         ok(!res, "We can't find our pinned atom!! retval: %lx\n", res);
197         ok(testAtom == Atom2, "We found wrong atom!!!\n");
198
199         res = pRtlLookupAtomInAtomTable(AtomTable, testAtom1, &testAtom);
200         ok(res == STATUS_OBJECT_NAME_NOT_FOUND, "We found the atom in our table eaven though we asked RtlEmptyAtomTable to remove it, retval: %lx\n", res);
201
202         res = pRtlAddAtomToAtomTable(AtomTable, testAtom3, &Atom3);
203         ok(!res, "Unable to add atom to table, retval: %lx\n", res);
204
205         res = pRtlEmptyAtomTable(AtomTable, TRUE);
206         ok(!res, "Unable to empty atom table, retval: %lx\n", res);
207
208         res = pRtlLookupAtomInAtomTable(AtomTable, testAtom2, &testAtom);
209         ok(res == STATUS_OBJECT_NAME_NOT_FOUND, "The pinned atom should be removed, retval: %lx\n", res);
210
211         res = pRtlLookupAtomInAtomTable(AtomTable, testAtom3, &testAtom);
212         ok(res == STATUS_OBJECT_NAME_NOT_FOUND, "Non pinned atom should also be removed, retval: %lx\n", res);
213
214         res = pRtlDestroyAtomTable(AtomTable);
215         ok(!res, "Can't destroy atom table, retval: %lx\n", res);
216     }
217
218     AtomTable = NULL;
219     res = pRtlCreateAtomTable(37, &AtomTable);
220     ok(!res, "Unable to create atom table, retval: %lx\n", res);
221
222     if (!res)
223     {
224         res = pRtlLookupAtomInAtomTable(AtomTable, testAtom1, &testAtom);
225         ok(res == STATUS_OBJECT_NAME_NOT_FOUND, "Didn't get expected retval with querying an empty atom table, retval: %lx\n", res);
226
227         res = pRtlAddAtomToAtomTable(AtomTable, testAtom1, &Atom1);
228         ok(!res, "Unable to add atom to atom table, retval %lx\n", res);
229
230         res = pRtlLookupAtomInAtomTable(AtomTable, testAtom1, &testAtom);
231         ok(!res, "Can't find previously added atom in table, retval: %lx\n", res);
232         ok(testAtom == Atom1, "Found wrong atom! retval: %lx\n", res);
233
234         res = pRtlDeleteAtomFromAtomTable(AtomTable, Atom1);
235         ok(!res, "Unable to delete atom from table, retval: %lx\n", res);
236
237         res = pRtlLookupAtomInAtomTable(AtomTable, testAtom1, &testAtom);
238         ok(res == STATUS_OBJECT_NAME_NOT_FOUND, "Able to find previously deleted atom in table, retval: %lx\n", res);
239
240         res = pRtlAddAtomToAtomTable(AtomTable, testAtom1, &Atom1);
241         ok(!res, "Unable to add atom to atom table, retval: %lx\n", res);
242
243         Len = 0;
244         res = pRtlQueryAtomInAtomTable(AtomTable, Atom1, NULL, NULL, Name, &Len);
245         ok(res == STATUS_BUFFER_TOO_SMALL, "Got wrong retval, retval: %lx\n", res);
246         ok((strlenW(testAtom1) * sizeof(WCHAR)) == Len, "Got wrong length %lx\n", Len);
247
248         res = pRtlPinAtomInAtomTable(AtomTable, Atom1);
249         ok(!res, "Unable to pin atom in atom table, retval: %lx\n", res);
250
251         res = pRtlLookupAtomInAtomTable(AtomTable, testAtom1, &testAtom);
252         ok(!res, "Unable to find atom in atom table, retval: %lx\n", res);
253         ok(testAtom == Atom1, "Wrong atom found\n");
254
255         res = pRtlDeleteAtomFromAtomTable(AtomTable, Atom1);
256         ok(res == STATUS_WAS_LOCKED, "Unable to delete atom from table, retval: %lx\n", res);
257
258         res = pRtlLookupAtomInAtomTable(AtomTable, testAtom1, &testAtom);
259         ok(!res, "Able to find deleted atom in table\n");
260
261         res = pRtlDestroyAtomTable(AtomTable);
262         ok(!res, "Unable to destroy atom table\n");
263     }
264 }
265
266 /* Test Adding integer atoms to atom table */
267 static void test_NtIntAtom(void)
268 {
269     NTSTATUS res;
270     RTL_ATOM_TABLE AtomTable;
271     RTL_ATOM testAtom;
272     ULONG RefCount = 0, PinCount = 0;
273     int i;
274     WCHAR Name[64];
275     ULONG Len;
276
277     AtomTable = NULL;
278     res = pRtlCreateAtomTable(37, &AtomTable);
279     ok(!res, "Unable to create atom table, %lx\n", res);
280
281     if (!res)
282     {
283         /* According to the kernel32 functions, integer atoms are only allowd from
284          * 0x0001 to 0xbfff and not 0xc000 to 0xffff, which is correct */
285         res = pRtlAddAtomToAtomTable(AtomTable, (PWSTR)0, &testAtom);
286         ok(res == STATUS_INVALID_PARAMETER, "Didn't get expected result from adding 0 int atom, retval: %lx\n", res);
287         for (i = 1; i <= 0xbfff; i++)
288         {
289             res = pRtlAddAtomToAtomTable(AtomTable, (PWSTR)i, &testAtom);
290             ok(!res, "Unable to add valid integer atom %i, retval: %lx\n", i, res);
291         }
292
293         for (i = 1; i <= 0xbfff; i++)
294         {
295             res = pRtlLookupAtomInAtomTable(AtomTable, (PWSTR)i, &testAtom);
296             ok(!res, "Unable to find int atom %i, retval: %lx\n", i, res);
297             if (!res)
298             {
299                 res = pRtlPinAtomInAtomTable(AtomTable, testAtom);
300                 ok(!res, "Unable to pin int atom %i, retval: %lx\n", i, res);
301             }
302         }
303
304         for (i = 0xc000; i <= 0xffff; i++)
305         {
306             res = pRtlAddAtomToAtomTable(AtomTable, (PWSTR)i, &testAtom);
307             ok(res, "Able to illeageal integer atom %i, retval: %lx\n", i, res);
308         }
309
310         res = pRtlDestroyAtomTable(AtomTable);
311         ok(!res, "Unable to destroy atom table, retval: %lx\n", res);
312     }
313
314     AtomTable = NULL;
315     res = pRtlCreateAtomTable(37, &AtomTable);
316     ok(!res, "Unable to create atom table, %lx\n", res);
317     if (!res)
318     {
319         res = pRtlLookupAtomInAtomTable(AtomTable, (PWSTR)123, &testAtom);
320         ok(!res, "Unable to query atom in atom table, retval: %lx\n", res);
321
322         res = pRtlAddAtomToAtomTable(AtomTable, testAtomInt, &testAtom);
323         ok(!res, "Unable to add int atom to table, retval: %lx\n", res);
324
325         res = pRtlAddAtomToAtomTable(AtomTable, testAtomIntInv, &testAtom);
326         ok(!res, "Unable to add int atom to table, retval: %lx\n", res);
327
328         res = pRtlAddAtomToAtomTable(AtomTable, (PWSTR)123, &testAtom);
329         ok(!res, "Unable to add int atom to table, retval: %lx\n", res);
330
331         res = pRtlAddAtomToAtomTable(AtomTable, (PWSTR)123, &testAtom);
332         ok(!res, "Unable to re-add int atom to table, retval: %lx\n", res);
333
334         Len = 64;
335         res = pRtlQueryAtomInAtomTable(AtomTable, testAtom, &RefCount, &PinCount, Name, &Len);
336         ok(!res, "Unable to query atom in atom table, retval: %lx\n", res);
337         ok(PinCount == 1, "Expected pincount 1 but got %lx\n", PinCount);
338         ok(RefCount == 1, "Expected refcount 1 but got %lx\n", RefCount);
339         ok(!strcmpW(testAtomOTT, Name), "Got wrong atom name\n");
340         ok((strlenW(testAtomOTT) * sizeof(WCHAR)) == Len, "Got wrong len %ld\n", Len);
341
342         res = pRtlPinAtomInAtomTable(AtomTable, testAtom);
343         ok(!res, "Unable to pin int atom, retval: %lx\n", res);
344
345         res = pRtlPinAtomInAtomTable(AtomTable, testAtom);
346         ok(!res, "Unable to pin int atom, retval: %lx\n", res);
347
348         res = pRtlQueryAtomInAtomTable(AtomTable, testAtom, &RefCount, &PinCount, NULL, NULL);
349         ok(!res, "Unable to query atom in atom table, retval: %lx\n", res);
350         ok(PinCount == 1, "Expected pincount 1 but got %lx\n", PinCount);
351         ok(RefCount == 1, "Expected refcount 1 but got %lx\n", RefCount);
352
353         res = pRtlDestroyAtomTable(AtomTable);
354         ok(!res, "Unable to destroy atom table, retval: %lx\n", res);
355     }
356 }
357
358 /* Tests to see how the pincount and refcount actually works */
359 static void test_NtRefPinAtom(void)
360 {
361     RTL_ATOM_TABLE AtomTable;
362     RTL_ATOM Atom;
363     ULONG PinCount = 0, RefCount = 0;
364     NTSTATUS res;
365
366     AtomTable = NULL;
367     res = pRtlCreateAtomTable(37, &AtomTable);
368     ok(!res, "Unable to create atom table, %lx\n", res);
369
370     if (!res)
371     {
372         res = pRtlAddAtomToAtomTable(AtomTable, testAtom1, &Atom);
373         ok(!res, "Unable to add our atom to the atom table, retval: %lx\n", res);
374
375         res = pRtlAddAtomToAtomTable(AtomTable, testAtom1, &Atom);
376         ok(!res, "Unable to add our atom to the atom table, retval: %lx\n", res);
377
378         res = pRtlAddAtomToAtomTable(AtomTable, testAtom1, &Atom);
379         ok(!res, "Unable to add our atom to the atom table, retval: %lx\n", res);
380
381         res = pRtlQueryAtomInAtomTable(AtomTable, Atom, &RefCount, &PinCount, NULL, NULL);
382         ok(!res, "Unable to query atom in atom table, retval: %lx\n", res);
383         ok(PinCount == 0, "Expected pincount 0 but got %lx\n", PinCount);
384         ok(RefCount == 3, "Expected refcount 3 but got %lx\n", RefCount); 
385
386         res = pRtlPinAtomInAtomTable(AtomTable, Atom);
387         ok(!res, "Unable to pin atom in atom table, retval: %lx\n", res);
388
389         res = pRtlPinAtomInAtomTable(AtomTable, Atom);
390         ok(!res, "Unable to pin atom in atom table, retval: %lx\n", res);
391
392         res = pRtlPinAtomInAtomTable(AtomTable, Atom);
393         ok(!res, "Unable to pin atom in atom table, retval: %lx\n", res);
394
395         res = pRtlQueryAtomInAtomTable(AtomTable, Atom, &RefCount, &PinCount, NULL, NULL);
396         ok(!res, "Unable to query atom in atom table, retval: %lx\n", res);
397         ok(PinCount == 1, "Expected pincount 1 but got %lx\n", PinCount);
398         ok(RefCount == 3, "Expected refcount 3 but got %lx\n", RefCount);
399
400         res = pRtlDestroyAtomTable(AtomTable);
401         ok(!res, "Unable to destroy atom table, retval: %lx\n", res);
402     }
403 }
404
405 START_TEST(atom)
406 {
407     InitFunctionPtr();
408     if (pRtlCreateAtomTable)
409     {
410         test_NtAtom();
411         test_NtIntAtom();
412         test_NtRefPinAtom();
413     }
414 }