Committing regression tests for all implemented nsswitch databases.

Detailed description and instructions are in the README file.
This work had been basically done during GSoC 2006.

Approved by:	brooks (mentor)
This commit is contained in:
bushman 2007-04-15 11:02:31 +00:00
parent 1e51d3c721
commit 31175191f1
20 changed files with 5390 additions and 0 deletions

View File

@ -0,0 +1,12 @@
# $FreeBSD$
TESTS= test-getaddr test-getgr test-gethostby test-getpw test-getproto\
test-getrpc test-getserv test-getusershell
CFLAGS+= -g -Wall
.PHONY: tests
tests: ${TESTS}
.PHONY: clean
clean:
-rm -f ${TESTS}

View File

@ -0,0 +1,203 @@
$FreeBSD$
A brief how-to
--------------
Each nsswitch regression test does 2 kinds of actions:
1. It runs a series of queries and tests the correctness of results.
There are 2 basic criterias which are used for that:
- numbers must be in the correct range
- certain pointers should not be NULL
2. It makes a snapshot of the results of all queries that were made.
The idea of snapshots is to test that nsswitch-related function
calls behave equally (i.e. return same results for the same queries)
between system upgrades. When the test is executed and the snapshot is
already created, the test will compare the result of each query with
the appropriate result from the snapshot and will signal if they
differ.
In order for nsswitch tests to be as useful as possible you should use
them in the following way:
Step 1 (before upgrading your system).
Build the tests with "make" command and execute them with "prove -v"
command. If there are errors during the execution, then appropriate
nsswitch functions should be checked. Note, that errors on this state
can happen only if the particular function return incorrect data.
After the stage 1 a number of "snapshot_[test name]" files will appear
in your test folder.
Step 2 (after upgrading you system).
Rebuild the tests with "make clean; make" command and execute them
again with "prove -v" (check that "snapshot_[test name]" files
are in the same folder with tests). On this stage regression tests
will catch not only the correctness errors, but will also determine
the changes in nsswitch functions behaviour.
In case of the test failure you will get the following message:
To get more details about the error you should do the following:
Step 1. Run the test alone with debug output enabled.
Step 2. Mail the snapshot file and the debug test output to the
freebsd-current@ mailing list.
Example testing session for getpwXXX() family of functions
----------------------------------------------------------
1. make
2. prove -v ./test-getpw.t
test-getpw....1..8
ok 1 - getpwnam()
ok 2 - getpwuid()
ok 3 - getpwent()
ok 4 - getpwent() 2-pass
ok 5 - building snapshot, if needed
ok 6 - getpwnam() snapshot
ok 7 - getpwuid() snapshot
ok 8 - getpwent() snapshot
ok
All tests successful.
Files=1, Tests=8, 1 wallclock secs ( 0.00 cusr + 0.20 csys = 0.20 CPU)
3. Upgrading the system.
4. make clean; make
5. prove -v ./test-getpw.t (suppose that something has gone wrong)
test-getpw....1..8
ok 1 - getpwnam()
ok 2 - getpwuid()
ok 3 - getpwent()
ok 4 - getpwent() 2-pass
ok 5 - building snapshot, if needed
not ok 6 - getpwnam() snapshot
ok 7 - getpwuid() snapshot
not ok 8 - getpwent() snapshot
FAILED tests 6, 8
Failed 2/8 tests, 75.00% okay
Failed 1/1 test scripts, 0.00% okay. 2/8 subtests failed, 75.00% okay.
6. We see that test number 6 failed. According to get-getpw.t, this test
is executed like this:
do_test 6 'getpwnam() snapshot' '-n -s snapshot_pwd'
To determine why the test has failed, we need to run it in debug mode -
it means adding "-d" to the options list.
7. ./test-getpw -dn -s snapshot_pwd
...
testing getpwnam() with the following data:
toor:*:0:0:0::ne-again Superuser:/root::0:4831
testing correctness with the following data:
toor:*:0:0:0::Bourne-again Superuser:/root::0:4831
correct
not ok
8. Here we can see that the data from snapshot (first "toor" line) and
the data received from the getpwnam() call (second "toor" line) are
different. It is the reason why the test has failed. If you can't
(or don't want) to investigate the problem by yourself, mail
the test debug output and the snapshot file to the developers list.
Notes on using standalone nsswitch tests
----------------------------------------
All nsswitch tests have [-d] optional command line argument which enables
debug output. The debug output can be extremely helpful to determine the
cause of test failure.
In all nsswitch tests -s <file> command line argument specifies the
snapshot file. If this file doesn't exist, it would be built during
test execution. If it already exists then it will be used to check
the results of particular function calls. This argument is mostly
optional, but some tests (test-getaddr and test-getusershell) force
it to be specified.
test-gethostby and test-getaddr require the list of hostnames, that should
be queried during the test. This list must be specified via -f <file>
command line argument. Each hostname should occupy exactly one line
in the file.
Detailed tests description
--------------------------
./test-getaddr - tests the getaddrinfo() function.
Usage: test-getaddr [-d] [-46] [-s <file>] -f <file>
-d - enable debug output
-4 - force IPv4 usage
-6 - force IPv6 usage
-s - build/use specified snapshot file
-f - use specified hostnames list for testing
./test-getgr
Usage: test-getgr -nge2 [-d] [-s <file>]
-d - enable debug output
-n - test getgrnam(3)
-g - test getgrgid(3)
-e - test getgrent(3)
-2 - test getgrent(3) in 2-pass mode
-s - build/use specified snapshot file
./test-gethostby
Usage: test-gethostby -na2i [-o] [-d] [-m46] [-s <file>] -f <file>
-n - test gethostbyname2(3)
-a - test gethostbyaddr(3)
-2 - test gethostbyname2(3) results to be equal with getaddrinfo(3)
results for the similar query
-i - test gethostbyaddr(3) results to be equal with getnameinfo(3)
results for the similar query
-o - use getipnodebyname(3)/getipnodebyaddr(3) for testing instead of
gethostbyname2(3)/gethostbyaddr(3)
-d - enable debug output
-m - force IPv4-to-IPv6 mapping
-4 - force IPv4 usage
-6 - force IPv6 usage
-s - build/use specified snapshot file
-f - use specified hostnames list for testing
./test-getproto
Usage: test-getproto -nve2 [-d] [-s <file>]
-d - enable debug output
-n - test getprotobyname(3)
-v - test getprotobynumber(3)
-e - test getprotoent(3)
-2 - test getprotoent(3) in 2-pass mode
-s - build/use specified snapshot file
./test-getpw
Usage: test-getpw -nue2 [-d] [-s <file>]
-d - enable debug output
-n - test getpwnam(3)
-u - test getpwuid(3)
-e - test getpwent(3)
-2 - test getpwent(3) in 2-pass mode
-s - build/use snapshot file
./test-getrpc
Usage: test-getrpc -nve2 [-d] [-s <file>]
-d - enable debug output
-n - test getrpcbyname(3)
-v - test getrpcbynumber(3)
-e - test getrpcent(3)
-2 - test getrpcent(3) in 2-pass mode
-s - build/use specified snapshot file
./test-getserv
Usage: test-getserv -npe2 [-d] [-s <file>]
-d - enable debug output
-n - test getservbyname(3)
-p - test getservbyport(3)
-e - test getservent(3)
-2 - test getservent(3) in 2-pass mode
-s - build/use specified snapshot file
./test-getusershell
Usage: test-getusershell [-d] -s <file>
-d - enable debug output
-s - build/use specified snapshot file

View File

@ -0,0 +1,94 @@
# $FreeBSD$
localhost
above.warped.net
anoncvs.cirr.com
anoncvs.isc.netbsd.org
anoncvs.leo.org
anoncvs.netbsd.lt
anoncvs.netbsd.ro
anoncvs.netbsd.se
antioche.antioche.eu.org
boulder.tele.dk
centaurus.4web.cz
chur.math.ntnu.no
cnftp.bjpu.edu.cn
console.netbsd.org
cvs.fi.netbsd.org
cvs.mikrolahti.fi
cvs.netbsd.org
cvsup-netbsd.leo.org
cvsup.netbsd.se
cvsup.pasta.cs.uit.no
ftp.bitcon.no
ftp.chg.ru
ftp.duth.gr
ftp.estpak.ee
ftp.fsn.hu
ftp.funet.fi
ftp.grondar.za
ftp.leo.org
ftp.netbsd.lt
ftp.netbsd.org
ftp.nluug.nl
ftp.plig.org
ftp.uni-erlangen.de
ftp.xgate.co.kr
gd.tuwien.ac.at
gort.ludd.luth.se
grappa.unix-ag.uni-kl.de
info.wins.uva.nl
irc.warped.net
knug.youn.co.kr
lala.iri.co.jp
mail.jp.netbsd.org
mail.kr.netbsd.org
mail.netbsd.org
melanoma.cs.rmit.edu.au
mirror.aarnet.edu.au
mirror.netbsd.com.br
mirror03.inet.tele.dk
moon.vub.ac.be
nbwww.sergei.cc
net.bsd.cz
netbsd.3miasto.net
netbsd.4ka.mipt.ru
netbsd.apk.od.ua
netbsd.csie.nctu.edu.tw
netbsd.enderunix.org
netbsd.ftp.fu-berlin.de
netbsd.netlead.com.au
netbsd.nsysu.edu.tw
netbsd.pair.com
netbsd.stevens-tech.edu
netbsd.triada.bg
netbsd.unix.net.nz
netbsd.unixtech.be
netbsd.vejas.lt
netbsd.wagener-consulting.lu
netbsd.zarco.org
netbsdiso.interoute.net.uk
netbsdwww.bitcon.no
netbsdwww.cordef.com.pl
netbsdwww.cs.rmit.edu.au
netbsdwww.interoute.net.uk
news.gw.com
ns.netbsd.org
pigu.iri.co.jp
pluto.cdpa.nsysu.edu.tw
projects.slowass.net
server6.pasta.cs.uit.no
skeleton.phys.spbu.ru
snoopy.allbsd.org
spike.allbsd.org
sundry.netbsd.org
tanya.sergei.cc
web-a.fi.gw.com
web-a.us.gw.com
web.netbsd.mirror.arhea.net
www.en.netbsd.de
www.netbsd.cl
www.netbsd.nl
www.netbsd.org
www.netbsd.ro
zathras.netbsd.org
zeppo.rediris.es

View File

@ -0,0 +1,538 @@
/*-
* Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
* All rights rehted.
*
* 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 <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <assert.h>
#include <errno.h>
#include <netdb.h>
#include <resolv.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stringlist.h>
#include <unistd.h>
#include "testutil.h"
enum test_methods {
TEST_GETADDRINFO,
TEST_BUILD_SNAPSHOT
};
static int debug = 0;
static struct addrinfo hints;
static enum test_methods method = TEST_GETADDRINFO;
DECLARE_TEST_DATA(addrinfo)
DECLARE_TEST_FILE_SNAPSHOT(addrinfo)
DECLARE_2PASS_TEST(addrinfo)
static void clone_addrinfo(struct addrinfo *, struct addrinfo const *);
static int compare_addrinfo(struct addrinfo *, struct addrinfo *, void *);
static void dump_addrinfo(struct addrinfo *);
static void free_addrinfo(struct addrinfo *);
static void sdump_addrinfo(struct addrinfo *, char *, size_t);
IMPLEMENT_TEST_DATA(addrinfo)
IMPLEMENT_TEST_FILE_SNAPSHOT(addrinfo)
IMPLEMENT_2PASS_TEST(addrinfo)
static void
clone_addrinfo(struct addrinfo *dest, struct addrinfo const *src)
{
assert(dest != NULL);
assert(src != NULL);
memcpy(dest, src, sizeof(struct addrinfo));
if (src->ai_canonname != NULL)
dest->ai_canonname = strdup(src->ai_canonname);
if (src->ai_addr != NULL) {
dest->ai_addr = (struct sockaddr *)malloc(src->ai_addrlen);
assert(dest->ai_addr != NULL);
memcpy(dest->ai_addr, src->ai_addr, src->ai_addrlen);
}
if (src->ai_next != NULL) {
dest->ai_next = (struct addrinfo *)malloc(
sizeof(struct addrinfo));
assert(dest->ai_next != NULL);
clone_addrinfo(dest->ai_next, src->ai_next);
}
}
static int
compare_addrinfo_(struct addrinfo *ai1, struct addrinfo *ai2)
{
if ((ai1 == NULL) || (ai2 == NULL))
return (-1);
if ((ai1->ai_flags != ai2->ai_flags) ||
(ai1->ai_family != ai2->ai_family) ||
(ai1->ai_socktype != ai2->ai_socktype) ||
(ai1->ai_protocol != ai2->ai_protocol) ||
(ai1->ai_addrlen != ai2->ai_addrlen) ||
(((ai1->ai_addr == NULL) || (ai2->ai_addr == NULL)) &&
(ai1->ai_addr != ai2->ai_addr)) ||
(((ai1->ai_canonname == NULL) || (ai2->ai_canonname == NULL)) &&
(ai1->ai_canonname != ai2->ai_canonname)))
return (-1);
if ((ai1->ai_canonname != NULL) &&
(strcmp(ai1->ai_canonname, ai2->ai_canonname) != 0))
return (-1);
if ((ai1->ai_addr != NULL) &&
(memcmp(ai1->ai_addr, ai2->ai_addr, ai1->ai_addrlen) != 0))
return (-1);
if ((ai1->ai_next == NULL) && (ai2->ai_next == NULL))
return (0);
else
return (compare_addrinfo_(ai1->ai_next, ai2->ai_next));
}
static int
compare_addrinfo(struct addrinfo *ai1, struct addrinfo *ai2, void *mdata)
{
int rv;
if (debug) {
printf("testing equality of 2 addrinfo structures\n");
}
rv = compare_addrinfo_(ai1, ai2);
if (debug) {
if (rv == 0)
printf("equal\n");
else {
dump_addrinfo(ai1);
dump_addrinfo(ai2);
printf("not equal\n");
}
}
return (rv);
}
void
free_addrinfo(struct addrinfo *ai)
{
if (ai == NULL)
return;
free(ai->ai_addr);
free(ai->ai_canonname);
free_addrinfo(ai->ai_next);
}
void
sdump_addrinfo(struct addrinfo *ai, char *buffer, size_t buflen)
{
int written, i;
written = snprintf(buffer, buflen, "%d %d %d %d %d ",
ai->ai_flags, ai->ai_family, ai->ai_socktype, ai->ai_protocol,
ai->ai_addrlen);
buffer += written;
if (written > buflen)
return;
buflen -= written;
written = snprintf(buffer, buflen, "%s ",
ai->ai_canonname == NULL ? "(null)" : ai->ai_canonname);
buffer += written;
if (written > buflen)
return;
buflen -= written;
if (ai->ai_addr == NULL) {
written = snprintf(buffer, buflen, "(null)");
buffer += written;
if (written > buflen)
return;
buflen -= written;
} else {
for (i = 0; i < ai->ai_addrlen; ++i ) {
written = snprintf(buffer, buflen,
i + 1 != ai->ai_addrlen ? "%d." : "%d",
((unsigned char *)ai->ai_addr)[i]);
buffer += written;
if (written > buflen)
return;
buflen -= written;
if (buflen == 0)
return;
}
}
if (ai->ai_next != NULL) {
written = snprintf(buffer, buflen, ":");
buffer += written;
if (written > buflen)
return;
buflen -= written;
sdump_addrinfo(ai->ai_next, buffer, buflen);
}
}
void
dump_addrinfo(struct addrinfo *result)
{
if (result != NULL) {
char buffer[2048];
sdump_addrinfo(result, buffer, sizeof(buffer));
printf("%s\n", buffer);
} else
printf("(null)\n");
}
static int
addrinfo_read_snapshot_addr(char *addr, unsigned char *result, size_t len)
{
char *s, *ps, *ts;
ps = addr;
while ( (s = strsep(&ps, ".")) != NULL) {
if (len == 0)
return (-1);
*result = (unsigned char)strtol(s, &ts, 10);
++result;
if (*ts != '\0')
return (-1);
--len;
}
if (len != 0)
return (-1);
else
return (0);
}
static int
addrinfo_read_snapshot_ai(struct addrinfo *ai, char *line)
{
char *s, *ps, *ts;
int i, rv, *pi;
rv = 0;
i = 0;
ps = line;
memset(ai, 0, sizeof(struct addrinfo));
while ( (s = strsep(&ps, " ")) != NULL) {
switch (i) {
case 0:
case 1:
case 2:
case 3:
pi = &ai->ai_flags + i;
*pi = (int)strtol(s, &ts, 10);
if (*ts != '\0')
goto fin;
break;
case 4:
ai->ai_addrlen = (socklen_t)strtol(s, &ts, 10);
if (*ts != '\0')
goto fin;
break;
case 5:
if (strcmp(s, "(null)") != 0) {
ai->ai_canonname = strdup(s);
assert(ai->ai_canonname != NULL);
}
break;
case 6:
if (strcmp(s, "(null)") != 0) {
ai->ai_addr = (struct sockaddr *)malloc(
ai->ai_addrlen);
assert(ai->ai_addr != NULL);
memset(ai->ai_addr, 0, ai->ai_addrlen);
rv = addrinfo_read_snapshot_addr(s,
(unsigned char *)ai->ai_addr,
ai->ai_addrlen);
if (rv != 0)
goto fin;
}
break;
default:
/* NOTE: should not be reachable */
rv = -1;
goto fin;
};
++i;
}
fin:
if ((i != 7) || (rv != 0)) {
free_addrinfo(ai);
memset(ai, 0, sizeof(struct addrinfo));
return (-1);
}
return (0);
}
static int
addrinfo_read_snapshot_func(struct addrinfo *ai, char *line)
{
struct addrinfo *ai2;
char *s, *ps;
int i, rv;
if (debug)
printf("1 line read from snapshot:\n%s\n", line);
rv = 0;
i = 0;
ps = line;
s = strsep(&ps, ":");
if (s == NULL)
return (-1);
rv = addrinfo_read_snapshot_ai(ai, s);
if (rv != 0)
return (-1);
ai2 = ai;
while ( (s = strsep(&ps, ":")) != NULL) {
ai2->ai_next = (struct addrinfo *)malloc(
sizeof(struct addrinfo));
assert(ai2->ai_next != NULL);
memset(ai2->ai_next, 0, sizeof(struct addrinfo));
rv = addrinfo_read_snapshot_ai(ai2->ai_next, s);
if (rv != 0) {
free_addrinfo(ai);
return (-1);
}
ai2 = ai2->ai_next;
}
return (0);
}
static int
addrinfo_test_correctness(struct addrinfo *ai, void *mdata)
{
if (debug) {
printf("testing correctness with the following data:\n");
dump_addrinfo(ai);
}
if (ai == NULL)
goto errfin;
if (!((ai->ai_family >= 0) && (ai->ai_family < AF_MAX)))
goto errfin;
if ((ai->ai_socktype != 0) && (ai->ai_socktype != SOCK_STREAM) &&
(ai->ai_socktype != SOCK_DGRAM) && (ai->ai_socktype != SOCK_RAW))
goto errfin;
if ((ai->ai_protocol != 0) && (ai->ai_protocol != IPPROTO_UDP) &&
(ai->ai_protocol != IPPROTO_TCP))
goto errfin;
if ((ai->ai_flags & ~(AI_CANONNAME | AI_NUMERICHOST | AI_PASSIVE)) != 0)
goto errfin;
if ((ai->ai_addrlen != ai->ai_addr->sa_len) ||
(ai->ai_family != ai->ai_addr->sa_family))
goto errfin;
if (debug)
printf("correct\n");
return (0);
errfin:
if (debug)
printf("incorrect\n");
return (-1);
}
static int
addrinfo_read_hostlist_func(struct addrinfo *ai, char *line)
{
struct addrinfo *result;
int rv;
if (debug)
printf("resolving %s: ", line);
rv = getaddrinfo(line, NULL, &hints, &result);
if (rv == 0) {
if (debug)
printf("found\n");
rv = addrinfo_test_correctness(result, NULL);
if (rv != 0) {
freeaddrinfo(result);
return (rv);
}
clone_addrinfo(ai, result);
freeaddrinfo(result);
} else {
if (debug)
printf("not found\n");
memset(ai, 0, sizeof(struct addrinfo));
}
return (0);
}
static void
usage(void)
{
(void)fprintf(stderr,
"Usage: %s [-d] [-46] [-s <file]> -f <file>\n",
getprogname());
exit(1);
}
int
main(int argc, char **argv)
{
struct addrinfo_test_data td, td_snap;
char *snapshot_file, *hostlist_file;
int rv;
int c;
if (argc < 2)
usage();
snapshot_file = NULL;
hostlist_file = NULL;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = PF_UNSPEC;
hints.ai_flags = AI_CANONNAME;
while ((c = getopt(argc, argv, "46dns:f:")) != -1)
switch (c) {
case '4':
hints.ai_family = PF_INET;
case '6':
hints.ai_family = PF_INET6;
break;
case 'd':
debug = 1;
break;
case 's':
snapshot_file = strdup(optarg);
method = TEST_BUILD_SNAPSHOT;
break;
case 'f':
hostlist_file = strdup(optarg);
break;
default:
usage();
}
TEST_DATA_INIT(addrinfo, &td, clone_addrinfo, free_addrinfo);
TEST_DATA_INIT(addrinfo, &td_snap, clone_addrinfo, free_addrinfo);
if (hostlist_file == NULL)
usage();
if (access(hostlist_file, R_OK) != 0) {
if (debug)
printf("can't access the hostlist file %s\n",
hostlist_file);
usage();
}
if (debug)
printf("building host lists from %s\n", hostlist_file);
rv = TEST_SNAPSHOT_FILE_READ(addrinfo, hostlist_file, &td,
addrinfo_read_hostlist_func);
if (rv != 0)
goto fin;
if (snapshot_file != NULL) {
if (access(snapshot_file, W_OK | R_OK) != 0) {
if (errno == ENOENT)
method = TEST_BUILD_SNAPSHOT;
else {
if (debug)
printf("can't access the snapshot file %s\n",
snapshot_file);
rv = -1;
goto fin;
}
} else {
rv = TEST_SNAPSHOT_FILE_READ(addrinfo, snapshot_file,
&td_snap, addrinfo_read_snapshot_func);
if (rv != 0) {
if (debug)
printf("error reading snapshot file\n");
goto fin;
}
}
}
switch (method) {
case TEST_GETADDRINFO:
if (snapshot_file != NULL)
rv = DO_2PASS_TEST(addrinfo, &td, &td_snap,
compare_addrinfo, NULL);
break;
case TEST_BUILD_SNAPSHOT:
if (snapshot_file != NULL) {
rv = TEST_SNAPSHOT_FILE_WRITE(addrinfo, snapshot_file, &td,
sdump_addrinfo);
}
break;
default:
rv = 0;
break;
};
fin:
TEST_DATA_DESTROY(addrinfo, &td_snap);
TEST_DATA_DESTROY(addrinfo, &td);
free(hostlist_file);
free(snapshot_file);
return (rv);
}

