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