diff options
Diffstat (limited to '')
-rw-r--r-- | nbase/test/nmakefile | 13 | ||||
-rw-r--r-- | nbase/test/test-escape_windows_command_arg.c | 204 |
2 files changed, 217 insertions, 0 deletions
diff --git a/nbase/test/nmakefile b/nbase/test/nmakefile new file mode 100644 index 0000000..bf3f521 --- /dev/null +++ b/nbase/test/nmakefile @@ -0,0 +1,13 @@ +# Build nbase in Visual C++ (so ..\nbase.lib exists). Then open a Visual +# Studio Command Prompt (from the Start menu), and run: +# nmake /F nmakefile + +!include <win32.mak> + +all: test-escape_windows_command_arg + +.c.obj: + $(cc) /c /D WIN32=1 /I .. $*.c + +test-escape_windows_command_arg: test-escape_windows_command_arg.obj + $(link) /OUT:test-escape_windows_command_arg.exe test-escape_windows_command_arg.obj /NODEFAULTLIB:LIBCMT ..\nbase.lib shell32.lib diff --git a/nbase/test/test-escape_windows_command_arg.c b/nbase/test/test-escape_windows_command_arg.c new file mode 100644 index 0000000..4b7bcdc --- /dev/null +++ b/nbase/test/test-escape_windows_command_arg.c @@ -0,0 +1,204 @@ +/* +Usage: test-escape_windows_command_arg.exe + +This is a test program for the escape_windows_command_arg function from +nbase_str.c. Its code is strictly Windows-specific. Basically, it performs +escape_windows_command_arg on arrays of strings merging its results with spaces +and tests if an attempt to decode them with CommandLineToArgvW results in the +same strings. +*/ + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> + +#include "nbase.h" + +#include <shellapi.h> + +const char *TESTS[][5] = { + { NULL }, + {"", NULL}, + {"", "", NULL}, + {"1", "2", "3", "4", NULL}, + {"a", "b", "c", NULL}, + {"a b", "c", NULL}, + {"a b c", NULL}, + {" a b c ", NULL}, + {"\"quote\"", NULL}, + {"back\\slash", NULL}, + {"backslash at end\\", NULL}, + {"double\"\"quote", NULL}, + {" a\nb\tc\rd\ne", NULL}, + {"..\\test\\toupper.lua", NULL}, + {"backslash at end\\", "som\\ething\"af\\te\\r", NULL}, + {"three\\\\\\backslashes", "som\\ething\"af\\te\\r", NULL}, + {"three\"\"\"quotes", "som\\ething\"af\\te\\r", NULL}, +}; + +static LPWSTR utf8_to_wchar(const char *s) +{ + LPWSTR result; + int size, ret; + + /* Get needed buffer size. */ + size = MultiByteToWideChar(CP_UTF8, 0, s, -1, NULL, 0); + if (size == 0) { + fprintf(stderr, "MultiByteToWideChar 1 failed: %d\n", GetLastError()); + exit(1); + } + result = (LPWSTR) malloc(sizeof(*result) * size); + ret = MultiByteToWideChar(CP_UTF8, 0, s, -1, result, size); + if (ret == 0) { + fprintf(stderr, "MultiByteToWideChar 2 failed: %d\n", GetLastError()); + exit(1); + } + + return result; +} + +static char *wchar_to_utf8(const LPWSTR s) +{ + char *result; + int size, ret; + + /* Get needed buffer size. */ + size = WideCharToMultiByte(CP_UTF8, 0, s, -1, NULL, 0, NULL, NULL); + if (size == 0) { + fprintf(stderr, "WideCharToMultiByte 1 failed: %d\n", GetLastError()); + exit(1); + } + result = (char *) malloc(size); + ret = WideCharToMultiByte(CP_UTF8, 0, s, -1, result, size, NULL, NULL); + if (ret == 0) { + fprintf(stderr, "WideCharToMultiByte 2 failed: %d\n", GetLastError()); + exit(1); + } + + return result; +} + +static char **wchar_to_utf8_array(const LPWSTR a[], unsigned int len) +{ + char **result; + unsigned int i; + + result = (char **) malloc(sizeof(*result) * len); + if (result == NULL) + return NULL; + for (i = 0; i < len; i++) + result[i] = wchar_to_utf8(a[i]); + + return result; +} + +static unsigned int nullarray_length(const char *a[]) +{ + unsigned int i; + + for (i = 0; a[i] != NULL; i++) + ; + + return i; +} + +static char *append(char *p, const char *s) +{ + size_t plen, slen; + + plen = strlen(p); + slen = strlen(s); + p = (char *) realloc(p, plen + slen + 1); + if (p == NULL) + return NULL; + + return strncat(p, s, plen+slen); +} + +/* Turns an array of strings into an escaped flat command line. */ +static LPWSTR build_commandline(const char *args[], unsigned int len) +{ + unsigned int i; + char *result; + + result = strdup("progname"); + for (i = 0; i < len; i++) { + result = append(result, " "); + result = append(result, escape_windows_command_arg(args[i])); + } + + return utf8_to_wchar(result); +} + +static int arrays_equal(const char **a, unsigned int alen, const char **b, unsigned int blen) +{ + unsigned int i; + + if (alen != blen) + return 0; + for (i = 0; i < alen; i++) { + if (strcmp(a[i], b[i]) != 0) + return 0; + } + + return 1; +} + +static char *format_array(const char **args, unsigned int len) +{ + char *result; + unsigned int i; + + result = strdup(""); + result = append(result, "{"); + for (i = 0; i < len; i++) { + if (i > 0) + result = append(result, ", "); + result = append(result, "["); + result = append(result, args[i]); + result = append(result, "]"); + } + result = append(result, "}"); + + return result; +} + +static int run_test(const char *args[]) +{ + LPWSTR *argvw; + char **result; + int args_len, argvw_len, result_len; + + args_len = nullarray_length(args); + argvw = CommandLineToArgvW(build_commandline(args, args_len), &argvw_len); + /* Account for added argv[0] in argvw. */ + result = wchar_to_utf8_array(argvw+1, argvw_len-1); + result_len = argvw_len - 1; + + if (arrays_equal((const char **) result, result_len, args, args_len)) { + printf("PASS %s\n", format_array(args, args_len)); + return 1; + } else { + printf("FAIL got %s\n", format_array((const char **) result, result_len)); + printf("expected %s\n", format_array(args, args_len)); + return 0; + } +} + +int main(int argc, char *argv[]) +{ + unsigned int num_tests, num_passed; + unsigned int i; + + num_tests = 0; + num_passed = 0; + for (i = 0; i < sizeof(TESTS) / sizeof(*TESTS); i++) { + num_tests++; + if (run_test(TESTS[i])) + num_passed++; + } + + printf("%ld / %ld tests passed.\n", num_passed, num_tests); + + return num_passed == num_tests ? 0 : 1; +} |