View File

@ -0,0 +1,33 @@
#!/bin/sh
# $FreeBSD$
do_test() {
number=$1
comment=$2
opt=$3
if ./$executable $opt; then
echo "ok $number - $comment"
else
echo "not ok $number - $comment"
fi
}
cd `dirname $0`
executable=`basename $0 .t`
make $executable 2>&1 > /dev/null
echo 1..6
#Tests with hints.ai_family is set to PF_UNSPEC
do_test 1 'getaddrinfo() (PF_UNSPEC)' '-f mach'
do_test 2 'getaddrinfo() snapshot (PF_UNSPEC)' '-f mach -s snapshot_ai'
#Tests with hints.ai_family is set to PF_INET
do_test 3 'getaddrinfo() (PF_INET)' '-f mach'
do_test 4 'getaddrinfo() snapshot (PF_INET)' '-4 -f mach -s snapshot_ai4'
#Tests with hints.ai_family is set to PF_INET6
do_test 5 'getaddrinfo() (PF_INET6)' '-f mach'
do_test 6 'getaddrinfo() snapshot (PF_INET6)' '-6 -f mach -s snapshot_ai6'

View File

@ -0,0 +1,534 @@
/*-
* Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
* All rights regrped.
*
* 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 <arpa/inet.h>
#include <assert.h>
#include <errno.h>
#include <grp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stringlist.h>
#include <unistd.h>
#include "testutil.h"
enum test_methods {
TEST_GETGRENT,
TEST_GETGRNAM,
TEST_GETGRGID,
TEST_GETGRENT_2PASS,
TEST_BUILD_SNAPSHOT
};
static int debug = 0;
static enum test_methods method = TEST_BUILD_SNAPSHOT;
DECLARE_TEST_DATA(group)
DECLARE_TEST_FILE_SNAPSHOT(group)
DECLARE_1PASS_TEST(group)
DECLARE_2PASS_TEST(group)
static void clone_group(struct group *, struct group const *);
static int compare_group(struct group *, struct group *, void *);
static void dump_group(struct group *);
static void free_group(struct group *);
static void sdump_group(struct group *, char *, size_t);
static int group_read_snapshot_func(struct group *, char *);
static int group_check_ambiguity(struct group_test_data *,
struct group *);
static int group_fill_test_data(struct group_test_data *);
static int group_test_correctness(struct group *, void *);
static int group_test_getgrnam(struct group *, void *);
static int group_test_getgrgid(struct group *, void *);
static int group_test_getgrent(struct group *, void *);
static void usage(void) __attribute__((__noreturn__));
IMPLEMENT_TEST_DATA(group)
IMPLEMENT_TEST_FILE_SNAPSHOT(group)
IMPLEMENT_1PASS_TEST(group)
IMPLEMENT_2PASS_TEST(group)
static void
clone_group(struct group *dest, struct group const *src)
{
assert(dest != NULL);
assert(src != NULL);
char **cp;
int members_num;
memset(dest, 0, sizeof(struct group));
if (src->gr_name != NULL) {
dest->gr_name = strdup(src->gr_name);
assert(dest->gr_name != NULL);
}
if (src->gr_passwd != NULL) {
dest->gr_passwd = strdup(src->gr_passwd);
assert(dest->gr_passwd != NULL);
}
dest->gr_gid = src->gr_gid;
if (src->gr_mem != NULL) {
members_num = 0;
for (cp = src->gr_mem; *cp; ++cp)
++members_num;
dest->gr_mem = (char **)malloc(
(members_num + 1) * (sizeof(char *)));
assert(dest->gr_mem != NULL);
memset(dest->gr_mem, 0, (members_num+1) * (sizeof(char *)));
for (cp = src->gr_mem; *cp; ++cp) {
dest->gr_mem[cp - src->gr_mem] = strdup(*cp);
assert(dest->gr_mem[cp - src->gr_mem] != NULL);
}
}
}
static void
free_group(struct group *grp)
{
char **cp;
assert(grp != NULL);
free(grp->gr_name);
free(grp->gr_passwd);
for (cp = grp->gr_mem; *cp; ++cp)
free(*cp);
free(grp->gr_mem);
}
static int
compare_group(struct group *grp1, struct group *grp2, void *mdata)
{
char **c1, **c2;
if (grp1 == grp2)
return (0);
if ((grp1 == NULL) || (grp2 == NULL))
goto errfin;
if ((strcmp(grp1->gr_name, grp2->gr_name) != 0) ||
(strcmp(grp1->gr_passwd, grp2->gr_passwd) != 0) ||
(grp1->gr_gid != grp2->gr_gid))
goto errfin;
c1 = grp1->gr_mem;
c2 = grp2->gr_mem;
if ((grp1->gr_mem == NULL) || (grp2->gr_mem == NULL))
goto errfin;
for (;*c1 && *c2; ++c1, ++c2)
if (strcmp(*c1, *c2) != 0)
goto errfin;
if ((*c1 != '\0') || (*c2 != '\0'))
goto errfin;
return 0;
errfin:
if ((debug) && (mdata == NULL)) {
printf("following structures are not equal:\n");
dump_group(grp1);
dump_group(grp2);
}
return (-1);
}
static void
sdump_group(struct group *grp, char *buffer, size_t buflen)
{
char **cp;
int written;
written = snprintf(buffer, buflen, "%s %s %d",
grp->gr_name, grp->gr_passwd, grp->gr_gid);
buffer += written;
if (written > buflen)
return;
buflen -= written;
if (grp->gr_mem != NULL) {
if (*(grp->gr_mem) != '\0') {
for (cp = grp->gr_mem; *cp; ++cp) {
written = snprintf(buffer, buflen, " %s",*cp);
buffer += written;
if (written > buflen)
return;
buflen -= written;
if (buflen == 0)
return;
}
} else
snprintf(buffer, buflen, " nomem");
} else
snprintf(buffer, buflen, " (null)");
}
static int
group_read_snapshot_func(struct group *grp, char *line)
{
StringList *sl;
char *s, *ps, *ts;
int i;
if (debug)
printf("1 line read from snapshot:\n%s\n", line);
i = 0;
sl = NULL;
ps = line;
memset(grp, 0, sizeof(struct group));
while ( (s = strsep(&ps, " ")) != NULL) {
switch (i) {
case 0:
grp->gr_name = strdup(s);
assert(grp->gr_name != NULL);
break;
case 1:
grp->gr_passwd = strdup(s);
assert(grp->gr_passwd != NULL);
break;
case 2:
grp->gr_gid = (gid_t)strtol(s, &ts, 10);
if (*ts != '\0') {
free(grp->gr_name);
free(grp->gr_passwd);
return (-1);
}
break;
default:
if (sl == NULL) {
if (strcmp(s, "(null)") == 0)
return (0);
sl = sl_init();
assert(sl != NULL);
if (strcmp(s, "nomem") != 0) {
ts = strdup(s);
assert(ts != NULL);
sl_add(sl, ts);
}
} else {
ts = strdup(s);
assert(ts != NULL);
sl_add(sl, ts);
}
break;
};
++i;
}
if (i < 3) {
free(grp->gr_name);
free(grp->gr_passwd);
memset(grp, 0, sizeof(struct group));
return (-1);
}
sl_add(sl, NULL);
grp->gr_mem = sl->sl_str;
/* NOTE: is it a dirty hack or not? */
free(sl);
return (0);
}
static void
dump_group(struct group *result)
{
if (result != NULL) {
char buffer[1024];
sdump_group(result, buffer, sizeof(buffer));
printf("%s\n", buffer);
} else
printf("(null)\n");
}
static int
group_fill_test_data(struct group_test_data *td)
{
struct group *grp;
setgroupent(1);
while ((grp = getgrent()) != NULL) {
if (group_test_correctness(grp, NULL) == 0)
TEST_DATA_APPEND(group, td, grp);
else
return (-1);
}
endgrent();
return (0);
}
static int
group_test_correctness(struct group *grp, void *mdata)
{
if (debug) {
printf("testing correctness with the following data:\n");
dump_group(grp);
}
if (grp == NULL)
goto errfin;
if (grp->gr_name == NULL)
goto errfin;
if (grp->gr_passwd == NULL)
goto errfin;
if (grp->gr_mem == NULL)
goto errfin;
if (debug)
printf("correct\n");
return (0);
errfin:
if (debug)
printf("incorrect\n");
return (-1);
}
/* group_check_ambiguity() is needed here because when doing the getgrent()
* calls sequence, records from different nsswitch sources can be different,
* though having the same pw_name/pw_uid */
static int
group_check_ambiguity(struct group_test_data *td, struct group *pwd)
{
return (TEST_DATA_FIND(group, td, pwd, compare_group,
NULL) != NULL ? 0 : -1);
}
static int
group_test_getgrnam(struct group *grp_model, void *mdata)
{
struct group *grp;
if (debug) {
printf("testing getgrnam() with the following data:\n");
dump_group(grp_model);
}
grp = getgrnam(grp_model->gr_name);
if (group_test_correctness(grp, NULL) != 0)
goto errfin;
if ((compare_group(grp, grp_model, NULL) != 0) &&
(group_check_ambiguity((struct group_test_data *)mdata, grp)
!=0))
goto errfin;
if (debug)
printf("ok\n");
return (0);
errfin:
if (debug)
printf("not ok\n");
return (-1);
}
static int
group_test_getgrgid(struct group *grp_model, void *mdata)
{
struct group *grp;
if (debug) {
printf("testing getgrgid() with the following data...\n");
dump_group(grp_model);
}
grp = getgrgid(grp_model->gr_gid);
if ((group_test_correctness(grp, NULL) != 0) ||
((compare_group(grp, grp_model, NULL) != 0) &&
(group_check_ambiguity((struct group_test_data *)mdata, grp)
!= 0))) {
if (debug)
printf("not ok\n");
return (-1);
} else {
if (debug)
printf("ok\n");
return (0);
}
}
static int
group_test_getgrent(struct group *grp, void *mdata)
{
/* Only correctness can be checked when doing 1-pass test for
* getgrent(). */
return (group_test_correctness(grp, NULL));
}
static void
usage(void)
{
(void)fprintf(stderr,
"Usage: %s -nge2 [-d] [-s <file>]\n",
getprogname());
exit(1);
}
int
main(int argc, char **argv)
{
struct group_test_data td, td_snap, td_2pass;
char *snapshot_file;
int rv;
int c;
if (argc < 2)
usage();
snapshot_file = NULL;
while ((c = getopt(argc, argv, "nge2ds:")) != -1)
switch (c) {
case 'd':
debug++;
break;
case 'n':
method = TEST_GETGRNAM;
break;
case 'g':
method = TEST_GETGRGID;
break;
case 'e':
method = TEST_GETGRENT;
break;
case '2':
method = TEST_GETGRENT_2PASS;
break;
case 's':
snapshot_file = strdup(optarg);
break;
default:
usage();
}
TEST_DATA_INIT(group, &td, clone_group, free_group);
TEST_DATA_INIT(group, &td_snap, clone_group, free_group);
if (snapshot_file != NULL) {
if (access(snapshot_file, W_OK | R_OK) != 0) {
if (errno == ENOENT)
method = TEST_BUILD_SNAPSHOT;
else {
if (debug)
printf("can't access the file %s\n",
snapshot_file);
rv = -1;
goto fin;
}
} else {
if (method == TEST_BUILD_SNAPSHOT) {
rv = 0;
goto fin;
}
TEST_SNAPSHOT_FILE_READ(group, snapshot_file,
&td_snap, group_read_snapshot_func);
}
}
rv = group_fill_test_data(&td);
if (rv == -1)
return (-1);
switch (method) {
case TEST_GETGRNAM:
if (snapshot_file == NULL)
rv = DO_1PASS_TEST(group, &td,
group_test_getgrnam, (void *)&td);
else
rv = DO_1PASS_TEST(group, &td_snap,
group_test_getgrnam, (void *)&td_snap);
break;
case TEST_GETGRGID:
if (snapshot_file == NULL)
rv = DO_1PASS_TEST(group, &td,
group_test_getgrgid, (void *)&td);
else
rv = DO_1PASS_TEST(group, &td_snap,
group_test_getgrgid, (void *)&td_snap);
break;
case TEST_GETGRENT:
if (snapshot_file == NULL)
rv = DO_1PASS_TEST(group, &td, group_test_getgrent,
(void *)&td);
else
rv = DO_2PASS_TEST(group, &td, &td_snap,
compare_group, NULL);
break;
case TEST_GETGRENT_2PASS:
TEST_DATA_INIT(group, &td_2pass, clone_group, free_group);
rv = group_fill_test_data(&td_2pass);
if (rv != -1)
rv = DO_2PASS_TEST(group, &td, &td_2pass,
compare_group, NULL);
TEST_DATA_DESTROY(group, &td_2pass);
break;
case TEST_BUILD_SNAPSHOT:
if (snapshot_file != NULL)
rv = TEST_SNAPSHOT_FILE_WRITE(group, snapshot_file, &td,
sdump_group);
break;
default:
rv = 0;
break;
};
fin:
TEST_DATA_DESTROY(group, &td_snap);
TEST_DATA_DESTROY(group, &td);
free(snapshot_file);
return (rv);
}

