s4:heimdal: import lorikeet-heimdal-202201172009 (commit 5a0b45cd723628b3690ea848548b...
[samba.git] / source4 / heimdal / lib / roken / dirent-test.c
1 /***********************************************************************
2  * Copyright (c) 2009, Secure Endpoints Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * - Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * - Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in
14  *   the documentation and/or other materials provided with the
15  *   distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28  * OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  **********************************************************************/
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <stdarg.h>
35 #include <direct.h>
36 #include <errno.h>
37 #include <io.h>
38 #include <fcntl.h>
39 #include <sys/stat.h>
40 #include <string.h>
41 #include "dirent.h"
42
43 /* Note that we create a known directory structure in a subdirectory
44    of the current directory to run our tests. */
45
46 #define TESTDIR "dirent-test-dir"
47
48 const char * dir_entries[] = {
49     "A",
50     "B",
51     "C",
52     "CAA",
53     "CAAA",
54     "CABBBB",
55     "CAABBB.txt",
56     "A filename with spaces"
57 };
58
59 const char * entries_begin_with_C[] = {
60     "C",
61     "CAA",
62     "CAAA",
63     "CABBBB",
64     "CAABBB.txt"
65 };
66
67 const char * entries_end_with_A[] = {
68     "A",
69     "CAA",
70     "CAAA"
71 };
72
73 const int n_dir_entries = sizeof(dir_entries)/sizeof(dir_entries[0]);
74
75 int teardown_test(void);
76
77 void fail_test(const char * reason, ...)
78 {
79     va_list args;
80
81     va_start(args, reason);
82     vfprintf(stderr, reason, args);
83     va_end(args);
84
85     fprintf(stderr, " : errno = %d (%s)\n", errno, strerror(errno));
86     teardown_test();
87     abort();
88 }
89
90 void fail_test_nf(const char * format, ...)
91 {
92     va_list args;
93
94     fprintf(stderr, "FAIL:");
95
96     va_start(args, format);
97     vfprintf(stderr, format, args);
98     va_end(args);
99
100     fprintf(stderr, " : errno = %d (%s)\n", errno, strerror(errno));
101 }
102
103 int touch(const char * filename)
104 {
105     int fd;
106
107     fd = _open(filename, _O_CREAT, _S_IREAD| _S_IWRITE);
108
109     if (fd == -1)
110         return -1;
111
112     return _close(fd);
113 }
114
115 int setup_test(void)
116 {
117     int i;
118
119     fprintf(stderr, "Creating test directory %s ...\n", TESTDIR);
120
121     if (_mkdir(TESTDIR))
122         fail_test("Can't create test directory \"" TESTDIR "\"");
123
124     if (_chdir(TESTDIR))
125         fail_test("Can't change to test directory");
126
127     for (i=0; i < n_dir_entries; i++) {
128         if (touch(dir_entries[i]))
129             fail_test("Can't create test file '%s'", dir_entries[i]);
130     }
131
132     fprintf(stderr, "Done with test setup.\n");
133
134     return 0;
135 }
136
137 int teardown_test(void)
138 {
139     char dirname[_MAX_PATH];
140     size_t len;
141     int i;
142
143     printf ("Begin cleanup...\n");
144
145     if (_getcwd(dirname, sizeof(dirname)/sizeof(char)) != NULL &&
146
147         (len = strlen(dirname)) > sizeof(TESTDIR)/sizeof(char) &&
148
149         strcmp(dirname + len + 1 - sizeof(TESTDIR)/sizeof(char), TESTDIR) == 0) {
150
151         /* fallthrough */
152
153     } else {
154         /* did we create the directory? */
155
156         if (!_rmdir( TESTDIR )) {
157             fprintf(stderr, "Removed test directory\n");
158             return 0;
159         } else {
160             if (errno == ENOTEMPTY) {
161                 if (_chdir(TESTDIR)) {
162                     fprintf(stderr, "Can't change to test directory. Aborting cleanup.\n");
163                     return -1;
164                 } else {
165                     /* fallthrough */
166                 }
167             } else {
168                 return -1;
169             }
170         }
171     }
172
173     fprintf(stderr, "Cleaning up test directory %s ...\n", TESTDIR);
174
175     for (i=0; i < n_dir_entries; i++) {
176         if (_unlink(dir_entries[i])) {
177             /* if the test setup failed, we expect this to happen for
178                at least some files */
179         }
180     }
181
182     if (_chdir("..")) {
183         fprintf(stderr, "Can't escape test directory. Giving in.\n");
184         return -1;
185     }
186
187     if (_rmdir( TESTDIR )) {
188         fprintf(stderr, "Can't remove test directory.\n");
189         return -1;
190     }
191
192     printf("Cleaned up test directory\n");
193     return 0;
194 }
195
196 int check_list(const char * filespec, const char ** list, int n, int expect_dot_and_dotdot)
197 {
198     DIR * d;
199     struct dirent * e;
200     int n_found = 0;
201     int i;
202     int rv = 0;
203     int retry = 1;
204
205     d = opendir(filespec);
206     if (d == NULL) {
207         fail_test_nf("opendir failed for [%s]", filespec);
208         return -1;
209     }
210
211     printf("Checking filespec [%s]... ", filespec);
212
213  retry:
214     while ((e = readdir(d)) != NULL) {
215         n_found ++;
216
217         if (expect_dot_and_dotdot &&
218             (strcmp(e->d_name, ".") == 0 ||
219              strcmp(e->d_name, "..") == 0))
220             continue;
221
222         for (i=0; i < n; i++) {
223             if (strcmp(list[i], e->d_name) == 0)
224                 break;
225         }
226
227         if (i == n) {
228             fail_test_nf("Found unexpected entry [%s]", e->d_name);
229             rv = -1;
230         }
231     }
232
233     if (n_found != n) {
234         fail_test_nf("Unexpected number of entries [%d].  Expected %d", n_found, n);
235         rv = -1;
236     }
237
238     if (retry) {
239         retry = 0;
240         n_found = 0;
241
242         rewinddir(d);
243         goto retry;
244     }
245
246     if (closedir(d)) {
247         fail_test_nf("closedir() failed");
248     }
249
250     printf("done\n");
251
252     return rv;
253 }
254
255 int run_tests()
256 {
257     /* assumes that the test directory has been set up and we have
258        changed into the test directory. */
259
260     check_list("*", dir_entries, n_dir_entries + 2, 1);
261     check_list("*.*", dir_entries, n_dir_entries + 2, 1);
262     check_list("C*", entries_begin_with_C, sizeof(entries_begin_with_C)/sizeof(entries_begin_with_C[0]), 0);
263     check_list("*A", entries_end_with_A, sizeof(entries_end_with_A)/sizeof(entries_end_with_A[0]), 0);
264
265     return 0;
266 }
267
268 int main(int argc, char ** argv)
269 {
270     if (setup_test())
271         return 1;
272
273     run_tests();
274
275     teardown_test();
276
277     return 0;
278 }