Skip to content

Commit

Permalink
tests: add a helper to stress test argument quoting
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Johannes Schindelin <[email protected]>
  • Loading branch information
garimasi514 authored and dscho committed Dec 5, 2019
1 parent 6d86841 commit ad15592
Showing 1 changed file with 116 additions and 2 deletions.
118 changes: 116 additions & 2 deletions t/helper/test-run-command.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,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,
Expand Down Expand Up @@ -49,11 +49,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-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-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_main(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;
proc.argv = (const char **)argv + 2;
Expand Down

0 comments on commit ad15592

Please sign in to comment.