View File

@ -0,0 +1,29 @@
#!/bin/sh
# $FreeBSD$
do_test() {
number=$1
comment=$2
opt=$3
if ./$executable $opt; then
echo "ok $number - $comment"
else
echo "not ok $number - $comment"
fi
}
cd `dirname $0`
executable=`basename $0 .t`
make $executable 2>&1 > /dev/null
echo 1..8
do_test 1 'getgrnam()' '-n'
do_test 2 'getgrgid()' '-g'
do_test 3 'getgrent()' '-e'
do_test 4 'getgrent() 2-pass' '-2'
do_test 5 'building snapshot, if needed' '-s snapshot_grp'
do_test 6 'getgrnam() snapshot' '-n -s snapshot_grp'
do_test 7 'getgrgid() snapshot' '-g -s snapshot_grp'
do_test 8 'getgrent() snapshot' '-e -s snapshot_grp'

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,78 @@
#!/bin/sh
# $FreeBSD$
do_test() {
number=$1
comment=$2
opt=$3
if ./$executable $opt; then
echo "ok $number - $comment"
else
echo "not ok $number - $comment"
fi
}
cd `dirname $0`
executable=`basename $0 .t`
make $executable 2>&1 > /dev/null
echo 1..32
#Tests for gethostby***() functions
#IPv4-driven testing
do_test 1 'gethostbyname2() (IPv4)' '-4 -n -f mach'
do_test 2 'gethostbyaddr() (IPv4)' '-4 -a -f mach'
do_test 3 'gethostbyname2()-getaddrinfo() (IPv4)' '-4 -2 -f mach'
do_test 4 'gethostbyaddr()-getnameinfo() (IPv4)' '-4 -i -f mach'
do_test 5 'gethostbyname2() snapshot (IPv4)'\
'-4 -n -s snapshot_htname4 -f mach'
do_test 6 'gethostbyaddr() snapshot (IPv4)'\
'-4 -a -s snapshot_htaddr4 -f mach'
#IPv6-driven testing
do_test 7 'gethostbyname2() (IPv6)' '-6 -n -f mach'
do_test 8 'gethostbyaddr() (IPv6)' '-6 -a -f mach'
do_test 9 'gethostbyname2()-getaddrinfo() (IPv6)' '-6 -2 -f mach'
do_test 10 'gethostbyaddr()-getnameinfo() (IPv6)' '-6 -i -f mach'
do_test 11 'gethostbyname2() snapshot (IPv6)'\
'-6 -n -s snapshot_htname6 -f mach'
do_test 12 'gethostbyaddr() snapshot (IPv6)'\
'-6 -a -s snapshot_htaddr6 -f mach'
#Mapped IPv6-driven testing (getaddrinfo() equality test is useless here)
do_test 13 'gethostbyname2() (IPv6 mapped)' '-m -n -f mach'
do_test 14 'gethostbyaddr() (IPv6 mapped)' '-m -a -f mach'
do_test 15 'gethostbyname2() snapshot (IPv6 mapped)'\
'-m -n -s snapshot_htname6map -f mach'
do_test 16 'gethostbyaddr() snapshot (IPv6 mapped)'\
'-m -a -s snapshot_htaddr6map -f mach'
#Tests for getipnodeby***() functions
#IPv4-driven testing
do_test 17 'getipnodebyname() (IPv4)' '-o -4 -n -f mach'
do_test 18 'getipnodebyaddr() (IPv4)' '-o -4 -a -f mach'
do_test 19 'getipnodebyname()-getaddrinfo() (IPv4)' '-o -4 -2 -f mach'
do_test 20 'getipnodebyaddr()-getnameinfo() (IPv4)' '-o -4 -i -f mach'
do_test 21 'getipnodebyname() snapshot (IPv4)'\
'-o -4 -n -s snapshot_ipnodename4 -f mach'
do_test 22 'getipnodebyname() snapshot (IPv4)'\
'-o -4 -a -s snapshot_ipnodeaddr4 -f mach'
#IPv6-driven testing
do_test 23 'getipnodebyname() (IPv6)' '-o -6 -n -f mach'
do_test 24 'getipnodebyaddr() (IPv6)' '-o -6 -a -f mach'
do_test 25 'getipnodebyname()-getaddrinfo() (IPv6)' '-o -6 -2 -f mach'
do_test 26 'getipnodebyaddr()-getnameinfo() (IPv6)' '-o -6 -i -f mach'
do_test 27 'getipnodebyname() snapshot (IPv6)'\
'-o -6 -n -s snapshot_ipnodename6 -f mach'
do_test 28 'getipnodebyaddr() snapshot (IPv6)'\
'-o -6 -a -s snapshot_ipnodeaddr6 -f mach'
#Mapped IPv6-driven testing (getaddrinfo() equality test is useless here)
do_test 29 'getipnodebyname() (IPv6)' '-o -m -n -f mach'
do_test 30 'getipnodebyaddr() (IPv6)' '-o -m -a -f mach'
do_test 31 'getipnodebyname() snapshot (IPv6)'\
'-o -m -n -s snapshot_ipnodename6map -f mach'
do_test 32 'getipnodebyaddr() snapshot (IPv6)'\
'-o -m -a -s snapshot_ipnodeaddr6map -f mach'

View File

