summary refs log tree commit diff
path: root/resolv/tst-ns_name.c
diff options
context:
space:
mode:
authorFlorian Weimer <fweimer@redhat.com>2017-04-04 14:09:56 +0200
committerFlorian Weimer <fweimer@redhat.com>2017-04-04 20:56:17 +0200
commit07d6f1a3ca990e0e4f93b010605d4d87a3abdf24 (patch)
tree770f01ae611f7835f61b9809ffc4a68c3ef90b13 /resolv/tst-ns_name.c
parentfce3da82e56a66bdafcef437abef0fa7b82b8d2b (diff)
downloadglibc-07d6f1a3ca990e0e4f93b010605d4d87a3abdf24.tar.gz
glibc-07d6f1a3ca990e0e4f93b010605d4d87a3abdf24.tar.xz
glibc-07d6f1a3ca990e0e4f93b010605d4d87a3abdf24.zip
resolv: Add test coverage for ns_name_unpack, ns_name_ntop
Diffstat (limited to 'resolv/tst-ns_name.c')
-rw-r--r--resolv/tst-ns_name.c303
1 files changed, 303 insertions, 0 deletions
diff --git a/resolv/tst-ns_name.c b/resolv/tst-ns_name.c
new file mode 100644
index 0000000000..66d9a6666b
--- /dev/null
+++ b/resolv/tst-ns_name.c
@@ -0,0 +1,303 @@
+/* Test ns_name-related functions.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* This test program processes the tst-ns_name.data file.  */
+
+#include <ctype.h>
+#include <resolv.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/xstdio.h>
+
+/* A byte buffer and its length.  */
+struct buffer
+{
+  unsigned char *data;
+  size_t length;
+};
+
+/* Convert a base64-encoded string to its binary representation.  */
+static bool
+base64_to_buffer (const char *base64, struct buffer *result)
+{
+  /* "-" denotes an empty input.  */
+  if (strcmp (base64, "-") == 0)
+    {
+      result->data = xmalloc (1);
+      result->length = 0;
+      return true;
+    }
+
+  size_t size = strlen (base64);
+  unsigned char *data = xmalloc (size);
+  int ret = b64_pton (base64, data, size);
+  if (ret < 0 || ret > size)
+    return false;
+  result->data = xrealloc (data, ret);
+  result->length = ret;
+  return true;
+}
+
+/* A test case for ns_name_unpack and ns_name_ntop.  */
+struct test_case
+{
+  char *path;
+  size_t lineno;
+  struct buffer input;
+  size_t input_offset;
+  int unpack_result;
+  struct buffer unpack_output;
+  int ntop_result;
+  char *ntop_text;
+};
+
+/* Deallocate the buffers associated with the test case.  */
+static void
+free_test_case (struct test_case *t)
+{
+  free (t->path);
+  free (t->input.data);
+  free (t->unpack_output.data);
+  free (t->ntop_text);
+}
+
+/* Extract the test case information from a test file line.  */
+static bool
+parse_test_case (const char *path, size_t lineno, const char *line,
+                 struct test_case *result)
+{
+  memset (result, 0, sizeof (*result));
+  result->path = xstrdup (path);
+  result->lineno = lineno;
+  result->ntop_result = -1;
+  char *input = NULL;
+  char *unpack_output = NULL;
+  int ret = sscanf (line, "%ms %zu %d %ms %d %ms",
+                    &input, &result->input_offset,
+                    &result->unpack_result, &unpack_output,
+                    &result->ntop_result, &result->ntop_text);
+  if (ret < 3)
+    {
+      printf ("%s:%zu: error: missing input fields\n", path, lineno);
+      free (input);
+      return false;
+    }
+  if (!base64_to_buffer (input, &result->input))
+    {
+      printf ("%s:%zu: error: malformed base64 input data\n", path, lineno);
+      free (input);
+      free (unpack_output);
+      free (result->ntop_text);
+      return false;
+    }
+  free (input);
+
+  if (unpack_output == NULL)
+    result->unpack_output = (struct buffer) { NULL, 0 };
+  else if (!base64_to_buffer (unpack_output, &result->unpack_output))
+    {
+      printf ("%s:%zu: error: malformed base64 unpack data\n", path, lineno);
+      free (result->input.data);
+      free (unpack_output);
+      free (result->ntop_text);
+      return false;
+    }
+  free (unpack_output);
+
+  /* At this point, all allocated buffers have been transferred to
+     *result.  */
+
+  if (result->input_offset > result->input.length)
+    {
+      printf ("%s:%zu: error: input offset %zu exceeds buffer size %zu\n",
+              path, lineno, result->input_offset, result->input.length);
+      free_test_case (result);
+      return false;
+    }
+  if (result->unpack_result < -1)
+    {
+      printf ("%s:%zu: error: invalid unpack result %d\n",
+              path, lineno, result->unpack_result);
+      free_test_case (result);
+      return false;
+    }
+  if (result->ntop_result < -1)
+    {
+      printf ("%s:%zu: error: invalid ntop result %d\n",
+              path, lineno, result->ntop_result);
+      free_test_case (result);
+      return false;
+    }
+
+  bool fields_consistent;
+  switch (ret)
+    {
+    case 3:
+      fields_consistent = result->unpack_result == -1;
+      break;
+    case 5:
+      fields_consistent = result->unpack_result != -1
+        && result->ntop_result == -1;
+      break;
+    case 6:
+      fields_consistent = result->unpack_result != -1
+        && result->ntop_result != -1;
+      break;
+    default:
+      fields_consistent = false;
+    }
+  if (!fields_consistent)
+    {
+      printf ("%s:%zu: error: wrong number of fields: %d\n",
+              path, lineno, ret);
+      free_test_case (result);
+      return false;
+    }
+  return true;
+}
+
+/* Format the buffer as a hexadecimal string and write it to standard
+   output.  */
+static void
+print_hex (const char *label, struct buffer buffer)
+{
+  printf ("  %s ", label);
+  unsigned char *p = buffer.data;
+  unsigned char *end = p + buffer.length;
+  while (p < end)
+    {
+      printf ("%02X", *p & 0xFF);
+      ++p;
+    }
+  putchar ('\n');
+}
+
+/* Run the test case specified in *T.  */
+static void
+run_test_case (struct test_case *t)
+{
+  unsigned char *unpacked = xmalloc (NS_MAXCDNAME);
+  int consumed = ns_name_unpack
+    (t->input.data, t->input.data + t->input.length,
+     t->input.data + t->input_offset,
+     unpacked, NS_MAXCDNAME);
+  if (consumed != t->unpack_result)
+    {
+      support_record_failure ();
+      printf ("%s:%zu: error: wrong result from ns_name_unpack\n"
+              "  expected: %d\n"
+              "  actual:   %d\n",
+              t->path, t->lineno, t->unpack_result, consumed);
+      return;
+    }
+  if (consumed != -1)
+    {
+      if (memcmp (unpacked, t->unpack_output.data, consumed) != 0)
+        {
+          support_record_failure ();
+          printf ("%s:%zu: error: wrong data from ns_name_unpack\n",
+                  t->path, t->lineno);
+          print_hex ("expected:", t->unpack_output);
+          print_hex ("actual:  ", (struct buffer) { unpacked, consumed });
+          return;
+        }
+
+      char *text = xmalloc (NS_MAXDNAME);
+      int ret = ns_name_ntop (unpacked, text, NS_MAXDNAME);
+      if (ret != t->ntop_result)
+        {
+          support_record_failure ();
+          printf ("%s:%zu: error: wrong result from ns_name_top\n"
+                  "  expected: %d\n"
+                  "  actual:   %d\n",
+                  t->path, t->lineno, t->ntop_result, ret);
+          return;
+        }
+      if (ret != -1)
+        {
+          if (strcmp (text, t->ntop_text) != 0)
+            {
+              support_record_failure ();
+              printf ("%s:%zu: error: wrong data from ns_name_ntop\n",
+                      t->path, t->lineno);
+              printf ("  expected: \"%s\"\n", t->ntop_text);
+              printf ("  actual:   \"%s\"\n", text);
+              return;
+            }
+        }
+      free (text);
+    }
+  free (unpacked);
+}
+
+/* Open the file at PATH, parse the test cases contained in it, and
+   run them.  */
+static void
+run_test_file (const char *path)
+{
+  FILE *fp = xfopen (path, "re");
+  char *line = NULL;
+  size_t line_allocated = 0;
+  size_t lineno = 0;
+
+  while (true)
+    {
+      ssize_t ret = getline (&line, &line_allocated, fp);
+      if (ret < 0)
+        {
+          if (ferror (fp))
+            {
+              printf ("%s: error reading file: %m\n", path);
+              exit (1);
+            }
+          TEST_VERIFY (feof (fp));
+          break;
+        }
+
+      ++lineno;
+      char *p = line;
+      while (isspace (*p))
+        ++p;
+      if (*p == '\0' || *p == '#')
+        continue;
+
+      struct test_case test_case;
+      if (!parse_test_case (path, lineno, line, &test_case))
+        {
+          support_record_failure ();
+          continue;
+        }
+      run_test_case (&test_case);
+      free_test_case (&test_case);
+    }
+  free (line);
+  xfclose (fp);
+}
+
+static int
+do_test (void)
+{
+  run_test_file ("tst-ns_name.data");
+  return 0;
+}
+
+#include <support/test-driver.c>