common,w32: Silence an unused arg warning message.
[gnupg.git] / common / t-stringhelp.c
index f5b6cd9..b4a41ac 100644 (file)
@@ -2,9 +2,9 @@
  * Copyright (C) 2007 Free Software Foundation, Inc.
  *               2015  g10 Code GmbH
  *
- * This file is part of JNLIB, which is a subsystem of GnuPG.
+ * This file is part of GnuPG.
  *
- * JNLIB is free software; you can redistribute it and/or modify it
+ * GnuPG is free software; you can redistribute it and/or modify it
  * under the terms of either
  *
  *   - the GNU Lesser General Public License as published by the Free
@@ -19,7 +19,7 @@
  *
  * or both in parallel, as here.
  *
- * JNLIB is distributed in the hope that it will be useful, but
+ * 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.
@@ -40,9 +40,8 @@
 #include <unistd.h>
 #include <sys/types.h>
 
-#include "stringhelp.h"
-
 #include "t-support.h"
+#include "stringhelp.h"
 
 
 static char *home_buffer;
@@ -144,7 +143,7 @@ test_percent_escape (void)
       result = percent_escape (tests[testno].value, tests[testno].extra);
       if (!result)
         fail (testno);
-      if (strcmp (result, tests[testno].expected))
+      else if (strcmp (result, tests[testno].expected))
         fail (testno);
       xfree (result);
     }
@@ -399,13 +398,13 @@ test_make_filename_try (void)
   out = make_filename_try ("~/foo", "bar", NULL);
   if (!out)
     fail (2);
-  if (home)
+  else if (home)
     {
       if (strlen (out) < homelen + 7)
         fail (2);
-      if (strncmp (out, home, homelen))
+      else if (strncmp (out, home, homelen))
         fail (2);
-      if (strcmp (out+homelen, "/foo/bar"))
+      else if (strcmp (out+homelen, "/foo/bar"))
         fail (2);
     }
   else
@@ -418,13 +417,13 @@ test_make_filename_try (void)
   out = make_filename_try ("~", "bar", NULL);
   if (!out)
     fail (2);
-  if (home)
+  else if (home)
     {
       if (strlen (out) < homelen + 3)
         fail (2);
-      if (strncmp (out, home, homelen))
+      else if (strncmp (out, home, homelen))
         fail (2);
-      if (strcmp (out+homelen, "/bar"))
+      else if (strcmp (out+homelen, "/bar"))
         fail (2);
     }
   else
@@ -446,33 +445,33 @@ test_make_absfilename_try (void)
   out = make_absfilename_try ("foo", "bar", NULL);
   if (!out)
     fail (0);
-  if (strlen (out) < cwdlen + 7)
+  else if (strlen (out) < cwdlen + 7)
     fail (0);
-  if (strncmp (out, cwd, cwdlen))
+  else if (strncmp (out, cwd, cwdlen))
     fail (0);
-  if (strcmp (out+cwdlen, "/foo/bar"))
+  else if (strcmp (out+cwdlen, "/foo/bar"))
     fail (0);
   xfree (out);
 
   out = make_absfilename_try ("./foo", NULL);
   if (!out)
     fail (1);
-  if (strlen (out) < cwdlen + 5)
+  else if (strlen (out) < cwdlen + 5)
     fail (1);
-  if (strncmp (out, cwd, cwdlen))
+  else if (strncmp (out, cwd, cwdlen))
     fail (1);
-  if (strcmp (out+cwdlen, "/./foo"))
+  else if (strcmp (out+cwdlen, "/./foo"))
     fail (1);
   xfree (out);
 
   out = make_absfilename_try (".", NULL);
   if (!out)
     fail (2);
-  if (strlen (out) < cwdlen)
+  else if (strlen (out) < cwdlen)
     fail (2);
-  if (strncmp (out, cwd, cwdlen))
+  else if (strncmp (out, cwd, cwdlen))
     fail (2);
-  if (strcmp (out+cwdlen, ""))
+  else if (strcmp (out+cwdlen, ""))
     fail (2);
   xfree (out);
 