@ -0,0 +1,536 @@
/*-
* Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
* All rights repeed.
*
* 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 <arpa/inet.h>
#include <assert.h>
#include <errno.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stringlist.h>
#include <unistd.h>
#include "testutil.h"
enum test_methods {
TEST_GETPROTOENT,
TEST_GETPROTOBYNAME,
TEST_GETPROTOBYNUMBER,
TEST_GETPROTOENT_2PASS,
TEST_BUILD_SNAPSHOT
};
static int debug = 0;
static enum test_methods method = TEST_BUILD_SNAPSHOT;
DECLARE_TEST_DATA(protoent)
DECLARE_TEST_FILE_SNAPSHOT(protoent)
DECLARE_1PASS_TEST(protoent)
DECLARE_2PASS_TEST(protoent)
static void clone_protoent(struct protoent *, struct protoent const *);
static int compare_protoent(struct protoent *, struct protoent *, void *);
static void dump_protoent(struct protoent *);
static void free_protoent(struct protoent *);
static void sdump_protoent(struct protoent *, char *, size_t);
static int protoent_read_snapshot_func(struct protoent *, char *);
static int protoent_check_ambiguity(struct protoent_test_data *,
struct protoent *);
static int protoent_fill_test_data(struct protoent_test_data *);
static int protoent_test_correctness(struct protoent *, void *);
static int protoent_test_getprotobyname(struct protoent *, void *);
static int protoent_test_getprotobynumber(struct protoent *, void *);
static int protoent_test_getprotoent(struct protoent *, void *);
static void usage(void) __attribute__((__noreturn__));
IMPLEMENT_TEST_DATA(protoent)
IMPLEMENT_TEST_FILE_SNAPSHOT(protoent)
IMPLEMENT_1PASS_TEST(protoent)
IMPLEMENT_2PASS_TEST(protoent)
static void
clone_protoent(struct protoent *dest, struct protoent const *src)
{
assert(dest != NULL);
assert(src != NULL);
char **cp;
int aliases_num;
memset(dest, 0, sizeof(struct protoent));
if (src->p_name != NULL) {
dest->p_name = strdup(src->p_name);
assert(dest->p_name != NULL);
}
dest->p_proto = src->p_proto;
if (src->p_aliases != NULL) {
aliases_num = 0;
for (cp = src->p_aliases; *cp; ++cp)
++aliases_num;
dest->p_aliases = (char **)malloc((aliases_num+1) * (sizeof(char *)));
assert(dest->p_aliases != NULL);
memset(dest->p_aliases, 0, (aliases_num+1) * (sizeof(char *)));
for (cp = src->p_aliases; *cp; ++cp) {
dest->p_aliases[cp - src->p_aliases] = strdup(*cp);
assert(dest->p_aliases[cp - src->p_aliases] != NULL);
}
}
}
static void
free_protoent(struct protoent *pe)
{
char **cp;
assert(pe != NULL);
free(pe->p_name);
for (cp = pe->p_aliases; *cp; ++cp)
free(*cp);
free(pe->p_aliases);
}
static int
compare_protoent(struct protoent *pe1, struct protoent *pe2, void *mdata)
{
char **c1, **c2;
if (pe1 == pe2)
return 0;
if ((pe1 == NULL) || (pe2 == NULL))
goto errfin;
if ((strcmp(pe1->p_name, pe2->p_name) != 0) ||
(pe1->p_proto != pe2->p_proto))
goto errfin;
c1 = pe1->p_aliases;
c2 = pe2->p_aliases;
if ((pe1->p_aliases == NULL) || (pe2->p_aliases == NULL))
goto errfin;
for (;*c1 && *c2; ++c1, ++c2)
if (strcmp(*c1, *c2) != 0)
goto errfin;
if ((*c1 != '\0') || (*c2 != '\0'))
goto errfin;
return 0;
errfin:
if ((debug) && (mdata == NULL)) {
printf("following structures are not equal:\n");
dump_protoent(pe1);
dump_protoent(pe2);
}
return (-1);
}
static void
sdump_protoent(struct protoent *pe, char *buffer, size_t buflen)
{
char **cp;
int written;
written = snprintf(buffer, buflen, "%s %d",
pe->p_name, pe->p_proto);
buffer += written;
if (written > buflen)
return;
buflen -= written;
if (pe->p_aliases != NULL) {
if (*(pe->p_aliases) != '\0') {
for (cp = pe->p_aliases; *cp; ++cp) {
written = snprintf(buffer, buflen, " %s",*cp);
buffer += written;
if (written > buflen)
return;
buflen -= written;
if (buflen == 0)
return;
}
} else
snprintf(buffer, buflen, " noaliases");
} else
snprintf(buffer, buflen, " (null)");
}
static int
protoent_read_snapshot_func(struct protoent *pe, char *line)
{
StringList *sl;
char *s, *ps, *ts;
int i;
if (debug)
printf("1 line read from snapshot:\n%s\n", line);
i = 0;
sl = NULL;
ps = line;
memset(pe, 0, sizeof(struct protoent));
while ( (s = strsep(&ps, " ")) != NULL) {
switch (i) {
case 0:
pe->p_name = strdup(s);
assert(pe->p_name != NULL);
break;
case 1:
pe->p_proto = (int)strtol(s, &ts, 10);
if (*ts != '\0') {
free(pe->p_name);
return (-1);
}
break;
default:
if (sl == NULL) {
if (strcmp(s, "(null)") == 0)
return (0);
sl = sl_init();
assert(sl != NULL);
if (strcmp(s, "noaliases") != 0) {
ts = strdup(s);
assert(ts != NULL);
sl_add(sl, ts);
}
} else {
ts = strdup(s);
assert(ts != NULL);
sl_add(sl, ts);
}
break;
};
++i;
}
if (i < 3) {
free(pe->p_name);
memset(pe, 0, sizeof(struct protoent));
return (-1);
}
sl_add(sl, NULL);
pe->p_aliases = sl->sl_str;
/* NOTE: is it a dirty hack or not? */
free(sl);
return (0);
}
static void
dump_protoent(struct protoent *result)
{
if (result != NULL) {
char buffer[1024];
sdump_protoent(result, buffer, sizeof(buffer));
printf("%s\n", buffer);
} else
printf("(null)\n");
}
static int
protoent_fill_test_data(struct protoent_test_data *td)
{
struct protoent *pe;
setprotoent(1);
while ((pe = getprotoent()) != NULL) {
if (protoent_test_correctness(pe, NULL) == 0)
TEST_DATA_APPEND(protoent, td, pe);
else
return (-1);
}
endprotoent();
return (0);
}
static int
protoent_test_correctness(struct protoent *pe, void *mdata)
{
if (debug) {
printf("testing correctness with the following data:\n");
dump_protoent(pe);
}
if (pe == NULL)
goto errfin;
if (pe->p_name == NULL)
goto errfin;
if (pe->p_proto < 0)
goto errfin;
if (pe->p_aliases == NULL)
goto errfin;
if (debug)
printf("correct\n");
return (0);
errfin:
if (debug)
printf("incorrect\n");
return (-1);
}
/* protoent_check_ambiguity() is needed when one port+proto is associated with
* more than one peice (these cases are usually marked as PROBLEM in
* /etc/peices. This functions is needed also when one peice+proto is
* associated with several ports. We have to check all the protoent structures
* to make sure that pe really exists and correct */
static int
protoent_check_ambiguity(struct protoent_test_data *td, struct protoent *pe)
{
return (TEST_DATA_FIND(protoent, td, pe, compare_protoent,
NULL) != NULL ? 0 : -1);
}
static int
protoent_test_getprotobyname(struct protoent *pe_model, void *mdata)
{
char **alias;
struct protoent *pe;
if (debug) {
printf("testing getprotobyname() with the following data:\n");
dump_protoent(pe_model);
}
pe = getprotobyname(pe_model->p_name);
if (protoent_test_correctness(pe, NULL) != 0)
goto errfin;
if ((compare_protoent(pe, pe_model, NULL) != 0) &&
(protoent_check_ambiguity((struct protoent_test_data *)mdata, pe)
!=0))
goto errfin;
for (alias = pe_model->p_aliases; *alias; ++alias) {
pe = getprotobyname(*alias);
if (protoent_test_correctness(pe, NULL) != 0)
goto errfin;
if ((compare_protoent(pe, pe_model, NULL) != 0) &&
(protoent_check_ambiguity(
(struct protoent_test_data *)mdata, pe) != 0))
goto errfin;
}
if (debug)
printf("ok\n");
return (0);
errfin:
if (debug)
printf("not ok\n");
return (-1);
}
static int
protoent_test_getprotobynumber(struct protoent *pe_model, void *mdata)
{
struct protoent *pe;
if (debug) {
printf("testing getprotobyport() with the following data...\n");
dump_protoent(pe_model);
}
pe = getprotobynumber(pe_model->p_proto);
if ((protoent_test_correctness(pe, NULL) != 0) ||
((compare_protoent(pe, pe_model, NULL) != 0) &&
(protoent_check_ambiguity((struct protoent_test_data *)mdata, pe)
!= 0))) {
if (debug)
printf("not ok\n");
return (-1);
} else {
if (debug)
printf("ok\n");
return (0);
}
}
static int
protoent_test_getprotoent(struct protoent *pe, void *mdata)
{
/* Only correctness can be checked when doing 1-pass test for
* getprotoent(). */
return (protoent_test_correctness(pe, NULL));
}
static void
usage(void)
{
(void)fprintf(stderr,
"Usage: %s -nve2 [-d] [-s <file>]\n",
getprogname());
exit(1);
}
int
main(int argc, char **argv)
{
struct protoent_test_data td, td_snap, td_2pass;
char *snapshot_file;
int rv;
int c;
if (argc < 2)
usage();
snapshot_file = NULL;
while ((c = getopt(argc, argv, "nve2ds:")) != -1)
switch (c) {
case 'd':
debug++;
break;
case 'n':
method = TEST_GETPROTOBYNAME;
break;
case 'v':
method = TEST_GETPROTOBYNUMBER;
break;
case 'e':
method = TEST_GETPROTOENT;
break;
case '2':
method = TEST_GETPROTOENT_2PASS;
break;
case 's':
snapshot_file = strdup(optarg);
break;
default:
usage();
}
TEST_DATA_INIT(protoent, &td, clone_protoent, free_protoent);
TEST_DATA_INIT(protoent, &td_snap, clone_protoent, free_protoent);
if (snapshot_file != NULL) {
if (access(snapshot_file, W_OK | R_OK) != 0) {
if (errno == ENOENT)
method = TEST_BUILD_SNAPSHOT;
else {
if (debug)
printf("can't access the file %s\n",
snapshot_file);
rv = -1;
goto fin;
}
} else {
if (method == TEST_BUILD_SNAPSHOT) {
rv = 0;
goto fin;
}
TEST_SNAPSHOT_FILE_READ(protoent, snapshot_file,
&td_snap, protoent_read_snapshot_func);
}
}
rv = protoent_fill_test_data(&td);
if (rv == -1)
return (-1);
switch (method) {
case TEST_GETPROTOBYNAME:
if (snapshot_file == NULL)
rv = DO_1PASS_TEST(protoent, &td,
protoent_test_getprotobyname, (void *)&td);
else
rv = DO_1PASS_TEST(protoent, &td_snap,
protoent_test_getprotobyname, (void *)&td_snap);
break;
case TEST_GETPROTOBYNUMBER:
if (snapshot_file == NULL)
rv = DO_1PASS_TEST(protoent, &td,
protoent_test_getprotobynumber, (void *)&td);
else
rv = DO_1PASS_TEST(protoent, &td_snap,
protoent_test_getprotobynumber, (void *)&td_snap);
break;
case TEST_GETPROTOENT:
if (snapshot_file == NULL)
rv = DO_1PASS_TEST(protoent, &td,
protoent_test_getprotoent, (void *)&td);
else
rv = DO_2PASS_TEST(protoent, &td, &td_snap,
compare_protoent, NULL);
break;
case TEST_GETPROTOENT_2PASS:
TEST_DATA_INIT(protoent, &td_2pass, clone_protoent,
free_protoent);
rv = protoent_fill_test_data(&td_2pass);
if (rv != -1)
rv = DO_2PASS_TEST(protoent, &td, &td_2pass,
compare_protoent, NULL);
TEST_DATA_DESTROY(protoent, &td_2pass);
break;
case TEST_BUILD_SNAPSHOT:
if (snapshot_file != NULL)
rv = TEST_SNAPSHOT_FILE_WRITE(protoent, snapshot_file, &td,
sdump_protoent);
break;
default:
rv = 0;
break;
};
fin:
TEST_DATA_DESTROY(protoent, &td_snap);
TEST_DATA_DESTROY(protoent, &td);
free(snapshot_file);
return (rv);
}

View File

@ -0,0 +1,29 @@
#!/bin/sh
# $FreeBSD$
do_test() {
number=$1
comment=$2
opt=$3
if ./$executable $opt; then
echo "ok $number - $comment"
else
echo "not ok $number - $comment"
fi
}
cd `dirname $0`
executable=`basename $0 .t`
make $executable 2>&1 > /dev/null
echo 1..8
do_test 1 'getprotobyname()' '-n'
do_test 2 'getprotobynumber()' '-v'
do_test 3 'getprotoent()' '-e'
do_test 4 'getprotoent() 2-pass' '-2'
do_test 5 'building snapshot, if needed' '-s snapshot_proto'
do_test 6 'getprotobyname() snapshot' '-n -s snapshot_proto'
do_test 7 'getprotobynumber() snapshot' '-v -s snapshot_proto'
do_test 8 'getprotoent() snapshot' '-e -s snapshot_proto'

View File

