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