diff options
author | ngie <ngie@FreeBSD.org> | 2015-11-23 10:53:01 +0000 |
---|---|---|
committer | ngie <ngie@FreeBSD.org> | 2015-11-23 10:53:01 +0000 |
commit | d3ec13a080e77a0638fb598e31d77dc952bfd2e2 (patch) | |
tree | b388d5645fbd600d6dbf8f2ee449d598f11da503 | |
parent | 555179a315c176c27179f70f489b3500348c42fd (diff) | |
download | FreeBSD-src-d3ec13a080e77a0638fb598e31d77dc952bfd2e2.zip FreeBSD-src-d3ec13a080e77a0638fb598e31d77dc952bfd2e2.tar.gz |
MFC r290572,r290646,r290848,r290849:
r290572:
Integrate tools/regression/lib/libc/gen into the FreeBSD test suite
as lib/libc/tests/gen
The code in test-fnmatch that was used for generating:
- bin/sh/tests/builtins/case2.0
- bin/sh/tests/builtins/case3.0
has been left undisturbed. The target `make sh-tests` has been moved over
from tools/regression/lib/libc/gen/Makefile to
lib/libc/tests/gen/Makefile and made into a PHONY target
case2.0 and case3.0 test input generation isn't being done automatically.
This needs additional discussion.
Sponsored by: EMC / Isilon Storage Division
r290646:
Add missing licensing boilerplate to test-fnmatch.c
Carry over licensing author info from fnmatch_test.c (jilles@)
Sponsored by: EMC / Isilon Storage Division
r290848:
Fix -Wunused warnings
Sponsored by: EMC / Isilon Storage Division
r290849:
Fix -Wmissing-braces warnings by adding braces around all the
testcase inputs
Sponsored by: EMC / Isilon Storage Division
-rw-r--r-- | lib/libc/tests/gen/Makefile | 27 | ||||
-rw-r--r-- | lib/libc/tests/gen/fmtcheck_test.c | 105 | ||||
-rw-r--r-- | lib/libc/tests/gen/fmtmsg_test.c | 252 | ||||
-rw-r--r-- | lib/libc/tests/gen/fnmatch_test.c | 188 | ||||
-rw-r--r-- | lib/libc/tests/gen/fnmatch_testcases.h | 176 | ||||
-rw-r--r-- | lib/libc/tests/gen/ftw_test.c | 127 | ||||
-rw-r--r-- | lib/libc/tests/gen/popen_test.c | 251 | ||||
-rw-r--r-- | lib/libc/tests/gen/posix_spawn_test.c | 103 | ||||
-rw-r--r-- | lib/libc/tests/gen/test-fnmatch.c | 102 | ||||
-rw-r--r-- | lib/libc/tests/gen/wordexp_test.c | 360 |
10 files changed, 1690 insertions, 1 deletions
diff --git a/lib/libc/tests/gen/Makefile b/lib/libc/tests/gen/Makefile index f9a0bd4..91097ef 100644 --- a/lib/libc/tests/gen/Makefile +++ b/lib/libc/tests/gen/Makefile @@ -4,8 +4,15 @@ TESTSDIR= ${TESTSBASE}/lib/libc/gen -ATF_TESTS_C= arc4random_test +ATF_TESTS_C+= arc4random_test +ATF_TESTS_C+= fmtcheck2_test +ATF_TESTS_C+= fmtmsg_test +ATF_TESTS_C+= fnmatch2_test ATF_TESTS_C+= fpclassify2_test +ATF_TESTS_C+= ftw_test +ATF_TESTS_C+= popen_test +ATF_TESTS_C+= posix_spawn_test +ATF_TESTS_C+= wordexp_test # TODO: t_closefrom, t_cpuset, t_fmtcheck, t_randomid, t_sleep # TODO: t_siginfo (fixes require further inspection) @@ -55,7 +62,25 @@ DPADD.nice_test+= ${LIBPTHREAD} LDADD.syslog_test+= -lpthread DPADD.syslog_test+= ${LIBPTHREAD} +CFLAGS+= -I${.CURDIR} + +SRCS.fmtcheck2_test= fmtcheck_test.c +SRCS.fnmatch2_test= fnmatch_test.c + TESTS_SUBDIRS= execve TESTS_SUBDIRS+= posix_spawn +# The old testcase name +TEST_FNMATCH= test-fnmatch +CLEANFILES+= ${GEN_SH_CASE_TESTCASES} +sh-tests: .PHONY +.for target in clean obj depend all + @cd ${.CURDIR} && ${MAKE} PROG=${TEST_FNMATCH} \ + -DNO_SUBDIR ${target} +.endfor + @cd ${.OBJDIR} && ./${TEST_FNMATCH} -s 1 > \ + ${SRCTOP}/bin/sh/tests/builtins/case2.0 + @cd ${.OBJDIR} && ./${TEST_FNMATCH} -s 2 > \ + ${SRCTOP}/bin/sh/tests/builtins/case3.0 + .include <bsd.test.mk> diff --git a/lib/libc/tests/gen/fmtcheck_test.c b/lib/libc/tests/gen/fmtcheck_test.c new file mode 100644 index 0000000..3e180c9 --- /dev/null +++ b/lib/libc/tests/gen/fmtcheck_test.c @@ -0,0 +1,105 @@ +/* $NetBSD: tfmtcheck.c,v 1.3 2008/04/28 20:23:04 martin Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code was contributed to The NetBSD Foundation by Allen Briggs. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <err.h> +#include <stdio.h> +#include <stdlib.h> + +#include <atf-c.h> + +struct test_fmt { + char *fmt1; + char *fmt2; + int correct; +} test_fmts[] = { + { "%d", "%d", 1 }, + { "%2d", "%2.2d", 1 }, + { "%x", "%d", 1 }, + { "%u", "%d", 1 }, + { "%03d", "%d", 1 }, + { "%-2d", "%d", 1 }, + { "%d", "%-12.1d", 1 }, + { "%d", "%-01.3d", 1 }, + { "%X", "%-01.3d", 1 }, + { "%D", "%ld", 1 }, + { "%s", "%s", 1 }, + { "%s", "This is a %s test", 1 }, + { "Hi, there. This is a %s test", "%s", 1 }, + { "%d", "%s", 2 }, + { "%e", "%s", 2 }, + { "%r", "%d", 2 }, + { "%*.2d", "%*d", 1 }, + { "%2.*d", "%*d", 2 }, + { "%*d", "%*d", 1 }, + { "%-3", "%d", 2 }, + { "%d %s", "%d", 2 }, + { "%*.*.*d", "%*.*.*d", 2 }, + { "%d", "%d %s", 1 }, + { "%40s", "%20s", 1 }, + { "%x %x %x", "%o %u %d", 1 }, + { "%o %u %d", "%x %x %X", 1 }, + { "%#o %u %#-d", "%x %#x %X", 1 }, + { "%qd", "%llx", 1 }, + { "%%", "%llx", 1 }, + { "%p %30s %#llx %-10.*e", "This number %lu%% and string %s has %qd numbers and %.*g floats", 1 }, +}; + +ATF_TC_WITHOUT_HEAD(fmtcheck_test); +ATF_TC_BODY(fmtcheck_test, tc) +{ + int i; + const char *f, *cf, *f1, *f2; + + for (i = 0; i < nitems(test_fmts); i++) { + f1 = test_fmts[i].fmt1; + f2 = test_fmts[i].fmt2; + f = fmtcheck(f1, f2); + if (test_fmts[i].correct == 1) + cf = f1; + else + cf = f2; + ATF_CHECK_MSG(f == cf, + "Test %d: (%s) vs. (%s) failed " + "(should have returned %s)", i + 1, f1, f2, + (test_fmts[i].correct == 1) ? "1st" : "2nd"); + } +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, fmtcheck_test); + + return (atf_no_error()); +} diff --git a/lib/libc/tests/gen/fmtmsg_test.c b/lib/libc/tests/gen/fmtmsg_test.c new file mode 100644 index 0000000..aa3ca19 --- /dev/null +++ b/lib/libc/tests/gen/fmtmsg_test.c @@ -0,0 +1,252 @@ +/*- + * Copyright (c) 2012 Jilles Tjoelker + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/wait.h> +#include <err.h> +#include <errno.h> +#include <fmtmsg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <atf-c.h> + +static char *run_test(long classification, const char *label, int severity, + const char *text, const char *action, const char *tag); + +struct testcase { + long classification; + const char *label; + int severity; + const char *text; + const char *action; + const char *tag; + const char *msgverb; + const char *result; +} testcases[] = { + { + MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR, + "illegal option -- z", "refer to manual", "BSD:ls:001", + NULL, + "BSD:ls: ERROR: illegal option -- z\n" + "TO FIX: refer to manual BSD:ls:001\n" + }, + { + MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR, + "illegal option -- z", "refer to manual", "BSD:ls:001", + "text:severity:action:tag", + "illegal option -- z: ERROR\n" + "TO FIX: refer to manual BSD:ls:001\n" + }, + { + MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR, + "illegal option -- z", "refer to manual", "BSD:ls:001", + "text", + "illegal option -- z\n" + }, + { + MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR, + "illegal option -- z", "refer to manual", "BSD:ls:001", + "severity:text", + "ERROR: illegal option -- z\n" + }, + { + MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR, + "illegal option -- z", "refer to manual", "BSD:ls:001", + "ignore me", + "BSD:ls: ERROR: illegal option -- z\n" + "TO FIX: refer to manual BSD:ls:001\n" + }, + { + MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR, + "illegal option -- z", "refer to manual", "BSD:ls:001", + "tag:severity:text:nothing:action", + "BSD:ls: ERROR: illegal option -- z\n" + "TO FIX: refer to manual BSD:ls:001\n" + }, + { + MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR, + "illegal option -- z", "refer to manual", "BSD:ls:001", + "", + "BSD:ls: ERROR: illegal option -- z\n" + "TO FIX: refer to manual BSD:ls:001\n" + }, + { + MM_UTIL | MM_PRINT, MM_NULLLBL, MM_ERROR, + "illegal option -- z", "refer to manual", "BSD:ls:001", + NULL, + "ERROR: illegal option -- z\n" + "TO FIX: refer to manual BSD:ls:001\n" + }, + { + MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR, + "illegal option -- z", MM_NULLACT, MM_NULLTAG, + NULL, + "BSD:ls: ERROR: illegal option -- z\n" + }, + { + MM_UTIL | MM_NULLMC, "BSD:ls", MM_ERROR, + "illegal option -- z", "refer to manual", "BSD:ls:001", + NULL, + "" + }, + { + MM_APPL | MM_PRINT, "ABCDEFGHIJ:abcdefghijklmn", MM_INFO, + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "refer to manual", "ABCDEFGHIJ:abcdefghijklmn:001", + NULL, + "ABCDEFGHIJ:abcdefghijklmn: INFO: " + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n" + "TO FIX: refer to manual ABCDEFGHIJ:abcdefghijklmn:001\n" + }, + { + MM_OPSYS | MM_PRINT, "TEST:test", MM_HALT, + "failed", "nothing can help me", "NOTHING", + NULL, + "TEST:test: HALT: failed\n" + "TO FIX: nothing can help me NOTHING\n" + }, + { + MM_OPSYS | MM_PRINT, "TEST:test", MM_WARNING, + "failed", "nothing can help me", "NOTHING", + NULL, + "TEST:test: WARNING: failed\n" + "TO FIX: nothing can help me NOTHING\n" + }, + { + MM_OPSYS | MM_PRINT, "TEST:test", MM_NOSEV, + "failed", "nothing can help me", "NOTHING", + NULL, + "TEST:test: failed\n" + "TO FIX: nothing can help me NOTHING\n" + } +}; + +static char * +run_test(long classification, const char *label, int severity, + const char *text, const char *action, const char *tag) +{ + int pip[2]; + pid_t pid, wpid; + char *result, *p; + size_t resultsize; + ssize_t n; + int status; + + if (pipe(pip) == -1) + err(2, "pipe"); + pid = fork(); + if (pid == -1) + err(2, "fork"); + if (pid == 0) { + close(pip[0]); + if (pip[1] != STDERR_FILENO && + dup2(pip[1], STDERR_FILENO) == -1) + _exit(2); + if (fmtmsg(classification, label, severity, text, action, tag) + != MM_OK) + _exit(1); + else + _exit(0); + } + close(pip[1]); + resultsize = 1024; + result = malloc(resultsize); + p = result; + while ((n = read(pip[0], p, result + resultsize - p - 1)) != 0) { + if (n == -1) { + if (errno == EINTR) + continue; + else + err(2, "read"); + } + p += n; + if (result + resultsize == p - 1) { + resultsize *= 2; + result = realloc(result, resultsize); + if (result == NULL) + err(2, "realloc"); + } + } + if (memchr(result, '\0', p - result) != NULL) { + free(result); + return (NULL); + } + *p = '\0'; + close(pip[0]); + while ((wpid = waitpid(pid, &status, 0)) == -1 && errno == EINTR) + ; + if (wpid == -1) + err(2, "waitpid"); + if (status != 0) { + free(result); + return (NULL); + } + return (result); +} + +ATF_TC_WITHOUT_HEAD(fmtmsg_test); +ATF_TC_BODY(fmtmsg_test, tc) +{ + char *result; + struct testcase *t; + int i; + + for (i = 0; i < nitems(testcases); i++) { + t = &testcases[i]; + if (t->msgverb != NULL) + setenv("MSGVERB", t->msgverb, 1); + else + unsetenv("MSGVERB"); + result = run_test(t->classification, t->label, t->severity, + t->text, t->action, t->tag); + ATF_CHECK_MSG(result != NULL, "testcase %d failed", i + 1); + if (result != NULL) + ATF_CHECK_MSG(strcmp(result, t->result) == 0, + "results for testcase %d didn't match; " + "`%s` != `%s`", i + 1, result, t->result); + free(result); + } +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, fmtmsg_test); + + return (atf_no_error()); +} diff --git a/lib/libc/tests/gen/fnmatch_test.c b/lib/libc/tests/gen/fnmatch_test.c new file mode 100644 index 0000000..8d9ead2 --- /dev/null +++ b/lib/libc/tests/gen/fnmatch_test.c @@ -0,0 +1,188 @@ +/*- + * Copyright (c) 2010 Jilles Tjoelker + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <atf-c.h> + +#include "fnmatch_testcases.h" + +static const char * +flags_to_string(int flags) +{ + static const int flagvalues[] = { FNM_NOESCAPE, FNM_PATHNAME, + FNM_PERIOD, FNM_LEADING_DIR, FNM_CASEFOLD, 0 }; + static const char flagnames[] = "FNM_NOESCAPE\0FNM_PATHNAME\0FNM_PERIOD\0FNM_LEADING_DIR\0FNM_CASEFOLD\0"; + static char result[sizeof(flagnames) + 3 * sizeof(int) + 2]; + char *p; + size_t i, len; + const char *fp; + + p = result; + fp = flagnames; + for (i = 0; flagvalues[i] != 0; i++) { + len = strlen(fp); + if (flags & flagvalues[i]) { + if (p != result) + *p++ = '|'; + memcpy(p, fp, len); + p += len; + flags &= ~flagvalues[i]; + } + fp += len + 1; + } + if (p == result) + memcpy(p, "0", 2); + else if (flags != 0) + sprintf(p, "%d", flags); + else + *p = '\0'; + return result; +} + +ATF_TC_WITHOUT_HEAD(fnmatch_test); +ATF_TC_BODY(fnmatch_test, tc) +{ + size_t i; + int flags, result; + struct testcase *t; + + for (i = 0; i < nitems(testcases); i++) { + t = &testcases[i]; + flags = t->flags; + do { + result = fnmatch(t->pattern, t->string, flags); + if (result != t->result) + break; + if (strchr(t->pattern, '\\') == NULL && + !(flags & FNM_NOESCAPE)) { + flags |= FNM_NOESCAPE; + result = fnmatch(t->pattern, t->string, flags); + if (result != t->result) + break; + flags = t->flags; + } + if (strchr(t->pattern, '\\') != NULL && + strchr(t->string, '\\') == NULL && + t->result == FNM_NOMATCH && + !(flags & (FNM_NOESCAPE | FNM_LEADING_DIR))) { + flags |= FNM_NOESCAPE; + result = fnmatch(t->pattern, t->string, flags); + if (result != t->result) + break; + flags = t->flags; + } + if ((t->string[0] != '.' || t->pattern[0] == '.' || + t->result == FNM_NOMATCH) && + !(flags & (FNM_PATHNAME | FNM_PERIOD))) { + flags |= FNM_PERIOD; + result = fnmatch(t->pattern, t->string, flags); + if (result != t->result) + break; + flags = t->flags; + } + if ((strchr(t->string, '/') == NULL || + t->result == FNM_NOMATCH) && + !(flags & FNM_PATHNAME)) { + flags |= FNM_PATHNAME; + result = fnmatch(t->pattern, t->string, flags); + if (result != t->result) + break; + flags = t->flags; + } + if ((((t->string[0] != '.' || t->pattern[0] == '.') && + strstr(t->string, "/.") == NULL) || + t->result == FNM_NOMATCH) && + flags & FNM_PATHNAME && !(flags & FNM_PERIOD)) { + flags |= FNM_PERIOD; + result = fnmatch(t->pattern, t->string, flags); + if (result != t->result) + break; + flags = t->flags; + } + if ((((t->string[0] != '.' || t->pattern[0] == '.') && + strchr(t->string, '/') == NULL) || + t->result == FNM_NOMATCH) && + !(flags & (FNM_PATHNAME | FNM_PERIOD))) { + flags |= FNM_PATHNAME | FNM_PERIOD; + result = fnmatch(t->pattern, t->string, flags); + if (result != t->result) + break; + flags = t->flags; + } + if ((strchr(t->string, '/') == NULL || t->result == 0) + && !(flags & FNM_LEADING_DIR)) { + flags |= FNM_LEADING_DIR; + result = fnmatch(t->pattern, t->string, flags); + if (result != t->result) + break; + flags = t->flags; + } + if (t->result == 0 && !(flags & FNM_CASEFOLD)) { + flags |= FNM_CASEFOLD; + result = fnmatch(t->pattern, t->string, flags); + if (result != t->result) + break; + flags = t->flags; + } + if (strchr(t->pattern, '\\') == NULL && + t->result == 0 && + !(flags & (FNM_NOESCAPE | FNM_CASEFOLD))) { + flags |= FNM_NOESCAPE | FNM_CASEFOLD; + result = fnmatch(t->pattern, t->string, flags); + if (result != t->result) + break; + flags = t->flags; + } + } while (0); + + ATF_CHECK(result == t->result); + if (result == t->result) + printf("fnmatch(\"%s\", \"%s\", %s) == %d\n", + t->pattern, t->string, flags_to_string(flags), result); + else + printf("fnmatch(\"%s\", \"%s\", %s) != %d (was %d)\n", + t->pattern, t->string, flags_to_string(flags), + t->result, result); + } + +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, fnmatch_test); + + return (atf_no_error()); +} diff --git a/lib/libc/tests/gen/fnmatch_testcases.h b/lib/libc/tests/gen/fnmatch_testcases.h new file mode 100644 index 0000000..537011f --- /dev/null +++ b/lib/libc/tests/gen/fnmatch_testcases.h @@ -0,0 +1,176 @@ +/*- + * Copyright (c) 2010 Jilles Tjoelker + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <fnmatch.h> + +struct testcase { + const char *pattern; + const char *string; + int flags; + int result; +} testcases[] = { + { "", "", 0, 0 }, + { "a", "a", 0, 0 }, + { "a", "b", 0, FNM_NOMATCH }, + { "a", "A", 0, FNM_NOMATCH }, + { "*", "a", 0, 0 }, + { "*", "aa", 0, 0 }, + { "*a", "a", 0, 0 }, + { "*a", "b", 0, FNM_NOMATCH }, + { "*a*", "b", 0, FNM_NOMATCH }, + { "*a*b*", "ab", 0, 0 }, + { "*a*b*", "qaqbq", 0, 0 }, + { "*a*bb*", "qaqbqbbq", 0, 0 }, + { "*a*bc*", "qaqbqbcq", 0, 0 }, + { "*a*bb*", "qaqbqbb", 0, 0 }, + { "*a*bc*", "qaqbqbc", 0, 0 }, + { "*a*bb", "qaqbqbb", 0, 0 }, + { "*a*bc", "qaqbqbc", 0, 0 }, + { "*a*bb", "qaqbqbbq", 0, FNM_NOMATCH }, + { "*a*bc", "qaqbqbcq", 0, FNM_NOMATCH }, + { "*a*a*a*a*a*a*a*a*a*a*", "aaaaaaaaa", 0, FNM_NOMATCH }, + { "*a*a*a*a*a*a*a*a*a*a*", "aaaaaaaaaa", 0, 0 }, + { "*a*a*a*a*a*a*a*a*a*a*", "aaaaaaaaaaa", 0, 0 }, + { ".*.*.*.*.*.*.*.*.*.*", ".........", 0, FNM_NOMATCH }, + { ".*.*.*.*.*.*.*.*.*.*", "..........", 0, 0 }, + { ".*.*.*.*.*.*.*.*.*.*", "...........", 0, 0 }, + { "*?*?*?*?*?*?*?*?*?*?*", "123456789", 0, FNM_NOMATCH }, + { "??????????*", "123456789", 0, FNM_NOMATCH }, + { "*??????????", "123456789", 0, FNM_NOMATCH }, + { "*?*?*?*?*?*?*?*?*?*?*", "1234567890", 0, 0 }, + { "??????????*", "1234567890", 0, 0 }, + { "*??????????", "1234567890", 0, 0 }, + { "*?*?*?*?*?*?*?*?*?*?*", "12345678901", 0, 0 }, + { "??????????*", "12345678901", 0, 0 }, + { "*??????????", "12345678901", 0, 0 }, + { "[x]", "x", 0, 0 }, + { "[*]", "*", 0, 0 }, + { "[?]", "?", 0, 0 }, + { "[", "[", 0, 0 }, + { "[[]", "[", 0, 0 }, + { "[[]", "x", 0, FNM_NOMATCH }, + { "[*]", "", 0, FNM_NOMATCH }, + { "[*]", "x", 0, FNM_NOMATCH }, + { "[?]", "x", 0, FNM_NOMATCH }, + { "*[*]*", "foo*foo", 0, 0 }, + { "*[*]*", "foo", 0, FNM_NOMATCH }, + { "[0-9]", "0", 0, 0 }, + { "[0-9]", "5", 0, 0 }, + { "[0-9]", "9", 0, 0 }, + { "[0-9]", "/", 0, FNM_NOMATCH }, + { "[0-9]", ":", 0, FNM_NOMATCH }, + { "[0-9]", "*", 0, FNM_NOMATCH }, + { "[!0-9]", "0", 0, FNM_NOMATCH }, + { "[!0-9]", "5", 0, FNM_NOMATCH }, + { "[!0-9]", "9", 0, FNM_NOMATCH }, + { "[!0-9]", "/", 0, 0 }, + { "[!0-9]", ":", 0, 0 }, + { "[!0-9]", "*", 0, 0 }, + { "*[0-9]", "a0", 0, 0 }, + { "*[0-9]", "a5", 0, 0 }, + { "*[0-9]", "a9", 0, 0 }, + { "*[0-9]", "a/", 0, FNM_NOMATCH }, + { "*[0-9]", "a:", 0, FNM_NOMATCH }, + { "*[0-9]", "a*", 0, FNM_NOMATCH }, + { "*[!0-9]", "a0", 0, FNM_NOMATCH }, + { "*[!0-9]", "a5", 0, FNM_NOMATCH }, + { "*[!0-9]", "a9", 0, FNM_NOMATCH }, + { "*[!0-9]", "a/", 0, 0 }, + { "*[!0-9]", "a:", 0, 0 }, + { "*[!0-9]", "a*", 0, 0 }, + { "*[0-9]", "a00", 0, 0 }, + { "*[0-9]", "a55", 0, 0 }, + { "*[0-9]", "a99", 0, 0 }, + { "*[0-9]", "a0a0", 0, 0 }, + { "*[0-9]", "a5a5", 0, 0 }, + { "*[0-9]", "a9a9", 0, 0 }, + { "\\*", "*", 0, 0 }, + { "\\?", "?", 0, 0 }, + { "\\[x]", "[x]", 0, 0 }, + { "\\[", "[", 0, 0 }, + { "\\\\", "\\", 0, 0 }, + { "*\\**", "foo*foo", 0, 0 }, + { "*\\**", "foo", 0, FNM_NOMATCH }, + { "*\\\\*", "foo\\foo", 0, 0 }, + { "*\\\\*", "foo", 0, FNM_NOMATCH }, + { "\\(", "(", 0, 0 }, + { "\\a", "a", 0, 0 }, + { "\\*", "a", 0, FNM_NOMATCH }, + { "\\?", "a", 0, FNM_NOMATCH }, + { "\\*", "\\*", 0, FNM_NOMATCH }, + { "\\?", "\\?", 0, FNM_NOMATCH }, + { "\\[x]", "\\[x]", 0, FNM_NOMATCH }, + { "\\[x]", "\\x", 0, FNM_NOMATCH }, + { "\\[", "\\[", 0, FNM_NOMATCH }, + { "\\(", "\\(", 0, FNM_NOMATCH }, + { "\\a", "\\a", 0, FNM_NOMATCH }, + { "\\", "\\", 0, FNM_NOMATCH }, + { "\\", "", 0, 0 }, + { "\\*", "\\*", FNM_NOESCAPE, 0 }, + { "\\?", "\\?", FNM_NOESCAPE, 0 }, + { "\\", "\\", FNM_NOESCAPE, 0 }, + { "\\\\", "\\", FNM_NOESCAPE, FNM_NOMATCH }, + { "\\\\", "\\\\", FNM_NOESCAPE, 0 }, + { "*\\*", "foo\\foo", FNM_NOESCAPE, 0 }, + { "*\\*", "foo", FNM_NOESCAPE, FNM_NOMATCH }, + { "*", ".", FNM_PERIOD, FNM_NOMATCH }, + { "?", ".", FNM_PERIOD, FNM_NOMATCH }, + { ".*", ".", 0, 0 }, + { ".*", "..", 0, 0 }, + { ".*", ".a", 0, 0 }, + { "[0-9]", ".", FNM_PERIOD, FNM_NOMATCH }, + { "a*", "a.", 0, 0 }, + { "a/a", "a/a", FNM_PATHNAME, 0 }, + { "a/*", "a/a", FNM_PATHNAME, 0 }, + { "*/a", "a/a", FNM_PATHNAME, 0 }, + { "*/*", "a/a", FNM_PATHNAME, 0 }, + { "a*b/*", "abbb/x", FNM_PATHNAME, 0 }, + { "a*b/*", "abbb/.x", FNM_PATHNAME, 0 }, + { "*", "a/a", FNM_PATHNAME, FNM_NOMATCH }, + { "*/*", "a/a/a", FNM_PATHNAME, FNM_NOMATCH }, + { "b/*", "b/.x", FNM_PATHNAME | FNM_PERIOD, FNM_NOMATCH }, + { "b*/*", "a/.x", FNM_PATHNAME | FNM_PERIOD, FNM_NOMATCH }, + { "b/.*", "b/.x", FNM_PATHNAME | FNM_PERIOD, 0 }, + { "b*/.*", "b/.x", FNM_PATHNAME | FNM_PERIOD, 0 }, + { "a", "A", FNM_CASEFOLD, 0 }, + { "A", "a", FNM_CASEFOLD, 0 }, + { "[a]", "A", FNM_CASEFOLD, 0 }, + { "[A]", "a", FNM_CASEFOLD, 0 }, + { "a", "b", FNM_CASEFOLD, FNM_NOMATCH }, + { "a", "a/b", FNM_PATHNAME, FNM_NOMATCH }, + { "*", "a/b", FNM_PATHNAME, FNM_NOMATCH }, + { "*b", "a/b", FNM_PATHNAME, FNM_NOMATCH }, + { "a", "a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0 }, + { "*", "a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0 }, + { "*", ".a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0 }, + { "*a", ".a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0 }, + { "*", ".a/b", FNM_PATHNAME | FNM_PERIOD | FNM_LEADING_DIR, FNM_NOMATCH }, + { "*a", ".a/b", FNM_PATHNAME | FNM_PERIOD | FNM_LEADING_DIR, FNM_NOMATCH }, + { "a*b/*", "abbb/.x", FNM_PATHNAME | FNM_PERIOD, FNM_NOMATCH }, +}; diff --git a/lib/libc/tests/gen/ftw_test.c b/lib/libc/tests/gen/ftw_test.c new file mode 100644 index 0000000..b120f01 --- /dev/null +++ b/lib/libc/tests/gen/ftw_test.c @@ -0,0 +1,127 @@ +/*- + * Copyright (c) 2012 Jilles Tjoelker + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Limited test program for nftw() as specified by IEEE Std. 1003.1-2008. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/wait.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <ftw.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <spawn.h> +#include <unistd.h> + +#include <atf-c.h> + +extern char **environ; + +static char template[] = "testftw.XXXXXXXXXX"; +static char dir[PATH_MAX]; +static int ftwflags; + +static int +cb(const char *path, const struct stat *st, int type, struct FTW *f) +{ + + switch (type) { + case FTW_D: + if ((ftwflags & FTW_DEPTH) == 0) + return (0); + break; + case FTW_DP: + if ((ftwflags & FTW_DEPTH) != 0) + return (0); + break; + case FTW_SL: + if ((ftwflags & FTW_PHYS) != 0) + return (0); + break; + } + ATF_CHECK_MSG(false, + "unexpected path=%s type=%d f.level=%d\n", + path, type, f->level); + return (0); +} + +ATF_TC_WITHOUT_HEAD(ftw_test); +ATF_TC_BODY(ftw_test, tc) +{ + int fd; + + ATF_REQUIRE_MSG(mkdtemp(template) != NULL, "mkdtemp failed"); + + /* XXX: the path needs to be absolute for the 0/FTW_DEPTH testcases */ + ATF_REQUIRE_MSG(realpath(template, dir) != NULL, + "realpath failed; errno=%d", errno); + + fd = open(dir, O_DIRECTORY|O_RDONLY); + ATF_REQUIRE_MSG(fd != -1, "open failed; errno=%d", errno); + + ATF_REQUIRE_MSG(mkdirat(fd, "d1", 0777) == 0, + "mkdirat failed; errno=%d", errno); + + ATF_REQUIRE_MSG(symlinkat(dir, fd, "d1/looper") == 0, + "symlinkat failed; errno=%d", errno); + + printf("ftwflags=FTW_PHYS\n"); + ftwflags = FTW_PHYS; + ATF_REQUIRE_MSG(nftw(dir, cb, 10, ftwflags) != -1, + "nftw FTW_PHYS failed; errno=%d", errno); + + printf("ftwflags=FTW_PHYS|FTW_DEPTH\n"); + ftwflags = FTW_PHYS|FTW_DEPTH; + ATF_REQUIRE_MSG(nftw(dir, cb, 10, ftwflags) != -1, + "nftw FTW_PHYS|FTW_DEPTH failed; errno=%d", errno); + + printf("ftwflags=0\n"); + ftwflags = 0; + ATF_REQUIRE_MSG(nftw(dir, cb, 10, ftwflags) != -1, + "nftw 0 failed; errno=%d", errno); + + printf("ftwflags=FTW_DEPTH\n"); + ftwflags = FTW_DEPTH; + ATF_REQUIRE_MSG(nftw(dir, cb, 10, ftwflags) != -1, + "nftw FTW_DEPTH failed; errno=%d", errno); + + close(fd); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, ftw_test); + + return (atf_no_error()); +} diff --git a/lib/libc/tests/gen/popen_test.c b/lib/libc/tests/gen/popen_test.c new file mode 100644 index 0000000..5c615b7 --- /dev/null +++ b/lib/libc/tests/gen/popen_test.c @@ -0,0 +1,251 @@ +/*- + * Copyright (c) 2013 Jilles Tjoelker + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Limited test program for popen() as specified by IEEE Std. 1003.1-2008, + * with BSD extensions. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/wait.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <atf-c.h> + +static volatile sig_atomic_t got_sigpipe; + +static void +sigpipe_handler(int sig __unused) +{ + got_sigpipe = 1; +} + +static void +check_cloexec(FILE *fp, const char *mode) +{ + int exp_flags, flags; + + flags = fcntl(fileno(fp), F_GETFD); + ATF_CHECK_MSG(flags != -1, "fcntl(F_GETFD) failed; errno=%d", errno); + if (flags == -1) + return; + if (strchr(mode, 'e') != NULL) + exp_flags = FD_CLOEXEC; + else + exp_flags = 0; + ATF_CHECK_MSG((flags & FD_CLOEXEC) == exp_flags, + "bad cloexec flag; %d != %d", flags, exp_flags); +} + +ATF_TC_WITHOUT_HEAD(popen_all_modes_test); +ATF_TC_BODY(popen_all_modes_test, tc) +{ + FILE *fp; + int i, status; + const char *mode; + const char *allmodes[] = { "r", "w", "r+", "re", "we", "r+e", "re+" }; + + for (i = 0; i < nitems(allmodes); i++) { + mode = allmodes[i]; + fp = popen("exit 7", mode); + ATF_CHECK_MSG(fp != NULL, "popen(, \"%s\") failed", mode); + if (fp == NULL) + continue; + check_cloexec(fp, mode); + status = pclose(fp); + ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 7, + "bad exit status (no I/O)"); + } +} + +ATF_TC_WITHOUT_HEAD(popen_rmodes_test); +ATF_TC_BODY(popen_rmodes_test, tc) +{ + FILE *fp; + const char *rmodes[] = { "r", "r+", "re", "r+e", "re+" }; + const char *mode; + char buf[80]; + int i, status; + + for (i = 0; i < nitems(rmodes); i++) { + mode = rmodes[i]; + fp = popen("exit 9", mode); + ATF_CHECK_MSG(fp != NULL, "popen(, \"%s\") failed", mode); + if (fp == NULL) + continue; + check_cloexec(fp, mode); + bool input_error_1 = !(fgetc(fp) != EOF || !feof(fp) || !ferror(fp)); + ATF_CHECK_MSG(!input_error_1, "input error 1"); + if (input_error_1) + continue; + status = pclose(fp); + ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 9, + "bad exit status (input)"); + } + + for (i = 0; i < nitems(rmodes); i++) { + char *sres; + mode = rmodes[i]; + fp = popen("echo hi there", mode); + ATF_CHECK_MSG(fp != NULL, "popen(, \"%s\") failed", mode); + if (fp == NULL) + continue; + check_cloexec(fp, mode); + ATF_CHECK_MSG((sres = fgets(buf, sizeof(buf), fp)) != NULL, + "Input error 2"); + if (sres != NULL) + ATF_CHECK_MSG(strcmp(buf, "hi there\n") == 0, + "Bad input 1"); + status = pclose(fp); + ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 0, + "Bad exit status (input)"); + } +} + +ATF_TC_WITHOUT_HEAD(popen_wmodes_test); +ATF_TC_BODY(popen_wmodes_test, tc) +{ + FILE *fp, *fp2; + const char *wmodes[] = { "w", "r+", "we", "r+e", "re+" }; + const char *mode; + struct sigaction act, oact; + int i, j, status; + + for (i = 0; i < nitems(wmodes); i++) { + mode = wmodes[i]; + fp = popen("read x && [ \"$x\" = abcd ]", mode); + ATF_CHECK_MSG(fp != NULL, "popen(, \"%s\") failed", mode); + if (fp == NULL) + continue; + check_cloexec(fp, mode); + ATF_CHECK_MSG(fputs("abcd\n", fp) != EOF, + "Output error 1"); + status = pclose(fp); + ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 0, + "Bad exit status (output)"); + } + + act.sa_handler = sigpipe_handler; + act.sa_flags = SA_RESTART; + sigemptyset(&act.sa_mask); + ATF_CHECK_MSG(sigaction(SIGPIPE, &act, &oact) != -1, + "sigaction() failed"); + for (i = 0; i < nitems(wmodes); i++) { + mode = wmodes[i]; + fp = popen("exit 88", mode); + ATF_CHECK_MSG(fp != NULL, "popen(, \"%s\") failed", mode); + if (fp == NULL) + continue; + check_cloexec(fp, mode); + got_sigpipe = 0; + while (fputs("abcd\n", fp) != EOF) + ; + ATF_CHECK_MSG(ferror(fp) && errno == EPIPE, "Expected EPIPE"); + ATF_CHECK_MSG(got_sigpipe, "Expected SIGPIPE"); + status = pclose(fp); + ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 88, + "Bad exit status (EPIPE)"); + } + ATF_CHECK_MSG(sigaction(SIGPIPE, &oact, NULL) != -1, + "sigaction() failed"); + + for (i = 0; i < nitems(wmodes); i++) { + for (j = 0; j < nitems(wmodes); j++) { + mode = wmodes[i]; + fp = popen("read x", mode); + ATF_CHECK_MSG(fp != NULL, + "popen(, \"%s\") failed", mode); + if (fp == NULL) + continue; + mode = wmodes[j]; + fp2 = popen("read x", mode); + ATF_CHECK_MSG(fp2 != NULL, + "popen(, \"%s\") failed", mode); + if (fp2 == NULL) { + pclose(fp); + continue; + } + /* If fp2 inherits fp's pipe, we will deadlock here. */ + status = pclose(fp); + ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 1, + "bad exit status (2 pipes)"); + status = pclose(fp2); + ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 1, + "bad exit status (2 pipes)"); + } + } +} + +ATF_TC_WITHOUT_HEAD(popen_rwmodes_test); +ATF_TC_BODY(popen_rwmodes_test, tc) +{ + const char *rwmodes[] = { "r+", "r+e", "re+" }; + FILE *fp; + const char *mode; + char *sres; + char buf[80]; + int i, ires, status; + + for (i = 0; i < nitems(rwmodes); i++) { + mode = rwmodes[i]; + fp = popen("read x && printf '%s\\n' \"Q${x#a}\"", mode); + ATF_CHECK_MSG(fp != NULL, "popen(, \"%s\") failed", mode); + if (fp == NULL) + continue; + check_cloexec(fp, mode); + ATF_CHECK_MSG((ires = fputs("abcd\n", fp)) != EOF, + "Output error 2"); + if (ires != EOF) { + sres = fgets(buf, sizeof(buf), fp); + ATF_CHECK_MSG(sres != NULL, "Input error 3"); + if (sres != NULL) + ATF_CHECK_MSG(strcmp(buf, "Qbcd\n") == 0, + "Bad input 2"); + } + status = pclose(fp); + ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 0, + "bad exit status (I/O)"); + } +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, popen_all_modes_test); + ATF_TP_ADD_TC(tp, popen_rmodes_test); + ATF_TP_ADD_TC(tp, popen_wmodes_test); + ATF_TP_ADD_TC(tp, popen_rwmodes_test); + + return (atf_no_error()); +} diff --git a/lib/libc/tests/gen/posix_spawn_test.c b/lib/libc/tests/gen/posix_spawn_test.c new file mode 100644 index 0000000..e04d103 --- /dev/null +++ b/lib/libc/tests/gen/posix_spawn_test.c @@ -0,0 +1,103 @@ +/*- + * Copyright (c) 2011 Jilles Tjoelker + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Test program for posix_spawn() and posix_spawnp() as specified by + * IEEE Std. 1003.1-2008. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/wait.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <spawn.h> + +#include <atf-c.h> + +char *myenv[2] = { "answer=42", NULL }; + +ATF_TC_WITHOUT_HEAD(posix_spawn_simple_test); +ATF_TC_BODY(posix_spawn_simple_test, tc) +{ + char *myargs[4]; + int error, status; + pid_t pid, waitres; + + /* Make sure we have no child processes. */ + while (waitpid(-1, NULL, 0) != -1) + ; + ATF_REQUIRE_MSG(errno == ECHILD, "errno was not ECHILD: %d", errno); + + /* Simple test. */ + myargs[0] = "sh"; + myargs[1] = "-c"; + myargs[2] = "exit $answer"; + myargs[3] = NULL; + error = posix_spawnp(&pid, myargs[0], NULL, NULL, myargs, myenv); + ATF_REQUIRE(error == 0); + waitres = waitpid(pid, &status, 0); + ATF_REQUIRE(waitres == pid); + ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == 42); +} + +ATF_TC_WITHOUT_HEAD(posix_spawn_no_such_command_negative_test); +ATF_TC_BODY(posix_spawn_no_such_command_negative_test, tc) +{ + char *myargs[4]; + int error, status; + pid_t pid, waitres; + + /* + * If the executable does not exist, the function shall either fail + * and not create a child process or succeed and create a child + * process that exits with status 127. + */ + myargs[0] = "/var/empty/nonexistent"; + myargs[1] = NULL; + error = posix_spawn(&pid, myargs[0], NULL, NULL, myargs, myenv); + if (error == 0) { + waitres = waitpid(pid, &status, 0); + ATF_REQUIRE(waitres == pid); + ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == 127); + } else { + ATF_REQUIRE(error == ENOENT); + waitres = waitpid(-1, NULL, 0); + ATF_REQUIRE(waitres == -1 && errno == ECHILD); + } +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, posix_spawn_simple_test); + ATF_TP_ADD_TC(tp, posix_spawn_no_such_command_negative_test); + + return (atf_no_error()); +} diff --git a/lib/libc/tests/gen/test-fnmatch.c b/lib/libc/tests/gen/test-fnmatch.c new file mode 100644 index 0000000..7771ab3 --- /dev/null +++ b/lib/libc/tests/gen/test-fnmatch.c @@ -0,0 +1,102 @@ +/*- + * Copyright (c) 2010 Jilles Tjoelker + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "fnmatch_testcases.h" + +static int +write_sh_tests(const char *progname, int num) +{ + size_t i; + struct testcase *t; + + printf("# Generated by %s -s %d, do not edit.\n", progname, num); + printf("# $" "FreeBSD$\n"); + printf("failures=\n"); + printf("failed() { printf '%%s\\n' \"Failed: $1 '$2' '$3'\"; failures=x$failures; }\n"); + if (num == 1) { + printf("testmatch() { eval \"case \\$2 in ''$1) ;; *) failed testmatch \\\"\\$@\\\";; esac\"; }\n"); + printf("testnomatch() { eval \"case \\$2 in ''$1) failed testnomatch \\\"\\$@\\\";; esac\"; }\n"); + } else if (num == 2) { + printf("# We do not treat a backslash specially in this case,\n"); + printf("# but this is not the case in all shells.\n"); + printf("netestmatch() { case $2 in $1) ;; *) failed netestmatch \"$@\";; esac; }\n"); + printf("netestnomatch() { case $2 in $1) failed netestnomatch \"$@\";; esac; }\n"); + } + + for (i = 0; i < nitems(testcases); i++) { + t = &testcases[i]; + if (strchr(t->pattern, '\'') != NULL || + strchr(t->string, '\'') != NULL) + continue; + if (t->flags == 0 && strcmp(t->pattern, "\\") == 0) + continue; + if (num == 1 && t->flags == 0) + printf("test%smatch '%s' '%s'\n", + t->result == FNM_NOMATCH ? "no" : "", + t->pattern, t->string); + if (num == 2 && (t->flags == FNM_NOESCAPE || + (t->flags == 0 && strchr(t->pattern, '\\') == NULL))) + printf("netest%smatch '%s' '%s'\n", + t->result == FNM_NOMATCH ? "no" : "", + t->pattern, t->string); + } + printf("[ -z \"$failures\" ]\n"); + return 0; +} + +static void +usage(char *progname) +{ + fprintf(stderr, "usage: %s [-s num]\n", progname); + fprintf(stderr, "-s option writes tests for sh(1), num is 1 or 2\n"); +} + +int +main(int argc, char *argv[]) +{ + int opt; + + while ((opt = getopt(argc, argv, "s:")) != -1) { + switch (opt) { + case 's': + return (write_sh_tests(argv[0], atoi(optarg))); + default: + usage(argv[0]); + exit(1); + } + } + usage(argv[0]); + exit(1); +} diff --git a/lib/libc/tests/gen/wordexp_test.c b/lib/libc/tests/gen/wordexp_test.c new file mode 100644 index 0000000..3ccc677 --- /dev/null +++ b/lib/libc/tests/gen/wordexp_test.c @@ -0,0 +1,360 @@ +/*- + * Copyright (c) 2003 Tim J. Robbins + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Test program for wordexp() and wordfree() as specified by + * IEEE Std. 1003.1-2001. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/wait.h> +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <wordexp.h> + +#include <atf-c.h> + +static void +chld_handler(int x) +{ + int status, serrno; + + (void)x; + serrno = errno; + while (waitpid(-1, &status, WNOHANG) > 0) + ; + errno = serrno; +} + +ATF_TC_WITHOUT_HEAD(simple_test); +ATF_TC_BODY(simple_test, tc) +{ + wordexp_t we; + int r; + + /* Test that the macros are there. */ + (void)(WRDE_APPEND + WRDE_DOOFFS + WRDE_NOCMD + WRDE_REUSE + + WRDE_SHOWERR + WRDE_UNDEF); + (void)(WRDE_BADCHAR + WRDE_BADVAL + WRDE_CMDSUB + WRDE_NOSPACE + + WRDE_SYNTAX); + + /* Simple test. */ + r = wordexp("hello world", &we, 0); + ATF_REQUIRE(r == 0); + ATF_REQUIRE(we.we_wordc == 2); + ATF_REQUIRE(strcmp(we.we_wordv[0], "hello") == 0); + ATF_REQUIRE(strcmp(we.we_wordv[1], "world") == 0); + ATF_REQUIRE(we.we_wordv[2] == NULL); + wordfree(&we); +} + +ATF_TC_WITHOUT_HEAD(long_output_test); +ATF_TC_BODY(long_output_test, tc) +{ + char longdata[6 * 10000 + 1]; + wordexp_t we; + int i, r; + + /* Long output. */ + for (i = 0; i < 10000; i++) + snprintf(longdata + 6 * i, 7, "%05d ", i); + r = wordexp(longdata, &we, 0); + ATF_REQUIRE(r == 0); + ATF_REQUIRE(we.we_wordc == 10000); + ATF_REQUIRE(we.we_wordv[10000] == NULL); + wordfree(&we); +} + +ATF_TC_WITHOUT_HEAD(WRDE_DOOFFS_test); +ATF_TC_BODY(WRDE_DOOFFS_test, tc) +{ + wordexp_t we; + int r; + + we.we_offs = 3; + r = wordexp("hello world", &we, WRDE_DOOFFS); + ATF_REQUIRE(r == 0); + ATF_REQUIRE(we.we_wordc == 2); + ATF_REQUIRE(we.we_wordv[0] == NULL); + ATF_REQUIRE(we.we_wordv[1] == NULL); + ATF_REQUIRE(we.we_wordv[2] == NULL); + ATF_REQUIRE(strcmp(we.we_wordv[3], "hello") == 0); + ATF_REQUIRE(strcmp(we.we_wordv[4], "world") == 0); + ATF_REQUIRE(we.we_wordv[5] == NULL); + wordfree(&we); +} + +ATF_TC_WITHOUT_HEAD(WRDE_REUSE_test); +ATF_TC_BODY(WRDE_REUSE_test, tc) +{ + wordexp_t we; + int r; + + r = wordexp("hello world", &we, 0); + r = wordexp("hello world", &we, WRDE_REUSE); + ATF_REQUIRE(r == 0); + ATF_REQUIRE(we.we_wordc == 2); + ATF_REQUIRE(strcmp(we.we_wordv[0], "hello") == 0); + ATF_REQUIRE(strcmp(we.we_wordv[1], "world") == 0); + ATF_REQUIRE(we.we_wordv[2] == NULL); + wordfree(&we); +} + +ATF_TC_WITHOUT_HEAD(WRDE_APPEND_test); +ATF_TC_BODY(WRDE_APPEND_test, tc) +{ + wordexp_t we; + int r; + + r = wordexp("this is", &we, 0); + ATF_REQUIRE(r == 0); + r = wordexp("a test", &we, WRDE_APPEND); + ATF_REQUIRE(r == 0); + ATF_REQUIRE(we.we_wordc == 4); + ATF_REQUIRE(strcmp(we.we_wordv[0], "this") == 0); + ATF_REQUIRE(strcmp(we.we_wordv[1], "is") == 0); + ATF_REQUIRE(strcmp(we.we_wordv[2], "a") == 0); + ATF_REQUIRE(strcmp(we.we_wordv[3], "test") == 0); + ATF_REQUIRE(we.we_wordv[4] == NULL); + wordfree(&we); +} + +ATF_TC_WITHOUT_HEAD(WRDE_DOOFFS__WRDE_APPEND_test); +ATF_TC_BODY(WRDE_DOOFFS__WRDE_APPEND_test, tc) +{ + wordexp_t we; + int r; + + we.we_offs = 2; + r = wordexp("this is", &we, WRDE_DOOFFS); + ATF_REQUIRE(r == 0); + r = wordexp("a test", &we, WRDE_APPEND|WRDE_DOOFFS); + ATF_REQUIRE(r == 0); + r = wordexp("of wordexp", &we, WRDE_APPEND|WRDE_DOOFFS); + ATF_REQUIRE(r == 0); + ATF_REQUIRE(we.we_wordc == 6); + ATF_REQUIRE(we.we_wordv[0] == NULL); + ATF_REQUIRE(we.we_wordv[1] == NULL); + ATF_REQUIRE(strcmp(we.we_wordv[2], "this") == 0); + ATF_REQUIRE(strcmp(we.we_wordv[3], "is") == 0); + ATF_REQUIRE(strcmp(we.we_wordv[4], "a") == 0); + ATF_REQUIRE(strcmp(we.we_wordv[5], "test") == 0); + ATF_REQUIRE(strcmp(we.we_wordv[6], "of") == 0); + ATF_REQUIRE(strcmp(we.we_wordv[7], "wordexp") == 0); + ATF_REQUIRE(we.we_wordv[8] == NULL); + wordfree(&we); +} + +ATF_TC_WITHOUT_HEAD(WRDE_UNDEF_test); +ATF_TC_BODY(WRDE_UNDEF_test, tc) +{ + wordexp_t we; + int r; + + r = wordexp("${dont_set_me}", &we, WRDE_UNDEF); + ATF_REQUIRE(r == WRDE_BADVAL); +} + +ATF_TC_WITHOUT_HEAD(WRDE_NOCMD_test); +ATF_TC_BODY(WRDE_NOCMD_test, tc) +{ + wordexp_t we; + int r; + + r = wordexp("`date`", &we, WRDE_NOCMD); + ATF_REQUIRE(r == WRDE_CMDSUB); + r = wordexp("\"`date`\"", &we, WRDE_NOCMD); + ATF_REQUIRE(r == WRDE_CMDSUB); + r = wordexp("$(date)", &we, WRDE_NOCMD); + ATF_REQUIRE(r == WRDE_CMDSUB); + r = wordexp("\"$(date)\"", &we, WRDE_NOCMD); + ATF_REQUIRE(r == WRDE_CMDSUB); + r = wordexp("$((3+5))", &we, WRDE_NOCMD); + ATF_REQUIRE(r == 0); + r = wordexp("\\$\\(date\\)", &we, WRDE_NOCMD|WRDE_REUSE); + ATF_REQUIRE(r == 0); + r = wordexp("'`date`'", &we, WRDE_NOCMD|WRDE_REUSE); + ATF_REQUIRE(r == 0); + r = wordexp("'$(date)'", &we, WRDE_NOCMD|WRDE_REUSE); + ATF_REQUIRE(r == 0); + wordfree(&we); +} + +ATF_TC_WITHOUT_HEAD(WRDE_BADCHAR_test); +ATF_TC_BODY(WRDE_BADCHAR_test, tc) +{ + wordexp_t we; + int r; + + r = wordexp("'\n|&;<>(){}'", &we, 0); + ATF_REQUIRE(r == 0); + r = wordexp("\"\n|&;<>(){}\"", &we, WRDE_REUSE); + ATF_REQUIRE(r == 0); + r = wordexp("\\\n\\|\\&\\;\\<\\>\\(\\)\\{\\}", &we, WRDE_REUSE); + ATF_REQUIRE(r == 0); + wordfree(&we); + r = wordexp("test \n test", &we, 0); + ATF_REQUIRE(r == WRDE_BADCHAR); + r = wordexp("test | test", &we, 0); + ATF_REQUIRE(r == WRDE_BADCHAR); + r = wordexp("test & test", &we, 0); + ATF_REQUIRE(r == WRDE_BADCHAR); + r = wordexp("test ; test", &we, 0); + ATF_REQUIRE(r == WRDE_BADCHAR); + r = wordexp("test > test", &we, 0); + ATF_REQUIRE(r == WRDE_BADCHAR); + r = wordexp("test < test", &we, 0); + ATF_REQUIRE(r == WRDE_BADCHAR); + r = wordexp("test ( test", &we, 0); + ATF_REQUIRE(r == WRDE_BADCHAR); + r = wordexp("test ) test", &we, 0); + ATF_REQUIRE(r == WRDE_BADCHAR); + r = wordexp("test { test", &we, 0); + ATF_REQUIRE(r == WRDE_BADCHAR); + r = wordexp("test } test", &we, 0); + ATF_REQUIRE(r == WRDE_BADCHAR); +} + +ATF_TC_WITHOUT_HEAD(WRDE_SYNTAX_test); +ATF_TC_BODY(WRDE_SYNTAX_test, tc) +{ + wordexp_t we; + int r; + + r = wordexp("'", &we, 0); + ATF_REQUIRE(r == WRDE_SYNTAX); + r = wordexp("'", &we, WRDE_UNDEF); + ATF_REQUIRE(r == WRDE_SYNTAX); + r = wordexp("'\\'", &we, 0); + ATF_REQUIRE(r == 0); + ATF_REQUIRE(we.we_wordc == 1); + ATF_REQUIRE(strcmp(we.we_wordv[0], "\\") == 0); + ATF_REQUIRE(we.we_wordv[1] == NULL); + wordfree(&we); + /* Two syntax errors that are not detected by the current we_check(). */ + r = wordexp("${IFS:+'}", &we, 0); + ATF_REQUIRE(r == WRDE_SYNTAX); + r = wordexp("${IFS:+'}", &we, WRDE_UNDEF); + ATF_REQUIRE(r == WRDE_SYNTAX); + r = wordexp("$(case)", &we, 0); + ATF_REQUIRE(r == WRDE_SYNTAX); + r = wordexp("$(case)", &we, WRDE_UNDEF); + ATF_REQUIRE(r == WRDE_SYNTAX); +} + +ATF_TC_WITHOUT_HEAD(with_SIGCHILD_handler_test); +ATF_TC_BODY(with_SIGCHILD_handler_test, tc) +{ + struct sigaction sa; + wordexp_t we; + int r; + + /* With a SIGCHLD handler that reaps all zombies. */ + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + sa.sa_handler = chld_handler; + r = sigaction(SIGCHLD, &sa, NULL); + ATF_REQUIRE(r == 0); + r = wordexp("hello world", &we, 0); + ATF_REQUIRE(r == 0); + ATF_REQUIRE(we.we_wordc == 2); + ATF_REQUIRE(strcmp(we.we_wordv[0], "hello") == 0); + ATF_REQUIRE(strcmp(we.we_wordv[1], "world") == 0); + ATF_REQUIRE(we.we_wordv[2] == NULL); + wordfree(&we); + sa.sa_handler = SIG_DFL; + r = sigaction(SIGCHLD, &sa, NULL); + ATF_REQUIRE(r == 0); +} + +ATF_TC_WITHOUT_HEAD(with_unused_non_default_IFS_test); +ATF_TC_BODY(with_unused_non_default_IFS_test, tc) +{ + wordexp_t we; + int r; + + /* + * With IFS set to a non-default value (without depending on whether + * IFS is inherited or not). + */ + r = setenv("IFS", ":", 1); + ATF_REQUIRE(r == 0); + r = wordexp("hello world", &we, 0); + ATF_REQUIRE(r == 0); + ATF_REQUIRE(we.we_wordc == 2); + ATF_REQUIRE(strcmp(we.we_wordv[0], "hello") == 0); + ATF_REQUIRE(strcmp(we.we_wordv[1], "world") == 0); + ATF_REQUIRE(we.we_wordv[2] == NULL); + wordfree(&we); + r = unsetenv("IFS"); + ATF_REQUIRE(r == 0); +} + +ATF_TC_WITHOUT_HEAD(with_used_non_default_IFS_test); +ATF_TC_BODY(with_used_non_default_IFS_test, tc) +{ + wordexp_t we; + int r; + + /* + * With IFS set to a non-default value, and using it. + */ + r = setenv("IFS", ":", 1); + ATF_REQUIRE(r == 0); + r = wordexp("${IFS+hello:world}", &we, 0); + ATF_REQUIRE(r == 0); + ATF_REQUIRE(we.we_wordc == 2); + ATF_REQUIRE(strcmp(we.we_wordv[0], "hello") == 0); + ATF_REQUIRE(strcmp(we.we_wordv[1], "world") == 0); + ATF_REQUIRE(we.we_wordv[2] == NULL); + wordfree(&we); + r = unsetenv("IFS"); + ATF_REQUIRE(r == 0); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, simple_test); + ATF_TP_ADD_TC(tp, long_output_test); + ATF_TP_ADD_TC(tp, WRDE_DOOFFS_test); + ATF_TP_ADD_TC(tp, WRDE_REUSE_test); + ATF_TP_ADD_TC(tp, WRDE_APPEND_test); + ATF_TP_ADD_TC(tp, WRDE_DOOFFS__WRDE_APPEND_test); + ATF_TP_ADD_TC(tp, WRDE_UNDEF_test); + ATF_TP_ADD_TC(tp, WRDE_NOCMD_test); + ATF_TP_ADD_TC(tp, WRDE_BADCHAR_test); + ATF_TP_ADD_TC(tp, WRDE_SYNTAX_test); + ATF_TP_ADD_TC(tp, with_SIGCHILD_handler_test); + ATF_TP_ADD_TC(tp, with_unused_non_default_IFS_test); + ATF_TP_ADD_TC(tp, with_used_non_default_IFS_test); + + return (atf_no_error()); +} |