@ -0,0 +1,489 @@
/*-
* Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
* All rights repwded.
*
* 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 <assert.h>
#include <errno.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "testutil.h"
enum test_methods {
TEST_GETPWENT,
TEST_GETPWNAM,
TEST_GETPWUID,
TEST_GETPWENT_2PASS,
TEST_BUILD_SNAPSHOT
};
static int debug = 0;
static enum test_methods method = TEST_BUILD_SNAPSHOT;
DECLARE_TEST_DATA(passwd)
DECLARE_TEST_FILE_SNAPSHOT(passwd)
DECLARE_1PASS_TEST(passwd)
DECLARE_2PASS_TEST(passwd)
static void clone_passwd(struct passwd *, struct passwd const *);
static int compare_passwd(struct passwd *, struct passwd *, void *);
static void free_passwd(struct passwd *);
static void sdump_passwd(struct passwd *, char *, size_t);
static void dump_passwd(struct passwd *);
static int passwd_read_snapshot_func(struct passwd *, char *);
static int passwd_check_ambiguity(struct passwd_test_data *, struct passwd *);
static int passwd_fill_test_data(struct passwd_test_data *);
static int passwd_test_correctness(struct passwd *, void *);
static int passwd_test_getpwnam(struct passwd *, void *);
static int passwd_test_getpwuid(struct passwd *, void *);
static int passwd_test_getpwent(struct passwd *, void *);
static void usage(void) __attribute__((__noreturn__));
IMPLEMENT_TEST_DATA(passwd)
IMPLEMENT_TEST_FILE_SNAPSHOT(passwd)
IMPLEMENT_1PASS_TEST(passwd)
IMPLEMENT_2PASS_TEST(passwd)
static void
clone_passwd(struct passwd *dest, struct passwd const *src)
{
assert(dest != NULL);
assert(src != NULL);
memcpy(dest, src, sizeof(struct passwd));
if (src->pw_name != NULL)
dest->pw_name = strdup(src->pw_name);
if (src->pw_passwd != NULL)
dest->pw_passwd = strdup(src->pw_passwd);
if (src->pw_class != NULL)
dest->pw_class = strdup(src->pw_class);
if (src->pw_gecos != NULL)
dest->pw_gecos = strdup(src->pw_gecos);
if (src->pw_dir != NULL)
dest->pw_dir = strdup(src->pw_dir);
if (src->pw_shell != NULL)
dest->pw_shell = strdup(dest->pw_shell);
}
static int
compare_passwd(struct passwd *pwd1, struct passwd *pwd2, void *mdata)
{
assert(pwd1 != NULL);
assert(pwd2 != NULL);
if (pwd1 == pwd2)
return (0);
if ((pwd1->pw_uid != pwd2->pw_uid) ||
(pwd1->pw_gid != pwd2->pw_gid) ||
(pwd1->pw_change != pwd2->pw_change) ||
(pwd1->pw_expire != pwd2->pw_expire) ||
(pwd1->pw_fields != pwd2->pw_fields) ||
(strcmp(pwd1->pw_name, pwd2->pw_name) != 0) ||
(strcmp(pwd1->pw_passwd, pwd2->pw_passwd) != 0) ||
(strcmp(pwd1->pw_class, pwd2->pw_class) != 0) ||
(strcmp(pwd1->pw_gecos, pwd2->pw_gecos) != 0) ||
(strcmp(pwd1->pw_dir, pwd2->pw_dir) != 0) ||
(strcmp(pwd1->pw_shell, pwd2->pw_shell) != 0)
)
return (-1);
else
return (0);
}
static void
free_passwd(struct passwd *pwd)
{
free(pwd->pw_name);
free(pwd->pw_passwd);
free(pwd->pw_class);
free(pwd->pw_gecos);
free(pwd->pw_dir);
free(pwd->pw_shell);
}
static void
sdump_passwd(struct passwd *pwd, char *buffer, size_t buflen)
{
snprintf(buffer, buflen, "%s:%s:%d:%d:%d:%s:%s:%s:%s:%d:%d",
pwd->pw_name, pwd->pw_passwd, pwd->pw_uid, pwd->pw_gid,
pwd->pw_change, pwd->pw_class, pwd->pw_gecos, pwd->pw_dir,
pwd->pw_shell, pwd->pw_expire, pwd->pw_fields);
}
static void
dump_passwd(struct passwd *pwd)
{
if (pwd != NULL) {
char buffer[2048];
sdump_passwd(pwd, buffer, sizeof(buffer));
printf("%s\n", buffer);
} else
printf("(null)\n");
}
static int
passwd_read_snapshot_func(struct passwd *pwd, char *line)
{
char *s, *ps, *ts;
int i;
if (debug)
printf("1 line read from snapshot:\n%s\n", line);
i = 0;
ps = line;
memset(pwd, 0, sizeof(struct passwd));
while ( (s = strsep(&ps, ":")) != NULL) {
switch (i) {
case 0:
pwd->pw_name = strdup(s);
assert(pwd->pw_name != NULL);
break;
case 1:
pwd->pw_passwd = strdup(s);
assert(pwd->pw_passwd != NULL);
break;
case 2:
pwd->pw_uid = (uid_t)strtol(s, &ts, 10);
if (*ts != '\0')
goto fin;
break;
case 3:
pwd->pw_gid = (gid_t)strtol(s, &ts, 10);
if (*ts != '\0')
goto fin;
break;
case 4:
pwd->pw_change = (time_t)strtol(s, &ts, 10);
if (*ts != '\0')
goto fin;
break;
case 5:
pwd->pw_class = strdup(s);
assert(pwd->pw_class != NULL);
break;
case 6:
pwd->pw_gecos = strdup(s);
assert(pwd->pw_gecos != NULL);
break;
case 7:
pwd->pw_dir = strdup(s);
assert(pwd->pw_dir != NULL);
break;
case 8:
pwd->pw_shell = strdup(s);
assert(pwd->pw_shell != NULL);
break;
case 9:
pwd->pw_expire = (time_t)strtol(s, &ts, 10);
if (*ts != '\0')
goto fin;
break;
case 10:
pwd->pw_fields = (int)strtol(s, &ts, 10);
if (*ts != '\0')
goto fin;
break;
default:
break;
};
++i;
}
fin:
if (i != 11) {
free_passwd(pwd);
memset(pwd, 0, sizeof(struct passwd));
return (-1);
}
return (0);
}
static int
passwd_fill_test_data(struct passwd_test_data *td)
{
struct passwd *pwd;
setpassent(1);
while ((pwd = getpwent()) != NULL) {
if (passwd_test_correctness(pwd, NULL) == 0)
TEST_DATA_APPEND(passwd, td, pwd);
else
return (-1);
}
endpwent();
return (0);
}
static int
passwd_test_correctness(struct passwd *pwd, void *mdata)
{
if (debug) {
printf("testing correctness with the following data:\n");
dump_passwd(pwd);
}
if (pwd == NULL)
return (-1);
if (pwd->pw_name == NULL)
goto errfin;
if (pwd->pw_passwd == NULL)
goto errfin;
if (pwd->pw_class == NULL)
goto errfin;
if (pwd->pw_gecos == NULL)
goto errfin;
if (pwd->pw_dir == NULL)
goto errfin;
if (pwd->pw_shell == NULL)
goto errfin;
if (debug)
printf("correct\n");
return (0);
errfin:
if (debug)
printf("incorrect\n");
return (-1);
}
/* passwd_check_ambiguity() is needed here because when doing the getpwent()
* calls sequence, records from different nsswitch sources can be different,
* though having the same pw_name/pw_uid */
static int
passwd_check_ambiguity(struct passwd_test_data *td, struct passwd *pwd)
{
return (TEST_DATA_FIND(passwd, td, pwd, compare_passwd,
NULL) != NULL ? 0 : -1);
}
static int
passwd_test_getpwnam(struct passwd *pwd_model, void *mdata)
{
struct passwd *pwd;
if (debug) {
printf("testing getpwnam() with the following data:\n");
dump_passwd(pwd_model);
}
pwd = getpwnam(pwd_model->pw_name);
if (passwd_test_correctness(pwd, NULL) != 0)
goto errfin;
if ((compare_passwd(pwd, pwd_model, NULL) != 0) &&
(passwd_check_ambiguity((struct passwd_test_data *)mdata, pwd)
!=0))
goto errfin;
if (debug)
printf("ok\n");
return (0);
errfin:
if (debug)
printf("not ok\n");
return (-1);
}
static int
passwd_test_getpwuid(struct passwd *pwd_model, void *mdata)
{
struct passwd *pwd;
if (debug) {
printf("testing getpwuid() with the following data...\n");
dump_passwd(pwd_model);
}
pwd = getpwuid(pwd_model->pw_uid);
if ((passwd_test_correctness(pwd, NULL) != 0) ||
((compare_passwd(pwd, pwd_model, NULL) != 0) &&
(passwd_check_ambiguity((struct passwd_test_data *)mdata, pwd)
!= 0))) {
if (debug)
printf("not ok\n");
return (-1);
} else {
if (debug)
printf("ok\n");
return (0);
}
}
static int
passwd_test_getpwent(struct passwd *pwd, void *mdata)
{
/* Only correctness can be checked when doing 1-pass test for
* getpwent(). */
return (passwd_test_correctness(pwd, NULL));
}
static void
usage(void)
{
(void)fprintf(stderr,
"Usage: %s -nue2 [-d] [-s <file>]\n",
getprogname());
exit(1);
}
int
main(int argc, char **argv)
{
struct passwd_test_data td, td_snap, td_2pass;
char *snapshot_file;
int rv;
int c;
if (argc < 2)
usage();
snapshot_file = NULL;
while ((c = getopt(argc, argv, "nue2ds:")) != -1)
switch (c) {
case 'd':
debug++;
break;
case 'n':
method = TEST_GETPWNAM;
break;
case 'u':
method = TEST_GETPWUID;
break;
case 'e':
method = TEST_GETPWENT;
break;
case '2':
method = TEST_GETPWENT_2PASS;
break;
case 's':
snapshot_file = strdup(optarg);
break;
default:
usage();
}
TEST_DATA_INIT(passwd, &td, clone_passwd, free_passwd);
TEST_DATA_INIT(passwd, &td_snap, clone_passwd, free_passwd);
if (snapshot_file != NULL) {
if (access(snapshot_file, W_OK | R_OK) != 0) {
if (errno == ENOENT)
method = TEST_BUILD_SNAPSHOT;
else {
if (debug)
printf("can't access the file %s\n",
snapshot_file);
rv = -1;
goto fin;
}
} else {
if (method == TEST_BUILD_SNAPSHOT) {
rv = 0;
goto fin;
}
TEST_SNAPSHOT_FILE_READ(passwd, snapshot_file,
&td_snap, passwd_read_snapshot_func);
}
}
rv = passwd_fill_test_data(&td);
if (rv == -1)
return (-1);
switch (method) {
case TEST_GETPWNAM:
if (snapshot_file == NULL)
rv = DO_1PASS_TEST(passwd, &td,
passwd_test_getpwnam, (void *)&td);
else
rv = DO_1PASS_TEST(passwd, &td_snap,
passwd_test_getpwnam, (void *)&td_snap);
break;
case TEST_GETPWUID:
if (snapshot_file == NULL)
rv = DO_1PASS_TEST(passwd, &td,
passwd_test_getpwuid, (void *)&td);
else
rv = DO_1PASS_TEST(passwd, &td_snap,
passwd_test_getpwuid, (void *)&td_snap);
break;
case TEST_GETPWENT:
if (snapshot_file == NULL)
rv = DO_1PASS_TEST(passwd, &td, passwd_test_getpwent,
(void *)&td);
else
rv = DO_2PASS_TEST(passwd, &td, &td_snap,
compare_passwd, NULL);
break;
case TEST_GETPWENT_2PASS:
TEST_DATA_INIT(passwd, &td_2pass, clone_passwd, free_passwd);
rv = passwd_fill_test_data(&td_2pass);
if (rv != -1)
rv = DO_2PASS_TEST(passwd, &td, &td_2pass,
compare_passwd, NULL);
TEST_DATA_DESTROY(passwd, &td_2pass);
break;
case TEST_BUILD_SNAPSHOT:
if (snapshot_file != NULL)
rv = TEST_SNAPSHOT_FILE_WRITE(passwd, snapshot_file, &td,
sdump_passwd);
break;
default:
rv = 0;
break;
};
fin:
TEST_DATA_DESTROY(passwd, &td_snap);
TEST_DATA_DESTROY(passwd, &td);
free(snapshot_file);
return (rv);
}

View File

@ -0,0 +1,29 @@
#!/bin/sh
# $FreeBSD$
do_test() {
number=$1
comment=$2
opt=$3
if ./$executable $opt; then
echo "ok $number - $comment"
else
echo "not ok $number - $comment"
fi
}
cd `dirname $0`
executable=`basename $0 .t`
make $executable 2>&1 > /dev/null
echo 1..8
do_test 1 'getpwnam()' '-n'
do_test 2 'getpwuid()' '-u'
do_test 3 'getpwent()' '-e'
do_test 4 'getpwent() 2-pass' '-2'
do_test 5 'building snapshot, if needed' '-s snapshot_pwd'
do_test 6 'getpwnam() snapshot' '-n -s snapshot_pwd'
do_test 7 'getpwuid() snapshot' '-u -s snapshot_pwd'
do_test 8 'getpwent() snapshot' '-e -s snapshot_pwd'

View File

