1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
| | #include <string.h>
#include <stdlib.h>
#include <glob.h>
#include <stdio.h>
#include "test.h"
glob_t globbuf;
int paths_match(int expected_num, const char **expected) {
if (globbuf.gl_pathc + globbuf.gl_offs != expected_num)
return 0;
for (int i = 0; i < expected_num; ++i) {
if ((globbuf.gl_pathv[i] == NULL) != (expected[i] == NULL))
return 0;
if (expected[i] && strcmp(globbuf.gl_pathv[i], expected[i]) != 0)
return 0;
}
return 1;
}
void print_mismatch(int expected_num, const char **expected) {
t_printf("Expected paths (%d):\n", expected_num);
for (int i = 0; i < expected_num; ++i)
t_printf(" %s\n", expected[i] ? expected[i] : "NULL");
t_printf("Got paths (%d):\n", globbuf.gl_pathc + globbuf.gl_offs);
for (int i = 0; i < globbuf.gl_pathc + globbuf.gl_offs; ++i)
t_printf(" %s\n", globbuf.gl_pathv ? globbuf.gl_pathv[i] : "NULL");
}
#define TEST_NOFREE(pat, flags, expected_ret, ...) do { \
int tflags = flags|extraflags; \
int ret = glob(pat, tflags, NULL, &globbuf); \
const char *e[] = __VA_ARGS__; \
if (ret != expected_ret) \
t_error("glob(\"%s\", %d) failed (return %d, expected %d)\n", \
pat, tflags, ret, expected_ret); \
if (!paths_match(sizeof(e)/sizeof(*e), e)) { \
t_error("glob(\"%s\", %d) returned unexpected paths.\n", \
pat, tflags); \
print_mismatch(sizeof(e)/sizeof(*e), e); \
} \
} while(0)
#define TEST(pat, flags, expected_ret, ...) do { \
TEST_NOFREE(pat, flags, expected_ret, __VA_ARGS__); \
globfree(&globbuf); \
} while(0)
#define TEST_UNMATCH(pat) do { \
if (extraflags & GLOB_NOCHECK) \
TEST(pat, extraflags, 0, {pat}); \
else \
TEST(pat, extraflags, GLOB_NOMATCH, {}); \
} while(0)
#define MARK(str) ((extraflags & GLOB_MARK) ? str "/" : str)
static void do_tests(int extraflags) {
// Check basic functioning of paths
TEST("basic/file", 0,
0, {"basic/file"});
TEST("basic/symlink-file", 0,
0, {"basic/symlink-file"});
TEST("basic/dir", 0,
0, {MARK("basic/dir")});
TEST("basic/symlink-dir", 0,
0, {MARK("basic/symlink-dir")});
// With trailing slash input, always returns a trailing slash
TEST("basic/dir/", 0,
0, {"basic/dir/"});
// And patterns...
TEST("basic/*", 0,
0, {MARK("basic/dir"), "basic/file", MARK("basic/symlink-dir"), "basic/symlink-file"});
TEST("basic/d?r", 0,
0, {MARK("basic/dir")});
TEST("basic/[df]??", 0,
0, {MARK("basic/dir")});
TEST("basic/fi[l]e", 0,
0, {"basic/file"});
TEST("basic/*/", 0,
0, {"basic/dir/", "basic/symlink-dir/"});
TEST("basic/*/*", 0,
0, {"basic/dir/file", "basic/symlink-dir/file"});
TEST("weird-chars/foo-[a]", 0,
0, {"weird-chars/foo-a"});
TEST("weird-chars/foo-\\[a\\]", 0,
0, {"weird-chars/foo-[a]"});
// Non-matching patterns
TEST_UNMATCH("basic/not-there");
TEST_UNMATCH("basic/not-there*");
TEST_UNMATCH("basic/not-there/*");
// A file can't be specified with a trailing slash
TEST_UNMATCH("basic/file/");
// Check GLOB_APPEND, GLOB_DOOFFS, and both together
globbuf.gl_offs = 2; // should be ignored without GLOB_DOOFFS
TEST_NOFREE("basic/file", 0,
0, {"basic/file"});
TEST("basic/dir", GLOB_APPEND,
0, {"basic/file", MARK("basic/dir")});
globbuf.gl_offs = 2;
TEST_NOFREE("basic/file", GLOB_DOOFFS,
0, {NULL, NULL, "basic/file"});
TEST("basic/dir", GLOB_APPEND|GLOB_DOOFFS,
0, {NULL, NULL, "basic/file", MARK("basic/dir")});
// Check proper support for broken symlinks. Both completely-specified,
// and pattern matched.
TEST("broken-links/broken-symlink", 0,
0, {"broken-links/broken-symlink"});
TEST("broken-links/*", 0,
0, {"broken-links/broken-symlink"});
}
int main(int argc, char **argv)
{
char buf[512];
if (!t_pathrel(buf, sizeof buf, argv[0], "glob.data")) {
t_error("failed to obtain relative path to glob data\n");
return 1;
}
chdir(buf);
do_tests(0);
do_tests(GLOB_MARK);
do_tests(GLOB_NOCHECK);
return t_status;
}
|