[USB]
[reactos.git] / rostests / winetests / ntdll / 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include <stdio.h>
22
23 #include "ntdll_test.h"
24
25 static NTSTATUS (WINAPI *pRtlMultiByteToUnicodeN)( LPWSTR dst, DWORD dstlen, LPDWORD reslen,
26 LPCSTR src, DWORD srclen );
27 static NTSTATUS (WINAPI *pRtlCreateEnvironment)(BOOLEAN, PWSTR*);
28 static NTSTATUS (WINAPI *pRtlDestroyEnvironment)(PWSTR);
29 static NTSTATUS (WINAPI *pRtlQueryEnvironmentVariable_U)(PWSTR, PUNICODE_STRING, PUNICODE_STRING);
30 static void (WINAPI *pRtlSetCurrentEnvironment)(PWSTR, PWSTR*);
31 static NTSTATUS (WINAPI *pRtlSetEnvironmentVariable)(PWSTR*, PUNICODE_STRING, PUNICODE_STRING);
32 static NTSTATUS (WINAPI *pRtlExpandEnvironmentStrings_U)(LPWSTR, PUNICODE_STRING, PUNICODE_STRING, PULONG);
33
34 static WCHAR small_env[] = {'f','o','o','=','t','o','t','o',0,
35 'f','o','=','t','i','t','i',0,
36 'f','o','o','o','=','t','u','t','u',0,
37 's','r','=','a','n','=','o','u','o',0,
38 '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',
39 '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',
40 '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',
41 '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',
42 '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',
43 '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',
44 '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',
45 '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',0,
48 '=','o','O','H','=','I','I','I',0,
49 'n','u','l','=',0,
50 0};
51
52 static void testQuery(void)
53 {
54 struct test
55 {
56 const char *var;
57 int len;
58 NTSTATUS status;
59 const char *val;
60 NTSTATUS alt;
61 };
62
63 static const struct test tests[] =
64 {
65 {"foo", 256, STATUS_SUCCESS, "toto"},
66 {"FoO", 256, STATUS_SUCCESS, "toto"},
67 {"foo=", 256, STATUS_VARIABLE_NOT_FOUND, NULL},
68 {"foo ", 256, STATUS_VARIABLE_NOT_FOUND, NULL},
69 {"foo", 1, STATUS_BUFFER_TOO_SMALL, "toto"},
70 {"foo", 3, STATUS_BUFFER_TOO_SMALL, "toto"},
71 {"foo", 4, STATUS_SUCCESS, "toto", STATUS_BUFFER_TOO_SMALL},
72 {"foo", 5, STATUS_SUCCESS, "toto"},
73 {"fooo", 256, STATUS_SUCCESS, "tutu"},
74 {"f", 256, STATUS_VARIABLE_NOT_FOUND, NULL},
75 {"g", 256, STATUS_SUCCESS, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
76 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
77 {"sr=an", 256, STATUS_SUCCESS, "ouo", STATUS_VARIABLE_NOT_FOUND},
78 {"sr", 256, STATUS_SUCCESS, "an=ouo"},
79 {"=oOH", 256, STATUS_SUCCESS, "III"},
80 {"", 256, STATUS_VARIABLE_NOT_FOUND, NULL},
81 {"nul", 256, STATUS_SUCCESS, ""},
82 {NULL, 0, 0, NULL}
83 };
84
85 WCHAR bn[257];
86 WCHAR bv[257];
87 UNICODE_STRING name;
88 UNICODE_STRING value;
89 NTSTATUS nts;
90 unsigned int i;
91
92 for (i = 0; tests[i].var; i++)
93 {
94 const struct test *test = &tests[i];
95 name.Length = strlen(test->var) * 2;
96 name.MaximumLength = name.Length + 2;
97 name.Buffer = bn;
98 value.Length = 0;
99 value.MaximumLength = test->len * 2;
100 value.Buffer = bv;
101 bv[test->len] = '@';
102
103 pRtlMultiByteToUnicodeN( bn, sizeof(bn), NULL, test->var, strlen(test->var)+1 );
104 nts = pRtlQueryEnvironmentVariable_U(small_env, &name, &value);
105 ok( nts == test->status || (test->alt && nts == test->alt),
106 "[%d]: Wrong status for '%s', expecting %x got %x\n",
107 i, test->var, test->status, nts );
108 if (nts == test->status) switch (nts)
109 {
110 case STATUS_SUCCESS:
111 pRtlMultiByteToUnicodeN( bn, sizeof(bn), NULL, test->val, strlen(test->val)+1 );
112 ok( value.Length == strlen(test->val) * sizeof(WCHAR), "Wrong length %d for %s\n",
113 value.Length, test->var );
114 ok((value.Length == strlen(test->val) * sizeof(WCHAR) && memcmp(bv, bn, test->len*sizeof(WCHAR)) == 0) ||
115 lstrcmpW(bv, bn) == 0,
116 "Wrong result for %s/%d\n", test->var, test->len);
117 ok(bv[test->len] == '@', "Writing too far away in the buffer for %s/%d\n", test->var, test->len);
118 break;
119 case STATUS_BUFFER_TOO_SMALL:
120 ok( value.Length == strlen(test->val) * sizeof(WCHAR),
121 "Wrong returned length %d (too small buffer) for %s\n", value.Length, test->var );
122 break;
123 }
124 }
125 }
126
127 static void testSetHelper(LPWSTR* env, const char* var, const char* val, NTSTATUS ret, NTSTATUS alt)
128 {
129 WCHAR bvar[256], bval1[256], bval2[256];
130 UNICODE_STRING uvar;
131 UNICODE_STRING uval;
132 NTSTATUS nts;
133
134 uvar.Length = strlen(var) * sizeof(WCHAR);
135 uvar.MaximumLength = uvar.Length + sizeof(WCHAR);
136 uvar.Buffer = bvar;
137 pRtlMultiByteToUnicodeN( bvar, sizeof(bvar), NULL, var, strlen(var)+1 );
138 if (val)
139 {
140 uval.Length = strlen(val) * sizeof(WCHAR);
141 uval.MaximumLength = uval.Length + sizeof(WCHAR);
142 uval.Buffer = bval1;
143 pRtlMultiByteToUnicodeN( bval1, sizeof(bval1), NULL, val, strlen(val)+1 );
144 }
145 nts = pRtlSetEnvironmentVariable(env, &uvar, val ? &uval : NULL);
146 ok(nts == ret || (alt && nts == alt), "Setting var %s=%s (%x/%x)\n", var, val, nts, ret);
147 if (nts == STATUS_SUCCESS)
148 {
149 uval.Length = 0;
150 uval.MaximumLength = sizeof(bval2);
151 uval.Buffer = bval2;
152 nts = pRtlQueryEnvironmentVariable_U(*env, &uvar, &uval);
153 switch (nts)
154 {
155 case STATUS_SUCCESS:
156 ok(lstrcmpW(bval1, bval2) == 0, "Cannot get value written to environment\n");
157 break;
158 case STATUS_VARIABLE_NOT_FOUND:
159 ok(val == NULL ||
160 broken(strchr(var,'=') != NULL), /* variable containing '=' may be set but not found again on NT4 */
161 "Couldn't find variable, but didn't delete it. val = %s\n", val);
162 break;
163 default:
164 ok(0, "Wrong ret %u for %s\n", nts, var);
165 break;
166 }
167 }
168 }
169
170 static void testSet(void)
171 {
172 LPWSTR env;
173 char tmp[16];
174 int i;
175
176 ok(pRtlCreateEnvironment(FALSE, &env) == STATUS_SUCCESS, "Creating environment\n");
177
178 testSetHelper(&env, "cat", "dog", STATUS_SUCCESS, 0);
179 testSetHelper(&env, "cat", "horse", STATUS_SUCCESS, 0);
180 testSetHelper(&env, "cat", "zz", STATUS_SUCCESS, 0);
181 testSetHelper(&env, "cat", NULL, STATUS_SUCCESS, 0);
182 testSetHelper(&env, "cat", NULL, STATUS_SUCCESS, STATUS_VARIABLE_NOT_FOUND);
183 testSetHelper(&env, "foo", "meouw", STATUS_SUCCESS, 0);
184 testSetHelper(&env, "me=too", "also", STATUS_SUCCESS, STATUS_INVALID_PARAMETER);
185 testSetHelper(&env, "me", "too=also", STATUS_SUCCESS, 0);
186 testSetHelper(&env, "=too", "also", STATUS_SUCCESS, 0);
187 testSetHelper(&env, "=", "also", STATUS_SUCCESS, 0);
188
189 for (i = 0; i < 128; i++)
190 {
191 sprintf(tmp, "zork%03d", i);
192 testSetHelper(&env, tmp, "is alive", STATUS_SUCCESS, 0);
193 }
194
195 for (i = 0; i < 128; i++)
196 {
197 sprintf(tmp, "zork%03d", i);
198 testSetHelper(&env, tmp, NULL, STATUS_SUCCESS, 0);
199 }
200 testSetHelper(&env, "fOo", NULL, STATUS_SUCCESS, 0);
201
202 ok(pRtlDestroyEnvironment(env) == STATUS_SUCCESS, "Destroying environment\n");
203 }
204
205 static void testExpand(void)
206 {
207 static const struct test
208 {
209 const char *src;
210 const char *dst;
211 } tests[] =
212 {
213 {"hello%foo%world", "hellototoworld"},
214 {"hello%=oOH%world", "helloIIIworld"},
215 {"hello%foo", "hello%foo"},
216 {"hello%bar%world", "hello%bar%world"},
217 /*
218 * {"hello%foo%world%=oOH%eeck", "hellototoworldIIIeeck"},
219 * Interestingly enough, with a 8 WCHAR buffers, we get on 2k:
220 * helloIII
221 * so it seems like strings overflowing the buffer are written
222 * (truncated) but the write cursor is not advanced :-/
223 */
224 {NULL, NULL}
225 };
226
227 const struct test* test;
228 NTSTATUS nts;
229 UNICODE_STRING us_src, us_dst;
230 WCHAR src[256], dst[256], rst[256];
231 ULONG ul;
232
233 for (test = tests; test->src; test++)
234 {
235 pRtlMultiByteToUnicodeN(src, sizeof(src), NULL, test->src, strlen(test->src)+1);
236 pRtlMultiByteToUnicodeN(rst, sizeof(rst), NULL, test->dst, strlen(test->dst)+1);
237
238 us_src.Length = strlen(test->src) * sizeof(WCHAR);
239 us_src.MaximumLength = us_src.Length + 2;
240 us_src.Buffer = src;
241
242 us_dst.Length = 0;
243 us_dst.MaximumLength = 0;
244 us_dst.Buffer = NULL;
245
246 nts = pRtlExpandEnvironmentStrings_U(small_env, &us_src, &us_dst, &ul);
247 ok(nts == STATUS_BUFFER_TOO_SMALL, "Call failed (%u)\n", nts);
248 ok(ul == strlen(test->dst) * sizeof(WCHAR) + sizeof(WCHAR),
249 "Wrong returned length for %s: %u\n", test->src, ul );
250
251 us_dst.Length = 0;
252 us_dst.MaximumLength = sizeof(dst);
253 us_dst.Buffer = dst;
254
255 nts = pRtlExpandEnvironmentStrings_U(small_env, &us_src, &us_dst, &ul);
256 ok(nts == STATUS_SUCCESS, "Call failed (%u)\n", nts);
257 ok(ul == us_dst.Length + sizeof(WCHAR),
258 "Wrong returned length for %s: %u\n", test->src, ul);
259 ok(ul == strlen(test->dst) * sizeof(WCHAR) + sizeof(WCHAR),
260 "Wrong returned length for %s: %u\n", test->src, ul);
261 ok(lstrcmpW(dst, rst) == 0, "Wrong result for %s: expecting %s\n",
262 test->src, test->dst);
263
264 us_dst.Length = 0;
265 us_dst.MaximumLength = 8 * sizeof(WCHAR);
266 us_dst.Buffer = dst;
267 dst[8] = '-';
268 nts = pRtlExpandEnvironmentStrings_U(small_env, &us_src, &us_dst, &ul);
269 ok(nts == STATUS_BUFFER_TOO_SMALL, "Call failed (%u)\n", nts);
270 ok(ul == strlen(test->dst) * sizeof(WCHAR) + sizeof(WCHAR),
271 "Wrong returned length for %s (with buffer too small): %u\n", test->src, ul);
272 ok(dst[8] == '-', "Writing too far in buffer (got %c/%d)\n", dst[8], dst[8]);
273 }
274
275 }
276
277 START_TEST(env)
278 {
279 HMODULE mod = GetModuleHandleA("ntdll.dll");
280 if (!mod)
281 {
282 win_skip("Not running on NT, skipping tests\n");
283 return;
284 }
285
286 pRtlMultiByteToUnicodeN = (void *)GetProcAddress(mod,"RtlMultiByteToUnicodeN");
287 pRtlCreateEnvironment = (void*)GetProcAddress(mod, "RtlCreateEnvironment");
288 pRtlDestroyEnvironment = (void*)GetProcAddress(mod, "RtlDestroyEnvironment");
289 pRtlQueryEnvironmentVariable_U = (void*)GetProcAddress(mod, "RtlQueryEnvironmentVariable_U");
290 pRtlSetCurrentEnvironment = (void*)GetProcAddress(mod, "RtlSetCurrentEnvironment");
291 pRtlSetEnvironmentVariable = (void*)GetProcAddress(mod, "RtlSetEnvironmentVariable");
292 pRtlExpandEnvironmentStrings_U = (void*)GetProcAddress(mod, "RtlExpandEnvironmentStrings_U");
293
294 if (pRtlQueryEnvironmentVariable_U)
295 testQuery();
296 if (pRtlSetEnvironmentVariable)
297 testSet();
298 if (pRtlExpandEnvironmentStrings_U)
299 testExpand();
300 }