@ -0,0 +1,535 @@
/*-
* Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
* All rights repeed.
*
* 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 <arpa/inet.h>
#include <rpc/rpc.h>
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stringlist.h>
#include <unistd.h>
#include "testutil.h"
enum test_methods {
TEST_GETRPCENT,
TEST_GETRPCBYNAME,
TEST_GETRPCBYNUMBER,
TEST_GETRPCENT_2PASS,
TEST_BUILD_SNAPSHOT
};
static int debug = 0;
static enum test_methods method = TEST_BUILD_SNAPSHOT;
DECLARE_TEST_DATA(rpcent)
DECLARE_TEST_FILE_SNAPSHOT(rpcent)
DECLARE_1PASS_TEST(rpcent)
DECLARE_2PASS_TEST(rpcent)
static void clone_rpcent(struct rpcent *, struct rpcent const *);
static int compare_rpcent(struct rpcent *, struct rpcent *, void *);
static void dump_rpcent(struct rpcent *);
static void free_rpcent(struct rpcent *);
static void sdump_rpcent(struct rpcent *, char *, size_t);
static int rpcent_read_snapshot_func(struct rpcent *, char *);
static int rpcent_check_ambiguity(struct rpcent_test_data *,
struct rpcent *);
static int rpcent_fill_test_data(struct rpcent_test_data *);
static int rpcent_test_correctness(struct rpcent *, void *);
static int rpcent_test_getrpcbyname(struct rpcent *, void *);
static int rpcent_test_getrpcbynumber(struct rpcent *, void *);
static int rpcent_test_getrpcent(struct rpcent *, void *);
static void usage(void) __attribute__((__noreturn__));
IMPLEMENT_TEST_DATA(rpcent)
IMPLEMENT_TEST_FILE_SNAPSHOT(rpcent)
IMPLEMENT_1PASS_TEST(rpcent)
IMPLEMENT_2PASS_TEST(rpcent)
static void
clone_rpcent(struct rpcent *dest, struct rpcent const *src)
{
assert(dest != NULL);
assert(src != NULL);
char **cp;
int aliases_num;
memset(dest, 0, sizeof(struct rpcent));
if (src->r_name != NULL) {
dest->r_name = strdup(src->r_name);
assert(dest->r_name != NULL);
}
dest->r_number = src->r_number;
if (src->r_aliases != NULL) {
aliases_num = 0;
for (cp = src->r_aliases; *cp; ++cp)
++aliases_num;
dest->r_aliases = (char **)malloc((aliases_num+1) * (sizeof(char *)));
assert(dest->r_aliases != NULL);
memset(dest->r_aliases, 0, (aliases_num+1) * (sizeof(char *)));
for (cp = src->r_aliases; *cp; ++cp) {
dest->r_aliases[cp - src->r_aliases] = strdup(*cp);
assert(dest->r_aliases[cp - src->r_aliases] != NULL);
}
}
}
static void
free_rpcent(struct rpcent *rpc)
{
char **cp;
assert(rpc != NULL);
free(rpc->r_name);
for (cp = rpc->r_aliases; *cp; ++cp)
free(*cp);
free(rpc->r_aliases);
}
static int
compare_rpcent(struct rpcent *rpc1, struct rpcent *rpc2, void *mdata)
{
char **c1, **c2;
if (rpc1 == rpc2)
return 0;
if ((rpc1 == NULL) || (rpc2 == NULL))
goto errfin;
if ((strcmp(rpc1->r_name, rpc2->r_name) != 0) ||
(rpc1->r_number != rpc2->r_number))
goto errfin;
c1 = rpc1->r_aliases;
c2 = rpc2->r_aliases;
if ((rpc1->r_aliases == NULL) || (rpc2->r_aliases == NULL))
goto errfin;
for (;*c1 && *c2; ++c1, ++c2)
if (strcmp(*c1, *c2) != 0)
goto errfin;
if ((*c1 != '\0') || (*c2 != '\0'))
goto errfin;
return 0;
errfin:
if ((debug) && (mdata == NULL)) {
printf("following structures are not equal:\n");
dump_rpcent(rpc1);
dump_rpcent(rpc2);
}
return (-1);
}
static void
sdump_rpcent(struct rpcent *rpc, char *buffer, size_t buflen)
{
char **cp;
int written;
written = snprintf(buffer, buflen, "%s %d",
rpc->r_name, rpc->r_number);
buffer += written;
if (written > buflen)
return;
buflen -= written;
if (rpc->r_aliases != NULL) {
if (*(rpc->r_aliases) != '\0') {
for (cp = rpc->r_aliases; *cp; ++cp) {
written = snprintf(buffer, buflen, " %s",*cp);
buffer += written;
if (written > buflen)
return;
buflen -= written;
if (buflen == 0)
return;
}
} else
snprintf(buffer, buflen, " noaliases");
} else
snprintf(buffer, buflen, " (null)");
}
static int
rpcent_read_snapshot_func(struct rpcent *rpc, char *line)
{
StringList *sl;
char *s, *ps, *ts;
int i;
if (debug)
printf("1 line read from snapshot:\n%s\n", line);
i = 0;
sl = NULL;
ps = line;
memset(rpc, 0, sizeof(struct rpcent));
while ( (s = strsep(&ps, " ")) != NULL) {
switch (i) {
case 0:
rpc->r_name = strdup(s);
assert(rpc->r_name != NULL);
break;
case 1:
rpc->r_number = (int)strtol(s, &ts, 10);
if (*ts != '\0') {
free(rpc->r_name);
return (-1);
}
break;
default:
if (sl == NULL) {
if (strcmp(s, "(null)") == 0)
return (0);
sl = sl_init();
assert(sl != NULL);
if (strcmp(s, "noaliases") != 0) {
ts = strdup(s);
assert(ts != NULL);
sl_add(sl, ts);
}
} else {
ts = strdup(s);
assert(ts != NULL);
sl_add(sl, ts);
}
break;
};
++i;
}
if (i < 3) {
free(rpc->r_name);
memset(rpc, 0, sizeof(struct rpcent));
return (-1);
}
sl_add(sl, NULL);
rpc->r_aliases = sl->sl_str;
/* NOTE: is it a dirty hack or not? */
free(sl);
return (0);
}
static void
dump_rpcent(struct rpcent *result)
{
if (result != NULL) {
char buffer[1024];
sdump_rpcent(result, buffer, sizeof(buffer));
printf("%s\n", buffer);
} else
printf("(null)\n");
}
static int
rpcent_fill_test_data(struct rpcent_test_data *td)
{
struct rpcent *rpc;
setrpcent(1);
while ((rpc = getrpcent()) != NULL) {
if (rpcent_test_correctness(rpc, NULL) == 0)
TEST_DATA_APPEND(rpcent, td, rpc);
else
return (-1);
}
endrpcent();
return (0);
}
static int
rpcent_test_correctness(struct rpcent *rpc, void *mdata)
{
if (debug) {
printf("testing correctness with the following data:\n");
dump_rpcent(rpc);
}
if (rpc == NULL)
goto errfin;
if (rpc->r_name == NULL)
goto errfin;
if (rpc->r_number < 0)
goto errfin;
if (rpc->r_aliases == NULL)
goto errfin;
if (debug)
printf("correct\n");
return (0);
errfin:
if (debug)
printf("incorrect\n");
return (-1);
}
/* rpcent_check_ambiguity() is needed when one port+rpc is associated with
* more than one peice (these cases are usually marked as PROBLEM in
* /etc/peices. This functions is needed also when one peice+rpc is
* associated with several ports. We have to check all the rpcent structures
* to make sure that rpc really exists and correct */
static int
rpcent_check_ambiguity(struct rpcent_test_data *td, struct rpcent *rpc)
{
return (TEST_DATA_FIND(rpcent, td, rpc, compare_rpcent,
NULL) != NULL ? 0 : -1);
}
static int
rpcent_test_getrpcbyname(struct rpcent *rpc_model, void *mdata)
{
char **alias;
struct rpcent *rpc;
if (debug) {
printf("testing getrpcbyname() with the following data:\n");
dump_rpcent(rpc_model);
}
rpc = getrpcbyname(rpc_model->r_name);
if (rpcent_test_correctness(rpc, NULL) != 0)
goto errfin;
if ((compare_rpcent(rpc, rpc_model, NULL) != 0) &&
(rpcent_check_ambiguity((struct rpcent_test_data *)mdata, rpc)
!=0))
goto errfin;
for (alias = rpc_model->r_aliases; *alias; ++alias) {
rpc = getrpcbyname(*alias);
if (rpcent_test_correctness(rpc, NULL) != 0)
goto errfin;
if ((compare_rpcent(rpc, rpc_model, NULL) != 0) &&
(rpcent_check_ambiguity(
(struct rpcent_test_data *)mdata, rpc) != 0))
goto errfin;
}
if (debug)
printf("ok\n");
return (0);
errfin:
if (debug)
printf("not ok\n");
return (-1);
}
static int
rpcent_test_getrpcbynumber(struct rpcent *rpc_model, void *mdata)
{
struct rpcent *rpc;
if (debug) {
printf("testing getrpcbyport() with the following data...\n");
dump_rpcent(rpc_model);
}
rpc = getrpcbynumber(rpc_model->r_number);
if ((rpcent_test_correctness(rpc, NULL) != 0) ||
((compare_rpcent(rpc, rpc_model, NULL) != 0) &&
(rpcent_check_ambiguity((struct rpcent_test_data *)mdata, rpc)
!= 0))) {
if (debug)
printf("not ok\n");
return (-1);
} else {
if (debug)
printf("ok\n");
return (0);
}
}
static int
rpcent_test_getrpcent(struct rpcent *rpc, void *mdata)
{
/* Only correctness can be checked when doing 1-pass test for
* getrpcent(). */
return (rpcent_test_correctness(rpc, NULL));
}
static void
usage(void)
{
(void)fprintf(stderr,
"Usage: %s -nve2 [-d] [-s <file>]\n",
getprogname());
exit(1);
}
int
main(int argc, char **argv)
{
struct rpcent_test_data td, td_snap, td_2pass;
char *snapshot_file;
int rv;
int c;
if (argc < 2)
usage();
snapshot_file = NULL;
while ((c = getopt(argc, argv, "nve2ds:")) != -1)
switch (c) {
case 'd':
debug++;
break;
case 'n':
method = TEST_GETRPCBYNAME;
break;
case 'v':
method = TEST_GETRPCBYNUMBER;
break;
case 'e':
method = TEST_GETRPCENT;
break;
case '2':
method = TEST_GETRPCENT_2PASS;
break;
case 's':
snapshot_file = strdup(optarg);
break;
default:
usage();
}
TEST_DATA_INIT(rpcent, &td, clone_rpcent, free_rpcent);
TEST_DATA_INIT(rpcent, &td_snap, clone_rpcent, free_rpcent);
if (snapshot_file != NULL) {
if (access(snapshot_file, W_OK | R_OK) != 0) {
if (errno == ENOENT)
method = TEST_BUILD_SNAPSHOT;
else {
if (debug)
printf("can't access the file %s\n",
snapshot_file);
rv = -1;
goto fin;
}
} else {
if (method == TEST_BUILD_SNAPSHOT) {
rv = 0;
goto fin;
}
TEST_SNAPSHOT_FILE_READ(rpcent, snapshot_file,
&td_snap, rpcent_read_snapshot_func);
}
}
rv = rpcent_fill_test_data(&td);
if (rv == -1)
return (-1);
switch (method) {
case TEST_GETRPCBYNAME:
if (snapshot_file == NULL)
rv = DO_1PASS_TEST(rpcent, &td,
rpcent_test_getrpcbyname, (void *)&td);
else
rv = DO_1PASS_TEST(rpcent, &td_snap,
rpcent_test_getrpcbyname, (void *)&td_snap);
break;
case TEST_GETRPCBYNUMBER:
if (snapshot_file == NULL)
rv = DO_1PASS_TEST(rpcent, &td,
rpcent_test_getrpcbynumber, (void *)&td);
else
rv = DO_1PASS_TEST(rpcent, &td_snap,
rpcent_test_getrpcbynumber, (void *)&td_snap);
break;
case TEST_GETRPCENT:
if (snapshot_file == NULL)
rv = DO_1PASS_TEST(rpcent, &td, rpcent_test_getrpcent,
(void *)&td);
else
rv = DO_2PASS_TEST(rpcent, &td, &td_snap,
compare_rpcent, NULL);
break;
case TEST_GETRPCENT_2PASS:
TEST_DATA_INIT(rpcent, &td_2pass, clone_rpcent, free_rpcent);
rv = rpcent_fill_test_data(&td_2pass);
if (rv != -1)
rv = DO_2PASS_TEST(rpcent, &td, &td_2pass,
compare_rpcent, NULL);
TEST_DATA_DESTROY(rpcent, &td_2pass);
break;
case TEST_BUILD_SNAPSHOT:
if (snapshot_file != NULL)
rv = TEST_SNAPSHOT_FILE_WRITE(rpcent, snapshot_file, &td,
sdump_rpcent);
break;
default:
rv = 0;
break;
};
fin:
TEST_DATA_DESTROY(rpcent, &td_snap);
TEST_DATA_DESTROY(rpcent, &td);
free(snapshot_file);
return (rv);
}

View File

@ -0,0 +1,29 @@
#!/bin/sh
# $FreeBSD$
do_test() {
number=$1
comment=$2
opt=$3
if ./$executable $opt; then
echo "ok $number - $comment"
else
echo "not ok $number - $comment"
fi
}
cd `dirname $0`
executable=`basename $0 .t`
make $executable 2>&1 > /dev/null
echo 1..8
do_test 1 'getrpcbyname()' '-n'
do_test 2 'getrpcbynumber()' '-v'
do_test 3 'getrpcent()' '-e'
do_test 4 'getrpcent() 2-pass' '-2'
do_test 5 'building snapshot, if needed' '-s snapshot_rpc'
do_test 6 'getrpcbyname() snapshot' '-n -s snapshot_rpc'
do_test 7 'getrpcbynumber() snapshot' '-v -s snapshot_rpc'
do_test 8 'getrpcent() snapshot' '-e -s snapshot_rpc'

View File

