Skip to content

Commit ad15592

Browse files
garimasi514dscho
authored andcommitted
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 <[email protected]> Signed-off-by: Johannes Schindelin <[email protected]>
1 parent 6d86841 commit ad15592

File tree

1 file changed

+116
-2
lines changed

1 file changed

+116
-2
lines changed

t/helper/test-run-command.c

Lines changed: 116 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
#include "run-command.h"
1313
#include "argv-array.h"
1414
#include "strbuf.h"
15-
#include <string.h>
16-
#include <errno.h>
15+
#include "gettext.h"
16+
#include "parse-options.h"
1717

1818
static int number_callbacks;
1919
static int parallel_next(struct child_process *cp,
@@ -49,11 +49,125 @@ static int task_finished(int result,
4949
return 1;
5050
}
5151

52+
static uint64_t my_random_next = 1234;
53+
54+
static uint64_t my_random(void)
55+
{
56+
uint64_t res = my_random_next;
57+
my_random_next = my_random_next * 1103515245 + 12345;
58+
return res;
59+
}
60+
61+
static int quote_stress_test(int argc, const char **argv)
62+
{
63+
/*
64+
* We are running a quote-stress test.
65+
* spawn a subprocess that runs quote-stress with a
66+
* special option that echoes back the arguments that
67+
* were passed in.
68+
*/
69+
char special[] = ".?*\\^_\"'`{}()[]<>@~&+:;$%"; // \t\r\n\a";
70+
int i, j, k, trials = 100;
71+
struct strbuf out = STRBUF_INIT;
72+
struct argv_array args = ARGV_ARRAY_INIT;
73+
struct option options[] = {
74+
OPT_INTEGER('n', "trials", &trials, "Number of trials"),
75+
OPT_END()
76+
};
77+
const char * const usage[] = {
78+
"test-run-command quote-stress-test <options>",
79+
NULL
80+
};
81+
82+
argc = parse_options(argc, argv, NULL, options, usage, 0);
83+
84+
for (i = 0; i < trials; i++) {
85+
struct child_process cp = CHILD_PROCESS_INIT;
86+
size_t arg_count = 1 + (my_random() % 5), arg_offset;
87+
int ret = 0;
88+
89+
argv_array_clear(&args);
90+
argv_array_pushl(&args, "test-run-command",
91+
"quote-echo", NULL);
92+
arg_offset = args.argc;
93+
for (j = 0; j < arg_count; j++) {
94+
char buf[20];
95+
size_t min_len = 1;
96+
size_t arg_len = min_len +
97+
(my_random() % (ARRAY_SIZE(buf) - min_len));
98+
99+
for (k = 0; k < arg_len; k++)
100+
buf[k] = special[my_random() %
101+
ARRAY_SIZE(special)];
102+
buf[arg_len] = '\0';
103+
104+
argv_array_push(&args, buf);
105+
}
106+
107+
cp.argv = args.argv;
108+
strbuf_reset(&out);
109+
if (pipe_command(&cp, NULL, 0, &out, 0, NULL, 0) < 0)
110+
return error("Failed to spawn child process");
111+
112+
for (j = 0, k = 0; j < arg_count; j++) {
113+
const char *arg = args.argv[j + arg_offset];
114+
115+
if (strcmp(arg, out.buf + k))
116+
ret = error("incorrectly quoted arg: '%s', "
117+
"echoed back as '%s'",
118+
arg, out.buf + k);
119+
k += strlen(out.buf + k) + 1;
120+
}
121+
122+
if (k != out.len)
123+
ret = error("got %d bytes, but consumed only %d",
124+
(int)out.len, (int)k);
125+
126+
if (ret) {
127+
fprintf(stderr, "Trial #%d failed. Arguments:\n", i);
128+
for (j = 0; j < arg_count; j++)
129+
fprintf(stderr, "arg #%d: '%s'\n",
130+
(int)j, args.argv[j + arg_offset]);
131+
132+
strbuf_release(&out);
133+
argv_array_clear(&args);
134+
135+
return ret;
136+
}
137+
138+
if (i && (i % 100) == 0)
139+
fprintf(stderr, "Trials completed: %d\n", (int)i);
140+
}
141+
142+
strbuf_release(&out);
143+
argv_array_clear(&args);
144+
145+
return 0;
146+
}
147+
148+
static int quote_echo(int argc, const char **argv)
149+
{
150+
while (argc > 1) {
151+
fwrite(argv[1], strlen(argv[1]), 1, stdout);
152+
fputc('\0', stdout);
153+
argv++;
154+
argc--;
155+
}
156+
157+
return 0;
158+
}
159+
52160
int cmd_main(int argc, const char **argv)
53161
{
54162
struct child_process proc = CHILD_PROCESS_INIT;
55163
int jobs;
56164

165+
if (argc >= 2 && !strcmp(argv[1], "quote-stress-test"))
166+
return !!quote_stress_test(argc - 1, argv + 1);
167+
168+
if (argc >= 2 && !strcmp(argv[1], "quote-echo"))
169+
return !!quote_echo(argc - 1, argv + 1);
170+
57171
if (argc < 3)
58172
return 1;
59173
proc.argv = (const char **)argv + 2;

0 commit comments

Comments
 (0)