1272343Sngie/*	$NetBSD: t_basedirname.c,v 1.2 2011/07/07 09:49:59 jruoho Exp $	*/
2272343Sngie
3272343Sngie/*
4272343Sngie * Regression test for basename(3).
5272343Sngie *
6272343Sngie * Written by Jason R. Thorpe <thorpej@NetBSD.org>, Oct. 2002.
7272343Sngie * Public domain.
8272343Sngie */
9272343Sngie
10272343Sngie#include <atf-c.h>
11272343Sngie
12272343Sngie#include <assert.h>
13272343Sngie#include <stdio.h>
14272343Sngie#include <stdlib.h>
15272343Sngie#include <string.h>
16272343Sngie#include <libgen.h>
17272343Sngie
18272343Sngiestruct {
19272343Sngie	const char *input;
20272343Sngie	const char *output;
21272343Sngie} test_basename_table[] = {
22272343Sngie/*
23272343Sngie * The following are taken from the "Sample Input and Output Strings
24272343Sngie * for basename()" table in IEEE Std 1003.1-2001.
25272343Sngie */
26272343Sngie	{ "/usr/lib",		"lib" },
27272343Sngie	{ "/usr/",		"usr" },
28272343Sngie	{ "/",			"/" },
29272343Sngie	{ "///",		"/" },
30272343Sngie	{ "//usr//lib//",	"lib" },
31272343Sngie/*
32272343Sngie * IEEE Std 1003.1-2001:
33272343Sngie *
34272343Sngie *	If path is a null pointer or points to an empty string,
35272343Sngie *	basename() shall return a pointer to the string "." .
36272343Sngie */
37272343Sngie	{ "",			"." },
38272343Sngie	{ NULL,			"." },
39272343Sngie/*
40272343Sngie * IEEE Std 1003.1-2001:
41272343Sngie *
42272343Sngie *	If the string is exactly "//", it is implementation-defined
43272343Sngie *	whether "/" or "//" is returned.
44272343Sngie *
45272343Sngie * The NetBSD implementation returns "/".
46272343Sngie */
47272343Sngie	{ "//",			"/" },
48272343Sngie
49272343Sngie	{ NULL,			NULL }
50272343Sngie};
51272343Sngie
52272343Sngiestruct {
53272343Sngie	const char *input;
54272343Sngie	const char *output;
55272343Sngie} test_dirname_table[] = {
56272343Sngie/*
57272343Sngie * The following are taken from the "Sample Input and Output Strings
58272343Sngie * for dirname()" table in IEEE Std 1003.1-2001.
59272343Sngie */
60272343Sngie	{ "/usr/lib",		"/usr" },
61272343Sngie	{ "/usr/",		"/" },
62272343Sngie	{ "usr",		"." },
63272343Sngie	{ "/",			"/" },
64272343Sngie	{ ".",			"." },
65272343Sngie	{ "..",			"." },
66272343Sngie/*
67272343Sngie * IEEE Std 1003.1-2001:
68272343Sngie *
69272343Sngie *	If path is a null pointer or points to an empty string,
70272343Sngie *	dirname() shall return a pointer to the string "." .
71272343Sngie */
72272343Sngie	{ "",			"." },
73272343Sngie	{ NULL,			"." },
74272343Sngie/*
75272343Sngie * IEEE Std 1003.1-2001:
76272343Sngie *
77272343Sngie *	Since the meaning of the leading "//" is implementation-defined,
78272343Sngie *	dirname("//foo") may return either "//" or "/" (but nothing else).
79272343Sngie *
80272343Sngie * The NetBSD implementation returns "/".
81272343Sngie */
82272343Sngie	{ "//foo",		"/" },
83272343Sngie/*
84272343Sngie * Make sure the trailing slashes after the directory name component
85272343Sngie * get trimmed.  The Std does not talk about this, but this is what
86272343Sngie * Solaris 8's dirname(3) does.
87272343Sngie */
88272343Sngie	{ "/usr///lib",		"/usr" },
89272343Sngie
90272343Sngie	{ NULL,			NULL }
91272343Sngie};
92272343Sngie
93272343SngieATF_TC(basename_posix);
94272343SngieATF_TC_HEAD(basename_posix, tc)
95272343Sngie{
96272343Sngie	atf_tc_set_md_var(tc, "descr", "Test basename(3) with POSIX examples");
97272343Sngie}
98272343Sngie
99272343SngieATF_TC_BODY(basename_posix, tc)
100272343Sngie{
101272343Sngie	char testbuf[32], *base;
102272343Sngie	int i;
103272343Sngie
104272343Sngie	for (i = 0; test_basename_table[i].output != NULL; i++) {
105272343Sngie		if (test_basename_table[i].input != NULL) {
106272343Sngie			if (strlen(test_basename_table[i].input) >=
107272343Sngie			    sizeof(testbuf))
108272343Sngie				atf_tc_skip("Testbuf too small!");
109272343Sngie			strcpy(testbuf, test_basename_table[i].input);
110272343Sngie			base = basename(testbuf);
111272343Sngie		} else
112272343Sngie			base = basename(NULL);
113272343Sngie
114272343Sngie		/*
115272343Sngie		 * basename(3) is allowed to modify the input buffer.
116272343Sngie		 * However, that is considered hostile by some programs,
117272343Sngie		 * and so we elect to consider this an error.
118272343Sngie		 *
119272343Sngie		 * This is not a problem, as basename(3) is also allowed
120272343Sngie		 * to return a pointer to a statically-allocated buffer
121272343Sngie		 * (it is explicitly not required to be reentrant).
122272343Sngie		 */
123272343Sngie		if (test_basename_table[i].input != NULL &&
124272343Sngie		    strcmp(test_basename_table[i].input, testbuf) != 0) {
125272343Sngie			fprintf(stderr,
126272343Sngie			    "Input buffer for \"%s\" was modified\n",
127272343Sngie			    test_basename_table[i].input);
128272343Sngie			atf_tc_fail("Input buffer was modified.");
129272343Sngie		}
130272343Sngie
131272343Sngie		/* Make sure the result is correct. */
132272343Sngie		if (strcmp(test_basename_table[i].output, base) != 0) {
133272343Sngie			fprintf(stderr,
134272343Sngie			    "Input \"%s\", output \"%s\", expected \"%s\"\n",
135272343Sngie			    test_basename_table[i].input ==
136272343Sngie				NULL ? "(null)" : test_basename_table[i].input,
137272343Sngie			    base, test_basename_table[i].output);
138272343Sngie			atf_tc_fail("Output does not match expected value.");
139272343Sngie		}
140272343Sngie	}
141272343Sngie}
142272343Sngie
143272343Sngie
144272343SngieATF_TC(dirname_posix);
145272343SngieATF_TC_HEAD(dirname_posix, tc)
146272343Sngie{
147272343Sngie	atf_tc_set_md_var(tc, "descr", "Test dirname(3) with POSIX examples");
148272343Sngie}
149272343Sngie
150272343SngieATF_TC_BODY(dirname_posix, tc)
151272343Sngie{
152272343Sngie	char testbuf[32], *base;
153272343Sngie	int i;
154272343Sngie
155272343Sngie	for (i = 0; test_dirname_table[i].output != NULL; i++) {
156272343Sngie		if (test_dirname_table[i].input != NULL) {
157272343Sngie			if (strlen(test_dirname_table[i].input) >=
158272343Sngie			    sizeof(testbuf))
159272343Sngie				atf_tc_skip("Testbuf too small!");
160272343Sngie			strcpy(testbuf, test_dirname_table[i].input);
161272343Sngie			base = dirname(testbuf);
162272343Sngie		} else
163272343Sngie			base = dirname(NULL);
164272343Sngie
165272343Sngie		/*
166272343Sngie		 * dirname(3) is allowed to modify the input buffer.
167272343Sngie		 * However, that is considered hostile by some programs,
168272343Sngie		 * and so we elect to consider this an error.
169272343Sngie		 *
170272343Sngie		 * This is not a problem, as dirname(3) is also allowed
171272343Sngie		 * to return a pointer to a statically-allocated buffer
172272343Sngie		 * (it is explicitly not required to be reentrant).
173272343Sngie		 */
174272343Sngie		if (test_dirname_table[i].input != NULL &&
175272343Sngie		    strcmp(test_dirname_table[i].input, testbuf) != 0) {
176272343Sngie			fprintf(stderr,
177272343Sngie			    "Input buffer for \"%s\" was modified\n",
178272343Sngie			    test_dirname_table[i].input);
179272343Sngie			atf_tc_fail("Input buffer was modified.");
180272343Sngie		}
181272343Sngie
182272343Sngie		/* Make sure the result is correct. */
183272343Sngie		if (strcmp(test_dirname_table[i].output, base) != 0) {
184272343Sngie			fprintf(stderr,
185272343Sngie			    "Input \"%s\", output \"%s\", expected \"%s\"\n",
186272343Sngie			    test_dirname_table[i].input ==
187272343Sngie				NULL ? "(null)" : test_dirname_table[i].input,
188272343Sngie			    base, test_dirname_table[i].output);
189272343Sngie			atf_tc_fail("Output does not match expected value.");
190272343Sngie		}
191272343Sngie	}
192272343Sngie}
193272343Sngie
194272343SngieATF_TP_ADD_TCS(tp)
195272343Sngie{
196272343Sngie	ATF_TP_ADD_TC(tp, basename_posix);
197272343Sngie	ATF_TP_ADD_TC(tp, dirname_posix);
198272343Sngie
199272343Sngie	return atf_no_error();
200272343Sngie}
201