Merge branch 'ls/p4-path-encoding'
[git] / t / helper / test-path-utils.c
1 #include "cache.h"
2 #include "string-list.h"
3
4 /*
5  * A "string_list_each_func_t" function that normalizes an entry from
6  * GIT_CEILING_DIRECTORIES.  If the path is unusable for some reason,
7  * die with an explanation.
8  */
9 static int normalize_ceiling_entry(struct string_list_item *item, void *unused)
10 {
11         char *ceil = item->string;
12
13         if (!*ceil)
14                 die("Empty path is not supported");
15         if (!is_absolute_path(ceil))
16                 die("Path \"%s\" is not absolute", ceil);
17         if (normalize_path_copy(ceil, ceil) < 0)
18                 die("Path \"%s\" could not be normalized", ceil);
19         return 1;
20 }
21
22 static void normalize_argv_string(const char **var, const char *input)
23 {
24         if (!strcmp(input, "<null>"))
25                 *var = NULL;
26         else if (!strcmp(input, "<empty>"))
27                 *var = "";
28         else
29                 *var = input;
30
31         if (*var && (**var == '<' || **var == '('))
32                 die("Bad value: %s\n", input);
33 }
34
35 struct test_data {
36         const char *from;  /* input:  transform from this ... */
37         const char *to;    /* output: ... to this.            */
38         const char *alternative; /* output: ... or this.      */
39 };
40
41 static int test_function(struct test_data *data, char *(*func)(char *input),
42         const char *funcname)
43 {
44         int failed = 0, i;
45         char buffer[1024];
46         char *to;
47
48         for (i = 0; data[i].to; i++) {
49                 if (!data[i].from)
50                         to = func(NULL);
51                 else {
52                         xsnprintf(buffer, sizeof(buffer), "%s", data[i].from);
53                         to = func(buffer);
54                 }
55                 if (!strcmp(to, data[i].to))
56                         continue;
57                 if (!data[i].alternative)
58                         error("FAIL: %s(%s) => '%s' != '%s'\n",
59                                 funcname, data[i].from, to, data[i].to);
60                 else if (!strcmp(to, data[i].alternative))
61                         continue;
62                 else
63                         error("FAIL: %s(%s) => '%s' != '%s', '%s'\n",
64                                 funcname, data[i].from, to, data[i].to,
65                                 data[i].alternative);
66                 failed = 1;
67         }
68         return failed;
69 }
70
71 static struct test_data basename_data[] = {
72         /* --- POSIX type paths --- */
73         { NULL,              "."    },
74         { "",                "."    },
75         { ".",               "."    },
76         { "..",              ".."   },
77         { "/",               "/"    },
78         { "//",              "/", "//" },
79         { "///",             "/", "//" },
80         { "////",            "/", "//" },
81         { "usr",             "usr"  },
82         { "/usr",            "usr"  },
83         { "/usr/",           "usr"  },
84         { "/usr//",          "usr"  },
85         { "/usr/lib",        "lib"  },
86         { "usr/lib",         "lib"  },
87         { "usr/lib///",      "lib"  },
88
89 #if defined(__MINGW32__) || defined(_MSC_VER)
90         /* --- win32 type paths --- */
91         { "\\usr",           "usr"  },
92         { "\\usr\\",         "usr"  },
93         { "\\usr\\\\",       "usr"  },
94         { "\\usr\\lib",      "lib"  },
95         { "usr\\lib",        "lib"  },
96         { "usr\\lib\\\\\\",  "lib"  },
97         { "C:/usr",          "usr"  },
98         { "C:/usr",          "usr"  },
99         { "C:/usr/",         "usr"  },
100         { "C:/usr//",        "usr"  },
101         { "C:/usr/lib",      "lib"  },
102         { "C:usr/lib",       "lib"  },
103         { "C:usr/lib///",    "lib"  },
104         { "C:",              "."    },
105         { "C:a",             "a"    },
106         { "C:/",             "/"    },
107         { "C:///",           "/"    },
108         { "\\",              "\\", "/" },
109         { "\\\\",            "\\", "/" },
110         { "\\\\\\",          "\\", "/" },
111 #endif
112         { NULL,              NULL   }
113 };
114
115 static struct test_data dirname_data[] = {
116         /* --- POSIX type paths --- */
117         { NULL,              "."      },
118         { "",                "."      },
119         { ".",               "."      },
120         { "..",              "."      },
121         { "/",               "/"      },
122         { "//",              "/", "//" },
123         { "///",             "/", "//" },
124         { "////",            "/", "//" },
125         { "usr",             "."      },
126         { "/usr",            "/"      },
127         { "/usr/",           "/"      },
128         { "/usr//",          "/"      },
129         { "/usr/lib",        "/usr"   },
130         { "usr/lib",         "usr"    },
131         { "usr/lib///",      "usr"    },
132
133 #if defined(__MINGW32__) || defined(_MSC_VER)
134         /* --- win32 type paths --- */
135         { "\\",              "\\"     },
136         { "\\\\",            "\\\\"   },
137         { "\\usr",           "\\"     },
138         { "\\usr\\",         "\\"     },
139         { "\\usr\\\\",       "\\"     },
140         { "\\usr\\lib",      "\\usr"  },
141         { "usr\\lib",        "usr"    },
142         { "usr\\lib\\\\\\",  "usr"    },
143         { "C:a",             "C:."    },
144         { "C:/",             "C:/"    },
145         { "C:///",           "C:/"    },
146         { "C:/usr",          "C:/"    },
147         { "C:/usr/",         "C:/"    },
148         { "C:/usr//",        "C:/"    },
149         { "C:/usr/lib",      "C:/usr" },
150         { "C:usr/lib",       "C:usr"  },
151         { "C:usr/lib///",    "C:usr"  },
152         { "\\\\\\",          "\\"     },
153         { "\\\\\\\\",        "\\"     },
154         { "C:",              "C:.", "." },
155 #endif
156         { NULL,              NULL     }
157 };
158
159 int cmd_main(int argc, const char **argv)
160 {
161         if (argc == 3 && !strcmp(argv[1], "normalize_path_copy")) {
162                 char *buf = xmallocz(strlen(argv[2]));
163                 int rv = normalize_path_copy(buf, argv[2]);
164                 if (rv)
165                         buf = "++failed++";
166                 puts(buf);
167                 return 0;
168         }
169
170         if (argc >= 2 && !strcmp(argv[1], "real_path")) {
171                 while (argc > 2) {
172                         puts(real_path(argv[2]));
173                         argc--;
174                         argv++;
175                 }
176                 return 0;
177         }
178
179         if (argc >= 2 && !strcmp(argv[1], "absolute_path")) {
180                 while (argc > 2) {
181                         puts(absolute_path(argv[2]));
182                         argc--;
183                         argv++;
184                 }
185                 return 0;
186         }
187
188         if (argc == 4 && !strcmp(argv[1], "longest_ancestor_length")) {
189                 int len;
190                 struct string_list ceiling_dirs = STRING_LIST_INIT_DUP;
191                 char *path = xstrdup(argv[2]);
192
193                 /*
194                  * We have to normalize the arguments because under
195                  * Windows, bash mangles arguments that look like
196                  * absolute POSIX paths or colon-separate lists of
197                  * absolute POSIX paths into DOS paths (e.g.,
198                  * "/foo:/foo/bar" might be converted to
199                  * "D:\Src\msysgit\foo;D:\Src\msysgit\foo\bar"),
200                  * whereas longest_ancestor_length() requires paths
201                  * that use forward slashes.
202                  */
203                 if (normalize_path_copy(path, path))
204                         die("Path \"%s\" could not be normalized", argv[2]);
205                 string_list_split(&ceiling_dirs, argv[3], PATH_SEP, -1);
206                 filter_string_list(&ceiling_dirs, 0,
207                                    normalize_ceiling_entry, NULL);
208                 len = longest_ancestor_length(path, &ceiling_dirs);
209                 string_list_clear(&ceiling_dirs, 0);
210                 free(path);
211                 printf("%d\n", len);
212                 return 0;
213         }
214
215         if (argc >= 4 && !strcmp(argv[1], "prefix_path")) {
216                 const char *prefix = argv[2];
217                 int prefix_len = strlen(prefix);
218                 int nongit_ok;
219                 setup_git_directory_gently(&nongit_ok);
220                 while (argc > 3) {
221                         puts(prefix_path(prefix, prefix_len, argv[3]));
222                         argc--;
223                         argv++;
224                 }
225                 return 0;
226         }
227
228         if (argc == 4 && !strcmp(argv[1], "strip_path_suffix")) {
229                 char *prefix = strip_path_suffix(argv[2], argv[3]);
230                 printf("%s\n", prefix ? prefix : "(null)");
231                 return 0;
232         }
233
234         if (argc == 3 && !strcmp(argv[1], "print_path")) {
235                 puts(argv[2]);
236                 return 0;
237         }
238
239         if (argc == 4 && !strcmp(argv[1], "relative_path")) {
240                 struct strbuf sb = STRBUF_INIT;
241                 const char *in, *prefix, *rel;
242                 normalize_argv_string(&in, argv[2]);
243                 normalize_argv_string(&prefix, argv[3]);
244                 rel = relative_path(in, prefix, &sb);
245                 if (!rel)
246                         puts("(null)");
247                 else
248                         puts(strlen(rel) > 0 ? rel : "(empty)");
249                 strbuf_release(&sb);
250                 return 0;
251         }
252
253         if (argc == 2 && !strcmp(argv[1], "basename"))
254                 return test_function(basename_data, basename, argv[1]);
255
256         if (argc == 2 && !strcmp(argv[1], "dirname"))
257                 return test_function(dirname_data, dirname, argv[1]);
258
259         fprintf(stderr, "%s: unknown function name: %s\n", argv[0],
260                 argv[1] ? argv[1] : "(there was none)");
261         return 1;
262 }