diff options
Diffstat (limited to 'src/VBox/Runtime/testcase/tstRTGetOptArgv.cpp')
-rw-r--r-- | src/VBox/Runtime/testcase/tstRTGetOptArgv.cpp | 632 |
1 files changed, 632 insertions, 0 deletions
diff --git a/src/VBox/Runtime/testcase/tstRTGetOptArgv.cpp b/src/VBox/Runtime/testcase/tstRTGetOptArgv.cpp new file mode 100644 index 00000000..0eef1787 --- /dev/null +++ b/src/VBox/Runtime/testcase/tstRTGetOptArgv.cpp @@ -0,0 +1,632 @@ +/* $Id: tstRTGetOptArgv.cpp $ */ +/** @file + * IPRT Testcase - RTGetOptArgv*. + */ + +/* + * Copyright (C) 2010-2020 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <iprt/path.h> + +#include <iprt/errcore.h> +#include <iprt/getopt.h> +#include <iprt/ldr.h> +#include <iprt/param.h> +#include <iprt/string.h> +#include <iprt/test.h> +#include <iprt/utf16.h> + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +static const struct +{ + /** The input string, bourne shell. */ + const char *pszInBourne; + /** The input string, MS CRT. */ + const char *pszInMsCrt; + /** Separators, NULL if default. */ + const char *pszSeparators; + /** The number of arguments. */ + int cArgs; + /** Expected argument vector. */ + const char *apszArgs[16]; + /** Expected quoted string, bourne shell. */ + const char *pszOutBourneSh; + /** Expected quoted string, MS CRT. */ + const char *pszOutMsCrt; +} g_aTests[] = +{ + { + "0 1 \"\"2'' '3' 4 5 '''''6' 7 8 9 10 11", + "0 1 \"\"2 3 4 5 \"6\" 7 8 \"\"9\"\" 10 11", + NULL, + 12, + { + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "10", + "11", + NULL, NULL, NULL, NULL, + }, + "0 1 2 3 4 5 6 7 8 9 10 11", + "0 1 2 3 4 5 6 7 8 9 10 11" + }, + { + "\t\" asdf \" '\"'xyz \"\t\" '\n' '\"' \"'\"\n\r \\\"xyz", + /* Note! Two things here to make CommandLineArgW happy. First, it doesn't use IFS including newline/return, so + we skip that bit of the test. Second, it uses pre-2008 doubledouble quoting rules, unlike the CRT and IPRT + which uses the post-2008 rules. We work around that by putting that test last. + See http://www.daviddeley.com/autohotkey/parameters/parameters.htm */ + "\t\" asdf \" \\\"xyz \"\t\" \"\n\" \"\\\"\" ' \"\"\"xyz\"", + NULL, + 7, + { + " asdf ", + "\"xyz", + "\t", + "\n", + "\"", + "\'", + "\"xyz", + NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + }, + "' asdf ' '\"xyz' '\t' '\n' '\"' ''\"'\"'' '\"xyz'", + "\" asdf \" \"\\\"xyz\" \"\t\" \"\n\" \"\\\"\" ' \"\\\"xyz\"" + }, + { + ":0::1::::2:3:4:5:", + ":0::1::::2:3:4:5:", + ":", + 6, + { + "0", + "1", + "2", + "3", + "4", + "5", + NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + }, + "0 1 2 3 4 5", + "0 1 2 3 4 5" + }, + { + "0:1;2:3;4:5", + "0:1;2:3;4:5", + ";;;;;;;;;;;;;;;;;;;;;;:", + 6, + { + "0", + "1", + "2", + "3", + "4", + "5", + NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + }, + "0 1 2 3 4 5", + "0 1 2 3 4 5" + }, + { + "abcd 'a ' ' b' ' c '", + "abcd \"a \" \" b\" \" c \"", + NULL, + 4, + { + "abcd", + "a ", + " b", + " c ", + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + }, + "abcd 'a ' ' b' ' c '", + "abcd \"a \" \" b\" \" c \"" + }, + { + "'a\n\\b' 'de'\"'\"'fg' h ''\"'\"''", + "\"a\n\\b\" de'fg h \"'\" ", + NULL, + 4, + { + "a\n\\b", + "de'fg", + "h", + "'", + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + }, + "'a\n\\b' 'de'\"'\"'fg' h ''\"'\"''", + "\"a\n\\b\" de'fg h '" + }, + { + "arg1 \"arg2=\\\"zyx\\\"\" 'arg3=\\\\\\'", + "arg1 arg2=\\\"zyx\\\" arg3=\\\\\\", + NULL, + 3, + { + "arg1", + "arg2=\"zyx\"", + "arg3=\\\\\\", + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + }, + "arg1 'arg2=\"zyx\"' 'arg3=\\\\\\'", + "arg1 \"arg2=\\\"zyx\\\"\" arg3=\\\\\\" + }, + { + " a\\\\\\\\b d\"e f\"g h ij\t", + " a\\\\b d\"e f\"g h ij\t", + NULL, + 4, + { + "a\\\\b", + "de fg", + "h", + "ij", + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + }, + "'a\\\\b' 'de fg' h ij", + "a\\\\b \"de fg\" h ij", + } +}; + + + +static void tstCheckNativeMsCrtToArgv(const char *pszCmdLine, int cExpectedArgs, const char * const *papszExpectedArgs) +{ +#ifdef RT_OS_WINDOWS + /* + * Resolve APIs. + */ + static void *(__stdcall * s_pfnLocalFree)(void *pvFree); + static PRTUTF16 *(__stdcall * s_pfnCommandLineToArgvW)(PCRTUTF16 pwszCmdLine, int *pcArgs); + if (!s_pfnCommandLineToArgvW) + { + *(void **)&s_pfnLocalFree = RTLdrGetSystemSymbol("kernel32.dll", "LocalFree"); + RTTESTI_CHECK_RETV(s_pfnLocalFree != NULL); + *(void **)&s_pfnCommandLineToArgvW = RTLdrGetSystemSymbol("shell32.dll", "CommandLineToArgvW"); + RTTESTI_CHECK_RETV(s_pfnCommandLineToArgvW != NULL); + } + + /* + * Calc expected arguments if needed. + */ + if (cExpectedArgs == -1) + for (cExpectedArgs = 0; papszExpectedArgs[cExpectedArgs]; cExpectedArgs++) + { /* nothing */ } + + /* + * Convert input command line to UTF-16 and call native API. + */ + RTUTF16 wszCmdLine[1024]; + PRTUTF16 pwszCmdLine = &wszCmdLine[1]; + RTTESTI_CHECK_RC_RETV(RTStrToUtf16Ex(pszCmdLine, RTSTR_MAX, &pwszCmdLine, 1023, NULL), VINF_SUCCESS); + wszCmdLine[0] = ' '; + + int cArgs = -2; + PRTUTF16 *papwszArgs = s_pfnCommandLineToArgvW(wszCmdLine, &cArgs); + + /* + * Check the result. + */ + if (cArgs - 1 != cExpectedArgs) + RTTestIFailed("Native returns cArgs=%d, expected %d (cmdline=|%s|)", cArgs - 1, cExpectedArgs, pszCmdLine); + int cArgsCheck = RT_MIN(cArgs - 1, cExpectedArgs); + for (int i = 0; i < cArgsCheck; i++) + { + char *pszArg = NULL; + RTTESTI_CHECK_RC_RETV(RTUtf16ToUtf8(papwszArgs[i + 1], &pszArg), VINF_SUCCESS); + if (strcmp(pszArg, papszExpectedArgs[i])) + RTTestIFailed("Native returns argv[%i]='%s', expected '%s' (cmdline=|%s|)", + i, pszArg, papszExpectedArgs[i], pszCmdLine); + RTStrFree(pszArg); + } + + if (papwszArgs) + s_pfnLocalFree(papwszArgs); +#else + NOREF(pszCmdLine); + NOREF(cExpectedArgs); + NOREF(papszExpectedArgs); +#endif +} + + +static void tst4(void) +{ + /* + * Microsoft CRT round-tripping. + */ + RTTestISub("Round-trips / MS_CRT"); + for (unsigned i = 0; i < RT_ELEMENTS(g_aTests); i++) + { + /* First */ + char **papszArgs1 = NULL; + int cArgs1 = -1; + int rc = RTGetOptArgvFromString(&papszArgs1, &cArgs1, g_aTests[i].pszInMsCrt, + RTGETOPTARGV_CNV_QUOTE_MS_CRT, g_aTests[i].pszSeparators); + if (rc == VINF_SUCCESS) + { + if (cArgs1 != g_aTests[i].cArgs) + RTTestIFailed("g_aTests[%i]: #1=%d, expected %d", i, cArgs1, g_aTests[i].cArgs); + for (int iArg = 0; iArg < cArgs1; iArg++) + if (strcmp(papszArgs1[iArg], g_aTests[i].apszArgs[iArg]) != 0) + RTTestIFailed("g_aTests[%i]/1: argv[%i] differs: got '%s', expected '%s' (RTGetOptArgvFromString(,,'%s', '%s'))", + i, iArg, papszArgs1[iArg], g_aTests[i].apszArgs[iArg], + g_aTests[i].pszInMsCrt, g_aTests[i].pszSeparators); + RTTESTI_CHECK_RETV(papszArgs1[cArgs1] == NULL); + if (g_aTests[i].pszSeparators == NULL) + tstCheckNativeMsCrtToArgv(g_aTests[i].pszInMsCrt, g_aTests[i].cArgs, g_aTests[i].apszArgs); + + /* Second */ + char *pszArgs2 = NULL; + rc = RTGetOptArgvToString(&pszArgs2, papszArgs1, RTGETOPTARGV_CNV_QUOTE_MS_CRT); + if (rc == VINF_SUCCESS) + { + if (strcmp(pszArgs2, g_aTests[i].pszOutMsCrt)) + RTTestIFailed("g_aTests[%i]/2: '%s', expected '%s'", i, pszArgs2, g_aTests[i].pszOutMsCrt); + + /* + * Third + */ + char **papszArgs3 = NULL; + int cArgs3 = -1; + rc = RTGetOptArgvFromString(&papszArgs3, &cArgs3, pszArgs2, RTGETOPTARGV_CNV_QUOTE_MS_CRT, NULL); + if (rc == VINF_SUCCESS) + { + if (cArgs3 != g_aTests[i].cArgs) + RTTestIFailed("g_aTests[%i]/3: %d, expected %d", i, cArgs3, g_aTests[i].cArgs); + for (int iArg = 0; iArg < cArgs3; iArg++) + if (strcmp(papszArgs3[iArg], g_aTests[i].apszArgs[iArg]) != 0) + RTTestIFailed("g_aTests[%i]/3: argv[%i] differs: got '%s', expected '%s' (RTGetOptArgvFromString(,,'%s',))", + i, iArg, papszArgs3[iArg], g_aTests[i].apszArgs[iArg], pszArgs2); + RTTESTI_CHECK_RETV(papszArgs3[cArgs3] == NULL); + if (g_aTests[i].pszSeparators == NULL) + tstCheckNativeMsCrtToArgv(pszArgs2, g_aTests[i].cArgs, g_aTests[i].apszArgs); + + /* + * Fourth + */ + char *pszArgs4 = NULL; + rc = RTGetOptArgvToString(&pszArgs4, papszArgs3, RTGETOPTARGV_CNV_QUOTE_MS_CRT); + if (rc == VINF_SUCCESS) + { + if (strcmp(pszArgs4, pszArgs2)) + RTTestIFailed("g_aTests[%i]/4: '%s' does not match #4='%s'", i, pszArgs2, pszArgs4); + RTStrFree(pszArgs4); + } + else + RTTestIFailed("g_aTests[%i]/4: RTGetOptArgvToString() -> %Rrc", i, rc); + RTGetOptArgvFree(papszArgs3); + } + else + RTTestIFailed("g_aTests[%i]/3: RTGetOptArgvFromString() -> %Rrc", i, rc); + RTStrFree(pszArgs2); + } + else + RTTestIFailed("g_aTests[%i]/2: RTGetOptArgvToString() -> %Rrc", i, rc); + RTGetOptArgvFree(papszArgs1); + } + else + RTTestIFailed("g_aTests[%i]/1: RTGetOptArgvFromString(,,'%s', '%s') -> %Rrc", + i, g_aTests[i].pszInMsCrt, g_aTests[i].pszSeparators, rc); + } + +} + + + +static void tst3(void) +{ + /* + * Bourne shell round-tripping. + */ + RTTestISub("Round-trips / BOURNE_SH"); + for (unsigned i = 0; i < RT_ELEMENTS(g_aTests); i++) + { + /* First */ + char **papszArgs1 = NULL; + int cArgs1 = -1; + int rc = RTGetOptArgvFromString(&papszArgs1, &cArgs1, g_aTests[i].pszInBourne, + RTGETOPTARGV_CNV_QUOTE_BOURNE_SH, g_aTests[i].pszSeparators); + if (rc == VINF_SUCCESS) + { + if (cArgs1 != g_aTests[i].cArgs) + RTTestIFailed("g_aTests[%i]: #1=%d, expected %d", i, cArgs1, g_aTests[i].cArgs); + for (int iArg = 0; iArg < cArgs1; iArg++) + if (strcmp(papszArgs1[iArg], g_aTests[i].apszArgs[iArg]) != 0) + RTTestIFailed("g_aTests[%i]/1: argv[%i] differs: got '%s', expected '%s' (RTGetOptArgvFromString(,,'%s', '%s'))", + i, iArg, papszArgs1[iArg], g_aTests[i].apszArgs[iArg], + g_aTests[i].pszInBourne, g_aTests[i].pszSeparators); + RTTESTI_CHECK_RETV(papszArgs1[cArgs1] == NULL); + + /* Second */ + char *pszArgs2 = NULL; + rc = RTGetOptArgvToString(&pszArgs2, papszArgs1, RTGETOPTARGV_CNV_QUOTE_BOURNE_SH); + if (rc == VINF_SUCCESS) + { + if (strcmp(pszArgs2, g_aTests[i].pszOutBourneSh)) + RTTestIFailed("g_aTests[%i]/2: '%s', expected '%s'", i, pszArgs2, g_aTests[i].pszOutBourneSh); + + /* + * Third + */ + char **papszArgs3 = NULL; + int cArgs3 = -1; + rc = RTGetOptArgvFromString(&papszArgs3, &cArgs3, pszArgs2, RTGETOPTARGV_CNV_QUOTE_BOURNE_SH, NULL); + if (rc == VINF_SUCCESS) + { + if (cArgs3 != g_aTests[i].cArgs) + RTTestIFailed("g_aTests[%i]/3: %d, expected %d", i, cArgs3, g_aTests[i].cArgs); + for (int iArg = 0; iArg < cArgs3; iArg++) + if (strcmp(papszArgs3[iArg], g_aTests[i].apszArgs[iArg]) != 0) + RTTestIFailed("g_aTests[%i]/3: argv[%i] differs: got '%s', expected '%s' (RTGetOptArgvFromString(,,'%s',))", + i, iArg, papszArgs3[iArg], g_aTests[i].apszArgs[iArg], pszArgs2); + RTTESTI_CHECK_RETV(papszArgs3[cArgs3] == NULL); + + /* + * Fourth + */ + char *pszArgs4 = NULL; + rc = RTGetOptArgvToString(&pszArgs4, papszArgs3, RTGETOPTARGV_CNV_QUOTE_BOURNE_SH); + if (rc == VINF_SUCCESS) + { + if (strcmp(pszArgs4, pszArgs2)) + RTTestIFailed("g_aTests[%i]/4: '%s' does not match #4='%s'", i, pszArgs2, pszArgs4); + RTStrFree(pszArgs4); + } + else + RTTestIFailed("g_aTests[%i]/4: RTGetOptArgvToString() -> %Rrc", i, rc); + RTGetOptArgvFree(papszArgs3); + } + else + RTTestIFailed("g_aTests[%i]/3: RTGetOptArgvFromString() -> %Rrc", i, rc); + RTStrFree(pszArgs2); + } + else + RTTestIFailed("g_aTests[%i]/2: RTGetOptArgvToString() -> %Rrc", i, rc); + RTGetOptArgvFree(papszArgs1); + } + else + RTTestIFailed("g_aTests[%i]/1: RTGetOptArgvFromString(,,'%s', '%s') -> %Rrc", + i, g_aTests[i].pszInBourne, g_aTests[i].pszSeparators, rc); + } +} + + +/* Global to avoid weird C4640 warning about "construction of local static object is not thread-safe". */ +static const struct +{ + const char * const apszArgs[5]; + const char *pszCmdLine; +} g_aMscCrtTests[] = +{ + { + { "abcd", "a ", " b", " c ", NULL }, + "abcd \"a \" \" b\" \" c \"" + }, + { + { "a\\\\\\b", "de fg", "h", NULL, NULL }, + "a\\\\\\b \"de fg\" h" + }, + { + { "a\\\"b", "c", "d", "\"", NULL }, + "\"a\\\\\\\"b\" c d \"\\\"\"" + }, + { + { "a\\\\b c", "d", "e", " \\", NULL }, + "\"a\\\\b c\" d e \" \\\\\"" + }, +}; + +static void tst2(void) +{ + RTTestISub("RTGetOptArgvToString / MS_CRT"); + + for (size_t i = 0; i < RT_ELEMENTS(g_aMscCrtTests); i++) + { + char *pszCmdLine = NULL; + int rc = RTGetOptArgvToString(&pszCmdLine, g_aMscCrtTests[i].apszArgs, RTGETOPTARGV_CNV_QUOTE_MS_CRT); + RTTESTI_CHECK_RC_RETV(rc, VINF_SUCCESS); + if (!strcmp(g_aMscCrtTests[i].pszCmdLine, pszCmdLine)) + tstCheckNativeMsCrtToArgv(pszCmdLine, -1, g_aMscCrtTests[i].apszArgs); + else + RTTestIFailed("g_aTest[%i] failed:\n" + " got '%s'\n" + " expected '%s'\n", + i, pszCmdLine, g_aMscCrtTests[i].pszCmdLine); + RTStrFree(pszCmdLine); + } + + for (size_t i = 0; i < RT_ELEMENTS(g_aTests); i++) + { + char *pszCmdLine = NULL; + int rc = RTGetOptArgvToString(&pszCmdLine, g_aTests[i].apszArgs, RTGETOPTARGV_CNV_QUOTE_MS_CRT); + RTTESTI_CHECK_RC_RETV(rc, VINF_SUCCESS); + if (!strcmp(g_aTests[i].pszOutMsCrt, pszCmdLine)) + tstCheckNativeMsCrtToArgv(pszCmdLine, g_aTests[i].cArgs, g_aTests[i].apszArgs); + else + RTTestIFailed("g_aTests[%i] failed:\n" + " got |%s|\n" + " expected |%s|\n", + i, pszCmdLine, g_aTests[i].pszOutMsCrt); + RTStrFree(pszCmdLine); + } + + + + RTTestISub("RTGetOptArgvToString / BOURNE_SH"); + + for (size_t i = 0; i < RT_ELEMENTS(g_aTests); i++) + { + char *pszCmdLine = NULL; + int rc = RTGetOptArgvToString(&pszCmdLine, g_aTests[i].apszArgs, RTGETOPTARGV_CNV_QUOTE_BOURNE_SH); + RTTESTI_CHECK_RC_RETV(rc, VINF_SUCCESS); + if (strcmp(g_aTests[i].pszOutBourneSh, pszCmdLine)) + RTTestIFailed("g_aTests[%i] failed:\n" + " got |%s|\n" + " expected |%s|\n", + i, pszCmdLine, g_aTests[i].pszOutBourneSh); + RTStrFree(pszCmdLine); + } +} + +static void tst1(void) +{ + RTTestISub("RTGetOptArgvFromString"); + char **papszArgs = NULL; + int cArgs = -1; + RTTESTI_CHECK_RC_RETV(RTGetOptArgvFromString(&papszArgs, &cArgs, "", RTGETOPTARGV_CNV_QUOTE_BOURNE_SH, NULL), VINF_SUCCESS); + RTTESTI_CHECK_RETV(cArgs == 0); + RTTESTI_CHECK_RETV(papszArgs); + RTTESTI_CHECK_RETV(!papszArgs[0]); + RTGetOptArgvFree(papszArgs); + + RTTESTI_CHECK_RC_RETV(RTGetOptArgvFromString(&papszArgs, &cArgs, "0 1 \"\"2'' '3' 4 5 '''''6' 7 8 9 10 11", + RTGETOPTARGV_CNV_QUOTE_BOURNE_SH, NULL), VINF_SUCCESS); + RTTESTI_CHECK_RETV(cArgs == 12); + RTTESTI_CHECK_RETV(!strcmp(papszArgs[0], "0")); + RTTESTI_CHECK_RETV(!strcmp(papszArgs[1], "1")); + RTTESTI_CHECK_RETV(!strcmp(papszArgs[2], "2")); + RTTESTI_CHECK_RETV(!strcmp(papszArgs[3], "3")); + RTTESTI_CHECK_RETV(!strcmp(papszArgs[4], "4")); + RTTESTI_CHECK_RETV(!strcmp(papszArgs[5], "5")); + RTTESTI_CHECK_RETV(!strcmp(papszArgs[6], "6")); + RTTESTI_CHECK_RETV(!strcmp(papszArgs[7], "7")); + RTTESTI_CHECK_RETV(!strcmp(papszArgs[8], "8")); + RTTESTI_CHECK_RETV(!strcmp(papszArgs[9], "9")); + RTTESTI_CHECK_RETV(!strcmp(papszArgs[10], "10")); + RTTESTI_CHECK_RETV(!strcmp(papszArgs[11], "11")); + RTTESTI_CHECK_RETV(!papszArgs[12]); + RTGetOptArgvFree(papszArgs); + + RTTESTI_CHECK_RC_RETV(RTGetOptArgvFromString(&papszArgs, &cArgs, "\t\" asdf \" '\"'xyz \"\t\" '\n' '\"' \"'\"\n\r ", + RTGETOPTARGV_CNV_QUOTE_BOURNE_SH, NULL), VINF_SUCCESS); + RTTESTI_CHECK_RETV(cArgs == 6); + RTTESTI_CHECK_RETV(!strcmp(papszArgs[0], " asdf ")); + RTTESTI_CHECK_RETV(!strcmp(papszArgs[1], "\"xyz")); + RTTESTI_CHECK_RETV(!strcmp(papszArgs[2], "\t")); + RTTESTI_CHECK_RETV(!strcmp(papszArgs[3], "\n")); + RTTESTI_CHECK_RETV(!strcmp(papszArgs[4], "\"")); + RTTESTI_CHECK_RETV(!strcmp(papszArgs[5], "\'")); + RTTESTI_CHECK_RETV(!papszArgs[6]); + RTGetOptArgvFree(papszArgs); + + RTTESTI_CHECK_RC_RETV(RTGetOptArgvFromString(&papszArgs, &cArgs, ":0::1::::2:3:4:5:", + RTGETOPTARGV_CNV_QUOTE_BOURNE_SH, ":"), VINF_SUCCESS); + RTTESTI_CHECK_RETV(cArgs == 6); + RTTESTI_CHECK_RETV(!strcmp(papszArgs[0], "0")); + RTTESTI_CHECK_RETV(!strcmp(papszArgs[1], "1")); + RTTESTI_CHECK_RETV(!strcmp(papszArgs[2], "2")); + RTTESTI_CHECK_RETV(!strcmp(papszArgs[3], "3")); + RTTESTI_CHECK_RETV(!strcmp(papszArgs[4], "4")); + RTTESTI_CHECK_RETV(!strcmp(papszArgs[5], "5")); + RTTESTI_CHECK_RETV(!papszArgs[6]); + RTGetOptArgvFree(papszArgs); + + RTTESTI_CHECK_RC_RETV(RTGetOptArgvFromString(&papszArgs, &cArgs, "0:1;2:3;4:5", RTGETOPTARGV_CNV_QUOTE_BOURNE_SH, + ";;;;;;;;;;;;;;;;;;;;;;:"), VINF_SUCCESS); + RTTESTI_CHECK_RETV(cArgs == 6); + RTTESTI_CHECK_RETV(!strcmp(papszArgs[0], "0")); + RTTESTI_CHECK_RETV(!strcmp(papszArgs[1], "1")); + RTTESTI_CHECK_RETV(!strcmp(papszArgs[2], "2")); + RTTESTI_CHECK_RETV(!strcmp(papszArgs[3], "3")); + RTTESTI_CHECK_RETV(!strcmp(papszArgs[4], "4")); + RTTESTI_CHECK_RETV(!strcmp(papszArgs[5], "5")); + RTTESTI_CHECK_RETV(!papszArgs[6]); + RTGetOptArgvFree(papszArgs); + + /* + * Tests from the list. + */ + for (unsigned i = 0; i < RT_ELEMENTS(g_aTests); i++) + { + papszArgs = NULL; + cArgs = -1; + int rc = RTGetOptArgvFromString(&papszArgs, &cArgs, g_aTests[i].pszInBourne, RTGETOPTARGV_CNV_QUOTE_BOURNE_SH, + g_aTests[i].pszSeparators); + if (rc == VINF_SUCCESS) + { + if (cArgs == g_aTests[i].cArgs) + { + for (int iArg = 0; iArg < cArgs; iArg++) + if (strcmp(papszArgs[iArg], g_aTests[i].apszArgs[iArg]) != 0) + RTTestIFailed("g_aTests[%i]: argv[%i] differs: got '%s', expected '%s' (RTGetOptArgvFromString(,,'%s', '%s'))", + i, iArg, papszArgs[iArg], g_aTests[i].apszArgs[iArg], + g_aTests[i].pszInBourne, g_aTests[i].pszSeparators); + RTTESTI_CHECK_RETV(papszArgs[cArgs] == NULL); + } + else + RTTestIFailed("g_aTests[%i]: cArgs=%u, expected %u for RTGetOptArgvFromString(,,'%s', '%s')", + i, cArgs, g_aTests[i].cArgs, g_aTests[i].pszInBourne, g_aTests[i].pszSeparators); + RTGetOptArgvFree(papszArgs); + } + else + RTTestIFailed("g_aTests[%i]: RTGetOptArgvFromString(,,'%s', '%s') -> %Rrc", + i, g_aTests[i].pszInBourne, g_aTests[i].pszSeparators, rc); + } +} + + +int main() +{ + /* + * Init RT+Test. + */ + RTTEST hTest; + int rc = RTTestInitAndCreate("tstRTGetOptArgv", &hTest); + if (rc) + return rc; + RTTestBanner(hTest); + + /* + * The test. + */ + tst1(); + tst2(); + tst4(); + tst3(); + + /* + * Summary. + */ + return RTTestSummaryAndDestroy(hTest); +} + |