ntdll pending some winerror.h fixes
[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 = pRtlPinAtomInAtomTable(AtomTable, Atom1);
237 ok(!res, "Unable to pin atom in atom table, retval: %lx\n", res);
238
239 res = pRtlLookupAtomInAtomTable(AtomTable, testAtom1, &testAtom);
240 ok(!res, "Unable to find atom in atom table, retval: %lx\n", res);
241 ok(testAtom == Atom1, "Wrong atom found\n");
242
243 res = pRtlDeleteAtomFromAtomTable(AtomTable, Atom1);
244 ok(res == STATUS_WAS_LOCKED, "Unable to delete atom from table, retval: %lx\n", res);
245
246 res = pRtlLookupAtomInAtomTable(AtomTable, testAtom1, &testAtom);
247 ok(!res, "Able to find deleted atom in table\n");
248
249 res = pRtlDestroyAtomTable(AtomTable);
250 ok(!res, "Unable to destroy atom table\n");
251 }
252 }
253
254 /* Test Adding integer atoms to atom table */
255 static void test_NtIntAtom(void)
256 {
257 NTSTATUS res;
258 RTL_ATOM_TABLE AtomTable;
259 RTL_ATOM testAtom;
260 ULONG RefCount = 0, PinCount = 0;
261 int i;
262 WCHAR Name[64];
263 ULONG Len;
264
265 AtomTable = NULL;
266 res = pRtlCreateAtomTable(37, &AtomTable);
267 ok(!res, "Unable to create atom table, %lx\n", res);
268
269 if (!res)
270 {
271 /* According to the kernel32 functions, integer atoms are only allowd from
272 * 0x0001 to 0xbfff and not 0xc000 to 0xffff, which is correct */
273 res = pRtlAddAtomToAtomTable(AtomTable, (PWSTR)0, &testAtom);
274 ok(res == STATUS_INVALID_PARAMETER, "Didn't get expected result from adding 0 int atom, retval: %lx\n", res);
275 for (i = 1; i <= 0xbfff; i++)
276 {
277 res = pRtlAddAtomToAtomTable(AtomTable, (PWSTR)i, &testAtom);
278 ok(!res, "Unable to add valid integer atom %i, retval: %lx\n", i, res);
279 }
280
281 for (i = 1; i <= 0xbfff; i++)
282 {
283 res = pRtlLookupAtomInAtomTable(AtomTable, (PWSTR)i, &testAtom);
284 ok(!res, "Unable to find int atom %i, retval: %lx\n", i, res);
285 if (!res)
286 {
287 res = pRtlPinAtomInAtomTable(AtomTable, testAtom);
288 ok(!res, "Unable to pin int atom %i, retval: %lx\n", i, res);
289 }
290 }
291
292 for (i = 0xc000; i <= 0xffff; i++)
293 {
294 res = pRtlAddAtomToAtomTable(AtomTable, (PWSTR)i, &testAtom);
295 ok(res, "Able to illeageal integer atom %i, retval: %lx\n", i, res);
296 }
297
298 res = pRtlDestroyAtomTable(AtomTable);
299 ok(!res, "Unable to destroy atom table, retval: %lx\n", res);
300 }
301
302 AtomTable = NULL;
303 res = pRtlCreateAtomTable(37, &AtomTable);
304 ok(!res, "Unable to create atom table, %lx\n", res);
305 if (!res)
306 {
307 res = pRtlLookupAtomInAtomTable(AtomTable, (PWSTR)123, &testAtom);
308 ok(!res, "Unable to query atom in atom table, retval: %lx\n", res);
309
310 res = pRtlAddAtomToAtomTable(AtomTable, testAtomInt, &testAtom);
311 ok(!res, "Unable to add int atom to table, retval: %lx\n", res);
312
313 res = pRtlAddAtomToAtomTable(AtomTable, testAtomIntInv, &testAtom);
314 ok(!res, "Unable to add int atom to table, retval: %lx\n", res);
315
316 res = pRtlAddAtomToAtomTable(AtomTable, (PWSTR)123, &testAtom);
317 ok(!res, "Unable to add int atom to table, retval: %lx\n", res);
318
319 res = pRtlAddAtomToAtomTable(AtomTable, (PWSTR)123, &testAtom);
320 ok(!res, "Unable to re-add int atom to table, retval: %lx\n", res);
321
322 Len = 64;
323 res = pRtlQueryAtomInAtomTable(AtomTable, testAtom, &RefCount, &PinCount, Name, &Len);
324 ok(!res, "Unable to query atom in atom table, retval: %lx\n", res);
325 ok(PinCount == 1, "Expected pincount 1 but got %lx\n", PinCount);
326 ok(RefCount == 1, "Expected refcount 1 but got %lx\n", RefCount);
327 ok(!strcmpW(testAtomOTT, Name), "Got wrong atom name\n");
328 ok((strlenW(testAtomOTT) * sizeof(WCHAR)) == Len, "Got wrong len %ld\n", Len);
329
330 res = pRtlPinAtomInAtomTable(AtomTable, testAtom);
331 ok(!res, "Unable to pin int atom, retval: %lx\n", res);
332
333 res = pRtlPinAtomInAtomTable(AtomTable, testAtom);
334 ok(!res, "Unable to pin int atom, retval: %lx\n", res);
335
336 res = pRtlQueryAtomInAtomTable(AtomTable, testAtom, &RefCount, &PinCount, NULL, NULL);
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
341 res = pRtlDestroyAtomTable(AtomTable);
342 ok(!res, "Unable to destroy atom table, retval: %lx\n", res);
343 }
344 }
345
346 /* Tests to see how the pincount and refcount actually works */
347 static void test_NtRefPinAtom(void)
348 {
349 RTL_ATOM_TABLE AtomTable;
350 RTL_ATOM Atom;
351 ULONG PinCount = 0, RefCount = 0;
352 NTSTATUS res;
353
354 AtomTable = NULL;
355 res = pRtlCreateAtomTable(37, &AtomTable);
356 ok(!res, "Unable to create atom table, %lx\n", res);
357
358 if (!res)
359 {
360 res = pRtlAddAtomToAtomTable(AtomTable, testAtom1, &Atom);
361 ok(!res, "Unable to add our atom to the atom table, retval: %lx\n", res);
362
363 res = pRtlAddAtomToAtomTable(AtomTable, testAtom1, &Atom);
364 ok(!res, "Unable to add our atom to the atom table, retval: %lx\n", res);
365
366 res = pRtlAddAtomToAtomTable(AtomTable, testAtom1, &Atom);
367 ok(!res, "Unable to add our atom to the atom table, retval: %lx\n", res);
368
369 res = pRtlQueryAtomInAtomTable(AtomTable, Atom, &RefCount, &PinCount, NULL, NULL);
370 ok(!res, "Unable to query atom in atom table, retval: %lx\n", res);
371 ok(PinCount == 0, "Expected pincount 0 but got %lx\n", PinCount);
372 ok(RefCount == 3, "Expected refcount 3 but got %lx\n", RefCount);
373
374 res = pRtlPinAtomInAtomTable(AtomTable, Atom);
375 ok(!res, "Unable to pin atom in atom table, retval: %lx\n", res);
376
377 res = pRtlPinAtomInAtomTable(AtomTable, Atom);
378 ok(!res, "Unable to pin atom in atom table, retval: %lx\n", res);
379
380 res = pRtlPinAtomInAtomTable(AtomTable, Atom);
381 ok(!res, "Unable to pin atom in atom table, retval: %lx\n", res);
382
383 res = pRtlQueryAtomInAtomTable(AtomTable, Atom, &RefCount, &PinCount, NULL, NULL);
384 ok(!res, "Unable to query atom in atom table, retval: %lx\n", res);
385 ok(PinCount == 1, "Expected pincount 1 but got %lx\n", PinCount);
386 ok(RefCount == 3, "Expected refcount 3 but got %lx\n", RefCount);
387
388 res = pRtlDestroyAtomTable(AtomTable);
389 ok(!res, "Unable to destroy atom table, retval: %lx\n", res);
390 }
391 }
392
393 START_TEST(atom)
394 {
395 InitFunctionPtr();
396 if (pRtlCreateAtomTable)
397 {
398 test_NtAtom();
399 test_NtIntAtom();
400 test_NtRefPinAtom();
401 }
402 }