Implement A->W call for GetNamedSecurityInfo.
[wine] / dlls / ntdll / tests / env.c
1 /*
2  * Unit test suite for ntdll path functions
3  *
4  * Copyright 2003 Eric Pouech
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdarg.h>
22 #include <stdio.h>
23 #include "wine/test.h"
24 #include "ntstatus.h"
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winnt.h"
28 #include "winreg.h"
29 #include "winternl.h"
30 #include "wine/unicode.h"
31
32 static NTSTATUS (WINAPI *pRtlMultiByteToUnicodeN)( LPWSTR dst, DWORD dstlen, LPDWORD reslen,
33                                                    LPCSTR src, DWORD srclen );
34 static NTSTATUS (WINAPI *pRtlCreateEnvironment)(BOOLEAN, PWSTR*);
35 static NTSTATUS (WINAPI *pRtlDestroyEnvironment)(PWSTR);
36 static NTSTATUS (WINAPI *pRtlQueryEnvironmentVariable_U)(PWSTR, PUNICODE_STRING, PUNICODE_STRING);
37 static void     (WINAPI *pRtlSetCurrentEnvironment)(PWSTR, PWSTR*);
38 static NTSTATUS (WINAPI *pRtlSetEnvironmentVariable)(PWSTR*, PUNICODE_STRING, PUNICODE_STRING);
39 static NTSTATUS (WINAPI *pRtlExpandEnvironmentStrings_U)(LPWSTR, PUNICODE_STRING, PUNICODE_STRING, PULONG);
40
41 static WCHAR  small_env[] = {'f','o','o','=','t','o','t','o',0,
42                              'f','o','=','t','i','t','i',0,
43                              'f','o','o','o','=','t','u','t','u',0,
44                              's','r','=','a','n','=','o','u','o',0,
45                              'g','=','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
46                                      'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
47                                      'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
48                                      'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
49                                      'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
50                                      'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
51                                      'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
52                                      'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
53                                      'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
54                                      'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',0,
55                              '=','o','O','H','=','I','I','I',0,
56                              'n','u','l','=',0,
57                              0};
58
59 static void testQuery(void)
60 {
61     struct test
62     {
63         const char *var;
64         int len;
65         NTSTATUS status;
66         const char *val;
67     };
68
69     static const struct test tests[] =
70     {
71         {"foo", 256, STATUS_SUCCESS, "toto"},
72         {"FoO", 256, STATUS_SUCCESS, "toto"},
73         {"foo=", 256, STATUS_VARIABLE_NOT_FOUND, NULL},
74         {"foo ", 256, STATUS_VARIABLE_NOT_FOUND, NULL},
75         {"foo", 1, STATUS_BUFFER_TOO_SMALL, "toto"},
76         {"foo", 3, STATUS_BUFFER_TOO_SMALL, "toto"},
77         {"foo", 4, STATUS_SUCCESS, "toto"},
78         {"fooo", 256, STATUS_SUCCESS, "tutu"},
79         {"f", 256, STATUS_VARIABLE_NOT_FOUND, NULL},
80         {"g", 256, STATUS_SUCCESS, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
81 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
82         {"sr=an", 256, STATUS_VARIABLE_NOT_FOUND, NULL},
83         {"sr", 256, STATUS_SUCCESS, "an=ouo"},
84         {"=oOH", 256, STATUS_SUCCESS, "III"},
85         {"", 256, STATUS_VARIABLE_NOT_FOUND, NULL},
86         {"nul", 256, STATUS_SUCCESS, ""},
87         {NULL, 0, 0, NULL}
88     };
89
90     WCHAR               bn[257];
91     WCHAR               bv[257];
92     UNICODE_STRING      name;
93     UNICODE_STRING      value;
94     const struct test*  test;
95     NTSTATUS            nts;
96
97     for (test = tests; test->var; test++)
98     {
99         name.Length = strlen(test->var) * 2;
100         name.MaximumLength = name.Length + 2;
101         name.Buffer = bn;
102         value.Length = 0;
103         value.MaximumLength = test->len * 2;
104         value.Buffer = bv;
105         bv[test->len] = '@';
106
107         pRtlMultiByteToUnicodeN( bn, sizeof(bn), NULL, test->var, strlen(test->var)+1 );
108         nts = pRtlQueryEnvironmentVariable_U(small_env, &name, &value);
109         ok( nts == test->status, "[%d]: Wrong status for '%s', expecting %lx got %lx\n",
110             test - tests, test->var, test->status, nts );
111         if (nts == test->status) switch (nts)
112         {
113         case STATUS_SUCCESS:
114             pRtlMultiByteToUnicodeN( bn, sizeof(bn), NULL, test->val, strlen(test->val)+1 );
115             ok( value.Length == strlen(test->val) * sizeof(WCHAR), "Wrong length %d/%d for %s\n",
116                 value.Length, strlen(test->val) * sizeof(WCHAR), test->var );
117             ok((value.Length == strlen(test->val) * sizeof(WCHAR) && strncmpW(bv, bn, test->len) == 0) ||
118                strcmpW(bv, bn) == 0, 
119                "Wrong result for %s/%d\n", test->var, test->len);
120             ok(bv[test->len] == '@', "Writing too far away in the buffer for %s/%d\n", test->var, test->len);
121             break;
122         case STATUS_BUFFER_TOO_SMALL:
123             ok( value.Length == strlen(test->val) * sizeof(WCHAR), 
124                 "Wrong returned length %d/%d (too small buffer) for %s\n",
125                 value.Length, strlen(test->val) * sizeof(WCHAR), test->var );
126             break;
127         }
128     }
129 }
130
131 static void testSetHelper(LPWSTR* env, const char* var, const char* val, NTSTATUS ret)
132 {
133     WCHAR               bvar[256], bval1[256], bval2[256];
134     UNICODE_STRING      uvar;
135     UNICODE_STRING      uval;
136     NTSTATUS            nts;
137
138     uvar.Length = strlen(var) * sizeof(WCHAR);
139     uvar.MaximumLength = uvar.Length + sizeof(WCHAR);
140     uvar.Buffer = bvar;
141     pRtlMultiByteToUnicodeN( bvar, sizeof(bvar), NULL, var, strlen(var)+1 );
142     if (val)
143     {
144         uval.Length = strlen(val) * sizeof(WCHAR);
145         uval.MaximumLength = uval.Length + sizeof(WCHAR);
146         uval.Buffer = bval1;
147         pRtlMultiByteToUnicodeN( bval1, sizeof(bval1), NULL, val, strlen(val)+1 );
148     }
149     nts = pRtlSetEnvironmentVariable(env, &uvar, val ? &uval : NULL);
150     ok(nts == ret, "Setting var %s=%s (%lx/%lx)\n", var, val, nts, ret);
151     if (nts == STATUS_SUCCESS)
152     {
153         uval.Length = 0;
154         uval.MaximumLength = sizeof(bval2);
155         uval.Buffer = bval2;
156         nts = pRtlQueryEnvironmentVariable_U(*env, &uvar, &uval);
157         switch (nts)
158         {
159         case STATUS_SUCCESS:
160             ok(strcmpW(bval1, bval2) == 0, "Cannot get value written to environment\n");
161             break;
162         case STATUS_VARIABLE_NOT_FOUND:
163             ok(val == NULL, "Couldn't find variable, but didn't delete it\n");
164             break;
165         default:
166             ok(0, "Wrong ret %lu for %s\n", nts, var);
167             break;
168         }
169     }
170 }
171
172 static void testSet(void)
173 {
174     LPWSTR              env;
175     char                tmp[16];
176     int                 i;
177
178     ok(pRtlCreateEnvironment(FALSE, &env) == STATUS_SUCCESS, "Creating environment\n");
179     memmove(env, small_env, sizeof(small_env));
180
181     testSetHelper(&env, "cat", "dog", STATUS_SUCCESS);
182     testSetHelper(&env, "cat", "horse", STATUS_SUCCESS);
183     testSetHelper(&env, "cat", "zz", STATUS_SUCCESS);
184     testSetHelper(&env, "cat", NULL, STATUS_SUCCESS);
185     testSetHelper(&env, "cat", NULL, STATUS_VARIABLE_NOT_FOUND);
186     testSetHelper(&env, "foo", "meouw", STATUS_SUCCESS);
187     testSetHelper(&env, "me=too", "also", STATUS_INVALID_PARAMETER);
188     testSetHelper(&env, "me", "too=also", STATUS_SUCCESS);
189     testSetHelper(&env, "=too", "also", STATUS_SUCCESS);
190     testSetHelper(&env, "=", "also", STATUS_SUCCESS);
191
192     for (i = 0; i < 128; i++)
193     {
194         sprintf(tmp, "zork%03d", i);
195         testSetHelper(&env, tmp, "is alive", STATUS_SUCCESS);
196     }
197
198     for (i = 0; i < 128; i++)
199     {
200         sprintf(tmp, "zork%03d", i);
201         testSetHelper(&env, tmp, NULL, STATUS_SUCCESS);
202     }
203     testSetHelper(&env, "fOo", NULL, STATUS_SUCCESS);
204
205     ok(pRtlDestroyEnvironment(env) == STATUS_SUCCESS, "Destroying environment\n");
206 }
207
208 static void testExpand(void)
209 {
210     static const struct test
211     {
212         const char *src;
213         const char *dst;
214     } tests[] =
215     {
216         {"hello%foo%world",             "hellototoworld"},
217         {"hello%=oOH%world",            "helloIIIworld"},
218         {"hello%foo",                   "hello%foo"},
219         {"hello%bar%world",             "hello%bar%world"},
220         /*
221          * {"hello%foo%world%=oOH%eeck",   "hellototoworldIIIeeck"},
222          * Interestingly enough, with a 8 WCHAR buffers, we get on 2k:
223          *      helloIII
224          * so it seems like strings overflowing the buffer are written 
225          * (troncated) but the write cursor is not advanced :-/
226          */
227         {NULL, NULL}
228     };
229
230     const struct test*  test;
231     NTSTATUS            nts;
232     UNICODE_STRING      us_src, us_dst;
233     WCHAR               src[256], dst[256], rst[256];
234     ULONG               ul;
235
236     for (test = tests; test->src; test++)
237     {
238         pRtlMultiByteToUnicodeN(src, sizeof(src), NULL, test->src, strlen(test->src)+1);
239         pRtlMultiByteToUnicodeN(rst, sizeof(rst), NULL, test->dst, strlen(test->dst)+1);
240
241         us_src.Length = strlen(test->src) * sizeof(WCHAR);
242         us_src.MaximumLength = us_src.Length + 2;
243         us_src.Buffer = src;
244
245         us_dst.Length = 0;
246         us_dst.MaximumLength = 0;
247         us_dst.Buffer = NULL;
248
249         nts = pRtlExpandEnvironmentStrings_U(small_env, &us_src, &us_dst, &ul);
250         ok(ul == strlen(test->dst) * sizeof(WCHAR) + sizeof(WCHAR), 
251            "Wrong  returned length for %s: %lu <> %u\n",
252            test->src, ul, strlen(test->dst) * sizeof(WCHAR) + sizeof(WCHAR));
253
254         us_dst.Length = 0;
255         us_dst.MaximumLength = sizeof(dst);
256         us_dst.Buffer = dst;
257
258         nts = pRtlExpandEnvironmentStrings_U(small_env, &us_src, &us_dst, &ul);
259         ok(nts == STATUS_SUCCESS, "Call failed (%lu)\n", nts);
260         ok(ul == us_dst.Length + sizeof(WCHAR), 
261            "Wrong returned length for %s: %lu <> %u\n",
262            test->src, ul, us_dst.Length + sizeof(WCHAR));
263         ok(ul == strlen(test->dst) * sizeof(WCHAR) + sizeof(WCHAR), 
264            "Wrong  returned length for %s: %lu <> %u\n",
265            test->src, ul, strlen(test->dst) * sizeof(WCHAR) + sizeof(WCHAR));
266         ok(strcmpW(dst, rst) == 0, "Wrong result for %s: expecting %s\n",
267            test->src, test->dst);
268
269         us_dst.Length = 0;
270         us_dst.MaximumLength = 8 * sizeof(WCHAR);
271         us_dst.Buffer = dst;
272         dst[8] = '-';
273         nts = pRtlExpandEnvironmentStrings_U(small_env, &us_src, &us_dst, &ul);
274         ok(nts == STATUS_BUFFER_TOO_SMALL, "Call failed (%lu)\n", nts);
275         ok(ul == strlen(test->dst) * sizeof(WCHAR) + sizeof(WCHAR), 
276            "Wrong  returned length for %s (with buffer too small): %lu <> %u\n",
277            test->src, ul, strlen(test->dst) * sizeof(WCHAR) + sizeof(WCHAR));
278         ok(strncmpW(dst, rst, 8) == 0, 
279            "Wrong result for %s (with buffer too small): expecting %s\n",
280            test->src, test->dst);
281         ok(dst[8] == '-', "Writing too far in buffer (got %c/%d)\n", dst[8], dst[8]);
282     }
283
284 }
285
286 START_TEST(env)
287 {
288     HMODULE mod = GetModuleHandleA("ntdll.dll");
289
290     pRtlMultiByteToUnicodeN = (void *)GetProcAddress(mod,"RtlMultiByteToUnicodeN");
291     pRtlCreateEnvironment = (void*)GetProcAddress(mod, "RtlCreateEnvironment");
292     pRtlDestroyEnvironment = (void*)GetProcAddress(mod, "RtlDestroyEnvironment");
293     pRtlQueryEnvironmentVariable_U = (void*)GetProcAddress(mod, "RtlQueryEnvironmentVariable_U");
294     pRtlSetCurrentEnvironment = (void*)GetProcAddress(mod, "RtlSetCurrentEnvironment");
295     pRtlSetEnvironmentVariable = (void*)GetProcAddress(mod, "RtlSetEnvironmentVariable");
296     pRtlExpandEnvironmentStrings_U = (void*)GetProcAddress(mod, "RtlExpandEnvironmentStrings_U");
297
298     if (pRtlQueryEnvironmentVariable_U)
299         testQuery();
300     if (pRtlSetEnvironmentVariable)
301         testSet();
302     if (pRtlExpandEnvironmentStrings_U)
303         testExpand();
304 }