@@ -482,60 +481,398 @@ test_make_absfilename_try (void)
 static void
 test_strsplit (void)
 {
-  int test_count = 0;
-  void test (const char *s, char delim, char replacement,
-            const char *fields_expected[])
-  {
-    char *s2;
-    int field_count;
-    char **fields;
-    int field_count_expected;
-    int i;
-
-    /* Count the fields.  */
-    for (field_count_expected = 0;
-        fields_expected[field_count_expected];
-        field_count_expected ++)
-      ;
-
-    test_count ++;
-
-    /* We need to copy s since strsplit modifies it in place.  */
-    s2 = xstrdup (s);
-    fields = strsplit (s2, delim, replacement, &field_count);
-
-    if (field_count != field_count_expected)
-      fail (test_count * 1000);
-
-    for (i = 0; i < field_count_expected; i ++)
-      if (strcmp (fields_expected[i], fields[i]) != 0)
-       {
-         printf ("For field %d, expected '%s', but got '%s'\n",
-                 i, fields_expected[i], fields[i]);
-         fail (test_count * 1000 + i + 1);
-       }
-
-    xfree (s2);
-  }
+  struct {
+    const char *s;
+    char delim;
+    char replacement;
+    const char *fields_expected[10];
+  } tv[] = {
+    {
+      "a:bc:cde:fghi:jklmn::foo:", ':', '\0',
+      { "a", "bc", "cde", "fghi", "jklmn", "", "foo", "", NULL }
+    },
+    {
+      ",a,bc,,def,", ',', '!',
+      { "!a!bc!!def!", "a!bc!!def!", "bc!!def!", "!def!", "def!", "", NULL }
+    },
+    {
+      "", ':', ',',
+      { "", NULL }
+    }
+  };
 
-  {
-    const char *expected_result[] =
-      { "a", "bc", "cde", "fghi", "jklmn", "", "foo", "", NULL };
-    test ("a:bc:cde:fghi:jklmn::foo:", ':', '\0', expected_result);
-  }
+  int tidx;
 
-  {
-    const char *expected_result[] =
-      { "!a!bc!!def!", "a!bc!!def!", "bc!!def!", "!def!", "def!", "", NULL };
-    test (",a,bc,,def,", ',', '!', expected_result);
-  }
+  for (tidx = 0; tidx < DIM(tv); tidx++)
+    {
+      char *s2;
+      int field_count;
+      char **fields;
+      int field_count_expected;
+      int i;
+
+      /* Count the fields.  */
+      for (field_count_expected = 0;
+           tv[tidx].fields_expected[field_count_expected];
+           field_count_expected ++)
+        ;
+
+      /* We need to copy s since strsplit modifies it in place.  */
+      s2 = xstrdup (tv[tidx].s);
+      fields = strsplit (s2, tv[tidx].delim, tv[tidx].replacement,
+                         &field_count);
+
+      if (field_count != field_count_expected)
+        fail (tidx * 1000);
+
+      for (i = 0; i < field_count_expected; i ++)
+        if (strcmp (tv[tidx].fields_expected[i], fields[i]) != 0)
+          {
+            printf ("For field %d, expected '%s', but got '%s'\n",
+                    i, tv[tidx].fields_expected[i], fields[i]);
+            fail (tidx * 1000 + i + 1);
+          }
+
+      xfree (s2);
+    }
+}
+
+
+
+static void
+test_strtokenize (void)
+{
+  struct {
+    const char *s;
+    const char *delim;
+    const char *fields_expected[10];
+  } tv[] = {
+    {
+      "", ":",
+      { "", NULL }
+    },
+    {
+      "a", ":",
+      { "a", NULL }
+    },
+    {
+      ":", ":",
+      { "", "", NULL }
+    },
+    {
+      "::", ":",
+      { "", "", "", NULL }
+    },
+    {
+      "a:b:c", ":",
+      { "a", "b", "c", NULL }
+    },
+    {
+      "a:b:", ":",
+      { "a", "b", "", NULL }
+    },
+    {
+      "a:b", ":",
+      { "a", "b", NULL }
+    },
+    {
+      "aa:b:cd", ":",
+      { "aa", "b", "cd", NULL }
+    },
+    {
+      "aa::b:cd", ":",
+      { "aa", "", "b", "cd", NULL }
+    },
+    {
+      "::b:cd", ":",
+      { "", "", "b", "cd", NULL }
+    },
+    {
+      "aa:   : b:cd ", ":",
+      { "aa", "", "b", "cd", NULL }
+    },
+    {
+      "  aa:   : b:  cd ", ":",
+      { "aa", "", "b", "cd", NULL }
+    },
+    {
+      "  ", ":",
+      { "", NULL }
+    },
+    {
+      "  :", ":",
+      { "", "", NULL }
+    },
+    {
+      "  : ", ":",
+      { "", "", NULL }
+    },
+    {
+      ": ", ":",
+      { "", "", NULL }
+    },
+    {
+      ": x ", ":",
+      { "", "x", NULL }
+    },
+    {
+      "a:bc:cde:fghi:jklmn::foo:", ":",
+      { "a", "bc", "cde", "fghi", "jklmn", "", "foo", "", NULL }
+    },
+    {
+      ",a,bc,,def,", ",",
+      { "", "a", "bc", "", "def", "", NULL }
+    },
+    {
+      " a ", " ",
+      { "", "a", "", NULL }
+    },
+    {
+      " ", " ",
+      { "", "", NULL }
+    },
+    {
+      "", " ",
+      { "", NULL }
+    }
+  };
+
+  int tidx;
+
+  for (tidx = 0; tidx < DIM(tv); tidx++)
+    {
+      char **fields;
+      int field_count;
+      int field_count_expected;
+      int i;
+
+      for (field_count_expected = 0;
+           tv[tidx].fields_expected[field_count_expected];
+           field_count_expected ++)
+        ;
+
+      fields = strtokenize (tv[tidx].s, tv[tidx].delim);
+      if (!fields)
+        fail (tidx * 1000);
+      else
+        {
+          for (field_count = 0; fields[field_count]; field_count++)
+            ;
+          if (field_count != field_count_expected)
+            fail (tidx * 1000);
+          else
+            {
+              for (i = 0; i < field_count_expected; i++)
+                if (strcmp (tv[tidx].fields_expected[i], fields[i]))
+                  {
+                    printf ("For field %d, expected '%s', but got '%s'\n",
+                            i, tv[tidx].fields_expected[i], fields[i]);
+                    fail (tidx * 1000 + i + 1);
+                  }
+            }
+          }
+
+      xfree (fields);
+    }
+}
 
