ctdb-common: Add command line processing abstraction
[samba.git] / ctdb / tests / src / cmdline_test.c
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
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
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, &cmdline);
55         assert(ret == EINVAL);
56
57         ret = cmdline_init(mem_ctx, "test1", NULL, NULL, &cmdline);
58         assert(ret == EINVAL);
59
60         ret = cmdline_init(mem_ctx, "test1", dummy_options, NULL, &cmdline);
61         assert(ret == EINVAL);
62
63         talloc_free(mem_ctx);
64 }
65
66 static struct cmdline_command test2_nofunc[] = {
67         { "nofunc", NULL, NULL, NULL },
68         CMDLINE_TABLEEND
69 };
70
71 static struct cmdline_command test2_nohelp[] = {
72         { "nohelp", dummy_func, NULL, NULL },
73         CMDLINE_TABLEEND
74 };
75
76 static struct cmdline_command test2_long[] = {
77         { "really really long command with lots of words",
78           dummy_func, "long command help",
79           "<and lots of really long long arguments>" },
80         CMDLINE_TABLEEND
81 };
82
83 static struct cmdline_command test2_longhelp[] = {
84         { "longhelp", dummy_func,
85           "this is a really really really long help message" \
86           "with lots of words and lots of description",
87           NULL },
88         CMDLINE_TABLEEND
89 };
90
91 static struct cmdline_command test2_twowords[] = {
92         { "multiple words", dummy_func, "multiple words help", NULL },
93         CMDLINE_TABLEEND
94 };
95
96 static void test2(void)
97 {
98         TALLOC_CTX *mem_ctx;
99         struct cmdline_context *cmdline;
100         int ret;
101
102         mem_ctx = talloc_new(NULL);
103         assert(mem_ctx != NULL);
104
105         ret = cmdline_init(mem_ctx, "test2", NULL, test2_nofunc, &cmdline);
106         assert(ret == EINVAL);
107
108         ret = cmdline_init(mem_ctx, "test2", NULL, test2_nohelp, &cmdline);
109         assert(ret == EINVAL);
110
111         ret = cmdline_init(mem_ctx, "test2", NULL, test2_long, &cmdline);
112         assert(ret == EINVAL);
113
114         ret = cmdline_init(mem_ctx, "test2", NULL, test2_longhelp, &cmdline);
115         assert(ret == EINVAL);
116
117         ret = cmdline_init(mem_ctx, "test2", NULL, test2_twowords, &cmdline);
118         assert(ret == 0);
119
120         talloc_free(mem_ctx);
121 }
122
123 struct {
124         const char *str;
125 } test3_data;
126
127 static struct poptOption test3_noname[] = {
128         { NULL, 'o', POPT_ARG_STRING, &test3_data.str, 0,
129           "Noname option", NULL },
130         POPT_TABLEEND
131 };
132
133 static struct poptOption test3_notype[] = {
134         { "debug", 'd', POPT_ARG_NONE, NULL, 0,
135           "No argument option", NULL },
136         POPT_TABLEEND
137 };
138
139 static struct poptOption test3_noarg[] = {
140         { "debug", 'd', POPT_ARG_STRING, NULL, 0,
141           "No argument option", NULL },
142         POPT_TABLEEND
143 };
144
145 static void test3(void)
146 {
147         TALLOC_CTX *mem_ctx;
148         struct cmdline_context *cmdline;
149         int ret;
150
151         mem_ctx = talloc_new(NULL);
152         assert(mem_ctx != NULL);
153
154         ret = cmdline_init(mem_ctx,
155                            "test3",
156                            test3_noname,
157                            dummy_commands,
158                            &cmdline);
159         assert(ret == EINVAL);
160
161         ret = cmdline_init(mem_ctx,
162                            "test3",
163                            test3_notype,
164                            dummy_commands,
165                            &cmdline);
166         assert(ret == EINVAL);
167
168         ret = cmdline_init(mem_ctx,
169                            "test3",
170                            test3_noarg,
171                            dummy_commands,
172                            &cmdline);
173         assert(ret == EINVAL);
174
175         talloc_free(mem_ctx);
176 }
177
178 static int test4_count;
179 static int test4_value;
180
181 static struct poptOption test4_options[] = {
182         { "count", 'c', POPT_ARG_INT, &test4_count, 0,
183           "Option help of length thirty.", NULL },
184         { "value", 'v', POPT_ARG_INT, &test4_value, 0,
185           "Short description", "Value help of length 23" },
186         POPT_TABLEEND
187 };
188
189 static struct cmdline_command test4_commands[] = {
190         { "A really really long command", dummy_func,
191           "This is a really long help message",
192           "<a long arguments message>" },
193         { "short command", dummy_func,
194           "short msg for short command", "<short arg msg>" },
195         CMDLINE_TABLEEND
196 };
197
198 static void test4(void)
199 {
200         TALLOC_CTX *mem_ctx;
201         struct cmdline_context *cmdline;
202         int ret;
203
204         mem_ctx = talloc_new(NULL);
205         assert(mem_ctx != NULL);
206
207         ret = cmdline_init(mem_ctx,
208                            "test4",
209                            test4_options,
210                            test4_commands,
211                            &cmdline);
212         assert(ret == 0);
213
214         cmdline_usage(cmdline, NULL);
215         cmdline_usage(cmdline, "short command");
216
217         talloc_free(mem_ctx);
218 }
219
220 static int action_func(TALLOC_CTX *mem_ctx,
221                        int argc,
222                        const char **argv,
223                        void *private_data)
224 {
225         if (argc != 1) {
226                 return 100;
227         }
228
229         printf("%s\n", argv[0]);
230         return 200;
231 }
232
233 static struct cmdline_command action_commands[] = {
234         { "action one", dummy_func, "action one help", NULL },
235         { "action two", action_func, "action two help", NULL },
236         CMDLINE_TABLEEND
237 };
238
239 static void test5(void)
240 {
241         TALLOC_CTX *mem_ctx;
242         struct cmdline_context *cmdline;
243         const char *argv1[] = { "test5", "--help" };
244         const char *argv2[] = { "test5", "action" };
245         const char *argv3[] = { "test5", "action", "--help" };
246         const char *argv4[] = { "test5", "action", "one" };
247         int ret, result;
248
249         mem_ctx = talloc_new(NULL);
250         assert(mem_ctx != NULL);
251
252         ret = cmdline_init(mem_ctx, "test5", NULL, action_commands, &cmdline);
253         assert(ret == 0);
254
255         ret = cmdline_parse(cmdline, 2, argv1, true);
256         assert(ret == 0);
257
258         ret = cmdline_run(cmdline, NULL, &result);
259         assert(ret == EAGAIN);
260         assert(result == 0);
261
262         ret = cmdline_parse(cmdline, 2, argv2, true);
263         assert(ret == ENOENT);
264
265         ret = cmdline_parse(cmdline, 3, argv3, true);
266         assert(ret == 0);
267
268         ret = cmdline_parse(cmdline, 3, argv4, true);
269         assert(ret == 0);
270
271         talloc_free(mem_ctx);
272 }
273
274 static void test6(void)
275 {
276         TALLOC_CTX *mem_ctx;
277         struct cmdline_context *cmdline;
278         const char *argv1[] = { "action", "two" };
279         const char *argv2[] = { "action", "two", "arg1" };
280         const char *argv3[] = { "action", "two", "arg1", "arg2" };
281         int ret, result;
282
283         mem_ctx = talloc_new(NULL);
284         assert(mem_ctx != NULL);
285
286         ret = cmdline_init(mem_ctx, "test6", NULL, action_commands, &cmdline);
287         assert(ret == 0);
288
289         ret = cmdline_parse(cmdline, 2, argv1, false);
290         assert(ret == 0);
291
292         ret = cmdline_run(cmdline, NULL, &result);
293         assert(ret == 0);
294         assert(result == 100);
295
296         ret = cmdline_parse(cmdline, 3, argv2, false);
297         assert(ret == 0);
298
299         ret = cmdline_run(cmdline, NULL, &result);
300         assert(ret == 0);
301         assert(result == 200);
302
303         ret = cmdline_parse(cmdline, 4, argv3, false);
304         assert(ret == 0);
305
306         ret = cmdline_run(cmdline, NULL, &result);
307         assert(ret == 0);
308         assert(result == 100);
309
310         talloc_free(mem_ctx);
311 }
312
313 int main(int argc, const char **argv)
314 {
315         int num;
316
317         if (argc < 2) {
318                 fprintf(stderr, "Usage %s <testnum>\n", argv[0]);
319                 exit(1);
320         }
321
322         num = atoi(argv[1]);
323
324         switch (num) {
325         case 1:
326                 test1();
327                 break;
328
329         case 2:
330                 test2();
331                 break;
332
333         case 3:
334                 test3();
335                 break;
336
337         case 4:
338                 test4();
339                 break;
340
341         case 5:
342                 test5();
343                 break;
344
345         case 6:
346                 test6();
347                 break;
348         }
349
350         return 0;
351 }