@ -0,0 +1,551 @@
/*-
* Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
* 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 <arpa/inet.h>
#include <assert.h>
#include <errno.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stringlist.h>
#include <unistd.h>
#include "testutil.h"
enum test_methods {
TEST_GETSERVENT,
TEST_GETSERVBYNAME,
TEST_GETSERVBYPORT,
TEST_GETSERVENT_2PASS,
TEST_BUILD_SNAPSHOT
};
static int debug = 0;
static enum test_methods method = TEST_BUILD_SNAPSHOT;
DECLARE_TEST_DATA(servent)
DECLARE_TEST_FILE_SNAPSHOT(servent)
DECLARE_1PASS_TEST(servent)
DECLARE_2PASS_TEST(servent)
static void clone_servent(struct servent *, struct servent const *);
static int compare_servent(struct servent *, struct servent *, void *);
static void dump_servent(struct servent *);
static void free_servent(struct servent *);
static void sdump_servent(struct servent *, char *, size_t);
static int servent_read_snapshot_func(struct servent *, char *);
static int servent_check_ambiguity(struct servent_test_data *,
struct servent *);
static int servent_fill_test_data(struct servent_test_data *);
static int servent_test_correctness(struct servent *, void *);
static int servent_test_getservbyname(struct servent *, void *);
static int servent_test_getservbyport(struct servent *, void *);
static int servent_test_getservent(struct servent *, void *);
static void usage(void) __attribute__((__noreturn__));
IMPLEMENT_TEST_DATA(servent)
IMPLEMENT_TEST_FILE_SNAPSHOT(servent)
IMPLEMENT_1PASS_TEST(servent)
IMPLEMENT_2PASS_TEST(servent)
static void
clone_servent(struct servent *dest, struct servent const *src)
{
assert(dest != NULL);
assert(src != NULL);
char **cp;
int aliases_num;
memset(dest, 0, sizeof(struct servent));
if (src->s_name != NULL) {
dest->s_name = strdup(src->s_name);
assert(dest->s_name != NULL);
}
if (src->s_proto != NULL) {
dest->s_proto = strdup(src->s_proto);
assert(dest->s_proto != NULL);
}
dest->s_port = src->s_port;
if (src->s_aliases != NULL) {
aliases_num = 0;
for (cp = src->s_aliases; *cp; ++cp)
++aliases_num;
dest->s_aliases = (char **)malloc((aliases_num+1) * (sizeof(char *)));
assert(dest->s_aliases != NULL);
memset(dest->s_aliases, 0, (aliases_num+1) * (sizeof(char *)));
for (cp = src->s_aliases; *cp; ++cp) {
dest->s_aliases[cp - src->s_aliases] = strdup(*cp);
assert(dest->s_aliases[cp - src->s_aliases] != NULL);
}
}
}
static void
free_servent(struct servent *serv)
{
char **cp;
assert(serv != NULL);
free(serv->s_name);
free(serv->s_proto);
for (cp = serv->s_aliases; *cp; ++cp)
free(*cp);
free(serv->s_aliases);
}
static int
compare_servent(struct servent *serv1, struct servent *serv2, void *mdata)
{
char **c1, **c2;
if (serv1 == serv2)
return 0;
if ((serv1 == NULL) || (serv2 == NULL))
goto errfin;
if ((strcmp(serv1->s_name, serv2->s_name) != 0) ||
(strcmp(serv1->s_proto, serv2->s_proto) != 0) ||
(serv1->s_port != serv2->s_port))
goto errfin;
c1 = serv1->s_aliases;
c2 = serv2->s_aliases;
if ((serv1->s_aliases == NULL) || (serv2->s_aliases == NULL))
goto errfin;
for (;*c1 && *c2; ++c1, ++c2)
if (strcmp(*c1, *c2) != 0)
goto errfin;
if ((*c1 != '\0') || (*c2 != '\0'))
goto errfin;
return 0;
errfin:
if ((debug) && (mdata == NULL)) {
printf("following structures are not equal:\n");
dump_servent(serv1);
dump_servent(serv2);
}
return (-1);
}
static void
sdump_servent(struct servent *serv, char *buffer, size_t buflen)
{
char **cp;
int written;
written = snprintf(buffer, buflen, "%s %d %s",
serv->s_name, ntohs(serv->s_port), serv->s_proto);
buffer += written;
if (written > buflen)
return;
buflen -= written;
if (serv->s_aliases != NULL) {
if (*(serv->s_aliases) != '\0') {
for (cp = serv->s_aliases; *cp; ++cp) {
written = snprintf(buffer, buflen, " %s",*cp);
buffer += written;
if (written > buflen)
return;
buflen -= written;
if (buflen == 0)
return;
}
} else
snprintf(buffer, buflen, " noaliases");
} else
snprintf(buffer, buflen, " (null)");
}
static int
servent_read_snapshot_func(struct servent *serv, char *line)
{
StringList *sl;
char *s, *ps, *ts;
int i;
if (debug)
printf("1 line read from snapshot:\n%s\n", line);
i = 0;
sl = NULL;
ps = line;
memset(serv, 0, sizeof(struct servent));
while ( (s = strsep(&ps, " ")) != NULL) {
switch (i) {
case 0:
serv->s_name = strdup(s);
assert(serv->s_name != NULL);
break;
case 1:
serv->s_port = htons(
(int)strtol(s, &ts, 10));
if (*ts != '\0') {
free(serv->s_name);
return (-1);
}
break;
case 2:
serv->s_proto = strdup(s);
assert(serv->s_proto != NULL);
break;
default:
if (sl == NULL) {
if (strcmp(s, "(null)") == 0)
return (0);
sl = sl_init();
assert(sl != NULL);
if (strcmp(s, "noaliases") != 0) {
ts = strdup(s);
assert(ts != NULL);
sl_add(sl, ts);
}
} else {
ts = strdup(s);
assert(ts != NULL);
sl_add(sl, ts);
}
break;
};
++i;
}
if (i < 3) {
free(serv->s_name);
free(serv->s_proto);
memset(serv, 0, sizeof(struct servent));
return (-1);
}
sl_add(sl, NULL);
serv->s_aliases = sl->sl_str;
/* NOTE: is it a dirty hack or not? */
free(sl);
return (0);
}
static void
dump_servent(struct servent *result)
{
if (result != NULL) {
char buffer[1024];
sdump_servent(result, buffer, sizeof(buffer));
printf("%s\n", buffer);
} else
printf("(null)\n");
}
static int
servent_fill_test_data(struct servent_test_data *td)
{
struct servent *serv;
setservent(1);
while ((serv = getservent()) != NULL) {
if (servent_test_correctness(serv, NULL) == 0)
TEST_DATA_APPEND(servent, td, serv);
else
return (-1);
}
endservent();
return (0);
}
static int
servent_test_correctness(struct servent *serv, void *mdata)
{
if (debug) {
printf("testing correctness with the following data:\n");
dump_servent(serv);
}
if (serv == NULL)
goto errfin;
if (serv->s_name == NULL)
goto errfin;
if (serv->s_proto == NULL)
goto errfin;
if (ntohs(serv->s_port < 0))
goto errfin;
if (serv->s_aliases == NULL)
goto errfin;
if (debug)
printf("correct\n");
return (0);
errfin:
if (debug)
printf("incorrect\n");
return (-1);
}
/* servent_check_ambiguity() is needed when one port+proto is associated with
* more than one service (these cases are usually marked as PROBLEM in
* /etc/services. This functions is needed also when one service+proto is
* associated with several ports. We have to check all the servent structures
* to make sure that serv really exists and correct */
static int
servent_check_ambiguity(struct servent_test_data *td, struct servent *serv)
{
return (TEST_DATA_FIND(servent, td, serv, compare_servent,
NULL) != NULL ? 0 : -1);
}
static int
servent_test_getservbyname(struct servent *serv_model, void *mdata)
{
char **alias;
struct servent *serv;
if (debug) {
printf("testing getservbyname() with the following data:\n");
dump_servent(serv_model);
}
serv = getservbyname(serv_model->s_name, serv_model->s_proto);
if (servent_test_correctness(serv, NULL) != 0)
goto errfin;
if ((compare_servent(serv, serv_model, NULL) != 0) &&
(servent_check_ambiguity((struct servent_test_data *)mdata, serv)
!=0))
goto errfin;
for (alias = serv_model->s_aliases; *alias; ++alias) {
serv = getservbyname(*alias, serv_model->s_proto);
if (servent_test_correctness(serv, NULL) != 0)
goto errfin;
if ((compare_servent(serv, serv_model, NULL) != 0) &&
(servent_check_ambiguity(
(struct servent_test_data *)mdata, serv) != 0))
goto errfin;
}
if (debug)
printf("ok\n");
return (0);
errfin:
if (debug)
printf("not ok\n");
return (-1);
}
static int
servent_test_getservbyport(struct servent *serv_model, void *mdata)
{
struct servent *serv;
if (debug) {
printf("testing getservbyport() with the following data...\n");
dump_servent(serv_model);
}
serv = getservbyport(serv_model->s_port, serv_model->s_proto);
if ((servent_test_correctness(serv, NULL) != 0) ||
((compare_servent(serv, serv_model, NULL) != 0) &&
(servent_check_ambiguity((struct servent_test_data *)mdata, serv)
!= 0))) {
if (debug)
printf("not ok\n");
return (-1);
} else {
if (debug)
printf("ok\n");
return (0);
}
}
static int
servent_test_getservent(struct servent *serv, void *mdata)
{
/* Only correctness can be checked when doing 1-pass test for
* getservent(). */
return (servent_test_correctness(serv, NULL));
}
static void
usage(void)
{
(void)fprintf(stderr,
"Usage: %s -npe2 [-d] [-s <file>]\n",
getprogname());
exit(1);
}
int
main(int argc, char **argv)
{
struct servent_test_data td, td_snap, td_2pass;
char *snapshot_file;
int rv;
int c;
if (argc < 2)
usage();
snapshot_file = NULL;
while ((c = getopt(argc, argv, "npe2ds:")) != -1)
switch (c) {
case 'd':
debug++;
break;
case 'n':
method = TEST_GETSERVBYNAME;
break;
case 'p':
method = TEST_GETSERVBYPORT;
break;
case 'e':
method = TEST_GETSERVENT;
break;
case '2':
method = TEST_GETSERVENT_2PASS;
break;
case 's':
snapshot_file = strdup(optarg);
break;
default:
usage();
}
TEST_DATA_INIT(servent, &td, clone_servent, free_servent);
TEST_DATA_INIT(servent, &td_snap, clone_servent, free_servent);
if (snapshot_file != NULL) {
if (access(snapshot_file, W_OK | R_OK) != 0) {
if (errno == ENOENT)
method = TEST_BUILD_SNAPSHOT;
else {
if (debug)
printf("can't access the file %s\n",
snapshot_file);
rv = -1;
goto fin;
}
} else {
if (method == TEST_BUILD_SNAPSHOT) {
rv = 0;
goto fin;
}
TEST_SNAPSHOT_FILE_READ(servent, snapshot_file,
&td_snap, servent_read_snapshot_func);
}
}
rv = servent_fill_test_data(&td);
if (rv == -1)
return (-1);
switch (method) {
case TEST_GETSERVBYNAME:
if (snapshot_file == NULL)
rv = DO_1PASS_TEST(servent, &td,
servent_test_getservbyname, (void *)&td);
else
rv = DO_1PASS_TEST(servent, &td_snap,
servent_test_getservbyname, (void *)&td_snap);
break;
case TEST_GETSERVBYPORT:
if (snapshot_file == NULL)
rv = DO_1PASS_TEST(servent, &td,
servent_test_getservbyport, (void *)&td);
else
rv = DO_1PASS_TEST(servent, &td_snap,
servent_test_getservbyport, (void *)&td_snap);
break;
case TEST_GETSERVENT:
if (snapshot_file == NULL)
rv = DO_1PASS_TEST(servent, &td, servent_test_getservent,
(void *)&td);
else
rv = DO_2PASS_TEST(servent, &td, &td_snap,
compare_servent, NULL);
break;
case TEST_GETSERVENT_2PASS:
TEST_DATA_INIT(servent, &td_2pass, clone_servent, free_servent);
rv = servent_fill_test_data(&td_2pass);
if (rv != -1)
rv = DO_2PASS_TEST(servent, &td, &td_2pass,
compare_servent, NULL);
TEST_DATA_DESTROY(servent, &td_2pass);
break;
case TEST_BUILD_SNAPSHOT:
if (snapshot_file != NULL)
rv = TEST_SNAPSHOT_FILE_WRITE(servent, snapshot_file, &td,
sdump_servent);
break;
default:
rv = 0;
break;
};
fin:
TEST_DATA_DESTROY(servent, &td_snap);
TEST_DATA_DESTROY(servent, &td);
free(snapshot_file);
return (rv);
}

View File

@ -0,0 +1,29 @@
#!/bin/sh
# $FreeBSD$
do_test() {
number=$1
comment=$2
opt=$3
if ./$executable $opt; then
echo "ok $number - $comment"
else
echo "not ok $number - $comment"
fi
}
cd `dirname $0`
executable=`basename $0 .t`
make $executable 2>&1 > /dev/null
echo 1..8
do_test 1 'getservbyname()' '-n'
do_test 2 'getservbyport()' '-p'
do_test 3 'getservent()' '-e'
do_test 4 'getservent() 2-pass' '-2'
do_test 5 'building snapshot, if needed' '-s snapshot_serv'
do_test 6 'getservbyname() snapshot' '-n -s snapshot_serv'
do_test 7 'getservbyport() snapshot' '-p -s snapshot_serv'
do_test 8 'getservent() snapshot' '-e -s snapshot_serv'

View File