+static char *
+stresc (char *s)
+{
+  char *p;
+  int l = strlen (s) + 1;
+
+  for (p = s; *p; p ++)
+    if (*p == '\n')
+      l ++;
+
+  p = xmalloc (l);
+  for (l = 0; *s; s ++, l ++)
+    {
+      if (*s == ' ')
+        p[l] = '_';
+      else if (*p == '\n')
+        {
+          p[l ++] = '\\';
+          p[l ++] = 'n';
+          p[l] = '\n';
+        }
+      else
+        p[l] = *s;
+    }
+  p[l] = *s;
+
+  return p;
+}
+
+
+static void
+test_format_text (void)
+{
+  struct test
   {
-    const char *expected_result[] = { "", NULL };
-    test ("", ':', ',', expected_result);
-  }
+    int target_cols, max_cols;
+    char *input;
+    char *expected;
+  };
+
+  struct test tests[] = {
+    {
+      10, 12,
+      "",
+      "",
+    },
+    {
+      10, 12,
+      " ",
+      "",
+    },
+    {
+      10, 12,
+      "  ",
+      "",
+    },
+    {
+      10, 12,
+      " \n ",
+      " \n",
+    },
+    {
+      10, 12,
+      " \n  \n ",
+      " \n  \n",
+    },
+    {
+      10, 12,
+      "0123456789 0123456789 0",
+      "0123456789\n0123456789\n0",
+    },
+    {
+      10, 12,
+      "   0123456789   0123456789   0  ",
+      "   0123456789\n0123456789\n0",
+    },
+    {
+      10, 12,
+      "01 34 67 90 23 56  89 12 45 67 89 1",
+      "01 34 67\n90 23 56\n89 12 45\n67 89 1"
+    },
+    {
+      10, 12,
+      "01 34 67 90 23 56  89 12 45 67 89 1",
+      "01 34 67\n90 23 56\n89 12 45\n67 89 1"
+    },
+    {
+      72, 80,
+      "Warning: if you think you've seen more than 10 messages "
+      "signed by this key, then this key might be a forgery!  "
+      "Carefully examine the email address for small variations "
+      "(e.g., additional white space).  If the key is suspect, "
+      "then use 'gpg --tofu-policy bad \"FINGERPRINT\"' to mark it as being bad.\n",
+      "Warning: if you think you've seen more than 10 messages signed by this\n"
+      "key, then this key might be a forgery!  Carefully examine the email\n"
+      "address for small variations (e.g., additional white space).  If the key\n"
+      "is suspect, then use 'gpg --tofu-policy bad \"FINGERPRINT\"' to mark it as\n"
+      "being bad.\n"
+
+    },
+    {
+      72, 80,
+      "Normally, there is only a single key associated with an email "
+      "address.  However, people sometimes generate a new key if "
+      "their key is too old or they think it might be compromised.  "
+      "Alternatively, a new key may indicate a man-in-the-middle "
+      "attack!  Before accepting this key, you should talk to or "
+      "call the person to make sure this new key is legitimate.",
+      "Normally, there is only a single key associated with an email "
+      "address.\nHowever, people sometimes generate a new key if "
+      "their key is too old or\nthey think it might be compromised.  "
+      "Alternatively, a new key may indicate\na man-in-the-middle "
+      "attack!  Before accepting this key, you should talk\nto or "
+      "call the person to make sure this new key is legitimate.",
+    }
+  };
+
+  int i;
+  int failed = 0;
+
+  for (i = 0; i < sizeof (tests) / sizeof (tests[0]); i ++)
+    {
+      struct test *test = &tests[i];
+      char *result =
+        format_text (test->input, 0, test->target_cols, test->max_cols);
+      if (strcmp (result, test->expected) != 0)
+        {
+          printf ("%s: Test #%d failed.\nExpected: '%s'\nResult: '%s'\n",
+                  __func__, i + 1, stresc (test->expected), stresc (result));
+          failed ++;
+        }
+      xfree (result);
+    }
+
+  if (failed)
+    fail(0);
+}
+
+
+static void
+test_compare_version_strings (void)
+{
+  struct { const char *a; const char *b; int okay; } tests[] = {
+    { "1.0.0",   "1.0.0", 1 },
+    { "1.0.0-",  "1.0.0", 1 },
+    { "1.0.0-1", "1.0.0", 1 },
+    { "1.0.0.1", "1.0.0", 1 },
+    { "1.0.0",   "1.0.1", 0 },
+    { "1.0.0-",  "1.0.1", 0 },
+    { "1.0.0-1", "1.0.1", 0 },
+    { "1.0.0.1", "1.0.1", 0 },
+    { "1.0.0",   "1.1.0", 0 },
+    { "1.0.0-",  "1.1.0", 0 },
+    { "1.0.0-1", "1.1.0", 0 },
+    { "1.0.0.1", "1.1.0", 0 },
+
+    { "1.0.0",   "1.0.0-", 1 },
+    { "1.0.0",   "1.0.0-1", 1 },
+    { "1.0.0",   "1.0.0.1", 1 },
+    { "1.1.0",   "1.0.0", 1 },
+    { "1.1.1",   "1.1.0", 1 },
+    { "1.1.2",   "1.1.2", 1 },
+    { "1.1.2",   "1.0.2", 1 },
+    { "1.1.2",   "0.0.2", 1 },
+    { "1.1.2",   "1.1.3", 0 },
+
+    { "0.99.1",  "0.9.9", 1 },
+    { "0.9.1",   "0.91.0", 0 },
+
+    { "1.5.3",   "1.5",  1 },
+    { "1.5.0",   "1.5",  1 },
+    { "1.4.99",  "1.5",  0 },
+    { "1.5",     "1.4.99",  1 },
+    { "1.5",     "1.5.0",  1 },
+    { "1.5",     "1.5.1",  0 },
+
+    { "1.5.3-x17",   "1.5-23",  1 },
+
+    { "1.5.3a",   "1.5.3",  1 },
+    { "1.5.3a",   "1.5.3b",  1 },
+
+    { NULL, NULL, 0 }
+  };
+  int idx;
+  int res;
+
+  for (idx=0; idx < DIM(tests); idx++)
+    {
+      res = compare_version_strings (tests[idx].a, tests[idx].b);
+      /* printf ("test %d: '%s'  '%s'  %d  ->  %d\n", */
+      /*         idx, tests[idx].a, tests[idx].b, tests[idx].okay, res); */
+      if (res != tests[idx].okay)
+        fail (idx);
+    }
 }
 
+
 int
 main (int argc, char **argv)
 {
@@ -549,7 +886,10 @@ main (int argc, char **argv)
   test_make_filename_try ();
   test_make_absfilename_try ();
   test_strsplit ();
+  test_strtokenize ();
+  test_compare_version_strings ();
+  test_format_text ();
 
   xfree (home_buffer);
-  return 0;
+  return !!errcount;
 }