VirtualBox

source: vbox/trunk/src/VBox/Runtime/testcase/tstRTGetOptArgv.cpp@ 55562

Last change on this file since 55562 was 55499, checked in by vboxsync, 10 years ago

tstRTGetOptArgv.cpp: Use CommandLineToArgvW to verify the RTGetOptArgvToString/MS_CRT output when we're on windows.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.9 KB
Line 
1/* $Id: tstRTGetOptArgv.cpp 55499 2015-04-28 23:54:11Z vboxsync $ */
2/** @file
3 * IPRT Testcase - RTGetOptArgv*.
4 */
5
6/*
7 * Copyright (C) 2010 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27/*******************************************************************************
28* Header Files *
29*******************************************************************************/
30#include <iprt/path.h>
31
32#include <iprt/err.h>
33#include <iprt/param.h>
34#include <iprt/getopt.h>
35#include <iprt/ldr.h>
36#include <iprt/string.h>
37#include <iprt/test.h>
38
39
40/*******************************************************************************
41* Global Variables *
42*******************************************************************************/
43static const struct
44{
45 /** The input string. */
46 const char *pszInput;
47 /** Separators, NULL if default. */
48 const char *pszSeparators;
49 /** The number of arguments. */
50 int cArgs;
51 /** Expected argument vector. */
52 const char *apszArgs[16];
53 /** Expected quoted string, bourne shell. */
54 const char *pszOutBourneSh;
55 /** Expected quoted string, MSC CRT. */
56 const char *pszOutMsCrt;
57} g_aBourneTests[] =
58{
59 {
60 "0 1 \"\"2'' '3' 4 5 '''''6' 7 8 9 10 11",
61 NULL,
62 12,
63 {
64 "0",
65 "1",
66 "2",
67 "3",
68 "4",
69 "5",
70 "6",
71 "7",
72 "8",
73 "9",
74 "10",
75 "11",
76 NULL, NULL, NULL, NULL,
77 },
78 "0 1 2 3 4 5 6 7 8 9 10 11",
79 "0 1 2 3 4 5 6 7 8 9 10 11"
80 },
81 {
82 "\t\" asdf \" '\"'xyz \"\t\" '\n' '\"' \"'\"\n\r ",
83 NULL,
84 6,
85 {
86 " asdf ",
87 "\"xyz",
88 "\t",
89 "\n",
90 "\"",
91 "\'",
92 NULL, NULL,
93 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
94 },
95 "' asdf ' '\"xyz' '\t' '\n' '\"' ''\"'\"''",
96 "\" asdf \" \"\\\"xyz\" \"\t\" \"\n\" \"\\\"\" '"
97 },
98 {
99 ":0::1::::2:3:4:5:",
100 ":",
101 6,
102 {
103 "0",
104 "1",
105 "2",
106 "3",
107 "4",
108 "5",
109 NULL, NULL,
110 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
111 },
112 "0 1 2 3 4 5",
113 "0 1 2 3 4 5"
114 },
115 {
116 "0:1;2:3;4:5",
117 ";;;;;;;;;;;;;;;;;;;;;;:",
118 6,
119 {
120 "0",
121 "1",
122 "2",
123 "3",
124 "4",
125 "5",
126 NULL, NULL,
127 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
128 },
129 "0 1 2 3 4 5",
130 "0 1 2 3 4 5"
131 },
132 {
133 "abcd 'a ' ' b' ' c '",
134 NULL,
135 4,
136 {
137 "abcd",
138 "a ",
139 " b",
140 " c ",
141 NULL, NULL, NULL, NULL,
142 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
143 },
144 "abcd 'a ' ' b' ' c '",
145 "abcd \"a \" \" b\" \" c \""
146 },
147 {
148 "'a\n\\b' 'de'\"'\"'fg' h ''\"'\"''",
149 NULL,
150 4,
151 {
152 "a\n\\b",
153 "de'fg",
154 "h",
155 "'",
156 NULL, NULL, NULL, NULL,
157 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
158 },
159 "'a\n\\b' 'de'\"'\"'fg' h ''\"'\"''",
160 "\"a\n\\b\" de'fg h '"
161 },
162 {
163 "arg1 \"arg2=\\\"zyx\\\"\" 'arg3=\\\\\\'",
164 NULL,
165 3,
166 {
167 "arg1",
168 "arg2=\"zyx\"",
169 "arg3=\\\\\\",
170 NULL, NULL, NULL, NULL, NULL,
171 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
172 },
173 "arg1 'arg2=\"zyx\"' 'arg3=\\\\\\'",
174 "arg1 \"arg2=\\\"zyx\\\"\" arg3=\\\\\\"
175 },
176 {
177 " a\\\\\\\\b d\"e f\"g h ij\t",
178 NULL,
179 4,
180 {
181 "a\\\\b",
182 "de fg",
183 "h",
184 "ij",
185 NULL, NULL, NULL, NULL,
186 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
187 },
188 "'a\\\\b' 'de fg' h ij",
189 "a\\\\b \"de fg\" h ij",
190 }
191};
192
193
194
195static void tstCheckNativeMsCrtToArgv(const char *pszCmdLine, int cExpectedArgs, const char * const *papszExpectedArgs)
196{
197#ifdef RT_OS_WINDOWS
198 /*
199 * Resolve APIs.
200 */
201 static void *(__stdcall * s_pfnLocalFree)(void *pvFree);
202 static PRTUTF16 *(__stdcall * s_pfnCommandLineToArgvW)(PCRTUTF16 pwszCmdLine, int *pcArgs);
203 if (!s_pfnCommandLineToArgvW)
204 {
205 *(void **)&s_pfnLocalFree = RTLdrGetSystemSymbol("kernel32.dll", "LocalFree");
206 RTTESTI_CHECK_RETV(s_pfnLocalFree != NULL);
207 *(void **)&s_pfnCommandLineToArgvW = RTLdrGetSystemSymbol("shell32.dll", "CommandLineToArgvW");
208 RTTESTI_CHECK_RETV(s_pfnCommandLineToArgvW != NULL);
209 }
210
211 /*
212 * Calc expected arguments if needed.
213 */
214 if (cExpectedArgs == -1)
215 for (cExpectedArgs = 0; papszExpectedArgs[cExpectedArgs]; cExpectedArgs++)
216 { /* nothing */ }
217
218 /*
219 * Convert input command line to UTF-16 and call native API.
220 */
221 RTUTF16 wszCmdLine[1024];
222 PRTUTF16 pwszCmdLine = &wszCmdLine[1];
223 RTTESTI_CHECK_RC_RETV(RTStrToUtf16Ex(pszCmdLine, RTSTR_MAX, &pwszCmdLine, 1023, NULL), VINF_SUCCESS);
224 wszCmdLine[0] = ' ';
225
226 int cArgs = -2;
227 PRTUTF16 *papwszArgs = s_pfnCommandLineToArgvW(wszCmdLine, &cArgs);
228
229 /*
230 * Check the result.
231 */
232 if (cArgs - 1 != cExpectedArgs)
233 RTTestIFailed("Native returns cArgs=%d, expected %d (cmdline=|%s|)", cArgs - 1, cExpectedArgs, pszCmdLine);
234 int cArgsCheck = RT_MIN(cArgs - 1, cExpectedArgs);
235 for (int i = 0; i < cArgsCheck; i++)
236 {
237 char *pszArg = NULL;
238 RTTESTI_CHECK_RC_RETV(RTUtf16ToUtf8(papwszArgs[i + 1], &pszArg), VINF_SUCCESS);
239 if (strcmp(pszArg, papszExpectedArgs[i]))
240 RTTestIFailed("Native returns argv[%i]='%s', expected '%s' (cmdline=|%s|)",
241 i, pszArg, papszExpectedArgs[i], pszCmdLine);
242 RTStrFree(pszArg);
243 }
244
245 if (papwszArgs)
246 s_pfnLocalFree(papwszArgs);
247#else
248 NOREF(pszCmdLine);
249 NOREF(cExpectedArgs);
250 NOREF(papszExpectedArgs);
251#endif
252}
253
254
255
256static void tst3(void)
257{
258 /*
259 * Bourne shell round-tripping.
260 */
261 RTTestISub("Round-trips / BOURNE_SH");
262 for (unsigned i = 0; i < RT_ELEMENTS(g_aBourneTests); i++)
263 {
264 /* First */
265 char **papszArgs1 = NULL;
266 int cArgs1 = -1;
267 int rc = RTGetOptArgvFromString(&papszArgs1, &cArgs1, g_aBourneTests[i].pszInput, g_aBourneTests[i].pszSeparators);
268 if (rc == VINF_SUCCESS)
269 {
270 if (cArgs1 != g_aBourneTests[i].cArgs)
271 RTTestIFailed("g_aBourneTests[%i]: #1=%d, expected %d", i, cArgs1, g_aBourneTests[i].cArgs);
272 for (int iArg = 0; iArg < cArgs1; iArg++)
273 if (strcmp(papszArgs1[iArg], g_aBourneTests[i].apszArgs[iArg]) != 0)
274 RTTestIFailed("g_aBourneTests[%i]/1: argv[%i] differs: got '%s', expected '%s' (RTGetOptArgvFromString(,,'%s', '%s'))",
275 i, iArg, papszArgs1[iArg], g_aBourneTests[i].apszArgs[iArg],
276 g_aBourneTests[i].pszInput, g_aBourneTests[i].pszSeparators);
277 RTTESTI_CHECK_RETV(papszArgs1[cArgs1] == NULL);
278
279 /* Second */
280 char *pszArgs2 = NULL;
281 rc = RTGetOptArgvToString(&pszArgs2, papszArgs1, RTGETOPTARGV_CNV_QUOTE_BOURNE_SH);
282 if (rc == VINF_SUCCESS)
283 {
284 if (strcmp(pszArgs2, g_aBourneTests[i].pszOutBourneSh))
285 RTTestIFailed("g_aBourneTests[%i]/2: '%s', expected '%s'", i, pszArgs2, g_aBourneTests[i].pszOutBourneSh);
286
287 /*
288 * Third
289 */
290 char **papszArgs3 = NULL;
291 int cArgs3 = -1;
292 rc = RTGetOptArgvFromString(&papszArgs3, &cArgs3, pszArgs2, NULL);
293 if (rc == VINF_SUCCESS)
294 {
295 if (cArgs3 != g_aBourneTests[i].cArgs)
296 RTTestIFailed("g_aBourneTests[%i]/3: %d, expected %d", i, cArgs3, g_aBourneTests[i].cArgs);
297 for (int iArg = 0; iArg < cArgs3; iArg++)
298 if (strcmp(papszArgs3[iArg], g_aBourneTests[i].apszArgs[iArg]) != 0)
299 RTTestIFailed("g_aBourneTests[%i]/3: argv[%i] differs: got '%s', expected '%s' (RTGetOptArgvFromString(,,'%s',))",
300 i, iArg, papszArgs3[iArg], g_aBourneTests[i].apszArgs[iArg], pszArgs2);
301 RTTESTI_CHECK_RETV(papszArgs3[cArgs3] == NULL);
302
303 /*
304 * Fourth
305 */
306 char *pszArgs4 = NULL;
307 rc = RTGetOptArgvToString(&pszArgs4, papszArgs3, RTGETOPTARGV_CNV_QUOTE_BOURNE_SH);
308 if (rc == VINF_SUCCESS)
309 {
310 if (strcmp(pszArgs4, pszArgs2))
311 RTTestIFailed("g_aBourneTests[%i]/4: '%s' does not match #4='%s'", i, pszArgs2, pszArgs4);
312 RTStrFree(pszArgs4);
313 }
314 else
315 RTTestIFailed("g_aBourneTests[%i]/4: RTGetOptArgvToString() -> %Rrc", i, rc);
316 RTGetOptArgvFree(papszArgs3);
317 }
318 else
319 RTTestIFailed("g_aBourneTests[%i]/3: RTGetOptArgvFromString() -> %Rrc", i, rc);
320 RTStrFree(pszArgs2);
321 }
322 else
323 RTTestIFailed("g_aBourneTests[%i]/2: RTGetOptArgvToString() -> %Rrc", i, rc);
324 RTGetOptArgvFree(papszArgs1);
325 }
326 else
327 RTTestIFailed("g_aBourneTests[%i]/1: RTGetOptArgvFromString(,,'%s', '%s') -> %Rrc",
328 i, g_aBourneTests[i].pszInput, g_aBourneTests[i].pszSeparators, rc);
329 }
330
331}
332
333
334static void tst2(void)
335{
336 RTTestISub("RTGetOptArgvToString / MS_CRT");
337
338 static const struct
339 {
340 const char * const apszArgs[5];
341 const char *pszCmdLine;
342 } s_aMscCrtTests[] =
343 {
344 {
345 { "abcd", "a ", " b", " c ", NULL },
346 "abcd \"a \" \" b\" \" c \""
347 },
348 {
349 { "a\\\\\\b", "de fg", "h", NULL, NULL },
350 "a\\\\\\b \"de fg\" h"
351 },
352 {
353 { "a\\\"b", "c", "d", "\"", NULL },
354 "\"a\\\\\\\"b\" c d \"\\\"\""
355 },
356 {
357 { "a\\\\b c", "d", "e", " \\", NULL },
358 "\"a\\\\b c\" d e \" \\\\\""
359 },
360 };
361
362 for (size_t i = 0; i < RT_ELEMENTS(s_aMscCrtTests); i++)
363 {
364 char *pszCmdLine = NULL;
365 int rc = RTGetOptArgvToString(&pszCmdLine, s_aMscCrtTests[i].apszArgs, RTGETOPTARGV_CNV_QUOTE_MS_CRT);
366 RTTESTI_CHECK_RC_RETV(rc, VINF_SUCCESS);
367 if (!strcmp(s_aMscCrtTests[i].pszCmdLine, pszCmdLine))
368 tstCheckNativeMsCrtToArgv(pszCmdLine, -1, s_aMscCrtTests[i].apszArgs);
369 else
370 RTTestIFailed("g_aTest[%i] failed:\n"
371 " got '%s'\n"
372 " expected '%s'\n",
373 i, pszCmdLine, s_aMscCrtTests[i].pszCmdLine);
374 RTStrFree(pszCmdLine);
375 }
376
377 for (size_t i = 0; i < RT_ELEMENTS(g_aBourneTests); i++)
378 {
379 char *pszCmdLine = NULL;
380 int rc = RTGetOptArgvToString(&pszCmdLine, g_aBourneTests[i].apszArgs, RTGETOPTARGV_CNV_QUOTE_MS_CRT);
381 RTTESTI_CHECK_RC_RETV(rc, VINF_SUCCESS);
382 if (!strcmp(g_aBourneTests[i].pszOutMsCrt, pszCmdLine))
383 tstCheckNativeMsCrtToArgv(pszCmdLine, g_aBourneTests[i].cArgs, g_aBourneTests[i].apszArgs);
384 else
385 RTTestIFailed("g_aBourneTests[%i] failed:\n"
386 " got |%s|\n"
387 " expected |%s|\n",
388 i, pszCmdLine, g_aBourneTests[i].pszOutMsCrt);
389 RTStrFree(pszCmdLine);
390 }
391
392
393
394 RTTestISub("RTGetOptArgvToString / BOURNE_SH");
395
396 for (size_t i = 0; i < RT_ELEMENTS(g_aBourneTests); i++)
397 {
398 char *pszCmdLine = NULL;
399 int rc = RTGetOptArgvToString(&pszCmdLine, g_aBourneTests[i].apszArgs, RTGETOPTARGV_CNV_QUOTE_BOURNE_SH);
400 RTTESTI_CHECK_RC_RETV(rc, VINF_SUCCESS);
401 if (strcmp(g_aBourneTests[i].pszOutBourneSh, pszCmdLine))
402 RTTestIFailed("g_aBourneTests[%i] failed:\n"
403 " got |%s|\n"
404 " expected |%s|\n",
405 i, pszCmdLine, g_aBourneTests[i].pszOutBourneSh);
406 RTStrFree(pszCmdLine);
407 }
408}
409
410static void tst1(void)
411{
412 RTTestISub("RTGetOptArgvFromString");
413 char **papszArgs = NULL;
414 int cArgs = -1;
415 RTTESTI_CHECK_RC_RETV(RTGetOptArgvFromString(&papszArgs, &cArgs, "", NULL), VINF_SUCCESS);
416 RTTESTI_CHECK_RETV(cArgs == 0);
417 RTTESTI_CHECK_RETV(papszArgs);
418 RTTESTI_CHECK_RETV(!papszArgs[0]);
419 RTGetOptArgvFree(papszArgs);
420
421 RTTESTI_CHECK_RC_RETV(RTGetOptArgvFromString(&papszArgs, &cArgs, "0 1 \"\"2'' '3' 4 5 '''''6' 7 8 9 10 11", NULL), VINF_SUCCESS);
422 RTTESTI_CHECK_RETV(cArgs == 12);
423 RTTESTI_CHECK_RETV(!strcmp(papszArgs[0], "0"));
424 RTTESTI_CHECK_RETV(!strcmp(papszArgs[1], "1"));
425 RTTESTI_CHECK_RETV(!strcmp(papszArgs[2], "2"));
426 RTTESTI_CHECK_RETV(!strcmp(papszArgs[3], "3"));
427 RTTESTI_CHECK_RETV(!strcmp(papszArgs[4], "4"));
428 RTTESTI_CHECK_RETV(!strcmp(papszArgs[5], "5"));
429 RTTESTI_CHECK_RETV(!strcmp(papszArgs[6], "6"));
430 RTTESTI_CHECK_RETV(!strcmp(papszArgs[7], "7"));
431 RTTESTI_CHECK_RETV(!strcmp(papszArgs[8], "8"));
432 RTTESTI_CHECK_RETV(!strcmp(papszArgs[9], "9"));
433 RTTESTI_CHECK_RETV(!strcmp(papszArgs[10], "10"));
434 RTTESTI_CHECK_RETV(!strcmp(papszArgs[11], "11"));
435 RTTESTI_CHECK_RETV(!papszArgs[12]);
436 RTGetOptArgvFree(papszArgs);
437
438 RTTESTI_CHECK_RC_RETV(RTGetOptArgvFromString(&papszArgs, &cArgs, "\t\" asdf \" '\"'xyz \"\t\" '\n' '\"' \"'\"\n\r ", NULL), VINF_SUCCESS);
439 RTTESTI_CHECK_RETV(cArgs == 6);
440 RTTESTI_CHECK_RETV(!strcmp(papszArgs[0], " asdf "));
441 RTTESTI_CHECK_RETV(!strcmp(papszArgs[1], "\"xyz"));
442 RTTESTI_CHECK_RETV(!strcmp(papszArgs[2], "\t"));
443 RTTESTI_CHECK_RETV(!strcmp(papszArgs[3], "\n"));
444 RTTESTI_CHECK_RETV(!strcmp(papszArgs[4], "\""));
445 RTTESTI_CHECK_RETV(!strcmp(papszArgs[5], "\'"));
446 RTTESTI_CHECK_RETV(!papszArgs[6]);
447 RTGetOptArgvFree(papszArgs);
448
449 RTTESTI_CHECK_RC_RETV(RTGetOptArgvFromString(&papszArgs, &cArgs, ":0::1::::2:3:4:5:", ":"), VINF_SUCCESS);
450 RTTESTI_CHECK_RETV(cArgs == 6);
451 RTTESTI_CHECK_RETV(!strcmp(papszArgs[0], "0"));
452 RTTESTI_CHECK_RETV(!strcmp(papszArgs[1], "1"));
453 RTTESTI_CHECK_RETV(!strcmp(papszArgs[2], "2"));
454 RTTESTI_CHECK_RETV(!strcmp(papszArgs[3], "3"));
455 RTTESTI_CHECK_RETV(!strcmp(papszArgs[4], "4"));
456 RTTESTI_CHECK_RETV(!strcmp(papszArgs[5], "5"));
457 RTTESTI_CHECK_RETV(!papszArgs[6]);
458 RTGetOptArgvFree(papszArgs);
459
460 RTTESTI_CHECK_RC_RETV(RTGetOptArgvFromString(&papszArgs, &cArgs, "0:1;2:3;4:5", ";;;;;;;;;;;;;;;;;;;;;;:"), VINF_SUCCESS);
461 RTTESTI_CHECK_RETV(cArgs == 6);
462 RTTESTI_CHECK_RETV(!strcmp(papszArgs[0], "0"));
463 RTTESTI_CHECK_RETV(!strcmp(papszArgs[1], "1"));
464 RTTESTI_CHECK_RETV(!strcmp(papszArgs[2], "2"));
465 RTTESTI_CHECK_RETV(!strcmp(papszArgs[3], "3"));
466 RTTESTI_CHECK_RETV(!strcmp(papszArgs[4], "4"));
467 RTTESTI_CHECK_RETV(!strcmp(papszArgs[5], "5"));
468 RTTESTI_CHECK_RETV(!papszArgs[6]);
469 RTGetOptArgvFree(papszArgs);
470
471 /*
472 * Tests from the list.
473 */
474 for (unsigned i = 0; i < RT_ELEMENTS(g_aBourneTests); i++)
475 {
476 papszArgs = NULL;
477 cArgs = -1;
478 int rc = RTGetOptArgvFromString(&papszArgs, &cArgs, g_aBourneTests[i].pszInput, g_aBourneTests[i].pszSeparators);
479 if (rc == VINF_SUCCESS)
480 {
481 if (cArgs == g_aBourneTests[i].cArgs)
482 {
483 for (int iArg = 0; iArg < cArgs; iArg++)
484 if (strcmp(papszArgs[iArg], g_aBourneTests[i].apszArgs[iArg]) != 0)
485 RTTestIFailed("g_aBourneTests[%i]: argv[%i] differs: got '%s', expected '%s' (RTGetOptArgvFromString(,,'%s', '%s'))",
486 i, iArg, papszArgs[iArg], g_aBourneTests[i].apszArgs[iArg],
487 g_aBourneTests[i].pszInput, g_aBourneTests[i].pszSeparators);
488 RTTESTI_CHECK_RETV(papszArgs[cArgs] == NULL);
489 }
490 else
491 RTTestIFailed("g_aBourneTests[%i]: cArgs=%u, expected %u for RTGetOptArgvFromString(,,'%s', '%s')",
492 i, cArgs, g_aBourneTests[i].cArgs, g_aBourneTests[i].pszInput, g_aBourneTests[i].pszSeparators);
493 RTGetOptArgvFree(papszArgs);
494 }
495 else
496 RTTestIFailed("g_aBourneTests[%i]: RTGetOptArgvFromString(,,'%s', '%s') -> %Rrc",
497 i, g_aBourneTests[i].pszInput, g_aBourneTests[i].pszSeparators, rc);
498 }
499}
500
501
502int main()
503{
504 /*
505 * Init RT+Test.
506 */
507 RTTEST hTest;
508 int rc = RTTestInitAndCreate("tstRTGetOptArgv", &hTest);
509 if (rc)
510 return rc;
511 RTTestBanner(hTest);
512
513 /*
514 * The test.
515 */
516 tst1();
517 tst2();
518 tst3();
519
520 /*
521 * Summary.
522 */
523 return RTTestSummaryAndDestroy(hTest);
524}
525
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette