userspec-tests: test the userspec module
authorJim Meyering <meyering@redhat.com>
Sat, 28 Nov 2009 10:51:08 +0000 (11:51 +0100)
committerJim Meyering <meyering@redhat.com>
Fri, 22 Jan 2010 11:26:07 +0000 (12:26 +0100)
* tests/test-userspec.c: New file.
* modules/userspec-tests: Likewise.

ChangeLog
modules/userspec-tests [new file with mode: 0644]
tests/test-userspec.c [new file with mode: 0644]

index e294c72..0ced685 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2010-01-22  Jim Meyering  <meyering@redhat.com>
+
+       userspec: add unit tests
+       * tests/test-userspec.c: New file.
+       * modules/userspec-tests: Likewise.
+
 2010-01-21  Jim Meyering  <meyering@redhat.com>
 
        maint.mk: handle source file names containing "." robustly
diff --git a/modules/userspec-tests b/modules/userspec-tests
new file mode 100644 (file)
index 0000000..0d955ba
--- /dev/null
@@ -0,0 +1,11 @@
+Files:
+tests/test-userspec.c
+
+Depends-on:
+xalloc
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-userspec
+check_PROGRAMS += test-userspec
diff --git a/tests/test-userspec.c b/tests/test-userspec.c
new file mode 100644 (file)
index 0000000..3e101f3
--- /dev/null
@@ -0,0 +1,186 @@
+/* Test userspec.c
+   Copyright (C) 2009-2010 Free Software Foundation, Inc.
+
+   This program 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.
+
+   This program 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/>.  */
+
+/* Written by Jim Meyering.  */
+
+#include <config.h>
+
+#include "userspec.h"
+
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include "xalloc.h"
+
+#define ARRAY_CARDINALITY(Array) (sizeof (Array) / sizeof *(Array))
+
+struct test
+{
+  char *in;
+  uid_t uid;
+  gid_t gid;
+  char *user_name;
+  char *group_name;
+  char *result;
+};
+
+static struct test T[] =
+  {
+    { "",                      -1, -1, "",   "",   NULL},
+    { ":",                     -1, -1, "",   "",   NULL},
+    { "0:0",                    0,  0, "",   "",   NULL},
+    { ":1",                    -1,  1, "",   "",   NULL},
+    { "1",                      1, -1, "",   "",   NULL},
+    { ":+0",                   -1,  0, "",   "",   NULL},
+    { "22:42",                 22, 42, "",   "",   NULL},
+    /* (uint32_t)-1 should be invalid everywhere */
+    { "4294967295:4294967295",  0,  0, NULL, NULL, "invalid user"},
+    /* likewise, but with only the group being invalid */
+    { "0:4294967295",           0,  0, NULL, NULL, "invalid group"},
+    { ":4294967295",            0,  0, NULL, NULL, "invalid group"},
+    /* and only the user being invalid */
+    { "4294967295:0",           0,  0, NULL, NULL, "invalid user"},
+    /* and using 2^32 */
+    { "4294967296:4294967296",  0,  0, NULL, NULL, "invalid user"},
+    { "0:4294967296",           0,  0, NULL, NULL, "invalid group"},
+    { ":4294967296",            0,  0, NULL, NULL, "invalid group"},
+    { "4294967296:0",           0,  0, NULL, NULL, "invalid user"},
+    /* numeric user and no group is invalid */
+    { "4294967295:",            0,  0, NULL, NULL, "invalid spec"},
+    { "4294967296:",            0,  0, NULL, NULL, "invalid spec"},
+    { "1:",                     0,  0, NULL, NULL, "invalid spec"},
+    { "+0:",                    0,  0, NULL, NULL, "invalid spec"},
+
+    /* "username:" must expand to UID:GID where GID is username's login group */
+    /* Add an entry like the following to the table, if possible.
+    { "U_NAME:",              UID,GID, U_NAME, G_NAME, NULL}, */
+    { NULL,                     0,  0, NULL, NULL, ""},  /* place-holder */
+
+    { NULL,                     0,  0, NULL, NULL, ""}
+  };
+
+#define STREQ(a, b) (strcmp (a, b) == 0)
+
+static char const *
+maybe_null (char const *s)
+{
+  return s ? s : "NULL";
+}
+
+static bool
+same_diag (char const *s, char const *t)
+{
+  if (s == NULL && t == NULL)
+    return true;
+  if (s == NULL || t == NULL)
+    return false;
+  return STREQ (s, t);
+}
+
+int
+main (void)
+{
+  unsigned int i;
+  int fail = 0;
+  uid_t uid;
+
+  /* Find a UID that has both a user name and login group name,
+     but skip UID 0.  */
+  for (uid = 1200; 0 < uid; uid--)
+    {
+      struct group *gr;
+      struct passwd *pw = getpwuid (uid);
+      unsigned int j;
+      size_t len;
+      if (!pw || !pw->pw_name || !(gr = getgrgid (pw->pw_gid)) || !gr->gr_name)
+        continue;
+      j = ARRAY_CARDINALITY (T) - 2;
+      assert (T[j].in == NULL);
+      assert (T[j+1].in == NULL);
+      len = strlen (pw->pw_name);
+
+      /* Store "username:" in T[j].in.  */
+      T[j].in = xmalloc (len + 1 + 1);
+      memcpy (T[j].in, pw->pw_name, len);
+      T[j].in[len] = ':';
+      T[j].in[len+1] = '\0';
+
+      T[j].uid = uid;
+      T[j].gid = gr->gr_gid;
+      T[j].user_name = xstrdup (pw->pw_name);
+      T[j].group_name = xstrdup (gr->gr_name);
+      T[j].result = NULL;
+      break;
+    }
+
+  for (i = 0; T[i].in; i++)
+    {
+      uid_t uid = (uid_t) -1;
+      gid_t gid = (gid_t) -1;
+      char *user_name;
+      char *group_name;
+      char const *diag = parse_user_spec (T[i].in, &uid, &gid,
+                                         &user_name, &group_name);
+      free (user_name);
+      free (group_name);
+      if (!same_diag (diag, T[i].result))
+        {
+          printf ("%s return value mismatch: got %s, expected %s\n",
+                  T[i].in, maybe_null (diag), maybe_null (T[i].result));
+          fail = 1;
+          continue;
+        }
+
+      if (diag)
+        continue;
+
+      if (uid != T[i].uid || gid != T[i].gid)
+        {
+          printf ("%s mismatch (-: expected uid,gid; +:actual)\n"
+                 "-%3lu,%3lu\n+%3lu,%3lu\n",
+                 T[i].in,
+                  (unsigned long int) T[i].uid,
+                  (unsigned long int) T[i].gid,
+                  (unsigned long int) uid,
+                  (unsigned long int) gid);
+          fail = 1;
+        }
+
+      if (!diag && !T[i].result)
+        continue;
+
+        {
+          printf ("%s diagnostic mismatch (-: expected uid,gid; +:actual)\n"
+                 "-%s\n+%s\n",
+                 T[i].in, T[i].result, diag);
+          fail = 1;
+        }
+    }
+
+  return fail;
+}
+
+/*
+Local Variables:
+indent-tabs-mode: nil
+End:
+*/