@ -0,0 +1,235 @@
/*-
* Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
* All rights repwded.
*
* 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 <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "testutil.h"
enum test_methods {
TEST_GETUSERSHELL,
TEST_BUILD_SNAPSHOT
};
struct usershell {
char *path;
};
static int debug = 0;
static enum test_methods method = TEST_GETUSERSHELL;
DECLARE_TEST_DATA(usershell)
DECLARE_TEST_FILE_SNAPSHOT(usershell)
DECLARE_2PASS_TEST(usershell)
static void clone_usershell(struct usershell *, struct usershell const *);
static int compare_usershell(struct usershell *, struct usershell *, void *);
static void free_usershell(struct usershell *);
static void sdump_usershell(struct usershell *, char *, size_t);
static void dump_usershell(struct usershell *);
static int usershell_read_snapshot_func(struct usershell *, char *);
static void usage(void) __attribute__((__noreturn__));
IMPLEMENT_TEST_DATA(usershell)
IMPLEMENT_TEST_FILE_SNAPSHOT(usershell)
IMPLEMENT_2PASS_TEST(usershell)
static void
clone_usershell(struct usershell *dest, struct usershell const *src)
{
assert(dest != NULL);
assert(src != NULL);
if (src->path != NULL) {
dest->path = strdup(src->path);
assert(dest->path != NULL);
}
}
static int
compare_usershell(struct usershell *us1, struct usershell *us2, void *mdata)
{
int rv;
assert(us1 != NULL);
assert(us2 != NULL);
dump_usershell(us1);
dump_usershell(us2);
if (us1 == us2)
return (0);
rv = strcmp(us1->path, us2->path);
if (rv != 0) {
printf("following structures are not equal:\n");
dump_usershell(us1);
dump_usershell(us2);
}
return (rv);
}
static void
free_usershell(struct usershell *us)
{
free(us->path);
}
static void
sdump_usershell(struct usershell *us, char *buffer, size_t buflen)
{
snprintf(buffer, buflen, "%s", us->path);
}
static void
dump_usershell(struct usershell *us)
{
if (us != NULL) {
char buffer[2048];
sdump_usershell(us, buffer, sizeof(buffer));
printf("%s\n", buffer);
} else
printf("(null)\n");
}
static int
usershell_read_snapshot_func(struct usershell *us, char *line)
{
us->path = strdup(line);
assert(us->path != NULL);
return (0);
}
static void
usage(void)
{
(void)fprintf(stderr,
"Usage: %s [-d] -s <file>\n",
getprogname());
exit(1);
}
int
main(int argc, char **argv)
{
struct usershell_test_data td, td_snap;
struct usershell ushell;
char *snapshot_file;
int rv;
int c;
if (argc < 2)
usage();
rv = 0;
snapshot_file = NULL;
while ((c = getopt(argc, argv, "ds:")) != -1) {
switch (c) {
case 'd':
debug = 1;
break;
case 's':
snapshot_file = strdup(optarg);
break;
default:
usage();
}
}
TEST_DATA_INIT(usershell, &td, clone_usershell, free_usershell);
TEST_DATA_INIT(usershell, &td_snap, clone_usershell, free_usershell);
setusershell();
while ((ushell.path = getusershell()) != NULL) {
if (debug) {
printf("usershell found:\n");
dump_usershell(&ushell);
}
TEST_DATA_APPEND(usershell, &td, &ushell);
}
endusershell();
if (snapshot_file != NULL) {
if (access(snapshot_file, W_OK | R_OK) != 0) {
if (errno == ENOENT)
method = TEST_BUILD_SNAPSHOT;
else {
if (debug)
printf("can't access the snapshot file %s\n",
snapshot_file);
rv = -1;
goto fin;
}
} else {
rv = TEST_SNAPSHOT_FILE_READ(usershell, snapshot_file,
&td_snap, usershell_read_snapshot_func);
if (rv != 0) {
if (debug)
printf("error reading snapshot file\n");
goto fin;
}
}
}
switch (method) {
case TEST_GETUSERSHELL:
if (snapshot_file != NULL) {
rv = DO_2PASS_TEST(usershell, &td, &td_snap,
compare_usershell, NULL);
}
break;
case TEST_BUILD_SNAPSHOT:
if (snapshot_file != NULL) {
rv = TEST_SNAPSHOT_FILE_WRITE(usershell, snapshot_file, &td,
sdump_usershell);
}
break;
default:
rv = 0;
break;
};
fin:
TEST_DATA_DESTROY(usershell, &td_snap);
TEST_DATA_DESTROY(usershell, &td);
free(snapshot_file);
return (rv);
}

View File

@ -0,0 +1,22 @@
#!/bin/sh
# $FreeBSD$
do_test() {
number=$1
comment=$2
opt=$3
if ./$executable $opt; then
echo "ok $number - $comment"
else
echo "not ok $number - $comment"
fi
}
cd `dirname $0`
executable=`basename $0 .t`
make $executable 2>&1 > /dev/null
echo 1..1
do_test 1 'getusershell() snapshot' '-s snapshot_usershell'

View File

@ -0,0 +1,334 @@
/*-
* Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
* 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.
*
* $FreeBSD$
*/
#include <sys/queue.h>
#define DECLARE_TEST_DATA(ent) \
struct ent##_entry { \
struct ent data; \
STAILQ_ENTRY(ent##_entry) entries; \
}; \
\
struct ent##_test_data { \
void (*clone_func)(struct ent *, struct ent const *); \
void (*free_func)(struct ent *); \
\
STAILQ_HEAD(ent_head, ent##_entry) snapshot_data; \
}; \
\
void __##ent##_test_data_init(struct ent##_test_data *, \
void (*)(struct ent *, struct ent const *), \
void (*freef)(struct ent *)); \
void __##ent##_test_data_destroy(struct ent##_test_data *); \
\
void __##ent##_test_data_append(struct ent##_test_data *, struct ent *data);\
int __##ent##_test_data_foreach(struct ent##_test_data *, \
int (*)(struct ent *, void *), void *); \
int __##ent##_test_data_compare(struct ent##_test_data *, \
struct ent##_test_data *, int (*)(struct ent *, struct ent *, \
void *), void *); \
struct ent *__##ent##_test_data_find(struct ent##_test_data *, struct ent *,\
int (*)(struct ent *, struct ent *, void *), void *); \
void __##ent##_test_data_clear(struct ent##_test_data *);
#define TEST_DATA_INIT(ent, td, clonef, freef)\
__##ent##_test_data_init(td, clonef, freef)
#define TEST_DATA_DESTROY(ent, td) __##ent##_test_data_destroy(td)
#define TEST_DATA_APPEND(ent, td, d) __##ent##_test_data_append(td, d)
#define TEST_DATA_FOREACH(ent, td, f, mdata)\
__##ent##_test_data_foreach(td, f, mdata)
#define TEST_DATA_COMPARE(ent, td1, td2, fcmp, mdata)\
__##ent##_test_data_compare(td1, td2, fcmp, mdata);
#define TEST_DATA_FIND(ent, td, d, fcmp, mdata)\
__##ent##_test_data_find(td, d, fcmp, mdata)
#define TEST_DATA_CLEAR(ent, td) __##ent##_test_data_clear(td)
#define IMPLEMENT_TEST_DATA(ent) \
void \
__##ent##_test_data_init(struct ent##_test_data *td, \
void (*clonef)(struct ent *, struct ent const *), \
void (*freef)(struct ent *)) \
{ \
assert(td != NULL); \
assert(clonef != NULL); \
assert(freef != NULL); \
\
memset(td, 0, sizeof(*td)); \
td->clone_func = clonef; \
td->free_func = freef; \
STAILQ_INIT(&td->snapshot_data); \
} \
\
void \
__##ent##_test_data_destroy(struct ent##_test_data *td) \
{ \
__##ent##_test_data_clear(td); \
} \
\
void \
__##ent##_test_data_append(struct ent##_test_data *td, struct ent *app_data)\
{ \
struct ent##_entry *e; \
\
assert(td != NULL); \
assert(app_data != NULL); \
\
e = (struct ent##_entry *)malloc(sizeof(struct ent##_entry)); \
assert(e != NULL); \
memset(e, 0, sizeof(struct ent##_entry)); \
\
td->clone_func(&e->data, app_data); \
STAILQ_INSERT_TAIL(&td->snapshot_data, e, entries); \
} \
\
int \
__##ent##_test_data_foreach(struct ent##_test_data *td, \
int (*forf)(struct ent *, void *), void *mdata) \
{ \
struct ent##_entry *e; \
int rv; \
\
assert(td != NULL); \
assert(forf != NULL); \
\
rv = 0; \
STAILQ_FOREACH(e, &td->snapshot_data, entries) { \
rv = forf(&e->data, mdata); \
if (rv != 0) \
break; \
} \
\
return (rv); \
} \
\
int \
__##ent##_test_data_compare(struct ent##_test_data *td1, struct ent##_test_data *td2,\
int (*cmp_func)(struct ent *, struct ent *, void *), void *mdata)\
{ \
struct ent##_entry *e1, *e2; \
int rv; \
\
assert(td1 != NULL); \
assert(td2 != NULL); \
assert(cmp_func != NULL); \
\
e1 = STAILQ_FIRST(&td1->snapshot_data); \
e2 = STAILQ_FIRST(&td2->snapshot_data); \
\
rv = 0; \
do { \
if ((e1 == NULL) || (e2 == NULL)) { \
if (e1 == e2) \
return (0); \
else \
return (-1); \
} \
\
rv = cmp_func(&e1->data, &e2->data, mdata); \
e1 = STAILQ_NEXT(e1, entries); \
e2 = STAILQ_NEXT(e2, entries); \
} while (rv == 0); \
\
return (rv); \
} \
\
struct ent * \
__##ent##_test_data_find(struct ent##_test_data *td, struct ent *data, \
int (*cmp)(struct ent *, struct ent *, void *), void *mdata) \
{ \
struct ent##_entry *e; \
struct ent *result; \
\
assert(td != NULL); \
assert(cmp != NULL); \
\
result = NULL; \
STAILQ_FOREACH(e, &td->snapshot_data, entries) { \
if (cmp(&e->data, data, mdata) == 0) { \
result = &e->data; \
break; \
} \
} \
\
return (result); \
} \
\
\
void \
__##ent##_test_data_clear(struct ent##_test_data *td) \
{ \
struct ent##_entry *e; \
assert(td != NULL); \
\
while (!STAILQ_EMPTY(&td->snapshot_data)) { \
e = STAILQ_FIRST(&td->snapshot_data); \
STAILQ_REMOVE_HEAD(&td->snapshot_data, entries); \
\
td->free_func(&e->data); \
free(e); \
} \
}
\
#define DECLARE_TEST_FILE_SNAPSHOT(ent) \
struct ent##_snp_param { \
FILE *fp; \
void (*sdump_func)(struct ent *, char *, size_t); \
}; \
\
int __##ent##_snapshot_write_func(struct ent *, void *); \
int __##ent##_snapshot_write(char const *, struct ent##_test_data *, \
void (*)(struct ent *, char *, size_t)); \
int __##ent##_snapshot_read(char const *, struct ent##_test_data *, \
int (*)(struct ent *, char *));
#define TEST_SNAPSHOT_FILE_WRITE(ent, fname, td, f) \
__##ent##_snapshot_write(fname, td, f)
#define TEST_SNAPSHOT_FILE_READ(ent, fname, td, f) \
__##ent##_snapshot_read(fname, td, f)
#define IMPLEMENT_TEST_FILE_SNAPSHOT(ent) \
int \
__##ent##_snapshot_write_func(struct ent *data, void *mdata) \
{ \
char buffer[1024]; \
struct ent##_snp_param *param; \
\
assert(data != NULL); \
\
param = (struct ent##_snp_param *)mdata; \
param->sdump_func(data, buffer, sizeof(buffer)); \
fputs(buffer, param->fp); \
fputc('\n', param->fp); \
\
return (0); \
} \
\
int \
__##ent##_snapshot_write(char const *fname, struct ent##_test_data *td, \
void (*sdump_func)(struct ent *, char *, size_t)) \
{ \
struct ent##_snp_param param; \
\
assert(fname != NULL); \
assert(td != NULL); \
\
param.fp = fopen(fname, "w"); \
if (param.fp == NULL) \
return (-1); \
\
param.sdump_func = sdump_func; \
__##ent##_test_data_foreach(td, __##ent##_snapshot_write_func, &param);\
fclose(param.fp); \
\
return (0); \
} \
\
int \
__##ent##_snapshot_read(char const *fname, struct ent##_test_data *td, \
int (*read_func)(struct ent *, char *)) \
{ \
char buffer[1024]; \
struct ent data; \
char *s; \
FILE *fi; \
size_t len; \
int rv; \
\
assert(fname != NULL); \
assert(td != NULL); \
\
fi = fopen(fname, "r"); \
if (fi == NULL) \
return (-1); \
\
rv = 0; \
memset(buffer, 0, sizeof(buffer)); \
while (!feof(fi)) { \
s = fgets(buffer, sizeof(buffer), fi); \
if (s != NULL && s[0] != '#') { \
len = strlen(s); \
if (len == 0) \
continue; \
if (buffer[len - 1] == '\n') \
buffer[len -1] = '\0'; \
\
rv = read_func(&data, s); \
if (rv == 0) { \
__##ent##_test_data_append(td, &data); \
td->free_func(&data); \
} else \
goto fin; \
} \
} \
\
fin: \
fclose(fi); \
return (rv); \
}
#define DECLARE_1PASS_TEST(ent) \
int __##ent##_1pass_test(struct ent##_test_data *, \
int (*)(struct ent *, void *), \
void *);
#define DO_1PASS_TEST(ent, td, f, mdata) \
__##ent##_1pass_test(td, f, mdata)
#define IMPLEMENT_1PASS_TEST(ent) \
int \
__##ent##_1pass_test(struct ent##_test_data *td, \
int (*tf)(struct ent *, void *), \
void *mdata) \
{ \
int rv; \
rv = __##ent##_test_data_foreach(td, tf, mdata); \
\
return (rv); \
}
#define DECLARE_2PASS_TEST(ent) \
int __##ent##_2pass_test(struct ent##_test_data *, \
struct ent##_test_data *, \
int (*)(struct ent *, struct ent *, void *), void *);
#define DO_2PASS_TEST(ent, td1, td2, f, mdata) \
__##ent##_2pass_test(td1, td2, f, mdata)
#define IMPLEMENT_2PASS_TEST(ent) \
int \
__##ent##_2pass_test(struct ent##_test_data *td1, \
struct ent##_test_data *td2, \
int (*cmp_func)(struct ent *, struct ent *, void *), \
void *cmp_mdata) \
{ \
int rv; \
\
rv = __##ent##_test_data_compare(td1, td2, cmp_func, cmp_mdata); \
return (rv); \
}