Blob


1 /*
2 * Copyright (c) 2018, 2019 Stefan Sperling <stsp@openbsd.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
17 #include "got_compat.h"
19 #include <sys/queue.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <unistd.h>
26 #include <err.h>
28 #include "got_error.h"
29 #include "got_path.h"
31 #ifndef nitems
32 #define nitems(_a) (sizeof(_a) / sizeof((_a)[0]))
33 #endif
35 static int verbose;
36 static int quiet;
38 static void
39 test_printf(const char *fmt, ...)
40 {
41 va_list ap;
43 if (!verbose)
44 return;
46 va_start(ap, fmt);
47 vprintf(fmt, ap);
48 va_end(ap);
49 }
51 static int
52 path_cmp(void)
53 {
54 const struct path_cmp_test {
55 const char *path1;
56 const char *path2;
57 int expected;
58 } test_data[] = {
59 { "", "", 0 },
60 { "/", "/", 0 },
61 { "/a", "/b", -1 },
62 { "x/a", "x.a", -1 },
63 { "x.a", "x/a", 1 },
64 { "//foo", "/bar", 1 },
65 { "/foo", "/bar", 1 },
66 { "foo", "bar", 1 },
67 { "/foo/sub", "/bar", 1 },
68 { "/foo", "/bar/sub", 1 },
69 { "/foo/", "/bar", 1 },
70 { "/foo", "/bar/", 1 },
71 { "/foo/", "/bar/", 1 },
72 { "/bar/", "/bar/", 0 },
73 { "/bar/", "/bar", 0 },
74 { "//bar//", "/bar/", 0 },
75 { "//bar//", "/bar////", 0 },
76 { "/bar/sub", "/bar.", -1 },
77 { "/bar/sub", "/bar/", 1 },
78 { "/bar/sub/", "/bar///", 1 },
79 { "/bar/sub/sub2", "/bar/", 1 },
80 { "/bar/sub/sub2", "/bar", 1 },
81 { "/bar.sub.sub2", "/bar", 1 },
82 { "/bar/sub/sub2", "/bar.c", -1 },
83 };
84 size_t i;
86 for (i = 0; i < nitems(test_data); i++) {
87 const char *path1 = test_data[i].path1;
88 const char *path2 = test_data[i].path2;
89 int expected = test_data[i].expected;
90 int cmp = got_path_cmp(path1, path2,
91 strlen(path1), strlen(path2));
93 if (cmp != expected) {
94 test_printf("%d: '%s' vs '%s' == %d; expected %d\n",
95 i, path1, path2, cmp, expected);
96 return 0;
97 }
98 }
100 return 1;
103 const char *path_list_input[] = {
104 "", "/", "a", "/b", "/bar", "bar/sub", "/bar/sub", "/bar/",
105 "/bar.c", "/bar/sub/sub2", "/bar.sub.sub2", "/foo",
106 "/foo/sub", "/foo/", "/foo/", "x/a",
107 };
108 const char *path_list_expected[] = {
109 "",
110 "a",
111 "/b",
112 "/bar",
113 "bar/sub",
114 "/bar/sub/sub2",
115 "/bar.c",
116 "/bar.sub.sub2",
117 "/foo",
118 "/foo/sub",
119 "x/a",
120 };
122 /* If inserting pathlist_input in reverse the result is slightly different. */
123 const char *path_list_expected_reverse[] = {
124 "/",
125 "a",
126 "/b",
127 "/bar/",
128 "/bar/sub",
129 "/bar/sub/sub2",
130 "/bar.c",
131 "/bar.sub.sub2",
132 "/foo/",
133 "/foo/sub",
134 "x/a",
135 };
138 static int
139 path_list(void)
141 const struct got_error *err = NULL;
142 struct got_pathlist_head paths;
143 struct got_pathlist_entry *pe;
144 size_t i;
146 TAILQ_INIT(&paths);
147 for (i = 0; i < nitems(path_list_input); i++) {
148 err = got_pathlist_insert(NULL, &paths, path_list_input[i],
149 NULL);
150 if (err) {
151 test_printf("%s\n", __func__, err->msg);
152 return 0;
156 i = 0;
157 TAILQ_FOREACH(pe, &paths, entry) {
158 test_printf("'%s' -- '%s'\n", pe->path, path_list_expected[i]);
159 if (i >= nitems(path_list_expected)) {
160 test_printf("too many elements on list\n");
161 return 0;
163 if (strcmp(pe->path, path_list_expected[i]) != 0) {
164 test_printf("unordered elements on list\n");
165 return 0;
167 i++;
170 got_pathlist_free(&paths, GOT_PATHLIST_FREE_NONE);
171 return 1;
174 static int
175 path_list_reverse_input(void)
177 const struct got_error *err = NULL;
178 struct got_pathlist_head paths;
179 struct got_pathlist_entry *pe;
180 size_t i;
182 TAILQ_INIT(&paths);
183 for (i = nitems(path_list_input); i > 0;) {
184 err = got_pathlist_insert(NULL, &paths, path_list_input[--i],
185 NULL);
186 if (err) {
187 test_printf("%s\n", __func__, err->msg);
188 return 0;
192 i = 0;
193 TAILQ_FOREACH(pe, &paths, entry) {
194 test_printf("'%s' -- '%s'\n", pe->path,
195 path_list_expected_reverse[i]);
196 if (i >= nitems(path_list_expected_reverse)) {
197 test_printf("too many elements on list\n");
198 return 0;
200 if (strcmp(pe->path, path_list_expected_reverse[i]) != 0) {
201 test_printf("unordered elements on list\n");
202 return 0;
204 i++;
207 got_pathlist_free(&paths, GOT_PATHLIST_FREE_NONE);
208 return 1;
211 #define RUN_TEST(expr, name) \
212 { test_ok = (expr); \
213 if (!quiet) printf("test_%s %s\n", (name), test_ok ? "ok" : "failed"); \
214 failure = (failure || !test_ok); }
216 static void
217 usage(void)
219 fprintf(stderr, "usage: path_test [-v] [-q]\n");
222 int
223 main(int argc, char *argv[])
225 int test_ok = 0, failure = 0;
226 int ch;
228 #ifndef PROFILE
229 if (pledge("stdio", NULL) == -1)
230 err(1, "pledge");
231 #endif
233 while ((ch = getopt(argc, argv, "qv")) != -1) {
234 switch (ch) {
235 case 'q':
236 quiet = 1;
237 verbose = 0;
238 break;
239 case 'v':
240 verbose = 1;
241 quiet = 0;
242 break;
243 default:
244 usage();
245 return 1;
248 argc -= optind;
249 argv += optind;
251 RUN_TEST(path_cmp(), "path_cmp");
252 RUN_TEST(path_list(), "path_list");
253 RUN_TEST(path_list_reverse_input(), "path_list_reverse_input");
255 return failure ? 1 : 0;