Commit | Line | Data |
---|---|---|
903a5b8a SM |
1 | /* |
2 | * Copyright (c) 2019 Philippe Proulx <pproulx@efficios.com> | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License as published by | |
6 | * the Free Software Foundation; under version 2 of the License. | |
7 | * | |
8 | * This program is distributed in the hope that it will be useful, | |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | * GNU General Public License for more details. | |
12 | * | |
13 | * You should have received a copy of the GNU General Public License along | |
14 | * with this program; if not, write to the Free Software Foundation, Inc., | |
15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
16 | */ | |
17 | ||
7ac57709 | 18 | #include <assert.h> |
903a5b8a SM |
19 | #include <stdlib.h> |
20 | #include <string.h> | |
21 | #include <glib.h> | |
22 | ||
23 | #include "tap/tap.h" | |
903a5b8a SM |
24 | #include "argpar/argpar.h" |
25 | ||
26 | /* | |
27 | * Tests that the command line `cmdline`, with non-quoted | |
28 | * space-delimited arguments, once parsed given the option descriptors | |
29 | * `descrs` and the option `fail_on_unknown_opt`, succeeds and gives the | |
30 | * expected command line `expected_cmd_line` and number of ingested | |
31 | * original arguments `expected_ingested_orig_args`. | |
32 | * | |
33 | * The resulting command-line is built from the resulting arguments, | |
34 | * space-delimiting each argument, preferring the `--long-opt=arg` style | |
35 | * over the `-s arg` style, and using the `arg<A,B>` form for non-option | |
36 | * arguments where `A` is the original argument index and `B` is the | |
37 | * non-option argument index. | |
38 | */ | |
39 | static | |
40 | void test_succeed(const char *cmdline, | |
41 | const char *expected_cmd_line, | |
42 | const struct bt_argpar_opt_descr *descrs, | |
43 | unsigned int expected_ingested_orig_args) | |
44 | { | |
45 | struct bt_argpar_parse_ret parse_ret; | |
46 | GString *res_str = g_string_new(NULL); | |
47 | gchar **argv = g_strsplit(cmdline, " ", 0); | |
48 | unsigned int i; | |
49 | ||
7ac57709 SM |
50 | assert(argv); |
51 | assert(res_str); | |
903a5b8a SM |
52 | parse_ret = bt_argpar_parse(g_strv_length(argv), |
53 | (const char * const *) argv, descrs, false); | |
54 | ok(parse_ret.items, | |
55 | "bt_argpar_parse() succeeds for command line `%s`", cmdline); | |
56 | ok(!parse_ret.error, | |
57 | "bt_argpar_parse() does not write an error for command line `%s`", cmdline); | |
58 | ok(parse_ret.ingested_orig_args == expected_ingested_orig_args, | |
59 | "bt_argpar_parse() returns the correct number of ingested " | |
60 | "original arguments for command line `%s`", cmdline); | |
61 | if (parse_ret.ingested_orig_args != expected_ingested_orig_args) { | |
62 | diag("Expected: %u Got: %u", expected_ingested_orig_args, | |
63 | parse_ret.ingested_orig_args); | |
64 | } | |
65 | ||
66 | if (!parse_ret.items) { | |
67 | fail("bt_argpar_parse() returns the expected parsed arguments " | |
68 | "for command line `%s`", cmdline); | |
69 | goto end; | |
70 | } | |
71 | ||
7ac57709 SM |
72 | for (i = 0; i < parse_ret.items->n_items; i++) { |
73 | const struct bt_argpar_item *arg = parse_ret.items->items[i]; | |
903a5b8a SM |
74 | |
75 | switch (arg->type) { | |
76 | case BT_ARGPAR_ITEM_TYPE_OPT: | |
77 | { | |
78 | const struct bt_argpar_item_opt *arg_opt = | |
79 | (const void *) arg; | |
80 | ||
81 | if (arg_opt->descr->long_name) { | |
82 | g_string_append_printf(res_str, "--%s", | |
83 | arg_opt->descr->long_name); | |
84 | ||
85 | if (arg_opt->arg) { | |
86 | g_string_append_printf(res_str, "=%s", | |
87 | arg_opt->arg); | |
88 | } | |
89 | ||
90 | g_string_append_c(res_str, ' '); | |
91 | } else if (arg_opt->descr->short_name) { | |
92 | g_string_append_printf(res_str, "-%c", | |
93 | arg_opt->descr->short_name); | |
94 | ||
95 | if (arg_opt->arg) { | |
96 | g_string_append_printf(res_str, " %s", | |
97 | arg_opt->arg); | |
98 | } | |
99 | ||
100 | g_string_append_c(res_str, ' '); | |
101 | } | |
102 | ||
103 | break; | |
104 | } | |
105 | case BT_ARGPAR_ITEM_TYPE_NON_OPT: | |
106 | { | |
107 | const struct bt_argpar_item_non_opt *arg_non_opt = | |
108 | (const void *) arg; | |
109 | ||
110 | g_string_append_printf(res_str, "%s<%u,%u> ", | |
111 | arg_non_opt->arg, arg_non_opt->orig_index, | |
112 | arg_non_opt->non_opt_index); | |
113 | break; | |
114 | } | |
115 | default: | |
116 | abort(); | |
117 | } | |
118 | } | |
119 | ||
120 | if (res_str->len > 0) { | |
121 | g_string_truncate(res_str, res_str->len - 1); | |
122 | } | |
123 | ||
124 | ok(strcmp(expected_cmd_line, res_str->str) == 0, | |
125 | "bt_argpar_parse() returns the expected parsed arguments " | |
126 | "for command line `%s`", cmdline); | |
127 | if (strcmp(expected_cmd_line, res_str->str) != 0) { | |
128 | diag("Expected: `%s`", expected_cmd_line); | |
129 | diag("Got: `%s`", res_str->str); | |
130 | } | |
131 | ||
132 | end: | |
133 | bt_argpar_parse_ret_fini(&parse_ret); | |
134 | g_string_free(res_str, TRUE); | |
135 | g_strfreev(argv); | |
136 | } | |
137 | ||
138 | static | |
139 | void succeed_tests(void) | |
140 | { | |
141 | /* No arguments */ | |
142 | { | |
143 | const struct bt_argpar_opt_descr descrs[] = { | |
144 | BT_ARGPAR_OPT_DESCR_SENTINEL | |
145 | }; | |
146 | ||
147 | test_succeed( | |
148 | "", | |
149 | "", | |
150 | descrs, 0); | |
151 | } | |
152 | ||
153 | /* Single long option */ | |
154 | { | |
155 | const struct bt_argpar_opt_descr descrs[] = { | |
156 | { 0, '\0', "salut", false }, | |
157 | BT_ARGPAR_OPT_DESCR_SENTINEL | |
158 | }; | |
159 | ||
160 | test_succeed( | |
161 | "--salut", | |
162 | "--salut", | |
163 | descrs, 1); | |
164 | } | |
165 | ||
166 | /* Single short option */ | |
167 | { | |
168 | const struct bt_argpar_opt_descr descrs[] = { | |
169 | { 0, 'f', NULL, false }, | |
170 | BT_ARGPAR_OPT_DESCR_SENTINEL | |
171 | }; | |
172 | ||
173 | test_succeed( | |
174 | "-f", | |
175 | "-f", | |
176 | descrs, 1); | |
177 | } | |
178 | ||
179 | /* Short and long option (aliases) */ | |
180 | { | |
181 | const struct bt_argpar_opt_descr descrs[] = { | |
182 | { 0, 'f', "flaw", false }, | |
183 | BT_ARGPAR_OPT_DESCR_SENTINEL | |
184 | }; | |
185 | ||
186 | test_succeed( | |
187 | "-f --flaw", | |
188 | "--flaw --flaw", | |
189 | descrs, 2); | |
190 | } | |
191 | ||
192 | /* Long option with argument (space form) */ | |
193 | { | |
194 | const struct bt_argpar_opt_descr descrs[] = { | |
195 | { 0, '\0', "tooth", true }, | |
196 | BT_ARGPAR_OPT_DESCR_SENTINEL | |
197 | }; | |
198 | ||
199 | test_succeed( | |
200 | "--tooth 67", | |
201 | "--tooth=67", | |
202 | descrs, 2); | |
203 | } | |
204 | ||
205 | /* Long option with argument (equal form) */ | |
206 | { | |
207 | const struct bt_argpar_opt_descr descrs[] = { | |
208 | { 0, '\0', "polish", true }, | |
209 | BT_ARGPAR_OPT_DESCR_SENTINEL | |
210 | }; | |
211 | ||
212 | test_succeed( | |
213 | "--polish=brick", | |
214 | "--polish=brick", | |
215 | descrs, 1); | |
216 | } | |
217 | ||
218 | /* Short option with argument (space form) */ | |
219 | { | |
220 | const struct bt_argpar_opt_descr descrs[] = { | |
221 | { 0, 'c', NULL, true }, | |
222 | BT_ARGPAR_OPT_DESCR_SENTINEL | |
223 | }; | |
224 | ||
225 | test_succeed( | |
226 | "-c chilly", | |
227 | "-c chilly", | |
228 | descrs, 2); | |
229 | } | |
230 | ||
231 | /* Short option with argument (glued form) */ | |
232 | { | |
233 | const struct bt_argpar_opt_descr descrs[] = { | |
234 | { 0, 'c', NULL, true }, | |
235 | BT_ARGPAR_OPT_DESCR_SENTINEL | |
236 | }; | |
237 | ||
238 | test_succeed( | |
239 | "-cchilly", | |
240 | "-c chilly", | |
241 | descrs, 1); | |
242 | } | |
243 | ||
244 | /* Short and long option (aliases) with argument (all forms) */ | |
245 | { | |
246 | const struct bt_argpar_opt_descr descrs[] = { | |
247 | { 0, 'd', "dry", true }, | |
248 | BT_ARGPAR_OPT_DESCR_SENTINEL | |
249 | }; | |
250 | ||
251 | test_succeed( | |
252 | "--dry=rate -dthing --dry street --dry=shape", | |
253 | "--dry=rate --dry=thing --dry=street --dry=shape", | |
254 | descrs, 5); | |
255 | } | |
256 | ||
257 | /* Many short options, last one with argument (glued form) */ | |
258 | { | |
259 | const struct bt_argpar_opt_descr descrs[] = { | |
260 | { 0, 'd', NULL, false }, | |
261 | { 0, 'e', NULL, false }, | |
262 | { 0, 'f', NULL, true }, | |
263 | BT_ARGPAR_OPT_DESCR_SENTINEL | |
264 | }; | |
265 | ||
266 | test_succeed( | |
267 | "-defmeow", | |
268 | "-d -e -f meow", | |
269 | descrs, 1); | |
270 | } | |
271 | ||
272 | /* Many options */ | |
273 | { | |
274 | const struct bt_argpar_opt_descr descrs[] = { | |
275 | { 0, 'd', NULL, false }, | |
276 | { 0, 'e', "east", true }, | |
277 | { 0, '\0', "mind", false }, | |
278 | BT_ARGPAR_OPT_DESCR_SENTINEL | |
279 | }; | |
280 | ||
281 | test_succeed( | |
282 | "-d --mind -destart --mind --east cough -d --east=itch", | |
283 | "-d --mind -d --east=start --mind --east=cough -d --east=itch", | |
284 | descrs, 8); | |
285 | } | |
286 | ||
287 | /* Single non-option argument */ | |
288 | { | |
289 | const struct bt_argpar_opt_descr descrs[] = { | |
290 | BT_ARGPAR_OPT_DESCR_SENTINEL | |
291 | }; | |
292 | ||
293 | test_succeed( | |
294 | "kilojoule", | |
295 | "kilojoule<0,0>", | |
296 | descrs, 1); | |
297 | } | |
298 | ||
299 | /* Two non-option arguments */ | |
300 | { | |
301 | const struct bt_argpar_opt_descr descrs[] = { | |
302 | BT_ARGPAR_OPT_DESCR_SENTINEL | |
303 | }; | |
304 | ||
305 | test_succeed( | |
306 | "kilojoule mitaine", | |
307 | "kilojoule<0,0> mitaine<1,1>", | |
308 | descrs, 2); | |
309 | } | |
310 | ||
311 | /* Single non-option argument mixed with options */ | |
312 | { | |
313 | const struct bt_argpar_opt_descr descrs[] = { | |
314 | { 0, 'd', NULL, false }, | |
315 | { 0, '\0', "squeeze", true }, | |
316 | BT_ARGPAR_OPT_DESCR_SENTINEL | |
317 | }; | |
318 | ||
319 | test_succeed( | |
320 | "-d sprout yes --squeeze little bag -d", | |
321 | "-d sprout<1,0> yes<2,1> --squeeze=little bag<5,2> -d", | |
322 | descrs, 7); | |
323 | } | |
324 | ||
325 | /* Unknown short option (space form) */ | |
326 | { | |
327 | const struct bt_argpar_opt_descr descrs[] = { | |
328 | { 0, 'd', NULL, true }, | |
329 | BT_ARGPAR_OPT_DESCR_SENTINEL | |
330 | }; | |
331 | ||
332 | test_succeed( | |
333 | "-d salut -e -d meow", | |
334 | "-d salut", | |
335 | descrs, 2); | |
336 | } | |
337 | ||
338 | /* Unknown short option (glued form) */ | |
339 | { | |
340 | const struct bt_argpar_opt_descr descrs[] = { | |
341 | { 0, 'd', NULL, true }, | |
342 | BT_ARGPAR_OPT_DESCR_SENTINEL | |
343 | }; | |
344 | ||
345 | test_succeed( | |
346 | "-dsalut -e -d meow", | |
347 | "-d salut", | |
348 | descrs, 1); | |
349 | } | |
350 | ||
351 | /* Unknown long option (space form) */ | |
352 | { | |
353 | const struct bt_argpar_opt_descr descrs[] = { | |
354 | { 0, '\0', "sink", true }, | |
355 | BT_ARGPAR_OPT_DESCR_SENTINEL | |
356 | }; | |
357 | ||
358 | test_succeed( | |
359 | "--sink party --food --sink impulse", | |
360 | "--sink=party", | |
361 | descrs, 2); | |
362 | } | |
363 | ||
364 | /* Unknown long option (equal form) */ | |
365 | { | |
366 | const struct bt_argpar_opt_descr descrs[] = { | |
367 | { 0, '\0', "sink", true }, | |
368 | BT_ARGPAR_OPT_DESCR_SENTINEL | |
369 | }; | |
370 | ||
371 | test_succeed( | |
372 | "--sink=party --food --sink=impulse", | |
373 | "--sink=party", | |
374 | descrs, 1); | |
375 | } | |
376 | ||
377 | /* Unknown option before non-option argument */ | |
378 | { | |
379 | const struct bt_argpar_opt_descr descrs[] = { | |
380 | { 0, '\0', "thumb", true }, | |
381 | BT_ARGPAR_OPT_DESCR_SENTINEL | |
382 | }; | |
383 | ||
384 | test_succeed( | |
385 | "--thumb=party --food bateau --thumb waves", | |
386 | "--thumb=party", | |
387 | descrs, 1); | |
388 | } | |
389 | ||
390 | /* Unknown option after non-option argument */ | |
391 | { | |
392 | const struct bt_argpar_opt_descr descrs[] = { | |
393 | { 0, '\0', "thumb", true }, | |
394 | BT_ARGPAR_OPT_DESCR_SENTINEL | |
395 | }; | |
396 | ||
397 | test_succeed( | |
398 | "--thumb=party wound --food --thumb waves", | |
399 | "--thumb=party wound<1,0>", | |
400 | descrs, 2); | |
401 | } | |
402 | ||
403 | /* Valid `---opt` */ | |
404 | { | |
405 | const struct bt_argpar_opt_descr descrs[] = { | |
406 | { 0, '\0', "-fuel", true }, | |
407 | BT_ARGPAR_OPT_DESCR_SENTINEL | |
408 | }; | |
409 | ||
410 | test_succeed( | |
411 | "---fuel=three", | |
412 | "---fuel=three", | |
413 | descrs, 1); | |
414 | } | |
415 | ||
416 | /* Long option containing `=` in argument (equal form) */ | |
417 | { | |
418 | const struct bt_argpar_opt_descr descrs[] = { | |
419 | { 0, '\0', "zebra", true }, | |
420 | BT_ARGPAR_OPT_DESCR_SENTINEL | |
421 | }; | |
422 | ||
423 | test_succeed( | |
424 | "--zebra=three=yes", | |
425 | "--zebra=three=yes", | |
426 | descrs, 1); | |
427 | } | |
428 | ||
429 | /* Short option's argument starting with `-` (glued form) */ | |
430 | { | |
431 | const struct bt_argpar_opt_descr descrs[] = { | |
432 | { 0, 'z', NULL, true }, | |
433 | BT_ARGPAR_OPT_DESCR_SENTINEL | |
434 | }; | |
435 | ||
436 | test_succeed( | |
437 | "-z-will", | |
438 | "-z -will", | |
439 | descrs, 1); | |
440 | } | |
441 | ||
442 | /* Short option's argument starting with `-` (space form) */ | |
443 | { | |
444 | const struct bt_argpar_opt_descr descrs[] = { | |
445 | { 0, 'z', NULL, true }, | |
446 | BT_ARGPAR_OPT_DESCR_SENTINEL | |
447 | }; | |
448 | ||
449 | test_succeed( | |
450 | "-z -will", | |
451 | "-z -will", | |
452 | descrs, 2); | |
453 | } | |
454 | ||
455 | /* Long option's argument starting with `-` (space form) */ | |
456 | { | |
457 | const struct bt_argpar_opt_descr descrs[] = { | |
458 | { 0, '\0', "janine", true }, | |
459 | BT_ARGPAR_OPT_DESCR_SENTINEL | |
460 | }; | |
461 | ||
462 | test_succeed( | |
463 | "--janine -sutto", | |
464 | "--janine=-sutto", | |
465 | descrs, 2); | |
466 | } | |
467 | ||
468 | /* Long option's argument starting with `-` (equal form) */ | |
469 | { | |
470 | const struct bt_argpar_opt_descr descrs[] = { | |
471 | { 0, '\0', "janine", true }, | |
472 | BT_ARGPAR_OPT_DESCR_SENTINEL | |
473 | }; | |
474 | ||
475 | test_succeed( | |
476 | "--janine=-sutto", | |
477 | "--janine=-sutto", | |
478 | descrs, 1); | |
479 | } | |
480 | ||
481 | /* Long option's empty argument (equal form) */ | |
482 | { | |
483 | const struct bt_argpar_opt_descr descrs[] = { | |
484 | { 0, 'f', NULL, false }, | |
485 | { 0, '\0', "yeah", true }, | |
486 | BT_ARGPAR_OPT_DESCR_SENTINEL | |
487 | }; | |
488 | ||
489 | test_succeed( | |
490 | "-f --yeah= -f", | |
491 | "-f --yeah= -f", | |
492 | descrs, 3); | |
493 | } | |
494 | } | |
495 | ||
496 | /* | |
497 | * Tests that the command line `cmdline`, with non-quoted | |
498 | * space-delimited arguments, once parsed given the option descriptors | |
499 | * `descrs`, fails and gives the expected error `expected_error`. | |
500 | */ | |
501 | static | |
502 | void test_fail(const char *cmdline, const char *expected_error, | |
503 | const struct bt_argpar_opt_descr *descrs) | |
504 | { | |
505 | struct bt_argpar_parse_ret parse_ret; | |
506 | gchar **argv = g_strsplit(cmdline, " ", 0); | |
507 | ||
508 | parse_ret = bt_argpar_parse(g_strv_length(argv), | |
509 | (const char * const *) argv, descrs, true); | |
510 | ok(!parse_ret.items, | |
511 | "bt_argpar_parse() fails for command line `%s`", cmdline); | |
512 | ok(parse_ret.error, | |
513 | "bt_argpar_parse() writes an error string for command line `%s`", | |
514 | cmdline); | |
515 | if (parse_ret.items) { | |
516 | fail("bt_argpar_parse() writes the expected error string"); | |
517 | goto end; | |
518 | } | |
519 | ||
7ac57709 | 520 | ok(strcmp(expected_error, parse_ret.error) == 0, |
903a5b8a SM |
521 | "bt_argpar_parse() writes the expected error string " |
522 | "for command line `%s`", cmdline); | |
7ac57709 | 523 | if (strcmp(expected_error, parse_ret.error) != 0) { |
903a5b8a | 524 | diag("Expected: `%s`", expected_error); |
7ac57709 | 525 | diag("Got: `%s`", parse_ret.error); |
903a5b8a SM |
526 | } |
527 | ||
528 | end: | |
529 | bt_argpar_parse_ret_fini(&parse_ret); | |
530 | g_strfreev(argv); | |
531 | } | |
532 | ||
533 | static | |
534 | void fail_tests(void) | |
535 | { | |
536 | /* Unknown long option */ | |
537 | { | |
538 | const struct bt_argpar_opt_descr descrs[] = { | |
539 | { 0, '\0', "thumb", true }, | |
540 | BT_ARGPAR_OPT_DESCR_SENTINEL | |
541 | }; | |
542 | ||
543 | test_fail( | |
544 | "--thumb=party --meow", | |
545 | "While parsing argument #2 (`--meow`): Unknown option `--meow`", | |
546 | descrs); | |
547 | } | |
548 | ||
549 | /* Unknown short option */ | |
550 | { | |
551 | const struct bt_argpar_opt_descr descrs[] = { | |
552 | { 0, '\0', "thumb", true }, | |
553 | BT_ARGPAR_OPT_DESCR_SENTINEL | |
554 | }; | |
555 | ||
556 | test_fail( | |
557 | "--thumb=party -x", | |
558 | "While parsing argument #2 (`-x`): Unknown option `-x`", | |
559 | descrs); | |
560 | } | |
561 | ||
562 | /* Missing long option argument */ | |
563 | { | |
564 | const struct bt_argpar_opt_descr descrs[] = { | |
565 | { 0, '\0', "thumb", true }, | |
566 | BT_ARGPAR_OPT_DESCR_SENTINEL | |
567 | }; | |
568 | ||
569 | test_fail( | |
570 | "--thumb", | |
571 | "While parsing argument #1 (`--thumb`): Missing required argument for option `--thumb`", | |
572 | descrs); | |
573 | } | |
574 | ||
575 | /* Missing short option argument */ | |
576 | { | |
577 | const struct bt_argpar_opt_descr descrs[] = { | |
578 | { 0, 'k', NULL, true }, | |
579 | BT_ARGPAR_OPT_DESCR_SENTINEL | |
580 | }; | |
581 | ||
582 | test_fail( | |
583 | "-k", | |
584 | "While parsing argument #1 (`-k`): Missing required argument for option `-k`", | |
585 | descrs); | |
586 | } | |
587 | ||
588 | /* Missing short option argument (multiple glued) */ | |
589 | { | |
590 | const struct bt_argpar_opt_descr descrs[] = { | |
591 | { 0, 'a', NULL, false }, | |
592 | { 0, 'b', NULL, false }, | |
593 | { 0, 'c', NULL, true }, | |
594 | BT_ARGPAR_OPT_DESCR_SENTINEL | |
595 | }; | |
596 | ||
597 | test_fail( | |
598 | "-abc", | |
599 | "While parsing argument #1 (`-abc`): Missing required argument for option `-c`", | |
600 | descrs); | |
601 | } | |
602 | ||
603 | /* Invalid `-` */ | |
604 | { | |
605 | const struct bt_argpar_opt_descr descrs[] = { | |
606 | { 0, 'a', NULL, false }, | |
607 | { 0, 'b', NULL, false }, | |
608 | { 0, 'c', NULL, true }, | |
609 | BT_ARGPAR_OPT_DESCR_SENTINEL | |
610 | }; | |
611 | ||
612 | test_fail( | |
613 | "-ab - -c", | |
614 | "While parsing argument #2 (`-`): Invalid argument", | |
615 | descrs); | |
616 | } | |
617 | ||
618 | /* Invalid `--` */ | |
619 | { | |
620 | const struct bt_argpar_opt_descr descrs[] = { | |
621 | { 0, 'a', NULL, false }, | |
622 | { 0, 'b', NULL, false }, | |
623 | { 0, 'c', NULL, true }, | |
624 | BT_ARGPAR_OPT_DESCR_SENTINEL | |
625 | }; | |
626 | ||
627 | test_fail( | |
628 | "-ab -- -c", | |
629 | "While parsing argument #2 (`--`): Invalid argument", | |
630 | descrs); | |
631 | } | |
632 | } | |
633 | ||
634 | int main(void) | |
635 | { | |
636 | plan_tests(129); | |
637 | succeed_tests(); | |
638 | fail_tests(); | |
639 | return exit_status(); | |
640 | } |