2 * Copyright (C) 2009-2010 Red Hat Inc.
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; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 (* Please read generator/README first. *)
26 open Generator_docstrings
27 open Generator_optgroups
28 open Generator_actions
29 open Generator_structs
31 (* Generate the tests. *)
32 let rec generate_tests () =
33 generate_header CStyle GPLv2plus;
40 #include <sys/types.h>
43 #include \"guestfs.h\"
44 #include \"guestfs-internal.h\"
47 static int suppress_error = 0;
49 static void print_error (guestfs_h *g, void *data, const char *msg)
52 fprintf (stderr, \"%%s\\n\", msg);
55 /* FIXME: nearly identical code appears in fish.c */
56 static void print_strings (char *const *argv)
60 for (argc = 0; argv[argc] != NULL; ++argc)
61 printf (\"\\t%%s\\n\", argv[argc]);
65 static void print_table (char const *const *argv)
69 for (i = 0; argv[i] != NULL; i += 2)
70 printf (\"%%s: %%s\\n\", argv[i], argv[i+1]);
75 is_available (const char *group)
77 const char *groups[] = { group, NULL };
81 r = guestfs_available (g, (char **) groups);
88 incr (guestfs_h *g, void *iv)
94 /* Get md5sum of the named file. */
96 md5sum (const char *filename, char *result)
99 snprintf (cmd, sizeof cmd, \"md5sum %%s\", filename);
100 FILE *pp = popen (cmd, \"r\");
105 if (fread (result, 1, 32, pp) != 32) {
106 perror (\"md5sum: fread\");
109 if (pclose (pp) != 0) {
116 #if 0 /* <- Remove this if we add RHashtable tests in 1.14 branch. */
117 /* Return the value for a key in a hashtable.
118 * Note: the return value is part of the hash and should not be freed.
121 get_key (char **hash, const char *key)
125 for (i = 0; hash[i] != NULL; i += 2) {
126 if (STREQ (hash[i], key))
130 return NULL; /* key not found */
136 (* Generate a list of commands which are not tested anywhere. *)
137 pr "static void no_test_warnings (void)\n";
140 let hash : (string, bool) Hashtbl.t = Hashtbl.create 13 in
142 fun (_, _, _, _, tests, _, _) ->
143 let tests = filter_map (
145 | (_, (Always|If _|Unless _|IfAvailable _), test) -> Some test
146 | (_, Disabled, _) -> None
148 let seq = List.concat (List.map seq_of_test tests) in
149 let cmds_tested = List.map List.hd seq in
150 List.iter (fun cmd -> Hashtbl.replace hash cmd true) cmds_tested
154 fun (name, _, _, _, _, _, _) ->
155 if not (Hashtbl.mem hash name) then
156 pr " fprintf (stderr, \"warning: \\\"guestfs_%s\\\" has no tests\\n\");\n" name
162 (* Generate the actual tests. Note that we generate the tests
163 * in reverse order, deliberately, so that (in general) the
164 * newest tests run first. This makes it quicker and easier to
169 fun (name, _, _, flags, tests, _, _) ->
170 mapi (generate_one_test name flags) tests
171 ) (List.rev all_functions) in
172 let test_names = List.concat test_names in
173 let nr_tests = List.length test_names in
176 int main (int argc, char *argv[])
179 unsigned long int n_failed = 0;
180 const char *filename;
182 int nr_tests, test_num = 0;
184 setbuf (stdout, NULL);
188 g = guestfs_create ();
190 printf (\"guestfs_create FAILED\\n\");
194 guestfs_set_error_handler (g, print_error, NULL);
196 filename = \"test1.img\";
197 fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_TRUNC, 0666);
202 if (ftruncate (fd, %d) == -1) {
203 perror (\"ftruncate\");
208 if (close (fd) == -1) {
213 if (guestfs_add_drive (g, filename) == -1) {
214 printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
218 filename = \"test2.img\";
219 fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_TRUNC, 0666);
224 if (ftruncate (fd, %d) == -1) {
225 perror (\"ftruncate\");
230 if (close (fd) == -1) {
235 if (guestfs_add_drive (g, filename) == -1) {
236 printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
240 filename = \"test3.img\";
241 fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_TRUNC, 0666);
246 if (ftruncate (fd, %d) == -1) {
247 perror (\"ftruncate\");
252 if (close (fd) == -1) {
257 if (guestfs_add_drive (g, filename) == -1) {
258 printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
262 if (guestfs_add_drive_ro (g, \"../images/test.iso\") == -1) {
263 printf (\"guestfs_add_drive_ro ../images/test.iso FAILED\\n\");
267 /* Set a timeout in case qemu hangs during launch (RHBZ#505329). */
270 if (guestfs_launch (g) == -1) {
271 printf (\"guestfs_launch FAILED\\n\");
275 /* Cancel previous alarm. */
278 /* Create ext2 filesystem on /dev/sdb1 partition. */
279 if (guestfs_part_disk (g, \"/dev/sdb\", \"mbr\") == -1) {
280 printf (\"guestfs_part_disk FAILED\\n\");
283 if (guestfs_mkfs (g, \"ext2\", \"/dev/sdb1\") == -1) {
284 printf (\"guestfs_mkfs (/dev/sdb1) FAILED\\n\");
290 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
295 pr " if (guestfs_get_verbose (g))\n";
296 pr " printf (\"-------------------------------------------------------------------------------\\n\");\n";
297 pr " printf (\"%%3d/%%3d %s\\n\", test_num, nr_tests);\n" test_name;
298 pr " if (%s () == -1) {\n" test_name;
299 pr " printf (\"%s FAILED\\n\");\n" test_name;
305 pr " /* Check close callback is called. */
306 int close_sentinel = 1;
307 guestfs_set_close_callback (g, incr, &close_sentinel);
311 if (close_sentinel != 2) {
312 fprintf (stderr, \"close callback was not called\\n\");
316 unlink (\"test1.img\");
317 unlink (\"test2.img\");
318 unlink (\"test3.img\");
322 pr " if (n_failed > 0) {\n";
323 pr " printf (\"***** %%lu / %%d tests FAILED *****\\n\", n_failed, nr_tests);\n";
324 pr " exit (EXIT_FAILURE);\n";
328 pr " exit (EXIT_SUCCESS);\n";
331 and generate_one_test name flags i (init, prereq, test) =
332 let test_name = sprintf "test_%s_%d" name i in
335 static int %s_skip (void)
339 str = getenv (\"TEST_ONLY\");
341 return strstr (str, \"%s\") == NULL;
342 str = getenv (\"SKIP_%s\");
343 if (str && STREQ (str, \"1\")) return 1;
344 str = getenv (\"SKIP_TEST_%s\");
345 if (str && STREQ (str, \"1\")) return 1;
349 " test_name name (String.uppercase test_name) (String.uppercase name);
352 | Disabled | Always | IfAvailable _ -> ()
353 | If code | Unless code ->
354 pr "static int %s_prereq (void)\n" test_name;
365 printf (\" %%s skipped (reason: environment variable set)\\n\", \"%s\");
369 " test_name test_name test_name;
371 (* Optional functions should only be tested if the relevant
372 * support is available in the daemon.
377 pr " if (!is_available (\"%s\")) {\n" group;
378 pr " printf (\" %%s skipped (reason: group %%s not available in daemon)\\n\", \"%s\", \"%s\");\n" test_name group;
386 pr " printf (\" %%s skipped (reason: test disabled in generator)\\n\", \"%s\");\n" test_name
388 pr " if (! %s_prereq ()) {\n" test_name;
389 pr " printf (\" %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
393 generate_one_test_body name i test_name init test;
395 pr " if (%s_prereq ()) {\n" test_name;
396 pr " printf (\" %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
400 generate_one_test_body name i test_name init test;
401 | IfAvailable group ->
402 pr " if (!is_available (\"%s\")) {\n" group;
403 pr " printf (\" %%s skipped (reason: %%s not available)\\n\", \"%s\", \"%s\");\n" test_name group;
407 generate_one_test_body name i test_name init test;
409 generate_one_test_body name i test_name init test
417 and generate_one_test_body name i test_name init test =
419 | InitNone (* XXX at some point, InitNone and InitEmpty became
420 * folded together as the same thing. Really we should
421 * make InitNone do nothing at all, but the tests may
422 * need to be checked to make sure this is OK.
425 pr " /* InitNone|InitEmpty for %s */\n" test_name;
426 List.iter (generate_test_command_call test_name)
427 [["blockdev_setrw"; "/dev/sda"];
431 pr " /* InitPartition for %s: create /dev/sda1 */\n" test_name;
432 List.iter (generate_test_command_call test_name)
433 [["blockdev_setrw"; "/dev/sda"];
436 ["part_disk"; "/dev/sda"; "mbr"]]
438 pr " /* InitBasicFS for %s: create ext2 on /dev/sda1 */\n" test_name;
439 List.iter (generate_test_command_call test_name)
440 [["blockdev_setrw"; "/dev/sda"];
443 ["part_disk"; "/dev/sda"; "mbr"];
444 ["mkfs"; "ext2"; "/dev/sda1"];
445 ["mount_options"; ""; "/dev/sda1"; "/"]]
446 | InitBasicFSonLVM ->
447 pr " /* InitBasicFSonLVM for %s: create ext2 on /dev/VG/LV */\n"
449 List.iter (generate_test_command_call test_name)
450 [["blockdev_setrw"; "/dev/sda"];
453 ["part_disk"; "/dev/sda"; "mbr"];
454 ["pvcreate"; "/dev/sda1"];
455 ["vgcreate"; "VG"; "/dev/sda1"];
456 ["lvcreate"; "LV"; "VG"; "8"];
457 ["mkfs"; "ext2"; "/dev/VG/LV"];
458 ["mount_options"; ""; "/dev/VG/LV"; "/"]]
460 pr " /* InitISOFS for %s */\n" test_name;
461 List.iter (generate_test_command_call test_name)
462 [["blockdev_setrw"; "/dev/sda"];
465 ["mount_ro"; "/dev/sdd"; "/"]]
467 pr " /* InitScratchFS for %s */\n" test_name;
468 List.iter (generate_test_command_call test_name)
469 [["blockdev_setrw"; "/dev/sda"];
472 ["mount_options"; ""; "/dev/sdb1"; "/"]]
475 let get_seq_last = function
477 failwithf "%s: you cannot use [] (empty list) when expecting a command"
480 let seq = List.rev seq in
481 List.rev (List.tl seq), List.hd seq
486 pr " /* TestRun for %s (%d) */\n" name i;
487 List.iter (generate_test_command_call test_name) seq
488 | TestOutput (seq, expected) ->
489 pr " /* TestOutput for %s (%d) */\n" name i;
490 pr " const char *expected = \"%s\";\n" (c_quote expected);
491 let seq, last = get_seq_last seq in
493 pr " if (STRNEQ (r, expected)) {\n";
494 pr " fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
498 List.iter (generate_test_command_call test_name) seq;
499 generate_test_command_call ~test test_name last
500 | TestOutputList (seq, expected) ->
501 pr " /* TestOutputList for %s (%d) */\n" name i;
502 let seq, last = get_seq_last seq in
506 pr " if (!r[%d]) {\n" i;
507 pr " fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
508 pr " print_strings (r);\n";
512 pr " const char *expected = \"%s\";\n" (c_quote str);
513 pr " if (STRNEQ (r[%d], expected)) {\n" i;
514 pr " fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
519 pr " if (r[%d] != NULL) {\n" (List.length expected);
520 pr " fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
522 pr " print_strings (r);\n";
526 List.iter (generate_test_command_call test_name) seq;
527 generate_test_command_call ~test test_name last
528 | TestOutputListOfDevices (seq, expected) ->
529 pr " /* TestOutputListOfDevices for %s (%d) */\n" name i;
530 let seq, last = get_seq_last seq in
534 pr " if (!r[%d]) {\n" i;
535 pr " fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
536 pr " print_strings (r);\n";
540 pr " const char *expected = \"%s\";\n" (c_quote str);
541 pr " r[%d][5] = 's';\n" i;
542 pr " if (STRNEQ (r[%d], expected)) {\n" i;
543 pr " fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
548 pr " if (r[%d] != NULL) {\n" (List.length expected);
549 pr " fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
551 pr " print_strings (r);\n";
555 List.iter (generate_test_command_call test_name) seq;
556 generate_test_command_call ~test test_name last
557 | TestOutputInt (seq, expected) ->
558 pr " /* TestOutputInt for %s (%d) */\n" name i;
559 let seq, last = get_seq_last seq in
561 pr " if (r != %d) {\n" expected;
562 pr " fprintf (stderr, \"%s: expected %d but got %%d\\n\","
568 List.iter (generate_test_command_call test_name) seq;
569 generate_test_command_call ~test test_name last
570 | TestOutputIntOp (seq, op, expected) ->
571 pr " /* TestOutputIntOp for %s (%d) */\n" name i;
572 let seq, last = get_seq_last seq in
574 pr " if (! (r %s %d)) {\n" op expected;
575 pr " fprintf (stderr, \"%s: expected %s %d but got %%d\\n\","
576 test_name op expected;
581 List.iter (generate_test_command_call test_name) seq;
582 generate_test_command_call ~test test_name last
583 | TestOutputTrue seq ->
584 pr " /* TestOutputTrue for %s (%d) */\n" name i;
585 let seq, last = get_seq_last seq in
588 pr " fprintf (stderr, \"%s: expected true, got false\\n\");\n"
593 List.iter (generate_test_command_call test_name) seq;
594 generate_test_command_call ~test test_name last
595 | TestOutputFalse seq ->
596 pr " /* TestOutputFalse for %s (%d) */\n" name i;
597 let seq, last = get_seq_last seq in
600 pr " fprintf (stderr, \"%s: expected false, got true\\n\");\n"
605 List.iter (generate_test_command_call test_name) seq;
606 generate_test_command_call ~test test_name last
607 | TestOutputLength (seq, expected) ->
608 pr " /* TestOutputLength for %s (%d) */\n" name i;
609 let seq, last = get_seq_last seq in
612 pr " for (j = 0; j < %d; ++j)\n" expected;
613 pr " if (r[j] == NULL) {\n";
614 pr " fprintf (stderr, \"%s: short list returned\\n\");\n"
616 pr " print_strings (r);\n";
619 pr " if (r[j] != NULL) {\n";
620 pr " fprintf (stderr, \"%s: long list returned\\n\");\n"
622 pr " print_strings (r);\n";
626 List.iter (generate_test_command_call test_name) seq;
627 generate_test_command_call ~test test_name last
628 | TestOutputBuffer (seq, expected) ->
629 pr " /* TestOutputBuffer for %s (%d) */\n" name i;
630 pr " const char *expected = \"%s\";\n" (c_quote expected);
631 let seq, last = get_seq_last seq in
632 let len = String.length expected in
634 pr " if (size != %d) {\n" len;
635 pr " fprintf (stderr, \"%s: returned size of buffer wrong, expected %d but got %%zu\\n\", size);\n" test_name len;
638 pr " if (STRNEQLEN (r, expected, size)) {\n";
639 pr " fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
643 List.iter (generate_test_command_call test_name) seq;
644 generate_test_command_call ~test test_name last
645 | TestOutputStruct (seq, checks) ->
646 pr " /* TestOutputStruct for %s (%d) */\n" name i;
647 let seq, last = get_seq_last seq in
651 | CompareWithInt (field, expected) ->
652 pr " if (r->%s != %d) {\n" field expected;
653 pr " fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
654 test_name field expected;
655 pr " (int) r->%s);\n" field;
658 | CompareWithIntOp (field, op, expected) ->
659 pr " if (!(r->%s %s %d)) {\n" field op expected;
660 pr " fprintf (stderr, \"%s: %s was %%d, expected %s %d\\n\",\n"
661 test_name field op expected;
662 pr " (int) r->%s);\n" field;
665 | CompareWithString (field, expected) ->
666 pr " if (STRNEQ (r->%s, \"%s\")) {\n" field expected;
667 pr " fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
668 test_name field expected;
669 pr " r->%s);\n" field;
672 | CompareFieldsIntEq (field1, field2) ->
673 pr " if (r->%s != r->%s) {\n" field1 field2;
674 pr " fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
675 test_name field1 field2;
676 pr " (int) r->%s, (int) r->%s);\n" field1 field2;
679 | CompareFieldsStrEq (field1, field2) ->
680 pr " if (STRNEQ (r->%s, r->%s)) {\n" field1 field2;
681 pr " fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
682 test_name field1 field2;
683 pr " r->%s, r->%s);\n" field1 field2;
688 List.iter (generate_test_command_call test_name) seq;
689 generate_test_command_call ~test test_name last
690 | TestOutputFileMD5 (seq, filename) ->
691 pr " /* TestOutputFileMD5 for %s (%d) */\n" name i;
692 pr " char expected[33];\n";
693 pr " md5sum (\"%s\", expected);\n" filename;
694 let seq, last = get_seq_last seq in
696 pr " if (STRNEQ (r, expected)) {\n";
697 pr " fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
701 List.iter (generate_test_command_call test_name) seq;
702 generate_test_command_call ~test test_name last
703 | TestOutputDevice (seq, expected) ->
704 pr " /* TestOutputDevice for %s (%d) */\n" name i;
705 pr " const char *expected = \"%s\";\n" (c_quote expected);
706 let seq, last = get_seq_last seq in
709 pr " if (STRNEQ (r, expected)) {\n";
710 pr " fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
714 List.iter (generate_test_command_call test_name) seq;
715 generate_test_command_call ~test test_name last
716 | TestOutputHashtable (seq, fields) ->
717 pr " /* TestOutputHashtable for %s (%d) */\n" name i;
718 pr " const char *key, *expected, *value;\n";
719 let seq, last = get_seq_last seq in
723 pr " key = \"%s\";\n" (c_quote key);
724 pr " expected = \"%s\";\n" (c_quote value);
725 pr " value = get_key (r, key);\n";
726 pr " if (value == NULL) {\n";
727 pr " fprintf (stderr, \"%s: key \\\"%%s\\\" not found in hash: expecting \\\"%%s\\\"\\n\", key, expected);\n" test_name;
730 pr " if (STRNEQ (value, expected)) {\n";
731 pr " fprintf (stderr, \"%s: key \\\"%%s\\\": expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", key, expected, value);\n" test_name;
736 List.iter (generate_test_command_call test_name) seq;
737 generate_test_command_call ~test test_name last
738 | TestLastFail seq ->
739 pr " /* TestLastFail for %s (%d) */\n" name i;
740 let seq, last = get_seq_last seq in
741 List.iter (generate_test_command_call test_name) seq;
742 generate_test_command_call test_name ~expect_error:true last
744 (* Generate the code to run a command, leaving the result in 'r'.
745 * If you expect to get an error then you should set expect_error:true.
747 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
751 (* Look up the command to find out what args/ret it has. *)
752 let style_ret, style_args, style_optargs =
754 let _, style, _, _, _, _, _ =
755 List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
758 failwithf "%s: in test, command %s was not found" test_name name in
760 (* Match up the arguments strings and argument types. *)
762 let rec loop argts args =
763 match argts, args with
764 | (t::ts), (s::ss) ->
765 let args, rest = loop ts ss in
766 ((t, s) :: args), rest
769 failwithf "%s: in test, too few args given to function %s"
772 let args, optargs = loop style_args args in
773 let optargs, rest = loop style_optargs optargs in
775 failwithf "%s: in test, too many args given to function %s"
783 | OptString n, "NULL" -> ()
790 pr " const char *%s = \"%s\";\n" n (c_quote arg);
792 pr " const char *%s = \"%s\";\n" n (c_quote arg);
793 pr " size_t %s_size = %d;\n" n (String.length arg)
797 | FileIn _, _ | FileOut _, _ -> ()
798 | StringList n, "" | DeviceList n, "" ->
799 pr " const char *const %s[1] = { NULL };\n" n
800 | StringList n, arg | DeviceList n, arg ->
801 let strs = string_split " " arg in
804 pr " const char *%s_%d = \"%s\";\n" n i (c_quote str);
806 pr " const char *const %s[] = {\n" n;
808 fun i _ -> pr " %s_%d,\n" n i
813 (* Difficult to make these pointers in order to run a test. *)
817 if optargs <> [] then (
818 pr " struct guestfs_%s_argv optargs;\n" name;
819 let _, bitmask = List.fold_left (
820 fun (shift, bitmask) optarg ->
823 | Bool n, "" -> false
825 pr " optargs.%s = 1;\n" n; true
827 pr " optargs.%s = 0;\n" n; true
829 failwithf "boolean optional arg '%s' should be empty string or \"true\" or \"false\"" n
834 with Failure _ -> failwithf "integer optional arg '%s' should be empty string or number" n in
835 pr " optargs.%s = %d;\n" n i; true
836 | Int64 n, "" -> false
839 try Int64.of_string i
840 with Failure _ -> failwithf "int64 optional arg '%s' should be empty string or number" n in
841 pr " optargs.%s = %Ld;\n" n i; true
842 | String n, "NOARG" -> false
844 pr " optargs.%s = \"%s\";\n" n (c_quote arg); true
845 | _ -> assert false in
846 let bit = if is_set then Int64.shift_left 1L shift else 0L in
847 let bitmask = Int64.logor bitmask bit in
848 let shift = shift + 1 in
851 pr " optargs.bitmask = UINT64_C(0x%Lx);\n" bitmask;
854 (match style_ret with
855 | RErr | RInt _ | RBool _ -> pr " int r;\n"
856 | RInt64 _ -> pr " int64_t r;\n"
857 | RConstString _ | RConstOptString _ ->
858 pr " const char *r;\n"
859 | RString _ -> pr " char *r;\n"
860 | RStringList _ | RHashtable _ ->
863 | RStruct (_, typ) ->
864 pr " struct guestfs_%s *r;\n" typ
865 | RStructList (_, typ) ->
866 pr " struct guestfs_%s_list *r;\n" typ
872 pr " suppress_error = %d;\n" (if expect_error then 1 else 0);
874 pr " r = guestfs_%s (g" name
876 pr " r = guestfs_%s_argv (g" name;
878 (* Generate the parameters. *)
881 | OptString _, "NULL" -> pr ", NULL"
883 | Device n, _ | Dev_or_Path n, _
889 pr ", %s, %s_size" n n
890 | FileIn _, arg | FileOut _, arg ->
891 pr ", \"%s\"" (c_quote arg)
892 | StringList n, _ | DeviceList n, _ ->
893 pr ", (char **) %s" n
896 try int_of_string arg
897 with Failure "int_of_string" ->
898 failwithf "%s: expecting an int, but got '%s'" test_name arg in
902 try Int64.of_string arg
903 with Failure "int_of_string" ->
904 failwithf "%s: expecting an int64, but got '%s'" test_name arg in
907 let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
908 | Pointer _, _ -> assert false
911 (match style_ret with
912 | RBufferOut _ -> pr ", &size"
916 if optargs <> [] then
921 (match errcode_of_ret style_ret, expect_error with
922 | `CannotReturnError, _ -> ()
923 | `ErrorIsMinusOne, false ->
924 pr " if (r == -1)\n";
926 | `ErrorIsMinusOne, true ->
927 pr " if (r != -1)\n";
929 | `ErrorIsNULL, false ->
930 pr " if (r == NULL)\n";
932 | `ErrorIsNULL, true ->
933 pr " if (r != NULL)\n";
937 (* Insert the test code. *)
943 (match style_ret with
944 | RErr | RInt _ | RInt64 _ | RBool _
945 | RConstString _ | RConstOptString _ -> ()
946 | RString _ | RBufferOut _ -> pr " free (r);\n"
947 | RStringList _ | RHashtable _ ->
948 pr " for (i = 0; r[i] != NULL; ++i)\n";
949 pr " free (r[i]);\n";
951 | RStruct (_, typ) ->
952 pr " guestfs_free_%s (r);\n" typ
953 | RStructList (_, typ) ->
954 pr " guestfs_free_%s_list (r);\n" typ