| From c8c38a021ac67f242bf486537b604c1647e357df Mon Sep 17 00:00:00 2001 |
| From: Garima Singh <garima.singh@microsoft.com> |
| Date: Wed, 18 Sep 2019 16:03:59 -0400 |
| Subject: tests: add a helper to stress test argument quoting |
| |
| On Windows, we have to do all the command-line argument quoting |
| ourselves. Worse: we have to have two versions of said quoting, one for |
| MSYS2 programs (which have their own dequoting rules) and the rest. |
| |
| We care mostly about the rest, and to make sure that that works, let's |
| have a stress test that comes up with all kinds of awkward arguments, |
| verifying that a spawned sub-process receives those unharmed. |
| |
| Signed-off-by: Garima Singh <garima.singh@microsoft.com> |
| Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> |
| (cherry picked from commit ad1559252945179e28fba7d693494051352810c5) |
| Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> |
| --- |
| t/helper/test-run-command.c | 118 +++++++++++++++++++++++++++++++++++- |
| 1 file changed, 116 insertions(+), 2 deletions(-) |
| |
| diff --git a/t/helper/test-run-command.c b/t/helper/test-run-command.c |
| index 2cc93bb69c..bdab5d362a 100644 |
| --- a/t/helper/test-run-command.c |
| +++ b/t/helper/test-run-command.c |
| @@ -13,8 +13,8 @@ |
| #include "run-command.h" |
| #include "argv-array.h" |
| #include "strbuf.h" |
| -#include <string.h> |
| -#include <errno.h> |
| +#include "gettext.h" |
| +#include "parse-options.h" |
| |
| static int number_callbacks; |
| static int parallel_next(struct child_process *cp, |
| @@ -50,11 +50,125 @@ static int task_finished(int result, |
| return 1; |
| } |
| |
| +static uint64_t my_random_next = 1234; |
| + |
| +static uint64_t my_random(void) |
| +{ |
| + uint64_t res = my_random_next; |
| + my_random_next = my_random_next * 1103515245 + 12345; |
| + return res; |
| +} |
| + |
| +static int quote_stress_test(int argc, const char **argv) |
| +{ |
| + /* |
| + * We are running a quote-stress test. |
| + * spawn a subprocess that runs quote-stress with a |
| + * special option that echoes back the arguments that |
| + * were passed in. |
| + */ |
| + char special[] = ".?*\\^_\"'`{}()[]<>@~&+:;$%"; // \t\r\n\a"; |
| + int i, j, k, trials = 100; |
| + struct strbuf out = STRBUF_INIT; |
| + struct argv_array args = ARGV_ARRAY_INIT; |
| + struct option options[] = { |
| + OPT_INTEGER('n', "trials", &trials, "Number of trials"), |
| + OPT_END() |
| + }; |
| + const char * const usage[] = { |
| + "test-tool run-command quote-stress-test <options>", |
| + NULL |
| + }; |
| + |
| + argc = parse_options(argc, argv, NULL, options, usage, 0); |
| + |
| + for (i = 0; i < trials; i++) { |
| + struct child_process cp = CHILD_PROCESS_INIT; |
| + size_t arg_count = 1 + (my_random() % 5), arg_offset; |
| + int ret = 0; |
| + |
| + argv_array_clear(&args); |
| + argv_array_pushl(&args, "test-tool", "run-command", |
| + "quote-echo", NULL); |
| + arg_offset = args.argc; |
| + for (j = 0; j < arg_count; j++) { |
| + char buf[20]; |
| + size_t min_len = 1; |
| + size_t arg_len = min_len + |
| + (my_random() % (ARRAY_SIZE(buf) - min_len)); |
| + |
| + for (k = 0; k < arg_len; k++) |
| + buf[k] = special[my_random() % |
| + ARRAY_SIZE(special)]; |
| + buf[arg_len] = '\0'; |
| + |
| + argv_array_push(&args, buf); |
| + } |
| + |
| + cp.argv = args.argv; |
| + strbuf_reset(&out); |
| + if (pipe_command(&cp, NULL, 0, &out, 0, NULL, 0) < 0) |
| + return error("Failed to spawn child process"); |
| + |
| + for (j = 0, k = 0; j < arg_count; j++) { |
| + const char *arg = args.argv[j + arg_offset]; |
| + |
| + if (strcmp(arg, out.buf + k)) |
| + ret = error("incorrectly quoted arg: '%s', " |
| + "echoed back as '%s'", |
| + arg, out.buf + k); |
| + k += strlen(out.buf + k) + 1; |
| + } |
| + |
| + if (k != out.len) |
| + ret = error("got %d bytes, but consumed only %d", |
| + (int)out.len, (int)k); |
| + |
| + if (ret) { |
| + fprintf(stderr, "Trial #%d failed. Arguments:\n", i); |
| + for (j = 0; j < arg_count; j++) |
| + fprintf(stderr, "arg #%d: '%s'\n", |
| + (int)j, args.argv[j + arg_offset]); |
| + |
| + strbuf_release(&out); |
| + argv_array_clear(&args); |
| + |
| + return ret; |
| + } |
| + |
| + if (i && (i % 100) == 0) |
| + fprintf(stderr, "Trials completed: %d\n", (int)i); |
| + } |
| + |
| + strbuf_release(&out); |
| + argv_array_clear(&args); |
| + |
| + return 0; |
| +} |
| + |
| +static int quote_echo(int argc, const char **argv) |
| +{ |
| + while (argc > 1) { |
| + fwrite(argv[1], strlen(argv[1]), 1, stdout); |
| + fputc('\0', stdout); |
| + argv++; |
| + argc--; |
| + } |
| + |
| + return 0; |
| +} |
| + |
| int cmd__run_command(int argc, const char **argv) |
| { |
| struct child_process proc = CHILD_PROCESS_INIT; |
| int jobs; |
| |
| + if (argc >= 2 && !strcmp(argv[1], "quote-stress-test")) |
| + return !!quote_stress_test(argc - 1, argv + 1); |
| + |
| + if (argc >= 2 && !strcmp(argv[1], "quote-echo")) |
| + return !!quote_echo(argc - 1, argv + 1); |
| + |
| if (argc < 3) |
| return 1; |
| while (!strcmp(argv[1], "env")) { |
| -- |
| 2.24.0.393.g34dc348eaf |
| |