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