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