2 * Unit test suite for ntdll path functions
4 * Copyright 2003 Eric Pouech
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.
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.
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
23 #include "ntdll_test.h"
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
);
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,
52 static void testQuery(void)
63 static const struct test tests
[] =
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
, ""},
92 for (i
= 0; tests
[i
].var
; i
++)
94 const struct test
*test
= &tests
[i
];
95 name
.Length
= strlen(test
->var
) * 2;
96 name
.MaximumLength
= name
.Length
+ 2;
99 value
.MaximumLength
= test
->len
* 2;
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
)
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
, value
.Length
) == 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
);
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
);
127 static void testSetHelper(LPWSTR
* env
, const char* var
, const char* val
, NTSTATUS ret
, NTSTATUS alt
)
129 WCHAR bvar
[256], bval1
[256], bval2
[256];
134 uvar
.Length
= strlen(var
) * sizeof(WCHAR
);
135 uvar
.MaximumLength
= uvar
.Length
+ sizeof(WCHAR
);
137 pRtlMultiByteToUnicodeN( bvar
, sizeof(bvar
), NULL
, var
, strlen(var
)+1 );
140 uval
.Length
= strlen(val
) * sizeof(WCHAR
);
141 uval
.MaximumLength
= uval
.Length
+ sizeof(WCHAR
);
143 pRtlMultiByteToUnicodeN( bval1
, sizeof(bval1
), NULL
, val
, strlen(val
)+1 );
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
)
150 uval
.MaximumLength
= sizeof(bval2
);
152 nts
= pRtlQueryEnvironmentVariable_U(*env
, &uvar
, &uval
);
156 ok(lstrcmpW(bval1
, bval2
) == 0, "Cannot get value written to environment\n");
158 case STATUS_VARIABLE_NOT_FOUND
:
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
);
164 ok(0, "Wrong ret %u for %s\n", nts
, var
);
170 static void testSet(void)
176 ok(pRtlCreateEnvironment(FALSE
, &env
) == STATUS_SUCCESS
, "Creating environment\n");
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);
189 for (i
= 0; i
< 128; i
++)
191 sprintf(tmp
, "zork%03d", i
);
192 testSetHelper(&env
, tmp
, "is alive", STATUS_SUCCESS
, 0);
195 for (i
= 0; i
< 128; i
++)
197 sprintf(tmp
, "zork%03d", i
);
198 testSetHelper(&env
, tmp
, NULL
, STATUS_SUCCESS
, 0);
200 testSetHelper(&env
, "fOo", NULL
, STATUS_SUCCESS
, 0);
202 ok(pRtlDestroyEnvironment(env
) == STATUS_SUCCESS
, "Destroying environment\n");
205 static void testExpand(void)
207 static const struct test
213 {"hello%foo%world", "hellototoworld"},
214 {"hello%=oOH%world", "helloIIIworld"},
215 {"hello%foo", "hello%foo"},
216 {"hello%bar%world", "hello%bar%world"},
218 * {"hello%foo%world%=oOH%eeck", "hellototoworldIIIeeck"},
219 * Interestingly enough, with a 8 WCHAR buffers, we get on 2k:
221 * so it seems like strings overflowing the buffer are written
222 * (truncated) but the write cursor is not advanced :-/
227 const struct test
* test
;
229 UNICODE_STRING us_src
, us_dst
;
230 WCHAR src
[256], dst
[256], rst
[256];
233 for (test
= tests
; test
->src
; test
++)
235 pRtlMultiByteToUnicodeN(src
, sizeof(src
), NULL
, test
->src
, strlen(test
->src
)+1);
236 pRtlMultiByteToUnicodeN(rst
, sizeof(rst
), NULL
, test
->dst
, strlen(test
->dst
)+1);
238 us_src
.Length
= strlen(test
->src
) * sizeof(WCHAR
);
239 us_src
.MaximumLength
= us_src
.Length
+ 2;
243 us_dst
.MaximumLength
= 0;
244 us_dst
.Buffer
= NULL
;
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
);
252 us_dst
.MaximumLength
= sizeof(dst
);
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
);
265 us_dst
.MaximumLength
= 8 * sizeof(WCHAR
);
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]);
279 HMODULE mod
= GetModuleHandleA("ntdll.dll");
282 win_skip("Not running on NT, skipping tests\n");
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");
294 if (pRtlQueryEnvironmentVariable_U
)
296 if (pRtlSetEnvironmentVariable
)
298 if (pRtlExpandEnvironmentStrings_U
)