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