user32/tests: Remove an unneeded cast.
[wine/testsucceed.git] / dlls / setupapi / tests / parser.c
blob1c3ca49bd4c37e5cd19c945549b5b371a05f3115
1 /*
2 * INF file parsing tests
4 * Copyright 2002, 2005 Alexandre Julliard for CodeWeavers
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
21 #include <assert.h>
22 #include <stdarg.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winreg.h"
29 #include "setupapi.h"
31 #include "wine/test.h"
33 /* function pointers */
34 static HMODULE hSetupAPI;
35 static LPCWSTR (WINAPI *pSetupGetField)(PINFCONTEXT,DWORD);
37 static void init_function_pointers(void)
39 hSetupAPI = GetModuleHandleA("setupapi.dll");
41 pSetupGetField = (void *)GetProcAddress(hSetupAPI, "pSetupGetField");
44 static const char tmpfilename[] = ".\\tmp.inf";
46 /* some large strings */
47 #define A255 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
48 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
49 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
50 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
51 #define A256 "a" A255
52 #define A400 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
53 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
54 "aaaaaaaaaaaaaaaa" A256
55 #define A511 A255 A256
56 #define A4097 "a" A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256
58 #define STD_HEADER "[Version]\r\nSignature=\"$CHICAGO$\"\r\n"
60 #define STR_SECTION "[Strings]\nfoo=aaa\nbar=bbb\nloop=%loop2%\nloop2=%loop%\n" \
61 "per%%cent=abcd\nper=1\ncent=2\n22=foo\n" \
62 "big=" A400 "\n" \
63 "mydrive=\"C:\\\"\n" \
64 "verybig=" A400 A400 A400 "\n"
66 /* create a new file with specified contents and open it */
67 static HINF test_file_contents( const char *data, UINT *err_line )
69 DWORD res;
70 HANDLE handle = CreateFileA( tmpfilename, GENERIC_READ|GENERIC_WRITE,
71 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, 0 );
72 if (handle == INVALID_HANDLE_VALUE) return 0;
73 if (!WriteFile( handle, data, strlen(data), &res, NULL )) trace( "write error\n" );
74 CloseHandle( handle );
75 return SetupOpenInfFileA( tmpfilename, 0, INF_STYLE_WIN4, err_line );
78 static const char *get_string_field( INFCONTEXT *context, DWORD index )
80 static char buffer[MAX_INF_STRING_LENGTH+32];
81 if (SetupGetStringFieldA( context, index, buffer, sizeof(buffer), NULL )) return buffer;
82 return NULL;
85 static const char *get_line_text( INFCONTEXT *context )
87 static char buffer[MAX_INF_STRING_LENGTH+32];
88 if (SetupGetLineTextA( context, 0, 0, 0, buffer, sizeof(buffer), NULL )) return buffer;
89 return NULL;
93 /* Test various valid/invalid file formats */
95 static const struct
97 const char *data;
98 DWORD error;
99 UINT err_line;
100 int todo;
101 } invalid_files[] =
103 /* file contents expected error (or 0) errline todo */
104 { "\r\n", ERROR_WRONG_INF_STYLE, 0, 0 },
105 { "abcd\r\n", ERROR_WRONG_INF_STYLE, 0, 1 },
106 { "[Version]\r\n", ERROR_WRONG_INF_STYLE, 0, 0 },
107 { "[Version]\nSignature=", ERROR_WRONG_INF_STYLE, 0, 0 },
108 { "[Version]\nSignature=foo", ERROR_WRONG_INF_STYLE, 0, 0 },
109 { "[version]\nsignature=$chicago$", 0, 0, 0 },
110 { "[VERSION]\nSIGNATURE=$CHICAGO$", 0, 0, 0 },
111 { "[Version]\nSignature=$chicago$,abcd", 0, 0, 0 },
112 { "[Version]\nabc=def\nSignature=$chicago$", 0, 0, 0 },
113 { "[Version]\nabc=def\n[Version]\nSignature=$chicago$", 0, 0, 0 },
114 { STD_HEADER, 0, 0, 0 },
115 { STD_HEADER "[]\r\n", 0, 0, 0 },
116 { STD_HEADER "]\r\n", 0, 0, 0 },
117 { STD_HEADER "[" A255 "]\r\n", 0, 0, 0 },
118 { STD_HEADER "[ab\r\n", ERROR_BAD_SECTION_NAME_LINE, 3, 0 },
119 { STD_HEADER "\n\n[ab\x1a]\n", ERROR_BAD_SECTION_NAME_LINE, 5, 0 },
120 { STD_HEADER "[" A256 "]\r\n", ERROR_SECTION_NAME_TOO_LONG, 3, 0 },
121 { "[abc]\n" STD_HEADER, 0, 0, 0 },
122 { "abc\r\n" STD_HEADER, ERROR_EXPECTED_SECTION_NAME, 1, 0 },
123 { ";\n;\nabc\r\n" STD_HEADER, ERROR_EXPECTED_SECTION_NAME, 3, 0 },
124 { ";\n;\nab\nab\n" STD_HEADER, ERROR_EXPECTED_SECTION_NAME, 3, 0 },
125 { ";aa\n;bb\n" STD_HEADER, 0, 0, 0 },
126 { STD_HEADER " [TestSection\x00] \n", ERROR_BAD_SECTION_NAME_LINE, 3, 0 },
127 { STD_HEADER " [Test\x00Section] \n", ERROR_BAD_SECTION_NAME_LINE, 3, 0 },
128 { STD_HEADER " [TestSection\x00] \n", ERROR_BAD_SECTION_NAME_LINE, 3, 0 },
129 { STD_HEADER " [Test\x00Section] \n", ERROR_BAD_SECTION_NAME_LINE, 3, 0 },
132 static void test_invalid_files(void)
134 unsigned int i;
135 UINT err_line;
136 HINF hinf;
137 DWORD err;
139 for (i = 0; i < sizeof(invalid_files)/sizeof(invalid_files[0]); i++)
141 SetLastError( 0xdeadbeef );
142 err_line = 0xdeadbeef;
143 hinf = test_file_contents( invalid_files[i].data, &err_line );
144 err = GetLastError();
145 trace( "hinf=%p err=0x%x line=%d\n", hinf, err, err_line );
146 if (invalid_files[i].error) /* should fail */
148 ok( hinf == INVALID_HANDLE_VALUE, "file %u: Open succeeded\n", i );
149 if (invalid_files[i].todo) todo_wine
151 ok( err == invalid_files[i].error, "file %u: Bad error %u/%u\n",
152 i, err, invalid_files[i].error );
153 ok( err_line == invalid_files[i].err_line, "file %u: Bad error line %d/%d\n",
154 i, err_line, invalid_files[i].err_line );
156 else
158 ok( err == invalid_files[i].error, "file %u: Bad error %u/%u\n",
159 i, err, invalid_files[i].error );
160 ok( err_line == invalid_files[i].err_line, "file %u: Bad error line %d/%d\n",
161 i, err_line, invalid_files[i].err_line );
164 else /* should succeed */
166 ok( hinf != INVALID_HANDLE_VALUE, "file %u: Open failed\n", i );
167 ok( err == 0, "file %u: Error code set to %u\n", i, err );
169 SetupCloseInfFile( hinf );
174 /* Test various section names */
176 static const struct
178 const char *data;
179 const char *section;
180 DWORD error;
181 } section_names[] =
183 /* file contents section name error code */
184 { STD_HEADER "[TestSection]", "TestSection", 0 },
185 { STD_HEADER "[TestSection]\n", "TestSection", 0 },
186 { STD_HEADER "[TESTSECTION]\r\n", "TestSection", 0 },
187 { STD_HEADER "[TestSection]\n[abc]", "testsection", 0 },
188 { STD_HEADER ";[TestSection]\n", "TestSection", ERROR_SECTION_NOT_FOUND },
189 { STD_HEADER "[TestSection]\n", "Bad name", ERROR_SECTION_NOT_FOUND },
190 /* spaces */
191 { STD_HEADER "[TestSection] \r\n", "TestSection", 0 },
192 { STD_HEADER " [TestSection]\r\n", "TestSection", 0 },
193 { STD_HEADER " [TestSection] dummy\r\n", "TestSection", 0 },
194 { STD_HEADER " [TestSection] [foo]\r\n", "TestSection", 0 },
195 { STD_HEADER " [ Test Section ] dummy\r\n", " Test Section ", 0 },
196 { STD_HEADER "[TestSection] \032\ndummy", "TestSection", 0 },
197 { STD_HEADER "[TestSection] \n\032dummy", "TestSection", 0 },
198 /* special chars in section name */
199 { STD_HEADER "[Test[Section]\r\n", "Test[Section", 0 },
200 { STD_HEADER "[Test[S]ection]\r\n", "Test[S", 0 },
201 { STD_HEADER "[Test[[[Section]\r\n", "Test[[[Section", 0 },
202 { STD_HEADER "[]\r\n", "", 0 },
203 { STD_HEADER "[[[]\n", "[[", 0 },
204 { STD_HEADER "[Test\"Section]\r\n", "Test\"Section", 0 },
205 { STD_HEADER "[Test\\Section]\r\n", "Test\\Section", 0 },
206 { STD_HEADER "[Test\\ Section]\r\n", "Test\\ Section", 0 },
207 { STD_HEADER "[Test;Section]\r\n", "Test;Section", 0 },
208 /* various control chars */
209 { STD_HEADER " [Test\r\b\tSection] \n", "Test\r\b\tSection", 0 },
210 /* nulls */
213 static void test_section_names(void)
215 unsigned int i;
216 UINT err_line;
217 HINF hinf;
218 DWORD err;
219 LONG ret;
221 for (i = 0; i < sizeof(section_names)/sizeof(section_names[0]); i++)
223 SetLastError( 0xdeadbeef );
224 hinf = test_file_contents( section_names[i].data, &err_line );
225 ok( hinf != INVALID_HANDLE_VALUE, "line %u: open failed err %u\n", i, GetLastError() );
226 if (hinf == INVALID_HANDLE_VALUE) continue;
228 ret = SetupGetLineCountA( hinf, section_names[i].section );
229 err = GetLastError();
230 trace( "hinf=%p ret=%d err=0x%x\n", hinf, ret, err );
231 if (ret != -1)
233 ok( !section_names[i].error, "line %u: section name %s found\n",
234 i, section_names[i].section );
235 ok( !err, "line %u: bad error code %u\n", i, err );
237 else
239 ok( section_names[i].error, "line %u: section name %s not found\n",
240 i, section_names[i].section );
241 ok( err == section_names[i].error, "line %u: bad error %u/%u\n",
242 i, err, section_names[i].error );
244 SetupCloseInfFile( hinf );
249 /* Test various key and value names */
251 static const struct
253 const char *data;
254 const char *key;
255 const char *fields[10];
256 } key_names[] =
258 /* file contents expected key expected fields */
259 { "ab=cd", "ab", { "cd" } },
260 { "ab=cd,ef,gh,ij", "ab", { "cd", "ef", "gh", "ij" } },
261 { "ab", "ab", { "ab" } },
262 { "ab,cd", NULL, { "ab", "cd" } },
263 { "ab,cd=ef", NULL, { "ab", "cd=ef" } },
264 { "=abcd,ef", "", { "abcd", "ef" } },
265 /* backslashes */
266 { "ba\\\ncd=ef", "bacd", { "ef" } },
267 { "ab \\ \ncd=ef", "abcd", { "ef" } },
268 { "ab\\\ncd,ef", NULL, { "abcd", "ef" } },
269 { "ab \\ ;cc\ncd=ef", "abcd", { "ef" } },
270 { "ab \\ \\ \ncd=ef", "abcd", { "ef" } },
271 { "ba \\ dc=xx", "ba \\ dc", { "xx" } },
272 { "ba \\\\ \nc=d", "bac", { "d" } },
273 { "a=b\\\\c", "a", { "b\\\\c" } },
274 { "ab=cd \\ ", "ab", { "cd" } },
275 { "ba=c \\ \n \\ \n a", "ba", { "ca" } },
276 { "ba=c \\ \n \\ a", "ba", { "c\\ a" } },
277 { " \\ a= \\ b", "\\ a", { "\\ b" } },
278 /* quotes */
279 { "Ab\"Cd\"=Ef", "AbCd", { "Ef" } },
280 { "Ab\"Cd=Ef\"", "AbCd=Ef", { "AbCd=Ef" } },
281 { "ab\"\"\"cd,ef=gh\"", "ab\"cd,ef=gh", { "ab\"cd,ef=gh" } },
282 { "ab\"\"cd=ef", "abcd", { "ef" } },
283 { "ab\"\"cd=ef,gh", "abcd", { "ef", "gh" } },
284 { "ab=cd\"\"ef", "ab", { "cdef" } },
285 { "ab=cd\",\"ef", "ab", { "cd,ef" } },
286 { "ab=cd\",ef", "ab", { "cd,ef" } },
287 { "ab=cd\",ef\\\nab", "ab", { "cd,ef\\" } },
289 /* single quotes (unhandled)*/
290 { "HKLM,A,B,'C',D", NULL, { "HKLM", "A","B","'C'","D" } },
291 /* spaces */
292 { " a b = c , d \n", "a b", { "c", "d" } },
293 { " a b = c ,\" d\" \n", "a b", { "c", " d" } },
294 { " a b\r = c\r\n", "a b", { "c" } },
295 /* empty fields */
296 { "a=b,,,c,,,d", "a", { "b", "", "", "c", "", "", "d" } },
297 { "a=b,\"\",c,\" \",d", "a", { "b", "", "c", " ", "d" } },
298 { "=,,b", "", { "", "", "b" } },
299 { ",=,,b", NULL, { "", "=", "", "b" } },
300 { "a=\n", "a", { "" } },
301 { "=", "", { "" } },
302 /* eof */
303 { "ab=c\032d", "ab", { "c" } },
304 { "ab\032=cd", "ab", { "ab" } },
305 /* nulls */
306 { "abcd=ef\x0gh", "abcd", { "ef" } },
307 /* multiple sections with same name */
308 { "[Test2]\nab\n[Test]\nee=ff\n", "ee", { "ff" } },
309 /* string substitution */
310 { "%foo%=%bar%\n" STR_SECTION, "aaa", { "bbb" } },
311 { "%foo%xx=%bar%yy\n" STR_SECTION, "aaaxx", { "bbbyy" } },
312 { "%% %foo%=%bar%\n" STR_SECTION, "% aaa", { "bbb" } },
313 { "%f\"o\"o%=ccc\n" STR_SECTION, "aaa", { "ccc" } },
314 { "abc=%bar;bla%\n" STR_SECTION, "abc", { "%bar" } },
315 { "loop=%loop%\n" STR_SECTION, "loop", { "%loop2%" } },
316 { "%per%%cent%=100\n" STR_SECTION, "12", { "100" } },
317 { "a=%big%\n" STR_SECTION, "a", { A400 } },
318 { "a=%verybig%\n" STR_SECTION, "a", { A511 } }, /* truncated to 511 */
319 { "a=%big%%big%%big%%big%\n" STR_SECTION, "a", { A400 A400 A400 A400 } },
320 { "a=%big%%big%%big%%big%%big%%big%%big%%big%%big%\n" STR_SECTION, "a", { A400 A400 A400 A400 A400 A400 A400 A400 A400 } },
321 { "a=%big%%big%%big%%big%%big%%big%%big%%big%%big%%big%%big%\n" STR_SECTION, "a", { A4097 /*MAX_INF_STRING_LENGTH+1*/ } },
323 /* Prove expansion of system entries removes extra \'s and string
324 replacements doesn't */
325 { "ab=\"%24%\"\n" STR_SECTION, "ab", { "C:\\" } },
326 { "ab=\"%mydrive%\"\n" STR_SECTION, "ab", { "C:\\" } },
327 { "ab=\"%24%\\fred\"\n" STR_SECTION, "ab", { "C:\\fred" } },
328 { "ab=\"%mydrive%\\fred\"\n" STR_SECTION,"ab", { "C:\\\\fred" } },
329 /* Confirm duplicate \'s kept */
330 { "ab=\"%24%\\\\fred\"", "ab", { "C:\\\\fred" } },
331 { "ab=C:\\\\FRED", "ab", { "C:\\\\FRED" } },
334 /* check the key of a certain line */
335 static const char *check_key( INFCONTEXT *context, const char *wanted )
337 const char *key = get_string_field( context, 0 );
338 DWORD err = GetLastError();
340 if (!key)
342 ok( !wanted, "missing key %s\n", wanted );
343 ok( err == 0 || err == ERROR_INVALID_PARAMETER, "last error set to %u\n", err );
345 else
347 ok( !strcmp( key, wanted ), "bad key %s/%s\n", key, wanted );
348 ok( err == 0, "last error set to %u\n", err );
350 return key;
353 static void test_key_names(void)
355 char buffer[MAX_INF_STRING_LENGTH+32];
356 const char *key, *line;
357 unsigned int i, index, count;
358 UINT err_line;
359 HINF hinf;
360 DWORD err;
361 BOOL ret;
362 INFCONTEXT context;
364 for (i = 0; i < sizeof(key_names)/sizeof(key_names[0]); i++)
366 strcpy( buffer, STD_HEADER "[Test]\n" );
367 strcat( buffer, key_names[i].data );
368 SetLastError( 0xdeadbeef );
369 hinf = test_file_contents( buffer, &err_line );
370 ok( hinf != INVALID_HANDLE_VALUE, "line %u: open failed err %u\n", i, GetLastError() );
371 if (hinf == INVALID_HANDLE_VALUE) continue;
373 ret = SetupFindFirstLineA( hinf, "Test", 0, &context );
374 assert( ret );
376 key = check_key( &context, key_names[i].key );
378 buffer[0] = buffer[1] = 0; /* build the full line */
379 for (index = 0; ; index++)
381 const char *field = get_string_field( &context, index + 1 );
382 err = GetLastError();
383 if (field)
385 ok( err == 0, "line %u: bad error %u\n", i, err );
386 if (key_names[i].fields[index])
387 ok( !strcmp( field, key_names[i].fields[index] ), "line %u: bad field %s/%s\n",
388 i, field, key_names[i].fields[index] );
389 else
390 ok( 0, "line %u: got extra field %s\n", i, field );
391 strcat( buffer, "," );
392 strcat( buffer, field );
394 else
396 ok( err == 0 || err == ERROR_INVALID_PARAMETER,
397 "line %u: bad error %u\n", i, err );
398 if (key_names[i].fields[index])
399 ok( 0, "line %u: missing field %s\n", i, key_names[i].fields[index] );
401 if (!key_names[i].fields[index]) break;
403 count = SetupGetFieldCount( &context );
404 ok( count == index, "line %u: bad count %d/%d\n", i, index, count );
406 line = get_line_text( &context );
407 ok( line != NULL, "line %u: SetupGetLineText failed\n", i );
408 if (line) ok( !strcmp( line, buffer+1 ), "line %u: bad text %s/%s\n", i, line, buffer+1 );
410 SetupCloseInfFile( hinf );
415 static void test_close_inf_file(void)
417 SetLastError(0xdeadbeef);
418 SetupCloseInfFile(NULL);
419 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %u\n", GetLastError());
421 SetLastError(0xdeadbeef);
422 SetupCloseInfFile(INVALID_HANDLE_VALUE);
423 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %u\n", GetLastError());
427 static const char *contents = "[Version]\n"
428 "Signature=\"$Windows NT$\"\n"
429 "FileVersion=5.1.1.2\n"
430 "[FileBranchInfo]\n"
431 "RTMQFE=\"%RTMGFE_NAME%\",SP1RTM,"A4097"\n"
432 "[Strings]\n"
433 "RTMQFE_NAME = \"RTMQFE\"\n";
435 static const WCHAR getfield_res[][20] =
437 {'R','T','M','Q','F','E',0},
438 {'%','R','T','M','G','F','E','_','N','A','M','E','%',0},
439 {'S','P','1','R','T','M',0},
442 static void test_pSetupGetField(void)
444 UINT err;
445 BOOL ret;
446 HINF hinf;
447 LPCWSTR field;
448 INFCONTEXT context;
449 int i;
451 hinf = test_file_contents( contents, &err );
452 ok( hinf != NULL, "Expected valid INF file\n" );
454 ret = SetupFindFirstLine( hinf, "FileBranchInfo", NULL, &context );
455 ok( ret, "Failed to find first line\n" );
457 /* native Windows crashes if a NULL context is sent in */
459 for ( i = 0; i < 3; i++ )
461 field = pSetupGetField( &context, i );
462 ok( field != NULL, "Failed to get field %i\n", i );
463 ok( !lstrcmpW( getfield_res[i], field ), "Wrong string returned\n" );
465 ret = HeapFree( GetProcessHeap(), 0, (LPVOID)field );
466 ok( !ret, "Expected HeapFree to fail\n" );
467 ok( GetLastError() == ERROR_INVALID_PARAMETER,
468 "Expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError() );
471 field = pSetupGetField( &context, 3 );
472 ok( field != NULL, "Failed to get field 3\n" );
473 ok( lstrlenW( field ) == 511, "Expected 511, got %d\n", lstrlenW( field ) );
475 field = pSetupGetField( &context, 4 );
476 ok( field == NULL, "Expected NULL, got %p\n", field );
477 ok( GetLastError() == ERROR_INVALID_PARAMETER,
478 "Expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError() );
480 SetupCloseInfFile( hinf );
483 START_TEST(parser)
485 init_function_pointers();
486 test_invalid_files();
487 test_section_names();
488 test_key_names();
489 test_close_inf_file();
490 test_pSetupGetField();
491 DeleteFileA( tmpfilename );