Fix compiler warning due to missing function prototype.
[svn.git] / subversion / tests / libsvn_subr / path-test.c
blob9ee598f8e5459456b7306e86d669c914cb49967b
1 /*
2 * path-test.c -- test the path functions
4 * ====================================================================
5 * Copyright (c) 2000-2006 CollabNet. All rights reserved.
7 * This software is licensed as described in the file COPYING, which
8 * you should have received as part of this distribution. The terms
9 * are also available at http://subversion.tigris.org/license-1.html.
10 * If newer versions of this license are posted there, you may use a
11 * newer version instead, at your option.
13 * This software consists of voluntary contributions made by many
14 * individuals. For exact contribution history, see the revision
15 * history and logs, available at http://subversion.tigris.org/.
16 * ====================================================================
19 #include <stdio.h>
20 #include <string.h>
21 #include "svn_pools.h"
22 #include "svn_path.h"
23 #include <apr_general.h>
25 #include "../svn_test.h"
27 /* Using a symbol, because I tried experimenting with different
28 representations */
29 #define SVN_EMPTY_PATH ""
31 static svn_error_t *
32 test_path_is_child(const char **msg,
33 svn_boolean_t msg_only,
34 svn_test_opts_t *opts,
35 apr_pool_t *pool)
37 int i, j;
39 /* The path checking code is platform specific, so we shouldn't run
40 the Windows path handling testcases on non-Windows platforms.
42 #define NUM_TEST_PATHS 11
44 static const char * const paths[NUM_TEST_PATHS] = {
45 "/foo/bar",
46 "/foo/bars",
47 "/foo/baz",
48 "/foo/bar/baz",
49 "/flu/blar/blaz",
50 "/foo/bar/baz/bing/boom",
51 SVN_EMPTY_PATH,
52 "foo",
53 ".foo",
54 "/",
55 "foo2",
58 static const char * const remainders[NUM_TEST_PATHS][NUM_TEST_PATHS] = {
59 { 0, 0, 0, "baz", 0, "baz/bing/boom", 0, 0, 0, 0, 0 },
60 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
61 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
62 { 0, 0, 0, 0, 0, "bing/boom", 0, 0, 0, 0, 0 },
63 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
64 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
65 { 0, 0, 0, 0, 0, 0, 0, "foo", ".foo", 0, "foo2" },
66 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
67 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
68 { "foo/bar", "foo/bars", "foo/baz", "foo/bar/baz", "flu/blar/blaz",
69 "foo/bar/baz/bing/boom", 0, 0, 0, 0, 0 },
70 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
73 *msg = "test svn_path_is_child";
75 if (msg_only)
76 return SVN_NO_ERROR;
78 for (i = 0; i < NUM_TEST_PATHS; i++)
80 for (j = 0; j < NUM_TEST_PATHS; j++)
82 const char *remainder;
84 remainder = svn_path_is_child(paths[i], paths[j], pool);
86 if (((remainder) && (! remainders[i][j]))
87 || ((! remainder) && (remainders[i][j]))
88 || (remainder && strcmp(remainder, remainders[i][j])))
89 return svn_error_createf
90 (SVN_ERR_TEST_FAILED, NULL,
91 "svn_path_is_child (%s, %s) returned '%s' instead of '%s'",
92 paths[i], paths[j],
93 remainder ? remainder : "(null)",
94 remainders[i][j] ? remainders[i][j] : "(null)" );
97 #undef NUM_TEST_PATHS
98 return SVN_NO_ERROR;
102 static svn_error_t *
103 test_path_split(const char **msg,
104 svn_boolean_t msg_only,
105 svn_test_opts_t *opts,
106 apr_pool_t *pool)
108 apr_size_t i;
110 static const char * const paths[][3] = {
111 { "/foo/bar", "/foo", "bar" },
112 { "/foo/bar/ ", "/foo/bar", " " },
113 { "/foo", "/", "foo" },
114 { "foo", SVN_EMPTY_PATH, "foo" },
115 { ".bar", SVN_EMPTY_PATH, ".bar" },
116 { "/.bar", "/", ".bar" },
117 { "foo/bar", "foo", "bar" },
118 { "/foo/bar", "/foo", "bar" },
119 { "foo/bar", "foo", "bar" },
120 { "foo./.bar", "foo.", ".bar" },
121 { "../foo", "..", "foo" },
122 { SVN_EMPTY_PATH, SVN_EMPTY_PATH, SVN_EMPTY_PATH },
123 { "/flu\\b/\\blarg", "/flu\\b", "\\blarg" },
124 { "/", "/", "/" },
127 *msg = "test svn_path_split";
129 if (msg_only)
130 return SVN_NO_ERROR;
132 for (i = 0; i < sizeof(paths) / sizeof(paths[0]); i++)
134 const char *dir, *base_name;
136 svn_path_split(paths[i][0], &dir, &base_name, pool);
137 if (strcmp(dir, paths[i][1]))
139 return svn_error_createf
140 (SVN_ERR_TEST_FAILED, NULL,
141 "svn_path_split (%s) returned dirname '%s' instead of '%s'",
142 paths[i][0], dir, paths[i][1]);
144 if (strcmp(base_name, paths[i][2]))
146 return svn_error_createf
147 (SVN_ERR_TEST_FAILED, NULL,
148 "svn_path_split (%s) returned basename '%s' instead of '%s'",
149 paths[i][0], base_name, paths[i][2]);
152 return SVN_NO_ERROR;
156 static svn_error_t *
157 test_is_url(const char **msg,
158 svn_boolean_t msg_only,
159 svn_test_opts_t *opts,
160 apr_pool_t *pool)
162 apr_size_t i;
164 /* Paths to test and their expected results. */
165 struct {
166 const char *path;
167 svn_boolean_t result;
168 } tests[] = {
169 { "", FALSE },
170 { "/blah/blah", FALSE },
171 { "//blah/blah", FALSE },
172 { "://blah/blah", FALSE },
173 { "a:abb://boo/", FALSE },
174 { "http://svn.collab.net/repos/svn", TRUE },
175 { "scheme/with", FALSE },
176 { "scheme/with:", FALSE },
177 { "scheme/with:/", FALSE },
178 { "scheme/with://", FALSE },
179 { "scheme/with://slash/", FALSE },
180 { "file:///path/to/repository", TRUE },
181 { "file://", TRUE },
182 { "file:/", FALSE },
183 { "file:", FALSE },
184 { "file", FALSE },
187 *msg = "test svn_path_is_url";
189 if (msg_only)
190 return SVN_NO_ERROR;
192 for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++)
194 svn_boolean_t retval;
196 retval = svn_path_is_url(tests[i].path);
197 if (tests[i].result != retval)
198 return svn_error_createf
199 (SVN_ERR_TEST_FAILED, NULL,
200 "svn_path_is_url (%s) returned %s instead of %s",
201 tests[i].path, retval ? "TRUE" : "FALSE",
202 tests[i].result ? "TRUE" : "FALSE");
205 return SVN_NO_ERROR;
209 static svn_error_t *
210 test_is_uri_safe(const char **msg,
211 svn_boolean_t msg_only,
212 svn_test_opts_t *opts,
213 apr_pool_t *pool)
215 apr_size_t i;
217 /* Paths to test and their expected results. */
218 struct {
219 const char *path;
220 svn_boolean_t result;
221 } tests[] = {
222 { "http://svn.collab.net/repos", TRUE },
223 { "http://svn.collab.net/repos%", FALSE },
224 { "http://svn.collab.net/repos%/svn", FALSE },
225 { "http://svn.collab.net/repos%2g", FALSE },
226 { "http://svn.collab.net/repos%2g/svn", FALSE },
227 { "http://svn.collab.net/repos%%", FALSE },
228 { "http://svn.collab.net/repos%%/svn", FALSE },
229 { "http://svn.collab.net/repos%2a", TRUE },
230 { "http://svn.collab.net/repos%2a/svn", TRUE },
233 *msg = "test svn_path_is_uri_safe";
235 if (msg_only)
236 return SVN_NO_ERROR;
238 for (i = 0; i < (sizeof(tests) / sizeof(tests[0])); i++)
240 svn_boolean_t retval;
242 retval = svn_path_is_uri_safe(tests[i].path);
243 if (tests[i].result != retval)
244 return svn_error_createf
245 (SVN_ERR_TEST_FAILED, NULL,
246 "svn_path_is_uri_safe (%s) returned %s instead of %s",
247 tests[i].path, retval ? "TRUE" : "FALSE",
248 tests[i].result ? "TRUE" : "FALSE");
251 return SVN_NO_ERROR;
255 static svn_error_t *
256 test_uri_encode(const char **msg,
257 svn_boolean_t msg_only,
258 svn_test_opts_t *opts,
259 apr_pool_t *pool)
261 int i;
263 struct {
264 const char *path;
265 const char *result;
266 } tests[] = {
267 { "http://subversion.tigris.org",
268 "http://subversion.tigris.org"},
269 { " special_at_beginning",
270 "%20special_at_beginning" },
271 { "special_at_end ",
272 "special_at_end%20" },
273 { "special in middle",
274 "special%20in%20middle" },
275 { "\"Ouch!\" \"Did that hurt?\"",
276 "%22Ouch!%22%20%20%22Did%20that%20hurt%3F%22" }
279 *msg = "test svn_path_uri_[en/de]code";
281 if (msg_only)
282 return SVN_NO_ERROR;
284 for (i = 0; i < 5; i++)
286 const char *en_path, *de_path;
288 /* URI-encode the path, and verify the results. */
289 en_path = svn_path_uri_encode(tests[i].path, pool);
290 if (strcmp(en_path, tests[i].result))
292 return svn_error_createf
293 (SVN_ERR_TEST_FAILED, NULL,
294 "svn_path_uri_encode ('%s') returned '%s' instead of '%s'",
295 tests[i].path, en_path, tests[i].result);
298 /* URI-decode the path, and make sure we're back where we started. */
299 de_path = svn_path_uri_decode(en_path, pool);
300 if (strcmp(de_path, tests[i].path))
302 return svn_error_createf
303 (SVN_ERR_TEST_FAILED, NULL,
304 "svn_path_uri_decode ('%s') returned '%s' instead of '%s'",
305 tests[i].result, de_path, tests[i].path);
308 return SVN_NO_ERROR;
312 static svn_error_t *
313 test_uri_decode(const char **msg,
314 svn_boolean_t msg_only,
315 svn_test_opts_t *opts,
316 apr_pool_t *pool)
318 int i;
320 struct {
321 const char *path;
322 const char *result;
323 } tests[] = {
324 { "http://c.r.a/s%\0008me",
325 "http://c.r.a/s%"},
326 { "http://c.r.a/s%6\000me",
327 "http://c.r.a/s%6" },
328 { "http://c.r.a/s%68me",
329 "http://c.r.a/shme" },
332 *msg = "test svn_path_uri_decode with invalid escape";
334 if (msg_only)
335 return SVN_NO_ERROR;
337 for (i = 0; i < 3; i++)
339 const char *de_path;
341 /* URI-decode the path, and verify the results. */
342 de_path = svn_path_uri_decode(tests[i].path, pool);
343 if (strcmp(de_path, tests[i].result))
345 return svn_error_createf
346 (SVN_ERR_TEST_FAILED, NULL,
347 "svn_path_uri_decode ('%s') returned '%s' instead of '%s'",
348 tests[i].path, de_path, tests[i].result);
351 return SVN_NO_ERROR;
355 static svn_error_t *
356 test_uri_autoescape(const char **msg,
357 svn_boolean_t msg_only,
358 svn_test_opts_t *opts,
359 apr_pool_t *pool)
361 struct {
362 const char *path;
363 const char *result;
364 } tests[] = {
365 { "http://svn.collab.net/", "http://svn.collab.net/" },
366 { "file:///<>\" {}|\\^`", "file:///%3C%3E%22%20%7B%7D%7C%5C%5E%60" },
367 { "http://[::1]", "http://[::1]" }
369 int i;
371 *msg = "test svn_path_uri_autoescape";
373 if (msg_only)
374 return SVN_NO_ERROR;
376 for (i = 0; i < 3; ++i)
378 const char* uri = svn_path_uri_autoescape(tests[i].path, pool);
379 if (strcmp(uri, tests[i].result) != 0)
380 return svn_error_createf
381 (SVN_ERR_TEST_FAILED, NULL,
382 "svn_path_uri_autoescape on '%s' returned '%s' instead of '%s'",
383 tests[i].path, uri, tests[i].result);
384 if (strcmp(tests[i].path, tests[i].result) == 0
385 && tests[i].path != uri)
386 return svn_error_createf
387 (SVN_ERR_TEST_FAILED, NULL,
388 "svn_path_uri_autoescape on '%s' returned identical but not same"
389 " string", tests[i].path);
392 return SVN_NO_ERROR;
395 static svn_error_t *
396 test_uri_from_iri(const char **msg,
397 svn_boolean_t msg_only,
398 svn_test_opts_t *opts,
399 apr_pool_t *pool)
401 /* We have to code the IRIs like this because the compiler might translate
402 character and string literals outside of ASCII to some character set,
403 but here we are hard-coding UTF-8. But we all read UTF-8 codes like
404 poetry, don't we. */
405 static const char p1[] = {
406 '\x66', '\x69', '\x6C', '\x65', '\x3A', '\x2F', '\x2F', '\x2F',
407 '\x72', '\xC3', '\xA4', '\x6B', '\x73', '\x6D', '\xC3', '\xB6', '\x72',
408 '\x67', '\xC3', '\xA5', '\x73', '\0' };
409 static const char p2[] = {
410 '\x66', '\x69', '\x6C', '\x65', '\x3A', '\x2F', '\x2F', '\x2F',
411 '\x61', '\x62', '\x25', '\x32', '\x30', '\x63', '\x64', '\0' };
412 static const char *paths[2][2] = {
413 { p1,
414 "file:///r%C3%A4ksm%C3%B6rg%C3%A5s" },
415 { p2,
416 "file:///ab%20cd" }
418 int i;
420 *msg = "test svn_path_uri_from_iri";
422 if (msg_only)
423 return SVN_NO_ERROR;
425 for (i = 0; i < 2; ++i)
427 const char *uri = svn_path_uri_from_iri(paths[i][0], pool);
428 if (strcmp(paths[i][1], uri) != 0)
429 return svn_error_createf
430 (SVN_ERR_TEST_FAILED, NULL,
431 "svn_path_uri_from_iri on '%s' returned '%s' instead of '%s'",
432 paths[i][0], uri, paths[i][1]);
433 if (strcmp(paths[i][0], uri) == 0
434 && paths[i][0] != uri)
435 return svn_error_createf
436 (SVN_ERR_TEST_FAILED, NULL,
437 "svn_path_uri_from_iri on '%s' returned identical but not same"
438 " string", paths[i][0]);
441 return SVN_NO_ERROR;
444 static svn_error_t *
445 test_join(const char **msg,
446 svn_boolean_t msg_only,
447 svn_test_opts_t *opts,
448 apr_pool_t *pool)
450 int i;
451 char *result;
453 static const char * const joins[][3] = {
454 { "abc", "def", "abc/def" },
455 { "a", "def", "a/def" },
456 { "a", "d", "a/d" },
457 { "/", "d", "/d" },
458 { "/abc", "d", "/abc/d" },
459 { "/abc", "def", "/abc/def" },
460 { "/abc", "/def", "/def" },
461 { "/abc", "/d", "/d" },
462 { "/abc", "/", "/" },
463 { SVN_EMPTY_PATH, "/", "/" },
464 { "/", SVN_EMPTY_PATH, "/" },
465 { SVN_EMPTY_PATH, "abc", "abc" },
466 { "abc", SVN_EMPTY_PATH, "abc" },
467 { SVN_EMPTY_PATH, "/abc", "/abc" },
468 { SVN_EMPTY_PATH, SVN_EMPTY_PATH, SVN_EMPTY_PATH },
471 *msg = "test svn_path_join(_many)";
472 if (msg_only)
473 return SVN_NO_ERROR;
475 for (i = sizeof(joins) / sizeof(joins[0]); i--; )
477 const char *base = joins[i][0];
478 const char *comp = joins[i][1];
479 const char *expect = joins[i][2];
481 result = svn_path_join(base, comp, pool);
482 if (strcmp(result, expect))
483 return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
484 "svn_path_join(\"%s\", \"%s\") returned "
485 "\"%s\". expected \"%s\"",
486 base, comp, result, expect);
488 result = svn_path_join_many(pool, base, comp, NULL);
489 if (strcmp(result, expect))
490 return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
491 "svn_path_join_many(\"%s\", \"%s\") returned "
492 "\"%s\". expected \"%s\"",
493 base, comp, result, expect);
496 #define TEST_MANY(args, expect) \
497 result = svn_path_join_many args ; \
498 if (strcmp(result, expect) != 0) \
499 return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, \
500 "svn_path_join_many" #args " returns \"%s\". " \
501 "expected \"%s\"", \
502 result, expect); \
503 else
505 TEST_MANY((pool, "abc", NULL), "abc");
506 TEST_MANY((pool, "/abc", NULL), "/abc");
507 TEST_MANY((pool, "/", NULL), "/");
509 TEST_MANY((pool, "abc", "def", "ghi", NULL), "abc/def/ghi");
510 TEST_MANY((pool, "abc", "/def", "ghi", NULL), "/def/ghi");
511 TEST_MANY((pool, "/abc", "def", "ghi", NULL), "/abc/def/ghi");
512 TEST_MANY((pool, "abc", "def", "/ghi", NULL), "/ghi");
513 TEST_MANY((pool, "/", "def", "/ghi", NULL), "/ghi");
514 TEST_MANY((pool, "/", "/def", "/ghi", NULL), "/ghi");
516 TEST_MANY((pool, SVN_EMPTY_PATH, "def", "ghi", NULL), "def/ghi");
517 TEST_MANY((pool, "abc", SVN_EMPTY_PATH, "ghi", NULL), "abc/ghi");
518 TEST_MANY((pool, "abc", "def", SVN_EMPTY_PATH, NULL), "abc/def");
519 TEST_MANY((pool, SVN_EMPTY_PATH, "def", SVN_EMPTY_PATH, NULL), "def");
520 TEST_MANY((pool, SVN_EMPTY_PATH, SVN_EMPTY_PATH, "ghi", NULL), "ghi");
521 TEST_MANY((pool, "abc", SVN_EMPTY_PATH, SVN_EMPTY_PATH, NULL), "abc");
522 TEST_MANY((pool, SVN_EMPTY_PATH, "def", "/ghi", NULL), "/ghi");
523 TEST_MANY((pool, SVN_EMPTY_PATH, SVN_EMPTY_PATH, "/ghi", NULL), "/ghi");
525 TEST_MANY((pool, "/", "def", "ghi", NULL), "/def/ghi");
526 TEST_MANY((pool, "abc", "/", "ghi", NULL), "/ghi");
527 TEST_MANY((pool, "abc", "def", "/", NULL), "/");
528 TEST_MANY((pool, "/", "/", "ghi", NULL), "/ghi");
529 TEST_MANY((pool, "/", "/", "/", NULL), "/");
530 TEST_MANY((pool, "/", SVN_EMPTY_PATH, "ghi", NULL), "/ghi");
531 TEST_MANY((pool, "/", "def", SVN_EMPTY_PATH, NULL), "/def");
532 TEST_MANY((pool, SVN_EMPTY_PATH, "/", "ghi", NULL), "/ghi");
533 TEST_MANY((pool, "/", SVN_EMPTY_PATH, SVN_EMPTY_PATH, NULL), "/");
534 TEST_MANY((pool, SVN_EMPTY_PATH, "/", SVN_EMPTY_PATH, NULL), "/");
535 TEST_MANY((pool, SVN_EMPTY_PATH, SVN_EMPTY_PATH, "/", NULL), "/");
537 /* ### probably need quite a few more tests... */
539 return SVN_NO_ERROR;
543 static svn_error_t *
544 test_basename(const char **msg,
545 svn_boolean_t msg_only,
546 svn_test_opts_t *opts,
547 apr_pool_t *pool)
549 int i;
550 char *result;
552 struct {
553 const char *path;
554 const char *result;
555 } tests[] = {
556 { "abc", "abc" },
557 { "/abc", "abc" },
558 { "/abc", "abc" },
559 { "/x/abc", "abc" },
560 { "/xx/abc", "abc" },
561 { "/xx/abc", "abc" },
562 { "/xx/abc", "abc" },
563 { "a", "a" },
564 { "/a", "a" },
565 { "/b/a", "a" },
566 { "/b/a", "a" },
567 { "/", "/" },
568 { SVN_EMPTY_PATH, SVN_EMPTY_PATH },
571 *msg = "test svn_path_basename";
572 if (msg_only)
573 return SVN_NO_ERROR;
575 for (i = sizeof(tests) / sizeof(tests[0]); i--; )
577 const char *path = tests[i].path;
578 const char *expect = tests[i].result;
580 result = svn_path_basename(path, pool);
581 if (strcmp(result, expect))
582 return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
583 "svn_path_basename(\"%s\") returned "
584 "\"%s\". expected \"%s\"",
585 path, result, expect);
588 return SVN_NO_ERROR;
592 static svn_error_t *
593 test_dirname(const char **msg,
594 svn_boolean_t msg_only,
595 svn_test_opts_t *opts,
596 apr_pool_t *pool)
598 int i;
599 char *result;
601 struct {
602 const char *path;
603 const char *result;
604 } tests[] = {
605 { "abc", "" },
606 { "/abc", "/" },
607 { "/x/abc", "/x" },
608 { "/xx/abc", "/xx" },
609 { "a", "" },
610 { "/a", "/" },
611 { "/b/a", "/b" },
612 { "/", "/" },
613 { SVN_EMPTY_PATH, SVN_EMPTY_PATH },
616 *msg = "test svn_path_dirname";
617 if (msg_only)
618 return SVN_NO_ERROR;
620 for (i = sizeof(tests) / sizeof(tests[0]); i--; )
622 const char *path = tests[i].path;
623 const char *expect = tests[i].result;
625 result = svn_path_dirname(path, pool);
626 if (strcmp(result, expect))
627 return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
628 "svn_path_dirname(\"%s\") returned "
629 "\"%s\". expected \"%s\"",
630 path, result, expect);
633 return SVN_NO_ERROR;
637 static svn_error_t *
638 test_decompose(const char **msg,
639 svn_boolean_t msg_only,
640 svn_test_opts_t *opts,
641 apr_pool_t *pool)
643 static const char * const paths[] = {
644 "/", "/", NULL,
645 "foo", "foo", NULL,
646 "/foo", "/", "foo", NULL,
647 "/foo/bar", "/", "foo", "bar", NULL,
648 "foo/bar", "foo", "bar", NULL,
650 /* Are these canonical? Should the middle bits produce SVN_EMPTY_PATH? */
651 "foo/bar", "foo", "bar", NULL,
652 NULL,
654 int i = 0;
656 *msg = "test svn_path_decompose";
657 if (msg_only)
658 return SVN_NO_ERROR;
660 for (;;)
662 if (! paths[i])
663 break;
664 else
666 apr_array_header_t *components = svn_path_decompose(paths[i], pool);
667 int j;
668 for (j = 0; j < components->nelts; ++j)
670 const char *component = APR_ARRAY_IDX(components,
672 const char*);
673 if (! paths[i+j+1])
674 return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
675 "svn_path_decompose(\"%s\") returned "
676 "unexpected component \"%s\"",
677 paths[i], component);
678 if (strcmp(component, paths[i+j+1]))
679 return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
680 "svn_path_decompose(\"%s\") returned "
681 "\"%s\" expected \"%s\"",
682 paths[i], component, paths[i+j+1]);
684 if (paths[i+j+1])
685 return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
686 "svn_path_decompose(\"%s\") failed "
687 "to return \"%s\"",
688 paths[i], paths[i+j+1]);
689 i += components->nelts + 2;
693 return SVN_NO_ERROR;
696 static svn_error_t *
697 test_canonicalize(const char **msg,
698 svn_boolean_t msg_only,
699 svn_test_opts_t *opts,
700 apr_pool_t *pool)
702 struct {
703 const char *path;
704 const char *result;
705 } tests[] = {
706 { "", "" },
707 { ".", "" },
708 { "/", "/" },
709 { "/.", "/" },
710 { "./", "" },
711 { "./.", "" },
712 { "//", "/" },
713 { "/////", "/" },
714 { "./././.", "" },
715 { "////././.", "/" },
716 { "foo", "foo" },
717 { ".foo", ".foo" },
718 { "foo.", "foo." },
719 { "/foo", "/foo" },
720 { "foo/", "foo" },
721 { "foo./", "foo." },
722 { "foo./.", "foo." },
723 { "foo././/.", "foo." },
724 { "/foo/bar", "/foo/bar" },
725 { "foo/..", "foo/.." },
726 { "foo/../", "foo/.." },
727 { "foo/../.", "foo/.." },
728 { "foo//.//bar", "foo/bar" },
729 { "///foo", "/foo" },
730 { "/.//./.foo", "/.foo" },
731 { ".///.foo", ".foo" },
732 { "../foo", "../foo" },
733 { "../../foo/", "../../foo" },
734 { "../../foo/..", "../../foo/.." },
735 { "/../../", "/../.." },
736 { "http://hst", "http://hst" },
737 { "http://hst/foo/../bar","http://hst/foo/../bar" },
738 { "http://hst/", "http://hst" },
739 { NULL, NULL }
741 int i;
743 *msg = "test svn_path_canonicalize";
744 if (msg_only)
745 return SVN_NO_ERROR;
747 i = 0;
748 while (tests[i].path)
750 const char *canonical = svn_path_canonicalize(tests[i].path, pool);
752 if (strcmp(canonical, tests[i].result))
753 return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
754 "svn_path_canonicalize(\"%s\") returned "
755 "\"%s\" expected \"%s\"",
756 tests[i].path, canonical, tests[i].result);
757 ++i;
760 return SVN_NO_ERROR;
763 static svn_error_t *
764 test_remove_component(const char **msg,
765 svn_boolean_t msg_only,
766 svn_test_opts_t *opts,
767 apr_pool_t *pool)
769 struct {
770 const char *path;
771 const char *result;
772 } tests[] = {
773 { "", "" },
774 { "/", "/" },
775 { "foo", "" },
776 { "foo/bar", "foo" },
777 { "/foo/bar", "/foo" },
778 { "/foo", "/" },
779 { NULL, NULL }
781 int i;
782 svn_stringbuf_t *buf;
784 *msg = "test svn_path_remove_component";
785 if (msg_only)
786 return SVN_NO_ERROR;
788 buf = svn_stringbuf_create("", pool);
790 i = 0;
791 while (tests[i].path)
793 svn_stringbuf_set(buf, tests[i].path);
795 svn_path_remove_component(buf);
797 if (strcmp(buf->data, tests[i].result))
798 return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
799 "svn_path_remove_component(\"%s\") returned "
800 "\"%s\" expected \"%s\"",
801 tests[i].path, buf->data, tests[i].result);
802 ++i;
805 return SVN_NO_ERROR;
808 static svn_error_t *
809 test_is_root(const char **msg,
810 svn_boolean_t msg_only,
811 svn_test_opts_t *opts,
812 apr_pool_t *pool)
814 apr_size_t i;
816 /* Paths to test and their expected results. */
817 struct {
818 const char *path;
819 svn_boolean_t result;
820 } tests[] = {
821 { "/foo/bar", FALSE },
822 { "/foo", FALSE },
823 { "/", TRUE },
824 { "", FALSE },
825 #if defined(WIN32) || defined(__CYGWIN__)
826 { "X:/foo", FALSE },
827 { "X:/", TRUE },
828 { "X:foo", FALSE },
829 { "X:", TRUE },
830 { "//srv/shr", TRUE },
831 { "//srv", TRUE },
832 { "//srv/shr/fld", FALSE },
833 #else /* WIN32 or Cygwin */
834 { "/X:foo", FALSE },
835 { "/X:", FALSE },
836 #endif /* non-WIN32 */
839 *msg = "test svn_dirent_is_root";
841 if (msg_only)
842 return SVN_NO_ERROR;
844 for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++)
846 svn_boolean_t retval;
848 retval = svn_dirent_is_root(tests[i].path, strlen(tests[i].path));
849 if (tests[i].result != retval)
850 return svn_error_createf
851 (SVN_ERR_TEST_FAILED, NULL,
852 "svn_dirent_is_root (%s) returned %s instead of %s",
853 tests[i].path, retval ? "TRUE" : "FALSE",
854 tests[i].result ? "TRUE" : "FALSE");
857 return SVN_NO_ERROR;
860 static svn_error_t *
861 test_path_check_valid(const char **msg,
862 svn_boolean_t msg_only,
863 svn_test_opts_t *opts,
864 apr_pool_t *pool)
866 apr_size_t i;
868 /* Paths to test and their expected results. */
869 struct {
870 const char *path;
871 svn_boolean_t result;
872 } tests[] = {
873 { "/foo/bar", TRUE },
874 { "/foo", TRUE },
875 { "/", TRUE },
876 { "foo/bar", TRUE },
877 { "foo bar", TRUE },
878 { "foo\7bar", FALSE },
879 { "foo\31bar", FALSE },
880 { "\7foo\31bar", FALSE },
881 { "\7", FALSE },
882 { "", TRUE },
885 *msg = "test svn_path_check_valid";
887 if (msg_only)
888 return SVN_NO_ERROR;
890 for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++)
892 svn_error_t *err = svn_path_check_valid(tests[i].path, pool);
893 svn_boolean_t retval = (err == SVN_NO_ERROR);
895 svn_error_clear(err);
896 if (tests[i].result != retval)
897 return svn_error_createf
898 (SVN_ERR_TEST_FAILED, NULL,
899 "svn_path_check_valid (%s) returned %s instead of %s",
900 tests[i].path, retval ? "TRUE" : "FALSE",
901 tests[i].result ? "TRUE" : "FALSE");
904 return SVN_NO_ERROR;
907 static svn_error_t *
908 test_path_is_ancestor(const char **msg,
909 svn_boolean_t msg_only,
910 svn_test_opts_t *opts,
911 apr_pool_t *pool)
913 apr_size_t i;
915 /* Paths to test and their expected results. */
916 struct {
917 const char *path1;
918 const char *path2;
919 svn_boolean_t result;
920 } tests[] = {
921 { "/foo", "/foo/bar", TRUE},
922 { "/foo/bar", "/foo/bar/", TRUE},
923 { "/", "/foo", TRUE},
924 { SVN_EMPTY_PATH, "foo", TRUE},
925 { SVN_EMPTY_PATH, ".bar", TRUE},
927 { "/.bar", "/", FALSE},
928 { "foo/bar", "foo", FALSE},
929 { "/foo/bar", "/foo", FALSE},
930 { "foo", "foo/bar", TRUE},
931 { "foo.", "foo./.bar", TRUE},
933 { "../foo", "..", FALSE},
934 { SVN_EMPTY_PATH, SVN_EMPTY_PATH, TRUE},
935 { "/", "/", TRUE},
937 { "http://test", "http://test", TRUE},
938 { "http://test", "http://taste", FALSE},
939 { "http://test", "http://test/foo", TRUE},
940 { "http://test", "file://test/foo", FALSE},
941 { "http://test", "http://testF", FALSE},
943 TODO: this testcase fails, showing that svn_path_is_ancestor
944 shouldn't be used on urls. This is related to issue #1711.
946 { "http://", "http://test", FALSE},
950 *msg = "test svn_path_is_ancestor";
952 if (msg_only)
953 return SVN_NO_ERROR;
955 for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++)
957 svn_boolean_t retval;
959 retval = svn_path_is_ancestor(tests[i].path1, tests[i].path2);
960 if (tests[i].result != retval)
961 return svn_error_createf
962 (SVN_ERR_TEST_FAILED, NULL,
963 "svn_path_is_ancestor (%s, %s) returned %s instead of %s",
964 tests[i].path1, tests[i].path2, retval ? "TRUE" : "FALSE",
965 tests[i].result ? "TRUE" : "FALSE");
967 return SVN_NO_ERROR;
970 static svn_error_t *
971 test_is_single_path_component(const char **msg,
972 svn_boolean_t msg_only,
973 svn_test_opts_t *opts,
974 apr_pool_t *pool)
976 apr_size_t i;
978 /* Paths to test and their expected results. */
979 struct {
980 const char *path;
981 svn_boolean_t result;
982 } tests[] = {
983 { "/foo/bar", FALSE },
984 { "/foo", FALSE },
985 { "/", FALSE },
986 { "foo/bar", FALSE },
987 { "foo", TRUE },
988 { ".", TRUE },
989 { "..", FALSE },
990 { "", FALSE },
993 *msg = "test svn_path_is_single_path_component";
995 if (msg_only)
996 return SVN_NO_ERROR;
998 for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++)
1000 svn_boolean_t retval;
1002 retval = svn_path_is_single_path_component(tests[i].path);
1003 if (tests[i].result != retval)
1004 return svn_error_createf
1005 (SVN_ERR_TEST_FAILED, NULL,
1006 "svn_path_is_single_path_component (%s) returned %s instead of %s",
1007 tests[i].path, retval ? "TRUE" : "FALSE",
1008 tests[i].result ? "TRUE" : "FALSE");
1011 return SVN_NO_ERROR;
1014 static svn_error_t *
1015 test_compare_paths(const char **msg,
1016 svn_boolean_t msg_only,
1017 svn_test_opts_t *opts,
1018 apr_pool_t *pool)
1020 apr_size_t i;
1022 /* Paths to test and their expected results. */
1023 struct {
1024 const char *path1;
1025 const char *path2;
1026 int result;
1027 } tests[] = {
1028 { "/foo", "/foo", 0},
1029 { "/foo/bar", "/foo/bar", 0},
1030 { "/", "/", 0},
1031 { SVN_EMPTY_PATH, SVN_EMPTY_PATH, 0},
1032 { "foo", "foo", 0},
1033 { "foo", "foo/bar", -1},
1034 { "foo/bar", "foo/boo", -1},
1035 { "boo", "foo", -1},
1036 { "foo", "boo", 1},
1037 { "foo/bar", "foo", 1},
1038 { "/", "/foo", -1},
1039 { "/foo", "/foo/bar", -1},
1040 { "/foo", "/foo/bar/boo", -1},
1041 { "foo", "/foo", 1},
1042 { "foo\xe0""bar", "foo", 1},
1045 *msg = "test svn_path_compare_paths";
1047 if (msg_only)
1048 return SVN_NO_ERROR;
1050 for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++)
1052 int retval;
1054 retval = svn_path_compare_paths(tests[i].path1, tests[i].path2);
1055 /* tests if expected and actual result are both < 0,
1056 equal to 0 or greater than 0. */
1057 if (! (tests[i].result * retval > 0 ||
1058 (tests[i].result == 0 && retval == 0)) )
1059 return svn_error_createf
1060 (SVN_ERR_TEST_FAILED, NULL,
1061 "svn_path_compare_paths (%s, %s) returned %d instead of %d",
1062 tests[i].path1, tests[i].path2, retval, tests[i].result);
1064 return SVN_NO_ERROR;
1067 static svn_error_t *
1068 test_get_longest_ancestor(const char **msg,
1069 svn_boolean_t msg_only,
1070 svn_test_opts_t *opts,
1071 apr_pool_t *pool)
1073 apr_size_t i;
1075 /* Paths to test and their expected results. */
1076 struct {
1077 const char *path1;
1078 const char *path2;
1079 const char *result;
1080 } tests[] = {
1081 { "/foo", "/foo/bar", "/foo"},
1082 { "/foo/bar", "foo/bar", ""},
1083 { "/", "/foo", "/"},
1084 { SVN_EMPTY_PATH, "foo", SVN_EMPTY_PATH},
1085 { SVN_EMPTY_PATH, ".bar", SVN_EMPTY_PATH},
1086 { "/.bar", "/", "/"},
1087 { "foo/bar", "foo", "foo"},
1088 { "/foo/bar", "/foo", "/foo"},
1089 { "/rif", "/raf", "/"},
1090 { "foo", "foo/bar", "foo"},
1091 { "foo.", "foo./.bar", "foo."},
1092 { SVN_EMPTY_PATH, SVN_EMPTY_PATH, SVN_EMPTY_PATH},
1093 { "/", "/", "/"},
1094 { "http://test", "http://test", "http://test"},
1095 { "http://test", "http://taste", ""},
1096 { "http://test", "http://test/foo", "http://test"},
1097 { "http://test", "file://test/foo", ""},
1098 { "http://test", "http://testF", ""},
1099 { "http://", "http://test", ""},
1102 *msg = "test svn_path_get_longest_ancestor";
1104 if (msg_only)
1105 return SVN_NO_ERROR;
1107 for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++)
1109 const char *retval;
1111 retval = svn_path_get_longest_ancestor(tests[i].path1, tests[i].path2,
1112 pool);
1114 if (strcmp(tests[i].result, retval))
1115 return svn_error_createf
1116 (SVN_ERR_TEST_FAILED, NULL,
1117 "svn_path_get_longest_ancestor (%s, %s) returned %s instead of %s",
1118 tests[i].path1, tests[i].path2, retval, tests[i].result);
1120 /* changing the order of the paths should return the same results */
1121 retval = svn_path_get_longest_ancestor(tests[i].path2, tests[i].path1,
1122 pool);
1124 if (strcmp(tests[i].result, retval))
1125 return svn_error_createf
1126 (SVN_ERR_TEST_FAILED, NULL,
1127 "svn_path_get_longest_ancestor (%s, %s) returned %s instead of %s",
1128 tests[i].path2, tests[i].path1, retval, tests[i].result);
1130 return SVN_NO_ERROR;
1134 static svn_error_t *
1135 test_splitext(const char **msg,
1136 svn_boolean_t msg_only,
1137 svn_test_opts_t *opts,
1138 apr_pool_t *pool)
1140 apr_size_t i;
1141 apr_pool_t *subpool = svn_pool_create(pool);
1143 /* Paths to test and their expected results. */
1144 struct {
1145 const char *path;
1146 const char *path_root;
1147 const char *path_ext;
1148 svn_boolean_t result;
1149 } tests[] = {
1150 { "no-ext", "no-ext", "" },
1151 { "test-file.py", "test-file.", "py" },
1152 { "period.file.ext", "period.file.", "ext" },
1153 { "multi-component/file.txt", "multi-component/file.", "txt" },
1154 { "yep.still/no-ext", "yep.still/no-ext", "" },
1155 { "folder.with/period.log", "folder.with/period.", "log" },
1156 { "period.", "period.", "" },
1157 { "file.ends-with/period.", "file.ends-with/period.", "" },
1158 { "two-periods..txt", "two-periods..", "txt" },
1159 { ".dot-file", ".dot-file", "" },
1160 { "sub/.dot-file", "sub/.dot-file", "" },
1161 { ".dot-file.withext", ".dot-file.", "withext" },
1162 { "sub/.dot-file.withext", "sub/.dot-file.", "withext" },
1163 { "", "", "" },
1166 *msg = "test svn_path_splitext";
1168 if (msg_only)
1169 return SVN_NO_ERROR;
1171 for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++)
1173 const char *path = tests[i].path;
1174 const char *path_root;
1175 const char *path_ext;
1177 svn_pool_clear(subpool);
1179 /* First, we'll try splitting and fetching both root and
1180 extension to see if they match our expected results. */
1181 svn_path_splitext(&path_root, &path_ext, path, subpool);
1182 if ((strcmp(tests[i].path_root, path_root))
1183 || (strcmp(tests[i].path_ext, path_ext)))
1184 return svn_error_createf
1185 (SVN_ERR_TEST_FAILED, NULL,
1186 "svn_path_splitext (%s) returned ('%s', '%s') "
1187 "instead of ('%s', '%s')",
1188 tests[i].path, path_root, path_ext,
1189 tests[i].path_root, tests[i].path_ext);
1191 /* Now, let's only fetch the root. */
1192 svn_path_splitext(&path_root, NULL, path, subpool);
1193 if (strcmp(tests[i].path_root, path_root))
1194 return svn_error_createf
1195 (SVN_ERR_TEST_FAILED, NULL,
1196 "svn_path_splitext (%s) with a NULL path_ext returned '%s' "
1197 "for the path_root instead of '%s'",
1198 tests[i].path, path_root, tests[i].path_root);
1200 /* Next, let's only fetch the extension. */
1201 svn_path_splitext(NULL, &path_ext, path, subpool);
1202 if ((strcmp(tests[i].path_root, path_root))
1203 || (strcmp(tests[i].path_ext, path_ext)))
1204 return svn_error_createf
1205 (SVN_ERR_TEST_FAILED, NULL,
1206 "svn_path_splitext (%s) with a NULL path_root returned '%s' "
1207 "for the path_ext instead of '%s'",
1208 tests[i].path, path_ext, tests[i].path_ext);
1210 svn_pool_destroy(subpool);
1211 return SVN_NO_ERROR;
1215 static svn_error_t *
1216 test_compose(const char **msg,
1217 svn_boolean_t msg_only,
1218 svn_test_opts_t *opts,
1219 apr_pool_t *pool)
1221 static const char * const paths[] = {
1223 "/",
1224 "/foo",
1225 "/foo/bar",
1226 "/foo/bar/baz",
1227 "foo",
1228 "foo/bar",
1229 "foo/bar/baz",
1230 NULL,
1232 const char * const *path_ptr = paths;
1233 const char *input_path;
1235 *msg = "test svn_path_decompose";
1236 if (msg_only)
1237 return SVN_NO_ERROR;
1239 for (input_path = *path_ptr; *path_ptr; input_path = *++path_ptr)
1241 apr_array_header_t *components = svn_path_decompose(input_path, pool);
1242 const char *output_path = svn_path_compose(components, pool);
1244 if (strcmp(input_path, output_path))
1245 return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
1246 "svn_path_compose("
1247 "svn_path_decompose(\"%s\")) "
1248 "returned \"%s\" expected \"%s\"",
1249 input_path, output_path, input_path);
1252 return SVN_NO_ERROR;
1255 /* local define to support XFail-ing tests on Windows/Cygwin only */
1256 #if defined(WIN32) || defined(__CYGWIN__)
1257 #define WINDOWS_OR_CYGWIN TRUE
1258 #else
1259 #define WINDOWS_OR_CYGWIN FALSE
1260 #endif /* WIN32 or Cygwin */
1263 /* The test table. */
1265 struct svn_test_descriptor_t test_funcs[] =
1267 SVN_TEST_NULL,
1268 SVN_TEST_PASS(test_path_is_child),
1269 SVN_TEST_PASS(test_path_split),
1270 SVN_TEST_PASS(test_is_url),
1271 SVN_TEST_PASS(test_is_uri_safe),
1272 SVN_TEST_PASS(test_uri_encode),
1273 SVN_TEST_PASS(test_uri_decode),
1274 SVN_TEST_PASS(test_uri_autoescape),
1275 SVN_TEST_PASS(test_uri_from_iri),
1276 SVN_TEST_PASS(test_join),
1277 SVN_TEST_PASS(test_basename),
1278 SVN_TEST_PASS(test_dirname),
1279 SVN_TEST_PASS(test_decompose),
1280 SVN_TEST_PASS(test_canonicalize),
1281 SVN_TEST_PASS(test_remove_component),
1282 SVN_TEST_PASS(test_is_root),
1283 SVN_TEST_PASS(test_path_is_ancestor),
1284 SVN_TEST_PASS(test_path_check_valid),
1285 SVN_TEST_PASS(test_is_single_path_component),
1286 SVN_TEST_PASS(test_compare_paths),
1287 SVN_TEST_PASS(test_get_longest_ancestor),
1288 SVN_TEST_PASS(test_splitext),
1289 SVN_TEST_PASS(test_compose),
1290 SVN_TEST_NULL