common: Add unit test for exectool.
authorJustus Winter <justus@g10code.com>
Tue, 26 Jul 2016 12:29:12 +0000 (14:29 +0200)
committerJustus Winter <justus@g10code.com>
Tue, 26 Jul 2016 12:29:54 +0000 (14:29 +0200)
* common/Makefile.am: Build new test.
* common/t-exectool.c: New file.

Signed-off-by: Justus Winter <justus@g10code.com>
common/Makefile.am
common/t-exectool.c [new file with mode: 0644]

index 6f9d96d..759800b 100644 (file)
@@ -160,7 +160,7 @@ module_tests = t-stringhelp t-timestuff \
               t-mapstrings t-zb32 t-mbox-util t-iobuf t-strlist \
               t-name-value t-ccparray t-recsel
 if !HAVE_W32CE_SYSTEM
-module_tests += t-exechelp
+module_tests += t-exechelp t-exectool
 endif
 if HAVE_W32_SYSTEM
 module_tests += t-w32-reg
@@ -196,6 +196,7 @@ t_helpfile_LDADD = $(t_common_ldadd)
 t_sexputil_LDADD = $(t_common_ldadd)
 t_b64_LDADD = $(t_common_ldadd)
 t_exechelp_LDADD = $(t_common_ldadd)
+t_exectool_LDADD = $(t_common_ldadd)
 t_session_env_LDADD = $(t_common_ldadd)
 t_openpgp_oid_LDADD = $(t_common_ldadd)
 t_ssh_utils_LDADD = $(t_common_ldadd)
diff --git a/common/t-exectool.c b/common/t-exectool.c
new file mode 100644 (file)
index 0000000..bbbf8fa
--- /dev/null
@@ -0,0 +1,223 @@
+/* t-exectool.c - Module test for exectool.c
+ * Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include <unistd.h>
+
+#include "util.h"
+#include "exectool.h"
+
+static int verbose;
+
+#define fail(msg, err)                                           \
+  do { fprintf (stderr, "%s:%d: %s failed: %s\n",                \
+                __FILE__,__LINE__, (msg), gpg_strerror (err));   \
+    exit (1);                                                    \
+  } while(0)
+
+static void
+test_executing_true (void)
+{
+  gpg_error_t err;
+  const char *argv[] = { "/bin/true", NULL };
+  char *result;
+  size_t len;
+
+  if (access (argv[0], X_OK))
+    {
+      fprintf (stderr, "skipping test: %s not executable: %s",
+               argv[0], strerror (errno));
+      return;
+    }
+
+  if (verbose)
+    fprintf (stderr, "Executing %s...\n", argv[0]);
+
+  err = gnupg_exec_tool (argv[0], &argv[1], "", &result, &len);
+  if (err)
+    fail ("gnupg_exec_tool", err);
+
+  assert (result);
+  assert (len == 0);
+  free (result);
+}
+
+static void
+test_executing_false (void)
+{
+  gpg_error_t err;
+  const char *argv[] = { "/bin/false", NULL };
+  char *result;
+  size_t len;
+
+  if (access (argv[0], X_OK))
+    {
+      fprintf (stderr, "skipping test: %s not executable: %s",
+               argv[0], strerror (errno));
+      return;
+    }
+
+  if (verbose)
+    fprintf (stderr, "Executing %s...\n", argv[0]);
+
+  err = gnupg_exec_tool (argv[0], &argv[1], "", &result, &len);
+  assert (err == GPG_ERR_GENERAL);
+}
+
+static void
+test_executing_cat (const char *vector)
+{
+  gpg_error_t err;
+  const char *argv[] = { "/bin/cat", NULL };
+  char *result;
+  size_t len;
+
+  if (access (argv[0], X_OK))
+    {
+      fprintf (stderr, "skipping test: %s not executable: %s",
+               argv[0], strerror (errno));
+      return;
+    }
+
+  if (verbose)
+    fprintf (stderr, "Executing %s...\n", argv[0]);
+
+  err = gnupg_exec_tool (argv[0], &argv[1], vector, &result, &len);
+  if (err)
+    fail ("gnupg_exec_tool", err);
+
+  assert (result);
+
+  /* gnupg_exec_tool returns the correct length... */
+  assert (len == strlen (vector));
+  /* ... but 0-terminates data for ease of use.  */
+  assert (result[len] == 0);
+
+  assert (strcmp (result, vector) == 0);
+  free (result);
+}
+
+
+static void
+test_catting_cat (void)
+{
+  gpg_error_t err;
+  const char *argv[] = { "/bin/cat", "/bin/cat", NULL };
+  char *result;
+  size_t len;
+  estream_t in;
+  char *reference, *p;
+  size_t reference_len;
+
+  if (access (argv[0], X_OK))
+    {
+      fprintf (stderr, "skipping test: %s not executable: %s",
+               argv[0], strerror (errno));
+      return;
+    }
+
+  in = es_fopen (argv[1], "r");
+  if (in == NULL)
+    {
+      fprintf (stderr, "skipping test: could not open %s: %s",
+               argv[1], strerror (errno));
+      return;
+    }
+
+  err = es_fseek (in, 0L, SEEK_END);
+  if (err)
+    {
+      fprintf (stderr, "skipping test: could not seek in %s: %s",
+               argv[1], gpg_strerror (err));
+      return;
+    }
+
+  reference_len = es_ftell (in);
+  err = es_fseek (in, 0L, SEEK_SET);
+  assert (!err || !"rewinding failed");
+
+  reference = malloc (reference_len);
+  assert (reference || !"allocating reference buffer failed");
+
+  for (p = reference; p - reference < reference_len; )
+    {
+      size_t bytes_read, left;
+      left = reference_len - (p - reference);
+      if (left > 4096)
+        left = 4096;
+      err = es_read (in, p, left, &bytes_read);
+      if (err)
+        {
+          fprintf (stderr, "error reading %s: %s",
+                   argv[1], gpg_strerror (err));
+          exit (1);
+        }
+
+      p += bytes_read;
+    }
+  es_fclose (in);
+
+  if (verbose)
+    fprintf (stderr, "Executing %s %s...\n", argv[0], argv[1]);
+
+  err = gnupg_exec_tool (argv[0], &argv[1], "", &result, &len);
+  if (err)
+    fail ("gnupg_exec_tool", err);
+
+  assert (result);
+
+  /* gnupg_exec_tool returns the correct length... */
+  assert (len == reference_len);
+  assert (memcmp (result, reference, reference_len) == 0);
+  free (reference);
+  free (result);
+}
+
+
+int
+main (int argc, char **argv)
+{
+  int i;
+  char binjunk[256];
+
+  if (argc)
+    { argc--; argv++; }
+  if (argc && !strcmp (argv[0], "--verbose"))
+    {
+      verbose = 1;
+      argc--; argv++;
+    }
+
+  test_executing_true ();
+  test_executing_false ();
+  test_executing_cat ("Talking to myself here...");
+
+  for (i = 0; i < 255 /* one less */; i++)
+    binjunk[i] = i + 1;        /* avoid 0 */
+  binjunk[255] = 0;
+
+  test_executing_cat (binjunk);
+  test_catting_cat ();
+
+  return 0;
+}