This patch doesn't say anything about whether we wanted or now want the design 
of *_is_canonical() and *_canonicalize() to be such that 
is_canonical(canonicalize(path)) is always true. I present this for interested 
parties to play with and make progress.

Sample outputs:
[[[
DBG: dirent_uri-test.c:1191: non-c. dirent: 'O:.' -> 'O:.'
DBG: dirent_uri-test.c:1191: non-c. dirent: './v:' -> 'v:'
DBG: dirent_uri-test.c:1198: non-c. URI: 'u9' -> 'u9'
...
DBG: dirent_uri-test.c:1180: f='/hxDC7/'
lt-dirent_uri-test: 
/home/julianfoad/src/subversion-fsrepli/subversion/libsvn_subr/dirent_uri.c:322:
 canonicalize: Assertion `*src != '/'' failed.
]]]

To get the dirent failures I forcibly defined SVN_USE_DOS_PATHS in 
libsvn_subr/dirent_uri.c.

For whatever invariants we do decide should hold, it would be beneficial to 
have such a test in place.

The relpath_* functions do currently seem to obey this invariant, so I suggest 
we commit at least the relpath part of this, if we agree that's intended 
behaviour.

-- 
- Julian
Proof of concept: add random testing of is_canonical(canonicalize(path)).

Sample outputs:
[[[
DBG: dirent_uri-test.c:1191: non-c. dirent: 'O:.' -> 'O:.'
DBG: dirent_uri-test.c:1191: non-c. dirent: './v:' -> 'v:'
DBG: dirent_uri-test.c:1198: non-c. URI: 'u9' -> 'u9'
...
DBG: dirent_uri-test.c:1180: f='/hxDC7/'
lt-dirent_uri-test: /home/julianfoad/src/subversion-fsrepli/subversion/libsvn_subr/dirent_uri.c:322: canonicalize: Assertion `*src != '/'' failed.
]]]

* subversion/tests/libsvn_subr/dirent_uri-test.c
  (random_filename): New.
  (test_dirent_is_canonical_random): New test.
  (test_funcs): Run it.
--This line, and those below, will be ignored--

Index: subversion/tests/libsvn_subr/dirent_uri-test.c
===================================================================
--- subversion/tests/libsvn_subr/dirent_uri-test.c	(revision 1848853)
+++ subversion/tests/libsvn_subr/dirent_uri-test.c	(working copy)
@@ -1129,12 +1129,89 @@ test_dirent_is_canonical(apr_pool_t *poo
                                  canonicalized);
     }
 
   return SVN_NO_ERROR;
 }
 
+/*  */
+static char *
+random_filename(void)
+{
+  static char s[10];
+  int len = (long)rand() * 9 / RAND_MAX;
+  int i;
+
+  for (i = 0; i < len; ++i)
+    {
+      float r1 = (float)rand() / RAND_MAX;
+      float r2 = (float)rand() / RAND_MAX;
+      char c;
+
+      if (r1 < 0.2)  /* about 1 in 5: special path chars */
+        {
+          c = "/:"[(int)(r2 * 1.2)];
+        }
+      else if (r1 < 0.3)
+        {
+          c = (char)(r2 * 32);  /* about 1 in 10: control chars */
+          if (c == 0) c = 127;
+        }
+      else
+        {
+          c = (char)(32 + r2 * 95);  /* the rest: printable ASCII chars */
+        }
+      s[i] = c;
+    }
+  s[i] = '\0';
+
+  return s;
+}
+
+static svn_error_t *
+test_dirent_is_canonical_random(apr_pool_t *pool)
+{
+  int tries = 1000000;
+  int i;
+
+  for (i = 0; i < tries; ++i)
+    {
+      const char *f = random_filename();
+      const char *ized;
+
+      /*SVN_DBG(("f='%s'", f));*/
+      ized = svn_relpath_canonicalize(f, pool);
+      if (!svn_relpath_is_canonical(ized))
+        {
+          SVN_DBG(("non-c. relpath: '%s' -> '%s'", f, ized));
+          /*SVN_TEST_ASSERT(svn_relpath_is_canonical(
+                            svn_relpath_canonicalize(f, pool)));*/
+        }
+      ized = svn_dirent_canonicalize(f, pool);
+      if (!svn_dirent_is_canonical(ized, pool))
+        {
+          SVN_DBG(("non-c. dirent: '%s' -> '%s'", f, ized));
+          /*SVN_TEST_ASSERT(svn_dirent_is_canonical(
+                            svn_dirent_canonicalize(f, pool), pool));*/
+        }
+#if 0  /* URI fails in many cases, and svn_uri_canonicalize assertion-fails
+          when input begins with '/' */
+      ized = svn_uri_canonicalize(f, pool);
+      if (!svn_uri_is_canonical(ized, pool))
+        {
+          SVN_DBG(("non-c. URI: '%s' -> '%s'", f, ized));
+          /*SVN_TEST_ASSERT(svn_uri_is_canonical(
+                            svn_uri_canonicalize(f, pool), pool));*/
+        }
+#endif
+    }
+
+  return SVN_NO_ERROR;
+}
+
+#undef SVN_USE_DOS_PATHS
+
 static svn_error_t *
 test_relpath_is_canonical(apr_pool_t *pool)
 {
   const testcase_is_canonical_t *t;
   static const testcase_is_canonical_t tests[] = {
     { "",                      TRUE },
@@ -3016,10 +3093,12 @@ static struct svn_test_descriptor_t test
     SVN_TEST_PASS2(test_fspath_get_longest_ancestor,
                    "test svn_fspath__get_longest_ancestor"),
     SVN_TEST_PASS2(test_cert_match_dns_identity,
                    "test svn_cert__match_dns_identity"),
     SVN_TEST_XFAIL2(test_rule3,
                     "test match with RFC 6125 s. 6.4.3 Rule 3"),
+    SVN_TEST_PASS2(test_dirent_is_canonical_random,
+                   "test dirent_is_canonical random"),
     SVN_TEST_NULL
   };
 
 SVN_TEST_MAIN

Reply via email to