xref: /netbsd-src/tests/lib/libc/gen/t_basedirname.c (revision 9a514225a10cafed11453993e50a21270a60e74c)
1*9a514225Sjruoho /*	$NetBSD: t_basedirname.c,v 1.2 2011/07/07 09:49:59 jruoho Exp $	*/
295456adcSpgoyette 
395456adcSpgoyette /*
495456adcSpgoyette  * Regression test for basename(3).
595456adcSpgoyette  *
695456adcSpgoyette  * Written by Jason R. Thorpe <thorpej@NetBSD.org>, Oct. 2002.
795456adcSpgoyette  * Public domain.
895456adcSpgoyette  */
995456adcSpgoyette 
1095456adcSpgoyette #include <atf-c.h>
1195456adcSpgoyette 
1295456adcSpgoyette #include <assert.h>
1395456adcSpgoyette #include <stdio.h>
1495456adcSpgoyette #include <stdlib.h>
1595456adcSpgoyette #include <string.h>
1695456adcSpgoyette #include <libgen.h>
1795456adcSpgoyette 
1895456adcSpgoyette struct {
1995456adcSpgoyette 	const char *input;
2095456adcSpgoyette 	const char *output;
2195456adcSpgoyette } test_basename_table[] = {
2295456adcSpgoyette /*
2395456adcSpgoyette  * The following are taken from the "Sample Input and Output Strings
2495456adcSpgoyette  * for basename()" table in IEEE Std 1003.1-2001.
2595456adcSpgoyette  */
2695456adcSpgoyette 	{ "/usr/lib",		"lib" },
2795456adcSpgoyette 	{ "/usr/",		"usr" },
2895456adcSpgoyette 	{ "/",			"/" },
2995456adcSpgoyette 	{ "///",		"/" },
3095456adcSpgoyette 	{ "//usr//lib//",	"lib" },
3195456adcSpgoyette /*
3295456adcSpgoyette  * IEEE Std 1003.1-2001:
3395456adcSpgoyette  *
3495456adcSpgoyette  *	If path is a null pointer or points to an empty string,
3595456adcSpgoyette  *	basename() shall return a pointer to the string "." .
3695456adcSpgoyette  */
3795456adcSpgoyette 	{ "",			"." },
3895456adcSpgoyette 	{ NULL,			"." },
3995456adcSpgoyette /*
4095456adcSpgoyette  * IEEE Std 1003.1-2001:
4195456adcSpgoyette  *
4295456adcSpgoyette  *	If the string is exactly "//", it is implementation-defined
4395456adcSpgoyette  *	whether "/" or "//" is returned.
4495456adcSpgoyette  *
4595456adcSpgoyette  * The NetBSD implementation returns "/".
4695456adcSpgoyette  */
4795456adcSpgoyette 	{ "//",			"/" },
4895456adcSpgoyette 
4995456adcSpgoyette 	{ NULL,			NULL }
5095456adcSpgoyette };
5195456adcSpgoyette 
5295456adcSpgoyette struct {
5395456adcSpgoyette 	const char *input;
5495456adcSpgoyette 	const char *output;
5595456adcSpgoyette } test_dirname_table[] = {
5695456adcSpgoyette /*
5795456adcSpgoyette  * The following are taken from the "Sample Input and Output Strings
5895456adcSpgoyette  * for dirname()" table in IEEE Std 1003.1-2001.
5995456adcSpgoyette  */
6095456adcSpgoyette 	{ "/usr/lib",		"/usr" },
6195456adcSpgoyette 	{ "/usr/",		"/" },
6295456adcSpgoyette 	{ "usr",		"." },
6395456adcSpgoyette 	{ "/",			"/" },
6495456adcSpgoyette 	{ ".",			"." },
6595456adcSpgoyette 	{ "..",			"." },
6695456adcSpgoyette /*
6795456adcSpgoyette  * IEEE Std 1003.1-2001:
6895456adcSpgoyette  *
6995456adcSpgoyette  *	If path is a null pointer or points to an empty string,
7095456adcSpgoyette  *	dirname() shall return a pointer to the string "." .
7195456adcSpgoyette  */
7295456adcSpgoyette 	{ "",			"." },
7395456adcSpgoyette 	{ NULL,			"." },
7495456adcSpgoyette /*
7595456adcSpgoyette  * IEEE Std 1003.1-2001:
7695456adcSpgoyette  *
7795456adcSpgoyette  *	Since the meaning of the leading "//" is implementation-defined,
7895456adcSpgoyette  *	dirname("//foo") may return either "//" or "/" (but nothing else).
7995456adcSpgoyette  *
8095456adcSpgoyette  * The NetBSD implementation returns "/".
8195456adcSpgoyette  */
8295456adcSpgoyette 	{ "//foo",		"/" },
8395456adcSpgoyette /*
8495456adcSpgoyette  * Make sure the trailing slashes after the directory name component
8595456adcSpgoyette  * get trimmed.  The Std does not talk about this, but this is what
8695456adcSpgoyette  * Solaris 8's dirname(3) does.
8795456adcSpgoyette  */
8895456adcSpgoyette 	{ "/usr///lib",		"/usr" },
8995456adcSpgoyette 
9095456adcSpgoyette 	{ NULL,			NULL }
9195456adcSpgoyette };
9295456adcSpgoyette 
93*9a514225Sjruoho ATF_TC(basename_posix);
ATF_TC_HEAD(basename_posix,tc)94*9a514225Sjruoho ATF_TC_HEAD(basename_posix, tc)
9595456adcSpgoyette {
9695456adcSpgoyette 	atf_tc_set_md_var(tc, "descr", "Test basename(3) with POSIX examples");
9795456adcSpgoyette }
9895456adcSpgoyette 
ATF_TC_BODY(basename_posix,tc)99*9a514225Sjruoho ATF_TC_BODY(basename_posix, tc)
10095456adcSpgoyette {
10195456adcSpgoyette 	char testbuf[32], *base;
10295456adcSpgoyette 	int i;
10395456adcSpgoyette 
10495456adcSpgoyette 	for (i = 0; test_basename_table[i].output != NULL; i++) {
10595456adcSpgoyette 		if (test_basename_table[i].input != NULL) {
10695456adcSpgoyette 			if (strlen(test_basename_table[i].input) >=
10795456adcSpgoyette 			    sizeof(testbuf))
10895456adcSpgoyette 				atf_tc_skip("Testbuf too small!");
10995456adcSpgoyette 			strcpy(testbuf, test_basename_table[i].input);
11095456adcSpgoyette 			base = basename(testbuf);
11195456adcSpgoyette 		} else
11295456adcSpgoyette 			base = basename(NULL);
11395456adcSpgoyette 
11495456adcSpgoyette 		/*
11595456adcSpgoyette 		 * basename(3) is allowed to modify the input buffer.
11695456adcSpgoyette 		 * However, that is considered hostile by some programs,
11795456adcSpgoyette 		 * and so we elect to consider this an error.
11895456adcSpgoyette 		 *
11995456adcSpgoyette 		 * This is not a problem, as basename(3) is also allowed
12095456adcSpgoyette 		 * to return a pointer to a statically-allocated buffer
12195456adcSpgoyette 		 * (it is explicitly not required to be reentrant).
12295456adcSpgoyette 		 */
12395456adcSpgoyette 		if (test_basename_table[i].input != NULL &&
12495456adcSpgoyette 		    strcmp(test_basename_table[i].input, testbuf) != 0) {
12595456adcSpgoyette 			fprintf(stderr,
12695456adcSpgoyette 			    "Input buffer for \"%s\" was modified\n",
12795456adcSpgoyette 			    test_basename_table[i].input);
12895456adcSpgoyette 			atf_tc_fail("Input buffer was modified.");
12995456adcSpgoyette 		}
13095456adcSpgoyette 
13195456adcSpgoyette 		/* Make sure the result is correct. */
13295456adcSpgoyette 		if (strcmp(test_basename_table[i].output, base) != 0) {
13395456adcSpgoyette 			fprintf(stderr,
13495456adcSpgoyette 			    "Input \"%s\", output \"%s\", expected \"%s\"\n",
13595456adcSpgoyette 			    test_basename_table[i].input ==
13695456adcSpgoyette 				NULL ? "(null)" : test_basename_table[i].input,
13795456adcSpgoyette 			    base, test_basename_table[i].output);
13895456adcSpgoyette 			atf_tc_fail("Output does not match expected value.");
13995456adcSpgoyette 		}
14095456adcSpgoyette 	}
14195456adcSpgoyette }
14295456adcSpgoyette 
14395456adcSpgoyette 
144*9a514225Sjruoho ATF_TC(dirname_posix);
ATF_TC_HEAD(dirname_posix,tc)145*9a514225Sjruoho ATF_TC_HEAD(dirname_posix, tc)
14695456adcSpgoyette {
14795456adcSpgoyette 	atf_tc_set_md_var(tc, "descr", "Test dirname(3) with POSIX examples");
14895456adcSpgoyette }
14995456adcSpgoyette 
ATF_TC_BODY(dirname_posix,tc)150*9a514225Sjruoho ATF_TC_BODY(dirname_posix, tc)
15195456adcSpgoyette {
15295456adcSpgoyette 	char testbuf[32], *base;
15395456adcSpgoyette 	int i;
15495456adcSpgoyette 
15595456adcSpgoyette 	for (i = 0; test_dirname_table[i].output != NULL; i++) {
15695456adcSpgoyette 		if (test_dirname_table[i].input != NULL) {
15795456adcSpgoyette 			if (strlen(test_dirname_table[i].input) >=
15895456adcSpgoyette 			    sizeof(testbuf))
15995456adcSpgoyette 				atf_tc_skip("Testbuf too small!");
16095456adcSpgoyette 			strcpy(testbuf, test_dirname_table[i].input);
16195456adcSpgoyette 			base = dirname(testbuf);
16295456adcSpgoyette 		} else
16395456adcSpgoyette 			base = dirname(NULL);
16495456adcSpgoyette 
16595456adcSpgoyette 		/*
16695456adcSpgoyette 		 * dirname(3) is allowed to modify the input buffer.
16795456adcSpgoyette 		 * However, that is considered hostile by some programs,
16895456adcSpgoyette 		 * and so we elect to consider this an error.
16995456adcSpgoyette 		 *
17095456adcSpgoyette 		 * This is not a problem, as dirname(3) is also allowed
17195456adcSpgoyette 		 * to return a pointer to a statically-allocated buffer
17295456adcSpgoyette 		 * (it is explicitly not required to be reentrant).
17395456adcSpgoyette 		 */
17495456adcSpgoyette 		if (test_dirname_table[i].input != NULL &&
17595456adcSpgoyette 		    strcmp(test_dirname_table[i].input, testbuf) != 0) {
17695456adcSpgoyette 			fprintf(stderr,
17795456adcSpgoyette 			    "Input buffer for \"%s\" was modified\n",
17895456adcSpgoyette 			    test_dirname_table[i].input);
17995456adcSpgoyette 			atf_tc_fail("Input buffer was modified.");
18095456adcSpgoyette 		}
18195456adcSpgoyette 
18295456adcSpgoyette 		/* Make sure the result is correct. */
18395456adcSpgoyette 		if (strcmp(test_dirname_table[i].output, base) != 0) {
18495456adcSpgoyette 			fprintf(stderr,
18595456adcSpgoyette 			    "Input \"%s\", output \"%s\", expected \"%s\"\n",
18695456adcSpgoyette 			    test_dirname_table[i].input ==
18795456adcSpgoyette 				NULL ? "(null)" : test_dirname_table[i].input,
18895456adcSpgoyette 			    base, test_dirname_table[i].output);
18995456adcSpgoyette 			atf_tc_fail("Output does not match expected value.");
19095456adcSpgoyette 		}
19195456adcSpgoyette 	}
19295456adcSpgoyette }
19395456adcSpgoyette 
ATF_TP_ADD_TCS(tp)19495456adcSpgoyette ATF_TP_ADD_TCS(tp)
19595456adcSpgoyette {
196*9a514225Sjruoho 	ATF_TP_ADD_TC(tp, basename_posix);
197*9a514225Sjruoho 	ATF_TP_ADD_TC(tp, dirname_posix);
19895456adcSpgoyette 
19995456adcSpgoyette 	return atf_no_error();
20095456adcSpgoyette }
201