1 /*
2    Command line processing tests
3 
4    Copyright (C) Amitay Isaacs  2018
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include "replace.h"
21 
22 #include <popt.h>
23 #include <talloc.h>
24 
25 #include <assert.h>
26 
27 #include "common/cmdline.c"
28 
dummy_func(TALLOC_CTX * mem_ctx,int argc,const char ** argv,void * private_data)29 static int dummy_func(TALLOC_CTX *mem_ctx,
30 		      int argc,
31 		      const char **argv,
32 		      void *private_data)
33 {
34 	return 0;
35 }
36 
37 static struct poptOption dummy_options[] = {
38 	POPT_TABLEEND
39 };
40 
41 static struct cmdline_command dummy_commands[] = {
42 	CMDLINE_TABLEEND
43 };
44 
test1(void)45 static void test1(void)
46 {
47 	TALLOC_CTX *mem_ctx;
48 	struct cmdline_context *cmdline;
49 	int ret;
50 
51 	mem_ctx = talloc_new(NULL);
52 	assert(mem_ctx != NULL);
53 
54 	ret = cmdline_init(mem_ctx, NULL, NULL, NULL, NULL, &cmdline);
55 	assert(ret == EINVAL);
56 
57 	ret = cmdline_init(mem_ctx, "test1", NULL, NULL, NULL, &cmdline);
58 	assert(ret == EINVAL);
59 
60 	ret = cmdline_init(mem_ctx,
61 			   "test1",
62 			   dummy_options,
63 			   NULL,
64 			   NULL,
65 			   &cmdline);
66 	assert(ret == EINVAL);
67 
68 	talloc_free(mem_ctx);
69 }
70 
71 static struct cmdline_command test2_nofunc[] = {
72 	{ "nofunc", NULL, NULL, NULL },
73 	CMDLINE_TABLEEND
74 };
75 
76 static struct cmdline_command test2_nohelp[] = {
77 	{ "nohelp", dummy_func, NULL, NULL },
78 	CMDLINE_TABLEEND
79 };
80 
81 static struct cmdline_command test2_long[] = {
82 	{ "really really long command with lots of words",
83 	  dummy_func, "long command help",
84 	  "<and lots of really long long arguments>" },
85 	CMDLINE_TABLEEND
86 };
87 
88 static struct cmdline_command test2_longhelp[] = {
89 	{ "longhelp", dummy_func,
90 	  "this is a really really really long help message" \
91 	  "with lots of words and lots of description",
92 	  NULL },
93 	CMDLINE_TABLEEND
94 };
95 
96 static struct cmdline_command test2_twowords[] = {
97 	{ "multiple words", dummy_func, "multiple words help", NULL },
98 	CMDLINE_TABLEEND
99 };
100 
test2(void)101 static void test2(void)
102 {
103 	TALLOC_CTX *mem_ctx;
104 	struct cmdline_context *cmdline;
105 	int ret;
106 
107 	mem_ctx = talloc_new(NULL);
108 	assert(mem_ctx != NULL);
109 
110 	ret = cmdline_init(mem_ctx,
111 			   "test2",
112 			   NULL,
113 			   NULL,
114 			   test2_nofunc,
115 			   &cmdline);
116 	assert(ret == EINVAL);
117 
118 	ret = cmdline_init(mem_ctx,
119 			   "test2",
120 			   NULL,
121 			   NULL,
122 			   test2_nohelp,
123 			   &cmdline);
124 	assert(ret == EINVAL);
125 
126 	ret = cmdline_init(mem_ctx,
127 			   "test2",
128 			   NULL,
129 			   NULL,
130 			   test2_long,
131 			   &cmdline);
132 	assert(ret == EINVAL);
133 
134 	ret = cmdline_init(mem_ctx,
135 			   "test2",
136 			   NULL,
137 			   NULL,
138 			   test2_longhelp,
139 			   &cmdline);
140 	assert(ret == EINVAL);
141 
142 	ret = cmdline_init(mem_ctx,
143 			   "test2",
144 			   NULL,
145 			   NULL,
146 			   test2_twowords,
147 			   &cmdline);
148 	assert(ret == 0);
149 
150 	talloc_free(mem_ctx);
151 }
152 
153 struct {
154 	const char *str;
155 } test3_data;
156 
157 static struct poptOption test3_noname[] = {
158 	{ NULL, 'o', POPT_ARG_STRING, &test3_data.str, 0,
159 	  "Noname option", NULL },
160 	POPT_TABLEEND
161 };
162 
163 static struct poptOption test3_notype[] = {
164 	{ "debug", 'd', POPT_ARG_NONE, NULL, 0,
165 	  "No argument option", NULL },
166 	POPT_TABLEEND
167 };
168 
169 static struct poptOption test3_noarg[] = {
170 	{ "debug", 'd', POPT_ARG_STRING, NULL, 0,
171 	  "No argument option", NULL },
172 	POPT_TABLEEND
173 };
174 
test3(void)175 static void test3(void)
176 {
177 	TALLOC_CTX *mem_ctx;
178 	struct cmdline_context *cmdline;
179 	int ret;
180 
181 	mem_ctx = talloc_new(NULL);
182 	assert(mem_ctx != NULL);
183 
184 	ret = cmdline_init(mem_ctx,
185 			   "test3",
186 			   test3_noname,
187 			   NULL,
188 			   dummy_commands,
189 			   &cmdline);
190 	assert(ret == EINVAL);
191 
192 	ret = cmdline_init(mem_ctx,
193 			   "test3",
194 			   test3_notype,
195 			   NULL,
196 			   dummy_commands,
197 			   &cmdline);
198 	assert(ret == EINVAL);
199 
200 	ret = cmdline_init(mem_ctx,
201 			   "test3",
202 			   test3_noarg,
203 			   NULL,
204 			   dummy_commands,
205 			   &cmdline);
206 	assert(ret == EINVAL);
207 
208 	talloc_free(mem_ctx);
209 }
210 
211 static int test4_count;
212 static int test4_value;
213 
214 static struct poptOption test4_options[] = {
215 	{ "count", 'c', POPT_ARG_INT, &test4_count, 0,
216 	  "Option help of length thirty.", NULL },
217 	{ "value", 'v', POPT_ARG_INT, &test4_value, 0,
218 	  "Short description", "Value help of length 23" },
219 	POPT_TABLEEND
220 };
221 
222 static struct cmdline_command test4_commands[] = {
223 	{ "A really really long command", dummy_func,
224 	  "This is a really long help message",
225 	  "<a long arguments message>" },
226 	{ "short command", dummy_func,
227 	  "short msg for short command", "<short arg msg>" },
228 	CMDLINE_TABLEEND
229 };
230 
test4(void)231 static void test4(void)
232 {
233 	TALLOC_CTX *mem_ctx;
234 	struct cmdline_context *cmdline;
235 	int ret;
236 
237 	mem_ctx = talloc_new(NULL);
238 	assert(mem_ctx != NULL);
239 
240 	ret = cmdline_init(mem_ctx,
241 			   "test4",
242 			   test4_options,
243 			   NULL,
244 			   test4_commands,
245 			   &cmdline);
246 	assert(ret == 0);
247 
248 	cmdline_usage(cmdline, NULL);
249 	cmdline_usage(cmdline, "short command");
250 
251 	talloc_free(mem_ctx);
252 }
253 
action_func(TALLOC_CTX * mem_ctx,int argc,const char ** argv,void * private_data)254 static int action_func(TALLOC_CTX *mem_ctx,
255 		       int argc,
256 		       const char **argv,
257 		       void *private_data)
258 {
259 	if (argc != 1) {
260 		return 100;
261 	}
262 
263 	printf("%s\n", argv[0]);
264 	return 200;
265 }
266 
267 static struct cmdline_command action_commands[] = {
268 	{ "action one", dummy_func, "action one help", NULL },
269 	{ "action two", action_func, "action two help", NULL },
270 	CMDLINE_TABLEEND
271 };
272 
test5(void)273 static void test5(void)
274 {
275 	TALLOC_CTX *mem_ctx;
276 	struct cmdline_context *cmdline;
277 	const char *argv1[] = { "test5", "--help" };
278 	const char *argv2[] = { "test5", "action" };
279 	const char *argv3[] = { "test5", "action", "--help" };
280 	const char *argv4[] = { "test5", "action", "one" };
281 	int ret;
282 
283 	mem_ctx = talloc_new(NULL);
284 	assert(mem_ctx != NULL);
285 
286 	ret = cmdline_init(mem_ctx,
287 			   "test5",
288 			   NULL,
289 			   "Action",
290 			   action_commands,
291 			   &cmdline);
292 	assert(ret == 0);
293 
294 	ret = cmdline_parse(cmdline, 2, argv1, true);
295 	assert(ret == EAGAIN);
296 
297 	ret = cmdline_parse(cmdline, 2, argv2, true);
298 	assert(ret == ENOENT);
299 
300 	ret = cmdline_parse(cmdline, 3, argv3, true);
301 	assert(ret == EAGAIN);
302 
303 	ret = cmdline_parse(cmdline, 3, argv4, true);
304 	assert(ret == 0);
305 
306 	talloc_free(mem_ctx);
307 }
308 
test6(void)309 static void test6(void)
310 {
311 	TALLOC_CTX *mem_ctx;
312 	struct cmdline_context *cmdline;
313 	const char *argv1[] = { "action", "two" };
314 	const char *argv2[] = { "action", "two", "arg1" };
315 	const char *argv3[] = { "action", "two", "arg1", "arg2" };
316 	int ret, result;
317 
318 	mem_ctx = talloc_new(NULL);
319 	assert(mem_ctx != NULL);
320 
321 	ret = cmdline_init(mem_ctx,
322 			   "test6",
323 			   NULL,
324 			   NULL,
325 			   action_commands,
326 			   &cmdline);
327 	assert(ret == 0);
328 
329 	ret = cmdline_parse(cmdline, 2, argv1, false);
330 	assert(ret == 0);
331 
332 	ret = cmdline_run(cmdline, NULL, &result);
333 	assert(ret == 0);
334 	assert(result == 100);
335 
336 	ret = cmdline_parse(cmdline, 3, argv2, false);
337 	assert(ret == 0);
338 
339 	ret = cmdline_run(cmdline, NULL, &result);
340 	assert(ret == 0);
341 	assert(result == 200);
342 
343 	ret = cmdline_parse(cmdline, 4, argv3, false);
344 	assert(ret == 0);
345 
346 	ret = cmdline_run(cmdline, NULL, &result);
347 	assert(ret == 0);
348 	assert(result == 100);
349 
350 	talloc_free(mem_ctx);
351 }
352 
test7_func(TALLOC_CTX * mem_ctx,int argc,const char ** argv,void * private_data)353 static int test7_func(TALLOC_CTX *mem_ctx,
354 		      int argc,
355 		      const char **argv,
356 		      void *private_data)
357 {
358 	assert(argc == 1);
359 
360 	printf("%s\n", argv[0]);
361 
362 	return 0;
363 }
364 
365 static struct cmdline_command test7_basic_commands[] = {
366 	{ "cmd1", test7_func, "command one help", NULL },
367 	{ "cmd2", test7_func, "command two help", NULL },
368 	CMDLINE_TABLEEND
369 };
370 
371 static struct cmdline_command test7_advanced_commands[] = {
372 	{ "cmd3", test7_func, "command three help", NULL },
373 	{ "cmd4", test7_func, "command four help", NULL },
374 	CMDLINE_TABLEEND
375 };
376 
377 static struct cmdline_command test7_ultimate_commands[] = {
378 	{ "cmd5", test7_func, "command five help", NULL },
379 	{ "cmd6", test7_func, "command six help", NULL },
380 	CMDLINE_TABLEEND
381 };
382 
test7(void)383 static void test7(void)
384 {
385 	TALLOC_CTX *mem_ctx;
386 	struct cmdline_context *cmdline;
387 	const char *argv1[] = { "cmd1", "one" };
388 	const char *argv2[] = { "cmd3", "three" };
389 	const char *argv3[] = { "cmd6", "six" };
390 	int ret, result;
391 
392 	mem_ctx = talloc_new(NULL);
393 	assert(mem_ctx != NULL);
394 
395 	ret = cmdline_init(mem_ctx,
396 			   "test7",
397 			   NULL,
398 			   "Basic",
399 			   test7_basic_commands,
400 			   &cmdline);
401 	assert(ret == 0);
402 
403 	ret = cmdline_add(cmdline, "Advanced", test7_advanced_commands);
404 	assert(ret == 0);
405 
406 	ret = cmdline_add(cmdline, "Ultimate", test7_ultimate_commands);
407 	assert(ret == 0);
408 
409 	cmdline_usage(cmdline, NULL);
410 
411 	printf("\n");
412 
413 	ret = cmdline_parse(cmdline, 2, argv1, false);
414 	assert(ret == 0);
415 
416 	ret = cmdline_run(cmdline, NULL, &result);
417 	assert(ret == 0);
418 	assert(result == 0);
419 
420 	ret = cmdline_parse(cmdline, 2, argv2, false);
421 	assert(ret == 0);
422 
423 	ret = cmdline_run(cmdline, NULL, &result);
424 	assert(ret == 0);
425 	assert(result == 0);
426 
427 	ret = cmdline_parse(cmdline, 2, argv3, false);
428 	assert(ret == 0);
429 
430 	ret = cmdline_run(cmdline, NULL, &result);
431 	assert(ret == 0);
432 	assert(result == 0);
433 
434 	talloc_free(mem_ctx);
435 }
436 
437 
main(int argc,const char ** argv)438 int main(int argc, const char **argv)
439 {
440 	int num;
441 
442 	if (argc < 2) {
443 		fprintf(stderr, "Usage %s <testnum>\n", argv[0]);
444 		exit(1);
445 	}
446 
447 	num = atoi(argv[1]);
448 
449 	switch (num) {
450 	case 1:
451 		test1();
452 		break;
453 
454 	case 2:
455 		test2();
456 		break;
457 
458 	case 3:
459 		test3();
460 		break;
461 
462 	case 4:
463 		test4();
464 		break;
465 
466 	case 5:
467 		test5();
468 		break;
469 
470 	case 6:
471 		test6();
472 		break;
473 
474 	case 7:
475 		test7();
476 		break;
477 	}
478 
479 	return 0;
480 }
481