]>
git.ipfire.org Git - thirdparty/git.git/blob - t/helper/test-path-utils.c
4 #include "environment.h"
5 #include "string-list.h"
9 * A "string_list_each_func_t" function that normalizes an entry from
10 * GIT_CEILING_DIRECTORIES. If the path is unusable for some reason,
11 * die with an explanation.
13 static int normalize_ceiling_entry(struct string_list_item
*item
,
16 char *ceil
= item
->string
;
19 die("Empty path is not supported");
20 if (!is_absolute_path(ceil
))
21 die("Path \"%s\" is not absolute", ceil
);
22 if (normalize_path_copy(ceil
, ceil
) < 0)
23 die("Path \"%s\" could not be normalized", ceil
);
27 static void normalize_argv_string(const char **var
, const char *input
)
29 if (!strcmp(input
, "<null>"))
31 else if (!strcmp(input
, "<empty>"))
36 if (*var
&& (**var
== '<' || **var
== '('))
37 die("Bad value: %s\n", input
);
41 const char *from
; /* input: transform from this ... */
42 const char *to
; /* output: ... to this. */
43 const char *alternative
; /* output: ... or this. */
47 * Compatibility wrappers for OpenBSD, whose basename(3) and dirname(3)
48 * have const parameters.
50 static char *posix_basename(char *path
)
52 return basename(path
);
55 static char *posix_dirname(char *path
)
60 static int test_function(struct test_data
*data
, char *(*func
)(char *input
),
67 for (i
= 0; data
[i
].to
; i
++) {
71 xsnprintf(buffer
, sizeof(buffer
), "%s", data
[i
].from
);
74 if (!strcmp(to
, data
[i
].to
))
76 if (!data
[i
].alternative
)
77 error("FAIL: %s(%s) => '%s' != '%s'\n",
78 funcname
, data
[i
].from
, to
, data
[i
].to
);
79 else if (!strcmp(to
, data
[i
].alternative
))
82 error("FAIL: %s(%s) => '%s' != '%s', '%s'\n",
83 funcname
, data
[i
].from
, to
, data
[i
].to
,
90 static struct test_data basename_data
[] = {
91 /* --- POSIX type paths --- */
99 { "////", "/", "//" },
104 { "/usr/lib", "lib" },
105 { "usr/lib", "lib" },
106 { "usr/lib///", "lib" },
108 #if defined(__MINGW32__) || defined(_MSC_VER)
109 /* --- win32 type paths --- */
111 { "\\usr\\", "usr" },
112 { "\\usr\\\\", "usr" },
113 { "\\usr\\lib", "lib" },
114 { "usr\\lib", "lib" },
115 { "usr\\lib\\\\\\", "lib" },
118 { "C:/usr/", "usr" },
119 { "C:/usr//", "usr" },
120 { "C:/usr/lib", "lib" },
121 { "C:usr/lib", "lib" },
122 { "C:usr/lib///", "lib" },
128 { "\\\\", "\\", "/" },
129 { "\\\\\\", "\\", "/" },
134 static struct test_data dirname_data
[] = {
135 /* --- POSIX type paths --- */
142 { "///", "/", "//" },
143 { "////", "/", "//" },
148 { "/usr/lib", "/usr" },
149 { "usr/lib", "usr" },
150 { "usr/lib///", "usr" },
152 #if defined(__MINGW32__) || defined(_MSC_VER)
153 /* --- win32 type paths --- */
158 { "\\usr\\\\", "\\" },
159 { "\\usr\\lib", "\\usr" },
160 { "usr\\lib", "usr" },
161 { "usr\\lib\\\\\\", "usr" },
166 { "C:/usr/", "C:/" },
167 { "C:/usr//", "C:/" },
168 { "C:/usr/lib", "C:/usr" },
169 { "C:usr/lib", "C:usr" },
170 { "C:usr/lib///", "C:usr" },
172 { "\\\\\\\\", "\\" },
173 { "C:", "C:.", "." },
178 static int check_dotfile(const char *x
, const char **argv
,
179 int (*is_hfs
)(const char *),
180 int (*is_ntfs
)(const char *))
182 int res
= 0, expect
= 1;
183 for (; *argv
; argv
++) {
184 if (!strcmp("--not", *argv
))
186 else if (expect
!= (is_hfs(*argv
) || is_ntfs(*argv
)))
187 res
= error("'%s' is %s.git%s", *argv
,
188 expect
? "not " : "", x
);
190 fprintf(stderr
, "ok: '%s' is %s.git%s\n",
191 *argv
, expect
? "" : "not ", x
);
196 static int cmp_by_st_size(const void *a
, const void *b
)
198 intptr_t x
= (intptr_t)((struct string_list_item
*)a
)->util
;
199 intptr_t y
= (intptr_t)((struct string_list_item
*)b
)->util
;
201 return x
> y
? -1 : (x
< y
? +1 : 0);
205 * A very simple, reproducible pseudo-random generator. Copied from
206 * `test-genrandom.c`.
208 static uint64_t my_random_value
= 1234;
210 static uint64_t my_random(void)
212 my_random_value
= my_random_value
* 1103515245 + 12345;
213 return my_random_value
;
217 * A fast approximation of the square root, without requiring math.h.
219 * It uses Newton's method to approximate the solution of 0 = x^2 - value.
221 static double my_sqrt(double value
)
223 const double epsilon
= 1e-6;
230 double delta
= (value
/ x
- x
) / 2;
231 if (delta
< epsilon
&& delta
> -epsilon
)
237 static int protect_ntfs_hfs_benchmark(int argc
, const char **argv
)
239 size_t i
, j
, nr
, min_len
= 3, max_len
= 20;
241 int repetitions
= 15, file_mode
= 0100644;
243 double m
[3][2], v
[3][2];
247 if (argc
> 1 && !strcmp(argv
[1], "--with-symlink-mode")) {
253 nr
= argc
> 1 ? strtoul(argv
[1], NULL
, 0) : 1000000;
254 ALLOC_ARRAY(names
, nr
);
257 min_len
= strtoul(argv
[2], NULL
, 0);
259 max_len
= strtoul(argv
[3], NULL
, 0);
260 if (min_len
> max_len
)
261 die("min_len > max_len");
264 for (i
= 0; i
< nr
; i
++) {
265 size_t len
= min_len
+ (my_random() % (max_len
+ 1 - min_len
));
267 names
[i
] = xmallocz(len
);
269 names
[i
][--len
] = (char)(' ' + (my_random() % ('\x7f' - ' ')));
272 for (protect_ntfs
= 0; protect_ntfs
< 2; protect_ntfs
++)
273 for (protect_hfs
= 0; protect_hfs
< 2; protect_hfs
++) {
276 for (i
= 0; i
< repetitions
; i
++) {
277 begin
= getnanotime();
278 for (j
= 0; j
< nr
; j
++)
279 verify_path(names
[j
], file_mode
);
281 printf("protect_ntfs = %d, protect_hfs = %d: %lfms\n", protect_ntfs
, protect_hfs
, (end
-begin
) / (double)1e6
);
282 cumul
+= end
- begin
;
283 cumul2
+= (end
- begin
) * (end
- begin
);
285 m
[protect_ntfs
][protect_hfs
] = cumul
/ (double)repetitions
;
286 v
[protect_ntfs
][protect_hfs
] = my_sqrt(cumul2
/ (double)repetitions
- m
[protect_ntfs
][protect_hfs
] * m
[protect_ntfs
][protect_hfs
]);
287 printf("mean: %lfms, stddev: %lfms\n", m
[protect_ntfs
][protect_hfs
] / (double)1e6
, v
[protect_ntfs
][protect_hfs
] / (double)1e6
);
290 for (protect_ntfs
= 0; protect_ntfs
< 2; protect_ntfs
++)
291 for (protect_hfs
= 0; protect_hfs
< 2; protect_hfs
++)
292 printf("ntfs=%d/hfs=%d: %lf%% slower\n", protect_ntfs
, protect_hfs
, (m
[protect_ntfs
][protect_hfs
] - m
[0][0]) * 100 / m
[0][0]);
297 int cmd__path_utils(int argc
, const char **argv
)
299 if (argc
== 3 && !strcmp(argv
[1], "normalize_path_copy")) {
300 char *buf
= xmallocz(strlen(argv
[2]));
301 int rv
= normalize_path_copy(buf
, argv
[2]);
302 puts(rv
? "++failed++" : buf
);
307 if (argc
>= 2 && !strcmp(argv
[1], "real_path")) {
308 struct strbuf realpath
= STRBUF_INIT
;
310 strbuf_realpath(&realpath
, argv
[2], 1);
315 strbuf_release(&realpath
);
319 if (argc
>= 2 && !strcmp(argv
[1], "absolute_path")) {
321 puts(absolute_path(argv
[2]));
328 if (argc
== 4 && !strcmp(argv
[1], "longest_ancestor_length")) {
330 struct string_list ceiling_dirs
= STRING_LIST_INIT_DUP
;
331 char *path
= xstrdup(argv
[2]);
334 * We have to normalize the arguments because under
335 * Windows, bash mangles arguments that look like
336 * absolute POSIX paths or colon-separate lists of
337 * absolute POSIX paths into DOS paths (e.g.,
338 * "/foo:/foo/bar" might be converted to
339 * "D:\Src\msysgit\foo;D:\Src\msysgit\foo\bar"),
340 * whereas longest_ancestor_length() requires paths
341 * that use forward slashes.
343 if (normalize_path_copy(path
, path
))
344 die("Path \"%s\" could not be normalized", argv
[2]);
345 string_list_split(&ceiling_dirs
, argv
[3], PATH_SEP
, -1);
346 filter_string_list(&ceiling_dirs
, 0,
347 normalize_ceiling_entry
, NULL
);
348 len
= longest_ancestor_length(path
, &ceiling_dirs
);
349 string_list_clear(&ceiling_dirs
, 0);
355 if (argc
>= 4 && !strcmp(argv
[1], "prefix_path")) {
356 const char *prefix
= argv
[2];
357 int prefix_len
= strlen(prefix
);
359 setup_git_directory_gently(&nongit_ok
);
361 char *pfx
= prefix_path(prefix
, prefix_len
, argv
[3]);
371 if (argc
== 4 && !strcmp(argv
[1], "strip_path_suffix")) {
372 char *prefix
= strip_path_suffix(argv
[2], argv
[3]);
373 printf("%s\n", prefix
? prefix
: "(null)");
378 if (argc
== 3 && !strcmp(argv
[1], "print_path")) {
383 if (argc
== 4 && !strcmp(argv
[1], "relative_path")) {
384 struct strbuf sb
= STRBUF_INIT
;
385 const char *in
, *prefix
, *rel
;
386 normalize_argv_string(&in
, argv
[2]);
387 normalize_argv_string(&prefix
, argv
[3]);
388 rel
= relative_path(in
, prefix
, &sb
);
392 puts(strlen(rel
) > 0 ? rel
: "(empty)");
397 if (argc
== 2 && !strcmp(argv
[1], "basename"))
398 return test_function(basename_data
, posix_basename
, argv
[1]);
400 if (argc
== 2 && !strcmp(argv
[1], "dirname"))
401 return test_function(dirname_data
, posix_dirname
, argv
[1]);
403 if (argc
> 2 && !strcmp(argv
[1], "is_dotgitmodules")) {
404 return check_dotfile("modules", argv
+ 2,
405 is_hfs_dotgitmodules
,
406 is_ntfs_dotgitmodules
);
408 if (argc
> 2 && !strcmp(argv
[1], "is_dotgitignore")) {
409 return check_dotfile("ignore", argv
+ 2,
411 is_ntfs_dotgitignore
);
413 if (argc
> 2 && !strcmp(argv
[1], "is_dotgitattributes")) {
414 return check_dotfile("attributes", argv
+ 2,
415 is_hfs_dotgitattributes
,
416 is_ntfs_dotgitattributes
);
418 if (argc
> 2 && !strcmp(argv
[1], "is_dotmailmap")) {
419 return check_dotfile("mailmap", argv
+ 2,
424 if (argc
> 2 && !strcmp(argv
[1], "file-size")) {
428 for (i
= 2; i
< argc
; i
++)
429 if (stat(argv
[i
], &st
))
430 res
= error_errno("Cannot stat '%s'", argv
[i
]);
432 printf("%"PRIuMAX
"\n", (uintmax_t)st
.st_size
);
436 if (argc
== 4 && !strcmp(argv
[1], "skip-n-bytes")) {
437 int fd
= open(argv
[2], O_RDONLY
), offset
= atoi(argv
[3]);
441 die_errno("could not open '%s'", argv
[2]);
442 if (lseek(fd
, offset
, SEEK_SET
) < 0)
443 die_errno("could not skip %d bytes", offset
);
445 ssize_t count
= read(fd
, buffer
, sizeof(buffer
));
447 die_errno("could not read '%s'", argv
[2]);
450 if (write(1, buffer
, count
) < 0)
451 die_errno("could not write to stdout");
457 if (argc
> 5 && !strcmp(argv
[1], "slice-tests")) {
459 long offset
, stride
, i
;
460 struct string_list list
= STRING_LIST_INIT_NODUP
;
463 offset
= strtol(argv
[2], NULL
, 10);
464 stride
= strtol(argv
[3], NULL
, 10);
467 for (i
= 4; i
< argc
; i
++)
468 if (stat(argv
[i
], &st
))
469 res
= error_errno("Cannot stat '%s'", argv
[i
]);
471 string_list_append(&list
, argv
[i
])->util
=
472 (void *)(intptr_t)st
.st_size
;
473 QSORT(list
.items
, list
.nr
, cmp_by_st_size
);
474 for (i
= offset
; i
< list
.nr
; i
+= stride
)
475 printf("%s\n", list
.items
[i
].string
);
480 if (argc
> 1 && !strcmp(argv
[1], "protect_ntfs_hfs"))
481 return !!protect_ntfs_hfs_benchmark(argc
- 1, argv
+ 1);
483 if (argc
> 1 && !strcmp(argv
[1], "is_valid_path")) {
484 int res
= 0, expect
= 1, i
;
486 for (i
= 2; i
< argc
; i
++)
487 if (!strcmp("--not", argv
[i
]))
489 else if (expect
!= is_valid_path(argv
[i
]))
490 res
= error("'%s' is%s a valid path",
491 argv
[i
], expect
? " not" : "");
494 "'%s' is%s a valid path\n",
495 argv
[i
], expect
? "" : " not");
500 fprintf(stderr
, "%s: unknown function name: %s\n", argv
[0],
501 argv
[1] ? argv
[1] : "(there was none)");