capitests: Allow tests to properly test optional arguments.
[libguestfs.git] / generator / generator_capitests.ml
index 594c867..963ed51 100644 (file)
@@ -175,22 +175,14 @@ int main (int argc, char *argv[])
 
   guestfs_set_error_handler (g, print_error, NULL);
 
-  guestfs_set_path (g, \"../appliance\");
-
   filename = \"test1.img\";
-  fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
+  fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_TRUNC, 0666);
   if (fd == -1) {
     perror (filename);
     exit (EXIT_FAILURE);
   }
-  if (lseek (fd, %d, SEEK_SET) == -1) {
-    perror (\"lseek\");
-    close (fd);
-    unlink (filename);
-    exit (EXIT_FAILURE);
-  }
-  if (write (fd, &c, 1) == -1) {
-    perror (\"write\");
+  if (ftruncate (fd, %d) == -1) {
+    perror (\"ftruncate\");
     close (fd);
     unlink (filename);
     exit (EXIT_FAILURE);
@@ -206,19 +198,13 @@ int main (int argc, char *argv[])
   }
 
   filename = \"test2.img\";
-  fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
+  fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_TRUNC, 0666);
   if (fd == -1) {
     perror (filename);
     exit (EXIT_FAILURE);
   }
-  if (lseek (fd, %d, SEEK_SET) == -1) {
-    perror (\"lseek\");
-    close (fd);
-    unlink (filename);
-    exit (EXIT_FAILURE);
-  }
-  if (write (fd, &c, 1) == -1) {
-    perror (\"write\");
+  if (ftruncate (fd, %d) == -1) {
+    perror (\"ftruncate\");
     close (fd);
     unlink (filename);
     exit (EXIT_FAILURE);
@@ -234,19 +220,13 @@ int main (int argc, char *argv[])
   }
 
   filename = \"test3.img\";
-  fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
+  fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_TRUNC, 0666);
   if (fd == -1) {
     perror (filename);
     exit (EXIT_FAILURE);
   }
-  if (lseek (fd, %d, SEEK_SET) == -1) {
-    perror (\"lseek\");
-    close (fd);
-    unlink (filename);
-    exit (EXIT_FAILURE);
-  }
-  if (write (fd, &c, 1) == -1) {
-    perror (\"write\");
+  if (ftruncate (fd, %d) == -1) {
+    perror (\"ftruncate\");
     close (fd);
     unlink (filename);
     exit (EXIT_FAILURE);
@@ -277,6 +257,16 @@ int main (int argc, char *argv[])
   /* Cancel previous alarm. */
   alarm (0);
 
+  /* Create ext2 filesystem on /dev/sdb1 partition. */
+  if (guestfs_part_disk (g, \"/dev/sdb\", \"mbr\") == -1) {
+    printf (\"guestfs_part_disk FAILED\\n\");
+    exit (EXIT_FAILURE);
+  }
+  if (guestfs_mkfs (g, \"ext2\", \"/dev/sdb1\") == -1) {
+    printf (\"guestfs_mkfs (/dev/sdb1) FAILED\\n\");
+    exit (EXIT_FAILURE);
+  }
+
   nr_tests = %d;
 
 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
@@ -455,6 +445,13 @@ and generate_one_test_body name i test_name init test =
           ["umount_all"];
           ["lvm_remove_all"];
           ["mount_ro"; "/dev/sdd"; "/"]]
+   | InitScratchFS ->
+       pr "  /* InitScratchFS for %s */\n" test_name;
+       List.iter (generate_test_command_call test_name)
+         [["blockdev_setrw"; "/dev/sda"];
+          ["umount_all"];
+          ["lvm_remove_all"];
+          ["mount_options"; ""; "/dev/sdb1"; "/"]]
   );
 
   let get_seq_last = function
@@ -712,7 +709,7 @@ and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
   | [] -> assert false
   | name :: args ->
       (* Look up the command to find out what args/ret it has. *)
-      let style =
+      let style_ret, style_args, style_optargs =
         try
           let _, style, _, _, _, _, _ =
             List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
@@ -720,9 +717,24 @@ and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
         with Not_found ->
           failwithf "%s: in test, command %s was not found" test_name name in
 
-      if List.length (snd style) <> List.length args then
-        failwithf "%s: in test, wrong number of args given to %s"
-          test_name name;
+      (* Match up the arguments strings and argument types. *)
+      let args, optargs =
+        let rec loop argts args =
+          match argts, args with
+          | (t::ts), (s::ss) ->
+              let args, rest = loop ts ss in
+              ((t, s) :: args), rest
+          | [], ss -> [], ss
+          | ts, [] ->
+              failwithf "%s: in test, too few args given to function %s"
+                test_name name
+        in
+        let args, optargs = loop style_args args in
+        let optargs, rest = loop style_optargs optargs in
+        if rest <> [] then
+          failwithf "%s: in test, too many args given to function %s"
+            test_name name;
+        args, optargs in
 
       pr "  {\n";
 
@@ -757,30 +769,70 @@ and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
             ) strs;
             pr "      NULL\n";
             pr "    };\n";
-      ) (List.combine (snd style) args);
-
-      let error_code =
-        match fst style with
-        | RErr | RInt _ | RBool _ -> pr "    int r;\n"; "-1"
-        | RInt64 _ -> pr "    int64_t r;\n"; "-1"
-        | RConstString _ | RConstOptString _ ->
-            pr "    const char *r;\n"; "NULL"
-        | RString _ -> pr "    char *r;\n"; "NULL"
-        | RStringList _ | RHashtable _ ->
-            pr "    char **r;\n";
-            pr "    size_t i;\n";
-            "NULL"
-        | RStruct (_, typ) ->
-            pr "    struct guestfs_%s *r;\n" typ; "NULL"
-        | RStructList (_, typ) ->
-            pr "    struct guestfs_%s_list *r;\n" typ; "NULL"
-        | RBufferOut _ ->
-            pr "    char *r;\n";
-            pr "    size_t size;\n";
-            "NULL" in
+        | Pointer _, _ ->
+            (* Difficult to make these pointers in order to run a test. *)
+            assert false
+      ) args;
+
+      if optargs <> [] then (
+        pr "    struct guestfs_%s_argv optargs;\n" name;
+        let bitmask = List.fold_left (
+          fun bitmask optarg ->
+            let is_set =
+              match optarg with
+              | Bool n, "" -> false
+              | Bool n, "true" ->
+                  pr "    optargs.%s = 1;\n" n; true
+              | Bool n, "false" ->
+                  pr "    optargs.%s = 0;\n" n; true
+              | Bool n, arg ->
+                  failwithf "boolean optional arg '%s' should be empty string or \"true\" or \"false\"" n
+              | Int n, "" -> false
+              | Int n, i ->
+                  let i =
+                    try int_of_string i
+                    with Failure _ -> failwithf "integer optional arg '%s' should be empty string or number" n in
+                  pr "    optargs.%s = %d;\n" n i; true
+              | Int64 n, "" -> false
+              | Int64 n, i ->
+                  let i =
+                    try Int64.of_string i
+                    with Failure _ -> failwithf "int64 optional arg '%s' should be empty string or number" n in
+                  pr "    optargs.%s = %Ld;\n" n i; true
+              | String n, "NOARG" -> false
+              | String n, arg ->
+                  pr "    optargs.%s = \"%s\";\n" n (c_quote arg); true
+              | _ -> assert false in
+            let bitmask = Int64.shift_left bitmask 1 in
+            let bitmask = if is_set then Int64.succ bitmask else bitmask in
+            bitmask
+        ) 0L optargs in
+        pr "    optargs.bitmask = UINT64_C(0x%Lx);\n" bitmask;
+      );
+
+      (match style_ret with
+       | RErr | RInt _ | RBool _ -> pr "    int r;\n"
+       | RInt64 _ -> pr "    int64_t r;\n"
+       | RConstString _ | RConstOptString _ ->
+           pr "    const char *r;\n"
+       | RString _ -> pr "    char *r;\n"
+       | RStringList _ | RHashtable _ ->
+           pr "    char **r;\n";
+           pr "    size_t i;\n"
+       | RStruct (_, typ) ->
+           pr "    struct guestfs_%s *r;\n" typ
+       | RStructList (_, typ) ->
+           pr "    struct guestfs_%s_list *r;\n" typ
+       | RBufferOut _ ->
+           pr "    char *r;\n";
+           pr "    size_t size;\n"
+      );
 
       pr "    suppress_error = %d;\n" (if expect_error then 1 else 0);
-      pr "    r = guestfs_%s (g" name;
+      if optargs = [] then
+        pr "    r = guestfs_%s (g" name
+      else
+        pr "    r = guestfs_%s_argv (g" name;
 
       (* Generate the parameters. *)
       List.iter (
@@ -812,20 +864,34 @@ and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
             pr ", %Ld" i
         | Bool _, arg ->
             let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
-      ) (List.combine (snd style) args);
+        | Pointer _, _ -> assert false
+      ) args;
 
-      (match fst style with
+      (match style_ret with
        | RBufferOut _ -> pr ", &size"
        | _ -> ()
       );
 
+      if optargs <> [] then
+        pr ", &optargs";
+
       pr ");\n";
 
-      if not expect_error then
-        pr "    if (r == %s)\n" error_code
-      else
-        pr "    if (r != %s)\n" error_code;
-      pr "      return -1;\n";
+      (match errcode_of_ret style_ret, expect_error with
+       | `CannotReturnError, _ -> ()
+       | `ErrorIsMinusOne, false ->
+           pr "    if (r == -1)\n";
+           pr "      return -1;\n";
+       | `ErrorIsMinusOne, true ->
+           pr "    if (r != -1)\n";
+           pr "      return -1;\n";
+       | `ErrorIsNULL, false ->
+           pr "    if (r == NULL)\n";
+           pr "      return -1;\n";
+       | `ErrorIsNULL, true ->
+           pr "    if (r != NULL)\n";
+           pr "      return -1;\n";
+      );
 
       (* Insert the test code. *)
       (match test with
@@ -833,7 +899,7 @@ and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
        | Some f -> f ()
       );
 
-      (match fst style with
+      (match style_ret with
        | RErr | RInt _ | RInt64 _ | RBool _
        | RConstString _ | RConstOptString _ -> ()
        | RString _ | RBufferOut _ -> pr "    free (r);\n"