-TABOUNCE_STATE
+-Taddrinfo
-TADDR_MATCH_LIST
-TADDR_PATTERN
-TALIAS_TOKEN
-TMKMAP_OPEN_FN
-TMKMAP_OPEN_INFO
-TMKMAP_SDBM
+-TMOCK_APPL
+-TMOCK_APPL_SIG
+-TMOCK_APPL_STATUS
+-TMOCK_EXPECT
+-TMSG_OUTPUT_INFO
-TMSG_STATS
-TMULTI_SERVER
-TMVECT
-TPSC_SMTPD_COMMAND
-TPSC_STARTTLS
-TPSC_STATE
+-TPTEST_CASE
+-TPTEST_CTX
-TQMGR_ENTRY
-TQMGR_FEEDBACK
-TQMGR_JOB
-TSTRING_LIST
-TSTRING_TABLE
-TSYS_EXITS_DETAIL
--TTEST_CASE
+-TTEST_JMP_BUF
-Ttime_t
-Ttlsa_filter
-TTLS_APPL_STATE
Documentation: Cyrus SASL configuration file location.
Viktor Dukhovni. File: proto/SASL_README.html.
+20220605
+
+ Cleanup: migrate biff_notify() from gethostbyname() and
+ getservbyname() to myaddrinfo. File: local/biff_notify.c.
+
+20220609
+
+ Cleanup: new find_inet_service(3) module that returns errors,
+ and deprecate find_inet(3) where all errors are fatal. File:
+ util/find_inet_service.c.
+
20220617
Cleanup: missing <stdio.h> include was causing a warning
on some platform. posttls-finger/posttls-finger.c.
+20220618
+
+ Cleanup: migrate the MySQL client from find_inet(3) to
+ find_inet_service(3). Files: src/global/dict_mysql.c.
+
20220620
Documentation: inet_interfaces and proxy_interfaces
descriptions. File: proto/postconf.proto.
+20220624
+
+ Cleanup: renamed global/test_main.[hc] to
+ global/test_server_main.[hc]. Files: global/test_server_main.[hc],
+ bounce/bounce_tester.c, Makefiles.
+
+20220626
+
+ Feature: when the NAME_MASK_NULL flag is present, the
+ str_name_mask_opt() function will output a string "0" when the
+ input mask is empty. Files: util/name_mask.[hc].
20220719
regression that broke TLS handshakes. It is rarely useful.
Report by Spil Oss, fix by Viktor Dukhovni. File:
tls/tls_server.c.
+
+ Feature: 'ptest' infrastructure for unit tests, and 'pmock'
+ infrastructure to make tests independent of host configuration,
+ network configuration, or DNS. ptest looks like Go test,
+ while pmock implements a few ideas from Google gmock.
+
+ This changes the Postfix file footprint as follows:
+
+ 1) This adds source files named 'foo_test.c' that test code
+ in 'foo.c' and 'foo.h'; and this adds source files mock_foo.c
+ and mock_foo.h with functions that produce prepared outputs
+ for expected inputs. For example, mock_getaddrinfo.c
+ implements getaddrinfo() and getnameinfo() functions that
+ return prepared outputs without doing host or DNS lookups.
+ More files will be added as tests are converted to the
+ ptest/pmock infrastructure.
+
+ 2) This removes obsolete test data files ('file.in*',
+ 'file.ref*'). More files will be removed as tests are
+ converted to the ptest/pmock infrastructure.
+
+ 3) This renames old files whose names end in test.c:
+ dict_test.c is now dict_cli.c, and stream_test.c is now
+ test_sunos5_stream.c.
src/postsuper src/qmqpd src/spawn src/flush src/verify \
src/virtual src/proxymap src/anvil src/scache src/discard src/tlsmgr \
src/postmulti src/postscreen src/dnsblog src/tlsproxy \
- src/posttls-finger src/postlogd
+ src/posttls-finger src/postlogd src/ptest src/testing
MANDIRS = proto man html
LIBEXEC = libexec/post-install libexec/postfix-script libexec/postfix-wrapper \
libexec/postmulti-script libexec/postfix-tls-script
--- /dev/null
+TODO write a TEST_README that summarizes how to write simple tests
+that don't need custom PTEST_CASE fields (use the example in
+ptest_main.h), how to report test errors and how to require them,
+how to require msg(3) logging, how to write subtests when test data
+does not fit in custom PTEST_CASE fields (use example in test_run.c),
+and how to mock out dependencies (use example in pmock_expect_test.c).
+
+TODO document NO_MOCK_WRAPPERS in makedefs.
+
+TODO move PCRE tests to src/global, and either make them skippable
+(#ifndef USE_DYNAMIC_MAPS) or support dynamic loading in tests.
+
+DONE Need a way to SKIP tests, and report those in the summmary.
+
+ NORETURN ptest_skip(TEST_CTX *t)
+ TEST_CTX has a 'skip' counter
+ main() reports skipped tests
+
+DONE PTEST_CASE.name should be PTEST_CASE.testname
+
+DONE Port hfrom_format.c to use PTEST.
+
+TODO Port haproxy_srvr.c, to use PTEST.
+
+TODO Test that eq_sockaddr() and eq_addrinfo compare all fields for equality.
+
+==============
+
+DONE Subtests. What would the API look like?
+
+With callback:
+test_run(TEST_CTX *t, const char *name, void (*cb)(void *), void *context)
+
+This is clumsy because the callback has to be implemented outside
+the test. Apart from that, the approach is robust and can temporarily
+redirect long jumps.
+
+With inline code:
+ new_ctx = test_start(TEST_CTX *t, const char *name);
+ ... do stuff with new_ctx context...
+ end_test(new_ctx); // merges pass/fail stats into parent.
+
+This keeps the code inside the test. The problem that this still
+exposes internal machinery, such as redircting long jumps and
+logging.
+
+With inline code, again:
+ START_SUB_TEST(new_ctx, name) {
+ ...do actual test...
+ }
+ END_SUB_TEST(new_ctx);
+
+That hides the internal machinery inside macros, but is still too clumsy.
+
+In-line code, single-macro alternative:
+
+ RUN_TEST(t, name, {
+ /* do actual test */
+ });
+
+Now we're talking!
+
+Both Linux gcc 11.3.1 and FreeBSD clang version 11.0.1 pre-process {}
+inside () without problems.
+
+indent complains about "Unbalanced parens" before the '(' and "Extra
+)" before the ')', but formats the code correctly.
+
+clang-format 12.0.1 handles {} inside (), but needs comments with /*
+clang-format off */ and /* clang-format on */ to avoid messing up the
+macro definition (it removes the '\' at the end of the lines).
+
+TODO: make sure that a subtest within a subtest propagates
+the number of subtests passed/failed.
+
+Assume that there always is a parent (the root is special).
+
+#define RUN_TEST(t, name, body_in_braces) \
+ MSG_JMP_BUF new_buf; \
+ TEST_CTX *parent = t;
+ t = test_ctx_create(name, &new_buf); \
+ test_info(t, "RUN %s", t->name); \
+ test_error_setup(t, VSTREAM_ERR); \
+ test_log_setup(t); \
+ msg_vstream_enable(0); \
+ if (msg_setjmp(&new_buf) == 0) { \
+ body_in_braces \
+ } \
+ msg_jmp_bufp = parent->jbuf; \
+ msg_vstream_enable(1); \
+ test_log_wrapup(t); \
+ mock_expect_wrapup(t); \
+ if (test_error_wrapup(t) == 0) { \
+ test_info(t, "PASS %s", t->name); \
+ parent->pass += 1;
+ } else { \
+ test_info(t, "FAIL %s", t->name); \
+ parent->fail += 1; \
+ } \
+ if (t->defer_fn) \
+ t->defer_fn(t->defer_ctx); \
+ test_ctx_free(t);
+ t = parent;
+
+This invites an archiecture where main() creates its own context with
+pass/fail counts and error handling, main() runs top-level tests in their
+own child context, subtests run in a child of a top-level test, and so on.
+
+Remaining questions
+
+- When would we NOT want the test framework to capture msg(3)
+logging? Perhaps in the main test context, where all logging is the
+result of a test framework failure, therefore no events should be
+suppressed with expectations.
+
+- When would we NOT want the test framework to catch panic/fatal
+errors? In a main context they indicate a test framework failure.
+Elsewhere, continuing after such a failure may still be desirable
+even if the result will be less reliable. mymalloc_test.c relies
+on this.
+
+================
+
+DONE: implemented with test_defer(TEST_CTX *t, callback, context) which
+is called from within a test, and which runs deferred code after a test
+is finished.
+
+Some tests just need do some pre setup post cleanup. Actually,
+they need to clean up after a fatal or paninc error. Would this be solved
+with an application callback for example expect_exception(callback, context)?
+Or should we just fork() the program that is being tested?
+
+
+================
+
+mock_expect_apply() should be a void function (now that errors are
+propagated through the test context.
+
+================
+
+DONE: Migrate test from argv.c, dict_stream.c
+
+Implement proper tests for vstream.c
+
+================
+
+DONE Add msg_output test that a popped handler accepts no further logging.
+
+=====================
+
+DONE: msg_output_pop(context) also pops all handlers that were
+registered later. This makes tests more robust and relaxes some
+awkward requirements in msg_output_test.c.
+
+======================
+
+Should we include all test helpers in <testing.h>? Otherwis
+test code would have to include
+separate files for matchers, to_string converters,
+with and without networking.
+
+No, testing.h should not pull in network-related code.
+
+============
+
+The *test.o files need to depend on ../../conf/makedefs.out
+
+=============
+
+wrap system library functions, so that we can mock the wrappers.
+
+And don't use the MOCKABLE (weak symbol) annotation, it breaks
+non-test code!
+
+=================
+
+make_sockaddr() should take an address family argument.
+
+=================
+
+Add a 'type' to the format strings that *print* support.
+
+vbuf_print_register(int char, callback)
+
+void callback(VBUF *bp, int width, int prec, va_list ap)
+
+But would the compiler's format-string checks complain,
+if the new 'type' appears amidst known types?
+
+==================
+
+Should we mock out getaddrinfo() and getnameinfo(), like we mocked
+out getservbyname? It would simplify a few tests, with aome risk of
+less realism. It could also provide a test bed for workarounds.
+
+===================
+
+Cleaning up the dns_lookup/dns_get_h_errno mess.
+
+Ideally, dns_get_h_errno() is removed from the API and all dns_lookup()
+functions return the last h_errno value. But deleting a function
+is bad.
+
+Maybe the mock set_dns_h_errno() can set an expectation for the next
+dns_get_h_errno() calls, then, dns_get_h_errno() would return that.
+
+Problem: dns_lookup_v() and dns_lookup_l() make multiple dns_lookup_x()
+calls, and not every call is followed by a dns_get_h_errno() call.
+So we would need to be able to control the order of mock calls.
+
+Solution: expect_dns_lookup_x() takes an expected h_errno value.
+Calling dns_lookup_x() will update a global variable that is shared with
+get_dns_h_errno() and set_dns_h_errno().
+
+================
+
+Would be nice to shut up msg_vstream() output whle a test runs so that
+logging goes only to the test_log_event() msg_output handler.
+
+Solution: add a msg_vstream_enable(int yesno) function.
+
+================
+
+Really would like to specify a logging expectation inside a test,
+instead of being required to put that outside a test function.
+
+Could it be folded into the test_error() infrastructure? Maybe generalize
+TEST_ERR_INFO interface (and rename it).
+
+Strawman:
+
+ test_log_setup(t)
+ create VSTRING memory stream buffer
+ push test_log_event() msg_output handler, with 't'
+ as callback context
+ expect_log(t, "blah blah")
+ append text to expected ll be made whose formatted text
+ test_log_wrapup(t)
+ pop msg_output handler
+ close memory stream
+ report mismatches between expected argv and actual logging.
+ delete the expected argv
+ delete VSTRING memory stream buffer
+
+One limitation is that code being tested should not push an output
+handler if it may triger a test_fatal() or msg_{fatal,panic}() call
+because their output handlers would persist.
+
+==============
+
+Perhaps add test_info(), test_error(), and test_fatal() for things
+that could be reported directly instead of through logging diffs.
+Question is where to keep the error state. In an object that is
+passed by reference, like other test system do.
+
+The test_xxx() would have to be callable from mock helpers so they
+can't be declared in mock_main.h. The would have to be declared in
+a different header file. For example, testing.h.
+
+Then we no longer rely on result values from test actions.
+
+Will this still work with testing the test system itself, for
+example, to test that eq_dns_rr() really reports all the expected
+differences?
+
+One could add an 'expect this error' method. At test wrap-up time,
+raise a new error when the expected error did not happen.
+
+How does the mock infrastructure know where to report errors? There
+can be only one test main active at a time, It could call a mock_setup
+function that storea a local pointer.
+
+Passing the test object pointer during call expectation setting
+like __FILE__ and __LINE__? That does not work for a mock call that
+has no expectation. This test object pointer would then be an
+eq_mumble argument.
+
+=====================
+
+Replace gethostby* with myaddrinfo calls.
+
+$ grep -l gethostby ../*/*c
+../local/biff_notify.c DONE
+../util/find_inet.c deprecate
+
+$ grep -l getservby ../*/*c
+../local/biff_notify.c DONE
+../posttls-finger/posttls-finger.c
+../smtp/smtp_connect.c
+../util/find_inet.c USE SURROGATE getservbyname
+
+Or deprecate find_inet.c. It's used only in:
+grep -l find_inet.h ../*/*c
+../global/dict_mysql.c
+
# Non-production: needs thorough testing, or major changes are still
# needed before the code stabilizes.
-#CCARGS="$CCARGS -DNONPROD"
+CCARGS="$CCARGS -DNONPROD"
# Workaround: prepend Postfix include files before other include files.
CCARGS="-I. -I../../include $CCARGS"
USE_FNV_32BIT USE_FNV_32BIT
void void cleanup_milter_receive state count
struct DICT open const char int int dict_xx_open
+void void msg_printf level format
+application application specific
+void void dns_set_h_errno int herrval
+application application sans mock_ prefix
+int int eq_enum
+int int eq_str
+void void defer_ctx
+ To undo a test_defer call call the function with a
+ static const struct mumble mumble
+ Null name or name name
+copy_addrinfo copy_addrinfo expectation helper
+ To undo a ptest_defer call call the function with a
reinit
COMPAR
deduplicate
+Deduplicate
+JMP
+MATCHERS
+MOCKABLE
+Matcher
+abc
+addrinfos
+clearjmp
+endservent
+errval
+expcted
+getservbyname
+getservent
+herrno
+herrval
+notexist
+servent
+setservent
+sockaddrinfos
+stayopen
+testcases
+unallocated
+wrapup
+yesno
+Aargh
+getservbyport
+gotlen
+hostlen
+ipprotocol
+lbrary
+mockable
+onlinepubs
+opengroup
+servlen
+sockadddr
+sockaddrinfo
+sockaddrs
+wantlen
+xrat
+xsh
+Matchers
+matchers
+resetjmp
+Subtests
+subtest
+PTEST
+pmock
+ptest
+ptestcase
+ptestcases
+subtests
+case's
segfaulting
srctoman
systemd
+Amma
+Jesper
+Pau
+gmock
+sunos
+Oss
+Spil
bounce_notify_util_tester.o: ../../include/recipient_list.h
bounce_notify_util_tester.o: ../../include/record.h
bounce_notify_util_tester.o: ../../include/sys_defs.h
-bounce_notify_util_tester.o: ../../include/test_main.h
+bounce_notify_util_tester.o: ../../include/test_server_main.h
bounce_notify_util_tester.o: ../../include/vbuf.h
bounce_notify_util_tester.o: ../../include/vstream.h
bounce_notify_util_tester.o: ../../include/vstring.h
/*
* Testing library.
*/
-#include <test_main.h>
+#include <test_server_main.h>
#define TEST_ENCODING "7bit"
#define NO_SMTPUTF8 (0)
0,
};
- test_main(argc, argv, test_driver,
+ test_server_main(argc, argv, test_driver,
CA_TEST_MAIN_INT_TABLE(int_table),
CA_TEST_MAIN_STR_TABLE(str_table),
CA_TEST_MAIN_TIME_TABLE(time_table),
SHELL = /bin/sh
SRCS = dns_lookup.c dns_rr.c dns_strerror.c dns_strtype.c dns_rr_to_pa.c \
dns_sa_to_rr.c dns_rr_eq_sa.c dns_rr_to_sa.c dns_strrecord.c \
- dns_rr_filter.c dns_str_resflags.c dns_sec.c
+ dns_rr_filter.c dns_str_resflags.c dns_sec.c dns_lookup_types.c
OBJS = dns_lookup.o dns_rr.o dns_strerror.o dns_strtype.o dns_rr_to_pa.o \
dns_sa_to_rr.o dns_rr_eq_sa.o dns_rr_to_sa.o dns_strrecord.o \
- dns_rr_filter.o dns_str_resflags.o dns_sec.o
+ dns_rr_filter.o dns_str_resflags.o dns_sec.o dns_lookup_types.o
+TEST_OBJ = dns_lookup_types_test.o
HDRS = dns.h
TESTSRC = test_dns_lookup.c test_alias_token.c
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
CFLAGS = $(DEBUG) $(OPT) $(DEFS)
INCL =
LIB = lib$(LIB_PREFIX)dns$(LIB_SUFFIX)
-TESTPROG= test_dns_lookup dns_rr_to_pa dns_rr_to_sa dns_sa_to_rr dns_rr_eq_sa
+TESTPROG= test_dns_lookup dns_rr_to_pa dns_rr_to_sa dns_sa_to_rr dns_rr_eq_sa \
+ dns_lookup_types_test
LIBS = ../../lib/lib$(LIB_PREFIX)global$(LIB_SUFFIX) \
../../lib/lib$(LIB_PREFIX)util$(LIB_SUFFIX)
+TEST_LIB= ../../lib/libtesting.a ../../lib/libptest.a
LIB_DIR = ../../lib
INC_DIR = ../../include
all: $(LIB)
-$(OBJS): ../../conf/makedefs.out
+$(OBJS) $(TEST_OBJ): ../../conf/makedefs.out
Makefile: Makefile.in
cat ../../conf/makedefs.out $? >$@
tests: test dns_rr_to_pa_test dns_rr_to_sa_test dns_sa_to_rr_test \
dns_rr_eq_sa_test no-a-test no-aaaa-test no-mx-test \
error-filter-test nullmx_test nxdomain_test mxonly_test \
- dnsbl_tests
+ dnsbl_tests test_dns_lookup_types
dnsbl_tests: \
dnsbl_ttl_127.0.0.2_bind_plain_test \
mv $@.o junk
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
mv junk $@.o
-
+
dns_rr_to_pa_test: dns_rr_to_pa dns_rr_to_pa.in dns_rr_to_pa.ref
$(SHLIB_ENV) ./dns_rr_to_pa `cat dns_rr_to_pa.in` >dns_rr_to_pa.tmp
diff dns_rr_to_pa.ref dns_rr_to_pa.tmp
diff mxonly_test.ref mxonly_test.tmp
rm -f mxonly_test.tmp
+dns_lookup_types_test: update dns_lookup_types_test.o \
+ $(LIB_DIR)/mock_dns_lookup.o $(TEST_LIB) $(LIB) $(LIBS)
+ $(CC) $(CFLAGS) -o $@ $@.o $(LIB_DIR)/mock_dns_lookup.o \
+ $(TEST_LIB) $(LIB) $(LIBS) $(SYSLIBS)
+
+test_dns_lookup_types: dns_lookup_types_test
+ $(SHLIB_ENV) $(VALGRIND) ./dns_lookup_types_test
+
# Non-existent record, libbind API, RFC 2308 disabled.
dnsbl_ttl_127.0.0.1_bind_plain_test: test_dns_lookup dnsbl_ttl_127.0.0.1_bind_plain.ref
dns_lookup.o: ../../include/vbuf.h
dns_lookup.o: ../../include/vstream.h
dns_lookup.o: ../../include/vstring.h
+dns_lookup.o: ../../include/wrap_netdb.h
dns_lookup.o: dns.h
dns_lookup.o: dns_lookup.c
+dns_lookup_types.o: ../../include/argv.h
+dns_lookup_types.o: ../../include/check_arg.h
+dns_lookup_types.o: ../../include/dict.h
+dns_lookup_types.o: ../../include/maps.h
+dns_lookup_types.o: ../../include/msg.h
+dns_lookup_types.o: ../../include/myaddrinfo.h
+dns_lookup_types.o: ../../include/myflock.h
+dns_lookup_types.o: ../../include/sock_addr.h
+dns_lookup_types.o: ../../include/sys_defs.h
+dns_lookup_types.o: ../../include/vbuf.h
+dns_lookup_types.o: ../../include/vstream.h
+dns_lookup_types.o: ../../include/vstring.h
+dns_lookup_types.o: ../../include/wrap_netdb.h
+dns_lookup_types.o: dns.h
+dns_lookup_types.o: dns_lookup_types.c
+dns_lookup_types_test.o: ../../include/argv.h
+dns_lookup_types_test.o: ../../include/check_arg.h
+dns_lookup_types_test.o: ../../include/mock_dns.h
+dns_lookup_types_test.o: ../../include/msg.h
+dns_lookup_types_test.o: ../../include/msg_output.h
+dns_lookup_types_test.o: ../../include/msg_vstream.h
+dns_lookup_types_test.o: ../../include/myaddrinfo.h
+dns_lookup_types_test.o: ../../include/pmock_expect.h
+dns_lookup_types_test.o: ../../include/ptest.h
+dns_lookup_types_test.o: ../../include/ptest_main.h
+dns_lookup_types_test.o: ../../include/sock_addr.h
+dns_lookup_types_test.o: ../../include/stringops.h
+dns_lookup_types_test.o: ../../include/sys_defs.h
+dns_lookup_types_test.o: ../../include/vbuf.h
+dns_lookup_types_test.o: ../../include/vstream.h
+dns_lookup_types_test.o: ../../include/vstring.h
+dns_lookup_types_test.o: ../../include/wrap_netdb.h
+dns_lookup_types_test.o: dns.h
+dns_lookup_types_test.o: dns_lookup_types_test.c
dns_rr.o: ../../include/check_arg.h
dns_rr.o: ../../include/msg.h
dns_rr.o: ../../include/myaddrinfo.h
dns_rr.o: ../../include/sys_defs.h
dns_rr.o: ../../include/vbuf.h
dns_rr.o: ../../include/vstring.h
+dns_rr.o: ../../include/wrap_netdb.h
dns_rr.o: dns.h
dns_rr.o: dns_rr.c
dns_rr_eq_sa.o: ../../include/check_arg.h
dns_rr_eq_sa.o: ../../include/sys_defs.h
dns_rr_eq_sa.o: ../../include/vbuf.h
dns_rr_eq_sa.o: ../../include/vstring.h
+dns_rr_eq_sa.o: ../../include/wrap_netdb.h
dns_rr_eq_sa.o: dns.h
dns_rr_eq_sa.o: dns_rr_eq_sa.c
dns_rr_filter.o: ../../include/argv.h
dns_rr_filter.o: ../../include/vbuf.h
dns_rr_filter.o: ../../include/vstream.h
dns_rr_filter.o: ../../include/vstring.h
+dns_rr_filter.o: ../../include/wrap_netdb.h
dns_rr_filter.o: dns.h
dns_rr_filter.o: dns_rr_filter.c
dns_rr_to_pa.o: ../../include/check_arg.h
dns_rr_to_pa.o: ../../include/sys_defs.h
dns_rr_to_pa.o: ../../include/vbuf.h
dns_rr_to_pa.o: ../../include/vstring.h
+dns_rr_to_pa.o: ../../include/wrap_netdb.h
dns_rr_to_pa.o: dns.h
dns_rr_to_pa.o: dns_rr_to_pa.c
dns_rr_to_sa.o: ../../include/check_arg.h
dns_rr_to_sa.o: ../../include/sys_defs.h
dns_rr_to_sa.o: ../../include/vbuf.h
dns_rr_to_sa.o: ../../include/vstring.h
+dns_rr_to_sa.o: ../../include/wrap_netdb.h
dns_rr_to_sa.o: dns.h
dns_rr_to_sa.o: dns_rr_to_sa.c
dns_sa_to_rr.o: ../../include/check_arg.h
dns_sa_to_rr.o: ../../include/sys_defs.h
dns_sa_to_rr.o: ../../include/vbuf.h
dns_sa_to_rr.o: ../../include/vstring.h
+dns_sa_to_rr.o: ../../include/wrap_netdb.h
dns_sa_to_rr.o: dns.h
dns_sa_to_rr.o: dns_sa_to_rr.c
dns_sec.o: ../../include/check_arg.h
dns_sec.o: ../../include/sys_defs.h
dns_sec.o: ../../include/vbuf.h
dns_sec.o: ../../include/vstring.h
+dns_sec.o: ../../include/wrap_netdb.h
dns_sec.o: dns.h
dns_sec.o: dns_sec.c
dns_str_resflags.o: ../../include/check_arg.h
dns_str_resflags.o: ../../include/sys_defs.h
dns_str_resflags.o: ../../include/vbuf.h
dns_str_resflags.o: ../../include/vstring.h
+dns_str_resflags.o: ../../include/wrap_netdb.h
dns_str_resflags.o: dns.h
dns_str_resflags.o: dns_str_resflags.c
dns_strerror.o: ../../include/check_arg.h
dns_strerror.o: ../../include/sys_defs.h
dns_strerror.o: ../../include/vbuf.h
dns_strerror.o: ../../include/vstring.h
+dns_strerror.o: ../../include/wrap_netdb.h
dns_strerror.o: dns.h
dns_strerror.o: dns_strerror.c
dns_strrecord.o: ../../include/check_arg.h
dns_strrecord.o: ../../include/sys_defs.h
dns_strrecord.o: ../../include/vbuf.h
dns_strrecord.o: ../../include/vstring.h
+dns_strrecord.o: ../../include/wrap_netdb.h
dns_strrecord.o: dns.h
dns_strrecord.o: dns_strrecord.c
dns_strtype.o: ../../include/check_arg.h
dns_strtype.o: ../../include/sys_defs.h
dns_strtype.o: ../../include/vbuf.h
dns_strtype.o: ../../include/vstring.h
+dns_strtype.o: ../../include/wrap_netdb.h
dns_strtype.o: dns.h
dns_strtype.o: dns_strtype.c
test_dns_lookup.o: ../../include/argv.h
test_dns_lookup.o: ../../include/vbuf.h
test_dns_lookup.o: ../../include/vstream.h
test_dns_lookup.o: ../../include/vstring.h
+test_dns_lookup.o: ../../include/wrap_netdb.h
test_dns_lookup.o: dns.h
test_dns_lookup.o: test_dns_lookup.c
extern int dns_lookup_rl(const char *, unsigned, DNS_RR **, VSTRING *,
VSTRING *, int *, int,...);
extern int dns_lookup_rv(const char *, unsigned, DNS_RR **, VSTRING *,
- VSTRING *, int *, int, unsigned *);
+ VSTRING *, int *, int, const unsigned *);
extern int dns_get_h_errno(void);
+extern void dns_set_h_errno(int);
#define dns_lookup(name, type, rflags, list, fqdn, why) \
dns_lookup_x((name), (type), (rflags), (list), (fqdn), (why), (int *) 0, \
/* unsigned *ltype;
/*
/* int dns_get_h_errno()
+/*
+/* void dns_set_h_errno(
+/* int errval)
/* AUXILIARY FUNCTIONS
/* extern int var_dns_ncache_ttl_fix;
/*
/* an invalid name is reported as a DNS_INVAL result, while
/* malformed replies are reported as transient errors.
/*
-/* dns_get_h_errno() returns the last error. This deprecates
-/* usage of the global h_errno variable. We should not rely
-/* on that being updated.
+/* dns_get_h_errno() returns the last error, and dns_set_h_errno()
+/* sets it. This deprecates usage of the global h_errno variable.
+/* We should not rely on that being updated.
/*
/* dns_lookup_l() and dns_lookup_v() allow the user to specify
/* a list of resource types.
#define INET6_ADDR_LEN 16 /* XXX */
/*
- * Use the threadsafe resolver API if available, not because it is theadsafe,
- * but because it has more functionality.
+ * Use the threadsafe resolver API if available, not because it is
+ * theadsafe, but because it has more functionality.
*/
#ifdef USE_RES_NCALLS
static struct __res_state dns_res_state;
return (DNS_NOTFOUND);
}
-/* dns_lookup_rl - DNS lookup interface with types list */
-
-int dns_lookup_rl(const char *name, unsigned flags, DNS_RR **rrlist,
- VSTRING *fqdn, VSTRING *why, int *rcode,
- int lflags,...)
-{
- va_list ap;
- unsigned type, next;
- int status = DNS_NOTFOUND;
- int hpref_status = INT_MIN;
- VSTRING *hpref_rtext = 0;
- int hpref_rcode;
- int hpref_h_errno;
- DNS_RR *rr;
-
- /* Save intermediate highest-priority result. */
-#define SAVE_HPREF_STATUS() do { \
- hpref_status = status; \
- if (rcode) \
- hpref_rcode = *rcode; \
- if (why && status != DNS_OK) \
- vstring_strcpy(hpref_rtext ? hpref_rtext : \
- (hpref_rtext = vstring_alloc(VSTRING_LEN(why))), \
- vstring_str(why)); \
- hpref_h_errno = DNS_GET_H_ERRNO(&dns_res_state); \
- } while (0)
-
- /* Restore intermediate highest-priority result. */
-#define RESTORE_HPREF_STATUS() do { \
- status = hpref_status; \
- if (rcode) \
- *rcode = hpref_rcode; \
- if (why && status != DNS_OK) \
- vstring_strcpy(why, vstring_str(hpref_rtext)); \
- DNS_SET_H_ERRNO(&dns_res_state, hpref_h_errno); \
- } while (0)
-
- if (rrlist)
- *rrlist = 0;
- va_start(ap, lflags);
- for (type = va_arg(ap, unsigned); type != 0; type = next) {
- next = va_arg(ap, unsigned);
- if (msg_verbose)
- msg_info("lookup %s type %s flags %s",
- name, dns_strtype(type), dns_str_resflags(flags));
- status = dns_lookup_x(name, type, flags, rrlist ? &rr : (DNS_RR **) 0,
- fqdn, why, rcode, lflags);
- if (rrlist && rr)
- *rrlist = dns_rr_append(*rrlist, rr);
- if (status == DNS_OK) {
- if (lflags & DNS_REQ_FLAG_STOP_OK)
- break;
- } else if (status == DNS_INVAL) {
- if (lflags & DNS_REQ_FLAG_STOP_INVAL)
- break;
- } else if (status == DNS_POLICY) {
- if (type == T_MX && (lflags & DNS_REQ_FLAG_STOP_MX_POLICY))
- break;
- } else if (status == DNS_NULLMX) {
- if (lflags & DNS_REQ_FLAG_STOP_NULLMX)
- break;
- }
- /* XXX Stop after NXDOMAIN error. */
- if (next == 0)
- break;
- if (status >= hpref_status)
- SAVE_HPREF_STATUS(); /* save last info */
- }
- va_end(ap);
- if (status < hpref_status)
- RESTORE_HPREF_STATUS(); /* else report last info */
- if (hpref_rtext)
- vstring_free(hpref_rtext);
- return (status);
-}
-
-/* dns_lookup_rv - DNS lookup interface with types vector */
+/* dns_get_h_errno - get the last lookup status */
-int dns_lookup_rv(const char *name, unsigned flags, DNS_RR **rrlist,
- VSTRING *fqdn, VSTRING *why, int *rcode,
- int lflags, unsigned *types)
+int dns_get_h_errno(void)
{
- unsigned type, next;
- int status = DNS_NOTFOUND;
- int hpref_status = INT_MIN;
- VSTRING *hpref_rtext = 0;
- int hpref_rcode;
- int hpref_h_errno;
- DNS_RR *rr;
-
- if (rrlist)
- *rrlist = 0;
- for (type = *types++; type != 0; type = next) {
- next = *types++;
- if (msg_verbose)
- msg_info("lookup %s type %s flags %s",
- name, dns_strtype(type), dns_str_resflags(flags));
- status = dns_lookup_x(name, type, flags, rrlist ? &rr : (DNS_RR **) 0,
- fqdn, why, rcode, lflags);
- if (rrlist && rr)
- *rrlist = dns_rr_append(*rrlist, rr);
- if (status == DNS_OK) {
- if (lflags & DNS_REQ_FLAG_STOP_OK)
- break;
- } else if (status == DNS_INVAL) {
- if (lflags & DNS_REQ_FLAG_STOP_INVAL)
- break;
- } else if (status == DNS_POLICY) {
- if (type == T_MX && (lflags & DNS_REQ_FLAG_STOP_MX_POLICY))
- break;
- } else if (status == DNS_NULLMX) {
- if (lflags & DNS_REQ_FLAG_STOP_NULLMX)
- break;
- }
- /* XXX Stop after NXDOMAIN error. */
- if (next == 0)
- break;
- if (status >= hpref_status)
- SAVE_HPREF_STATUS(); /* save last info */
- }
- if (status < hpref_status)
- RESTORE_HPREF_STATUS(); /* else report last info */
- if (hpref_rtext)
- vstring_free(hpref_rtext);
- return (status);
+ return (DNS_GET_H_ERRNO(&dns_res_state));
}
-/* dns_get_h_errno - get the last lookup status */
+/* dns_set_h_errno - set the last lookup status */
-int dns_get_h_errno(void)
+void dns_set_h_errno(int errval)
{
- return (DNS_GET_H_ERRNO(&dns_res_state));
+ DNS_SET_H_ERRNO(&dns_res_state, errval);
}
--- /dev/null
+/*++
+/* NAME
+/* dns_lookup_types 3
+/* SUMMARY
+/* domain name service lookup for multiple types
+/* SYNOPSIS
+/* #include <dns.h>
+/*
+/* int dns_lookup_l(name, rflags, list, fqdn, why, lflags, ...)
+/* const char *name;
+/* unsigned rflags;
+/* DNS_RR **list;
+/* VSTRING *fqdn;
+/* VSTRING *why;
+/* int lflags;
+/*
+/* int dns_lookup_v(name, rflags, list, fqdn, why, lflags, ltype)
+/* const char *name;
+/* unsigned rflags;
+/* DNS_RR **list;
+/* VSTRING *fqdn;
+/* VSTRING *why;
+/* int lflags;
+/* unsigned *ltype;
+/* AUXILIARY FUNCTIONS
+/* int dns_lookup_rl(name, rflags, list, fqdn, why, rcode, lflags, ...)
+/* const char *name;
+/* unsigned rflags;
+/* DNS_RR **list;
+/* VSTRING *fqdn;
+/* VSTRING *why;
+/* int *rcode;
+/* int lflags;
+/*
+/* int dns_lookup_rv(name, rflags, list, fqdn, why, rcode, lflags,
+/* ltype)
+/* const char *name;
+/* unsigned rflags;
+/* DNS_RR **list;
+/* VSTRING *fqdn;
+/* VSTRING *why;
+/* int *rcode;
+/* int lflags;
+/* unsigned *ltype;
+/* DESCRIPTION
+/* These functions iterate over a sequence of unsigned resource
+/* types, call dns_lookup_x() for each type, and carefully
+/* aggregate the resulting error and non-error results.
+/*
+/* dns_lookup_rl() and dns_lookup_l() iterate over a variadic
+/* list of query types, while dns_lookup_rv() and dns_lookup_v()
+/* iterate over a vector of query types.
+/* DIAGNOSTICS
+/* SEE ALSO
+/* dns_lookup(3), domain name service lookup
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+
+/* Utility library. */
+
+#include <vstring.h>
+#include <msg.h>
+
+/* DNS library. */
+
+#define LIBDNS_INTERNAL
+#include <dns.h>
+
+ /*
+ * KISS memory management.
+ */
+#define MAX_TYPE 10
+
+/* dns_lookup_rl - DNS lookup interface with types list */
+
+int dns_lookup_rl(const char *name, unsigned flags, DNS_RR **rrlist,
+ VSTRING *fqdn, VSTRING *why, int *rcode,
+ int lflags,...)
+{
+ va_list ap;
+ unsigned type, types[MAX_TYPE];
+ int count = 0;
+
+ va_start(ap, lflags);
+ for (type = va_arg(ap, unsigned); type != 0; type = va_arg(ap, unsigned)) {
+ if (count >= MAX_TYPE - 1)
+ msg_panic("dns_lookup_rl: too many types");
+ types[count++] = type;
+ }
+ types[count] = 0;
+ va_end(ap);
+ return (dns_lookup_rv(name, flags, rrlist, fqdn, why, rcode, lflags, types));
+}
+
+/* dns_lookup_rv - DNS lookup interface with types vector */
+
+int dns_lookup_rv(const char *name, unsigned flags, DNS_RR **rrlist,
+ VSTRING *fqdn, VSTRING *why, int *rcode,
+ int lflags, const unsigned *types)
+{
+ unsigned type, next;
+ int status = DNS_NOTFOUND;
+ int hpref_status = INT_MIN;
+ VSTRING *hpref_rtext = 0;
+ int hpref_rcode;
+ int hpref_h_errno;
+ DNS_RR *rr;
+
+ /* Save intermediate highest-priority result. */
+#define SAVE_HPREF_STATUS() do { \
+ hpref_status = status; \
+ if (rcode) \
+ hpref_rcode = *rcode; \
+ if (why && status != DNS_OK) \
+ vstring_strcpy(hpref_rtext ? hpref_rtext : \
+ (hpref_rtext = vstring_alloc(VSTRING_LEN(why))), \
+ vstring_str(why)); \
+ hpref_h_errno = dns_get_h_errno(); \
+ } while (0)
+
+ /* Restore intermediate highest-priority result. */
+#define RESTORE_HPREF_STATUS() do { \
+ status = hpref_status; \
+ if (rcode) \
+ *rcode = hpref_rcode; \
+ if (why && status != DNS_OK) \
+ vstring_strcpy(why, vstring_str(hpref_rtext)); \
+ dns_set_h_errno(hpref_h_errno); \
+ } while (0)
+
+ if (rrlist)
+ *rrlist = 0;
+ for (type = *types++; type != 0; type = next) {
+ next = *types++;
+ if (msg_verbose)
+ msg_info("lookup %s type %s flags %s",
+ name, dns_strtype(type), dns_str_resflags(flags));
+ status = dns_lookup_x(name, type, flags, rrlist ? &rr : (DNS_RR **) 0,
+ fqdn, why, rcode, lflags);
+ if (rrlist && rr)
+ *rrlist = dns_rr_append(*rrlist, rr);
+ if (status == DNS_OK) {
+ if (lflags & DNS_REQ_FLAG_STOP_OK)
+ break;
+ } else if (status == DNS_INVAL) {
+ if (lflags & DNS_REQ_FLAG_STOP_INVAL)
+ break;
+ } else if (status == DNS_POLICY) {
+ if (type == T_MX && (lflags & DNS_REQ_FLAG_STOP_MX_POLICY))
+ break;
+ } else if (status == DNS_NULLMX) {
+ if (lflags & DNS_REQ_FLAG_STOP_NULLMX)
+ break;
+ }
+ /* XXX Stop after NXDOMAIN error. */
+ if (next == 0)
+ break;
+ if (status >= hpref_status)
+ SAVE_HPREF_STATUS(); /* save last info */
+ }
+ if (status < hpref_status)
+ RESTORE_HPREF_STATUS(); /* else report last info */
+ if (hpref_rtext)
+ vstring_free(hpref_rtext);
+ return (status);
+}
--- /dev/null
+ /*
+ * Test program to mocks including logging. See pmock_expect_test.c and
+ * ptest_main.h for a documented example.
+ */
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+
+ /*
+ * Utility library.
+ */
+#include <msg.h>
+#include <vstring.h>
+
+ /*
+ * DNS library.
+ */
+#include <dns.h>
+
+ /*
+ * Test library.
+ */
+#include <mock_dns.h>
+#include <ptest.h>
+
+typedef struct PTEST_CASE {
+ const char *testname; /* Human-readable description */
+ void (*action) (PTEST_CTX *, const struct PTEST_CASE *);
+} PTEST_CASE;
+
+ /*
+ * dns_lookup_rl() forwards all calls to dns_lookup_rv(), therefore most
+ * tests will focus on dns_lookup_rl().
+ */
+#define NO_RFLAGS 0
+#define NO_LFLAGS 0
+
+static void test_dns_lookup_rl_success(PTEST_CTX *t, const PTEST_CASE *unused)
+{
+ int got_st, want_st = DNS_OK;
+ DNS_RR *got_rr = 0, *want_rr;
+ int got_rcode, want_rcode = NOERROR;
+ int got_herrval, want_herrval = 0;
+
+ /*
+ * Set up expectations and prepared responses.
+ */
+ want_rr = make_dns_rr("example.com", "example.com", T_MX, C_IN,
+ 5, 0, 10, "m1.example.com", 14);
+ expect_dns_lookup_x(1, want_herrval, DNS_OK, "example.com", T_MX,
+ NO_RFLAGS, want_rr, (VSTRING *) 0, (VSTRING *) 0,
+ NOERROR, NO_LFLAGS);
+
+ got_st = dns_lookup_rl("example.com", NO_RFLAGS, &got_rr, (VSTRING *) 0,
+ (VSTRING *) 0, &got_rcode, NO_LFLAGS, T_MX, 0);
+ if (got_st != want_st) {
+ ptest_error(t, "dns_lookup_rl: got result %d, want %d",
+ got_st, want_st);
+ } else if (got_rcode != want_rcode) {
+ ptest_error(t, "dns_lookup_rl: got rcode %d, want %d",
+ got_rcode, want_rcode);
+ } else {
+ (void) eq_dns_rr(t, "dns_lookup_rl", got_rr, want_rr);
+ }
+
+ got_herrval = dns_get_h_errno();
+ if (got_herrval != want_herrval)
+ ptest_error(t, "dns_get_h_errno: got %d, want %d",
+ got_herrval, want_herrval);
+
+ /*
+ * Cleanup.
+ */
+ dns_rr_free(want_rr);
+ if (got_rr)
+ dns_rr_free(got_rr);
+}
+
+static void test_dns_lookup_rv_success(PTEST_CTX *t, const PTEST_CASE *unused)
+{
+ int got_st, want_st = DNS_OK;
+ DNS_RR *got_rr = 0, *want_rr;
+ int got_rcode, want_rcode = NOERROR;
+ int got_herrval, want_herrval = 0;
+ static const unsigned rr_types[2] = {T_MX, 0};
+
+ /*
+ * Set up expectations and prepared responses,
+ */
+ want_rr = make_dns_rr("example.com", "example.com", T_MX, C_IN,
+ 5, 0, 10, "m1.example.com", 14);
+ expect_dns_lookup_x(1, want_herrval, DNS_OK, "example.com", T_MX,
+ NO_RFLAGS, want_rr, (VSTRING *) 0, (VSTRING *) 0,
+ NOERROR, NO_LFLAGS);
+
+ got_st = dns_lookup_rv("example.com", NO_RFLAGS, &got_rr, (VSTRING *) 0,
+ (VSTRING *) 0, &got_rcode, NO_LFLAGS, rr_types);
+ if (got_st != want_st) {
+ ptest_error(t, "dns_lookup_rv: got result %d, want %d",
+ got_st, want_st);
+ } else if (got_rcode != want_rcode) {
+ ptest_error(t, "dns_lookup_rv: got rcode %d, want %d",
+ got_rcode, want_rcode);
+ } else {
+ (void) eq_dns_rr(t, "dns_lookup_rv", got_rr, want_rr);
+ }
+
+ got_herrval = dns_get_h_errno();
+ if (got_herrval != want_herrval)
+ ptest_error(t, "dns_get_h_errno: got %d, want %d",
+ got_herrval, want_herrval);
+
+ /*
+ * Cleanup.
+ */
+ dns_rr_free(want_rr);
+ if (got_rr)
+ dns_rr_free(got_rr);
+}
+
+static void test_dns_lookup_rv_error_ladder(PTEST_CTX *t,
+ const PTEST_CASE *unused)
+{
+ int got_st;
+ int got_herrval;
+ struct step {
+ int want_st;
+ int want_herrval;
+ };
+ struct step ladder[] = {
+ DNS_OK, 0,
+ DNS_POLICY, 0,
+ DNS_RETRY, TRY_AGAIN,
+ DNS_INVAL, 0,
+ DNS_FAIL, NO_RECOVERY,
+ DNS_NULLMX, 0,
+ DNS_NOTFOUND, NO_DATA,
+ };
+ struct step *lp;
+ VSTRING *label = vstring_alloc(100);
+
+#define LADDER_SIZE (sizeof(ladder)/sizeof(*ladder))
+
+ for (lp = ladder; lp < ladder + LADDER_SIZE - 1; lp++) {
+
+ vstring_sprintf(label, "%s precedence over %s",
+ dns_status_to_string(lp->want_st),
+ dns_status_to_string(lp[1].want_st));
+
+ PTEST_RUN(t, vstring_str(label), {
+
+ /*
+ * Set up expectations and prepared responses.
+ */
+ expect_dns_lookup_x(1, lp->want_herrval, lp->want_st,
+ "example.com", T_MX, NO_RFLAGS, (DNS_RR *) 0,
+ (VSTRING *) 0, (VSTRING *) 0, NOERROR, NO_LFLAGS);
+ expect_dns_lookup_x(1, lp[1].want_herrval, lp[1].want_st,
+ "example.com", T_A, NO_RFLAGS, (DNS_RR *) 0,
+ (VSTRING *) 0, (VSTRING *) 0, NOERROR, NO_LFLAGS);
+
+ /*
+ * Call the mock and verify the results.
+ */
+ got_st = dns_lookup_rl("example.com", NO_RFLAGS, (DNS_RR **) 0,
+ (VSTRING *) 0, (VSTRING *) 0, (int *) 0,
+ NO_LFLAGS, T_MX, T_A, 0);
+ if (got_st != lp->want_st) {
+ ptest_error(t, "dns_lookup_rv: got result %d, want %d",
+ got_st, lp->want_st);
+ }
+ got_herrval = dns_get_h_errno();
+ if (got_herrval != lp->want_herrval)
+ ptest_error(t, "dns_get_h_errno: got %d, want %d",
+ got_herrval, lp->want_herrval);
+ });
+ }
+ vstring_free(label);
+}
+
+ /*
+ * Test cases. The "success" tests exercise the expectation match and apply
+ * helpers, and "failure" tests exercise the print helpers. All tests
+ * exercise the expectation free helpers.
+ */
+const PTEST_CASE ptestcases[] = {
+ {
+ "test_dns_lookup_rl success", test_dns_lookup_rl_success,
+ },
+ {
+ "test_dns_lookup_rv success", test_dns_lookup_rv_success,
+ },
+ {
+ "test_dns_lookup_rv error ladder", test_dns_lookup_rv_error_ladder,
+ },
+};
+
+#include <ptest_main.h>
dnsblog.o: ../../include/vbuf.h
dnsblog.o: ../../include/vstream.h
dnsblog.o: ../../include/vstring.h
+dnsblog.o: ../../include/wrap_netdb.h
dnsblog.o: dnsblog.c
mail_addr_form.c quote_flags.c maillog_client.c \
normalize_mailhost_addr.c map_search.c reject_deliver_request.c \
info_log_addr_form.c sasl_mech_filter.c login_sender_match.c \
- test_main.c compat_level.c config_known_tcp_ports.c \
+ test_server_main.c compat_level.c config_known_tcp_ports.c \
hfrom_format.c
OBJS = abounce.o anvil_clnt.o been_here.o bounce.o bounce_log.o \
canon_addr.o cfg_parser.o cleanup_strerror.o cleanup_strflags.o \
$(NON_PLUGIN_MAP_OBJ) mail_addr_form.o quote_flags.o maillog_client.o \
normalize_mailhost_addr.o map_search.o reject_deliver_request.o \
info_log_addr_form.o sasl_mech_filter.o login_sender_match.o \
- test_main.o compat_level.o config_known_tcp_ports.o \
+ test_server_main.o compat_level.o config_known_tcp_ports.o \
hfrom_format.o
# MAP_OBJ is for maps that may be dynamically loaded with dynamicmaps.cf.
# When hard-linking these maps, makedefs sets NON_PLUGIN_MAP_OBJ=$(MAP_OBJ),
# otherwise it sets the PLUGIN_* macros.
MAP_OBJ = dict_ldap.o dict_mysql.o dict_pgsql.o dict_sqlite.o
-
+TEST_OBJ = normalize_mailhost_addr_test.o smtp_reply_footer_test.o \
+ login_sender_match_test.o map_search_test.o delivered_hdr_test.o \
+ config_known_tcp_ports_test.o hfrom_format_test.o
HDRS = abounce.h anvil_clnt.h been_here.h bounce.h bounce_log.h \
canon_addr.h cfg_parser.h cleanup_user.h clnt_stream.h config.h \
conv_time.h db_common.h debug_peer.h debug_process.h defer.h \
attr_override.h mail_parm_split.h midna_adomain.h mail_addr_form.h \
maillog_client.h normalize_mailhost_addr.h map_search.h \
info_log_addr_form.h sasl_mech_filter.h login_sender_match.h \
- test_main.h compat_level.h config_known_tcp_ports.h \
+ test_server_main.h compat_level.h config_known_tcp_ports.h \
hfrom_format.h
-TESTSRC = rec2stream.c stream2rec.c recdump.c
+TESTSRC = rec2stream.c stream2rec.c recdump.c login_sender_match_test.c \
+ normalize_mailhost_addr_test.c smtp_reply_footer_test.c \
+ map_search_test.c
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
CFLAGS = $(DEBUG) $(OPT) $(DEFS)
INCL =
valid_mailhost_addr own_inet_addr header_body_checks \
data_redirect addr_match_list safe_ultostr verify_sender_addr \
mail_version mail_dict server_acl uxtext mail_parm_split \
- fold_addr smtp_reply_footer mail_addr_map normalize_mailhost_addr \
- haproxy_srvr map_search delivered_hdr login_sender_match \
- compat_level config_known_tcp_ports hfrom_format
+ fold_addr smtp_reply_footer_test mail_addr_map \
+ normalize_mailhost_addr_test haproxy_srvr map_search_test \
+ delivered_hdr_test login_sender_match_test \
+ compat_level config_known_tcp_ports_test hfrom_format_test
LIBS = ../../lib/lib$(LIB_PREFIX)util$(LIB_SUFFIX)
+TEST_LIB= ../../lib/libtesting.a ../../lib/libptest.a
LIB_DIR = ../../lib
INC_DIR = ../../include
PLUGIN_MAP_SO = $(LIB_PREFIX)ldap$(LIB_SUFFIX) $(LIB_PREFIX)mysql$(LIB_SUFFIX) \
all: $(LIB) $(PLUGIN_MAP_SO_MAKE) $(PLUGIN_MAP_OBJ)
-$(OBJS) $(PLUGIN_MAP_OBJ): ../../conf/makedefs.out
+$(OBJS) $(PLUGIN_MAP_OBJ) $(TEST_OBJ): ../../conf/makedefs.out
Makefile: Makefile.in
cat ../../conf/makedefs.out $? >$@
fold_addr: fold_addr.c $(LIB) $(LIBS)
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
-smtp_reply_footer: smtp_reply_footer.c $(LIB) $(LIBS)
- $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
-
-normalize_mailhost_addr: normalize_mailhost_addr.c $(LIB) $(LIBS)
- $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
-
haproxy_srvr: haproxy_srvr.c $(LIB) $(LIBS)
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
-map_search: map_search.c $(LIB) $(LIBS)
- $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
-
-delivered_hdr: delivered_hdr.c $(LIB) $(LIBS)
- $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
-
-login_sender_match: login_sender_match.c $(LIB) $(LIBS)
- $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
-
compat_level: compat_level.c $(LIB) $(LIBS)
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
-hfrom_format: hfrom_format.c $(LIB) $(LIBS)
- $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
-
-config_known_tcp_ports: config_known_tcp_ports.c $(LIB) $(LIBS)
- $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
-
tests: tok822_test mime_tests strip_addr_test tok822_limit_test \
xtext_test scache_multi_test ehlo_mask_test \
namadr_list_test mail_conf_time_test header_body_checks_tests \
mail_version_test server_acl_test resolve_local_test maps_test \
safe_ultostr_test mail_parm_split_test fold_addr_test \
- smtp_reply_footer_test off_cvt_test mail_addr_crunch_test \
+ test_smtp_reply_footer off_cvt_test mail_addr_crunch_test \
mail_addr_find_test mail_addr_map_test quote_822_local_test \
- normalize_mailhost_addr_test haproxy_srvr_test map_search_test \
- delivered_hdr_test login_sender_match_test compat_level_test \
- config_known_tcp_ports_test hfrom_format_test
+ test_normalize_mailhost_addr haproxy_srvr_test test_map_search \
+ delivered_hdr_test test_login_sender_match compat_level_test \
+ test_config_known_tcp_ports test_hfrom_format
mime_tests: mime_test mime_nest mime_8bit mime_dom mime_trunc mime_cvt \
mime_cvt2 mime_cvt3 mime_garb1 mime_garb2 mime_garb3 mime_garb4
diff fold_addr_test.ref fold_addr_test.tmp
rm -f fold_addr_test.tmp
-smtp_reply_footer_test: smtp_reply_footer smtp_reply_footer.ref
- $(SHLIB_ENV) $(VALGRIND) ./smtp_reply_footer >smtp_reply_footer.tmp 2>&1
- diff smtp_reply_footer.ref smtp_reply_footer.tmp
- rm -f smtp_reply_footer.tmp
+smtp_reply_footer_test: smtp_reply_footer_test.o $(TEST_LIB) $(LIB) $(LIBS)
+ $(CC) $(CFLAGS) -o $@ $@.o $(TEST_LIB) $(LIB) $(LIBS) $(SYSLIBS)
+
+test_smtp_reply_footer: smtp_reply_footer_test
+ $(SHLIB_ENV) $(VALGRIND) ./smtp_reply_footer_test
off_cvt_test: off_cvt off_cvt.in off_cvt.ref
$(SHLIB_ENV) $(VALGRIND) ./off_cvt <off_cvt.in >off_cvt.tmp 2>&1
diff quote_822_local.ref quote_822_local.tmp
rm -f quote_822_local.tmp
-normalize_mailhost_addr_test: update normalize_mailhost_addr
- -$(SHLIB_ENV) $(VALGRIND) ./normalize_mailhost_addr >normalize_mailhost_addr.tmp 2>&1
- diff /dev/null normalize_mailhost_addr.tmp
- rm -f normalize_mailhost_addr.tmp
+normalize_mailhost_addr_test: normalize_mailhost_addr_test.o \
+ $(TEST_LIB) $(LIB) $(LIBS)
+ $(CC) $(CFLAGS) -o $@ $@.o $(TEST_LIB) $(LIB) $(LIBS) $(SYSLIBS)
+
+test_normalize_mailhost_addr: update normalize_mailhost_addr_test
+ $(SHLIB_ENV) $(VALGRIND) ./normalize_mailhost_addr_test
haproxy_srvr_test: update haproxy_srvr
-$(SHLIB_ENV) $(VALGRIND) ./haproxy_srvr >haproxy_srvr.tmp 2>&1
diff /dev/null haproxy_srvr.tmp
rm -f haproxy_srvr.tmp
-map_search_test: update map_search map_search.ref
- -$(SHLIB_ENV) $(VALGRIND) ./map_search >map_search.tmp 2>&1
- diff map_search.ref map_search.tmp
- rm -f map_search.tmp
+map_search_test: map_search_test.o $(TEST_LIB) $(LIB) $(LIBS)
+ $(CC) $(CFLAGS) -o $@ $@.o $(TEST_LIB) $(LIB) $(LIBS) $(SYSLIBS)
-delivered_hdr_test: update delivered_hdr delivered_hdr.ref
- -$(SHLIB_ENV) $(VALGRIND) ./delivered_hdr >delivered_hdr.tmp 2>&1
- diff delivered_hdr.ref delivered_hdr.tmp
- rm -f delivered_hdr.tmp
+test_map_search: update map_search_test
+ $(SHLIB_ENV) $(VALGRIND) ./map_search_test
-login_sender_match_test: update login_sender_match login_sender_match.ref
- -$(SHLIB_ENV) $(VALGRIND) ./login_sender_match >login_sender_match.tmp 2>&1
- diff login_sender_match.ref login_sender_match.tmp
- rm -f login_sender_match.tmp
+delivered_hdr_test: delivered_hdr_test.o $(TEST_LIB) $(LIB) $(LIBS)
+ $(CC) $(CFLAGS) -o $@ $@.o $(TEST_LIB) $(LIB) $(LIBS) $(SYSLIBS)
+
+test_delivered_hdr: update delivered_hdr_test
+ $(SHLIB_ENV) $(VALGRIND) ./delivered_hdr_test
+
+login_sender_match_test: login_sender_match_test.o \
+ $(TEST_LIB) $(LIB) $(LIBS)
+ $(CC) $(CFLAGS) -o $@ $@.o $(TEST_LIB) $(LIB) $(LIBS) $(SYSLIBS)
+
+test_login_sender_match: update login_sender_match_test
+ $(SHLIB_ENV) $(VALGRIND) ./login_sender_match_test
compat_level_test: compat_level_expand_test compat_level_convert_test
diff compat_level_convert.ref compat_level_convert.tmp
rm -f compat_level_convert.tmp
-config_known_tcp_ports_test: update config_known_tcp_ports \
- config_known_tcp_ports.ref
- -$(SHLIB_ENV) $(VALGRIND) ./config_known_tcp_ports \
- >config_known_tcp_ports.tmp 2>&1
- diff config_known_tcp_ports.ref config_known_tcp_ports.tmp
- rm -f config_known_tcp_ports.tmp
+config_known_tcp_ports_test: config_known_tcp_ports_test.o $(TEST_LIB) $(LIB) $(LIBS)
+ $(CC) $(CFLAGS) -o $@ $@.o $(TEST_LIB) $(LIB) $(LIBS) $(SYSLIBS)
+
+test_config_known_tcp_ports: update config_known_tcp_ports_test
+ $(SHLIB_ENV) $(VALGRIND) ./config_known_tcp_ports_test
+
+hfrom_format_test: hfrom_format_test.o $(TEST_LIB) $(LIB) $(LIBS)
+ $(CC) $(CFLAGS) -o $@ $@.o $(TEST_LIB) $(LIB) $(LIBS) $(SYSLIBS)
-hfrom_format_test: update hfrom_format \
- hfrom_format.ref
- -$(SHLIB_ENV) $(VALGRIND) ./hfrom_format \
- >hfrom_format.tmp 2>&1
- diff hfrom_format.ref hfrom_format.tmp
- rm -f hfrom_format.tmp
+test_hfrom_format: update hfrom_format_test
+ $(SHLIB_ENV) $(VALGRIND) ./hfrom_format_test
printfck: $(OBJS) $(PROG)
rm -rf printfck
config_known_tcp_ports.o: ../../include/vstring.h
config_known_tcp_ports.o: config_known_tcp_ports.c
config_known_tcp_ports.o: config_known_tcp_ports.h
+config_known_tcp_ports_test.o: ../../include/argv.h
+config_known_tcp_ports_test.o: ../../include/check_arg.h
+config_known_tcp_ports_test.o: ../../include/known_tcp_ports.h
+config_known_tcp_ports_test.o: ../../include/msg.h
+config_known_tcp_ports_test.o: ../../include/msg_output.h
+config_known_tcp_ports_test.o: ../../include/msg_vstream.h
+config_known_tcp_ports_test.o: ../../include/pmock_expect.h
+config_known_tcp_ports_test.o: ../../include/ptest.h
+config_known_tcp_ports_test.o: ../../include/ptest_main.h
+config_known_tcp_ports_test.o: ../../include/stringops.h
+config_known_tcp_ports_test.o: ../../include/sys_defs.h
+config_known_tcp_ports_test.o: ../../include/vbuf.h
+config_known_tcp_ports_test.o: ../../include/vstream.h
+config_known_tcp_ports_test.o: ../../include/vstring.h
+config_known_tcp_ports_test.o: config_known_tcp_ports.h
+config_known_tcp_ports_test.o: config_known_tcp_ports_test.c
conv_time.o: ../../include/msg.h
conv_time.o: ../../include/sys_defs.h
conv_time.o: conv_time.c
delivered_hdr.o: quote_flags.h
delivered_hdr.o: rec_type.h
delivered_hdr.o: record.h
+delivered_hdr_test.o: ../../include/argv.h
+delivered_hdr_test.o: ../../include/check_arg.h
+delivered_hdr_test.o: ../../include/msg.h
+delivered_hdr_test.o: ../../include/msg_output.h
+delivered_hdr_test.o: ../../include/msg_vstream.h
+delivered_hdr_test.o: ../../include/mymalloc.h
+delivered_hdr_test.o: ../../include/pmock_expect.h
+delivered_hdr_test.o: ../../include/ptest.h
+delivered_hdr_test.o: ../../include/ptest_main.h
+delivered_hdr_test.o: ../../include/stringops.h
+delivered_hdr_test.o: ../../include/sys_defs.h
+delivered_hdr_test.o: ../../include/vbuf.h
+delivered_hdr_test.o: ../../include/vstream.h
+delivered_hdr_test.o: ../../include/vstring.h
+delivered_hdr_test.o: delivered_hdr.h
+delivered_hdr_test.o: delivered_hdr_test.c
+delivered_hdr_test.o: fold_addr.h
+delivered_hdr_test.o: mail_params.h
+delivered_hdr_test.o: rec_type.h
+delivered_hdr_test.o: record.h
dict_ldap.o: ../../include/argv.h
dict_ldap.o: ../../include/binhash.h
dict_ldap.o: ../../include/check_arg.h
haproxy_srvr.o: ../../include/valid_hostname.h
haproxy_srvr.o: ../../include/vbuf.h
haproxy_srvr.o: ../../include/vstring.h
+haproxy_srvr.o: ../../include/wrap_netdb.h
haproxy_srvr.o: haproxy_srvr.c
haproxy_srvr.o: haproxy_srvr.h
header_body_checks.o: ../../include/argv.h
hfrom_format.o: hfrom_format.c
hfrom_format.o: hfrom_format.h
hfrom_format.o: mail_params.h
+hfrom_format_test.o: ../../include/argv.h
+hfrom_format_test.o: ../../include/check_arg.h
+hfrom_format_test.o: ../../include/msg.h
+hfrom_format_test.o: ../../include/msg_output.h
+hfrom_format_test.o: ../../include/msg_vstream.h
+hfrom_format_test.o: ../../include/pmock_expect.h
+hfrom_format_test.o: ../../include/ptest.h
+hfrom_format_test.o: ../../include/ptest_main.h
+hfrom_format_test.o: ../../include/stringops.h
+hfrom_format_test.o: ../../include/sys_defs.h
+hfrom_format_test.o: ../../include/vbuf.h
+hfrom_format_test.o: ../../include/vstream.h
+hfrom_format_test.o: ../../include/vstring.h
+hfrom_format_test.o: hfrom_format.h
+hfrom_format_test.o: hfrom_format_test.c
+hfrom_format_test.o: mail_params.h
info_log_addr_form.o: ../../include/check_arg.h
info_log_addr_form.o: ../../include/msg.h
info_log_addr_form.o: ../../include/name_code.h
login_sender_match.o: quote_822_local.h
login_sender_match.o: quote_flags.h
login_sender_match.o: strip_addr.h
+login_sender_match_test.o: ../../include/argv.h
+login_sender_match_test.o: ../../include/check_arg.h
+login_sender_match_test.o: ../../include/dict.h
+login_sender_match_test.o: ../../include/msg.h
+login_sender_match_test.o: ../../include/msg_output.h
+login_sender_match_test.o: ../../include/msg_vstream.h
+login_sender_match_test.o: ../../include/myflock.h
+login_sender_match_test.o: ../../include/pmock_expect.h
+login_sender_match_test.o: ../../include/ptest.h
+login_sender_match_test.o: ../../include/ptest_main.h
+login_sender_match_test.o: ../../include/stringops.h
+login_sender_match_test.o: ../../include/sys_defs.h
+login_sender_match_test.o: ../../include/vbuf.h
+login_sender_match_test.o: ../../include/vstream.h
+login_sender_match_test.o: ../../include/vstring.h
+login_sender_match_test.o: login_sender_match.h
+login_sender_match_test.o: login_sender_match_test.c
+login_sender_match_test.o: mail_params.h
mail_addr.o: ../../include/check_arg.h
mail_addr.o: ../../include/stringops.h
mail_addr.o: ../../include/sys_defs.h
mail_params.o: ../../include/vstream.h
mail_params.o: ../../include/vstring.h
mail_params.o: ../../include/vstring_vstream.h
+mail_params.o: ../../include/wrap_netdb.h
mail_params.o: compat_level.h
mail_params.o: config_known_tcp_ports.h
mail_params.o: mail_conf.h
map_search.o: ../../include/vstring.h
map_search.o: map_search.c
map_search.o: map_search.h
+map_search_test.o: ../../include/argv.h
+map_search_test.o: ../../include/check_arg.h
+map_search_test.o: ../../include/msg.h
+map_search_test.o: ../../include/msg_output.h
+map_search_test.o: ../../include/msg_vstream.h
+map_search_test.o: ../../include/name_code.h
+map_search_test.o: ../../include/pmock_expect.h
+map_search_test.o: ../../include/ptest.h
+map_search_test.o: ../../include/ptest_main.h
+map_search_test.o: ../../include/stringops.h
+map_search_test.o: ../../include/sys_defs.h
+map_search_test.o: ../../include/vbuf.h
+map_search_test.o: ../../include/vstream.h
+map_search_test.o: ../../include/vstring.h
+map_search_test.o: map_search.h
+map_search_test.o: map_search_test.c
maps.o: ../../include/argv.h
maps.o: ../../include/check_arg.h
maps.o: ../../include/dict.h
mynetworks.o: ../../include/sys_defs.h
mynetworks.o: ../../include/vbuf.h
mynetworks.o: ../../include/vstring.h
+mynetworks.o: ../../include/wrap_netdb.h
mynetworks.o: been_here.h
mynetworks.o: mail_params.h
mynetworks.o: mynetworks.c
normalize_mailhost_addr.o: ../../include/valid_hostname.h
normalize_mailhost_addr.o: ../../include/vbuf.h
normalize_mailhost_addr.o: ../../include/vstring.h
+normalize_mailhost_addr.o: ../../include/wrap_netdb.h
normalize_mailhost_addr.o: normalize_mailhost_addr.c
normalize_mailhost_addr.o: normalize_mailhost_addr.h
normalize_mailhost_addr.o: valid_mailhost_addr.h
+normalize_mailhost_addr_test.o: ../../include/argv.h
+normalize_mailhost_addr_test.o: ../../include/check_arg.h
+normalize_mailhost_addr_test.o: ../../include/inet_proto.h
+normalize_mailhost_addr_test.o: ../../include/msg.h
+normalize_mailhost_addr_test.o: ../../include/msg_output.h
+normalize_mailhost_addr_test.o: ../../include/msg_vstream.h
+normalize_mailhost_addr_test.o: ../../include/mymalloc.h
+normalize_mailhost_addr_test.o: ../../include/pmock_expect.h
+normalize_mailhost_addr_test.o: ../../include/ptest.h
+normalize_mailhost_addr_test.o: ../../include/ptest_main.h
+normalize_mailhost_addr_test.o: ../../include/stringops.h
+normalize_mailhost_addr_test.o: ../../include/sys_defs.h
+normalize_mailhost_addr_test.o: ../../include/vbuf.h
+normalize_mailhost_addr_test.o: ../../include/vstream.h
+normalize_mailhost_addr_test.o: ../../include/vstring.h
+normalize_mailhost_addr_test.o: normalize_mailhost_addr.h
+normalize_mailhost_addr_test.o: normalize_mailhost_addr_test.c
off_cvt.o: ../../include/check_arg.h
off_cvt.o: ../../include/msg.h
off_cvt.o: ../../include/sys_defs.h
own_inet_addr.o: ../../include/sys_defs.h
own_inet_addr.o: ../../include/vbuf.h
own_inet_addr.o: ../../include/vstring.h
+own_inet_addr.o: ../../include/wrap_netdb.h
own_inet_addr.o: mail_params.h
own_inet_addr.o: own_inet_addr.c
own_inet_addr.o: own_inet_addr.h
resolve_local.o: ../../include/vbuf.h
resolve_local.o: ../../include/vstream.h
resolve_local.o: ../../include/vstring.h
+resolve_local.o: ../../include/wrap_netdb.h
resolve_local.o: mail_params.h
resolve_local.o: own_inet_addr.h
resolve_local.o: resolve_local.c
smtp_reply_footer.o: dsn_util.h
smtp_reply_footer.o: smtp_reply_footer.c
smtp_reply_footer.o: smtp_reply_footer.h
+smtp_reply_footer_test.o: ../../include/argv.h
+smtp_reply_footer_test.o: ../../include/check_arg.h
+smtp_reply_footer_test.o: ../../include/mac_expand.h
+smtp_reply_footer_test.o: ../../include/mac_parse.h
+smtp_reply_footer_test.o: ../../include/msg.h
+smtp_reply_footer_test.o: ../../include/msg_output.h
+smtp_reply_footer_test.o: ../../include/msg_vstream.h
+smtp_reply_footer_test.o: ../../include/pmock_expect.h
+smtp_reply_footer_test.o: ../../include/ptest.h
+smtp_reply_footer_test.o: ../../include/ptest_main.h
+smtp_reply_footer_test.o: ../../include/stringops.h
+smtp_reply_footer_test.o: ../../include/sys_defs.h
+smtp_reply_footer_test.o: ../../include/vbuf.h
+smtp_reply_footer_test.o: ../../include/vstream.h
+smtp_reply_footer_test.o: ../../include/vstring.h
+smtp_reply_footer_test.o: dsn_util.h
+smtp_reply_footer_test.o: smtp_reply_footer.h
+smtp_reply_footer_test.o: smtp_reply_footer_test.c
smtp_stream.o: ../../include/check_arg.h
smtp_stream.o: ../../include/iostuff.h
smtp_stream.o: ../../include/msg.h
sys_exits.o: ../../include/vstring.h
sys_exits.o: sys_exits.c
sys_exits.o: sys_exits.h
-test_main.o: ../../include/argv.h
-test_main.o: ../../include/check_arg.h
-test_main.o: ../../include/dict.h
-test_main.o: ../../include/msg.h
-test_main.o: ../../include/msg_vstream.h
-test_main.o: ../../include/myflock.h
-test_main.o: ../../include/mymalloc.h
-test_main.o: ../../include/stringops.h
-test_main.o: ../../include/sys_defs.h
-test_main.o: ../../include/vbuf.h
-test_main.o: ../../include/vstream.h
-test_main.o: ../../include/vstring.h
-test_main.o: mail_conf.h
-test_main.o: mail_dict.h
-test_main.o: mail_params.h
-test_main.o: mail_task.h
-test_main.o: mail_version.h
-test_main.o: test_main.c
-test_main.o: test_main.h
+test_server_main.o: ../../include/argv.h
+test_server_main.o: ../../include/check_arg.h
+test_server_main.o: ../../include/dict.h
+test_server_main.o: ../../include/msg.h
+test_server_main.o: ../../include/msg_vstream.h
+test_server_main.o: ../../include/myflock.h
+test_server_main.o: ../../include/mymalloc.h
+test_server_main.o: ../../include/stringops.h
+test_server_main.o: ../../include/sys_defs.h
+test_server_main.o: ../../include/vbuf.h
+test_server_main.o: ../../include/vstream.h
+test_server_main.o: ../../include/vstring.h
+test_server_main.o: mail_conf.h
+test_server_main.o: mail_dict.h
+test_server_main.o: mail_params.h
+test_server_main.o: mail_task.h
+test_server_main.o: mail_version.h
+test_server_main.o: test_server_main.c
+test_server_main.o: test_server_main.h
timed_ipc.o: ../../include/check_arg.h
timed_ipc.o: ../../include/msg.h
timed_ipc.o: ../../include/sys_defs.h
valid_mailhost_addr.o: ../../include/myaddrinfo.h
valid_mailhost_addr.o: ../../include/sys_defs.h
valid_mailhost_addr.o: ../../include/valid_hostname.h
+valid_mailhost_addr.o: ../../include/wrap_netdb.h
valid_mailhost_addr.o: valid_mailhost_addr.c
valid_mailhost_addr.o: valid_mailhost_addr.h
verify.o: ../../include/attr.h
wildcard_inet_addr.o: ../../include/msg.h
wildcard_inet_addr.o: ../../include/myaddrinfo.h
wildcard_inet_addr.o: ../../include/sys_defs.h
+wildcard_inet_addr.o: ../../include/wrap_netdb.h
wildcard_inet_addr.o: wildcard_inet_addr.c
wildcard_inet_addr.o: wildcard_inet_addr.h
xtext.o: ../../include/check_arg.h
}
argv_free(associations);
}
-
-#ifdef TEST
-
-#include <stdlib.h>
-#include <string.h>
-#include <msg_vstream.h>
-
-#define STR(x) vstring_str(x)
-
- /* TODO(wietse) make this a proper VSTREAM interface */
-
-/* vstream_swap - kludge to capture output for testing */
-
-static void vstream_swap(VSTREAM *one, VSTREAM *two)
-{
- VSTREAM save;
-
- save = *one;
- *one = *two;
- *two = save;
-}
-
-struct test_case {
- const char *label; /* identifies test case */
- const char *config; /* configuration under test */
- const char *exp_warning; /* expected warning or null */
- const char *exp_export; /* expected export or null */
-};
-
-static struct test_case test_cases[] = {
- {"good",
- /* config */ "smtp = 25, smtps = submissions = 465, lmtp = 24",
- /* warning */ "",
- /* export */ "lmtp=24 smtp=25 smtps=465 submissions=465"
- },
- {"equal-equal",
- /* config */ "smtp = 25, smtps == submissions = 465, lmtp = 24",
- /* warning */ "config_known_tcp_ports: warning: equal-equal: "
- "in \" smtps == submissions = 465\": missing service name before "
- "\"=\"\n",
- /* export */ "lmtp=24 smtp=25 smtps=465 submissions=465"
- },
- {"port test 1",
- /* config */ "smtps = submission =",
- /* warning */ "config_known_tcp_ports: warning: port test 1: "
- "in \"smtps = submission =\": missing port value after \"=\"\n",
- /* export */ ""
- },
- {"port test 2",
- /* config */ "smtps = submission = 4 65",
- /* warning */ "config_known_tcp_ports: warning: port test 2: "
- "in \"smtps = submission = 4 65\": whitespace in port number\n",
- /* export */ ""
- },
- {"port test 3",
- /* config */ "lmtp = 24, smtps = submission = foo",
- /* warning */ "config_known_tcp_ports: warning: port test 3: "
- "in \" smtps = submission = foo\": non-numerical service port\n",
- /* export */ "lmtp=24"
- },
- {"service name test 1",
- /* config */ "smtps = sub mission = 465",
- /* warning */ "config_known_tcp_ports: warning: service name test 1: "
- "in \"smtps = sub mission = 465\": whitespace in service name\n",
- /* export */ "smtps=465"
- },
- {"service name test 2",
- /* config */ "lmtp = 24, smtps = 1234 = submissions = 465",
- /* warning */ "config_known_tcp_ports: warning: service name test 2: "
- "in \" smtps = 1234 = submissions = 465\": numerical service name\n",
- /* export */ "lmtp=24 smtps=465 submissions=465"
- },
- 0,
-};
-
-int main(int argc, char **argv)
-{
- VSTRING *export_buf;
- struct test_case *tp;
- int pass = 0;
- int fail = 0;
- int test_failed;
- const char *export;
- VSTRING *msg_buf;
- VSTREAM *memory_stream;
-
-#define STRING_OR_NULL(s) ((s) ? (s) : "(null)")
-
- msg_vstream_init("config_known_tcp_ports", VSTREAM_ERR);
-
- export_buf = vstring_alloc(100);
- msg_buf = vstring_alloc(100);
- for (tp = test_cases; tp->label != 0; tp++) {
- test_failed = 0;
- if ((memory_stream = vstream_memopen(msg_buf, O_WRONLY)) == 0)
- msg_fatal("open memory stream: %m");
- vstream_swap(VSTREAM_ERR, memory_stream);
- config_known_tcp_ports(tp->label, tp->config);
- vstream_swap(memory_stream, VSTREAM_ERR);
- if (vstream_fclose(memory_stream))
- msg_fatal("close memory stream: %m");
- if (strcmp(STR(msg_buf), tp->exp_warning) != 0) {
- msg_warn("test case %s: got error: \"%s\", want: \"%s\"",
- tp->label, STR(msg_buf),
- STRING_OR_NULL(tp->exp_warning));
- test_failed = 1;
- } else {
- export = export_known_tcp_ports(export_buf);
- if (strcmp(export, tp->exp_export) != 0) {
- msg_warn("test case %s: got export: \"%s\", want: \"%s\"",
- tp->label, export, tp->exp_export);
- test_failed = 1;
- }
- clear_known_tcp_ports();
- VSTRING_RESET(msg_buf);
- VSTRING_TERMINATE(msg_buf);
- }
- if (test_failed) {
- msg_info("%s: FAIL", tp->label);
- fail++;
- } else {
- msg_info("%s: PASS", tp->label);
- pass++;
- }
- }
- msg_info("PASS=%d FAIL=%d", pass, fail);
- vstring_free(msg_buf);
- vstring_free(export_buf);
- exit(fail != 0);
-}
-
-#endif
--- /dev/null
+ /*
+ * Test program to exercise config_known_tcp_ports.c. See ptest_main.h for a
+ * documented example.
+ */
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <string.h>
+
+ /*
+ * Utility library.
+ */
+#include <known_tcp_ports.h>
+#include <vstring.h>
+
+ /*
+ * Global library.
+ */
+#include <config_known_tcp_ports.h>
+
+ /*
+ * Test library.
+ */
+#include <ptest.h>
+
+typedef struct PTEST_CASE {
+ const char *testname; /* identifies test case */
+ void (*action) (PTEST_CTX *, const struct PTEST_CASE *);
+ const char *config; /* configuration under test */
+ const char *want_warning; /* expected warning or null */
+ const char *want_export; /* expected export or null */
+} PTEST_CASE;
+
+static void test_config_known_tcp_ports(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ VSTRING *export_buf;
+ const char *got_export;
+
+ export_buf = vstring_alloc(100);
+ if (*tp->want_warning)
+ expect_ptest_error(t, tp->want_warning);
+ config_known_tcp_ports(tp->testname, tp->config);
+ got_export = export_known_tcp_ports(export_buf);
+ if (strcmp(got_export, tp->want_export) != 0)
+ ptest_error(t, "got export \"%s\", want \"%s\"",
+ got_export, tp->want_export);
+ clear_known_tcp_ports();
+ vstring_free(export_buf);
+}
+
+static const PTEST_CASE ptestcases[] = {
+ {"good", test_config_known_tcp_ports,
+ /* config */ "smtp = 25, smtps = submissions = 465, lmtp = 24",
+ /* warning */ "",
+ /* export */ "lmtp=24 smtp=25 smtps=465 submissions=465"
+ },
+ {"equal-equal", test_config_known_tcp_ports,
+ /* config */ "smtp = 25, smtps == submissions = 465, lmtp = 24",
+ /* warning */ "equal-equal: in \" smtps == submissions = 465\": "
+ "missing service name before \"=\"",
+ /* export */ "lmtp=24 smtp=25 smtps=465 submissions=465"
+ },
+ {"port test 1", test_config_known_tcp_ports,
+ /* config */ "smtps = submission =",
+ /* warning */ "port test 1: in \"smtps = submission =\": "
+ "missing port value after \"=\"",
+ /* export */ ""
+ },
+ {"port test 2", test_config_known_tcp_ports,
+ /* config */ "smtps = submission = 4 65",
+ /* warning */ "port test 2: in \"smtps = submission = 4 65\": "
+ "whitespace in port number",
+ /* export */ ""
+ },
+ {"port test 3", test_config_known_tcp_ports,
+ /* config */ "lmtp = 24, smtps = submission = foo",
+ /* warning */ "port test 3: in \" smtps = submission = foo\": "
+ "non-numerical service port",
+ /* export */ "lmtp=24"
+ },
+ {"service name test 1", test_config_known_tcp_ports,
+ /* config */ "smtps = sub mission = 465",
+ /* warning */ "service name test 1: in \"smtps = sub mission = 465\": "
+ "whitespace in service name",
+ /* export */ "smtps=465"
+ },
+ {"service name test 2", test_config_known_tcp_ports,
+ /* config */ "lmtp = 24, smtps = 1234 = submissions = 465",
+ /* warning */ "service name test 2: in \" smtps = 1234 = submissions "
+ "= 465\": numerical service name",
+ /* export */ "lmtp=24 smtps=465 submissions=465"
+ },
+};
+
+#include <ptest_main.h>
htable_free(info->table, (void (*) (void *)) 0);
myfree((void *) info);
}
-
-#ifdef TEST
-
-#include <msg_vstream.h>
-#include <mail_params.h>
-
-char *var_drop_hdrs;
-
-int main(int arc, char **argv)
-{
-
- /*
- * We write test records to a VSTRING, then read with delivered_hdr_init.
- */
- VSTRING *mem_bp;
- VSTREAM *mem_fp;
- DELIVERED_HDR_INFO *dp;
- struct test_case {
- int rec_type;
- const char *content;
- int expect_find;
- };
- const struct test_case test_cases[] = {
- REC_TYPE_CONT, "Delivered-To: one", 1,
- REC_TYPE_NORM, "Delivered-To: two", 0,
- REC_TYPE_NORM, "Delivered-To: three", 1,
- 0,
- };
- const struct test_case *tp;
- int actual_find;
- int errors;
-
- msg_vstream_init(argv[0], VSTREAM_ERR);
-
- var_drop_hdrs = mystrdup(DEF_DROP_HDRS);
-
- mem_bp = vstring_alloc(VSTREAM_BUFSIZE);
- if ((mem_fp = vstream_memopen(mem_bp, O_WRONLY)) == 0)
- msg_panic("vstream_memopen O_WRONLY failed: %m");
-
-#define REC_PUT_LIT(fp, type, lit) rec_put((fp), (type), (lit), strlen(lit))
-
- for (tp = test_cases; tp->content != 0; tp++)
- REC_PUT_LIT(mem_fp, tp->rec_type, tp->content);
-
- if (vstream_fclose(mem_fp))
- msg_panic("vstream_fclose fail: %m");
-
- if ((mem_fp = vstream_memopen(mem_bp, O_RDONLY)) == 0)
- msg_panic("vstream_memopen O_RDONLY failed: %m");
-
- dp = delivered_hdr_init(mem_fp, 0, FOLD_ADDR_ALL);
-
- for (errors = 0, tp = test_cases; tp->content != 0; tp++) {
- actual_find =
- delivered_hdr_find(dp, tp->content + sizeof("Delivered-To:"));
- msg_info("test case: %c >%s<: %s (expected: %s)",
- tp->rec_type, tp->content,
- actual_find == tp->expect_find ? "PASS" : "FAIL",
- tp->expect_find ? "MATCH" : "NO MATCH");
- errors += (actual_find != tp->expect_find);;
- }
- exit(errors);
-}
-
-#endif
--- /dev/null
+ /*
+ * Test program to exercise delivered_hdr.c. See ptest_main.h for a
+ * documented example.
+ */
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <string.h>
+
+ /*
+ * Utility library.
+ */
+#include <msg_vstream.h>
+#include <mymalloc.h>
+
+ /*
+ * Global library.
+ */
+#include <mail_params.h>
+#include <delivered_hdr.h>
+#include <rec_type.h>
+#include <record.h>
+
+ /*
+ * Test library.
+ */
+#include <ptest.h>
+
+ /*
+ * Satisfy a configuration dependency.
+ */
+char *var_drop_hdrs;
+
+ /*
+ * Test library adaptor.
+ */
+typedef struct PTEST_CASE {
+ const char *testname;
+ void (*action) (PTEST_CTX *, const struct PTEST_CASE *);
+} PTEST_CASE;
+
+#define FOUND 1
+#define NOT_FOUND 0
+
+static void test_delivered_hdr_find(PTEST_CTX *t, const PTEST_CASE *unused)
+{
+ VSTRING *mem_bp;
+ VSTREAM *mem_fp;
+ DELIVERED_HDR_INFO *dp;
+ struct test_case {
+ int rec_type;
+ const char *rec_content;
+ int want_found;
+ };
+
+ /*
+ * This structure specifies the order of records that will be written to
+ * a test queue file, and what we expect that delivered_hdr() will find.
+ * It should not find the record that immediately follows REC_TYPE_CONT.
+ */
+ static const struct test_case test_cases[] = {
+ REC_TYPE_CONT, "Delivered-To: one", FOUND,
+ REC_TYPE_NORM, "Delivered-To: two", NOT_FOUND,
+ REC_TYPE_NORM, "Delivered-To: three", FOUND,
+ 0,
+ };
+ const struct test_case *tp;
+ int got_found;
+
+ var_drop_hdrs = mystrdup(DEF_DROP_HDRS);
+
+ /*
+ * Write queue file records to memory stream.
+ */
+#define REC_PUT_LIT(fp, type, lit) rec_put((fp), (type), (lit), strlen(lit))
+
+ mem_bp = vstring_alloc(VSTREAM_BUFSIZE);
+ if ((mem_fp = vstream_memopen(mem_bp, O_WRONLY)) == 0)
+ ptest_fatal(t, "vstream_memopen O_WRONLY failed: %m");
+ for (tp = test_cases; tp->rec_content != 0; tp++)
+ REC_PUT_LIT(mem_fp, tp->rec_type, tp->rec_content);
+ if (vstream_fclose(mem_fp))
+ ptest_fatal(t, "vstream_fclose fail: %m");
+
+ /*
+ * Reopen the memory stream and populate the Delivered-To: cache.
+ */
+ if ((mem_fp = vstream_memopen(mem_bp, O_RDONLY)) == 0)
+ ptest_fatal(t, "vstream_memopen O_RDONLY failed: %m");
+ dp = delivered_hdr_init(mem_fp, 0, FOLD_ADDR_ALL);
+
+ /*
+ * Verify that what should be found will be found. XXX delivered_hdr()
+ * assumes that Delivered-To: records fit in one queue file record.
+ */
+#define FOUND_OR_NOT(x) ((x) ? "found" : "not found")
+
+ for (tp = test_cases; tp->rec_content != 0; tp++) {
+ got_found =
+ delivered_hdr_find(dp, tp->rec_content + sizeof("Delivered-To:"));
+ if (!got_found != !tp->want_found)
+ ptest_error(t, "delivered_hdr_find '%s': got '%s', want '%s'",
+ tp->rec_content, FOUND_OR_NOT(got_found),
+ FOUND_OR_NOT(tp->want_found));
+ }
+}
+
+ /*
+ * Test library adaptor.
+ */
+static PTEST_CASE ptestcases[] = {
+ "test_delivered_hdr_find", test_delivered_hdr_find,
+};
+
+#include <ptest_main.h>
}
host->name = mystrdup(d);
if ((s = split_at_right(host->name, ':')) != 0)
- host->port = ntohs(find_inet_port(s, "tcp"));
+ if ((host->port = find_inet_service(s, "tcp")) < 0)
+ /* TODO: return null and create a surrogate dictionary. */
+ msg_fatal("unknown service: %s/tcp", s);
if (strcasecmp(host->name, "localhost") == 0) {
/* The MySQL way: this will actually connect over the UNIX socket */
myfree(host->name);
/* DESCRIPTION
/* .nf
+ /*
+ * Utility library.
+ */
+#include <vstring.h>
+
/*
* External interface.
*/
*two = save;
}
-jmp_buf test_fatal_jbuf;
+jmp_buf ptest_fatal_jbuf;
#undef msg_fatal
va_start(ap, fmt);
vmsg_warn(fmt, ap);
va_end(ap);
- longjmp(test_fatal_jbuf, 1);
+ longjmp(ptest_fatal_jbuf, 1);
}
struct name_test_case {
if ((memory_stream = vstream_memopen(msg_buf, O_WRONLY)) == 0)
msg_fatal("open memory stream: %m");
vstream_swap(VSTREAM_ERR, memory_stream);
- if (setjmp(test_fatal_jbuf) == 0)
+ if (setjmp(ptest_fatal_jbuf) == 0)
code = hfrom_format_parse(np->label, np->config);
vstream_swap(memory_stream, VSTREAM_ERR);
if (vstream_fclose(memory_stream))
if ((memory_stream = vstream_memopen(msg_buf, O_WRONLY)) == 0)
msg_fatal("open memory stream: %m");
vstream_swap(VSTREAM_ERR, memory_stream);
- if (setjmp(test_fatal_jbuf) == 0)
+ if (setjmp(ptest_fatal_jbuf) == 0)
name = str_hfrom_format_code(cp->code);
vstream_swap(memory_stream, VSTREAM_ERR);
if (vstream_fclose(memory_stream))
+++ /dev/null
-hfrom_format: hfrom_format_parse good-standard: PASS
-hfrom_format: hfrom_format_parse good-obsolete: PASS
-hfrom_format: hfrom_format_parse bad: PASS
-hfrom_format: hfrom_format_parse empty: PASS
-hfrom_format: str_hfrom_format_code good-standard: PASS
-hfrom_format: str_hfrom_format_code good-obsolete: PASS
-hfrom_format: str_hfrom_format_code bad: PASS
-hfrom_format: PASS=7 FAIL=0
--- /dev/null
+ /*
+ * Test program to exercise hfrom_format.c. See ptest_main.h for a
+ * documented example.
+ */
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <string.h>
+
+ /*
+ * Global library.
+ */
+#include <hfrom_format.h>
+#include <mail_params.h>
+
+ /*
+ * Test library.
+ */
+#include <ptest.h>
+
+ /*
+ * Test adapter.
+ */
+typedef struct PTEST_CASE {
+ const char *testname;
+ void (*action) (PTEST_CTX *, const struct PTEST_CASE *);
+} PTEST_CASE;
+
+struct name_test_case {
+ const char *label; /* identifies test case */
+ const char *config; /* configuration under test */
+ const char *want_warning; /* expected warning or empty */
+ const int want_code; /* expected code */
+};
+
+static struct name_test_case name_test_cases[] = {
+ {"hfrom_format_parse good-standard",
+ /* config */ HFROM_FORMAT_NAME_STD,
+ /* warning */ "",
+ /* want_code */ HFROM_FORMAT_CODE_STD
+ },
+ {"hfrom_format_parse good-obsolete",
+ /* config */ HFROM_FORMAT_NAME_OBS,
+ /* warning */ "",
+ /* want_code */ HFROM_FORMAT_CODE_OBS
+ },
+ {"hfrom_format_parse bad",
+ /* config */ "does-not-exist,",
+ /* warning */ "invalid setting: \"hfrom_format_parse bad = does-not-exist,\"",
+ /* code */ 0,
+ },
+ {"hfrom_format_parse empty",
+ /* config */ "",
+ /* warning */ "invalid setting: \"hfrom_format_parse empty = \"",
+ /* code */ 0,
+ },
+ 0,
+};
+
+static void test_hfrom_format_parse(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ struct name_test_case *np;
+
+ for (np = name_test_cases; np->label != 0; np++) {
+ PTEST_RUN(t, np->label, {
+ int got_code;
+
+ if (*np->want_warning)
+ expect_ptest_error(t, np->want_warning);
+ got_code = hfrom_format_parse(np->label, np->config);
+ if (*np->want_warning == 0) {
+ if (got_code != np->want_code) {
+ ptest_error(t, "got code \"%d\", want \"%d\"(%s)",
+ got_code, np->want_code,
+ str_hfrom_format_code(np->want_code));
+ }
+ }
+ });
+ }
+}
+
+struct code_test_case {
+ const char *label; /* identifies test case */
+ int code; /* code under test */
+ const char *want_warning; /* expected warning or empty */
+ const char *want_name; /* expected namme */
+};
+
+static struct code_test_case code_test_cases[] = {
+ {"str_hfrom_format_code good-standard",
+ /* code */ HFROM_FORMAT_CODE_STD,
+ /* warning */ "",
+ /* want_name */ HFROM_FORMAT_NAME_STD
+ },
+ {"str_hfrom_format_code good-obsolete",
+ /* code */ HFROM_FORMAT_CODE_OBS,
+ /* warning */ "",
+ /* want_name */ HFROM_FORMAT_NAME_OBS
+ },
+ {"str_hfrom_format_code bad",
+ /* config */ 12345,
+ /* warning */ "invalid header format code: 12345",
+ /* want_name */ 0
+ },
+ 0,
+};
+
+static void test_str_hfrom_format_code(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ struct code_test_case *cp;
+
+ for (cp = code_test_cases; cp->label != 0; cp++) {
+ PTEST_RUN(t, cp->label, {
+ const char *got_name;
+
+ if (*cp->want_warning)
+ expect_ptest_error(t, cp->want_warning);
+ got_name = str_hfrom_format_code(cp->code);
+ if (*cp->want_warning == 0) {
+ if (strcmp(got_name, cp->want_name) != 0) {
+ ptest_error(t, "got name: \"%s\", want: \"%s\"",
+ got_name, cp->want_name);
+ }
+ }
+ });
+ }
+}
+
+ /*
+ * Test adapter.
+ */
+static const PTEST_CASE ptestcases[] = {
+ {"test hfrom_format_parse", test_hfrom_format_parse,},
+ {"test str_hfrom_format_code", test_str_hfrom_format_code,},
+};
+
+#include <ptest_main.h>
}
return (found_or_error);
}
-
-#ifdef TEST
-
-int main(int argc, char **argv)
-{
- struct testcase {
- const char *title;
- const char *map_names;
- const char *ext_delimiters;
- const char *null_sender;
- const char *wildcard;
- const char *login_name;
- const char *sender_addr;
- int exp_return;
- };
- struct testcase testcases[] = {
- {"wildcard works",
- "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}",
- "+-", "<>", "*", "root", "anything", LSM_STAT_FOUND
- },
- {"unknown user",
- "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}",
- "+-", "<>", "*", "toor", "anything", LSM_STAT_NOTFOUND
- },
- {"bare user",
- "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}",
- "+-", "<>", "*", "foo", "foo", LSM_STAT_FOUND
- },
- {"user@domain",
- "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}",
- "+-", "<>", "*", "foo", "foo@example.com", LSM_STAT_FOUND
- },
- {"user+ext@domain",
- "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}",
- "+-", "<>", "*", "foo", "foo+bar@example.com", LSM_STAT_FOUND
- },
- {"wrong sender",
- "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}",
- "+-", "<>", "*", "foo", "bar@example.com", LSM_STAT_NOTFOUND
- },
- {"@domain",
- "inline:{root=*, {foo = @example.com}, bar=<>}",
- "+-", "<>", "*", "foo", "anyone@example.com", LSM_STAT_FOUND
- },
- {"wrong @domain",
- "inline:{root=*, {foo = @example.com}, bar=<>}",
- "+-", "<>", "*", "foo", "anyone@example.org", LSM_STAT_NOTFOUND
- },
- {"null sender",
- "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}",
- "+-", "<>", "*", "bar", "", LSM_STAT_FOUND
- },
- {"wrong null sender",
- "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}",
- "+-", "<>", "*", "baz", "", LSM_STAT_NOTFOUND
- },
- {"error",
- "inline:{root=*}, fail:sorry",
- "+-", "<>", "*", "baz", "whatever", LSM_STAT_RETRY
- },
- {"no error",
- "inline:{root=*}, fail:sorry",
- "+-", "<>", "*", "root", "whatever", LSM_STAT_FOUND
- },
- {"unknown uid:number",
- "inline:{root=*, {uid:12345 = foo,foo@example.com}, bar=<>}",
- "+-", "<>", "*", "uid:54321", "foo", LSM_STAT_NOTFOUND
- },
- {"known uid:number",
- "inline:{root=*, {uid:12345 = foo,foo@example.com}, bar=<>}",
- "+-", "<>", "*", "uid:12345", "foo", LSM_STAT_FOUND
- },
- {"unknown \"other last\"",
- "inline:{root=*, {foo = \"first last\",\"first last\"@example.com}, bar=<>}",
- "+-", "<>", "*", "foo", "other last", LSM_STAT_NOTFOUND
- },
- {"bare \"first last\"",
- "inline:{root=*, {foo = \"first last\",\"first last\"@example.com}, bar=<>}",
- "+-", "<>", "*", "foo", "first last", LSM_STAT_FOUND
- },
- {"\"first last\"@domain",
- "inline:{root=*, {foo = \"first last\",\"first last\"@example.com}, bar=<>}",
- "+-", "<>", "*", "foo", "first last@example.com", LSM_STAT_FOUND
- },
- };
- struct testcase *tp;
- int act_return;
- int pass;
- int fail;
- LOGIN_SENDER_MATCH *lsm;
-
- /*
- * Fake variable settings.
- */
- var_double_bounce_sender = DEF_DOUBLE_BOUNCE;
- var_ownreq_special = DEF_OWNREQ_SPECIAL;
-
-#define NUM_TESTS sizeof(testcases)/sizeof(testcases[0])
-
- for (pass = fail = 0, tp = testcases; tp < testcases + NUM_TESTS; tp++) {
- msg_info("RUN test case %ld %s", (long) (tp - testcases), tp->title);
-#if 0
- msg_info("title=%s", tp->title);
- msg_info("map_names=%s", tp->map_names);
- msg_info("ext_delimiters=%s", tp->ext_delimiters);
- msg_info("null_sender=%s", tp->null_sender);
- msg_info("wildcard=%s", tp->wildcard);
- msg_info("login_name=%s", tp->login_name);
- msg_info("sender_addr=%s", tp->sender_addr);
- msg_info("exp_return=%d", tp->exp_return);
-#endif
- lsm = login_sender_create("test map", tp->map_names,
- tp->ext_delimiters, tp->null_sender,
- tp->wildcard);
- act_return = login_sender_match(lsm, tp->login_name, tp->sender_addr);
- if (act_return == tp->exp_return) {
- msg_info("PASS test %ld", (long) (tp - testcases));
- pass++;
- } else {
- msg_info("FAIL test %ld", (long) (tp - testcases));
- fail++;
- }
- login_sender_free(lsm);
- }
- return (fail > 0);
-}
-
-#endif /* TEST */
+++ /dev/null
-unknown: RUN test case 0 wildcard works
-unknown: PASS test 0
-unknown: RUN test case 1 unknown user
-unknown: PASS test 1
-unknown: RUN test case 2 bare user
-unknown: PASS test 2
-unknown: RUN test case 3 user@domain
-unknown: PASS test 3
-unknown: RUN test case 4 user+ext@domain
-unknown: PASS test 4
-unknown: RUN test case 5 wrong sender
-unknown: PASS test 5
-unknown: RUN test case 6 @domain
-unknown: PASS test 6
-unknown: RUN test case 7 wrong @domain
-unknown: PASS test 7
-unknown: RUN test case 8 null sender
-unknown: PASS test 8
-unknown: RUN test case 9 wrong null sender
-unknown: PASS test 9
-unknown: RUN test case 10 error
-unknown: warning: fail:sorry lookup error for "baz"
-unknown: PASS test 10
-unknown: RUN test case 11 no error
-unknown: PASS test 11
-unknown: RUN test case 12 unknown uid:number
-unknown: PASS test 12
-unknown: RUN test case 13 known uid:number
-unknown: PASS test 13
-unknown: RUN test case 14 unknown "other last"
-unknown: PASS test 14
-unknown: RUN test case 15 bare "first last"
-unknown: PASS test 15
-unknown: RUN test case 16 "first last"@domain
-unknown: PASS test 16
--- /dev/null
+ /*
+ * Test program to exercise login_sender_match.c. See and ptest_main.h for a
+ * documented example.
+ */
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+
+ /*
+ * Global library.
+ */
+#include <mail_params.h>
+#include <login_sender_match.h>
+
+ /*
+ * Test library.
+ */
+#include <ptest.h>
+
+typedef struct PTEST_CASE {
+ const char *testname;
+ void (*action) (PTEST_CTX *, const struct PTEST_CASE *tp);
+ const char *map_names;
+ const char *ext_delimiters;
+ const char *null_sender;
+ const char *wildcard;
+ const char *login_name;
+ const char *sender_addr;
+ int want_return;
+ const char *want_logging;
+} PTEST_CASE;
+
+static void tester(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ int got_return;
+ LOGIN_SENDER_MATCH *lsm;
+
+ /*
+ * Fake variable settings.
+ */
+ var_double_bounce_sender = DEF_DOUBLE_BOUNCE;
+ var_ownreq_special = DEF_OWNREQ_SPECIAL;
+
+#define NUM_TESTS sizeof(ptestcases)/sizeof(ptestcases[0])
+
+#if 0
+ msg_info("name=%s", tp->title);
+ msg_info("map_names=%s", tp->map_names);
+ msg_info("ext_delimiters=%s", tp->ext_delimiters);
+ msg_info("null_sender=%s", tp->null_sender);
+ msg_info("wildcard=%s", tp->wildcard);
+ msg_info("login_name=%s", tp->login_name);
+ msg_info("sender_addr=%s", tp->sender_addr);
+ msg_info("want_return=%d", tp->exp_return);
+#endif
+ lsm = login_sender_create("test map", tp->map_names,
+ tp->ext_delimiters, tp->null_sender,
+ tp->wildcard);
+ if (tp->want_logging)
+ expect_ptest_log_event(t, tp->want_logging);
+ got_return = login_sender_match(lsm, tp->login_name, tp->sender_addr);
+ if (got_return != tp->want_return)
+ ptest_error(t, "login_sender_match() got %d, want %d",
+ got_return, tp->want_return);
+ login_sender_free(lsm);
+}
+
+static const PTEST_CASE ptestcases[] = {
+ {"wildcard works", tester,
+ "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}",
+ "+-", "<>", "*", "root", "anything", LSM_STAT_FOUND
+ },
+ {"unknown user", tester,
+ "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}",
+ "+-", "<>", "*", "toor", "anything", LSM_STAT_NOTFOUND
+ },
+ {"bare user", tester,
+ "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}",
+ "+-", "<>", "*", "foo", "foo", LSM_STAT_FOUND
+ },
+ {"user@domain", tester,
+ "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}",
+ "+-", "<>", "*", "foo", "foo@example.com", LSM_STAT_FOUND
+ },
+ {"user+ext@domain", tester,
+ "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}",
+ "+-", "<>", "*", "foo", "foo+bar@example.com", LSM_STAT_FOUND
+ },
+ {"wrong sender", tester,
+ "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}",
+ "+-", "<>", "*", "foo", "bar@example.com", LSM_STAT_NOTFOUND
+ },
+ {"@domain", tester,
+ "inline:{root=*, {foo = @example.com}, bar=<>}",
+ "+-", "<>", "*", "foo", "anyone@example.com", LSM_STAT_FOUND
+ },
+ {"wrong @domain", tester,
+ "inline:{root=*, {foo = @example.com}, bar=<>}",
+ "+-", "<>", "*", "foo", "anyone@example.org", LSM_STAT_NOTFOUND
+ },
+ {"null sender", tester,
+ "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}",
+ "+-", "<>", "*", "bar", "", LSM_STAT_FOUND
+ },
+ {"wrong null sender", tester,
+ "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}",
+ "+-", "<>", "*", "baz", "", LSM_STAT_NOTFOUND
+ },
+ {"error", tester,
+ "inline:{root=*}, fail:sorry",
+ "+-", "<>", "*", "baz", "whatever", LSM_STAT_RETRY,
+ "fail:sorry lookup error"
+ },
+ {"no error", tester,
+ "inline:{root=*}, fail:sorry",
+ "+-", "<>", "*", "root", "whatever", LSM_STAT_FOUND
+ },
+ {"unknown uid:number", tester,
+ "inline:{root=*, {uid:12345 = foo,foo@example.com}, bar=<>}",
+ "+-", "<>", "*", "uid:54321", "foo", LSM_STAT_NOTFOUND
+ },
+ {"known uid:number", tester,
+ "inline:{root=*, {uid:12345 = foo,foo@example.com}, bar=<>}",
+ "+-", "<>", "*", "uid:12345", "foo", LSM_STAT_FOUND
+ },
+ {"unknown \"other last\"", tester,
+ "inline:{root=*, {foo = \"first last\",\"first last\"@example.com}, bar=<>}",
+ "+-", "<>", "*", "foo", "other last", LSM_STAT_NOTFOUND
+ },
+ {"bare \"first last\"", tester,
+ "inline:{root=*, {foo = \"first last\",\"first last\"@example.com}, bar=<>}",
+ "+-", "<>", "*", "foo", "first last", LSM_STAT_FOUND
+ },
+ {"\"first last\"@domain", tester,
+ "inline:{root=*, {foo = \"first last\",\"first last\"@example.com}, bar=<>}",
+ "+-", "<>", "*", "foo", "first last@example.com", LSM_STAT_FOUND
+ },
+};
+
+#include <ptest_main.h>
var_proxywrite_service = DEF_PROXYWRITE_SERVICE;
var_ipc_timeout = 3600;
mail_dict_init();
- dict_test(argc, argv);
+ dict_cli(argc, argv);
return (0);
}
return ((MAP_SEARCH *) htable_find(map_search_table, map_spec));
}
-
- /*
- * Test driver.
- */
-#ifdef TEST
-#include <stdlib.h>
-
- /*
- * Test search actions.
- */
-#define TEST_NAME_1 "one"
-#define TEST_NAME_2 "two"
-#define TEST_CODE_1 1
-#define TEST_CODE_2 2
-
-#define BAD_NAME "bad"
-
-static const NAME_CODE search_actions[] = {
- TEST_NAME_1, TEST_CODE_1,
- TEST_NAME_2, TEST_CODE_2,
- 0, MAP_SEARCH_CODE_UNKNOWN,
-};
-
-/* Helpers to simplify tests. */
-
-static const char *string_or_null(const char *s)
-{
- return (s ? s : "(null)");
-}
-
-static char *escape_order(VSTRING *buf, const char *search_order)
-{
- return (STR(escape(buf, search_order, strlen(search_order))));
-}
-
-int main(int argc, char **argv)
-{
- /* Test cases with inputs and expected outputs. */
- typedef struct TEST_CASE {
- const char *map_spec;
- int exp_return; /* 0=fail, 1=success */
- const char *exp_map_type_name; /* 0 or match */
- const char *exp_search_order; /* 0 or match */
- } TEST_CASE;
- static TEST_CASE test_cases[] = {
- {"type", 0, 0, 0},
- {"type:name", 1, "type:name", 0},
- {"{type:name}", 1, "type:name", 0},
- {"{type:name", 0, 0, 0}, /* } */
- {"{type}", 0, 0, 0},
- {"{type:name foo}", 0, 0, 0},
- {"{type:name foo=bar}", 0, 0, 0},
- {"{type:name search_order=}", 1, "type:name", ""},
- {"{type:name search_order=one, two}", 0, 0, 0},
- {"{type:name {search_order=one, two}}", 1, "type:name", "\01\02"},
- {"{type:name {search_order=one, two, bad}}", 0, 0, 0},
- {"{inline:{a=b} {search_order=one, two}}", 1, "inline:{a=b}", "\01\02"},
- {0},
- };
- TEST_CASE *test_case;
-
- /* Actual results. */
- const MAP_SEARCH *map_search_from_create;
- const MAP_SEARCH *map_search_from_create_2nd;
- const MAP_SEARCH *map_search_from_lookup;
-
- /* Findings. */
- int tests_failed = 0;
- int test_failed;
-
- /* Scratch */
- VSTRING *expect_escaped = vstring_alloc(100);
- VSTRING *actual_escaped = vstring_alloc(100);
-
- map_search_init(search_actions);
-
- for (tests_failed = 0, test_case = test_cases; test_case->map_spec;
- tests_failed += test_failed, test_case++) {
- test_failed = 0;
- msg_info("test case %d: '%s'",
- (int) (test_case - test_cases), test_case->map_spec);
- map_search_from_create = map_search_create(test_case->map_spec);
- if (!test_case->exp_return != !map_search_from_create) {
- if (map_search_from_create)
- msg_warn("test case %d return expected %s actual {%s, %s}",
- (int) (test_case - test_cases),
- test_case->exp_return ? "success" : "fail",
- map_search_from_create->map_type_name,
- escape_order(actual_escaped,
- map_search_from_create->search_order));
- else
- msg_warn("test case %d return expected %s actual %s",
- (int) (test_case - test_cases), "success",
- map_search_from_create ? "success" : "fail");
- test_failed = 1;
- continue;
- }
- if (test_case->exp_return == 0)
- continue;
- map_search_from_lookup = map_search_lookup(test_case->map_spec);
- if (map_search_from_create != map_search_from_lookup) {
- msg_warn("test case %d map_search_lookup expected=%p actual=%p",
- (int) (test_case - test_cases),
- map_search_from_create, map_search_from_lookup);
- test_failed = 1;
- }
- map_search_from_create_2nd = map_search_create(test_case->map_spec);
- if (map_search_from_create != map_search_from_create_2nd) {
- msg_warn("test case %d repeated map_search_create "
- "expected=%p actual=%p",
- (int) (test_case - test_cases),
- map_search_from_create, map_search_from_create_2nd);
- test_failed = 1;
- }
- if (strcmp(string_or_null(test_case->exp_map_type_name),
- string_or_null(map_search_from_create->map_type_name))) {
- msg_warn("test case %d map_type_name expected=%s actual=%s",
- (int) (test_case - test_cases),
- string_or_null(test_case->exp_map_type_name),
- string_or_null(map_search_from_create->map_type_name));
- test_failed = 1;
- }
- if (strcmp(string_or_null(test_case->exp_search_order),
- string_or_null(map_search_from_create->search_order))) {
- msg_warn("test case %d search_order expected=%s actual=%s",
- (int) (test_case - test_cases),
- escape_order(expect_escaped,
- string_or_null(test_case->exp_search_order)),
- escape_order(actual_escaped,
- string_or_null(map_search_from_create->search_order)));
- test_failed = 1;
- }
- }
- vstring_free(expect_escaped);
- vstring_free(actual_escaped);
-
- if (tests_failed)
- msg_info("tests failed: %d", tests_failed);
- exit(tests_failed != 0);
-}
-
-#endif
+++ /dev/null
-unknown: test case 0: 'type'
-unknown: warning: malformed map specification: 'type'
-unknown: warning: expected maptype:mapname instead of 'type'
-unknown: test case 1: 'type:name'
-unknown: test case 2: '{type:name}'
-unknown: test case 3: '{type:name'
-unknown: warning: malformed map specification: 'missing '}' in "{type:name"'
-unknown: test case 4: '{type}'
-unknown: warning: malformed map specification: '{type}'
-unknown: warning: expected maptype:mapname instead of 'type'
-unknown: test case 5: '{type:name foo}'
-unknown: warning: malformed map attribute in '{type:name foo}': 'missing '=' after attribute name'
-unknown: test case 6: '{type:name foo=bar}'
-unknown: warning: unknown map attribute in '{type:name foo=bar}': 'foo'
-unknown: test case 7: '{type:name search_order=}'
-unknown: test case 8: '{type:name search_order=one, two}'
-unknown: warning: malformed map attribute in '{type:name search_order=one, two}': 'missing '=' after attribute name'
-unknown: test case 9: '{type:name {search_order=one, two}}'
-unknown: test case 10: '{type:name {search_order=one, two, bad}}'
-unknown: warning: unknown search type 'bad' in '{type:name {search_order=one, two, bad}}'
-unknown: test case 11: '{inline:{a=b} {search_order=one, two}}'
--- /dev/null
+ /*
+ * Test program to exercise map_search.c. See ptest_main.h for a documented
+ * example.
+ */
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <stdlib.h>
+#include <string.h>
+
+ /*
+ * Utility library.
+ */
+#include <stringops.h>
+#include <vstring.h>
+
+ /*
+ * Global library.
+ */
+#include <map_search.h>
+
+ /*
+ * Test library.
+ */
+#include <ptest.h>
+
+ /*
+ * Test search actions.
+ */
+#define TEST_NAME_1 "one"
+#define TEST_NAME_2 "two"
+#define TEST_CODE_1 1
+#define TEST_CODE_2 2
+
+#define BAD_NAME "bad"
+
+#define STR(x) vstring_str(x)
+
+static const NAME_CODE search_actions[] = {
+ TEST_NAME_1, TEST_CODE_1,
+ TEST_NAME_2, TEST_CODE_2,
+ 0, MAP_SEARCH_CODE_UNKNOWN,
+};
+
+ /*
+ * Test library adaptor.
+ */
+typedef struct PTEST_CASE {
+ const char *testname;
+ void (*action) (PTEST_CTX *, const struct PTEST_CASE *);
+} PTEST_CASE;
+
+/* Helpers to simplify tests. */
+
+static const char *string_or_null(const char *s)
+{
+ return (s ? s : "(null)");
+}
+
+static char *escape_order(VSTRING *buf, const char *search_order)
+{
+ return (STR(escape(buf, search_order, strlen(search_order))));
+}
+
+#define MAX_WANT_LOG 5
+
+static void test_map_search(PTEST_CTX *t, const struct PTEST_CASE *unused)
+{
+ /* Test cases with inputs and expected outputs. */
+ struct test {
+ const char *map_spec;
+ int want_return; /* 0=fail, 1=success */
+ const char *want_log[MAX_WANT_LOG];
+ const char *want_map_type_name; /* 0 or match */
+ const char *exp_search_order; /* 0 or match */
+ };
+ static struct test test_cases[] = {
+ { /* 0 */ "type", 0, {
+ "malformed map specification: 'type'",
+ "expected maptype:mapname instead of 'type'",
+ }, 0},
+ { /* 1 */ "type:name", 1, {}, "type:name", 0},
+ { /* 2 */ "{type:name}", 1, {}, "type:name", 0},
+ { /* 3 */ "{type:name", 0, {
+ "missing '}' in \"{type:name\""
+ }, 0, 0}, /* } */
+ { /* 4 */ "{type}", 0, {
+ "malformed map specification: '{type}'",
+ "expected maptype:mapname instead of 'type'",
+ }, 0, 0},
+ { /* 5 */ "{type:name foo}", 0, {
+ "missing '=' after attribute name",
+ }, 0, 0},
+ { /* 6 */ "{type:name foo=bar}", 0, {
+ "warning: unknown map attribute in '{type:name foo=bar}': 'foo'",
+ }, 0, 0},
+ { /* 7 */ "{type:name search_order=}", 1, {}, "type:name", ""},
+ { /* 8 */ "{type:name search_order=one, two}", 0, {
+ "missing '=' after attribute name'",
+ }, 0, 0},
+ { /* 9 */ "{type:name {search_order=one, two}}", 1, {
+ }, "type:name", "\01\02"},
+ { /* 10 */ "{type:name {search_order=one, two, bad}}", 0, {
+ "'bad' in '{type:name {search_order=one, two, bad}}'",
+ }, 0, 0},
+ { /* 11 */ "{inline:{a=b} {search_order=one, two}}", 1, {
+ }, "inline:{a=b}", "\01\02"},
+ {0},
+ };
+ struct test *tp;
+ const char *const * cpp;
+
+ /* Actual results. */
+ const MAP_SEARCH *map_search_from_create;
+ const MAP_SEARCH *map_search_from_create_2nd;
+ const MAP_SEARCH *map_search_from_lookup;
+
+ /* Scratch */
+ VSTRING *want_escaped = vstring_alloc(100);
+ VSTRING *got_escaped = vstring_alloc(100);
+
+ /* Other */
+ VSTRING *test_label = vstring_alloc(100);
+
+ map_search_init(search_actions);
+
+ for (tp = test_cases; tp->map_spec; tp++) {
+ vstring_sprintf(test_label, "test %d", (int) (tp - test_cases));
+/**INDENT** Error@126: Unbalanced parens */
+ PTEST_RUN(t, STR(test_label), {
+ for (cpp = tp->want_log; cpp < tp->want_log + MAX_WANT_LOG && *cpp; cpp++)
+ expect_ptest_log_event(t, *cpp);
+ map_search_from_create = map_search_create(tp->map_spec);
+ if (!tp->want_return != !map_search_from_create) {
+ if (map_search_from_create)
+ ptest_fatal(t, "return: got {%s, %s}, want '%s'",
+ map_search_from_create->map_type_name,
+ escape_order(got_escaped,
+ map_search_from_create->search_order),
+ tp->want_return ? "success" : "fail");
+ else
+ ptest_fatal(t, "return: got '%s', want '%s'",
+ map_search_from_create ? "success" : "fail",
+ "success");
+ }
+ if (tp->want_return == 0)
+ ptest_return(t);
+ map_search_from_lookup = map_search_lookup(tp->map_spec);
+ if (map_search_from_create != map_search_from_lookup) {
+ ptest_error(t, "map_search_lookup: got %p, want %p",
+ map_search_from_lookup, map_search_from_create);
+ }
+ map_search_from_create_2nd = map_search_create(tp->map_spec);
+ if (map_search_from_create != map_search_from_create_2nd) {
+ ptest_error(t, "repeated map_search_create: got %p want %p",
+ map_search_from_create_2nd, map_search_from_create);
+ }
+ if (strcmp(string_or_null(tp->want_map_type_name),
+ string_or_null(map_search_from_create->map_type_name))) {
+ ptest_error(t, "map_type_name: got '%s', want '%s'",
+ string_or_null(map_search_from_create->map_type_name),
+ string_or_null(tp->want_map_type_name));
+ }
+ if (strcmp(string_or_null(tp->exp_search_order),
+ string_or_null(map_search_from_create->search_order))) {
+ ptest_error(t, "search_order: got '%s', want '%s'",
+ escape_order(got_escaped,
+ string_or_null(map_search_from_create->search_order)),
+ escape_order(want_escaped,
+ string_or_null(tp->exp_search_order)));
+ }
+/**INDENT** Warning@168: Extra ) */
+ });
+ }
+ vstring_free(want_escaped);
+ vstring_free(got_escaped);
+ vstring_free(test_label);
+}
+
+ /*
+ * Test library adaptor.
+ */
+static const PTEST_CASE ptestcases[] = {
+ "test_map_search", test_map_search,
+};
+
+#include <ptest_main.h>
+unknown: dict_open_lookup: fail
unknown: dict_open: fail:1maps
unknown: dict_register: fail:1maps(0,lock) 1
"": not found
}
return (0);
}
-
- /*
- * Test program.
- */
-#ifdef TEST
-#include <stdlib.h>
-#include <mymalloc.h>
-#include <msg.h>
-
- /*
- * Main test program.
- */
-int main(int argc, char **argv)
-{
- /* Test cases with inputs and expected outputs. */
- typedef struct TEST_CASE {
- const char *inet_protocols;
- const char *mailhost_addr;
- int exp_return;
- const char *exp_mailhost_addr;
- char *exp_bare_addr;
- int exp_addr_family;
- } TEST_CASE;
- static TEST_CASE test_cases[] = {
- /* IPv4 in IPv6. */
- {"ipv4, ipv6", "ipv6:::ffff:1.2.3.4", 0, "1.2.3.4", "1.2.3.4", AF_INET},
- {"ipv6", "ipv6:::ffff:1.2.3.4", 0, "IPv6:::ffff:1.2.3.4", "::ffff:1.2.3.4", AF_INET6},
- /* Pass IPv4 or IPV6. */
- {"ipv4, ipv6", "ipv6:fc00::1", 0, "IPv6:fc00::1", "fc00::1", AF_INET6},
- {"ipv4, ipv6", "1.2.3.4", 0, "1.2.3.4", "1.2.3.4", AF_INET},
- /* Normalize IPv4 or IPV6. */
- {"ipv4, ipv6", "ipv6:fc00::0", 0, "IPv6:fc00::", "fc00::", AF_INET6},
- {"ipv4, ipv6", "01.02.03.04", 0, "1.2.3.4", "1.2.3.4", AF_INET},
- /* Suppress specific outputs. */
- {"ipv4, ipv6", "ipv6:fc00::1", 0, 0, "fc00::1", AF_INET6},
- {"ipv4, ipv6", "ipv6:fc00::1", 0, "IPv6:fc00::1", 0, AF_INET6},
- {"ipv4, ipv6", "ipv6:fc00::1", 0, "IPv6:fc00::1", "fc00::1", -1},
- /* Address type mismatch. */
- {"ipv4, ipv6", "::ffff:1.2.3.4", -1},
- {"ipv4", "ipv6:fc00::1", -1},
- {"ipv6", "1.2.3.4", -1},
- 0,
- };
- TEST_CASE *test_case;
-
- /* Actual results. */
- int act_return;
- char *act_mailhost_addr = mystrdup("initial_mailhost_addr");
- char *act_bare_addr = mystrdup("initial_bare_addr");
- int act_addr_family = 0xdeadbeef;
-
- /* Findings. */
- int tests_failed = 0;
- int test_failed;
-
- for (tests_failed = 0, test_case = test_cases; test_case->inet_protocols;
- tests_failed += test_failed, test_case++) {
- test_failed = 0;
- inet_proto_init(argv[0], test_case->inet_protocols);
- act_return =
- normalize_mailhost_addr(test_case->mailhost_addr,
- test_case->exp_mailhost_addr ?
- &act_mailhost_addr : (char **) 0,
- test_case->exp_bare_addr ?
- &act_bare_addr : (char **) 0,
- test_case->exp_addr_family >= 0 ?
- &act_addr_family : (int *) 0);
- if (act_return != test_case->exp_return) {
- msg_warn("test case %d return expected=%d actual=%d",
- (int) (test_case - test_cases),
- test_case->exp_return, act_return);
- test_failed = 1;
- continue;
- }
- if (test_case->exp_return != 0)
- continue;
- if (test_case->exp_mailhost_addr
- && strcmp(test_case->exp_mailhost_addr, act_mailhost_addr)) {
- msg_warn("test case %d mailhost_addr expected=%s actual=%s",
- (int) (test_case - test_cases),
- test_case->exp_mailhost_addr, act_mailhost_addr);
- test_failed = 1;
- }
- if (test_case->exp_bare_addr
- && strcmp(test_case->exp_bare_addr, act_bare_addr)) {
- msg_warn("test case %d bare_addr expected=%s actual=%s",
- (int) (test_case - test_cases),
- test_case->exp_bare_addr, act_bare_addr);
- test_failed = 1;
- }
- if (test_case->exp_addr_family >= 0
- && test_case->exp_addr_family != act_addr_family) {
- msg_warn("test case %d addr_family expected=0x%x actual=0x%x",
- (int) (test_case - test_cases),
- test_case->exp_addr_family, act_addr_family);
- test_failed = 1;
- }
- }
- if (act_mailhost_addr)
- myfree(act_mailhost_addr);
- if (act_bare_addr)
- myfree(act_bare_addr);
- if (tests_failed)
- msg_info("tests failed: %d", tests_failed);
- exit(tests_failed != 0);
-}
-
-#endif
--- /dev/null
+ /*
+ * Test program to exercise normalize_mailhost_addr.c. See ptest_main.h for
+ * a documented example.
+ */
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+
+ /*
+ * Utility library.
+ */
+#include <mymalloc.h>
+#include <inet_proto.h>
+
+ /*
+ * Global library.
+ */
+#include <normalize_mailhost_addr.h>
+
+ /*
+ * Test library.
+ */
+#include <ptest.h>
+
+typedef struct PTEST_CASE {
+ const char *testname;
+ void (*action) (PTEST_CTX *, const struct PTEST_CASE *);
+ const char *inet_protocols;
+ const char *mailhost_addr;
+ int want_return;
+ const char *want_mailhost_addr;
+ char *want_bare_addr;
+ int want_addr_family;
+} PTEST_CASE;
+
+static void test_normalize_mailhost_addr(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ /* Actual results. */
+ int got_return;
+ char *got_mailhost_addr = mystrdup("initial_mailhost_addr");
+ char *got_bare_addr = mystrdup("initial_bare_addr");
+ int got_addr_family = 0xdeadbeef;
+
+#define CLEANUP_AND_RETURN() do { \
+ if (got_mailhost_addr) \
+ myfree(got_mailhost_addr); \
+ got_mailhost_addr = 0; \
+ if (got_bare_addr) \
+ myfree(got_bare_addr); \
+ got_bare_addr = 0; \
+ } while (0)
+
+ inet_proto_init(tp->testname, tp->inet_protocols);
+ got_return = normalize_mailhost_addr(tp->mailhost_addr,
+ tp->want_mailhost_addr ?
+ &got_mailhost_addr : (char **) 0,
+ tp->want_bare_addr ?
+ &got_bare_addr : (char **) 0,
+ tp->want_addr_family >= 0 ?
+ &got_addr_family : (int *) 0);
+ if (got_return != tp->want_return) {
+ ptest_error(t, "return value: got %d, want %d",
+ got_return, tp->want_return);
+ CLEANUP_AND_RETURN();
+ }
+ if (tp->want_return != 0)
+ CLEANUP_AND_RETURN();
+ if (tp->want_mailhost_addr
+ && strcmp(tp->want_mailhost_addr, got_mailhost_addr)) {
+ ptest_error(t, "mailhost_addr value: got '%s', want '%s'",
+ got_mailhost_addr, tp->want_mailhost_addr);
+ }
+ if (tp->want_bare_addr && strcmp(tp->want_bare_addr, got_bare_addr)) {
+ ptest_error(t, "bare_addr value: got '%s', want '%s'",
+ got_bare_addr, tp->want_bare_addr);
+ }
+ if (tp->want_addr_family > 0 && tp->want_addr_family != got_addr_family) {
+ ptest_error(t, "addr_family: got 0x%x, want 0x%x",
+ got_addr_family, tp->want_addr_family);
+ }
+ CLEANUP_AND_RETURN();
+}
+
+static PTEST_CASE ptestcases[] = {
+ {
+ "IPv4 in IPv6 #1", test_normalize_mailhost_addr,
+ /* inet_protocols */ "ipv4, ipv6",
+ /* mailhost_addr */ "ipv6:::ffff:1.2.3.4",
+ /* want_return */ 0,
+ /* want_mailhost_addr */ "1.2.3.4",
+ /* want_bare_addr */ "1.2.3.4",
+ /* want_addr_family */ AF_INET
+ }, {
+ "IPv4 in IPv6 #2", test_normalize_mailhost_addr,
+ /* inet_protocols */ "ipv6",
+ /* mailhost_addr */ "ipv6:::ffff:1.2.3.4",
+ /* want_return */ 0,
+ /* want_mailhost_addr */ "IPv6:::ffff:1.2.3.4",
+ /* want_bare_addr */ "::ffff:1.2.3.4",
+ /* want_addr_family */ AF_INET6
+ }, {
+ "Pass IPv4 or IPV6 #1", test_normalize_mailhost_addr,
+ /* inet_protocols */ "ipv4, ipv6",
+ /* mailhost_addr */ "ipv6:fc00::1",
+ /* want_return */ 0,
+ /* want_mailhost_addr */ "IPv6:fc00::1",
+ /* want_bare_addr */ "fc00::1",
+ /* want_addr_family */ AF_INET6
+ }, {
+ "Pass IPv4 or IPV6 #2", test_normalize_mailhost_addr,
+ /* inet_protocols */ "ipv4, ipv6",
+ /* mailhost_addr */ "1.2.3.4",
+ /* want_return */ 0,
+ /* want_mailhost_addr */ "1.2.3.4",
+ /* want_bare_addr */ "1.2.3.4",
+ /* want_addr_family */ AF_INET
+ }, {
+ "Normalize IPv4 or IPV6 #1", test_normalize_mailhost_addr,
+ /* inet_protocols */ "ipv4, ipv6",
+ /* mailhost_addr */ "ipv6:fc00::0",
+ /* want_return */ 0,
+ /* want_mailhost_addr */ "IPv6:fc00::",
+ /* want_bare_addr */ "fc00::",
+ /* want_addr_family */ AF_INET6
+ }, {
+ "Normalize IPv4 or IPV6 #2", test_normalize_mailhost_addr,
+ /* inet_protocols */ "ipv4, ipv6",
+ /* mailhost_addr */ "01.02.03.04",
+ /* want_return */ 0,
+ /* want_mailhost_addr */ "1.2.3.4",
+ /* want_bare_addr */ "1.2.3.4",
+ /* want_addr_family */ AF_INET
+ }, {
+ "Suppress specific outputs #1", test_normalize_mailhost_addr,
+ /* inet_protocols */ "ipv4, ipv6",
+ /* mailhost_addr */ "ipv6:fc00::1",
+ /* want_return */ 0,
+ /* want_mailhost_addr */ 0,
+ /* want_bare_addr */ "fc00::1",
+ /* want_addr_family */ AF_INET6
+ }, {
+ "Suppress specific outputs #2", test_normalize_mailhost_addr,
+ /* inet_protocols */ "ipv4, ipv6",
+ /* mailhost_addr */ "ipv6:fc00::1",
+ /* want_return */ 0,
+ /* want_mailhost_addr */ "IPv6:fc00::1",
+ /* want_bare_addr */ 0,
+ /* want_addr_family */ AF_INET6
+ }, {
+ "Suppress specific outputs #3", test_normalize_mailhost_addr,
+ /* inet_protocols */ "ipv4, ipv6",
+ /* mailhost_addr */ "ipv6:fc00::1",
+ /* want_return */ 0,
+ /* want_mailhost_addr */ "IPv6:fc00::1",
+ /* want_bare_addr */ "fc00::1", -1
+ }, {
+ "Address type mismatch #1", test_normalize_mailhost_addr,
+ /* inet_protocols */ "ipv4, ipv6",
+ /* mailhost_addr */ "::ffff:1.2.3.4",
+ /* want_return */ -1
+ }, {
+ "Address type mismatch #2", test_normalize_mailhost_addr,
+ /* inet_protocols */ "ipv4",
+ /* mailhost_addr */ "ipv6:fc00::1",
+ /* want_return */ -1
+ }, {
+ "Address type mismatch #3", test_normalize_mailhost_addr,
+ /* inet_protocols */ "ipv6",
+ /* mailhost_addr */ "1.2.3.4",
+ /* want_return */ -1
+ },
+};
+
+#include <ptest_main.h>
vstring_strcat(buffer, "\r\n");
return (mac_expand_error ? -2 : 0);
}
-
-#ifdef TEST
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <msg.h>
-#include <vstream.h>
-#include <vstring_vstream.h>
-#include <msg_vstream.h>
-
-struct test_case {
- const char *title;
- const char *orig_reply;
- const char *template;
- const char *filter;
- int expected_status;
- const char *expected_reply;
-};
-
-#define NO_FILTER ((char *) 0)
-#define NO_TEMPLATE "NO_TEMPLATE"
-#define NO_ERROR (0)
-#define BAD_SMTP (-1)
-#define BAD_MACRO (-2)
-
-static const struct test_case test_cases[] = {
- {"missing reply", "", NO_TEMPLATE, NO_FILTER, BAD_SMTP, 0},
- {"long smtp_code", "1234 foo", NO_TEMPLATE, NO_FILTER, BAD_SMTP, 0},
- {"short smtp_code", "12 foo", NO_TEMPLATE, NO_FILTER, BAD_SMTP, 0},
- {"good+bad smtp_code", "321 foo\r\n1234 foo", NO_TEMPLATE, NO_FILTER, BAD_SMTP, 0},
- {"1-line no dsn", "550 Foo", "\\c footer", NO_FILTER, NO_ERROR, "550 Foo footer"},
- {"1-line no dsn", "550 Foo", "Bar", NO_FILTER, NO_ERROR, "550-Foo\r\n550 Bar"},
- {"2-line no dsn", "550-Foo\r\n550 Bar", "Baz", NO_FILTER, NO_ERROR, "550-Foo\r\n550-Bar\r\n550 Baz"},
- {"1-line with dsn", "550 5.1.1 Foo", "Bar", NO_FILTER, NO_ERROR, "550-5.1.1 Foo\r\n550 5.1.1 Bar"},
- {"2-line with dsn", "550-5.1.1 Foo\r\n450 4.1.1 Bar", "Baz", NO_FILTER, NO_ERROR, "550-5.1.1 Foo\r\n450-4.1.1 Bar\r\n450 4.1.1 Baz"},
- {"bad macro", "220 myhostname", "\\c ${whatever", NO_FILTER, BAD_MACRO, 0},
- {"bad macroCRLF", "220 myhostname\r\n", "\\c ${whatever", NO_FILTER, BAD_MACRO, 0},
- {"good macro", "220 myhostname", "\\c $whatever", NO_FILTER, NO_ERROR, "220 myhostname DUMMY"},
- {"good macroCRLF", "220 myhostname\r\n", "\\c $whatever", NO_FILTER, NO_ERROR, "220 myhostname DUMMY\r\n"},
- 0,
-};
-
-static const char *lookup(const char *name, int unused_mode, void *context)
-{
- return "DUMMY";
-}
-
-int main(int argc, char **argv)
-{
- const struct test_case *tp;
- int status;
- VSTRING *buf = vstring_alloc(10);
- void *context = 0;
-
- msg_vstream_init(argv[0], VSTREAM_ERR);
-
- for (tp = test_cases; tp->title != 0; tp++) {
- vstring_strcpy(buf, tp->orig_reply);
- status = smtp_reply_footer(buf, 0, tp->template, tp->filter,
- lookup, context);
- if (status != tp->expected_status) {
- msg_warn("test \"%s\": status %d, expected %d",
- tp->title, status, tp->expected_status);
- } else if (status < 0 && strcmp(STR(buf), tp->orig_reply) != 0) {
- msg_warn("test \"%s\": result \"%s\", expected \"%s\"",
- tp->title, STR(buf), tp->orig_reply);
- } else if (status == 0 && strcmp(STR(buf), tp->expected_reply) != 0) {
- msg_warn("test \"%s\": result \"%s\", expected \"%s\"",
- tp->title, STR(buf), tp->expected_reply);
- } else {
- msg_info("test \"%s\": pass", tp->title);
- }
- }
- vstring_free(buf);
- exit(0);
-}
-
-#endif
+++ /dev/null
-./smtp_reply_footer: test "missing reply": pass
-./smtp_reply_footer: test "long smtp_code": pass
-./smtp_reply_footer: test "short smtp_code": pass
-./smtp_reply_footer: test "good+bad smtp_code": pass
-./smtp_reply_footer: test "1-line no dsn": pass
-./smtp_reply_footer: test "1-line no dsn": pass
-./smtp_reply_footer: test "2-line no dsn": pass
-./smtp_reply_footer: test "1-line with dsn": pass
-./smtp_reply_footer: test "2-line with dsn": pass
-./smtp_reply_footer: warning: truncated macro reference: " ${whatever"
-./smtp_reply_footer: test "bad macro": pass
-./smtp_reply_footer: warning: truncated macro reference: " ${whatever"
-./smtp_reply_footer: test "bad macroCRLF": pass
-./smtp_reply_footer: test "good macro": pass
-./smtp_reply_footer: test "good macroCRLF": pass
--- /dev/null
+ /*
+ * Test program to exercise smtp_reply_footer.c. See ptest_main.h for a
+ * documented example.
+ */
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <string.h>
+
+ /*
+ * Global library.
+ */
+#include <dsn_util.h>
+#include <smtp_reply_footer.h>
+
+ /*
+ * Test library.
+ */
+#include <ptest.h>
+
+ /*
+ * SLMs.
+ */
+#define STR vstring_str
+
+typedef struct PTEST_CASE {
+ const char *testname;
+ void (*action) (PTEST_CTX *, const struct PTEST_CASE *);
+ const char *orig_reply;
+ const char *template;
+ const char *filter;
+ int want_status;
+ const char *new_reply;
+ const char *ignore_warning;
+} PTEST_CASE;
+
+#define NO_FILTER ((char *) 0)
+#define NO_TEMPLATE "NO_TEMPLATE"
+#define NO_ERROR (0)
+#define BAD_SMTP (-1)
+#define BAD_MACRO (-2)
+
+static const char *lookup(const char *testname, int unused_mode, void *context)
+{
+ return "DUMMY";
+}
+
+static void test_footer(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ VSTRING *buf = vstring_alloc(10);
+ int got_status;
+ void *context = 0;
+
+ if (tp->ignore_warning)
+ expect_ptest_log_event(t, tp->ignore_warning);
+ vstring_strcpy(buf, tp->orig_reply);
+ got_status = smtp_reply_footer(buf, 0, tp->template, tp->filter,
+ lookup, context);
+ if (got_status != tp->want_status) {
+ ptest_error(t, "smtp_reply_footer status: got %d, want %d",
+ got_status, tp->want_status);
+ } else if (got_status < 0 && strcmp(STR(buf), tp->orig_reply) != 0) {
+ ptest_error(t, "smtp_reply_footer result: got \"%s\", want \"%s\"",
+ STR(buf), tp->orig_reply);
+ } else if (got_status == 0 && strcmp(STR(buf), tp->new_reply) != 0) {
+ ptest_error(t, "smtp_reply_footer result: got \"%s\", want \"%s\"",
+ STR(buf), tp->new_reply);
+ }
+ vstring_free(buf);
+}
+
+const PTEST_CASE ptestcases[] = {
+ {"missing reply", test_footer, "", NO_TEMPLATE, NO_FILTER, BAD_SMTP, 0},
+ {"long smtp_code", test_footer, "1234 foo", NO_TEMPLATE, NO_FILTER, BAD_SMTP, 0},
+ {"short smtp_code", test_footer, "12 foo", NO_TEMPLATE, NO_FILTER, BAD_SMTP, 0},
+ {"good+bad smtp_code", test_footer, "321 foo\r\n1234 foo", NO_TEMPLATE, NO_FILTER, BAD_SMTP, 0},
+ {"1-line no dsn", test_footer, "550 Foo", "\\c footer", NO_FILTER, NO_ERROR, "550 Foo footer"},
+ {"1-line no dsn", test_footer, "550 Foo", "Bar", NO_FILTER, NO_ERROR, "550-Foo\r\n550 Bar"},
+ {"2-line no dsn", test_footer, "550-Foo\r\n550 Bar", "Baz", NO_FILTER, NO_ERROR, "550-Foo\r\n550-Bar\r\n550 Baz"},
+ {"1-line with dsn", test_footer, "550 5.1.1 Foo", "Bar", NO_FILTER, NO_ERROR, "550-5.1.1 Foo\r\n550 5.1.1 Bar"},
+ {"2-line with dsn", test_footer, "550-5.1.1 Foo\r\n450 4.1.1 Bar", "Baz", NO_FILTER, NO_ERROR, "550-5.1.1 Foo\r\n450-4.1.1 Bar\r\n450 4.1.1 Baz"},
+ {"bad macro", test_footer, "220 myhostname", "\\c ${whatever", NO_FILTER, BAD_MACRO, 0, "truncated macro reference"},
+ {"bad macroCRLF", test_footer, "220 myhostname\r\n", "\\c ${whatever", NO_FILTER, BAD_MACRO, 0, "truncated macro reference"},
+ {"good macro", test_footer, "220 myhostname", "\\c $whatever", NO_FILTER, NO_ERROR, "220 myhostname DUMMY"},
+ {"good macroCRLF", test_footer, "220 myhostname\r\n", "\\c $whatever", NO_FILTER, NO_ERROR, "220 myhostname DUMMY\r\n"},
+};
+
+#include <ptest_main.h>
/*++
/* NAME
-/* test_main 3
+/* test_server_main 3
/* SUMMARY
/* test main program
/* SYNOPSIS
-/* #include <test_main.h>
+/* #include <test_server_main.h>
/*
-/* NORETURN test_main(argc, argv, test_driver, key, value, ...)
+/* NORETURN test_server_main(argc, argv, test_driver, key, value, ...)
/* int argc;
/* char **argv;
/* void (*test_driver)(int argc, char **argv);
/* This module implements a test main program for stand-alone
/* module tests.
/*
-/* test_main() should be called from a main program. It does
+/* test_server_main() should be called from a main program. It does
/* generic command-line options processing, and initializes
/* configurable parameters. After calling the test_driver()
-/* function, the test_main() function terminates.
+/* function, the test_server_main() function terminates.
/*
/* Arguments:
/* .IP "void (*test_driver)(int argc, char **argv)"
/* The argc and argv specify the process name and non-option
/* command-line arguments.
/* .PP
-/* Optional test_main() arguments are specified as a null-terminated
+/* Optional test_server_main() arguments are specified as a null-terminated
/* list with macros that have zero or more arguments:
/* .IP "CA_TEST_MAIN_INT_TABLE(CONFIG_INT_TABLE *)"
/* A table with configurable parameters, to be loaded from the
/*
* Test library.
*/
-#include <test_main.h>
+#include <test_server_main.h>
/* test_driver_main - the real main program */
-NORETURN test_main(int argc, char **argv, TEST_DRIVER_FN test_driver,...)
+NORETURN test_server_main(int argc, char **argv, TEST_DRIVER_FN test_driver,...)
{
const char *myname = "test_driver_main";
va_list ap;
/*++
/* NAME
-/* test_main 3h
+/* test_server_main 3h
/* SUMMARY
/* test main program
/* SYNOPSIS
-/* #include <test_main.h>
+/* #include <test_server_main.h>
/* DESCRIPTION
/* .nf
CHECK_CPTR_HELPER_DCL(TEST_MAIN, CONFIG_LONG_TABLE);
typedef void (*TEST_DRIVER_FN) (int, char **);
-extern NORETURN test_main(int, char **, TEST_DRIVER_FN,...);
+extern NORETURN test_server_main(int, char **, TEST_DRIVER_FN,...);
/* LICENSE
/* .ad
alias.o: ../../include/vstring.h
alias.o: alias.c
alias.o: local.h
+biff_notify.o: ../../include/inet_proto.h
biff_notify.o: ../../include/iostuff.h
biff_notify.o: ../../include/msg.h
+biff_notify.o: ../../include/myaddrinfo.h
biff_notify.o: ../../include/sys_defs.h
+biff_notify.o: ../../include/wrap_netdb.h
biff_notify.o: biff_notify.c
biff_notify.o: biff_notify.h
bounce_workaround.o: ../../include/argv.h
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
/*--*/
/* System library. */
#include "sys_defs.h"
#include <sys/socket.h>
#include <netinet/in.h>
-#include <netdb.h>
#include <string.h>
/* Utility library. */
#include <msg.h>
#include <iostuff.h>
+#include <myaddrinfo.h>
+#include <inet_proto.h>
/* Application-specific. */
void biff_notify(const char *text, ssize_t len)
{
- static struct sockaddr_in sin;
+ const char myname[] = "biff_notify";
+ const char *hostname = "localhost";
+ const char *servname = "biff";
+ int sock_type = SOCK_DGRAM;
+ const INET_PROTO_INFO *proto_info;
+ static struct sockaddr_storage sa;
+ static SOCKADDR_SIZE sa_len;
+ static int sa_family;
static int sock = -1;
- struct hostent *hp;
- struct servent *sp;
+ struct addrinfo *res0, *res;
+ int aierr;
+ int found;
/*
* Initialize a socket address structure, or re-use an existing one.
*/
- if (sin.sin_family == 0) {
- if ((sp = getservbyname("biff", "udp")) == 0) {
- msg_warn("service not found: biff/udp");
+ if (sa_len == 0) {
+ if ((aierr = hostname_to_sockaddr(hostname, servname, sock_type,
+ &res0)) != 0) {
+ msg_warn("lookup failed for host '%s' or service '%s': %s",
+ hostname, servname, MAI_STRERROR(aierr));
return;
}
- if ((hp = gethostbyname("localhost")) == 0) {
- msg_warn("host not found: localhost");
- return;
+ proto_info = inet_proto_info();
+ for (found = 0, res = res0; !found && res != 0; res = res->ai_next) {
+ if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) {
+ msg_info("skipping address family %d for host '%s' service '%s'",
+ res->ai_family, hostname, servname);
+ continue;
+ }
+ if (res->ai_addrlen > sizeof(sa)) {
+ msg_warn("skipping address size %d for host '%s' service '%s'",
+ res->ai_addrlen, hostname, servname);
+ continue;
+ }
+ found++;
+ memcpy(&sa, res->ai_addr, res->ai_addrlen);
+ sa_len = res->ai_addrlen;
+ sa_family = res->ai_family;
+ if (msg_verbose) {
+ MAI_HOSTADDR_STR hostaddr_str;
+ MAI_SERVPORT_STR servport_str;
+
+ SOCKADDR_TO_HOSTADDR((struct sockaddr *) &sa, sa_len,
+ &hostaddr_str, &servport_str, 0);
+ msg_info("%s: sending to: {%s, %s}",
+ myname, hostaddr_str.buf, servport_str.buf);
+ }
}
- if ((int) hp->h_length > (int) sizeof(sin.sin_addr)) {
- msg_warn("bad address size %d for localhost", hp->h_length);
+ freeaddrinfo(res0);
+ if (!found)
return;
- }
- sin.sin_family = hp->h_addrtype;
- sin.sin_port = sp->s_port;
- memcpy((void *) &sin.sin_addr, hp->h_addr_list[0], hp->h_length);
}
/*
* Open a socket, or re-use an existing one.
*/
if (sock < 0) {
- if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ if ((sock = socket(sa_family, sock_type, 0)) < 0) {
msg_warn("socket: %m");
return;
}
/*
* Biff!
*/
- if (sendto(sock, text, len, 0, (struct sockaddr *) &sin, sizeof(sin)) != len)
+ if (sendto(sock, text, len, 0, (struct sockaddr *) &sa, sa_len) != len)
msg_warn("biff_notify: %m");
}
master_ent.o: ../../include/vstream.h
master_ent.o: ../../include/vstring.h
master_ent.o: ../../include/wildcard_inet_addr.h
+master_ent.o: ../../include/wrap_netdb.h
master_ent.o: master.h
master_ent.o: master_ent.c
master_ent.o: master_proto.h
master_listen.o: ../../include/sys_defs.h
master_listen.o: ../../include/vbuf.h
master_listen.o: ../../include/vstring.h
+master_listen.o: ../../include/wrap_netdb.h
master_listen.o: master.h
master_listen.o: master_listen.c
master_monitor.o: ../../include/iostuff.h
postconf_other.o: ../../include/vbuf.h
postconf_other.o: ../../include/vstream.h
postconf_other.o: ../../include/vstring.h
+postconf_other.o: ../../include/wrap_netdb.h
postconf_other.o: ../../include/xsasl.h
postconf_other.o: postconf.h
postconf_other.o: postconf_other.c
--- /dev/null
+../../.indent.pro
\ No newline at end of file
postscreen.o: ../../include/vbuf.h
postscreen.o: ../../include/vstream.h
postscreen.o: ../../include/vstring.h
+postscreen.o: ../../include/wrap_netdb.h
postscreen.o: postscreen.c
postscreen.o: postscreen.h
postscreen_dict.o: ../../include/addr_match_list.h
postscreen_dict.o: ../../include/vbuf.h
postscreen_dict.o: ../../include/vstream.h
postscreen_dict.o: ../../include/vstring.h
+postscreen_dict.o: ../../include/wrap_netdb.h
postscreen_dict.o: postscreen.h
postscreen_dict.o: postscreen_dict.c
postscreen_dnsbl.o: ../../include/addr_match_list.h
postscreen_dnsbl.o: ../../include/vbuf.h
postscreen_dnsbl.o: ../../include/vstream.h
postscreen_dnsbl.o: ../../include/vstring.h
+postscreen_dnsbl.o: ../../include/wrap_netdb.h
postscreen_dnsbl.o: postscreen.h
postscreen_dnsbl.o: postscreen_dnsbl.c
postscreen_early.o: ../../include/addr_match_list.h
postscreen_early.o: ../../include/vbuf.h
postscreen_early.o: ../../include/vstream.h
postscreen_early.o: ../../include/vstring.h
+postscreen_early.o: ../../include/wrap_netdb.h
postscreen_early.o: postscreen.h
postscreen_early.o: postscreen_early.c
postscreen_endpt.o: ../../include/addr_match_list.h
postscreen_endpt.o: ../../include/vbuf.h
postscreen_endpt.o: ../../include/vstream.h
postscreen_endpt.o: ../../include/vstring.h
+postscreen_endpt.o: ../../include/wrap_netdb.h
postscreen_endpt.o: postscreen.h
postscreen_endpt.o: postscreen_endpt.c
postscreen_endpt.o: postscreen_haproxy.h
postscreen_expand.o: ../../include/vbuf.h
postscreen_expand.o: ../../include/vstream.h
postscreen_expand.o: ../../include/vstring.h
+postscreen_expand.o: ../../include/wrap_netdb.h
postscreen_expand.o: postscreen.h
postscreen_expand.o: postscreen_expand.c
postscreen_haproxy.o: ../../include/addr_match_list.h
postscreen_haproxy.o: ../../include/vbuf.h
postscreen_haproxy.o: ../../include/vstream.h
postscreen_haproxy.o: ../../include/vstring.h
+postscreen_haproxy.o: ../../include/wrap_netdb.h
postscreen_haproxy.o: postscreen.h
postscreen_haproxy.o: postscreen_haproxy.c
postscreen_haproxy.o: postscreen_haproxy.h
postscreen_misc.o: ../../include/vbuf.h
postscreen_misc.o: ../../include/vstream.h
postscreen_misc.o: ../../include/vstring.h
+postscreen_misc.o: ../../include/wrap_netdb.h
postscreen_misc.o: postscreen.h
postscreen_misc.o: postscreen_misc.c
postscreen_send.o: ../../include/addr_match_list.h
postscreen_send.o: ../../include/vbuf.h
postscreen_send.o: ../../include/vstream.h
postscreen_send.o: ../../include/vstring.h
+postscreen_send.o: ../../include/wrap_netdb.h
postscreen_send.o: postscreen.h
postscreen_send.o: postscreen_send.c
postscreen_smtpd.o: ../../include/addr_match_list.h
postscreen_smtpd.o: ../../include/vbuf.h
postscreen_smtpd.o: ../../include/vstream.h
postscreen_smtpd.o: ../../include/vstring.h
+postscreen_smtpd.o: ../../include/wrap_netdb.h
postscreen_smtpd.o: postscreen.h
postscreen_smtpd.o: postscreen_smtpd.c
postscreen_starttls.o: ../../include/addr_match_list.h
postscreen_starttls.o: ../../include/vbuf.h
postscreen_starttls.o: ../../include/vstream.h
postscreen_starttls.o: ../../include/vstring.h
+postscreen_starttls.o: ../../include/wrap_netdb.h
postscreen_starttls.o: postscreen.h
postscreen_starttls.o: postscreen_starttls.c
postscreen_state.o: ../../include/addr_match_list.h
postscreen_state.o: ../../include/vbuf.h
postscreen_state.o: ../../include/vstream.h
postscreen_state.o: ../../include/vstring.h
+postscreen_state.o: ../../include/wrap_netdb.h
postscreen_state.o: postscreen.h
postscreen_state.o: postscreen_state.c
postscreen_tests.o: ../../include/addr_match_list.h
postscreen_tests.o: ../../include/vbuf.h
postscreen_tests.o: ../../include/vstream.h
postscreen_tests.o: ../../include/vstring.h
+postscreen_tests.o: ../../include/wrap_netdb.h
postscreen_tests.o: postscreen.h
postscreen_tests.o: postscreen_tests.c
posttls-finger.o: ../../include/vstream.h
posttls-finger.o: ../../include/vstring.h
posttls-finger.o: ../../include/vstring_vstream.h
+posttls-finger.o: ../../include/wrap_netdb.h
posttls-finger.o: posttls-finger.c
posttls-finger.o: tlsmgrmem.h
tlsmgrmem.o: ../../include/argv.h
--- /dev/null
+../../.indent.pro
\ No newline at end of file
--- /dev/null
+SHELL = /bin/sh
+SRCS = ptest_ctx.c ptest_error.c ptest_log.c pmock_expect.c ptest_run.c
+LIB_OBJ = ptest_ctx.o ptest_error.o ptest_log.o pmock_expect.o ptest_run.o
+TEST_OBJ = pmock_expect_test.o ptest_log_test.o
+HDRS = ptest.h pmock_expect.h ptest_main.h
+TESTSRC =
+DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
+CFLAGS = $(DEBUG) $(OPT) $(DEFS)
+INCL =
+LIB = libptest.a
+TESTPROG= pmock_expect_test ptest_log_test
+
+LIBS = ../../lib/lib$(LIB_PREFIX)global$(LIB_SUFFIX) \
+ ../../lib/lib$(LIB_PREFIX)util$(LIB_SUFFIX)
+LIB_DIR = ../../lib
+INC_DIR = ../../include
+MAKES =
+
+.c.o:; $(CC) $(SHLIB_CFLAGS) $(CFLAGS) -c $*.c
+
+all: $(LIB_OBJ) $(MOCK_OBJ)
+
+$(LIB_OBJ) $(TEST_OBJ): ../../conf/makedefs.out
+
+Makefile: Makefile.in
+ cat ../../conf/makedefs.out $? >$@
+
+test: $(TESTPROG)
+
+$(LIB): $(LIB_OBJ)
+ $(_AR) $(ARFL) $(LIB) $?
+ $(_RANLIB) $(LIB)
+
+$(LIB_DIR)/$(LIB): $(LIB)
+ cp $(LIB) $(LIB_DIR)
+ $(_RANLIB) $(LIB_DIR)/$(LIB)
+
+update: $(LIB_DIR)/$(LIB) $(HDRS) $(MOCK_OBJ)
+ -for i in $(HDRS); \
+ do \
+ cmp -s $$i $(INC_DIR)/$$i 2>/dev/null || cp $$i $(INC_DIR); \
+ done
+ (cd $(INC_DIR); chmod 644 $(HDRS))
+ -for i in $(MOCK_OBJ); \
+ do \
+ cmp -s $$i $(LIB_DIR)/$$i 2>/dev/null || cp $$i $(LIB_DIR); \
+ done
+
+clean:
+ rm -f *.o $(LIB) *core $(TESTPROG) junk $(MAKES) *.tmp
+
+tidy: clean
+
+tests: test_pmock_expect test_ptest_log
+
+pmock_expect_test: pmock_expect_test.o $(LIB) $(LIBS)
+ $(CC) $(CFLAGS) -o $@ $@.o $(LIB) $(LIBS) $(SYSLIBS)
+
+test_pmock_expect: update pmock_expect_test
+ $(SHLIB_ENV) ${VALGRIND} ./pmock_expect_test
+
+ptest_log_test: ptest_log_test.o ptest_log.o $(LIB) $(LIBS)
+ $(CC) $(CFLAGS) -o $@ $@.o ptest_log.o $(LIB) $(LIBS) $(SYSLIBS)
+
+test_ptest_log: update ptest_log_test
+ $(SHLIB_ENV) ${VALGRIND} ./ptest_log_test
+
+depend: $(MAKES)
+ (sed '1,/^# do not edit/!d' Makefile.in; \
+ set -e; for i in [a-z][a-z0-9]*.c; do \
+ $(CC) -E $(DEFS) $(INCL) $$i | grep -v '[<>]' | sed -n -e '/^# *1 *"\([^"]*\)".*/{' \
+ -e 's//'`echo $$i|sed 's/c$$/o/'`': \1/' \
+ -e 's/o: \.\//o: /' -e p -e '}' ; \
+ done | LANG=C sort -u) | grep -v '[.][o][:][ ][/]' >$$$$ && mv $$$$ Makefile.in
+ @$(EXPORT) make -f Makefile.in Makefile 1>&2
+
+# do not edit below this line - it is generated by 'make depend'
+pmock_expect.o: ../../include/argv.h
+pmock_expect.o: ../../include/check_arg.h
+pmock_expect.o: ../../include/htable.h
+pmock_expect.o: ../../include/msg.h
+pmock_expect.o: ../../include/mymalloc.h
+pmock_expect.o: ../../include/sys_defs.h
+pmock_expect.o: ../../include/vbuf.h
+pmock_expect.o: ../../include/vstream.h
+pmock_expect.o: ../../include/vstring.h
+pmock_expect.o: pmock_expect.c
+pmock_expect.o: pmock_expect.h
+pmock_expect.o: ptest.h
+pmock_expect_test.o: ../../include/argv.h
+pmock_expect_test.o: ../../include/check_arg.h
+pmock_expect_test.o: ../../include/msg.h
+pmock_expect_test.o: ../../include/msg_output.h
+pmock_expect_test.o: ../../include/msg_vstream.h
+pmock_expect_test.o: ../../include/mymalloc.h
+pmock_expect_test.o: ../../include/stringops.h
+pmock_expect_test.o: ../../include/sys_defs.h
+pmock_expect_test.o: ../../include/vbuf.h
+pmock_expect_test.o: ../../include/vstream.h
+pmock_expect_test.o: ../../include/vstring.h
+pmock_expect_test.o: pmock_expect.h
+pmock_expect_test.o: pmock_expect_test.c
+pmock_expect_test.o: ptest.h
+pmock_expect_test.o: ptest_main.h
+ptest_ctx.o: ../../include/argv.h
+ptest_ctx.o: ../../include/check_arg.h
+ptest_ctx.o: ../../include/msg.h
+ptest_ctx.o: ../../include/mymalloc.h
+ptest_ctx.o: ../../include/stringops.h
+ptest_ctx.o: ../../include/sys_defs.h
+ptest_ctx.o: ../../include/vbuf.h
+ptest_ctx.o: ../../include/vstream.h
+ptest_ctx.o: ../../include/vstring.h
+ptest_ctx.o: ptest.h
+ptest_ctx.o: ptest_ctx.c
+ptest_error.o: ../../include/argv.h
+ptest_error.o: ../../include/check_arg.h
+ptest_error.o: ../../include/msg.h
+ptest_error.o: ../../include/mymalloc.h
+ptest_error.o: ../../include/sys_defs.h
+ptest_error.o: ../../include/vbuf.h
+ptest_error.o: ../../include/vstream.h
+ptest_error.o: ../../include/vstring.h
+ptest_error.o: ptest.h
+ptest_error.o: ptest_error.c
+ptest_log.o: ../../include/argv.h
+ptest_log.o: ../../include/check_arg.h
+ptest_log.o: ../../include/msg.h
+ptest_log.o: ../../include/msg_output.h
+ptest_log.o: ../../include/sys_defs.h
+ptest_log.o: ../../include/vbuf.h
+ptest_log.o: ../../include/vstream.h
+ptest_log.o: ../../include/vstring.h
+ptest_log.o: ptest.h
+ptest_log.o: ptest_log.c
+ptest_log_test.o: ../../include/argv.h
+ptest_log_test.o: ../../include/check_arg.h
+ptest_log_test.o: ../../include/msg.h
+ptest_log_test.o: ../../include/msg_output.h
+ptest_log_test.o: ../../include/msg_vstream.h
+ptest_log_test.o: ../../include/stringops.h
+ptest_log_test.o: ../../include/sys_defs.h
+ptest_log_test.o: ../../include/vbuf.h
+ptest_log_test.o: ../../include/vstream.h
+ptest_log_test.o: ../../include/vstring.h
+ptest_log_test.o: pmock_expect.h
+ptest_log_test.o: ptest.h
+ptest_log_test.o: ptest_log_test.c
+ptest_log_test.o: ptest_main.h
+ptest_run.o: ../../include/argv.h
+ptest_run.o: ../../include/check_arg.h
+ptest_run.o: ../../include/msg.h
+ptest_run.o: ../../include/msg_vstream.h
+ptest_run.o: ../../include/sys_defs.h
+ptest_run.o: ../../include/vbuf.h
+ptest_run.o: ../../include/vstream.h
+ptest_run.o: ../../include/vstring.h
+ptest_run.o: pmock_expect.h
+ptest_run.o: ptest.h
+ptest_run.o: ptest_run.c
--- /dev/null
+/*++
+/* NAME
+/* pmock_expect 3h
+/* SUMMARY
+/* mock support for hermetic tests
+/* SYNOPSIS
+/* #include <pmock_expect.h>
+/*
+/* MOCK_EXPECT *pmock_expect_create(
+/* const MOCK_APPL_SIG *sig,
+/* const char *file,
+/* int line,
+/* int calls_expected,
+/* ssize_t size)
+/*
+/* int pmock_expect_apply(
+/* const MOCK_APPL_SIG *sig,
+/* const MOCK_EXPECT *inputs,
+/* void *targets)
+/*
+/* void pmock_expect_free(MOCK_EXPECT *me)
+/*
+/* void pmock_expect_wrapup(PTEST_CTX *t)
+/* DESCRIPTION
+/* This module provides support to implement mock functions
+/* that emulate real functions with the same name, but that
+/* respond to calls with prepared outputs. This requires that
+/* the real function has the "MOCKABLE" annotation.
+/*
+/* For a simple example, see the pmock_expect_test.c file.
+/*
+/* pmock_expect_create() creates an expectation for calls into
+/* a mock function (whose details are given with the MOCK_APPL_SIG
+/* argument). pmock_expect_create() initializes the generic
+/* expectation fields (file name, line number, and number of
+/* calls), and appends the resulting object to a dedicated
+/* list for the user-defined mock function. The pmock_expect_create()
+/* caller must save deep copies of the expected inputs and
+/* prepared outputs.
+/*
+/* pmock_expect_apply() takes an inputs argument with mock call
+/* inputs, and looks up a matching expectation. If a match is
+/* found, and if its call count isn't already saturated,
+/* pmock_expect_apply() uses the targets argument to update the
+/* mock call outputs.
+/*
+/* pmock_expect_wrapup() reports unused expectations, and
+/* destroys all expectations. Subsequent calls of this function
+/* do nothing.
+/* DIAGNOSTICS
+/* pmock_expect_apply() returns 'true' when a match is found
+/* and the match is not saturated. Otherwise, it returns 'false'
+/* after generating a "too many calls" or "unexpected call"
+/* error. If that error is expected (with expect_ptest_error()),
+/* then it is ignored (not reported) and it will not count as
+/* a test failure.
+/*
+/* pmock_expect_wrapup() logs a warning when some expectation
+/* has not been used.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+
+ /*
+ * Utility library.
+ */
+#include <mymalloc.h>
+#include <htable.h>
+
+ /*
+ * Testing library.
+ */
+#include <pmock_expect.h>
+#include <ptest.h>
+
+ /*
+ * Private structure with all expectations for a single mock application.
+ */
+typedef struct MOCK_APPL {
+ const MOCK_APPL_SIG *sig; /* application-specific */
+ MOCK_EXPECT *head; /* first expectation */
+ MOCK_EXPECT *tail; /* last expectation */
+} MOCK_APPL;
+
+ /*
+ * Collection of MOCK_APPL instances indexed by application name.
+ */
+static HTABLE *mock_appl_list;
+
+/* mock_appl_create - create empty list for same-type expectations */
+
+static MOCK_APPL *mock_appl_create(const MOCK_APPL_SIG *sig)
+{
+ MOCK_APPL *ma;
+
+ /*
+ * Initialize self.
+ */
+ ma = (MOCK_APPL *) mymalloc(sizeof(*ma));
+ ma->sig = sig;
+ ma->head = ma->tail = 0;
+ return (ma);
+}
+
+/* mock_appl_list_free - destroy application node */
+
+static void mock_appl_list_free(MOCK_APPL *ma)
+{
+ myfree(ma);
+}
+
+/* pmock_expect_create - create one mock expectation */
+
+MOCK_EXPECT *pmock_expect_create(const MOCK_APPL_SIG *sig, const char *file,
+ int line, int calls_expected,
+ ssize_t size)
+{
+ MOCK_APPL *ma;
+ MOCK_EXPECT *me;
+
+ /*
+ * Look up or instantiate the expectation for this mock application.
+ */
+ if (mock_appl_list == 0)
+ mock_appl_list = htable_create(13);
+ if ((ma = (MOCK_APPL *) htable_find(mock_appl_list, sig->name)) == 0) {
+ ma = mock_appl_create(sig);
+ (void) htable_enter(mock_appl_list, sig->name, (void *) ma);
+ }
+
+ /*
+ * Initialize the generic expectation fields.
+ */
+ me = (MOCK_EXPECT *) mymalloc(size);
+ me->file = mystrdup(file);
+ me->line = line;
+ me->calls_expected = calls_expected;
+ me->calls_made = 0;
+ me->next = 0;
+
+ /*
+ * Append the new expectation to this mock application list.
+ */
+ if (ma->head == 0)
+ ma->head = me;
+ else
+ ma->tail->next = me;
+ ma->tail = me;
+
+ /*
+ * Let the caller fill in their application-specific fields.
+ */
+ return (me);
+}
+
+/* pmock_expect_free - destroy one expectation node */
+
+void pmock_expect_free(MOCK_EXPECT *me)
+{
+ myfree(me->file);
+ myfree(me);
+}
+
+/* pmock_expect_apply - match inputs and apply outputs */
+
+int pmock_expect_apply(const MOCK_APPL_SIG *sig,
+ const MOCK_EXPECT *inputs,
+ void *targets)
+{
+ MOCK_APPL *ma;
+ MOCK_EXPECT *me;
+ MOCK_EXPECT *saturated = 0; /* saturated expectation */
+ VSTRING *buf;
+ PTEST_CTX *t;
+
+ /*
+ * Look up the mock application list.
+ */
+ if (mock_appl_list != 0 && (ma = (MOCK_APPL *)
+ htable_find(mock_appl_list, sig->name)) != 0) {
+
+ /*
+ * Look for an expectation match that is not saturated. Remember the
+ * last saturated match.
+ */
+ for (me = ma->head; me != 0; me = me->next) {
+ const MOCK_APPL_SIG *sig = ma->sig;
+
+ if (sig->match_expect == 0 || sig->match_expect(me, inputs)) {
+ if (me->calls_expected == 0
+ || me->calls_made < me->calls_expected) {
+ if (sig->assign_expect)
+ sig->assign_expect(me, targets);
+ me->calls_made += 1;
+ return (1);
+ } else {
+ saturated = me;
+ }
+ }
+ }
+ }
+
+ /*
+ * Report a saturated or unmatched expectation.
+ */
+ buf = vstring_alloc(100);
+ t = ptest_ctx_current();
+ if (saturated != 0) {
+ ptest_error(t, "%s:%d too many calls: %s(%s)",
+ saturated->file, saturated->line, sig->name,
+ sig->print_expect(saturated, buf));
+ } else {
+ ptest_error(t, "unexpected call: %s(%s)", sig->name,
+ sig->print_expect(inputs, buf));
+ }
+ vstring_free(buf);
+ return (0);
+}
+
+/* pmock_expect_wrapup - report unused expectations and clean up */
+
+void pmock_expect_wrapup(PTEST_CTX *t)
+{
+ HTABLE_INFO **info, **ht;
+ MOCK_APPL *ma;
+ MOCK_EXPECT *me, *next_me;
+ VSTRING *buf = 0;
+ const char *plural[] = {"", "s"};
+
+ /*
+ * Iterate over each mock application.
+ *
+ * NOTE: do not call ptest_fatal(). This code runs after the test has
+ * completed.
+ */
+ if (mock_appl_list != 0) {
+ info = htable_list(mock_appl_list);
+ for (ht = info; *ht; ht++) {
+ ma = (MOCK_APPL *) ht[0]->value;
+
+ /*
+ * Iterate over each expectation.
+ */
+ for (me = ma->head; me != 0; me = next_me) {
+ next_me = me->next;
+ if (me->calls_expected > 0
+ && me->calls_expected > me->calls_made) {
+ ma->sig->print_expect(me, buf ? buf :
+ (buf = vstring_alloc(100)));
+ ptest_error(t, "%s:%d got %d call%s for %s(%s), want %d",
+ me->file, me->line, me->calls_made,
+ plural[me->calls_made != 1],
+ ma->sig->name, vstring_str(buf),
+ me->calls_expected);
+ } else if (me->calls_made == 0) {
+ ma->sig->print_expect(me, buf ? buf :
+ (buf = vstring_alloc(100)));
+ ptest_error(t, "%s:%d got 0 calls for %s(%s), want 1 or more",
+ me->file, me->line, ma->sig->name,
+ vstring_str(buf));
+ }
+ ma->sig->free_expect(me);
+ }
+ htable_delete(mock_appl_list, ma->sig->name, (void (*) (void *)) 0);
+ mock_appl_list_free(ma);
+ }
+ if (buf)
+ vstring_free(buf);
+ myfree(info);
+ }
+ if (mock_appl_list != 0 && mock_appl_list->used != 0)
+ ptest_error(t, "pmock_expect_wrapup: mock_appl_list->used is %ld",
+ (long) mock_appl_list->used);
+}
--- /dev/null
+#ifndef _PMOCK_EXPECT_H_INCLUDED_
+#define _PMOCK_EXPECT_H_INCLUDED_
+
+/*++
+/* NAME
+/* pmock_expect 3h
+/* SUMMARY
+/* mock test support
+/* SYNOPSIS
+/* #include <pmock_expect.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * Utility library.
+ */
+#include <vstring.h>
+
+ /*
+ * Test library.
+ */
+#include <ptest.h>
+
+ /*
+ * Generic MOCK expectation parent class. Real mock applications will
+ * subclass this, and add their own application-specific fields with
+ * expected inputs and prepared outputs.
+ */
+typedef struct MOCK_EXPECT {
+ char *file; /* __FILE__ */
+ int line; /* __LINE__ */
+ int calls_expected; /* expected count */
+ int calls_made; /* actual count */
+ struct MOCK_EXPECT *next; /* linkage */
+} MOCK_EXPECT;
+
+ /*
+ * Application signature with MOCK_EXPECT generic utility functions.
+ */
+typedef int (*MOCK_EXPECT_MATCH_FN) (const MOCK_EXPECT *, const MOCK_EXPECT *);
+typedef void (*MOCK_EXPECT_ASSIGN_FN) (const MOCK_EXPECT *, void *);
+typedef char *(*MOCK_EXPECT_PRNT_FN) (const MOCK_EXPECT *, VSTRING *);
+typedef void (*MOCK_EXPECT_FREE_FN) (MOCK_EXPECT *);
+
+ /*
+ * Common information for all expectations of a specific mock application.
+ */
+typedef struct MOCK_APPL_SIG {
+ const char *name; /* application sans mock_ prefix */
+ MOCK_EXPECT_MATCH_FN match_expect; /* match expectation inputs */
+ MOCK_EXPECT_ASSIGN_FN assign_expect;/* assign expectation outputs */
+ MOCK_EXPECT_PRNT_FN print_expect; /* print call or expectation */
+ MOCK_EXPECT_FREE_FN free_expect; /* destruct expectation */
+} MOCK_APPL_SIG;
+
+extern MOCK_EXPECT *pmock_expect_create(const MOCK_APPL_SIG *, const char *file,
+ int line, int calls_expected,
+ ssize_t);
+extern int pmock_expect_apply(const MOCK_APPL_SIG *, const MOCK_EXPECT *, void *);
+extern void pmock_expect_free(MOCK_EXPECT *);
+
+ /*
+ * Report unused expectations and destroy all evidence and expectations.
+ */
+extern void pmock_expect_wrapup(PTEST_CTX *);
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+#endif
--- /dev/null
+ /*
+ * This file contains two parts.
+ *
+ * 1 - A trivial mock function, including code to set up expectations and to
+ * respond to calls.
+ *
+ * 2 - Test cases that exercise this mock function and the mock support
+ * infrastructure.
+ */
+
+ /*
+ * Part 1: This emulates a trivial function:
+ *
+ * int foo(const char *arg_in, char **arg_out)
+ *
+ * When the mock foo() function is called with an arg_in value that matches an
+ * expected input (see below) then the mock foo() function stores a prepared
+ * value through the arg_out argument, and returns a prepared function
+ * result value.
+ *
+ * The prepared response an result are set up with:
+ *
+ * void expect_foo(const char *file, int line, int calls_expected, int retval,
+ * const char *arg_in, const char *arg_out)
+ *
+ * This saves deep copies of arg_in and arg_out, and the result value in
+ * retval. The file name and line number are used to improve warning
+ * messages; typically these are specified at the call site with __FILE__
+ * and __LINE__.
+ *
+ * The code below provides mock-specific helpers that match inputs against an
+ * expectation and that output prepared responses. These are called by the
+ * mock support infrastructure as needed.
+ */
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <stdlib.h>
+#include <string.h>
+
+ /*
+ * Utility library.
+ */
+#include <msg.h>
+
+ /*
+ * Test library.
+ */
+#include <mymalloc.h>
+#include <pmock_expect.h>
+#include <ptest.h>
+
+ /*
+ * Deep copies of expected inputs and prepared outputs specified in an
+ * 'expect_foo' call. This structure will also be used to capture shallow
+ * copies of inputs for a 'foo' call.
+ */
+struct foo_expectation {
+ MOCK_EXPECT mock_expect; /* generic fields */
+ char *arg_in; /* input arguments */
+ int retval; /* result value */
+ char *arg_out; /* output argument */
+};
+
+ /*
+ * Pointers to the outputs for a 'foo' call.
+ */
+struct foo_targets {
+ char **arg_out; /* output argument pointer */
+ int *retval; /* result value pointer */
+};
+
+/* match_foo - match inputs against expectation */
+
+static int match_foo(const MOCK_EXPECT *expect, const MOCK_EXPECT *inputs)
+{
+ struct foo_expectation *pe = (struct foo_expectation *) expect;
+ struct foo_expectation *pi = (struct foo_expectation *) inputs;
+
+ return (strcmp(pe->arg_in, pi->arg_in) == 0);
+}
+
+/* assign_foo - assign expected output */
+
+static void assign_foo(const MOCK_EXPECT *expect, void *targets)
+{
+ struct foo_expectation *pe = (struct foo_expectation *) expect;
+ struct foo_targets *pt = (struct foo_targets *) targets;
+
+ *(pt->arg_out) = mystrdup(pe->arg_out);
+ *(pt->retval) = pe->retval;
+}
+
+/* print_foo - print expected inputs */
+
+static char *print_foo(const MOCK_EXPECT *expect, VSTRING *buf)
+{
+ struct foo_expectation *pe = (struct foo_expectation *) expect;
+
+ vstring_sprintf(buf, "%s", pe->arg_in);
+ return (vstring_str(buf));
+}
+
+/* free_foo - destructor */
+
+static void free_foo(MOCK_EXPECT *expect)
+{
+ struct foo_expectation *pe = (struct foo_expectation *) expect;
+
+ if (pe->arg_in)
+ myfree(pe->arg_in);
+ if (pe->arg_out)
+ myfree(pe->arg_out);
+ pmock_expect_free(expect);
+}
+
+ /*
+ * The mock name and its helper callbacks in one place.
+ */
+static const MOCK_APPL_SIG foo_sig = {
+ "foo",
+ match_foo,
+ assign_foo,
+ print_foo,
+ free_foo,
+};
+
+/* expect_foo - set up expectation */
+
+static void expect_foo(const char *file, int line, int calls_expected,
+ int retval, const char *arg_in,
+ const char *arg_out)
+{
+ struct foo_expectation *pe;
+
+ pe = (struct foo_expectation *)
+ pmock_expect_create(&foo_sig, file, line, calls_expected, sizeof(*pe));
+ pe->arg_in = mystrdup(arg_in);
+ pe->retval = retval;
+ pe->arg_out = mystrdup(arg_out);
+}
+
+/* foo - mock foo */
+
+static int foo(const char *arg_in, char **arg_out)
+{
+ struct foo_expectation inputs;
+ struct foo_targets targets;
+ int retval = -1;
+
+ /*
+ * Bundle the arguments to simplify handling.
+ */
+ inputs.arg_in = (char *) arg_in;
+ targets.arg_out = arg_out;
+ targets.retval = &retval;
+
+ /*
+ * TODO: bail out if there was no match?
+ */
+ (void) pmock_expect_apply(&foo_sig, &inputs.mock_expect, (void *) &targets);
+
+ return (retval);
+}
+
+ /*
+ * Part 2: Test cases. See ptest_main.h for a documented example.
+ */
+
+ /*
+ * The ptestcase structure.
+ */
+typedef struct PTEST_CASE {
+ const char *testname; /* Human-readable description */
+ void (*action) (PTEST_CTX *, const struct PTEST_CASE *);
+} PTEST_CASE;
+
+static void test_unused_expectation_1_of_2(PTEST_CTX *t,
+ const PTEST_CASE *unused)
+{
+ const char *want_arg_out = "output";
+ char *got_arg_out = 0;
+ int got_retval, want_retval = 42;
+
+ /*
+ * Set up an expectation for two calls, but intentionally make only one.
+ */
+ expect_foo(__FILE__, __LINE__, 2, want_retval, "input", want_arg_out);
+ got_retval = foo("input", &got_arg_out);
+ if (got_arg_out == 0 || strcmp(got_arg_out, want_arg_out) != 0) {
+ ptest_error(t, "foo: got '%s', want '%s'",
+ got_arg_out ? got_arg_out : "(null)", want_arg_out);
+ } else if (got_retval != want_retval) {
+ ptest_error(t, "foo: got retval %d, want %d", got_retval, want_retval);
+ }
+
+ /*
+ * This error is intentional. Do not count as a failure. The error will
+ * be logged after this test terminates.
+ */
+ expect_ptest_error(t, " got 1 call for foo(input), want 2");
+
+ /*
+ * Cleanup.
+ */
+ if (got_arg_out)
+ myfree(got_arg_out);
+}
+
+static void test_unused_expectation_0_of_0_1(PTEST_CTX *t,
+ const PTEST_CASE *unused)
+{
+ int want_retval = 42;
+
+ /*
+ * Give each expectation a unique line number. Here, we make zero calls
+ * while expecting exactly one call, or one or more calls.
+ */
+ expect_foo(__FILE__, __LINE__, 1, want_retval, "input", "output");
+ expect_foo(__FILE__, __LINE__, 0, want_retval, "input", "output");
+
+ /*
+ * These errors are intentional. Do not count as a failure.
+ */
+ expect_ptest_error(t, " got 0 calls for foo(input), want 1 or more");
+ expect_ptest_error(t, " got 0 calls for foo(input), want 1");
+}
+
+ /*
+ * Test cases. The "success" calls exercise the expectation match and apply
+ * helpers, and "missing" tests exercise the print helpers. All tests
+ * exercise the expectation free helpers.
+ */
+const PTEST_CASE ptestcases[] = {
+ {
+ "unused expectation 1 of 2", test_unused_expectation_1_of_2,
+ },
+ {
+ "unused expectation 0 of 0-1", test_unused_expectation_0_of_0_1,
+ },
+};
+
+#include <ptest_main.h>
--- /dev/null
+#ifndef _PTEST_H_INCLUDED_
+#define _PTEST_H_INCLUDED_
+
+/*++
+/* NAME
+/* ptest 3h
+/* SUMMARY
+/* run-time test support
+/* SYNOPSIS
+/* #include <ptest.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <setjmp.h>
+
+ /*
+ * Utility library.
+ */
+#include <argv.h>
+#include <msg.h> /* XXX for MSG_JMP_BUF in PTEST_RUN */
+#include <vstream.h>
+#include <vstring.h>
+
+ /*
+ * TODO: factor out, and merge with DICT_JMP_BUF, MSG_JMP_BUF,
+ * SLMDB_JMP_BUF, VSTREAM_JMP_BUF.
+ */
+#ifdef NO_SIGSETJMP
+#define TEST_JMP_BUF jmp_buf
+#define ptest_longjmp(bufp, val) longjmp((bufp)[0], (val))
+#else
+#define TEST_JMP_BUF sigjmp_buf
+#define ptest_longjmp(bufp, val) siglongjmp((bufp)[0], (val))
+#endif
+
+ /*
+ * All run-time test info in one place.
+ */
+typedef void (*PTEST_DEFER_FN) (void *);
+
+#define PTEST_CTX_FLAG_SKIP (1<<0) /* This test is skipped */
+#define PTEST_CTX_FLAG_FAIL (1<<1) /* This test has failed */
+
+typedef struct PTEST_CTX {
+ /* ptest_ctx.c */
+ char *name; /* Null, name, or name/name/... */
+ TEST_JMP_BUF *jbuf; /* Used by ptest_fatal(), msg(3) */
+ struct PTEST_CTX *parent; /* In case tests are nested */
+ int flags; /* See above */
+ /* ptest_run.c */
+ int sub_pass; /* Subtests that passed */
+ int sub_fail; /* Subtests that failed */
+ int sub_skip; /* Subtests that were skipped */
+ PTEST_DEFER_FN defer_fn; /* To be called after test... */
+ void *defer_ctx; /* ...with this argument */
+ /* ptest_error.c */
+ VSTREAM *err_stream; /* Output stream */
+ VSTRING *err_buf; /* Formatting buffer */
+ ARGV *allow_errors; /* Allowed errors */
+ /* ptest_log.c */
+ VSTRING *log_buf; /* Formatting buffer */
+ ARGV *allow_logs; /* Allowed logs */
+} PTEST_CTX;
+
+ /*
+ * ptest_ctx.c
+ */
+extern PTEST_CTX *ptest_ctx_create(const char *, TEST_JMP_BUF *);
+extern PTEST_CTX *ptest_ctx_current(void);
+extern void ptest_ctx_free(PTEST_CTX *);
+
+ /*
+ * ptest_error.c
+ */
+extern void ptest_error_setup(PTEST_CTX *, VSTREAM *);
+extern void expect_ptest_error(PTEST_CTX *, const char *);
+extern void PRINTFLIKE(2, 3) ptest_info(PTEST_CTX *, const char *,...);
+extern void PRINTFLIKE(2, 3) ptest_error(PTEST_CTX *, const char *,...);
+extern NORETURN PRINTFLIKE(2, 3) ptest_fatal(PTEST_CTX *, const char *,...);
+extern int ptest_error_wrapup(PTEST_CTX *);
+
+ /*
+ * ptest_log.c
+ */
+extern void ptest_log_setup(PTEST_CTX *);
+extern void expect_ptest_log_event(PTEST_CTX *, const char *);
+extern void ptest_log_wrapup(PTEST_CTX *);
+
+ /*
+ * ptest_run.c
+ */
+extern void ptest_run_prolog(PTEST_CTX *);
+extern void ptest_run_epilog(PTEST_CTX *, PTEST_CTX *);
+extern NORETURN ptest_skip(PTEST_CTX *);
+extern NORETURN ptest_return(PTEST_CTX *);
+extern void ptest_defer(PTEST_CTX *, PTEST_DEFER_FN, void *);
+
+#define PTEST_RUN(t, test_name, body_in_braces) do { \
+ MSG_JMP_BUF new_buf; \
+ PTEST_CTX *parent = t; \
+ t = ptest_ctx_create((test_name), &new_buf); \
+ ptest_run_prolog(t); \
+ if (msg_setjmp(&new_buf) == 0) { \
+ body_in_braces \
+ } \
+ msg_resetjmp(parent->jbuf); \
+ ptest_run_epilog(t, parent); \
+ ptest_ctx_free(t); \
+ t = parent; \
+} while (0)
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+#endif
--- /dev/null
+/*++
+/* NAME
+/* ptest_ctx 3
+/* SUMMARY
+/* test context support
+/* SYNOPSIS
+/* #include <ptest.h>
+/*
+/* PTEST_CTX ptest_ctx_create(
+/* const char *name,
+/* TEST_JMP_BUF *jbuf)
+/*
+/* PTEST_CTX *ptest_ctx_current(void)
+/*
+/* int ptest_ctx_free(PTEST_CTX *t)
+/* DESCRIPTION
+/* This module manages a stack of contexts that are used by
+/* tests.
+/*
+/* ptest_ctx_create() is called by test infrastructure before
+/* a test is run. It returns an initialized PTEST_CTX object
+/* after making it the current test context. The jbuf argument
+/* references jump buffer that will be used by ptest_fatal(),
+/* msg_fatal() and msg_panic().
+/*
+/* ptest_ctx_current() returns the current test context. This
+/* function exists because mocked functions must be called
+/* without an argument that specifies a test context.
+/*
+/* ptest_ctx_free() is called by test infrastructure after a
+/* test terminates and all error reporting has completed.
+/* It destroys the PTEST_CTX object.
+/* DIAGNOSTICS
+/* ptest_ctx_current() will panic if the test context stack is
+/* empty.
+/*
+/* ptest_ctx_free() will panic if the argument does not specify
+/* the current test context.
+/* SEE ALSO
+/* pmock_expect(3), mock test support
+/* ptest_error(3), test error reporter
+/* ptest_log(3), log receiver
+/* ptest_main(3), test driver
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <setjmp.h>
+
+ /*
+ * Utility library.
+ */
+#include <msg.h>
+#include <mymalloc.h>
+#include <stringops.h>
+#include <vstream.h>
+
+ /*
+ * Test library.
+ */
+#include <ptest.h>
+
+static PTEST_CTX *ptest_ctx_head;
+
+/* ptest_ctx_create - create initialized PTEST_CTX object */
+
+PTEST_CTX *ptest_ctx_create(const char *name, TEST_JMP_BUF *jbuf)
+{
+ PTEST_CTX *parent = ptest_ctx_head;
+ PTEST_CTX *t;
+
+ t = mymalloc(sizeof(*t));
+ if (name == 0) /* main-level context */
+ t->name = 0;
+ else if (parent->name == 0) /* top-level test context */
+ t->name = mystrdup(name);
+ else /* sub test */
+ t->name = concatenate(parent->name, "/", name, (char *) 0);
+ t->jbuf = jbuf;
+ t->parent = parent;
+ t->flags = 0;
+ /* ptest_run.c specific */
+ t->sub_pass = t->sub_fail = t->sub_skip = 0;
+ /* ptest_error.c specific */
+ t->err_stream = 0;
+ t->err_buf = 0;
+ t->allow_errors = 0;
+ /* ptest_log.c specific */
+ t->log_buf = 0;
+ t->allow_logs = 0;
+ /* ptest_defer.c specific */
+ t->defer_fn = 0;
+ t->defer_ctx = 0;
+
+ ptest_ctx_head = t;
+
+ return (t);
+}
+
+/* ptest_ctx_current - return current context or die */
+
+PTEST_CTX *ptest_ctx_current()
+{
+ if (ptest_ctx_head == 0)
+ msg_panic("ptest_ctx_current: no test context");
+ return (ptest_ctx_head);
+}
+
+/* ptest_ctx_free - destroy PTEST_CTX or die */
+
+void ptest_ctx_free(PTEST_CTX *t)
+{
+ if (t != ptest_ctx_head)
+ msg_panic("ptest_ctx_free: wrong test context - "
+ "should you use ptest_return()?");
+ ptest_ctx_head = t->parent;
+ if (t->name)
+ myfree(t->name);
+ myfree((void *) t);
+}
--- /dev/null
+/*++
+/* NAME
+/* ptest_error 3
+/* SUMMARY
+/* test error and non-error support
+/* SYNOPSIS
+/* #include <ptest.h>
+/*
+/* void expect_ptest_error(
+/* PTEST_CTX *t,
+/* const char *text)
+/*
+/* void PRINTFLIKE(2, 3) ptest_info(
+/* PTEST_CTX *t,
+/* const char *, ...)
+/*
+/* void PRINTFLIKE(2, 3) ptest_error(
+/* PTEST_CTX *t,
+/* const char *, ...)
+/*
+/* NORETURN PRINTFLIKE(2, 3) ptest_fatal(
+/* PTEST_CTX *t,
+/* const char *, ...)
+/* TEST INFRASTRUCTURE SUPPORT
+/* PTEST_CTX ptest_error_setup(VSTREAM *err_stream)
+/*
+/* int ptest_error_wrapup(PTEST_CTX *t)
+/* DESCRIPTION
+/* This module manages errors and non-errors that are reported
+/* by tests.
+/*
+/* ptest_info() is called from inside a test, to report a
+/* non-error condition, for example, to report progress.
+/*
+/* ptest_error() is called from inside a test, to report a
+/* non-fatal test error (after the call is finished, the test
+/* will continue). If the error text matches a pattern given
+/* to an earlier expect_ptest_error() call (see below), then
+/* this ptest_error() call will be ignored once, and treated
+/* as a non-error. Otherwise, ptest_error() logs the error and
+/* increments an error count.
+/*
+/* expect_ptest_error() is called from inside a test. It requires
+/* that a ptest_error() call will be made whose formatted text
+/* contains a substring that matches the text argument. For
+/* robustness, do not include file line number information in
+/* the expected text. If the expected ptest_error() call is
+/* made, then that call will be ignored once, and treated as
+/* a non-error (call expect_ptest_error() multiple times to
+/* ignore an error multiple times). If the expected ptest_error()
+/* call is not made, then ptest_error_wrapup() will report an
+/* error and the test will fail.
+/*
+/* ptest_fatal() is called from inside a test. It reports a
+/* fatal test error and increments an error count. A ptest_fatal()
+/* call does not return, instead it terminates the test.
+/* ptest_fatal() calls cannot be expected and ignored with
+/* expect_ptest_error().
+/*
+/* ptest_error_setup() is called by test infrastructure before
+/* a test is run. It updates a PTEST_CTX object. The err_stream
+/* argument specifies the output stream for error reporting.
+/*
+/* ptest_error_wrapup() is called by test infrastructure after
+/* a test terminates. It calls ptest_error() to report any
+/* missing ptest_error() calls, destroys the PTEST_CTX information
+/* that was allocated with ptest_error_setup(), and returns the
+/* final error count.
+/* DIAGNOSTICS
+/* The above functions write to the VSTREAM specified in the
+/* ptest_error_setup() call.
+/* SEE ALSO
+/* pmock_expect(3), mock test support
+/* ptest_main(3h), test driver
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <setjmp.h>
+#include <string.h>
+
+ /*
+ * Utility library.
+ */
+#include <argv.h>
+#include <msg.h>
+#include <mymalloc.h>
+#include <vstream.h>
+#include <vstring.h>
+
+ /*
+ * Test library.
+ */
+#include <ptest.h>
+
+ /*
+ * SLMs.
+ */
+#define STR(x) vstring_str(x)
+
+/* ptest_error_setup - populate PTEST_CTX object */
+
+void ptest_error_setup(PTEST_CTX *t, VSTREAM *err_stream)
+{
+ t->flags &= ~PTEST_CTX_FLAG_FAIL;
+ t->err_stream = err_stream;
+ t->err_buf = vstring_alloc(100);
+ t->allow_errors = argv_alloc(1);
+}
+
+/* expect_ptest_error - require and bless a non-fatal error */
+
+void expect_ptest_error(PTEST_CTX *t, const char *text)
+{
+ argv_add(t->allow_errors, text, (char *) 0);
+}
+
+/* ptest_info - report non-error condition */
+
+void ptest_info(PTEST_CTX *t, const char *fmt,...)
+{
+ va_list ap;
+
+ /*
+ * Format the message.
+ */
+ va_start(ap, fmt);
+ vstream_vfprintf(t->err_stream, fmt, ap);
+ vstream_fprintf(t->err_stream, "\n");
+ va_end(ap);
+ vstream_fflush(t->err_stream);
+}
+
+/* ptest_error - report non-fatal error */
+
+void ptest_error(PTEST_CTX *t, const char *fmt,...)
+{
+ va_list ap;
+ char **cpp;
+
+ /*
+ * Format the message.
+ */
+ va_start(ap, fmt);
+ vstring_vsprintf(t->err_buf, fmt, ap);
+ va_end(ap);
+
+ /*
+ * Skip this error if it was expected.
+ */
+ for (cpp = t->allow_errors->argv; *cpp; cpp++) {
+ if (strstr(STR(t->err_buf), *cpp) != 0) {
+ argv_delete(t->allow_errors, cpp - t->allow_errors->argv, 1);
+ return;
+ }
+ }
+
+ /*
+ * Report the message.
+ */
+ vstream_fprintf(t->err_stream, "error: %s\n", STR(t->err_buf));
+ vstream_fflush(t->err_stream);
+ t->flags |= PTEST_CTX_FLAG_FAIL;
+}
+
+/* ptest_fatal - report fatal error */
+
+NORETURN ptest_fatal(PTEST_CTX *t, const char *fmt,...)
+{
+ va_list ap;
+
+ /*
+ * This has no code in common with ptest_error().
+ */
+ vstream_fprintf(t->err_stream, "fatal: ");
+ va_start(ap, fmt);
+ vstream_vfprintf(t->err_stream, fmt, ap);
+ va_end(ap);
+ vstream_fprintf(t->err_stream, "\n");
+ vstream_fflush(t->err_stream);
+ t->flags |= PTEST_CTX_FLAG_FAIL;
+ ptest_longjmp(t->jbuf, 1);
+}
+
+/* ptest_error_wrapup - enforce error expectations and clean up */
+
+extern int ptest_error_wrapup(PTEST_CTX *t)
+{
+ char **cpp;
+ int fail_flag;
+
+ /*
+ * Report a new error if an expected error did not happen.
+ */
+ for (cpp = t->allow_errors->argv; *cpp; cpp++) {
+ vstream_fprintf(t->err_stream, "Missing error: want '%s'\n", *cpp);
+ t->flags |= PTEST_CTX_FLAG_FAIL;
+ vstream_fflush(t->err_stream);
+ }
+ fail_flag = (t->flags & PTEST_CTX_FLAG_FAIL);
+
+ /*
+ * Clean up the PTEST_CTX fields that we created.
+ */
+ vstring_free(t->err_buf);
+ t->err_buf = 0;
+ argv_free(t->allow_errors);
+ t->flags &= ~PTEST_CTX_FLAG_FAIL;
+ return (fail_flag);
+}
--- /dev/null
+/*++
+/* NAME
+/* ptest_log 3
+/* SUMMARY
+/* log event receiver support
+/* SYNOPSIS
+/* #include <ptest.h>
+/*
+/* void expect_ptest_log_event(
+/* PTEST_CTX *t,
+/* const char *text)
+/* INFRASTRUCTURE SUPPORT
+/* void ptest_log_setup(
+/* PTEST_CTX *t)
+/*
+/* void ptest_log_wrapup(
+/* PTEST_CTX *t)
+/* DESCRIPTION
+/* This module inspects msg(3) logging.
+/*
+/* expect_ptest_log_event() is called from a test. It requires
+/* that an msg(3) call will be made whose formatted text
+/* contains a substring that matches the text argument. For
+/* robustness, do not include file name or line number
+/* information. If a match fails, then the log event receiver
+/* will call ptest_error() to report the unexpected msg(3)
+/* call. If the expected msg(3) call is not made, then
+/* ptest_log_wrapup() will call ptest_error() to report the
+/* missing call.
+/*
+/* ptest_log_setup() is called by testing infrastructure before
+/* a test is started. It updates the PTEST_CTX structure, and
+/* installs an msg(3) log event receiver.
+/*
+/* ptest_log_wrapup() is called by test infrastructure after
+/* a test terminates. It calls ptest_error() to report any
+/* unmatched expect_ptest_log_event() expectations, and destroys
+/* buffers that were created by ptest_log_setup().
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <string.h>
+
+ /*
+ * Utility library.
+ */
+#include <msg.h>
+#include <msg_output.h>
+#include <vstring.h>
+
+ /*
+ * Test library.
+ */
+#include <ptest.h>
+
+ /*
+ * SLMs.
+ */
+#define STR(x) vstring_str(x)
+
+/* ptest_log_event - receive log event */
+
+static void ptest_log_event(int level, const char *text, void *context)
+{
+ static const char *level_text[] = {
+ "info", "warning", "error", "fatal", "panic",
+ };
+ PTEST_CTX *t = (PTEST_CTX *) context;
+ char **cpp;
+
+ /*
+ * Silence events for parent handlers.
+ */
+ if (t != ptest_ctx_current())
+ return;
+
+ /*
+ * Sanity checks.
+ */
+ if (level < 0 || level >= (int) (sizeof(level_text) / sizeof(level_text[0])))
+ msg_panic("ptest_log_event: invalid severity level: %d", level);
+
+ /*
+ * Format the text.
+ */
+ if (level == MSG_INFO) {
+ vstring_sprintf(t->log_buf, "%s", text);
+ } else {
+ vstring_sprintf(t->log_buf, "%s: %s", level_text[level], text);
+ }
+
+ /*
+ * Handle expected versus unexpected text.
+ */
+ for (cpp = t->allow_logs->argv; *cpp; cpp++) {
+ if (strstr(STR(t->log_buf), *cpp) != 0) {
+ argv_delete(t->allow_logs, cpp - t->allow_logs->argv, 1);
+ return;
+ }
+ }
+ ptest_error(t, "Unexpected log event: got '%s'", STR(t->log_buf));
+}
+
+/* ptest_log_setup - install logging receiver */
+
+void ptest_log_setup(PTEST_CTX *t)
+{
+ if (t != ptest_ctx_current())
+ msg_panic("ptest_log_setup: not current context");
+ t->log_buf = vstring_alloc(100);
+ t->allow_logs = argv_alloc(1);
+ msg_output_push(ptest_log_event, (void *) t);
+}
+
+/* expect_ptest_log_event - add log event expectation */
+
+void expect_ptest_log_event(PTEST_CTX *t, const char *text)
+{
+ if (t != ptest_ctx_current())
+ msg_panic("expect_ptest_log_event: not current context");
+ argv_add(t->allow_logs, text, (char *) 0);
+}
+
+/* ptest_log_wrapup - enforce logging expectations */
+
+void ptest_log_wrapup(PTEST_CTX *t)
+{
+ char **cpp;
+
+ msg_output_pop(ptest_log_event, (void *) t);
+ for (cpp = t->allow_logs->argv; *cpp; cpp++)
+ ptest_error(t, "Missing log event: want '%s'", *cpp);
+ vstring_free(t->log_buf);
+ t->log_buf = 0;
+ argv_free(t->allow_logs);
+ t->allow_logs = 0;
+}
--- /dev/null
+ /*
+ * Test program to exercise ptest_log functions including logging. See
+ * comments in ptest_main.h and pmock_expect_test.c for a documented
+ * example.
+ */
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+
+ /*
+ * Test library.
+ */
+#include <ptest.h>
+
+typedef struct PTEST_CASE {
+ const char *testname; /* Human-readable description */
+ void (*action) (PTEST_CTX *t, const struct PTEST_CASE *);
+} PTEST_CASE;
+
+static void ptest_log_non_error(PTEST_CTX *t, const PTEST_CASE *unused)
+{
+ /* This test passes if there is no error. */
+ expect_ptest_log_event(t, "this is a non-error");
+ msg_info("this is a non-error");
+}
+
+static void ptest_log_flags_unexpected_message(PTEST_CTX *t, const PTEST_CASE *unused)
+{
+ expect_ptest_error(t, "this is a forced 'Unexpected log event' error");
+ msg_info("this is a forced 'Unexpected log event' error");
+}
+
+static void ptest_log_flags_missing_message(PTEST_CTX *t, const PTEST_CASE *unused)
+{
+ expect_ptest_error(t, "this is a forced 'Missing log event' error");
+ expect_ptest_log_event(t, "this is a forced 'Missing log event' error");
+}
+
+ /*
+ * Test cases.
+ */
+const PTEST_CASE ptestcases[] = {
+ {
+ "ptest_log_non_error", ptest_log_non_error,
+ },
+ {
+ "ptest_log_flags_unexpected_message", ptest_log_flags_unexpected_message,
+ },
+ {
+ "ptest_log_flags_missing_message", ptest_log_flags_missing_message,
+ },
+};
+
+#include <ptest_main.h>
--- /dev/null
+/*++
+/* NAME
+/* ptest_main 3h
+/* SUMMARY
+/* test driver
+/* DESCRIPTION
+/* This file should be included at the end of a *_test.c file.
+/* It contains a main program and test driver, and supports
+/* programs whether or not they use mocks as defined in
+/* <pmock_expect.h>.
+/*
+/* Before including this file, a *_test.c file should define
+/* the structure and content of its test cases, and the functions
+/* that implement those tests:
+/*
+/* .nf
+/* /* Begin example. */
+/*
+/* #include <ptest.h>
+/* #include <pmock_expect.h>
+/*
+/* /*
+/* * Test case structure. If multiple test functions cannot
+/* * have their test data in a shared PTEST_CASE structure, then
+/* * each test function can define its own test data, and run
+/* * multiple tests with PTEST_RUN(). See documentation in
+/* * ptest_run.c.
+/* */
+/* typedef struct PTEST_CASE {
+/* const char *testname; /* Human-readable description */
+/* void (*action) (PTEST_CTX *, const struct PTEST_CASE *);
+/* /* Optionally, your test data fields... */
+/* } PTEST_CASE;
+/*
+/* /*
+/* * Test functions. These should not use msg_xxx() functions.
+/* *
+/* * To report a test error use ptest_error(t, ...) and to abort a
+/* * test use ptest_fatal(t, ...). Tests with errors will not PASS.
+/* *
+/* * To "expect" a non-fatal error (and not count it as a failure)
+/* * use expect_ptest_error(t, text) where the text is a substring
+/* * of the expected error message.
+/* */
+/*
+/* static void test_abc(PTEST_CTX *t, const PTEST_CASE *tp)
+/* {
+/* int ret;
+/*
+/* want_abc = 42;
+/* got_abc = abc(1, 2, 3);
+/* if (got_abc != want_abc)
+/* ptest_error(t, "abc: got %d, want %d", got_abc, want_abc);
+/* }
+/*
+/* /* More test functions... */
+/*
+/* /* Test cases. Do not terminate with null. */
+/*
+/* const PTEST_CASE ptestcases[] = {
+/* { "test abc", test_abc, ...},
+/* /* More test cases... */
+/* };
+/*
+/* #include <ptest_main.h>
+/*
+/* /* End example. */
+/* .fi
+/*
+/* The <ptest_main.h> test driver iterates over each test case
+/* and invokes the test case's action function with a pointer
+/* to its test case. The test driver captures all logging that
+/* is generated while the test case runs, including logging
+/* from test functions, library functions and from the mock
+/* infrastructure.
+/*
+/* The action function should call ptest_error() or ptest_fatal()
+/* when a test fails. ptest_fatal() terminates a test but does
+/* not terminate the process.
+/*
+/* If the tests use mocks, the mock infrastructure will log
+/* unexpected mock calls, and unused mock call expectations.
+/*
+/* The ptest_log module will log a warning if the captured
+/* logging differs from the expected logging.
+/* SEE ALSO
+/* msg(3) diagnostics
+/* ptest_error(3) test error and non-error handling
+/* ptest_log(3) log event receiver support
+/* BUGS
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <string.h>
+#include <stdlib.h>
+
+ /*
+ * Utility library.
+ */
+#include <msg.h>
+#include <msg_output.h>
+#include <msg_vstream.h>
+#include <stringops.h>
+#include <vstream.h>
+
+ /*
+ * Test library.
+ */
+#include <pmock_expect.h>
+#include <ptest.h>
+
+/* main - test driver */
+
+int main(int argc, char **argv)
+{
+ PTEST_CTX *t;
+ const PTEST_CASE *tp;
+ int fail;
+
+ /*
+ * Send msg(3) logging to stderr by default.
+ */
+ msg_vstream_init(basename(argv[0]), VSTREAM_ERR);
+
+ /*
+ * The main-level PTEST_CTX context has no name and no long jump context.
+ * It's sole purpose is to run tests and to aggregate pass/skip/fail counts.
+ */
+ t = ptest_ctx_create((char *) 0, (MSG_JMP_BUF *) 0);
+
+ /*
+ * Run each test in its own PTEST_CTX context with its own log
+ * interceptor and long jump context. Each test can invoke PTEST_RUN() to
+ * run one or more of subtests in their own context with their own test
+ * data, instead of having to store all test data in a PTEST_CASE
+ * structure.
+ */
+#define NROF(x) (sizeof(x)/sizeof((x)[0]))
+
+ for (tp = ptestcases; tp < ptestcases + NROF(ptestcases); tp++) {
+ if (tp->testname == 0)
+ msg_fatal("Null testname in ptestcases array!");
+ PTEST_RUN(t, tp->testname, {
+ tp->action(t, tp);
+ });
+ }
+ msg_info("PASS: %d, SKIP: %d, FAIL: %d", t->sub_pass, t->sub_skip, fail = t->sub_fail);
+ ptest_ctx_free(t);
+ exit(fail > 0);
+}
--- /dev/null
+/*++
+/* NAME
+/* ptest_run 3h
+/* SUMMARY
+/* test runner
+/* SYNOPSIS
+/* #include <ptest.h>
+/*
+/* void PTEST_RUN(
+/* PTEST_CTX *t,
+/* const char *test_name,
+/* { body_in_braces })
+/*
+/* NORETURN ptest_skip(PTEST_CTX *t)
+/*
+/* NORETURN ptest_return(PTEST_CTX *t)
+/*
+/* void ptest_defer(
+/* PTEST_CTX *t,
+/* void (*defer_fn)(void *)
+/* void *defer_ctx)
+/* DESCRIPTION
+/* PTEST_RUN() is called from inside a test to run a subtest.
+/*
+/* PTEST_RUN() is a macro that runs the { body_in_braces }
+/* with msg(3) logging temporarily redirected to a buffer, and
+/* with panic, fatal, error, and non-error functions that
+/* terminate a test without terminating the process.
+/*
+/* To use this as a subtest inside a PTEST_CASE action:
+/*
+/* .na
+/* static void action(PTEST_CTX *t, const PTEST_CASE *tp)
+/* {
+/* struct subtest {
+/* // ...
+/* };
+/* static const struct subtest tests[] = {
+/* // ...subtest data and expectations...
+/* };
+/* struct subtest *sp;
+/* for (sp = tests; sp < tests + sizeof(tests) / sizeof(tests[0]); sp++) {
+/* PTEST_RUN(t, sp->name, {
+/* // Test code that uses sp->mumble here.
+/* // Use ptest_error(), ptest_fatal(), or ptest_return()
+/* // to report an error or terminate a test, or
+/* // ptest_skip() to skip a test.
+/* });
+/* }
+/* }
+/*
+/* ptest_skip() is called from inside a test. It flags a test
+/* as skipped, and terminates the test without terminating the
+/* process.
+/*
+/* ptest_return() is called from inside a test. It terminates
+/* the test without terminating the process.
+/*
+/* ptest_defer() may be called once from a test, to defer some
+/* processing until after the test completes. This is typically
+/* used to eliminate a resource leak in tests that terminate
+/* the test early (i.e. that return with a long jump).
+/*
+/* To "undo" a ptest_defer() call, call the function with a
+/* null defer_fn argument. Then, it may be called again to
+/* set up deferred execution.
+/* SEE ALSO
+/* pmock_expect(3), mock for hermetic tests
+/* ptest_error(3), test error support
+/* ptest_log(3), logging receiver support
+/* BUGS
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+
+ /*
+ * Utility library.
+ */
+#include <msg.h>
+#include <msg_vstream.h>
+#include <vstream.h>
+
+ /*
+ * Test library.
+ */
+#include <pmock_expect.h>
+#include <ptest.h>
+
+/* ptest_run_prolog - encapsulate PTEST_RUN() dependencies */
+
+void ptest_run_prolog(PTEST_CTX *t)
+{
+ ptest_error_setup(t, VSTREAM_ERR);
+ ptest_info(t, "RUN %s", t->name);
+ ptest_log_setup(t);
+ msg_vstream_enable(0);
+}
+
+/* ptest_run_epilog - encapsulate PTEST_RUN() dependencies */
+
+void ptest_run_epilog(PTEST_CTX *t, PTEST_CTX *parent)
+{
+ msg_vstream_enable(1);
+ ptest_log_wrapup(t);
+ pmock_expect_wrapup(t);
+ if (ptest_error_wrapup(t) != 0 || t->sub_fail != 0) {
+ ptest_info(t, "FAIL %s", t->name);
+ parent->sub_fail += 1;
+ } else if (t->flags & PTEST_CTX_FLAG_SKIP) {
+ ptest_info(t, "SKIP %s", t->name);
+ parent->sub_skip += 1;
+ } else {
+ ptest_info(t, "PASS %s", t->name);
+ parent->sub_pass += 1;
+ }
+ parent->sub_pass += t->sub_pass;
+ parent->sub_fail += t->sub_fail;
+ parent->sub_skip += t->sub_skip;
+ if (t->defer_fn)
+ t->defer_fn(t->defer_ctx);
+}
+
+/* ptest_skip - skip a test and return from test */
+
+NORETURN ptest_skip(PTEST_CTX *t)
+{
+ t->flags |= PTEST_CTX_FLAG_SKIP;
+ ptest_longjmp(t->jbuf, 1);
+}
+
+/* ptest_return - early return from test */
+
+NORETURN ptest_return(PTEST_CTX *t)
+{
+ ptest_longjmp(t->jbuf, 1);
+}
+
+/* ptest_defer - post-test processing */
+
+void ptest_defer(PTEST_CTX *t, PTEST_DEFER_FN defer_fn,
+ void *defer_ctx)
+{
+ if (t->defer_fn && defer_fn)
+ msg_panic("ptest_defer: multiple calls for this test context");
+ t->defer_fn = defer_fn;
+ t->defer_ctx = defer_ctx;
+}
qmqpd_peer.o: ../../include/vbuf.h
qmqpd_peer.o: ../../include/vstream.h
qmqpd_peer.o: ../../include/vstring.h
+qmqpd_peer.o: ../../include/wrap_netdb.h
qmqpd_peer.o: qmqpd.h
qmqpd_peer.o: qmqpd_peer.c
qmqpd_state.o: ../../include/attr.h
smtp.o: ../../include/vbuf.h
smtp.o: ../../include/vstream.h
smtp.o: ../../include/vstring.h
+smtp.o: ../../include/wrap_netdb.h
smtp.o: lmtp_params.c
smtp.o: smtp.c
smtp.o: smtp.h
smtp_addr.o: ../../include/vbuf.h
smtp_addr.o: ../../include/vstream.h
smtp_addr.o: ../../include/vstring.h
+smtp_addr.o: ../../include/wrap_netdb.h
smtp_addr.o: smtp.h
smtp_addr.o: smtp_addr.c
smtp_addr.o: smtp_addr.h
smtp_chat.o: ../../include/vbuf.h
smtp_chat.o: ../../include/vstream.h
smtp_chat.o: ../../include/vstring.h
+smtp_chat.o: ../../include/wrap_netdb.h
smtp_chat.o: smtp.h
smtp_chat.o: smtp_chat.c
smtp_connect.o: ../../include/argv.h
smtp_connect.o: ../../include/vbuf.h
smtp_connect.o: ../../include/vstream.h
smtp_connect.o: ../../include/vstring.h
+smtp_connect.o: ../../include/wrap_netdb.h
smtp_connect.o: smtp.h
smtp_connect.o: smtp_addr.h
smtp_connect.o: smtp_connect.c
smtp_key.o: ../../include/vbuf.h
smtp_key.o: ../../include/vstream.h
smtp_key.o: ../../include/vstring.h
+smtp_key.o: ../../include/wrap_netdb.h
smtp_key.o: smtp.h
smtp_key.o: smtp_key.c
smtp_map11.o: ../../include/argv.h
smtp_map11.o: ../../include/vbuf.h
smtp_map11.o: ../../include/vstream.h
smtp_map11.o: ../../include/vstring.h
+smtp_map11.o: ../../include/wrap_netdb.h
smtp_map11.o: smtp.h
smtp_map11.o: smtp_map11.c
smtp_misc.o: ../../include/argv.h
smtp_misc.o: ../../include/vbuf.h
smtp_misc.o: ../../include/vstream.h
smtp_misc.o: ../../include/vstring.h
+smtp_misc.o: ../../include/wrap_netdb.h
smtp_misc.o: smtp.h
smtp_misc.o: smtp_misc.c
smtp_params.o: smtp_params.c
smtp_proto.o: ../../include/vstream.h
smtp_proto.o: ../../include/vstring.h
smtp_proto.o: ../../include/vstring_vstream.h
+smtp_proto.o: ../../include/wrap_netdb.h
smtp_proto.o: ../../include/xtext.h
smtp_proto.o: smtp.h
smtp_proto.o: smtp_proto.c
smtp_rcpt.o: ../../include/vbuf.h
smtp_rcpt.o: ../../include/vstream.h
smtp_rcpt.o: ../../include/vstring.h
+smtp_rcpt.o: ../../include/wrap_netdb.h
smtp_rcpt.o: smtp.h
smtp_rcpt.o: smtp_rcpt.c
smtp_reuse.o: ../../include/argv.h
smtp_reuse.o: ../../include/vbuf.h
smtp_reuse.o: ../../include/vstream.h
smtp_reuse.o: ../../include/vstring.h
+smtp_reuse.o: ../../include/wrap_netdb.h
smtp_reuse.o: smtp.h
smtp_reuse.o: smtp_reuse.c
smtp_reuse.o: smtp_reuse.h
smtp_sasl_auth_cache.o: ../../include/vbuf.h
smtp_sasl_auth_cache.o: ../../include/vstream.h
smtp_sasl_auth_cache.o: ../../include/vstring.h
+smtp_sasl_auth_cache.o: ../../include/wrap_netdb.h
smtp_sasl_auth_cache.o: smtp.h
smtp_sasl_auth_cache.o: smtp_sasl_auth_cache.c
smtp_sasl_auth_cache.o: smtp_sasl_auth_cache.h
smtp_sasl_glue.o: ../../include/vbuf.h
smtp_sasl_glue.o: ../../include/vstream.h
smtp_sasl_glue.o: ../../include/vstring.h
+smtp_sasl_glue.o: ../../include/wrap_netdb.h
smtp_sasl_glue.o: ../../include/xsasl.h
smtp_sasl_glue.o: smtp.h
smtp_sasl_glue.o: smtp_sasl.h
smtp_sasl_proto.o: ../../include/vbuf.h
smtp_sasl_proto.o: ../../include/vstream.h
smtp_sasl_proto.o: ../../include/vstring.h
+smtp_sasl_proto.o: ../../include/wrap_netdb.h
smtp_sasl_proto.o: smtp.h
smtp_sasl_proto.o: smtp_sasl.h
smtp_sasl_proto.o: smtp_sasl_proto.c
smtp_session.o: ../../include/vbuf.h
smtp_session.o: ../../include/vstream.h
smtp_session.o: ../../include/vstring.h
+smtp_session.o: ../../include/wrap_netdb.h
smtp_session.o: smtp.h
smtp_session.o: smtp_sasl.h
smtp_session.o: smtp_session.c
smtp_state.o: ../../include/vbuf.h
smtp_state.o: ../../include/vstream.h
smtp_state.o: ../../include/vstring.h
+smtp_state.o: ../../include/wrap_netdb.h
smtp_state.o: smtp.h
smtp_state.o: smtp_sasl.h
smtp_state.o: smtp_state.c
smtp_tls_policy.o: ../../include/vbuf.h
smtp_tls_policy.o: ../../include/vstream.h
smtp_tls_policy.o: ../../include/vstring.h
+smtp_tls_policy.o: ../../include/wrap_netdb.h
smtp_tls_policy.o: smtp.h
smtp_tls_policy.o: smtp_tls_policy.c
smtp_trouble.o: ../../include/argv.h
smtp_trouble.o: ../../include/vbuf.h
smtp_trouble.o: ../../include/vstream.h
smtp_trouble.o: ../../include/vstring.h
+smtp_trouble.o: ../../include/wrap_netdb.h
smtp_trouble.o: smtp.h
smtp_trouble.o: smtp_sasl.h
smtp_trouble.o: smtp_trouble.c
smtp_unalias.o: ../../include/vbuf.h
smtp_unalias.o: ../../include/vstream.h
smtp_unalias.o: ../../include/vstring.h
+smtp_unalias.o: ../../include/wrap_netdb.h
smtp_unalias.o: smtp.h
smtp_unalias.o: smtp_unalias.c
/* lookups are done via the Internet domain name service (DNS).
/* A reasonable number of CNAME indirections is permitted. When
/* DNS lookups are disabled, host address lookup is done with
-/* getnameinfo() or gethostbyname().
+/* myaddrinfo(3).
/*
/* smtp_domain_addr() looks up the network addresses for mail
/* exchanger hosts listed for the named domain. Addresses are
smtpd.o: ../../include/vstring.h
smtpd.o: ../../include/vstring_vstream.h
smtpd.o: ../../include/watchdog.h
+smtpd.o: ../../include/wrap_netdb.h
smtpd.o: ../../include/xtext.h
smtpd.o: smtpd.c
smtpd.o: smtpd.h
smtpd_chat.o: ../../include/vbuf.h
smtpd_chat.o: ../../include/vstream.h
smtpd_chat.o: ../../include/vstring.h
+smtpd_chat.o: ../../include/wrap_netdb.h
smtpd_chat.o: smtpd.h
smtpd_chat.o: smtpd_chat.c
smtpd_chat.o: smtpd_chat.h
smtpd_check.o: ../../include/verify_clnt.h
smtpd_check.o: ../../include/vstream.h
smtpd_check.o: ../../include/vstring.h
+smtpd_check.o: ../../include/wrap_netdb.h
smtpd_check.o: ../../include/xtext.h
smtpd_check.o: smtpd.h
smtpd_check.o: smtpd_check.c
smtpd_expand.o: ../../include/vbuf.h
smtpd_expand.o: ../../include/vstream.h
smtpd_expand.o: ../../include/vstring.h
+smtpd_expand.o: ../../include/wrap_netdb.h
smtpd_expand.o: smtpd.h
smtpd_expand.o: smtpd_expand.c
smtpd_expand.o: smtpd_expand.h
smtpd_haproxy.o: ../../include/vbuf.h
smtpd_haproxy.o: ../../include/vstream.h
smtpd_haproxy.o: ../../include/vstring.h
+smtpd_haproxy.o: ../../include/wrap_netdb.h
smtpd_haproxy.o: smtpd.h
smtpd_haproxy.o: smtpd_haproxy.c
smtpd_milter.o: ../../include/argv.h
smtpd_milter.o: ../../include/vbuf.h
smtpd_milter.o: ../../include/vstream.h
smtpd_milter.o: ../../include/vstring.h
+smtpd_milter.o: ../../include/wrap_netdb.h
smtpd_milter.o: smtpd.h
smtpd_milter.o: smtpd_milter.c
smtpd_milter.o: smtpd_milter.h
smtpd_peer.o: ../../include/vbuf.h
smtpd_peer.o: ../../include/vstream.h
smtpd_peer.o: ../../include/vstring.h
+smtpd_peer.o: ../../include/wrap_netdb.h
smtpd_peer.o: smtpd.h
smtpd_peer.o: smtpd_peer.c
smtpd_proxy.o: ../../include/argv.h
smtpd_proxy.o: ../../include/vbuf.h
smtpd_proxy.o: ../../include/vstream.h
smtpd_proxy.o: ../../include/vstring.h
+smtpd_proxy.o: ../../include/wrap_netdb.h
smtpd_proxy.o: ../../include/xtext.h
smtpd_proxy.o: smtpd.h
smtpd_proxy.o: smtpd_proxy.c
smtpd_sasl_glue.o: ../../include/vbuf.h
smtpd_sasl_glue.o: ../../include/vstream.h
smtpd_sasl_glue.o: ../../include/vstring.h
+smtpd_sasl_glue.o: ../../include/wrap_netdb.h
smtpd_sasl_glue.o: ../../include/xsasl.h
smtpd_sasl_glue.o: smtpd.h
smtpd_sasl_glue.o: smtpd_chat.h
smtpd_sasl_proto.o: ../../include/vbuf.h
smtpd_sasl_proto.o: ../../include/vstream.h
smtpd_sasl_proto.o: ../../include/vstring.h
+smtpd_sasl_proto.o: ../../include/wrap_netdb.h
smtpd_sasl_proto.o: smtpd.h
smtpd_sasl_proto.o: smtpd_chat.h
smtpd_sasl_proto.o: smtpd_sasl_glue.h
smtpd_state.o: ../../include/vbuf.h
smtpd_state.o: ../../include/vstream.h
smtpd_state.o: ../../include/vstring.h
+smtpd_state.o: ../../include/wrap_netdb.h
smtpd_state.o: smtpd.h
smtpd_state.o: smtpd_chat.h
smtpd_state.o: smtpd_sasl_glue.h
smtpd_xforward.o: ../../include/vbuf.h
smtpd_xforward.o: ../../include/vstream.h
smtpd_xforward.o: ../../include/vstring.h
+smtpd_xforward.o: ../../include/wrap_netdb.h
smtpd_xforward.o: smtpd.h
smtpd_xforward.o: smtpd_xforward.c
qmqp-source.o: ../../include/vbuf.h
qmqp-source.o: ../../include/vstream.h
qmqp-source.o: ../../include/vstring.h
+qmqp-source.o: ../../include/wrap_netdb.h
qmqp-source.o: qmqp-source.c
smtp-sink.o: ../../include/check_arg.h
smtp-sink.o: ../../include/chroot_uid.h
smtp-sink.o: ../../include/vstream.h
smtp-sink.o: ../../include/vstring.h
smtp-sink.o: ../../include/vstring_vstream.h
+smtp-sink.o: ../../include/wrap_netdb.h
smtp-sink.o: smtp-sink.c
smtp-source.o: ../../include/check_arg.h
smtp-source.o: ../../include/compat_va_copy.h
smtp-source.o: ../../include/vstream.h
smtp-source.o: ../../include/vstring.h
smtp-source.o: ../../include/vstring_vstream.h
+smtp-source.o: ../../include/wrap_netdb.h
smtp-source.o: smtp-source.c
--- /dev/null
+../../.indent.pro
\ No newline at end of file
--- /dev/null
+SHELL = /bin/sh
+SRCS = mock_myaddrinfo.c mock_dns_lookup.c mock_servent.c \
+ mock_getaddrinfo.c match_basic.c match_addr.c make_addr.c \
+ addrinfo_to_string.c
+LIB_OBJ = match_basic.o match_addr.o make_addr.o addrinfo_to_string.o
+MOCK_OBJ= mock_myaddrinfo.o mock_dns_lookup.o mock_servent.o mock_getaddrinfo.o
+TEST_OBJ = mock_dns_lookup_test.o mock_getaddrinfo_test.o \
+ mock_myaddrinfo_test.o mock_servent_test.o match_addr_test.o
+HDRS = mock_myaddrinfo.h mock_dns.h mock_servent.h mock_getaddrinfo.h \
+ match_basic.h match_addr.h make_addr.h addrinfo_to_string.h
+TESTSRC =
+DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
+CFLAGS = $(DEBUG) $(OPT) $(DEFS)
+INCL =
+LIB = libtesting.a
+TESTPROG= mock_dns_lookup_test mock_getaddrinfo_test \
+ mock_myaddrinfo_test mock_servent_test match_addr_test
+
+LIBS = ../../lib/libptest.a \
+ ../../lib/lib$(LIB_PREFIX)dns$(LIB_SUFFIX) \
+ ../../lib/lib$(LIB_PREFIX)global$(LIB_SUFFIX) \
+ ../../lib/lib$(LIB_PREFIX)util$(LIB_SUFFIX)
+LIB_DIR = ../../lib
+INC_DIR = ../../include
+MAKES =
+
+.c.o:; $(CC) $(SHLIB_CFLAGS) $(CFLAGS) -c $*.c
+
+all: $(LIB_OBJ) $(MOCK_OBJ)
+
+$(LIB_OBJ) $(MOCK_OBJ) $(TEST_OBJ): ../../conf/makedefs.out
+
+Makefile: Makefile.in
+ cat ../../conf/makedefs.out $? >$@
+
+test: $(TESTPROG)
+
+$(LIB): $(LIB_OBJ)
+ $(_AR) $(ARFL) $(LIB) $?
+ $(_RANLIB) $(LIB)
+
+$(LIB_DIR)/$(LIB): $(LIB)
+ cp $(LIB) $(LIB_DIR)
+ $(_RANLIB) $(LIB_DIR)/$(LIB)
+
+update: $(LIB_DIR)/$(LIB) $(HDRS) $(MOCK_OBJ)
+ -for i in $(HDRS); \
+ do \
+ cmp -s $$i $(INC_DIR)/$$i 2>/dev/null || cp $$i $(INC_DIR); \
+ done
+ (cd $(INC_DIR); chmod 644 $(HDRS))
+ -for i in $(MOCK_OBJ); \
+ do \
+ cmp -s $$i $(LIB_DIR)/$$i 2>/dev/null || cp $$i $(LIB_DIR); \
+ done
+
+clean:
+ rm -f *.o $(LIB) *core $(TESTPROG) junk $(MAKES) *.tmp
+
+tidy: clean
+
+tests: test_mock_dns_lookup test_mock_getaddrinfo test_mock_myaddrinfo \
+ test_mock_servent test_match_addr
+
+mock_myaddrinfo_test: mock_myaddrinfo_test.o mock_myaddrinfo.o $(LIB) $(LIBS)
+ $(CC) $(CFLAGS) -o $@ $@.o mock_myaddrinfo.o $(LIB) $(LIBS) $(SYSLIBS)
+
+test_mock_myaddrinfo: update mock_myaddrinfo_test
+ $(SHLIB_ENV) ${VALGRIND} ./mock_myaddrinfo_test
+
+mock_dns_lookup_test: mock_dns_lookup_test.o mock_dns_lookup.o $(LIB) $(LIBS)
+ $(CC) $(CFLAGS) -o $@ $@.o mock_dns_lookup.o $(LIB) $(LIBS) $(SYSLIBS)
+
+test_mock_dns_lookup: update mock_dns_lookup_test
+ $(SHLIB_ENV) ${VALGRIND} ./mock_dns_lookup_test
+
+mock_servent_test: mock_servent_test.o mock_servent.o $(LIB) $(LIBS)
+ $(CC) $(CFLAGS) -o $@ $@.o mock_servent.o $(LIB) $(LIBS) $(SYSLIBS)
+
+test_mock_servent: update mock_servent_test
+ $(SHLIB_ENV) ${VALGRIND} ./mock_servent_test
+
+mock_getaddrinfo_test: mock_getaddrinfo_test.o mock_getaddrinfo.o $(LIB) $(LIBS)
+ $(CC) $(CFLAGS) -o $@ $@.o mock_getaddrinfo.o $(LIB) $(LIBS) $(SYSLIBS)
+
+test_mock_getaddrinfo: update mock_getaddrinfo_test
+ $(SHLIB_ENV) ${VALGRIND} ./mock_getaddrinfo_test
+
+match_addr_test: match_addr_test.o match_addr.o $(LIB) $(LIBS)
+ $(CC) $(CFLAGS) -o $@ $@.o match_addr.o $(LIB) $(LIBS) $(SYSLIBS)
+
+test_match_addr: update match_addr_test
+ $(SHLIB_ENV) ${VALGRIND} ./match_addr_test
+
+depend: $(MAKES)
+ (sed '1,/^# do not edit/!d' Makefile.in; \
+ set -e; for i in [a-z][a-z0-9]*.c; do \
+ $(CC) -E $(DEFS) $(INCL) $$i | grep -v '[<>]' | sed -n -e '/^# *1 *"\([^"]*\)".*/{' \
+ -e 's//'`echo $$i|sed 's/c$$/o/'`': \1/' \
+ -e 's/o: \.\//o: /' -e p -e '}' ; \
+ done | LANG=C sort -u) | grep -v '[.][o][:][ ][/]' >$$$$ && mv $$$$ Makefile.in
+ @$(EXPORT) make -f Makefile.in Makefile 1>&2
+
+# do not edit below this line - it is generated by 'make depend'
+addrinfo_to_string.o: ../../include/check_arg.h
+addrinfo_to_string.o: ../../include/msg.h
+addrinfo_to_string.o: ../../include/myaddrinfo.h
+addrinfo_to_string.o: ../../include/name_code.h
+addrinfo_to_string.o: ../../include/name_mask.h
+addrinfo_to_string.o: ../../include/sys_defs.h
+addrinfo_to_string.o: ../../include/vbuf.h
+addrinfo_to_string.o: ../../include/vstring.h
+addrinfo_to_string.o: ../../include/wrap_netdb.h
+addrinfo_to_string.o: addrinfo_to_string.c
+addrinfo_to_string.o: addrinfo_to_string.h
+make_addr.o: ../../include/msg.h
+make_addr.o: ../../include/mymalloc.h
+make_addr.o: ../../include/sys_defs.h
+make_addr.o: ../../include/wrap_netdb.h
+make_addr.o: make_addr.c
+make_addr.o: make_addr.h
+match_addr.o: ../../include/argv.h
+match_addr.o: ../../include/check_arg.h
+match_addr.o: ../../include/msg.h
+match_addr.o: ../../include/ptest.h
+match_addr.o: ../../include/sys_defs.h
+match_addr.o: ../../include/vbuf.h
+match_addr.o: ../../include/vstream.h
+match_addr.o: ../../include/vstring.h
+match_addr.o: ../../include/wrap_netdb.h
+match_addr.o: addrinfo_to_string.h
+match_addr.o: match_addr.c
+match_addr.o: match_addr.h
+match_addr.o: match_basic.h
+match_addr_test.o: ../../include/argv.h
+match_addr_test.o: ../../include/check_arg.h
+match_addr_test.o: ../../include/msg.h
+match_addr_test.o: ../../include/msg_output.h
+match_addr_test.o: ../../include/msg_vstream.h
+match_addr_test.o: ../../include/pmock_expect.h
+match_addr_test.o: ../../include/ptest.h
+match_addr_test.o: ../../include/ptest_main.h
+match_addr_test.o: ../../include/stringops.h
+match_addr_test.o: ../../include/sys_defs.h
+match_addr_test.o: ../../include/vbuf.h
+match_addr_test.o: ../../include/vstream.h
+match_addr_test.o: ../../include/vstring.h
+match_addr_test.o: ../../include/wrap_netdb.h
+match_addr_test.o: make_addr.h
+match_addr_test.o: match_addr.h
+match_addr_test.o: match_addr_test.c
+match_basic.o: ../../include/argv.h
+match_basic.o: ../../include/check_arg.h
+match_basic.o: ../../include/msg.h
+match_basic.o: ../../include/ptest.h
+match_basic.o: ../../include/sys_defs.h
+match_basic.o: ../../include/vbuf.h
+match_basic.o: ../../include/vstream.h
+match_basic.o: ../../include/vstring.h
+match_basic.o: match_basic.c
+match_basic.o: match_basic.h
+mock_dns_lookup.o: ../../include/argv.h
+mock_dns_lookup.o: ../../include/check_arg.h
+mock_dns_lookup.o: ../../include/dns.h
+mock_dns_lookup.o: ../../include/hex_code.h
+mock_dns_lookup.o: ../../include/msg.h
+mock_dns_lookup.o: ../../include/myaddrinfo.h
+mock_dns_lookup.o: ../../include/mymalloc.h
+mock_dns_lookup.o: ../../include/name_code.h
+mock_dns_lookup.o: ../../include/pmock_expect.h
+mock_dns_lookup.o: ../../include/ptest.h
+mock_dns_lookup.o: ../../include/sock_addr.h
+mock_dns_lookup.o: ../../include/stringops.h
+mock_dns_lookup.o: ../../include/sys_defs.h
+mock_dns_lookup.o: ../../include/vbuf.h
+mock_dns_lookup.o: ../../include/vstream.h
+mock_dns_lookup.o: ../../include/vstring.h
+mock_dns_lookup.o: ../../include/wrap_netdb.h
+mock_dns_lookup.o: mock_dns.h
+mock_dns_lookup.o: mock_dns_lookup.c
+mock_dns_lookup_test.o: ../../include/argv.h
+mock_dns_lookup_test.o: ../../include/check_arg.h
+mock_dns_lookup_test.o: ../../include/dns.h
+mock_dns_lookup_test.o: ../../include/msg.h
+mock_dns_lookup_test.o: ../../include/msg_output.h
+mock_dns_lookup_test.o: ../../include/msg_vstream.h
+mock_dns_lookup_test.o: ../../include/myaddrinfo.h
+mock_dns_lookup_test.o: ../../include/pmock_expect.h
+mock_dns_lookup_test.o: ../../include/ptest.h
+mock_dns_lookup_test.o: ../../include/ptest_main.h
+mock_dns_lookup_test.o: ../../include/sock_addr.h
+mock_dns_lookup_test.o: ../../include/stringops.h
+mock_dns_lookup_test.o: ../../include/sys_defs.h
+mock_dns_lookup_test.o: ../../include/vbuf.h
+mock_dns_lookup_test.o: ../../include/vstream.h
+mock_dns_lookup_test.o: ../../include/vstring.h
+mock_dns_lookup_test.o: ../../include/wrap_netdb.h
+mock_dns_lookup_test.o: mock_dns.h
+mock_dns_lookup_test.o: mock_dns_lookup_test.c
+mock_getaddrinfo.o: ../../include/argv.h
+mock_getaddrinfo.o: ../../include/check_arg.h
+mock_getaddrinfo.o: ../../include/msg.h
+mock_getaddrinfo.o: ../../include/myaddrinfo.h
+mock_getaddrinfo.o: ../../include/mymalloc.h
+mock_getaddrinfo.o: ../../include/pmock_expect.h
+mock_getaddrinfo.o: ../../include/ptest.h
+mock_getaddrinfo.o: ../../include/sys_defs.h
+mock_getaddrinfo.o: ../../include/vbuf.h
+mock_getaddrinfo.o: ../../include/vstream.h
+mock_getaddrinfo.o: ../../include/vstring.h
+mock_getaddrinfo.o: ../../include/wrap_netdb.h
+mock_getaddrinfo.o: addrinfo_to_string.h
+mock_getaddrinfo.o: make_addr.h
+mock_getaddrinfo.o: match_addr.h
+mock_getaddrinfo.o: match_basic.h
+mock_getaddrinfo.o: mock_getaddrinfo.c
+mock_getaddrinfo.o: mock_getaddrinfo.h
+mock_getaddrinfo_test.o: ../../include/argv.h
+mock_getaddrinfo_test.o: ../../include/check_arg.h
+mock_getaddrinfo_test.o: ../../include/msg.h
+mock_getaddrinfo_test.o: ../../include/msg_output.h
+mock_getaddrinfo_test.o: ../../include/msg_vstream.h
+mock_getaddrinfo_test.o: ../../include/myaddrinfo.h
+mock_getaddrinfo_test.o: ../../include/pmock_expect.h
+mock_getaddrinfo_test.o: ../../include/ptest.h
+mock_getaddrinfo_test.o: ../../include/ptest_main.h
+mock_getaddrinfo_test.o: ../../include/stringops.h
+mock_getaddrinfo_test.o: ../../include/sys_defs.h
+mock_getaddrinfo_test.o: ../../include/vbuf.h
+mock_getaddrinfo_test.o: ../../include/vstream.h
+mock_getaddrinfo_test.o: ../../include/vstring.h
+mock_getaddrinfo_test.o: ../../include/wrap_netdb.h
+mock_getaddrinfo_test.o: addrinfo_to_string.h
+mock_getaddrinfo_test.o: make_addr.h
+mock_getaddrinfo_test.o: match_addr.h
+mock_getaddrinfo_test.o: match_basic.h
+mock_getaddrinfo_test.o: mock_getaddrinfo.h
+mock_getaddrinfo_test.o: mock_getaddrinfo_test.c
+mock_myaddrinfo.o: ../../include/argv.h
+mock_myaddrinfo.o: ../../include/check_arg.h
+mock_myaddrinfo.o: ../../include/msg.h
+mock_myaddrinfo.o: ../../include/myaddrinfo.h
+mock_myaddrinfo.o: ../../include/mymalloc.h
+mock_myaddrinfo.o: ../../include/pmock_expect.h
+mock_myaddrinfo.o: ../../include/ptest.h
+mock_myaddrinfo.o: ../../include/sys_defs.h
+mock_myaddrinfo.o: ../../include/vbuf.h
+mock_myaddrinfo.o: ../../include/vstream.h
+mock_myaddrinfo.o: ../../include/vstring.h
+mock_myaddrinfo.o: ../../include/wrap_netdb.h
+mock_myaddrinfo.o: addrinfo_to_string.h
+mock_myaddrinfo.o: make_addr.h
+mock_myaddrinfo.o: match_addr.h
+mock_myaddrinfo.o: match_basic.h
+mock_myaddrinfo.o: mock_myaddrinfo.c
+mock_myaddrinfo.o: mock_myaddrinfo.h
+mock_myaddrinfo_test.o: ../../include/argv.h
+mock_myaddrinfo_test.o: ../../include/check_arg.h
+mock_myaddrinfo_test.o: ../../include/msg.h
+mock_myaddrinfo_test.o: ../../include/msg_output.h
+mock_myaddrinfo_test.o: ../../include/msg_vstream.h
+mock_myaddrinfo_test.o: ../../include/myaddrinfo.h
+mock_myaddrinfo_test.o: ../../include/pmock_expect.h
+mock_myaddrinfo_test.o: ../../include/ptest.h
+mock_myaddrinfo_test.o: ../../include/ptest_main.h
+mock_myaddrinfo_test.o: ../../include/stringops.h
+mock_myaddrinfo_test.o: ../../include/sys_defs.h
+mock_myaddrinfo_test.o: ../../include/vbuf.h
+mock_myaddrinfo_test.o: ../../include/vstream.h
+mock_myaddrinfo_test.o: ../../include/vstring.h
+mock_myaddrinfo_test.o: ../../include/wrap_netdb.h
+mock_myaddrinfo_test.o: addrinfo_to_string.h
+mock_myaddrinfo_test.o: make_addr.h
+mock_myaddrinfo_test.o: match_addr.h
+mock_myaddrinfo_test.o: match_basic.h
+mock_myaddrinfo_test.o: mock_myaddrinfo.h
+mock_myaddrinfo_test.o: mock_myaddrinfo_test.c
+mock_servent.o: ../../include/argv.h
+mock_servent.o: ../../include/check_arg.h
+mock_servent.o: ../../include/msg.h
+mock_servent.o: ../../include/mymalloc.h
+mock_servent.o: ../../include/pmock_expect.h
+mock_servent.o: ../../include/ptest.h
+mock_servent.o: ../../include/sys_defs.h
+mock_servent.o: ../../include/vbuf.h
+mock_servent.o: ../../include/vstream.h
+mock_servent.o: ../../include/vstring.h
+mock_servent.o: ../../include/wrap_netdb.h
+mock_servent.o: mock_servent.c
+mock_servent.o: mock_servent.h
+mock_servent_test.o: ../../include/argv.h
+mock_servent_test.o: ../../include/check_arg.h
+mock_servent_test.o: ../../include/msg.h
+mock_servent_test.o: ../../include/msg_output.h
+mock_servent_test.o: ../../include/msg_vstream.h
+mock_servent_test.o: ../../include/pmock_expect.h
+mock_servent_test.o: ../../include/ptest.h
+mock_servent_test.o: ../../include/ptest_main.h
+mock_servent_test.o: ../../include/stringops.h
+mock_servent_test.o: ../../include/sys_defs.h
+mock_servent_test.o: ../../include/vbuf.h
+mock_servent_test.o: ../../include/vstream.h
+mock_servent_test.o: ../../include/vstring.h
+mock_servent_test.o: ../../include/wrap_netdb.h
+mock_servent_test.o: mock_servent.h
+mock_servent_test.o: mock_servent_test.c
--- /dev/null
+/*++
+/* NAME
+/* addrinfo_to_string 3
+/* SUMMARY
+/* address info to string conversion
+/* SYNOPSIS
+/* #include <addrinfo_to_string.h>
+/*
+/* const char *pf_to_string(int);
+/*
+/* const char *af_to_string(int);
+/*
+/* const char *socktype_to_string(int);
+/*
+/* const char *ipprotocol_to_string(int);
+/*
+/* const char *ai_flags_to_string(
+/* VSTRING *buf,
+/* int flags);
+/*
+/* const char *ni_flags_to_string(
+/* VSTRING *buf,
+/* int flags);
+/* char *append_addrinfo_to_string(
+/* VSTRING *buf,
+/* const struct addrinfo *ai)
+/*
+/* char *addrinfo_hints_to_string(
+/* VSTRING *buf,
+/* const struct addrinfo *hints)
+/*
+/* char *sockaddr_to_string(
+/* VSTRING *buf,
+/* const struct sockaddr *sa,
+/* size_t sa_len);
+/* DESCRIPTION
+/* The functions in this module convert address information
+/* to textual form, for use in test error messages. They
+/* implement only the necessary subsets.
+/*
+/* pf_to_string(), af_to_string(), socktype_to_string,
+/* ipprotocol_to_string, ai_flags_to_string(), ni_flags_to_string()
+/* produce a textual representation of addrinfo properties or
+/* getnameinfo() flags.
+/*
+/* append_addrinfo_to_string() appends a textual representation
+/* of the referenced addrinfo object (only one) to the specified
+/* buffer.
+/*
+/* addrinfo_hints_to_string() writes a textual representation of
+/* the referenced getaddrinfo() hints object.
+/*
+/* sockaddr_to_string() writes a textual representation of the
+/* referenced sockaddr object.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <wrap_netdb.h>
+#include <stdio.h> /* sprintf/snprintf */
+
+ /*
+ * Utility library.
+ */
+#include <msg.h>
+#include <myaddrinfo.h>
+#include <name_code.h>
+#include <name_mask.h>
+
+ /*
+ * Test library.
+ */
+#include <addrinfo_to_string.h>
+
+#define STR_OR_NULL(s) ((s) ? (s) : "(null)")
+
+#ifdef NO_SNPRINTF
+#define MY_SNPRINTF(bp, sz, fmt, ...) \
+ sprintf((bp), (fmt), __VA_ARGS__)
+#else
+#define MY_SNPRINTF(bp, sz, fmt, ...) \
+ snprintf((bp), (sz), (fmt), __VA_ARGS__)
+#endif
+
+#define STR vstring_str
+
+/* pf_to_string - convert protocol family to human-readable form */
+
+const char *pf_to_string(int af)
+{
+ static const NAME_CODE pf_codes[] = {
+ "PF_INET", PF_INET,
+ "PF_INET6", PF_INET6,
+ 0,
+ };
+ const char *name;
+
+ name = str_name_code(pf_codes, af);
+ return (name ? name : "unknown-protocol-family");
+}
+
+/* af_to_string - convert address family to human-readable form */
+
+const char *af_to_string(int af)
+{
+ static const NAME_CODE af_codes[] = {
+ "AF_INET", AF_INET,
+ "AF_INET6", AF_INET6,
+ 0,
+ };
+ const char *name;
+
+ name = str_name_code(af_codes, af);
+ return (name ? name : "unknown-address-family");
+}
+
+/* socktype_to_string - convert socket type to human-readable form */
+
+const char *socktype_to_string(int socktype)
+{
+ static const NAME_CODE socktypes[] = {
+ "SOCK_STREAM", SOCK_STREAM,
+ "SOCK_DGRAM", SOCK_DGRAM,
+ "SOCK_RAW", SOCK_RAW,
+ "0", 0,
+ 0,
+ };
+ const char *name;
+
+ name = str_name_code(socktypes, socktype);
+ return (name ? name : "unknown-socket-type");
+}
+
+/* ipprotocol_to_string - convert protocol to human-readable form */
+
+const char *ipprotocol_to_string(int proto)
+{
+ static const NAME_CODE protocols[] = {
+ "IPPROTO_UDP", IPPROTO_UDP,
+ "IPPROTO_TCP", IPPROTO_TCP,
+ "0", 0,
+ 0,
+ };
+ const char *name;
+
+ name = str_name_code(protocols, proto);
+ return (name ? name : "unknown-protocol");
+}
+
+/* ai_flags_to_string - convert addrinfo flags to human-readable form */
+
+const char *ai_flags_to_string(VSTRING *buf, int flags)
+{
+ static const NAME_MASK ai_flags[] = {
+#ifdef AI_IDN
+ "AI_IDN", AI_IDN,
+#endif
+#ifdef AI_CANONIDN
+ "AI_CANONIDN", AI_CANONIDN,
+#endif
+#ifdef AI_IDN_ALLOW_UNASSIGNED
+ "AI_IDN_ALLOW_UNASSIGNED", AI_IDN_ALLOW_UNASSIGNED,
+#endif
+#ifdef AI_IDN_USE_STD3_ASCII_RULES
+ "AI_IDN_USE_STD3_ASCII_RULES", AI_IDN_USE_STD3_ASCII_RULES,
+#endif
+ "AI_ADDRCONFIG", AI_ADDRCONFIG,
+ "AI_CANONNAME", AI_CANONNAME,
+ "AI_NUMERICHOST", AI_NUMERICHOST,
+ "AI_NUMERICSERV", AI_NUMERICSERV,
+ "AI_PASSIVE", AI_PASSIVE,
+ 0,
+ };
+
+ return (str_name_mask_opt(buf, "ai_flags_to_string", ai_flags, flags,
+ NAME_MASK_NUMBER | NAME_MASK_PIPE | NAME_MASK_NULL));
+}
+
+/* ni_flags_to_string - convert getnameinfo flags to human-readable form */
+
+const char *ni_flags_to_string(VSTRING *buf, int flags)
+{
+ static const NAME_MASK ni_flags[] = {
+ "NI_NAMEREQD", NI_NAMEREQD,
+ "NI_DGRAM", NI_DGRAM,
+ "NI_NOFQDN", NI_NOFQDN,
+ "NI_NUMERICHOST", NI_NUMERICHOST,
+ "NI_NUMERICSERV", NI_NUMERICSERV,
+ 0,
+ };
+
+ return (str_name_mask_opt(buf, "ni_flags_to_string", ni_flags, flags,
+ NAME_MASK_NUMBER | NAME_MASK_PIPE | NAME_MASK_NULL));
+}
+
+/* append_addrinfo_to_string - print human-readable addrinfo */
+
+char *append_addrinfo_to_string(VSTRING *buf, const struct addrinfo *ai)
+{
+ if (ai == 0) {
+ vstring_sprintf_append(buf, "(null)");
+ } else {
+ VSTRING *sockaddr_buf = vstring_alloc(100);
+ VSTRING *flags_buf = vstring_alloc(100);
+
+ vstring_sprintf_append(buf, "{%s, %s, %s, %s, %d, %s, %s}",
+ ai_flags_to_string(flags_buf, ai->ai_flags),
+ pf_to_string(ai->ai_family),
+ socktype_to_string(ai->ai_socktype),
+ ipprotocol_to_string(ai->ai_protocol),
+ ai->ai_addrlen,
+ sockaddr_to_string(sockaddr_buf, ai->ai_addr,
+ ai->ai_addrlen),
+ STR_OR_NULL(ai->ai_canonname));
+ vstring_free(sockaddr_buf);
+ vstring_free(flags_buf);
+ }
+ return (STR(buf));
+}
+
+/* addrinfo_hints_to_string - append human-readable hints */
+
+char *addrinfo_hints_to_string(VSTRING *buf, const struct addrinfo *ai)
+{
+ if (ai == 0) {
+ vstring_sprintf(buf, "(null)");
+ } else {
+ VSTRING *flags_buf = vstring_alloc(100);
+
+ vstring_sprintf(buf, "{%s, %s, %s, %s}",
+ ai_flags_to_string(flags_buf, ai->ai_flags),
+ pf_to_string(ai->ai_family),
+ socktype_to_string(ai->ai_socktype),
+ ipprotocol_to_string(ai->ai_protocol));
+ vstring_free(flags_buf);
+ }
+ return (STR(buf));
+}
+
+/* sockaddr_to_strings - convert to printable host address and port */
+
+static void sockaddr_to_strings(const struct sockaddr *sa, size_t salen,
+ MAI_HOSTADDR_STR *hostaddr,
+ MAI_SERVPORT_STR *portnum)
+{
+ if (sa->sa_family == AF_INET) {
+ struct sockaddr_in *sin = (struct sockaddr_in *) sa;
+
+ if (salen < sizeof(*sin))
+ msg_fatal("sockaddr_to_strings: bad sockaddr length %ld",
+ (long) salen);
+ MY_SNPRINTF(portnum->buf, sizeof(*portnum), "%d", ntohs(sin->sin_port));
+ if (inet_ntop(AF_INET, &sin->sin_addr, hostaddr->buf,
+ sizeof(*hostaddr)) == 0)
+ msg_fatal("inet_ntop(AF_INET,...): %m");
+#ifdef HAS_IPV6
+ } else if (sa->sa_family == AF_INET6) {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa;
+
+ if (salen < sizeof(*sin6))
+ msg_fatal("sockaddr_to_strings: bad sockaddr length %ld",
+ (long) salen);
+ MY_SNPRINTF(portnum->buf, sizeof(*portnum), "%d",
+ ntohs(sin6->sin6_port));
+ if (inet_ntop(AF_INET6, &sin6->sin6_addr, hostaddr->buf,
+ sizeof(*hostaddr)) == 0)
+ msg_fatal("inet_ntop(AF_INET,...): %m");
+#endif
+ } else {
+ errno = EAFNOSUPPORT;
+ msg_panic("sockaddr_to_strings: protocol familiy %d: %m",
+ sa->sa_family);
+ }
+}
+
+/* sockaddr_to_string - render human-readable sockaddr */
+
+char *sockaddr_to_string(VSTRING *buf, const struct sockaddr *sa,
+ size_t salen)
+{
+ MAI_HOSTADDR_STR hostaddr;
+ MAI_SERVPORT_STR portnum;
+
+ sockaddr_to_strings(sa, salen, &hostaddr, &portnum);
+ vstring_sprintf(buf, "{%s, %s, %s}",
+ af_to_string(sa->sa_family),
+ hostaddr.buf, portnum.buf);
+ return (STR(buf));
+}
--- /dev/null
+#ifndef _ADDRINFO_TO_STRING_H_INCLUDED_
+#define _ADDRINFO_TO_STRING_H_INCLUDED_
+
+/*++
+/* NAME
+/* addrinfo_to_string 3h
+/* SUMMARY
+/* address info to string conversion
+/* SYNOPSIS
+/* #include <addrinfo_to_string.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <wrap_netdb.h>
+
+ /*
+ * Utility library.
+ */
+#include <vstring.h>
+
+ /*
+ * External interface.
+ */
+extern const char *pf_to_string(int);
+extern const char *af_to_string(int);
+extern const char *socktype_to_string(int);
+extern const char *ipprotocol_to_string(int);
+extern const char *ai_flags_to_string(VSTRING *, int);
+extern const char *ni_flags_to_string(VSTRING *, int);
+extern char *append_addrinfo_to_string(VSTRING *, const struct addrinfo *);
+extern char *addrinfo_hints_to_string(VSTRING *, const struct addrinfo *);
+extern char *sockaddr_to_string(VSTRING *, const struct sockaddr *, size_t);
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+#endif
--- /dev/null
+/*++
+/* NAME
+/* make_addr 3
+/* SUMMARY
+/* make_addrinfo(), freeaddrinfo(), make_sockaddr() for hermetic tests
+/* SYNOPSIS
+/* #include <make_addrinfo.h>
+/*
+/* struct addrinfo *make_addrinfo(
+/* const struct addrinfo *hints,
+/* const char *name,
+/* const char *addr,
+/* int port)
+/*
+/* struct addrinfo *copy_addrinfo(const struct addrinfo *ai)
+/*
+/* void freeaddrinfo(struct addrinfo *ai)
+/*
+/* struct sockaddr *make_sockaddr(
+/* int family,
+/* const char *addr,
+/* int port)
+/*
+/* void free_sockaddr(struct sockaddr *sa)
+/* DESCRIPTION
+/* This module contains helper functions to set up mock
+/* expectations.
+/*
+/* make_addrinfo() creates one addrinfo structure. The hints
+/* argument must specify the protocol family for the addr
+/* argument (i.e. not PF_UNSPEC). To create a linked list,
+/* manually append make_addrinfo() results. The port is in
+/* host byte order.
+/*
+/* copy_addrinfo() makes a deep copy of a linked list of
+/* addrinfo structures.
+/*
+/* freeaddrinfo() deletes a linked list of addrinfo structures.
+/* This function must be used for addrinfo structures created
+/* with make_addrinfo() and copy_addrinfo().
+/*
+/* make_sockaddr() creates a sockaddr structure from the string
+/* representation of an IP address, and a port in host byte
+/* order.
+/*
+/* free_sockaddr() exists to make program code more explicit.
+/* DIAGNOSTICS
+/* make_sockaddr() and make_addrinfo() terminate with a fatal
+/* error when an unknown address family is specified, or when
+/* the string representation of an IP address does not match
+/* the address family.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <wrap_netdb.h>
+#include <string.h>
+#include <errno.h>
+
+ /*
+ * Utility library.
+ */
+#include <msg.h>
+#include <mymalloc.h>
+
+ /*
+ * Test library.
+ */
+#include <make_addr.h>
+
+#define MYSTRDUP_OR_NULL(x) ((x) ? mystrdup(x) : 0)
+
+/* make_sockaddr - helper to create mock sockaddr instances */
+
+struct sockaddr *make_sockaddr(int family, const char *addr, int port)
+{
+ if (family == AF_INET) {
+ struct sockaddr_in *sa;
+
+ sa = (struct sockaddr_in *) mymalloc(sizeof(*sa));
+ memset(sa, 0, sizeof(*sa));
+ switch (inet_pton(AF_INET, addr, (void *) &sa->sin_addr)) {
+ case 1:
+ break;
+ case 0:
+ msg_fatal("bad address syntax: '%s'", addr);
+ case -1:
+ msg_fatal("inet_pton(AF_INET, %s, (ptr)): %m", addr);
+ }
+ sa->sin_family = AF_INET;
+ sa->sin_port = htons(port);
+ return ((struct sockaddr *) sa);
+#ifdef HAS_IPV6
+ } else if (family == AF_INET6) {
+ struct sockaddr_in6 *sa;
+
+ sa = (struct sockaddr_in6 *) mymalloc(sizeof(*sa));
+ memset(sa, 0, sizeof(*sa));
+ switch (inet_pton(AF_INET6, addr, (void *) &sa->sin6_addr)) {
+ case 1:
+ break;
+ case 0:
+ msg_fatal("bad address syntax: '%s'", addr);
+ case -1:
+ msg_fatal("inet_pton(AF_INET6, %s, (ptr)): %m", addr);
+ }
+ sa->sin6_family = AF_INET6;
+ sa->sin6_port = htons(port);
+ return ((struct sockaddr *) sa);
+#endif
+ } else {
+ errno = EAFNOSUPPORT;
+ msg_panic("make_sockaddr: address familiy %d: %m", family);
+ }
+}
+
+/* free_sockaddr - destructor for make_sockaddr() and copy_addrinfo() */
+
+void free_sockaddr(struct sockaddr *sa)
+{
+ myfree(sa);
+}
+
+/* copy_addrinfo - expectation helper */
+
+struct addrinfo *copy_addrinfo(const struct addrinfo *in)
+{
+ struct addrinfo *out;
+
+ /*
+ * First a shallow copy, followed by deep copies for pointer fields.
+ */
+ if (in == 0)
+ return (0);
+ out = (struct addrinfo *) mymalloc(sizeof(*out));
+ *out = *in;
+ if (in->ai_addr != 0) {
+ out->ai_addr = (struct sockaddr *) mymalloc(in->ai_addrlen);
+ memcpy(out->ai_addr, in->ai_addr, in->ai_addrlen);
+ }
+ if (in->ai_canonname != 0)
+ out->ai_canonname = mystrdup(in->ai_canonname);
+ if (in->ai_next)
+ out->ai_next = copy_addrinfo(in->ai_next);
+ return (out);
+}
+
+/* make_addrinfo - helper to create mock addrinfo input or result */
+
+struct addrinfo *make_addrinfo(const struct addrinfo *hints,
+ const char *name, const char *addr,
+ int port)
+{
+ struct addrinfo *out;
+
+ out = (struct addrinfo *) mymalloc(sizeof(*out));
+ memset(out, 0, sizeof(*out));
+ out->ai_canonname = MYSTRDUP_OR_NULL(name);
+ switch (hints->ai_family) {
+ case PF_INET6:
+ out->ai_addr = make_sockaddr(AF_INET6, addr, port);
+ out->ai_addrlen = sizeof(struct sockaddr_in6);
+ out->ai_family = hints->ai_family;
+ out->ai_socktype = hints->ai_socktype;
+ out->ai_protocol = hints->ai_protocol;
+ break;
+ case PF_INET:
+ out->ai_addr = make_sockaddr(AF_INET, addr, port);
+ out->ai_addrlen = sizeof(struct sockaddr_in);
+ out->ai_family = hints->ai_family;
+ out->ai_socktype = hints->ai_socktype;
+ out->ai_protocol = hints->ai_protocol;
+ break;
+ default:
+ msg_fatal("make_addrinfo: hints->ai_family: %d", hints->ai_family);
+ }
+ out->ai_next = 0;
+ return (out);
+}
+
+/* freeaddrinfo - free the mock-generated addrinfo structures */
+
+void freeaddrinfo(struct addrinfo *res)
+{
+ if (res) {
+ if (res->ai_next)
+ freeaddrinfo(res->ai_next);
+ if (res->ai_addr)
+ myfree(res->ai_addr);
+ if (res->ai_canonname)
+ myfree(res->ai_canonname);
+ myfree(res);
+ }
+}
--- /dev/null
+#ifndef _MAKE_ADDR_H_INCLUDED_
+#define _MAKE_ADDR_H_INCLUDED_
+
+/*++
+/* NAME
+/* make_addr 3h
+/* SUMMARY
+/* make_addrinfo(), freeaddrinfo(), make_sockaddr() for hermetic tests
+/* SYNOPSIS
+/* #include <mock_getaddrinfo.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <wrap_netdb.h>
+
+ /*
+ * External interface.
+ */
+extern struct addrinfo *make_addrinfo(const struct addrinfo *, const char *,
+ const char *, int);
+extern struct addrinfo *copy_addrinfo(const struct addrinfo *);
+extern struct sockaddr *make_sockaddr(int, const char *, int);
+extern void free_sockaddr(struct sockaddr *);
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+#endif
--- /dev/null
+/*++
+/* NAME
+/* match_addr 3
+/* SUMMARY
+/* matchers for network address information
+/* SYNOPSIS
+/* #include <match_addr.h>
+/*
+/* int eq_addrinfo(
+/* PTEST_CTX *t,
+/* const char *what,
+/* struct addrinfo got,
+/* struct addrinfo want)
+/*
+/* int eq_sockaddr(PTEST_CTX *t,
+/* const char *what,
+/* const struct sockaddr *got,
+/* size_t gotlen,
+/* const struct sockaddr *want,
+/* size_t wantlen)
+/* DESCRIPTION
+/* The functions described here are safe macros that include
+/* call-site information (file name, line number) that may be
+/* used in error messages.
+/*
+/* eq_addrinfo() compares two struct addrinfo linked lists,
+/* and eq_sockaddr() compares two struct sockaddr instances.
+/* Both functions return whether their arguments contain the
+/* same values. If the t argument is not null, both functions
+/* will report values that differ with ptest_error()).
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <string.h>
+
+ /*
+ * Test library.
+ */
+#include <ptest.h>
+#include <match_basic.h>
+#include <match_addr.h>
+#include <addrinfo_to_string.h>
+
+#define STR vstring_str
+
+/* _eq_addrinfo - match struct addrinfo instances */
+
+int _eq_addrinfo(const char *file, int line,
+ PTEST_CTX *t, const char *what,
+ const struct addrinfo *got,
+ const struct addrinfo *want)
+{
+ if (got == 0 && want == 0)
+ return (1);
+ if (got == 0 || want == 0) {
+ if (t) {
+ VSTRING *buf = vstring_alloc(100);
+
+ ptest_error(t, "%s:%d %s: got %s, want %s",
+ file, line, what, got ?
+ append_addrinfo_to_string(buf, got) : "(null)",
+ want ?
+ append_addrinfo_to_string(buf, want) : "(null)");
+ vstring_free(buf);
+ }
+ return (0);
+ }
+ return (_eq_flags(file, line, t, "ai_flags", got->ai_flags, want->ai_flags,
+ ai_flags_to_string)
+ && _eq_enum(file, line, t, "ai_family", got->ai_family,
+ want->ai_family, af_to_string)
+ && _eq_enum(file, line, t, "ai_socktype", got->ai_socktype,
+ want->ai_socktype, socktype_to_string)
+ && _eq_enum(file, line, t, "ai_protocol",
+ got->ai_protocol, want->ai_protocol,
+ ipprotocol_to_string)
+ && _eq_size_t(file, line, t, "ai_addrlen",
+ got->ai_addrlen, want->ai_addrlen)
+ && _eq_sockaddr(file, line, t, "ai_addr", got->ai_addr,
+ got->ai_addrlen, want->ai_addr, want->ai_addrlen)
+ && _eq_addrinfo(file, line, t, what, got->ai_next,
+ want->ai_next));
+}
+
+/* _eq_sockaddr - sockaddr matcher */
+
+int _eq_sockaddr(const char *file, int line,
+ PTEST_CTX *t, const char *what,
+ const struct sockaddr *got, size_t gotlen,
+ const struct sockaddr *want, size_t wantlen)
+{
+ if (got == 0 && want == 0)
+ return (1);
+ if (got == 0 || want == 0) {
+ if (t) {
+ VSTRING *got_buf = vstring_alloc(100);
+ VSTRING *want_buf = vstring_alloc(100);
+
+ ptest_error(t, "%s:%d %s: got %s, want %s",
+ file, line, what,
+ got ? sockaddr_to_string(got_buf, got, gotlen)
+ : "(null)",
+ want ? sockaddr_to_string(want_buf, want, wantlen)
+ : "(null)");
+ vstring_free(want_buf);
+ vstring_free(got_buf);
+ }
+ return (0);
+ }
+ if (!_eq_enum(file, line, (PTEST_CTX *) 0, "struct sockaddr address family",
+ got->sa_family, want->sa_family, af_to_string)
+ || !_eq_size_t(file, line, (PTEST_CTX *) 0, "struct sockaddr length",
+ gotlen, wantlen)
+ || memcmp(got, want, gotlen) != 0) {
+ VSTRING *got_buf = vstring_alloc(100);
+ VSTRING *want_buf = vstring_alloc(100);
+
+ ptest_error(t, "%s:%d %s: got %s, want %s",
+ file, line, what,
+ sockaddr_to_string(got_buf, got, gotlen),
+ sockaddr_to_string(want_buf, want, wantlen));
+ vstring_free(want_buf);
+ vstring_free(got_buf);
+ return (0);
+ }
+ return (1);
+}
--- /dev/null
+#ifndef _MATCH_ADDR_H_INCLUDED_
+#define _MATCH_ADDR_H_INCLUDED_
+
+/*++
+/* NAME
+/* match_addr 3h
+/* SUMMARY
+/* network address matcher
+/* SYNOPSIS
+/* #include <match_addr.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <wrap_netdb.h>
+
+ /*
+ * Test library.
+ */
+#include <ptest.h>
+
+ /*
+ * Matchers.
+ */
+#define eq_addrinfo(t, what, got, want) \
+ _eq_addrinfo(__FILE__, __LINE__, (t), (what), (got), (want))
+
+extern int _eq_addrinfo(const char *, int, PTEST_CTX *, const char *,
+ const struct addrinfo *,
+ const struct addrinfo *);
+
+#define eq_sockaddr(t, what, got, gotlen, want, wantlen) \
+ _eq_sockaddr(__FILE__, __LINE__, (t), (what), (got), (gotlen), (want), (wantlen))
+
+extern int _eq_sockaddr(const char *, int, PTEST_CTX *, const char *,
+ const struct sockaddr *, size_t,
+ const struct sockaddr *, size_t);
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+#endif
--- /dev/null
+ /*
+ * Test program to exercise make_addr functions including logging. See
+ * comments in ptest_main.h and pmock_expect_test.c for a documented
+ * example.
+ */
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <wrap_netdb.h>
+#include <string.h>
+
+ /*
+ * Test library.
+ */
+#include <make_addr.h>
+#include <match_addr.h>
+#include <ptest.h>
+
+typedef struct PTEST_CASE {
+ const char *testname; /* Human-readable description */
+ void (*action) (PTEST_CTX *t, const struct PTEST_CASE *);
+} PTEST_CASE;
+
+static void test_eq_addrinfo_diff(PTEST_CTX *t, const PTEST_CASE *unused)
+{
+ struct addrinfo hints;
+ struct addrinfo *want_addrinfo;
+ struct addrinfo *other_addrinfo;
+
+ /*
+ * Set up expectations.
+ */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ want_addrinfo = make_addrinfo(&hints, "localhost", "127.0.0.1", 25);
+ other_addrinfo = make_addrinfo(&hints, "localhost", "127.0.0.2", 25);
+
+ /*
+ * Verify that the two addrinfos don't match. Do not count this mismatch
+ * as an error. Instead, count the absence of the mismatch as an error.
+ */
+ expect_ptest_error(t, " ai_addr: "
+ "got {AF_INET, 127.0.0.2, 25}, "
+ "want {AF_INET, 127.0.0.1, 25}");
+ if (eq_addrinfo(t, "test_eq_addrinfo", other_addrinfo, want_addrinfo))
+ ptest_error(t, "eq_addrinfo() returned true for different objects");
+
+ /*
+ * Clean up.
+ */
+ freeaddrinfo(want_addrinfo);
+ freeaddrinfo(other_addrinfo);
+}
+
+static void test_eq_addrinfo_null(PTEST_CTX *t, const PTEST_CASE *unused)
+{
+ struct addrinfo hints;
+ struct addrinfo *want_addrinfo;
+ struct addrinfo *other_addrinfo = 0;
+
+ /*
+ * Set up expectations.
+ */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ want_addrinfo = make_addrinfo(&hints, "localhost", "127.0.0.1", 25);
+
+ /*
+ * Verify that the two addrinfos don't match. Do not count this mismatch
+ * as an error. Instead, count the absence of the mismatch as an error.
+ */
+ expect_ptest_error(t, "test_eq_addrinfo_null: got (null), "
+ "want {0, PF_INET, SOCK_STREAM, 0, 16, "
+ "{AF_INET, 127.0.0.1, 25}, localhost}");
+ if (eq_addrinfo(t, "test_eq_addrinfo_null", other_addrinfo, want_addrinfo))
+ ptest_error(t, "eq_addrinfo() returned true for different objects");
+
+ /*
+ * Clean up.
+ */
+ freeaddrinfo(want_addrinfo);
+}
+
+static void test_eq_sockaddr_diff(PTEST_CTX *t, const PTEST_CASE *unused)
+{
+ struct sockaddr *want_sockaddr;
+ struct sockaddr *other_sockaddr;
+
+ /*
+ * Set up expectations.
+ */
+ want_sockaddr = make_sockaddr(AF_INET, "127.0.0.1", 25);
+ other_sockaddr = make_sockaddr(AF_INET, "127.0.0.2", 25);
+
+ /*
+ * Verify that the two sockaddrs don't match. Do not count this mismatch
+ * as an error. Instead, count the absence of the mismatch as an error.
+ */
+ expect_ptest_error(t, "test_eq_sockaddr_diff: "
+ "got {AF_INET, 127.0.0.2, 25}, "
+ "want {AF_INET, 127.0.0.1, 25}");
+ if (eq_sockaddr(t, "test_eq_sockaddr_diff",
+ other_sockaddr, sizeof(struct sockaddr_in),
+ want_sockaddr, sizeof(struct sockaddr_in)))
+ ptest_error(t, "eq_sockaddr() returned true for different objects");
+
+ /*
+ * Clean up.
+ */
+ free_sockaddr(want_sockaddr);
+ free_sockaddr(other_sockaddr);
+}
+
+ /*
+ * Test cases.
+ */
+const PTEST_CASE ptestcases[] = {
+ {
+ "Compare different IPv4 addrinfos", test_eq_addrinfo_diff,
+ },
+ {
+ "Compare null and non-null IPv4 addrinfos", test_eq_addrinfo_null,
+ },
+ {
+ "Compare different IPv4 sockaddrs", test_eq_sockaddr_diff,
+ },
+};
+
+#include <ptest_main.h>
--- /dev/null
+/*++
+/* NAME
+/* match_basic 3
+/* SUMMARY
+/* basic matchers
+/* SYNOPSIS
+/* #include <match_basic.h>
+/*
+/* int eq_int(
+/* PTEST_CTX *t,
+/* const char *what,
+/* int got,
+/* int want)
+/*
+/* int eq_size_t(
+/* PTEST_CTX *t,
+/* const char *what,
+/* size_t got,
+/* size_t want)
+/*
+/* int eq_ssize_t(
+/* PTEST_CTX *t,
+/* const char *what,
+/* ssize_t got,
+/* ssize_t want)
+/*
+/* int eq_flags(
+/* PTEST_CTX *t,
+/* const char *what,
+/* int got,
+/* int want,
+/* const char *(*flags_to_str) (VSTRING *, int))
+/*
+/* int eq_enum(
+/* PTEST_CTX *t,
+/* const char *what,
+/* int got,
+/* int want,
+/* const char *(*enum_to_str) (int))
+/*
+/* int eq_str(
+/* PTEST_CTX *t,
+/* const char *what,
+/* const char *got,
+/* const char *want)
+/*
+/* int eq_argv(
+/* PTEST_CTX *t,
+/* const char *what,
+/* const ARGV *got,
+/* const ARGV *want)
+/* DESCRIPTION
+/* The functions described here are actually safe macros that
+/* include call-site information (file name, line number) in
+/* error messages.
+/*
+/* eq_int() compares two integers, and if t is not null, reports
+/* values that differ with ptest_error());
+/*
+/* eq_flags() compares two integer bitmasks, and if t is not
+/* null, reports values that differ with ptest_error());
+/*
+/* eq_enum() compares two integer enum values, and if t is not
+/* null, reports values that differ with ptest_error());
+/*
+/* eq_str() compares two null-terminated strings, and if t is
+/* not null, reports values that differ with ptest_error());
+/*
+/* eq_argv() compares two null-terminated string arrays, and
+/* if t is not null, reports values that differ with ptest_error());
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <string.h>
+
+ /*
+ * Utility library.
+ */
+#include <vstring.h>
+
+ /*
+ * Test library.
+ */
+#include <ptest.h>
+#include <match_basic.h>
+
+#define STR_OR_NULL(s) ((s) ? (s) : "(null)")
+
+/* _eq_int - match integers */
+
+int _eq_int(const char *file, int line, PTEST_CTX *t,
+ const char *what, int got, int want)
+{
+ if (got != want) {
+ if (t)
+ ptest_error(t, "%s:%d: %s: got %d, want %d", file, line, what, got, want);
+ return (0);
+ }
+ return (1);
+}
+
+/* _eq_size_t - match size_t */
+
+int _eq_size_t(const char *file, int line, PTEST_CTX *t,
+ const char *what, size_t got, size_t want)
+{
+ if (got != want) {
+ if (t)
+ ptest_error(t, "%s:%d: %s: got %lu, want %lu",
+ file, line, what, (long) got, (long) want);
+ return (0);
+ }
+ return (1);
+}
+
+/* _eq_ssize_t - match ssize_t */
+
+int _eq_ssize_t(const char *file, int line, PTEST_CTX *t,
+ const char *what, ssize_t got, ssize_t want)
+{
+ if (got != want) {
+ if (t)
+ ptest_error(t, "%s:%d: %s: got %ld, want %ld",
+ file, line, what, (long) got, (long) want);
+ return (0);
+ }
+ return (1);
+}
+
+/* _eq_flags - match flags */
+
+int _eq_flags(const char *file, int line, PTEST_CTX *t,
+ const char *what, int got, int want,
+ const char *(flags_to_string) (VSTRING *, int))
+{
+ if (got != want) {
+ if (t) {
+ VSTRING *got_buf = vstring_alloc(100);
+ VSTRING *want_buf = vstring_alloc(100);
+
+ ptest_error(t, "%s:%d: %s: got %s, want %s", file, line, what,
+ flags_to_string(got_buf, got),
+ flags_to_string(want_buf, want));
+ vstring_free(got_buf);
+ vstring_free(want_buf);
+ }
+ return (0);
+ }
+ return (1);
+}
+
+/* _eq_enum - match enum */
+
+int _eq_enum(const char *file, int line, PTEST_CTX *t,
+ const char *what, int got, int want,
+ const char *(enum_to_string) (int))
+{
+ if (got != want) {
+ if (t)
+ ptest_error(t, "%s:%d: %s: got %s, want %s", file, line, what,
+ enum_to_string(got), enum_to_string(want));
+ return (0);
+ }
+ return (1);
+}
+
+/* _eq_str - match null-terminated strings */
+
+int _eq_str(const char *file, int line, PTEST_CTX *t,
+ const char *what, const char *got, const char *want)
+{
+ if (strcmp(got, want) != 0) {
+ if (t)
+ ptest_error(t, "%s:%d: %s: got '%s', want '%s'",
+ file, line, what, got, want);
+ return (0);
+ }
+ return (1);
+}
+
+/* _eq_argv - match ARGV instances */
+
+int _eq_argv(const char *file, int line, PTEST_CTX *t,
+ const char *what, const ARGV *got, const ARGV *want)
+{
+ char **gpp, **wpp;
+
+ for (gpp = got->argv, wpp = want->argv; /* see below */ ; gpp++, wpp++) {
+ if (*gpp == 0 && *wpp == 0) {
+ return (1);
+ } else if (*gpp == 0 || *wpp == 0) {
+ if (t)
+ ptest_error(t, "%s:%d: %s: got %s, want %s",
+ file, line, what, STR_OR_NULL(*gpp),
+ STR_OR_NULL(*wpp));
+ return (0);
+ } else if (!_eq_str(file, line, t, what, *gpp, *wpp)) {
+ return (0);
+ }
+ }
+}
--- /dev/null
+#ifndef _MATCH_BASIC_H_INCLUDED_
+#define _MATCH_BASIC_H_INCLUDED_
+
+/*++
+/* NAME
+/* match_basic 3h
+/* SUMMARY
+/* basic matchers
+/* SYNOPSIS
+/* #include <matchers.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <setjmp.h>
+
+ /*
+ * Test library.
+ */
+#include <ptest.h>
+
+ /*
+ * Matchers.
+ */
+#define eq_int(t, what, got, want) \
+ _eq_int(__FILE__, __LINE__, (t), (what), (got), (want))
+
+extern int _eq_int(const char *, int, PTEST_CTX *,
+ const char *, int, int);
+
+#define eq_size_t(t, what, got, want) \
+ _eq_int(__FILE__, __LINE__, (t), (what), (got), (want))
+
+extern int _eq_size_t(const char *, int, PTEST_CTX *,
+ const char *, size_t, size_t);
+
+#define eq_ssize_t(t, what, got, want) \
+ _eq_int(__FILE__, __LINE__, (t), (what), (got), (want))
+
+extern int _eq_ssize_t(const char *, int, PTEST_CTX *,
+ const char *, ssize_t, ssize_t);
+
+#define eq_flags(t, what, got, want, flags_to_str) \
+ _eq_flags(__FILE__, __LINE__, (t), (what), (got), (want), (flags_to_str))
+
+extern int _eq_flags(const char *, int, PTEST_CTX *,
+ const char *, int, int,
+ const char *(*flags_to_str) (VSTRING *, int));
+
+#define eq_enum(t, what, got, want, enum_to_str) \
+ _eq_lflags(__FILE__, __LINE__, (t), (what), (got), (want), (enum_to_str))
+
+extern int _eq_enum(const char *, int, PTEST_CTX *,
+ const char *, int, int, const char *(*enum_to_str) (int));
+
+#define eq_str(t, what, got, want) \
+ _eq_str(__FILE__, __LINE__, (t), (what), (got), (want))
+
+extern int _eq_str(const char *, int, PTEST_CTX *,
+ const char *, const char *, const char *);
+
+#define eq_argv(t, what, got, want) \
+ _eq_argv(__FILE__, __LINE__, (t), (what), (got), (want))
+
+extern int _eq_argv(const char *, int, PTEST_CTX *,
+ const char *, const ARGV *, const ARGV *);
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+#endif
--- /dev/null
+#ifndef _MOCK_DNS_H_INCLUDED_
+#define _MOCK_DNS_H_INCLUDED_
+
+/*++
+/* NAME
+/* mock_dns 3h
+/* SUMMARY
+/* emulate DNS support for hermetic tests
+/* SYNOPSIS
+/* #include <mock_dns.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * DNS library.
+ */
+#include <dns.h>
+
+ /*
+ * Test library.
+ */
+#include <ptest.h>
+
+ /*
+ * Manage expectations and responses. Capture the source file name and line
+ * number for better diagnostics.
+ */
+#define expect_dns_lookup_x(exp_calls, herrval, retval, name, type, rflags, \
+ list, fqdn, why, rcode, lflags) \
+ _expect_dns_lookup_x(__FILE__, __LINE__, (exp_calls), (herrval), \
+ (retval), (name), (type), (rflags), (list), \
+ (fqdn), (why), (rcode), (lflags))
+
+extern void _expect_dns_lookup_x(const char *, int, int, int, int,
+ const char *, unsigned, unsigned, DNS_RR *,
+ VSTRING *, VSTRING *, int, unsigned);
+
+ /*
+ * Matcher predicates. Capture the source file name and line number for
+ * better diagnostics.
+ */
+#define eq_dns_rr(t, what, got, want) _eq_dns_rr((t), __FILE__, __LINE__, \
+ (what), (got), (want))
+
+extern int _eq_dns_rr(PTEST_CTX *, const char *, int, const char *, DNS_RR *, DNS_RR *);
+
+ /*
+ * Helper to create test data.
+ */
+extern DNS_RR *make_dns_rr(const char *, const char *, unsigned, unsigned,
+ unsigned, unsigned, unsigned,
+ void *, size_t);
+
+ /*
+ * Other helper.
+ */
+extern const char *dns_status_to_string(int);
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+#endif
--- /dev/null
+/*++
+/* NAME
+/* mock_dns_lookup 3
+/* SUMMARY
+/* dns_lookup mock for hermetic tests
+/* SYNOPSIS
+/* #include <mock_dns_lookup.h>
+/*
+/* int dns_lookup_x(
+/* const char *name,
+/* unsigned type,
+/* unsigned rflags,
+/* DNS_RR **list,
+/* VSTRING *fqdn,
+/* VSTRING *why,
+/* int *rcode,
+/* unsigned lflags)
+/*
+/* int dns_get_h_errno(void)
+/*
+/* void dns_set_h_errno(int herrval)
+/* EXPECTATION SETUP
+/* void expect_dns_lookup_x(
+/* int calls_expected,
+/* int herrval,
+/* int retval,
+/* const char *name,
+/* unsigned type,
+/* unsigned flags,
+/* DNS_RR *rrlist,
+/* VSTRING *fqdn,
+/* VSTRING *why,
+/* int rcode,
+/* unsigned lflags)
+/*
+/* DNS_RR *make_dns_rr(
+/* const char *qname,
+/* const char *rname,
+/* unsigned type,
+/* unsigned class,
+/* unsigned ttl,
+/* unsigned dnssec_valid,
+/* unsigned pref,
+/* void *data,
+/* size_t data_len)
+/* MATCHERS
+/* int eq_dns_rr(
+/* PTEST_CTX *t,
+/* const char *what,
+/* DNS_RR *got,
+/* DNS_RR *want)
+/* OTHER HELPERS
+/* const char *dns_status_to_string(int status)
+/* DESCRIPTION
+/* This module implements a mock dns_lookup_x() lookup function
+/* that produces prepared outputs in response to expected
+/* inputs. This supports hermetic tests, i.e. tests that do
+/* not depend on host configuration or on network access.
+/*
+/* expect_dns_lookup_x() makes deep copies of its input
+/* arguments, and of the arguments that specify prepared
+/* outputs. The herrval argument specifies a prepared
+/* dns_get_h_errno() result value, and the retval argument
+/* specifies a prepared dns_lookup_x() result value. The
+/* calls_expected argument specifies the expected number of
+/* dns_lookup_x() calls (zero means one or more calls, not:
+/* zero calls).
+/*
+/* dns_get_h_errno() returns an error value that is configured
+/* with expect_dns_lookup_x(), and that is assigned when
+/* dns_lookup_x() or dns_set_h_errno() are called.
+/*
+/* dns_set_h_errno() assigns the dns_get_h_errno() result
+/* value.
+/*
+/* make_dns_rr() is a wrapper around dns_rr_create() that also
+/* controls the dnssec_valid flag.
+/*
+/* eq_dns_rr() is a predicate that compares its arguments
+/* (linked lists) for equality. If t is not null, the what
+/* argument is used in logging when the inputs differ.
+/* DIAGNOSTICS
+/* If a mock is called unexpectedly (the call arguments do not
+/* match an expectation, or more calls are made than expected),
+/* a warning is logged, and the test will be flagged as failed.
+/* For now the mock returns an error result to the caller.
+/* TODO: consider aborting the test.
+/* SEE ALSO
+/* dns_lookup(3), domain name service lookup
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+
+ /*
+ * Utility library.
+ */
+#include <mymalloc.h>
+#include <msg.h>
+#include <vstring.h>
+#include <stringops.h>
+#include <hex_code.h>
+#include <name_code.h>
+
+ /*
+ * DNS library.
+ */
+#include <dns.h>
+
+ /*
+ * Test library.
+ */
+#include <mock_dns.h>
+#include <pmock_expect.h>
+#include <ptest.h>
+
+ /*
+ * Helpers.
+ */
+#define MYSTRDUP_OR_NULL(x) ((x) ? mystrdup(x) : 0)
+#define VSTRDUP_OR_NULL(x) \
+ ((x) ? vstring_strcpy(vstring_alloc(VSTRING_LEN(x)), vstring_str(x)) : 0)
+
+#define STR(x) vstring_str(x)
+
+#define STR_OR_NULL(s) ((s) ? (s) : "(null)")
+#define VSTR_STR_OR_NULL(s) ((s) ? STR(s) : "(null)")
+
+ /*
+ * Local state for the mock functions dns_get_herrno() and dns_set_herrno(),
+ * also updated when the mock function dns_lookup_x() is called.
+ *
+ * XXX This could leak information when tests are run successively in the same
+ * process. Should the test infrastructure fork() the process before each
+ * test? Leakage will not happen when each test calls a function that resets
+ * global_herrval.
+ */
+static int global_herrval = ~0;
+
+/* dns_status_to_string - convert status code to string */
+
+const char *dns_status_to_string(int status)
+{
+ static const NAME_CODE status_string[] = {
+ "DNS_OK", DNS_OK,
+ "DNS_POLICY", DNS_POLICY,
+ "DNS_RETRY", DNS_RETRY,
+ "DNS_INVAL", DNS_INVAL,
+ "DNS_FAIL", DNS_FAIL,
+ "DNS_NULLMX", DNS_NULLMX,
+ "DNS_NOTFOUND", DNS_NOTFOUND,
+ 0,
+ };
+
+ return (str_name_code(status_string, status));
+}
+
+/* copy_dns_rrlist - deep copy */
+
+static DNS_RR *copy_dns_rrlist(DNS_RR *list)
+{
+ DNS_RR *rr;
+
+ if (list == 0)
+ return (0);
+ rr = dns_rr_copy(list);
+ rr->next = copy_dns_rrlist(list->next);
+ return (rr);
+}
+
+/* make_dns_rr - dns_rr_create() wrapper */
+
+DNS_RR *make_dns_rr(const char *qname, const char *rname, unsigned type,
+ unsigned class, unsigned ttl,
+ unsigned dnssec_valid, unsigned pref,
+ void *data, size_t data_len)
+{
+ DNS_RR *rr;
+
+ rr = dns_rr_create(qname, rname, type, class, ttl, pref, data, data_len);
+ rr->dnssec_valid = dnssec_valid;
+ return (rr);
+}
+
+/* _eq_dns_rr - equality predicate */
+
+int _eq_dns_rr(PTEST_CTX *t, const char *file, int line,
+ const char *what,
+ DNS_RR *got, DNS_RR *want)
+{
+ if (got == 0 && want == 0) {
+ return (1);
+ }
+ if (got == 0 || want == 0) {
+ if (t)
+ ptest_error(t, "%s:%d %s: got %s, want %s",
+ file, line, what, got ? "(DNS_RR *)" : "(null)",
+ want ? "(DNS_RR *)" : "(null)");
+ return (0);
+ }
+ if (strcmp(got->qname, want->qname) != 0) {
+ if (t)
+ ptest_error(t, "%s:%d %s: got qname '%s', want '%s'",
+ file, line, what, got->qname, want->qname);
+ return (0);
+ }
+ if (strcmp(got->rname, want->rname) != 0) {
+ if (t)
+ ptest_error(t, "%s:%d %s: got rname '%s', want '%s'",
+ file, line, what, got->rname, want->rname);
+ return (0);
+ }
+ if (got->type != want->type) {
+ if (t)
+ ptest_error(t, "%s:%d %s: got type %d, want %d",
+ file, line, what, got->type, want->type);
+ return (0);
+ }
+ if (got->class != want->class) {
+ if (t)
+ ptest_error(t, "%s:%d %s: got class %d, want %d",
+ file, line, what, got->class, want->class);
+ return (0);
+ }
+ if (got->ttl != want->ttl) {
+ if (t)
+ ptest_error(t, "%s:%d %s: got ttl %d, want %d",
+ file, line, what, got->ttl, want->ttl);
+ return (0);
+ }
+ if (got->dnssec_valid != want->dnssec_valid) {
+ if (t)
+ ptest_error(t, "%s:%d %s: got dnssec_valid %d, want %d",
+ file, line, what, got->dnssec_valid, want->dnssec_valid);
+ return (0);
+ }
+ if (got->pref != want->pref) {
+ if (t)
+ ptest_error(t, "%s:%d %s: got pref %d, want %d",
+ file, line, what, got->pref, want->pref);
+ return (0);
+ }
+ if (got->data_len != want->data_len) {
+ if (t)
+ ptest_error(t, "%s:%d %s: got data_len %d, want %d",
+ file, line, what, (int) got->data_len, (int) want->data_len);
+ return (0);
+ }
+ if (memcmp(got->data, want->data, got->data_len) != 0) {
+ VSTRING *got_data_hex = vstring_alloc(100);
+ VSTRING *want_data_hex = vstring_alloc(100);
+
+ if (t)
+ ptest_error(t, "%s:%d %s: got data %s, want %s",
+ file, line, what, STR(hex_encode_opt(got_data_hex, got->data,
+ got->data_len, HEX_ENCODE_FLAG_USE_COLON)),
+ STR(hex_encode_opt(want_data_hex, want->data,
+ want->data_len, HEX_ENCODE_FLAG_USE_COLON)));
+ vstring_free(got_data_hex);
+ vstring_free(want_data_hex);
+ return (0);
+ }
+ return (_eq_dns_rr(t, file, line, what, got->next, want->next));
+}
+
+ /*
+ * Manage dns_lookup_x() expectations and responses. We use this structure
+ * for deep copies of expect_dns_lookup_x() expected inputs and prepared
+ * responses, and for shallow copies of dns_lookup_x() inputs.
+ */
+struct dns_lookup_x_expectation {
+ MOCK_EXPECT mock_expect; /* generic fields */
+ int herrval; /* h_errno value */
+ int retval; /* result value */
+ char *name; /* inputs */
+ unsigned type;
+ unsigned flags;
+ unsigned lflags;
+ DNS_RR *rrlist; /* outputs */
+ VSTRING *fqdn;
+ VSTRING *why;
+ int rcode;
+};
+
+ /*
+ * Pointers to dns_lookup_x() outputs.
+ */
+struct dns_lookup_x_targets {
+ int *herrval;
+ int *retval;
+ DNS_RR **rrlist;
+ VSTRING *fqdn;
+ VSTRING *why;
+ int *rcode;
+};
+
+/* match_dns_lookup_x - match inputs against expectation */
+
+static int match_dns_lookup_x(const MOCK_EXPECT *expect,
+ const MOCK_EXPECT *inputs)
+{
+ struct dns_lookup_x_expectation *pe =
+ (struct dns_lookup_x_expectation *) expect;
+ struct dns_lookup_x_expectation *pi =
+ (struct dns_lookup_x_expectation *) inputs;
+
+ return (strcmp(STR_OR_NULL(pe->name),
+ STR_OR_NULL(pi->name)) == 0
+ && pe->type == pi->type
+ && pe->flags == pi->flags
+ && pe->lflags == pi->lflags);
+}
+
+/* assign_dns_lookup_x - assign expected output */
+
+static void assign_dns_lookup_x(const MOCK_EXPECT *expect,
+ void *targets)
+{
+ struct dns_lookup_x_expectation *pe =
+ (struct dns_lookup_x_expectation *) expect;
+ struct dns_lookup_x_targets *pt =
+ (struct dns_lookup_x_targets *) targets;
+
+ if (pe->retval == DNS_OK) {
+ if (pt->rrlist)
+ *(pt->rrlist) = copy_dns_rrlist(pe->rrlist);
+ if (pt->fqdn && pe->fqdn)
+ vstring_strcpy(pt->fqdn, STR(pe->fqdn));
+ } else {
+ if (pt->why && pe->why)
+ vstring_strcpy(pt->why, STR(pe->why));
+ }
+ if (pt->rcode)
+ *pt->rcode = pe->rcode;
+ *pt->retval = pe->retval;
+ *pt->herrval = pe->herrval;
+}
+
+/* print_dns_lookup_x - print expected inputs */
+
+static char *print_dns_lookup_x(const MOCK_EXPECT *expect,
+ VSTRING *buf)
+{
+ struct dns_lookup_x_expectation *pe =
+ (struct dns_lookup_x_expectation *) expect;
+
+ vstring_sprintf(buf, "\"%s\", %s, %d, (ptr), (ptr), (ptr), (ptr), %d",
+ STR_OR_NULL(pe->name), dns_strtype(pe->type),
+ pe->flags, pe->lflags);
+ return (STR(buf));
+}
+
+/* free_dns_lookup_x - destructor */
+
+static void free_dns_lookup_x(MOCK_EXPECT *expect)
+{
+ struct dns_lookup_x_expectation *pe =
+ (struct dns_lookup_x_expectation *) expect;
+
+ myfree(pe->name);
+ if (pe->retval == DNS_OK) {
+ if (pe->rrlist)
+ dns_rr_free(pe->rrlist);
+ if (pe->fqdn)
+ vstring_free(pe->fqdn);
+ } else {
+ if (pe->why)
+ vstring_free(pe->why);
+ }
+ pmock_expect_free(expect);
+}
+
+ /*
+ * The mock name and its helper callbacks in one place.
+ */
+static const MOCK_APPL_SIG dns_lookup_x_sig = {
+ "dns_lookup_x",
+ match_dns_lookup_x,
+ assign_dns_lookup_x,
+ print_dns_lookup_x,
+ free_dns_lookup_x,
+};
+
+/* _expect_dns_lookup_x - set up expectation */
+
+void _expect_dns_lookup_x(const char *file, int line, int calls_expected,
+ int herrval, int retval,
+ const char *name, unsigned type, unsigned flags,
+ DNS_RR *rrlist, VSTRING *fqdn, VSTRING *why,
+ int rcode, unsigned lflags)
+{
+ struct dns_lookup_x_expectation *pe;
+
+ pe = (struct dns_lookup_x_expectation *)
+ pmock_expect_create(&dns_lookup_x_sig,
+ file, line, calls_expected, sizeof(*pe));
+
+ /*
+ * Inputs.
+ */
+ pe->name = MYSTRDUP_OR_NULL(name);
+ pe->type = type;
+ pe->flags = flags;
+ pe->lflags = lflags;
+
+ /*
+ * Outputs.
+ */
+ pe->herrval = herrval;
+ pe->retval = retval;
+ if (pe->retval == DNS_OK) {
+ pe->rrlist = copy_dns_rrlist(rrlist);
+ pe->fqdn = VSTRDUP_OR_NULL(fqdn);
+ } else {
+ pe->why = VSTRDUP_OR_NULL(why);
+ }
+ pe->rcode = rcode;
+}
+
+/* dns_lookup_x - answer the call with prepared responses */
+
+int dns_lookup_x(const char *name, unsigned type, unsigned flags,
+ DNS_RR **rrlist, VSTRING *fqdn, VSTRING *why,
+ int *rcode, unsigned lflags)
+{
+ struct dns_lookup_x_expectation inputs;
+ struct dns_lookup_x_targets targets;
+ int retval = DNS_FAIL;
+
+ /*
+ * Bundle the arguments to simplify handling.
+ */
+ inputs.name = (char *) name;
+ inputs.type = type;
+ inputs.flags = flags;
+ inputs.lflags = lflags;
+
+ targets.herrval = &global_herrval;
+ targets.retval = &retval;
+ targets.rrlist = rrlist;
+ targets.fqdn = fqdn;
+ targets.why = why;
+ targets.rcode = rcode;
+
+ /*
+ * Aargh.
+ */
+ if (rrlist)
+ *rrlist = 0;
+
+ /*
+ * TODO: bail out if there was no match?
+ */
+ (void) pmock_expect_apply(&dns_lookup_x_sig,
+ &inputs.mock_expect, (void *) &targets);
+ return (retval);
+}
+
+/* dns_get_h_errno - return prepared answer */
+
+int dns_get_h_errno(void)
+{
+ return (global_herrval);
+}
+
+/* dns_set_h_errno - return prepared answer */
+
+void dns_set_h_errno(int herrval)
+{
+ global_herrval = herrval;
+}
--- /dev/null
+ /*
+ * Test program to exercise mocks including logging. See comments in
+ * ptest_main.h and pmock_expect_test.c for a documented example.
+ */
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <arpa/inet.h>
+
+ /*
+ * Utility library.
+ */
+#include <msg.h>
+#include <vstring.h>
+
+ /*
+ * Test library.
+ */
+#include <mock_dns.h>
+#include <pmock_expect.h>
+#include <ptest.h>
+
+typedef struct PTEST_CASE {
+ const char *testname; /* Human-readable description */
+ void (*action) (PTEST_CTX *t, const struct PTEST_CASE *);
+} PTEST_CASE;
+
+#define NO_RES_FLAGS 0
+
+static void test_dns_lookup_x_success(PTEST_CTX *t, const PTEST_CASE *unused)
+{
+ VSTRING *got_fqdn = vstring_alloc(100), *want_fqdn = vstring_alloc(100);
+ int got_st, want_st = DNS_OK;
+ int got_herrval, want_herrval = 0;
+ DNS_RR *got_rr = 0, *want_rr;
+ int got_rcode, want_rcode = NOERROR;
+ struct in_addr sin_addr;
+ const char *localhost = "localhost";
+
+ /*
+ * Set up expectations.
+ */
+ vstring_strcpy(want_fqdn, localhost);
+ if (inet_pton(AF_INET, "127.0.0.1", &sin_addr) != 1)
+ ptest_fatal(t, "inet_pton(AF_INET, \"127.0.0.1\", (ptr)): bad address");
+ want_rr = make_dns_rr(localhost, localhost, T_A, C_IN,
+ 10, 0, 0, &sin_addr, sizeof(sin_addr));
+ expect_dns_lookup_x(1, want_herrval, want_st, localhost, T_A, NO_RES_FLAGS,
+ want_rr, want_fqdn, (VSTRING *) 0,
+ want_rcode, DNS_REQ_FLAG_NONE);
+
+ /*
+ * Invoke the mock and verify results.
+ */
+ got_st = dns_lookup_x("localhost", T_A, NO_RES_FLAGS, &got_rr,
+ got_fqdn, (VSTRING *) 0, &got_rcode,
+ DNS_REQ_FLAG_NONE);
+ if (got_st != want_st) {
+ ptest_error(t, "dns_lookup_x: got result %d, want %d", got_st, want_st);
+ } else if (eq_dns_rr(t, "dns_lookup_x", got_rr, want_rr) == 0) {
+ /* warning is already logged */ ;
+ } else if (strcmp(vstring_str(got_fqdn), vstring_str(want_fqdn)) != 0) {
+ ptest_error(t, "dns_lookup_x: got fqdn '%s', want '%s'",
+ vstring_str(got_fqdn), vstring_str(want_fqdn));
+ } else if (got_rcode != want_rcode) {
+ ptest_error(t, "dns_lookup_x: got rcode %d, want %d", got_rcode, want_rcode);
+ }
+ got_herrval = dns_get_h_errno();
+ if (got_herrval != want_herrval)
+ ptest_error(t, "dns_get_h_errno: got %d, want %d",
+ got_herrval, want_herrval);
+
+ /*
+ * Clean up.
+ */
+ vstring_free(got_fqdn);
+ vstring_free(want_fqdn);
+ dns_rr_free(want_rr);
+ if (got_rr)
+ dns_rr_free(got_rr);
+}
+
+static void test_dns_lookup_x_notexist(PTEST_CTX *t, const PTEST_CASE *unused)
+{
+ VSTRING *got_why = vstring_alloc(100), *want_why = vstring_alloc(100);
+ int got_st, want_st = DNS_NOTFOUND;
+ int got_herrval, want_herrval = HOST_NOT_FOUND;
+ int got_rcode, want_rcode = NXDOMAIN;
+
+ /*
+ * Set up expectations.
+ */
+ vstring_strcpy(want_why, "Host or domain name not found."
+ " Name service error for name=notexist type=A: Host not found");
+ expect_dns_lookup_x(1, want_herrval, want_st, "notexist", T_A, NO_RES_FLAGS,
+ (DNS_RR *) 0, (VSTRING *) 0, want_why, want_rcode,
+ DNS_REQ_FLAG_NONE);
+
+ /*
+ * Invoke the mock and verify results.
+ */
+ got_st = dns_lookup_x("notexist", T_A, NO_RES_FLAGS, (DNS_RR **) 0,
+ (VSTRING *) 0, got_why, &got_rcode,
+ DNS_REQ_FLAG_NONE);
+ if (got_st != want_st) {
+ ptest_error(t, "dns_lookup_x: got result %d, want %d", got_st, want_st);
+ } else if (got_rcode != want_rcode) {
+ ptest_error(t, "dns_lookup_x: got rcode %d, want %d", got_rcode, want_rcode);
+ } else if (strcmp(vstring_str(got_why), vstring_str(want_why)) != 0) {
+ ptest_error(t, "dns_lookup_x: got why '%s', want '%s'",
+ vstring_str(got_why), vstring_str(want_why));
+ }
+ got_herrval = dns_get_h_errno();
+ if (got_herrval != want_herrval)
+ ptest_error(t, "dns_get_h_errno: got %d, want %d",
+ got_herrval, want_herrval);
+
+ /*
+ * Clean up.
+ */
+ vstring_free(got_why);
+ vstring_free(want_why);
+}
+
+static void test_dns_lookup_x_unused(PTEST_CTX *t, const PTEST_CASE *unused)
+{
+
+ /*
+ * Create an expectation, without calling it. I does not matter what the
+ * expectation is, so we use the one from test_dns_lookup_x_notexist().
+ */
+ expect_dns_lookup_x(1, HOST_NOT_FOUND, NXDOMAIN, "notexist", T_A, NO_RES_FLAGS,
+ (DNS_RR *) 0, (VSTRING *) 0, (VSTRING *) 0, 0,
+ DNS_REQ_FLAG_NONE);
+
+ /*
+ * We expect that there will be a 'missing call' error. If the error does
+ * not happen then the test fails.
+ */
+ expect_ptest_error(t, "got 0 calls for dns_lookup_x(\"notexist\", A, "
+ "0, (ptr), (ptr), (ptr), (ptr), 0), want 1");
+}
+
+static void test_dns_set_h_errno_success(PTEST_CTX *t, const PTEST_CASE *unused)
+{
+ static int want_herrval[] = {12345, 54321};
+ int got_herrval;
+ int n;
+
+ for (n = 0; n < 2; n++) {
+ dns_set_h_errno(want_herrval[n]);
+ got_herrval = dns_get_h_errno();
+ if (got_herrval != want_herrval[n])
+ ptest_error(t, "dns_get_h_errno: got %d, want %d",
+ got_herrval, want_herrval[n]);
+ }
+}
+
+static void test_eq_dns_rr_differ(PTEST_CTX *t, const PTEST_CASE *unused)
+{
+ DNS_RR *got_rr, *want_rr;
+ struct in_addr sin_addr;
+ const char *localhost = "localhost";
+
+ if (inet_pton(AF_INET, "127.0.0.1", &sin_addr) != 1)
+ ptest_fatal(t, "inet_pton(AF_INET, \"127.0.0.1\", (ptr)): bad address");
+ want_rr = make_dns_rr(localhost, localhost, T_A, C_IN,
+ 10, 0, 0, &sin_addr, sizeof(sin_addr));
+
+ if (inet_pton(AF_INET, "127.0.0.2", &sin_addr) != 1)
+ ptest_fatal(t, "inet_pton(AF_INET, \"127.0.0.2\", (ptr)): bad address");
+ got_rr = make_dns_rr(localhost, localhost, T_A, C_IN,
+ 10, 0, 0, &sin_addr, sizeof(sin_addr));
+
+ expect_ptest_error(t, "eq_dns_rr: got data 7F:00:00:02, want 7F:00:00:01");
+ if (eq_dns_rr(t, "eq_dns_rr", got_rr, want_rr))
+ ptest_error(t, "eq_dns_rr: Unexpected match");
+ dns_rr_free(got_rr);
+ dns_rr_free(want_rr);
+}
+
+ /*
+ * Test cases. The "success" tests exercise the expectation match and apply
+ * helpers, and "unused" tests exercise the print helpers.
+ */
+const PTEST_CASE ptestcases[] = {
+ {
+ "test_dns_lookup_x success", test_dns_lookup_x_success,
+ },
+ {
+ "test_dns_lookup_x notexist", test_dns_lookup_x_notexist,
+ },
+ {
+ "test_dns_lookup_x unused", test_dns_lookup_x_unused,
+ },
+ {
+ "dns_set_h_errno success", test_dns_set_h_errno_success,
+ },
+ {
+ "test_eq_dns_rr differ", test_eq_dns_rr_differ,
+ },
+};
+
+#include <ptest_main.h>
--- /dev/null
+/*++
+/* NAME
+/* mock_getaddrinfo 3
+/* SUMMARY
+/* mock getaddrinfo/getnameinfo for hermetic tests
+/* SYNOPSIS
+/* #include <mock_getaddrinfo.h>
+/*
+/* int getaddrinfo(
+/* const char *hostname,
+/* const char *servname,
+/* const struct addrinfo *hints,
+/* struct addrinfo **result,
+/*
+/* int getnameinfo(
+/* const struct sockaddr *sa,
+/* size_t salen,
+/* char *host,
+/* size_t hostlen,
+/* char *serv,
+/* size_t servlen
+/* int flags)
+/* EXPECTATION SETUP
+/* void expect_getaddrinfo(
+/* int calls_expected,
+/* int retval,
+/* const char *hostname,
+/* const char *servname,
+/* const struct addrinfo *hints,
+/* struct addrinfo *result)
+/*
+/* void expect_getnameinfo(
+/* int calls_expected,
+/* int retval,
+/* const struct sockaddr *sa,
+/* size_t salen,
+/* char *host,
+/* size_t hostlen,
+/* char *serv,
+/* size_t servlen
+/* int flags)
+/* TEST DATA
+/* struct addrinfo *make_addrinfo(
+/* const struct addrinfo *hints,
+/* const char *name,
+/* const char *addr,
+/* int port)
+/*
+/* struct addrinfo *copy_addrinfo(const struct addrinfo *ai)
+/*
+/* void freeaddrinfo(struct addrinfo *ai)
+/*
+/* struct sockaddr *make_sockaddr(
+/* int family,
+/* const char *addr,
+/* int port)
+/*
+/* void free_sockaddr(struct sockaddr *sa)
+/* MATCHERS
+/* int eq_addrinfo(
+/* PTEST_CTX * t,
+/* const char *what,
+/* struct addrinfo got,
+/* struct addrinfo want)
+/*
+/* int eq_sockaddr
+/* PTEST_CTX * t,
+/* const char *what,
+/* const struct sockaddr *got,
+/* size_t gotlen,
+/* const struct sockaddr *want,
+/* size_t wantlen)
+/* DESCRIPTION
+/* This module implements mock system library functions that
+/* produce prepared outputs in response to expected inputs.
+/* This supports hermetic tests, i.e. tests that do not depend
+/* on host configuration or on network access.
+/*
+/* The "expect_" functions take expected inputs and corresponding
+/* outputs. They make deep copies of their arguments, including
+/* "struct addrinfo *" linked lists. The retval argument
+/* specifies a prepared result value. The calls_expected
+/* argument specifies the expected number of calls (zero means
+/* one or more calls, not: zero calls).
+/*
+/* make_addrinfo() creates one addrinfo structure. To create
+/* linked list, manually append make_addrinfo() results.
+/*
+/* copy_addrinfo() makes a deep copy of a linked list of
+/* addrinfo structures.
+/*
+/* freeaddrinfo() deletes a linked list of addrinfo structures.
+/* This function must be used for addrinfo structures created
+/* with make_addrinfo() and copy_addrinfo().
+/*
+/* make_sockaddr() creates a sockaddr structure from the string
+/* representation of an IP address.
+/*
+/* free_sockaddr() exists to make program code more explicit.
+/*
+/* eq_addrinfo() compares addrinfo linked lists and reports
+/* differences with ptest_error(). The what argument provides
+/* context. Specify a null test context for silent operation.
+/*
+/* eq_sockaddr() compares sockaddr instances and reports
+/* differences with ptest_error(). The what argument provides
+/* context. Specify a null test context for silent operation.
+/*
+/* append_addrinfo_to_string() appends a textual representation
+/* of the referenced addrinfo to the specified buffer.
+/*
+/* addrinfo_hints_to_string() writes a textual representation of
+/* the referenced getaddrinfo() hints object.
+/*
+/* sockaddr_to_string() writes a textual representation of the
+/* referenced sockaddr object.
+/*
+/* pf_to_string(), af_to_string(), socktype_to_string,
+/* ipprotocol_to_string, ai_flags_to_string(), ni_flags_to_string()
+/* produce a textual representation of addrinfo properties or
+/* getnameinfo() flags.
+/* DIAGNOSTICS
+/* If a mock is called unexpectedly (the call arguments do not
+/* match any expectation, or they do match, but more calls are
+/* made than were expected), a warning is logged, and the test
+/* will be flagged as failed. For now the mock returns an error
+/* result to the caller. TODO: consider aborting the test.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <wrap_netdb.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h> /* sprintf/snprintf */
+
+ /*
+ * Utility library.
+ */
+#include <msg.h>
+#include <myaddrinfo.h>
+#include <mymalloc.h>
+
+ /*
+ * Test library.
+ */
+#include <mock_getaddrinfo.h>
+#include <pmock_expect.h>
+#include <ptest.h>
+
+#define MYSTRDUP_OR_NULL(x) ((x) ? mystrdup(x) : 0)
+#define STR_OR_NULL(s) ((s) ? (s) : "(null)")
+
+#define STR vstring_str
+
+ /*
+ * Manage getaddrinfo() expectations and responses. We use this structure
+ * for deep copies of expect_getaddrinfo() expected inputs and prepared
+ * responses, and for shallow copies of getaddrinfo() inputs, so that we can
+ * reuse the print_getaddrinfo() helper.
+ */
+struct getaddrinfo_expectation {
+ MOCK_EXPECT mock_expect; /* generic fields */
+ int retval; /* result value */
+ char *node; /* inputs */
+ char *service;
+ struct addrinfo *hints;
+ struct addrinfo *res; /* outputs */
+};
+
+ /*
+ * Pointers to getaddrinfo() outputs.
+ */
+struct getaddrinfo_targets {
+ struct addrinfo **res;
+ int *retval;
+};
+
+/* match_getaddrinfo - match inputs against expectation */
+
+static int match_getaddrinfo(const MOCK_EXPECT *expect,
+ const MOCK_EXPECT *inputs)
+{
+ struct getaddrinfo_expectation *pe =
+ (struct getaddrinfo_expectation *) expect;
+ struct getaddrinfo_expectation *pi =
+ (struct getaddrinfo_expectation *) inputs;
+
+ return (strcmp(STR_OR_NULL(pe->node), STR_OR_NULL(pi->node)) == 0
+ && strcmp(STR_OR_NULL(pe->service), STR_OR_NULL(pi->service)) == 0
+ && eq_addrinfo((PTEST_CTX *) 0, (char *) 0, pe->hints, pi->hints));
+}
+
+/* assign_getaddrinfo - assign expected output */
+
+static void assign_getaddrinfo(const MOCK_EXPECT *expect, void *targets)
+{
+ struct getaddrinfo_expectation *pe =
+ (struct getaddrinfo_expectation *) expect;
+ struct getaddrinfo_targets *pt =
+ (struct getaddrinfo_targets *) targets;
+
+ if (pe->retval == 0)
+ *(pt->res) = copy_addrinfo(pe->res);
+ *pt->retval = pe->retval;
+}
+
+/* print_getaddrinfo - print expected inputs */
+
+static char *print_getaddrinfo(const MOCK_EXPECT *expect, VSTRING *buf)
+{
+ struct getaddrinfo_expectation *pe =
+ (struct getaddrinfo_expectation *) expect;
+ VSTRING *hints_buf = vstring_alloc(100);
+
+ vstring_sprintf(buf, "\"%s\", \"%s\", %s, (ptr)",
+ STR_OR_NULL(pe->node),
+ STR_OR_NULL(pe->service),
+ addrinfo_hints_to_string(hints_buf, pe->hints));
+ vstring_free(hints_buf);
+ return (vstring_str(buf));
+}
+
+/* free_getaddrinfo - destructor */
+
+static void free_getaddrinfo(MOCK_EXPECT *expect)
+{
+ struct getaddrinfo_expectation *pe =
+ (struct getaddrinfo_expectation *) expect;
+
+ if (pe->node)
+ myfree(pe->node);
+ if (pe->service)
+ myfree(pe->service);
+ if (pe->hints)
+ myfree(pe->hints);
+ if (pe->retval == 0)
+ freeaddrinfo(pe->res);
+ pmock_expect_free(expect);
+}
+
+ /*
+ * The mock name and its helper callbacks in one place.
+ */
+static const MOCK_APPL_SIG getaddrinfo_sig = {
+ "getaddrinfo",
+ match_getaddrinfo,
+ assign_getaddrinfo,
+ print_getaddrinfo,
+ free_getaddrinfo,
+};
+
+/* _expect_getaddrinfo - set up expectation */
+
+void _expect_getaddrinfo(const char *file, int line,
+ int calls_expected, int retval,
+ const char *node,
+ const char *service,
+ const struct addrinfo *hints,
+ struct addrinfo *res)
+{
+ struct getaddrinfo_expectation *pe;
+
+ pe = (struct getaddrinfo_expectation *)
+ pmock_expect_create(&getaddrinfo_sig,
+ file, line, calls_expected, sizeof(*pe));
+ pe->retval = retval;
+ pe->node = MYSTRDUP_OR_NULL(node);
+ pe->service = MYSTRDUP_OR_NULL(service);
+ pe->hints = copy_addrinfo(hints);
+ if (pe->retval == 0)
+ pe->res = copy_addrinfo(res);
+}
+
+/* getaddrinfo - mock getaddrinfo */
+
+int getaddrinfo(const char *node,
+ const char *service,
+ const struct addrinfo *hints,
+ struct addrinfo **res)
+{
+ struct getaddrinfo_expectation inputs;
+ struct getaddrinfo_targets targets;
+ int retval = EAI_FAIL;
+
+ /*
+ * Bundle the arguments to simplify handling.
+ */
+ inputs.node = (char *) node;
+ inputs.service = (char *) service;
+ inputs.hints = (struct addrinfo *) hints;
+
+ targets.res = res;
+ targets.retval = &retval;
+
+ /*
+ * TODO: bail out if there was no match?
+ */
+ (void) pmock_expect_apply(&getaddrinfo_sig,
+ &inputs.mock_expect, (void *) &targets);
+ return (retval);
+}
+
+ /*
+ * Manage getnameinfo() expectations and responses. We use this structure
+ * for deep copies of expect_getnameinfo() expected inputs and prepared
+ * responses, and for shallow copies of getnameinfo() inputs, so that we can
+ * reuse the print_getnameinfo() helper.
+ */
+struct getnameinfo_expectation {
+ MOCK_EXPECT mock_expect; /* generic fields */
+ int retval; /* result value */
+ struct sockaddr *sa; /* inputs */
+ size_t salen;
+ char *host; /* outputs */
+ size_t hostlen;
+ char *serv;
+ size_t servlen;
+ int flags; /* other input */
+};
+
+ /*
+ * Pointers to getnameinfo() outputs.
+ */
+struct getnameinfo_targets {
+ char *host;
+ size_t hostlen;
+ char *serv;
+ size_t servlen;
+ int *retval;
+};
+
+/* match_getnameinfo - match inputs against expectation */
+
+static int match_getnameinfo(const MOCK_EXPECT *expect,
+ const MOCK_EXPECT *inputs)
+{
+ struct getnameinfo_expectation *pe =
+ (struct getnameinfo_expectation *) expect;
+ struct getnameinfo_expectation *pi =
+ (struct getnameinfo_expectation *) inputs;
+
+ return (eq_sockaddr((PTEST_CTX *) 0, (char *) 0,
+ pe->sa, pe->salen, pi->sa, pi->salen)
+ && pe->flags == pi->flags);
+}
+
+/* assign_getnameinfo - assign expected output */
+
+static void assign_getnameinfo(const MOCK_EXPECT *expect, void *targets)
+{
+ struct getnameinfo_expectation *pe =
+ (struct getnameinfo_expectation *) expect;
+ struct getnameinfo_targets *pt =
+ (struct getnameinfo_targets *) targets;
+
+#define MIN_OF(x,y) ((x) < (y) ? (x) : (y))
+
+ if (pe->retval == 0) {
+ if (pt->host && pe->host) {
+ strncpy(pt->host, pe->host, MIN_OF(pt->hostlen, pe->hostlen));
+ pt->host[pt->hostlen - 1] = 0;
+ }
+ if (pt->serv && pe->serv) {
+ strncpy(pt->serv, pe->serv, MIN_OF(pt->servlen, pe->servlen));
+ pt->serv[pt->servlen - 1] = 0;
+ }
+ }
+ *pt->retval = pe->retval;
+}
+
+/* print_getnameinfo - print inputs */
+
+static char *print_getnameinfo(const MOCK_EXPECT *expect, VSTRING *buf)
+{
+ struct getnameinfo_expectation *pe =
+ (struct getnameinfo_expectation *) expect;
+ VSTRING *sockaddr_buf = vstring_alloc(100);
+ VSTRING *flags_buf = vstring_alloc(100);
+
+ vstring_sprintf(buf, "%s, %ld, (ptr), (len), (ptr), (len), %s",
+ sockaddr_to_string(sockaddr_buf, pe->sa, pe->salen),
+ (long) pe->salen,
+ ni_flags_to_string(flags_buf, pe->flags));
+ vstring_free(sockaddr_buf);
+ vstring_free(flags_buf);
+ return (STR(buf));
+}
+
+/* free_getnameinfo - destructor */
+
+static void free_getnameinfo(MOCK_EXPECT *expect)
+{
+ struct getnameinfo_expectation *pe =
+ (struct getnameinfo_expectation *) expect;
+
+ if (pe->sa)
+ myfree(pe->sa);
+ if (pe->host)
+ myfree(pe->host);
+ if (pe->serv)
+ myfree(pe->serv);
+ pmock_expect_free(expect);
+}
+
+ /*
+ * The mock name and its helper callbacks in one place.
+ */
+static const MOCK_APPL_SIG getnameinfo_sig = {
+ "getnameinfo",
+ match_getnameinfo,
+ assign_getnameinfo,
+ print_getnameinfo,
+ free_getnameinfo,
+};
+
+/* _expect_getnameinfo - set up expectation */
+
+void _expect_getnameinfo(const char *file, int line,
+ int calls_expected, int retval,
+ const struct sockaddr *sa, size_t salen,
+ const char *host, size_t hostlen,
+ const char *serv, size_t servlen,
+ int flags)
+{
+ struct getnameinfo_expectation *pe;
+
+ pe = (struct getnameinfo_expectation *)
+ pmock_expect_create(&getnameinfo_sig,
+ file, line, calls_expected, sizeof(*pe));
+ pe->retval = retval;
+ pe->sa = (struct sockaddr *) mymalloc(salen);
+ memcpy(pe->sa, sa, salen);
+ pe->salen = salen;
+ pe->host = MYSTRDUP_OR_NULL(host);
+ pe->hostlen = hostlen;
+ pe->serv = MYSTRDUP_OR_NULL(serv);
+ pe->servlen = servlen;
+ pe->flags = flags;
+}
+
+/* getnameinfo - mock getnameinfo */
+
+int getnameinfo(const struct sockaddr *sa, socklen_t salen,
+ char *host, size_t hostlen,
+ char *serv, size_t servlen, int flags)
+{
+ struct getnameinfo_expectation inputs;
+ struct getnameinfo_targets targets;
+ int retval = EAI_FAIL;
+
+ /*
+ * Bundle the arguments to simplify handling.
+ */
+ inputs.sa = (struct sockaddr *) sa;
+ inputs.salen = salen;
+ inputs.flags = flags;
+
+ targets.host = host;
+ targets.hostlen = hostlen;
+ targets.serv = serv;
+ targets.servlen = servlen;
+ targets.retval = &retval;
+
+ /*
+ * TODO: bail out if there was no match?
+ */
+ (void) pmock_expect_apply(&getnameinfo_sig,
+ &inputs.mock_expect, (void *) &targets);
+ return (retval);
+}
--- /dev/null
+#ifndef _MOCK_GETADDRINFO_H_INCLUDED_
+#define _MOCK_GETADDRINFO_H_INCLUDED_
+
+/*++
+/* NAME
+/* mock_getaddrinfo 3h
+/* SUMMARY
+/* getaddrinfo/getnameinfo mock for hermetic tests
+/* SYNOPSIS
+/* #include <mock_getaddrinfo.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <wrap_netdb.h>
+
+ /*
+ * Utility library.
+ */
+#include <myaddrinfo.h> /* MAI_HOSTNAME_STR, etc. */
+
+ /*
+ * Test library.
+ */
+#include <addrinfo_to_string.h>
+#include <make_addr.h>
+#include <match_addr.h>
+#include <match_basic.h>
+#include <ptest.h>
+
+ /*
+ * Manage expectations and responses. Capture the source file name and line
+ * number for better diagnostics.
+ */
+#define expect_getaddrinfo(exp_calls, retval, node, service, \
+ hints, res) \
+ _expect_getaddrinfo(__FILE__, __LINE__, (exp_calls), (retval), \
+ (node), (service), \
+ (hints), (res))
+
+extern void _expect_getaddrinfo(const char *, int, int, int,
+ const char *, const char *,
+ const struct addrinfo *,
+ struct addrinfo *);
+
+#define expect_getnameinfo(exp_calls, retval, sa, salen, \
+ host, hostlen, \
+ serv, servlen, flags) \
+ _expect_getnameinfo(__FILE__, __LINE__, (exp_calls), (retval), \
+ (sa), (salen), \
+ (host), (hostlen), \
+ (serv), (servlen), (flags))
+
+extern void _expect_getnameinfo(const char *, int, int, int,
+ const struct sockaddr *, size_t,
+ const char *, size_t,
+ const char *, size_t, int);
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+#endif
--- /dev/null
+ /*
+ * Test program for the mock_getaddrinfo module. See comments in
+ * ptest_main.h and pmock_expect_test.c for a documented example.
+ */
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <wrap_netdb.h>
+
+ /*
+ * Utility library.
+ */
+#include <vstring.h>
+
+ /*
+ * Test library.
+ */
+#include <mock_getaddrinfo.h>
+#include <pmock_expect.h>
+#include <ptest.h>
+
+#define STR vstring_str
+
+typedef struct PTEST_CASE {
+ const char *testname; /* Human-readable description */
+ void (*action) (PTEST_CTX *t, const struct PTEST_CASE *);
+} PTEST_CASE;
+
+static void test_getaddrinfo_success(PTEST_CTX *t, const PTEST_CASE *unused)
+{
+ struct addrinfo hints;
+ struct addrinfo *got_addrinfo;
+ struct addrinfo *want_addrinfo;
+ int got_st, want_st = 0;
+
+ /*
+ * Set up expectations.
+ */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ want_addrinfo = make_addrinfo(&hints, "localhost", "127.0.0.1", 25);
+ expect_getaddrinfo(1, want_st, "localhost", "smtp", &hints, want_addrinfo);
+
+ /*
+ * Invoke the mock and verify results.
+ */
+ got_st = getaddrinfo("localhost", "smtp", &hints, &got_addrinfo);
+ if (got_st != want_st) {
+ ptest_error(t, "getaddrinfo: got %d, want %d", got_st, want_st);
+ } else if (eq_addrinfo(t, "getaddrinfo", got_addrinfo,
+ want_addrinfo) == 0) {
+ VSTRING *got_buf = vstring_alloc(100);
+ VSTRING *want_buf = vstring_alloc(100);
+
+ ptest_error(t, "getaddrinfo: got %s, want %s",
+ append_addrinfo_to_string(got_buf, got_addrinfo),
+ append_addrinfo_to_string(want_buf, want_addrinfo));
+ vstring_free(got_buf);
+ vstring_free(want_buf);
+ }
+
+ /*
+ * Clean up.
+ */
+ freeaddrinfo(want_addrinfo);
+ if (got_addrinfo)
+ freeaddrinfo(got_addrinfo);
+}
+
+static void test_getaddrinfo_failure(PTEST_CTX *t, const PTEST_CASE *unused)
+{
+ struct addrinfo hints;
+ struct addrinfo *got_addrinfo = 0;
+ struct addrinfo *want_addrinfo = 0;
+ int got_st, want_st = EAI_FAIL;
+ VSTRING *event_buf = vstring_alloc(100);
+ VSTRING *hints_buf = vstring_alloc(100);
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+
+ /*
+ * The missing expectation is intentional. Do not count this as an error.
+ */
+ vstring_sprintf(event_buf, "unexpected call: "
+ "getaddrinfo(\"notexist\", \"smtp\", %s, (ptr))",
+ addrinfo_hints_to_string(hints_buf, &hints));
+ expect_ptest_error(t, STR(event_buf));
+ vstring_free(event_buf);
+ vstring_free(hints_buf);
+
+ /*
+ * Invoke the mock and verify results.
+ */
+ got_st = getaddrinfo("notexist", "smtp", &hints, &got_addrinfo);
+ if (got_st != want_st) {
+ ptest_error(t, "getaddrinfo: got %d, want %d", got_st, want_st);
+ } else if (eq_addrinfo(t, "getaddrinfo", got_addrinfo,
+ want_addrinfo) == 0) {
+ VSTRING *got_buf = vstring_alloc(100);
+
+ ptest_error(t, "getaddrinfo: got %s, want (null)",
+ append_addrinfo_to_string(got_buf, got_addrinfo));
+ vstring_free(got_buf);
+ }
+
+ /*
+ * Clean up.
+ */
+ if (got_addrinfo)
+ freeaddrinfo(got_addrinfo);
+}
+
+static void test_getnameinfo_numeric_success(PTEST_CTX *t,
+ const PTEST_CASE *unused)
+{
+ struct sockaddr *req_sockaddr = make_sockaddr(AF_INET, "127.0.0.1", 25);
+ size_t req_sockaddrlen = sizeof(struct sockaddr_in);
+ int got_st, want_st = 0;
+ MAI_HOSTADDR_STR want_hostaddr = {"127.0.0.1"};
+ MAI_SERVPORT_STR want_servport = {"25"};
+ MAI_HOSTADDR_STR got_hostaddr;
+ MAI_SERVPORT_STR got_servport;
+ int req_flags = NI_NUMERICHOST | NI_NUMERICSERV;
+
+ /*
+ * Set up expectations.
+ */
+ expect_getnameinfo(1, want_st, req_sockaddr, req_sockaddrlen,
+ want_hostaddr.buf, sizeof(want_hostaddr),
+ want_servport.buf, sizeof(want_servport),
+ req_flags);
+
+ /*
+ * Invoke the mock and verify results.
+ */
+ got_st = getnameinfo(req_sockaddr, req_sockaddrlen,
+ got_hostaddr.buf, sizeof(got_hostaddr),
+ got_servport.buf, sizeof(got_servport),
+ req_flags);
+
+ if (got_st != want_st) {
+ ptest_error(t, "getnameinfo: got %d, want %d", got_st, want_st);
+ } else if (strcmp(got_hostaddr.buf, want_hostaddr.buf) != 0) {
+ ptest_error(t, "getnameinfo hostaddr: got '%s', want '%s'",
+ got_hostaddr.buf, want_hostaddr.buf);
+ } else if (strcmp(got_servport.buf, want_servport.buf) != 0) {
+ ptest_error(t, "getnameinfo servport: got '%s', want '%s'",
+ got_servport.buf, want_servport.buf);
+ }
+
+ /*
+ * Clean up.
+ */
+ free_sockaddr(req_sockaddr);
+}
+
+static void test_getnameinfo_numeric_failure(PTEST_CTX *t,
+ const PTEST_CASE *unused)
+{
+ struct sockaddr *req_sockaddr = make_sockaddr(AF_INET, "127.0.0.1", 25);
+ size_t req_sockaddrlen = sizeof(struct sockaddr_in);
+ int req_flags = NI_NUMERICHOST | NI_NUMERICSERV;
+ int got_st, want_st = EAI_FAIL;
+ VSTRING *event_buf = vstring_alloc(100);
+ VSTRING *ni_flags_buf = vstring_alloc(100);
+
+ /*
+ * The missing expectation is intentional. Do not count this as an error.
+ */
+ vstring_sprintf(event_buf, "unexpected call: "
+ "getnameinfo({AF_INET, 127.0.0.1, 25}, %ld, "
+ "(ptr), (len), (ptr), (len), %s",
+ (long) req_sockaddrlen,
+ ni_flags_to_string(ni_flags_buf, req_flags));
+ expect_ptest_error(t, STR(event_buf));
+
+ /*
+ * Invoke the mock and verify results.
+ */
+ got_st = getnameinfo(req_sockaddr, req_sockaddrlen,
+ (char *) 0, (size_t) 0,
+ (char *) 0, (size_t) 0,
+ req_flags);
+ if (got_st != want_st)
+ ptest_error(t, "getnameinfo return: got %d, want %d", got_st, want_st);
+
+ /*
+ * Clean up.
+ */
+ vstring_free(event_buf);
+ vstring_free(ni_flags_buf);
+ free_sockaddr(req_sockaddr);
+}
+
+ /*
+ * Test cases. The "success" tests exercise the expectation match and apply
+ * helpers, and "failure" tests exercise the print helpers. All tests
+ * exercise the expectation free helpers.
+ */
+const PTEST_CASE ptestcases[] = {
+ {
+ "getaddrinfo success", test_getaddrinfo_success,
+ },
+ {
+ "getaddrinfo failure", test_getaddrinfo_failure,
+ },
+ {
+ "getnameinfo_numeric success", test_getnameinfo_numeric_success,
+ },
+ {
+ "getnameinfo_numeric failure", test_getnameinfo_numeric_failure,
+ },
+};
+
+#include <ptest_main.h>
--- /dev/null
+/*++
+/* NAME
+/* mock_myaddrinfo 3
+/* SUMMARY
+/* myaddrinfo mock for hermetic tests
+/* SYNOPSIS
+/* #include <mock_myaddrinfo.h>
+/*
+/* int hostname_to_sockaddr_pf(
+/* const char *hostname,
+/* int pf,
+/* const char *service,
+/* int socktype,
+/* struct addrinfo **result,
+/*
+/* int hostaddr_to_sockaddr(
+/* const char *hostaddr,
+/* const char *service,
+/* int socktype,
+/* struct addrinfo **result)
+/*
+/* int sockaddr_to_hostaddr(
+/* const struct sockaddr *sa,
+/* SOCKADDR_SIZE salen,
+/* MAI_HOSTADDR_STR *hostaddr,
+/* MAI_SERVPORT_STR *portnum,
+/* int socktype)
+/*
+/* int sockaddr_to_hostname(
+/* const struct sockaddr *sa,
+/* SOCKADDR_SIZE salen,
+/* MAI_HOSTNAME_STR *hostname,
+/* MAI_SERVNAME_STR *service,
+/* int socktype)
+/* EXPECTATION SETUP
+/* void expect_hostname_to_sockaddr_pf(
+/* int calls_expected,
+/* int retval,
+/* const char *hostname,
+/* int pf,
+/* const char *service,
+/* int socktype,
+/* struct addrinfo *result)
+/*
+/* void expect_hostaddr_to_sockaddr(
+/* int calls_expected,
+/* int retval,
+/* const char *hostaddr,
+/* const char *service,
+/* int socktype,
+/* struct addrinfo *result)
+/*
+/* void expect_sockaddr_to_hostaddr(
+/* int calls_expected,
+/* int retval,
+/* const struct sockaddr *sa,
+/* SOCKADDR_SIZE salen,
+/* MAI_HOSTADDR_STR *hostaddr,
+/* MAI_SERVPORT_STR *portnum,
+/* int socktype)
+/*
+/* void expect_sockaddr_to_hostname(
+/* int calls_expected,
+/* int retval,
+/* const struct sockaddr *sa,
+/* SOCKADDR_SIZE salen,
+/* MAI_HOSTNAME_STR *hostname,
+/* MAI_SERVNAME_STR *service,
+/* int socktype)
+/* TEST DATA
+/* struct addrinfo *make_addrinfo(
+/* const struct addrinfo *hints,
+/* const char *name,
+/* const char *addr)
+/*
+/* struct addrinfo *copy_addrinfo(const struct addrinfo *ai)
+/*
+/* void freeaddrinfo(struct addrinfo *ai)
+/*
+/* struct sockaddr *make_sockaddr(
+/* const char *addr,
+/* int port)
+/*
+/* void free_sockaddr(struct sockaddr *sa)
+/* MATCHERS
+/* int eq_addrinfo(
+/* PTEST_CTX *t,
+/* const char *what,
+/* struct addrinfo *got,
+/* struct addrinfo *want)
+/* DESCRIPTION
+/* This module implements mock myaddrinfo() lookup and conversion
+/* functions that produce prepared outputs in response to
+/* expected inputs. This supports hermetic tests, i.e. tests
+/* that do not depend on host configuration or on network
+/* access.
+/*
+/* This module also provides a mock freeaddrinfo() function.
+/* This is needed because the mock_myaddrinfo library and the
+/* system library may use different memory allocation strategies.
+/*
+/* The "expect_" functions take expected inputs and corresponding
+/* outputs. They make deep copies of their arguments, including
+/* the "struct addrinfo *" linked lists. The retval argument
+/* specifies a prepared result value. The calls_expected argument
+/* specifies the expected number of calls (zero means one or
+/* more calls, not: zero calls).
+/*
+/* make_addrinfo() creates one addrinfo structure. To create
+/* linked list, manually append make_addrinfo() results.
+/*
+/* copy_addrinfo() makes a deep copy of a linked list of
+/* addrinfo structures.
+/*
+/* freeaddrinfo() deletes a linked list of addrinfo structures.
+/* This function must be used for addrinfo structures created
+/* with make_addrinfo() and copy_addrinfo().
+/*
+/* make_sockaddr() creates a sockaddr structure from the string
+/* representation of an IP address.
+/*
+/* free_sockaddr() exists to make program code more explicit.
+/*
+/* eq_addrinfo() compares addrinfo linked lists and reports
+/* differences with ptest_error(). The what argument provides
+/* context. Specify a null test context for silent operation.
+/* DIAGNOSTICS
+/* If a mock is called unexpectedly (the call arguments do not
+/* match the expectation, or more calls are made than expected),
+/* a warning is logged, and the test will be flagged as failed.
+/* For now the mock returns an error result to the caller.
+/* TODO: consider aborting the test.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h> /* sprintf */
+
+ /*
+ * Utility library.
+ */
+#include <mymalloc.h>
+#include <msg.h>
+#include <myaddrinfo.h>
+
+ /*
+ * Test library.
+ */
+#include <mock_myaddrinfo.h>
+#include <pmock_expect.h>
+#include <make_addr.h>
+#include <ptest.h>
+
+#define MYSTRDUP_OR_NULL(x) ((x) ? mystrdup(x) : 0)
+#define STR_OR_NULL(s) ((s) ? (s) : "(null)")
+
+ /*
+ * Manage hostname_to_sockaddr_pf() expectations and responses. We use this
+ * structure for deep copies pf expect_hostname_to_sockaddr_pf() expected
+ * inputs and prepared responses, and for shallow copies of
+ * hostname_to_sockaddr_pf() inputs, so that we can reuse the
+ * print_hostname_to_sockaddr_pf() helper.
+ */
+struct hostname_to_sockaddr_pf_expectation {
+ MOCK_EXPECT mock_expect; /* generic fields */
+ int retval; /* result value */
+ char *hostname; /* inputs */
+ int pf;
+ char *service;
+ int socktype;
+ struct addrinfo *res; /* other outputs */
+};
+
+ /*
+ * Pointers to hostname_to_sockaddr_pf() outputs.
+ */
+struct hostname_to_sockaddr_pf_targets {
+ struct addrinfo **res;
+ int *retval;
+};
+
+/* match_hostname_to_sockaddr_pf - match inputs against expectation */
+
+static int match_hostname_to_sockaddr_pf(const MOCK_EXPECT *expect,
+ const MOCK_EXPECT *inputs)
+{
+ struct hostname_to_sockaddr_pf_expectation *pe =
+ (struct hostname_to_sockaddr_pf_expectation *) expect;
+ struct hostname_to_sockaddr_pf_expectation *pi =
+ (struct hostname_to_sockaddr_pf_expectation *) inputs;
+
+ return (strcmp(STR_OR_NULL(pe->hostname),
+ STR_OR_NULL(pi->hostname)) == 0
+ && pe->pf == pi->pf
+ && strcmp(STR_OR_NULL(pe->service),
+ STR_OR_NULL(pi->service)) == 0
+ && pe->socktype == pi->socktype);
+}
+
+/* assign_hostname_to_sockaddr_pf - assign expected output */
+
+static void assign_hostname_to_sockaddr_pf(const MOCK_EXPECT *expect,
+ void *targets)
+{
+ struct hostname_to_sockaddr_pf_expectation *pe =
+ (struct hostname_to_sockaddr_pf_expectation *) expect;
+ struct hostname_to_sockaddr_pf_targets *pt =
+ (struct hostname_to_sockaddr_pf_targets *) targets;
+
+ if (pe->retval == 0)
+ *(pt->res) = copy_addrinfo(pe->res);
+ *pt->retval = pe->retval;
+}
+
+/* print_hostname_to_sockaddr_pf - print expected inputs */
+
+static char *print_hostname_to_sockaddr_pf(const MOCK_EXPECT *expect,
+ VSTRING *buf)
+{
+ struct hostname_to_sockaddr_pf_expectation *pe =
+ (struct hostname_to_sockaddr_pf_expectation *) expect;
+
+ vstring_sprintf(buf, "\"%s\", %d, \"%s\", %d, (ptr)",
+ STR_OR_NULL(pe->hostname), pe->pf,
+ STR_OR_NULL(pe->service), pe->socktype);
+ return (vstring_str(buf));
+}
+
+/* free_hostname_to_sockaddr_pf - destructor */
+
+static void free_hostname_to_sockaddr_pf(MOCK_EXPECT *expect)
+{
+ struct hostname_to_sockaddr_pf_expectation *pe =
+ (struct hostname_to_sockaddr_pf_expectation *) expect;
+
+ if (pe->hostname)
+ myfree(pe->hostname);
+ if (pe->service)
+ myfree(pe->service);
+ if (pe->retval == 0)
+ freeaddrinfo(pe->res);
+ pmock_expect_free(expect);
+}
+
+ /*
+ * The mock name and its helper callbacks in one place.
+ */
+static const MOCK_APPL_SIG hostname_to_sockaddr_pf_sig = {
+ "hostname_to_sockaddr_pf",
+ match_hostname_to_sockaddr_pf,
+ assign_hostname_to_sockaddr_pf,
+ print_hostname_to_sockaddr_pf,
+ free_hostname_to_sockaddr_pf,
+};
+
+/* _expect_hostname_to_sockaddr_pf - set up expectation */
+
+void _expect_hostname_to_sockaddr_pf(const char *file, int line,
+ int calls_expected, int retval,
+ const char *hostname, int pf,
+ const char *service,
+ int socktype,
+ struct addrinfo *res)
+{
+ struct hostname_to_sockaddr_pf_expectation *pe;
+
+ pe = (struct hostname_to_sockaddr_pf_expectation *)
+ pmock_expect_create(&hostname_to_sockaddr_pf_sig,
+ file, line, calls_expected, sizeof(*pe));
+ pe->retval = retval;
+ pe->hostname = MYSTRDUP_OR_NULL(hostname);
+ pe->pf = pf;
+ pe->service = MYSTRDUP_OR_NULL(service);
+ pe->socktype = socktype;
+ if (pe->retval == 0)
+ pe->res = copy_addrinfo(res);
+}
+
+/* hostname_to_sockaddr_pf - mock hostname_to_sockaddr_pf */
+
+int hostname_to_sockaddr_pf(const char *hostname, int pf,
+ const char *service, int socktype,
+ struct addrinfo **res)
+{
+ struct hostname_to_sockaddr_pf_expectation inputs;
+ struct hostname_to_sockaddr_pf_targets targets;
+ int retval = EAI_FAIL;
+
+ /*
+ * Bundle the arguments to simplify handling.
+ */
+ inputs.hostname = (char *) hostname;
+ inputs.pf = pf;
+ inputs.service = (char *) service;
+ inputs.socktype = socktype;
+
+ targets.res = res;
+ targets.retval = &retval;
+
+ /*
+ * TODO: bail out if there was no match?
+ */
+ (void) pmock_expect_apply(&hostname_to_sockaddr_pf_sig,
+ &inputs.mock_expect, (void *) &targets);
+ return (retval);
+}
+
+ /*
+ * Manage hostaddr_to_sockaddr() expectations and responses. We use this
+ * structure for deep copies of expect_hostaddr_to_sockaddr() expected
+ * inputs and prepared responses, and for shallow copies
+ * hostaddr_to_sockaddr() inputs, so that we can reuse the
+ * print_hostaddr_to_sockaddr() helper.
+ */
+struct hostaddr_to_sockaddr_expectation {
+ MOCK_EXPECT mock_expect; /* generic fields */
+ int retval; /* result value */
+ char *hostaddr; /* inputs */
+ char *service;
+ int socktype;
+ struct addrinfo *res; /* other outputs */
+};
+
+ /*
+ * Pointers to hostaddr_to_sockaddr() outputs.
+ */
+struct hostaddr_to_sockaddr_targets {
+ struct addrinfo **res;
+ int *retval;
+};
+
+/* match_hostaddr_to_sockaddr - match inputs against expectation */
+
+static int match_hostaddr_to_sockaddr(const MOCK_EXPECT *expect,
+ const MOCK_EXPECT *inputs)
+{
+ struct hostaddr_to_sockaddr_expectation *pe =
+ (struct hostaddr_to_sockaddr_expectation *) expect;
+ struct hostaddr_to_sockaddr_expectation *pi =
+ (struct hostaddr_to_sockaddr_expectation *) inputs;
+
+ return (strcmp(STR_OR_NULL(pe->hostaddr),
+ STR_OR_NULL(pi->hostaddr)) == 0
+ && strcmp(STR_OR_NULL(pe->service),
+ STR_OR_NULL(pi->service)) == 0
+ && pe->socktype == pi->socktype);
+}
+
+/* assign_hostaddr_to_sockaddr - assign expected output */
+
+static void assign_hostaddr_to_sockaddr(const MOCK_EXPECT *expect,
+ void *targets)
+{
+ struct hostaddr_to_sockaddr_expectation *pe =
+ (struct hostaddr_to_sockaddr_expectation *) expect;
+ struct hostaddr_to_sockaddr_targets *pt =
+ (struct hostaddr_to_sockaddr_targets *) targets;
+
+ if (pe->retval == 0)
+ *(pt->res) = copy_addrinfo(pe->res);
+ *pt->retval = pe->retval;
+}
+
+/* print_hostaddr_to_sockaddr - print expected inputs */
+
+static char *print_hostaddr_to_sockaddr(const MOCK_EXPECT *expect,
+ VSTRING *buf)
+{
+ struct hostaddr_to_sockaddr_expectation *pe =
+ (struct hostaddr_to_sockaddr_expectation *) expect;
+
+ vstring_sprintf(buf, "\"%s\", \"%s\", %d, (ptr)",
+ STR_OR_NULL(pe->hostaddr),
+ STR_OR_NULL(pe->service), pe->socktype);
+ return (vstring_str(buf));
+}
+
+/* free_hostname_to_sockaddr_pf - destructor */
+
+static void free_hostaddr_to_sockaddr(MOCK_EXPECT *expect)
+{
+ struct hostaddr_to_sockaddr_expectation *pe =
+ (struct hostaddr_to_sockaddr_expectation *) expect;
+
+ if (pe->hostaddr)
+ myfree(pe->hostaddr);
+ if (pe->service)
+ myfree(pe->service);
+ if (pe->retval == 0)
+ freeaddrinfo(pe->res);
+ pmock_expect_free(expect);
+}
+
+ /*
+ * The mock name and its helper callbacks in one place.
+ */
+static const MOCK_APPL_SIG hostaddr_to_sockaddr_sig = {
+ "hostaddr_to_sockaddr",
+ match_hostaddr_to_sockaddr,
+ assign_hostaddr_to_sockaddr,
+ print_hostaddr_to_sockaddr,
+ free_hostaddr_to_sockaddr,
+};
+
+/* _expect_hostaddr_to_sockaddr - set up expectation */
+
+void _expect_hostaddr_to_sockaddr(const char *file, int line,
+ int calls_expected, int retval,
+ const char *hostaddr,
+ const char *service, int socktype,
+ struct addrinfo *res)
+{
+ struct hostaddr_to_sockaddr_expectation *pe;
+
+ pe = (struct hostaddr_to_sockaddr_expectation *)
+ pmock_expect_create(&hostaddr_to_sockaddr_sig,
+ file, line, calls_expected, sizeof(*pe));
+ pe->retval = retval;
+ pe->hostaddr = MYSTRDUP_OR_NULL(hostaddr);
+ pe->service = MYSTRDUP_OR_NULL(service);
+ pe->socktype = socktype;
+ if (pe->retval == 0)
+ pe->res = copy_addrinfo(res);
+}
+
+/* hostaddr_to_sockaddr - mock hostaddr_to_sockaddr */
+
+int hostaddr_to_sockaddr(const char *hostaddr, const char *service,
+ int socktype, struct addrinfo **res)
+{
+ struct hostaddr_to_sockaddr_expectation inputs;
+ struct hostaddr_to_sockaddr_targets targets;
+ int retval = EAI_FAIL;
+
+ /*
+ * Bundle the arguments to simplify handling.
+ */
+ inputs.hostaddr = (char *) hostaddr;
+ inputs.service = (char *) service;
+ inputs.socktype = socktype;
+
+ targets.res = res;
+ targets.retval = &retval;
+
+ /*
+ * TODO: bail out if there was no match?
+ */
+ (void) pmock_expect_apply(&hostaddr_to_sockaddr_sig,
+ &inputs.mock_expect, (void *) &targets);
+ return (retval);
+}
+
+ /*
+ * Manage sockaddr_to_hostaddr() expectations and responses. We use this
+ * structure for deep copies of expect_sockaddr_to_hostaddr() expected
+ * inputs and prepared responses, and for shallow copies of
+ * sockaddr_to_hostaddr() inputs, so that we can reuse the
+ * print_sockaddr_to_hostaddr() helper.
+ */
+struct sockaddr_to_hostaddr_expectation {
+ MOCK_EXPECT mock_expect; /* generic fields */
+ int retval; /* result value */
+ struct sockaddr_storage sa; /* inputs */
+ SOCKADDR_SIZE salen;
+ int socktype;
+ MAI_HOSTADDR_STR *hostaddr; /* other outputs */
+ MAI_SERVPORT_STR *portnum;
+ MAI_HOSTADDR_STR hostaddr_storage;
+ MAI_SERVPORT_STR portnum_storage;
+};
+
+ /*
+ * Pointers to sockaddr_to_hostaddr() outputs.
+ */
+struct sockaddr_to_hostaddr_targets {
+ MAI_HOSTADDR_STR *hostaddr;
+ MAI_SERVPORT_STR *portnum;
+ int *retval;
+};
+
+/* match_sockaddr_to_hostaddr - match inputs against expectation */
+
+static int match_sockaddr_to_hostaddr(const MOCK_EXPECT *expect,
+ const MOCK_EXPECT *inputs)
+{
+ struct sockaddr_to_hostaddr_expectation *pe =
+ (struct sockaddr_to_hostaddr_expectation *) expect;
+ struct sockaddr_to_hostaddr_expectation *pi =
+ (struct sockaddr_to_hostaddr_expectation *) inputs;
+
+ return (pe->salen == pi->salen
+ && memcmp(&pe->sa, &pi->sa, pe->salen) == 0
+ && pe->socktype == pi->socktype);
+}
+
+/* assign_sockaddr_to_hostaddr - assign expected output */
+
+static void assign_sockaddr_to_hostaddr(const MOCK_EXPECT *expect,
+ void *targets)
+{
+ struct sockaddr_to_hostaddr_expectation *pe =
+ (struct sockaddr_to_hostaddr_expectation *) expect;
+ struct sockaddr_to_hostaddr_targets *pt =
+ (struct sockaddr_to_hostaddr_targets *) targets;
+
+ if (pe->retval == 0) {
+ if (pe->hostaddr && pt->hostaddr)
+ *pt->hostaddr = *pe->hostaddr;
+ if (pe->portnum && pt->portnum)
+ *pt->portnum = *pe->portnum;
+ }
+ *pt->retval = pe->retval;
+}
+
+/* print_sockaddr_to_hostaddr - print expected inputs */
+
+static char *print_sockaddr_to_hostaddr(const MOCK_EXPECT *expect,
+ VSTRING *buf)
+{
+ struct sockaddr_to_hostaddr_expectation *pe =
+ (struct sockaddr_to_hostaddr_expectation *) expect;
+ VSTRING *sockaddr_buf = vstring_alloc(100);
+
+ vstring_sprintf(buf, "%s, %ld, (ptr), (ptr)",
+ sockaddr_to_string(sockaddr_buf,
+ (struct sockaddr *) &pe->sa,
+ pe->salen),
+ (long) pe->salen);
+ vstring_free(sockaddr_buf);
+ return (vstring_str(buf));
+}
+
+ /*
+ * The mock name and its helper callbacks in one place.
+ */
+static const MOCK_APPL_SIG sockaddr_to_hostaddr_sig = {
+ "sockaddr_to_hostaddr",
+ match_sockaddr_to_hostaddr,
+ assign_sockaddr_to_hostaddr,
+ print_sockaddr_to_hostaddr,
+ pmock_expect_free,
+};
+
+/* _expect_sockaddr_to_hostaddr - binary address to printable address form */
+
+void _expect_sockaddr_to_hostaddr(const char *file, int line,
+ int calls_expected, int retval,
+ const struct sockaddr *sa,
+ SOCKADDR_SIZE salen,
+ MAI_HOSTADDR_STR *hostaddr,
+ MAI_SERVPORT_STR *portnum,
+ int socktype)
+{
+ struct sockaddr_to_hostaddr_expectation *pe;
+
+ pe = (struct sockaddr_to_hostaddr_expectation *)
+ pmock_expect_create(&sockaddr_to_hostaddr_sig,
+ file, line, calls_expected, sizeof(*pe));
+ pe->retval = retval;
+ memcpy((void *) &pe->sa, (void *) sa, salen);
+ pe->salen = salen;
+ if (pe->retval == 0 && hostaddr) {
+ *(pe->hostaddr = &pe->hostaddr_storage) = *hostaddr;
+ } else {
+ pe->hostaddr = 0;
+ }
+ if (pe->retval == 0 && portnum) {
+ *(pe->portnum = &pe->portnum_storage) = *portnum;
+ } else {
+ pe->portnum = 0;
+ }
+ pe->socktype = socktype;
+}
+
+/* sockaddr_to_hostaddr - mock sockaddr_to_hostaddr */
+
+int sockaddr_to_hostaddr(const struct sockaddr *sa,
+ SOCKADDR_SIZE salen,
+ MAI_HOSTADDR_STR *hostaddr,
+ MAI_SERVPORT_STR *portnum,
+ int socktype)
+{
+ struct sockaddr_to_hostaddr_expectation inputs;
+ struct sockaddr_to_hostaddr_targets targets;
+ int retval = EAI_FAIL;
+
+ /*
+ * Bundle the arguments to simplify handling.
+ */
+ memcpy((void *) &inputs.sa, (void *) sa, salen);
+ inputs.salen = salen;
+ inputs.socktype = socktype;
+
+ targets.hostaddr = hostaddr;
+ targets.portnum = portnum;
+ targets.retval = &retval;
+
+ /*
+ * TODO: bail out if there was no match?
+ */
+ (void) pmock_expect_apply(&sockaddr_to_hostaddr_sig,
+ &inputs.mock_expect, (void *) &targets);
+ return (retval);
+}
+
+ /*
+ * Manage sockaddr_to_hostname() expectations and responses. We use this
+ * structure for deep copies of expect_sockaddr_to_hostname() expected
+ * inputs and prepared responses, and for shallow copies of
+ * sockaddr_to_hostname() inputs, so that we can reuse the
+ * print_sockaddr_to_hostname() helper.
+ */
+struct sockaddr_to_hostname_expectation {
+ MOCK_EXPECT mock_expect; /* generic fields */
+ int retval; /* result value */
+ struct sockaddr_storage sa; /* inputs */
+ SOCKADDR_SIZE salen;
+ int socktype;
+ MAI_HOSTNAME_STR *hostname; /* other outputs */
+ MAI_SERVNAME_STR *service;
+ MAI_HOSTNAME_STR hostname_storage;
+ MAI_SERVNAME_STR service_storage;
+};
+
+ /*
+ * Pointers to sockaddr_to_hostname() outputs.
+ */
+struct sockaddr_to_hostname_targets {
+ MAI_HOSTNAME_STR *hostname;
+ MAI_SERVNAME_STR *service;
+ int *retval;
+};
+
+/* match_sockaddr_to_hostname - match inputs against expectation */
+
+static int match_sockaddr_to_hostname(const MOCK_EXPECT *expect,
+ const MOCK_EXPECT *inputs)
+{
+ struct sockaddr_to_hostname_expectation *pe =
+ (struct sockaddr_to_hostname_expectation *) expect;
+ struct sockaddr_to_hostname_expectation *pi =
+ (struct sockaddr_to_hostname_expectation *) inputs;
+
+ return (pe->salen == pi->salen
+ && memcmp(&pe->sa, &pi->sa, pe->salen) == 0
+ && pe->socktype == pi->socktype);
+}
+
+/* assign_sockaddr_to_hostname - assign expected output */
+
+static void assign_sockaddr_to_hostname(const MOCK_EXPECT *expect,
+ void *targets)
+{
+ struct sockaddr_to_hostname_expectation *pe =
+ (struct sockaddr_to_hostname_expectation *) expect;
+ struct sockaddr_to_hostname_targets *pt =
+ (struct sockaddr_to_hostname_targets *) targets;
+
+ if (pe->retval == 0) {
+ if (pe->hostname && pt->hostname)
+ *pt->hostname = *pe->hostname;
+ if (pe->service && pt->service)
+ *pt->service = *pe->service;
+ }
+ *pt->retval = pe->retval;
+}
+
+/* print_sockaddr_to_hostname - print expected inputs */
+
+static char *print_sockaddr_to_hostname(const MOCK_EXPECT *expect,
+ VSTRING *buf)
+{
+ struct sockaddr_to_hostname_expectation *pe =
+ (struct sockaddr_to_hostname_expectation *) expect;
+ VSTRING *sockaddr_buf = vstring_alloc(100);
+
+ vstring_sprintf(buf, "%s, %ld, (ptr), (ptr)",
+ sockaddr_to_string(sockaddr_buf,
+ (struct sockaddr *) &pe->sa,
+ pe->salen),
+ (long) pe->salen);
+ vstring_free(sockaddr_buf);
+ return (vstring_str(buf));
+}
+
+ /*
+ * The mock name and its helper callbacks in one place.
+ */
+static const MOCK_APPL_SIG sockaddr_to_hostname_sig = {
+ "sockaddr_to_hostname",
+ match_sockaddr_to_hostname,
+ assign_sockaddr_to_hostname,
+ print_sockaddr_to_hostname,
+ pmock_expect_free,
+};
+
+/* _expect_sockaddr_to_hostname - set up expectations */
+
+void _expect_sockaddr_to_hostname(const char *file, int line,
+ int calls_expected, int retval,
+ const struct sockaddr *sa,
+ SOCKADDR_SIZE salen,
+ MAI_HOSTNAME_STR *hostname,
+ MAI_SERVNAME_STR *service,
+ int socktype)
+{
+ struct sockaddr_to_hostname_expectation *pe;
+
+ pe = (struct sockaddr_to_hostname_expectation *)
+ pmock_expect_create(&sockaddr_to_hostname_sig,
+ file, line, calls_expected, sizeof(*pe));
+ pe->retval = retval;
+ memcpy((void *) &pe->sa, (void *) sa, salen);
+ pe->salen = salen;
+ if (retval == 0 && hostname) {
+ *(pe->hostname = &pe->hostname_storage) = *hostname;
+ } else {
+ pe->hostname = 0;
+ }
+ if (retval == 0 && service) {
+ *(pe->service = &pe->service_storage) = *service;
+ } else {
+ pe->service = 0;
+ }
+ pe->socktype = socktype;
+}
+
+/* sockaddr_to_hostname - mock sockaddr_to_hostname */
+
+int sockaddr_to_hostname(const struct sockaddr *sa,
+ SOCKADDR_SIZE salen,
+ MAI_HOSTNAME_STR *hostname,
+ MAI_SERVNAME_STR *service,
+ int socktype)
+{
+ struct sockaddr_to_hostname_expectation inputs;
+ struct sockaddr_to_hostname_targets targets;
+ int retval = EAI_FAIL;
+
+ /*
+ * Bundle the arguments to simplify handling.
+ */
+ memcpy((void *) &inputs.sa, (void *) sa, salen);
+ inputs.salen = salen;
+ inputs.socktype = socktype;
+
+ targets.hostname = hostname;
+ targets.service = service;
+ targets.retval = &retval;
+
+ /*
+ * TODO: bail out if there was no match?
+ */
+ (void) pmock_expect_apply(&sockaddr_to_hostname_sig,
+ &inputs.mock_expect, (void *) &targets);
+ return (retval);
+}
--- /dev/null
+#ifndef _MOCK_MYADDRINFO_H_INCLUDED_
+#define _MOCK_MYADDRINFO_H_INCLUDED_
+
+/*++
+/* NAME
+/* mock_myaddrinfo 3h
+/* SUMMARY
+/* myaddrinfo mock for hermetic tests
+/* SYNOPSIS
+/* #include <mock_myaddrinfo.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * Utility library.
+ */
+#include <myaddrinfo.h>
+
+ /*
+ * Test library.
+ */
+#include <addrinfo_to_string.h>
+#include <make_addr.h>
+#include <match_addr.h>
+#include <match_basic.h>
+#include <ptest.h>
+
+ /*
+ * Manage expectations and responses. Capture the source file name and line
+ * number for better diagnostics.
+ */
+#define expect_hostname_to_sockaddr_pf(exp_calls, retval, hostname, pf, \
+ service, socktype, res) \
+ _expect_hostname_to_sockaddr_pf(__FILE__, __LINE__, (exp_calls), \
+ (retval), (hostname), (pf), \
+ (service), (socktype), (res))
+#define expect_hostaddr_to_sockaddr(exp_calls, retval, hostaddr, service, \
+ socktype, res) \
+ _expect_hostaddr_to_sockaddr(__FILE__, __LINE__, (exp_calls), \
+ (retval), \
+ (hostaddr), (service), (socktype), \
+ (res))
+#define expect_sockaddr_to_hostaddr(exp_calls, retval, sa, salen, hostaddr, \
+ portnum, socktype) \
+ _expect_sockaddr_to_hostaddr(__FILE__, __LINE__, (exp_calls), \
+ (retval), (sa), (salen), (hostaddr), \
+ (portnum), (socktype))
+#define expect_sockaddr_to_hostname(exp_calls, retval, sa, salen, hostname, \
+ service, socktype) \
+ _expect_sockaddr_to_hostname(__FILE__, __LINE__, (exp_calls), \
+ (retval), (sa), (salen), (hostname), \
+ (service), (socktype))
+
+extern void _expect_hostname_to_sockaddr_pf(const char *, int, int, int,
+ const char *, int, const char *,
+ int, struct addrinfo *);
+extern void _expect_hostaddr_to_sockaddr(const char *, int, int, int,
+ const char *, const char *,
+ int, struct addrinfo *);
+extern void _expect_sockaddr_to_hostaddr(const char *, int, int, int,
+ const struct sockaddr *,
+ SOCKADDR_SIZE,
+ MAI_HOSTADDR_STR *,
+ MAI_SERVPORT_STR *, int);
+extern void _expect_sockaddr_to_hostname(const char *, int, int, int,
+ const struct sockaddr *,
+ SOCKADDR_SIZE,
+ MAI_HOSTNAME_STR *,
+ MAI_SERVNAME_STR *, int);
+
+#define expect_hostname_to_sockaddr(count, ret, host, serv, sock, res) \
+ expect_hostname_to_sockaddr_pf((count), (ret), (host), PF_UNSPEC, \
+ (serv), (sock), (res))
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+#endif
--- /dev/null
+ /*
+ * Test program to exercise mocks including logging. See comments in
+ * ptest_main.h and pmock_expect_test.c for a documented example.
+ */
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+
+ /*
+ * Utility library.
+ */
+#include <msg.h>
+#include <vstring.h>
+
+ /*
+ * Test library.
+ */
+#include <mock_myaddrinfo.h>
+#include <pmock_expect.h>
+#include <ptest.h>
+
+typedef struct PTEST_CASE {
+ const char *testname; /* Human-readable description */
+ void (*action) (PTEST_CTX *t, const struct PTEST_CASE *);
+} PTEST_CASE;
+
+static void test_hostname_to_sockaddr_success(PTEST_CTX *t,
+ const PTEST_CASE *unused)
+{
+ struct addrinfo hints;
+ struct addrinfo *got_addrinfo;
+ struct addrinfo *want_addrinfo;
+ int got_st, want_st = 0;
+
+ /*
+ * Set up expectations.
+ */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ want_addrinfo = make_addrinfo(&hints, "localhost", "127.0.0.1", 25);
+ expect_hostname_to_sockaddr_pf(1, want_st, "localhost", PF_UNSPEC, "smtp",
+ SOCK_STREAM, want_addrinfo);
+
+ /*
+ * Invoke the mock and verify results.
+ */
+ got_st = hostname_to_sockaddr_pf("localhost", PF_UNSPEC, "smtp",
+ SOCK_STREAM, &got_addrinfo);
+ if (got_st != want_st) {
+ ptest_error(t, "hostname_to_sockaddr: got %d, want %d", got_st, want_st);
+ } else if (eq_addrinfo(t, "hostname_to_sockaddr", got_addrinfo,
+ want_addrinfo) == 0) {
+ ptest_error(t, "hostname_to_sockaddr: unexpected result mismatch");
+ }
+
+ /*
+ * Clean up.
+ */
+ freeaddrinfo(want_addrinfo);
+ if (got_addrinfo)
+ freeaddrinfo(got_addrinfo);
+}
+
+static void test_hostname_to_sockaddr_failure(PTEST_CTX *t,
+ const PTEST_CASE *unused)
+{
+ struct addrinfo *got_addrinfo = 0;
+ struct addrinfo *want_addrinfo = 0;
+ int got_st, want_st = EAI_FAIL;
+
+ /*
+ * The missing expectation is intentional. Do not count this as an error.
+ */
+ expect_ptest_error(t, "unexpected call: "
+ "hostname_to_sockaddr_pf(\"notexist\", 0, \"smtp\", 1, (ptr))");
+
+ /*
+ * Invoke the mock and verify results.
+ */
+ got_st = hostname_to_sockaddr_pf("notexist", PF_UNSPEC, "smtp",
+ SOCK_STREAM, &got_addrinfo);
+ if (got_st != want_st) {
+ ptest_error(t, "hostname_to_sockaddr: got %d, want %d", got_st, want_st);
+ } else if (eq_addrinfo(t, "hostname_to_sockaddr", got_addrinfo,
+ want_addrinfo) == 0) {
+ ptest_error(t, "hostname_to_sockaddr: unexpected result mismatch");
+ }
+
+ /*
+ * Clean up.
+ */
+ if (got_addrinfo)
+ freeaddrinfo(got_addrinfo);
+}
+
+static void test_hostaddr_to_sockaddr_success(PTEST_CTX *t,
+ const PTEST_CASE *unused)
+{
+ struct addrinfo hints;
+ struct addrinfo *got_addrinfo = 0;
+ struct addrinfo *want_addrinfo;
+ int got_st, want_st = 0;
+
+ /*
+ * Set up expectations.
+ */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ want_addrinfo = make_addrinfo(&hints, (char *) 0, "127.0.0.1", 25);
+ expect_hostaddr_to_sockaddr(1, want_st, "127.0.0.1", "25", SOCK_STREAM,
+ want_addrinfo);
+
+ /*
+ * Invoke the mock and verify results.
+ */
+ got_st = hostaddr_to_sockaddr("127.0.0.1", "25", SOCK_STREAM,
+ &got_addrinfo);
+ if (got_st != want_st) {
+ ptest_error(t, "hostaddr_to_sockaddr: got %d, want %d", got_st, want_st);
+ } else if (eq_addrinfo(t, "hostaddr_to_sockaddr", got_addrinfo,
+ want_addrinfo) == 0) {
+ ptest_error(t, "hostname_to_sockaddr: unexpected result mismatch");
+ }
+
+ /*
+ * Clean up.
+ */
+ freeaddrinfo(want_addrinfo);
+ if (got_addrinfo)
+ freeaddrinfo(got_addrinfo);
+}
+
+static void test_hostaddr_to_sockaddr_failure(PTEST_CTX *t,
+ const PTEST_CASE *unused)
+{
+ struct addrinfo *got_addrinfo = 0;
+ struct addrinfo *want_addrinfo = 0;
+ int got_st, want_st = EAI_FAIL;
+
+ /*
+ * The missing expectation is intentional. Do not count this as an error.
+ */
+ expect_ptest_error(t, "unexpected call: "
+ "hostaddr_to_sockaddr(\"127.0.0.1\", \"25\", "
+ "1, (ptr))");
+
+ /*
+ * Invoke the mock and verify results.
+ */
+ got_st = hostaddr_to_sockaddr("127.0.0.1", "25", SOCK_STREAM,
+ &got_addrinfo);
+ if (got_st != want_st) {
+ ptest_error(t, "hostaddr_to_sockaddr: got %d, want %d", got_st, want_st);
+ } else if (eq_addrinfo(t, "hostaddr_to_sockaddr", got_addrinfo,
+ want_addrinfo) == 0) {
+ ptest_error(t, "hostname_to_sockaddr: unexpected result mismatch");
+ }
+
+ /*
+ * Clean up.
+ */
+ if (got_addrinfo)
+ freeaddrinfo(got_addrinfo);
+}
+
+static void test_sockaddr_to_hostaddr_success(PTEST_CTX *t,
+ const PTEST_CASE *unused)
+{
+ struct sockaddr *sa;
+ SOCKADDR_SIZE salen;
+ int got_st, want_st = 0;
+ MAI_HOSTADDR_STR want_hostaddr;
+ MAI_SERVPORT_STR want_portnum;
+ MAI_HOSTADDR_STR got_hostaddr;
+ MAI_SERVPORT_STR got_portnum;
+
+ /*
+ * Set up expectations.
+ */
+ sa = make_sockaddr(AF_INET, "127.0.0.1", 25);
+ salen = sizeof(struct sockaddr_in);
+ strncpy(want_hostaddr.buf, "127.0.0.1", sizeof(want_hostaddr.buf));
+ strncpy(want_portnum.buf, "25", sizeof(want_portnum.buf));
+ expect_sockaddr_to_hostaddr(1, want_st, sa, salen,
+ &want_hostaddr, &want_portnum, 0);
+
+ /*
+ * Invoke the mock and verify results.
+ */
+ got_st = sockaddr_to_hostaddr(sa, salen, &got_hostaddr, &got_portnum, 0);
+ if (got_st != want_st) {
+ ptest_error(t, "sockaddr_to_hostaddr ret: got %d, want %d", got_st, want_st);
+ } else if (strcmp(got_hostaddr.buf, want_hostaddr.buf) != 0) {
+ ptest_error(t, "sockaddr_to_hostaddr hostaddr.buf: got %s, want %s",
+ got_hostaddr.buf, want_hostaddr.buf);
+ } else if (strcmp(got_portnum.buf, want_portnum.buf) != 0) {
+ ptest_error(t, "sockaddr_to_hostaddr portnum.buf: got %s, want %s",
+ got_portnum.buf, want_portnum.buf);
+ }
+
+ /*
+ * Clean up.
+ */
+ free_sockaddr(sa);
+}
+
+static void test_sockaddr_to_hostaddr_failure(PTEST_CTX *t,
+ const PTEST_CASE *unused)
+{
+ struct sockaddr *sa;
+ SOCKADDR_SIZE salen;
+ int got_st, want_st = EAI_FAIL;
+
+ /*
+ * The missing expectation is intentional. Do not count this as an error.
+ */
+ expect_ptest_error(t, "unexpected call: "
+ "sockaddr_to_hostaddr({AF_INET, 127.0.0.1, 25}, 16, "
+ "(ptr), (ptr))");
+
+ /*
+ * Invoke the mock and verify results.
+ */
+ sa = make_sockaddr(AF_INET, "127.0.0.1", 25);
+ salen = sizeof(struct sockaddr_in);
+ got_st = sockaddr_to_hostaddr(sa, salen, (MAI_HOSTADDR_STR *) 0,
+ (MAI_SERVPORT_STR *) 0, 0);
+ if (got_st != want_st)
+ ptest_error(t, "sockaddr_to_hostaddr ret: got %d, want %d", got_st, want_st);
+
+ /*
+ * Clean up.
+ */
+ free_sockaddr(sa);
+}
+
+static void test_sockaddr_to_hostname_success(PTEST_CTX *t,
+ const PTEST_CASE *unused)
+{
+ struct sockaddr *sa;
+ SOCKADDR_SIZE salen;
+ int got_st, want_st = 0;
+ MAI_HOSTNAME_STR want_hostname;
+ MAI_SERVNAME_STR want_service;
+ MAI_HOSTNAME_STR got_hostname;
+ MAI_SERVNAME_STR got_service;
+
+ /*
+ * Set up expectations.
+ */
+ sa = make_sockaddr(AF_INET, "127.0.0.1", 25);
+ salen = sizeof(struct sockaddr_in);
+ strncpy(want_hostname.buf, "localhost", sizeof(want_hostname.buf));
+ strncpy(want_service.buf, "smtp", sizeof(want_service.buf));
+ expect_sockaddr_to_hostname(1, want_st, sa, salen, &want_hostname, &want_service, 0);
+
+ /*
+ * Invoke the mock and verify results.
+ */
+ got_st = sockaddr_to_hostname(sa, salen, &got_hostname, &got_service, 0);
+ if (got_st != want_st) {
+ ptest_error(t, "sockaddr_to_hostname ret: got %d, want %d", got_st, want_st);
+ } else if (strcmp(got_hostname.buf, want_hostname.buf) != 0) {
+ ptest_error(t, "sockaddr_to_hostname hostname.buf: got %s, want %s",
+ got_hostname.buf, want_hostname.buf);
+ } else if (strcmp(got_service.buf, want_service.buf) != 0) {
+ ptest_error(t, "sockaddr_to_hostname service.buf: got %s, want %s",
+ got_service.buf, want_service.buf);
+ }
+
+ /*
+ * Clean up.
+ */
+ free_sockaddr(sa);
+}
+
+static void test_sockaddr_to_hostname_failure(PTEST_CTX *t,
+ const PTEST_CASE *unused)
+{
+ struct sockaddr *sa;
+ SOCKADDR_SIZE salen;
+ int got_st, want_st = EAI_FAIL;
+
+ /*
+ * The missing expectation is intentional. Do not count this as an error.
+ */
+ expect_ptest_error(t, "unexpected call: "
+ "sockaddr_to_hostname({AF_INET, 127.0.0.1, 0}, 16, "
+ "(ptr), (ptr))");
+
+ /*
+ * Invoke the mock and verify results.
+ */
+ sa = make_sockaddr(AF_INET, "127.0.0.1", 65536);
+ salen = sizeof(struct sockaddr_in);
+ got_st = sockaddr_to_hostname(sa, salen, (MAI_HOSTNAME_STR *) 0,
+ (MAI_SERVNAME_STR *) 0, 0);
+ if (got_st != want_st)
+ ptest_error(t, "sockaddr_to_hostname ret: got %d, want %d", got_st, want_st);
+
+ /*
+ * Clean up.
+ */
+ free_sockaddr(sa);
+}
+
+ /*
+ * Test cases. The "success" tests exercise the expectation match and apply
+ * helpers, and "failure" tests exercise the print helpers. All tests
+ * exercise the expectation free helpers.
+ */
+const PTEST_CASE ptestcases[] = {
+ {
+ "hostname_to_sockaddr success", test_hostname_to_sockaddr_success,
+ },
+ {
+ "hostname_to_sockaddr failure", test_hostname_to_sockaddr_failure,
+ },
+ {
+ "hostaddr_to_sockaddr success", test_hostaddr_to_sockaddr_success,
+ },
+ {
+ "hostaddr_to_sockaddr failure", test_hostaddr_to_sockaddr_failure,
+ },
+ {
+ "sockaddr_to_hostaddr success", test_sockaddr_to_hostaddr_success,
+ },
+ {
+ "sockaddr_to_hostaddr failure", test_sockaddr_to_hostaddr_failure,
+ },
+ {
+ "sockaddr_to_hostname success", test_sockaddr_to_hostname_success,
+ },
+ {
+ "sockaddr_to_hostname failure", test_sockaddr_to_hostname_failure,
+ },
+};
+
+#include <ptest_main.h>
--- /dev/null
+/*++
+/* NAME
+/* mock_servent 3
+/* SUMMARY
+/* getservbyname mock for hermetic tests
+/* SYNOPSIS
+/* #include <mock_servent.h>
+/*
+/* struct servent *getservbyname(
+/* const char *name,
+/* const char *proto)
+/*
+/* void setservent(
+/* int stayopen)
+/*
+/* void endservent(void)
+/* EXPECTATION SETUP
+/* void expect_getservbyname(
+/* int calls_expected,
+/* int retval,
+/* const char *name,
+/* const char *proto)
+/*
+/* void expect_setservent(
+/* int calls_expected,
+/* int stayopen)
+/*
+/* void expect_endservent(
+/* int calls_expected)
+/*
+/* struct servent *make_servent(
+/* const char *name,
+/* int port,
+/* const char *proto)
+/*
+/* void free_servent(
+/* struct servent *ent)
+/* MATCHERS
+/* int eq_servent(
+/* PTEST_CTX *t,
+/* const char *what,
+/* struct servent *got,
+/* struct servent *want)
+/* DESCRIPTION
+/* This module implements a partial mock getservent(3) module
+/* that produces prepared outputs in response to expected
+/* inputs. This supports hermetic tests, i.e. tests that do
+/* not depend on host configuration or on network access.
+/*
+/* expect_getservbyname() makes deep copies of its input
+/* arguments. The retval argument specifies a prepared result
+/* value. The calls_expected argument specifies the expected
+/* number of calls (zero means one or more calls, not: zero
+/* calls).
+/*
+/* Note: getservbyname() maintains ownership of the struct
+/* servent result that is returned by the mock getservbyname()
+/* function. This is for consistency with the real getservbyname()
+/* which also maintains ownership of the result.
+/*
+/* expect_setservent() copies its stayopen argument. The
+/* calls_expected argument specifies the expected number of
+/* calls (zero means one or more calls, not: zero calls).
+/*
+/* expect_endservent() has no expected inputs. The calls_expected
+/* argument specifies the expected number of calls (zero means
+/* one or more calls, not: zero calls).
+/*
+/* make_servent() returns a pointer to a minimal struct servent
+/* instance. Use free_servent() to destroy it.
+/*
+/* eq_servent() is a predicate that compares its arguments for
+/* equality. The what argument is used in logging when the
+/* inputs differ. Specify a null test context for silent
+/* operation.
+/* DIAGNOSTICS
+/* If a mock is called unexpectedly (the call arguments do not
+/* match an expectation, or more calls are made than expected),
+/* a warning is logged, and the test will be flagged as failed.
+/* For now the mock returns an error result to the caller.
+/* TODO: consider aborting the test.
+/* SEE ALSO
+/* dns_lookup(3), domain name service lookup
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <wrap_netdb.h>
+#include <string.h>
+
+ /*
+ * Utility library.
+ */
+#include <mymalloc.h>
+#include <msg.h>
+
+ /*
+ * Test library.
+ */
+#include <mock_servent.h>
+#include <pmock_expect.h>
+
+ /*
+ * Helpers.
+ */
+#define MYSTRDUP_OR_NULL(x) ((x) ? mystrdup(x) : 0)
+#define STR_OR_NULL(s) ((s) ? (s) : "(null)")
+
+#define STR(x) vstring_str(x)
+
+/* copy_servent - deep copy */
+
+static struct servent *copy_servent(struct servent * src)
+{
+ struct servent *dst;
+
+ dst = (struct servent *) mymalloc(sizeof(*dst));
+ dst->s_name = MYSTRDUP_OR_NULL(src->s_name);
+ dst->s_aliases = mymalloc(sizeof(*dst->s_aliases));
+ dst->s_aliases[0] = 0;
+ dst->s_port = src->s_port;
+ dst->s_proto = MYSTRDUP_OR_NULL(src->s_proto);
+ return (dst);
+}
+
+/* make_servent - create mock servent instance */
+
+struct servent *make_servent(const char *name, int port, const char *proto)
+{
+ struct servent *dst;
+
+ dst = (struct servent *) mymalloc(sizeof(*dst));
+ dst->s_name = MYSTRDUP_OR_NULL(name);
+ dst->s_aliases = mymalloc(sizeof(*dst->s_aliases));
+ dst->s_aliases[0] = 0;
+ dst->s_port = htons(port);
+ dst->s_proto = MYSTRDUP_OR_NULL(proto);
+ return (dst);
+}
+
+/* free_servent - destructor */
+
+void free_servent(struct servent * ent)
+{
+ if (ent->s_name)
+ myfree(ent->s_name);
+ if (ent->s_aliases)
+ myfree((char *) ent->s_aliases);
+ if (ent->s_proto)
+ myfree(ent->s_proto);
+ myfree(ent);
+}
+
+/* eq_aliases - equality predicate */
+
+static int eq_aliases(PTEST_CTX *t, const char *file, int line, const char *what,
+ char **got, char **want)
+{
+ if (got[0] == 0 && want[0] == 0)
+ return (1);
+ if (got[0] == 0 || want[0] == 0) {
+ if (t)
+ ptest_error(t, "%s: got alias %s, want %s",
+ what, got[0] ? got[0] : "(null)",
+ want[0] ? want[0] : "(null)");
+ return (0);
+ }
+ if (strcmp(got[0], want[0]) != 0) {
+ if (t)
+ ptest_error(t, "%s: got alias '%s', want '%s'",
+ what, got[0], want[0]);
+ return (0);
+ }
+ return (1);
+}
+
+/* _eq_servent - equality predicate */
+
+int _eq_servent(PTEST_CTX *t, const char *file, int line,
+ const char *what,
+ struct servent * got, struct servent * want)
+{
+ if (got == 0 && want == 0)
+ return (1);
+ if (got == 0 || want == 0) {
+ if (t)
+ ptest_error(t, "%s: got %s, want %s",
+ what, got ? "(struct servent *)" : "(null)",
+ want ? "(struct servent *)" : "(null)");
+ return (0);
+ }
+ if (strcmp(got->s_name, want->s_name) != 0) {
+ if (t)
+ ptest_error(t, "%s: got name '%s', want '%s'",
+ what, got->s_name, want->s_name);
+ return (0);
+ }
+ if (!eq_aliases(t, file, line, what, got->s_aliases, want->s_aliases))
+ return (0);
+ if (got->s_port != want->s_port) {
+ if (t)
+ ptest_error(t, "%s: got port %d, want %d",
+ what, ntohs(got->s_port), ntohs(want->s_port));
+ return (0);
+ }
+ if (strcmp(got->s_proto, want->s_proto) != 0) {
+ if (t)
+ ptest_error(t, "%s: got proto '%s', want '%s'",
+ what, got->s_proto, want->s_proto);
+ return (0);
+ }
+ return (1);
+}
+
+ /*
+ * Manage getservbyname() expectations and responses. We use this structure
+ * for deep copies of expect_getservbyname() expected inputs and prepared
+ * responses, and for shallow copies of getservbyname() inputs.
+ */
+struct getservbyname_expectation {
+ MOCK_EXPECT mock_expect; /* generic fields */
+ char *name; /* inputs */
+ char *proto;
+ struct servent *retval; /* outputs */
+};
+
+ /*
+ * Pointers to getservbyname() outputs.
+ */
+struct getservbyname_targets {
+ struct servent **retval;
+};
+
+/* match_getservbyname - match inputs against expectation */
+
+static int match_getservbyname(const MOCK_EXPECT *expect,
+ const MOCK_EXPECT *inputs)
+{
+ struct getservbyname_expectation *pe =
+ (struct getservbyname_expectation *) expect;
+ struct getservbyname_expectation *pi =
+ (struct getservbyname_expectation *) inputs;
+
+ return (strcmp(STR_OR_NULL(pe->name),
+ STR_OR_NULL(pi->name)) == 0
+ && strcmp(STR_OR_NULL(pe->proto),
+ STR_OR_NULL(pi->proto)) == 0);
+}
+
+/* assign_getservbyname - assign expected output */
+
+static void assign_getservbyname(const MOCK_EXPECT *expect,
+ void *targets)
+{
+ struct getservbyname_expectation *pe =
+ (struct getservbyname_expectation *) expect;
+ struct getservbyname_targets *pt =
+ (struct getservbyname_targets *) targets;
+
+ /* Not a deep copy. */
+ *pt->retval = pe->retval;
+}
+
+/* print_getservbyname - print expected inputs */
+
+static char *print_getservbyname(const MOCK_EXPECT *expect,
+ VSTRING *buf)
+{
+ struct getservbyname_expectation *pe =
+ (struct getservbyname_expectation *) expect;
+
+ vstring_sprintf(buf, "\"%s\", \"%s\"",
+ STR_OR_NULL(pe->name), STR_OR_NULL(pe->proto));
+ return (STR(buf));
+}
+
+/* free_getservbyname - destructor */
+
+static void free_getservbyname(MOCK_EXPECT *expect)
+{
+ struct getservbyname_expectation *pe =
+ (struct getservbyname_expectation *) expect;
+
+ if (pe->name)
+ myfree(pe->name);
+ if (pe->proto)
+ myfree(pe->proto);
+ if (pe->retval)
+ free_servent(pe->retval);
+ pmock_expect_free(expect);
+}
+
+ /*
+ * The mock name and its helper callbacks in one place.
+ */
+static const MOCK_APPL_SIG getservbyname_sig = {
+ "getservbyname",
+ match_getservbyname,
+ assign_getservbyname,
+ print_getservbyname,
+ free_getservbyname,
+};
+
+/* _expect_getservbyname - set up expectation */
+
+void _expect_getservbyname(const char *file, int line,
+ int calls_expected, struct servent * retval,
+ const char *name, const char *proto)
+{
+ struct getservbyname_expectation *pe;
+
+ pe = (struct getservbyname_expectation *)
+ pmock_expect_create(&getservbyname_sig,
+ file, line, calls_expected, sizeof(*pe));
+ /* Inputs. */
+ pe->name = MYSTRDUP_OR_NULL(name);
+ pe->proto = MYSTRDUP_OR_NULL(proto);
+ /* Outputs. */
+ pe->retval = retval ? copy_servent(retval) : retval;
+}
+
+/* getservbyname - answer the call with prepared responses */
+
+struct servent *getservbyname(const char *name, const char *proto)
+{
+ struct getservbyname_expectation inputs;
+ struct getservbyname_targets targets;
+ struct servent *retval = 0;
+
+ /*
+ * Bundle the arguments to simplify handling.
+ */
+ inputs.name = (char *) name;
+ inputs.proto = (char *) proto;
+
+ targets.retval = &retval;
+
+ /*
+ * TODO: bail out if there was no match?
+ */
+ (void) pmock_expect_apply(&getservbyname_sig,
+ &inputs.mock_expect, (void *) &targets);
+ return (retval);
+}
+
+ /*
+ * Manage setservent() expectations. This function has no outputs.
+ */
+struct setservent_expectation {
+ MOCK_EXPECT mock_expect; /* generic fields */
+ int stayopen; /* input */
+};
+
+static int match_setservent(const MOCK_EXPECT *expect,
+ const MOCK_EXPECT *inputs)
+{
+ struct setservent_expectation *pe =
+ (struct setservent_expectation *) expect;
+ struct setservent_expectation *pi =
+ (struct setservent_expectation *) inputs;
+
+ return (pe->stayopen == pi->stayopen);
+}
+
+/* print_setservent - print expected inputs */
+
+static char *print_setservent(const MOCK_EXPECT *expect,
+ VSTRING *buf)
+{
+ struct setservent_expectation *pe =
+ (struct setservent_expectation *) expect;
+
+ vstring_sprintf(buf, "%d", pe->stayopen);
+ return (STR(buf));
+}
+
+ /*
+ * The mock name and its helper callbacks in one place.
+ */
+static const MOCK_APPL_SIG setservent_sig = {
+ "setservent",
+ match_setservent,
+ 0, /* no outputs to assign */
+ print_setservent,
+ pmock_expect_free,
+};
+
+/* _expect_setservent - set up expectation */
+
+void _expect_setservent(const char *file, int line,
+ int calls_expected, int stayopen)
+{
+ struct setservent_expectation *pe;
+
+ pe = (struct setservent_expectation *)
+ pmock_expect_create(&setservent_sig,
+ file, line, calls_expected, sizeof(*pe));
+ /* Inputs. */
+ pe->stayopen = stayopen;
+}
+
+/* setservent - answer the call */
+
+void setservent(int stayopen)
+{
+ struct setservent_expectation inputs;
+
+ /*
+ * Bundle the arguments to simplify handling.
+ */
+ inputs.stayopen = stayopen;
+
+ /*
+ * TODO: bail out if there was no match?
+ */
+ (void) pmock_expect_apply(&setservent_sig,
+ &inputs.mock_expect, (void *) 0);
+}
+
+ /*
+ * Manage endservent() expectations. This function has no arguments (all
+ * calls will match), and no outputs.
+ */
+
+/* print_endservent - print expected inputs */
+
+static char *print_endservent(const MOCK_EXPECT *expect,
+ VSTRING *buf)
+{
+ VSTRING_RESET(buf);
+ VSTRING_TERMINATE(buf);
+ return (STR(buf));
+}
+
+ /*
+ * The mock name and its helper callbacks in one place.
+ */
+static const MOCK_APPL_SIG endservent_sig = {
+ "endservent",
+ 0, /* no inputs to match */
+ 0, /* no outputs to assign */
+ print_endservent,
+ pmock_expect_free,
+};
+
+/* _expect_endservent - set up expectation */
+
+void _expect_endservent(const char *file, int line, int calls_expected)
+{
+ (void) pmock_expect_create(&endservent_sig,
+ file, line, calls_expected, sizeof(MOCK_EXPECT));
+}
+
+/* endservent - return no answer */
+
+void endservent(void)
+{
+
+ /*
+ * TODO: bail out if there was no match?
+ */
+ (void) pmock_expect_apply(&endservent_sig, (MOCK_EXPECT *) 0, (void *) 0);
+}
--- /dev/null
+#ifndef _MOCK_SERVENT_H_INCLUDED_
+#define _MOCK_SERVENT_H_INCLUDED_
+
+/*++
+/* NAME
+/* mock_servent 3h
+/* SUMMARY
+/* getservbyname mock for hermetic tests
+/* SYNOPSIS
+/* #include <mock_servent.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <wrap_netdb.h>
+
+ /*
+ * Test library.
+ */
+#include <ptest.h>
+
+ /*
+ * Manage expectations and responses. Capture the source file name and line
+ * number for better diagnostics.
+ */
+#define expect_getservbyname(exp_calls, retval, name, proto) \
+ _expect_getservbyname(__FILE__, __LINE__, (exp_calls), (retval), \
+ (name), (proto))
+
+extern void _expect_getservbyname(const char *, int, int, struct servent *,
+ const char *, const char *);
+
+#define expect_setservent(exp_calls, stayopen) \
+ _expect_setservent(__FILE__, __LINE__, (exp_calls), (stayopen))
+
+extern void _expect_setservent(const char *, int, int, int);
+
+#define expect_endservent(exp_calls) \
+ _expect_endservent(__FILE__, __LINE__, (exp_calls))
+
+extern void _expect_endservent(const char *, int, int);
+
+ /*
+ * Matcher predicates. Capture the source file name and line number for
+ * better diagnostics.
+ */
+#define eq_servent(t, what, got, want) _eq_servent((t), __FILE__, __LINE__, \
+ (what), (got), (want))
+
+extern int _eq_servent(PTEST_CTX *, const char *, int,
+ const char *, struct servent *,
+ struct servent *);
+
+ /*
+ * Helper to create test data.
+ */
+extern struct servent *make_servent(const char *, int, const char *);
+
+extern void free_servent(struct servent *);
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+#endif
--- /dev/null
+ /*
+ * Test program to exercise mocks including logging. See pmock_expect_test.c
+ * and ptest_main.h for a documented example.
+ */
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <wrap_netdb.h>
+
+ /*
+ * Utility library.
+ */
+#include <msg.h>
+
+ /*
+ * Test library.
+ */
+#include <mock_servent.h>
+#include <pmock_expect.h>
+#include <ptest.h>
+
+typedef struct PTEST_CASE {
+ const char *testname; /* Human-readable description */
+ void (*action) (PTEST_CTX *, const struct PTEST_CASE *);
+} PTEST_CASE;
+
+static void test_getservbyname_success(PTEST_CTX *t, const PTEST_CASE *unused)
+{
+ struct servent *got_ent = 0, *want_ent;
+
+ /*
+ * Set up expectations.
+ */
+ want_ent = make_servent("smtp", 25, "tcp");
+ expect_getservbyname(1, want_ent, "smtp", "tcp");
+
+ /*
+ * Invoke the mock and verify results.
+ */
+ got_ent = getservbyname("smtp", "tcp");
+ if (eq_servent(t, "getservbyname", got_ent, want_ent) == 0)
+ ptest_error(t, "getservbyname: unexpected result mismatch");
+
+ /*
+ * Clean up.
+ */
+ free_servent(want_ent);
+}
+
+static void test_getservbyname_notexist(PTEST_CTX *t, const PTEST_CASE *unused)
+{
+ struct servent *got_ent, *want_ent = 0;
+
+ /*
+ * Set up expectations.
+ */
+ expect_getservbyname(1, want_ent, "noservice", "noproto");
+
+ /*
+ * Invoke the mock and verify results.
+ */
+ got_ent = getservbyname("noservice", "noproto");
+ if (eq_servent(t, "getservbyname", got_ent, want_ent) == 0)
+ ptest_error(t, "getservbyname: unexpected result mismatch");
+
+ /*
+ * Clean up.
+ */
+ if (got_ent)
+ free_servent(got_ent);
+}
+
+static void test_getservbyname_unused(PTEST_CTX *t, const PTEST_CASE *unused)
+{
+ struct servent *want_ent = 0;
+
+ /*
+ * Create an expectation, without calling it. I does not matter what the
+ * expectation is, so we use the one from test_getservbyname_notexist().
+ */
+ expect_getservbyname(1, want_ent, "noservice", "noproto");
+
+ /*
+ * We expect that there will be a 'missing call' error. If there is none
+ * then the test will fail.
+ */
+ expect_ptest_error(t, "got 0 calls for getservbyname(\"noservice\", "
+ "\"noproto\"), want 1");
+}
+
+static void test_eq_servent_differ(PTEST_CTX *t, const PTEST_CASE *unused)
+{
+
+ struct servent *got_ent, *want_ent = 0;
+ struct probes {
+ const char *name;
+ int port;
+ const char *proto;
+ const char *want_error;
+ };
+ static struct probes probes[4] = {
+ {"abc", 42, "def"},
+ {"cba", 42, "def", "eq_servent: got name 'cba', want 'abc'"},
+ {"abc", 24, "def", "eq_servent: got port 24, want 42"},
+ {"abc", 42, "fed", "eq_servent: got proto 'fed', want 'def'"},
+ };
+ struct probes *pp;
+ int want_eq;
+
+ pp = probes;
+ want_ent = make_servent(pp->name, pp->port, pp->proto);
+ for (pp = probes; pp < probes + sizeof(probes) / sizeof(probes[0]); pp++) {
+ got_ent = make_servent(pp->name, pp->port, pp->proto);
+ want_eq = !pp->want_error;
+ if (pp->want_error)
+ expect_ptest_error(t, pp->want_error);
+ if (eq_servent(t, "eq_servent", got_ent, want_ent) != want_eq)
+ ptest_error(t, "unexpected eq_servent result mismatch");
+ free_servent(got_ent);
+ }
+ free_servent(want_ent);
+}
+
+static void test_setservent_match(PTEST_CTX *t, const PTEST_CASE *unused)
+{
+
+ /*
+ * Set up expectations.
+ */
+ expect_setservent(1, 1);
+
+ /*
+ * Invoke the mock and verify results.
+ */
+ setservent(1);
+}
+
+static void test_setservent_nomatch(PTEST_CTX *t, const PTEST_CASE *unused)
+{
+
+ /*
+ * Set up expectations.
+ */
+ expect_setservent(1, 1);
+
+ /*
+ * These errors are intentional. If they don't happen then the test
+ * fails.
+ */
+ expect_ptest_error(t, "unexpected call: setservent(2)");
+ expect_ptest_error(t, "got 0 calls for setservent(1), want 1");
+
+ /*
+ * Invoke the mock and verify results.
+ */
+ setservent(2);
+}
+
+static void test_endservent_match(PTEST_CTX *t, const PTEST_CASE *unused)
+{
+
+ /*
+ * Set up expectations.
+ */
+ expect_endservent(1);
+
+ /*
+ * Invoke the mock and verify results.
+ */
+ endservent();
+}
+
+static void test_endservent_unused(PTEST_CTX *t, const PTEST_CASE *unused)
+{
+
+ /*
+ * Set up expectations without making a call.
+ */
+ expect_endservent(1);
+
+ /*
+ * This error is intentional. If it does not happen the test fails.
+ */
+ expect_ptest_error(t, "got 0 calls for endservent(), want 1");
+
+ /*
+ * Verify results (this happens in the test infrastructure).
+ */
+}
+
+ /*
+ * Test cases. The "success" tests exercise the expectation match and apply
+ * helpers, and "unused" tests exercise the print helpers.
+ */
+const PTEST_CASE ptestcases[] = {
+
+ /*
+ * getservbyname()
+ */
+ {
+ "test getservbyname success", test_getservbyname_success,
+ },
+ {
+ "test getservbyname notexist", test_getservbyname_notexist,
+ },
+ {
+ "test getservbyname unused", test_getservbyname_unused,
+ },
+
+ /*
+ * eq_servent()
+ */
+ {
+ "test eq_servent differ", test_eq_servent_differ,
+ },
+
+ /*
+ * setservent()
+ */
+ {
+ "test setservent match", test_setservent_match,
+ },
+ {
+ "test setservent nomatch", test_setservent_nomatch,
+ },
+
+ /*
+ * endservent()
+ */
+ {
+ "test endservent match", test_endservent_match,
+ },
+ {
+ "test endservent unused", test_endservent_unused,
+ },
+
+};
+
+#include <ptest_main.h>
tls_bio_ops.o: ../../include/vbuf.h
tls_bio_ops.o: ../../include/vstream.h
tls_bio_ops.o: ../../include/vstring.h
+tls_bio_ops.o: ../../include/wrap_netdb.h
tls_bio_ops.o: tls.h
tls_bio_ops.o: tls_bio_ops.c
tls_certkey.o: ../../include/argv.h
tls_certkey.o: ../../include/vbuf.h
tls_certkey.o: ../../include/vstream.h
tls_certkey.o: ../../include/vstring.h
+tls_certkey.o: ../../include/wrap_netdb.h
tls_certkey.o: tls.h
tls_certkey.o: tls_certkey.c
tls_client.o: ../../include/argv.h
tls_client.o: ../../include/vbuf.h
tls_client.o: ../../include/vstream.h
tls_client.o: ../../include/vstring.h
+tls_client.o: ../../include/wrap_netdb.h
tls_client.o: tls.h
tls_client.o: tls_client.c
tls_client.o: tls_mgr.h
tls_dane.o: ../../include/vbuf.h
tls_dane.o: ../../include/vstream.h
tls_dane.o: ../../include/vstring.h
+tls_dane.o: ../../include/wrap_netdb.h
tls_dane.o: tls.h
tls_dane.o: tls_dane.c
tls_dh.o: ../../include/argv.h
tls_dh.o: ../../include/vbuf.h
tls_dh.o: ../../include/vstream.h
tls_dh.o: ../../include/vstring.h
+tls_dh.o: ../../include/wrap_netdb.h
tls_dh.o: tls.h
tls_dh.o: tls_dh.c
tls_fprint.o: ../../include/argv.h
tls_fprint.o: ../../include/vbuf.h
tls_fprint.o: ../../include/vstream.h
tls_fprint.o: ../../include/vstring.h
+tls_fprint.o: ../../include/wrap_netdb.h
tls_fprint.o: tls.h
tls_fprint.o: tls_fprint.c
tls_level.o: ../../include/argv.h
tls_level.o: ../../include/vbuf.h
tls_level.o: ../../include/vstream.h
tls_level.o: ../../include/vstring.h
+tls_level.o: ../../include/wrap_netdb.h
tls_level.o: tls.h
tls_level.o: tls_level.c
tls_mgr.o: ../../include/argv.h
tls_misc.o: ../../include/vbuf.h
tls_misc.o: ../../include/vstream.h
tls_misc.o: ../../include/vstring.h
+tls_misc.o: ../../include/wrap_netdb.h
tls_misc.o: tls.h
tls_misc.o: tls_misc.c
tls_prng_dev.o: ../../include/connect.h
tls_proxy_client_misc.o: ../../include/vbuf.h
tls_proxy_client_misc.o: ../../include/vstream.h
tls_proxy_client_misc.o: ../../include/vstring.h
+tls_proxy_client_misc.o: ../../include/wrap_netdb.h
tls_proxy_client_misc.o: tls.h
tls_proxy_client_misc.o: tls_proxy.h
tls_proxy_client_misc.o: tls_proxy_client_misc.c
tls_proxy_client_print.o: ../../include/vbuf.h
tls_proxy_client_print.o: ../../include/vstream.h
tls_proxy_client_print.o: ../../include/vstring.h
+tls_proxy_client_print.o: ../../include/wrap_netdb.h
tls_proxy_client_print.o: tls.h
tls_proxy_client_print.o: tls_proxy.h
tls_proxy_client_print.o: tls_proxy_client_print.c
tls_proxy_client_scan.o: ../../include/vbuf.h
tls_proxy_client_scan.o: ../../include/vstream.h
tls_proxy_client_scan.o: ../../include/vstring.h
+tls_proxy_client_scan.o: ../../include/wrap_netdb.h
tls_proxy_client_scan.o: tls.h
tls_proxy_client_scan.o: tls_proxy.h
tls_proxy_client_scan.o: tls_proxy_client_scan.c
tls_proxy_clnt.o: ../../include/vbuf.h
tls_proxy_clnt.o: ../../include/vstream.h
tls_proxy_clnt.o: ../../include/vstring.h
+tls_proxy_clnt.o: ../../include/wrap_netdb.h
tls_proxy_clnt.o: tls.h
tls_proxy_clnt.o: tls_proxy.h
tls_proxy_clnt.o: tls_proxy_clnt.c
tls_proxy_context_print.o: ../../include/vbuf.h
tls_proxy_context_print.o: ../../include/vstream.h
tls_proxy_context_print.o: ../../include/vstring.h
+tls_proxy_context_print.o: ../../include/wrap_netdb.h
tls_proxy_context_print.o: tls.h
tls_proxy_context_print.o: tls_proxy.h
tls_proxy_context_print.o: tls_proxy_context_print.c
tls_proxy_context_scan.o: ../../include/vbuf.h
tls_proxy_context_scan.o: ../../include/vstream.h
tls_proxy_context_scan.o: ../../include/vstring.h
+tls_proxy_context_scan.o: ../../include/wrap_netdb.h
tls_proxy_context_scan.o: tls.h
tls_proxy_context_scan.o: tls_proxy.h
tls_proxy_context_scan.o: tls_proxy_context_scan.c
tls_proxy_server_print.o: ../../include/vbuf.h
tls_proxy_server_print.o: ../../include/vstream.h
tls_proxy_server_print.o: ../../include/vstring.h
+tls_proxy_server_print.o: ../../include/wrap_netdb.h
tls_proxy_server_print.o: tls.h
tls_proxy_server_print.o: tls_proxy.h
tls_proxy_server_print.o: tls_proxy_server_print.c
tls_proxy_server_scan.o: ../../include/vbuf.h
tls_proxy_server_scan.o: ../../include/vstream.h
tls_proxy_server_scan.o: ../../include/vstring.h
+tls_proxy_server_scan.o: ../../include/wrap_netdb.h
tls_proxy_server_scan.o: tls.h
tls_proxy_server_scan.o: tls_proxy.h
tls_proxy_server_scan.o: tls_proxy_server_scan.c
tls_seed.o: ../../include/vbuf.h
tls_seed.o: ../../include/vstream.h
tls_seed.o: ../../include/vstring.h
+tls_seed.o: ../../include/wrap_netdb.h
tls_seed.o: tls.h
tls_seed.o: tls_mgr.h
tls_seed.o: tls_scache.h
tls_server.o: ../../include/vbuf.h
tls_server.o: ../../include/vstream.h
tls_server.o: ../../include/vstring.h
+tls_server.o: ../../include/wrap_netdb.h
tls_server.o: tls.h
tls_server.o: tls_mgr.h
tls_server.o: tls_scache.h
tls_session.o: ../../include/vbuf.h
tls_session.o: ../../include/vstream.h
tls_session.o: ../../include/vstring.h
+tls_session.o: ../../include/wrap_netdb.h
tls_session.o: tls.h
tls_session.o: tls_session.c
tls_stream.o: ../../include/argv.h
tls_stream.o: ../../include/vbuf.h
tls_stream.o: ../../include/vstream.h
tls_stream.o: ../../include/vstring.h
+tls_stream.o: ../../include/wrap_netdb.h
tls_stream.o: tls.h
tls_stream.o: tls_stream.c
tls_verify.o: ../../include/argv.h
tls_verify.o: ../../include/vbuf.h
tls_verify.o: ../../include/vstream.h
tls_verify.o: ../../include/vstring.h
+tls_verify.o: ../../include/wrap_netdb.h
tls_verify.o: tls.h
tls_verify.o: tls_verify.c
tlsmgr.o: ../../include/vstring.h
tlsmgr.o: ../../include/vstring_vstream.h
tlsmgr.o: ../../include/warn_stat.h
+tlsmgr.o: ../../include/wrap_netdb.h
tlsmgr.o: tlsmgr.c
tlsproxy.o: ../../include/vbuf.h
tlsproxy.o: ../../include/vstream.h
tlsproxy.o: ../../include/vstring.h
+tlsproxy.o: ../../include/wrap_netdb.h
tlsproxy.o: tlsproxy.c
tlsproxy.o: tlsproxy.h
tlsproxy_state.o: ../../include/argv.h
tlsproxy_state.o: ../../include/vbuf.h
tlsproxy_state.o: ../../include/vstream.h
tlsproxy_state.o: ../../include/vstring.h
+tlsproxy_state.o: ../../include/wrap_netdb.h
tlsproxy_state.o: tlsproxy.h
tlsproxy_state.o: tlsproxy_state.c
allascii.c load_file.c killme_after.c vstream_tweak.c \
pass_trigger.c edit_file.c inet_windowsize.c \
unix_pass_fd_fix.c dict_cache.c valid_utf8_string.c dict_thash.c \
- ip_match.c nbbio.c base32_code.c dict_test.c \
+ ip_match.c nbbio.c base32_code.c dict_cli.c \
dict_fail.c msg_rate_delay.c dict_surrogate.c warn_stat.c \
dict_sockmap.c line_number.c recv_pass_attr.c pass_accept.c \
poll_fd.c timecmp.c slmdb.c dict_pipe.c dict_random.c \
msg_logger.c logwriter.c unix_dgram_connect.c unix_dgram_listen.c \
byte_mask.c known_tcp_ports.c argv_split_at.c dict_stream.c \
sane_strtol.c hash_fnv.c ldseed.c mkmap_cdb.c mkmap_db.c mkmap_dbm.c \
- mkmap_fail.c mkmap_lmdb.c mkmap_open.c mkmap_sdbm.c
+ mkmap_fail.c mkmap_lmdb.c mkmap_open.c mkmap_sdbm.c \
+ find_inet_service.c wrap_netdb.c
OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
attr_print64.o attr_print_plain.o attr_scan0.o attr_scan64.o \
attr_scan_plain.o auto_clnt.o base64_code.o basename.o binhash.o \
allascii.o load_file.o killme_after.o vstream_tweak.o \
pass_trigger.o edit_file.o inet_windowsize.o \
unix_pass_fd_fix.o dict_cache.o valid_utf8_string.o dict_thash.o \
- ip_match.o nbbio.o base32_code.o dict_test.o \
+ ip_match.o nbbio.o base32_code.o dict_cli.o \
dict_fail.o msg_rate_delay.o dict_surrogate.o warn_stat.o \
dict_sockmap.o line_number.o recv_pass_attr.o pass_accept.o \
poll_fd.o timecmp.o $(NON_PLUGIN_MAP_OBJ) dict_pipe.o dict_random.o \
msg_logger.o logwriter.o unix_dgram_connect.o unix_dgram_listen.o \
byte_mask.o known_tcp_ports.o argv_split_at.o dict_stream.o \
sane_strtol.o hash_fnv.o ldseed.o mkmap_db.o mkmap_dbm.o \
- mkmap_fail.o mkmap_open.o
+ mkmap_fail.o mkmap_open.o find_inet_service.o wrap_netdb.o
# MAP_OBJ is for maps that may be dynamically loaded with dynamicmaps.cf.
# When hard-linking these, makedefs sets NON_PLUGIN_MAP_OBJ=$(MAP_OBJ),
# otherwise it sets the PLUGIN_* macros.
MAP_OBJ = dict_pcre.o dict_cdb.o dict_lmdb.o dict_sdbm.o slmdb.o \
mkmap_cdb.o mkmap_lmdb.o mkmap_sdbm.o
+TEST_OBJ = dict_pipe_test.o dict_union_test.o find_inet_service_test.o \
+ known_tcp_ports_test.o msg_output_test.o myaddrinfo_test.o \
+ mymalloc_test.o mystrtok_test.o unescape_test.o hash_fnv_test.o \
+ argv_test.o dict_stream_test.o
HDRS = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \
chroot_uid.h cidr_match.h clean_env.h connect.h ctable.h dict.h \
dict_cdb.h dict_cidr.h dict_db.h dict_dbm.h dict_env.h dict_ht.h \
slmdb.h compat_va_copy.h dict_pipe.h dict_random.h \
valid_utf8_hostname.h midna_domain.h dict_union.h dict_inline.h \
check_arg.h argv_attr.h msg_logger.h logwriter.h byte_mask.h \
- known_tcp_ports.h sane_strtol.h hash_fnv.h ldseed.h mkmap.h
+ known_tcp_ports.h sane_strtol.h hash_fnv.h ldseed.h mkmap.h \
+ find_inet_service.h wrap_netdb.h
TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \
- stream_test.c dup2_pass_on_exec.c
+ stream_test.c dup2_pass_on_exec.c argv_test.c dict_pipe_test.c \
+ dict_stream_test.c dict_cli.c dict_union_test.c \
+ find_inet_service_test.c hash_fnv_test.c known_tcp_ports_test.c \
+ msg_output_test.c myaddrinfo_test.c mymalloc_test.c mystrtok_test.c \
+ unescape_test.c
DEFS = -I. -D$(SYSTYPE)
CFLAGS = $(DEBUG) $(OPT) $(DEFS)
FILES = Makefile $(SRCS) $(HDRS)
TESTPROG= dict_open dup2_pass_on_exec events exec_command fifo_open \
fifo_rdonly_bug fifo_rdwr_bug fifo_trigger fsspace fullname \
inet_addr_host inet_addr_local mac_parse make_dirs msg_syslog \
- mystrtok sigdelay translit valid_hostname vstream_popen \
+ mystrtok_test sigdelay translit valid_hostname vstream_popen \
vstring vstring_vstream doze select_bug stream_test mac_expand \
- watchdog unescape hex_quote name_mask rand_sleep sane_time ctable \
+ watchdog unescape_test hex_quote name_mask rand_sleep sane_time ctable \
inet_addr_list attr_print64 attr_scan64 base64_code attr_print0 \
attr_scan0 host_port attr_scan_plain attr_print_plain htable \
unix_recv_fd unix_send_fd stream_recv_fd stream_send_fd hex_code \
valid_utf8_string ip_match base32_code msg_rate_delay netstring \
vstream timecmp dict_cache midna_domain casefold strcasecmp_utf8 \
vbuf_print split_qnameval vstream msg_logger byte_mask \
- known_tcp_ports dict_stream find_inet binhash hash_fnv argv
+ known_tcp_ports_test dict_stream_test binhash hash_fnv_test \
+ argv_test find_inet_service_test mymalloc_test msg_output_test \
+ dict_union_test dict_pipe_test myaddrinfo_test
PLUGIN_MAP_SO = $(LIB_PREFIX)pcre$(LIB_SUFFIX) $(LIB_PREFIX)lmdb$(LIB_SUFFIX) \
$(LIB_PREFIX)cdb$(LIB_SUFFIX) $(LIB_PREFIX)sdbm$(LIB_SUFFIX)
HTABLE_FIX = NORANDOMIZE=1
+TEST_LIB= ../../lib/libtesting.a ../../lib/libptest.a
LIB_DIR = ../../lib
INC_DIR = ../../include
all: $(LIB) $(PLUGIN_MAP_SO_MAKE) $(PLUGIN_MAP_OBJ)
-$(OBJS) $(PLUGIN_MAP_OBJ): ../../conf/makedefs.out
+$(OBJS) $(PLUGIN_MAP_OBJ) $(TEST_OBJ): ../../conf/makedefs.out
Makefile: Makefile.in
cat ../../conf/makedefs.out $? >$@
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
mv junk $@.o
-mystrtok: $(LIB)
- mv $@.o junk
- $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
- mv junk $@.o
-
fifo_rdwr_bug: fifo_rdwr_bug.c $(LIB)
$(CC) $(CFLAGS) -o $@ $@.c $(LIB) $(SYSLIBS)
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
mv junk $@.o
-unescape: $(LIB)
- mv $@.o junk
- $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
- mv junk $@.o
-
hex_quote: $(LIB)
mv $@.o junk
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
mv junk $@.o
-find_inet: $(LIB)
- mv $@.o junk
- $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
- mv junk $@.o
-
-stream_test: stream_test.c $(LIB)
+test_sunos5_stream: test_sunos5_stream.c $(LIB)
$(CC) $(CFLAGS) -o $@ $@.c $(LIB) $(SYSLIBS)
gcctest: gccw.c gccw.ref
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
mv junk $@.o
-known_tcp_ports: $(LIB)
- mv $@.o junk
- $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
- mv junk $@.o
+known_tcp_ports_test: known_tcp_ports_test.o $(TEST_LIB) $(LIB)
+ $(CC) $(CFLAGS) -o $@ $@.o $(TEST_LIB) $(LIB) $(SYSLIBS)
+
+test_known_tcp_ports: update known_tcp_ports_test
+ $(SHLIB_ENV) ${VALGRIND} ./known_tcp_ports_test
dict_stream: $(LIB)
mv $@.o junk
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
mv junk $@.o
-tests: all valid_hostname_test mac_expand_test dict_test unescape_test \
+tests: all valid_hostname_test mac_expand_test dict_test test_unescape \
hex_quote_test ctable_test inet_addr_list_test base64_code_test \
attr_scan64_test attr_scan0_test host_port_test dict_tests \
- attr_scan_plain_test htable_test hex_code_test myaddrinfo_test \
+ attr_scan_plain_test htable_test hex_code_test test_myaddrinfo\
format_tv_test ip_match_test name_mask_tests base32_code_test \
surrogate_test timecmp_test midna_domain_test casefold_test \
strcasecmp_utf8_test vbuf_print_test miss_endif_cidr_test \
miss_endif_regexp_test split_qnameval_test vstring_test \
- vstream_test byte_mask_tests mystrtok_test known_tcp_ports_test \
- binhash_test argv_test
+ vstream_test byte_mask_tests test_mystrtok test_known_tcp_ports \
+ binhash_test test_argv test_find_inet_service test_mymalloc
dict_tests: all dict_test \
dict_pcre_tests dict_cidr_test dict_thash_test dict_static_test \
- dict_inline_test dict_utf8_test dict_regexp_test dict_union_test \
- dict_pipe_test dict_regexp_file_test dict_cidr_file_test \
+ dict_inline_test dict_utf8_test dict_regexp_test test_dict_union \
+ test_dict_pipe dict_regexp_file_test dict_cidr_file_test \
dict_static_file_test dict_random_test dict_random_file_test \
- dict_inline_file_test dict_stream_test dict_inline_regexp_test \
+ dict_inline_file_test test_dict_stream dict_inline_regexp_test \
dict_inline_cidr_test
dict_pcre_tests: dict_pcre_test miss_endif_pcre_test dict_pcre_file_test \
diff mac_expand.ref mac_expand.tmp
rm -f mac_expand.tmp
-unescape_test: unescape unescape.in unescape.ref
- $(SHLIB_ENV) ${VALGRIND} ./unescape <unescape.in | od -cb >unescape.tmp
- diff -b unescape.ref unescape.tmp
-# $(SHLIB_ENV) ${VALGRIND} ./unescape <unescape.in | $(SHLIB_ENV) ./unescape -e >unescape.tmp
-# diff unescape.in unescape.tmp
- rm -f unescape.tmp
+unescape_test: unescape_test.o $(TEST_LIB) $(LIB)
+ $(CC) $(CFLAGS) -o $@ $@.o $(TEST_LIB) $(LIB) $(SYSLIBS)
+
+test_unescape: update unescape_test
+ $(SHLIB_ENV) ${VALGRIND} ./unescape_test
hex_quote_test: hex_quote
$(SHLIB_ENV) ${VALGRIND} ./hex_quote <hex_quote.c | od -cb >hex_quote.tmp
binhash_test: binhash /usr/share/dict/words
$(SHLIB_ENV) ${VALGRIND} ./binhash < /usr/share/dict/words
-hash_fnv_test: hash_fnv
- $(SHLIB_ENV) ${VALGRIND} ./hash_fnv
+hash_fnv_test: hash_fnv_test.o $(TEST_LIB) $(LIB)
+ $(CC) $(CFLAGS) -o $@ $@.o $(LIB_DIR)/mock_getaddrinfo.o \
+ $(TEST_LIB) $(LIB) $(SYSLIBS)
+
+test_hash_fnv: update hash_fnv_test
+ $(SHLIB_ENV) ${VALGRIND} ./hash_fnv_test
hex_code_test: hex_code
$(SHLIB_ENV) ${VALGRIND} ./hex_code
timecmp_test: timecmp
$(SHLIB_ENV) ${VALGRIND} ./timecmp
-myaddrinfo_test: myaddrinfo myaddrinfo.ref myaddrinfo.ref2
- $(SHLIB_ENV) ${VALGRIND} ./myaddrinfo all belly.porcupine.org 168.100.3.2 >myaddrinfo.tmp 2>&1
- diff myaddrinfo.ref myaddrinfo.tmp
- rm -f myaddrinfo.tmp
- $(SHLIB_ENV) ${VALGRIND} ./myaddrinfo all null.porcupine.org 10.0.0.0 >myaddrinfo.tmp 2>&1
- diff myaddrinfo.ref2 myaddrinfo.tmp
- rm -f myaddrinfo.tmp
-
-myaddrinfo4_test: myaddrinfo4 myaddrinfo4.ref myaddrinfo4.ref2
- $(SHLIB_ENV) ${VALGRIND} ./myaddrinfo4 all belly.porcupine.org 168.100.3.2 >myaddrinfo4.tmp 2>&1
- diff myaddrinfo4.ref myaddrinfo4.tmp
- $(SHLIB_ENV) ${VALGRIND} ./myaddrinfo4 all null.porcupine.org 10.0.0.0 >myaddrinfo4.tmp 2>&1
- diff myaddrinfo4.ref2 myaddrinfo4.tmp
- rm -f myaddrinfo4.tmp
+myaddrinfo_test: myaddrinfo_test.o $(LIB_DIR)/mock_getaddrinfo.o \
+ $(TEST_LIB) $(LIB)
+ $(CC) $(CFLAGS) -o $@ $@.o $(LIB_DIR)/mock_getaddrinfo.o \
+ $(TEST_LIB) $(LIB) $(SYSLIBS)
+
+test_myaddrinfo: update myaddrinfo_test
+ $(SHLIB_ENV) ${VALGRIND} ./myaddrinfo_test
format_tv_test: format_tv format_tv.in format_tv.ref
$(SHLIB_ENV) ${VALGRIND} ./format_tv <format_tv.in >format_tv.tmp
diff vbuf_print_test.ref vbuf_print_test.tmp
rm -f vbuf_print_test.tmp
-dict_union_test: dict_open dict_union_test.in dict_union_test.ref
- $(SHLIB_ENV) ${VALGRIND} sh -x dict_union_test.in >dict_union_test.tmp 2>&1
- diff dict_union_test.ref dict_union_test.tmp
- rm -f dict_union_test.tmp
+dict_union_test: dict_union_test.o $(TEST_LIB) $(LIB)
+ $(CC) $(CFLAGS) -o $@ $@.o $(TEST_LIB) $(LIB) $(SYSLIBS)
+
+test_dict_union: update dict_union_test
+ $(SHLIB_ENV) ${VALGRIND} ./dict_union_test
-dict_pipe_test: dict_open dict_pipe_test.in dict_pipe_test.ref
- $(SHLIB_ENV) ${VALGRIND} sh -x dict_pipe_test.in >dict_pipe_test.tmp 2>&1
- diff dict_pipe_test.ref dict_pipe_test.tmp
- rm -f dict_pipe_test.tmp
+dict_pipe_test: dict_pipe_test.o $(TEST_LIB) $(LIB)
+ $(CC) $(CFLAGS) -o $@ $@.o $(TEST_LIB) $(LIB) $(SYSLIBS)
+
+test_dict_pipe: update dict_pipe_test
+ $(SHLIB_ENV) ${VALGRIND} ./dict_pipe_test
vstring_test: dict_open vstring vstring_test.ref
$(SHLIB_ENV) ${VALGRIND} ./vstring one two three >vstring_test.tmp 2>&1
diff vstream_test.ref vstream_test.tmp
rm -f vstream_test.tmp
-mystrtok_test: mystrtok mystrtok.ref
- $(SHLIB_ENV) ${VALGRIND} ./mystrtok >mystrtok.tmp 2>&1
- diff mystrtok.ref mystrtok.tmp
- rm -f mystrtok.tmp
+mystrtok_test: mystrtok_test.o $(TEST_LIB) $(LIB)
+ $(CC) $(CFLAGS) -o $@ $@.o $(TEST_LIB) $(LIB) $(SYSLIBS)
-known_tcp_ports_test: known_tcp_ports known_tcp_ports.ref
- $(SHLIB_ENV) ${VALGRIND} ./known_tcp_ports >known_tcp_ports.tmp 2>&1
- diff known_tcp_ports.ref known_tcp_ports.tmp
- rm -f known_tcp_ports.tmp
+test_mystrtok: update mystrtok_test
+ $(SHLIB_ENV) ${VALGRIND} ./mystrtok_test
-dict_stream_test: dict_stream dict_stream.ref
- $(SHLIB_ENV) ${VALGRIND} ./dict_stream >dict_stream.tmp 2>&1
- diff dict_stream.ref dict_stream.tmp
- rm -f dict_stream.tmp
+dict_stream_test: dict_stream_test.o $(TEST_LIB) $(LIB)
+ $(CC) $(CFLAGS) -o $@ $@.o $(TEST_LIB) $(LIB) $(SYSLIBS)
+
+test_dict_stream: update dict_stream_test
+ $(SHLIB_ENV) ${VALGRIND} ./dict_stream_test
dict_inline_pcre_test: dict_open dict_inline_pcre.ref
(echo get foo; echo get bar) | \
diff dict_inline_cidr.ref dict_inline_cidr.tmp
rm -f dict_inline_cidr.tmp
-find_inet_test: find_inet find_inet.ref
- $(SHLIB_ENV) ${VALGRIND} ./find_inet >find_inet.tmp 2>&1
- diff find_inet.ref find_inet.tmp
- rm -f find_inet.tmp
-
-argv_test: argv
- $(SHLIB_ENV) ${VALGRIND} ./argv
+find_inet_service_test: find_inet_service_test.o $(LIB_DIR)/mock_servent.o \
+ $(TEST_LIB) $(LIB)
+ $(CC) $(CFLAGS) -o $@ $@.o find_inet_service.o \
+ $(LIB_DIR)/mock_servent.o $(TEST_LIB) $(LIB) $(SYSLIBS)
+
+test_find_inet_service: update find_inet_service_test
+ $(SHLIB_ENV) ${VALGRIND} ./find_inet_service_test
+
+mymalloc_test: mymalloc_test.o $(TEST_LIB) $(LIB)
+ $(CC) $(CFLAGS) -o $@ $@.o $(TEST_LIB) $(LIB) $(SYSLIBS)
+
+test_mymalloc: update mymalloc_test
+ $(SHLIB_ENV) ${VALGRIND} ./mymalloc_test
+
+msg_output_test: msg_output_test.o $(TEST_LIB) $(LIB)
+ $(CC) $(CFLAGS) -o $@ $@.o $(TEST_LIB) $(LIB) $(SYSLIBS)
+
+test_msg_output: update msg_output_test
+ $(SHLIB_ENV) ${VALGRIND} ./msg_output_test
+
+argv_test: argv_test.o $(TEST_LIB) $(LIB)
+ $(CC) $(CFLAGS) -o $@ $@.o $(TEST_LIB) $(LIB) $(SYSLIBS)
+
+test_argv: update argv_test
+ $(SHLIB_ENV) ${VALGRIND} ./argv_test
depend: $(MAKES)
(sed '1,/^# do not edit/!d' Makefile.in; \
argv_splitq.o: sys_defs.h
argv_splitq.o: vbuf.h
argv_splitq.o: vstring.h
+argv_test.o: ../../include/pmock_expect.h
+argv_test.o: ../../include/ptest.h
+argv_test.o: ../../include/ptest_main.h
+argv_test.o: argv.h
+argv_test.o: argv_test.c
+argv_test.o: check_arg.h
+argv_test.o: msg.h
+argv_test.o: msg_output.h
+argv_test.o: msg_vstream.h
+argv_test.o: stringops.h
+argv_test.o: sys_defs.h
+argv_test.o: vbuf.h
+argv_test.o: vstream.h
+argv_test.o: vstring.h
attr_clnt.o: attr.h
attr_clnt.o: attr_clnt.c
attr_clnt.o: attr_clnt.h
cidr_match.o: sys_defs.h
cidr_match.o: vbuf.h
cidr_match.o: vstring.h
+cidr_match.o: wrap_netdb.h
clean_env.o: argv.h
clean_env.o: clean_env.c
clean_env.o: clean_env.h
dict_cidr.o: vstream.h
dict_cidr.o: vstring.h
dict_cidr.o: warn_stat.h
+dict_cidr.o: wrap_netdb.h
+dict_cli.o: argv.h
+dict_cli.o: check_arg.h
+dict_cli.o: dict.h
+dict_cli.o: dict_cli.c
+dict_cli.o: dict_db.h
+dict_cli.o: dict_lmdb.h
+dict_cli.o: mkmap.h
+dict_cli.o: msg.h
+dict_cli.o: msg_vstream.h
+dict_cli.o: myflock.h
+dict_cli.o: stringops.h
+dict_cli.o: sys_defs.h
+dict_cli.o: vbuf.h
+dict_cli.o: vstream.h
+dict_cli.o: vstring.h
+dict_cli.o: vstring_vstream.h
dict_db.o: argv.h
dict_db.o: check_arg.h
dict_db.o: dict.h
dict_pipe.o: vbuf.h
dict_pipe.o: vstream.h
dict_pipe.o: vstring.h
+dict_pipe_test.o: ../../include/pmock_expect.h
+dict_pipe_test.o: ../../include/ptest.h
+dict_pipe_test.o: ../../include/ptest_main.h
+dict_pipe_test.o: argv.h
+dict_pipe_test.o: check_arg.h
+dict_pipe_test.o: dict.h
+dict_pipe_test.o: dict_pipe.h
+dict_pipe_test.o: dict_pipe_test.c
+dict_pipe_test.o: msg.h
+dict_pipe_test.o: msg_output.h
+dict_pipe_test.o: msg_vstream.h
+dict_pipe_test.o: myflock.h
+dict_pipe_test.o: mymalloc.h
+dict_pipe_test.o: stringops.h
+dict_pipe_test.o: sys_defs.h
+dict_pipe_test.o: vbuf.h
+dict_pipe_test.o: vstream.h
+dict_pipe_test.o: vstring.h
dict_random.o: argv.h
dict_random.o: check_arg.h
dict_random.o: dict.h
dict_stream.o: vbuf.h
dict_stream.o: vstream.h
dict_stream.o: vstring.h
+dict_stream_test.o: ../../include/pmock_expect.h
+dict_stream_test.o: ../../include/ptest.h
+dict_stream_test.o: ../../include/ptest_main.h
+dict_stream_test.o: argv.h
+dict_stream_test.o: check_arg.h
+dict_stream_test.o: dict.h
+dict_stream_test.o: dict_stream_test.c
+dict_stream_test.o: msg.h
+dict_stream_test.o: msg_output.h
+dict_stream_test.o: msg_vstream.h
+dict_stream_test.o: myflock.h
+dict_stream_test.o: stringops.h
+dict_stream_test.o: sys_defs.h
+dict_stream_test.o: vbuf.h
+dict_stream_test.o: vstream.h
+dict_stream_test.o: vstring.h
dict_surrogate.o: argv.h
dict_surrogate.o: check_arg.h
dict_surrogate.o: compat_va_copy.h
dict_tcp.o: vstream.h
dict_tcp.o: vstring.h
dict_tcp.o: vstring_vstream.h
-dict_test.o: argv.h
-dict_test.o: check_arg.h
-dict_test.o: dict.h
-dict_test.o: dict_db.h
-dict_test.o: dict_lmdb.h
-dict_test.o: dict_test.c
-dict_test.o: mkmap.h
-dict_test.o: msg.h
-dict_test.o: msg_vstream.h
-dict_test.o: myflock.h
-dict_test.o: stringops.h
-dict_test.o: sys_defs.h
-dict_test.o: vbuf.h
-dict_test.o: vstream.h
-dict_test.o: vstring.h
-dict_test.o: vstring_vstream.h
dict_thash.o: argv.h
dict_thash.o: check_arg.h
dict_thash.o: dict.h
dict_union.o: vbuf.h
dict_union.o: vstream.h
dict_union.o: vstring.h
+dict_union_test.o: ../../include/pmock_expect.h
+dict_union_test.o: ../../include/ptest.h
+dict_union_test.o: ../../include/ptest_main.h
+dict_union_test.o: argv.h
+dict_union_test.o: check_arg.h
+dict_union_test.o: dict.h
+dict_union_test.o: dict_union.h
+dict_union_test.o: dict_union_test.c
+dict_union_test.o: msg.h
+dict_union_test.o: msg_output.h
+dict_union_test.o: msg_vstream.h
+dict_union_test.o: myflock.h
+dict_union_test.o: mymalloc.h
+dict_union_test.o: stringops.h
+dict_union_test.o: sys_defs.h
+dict_union_test.o: vbuf.h
+dict_union_test.o: vstream.h
+dict_union_test.o: vstring.h
dict_unix.o: argv.h
dict_unix.o: check_arg.h
dict_unix.o: dict.h
find_inet.o: sys_defs.h
find_inet.o: vbuf.h
find_inet.o: vstring.h
+find_inet_service.o: check_arg.h
+find_inet_service.o: find_inet_service.c
+find_inet_service.o: find_inet_service.h
+find_inet_service.o: known_tcp_ports.h
+find_inet_service.o: msg.h
+find_inet_service.o: sane_strtol.h
+find_inet_service.o: stringops.h
+find_inet_service.o: sys_defs.h
+find_inet_service.o: vbuf.h
+find_inet_service.o: vstring.h
+find_inet_service.o: wrap_netdb.h
+find_inet_service_test.o: ../../include/mock_servent.h
+find_inet_service_test.o: ../../include/pmock_expect.h
+find_inet_service_test.o: ../../include/ptest.h
+find_inet_service_test.o: ../../include/ptest_main.h
+find_inet_service_test.o: argv.h
+find_inet_service_test.o: check_arg.h
+find_inet_service_test.o: find_inet_service.h
+find_inet_service_test.o: find_inet_service_test.c
+find_inet_service_test.o: known_tcp_ports.h
+find_inet_service_test.o: msg.h
+find_inet_service_test.o: msg_output.h
+find_inet_service_test.o: msg_vstream.h
+find_inet_service_test.o: stringops.h
+find_inet_service_test.o: sys_defs.h
+find_inet_service_test.o: vbuf.h
+find_inet_service_test.o: vstream.h
+find_inet_service_test.o: vstring.h
+find_inet_service_test.o: wrap_netdb.h
format_tv.o: check_arg.h
format_tv.o: format_tv.c
format_tv.o: format_tv.h
hash_fnv.o: ldseed.h
hash_fnv.o: msg.h
hash_fnv.o: sys_defs.h
+hash_fnv_test.o: ../../include/pmock_expect.h
+hash_fnv_test.o: ../../include/ptest.h
+hash_fnv_test.o: ../../include/ptest_main.h
+hash_fnv_test.o: argv.h
+hash_fnv_test.o: check_arg.h
+hash_fnv_test.o: hash_fnv.h
+hash_fnv_test.o: hash_fnv_test.c
+hash_fnv_test.o: msg.h
+hash_fnv_test.o: msg_output.h
+hash_fnv_test.o: msg_vstream.h
+hash_fnv_test.o: stringops.h
+hash_fnv_test.o: sys_defs.h
+hash_fnv_test.o: vbuf.h
+hash_fnv_test.o: vstream.h
+hash_fnv_test.o: vstring.h
hex_code.o: check_arg.h
hex_code.o: hex_code.c
hex_code.o: hex_code.h
inet_addr_host.o: mymalloc.h
inet_addr_host.o: sock_addr.h
inet_addr_host.o: sys_defs.h
+inet_addr_host.o: wrap_netdb.h
inet_addr_list.o: inet_addr_list.c
inet_addr_list.o: inet_addr_list.h
inet_addr_list.o: msg.h
inet_addr_list.o: mymalloc.h
inet_addr_list.o: sock_addr.h
inet_addr_list.o: sys_defs.h
+inet_addr_list.o: wrap_netdb.h
inet_addr_local.o: check_arg.h
inet_addr_local.o: hex_code.h
inet_addr_local.o: inet_addr_list.h
inet_addr_local.o: sys_defs.h
inet_addr_local.o: vbuf.h
inet_addr_local.o: vstring.h
+inet_addr_local.o: wrap_netdb.h
inet_connect.o: connect.h
inet_connect.o: host_port.h
inet_connect.o: inet_connect.c
inet_connect.o: sock_addr.h
inet_connect.o: sys_defs.h
inet_connect.o: timed_connect.h
+inet_connect.o: wrap_netdb.h
inet_listen.o: host_port.h
inet_listen.o: htable.h
inet_listen.o: inet_listen.c
inet_listen.o: sane_accept.h
inet_listen.o: sock_addr.h
inet_listen.o: sys_defs.h
+inet_listen.o: wrap_netdb.h
inet_proto.o: check_arg.h
inet_proto.o: inet_proto.c
inet_proto.o: inet_proto.h
inet_proto.o: sys_defs.h
inet_proto.o: vbuf.h
inet_proto.o: vstring.h
+inet_proto.o: wrap_netdb.h
inet_trigger.o: connect.h
inet_trigger.o: events.h
inet_trigger.o: inet_trigger.c
known_tcp_ports.o: sys_defs.h
known_tcp_ports.o: vbuf.h
known_tcp_ports.o: vstring.h
+known_tcp_ports_test.o: ../../include/pmock_expect.h
+known_tcp_ports_test.o: ../../include/ptest.h
+known_tcp_ports_test.o: ../../include/ptest_main.h
+known_tcp_ports_test.o: argv.h
+known_tcp_ports_test.o: check_arg.h
+known_tcp_ports_test.o: known_tcp_ports.h
+known_tcp_ports_test.o: known_tcp_ports_test.c
+known_tcp_ports_test.o: msg.h
+known_tcp_ports_test.o: msg_output.h
+known_tcp_ports_test.o: msg_vstream.h
+known_tcp_ports_test.o: stringops.h
+known_tcp_ports_test.o: sys_defs.h
+known_tcp_ports_test.o: vbuf.h
+known_tcp_ports_test.o: vstream.h
+known_tcp_ports_test.o: vstring.h
ldseed.o: iostuff.h
ldseed.o: ldseed.c
ldseed.o: ldseed.h
load_file.o: vstream.h
load_file.o: warn_stat.h
load_lib.o: load_lib.c
-load_lib.o: load_lib.h
-load_lib.o: msg.h
load_lib.o: sys_defs.h
logwriter.o: check_arg.h
logwriter.o: iostuff.h
match_ops.o: vbuf.h
match_ops.o: vstream.h
match_ops.o: vstring.h
+match_ops.o: wrap_netdb.h
midna_domain.o: check_arg.h
midna_domain.o: ctable.h
midna_domain.o: midna_domain.c
msg_logger.o: vstream.h
msg_logger.o: vstring.h
msg_output.o: check_arg.h
+msg_output.o: msg.h
msg_output.o: msg_output.c
msg_output.o: msg_output.h
msg_output.o: msg_vstream.h
msg_output.o: vbuf.h
msg_output.o: vstream.h
msg_output.o: vstring.h
+msg_output_test.o: ../../include/match_basic.h
+msg_output_test.o: ../../include/pmock_expect.h
+msg_output_test.o: ../../include/ptest.h
+msg_output_test.o: ../../include/ptest_main.h
+msg_output_test.o: argv.h
+msg_output_test.o: check_arg.h
+msg_output_test.o: msg.h
+msg_output_test.o: msg_output.h
+msg_output_test.o: msg_output_test.c
+msg_output_test.o: msg_vstream.h
+msg_output_test.o: mymalloc.h
+msg_output_test.o: stringops.h
+msg_output_test.o: sys_defs.h
+msg_output_test.o: vbuf.h
+msg_output_test.o: vstream.h
+msg_output_test.o: vstring.h
msg_rate_delay.o: check_arg.h
msg_rate_delay.o: events.h
msg_rate_delay.o: msg.h
myaddrinfo.o: valid_hostname.h
myaddrinfo.o: vbuf.h
myaddrinfo.o: vstring.h
+myaddrinfo.o: wrap_netdb.h
+myaddrinfo_test.o: ../../include/addrinfo_to_string.h
+myaddrinfo_test.o: ../../include/make_addr.h
+myaddrinfo_test.o: ../../include/match_addr.h
+myaddrinfo_test.o: ../../include/match_basic.h
+myaddrinfo_test.o: ../../include/mock_getaddrinfo.h
+myaddrinfo_test.o: ../../include/pmock_expect.h
+myaddrinfo_test.o: ../../include/ptest.h
+myaddrinfo_test.o: ../../include/ptest_main.h
+myaddrinfo_test.o: argv.h
+myaddrinfo_test.o: check_arg.h
+myaddrinfo_test.o: inet_proto.h
+myaddrinfo_test.o: msg.h
+myaddrinfo_test.o: msg_output.h
+myaddrinfo_test.o: msg_vstream.h
+myaddrinfo_test.o: myaddrinfo.h
+myaddrinfo_test.o: myaddrinfo_test.c
+myaddrinfo_test.o: stringops.h
+myaddrinfo_test.o: sys_defs.h
+myaddrinfo_test.o: vbuf.h
+myaddrinfo_test.o: vstream.h
+myaddrinfo_test.o: vstring.h
+myaddrinfo_test.o: wrap_netdb.h
myflock.o: msg.h
myflock.o: myflock.c
myflock.o: myflock.h
mymalloc.o: mymalloc.c
mymalloc.o: mymalloc.h
mymalloc.o: sys_defs.h
+mymalloc_test.o: ../../include/pmock_expect.h
+mymalloc_test.o: ../../include/ptest.h
+mymalloc_test.o: ../../include/ptest_main.h
+mymalloc_test.o: argv.h
+mymalloc_test.o: check_arg.h
+mymalloc_test.o: msg.h
+mymalloc_test.o: msg_output.h
+mymalloc_test.o: msg_vstream.h
+mymalloc_test.o: mymalloc.h
+mymalloc_test.o: mymalloc_test.c
+mymalloc_test.o: stringops.h
+mymalloc_test.o: sys_defs.h
+mymalloc_test.o: vbuf.h
+mymalloc_test.o: vstream.h
+mymalloc_test.o: vstring.h
myrand.o: myrand.c
myrand.o: myrand.h
myrand.o: sys_defs.h
mystrtok.o: sys_defs.h
mystrtok.o: vbuf.h
mystrtok.o: vstring.h
+mystrtok_test.o: ../../include/pmock_expect.h
+mystrtok_test.o: ../../include/ptest.h
+mystrtok_test.o: ../../include/ptest_main.h
+mystrtok_test.o: argv.h
+mystrtok_test.o: check_arg.h
+mystrtok_test.o: msg.h
+mystrtok_test.o: msg_output.h
+mystrtok_test.o: msg_vstream.h
+mystrtok_test.o: mymalloc.h
+mystrtok_test.o: mystrtok_test.c
+mystrtok_test.o: stringops.h
+mystrtok_test.o: sys_defs.h
+mystrtok_test.o: vbuf.h
+mystrtok_test.o: vstream.h
+mystrtok_test.o: vstring.h
name_code.o: name_code.c
name_code.o: name_code.h
name_code.o: sys_defs.h
stream_send_fd.o: msg.h
stream_send_fd.o: stream_send_fd.c
stream_send_fd.o: sys_defs.h
-stream_test.o: check_arg.h
-stream_test.o: connect.h
-stream_test.o: htable.h
-stream_test.o: iostuff.h
-stream_test.o: listen.h
-stream_test.o: msg.h
-stream_test.o: msg_vstream.h
-stream_test.o: stream_test.c
-stream_test.o: sys_defs.h
-stream_test.o: vbuf.h
-stream_test.o: vstream.h
stream_trigger.o: connect.h
stream_trigger.o: events.h
stream_trigger.o: iostuff.h
stream_trigger.o: trigger.h
sys_compat.o: sys_compat.c
sys_compat.o: sys_defs.h
+test_sunos5_stream.o: check_arg.h
+test_sunos5_stream.o: connect.h
+test_sunos5_stream.o: htable.h
+test_sunos5_stream.o: iostuff.h
+test_sunos5_stream.o: listen.h
+test_sunos5_stream.o: msg.h
+test_sunos5_stream.o: msg_vstream.h
+test_sunos5_stream.o: sys_defs.h
+test_sunos5_stream.o: test_sunos5_stream.c
+test_sunos5_stream.o: vbuf.h
+test_sunos5_stream.o: vstream.h
timecmp.o: timecmp.c
timecmp.o: timecmp.h
timed_connect.o: iostuff.h
unescape.o: unescape.c
unescape.o: vbuf.h
unescape.o: vstring.h
+unescape_test.o: ../../include/pmock_expect.h
+unescape_test.o: ../../include/ptest.h
+unescape_test.o: ../../include/ptest_main.h
+unescape_test.o: argv.h
+unescape_test.o: check_arg.h
+unescape_test.o: msg.h
+unescape_test.o: msg_output.h
+unescape_test.o: msg_vstream.h
+unescape_test.o: stringops.h
+unescape_test.o: sys_defs.h
+unescape_test.o: unescape_test.c
+unescape_test.o: vbuf.h
+unescape_test.o: vstream.h
+unescape_test.o: vstring.h
unix_connect.o: connect.h
unix_connect.o: iostuff.h
unix_connect.o: msg.h
watchdog.o: sys_defs.h
watchdog.o: watchdog.c
watchdog.o: watchdog.h
+wrap_netdb.o: sys_defs.h
+wrap_netdb.o: wrap_netdb.c
+wrap_netdb.o: wrap_netdb.h
write_buf.o: iostuff.h
write_buf.o: msg.h
write_buf.o: sys_defs.h
argvp->argv[pos] = argvp->argv[pos + how_many];
argvp->argc -= how_many;
}
-
-#ifdef TEST
-
- /*
- * System library.
- */
-#include <setjmp.h>
-
- /*
- * Utility library.
- */
-#include <msg_vstream.h>
-#include <stringops.h>
-
-#define ARRAY_LEN (10)
-
-typedef struct TEST_CASE {
- const char *label; /* identifies test case */
- const char *inputs[ARRAY_LEN]; /* input strings */
- int terminate; /* terminate result */
- ARGV *(*populate_fn) (const struct TEST_CASE *, ARGV *);
- const char *exp_panic_msg; /* expected panic */
- int exp_argc; /* expected array length */
- const char *exp_argv[ARRAY_LEN]; /* expected array content */
-} TEST_CASE;
-
-#define TERMINATE_ARRAY (1)
-
-#define PASS (0)
-#define FAIL (1)
-
-VSTRING *test_panic_str;
-jmp_buf test_panic_jbuf;
-
-/* test_msg_panic - does not return, and does not terminate */
-
-void test_msg_panic(const char *fmt,...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- test_panic_str = vstring_alloc(100);
- vstring_vsprintf(test_panic_str, fmt, ap);
- va_end(ap);
- longjmp(test_panic_jbuf, 1);
-}
-
-/* test_argv_populate - populate result, optionally terminate */
-
-static ARGV *test_argv_populate(const TEST_CASE *tp, ARGV *argvp)
-{
- const char *const * cpp;
-
- for (cpp = tp->inputs; *cpp; cpp++)
- argv_add(argvp, *cpp, (char *) 0);
- if (tp->terminate)
- argv_terminate(argvp);
- return (argvp);
-}
-
-/* test_argv_sort - populate and sort result */
-
-static ARGV *test_argv_sort(const TEST_CASE *tp, ARGV *argvp)
-{
- test_argv_populate(tp, argvp);
- argv_qsort(argvp, (ARGV_COMPAR_FN) 0);
- return (argvp);
-}
-
-/* test_argv_sort_uniq - populate, sort, uniq result */
-
-static ARGV *test_argv_sort_uniq(const TEST_CASE *tp, ARGV *argvp)
-{
-
- /*
- * This also tests argv_delete().
- */
- test_argv_sort(tp, argvp);
- argv_uniq(argvp, (ARGV_COMPAR_FN) 0);
- return (argvp);
-}
-
-/* test_argv_good_truncate - populate and truncate to good size */
-
-static ARGV *test_argv_good_truncate(const TEST_CASE *tp, ARGV *argvp)
-{
- test_argv_populate(tp, argvp);
- argv_truncate(argvp, tp->exp_argc);
- return (argvp);
-}
-
-/* test_argv_bad_truncate - populate and truncate to bad size */
-
-static ARGV *test_argv_bad_truncate(const TEST_CASE *tp, ARGV *argvp)
-{
- test_argv_populate(tp, argvp);
- argv_truncate(argvp, -1);
- return (argvp);
-}
-
-/* test_argv_good_insert - populate and insert at good position */
-
-static ARGV *test_argv_good_insert(const TEST_CASE *tp, ARGV *argvp)
-{
- test_argv_populate(tp, argvp);
- argv_insert_one(argvp, 1, "new");
- return (argvp);
-}
-
-/* test_argv_bad_insert1 - populate and insert at bad position */
-
-static ARGV *test_argv_bad_insert1(const TEST_CASE *tp, ARGV *argvp)
-{
- test_argv_populate(tp, argvp);
- argv_insert_one(argvp, -1, "new");
- return (argvp);
-}
-
-/* test_argv_bad_insert2 - populate and insert at bad position */
-
-static ARGV *test_argv_bad_insert2(const TEST_CASE *tp, ARGV *argvp)
-{
- test_argv_populate(tp, argvp);
- argv_insert_one(argvp, 100, "new");
- return (argvp);
-}
-
-/* test_argv_good_replace - populate and replace at good position */
-
-static ARGV *test_argv_good_replace(const TEST_CASE *tp, ARGV *argvp)
-{
- test_argv_populate(tp, argvp);
- argv_replace_one(argvp, 1, "new");
- return (argvp);
-}
-
-/* test_argv_bad_replace1 - populate and replace at bad position */
-
-static ARGV *test_argv_bad_replace1(const TEST_CASE *tp, ARGV *argvp)
-{
- test_argv_populate(tp, argvp);
- argv_replace_one(argvp, -1, "new");
- return (argvp);
-}
-
-/* test_argv_bad_replace2 - populate and replace at bad position */
-
-static ARGV *test_argv_bad_replace2(const TEST_CASE *tp, ARGV *argvp)
-{
- test_argv_populate(tp, argvp);
- argv_replace_one(argvp, 100, "new");
- return (argvp);
-}
-
-/* test_argv_bad_delete1 - populate and delete at bad position */
-
-static ARGV *test_argv_bad_delete1(const TEST_CASE *tp, ARGV *argvp)
-{
- test_argv_populate(tp, argvp);
- argv_delete(argvp, -1, 1);
- return (argvp);
-}
-
-/* test_argv_bad_delete2 - populate and delete at bad position */
-
-static ARGV *test_argv_bad_delete2(const TEST_CASE *tp, ARGV *argvp)
-{
- test_argv_populate(tp, argvp);
- argv_delete(argvp, 0, -1);
- return (argvp);
-}
-
-/* test_argv_bad_delete3 - populate and delete at bad position */
-
-static ARGV *test_argv_bad_delete3(const TEST_CASE *tp, ARGV *argvp)
-{
- test_argv_populate(tp, argvp);
- argv_delete(argvp, 100, 1);
- return (argvp);
-}
-
-/* test_argv_verify - verify result */
-
-static int test_argv_verify(const TEST_CASE *tp, ARGV *argvp)
-{
- int idx;
-
- if (tp->exp_panic_msg != 0) {
- if (test_panic_str == 0) {
- msg_warn("test case '%s': got no panic, want: '%s'",
- tp->label, tp->exp_panic_msg);
- return (FAIL);
- }
- if (strcmp(vstring_str(test_panic_str), tp->exp_panic_msg) != 0) {
- msg_warn("test case '%s': got '%s', want: '%s'",
- tp->label, vstring_str(test_panic_str), tp->exp_panic_msg);
- return (FAIL);
- }
- return (PASS);
- }
- if (test_panic_str != 0) {
- msg_warn("test case '%s': got '%s', want: no panic",
- tp->label, vstring_str(test_panic_str));
- return (FAIL);
- }
- if (argvp->argc != tp->exp_argc) {
- msg_warn("test case '%s': got argc: %ld, want: %d",
- tp->label, (long) argvp->argc, tp->exp_argc);
- return (FAIL);
- }
- if (argvp->argv[argvp->argc] != 0 && tp->terminate) {
- msg_warn("test case '%s': got unterminated, want: terminated", tp->label);
- return (FAIL);
- }
- for (idx = 0; idx < argvp->argc; idx++) {
- if (strcmp(argvp->argv[idx], tp->exp_argv[idx]) != 0) {
- msg_warn("test case '%s': index %d: got '%s', want: '%s'",
- tp->label, idx, argvp->argv[idx], tp->exp_argv[idx]);
- return (FAIL);
- }
- }
- return (PASS);
-}
-
- /*
- * The test cases. TODO: argv_addn with good and bad string length.
- */
-static const TEST_CASE test_cases[] = {
- {"multiple strings, unterminated array",
- {"foo", "baz", "bar", 0}, 0, test_argv_populate,
- 0, 3, {"foo", "baz", "bar", 0}
- },
- {"multiple strings, terminated array",
- {"foo", "baz", "bar", 0}, TERMINATE_ARRAY, test_argv_populate,
- 0, 3, {"foo", "baz", "bar", 0}
- },
- {"distinct strings, sorted array",
- {"foo", "baz", "bar", 0}, 0, test_argv_sort,
- 0, 3, {"bar", "baz", "foo", 0}
- },
- {"duplicate strings, sorted array",
- {"foo", "baz", "baz", "bar", 0}, 0, test_argv_sort,
- 0, 4, {"bar", "baz", "baz", "foo", 0}
- },
- {"duplicate strings, sorted, uniqued-middle elements",
- {"foo", "baz", "baz", "bar", 0}, 0, test_argv_sort_uniq,
- 0, 3, {"bar", "baz", "foo", 0}
- },
- {"duplicate strings, sorted, uniqued-first elements",
- {"foo", "bar", "baz", "bar", 0}, 0, test_argv_sort_uniq,
- 0, 3, {"bar", "baz", "foo", 0}
- },
- {"duplicate strings, sorted, uniqued-last elements",
- {"foo", "foo", "baz", "bar", 0}, 0, test_argv_sort_uniq,
- 0, 3, {"bar", "baz", "foo", 0}
- },
- {"multiple strings, truncate array by one",
- {"foo", "baz", "bar", 0}, 0, test_argv_good_truncate,
- 0, 2, {"foo", "baz", 0}
- },
- {"multiple strings, truncate whole array",
- {"foo", "baz", "bar", 0}, 0, test_argv_good_truncate,
- 0, 0, {"foo", "baz", 0}
- },
- {"multiple strings, bad truncate",
- {"foo", "baz", "bar", 0}, 0, test_argv_bad_truncate,
- "argv_truncate: bad length -1"
- },
- {"multiple strings, insert one at good position",
- {"foo", "baz", "bar", 0}, 0, test_argv_good_insert,
- 0, 4, {"foo", "new", "baz", "bar", 0}
- },
- {"multiple strings, insert one at bad position",
- {"foo", "baz", "bar", 0}, 0, test_argv_bad_insert1,
- "argv_insert_one bad position: -1"
- },
- {"multiple strings, insert one at bad position",
- {"foo", "baz", "bar", 0}, 0, test_argv_bad_insert2,
- "argv_insert_one bad position: 100"
- },
- {"multiple strings, replace one at good position",
- {"foo", "baz", "bar", 0}, 0, test_argv_good_replace,
- 0, 3, {"foo", "new", "bar", 0}
- },
- {"multiple strings, replace one at bad position",
- {"foo", "baz", "bar", 0}, 0, test_argv_bad_replace1,
- "argv_replace_one bad position: -1"
- },
- {"multiple strings, replace one at bad position",
- {"foo", "baz", "bar", 0}, 0, test_argv_bad_replace2,
- "argv_replace_one bad position: 100"
- },
- {"multiple strings, delete one at negative position",
- {"foo", "baz", "bar", 0}, 0, test_argv_bad_delete1,
- "argv_delete bad range: (start=-1 count=1)"
- },
- {"multiple strings, delete with bad range end",
- {"foo", "baz", "bar", 0}, 0, test_argv_bad_delete2,
- "argv_delete bad range: (start=0 count=-1)"
- },
- {"multiple strings, delete at too large position",
- {"foo", "baz", "bar", 0}, 0, test_argv_bad_delete3,
- "argv_delete bad range: (start=100 count=1)"
- },
- 0,
-};
-
-int main(int argc, char **argv)
-{
- const TEST_CASE *tp;
- int pass = 0;
- int fail = 0;
-
- msg_vstream_init(sane_basename((VSTRING *) 0, argv[0]), VSTREAM_ERR);
-
- for (tp = test_cases; tp->label != 0; tp++) {
- int test_failed;
- ARGV *argvp;
-
- argvp = argv_alloc(1);
- if (setjmp(test_panic_jbuf) == 0)
- tp->populate_fn(tp, argvp);
- test_failed = test_argv_verify(tp, argvp);
- if (test_failed) {
- msg_info("%s: FAIL", tp->label);
- fail++;
- } else {
- msg_info("%s: PASS", tp->label);
- pass++;
- }
- argv_free(argvp);
- if (test_panic_str) {
- vstring_free(test_panic_str);
- test_panic_str = 0;
- }
- }
- msg_info("PASS=%d FAIL=%d", pass, fail);
- exit(fail != 0);
-}
-
-#endif
--- /dev/null
+ /*
+ * Test program to exercise argv.c. See ptest_main.h for a documented
+ * example.
+ */
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <string.h>
+
+ /*
+ * Utility library.
+ */
+#include <argv.h>
+
+ /*
+ * Test library.
+ */
+#include <ptest.h>
+
+#define ARRAY_LEN (10)
+
+ /*
+ * All test data can fit in the same PTEST_CASE structure.
+ */
+typedef struct PTEST_CASE {
+ const char *testname; /* identifies test case */
+ void (*action) (PTEST_CTX *t, const struct PTEST_CASE *tp);
+ const char *inputs[ARRAY_LEN]; /* input strings */
+ int flags; /* see below */
+ const char *want_panic_msg; /* expected panic */
+ ssize_t want_argc; /* expected array length */
+ const char *want_argv[ARRAY_LEN]; /* expected array content */
+} PTEST_CASE;
+
+#define ARGV_TEST_FLAG_TERMINATE (1<<0)
+
+/* verify_argv - verify result */
+
+static void verify_argv(PTEST_CTX *t, const PTEST_CASE *tp, ARGV *argvp)
+{
+ int idx;
+
+ /*
+ * We don't use eq_argv() here. We must at least once compare argv.c
+ * output against data that was created without using any argv.c code.
+ */
+ if (argvp->argc != tp->want_argc)
+ ptest_fatal(t, "got argc %ld, want %ld",
+ (long) argvp->argc, (long) tp->want_argc);
+ if (argvp->argv[argvp->argc] != 0 && (tp->flags & ARGV_TEST_FLAG_TERMINATE))
+ ptest_error(t, "got unterminated, want terminated");
+ for (idx = 0; idx < argvp->argc; idx++) {
+ if (strcmp(argvp->argv[idx], tp->want_argv[idx]) != 0) {
+ ptest_error(t, "index %d: got '%s', want '%s'",
+ idx, argvp->argv[idx], tp->want_argv[idx]);
+ }
+ }
+}
+
+/* wrap_argv_free - in case (void *) != (struct *) */
+
+static void wrap_argv_free(void *context)
+{
+ argv_free((ARGV *) context);
+}
+
+/* populate_argv - populate result, optionally terminate */
+
+static ARGV *populate_argv(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ ARGV *argvp = argv_alloc(1);
+ const char *const * cpp;
+
+ /*
+ * Some tests use longjmp instead of returning normally, so we use
+ * deferred execution to clean up allocated memory.
+ */
+ ptest_defer(t, wrap_argv_free, (void *) argvp);
+ if (tp->want_panic_msg != 0)
+ expect_ptest_log_event(t, tp->want_panic_msg);
+ for (cpp = tp->inputs; *cpp; cpp++)
+ argv_add(argvp, *cpp, (char *) 0);
+ if (tp->flags & ARGV_TEST_FLAG_TERMINATE)
+ argv_terminate(argvp);
+ return (argvp);
+}
+
+/* test_argv_basic - populate and verify */
+
+static void test_argv_basic(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ ARGV *argvp = populate_argv(t, tp);
+
+ verify_argv(t, tp, argvp);
+}
+
+/* test_argv_sort - populate and sort result */
+
+static void test_argv_sort(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ ARGV *argvp = populate_argv(t, tp);
+
+ argv_qsort(argvp, (ARGV_COMPAR_FN) 0);
+ verify_argv(t, tp, argvp);
+}
+
+/* test_argv_sort_uniq - populate, sort, uniq result */
+
+static void test_argv_sort_uniq(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+
+ /*
+ * This also tests argv_delete().
+ */
+ ARGV *argvp = populate_argv(t, tp);
+
+ argv_qsort(argvp, (ARGV_COMPAR_FN) 0);
+ argv_uniq(argvp, (ARGV_COMPAR_FN) 0);
+ verify_argv(t, tp, argvp);
+}
+
+/* test_argv_good_truncate - populate and truncate to good size */
+
+static void test_argv_good_truncate(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ ARGV *argvp = populate_argv(t, tp);
+
+ argv_truncate(argvp, tp->want_argc);
+ verify_argv(t, tp, argvp);
+}
+
+/* test_argv_bad_truncate - populate and truncate to bad size */
+
+static void test_argv_bad_truncate(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ ARGV *argvp = populate_argv(t, tp);
+
+ argv_truncate(argvp, -1);
+ ptest_fatal(t, "argv_delete() returned");
+}
+
+/* test_argv_good_insert - populate and insert at good position */
+
+static void test_argv_good_insert(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ ARGV *argvp = populate_argv(t, tp);
+
+ argv_insert_one(argvp, 1, "new");
+ verify_argv(t, tp, argvp);
+}
+
+/* test_argv_bad_insert1 - populate and insert at bad position */
+
+static void test_argv_bad_insert1(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ ARGV *argvp = populate_argv(t, tp);
+
+ argv_insert_one(argvp, -1, "new");
+ ptest_fatal(t, "argv_delete() returned");
+}
+
+/* test_argv_bad_insert2 - populate and insert at bad position */
+
+static void test_argv_bad_insert2(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ ARGV *argvp = populate_argv(t, tp);
+
+ argv_insert_one(argvp, 100, "new");
+ ptest_fatal(t, "argv_delete() returned");
+}
+
+/* test_argv_good_replace - populate and replace at good position */
+
+static void test_argv_good_replace(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ ARGV *argvp = populate_argv(t, tp);
+
+ argv_replace_one(argvp, 1, "new");
+ verify_argv(t, tp, argvp);
+}
+
+/* test_argv_bad_replace1 - populate and replace at bad position */
+
+static void test_argv_bad_replace1(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ ARGV *argvp = populate_argv(t, tp);
+
+ argv_replace_one(argvp, -1, "new");
+ ptest_fatal(t, "argv_delete() returned");
+}
+
+/* test_argv_bad_replace2 - populate and replace at bad position */
+
+static void test_argv_bad_replace2(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ ARGV *argvp = populate_argv(t, tp);
+
+ argv_replace_one(argvp, 100, "new");
+ ptest_fatal(t, "argv_delete() returned");
+}
+
+/* test_argv_bad_delete1 - populate and delete at bad position */
+
+static void test_argv_bad_delete1(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ ARGV *argvp = populate_argv(t, tp);
+
+ argv_delete(argvp, -1, 1);
+ ptest_fatal(t, "argv_delete() returned");
+}
+
+/* test_argv_bad_delete2 - populate and delete at bad position */
+
+static void test_argv_bad_delete2(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ ARGV *argvp = populate_argv(t, tp);
+
+ argv_delete(argvp, 0, -1);
+ ptest_fatal(t, "argv_delete() returned");
+}
+
+/* test_argv_bad_delete3 - populate and delete at bad position */
+
+static void test_argv_bad_delete3(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ ARGV *argvp = populate_argv(t, tp);
+
+ argv_delete(argvp, 100, 1);
+ ptest_fatal(t, "argv_delete() returned");
+}
+
+ /*
+ * The test cases. TODO: argv_addn with good and bad string length.
+ */
+static const PTEST_CASE ptestcases[] = {
+ {"multiple strings, unterminated array", test_argv_basic,
+ {"foo", "baz", "bar", 0}, 0,
+ 0, 3, {"foo", "baz", "bar", 0}
+ },
+ {"multiple strings, terminated array", test_argv_basic,
+ {"foo", "baz", "bar", 0}, ARGV_TEST_FLAG_TERMINATE,
+ 0, 3, {"foo", "baz", "bar", 0}
+ },
+ {"distinct strings, sorted array", test_argv_sort,
+ {"foo", "baz", "bar", 0}, 0,
+ 0, 3, {"bar", "baz", "foo", 0}
+ },
+ {"duplicate strings, sorted array", test_argv_sort,
+ {"foo", "baz", "baz", "bar", 0}, 0,
+ 0, 4, {"bar", "baz", "baz", "foo", 0}
+ },
+ {"duplicate strings, sorted, uniqued-middle elements", test_argv_sort_uniq,
+ {"foo", "baz", "baz", "bar", 0}, 0,
+ 0, 3, {"bar", "baz", "foo", 0}
+ },
+ {"duplicate strings, sorted, uniqued-first elements", test_argv_sort_uniq,
+ {"foo", "bar", "baz", "bar", 0}, 0,
+ 0, 3, {"bar", "baz", "foo", 0}
+ },
+ {"duplicate strings, sorted, uniqued-last elements", test_argv_sort_uniq,
+ {"foo", "foo", "baz", "bar", 0}, 0,
+ 0, 3, {"bar", "baz", "foo", 0}
+ },
+ {"multiple strings, truncate array by one", test_argv_good_truncate,
+ {"foo", "baz", "bar", 0}, 0,
+ 0, 2, {"foo", "baz", 0}
+ },
+ {"multiple strings, truncate whole array", test_argv_good_truncate,
+ {"foo", "baz", "bar", 0}, 0,
+ 0, 0, {"foo", "baz", 0}
+ },
+ {"multiple strings, bad truncate", test_argv_bad_truncate,
+ {"foo", "baz", "bar", 0}, 0,
+ "argv_truncate: bad length -1"
+ },
+ {"multiple strings, insert one at good position", test_argv_good_insert,
+ {"foo", "baz", "bar", 0}, 0,
+ 0, 4, {"foo", "new", "baz", "bar", 0}
+ },
+ {"multiple strings, insert one at bad position", test_argv_bad_insert1,
+ {"foo", "baz", "bar", 0}, 0,
+ "argv_insert_one bad position: -1"
+ },
+ {"multiple strings, insert one at bad position", test_argv_bad_insert2,
+ {"foo", "baz", "bar", 0}, 0,
+ "argv_insert_one bad position: 100"
+ },
+ {"multiple strings, replace one at good position", test_argv_good_replace,
+ {"foo", "baz", "bar", 0}, 0,
+ 0, 3, {"foo", "new", "bar", 0}
+ },
+ {"multiple strings, replace one at bad position", test_argv_bad_replace1,
+ {"foo", "baz", "bar", 0}, 0,
+ "argv_replace_one bad position: -1"
+ },
+ {"multiple strings, replace one at bad position", test_argv_bad_replace2,
+ {"foo", "baz", "bar", 0}, 0,
+ "argv_replace_one bad position: 100"
+ },
+ {"multiple strings, delete one at negative position", test_argv_bad_delete1,
+ {"foo", "baz", "bar", 0}, 0,
+ "argv_delete bad range: (start=-1 count=1)"
+ },
+ {"multiple strings, delete with bad range end", test_argv_bad_delete2,
+ {"foo", "baz", "bar", 0}, 0,
+ "argv_delete bad range: (start=0 count=-1)"
+ },
+ {"multiple strings, delete at too large position", test_argv_bad_delete3,
+ {"foo", "baz", "bar", 0}, 0,
+ "argv_delete bad range: (start=100 count=1)"
+ },
+};
+
+#include <ptest_main.h>
/*
* Driver for interactive or scripted tests.
*/
-void dict_test(int, char **);
+void dict_cli(int, char **);
/*
* Behind-the-scenes support to continue execution with reduced
msg_fatal("usage: %s type:file read|write|create [flags...]", myname);
}
-void dict_test(int argc, char **argv)
+void dict_cli(int argc, char **argv)
{
VSTRING *keybuf = vstring_alloc(1);
VSTRING *inbuf = vstring_alloc(1);
*/
int main(int argc, char **argv)
{
- dict_test(argc, argv);
+ dict_cli(argc, argv);
return (0);
}
--- /dev/null
+ /*
+ * Test program to exercise dict_pipe.c. See ptest_main.h for a documented
+ * example.
+ */
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <string.h>
+
+ /*
+ * Utility library.
+ */
+#include <msg.h>
+#include <mymalloc.h>
+#include <stringops.h>
+#include <dict_pipe.h>
+
+ /*
+ * Test library.
+ */
+#include <ptest.h>
+
+ /*
+ * The following needs to be large enough to include a null terminator in
+ * every ptestcase.want field.
+ */
+#define MAX_PROBE 5
+
+struct probe {
+ const char *query;
+ const char *want_value;
+ int want_error;
+};
+
+typedef struct PTEST_CASE {
+ const char *testname;
+ void (*action) (PTEST_CTX *, const struct PTEST_CASE *);
+ const char *type_name;
+ const struct probe probes[MAX_PROBE];
+} PTEST_CASE;
+
+#define STR_OR_NULL(s) ((s) ? (s) : "null")
+
+static void test_dict_pipe(PTEST_CTX *t, const struct PTEST_CASE *tp)
+{
+ DICT *dict;
+ const struct probe *pp;
+ const char *got_value;
+ int got_error;
+
+ if ((dict = dict_open(tp->type_name, O_RDONLY, 0)) == 0)
+ ptest_fatal(t, "dict_open(\"%s\", O_RDONLY, 0) failed: %m",
+ tp->type_name);
+ for (pp = tp->probes; pp < tp->probes + MAX_PROBE && pp->query != 0; pp++) {
+ got_value = dict_get(dict, pp->query);
+ got_error = dict->error;
+ if (got_value == 0 && pp->want_value == 0)
+ continue;
+ if (got_value == 0 || pp->want_value == 0) {
+ ptest_error(t, "dict_get(dict, \"%s\"): got '%s', want '%s'",
+ pp->query, STR_OR_NULL(got_value),
+ STR_OR_NULL(pp->want_value));
+ break;
+ }
+ if (strcmp(got_value, pp->want_value) != 0) {
+ ptest_error(t, "dict_get(dict, \"%s\"): got '%s', want '%s'",
+ pp->query, got_value, pp->want_value);
+ }
+ if (got_error != pp->want_error)
+ ptest_error(t, "dict_get(dict,\"%s\") error: got %d, want %d",
+ pp->query, got_error, pp->want_error);
+ }
+ dict_free(dict);
+}
+
+static const PTEST_CASE ptestcases[] = {
+ {
+ /* name */ "successful lookup: inline map + inline map",
+ /* action */ test_dict_pipe,
+ /* type_name */ "pipemap:{inline:{k1=v1,k2=v2},inline:{v2=v3}}",
+ /* probes */ {
+ {"k0", 0},
+ {"k1", 0,},
+ {"k2", "v3"},
+ },
+ }, {
+ /* name */ "error propagation: inline map + fail map",
+ /* action */ test_dict_pipe,
+ /* type_name */ "pipemap:{inline:{k1=v1},fail:fail}",
+ /* probes */ {
+ {"k0", 0, 0},
+ {"k1", 0, DICT_STAT_ERROR},
+ },
+ }, {
+ /* name */ "error propagation: fail map + inline map",
+ /* action */ test_dict_pipe,
+ /* type_name */ "pipemap:{fail:fail,inline:{k1=v1}}",
+ /* probes */ {
+ {"k1", 0, DICT_STAT_ERROR},
+ },
+ },
+};
+
+#include <ptest_main.h>
+++ /dev/null
-${VALGRIND} ./dict_open 'pipemap:{inline:{k1=v1,k2=v2},inline:{v2=v3}}' read <<EOF
-get k0
-get k1
-get k2
-EOF
-${VALGRIND} ./dict_open 'pipemap:{inline:{k1=v1},fail:fail}' read <<EOF
-get k0
-get k1
-EOF
+++ /dev/null
-+ ./dict_open pipemap:{inline:{k1=v1,k2=v2},inline:{v2=v3}} read
-owner=trusted (uid=2147483647)
-> get k0
-k0: not found
-> get k1
-k1: not found
-> get k2
-k2=v3
-+ ./dict_open pipemap:{inline:{k1=v1},fail:fail} read
-owner=trusted (uid=2147483647)
-> get k0
-k0: not found
-> get k1
-k1: error
return (map_fp);
}
}
-
-#ifdef TEST
-
-#include <string.h>
-
-int main(int argc, char **argv)
-{
- struct testcase {
- const char *title;
- const char *mapname; /* starts with brace */
- const char *expect_err; /* null or message */
- const char *expect_cont; /* null or content */
- };
-
-#define EXP_NOERR 0
-#define EXP_NOCONT 0
-
-#define STRING_OR(s, text_if_null) ((s) ? (s) : (text_if_null))
-#define DICT_TYPE_TEST "test"
-
- const char rule_spec_error[] = DICT_TYPE_TEST " map: "
- "syntax error after '}' in \"{blah blah}x\"";
- const char inline_config_error[] = DICT_TYPE_TEST " map: "
- "syntax error after '}' in \"{{foo bar}, {blah blah}}x\"";
- struct testcase testcases[] = {
- {"normal",
- "{{foo bar}, {blah blah}}", EXP_NOERR, "foo bar\nblah blah\n"
- },
- {"trims leading/trailing wsp around rule-text",
- "{{ foo bar }, { blah blah }}", EXP_NOERR, "foo bar\nblah blah\n"
- },
- {"trims leading/trailing comma-wsp around rule-spec",
- "{, ,{foo bar}, {blah blah}, ,}", EXP_NOERR, "foo bar\nblah blah\n"
- },
- {"empty inline-file",
- "{, }", EXP_NOERR, ""
- },
- {"propagates extpar error for inline-file",
- "{{foo bar}, {blah blah}}x", inline_config_error, EXP_NOCONT
- },
- {"propagates extpar error for rule-spec",
- "{{foo bar}, {blah blah}x}", rule_spec_error, EXP_NOCONT
- },
- 0,
- };
- struct testcase *tp;
- VSTRING *act_err = 0;
- VSTRING *act_cont = vstring_alloc(100);
- VSTREAM *fp;
- struct stat st;
- ssize_t exp_len;
- ssize_t act_len;
- int pass;
- int fail;
-
- for (pass = fail = 0, tp = testcases; tp->title; tp++) {
- int test_passed = 0;
-
- msg_info("RUN test case %ld %s", (long) (tp - testcases), tp->title);
-
-#if 0
- msg_info("title=%s", tp->title);
- msg_info("mapname=%s", tp->mapname);
- msg_info("expect_err=%s", STRING_OR_NULL(tp->expect_err));
- msg_info("expect_cont=%s", STRINGOR_NULL(tp->expect_cont));
-#endif
-
- if (act_err)
- VSTRING_RESET(act_err);
- fp = dict_stream_open(DICT_TYPE_TEST, tp->mapname, O_RDONLY,
- 0, &st, &act_err);
- if (fp) {
- if (tp->expect_err) {
- msg_warn("test case %s: got stream, expected error", tp->title);
- } else if (!tp->expect_err && act_err && LEN(act_err) > 0) {
- msg_warn("test case %s: got error '%s', expected noerror",
- tp->title, STR(act_err));
- } else if (!tp->expect_cont) {
- msg_warn("test case %s: got stream, expected nostream",
- tp->title);
- } else {
- exp_len = strlen(tp->expect_cont);
- if ((act_len = vstream_fread_buf(fp, act_cont, 2 * exp_len)) < 0) {
- msg_warn("test case %s: content read error", tp->title);
- } else {
- VSTRING_TERMINATE(act_cont);
- if (strcmp(tp->expect_cont, STR(act_cont)) != 0) {
- msg_warn("test case %s: got content '%s', expected '%s'",
- tp->title, STR(act_cont), tp->expect_cont);
- } else {
- test_passed = 1;
- }
- }
- }
- } else {
- if (!tp->expect_err) {
- msg_warn("test case %s: got nostream, expected noerror",
- tp->title);
- } else if (tp->expect_cont) {
- msg_warn("test case %s: got nostream, expected stream",
- tp->title);
- } else if (strcmp(STR(act_err), tp->expect_err) != 0) {
- msg_warn("test case %s: got error '%s', expected '%s'",
- tp->title, STR(act_err), tp->expect_err);
- } else {
- test_passed = 1;
- }
-
- }
- if (test_passed) {
- msg_info("PASS test %ld", (long) (tp - testcases));
- pass++;
- } else {
- msg_info("FAIL test %ld", (long) (tp - testcases));
- fail++;
- }
- if (fp)
- vstream_fclose(fp);
- }
- if (act_err)
- vstring_free(act_err);
- vstring_free(act_cont);
- msg_info("PASS=%d FAIL=%d", pass, fail);
- return (fail > 0);
-}
-
-#endif /* TEST */
+++ /dev/null
-unknown: RUN test case 0 normal
-unknown: PASS test 0
-unknown: RUN test case 1 trims leading/trailing wsp around rule-text
-unknown: PASS test 1
-unknown: RUN test case 2 trims leading/trailing comma-wsp around rule-spec
-unknown: PASS test 2
-unknown: RUN test case 3 empty inline-file
-unknown: PASS test 3
-unknown: RUN test case 4 propagates extpar error for inline-file
-unknown: PASS test 4
-unknown: RUN test case 5 propagates extpar error for rule-spec
-unknown: PASS test 5
-unknown: PASS=6 FAIL=0
--- /dev/null
+ /*
+ * Test program to exercise dict_stream.c. See ptest_main.h for a documented
+ * example.
+ */
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <string.h>
+
+ /*
+ * Utility library.
+ */
+#include <vstream.h>
+#include <vstring.h>
+#include <dict.h>
+
+ /*
+ * Test library.
+ */
+#include <ptest.h>
+
+typedef struct PTEST_CASE {
+ const char *testname;
+ void (*action) (PTEST_CTX *t, const struct PTEST_CASE *);
+ const char *mapname; /* starts with brace */
+ const char *want_err; /* null or message */
+ const char *want_cont; /* null or content */
+} PTEST_CASE;
+
+#define DICT_TYPE_TEST "test"
+#define LEN(x) VSTRING_LEN(x)
+#define STR(x) vstring_str(x)
+
+static void test_dict_stream(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ VSTRING *got_err = 0;
+ VSTRING *got_cont = vstring_alloc(100);
+ VSTREAM *fp;
+ struct stat st;
+ ssize_t want_len;
+ ssize_t got_len;
+
+ fp = dict_stream_open(DICT_TYPE_TEST, tp->mapname, O_RDONLY,
+ 0, &st, &got_err);
+ if (fp) {
+ if (tp->want_err) {
+ ptest_error(t, "got stream, want error '%s'", tp->want_err);
+ } else if (!tp->want_err && got_err && LEN(got_err) > 0) {
+ ptest_error(t, "got error '%s', want noerror", STR(got_err));
+ } else if (!tp->want_cont) {
+ ptest_error(t, "got stream, expected nostream");
+ } else {
+ want_len = strlen(tp->want_cont);
+ if ((got_len = vstream_fread_buf(fp, got_cont, 2 * want_len)) < 0) {
+ ptest_error(t, "content read error");
+ } else {
+ VSTRING_TERMINATE(got_cont);
+ if (strcmp(tp->want_cont, STR(got_cont)) != 0) {
+ ptest_error(t, "got content '%s', want '%s'",
+ STR(got_cont), tp->want_cont);
+ }
+ }
+ }
+ } else {
+ if (!tp->want_err) {
+ ptest_error(t, "got nostream, want noerror");
+ } else if (tp->want_cont) {
+ ptest_error(t, "got nostream, want stream");
+ } else if (strcmp(STR(got_err), tp->want_err) != 0) {
+ ptest_error(t, "got error '%s', want '%s'",
+ STR(got_err), tp->want_err);
+ }
+ }
+ if (fp)
+ vstream_fclose(fp);
+ if (got_err)
+ vstring_free(got_err);
+ vstring_free(got_cont);
+}
+
+
+#define WANT_NOERR 0
+#define WANT_NOCONT 0
+
+const char rule_spec_error[] = DICT_TYPE_TEST " map: "
+"syntax error after '}' in \"{blah blah}x\"";
+
+const char inline_config_error[] = DICT_TYPE_TEST " map: "
+"syntax error after '}' in \"{{foo bar}, {blah blah}}x\"";
+
+static PTEST_CASE ptestcases[] = {
+ {"normal", test_dict_stream,
+ "{{foo bar}, {blah blah}}", WANT_NOERR, "foo bar\nblah blah\n"
+ },
+ {"trims leading/trailing wsp around rule-text", test_dict_stream,
+ "{{ foo bar }, { blah blah }}", WANT_NOERR, "foo bar\nblah blah\n"
+ },
+ {"trims leading/trailing comma-wsp around rule-spec", test_dict_stream,
+ "{, ,{foo bar}, {blah blah}, ,}", WANT_NOERR, "foo bar\nblah blah\n"
+ },
+ {"empty inline-file", test_dict_stream,
+ "{, }", WANT_NOERR, ""
+ },
+ {"propagates extpar error for inline-file", test_dict_stream,
+ "{{foo bar}, {blah blah}}x", inline_config_error, WANT_NOCONT
+ },
+ {"propagates extpar error for rule-spec", test_dict_stream,
+ "{{foo bar}, {blah blah}x}", rule_spec_error, WANT_NOCONT
+ },
+};
+
+#include <ptest_main.h>
--- /dev/null
+ /*
+ * Test program to exercise dict_union.c. See ptest_main.h for a documented
+ * example.
+ */
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <string.h>
+
+ /*
+ * Utility library.
+ */
+#include <msg.h>
+#include <mymalloc.h>
+#include <stringops.h>
+#include <dict_union.h>
+
+ /*
+ * Test library.
+ */
+#include <ptest.h>
+
+ /*
+ * The following needs to be large enough to include a null terminator in
+ * every ptestcase.want field.
+ */
+#define MAX_PROBE 5
+
+struct probe {
+ const char *query;
+ const char *want_value;
+ int want_error;
+};
+
+typedef struct PTEST_CASE {
+ const char *testname;
+ void (*action) (PTEST_CTX *, const struct PTEST_CASE *);
+ const char *type_name;
+ const struct probe probes[MAX_PROBE];
+} PTEST_CASE;
+
+#define STR_OR_NULL(s) ((s) ? (s) : "null")
+
+static void test_dict_union(PTEST_CTX *t, const struct PTEST_CASE *tp)
+{
+ DICT *dict;
+ const struct probe *pp;
+ const char *got_value;
+ int got_error;
+
+ if ((dict = dict_open(tp->type_name, O_RDONLY, 0)) == 0)
+ ptest_fatal(t, "dict_open(\"%s\", O_RDONLY, 0) failed: %m",
+ tp->type_name);
+ for (pp = tp->probes; pp < tp->probes + MAX_PROBE && pp->query != 0; pp++) {
+ got_value = dict_get(dict, pp->query);
+ got_error = dict->error;
+ if (got_value == 0 && pp->want_value == 0)
+ continue;
+ if (got_value == 0 || pp->want_value == 0) {
+ ptest_error(t, "dict_get(dict, \"%s\"): got '%s', want '%s'",
+ pp->query, STR_OR_NULL(got_value),
+ STR_OR_NULL(pp->want_value));
+ break;
+ }
+ if (strcmp(got_value, pp->want_value) != 0) {
+ ptest_error(t, "dict_get(dict, \"%s\"): got '%s', want '%s'",
+ pp->query, got_value, pp->want_value);
+ }
+ if (got_error != pp->want_error)
+ ptest_error(t, "dict_get(dict,\"%s\") error: got %d, want %d",
+ pp->query, got_error, pp->want_error);
+ }
+ dict_free(dict);
+}
+
+static const PTEST_CASE ptestcases[] = {
+ {
+ /* name */ "successful lookup: static map + inline map",
+ /* action */ test_dict_union,
+ /* type_name */ "unionmap:{static:one,inline:{foo=two}}",
+ /* probes */ {
+ {"foo", "one,two"},
+ {"bar", "one"},
+ },
+ }, {
+ /* name */ "error propagation: static map + fail map",
+ /* action */ test_dict_union,
+ /* type_name */ "unionmap:{static:one,fail:fail}",
+ /* probes */ {
+ {"foo", 0, DICT_STAT_ERROR},
+ },
+ }, {
+ /* name */ "error propagation: fail map + static map",
+ /* action */ test_dict_union,
+ /* type_name */ "unionmap:{fail:fail,static:one}",
+ /* probes */ {
+ {"foo", 0, DICT_STAT_ERROR},
+ },
+ },
+};
+
+#include <ptest_main.h>
+++ /dev/null
-${VALGRIND} ./dict_open 'unionmap:{static:one,static:two,inline:{foo=three}}' read <<EOF
-get foo
-get bar
-EOF
-${VALGRIND} ./dict_open 'unionmap:{static:one,fail:fail}' read <<EOF
-get foo
-EOF
+++ /dev/null
-+ ./dict_open unionmap:{static:one,static:two,inline:{foo=three}} read
-owner=trusted (uid=2147483647)
-> get foo
-foo=one,two,three
-> get bar
-bar=one,two
-+ ./dict_open unionmap:{static:one,fail:fail} read
-owner=trusted (uid=2147483647)
-> get foo
-foo: error
--- /dev/null
+/*++
+/* NAME
+/* find_inet_service 3
+/* SUMMARY
+/* TCP service lookup
+/* SYNOPSIS
+/* #include <find_inet_service.h>
+/*
+/* int find_inet_service(service, proto)
+/* const char *service;
+/* const char *proto;
+/* DESCRIPTION
+/* find_inet_service() looks up the numerical TCP/IP port (in
+/* host byte order) for the specified service. If the service
+/* is in numerical form, then that is converted instead.
+/*
+/* TCP services are mapped with known_tcp_ports(3).
+/* DIAGNOSTICS
+/* find_inet_service() returns -1 when the service is not
+/* found, or when a numerical service is out of range.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+/* System libraries. */
+
+#include <sys_defs.h>
+#include <wrap_netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+/* Application-specific. */
+
+#include <find_inet_service.h>
+#include <known_tcp_ports.h>
+#include <msg.h>
+#include <sane_strtol.h>
+#include <stringops.h>
+
+/* find_inet_service - translate numerical or symbolic service name */
+
+int find_inet_service(const char *service, const char *protocol)
+{
+ struct servent *sp;
+ unsigned long lport;
+ char *cp;
+
+ if (strcmp(protocol, "tcp") == 0)
+ service = filter_known_tcp_port(service);
+ if (alldig(service)) {
+ lport = sane_strtoul(service, &cp, 10);
+ if (*cp != '\0' || errno == ERANGE || lport > 65535)
+ return (-1); /* bad numerical service */
+ return ((int) lport);
+ } else {
+ if ((sp = getservbyname(service, protocol)) == 0)
+ return (-1); /* bad symbolic service */
+ return (ntohs(sp->s_port));
+ }
+}
--- /dev/null
+#ifndef _FIND_TCP_PORT_H_INCLUDED_
+#define _FIND_TCP_PORT_H_INCLUDED_
+
+/*++
+/* NAME
+/* find_inet_service 3h
+/* SUMMARY
+/* TCP service lookup
+/* SYNOPSIS
+/* #include <find_inet_service.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * External interface.
+ */
+extern int find_inet_service(const char *, const char *);
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+#endif
--- /dev/null
+ /*
+ * Test program to exercise find_inet_service.c. See pmock_expect_test.c and
+ * ptest_main.h for a documented example.
+ */
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+
+ /*
+ * Utility library
+ */
+#include <find_inet_service.h>
+#include <known_tcp_ports.h>
+#include <msg.h>
+
+ /*
+ * Test library.
+ */
+#include <mock_servent.h>
+#include <ptest.h>
+
+struct association {
+ const char *lhs; /* service name */
+ const char *rhs; /* service port */
+};
+
+typedef struct PTEST_CASE {
+ const char *testname; /* Human-readable description */
+ void (*action) (PTEST_CTX *, const struct PTEST_CASE *);
+ struct association associations[10];
+ const char *service;
+ const char *proto;
+ int want_port; /* expected port, host byte order */
+ int needs_mock;
+} PTEST_CASE;
+
+static void test_find_inet_service(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ struct servent *want_ent = 0;
+ const struct association *ap;
+ int got_port;
+ const char *err;
+
+ /*
+ * Set up expectations. Note that the test infrastructure will catch
+ * fatal errors and panics for us.
+ */
+ clear_known_tcp_ports();
+ for (err = 0, ap = tp->associations; err == 0 && ap->lhs != 0; ap++)
+ err = add_known_tcp_port(ap->lhs, ap->rhs);
+ if (err != 0)
+ ptest_fatal(t, "add_known_tcp_port: got err '%s'", err);
+ if (tp->needs_mock) {
+ if (tp->want_port != -1)
+ want_ent = make_servent(tp->service, tp->want_port, tp->proto);
+ else
+ want_ent = 0;
+ expect_getservbyname(1, want_ent, tp->service, tp->proto);
+ }
+
+ /*
+ * Make the call and verify the result. If the call fails with a fatal
+ * error or panic, the test infrastructure will verify that the logging
+ * is as expected.
+ */
+ got_port = find_inet_service(tp->service, tp->proto);
+ if (got_port != tp->want_port) {
+ ptest_error(t, "find_inet_service: got port %d, want %d",
+ got_port, tp->want_port);
+ }
+ if (want_ent)
+ free_servent(want_ent);
+}
+
+const PTEST_CASE ptestcases[] = {
+ {
+ "good-symbolic",
+ test_find_inet_service,
+ /* association */ {{"foobar", "25252"}, 0},
+ /* service */ "foobar",
+ /* proto */ "tcp",
+ /* want_port */ 25252,
+ /* needs mock */ 0,
+ },
+ {
+ "good-numeric",
+ test_find_inet_service,
+ /* association */ {{"foobar", "25252"}, 0},
+ /* service */ "25252",
+ /* proto */ "tcp",
+ /* want_port */ 25252,
+ /* needs mock */ 0,
+ },
+ {
+ "bad-symbolic",
+ test_find_inet_service,
+ /* association */ {{"foobar", "25252"}, 0},
+ /* service */ "an-impossible-name",
+ /* proto */ "tcp",
+ /* want_port */ -1,
+ /* needs mock */ 1,
+ },
+ {
+ "bad-numeric",
+ test_find_inet_service,
+ /* association */ {{"foobar", "25252"}, 0},
+ /* service */ "123456",
+ /* proto */ "tcp",
+ /* want_port */ -1,
+ /* needs mock */ 0,
+ },
+};
+
+ /*
+ * Test library.
+ */
+#include <ptest_main.h>
}
return (hash);
}
-
-#ifdef TEST
-#include <stdlib.h>
-#include <string.h>
-#include <msg.h>
-
-int main(void)
-{
- int pass = 0;
- int fail = 0;
-
- /*
- * Sanity check.
- */
-#ifdef STRICT_FNV1A
- msg_fatal("This test requires no STRICT_FNV1A");
-#endif
-
- /*
- * Force unseeded hash, to make tests predictable.
- */
- if (putenv("NORANDOMIZE=") != 0)
- msg_fatal("putenv(\"NORANDOMIZE=\"): %m");
-
- /*
- * Test: hashing produces the expected results.
- */
- {
- struct testcase {
- HASH_FNV_T hval;
- const char *str;
- };
- static struct testcase testcases[] =
- {
-#ifdef USE_FNV_32BIT
- 0x1c00fc06UL, "overdeeply",
- 0x1c00fc06UL, "undescript",
- 0x1e1e52a4UL, "fanfold",
- 0x1e1e52a4UL, "phrensied",
-#else
- 0xda19999ec0bda706ULL, "overdeeply",
- 0xd7b9e43f26396a66ULL, "undescript",
- 0xa50c585d385a2604ULL, "fanfold",
- 0x1ec3ef9bb2b734a4ULL, "phrensied",
-#endif
- 0,
- };
- struct testcase *tp;
- HASH_FNV_T hval;
- int test_failed;
-
- for (tp = testcases; tp->str; tp++) {
- test_failed = 0;
- if ((hval = hash_fnvz(tp->str)) != tp->hval) {
- msg_warn("hash_fnv(\"%s\") want %lu, got: %lu",
- tp->str, (unsigned long) tp->hval,
- (unsigned long) hval);
- test_failed = 1;
- }
- if (test_failed) {
- fail += 1;
- msg_info("FAIL: %s", tp->str);
- } else {
- pass += 1;
- msg_info("PASS: %s", tp->str);
- }
- }
- }
-
- /*
- * Test: hash_fnvz(s) is equivalent to hash_fnv(s, strlen(s)). No need to
- * verify the actual result; we already did that above.
- */
- {
- const char *strval = "foobar";
- HASH_FNV_T h1 = hash_fnv(strval, strlen(strval));
- HASH_FNV_T h2 = hash_fnvz(strval);
-
- if (h1 == h2) {
- pass += 1;
- msg_info("PASS: hash_fnvz(\"%s\") == hash_fnv(\"%s\", %ld)",
- strval, strval, (long) strlen(strval));
- } else {
- fail += 1;
- msg_info("FAIL: hash_fnvz(\"%s\") == hash_fnv(\"%s\", %ld)",
- strval, strval, (long) strlen(strval));
- }
- }
-
-
- /*
- * Wrap up.
- */
- msg_info("PASS=%d FAIL=%d", pass, fail);
- return (fail != 0);
-}
-
-#endif
--- /dev/null
+ /*
+ * Test program to exercise the hash_fnv implementation. See comments in
+ * ptest_main.h for a documented example.
+ */
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <stdlib.h>
+#include <string.h>
+
+ /*
+ * Utility library.
+ */
+#include <msg.h>
+#include <hash_fnv.h>
+
+ /*
+ * Test library.
+ */
+#include <ptest.h>
+
+typedef struct PTEST_CASE {
+ const char *testname;
+ void (*action) (PTEST_CTX *t, const struct PTEST_CASE *tp);
+ HASH_FNV_T want_hval;
+ const char *str;
+} PTEST_CASE;
+
+static void setup_test(void)
+{
+
+ /*
+ * Sanity check.
+ */
+#ifdef STRICT_FNV1A
+ msg_fatal("This test requires no STRICT_FNV1A");
+#endif
+
+ /*
+ * Force unseeded hash, to make tests predictable.
+ */
+ if (putenv("NORANDOMIZE=") != 0)
+ msg_fatal("putenv(\"NORANDOMIZE=\"): %m");
+}
+
+static void test_known_input(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ HASH_FNV_T got_hval;
+
+ setup_test();
+
+ if ((got_hval = hash_fnvz(tp->str)) != tp->want_hval)
+ ptest_error(t, "hash_fnvz(\"%s\") got %lu, want %lu",
+ tp->str, (unsigned long) got_hval,
+ (unsigned long) tp->want_hval);
+
+ if ((got_hval = hash_fnv(tp->str, strlen(tp->str))) != tp->want_hval)
+ ptest_error(t, "hash_fnv(\"%s\", strlen(\"%s\")) got %lu, want %lu",
+ tp->str, tp->str, (unsigned long) got_hval,
+ (unsigned long) tp->want_hval);
+}
+
+
+static const PTEST_CASE ptestcases[] =
+{
+#ifdef USE_FNV_32BIT
+ "test_known_input_overdeeply", test_known_input, 0x1c00fc06UL, "overdeeply",
+ "test_known_input_undescript", test_known_input, 0x1c00fc06UL, "undescript",
+ "test_known_input_fanfold", test_known_input, 0x1e1e52a4UL, "fanfold",
+ "test_known_input_phrensied", test_known_input, 0x1e1e52a4UL, "phrensied",
+#else
+ "test_known_input_overdeeply", test_known_input, 0xda19999ec0bda706ULL, "overdeeply",
+ "test_known_input_undescript", test_known_input, 0xd7b9e43f26396a66ULL, "undescript",
+ "test_known_input_fanfold", test_known_input, 0xa50c585d385a2604ULL, "fanfold",
+ "test_known_input_phrensied", test_known_input, 0x1ec3ef9bb2b734a4ULL, "phrensied",
+#endif
+};
+
+#include <ptest_main.h>
int main(int argc, char **argv)
{
INET_ADDR_LIST list;
- INET_PROTO_INFO *proto_info;
- proto_info = inet_proto_init(argv[0], INET_PROTO_NAME_ALL);
+ (void) inet_proto_init(argv[0], INET_PROTO_NAME_ALL);
inet_addr_list_init(&list);
while (--argc && *++argv)
if (inet_addr_host(&list, *argv) == 0)
return ("numerical service name");
if (!alldig(port))
return ("non-numerical service port");
+ if (strlen(port) > 5 || (strlen(port) == 5 && strcmp(port, "65535") > 0))
+ return ("port number out of range");
if (known_tcp_ports == 0)
known_tcp_ports = htable_create(10);
if (htable_locate(known_tcp_ports, name) != 0)
VSTRING_TERMINATE(out);
return (STR(out));
}
-
-#ifdef TEST
-
-#include <msg.h>
-
-struct association {
- const char *lhs; /* service name */
- const char *rhs; /* service port */
-};
-
-struct probe {
- const char *query; /* query */
- const char *exp_reply; /* expected reply */
-};
-
-struct test_case {
- const char *label; /* identifies test case */
- struct association associations[10];
- const char *exp_err; /* expected error */
- const char *exp_export; /* expected export output */
- struct probe probes[10];
-};
-
-struct test_case test_cases[] = {
- {"good",
- /* association */ {{"smtp", "25"}, {"lmtp", "24"}, 0},
- /* error */ 0,
- /* export */ "lmtp=24 smtp=25",
- /* probe */ {{"smtp", "25"}, {"1", "1"}, {"x", "x"}, {"lmtp", "24"}, 0}
- },
- {"duplicate lhs",
- /* association */ {{"smtp", "25"}, {"smtp", "100"}, 0},
- /* error */ "duplicate service name"
- },
- {"numerical lhs",
- /* association */ {{"100", "100"}, 0},
- /* error */ "numerical service name"
- },
- {"symbolic rhs",
- /* association */ {{"smtp", "lmtp"}, 0},
- /* error */ "non-numerical service port"
- },
- {"uninitialized",
- /* association */ {0},
- /* error */ 0,
- /* export */ "",
- /* probe */ {{"smtp", "smtp"}, {"1", "1"}, {"x", "x"}, 0}
- },
- 0,
-};
-
-int main(int argc, char **argv)
-{
- VSTRING *export_buf;
- struct test_case *tp;
- struct association *ap;
- struct probe *pp;
- int pass = 0;
- int fail = 0;
- const char *err;
- int test_failed;
- const char *reply;
- const char *export;
-
-#define STRING_OR_NULL(s) ((s) ? (s) : "(null)")
-
- export_buf = vstring_alloc(100);
- for (tp = test_cases; tp->label != 0; tp++) {
- test_failed = 0;
- for (err = 0, ap = tp->associations; err == 0 && ap->lhs != 0; ap++)
- err = add_known_tcp_port(ap->lhs, ap->rhs);
- if (!err != !tp->exp_err) {
- msg_warn("test case %s: got error: \"%s\", want: \"%s\"",
- tp->label, STRING_OR_NULL(err), STRING_OR_NULL(tp->exp_err));
- test_failed = 1;
- } else if (err != 0) {
- if (strcmp(err, tp->exp_err) != 0) {
- msg_warn("test case %s: got err: \"%s\", want: \"%s\"",
- tp->label, err, tp->exp_err);
- test_failed = 1;
- }
- } else {
- export = export_known_tcp_ports(export_buf);
- if (strcmp(export, tp->exp_export) != 0) {
- msg_warn("test case %s: got export: \"%s\", want: \"%s\"",
- tp->label, export, tp->exp_export);
- test_failed = 1;
- }
- for (pp = tp->probes; test_failed == 0 && pp->query != 0; pp++) {
- reply = filter_known_tcp_port(pp->query);
- if (strcmp(reply, pp->exp_reply) != 0) {
- msg_warn("test case %s: got reply: \"%s\", want: \"%s\"",
- tp->label, reply, pp->exp_reply);
- test_failed = 1;
- }
- }
- }
- clear_known_tcp_ports();
- if (test_failed) {
- msg_info("%s: FAIL", tp->label);
- fail++;
- } else {
- msg_info("%s: PASS", tp->label);
- pass++;
- }
- }
- msg_info("PASS=%d FAIL=%d", pass, fail);
- vstring_free(export_buf);
- exit(fail != 0);
-}
-
-#endif
+++ /dev/null
-unknown: good: PASS
-unknown: duplicate lhs: PASS
-unknown: numerical lhs: PASS
-unknown: symbolic rhs: PASS
-unknown: uninitialized: PASS
-unknown: PASS=5 FAIL=0
--- /dev/null
+ /*
+ * Test program to exercise known_tcp_ports.c. See ptest_main.h for a
+ * documented example.
+ */
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <string.h>
+
+ /*
+ * Utility library
+ */
+#include <known_tcp_ports.h>
+#include <msg.h>
+
+ /*
+ * Test library.
+ */
+#include <ptest.h>
+
+struct association {
+ const char *lhs; /* service name */
+ const char *rhs; /* service port */
+};
+
+struct probe {
+ const char *query; /* query */
+ const char *want_reply; /* expected reply */
+};
+
+typedef struct PTEST_CASE {
+ const char *testname; /* identifies test case */
+ void (*action) (PTEST_CTX *, const struct PTEST_CASE *);
+ struct association associations[10];
+ const char *want_err; /* expected error */
+ const char *want_export; /* expected export output */
+ struct probe probes[10];
+} PTEST_CASE;
+
+static void test_known_tcp_ports(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ VSTRING *export_buf;
+ const struct association *ap;
+ const struct probe *pp;
+ const char *got_err;
+ const char *got_reply;
+ const char *got_export;
+
+#define STRING_OR_NULL(s) ((s) ? (s) : "(null)")
+
+ export_buf = vstring_alloc(100);
+ for (got_err = 0, ap = tp->associations; got_err == 0 && ap->lhs != 0; ap++)
+ got_err = add_known_tcp_port(ap->lhs, ap->rhs);
+ if (!got_err != !tp->want_err) {
+ ptest_error(t, "got error '%s', want '%s'",
+ STRING_OR_NULL(got_err), STRING_OR_NULL(tp->want_err));
+ } else if (got_err != 0) {
+ if (strcmp(got_err, tp->want_err) != 0) {
+ ptest_error(t, "got err '%s', want '%s'", got_err, tp->want_err);
+ }
+ } else {
+ got_export = export_known_tcp_ports(export_buf);
+ if (strcmp(got_export, tp->want_export) != 0) {
+ ptest_error(t, "got export '%s', want '%s'",
+ got_export, tp->want_export);
+ }
+ for (pp = tp->probes; pp->query != 0; pp++) {
+ got_reply = filter_known_tcp_port(pp->query);
+ if (strcmp(got_reply, pp->want_reply) != 0) {
+ ptest_error(t, "got reply '%s', want '%s'",
+ got_reply, pp->want_reply);
+ break;
+ }
+ }
+ }
+ clear_known_tcp_ports();
+ vstring_free(export_buf);
+}
+
+const PTEST_CASE ptestcases[] = {
+ {"good", test_known_tcp_ports,
+ /* association */ {{"smtp", "25"}, {"lmtp", "24"}, 0},
+ /* error */ 0,
+ /* export */ "lmtp=24 smtp=25",
+ /* probe */ {{"smtp", "25"}, {"1", "1"}, {"x", "x"}, {"lmtp", "24"}, 0}
+ },
+ {"duplicate lhs", test_known_tcp_ports,
+ /* association */ {{"smtp", "25"}, {"smtp", "100"}, 0},
+ /* error */ "duplicate service name"
+ },
+ {"numerical lhs", test_known_tcp_ports,
+ /* association */ {{"100", "100"}, 0},
+ /* error */ "numerical service name"
+ },
+ {"symbolic rhs", test_known_tcp_ports,
+ /* association */ {{"smtp", "lmtp"}, 0},
+ /* error */ "non-numerical service port"
+ },
+ {"uninitialized", test_known_tcp_ports,
+ /* association */ {0},
+ /* error */ 0,
+ /* export */ "",
+ /* probe */ {{"smtp", "smtp"}, {"1", "1"}, {"x", "x"}, 0}
+ },
+ {"too large", test_known_tcp_ports,
+ /* association */ {{"one", "65535"}, {"two", "65536"}, 0},
+ /* error */ "port number out of range",
+ },
+};
+
+ /*
+ * Test library.
+ */
+#include <ptest_main.h>
/* int count;
/*
/* void msg_error_clear()
+/*
+/* int msg_setjmp(
+/* MSG_JMP_BUF *bufp)
+/*
+/* void msg_longjmp(
+/* int value)
+/*
+/* void msg_resetjmp(
+/* MSG_JMP_BUF *bufp)
+/*
+/* void msg_clearjmp(void)
/* DESCRIPTION
/* This module reports diagnostics. By default, diagnostics are sent
/* to the standard error stream, but the disposition can be changed
/* This protection exists under the condition that these
/* specific resources are accessed exclusively via the msg_info()
/* etc. functions.
+/* EXCEPTIONS AND NON-PRODUCTION TESTS
+/* The default action for msg_fatal*() and msg_panic is to
+/* terminate the program. In order to support non-production
+/* tests, the following macros implement support for long
+/* jumps.
+/*
+/* msg_setjmp() specifies a caller-specified buffer and saves
+/* state for a future long jump. The buffer lifetime must
+/* extend to the next msg_resetjmp() or msg_clearjmp() call.
+/*
+/* In-between the msg_setjmp() and msg_clearjmp() calls,
+/* msg_fatal*() and msg_panic() will perform a long jump instead
+/* of terminating the program.
+/*
+/* msg_resetjmp() should be used to restore state that was
+/* previously saved with msg_setjmp(). The buffer lifetime
+/* must extend to the next msg_resetjmp() or msg_clearjmp()
+/* call.
+/* .ad
+/* .fi
/* SEE ALSO
/* msg_output(3) specify diagnostics disposition
/* msg_stdio(3) direct diagnostics to standard I/O stream
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
/*--*/
/* System libraries. */
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
+#include <signal.h>
/* Application-specific. */
*/
int msg_verbose = 0;
+ /*
+ * Semi-private state. Managed with msg_setjmp(), msg_longjmp(), and
+ * msg_clearjmp().
+ */
+MSG_JMP_BUF *msg_jmp_bufp;
+
/*
* Private state.
*/
if (msg_cleanup_fn)
msg_cleanup_fn();
}
+ if (msg_jmp_bufp) {
+ /* This code is for testing only. */
+ msg_exiting = 0;
+ msg_longjmp(MSG_LONGJMP_FATAL);
+ }
sleep(1);
/* In case we're running as a signal handler. */
_exit(1);
if (msg_cleanup_fn)
msg_cleanup_fn();
}
+ if (msg_jmp_bufp) {
+ /* This code is for testing only. */
+ msg_exiting = 0;
+ msg_longjmp(MSG_LONGJMP_FATAL);
+ }
sleep(1);
/* In case we're running as a signal handler. */
_exit(status);
if (msg_exiting++ == 0) {
msg_vprintf(MSG_PANIC, fmt, ap);
}
+ if (msg_jmp_bufp) {
+ /* This code is for testing only. */
+ msg_exiting = 0;
+ msg_longjmp(MSG_LONGJMP_PANIC);
+ }
sleep(1);
abort(); /* Die! */
/* In case we're running as a signal handler. */
*/
#include <stdarg.h>
#include <time.h>
+#include <setjmp.h>
/*
* External interface.
void PRINTFPTRLIKE(1, 2) (*log_fn) (const char *,...),
const char *,...);
+ /*
+ * Only for tests: make a long jump instead of terminating.
+ */
+#ifdef NO_SIGSETJMP
+#define MSG_JMP_BUF jmp_buf
+#define msg_setjmp(bufp) setjmp((msg_jmp_bufp = (bufp))[0])
+#define msg_longjmp(val) longjmp(msg_jmp_bufp[0], (val))
+#else
+#define MSG_JMP_BUF sigjmp_buf
+#define msg_setjmp(bufp) sigsetjmp((msg_jmp_bufp = (bufp))[0], 1)
+#define msg_longjmp(val) siglongjmp(msg_jmp_bufp[0], (val))
+#endif
+#define msg_resetjmp(bufp) do { msg_jmp_bufp = (bufp); } while (0)
+#define msg_clearjmp() do { msg_jmp_bufp = 0; } while (0)
+
+extern MSG_JMP_BUF *msg_jmp_bufp;
+
+#define MSG_LONGJMP_FATAL 2 /* msg_fatal longjmp code */
+#define MSG_LONGJMP_PANIC 3 /* msg_panic longjmp code */
+
/* LICENSE
/* .ad
/* .fi
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
/*--*/
#endif
/* SYNOPSIS
/* #include <msg_output.h>
/*
-/* typedef void (*MSG_OUTPUT_FN)(int level, char *text)
+/* typedef void (*MSG_OUTPUT3_FN)(int level, char *text, void *context)
/*
-/* void msg_output(output_fn)
-/* MSG_OUTPUT_FN output_fn;
+/* void msg_output_push(output_fn, context)
+/* MSG_OUTPUT3_FN output_fn;
+/* void *context;
+/*
+/* msg_output_pop(output_fn, context)
+/* MSG_OUTPUT3_FN output_fn
+/* void *context;
/*
/* void msg_printf(level, format, ...)
/* int level;
/* int level;
/* const char *format;
/* va_list ap;
+/* LEGACY API
+/* typedef void (*MSG_OUTPUT_FN)(int level, char *text)
+/*
+/* void msg_output(output_fn)
+/* MSG_OUTPUT_FN output_fn;
/* DESCRIPTION
/* This module implements low-level output management for the
/* msg(3) diagnostics interface.
/*
-/* msg_output() registers an output handler for the diagnostics
-/* interface. An application can register multiple output handlers.
-/* Output handlers are called in the specified order.
-/* An output handler takes as arguments a severity level (MSG_INFO,
-/* MSG_WARN, MSG_ERROR, MSG_FATAL, MSG_PANIC, monotonically increasing
+/* msg_output_push() registers an output handler and call-back
+/* context, if that handler and context are not already
+/* registered. Output handlers are called in the specified
+/* order. The context pointer is passed as the third argument
+/* to an MSG_OUTPUT3_FN output handler. An output handler
+/* takes as arguments a severity level (MSG_INFO, MSG_WARN,
+/* MSG_ERROR, MSG_FATAL, MSG_PANIC, monotonically increasing
/* integer values ranging from 0 to MSG_LAST) and pre-formatted,
/* sanitized, text in the form of a null-terminated string.
/*
-/* msg_printf() and msg_vprintf() format their arguments, sanitize the
-/* result, and call the output handlers registered with msg_output().
+/* msg_output_pop() unregisters the specified output handler
+/* and context, and all later registered (handler, context)
+/* pairs. It invokes a panic when the handler and context are
+/* not found.
+/*
+/* msg_printf() and msg_vprintf() format their arguments,
+/* sanitize the result, and call the output handlers registered
+/* with msg_output().
/*
-/* msg_text() copies a pre-formatted text, sanitizes the result, and
-/* calls the output handlers registered with msg_output().
+/* msg_text() copies a pre-formatted text, sanitizes the result,
+/* and calls the output handlers registered with msg_output().
/* REENTRANCY
/* .ad
/* .fi
-/* The above output routines are protected against ordinary
-/* recursive calls and against re-entry by signal
-/* handlers, with the following limitations:
+/* The output routines are protected against ordinary recursive
+/* calls and against re-entry by signal handlers, with the
+/* following limitations:
/* .IP \(bu
/* The signal handlers must never return. In other words, the
/* signal handlers must do one or more of the following: call
-/* _exit(), kill the process with a signal, and permanently
+/* _exit(), kill the process with a signal, or permanently
/* block the process.
/* .IP \(bu
/* The signal handlers must call the above output routines not
-/* until after msg_output() completes initialization, and not
-/* until after the first formatted output to a VSTRING or
-/* VSTREAM.
+/* until after msg_output() completes initialization.
/* .IP \(bu
/* Each msg_output() call-back function, and each Postfix or
/* system function called by that call-back function, either
#include <vstream.h>
#include <msg_vstream.h>
#include <stringops.h>
+#include <msg.h>
#include <msg_output.h>
/*
* Private state. Allow one nested call, so that one logging error can be
* reported to stderr before bailing out.
*/
+typedef struct MSG_OUTPUT_INFO {
+ int argc; /* 2 or 3 arguments */
+ union {
+ MSG_OUTPUT_FN output_fn; /* two-argument form */
+ MSG_OUTPUT3_FN output3_fn; /* three-argument form */
+ } u;
+ void *context; /* used for three-argument form */
+} MSG_OUTPUT_INFO;
+
#define MSG_OUT_NESTING_LIMIT 2
-static MSG_OUTPUT_FN *msg_output_fn = 0;
-static int msg_output_fn_count = 0;
+static MSG_OUTPUT_INFO *msg_output_info = 0;
+static int msg_output_info_count = 0;
static VSTRING *msg_buffers[MSG_OUT_NESTING_LIMIT];
-/* msg_output - specify output handler */
+/* do_msg_output - add output handler */
-void msg_output(MSG_OUTPUT_FN output_fn)
+static void do_msg_output(MSG_OUTPUT_INFO *info)
{
- int i;
+ VSTRING **bp;
+ MSG_OUTPUT_INFO *mp;
/*
* Allocate all resources during initialization. This may result in a
* recursive call due to memory allocation error.
*/
if (msg_buffers[MSG_OUT_NESTING_LIMIT - 1] == 0) {
- for (i = 0; i < MSG_OUT_NESTING_LIMIT; i++)
- msg_buffers[i] = vstring_alloc(100);
+ for (bp = msg_buffers; bp < msg_buffers + MSG_OUT_NESTING_LIMIT; bp++)
+ *bp = vstring_alloc(100);
+ }
+
+ /*
+ * Deduplicate requests.
+ */
+ for (mp = msg_output_info; mp < msg_output_info + msg_output_info_count; mp++) {
+ if (mp->argc == info->argc
+ && mp->context == info->context
+ && ((info->argc == 2 && mp->u.output_fn == info->u.output_fn)
+ || (info->argc == 3 && mp->u.output3_fn == info->u.output3_fn)))
+ return;
}
/*
* We're not doing this often, so avoid complexity and allocate memory
* for an exact fit.
*/
- if (msg_output_fn_count == 0)
- msg_output_fn = (MSG_OUTPUT_FN *) mymalloc(sizeof(*msg_output_fn));
+ if (msg_output_info_count == 0)
+ msg_output_info = (MSG_OUTPUT_INFO *) mymalloc(sizeof(*msg_output_info));
else
- msg_output_fn = (MSG_OUTPUT_FN *) myrealloc((void *) msg_output_fn,
- (msg_output_fn_count + 1) * sizeof(*msg_output_fn));
- msg_output_fn[msg_output_fn_count++] = output_fn;
+ msg_output_info = (MSG_OUTPUT_INFO *) myrealloc((void *) msg_output_info,
+ (msg_output_info_count + 1) * sizeof(*msg_output_info));
+ msg_output_info[msg_output_info_count++] = *info;
+}
+
+/* msg_output - specify output handler */
+
+void msg_output(MSG_OUTPUT_FN output_fn)
+{
+ MSG_OUTPUT_INFO info;
+
+ info.argc = 2;
+ info.u.output_fn = output_fn;
+ info.context = 0;
+ do_msg_output(&info);
+}
+
+/* msg_output_push - specify three-argument output handler */
+
+void msg_output_push(MSG_OUTPUT3_FN output_fn, void *context)
+{
+ MSG_OUTPUT_INFO info;
+
+ info.argc = 3;
+ info.u.output3_fn = output_fn;
+ info.context = context;
+ do_msg_output(&info);
}
/* msg_printf - format text and log it */
void msg_vprintf(int level, const char *format, va_list ap)
{
int saved_errno = errno;
+ MSG_OUTPUT_INFO *mp;
VSTRING *vp;
- int i;
if (msg_vprintf_level < MSG_OUT_NESTING_LIMIT) {
msg_vprintf_level += 1;
/* On-the-fly initialization for test programs and startup errors. */
- if (msg_output_fn_count == 0)
+ if (msg_output_info_count == 0)
msg_vstream_init("unknown", VSTREAM_ERR);
vp = msg_buffers[msg_vprintf_level - 1];
/* OK if terminating signal handler hijacks control before next stmt. */
vstring_vsprintf(vp, format, ap);
printable(vstring_str(vp), '?');
- for (i = 0; i < msg_output_fn_count; i++)
- msg_output_fn[i] (level, vstring_str(vp));
+ for (mp = msg_output_info; mp < msg_output_info + msg_output_info_count; mp++) {
+ switch (mp->argc) {
+ case 3:
+ mp->u.output3_fn(level, vstring_str(vp), mp->context);
+ break;
+ case 2:
+ mp->u.output_fn(level, vstring_str(vp));
+ break;
+ default:
+ msg_panic("msg_vprintf: bad argument count: %d", mp->argc);
+ }
+ }
msg_vprintf_level -= 1;
}
errno = saved_errno;
}
+
+/* msg_output_pop - pop output handler and context */
+
+void msg_output_pop(MSG_OUTPUT3_FN output_fn, void *context)
+{
+ MSG_OUTPUT_INFO *mp;
+
+ for (;;) {
+ if (msg_output_info_count <= 0)
+ msg_panic("msg_output_pop: handler and context not found");
+ mp = msg_output_info + --msg_output_info_count;
+ if (context == mp->context && mp->u.output3_fn == output_fn)
+ return;
+ }
+}
*/
typedef void (*MSG_OUTPUT_FN) (int, const char *);
extern void msg_output(MSG_OUTPUT_FN);
+typedef void (*MSG_OUTPUT3_FN) (int, const char *, void *);
+extern void msg_output_push(MSG_OUTPUT3_FN, void *);
+extern void msg_output_pop(MSG_OUTPUT3_FN, void *);
extern void PRINTFLIKE(2, 3) msg_printf(int, const char *,...);
extern void msg_vprintf(int, const char *, va_list);
--- /dev/null
+ /*
+ * Test program to exercise the msg_output module. See comments in
+ * ptest_main.h for documented examples.
+ */
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <string.h>
+
+ /*
+ * Utility library.
+ */
+#include <argv.h>
+#include <msg.h>
+#include <msg_output.h>
+#include <mymalloc.h>
+#include <vstring.h>
+
+ /*
+ * Test library.
+ */
+#include <ptest.h>
+#include <match_basic.h>
+
+ /*
+ * Note: the test framework calls msg_output_pop() after a test returns or
+ * makes a long jump, so there is no requirement that each test below pops
+ * the handlers that it has pushed.
+ */
+static ARGV *got_argv;
+static VSTRING *buf;
+
+typedef struct PTEST_CASE {
+ const char *testname; /* Human-readable description */
+ void (*action) (PTEST_CTX *t, const struct PTEST_CASE *);
+} PTEST_CASE;
+
+/* update_argv - append formatted handler inputs */
+
+static void update_argv(ARGV *argv, int level, const char *text, void *context)
+{
+ if (buf == 0)
+ buf = vstring_alloc(10);
+ vstring_sprintf(buf, "%d:%s:%s", level, text, (char *) context);
+ argv_add(argv, vstring_str(buf), (char *) 0);
+}
+
+/* handler - output handler */
+
+static void handler(int level, const char *text, void *context)
+{
+ update_argv(got_argv, level, text, context);
+}
+
+static void test_msg_output_push_pop_works(PTEST_CTX *t, const PTEST_CASE *unused)
+{
+ ARGV *want_argv = argv_alloc(1);
+ char *req_context = "handler";
+
+ /*
+ * Install our logging output handler.
+ */
+ got_argv = argv_alloc(1);
+ msg_output_push(handler, req_context);
+
+ /*
+ * Expect and generate one logging event.
+ */
+ update_argv(want_argv, 0, "text", req_context);
+ expect_ptest_log_event(t, "text");
+ msg_info("text");
+
+ /*
+ * Verify that the event was sent to our logging handler.
+ */
+ if (got_argv->argc != 1)
+ ptest_error(t, "handler: got %ld results, want 1",
+ (long) got_argv->argc);
+ else
+ (void) eq_argv(t, "handler events", got_argv, want_argv);
+
+ /*
+ * Pop our logging output handler and verify that it no longer receives
+ * logging
+ */
+ msg_output_pop(handler, req_context);
+ expect_ptest_log_event(t, "more text");
+ msg_info("more text");
+ if (got_argv->argc > 1)
+ ptest_error(t, "handler: got result after it was popped");
+
+ /*
+ * Clean up.
+ */
+ argv_free(got_argv);
+ argv_free(want_argv);
+}
+
+static void test_msg_output_push_dedups(PTEST_CTX *t, const PTEST_CASE *unused)
+{
+ ARGV *want_argv = argv_alloc(1);
+ char *req_context = "handler";
+
+ /*
+ * Push the same logging handler twice.
+ */
+ got_argv = argv_alloc(1);
+ msg_output_push(handler, req_context);
+ msg_output_push(handler, req_context);
+
+ /*
+ * Expect and generate a logging event.
+ */
+ update_argv(want_argv, 0, "text", req_context);
+ expect_ptest_log_event(t, "text");
+ msg_info("text");
+
+ /*
+ * Verify the handler is called only once.
+ */
+ if (got_argv->argc != 1)
+ ptest_error(t, "handler: got %ld results, want 1",
+ (long) got_argv->argc);
+ else
+ (void) eq_argv(t, "handler events", got_argv, want_argv);
+
+ /*
+ * Clean up.
+ */
+ msg_output_pop(handler, req_context);
+ argv_free(got_argv);
+ argv_free(want_argv);
+}
+
+static PTEST_CASE ptestcases[] = {
+ {"test msg_output_push_pop works", test_msg_output_push_pop_works},
+ {"test msg_output_push dedups", test_msg_output_push_dedups},
+};
+
+#include <ptest_main.h>
/* void msg_vstream_init(progname, stream)
/* const char *progname;
/* VSTREAM *stream;
+/*
+/* void msg_vstream_enable(yesno)
+/* int yesno;
/* DESCRIPTION
/* This module implements support to report msg(3) diagnostics
/* to a VSTREAM.
/* msg_vstream_init() sets the program name that appears in each output
/* record, and directs diagnostics (see msg(3)) to the specified
/* VSTREAM. The \fIprogname\fR argument is not copied.
+/*
+/* msg_vstream_enable() enables or disables msg_vstream logging,
+/* depending on the argument value.
/* SEE ALSO
/* msg(3)
/* BUGS
*/
static const char *msg_tag;
static VSTREAM *msg_stream;
+static int msg_vstream_enabled;
/* msg_vstream_print - log diagnostic to VSTREAM */
"info", "warning", "error", "fatal", "panic",
};
+ if (!msg_vstream_enabled)
+ return;
+
if (level < 0 || level >= (int) (sizeof(level_text) / sizeof(level_text[0])))
msg_panic("invalid severity level: %d", level);
if (level == MSG_INFO) {
void msg_vstream_init(const char *name, VSTREAM *vp)
{
- static int first_call = 1;
-
msg_tag = name;
msg_stream = vp;
- if (first_call) {
- first_call = 0;
- msg_output(msg_vstream_print);
- }
+ msg_output(msg_vstream_print);
+ msg_vstream_enabled = 1;
+}
+
+/* msg_vstream_enable - on/off switch */
+
+void msg_vstream_enable(int yesno)
+{
+ msg_vstream_enabled = yesno;
}
* External interface.
*/
extern void msg_vstream_init(const char *, VSTREAM *);
+extern void msg_vstream_enable(int);
/* LICENSE
/* .ad
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
-#include <netdb.h>
+#include <wrap_netdb.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
-#include <netdb.h>
+#include <wrap_netdb.h>
#include <string.h>
#include <errno.h> /* MAI_STRERROR() */
#include <limits.h> /* CHAR_BIT */
#define sockaddr_storage mai_sockaddr_storage
/*
- * Modern systems define this in <netdb.h>.
+ * Modern systems define this in <wrap_netdb.h>.
*/
struct addrinfo {
int ai_flags; /* AI_PASSIVE|CANONNAME|NUMERICHOST */
+++ /dev/null
-./myaddrinfo: === hostname belly.porcupine.org ===
-./myaddrinfo: belly.porcupine.org -> family=2 sock=1 proto=6 168.100.3.6
-./myaddrinfo: 168.100.3.6 -> belly.porcupine.org
-./myaddrinfo: belly.porcupine.org -> family=28 sock=1 proto=6 2604:8d00:189::6
-./myaddrinfo: 2604:8d00:189::6 -> belly.porcupine.org
-./myaddrinfo: === host address 168.100.3.2 ===
-./myaddrinfo: 168.100.3.2 -> family=2 sock=1 proto=6 168.100.3.2
-./myaddrinfo: 168.100.3.2 -> spike.porcupine.org
+++ /dev/null
-./myaddrinfo: === hostname null.porcupine.org ===
-./myaddrinfo: hostname_to_sockaddr(null.porcupine.org): hostname nor servname provided, or not known
-./myaddrinfo: === host address 10.0.0.0 ===
-./myaddrinfo: 10.0.0.0 -> family=2 sock=1 proto=6 10.0.0.0
-./myaddrinfo: sockaddr_to_hostname: hostname nor servname provided, or not known
+++ /dev/null
-./myaddrinfo4: === hostname belly.porcupine.org ===
-./myaddrinfo4: belly.porcupine.org -> family=2 sock=1 proto=6 168.100.3.6
-./myaddrinfo4: 168.100.3.6 -> belly.porcupine.org
-./myaddrinfo4: === host address 168.100.3.2 ===
-./myaddrinfo4: 168.100.3.2 -> family=2 sock=1 proto=6 168.100.3.2
-./myaddrinfo4: 168.100.3.2 -> spike.porcupine.org
+++ /dev/null
-./myaddrinfo4: === hostname null.porcupine.org ===
-./myaddrinfo4: hostname2sockaddr(null.porcupine.org): No address associated with hostname
-./myaddrinfo4: === host address 10.0.0.0 ===
-./myaddrinfo4: 10.0.0.0 -> family=2 sock=1 proto=6 10.0.0.0
-./myaddrinfo4: sockaddr2hostname: hostname nor servname provided, or not known
--- /dev/null
+ /*
+ * Test program for the myaddrinfo module. The purpose is to verify that the
+ * myaddrinfo functions make the expected calls, and that they forward the
+ * expected results. See comments in ptest_main.h and pmock_expect_test.c
+ * for a documented example.
+ */
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <wrap_netdb.h>
+
+ /*
+ * Utility library.
+ */
+#include <vstring.h>
+#include <inet_proto.h>
+
+ /*
+ * Test library.
+ */
+#include <ptest.h>
+#include <mock_getaddrinfo.h>
+
+#define STR vstring_str
+
+typedef struct PTEST_CASE {
+ const char *testname; /* Human-readable description */
+ void (*action) (PTEST_CTX *t, const struct PTEST_CASE *);
+} PTEST_CASE;
+
+static void test_hostname_to_sockaddr_host(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ int got_st, want_st = 0;
+ struct addrinfo *got_info = 0, *want_info;
+ struct addrinfo req_hints;
+ const char *hostname = "belly.porcupine.org";
+
+ inet_proto_init(tp->testname, "all");
+
+ /*
+ * Set up expectations.
+ */
+ memset(&req_hints, 0, sizeof(req_hints));
+ req_hints.ai_family = PF_INET;
+ want_info = make_addrinfo(&req_hints, (char *) 0, "168.100.3.6", 0);
+ req_hints.ai_family = PF_INET6;
+ want_info->ai_next = make_addrinfo(&req_hints, (char *) 0,
+ "2604:8d00:189::6", 0);
+ req_hints.ai_family = inet_proto_info()->ai_family;
+ req_hints.ai_socktype = SOCK_STREAM; /* XXX */
+ expect_getaddrinfo(1, want_st, hostname, (char *) 0,
+ &req_hints, want_info);
+
+ /*
+ * Call the mock and verify the results.
+ */
+ got_st = hostname_to_sockaddr(hostname, (char *) 0, 0, &got_info);
+ if (got_st != want_st) {
+ ptest_error(t, "hostname_to_sockaddr status: got %d, want %d",
+ got_st, want_st);
+ } else if (!eq_addrinfo(t, "hostname_to_sockaddr addrinfo",
+ got_info, want_info)) {
+ /* already logged by eq_addrinfo() */
+ }
+
+ /*
+ * Clean up.
+ */
+ freeaddrinfo(want_info);
+ if (got_info)
+ freeaddrinfo(got_info);
+}
+
+static void test_hostname_to_sockaddr_v4host(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ int got_st, want_st = 0;
+ struct addrinfo *got_info = 0, *want_info;
+ struct addrinfo req_hints;
+ const char *hostname = "belly.porcupine.org";
+
+ inet_proto_init(tp->testname, "ipv4");
+
+ /*
+ * Set up expectations.
+ */
+ memset(&req_hints, 0, sizeof(req_hints));
+ req_hints.ai_family = PF_INET;
+ want_info = make_addrinfo(&req_hints, (char *) 0, "168.100.3.6", 0);
+ req_hints.ai_family = inet_proto_info()->ai_family;
+ req_hints.ai_socktype = SOCK_STREAM; /* XXX */
+ expect_getaddrinfo(1, want_st, hostname, (char *) 0,
+ &req_hints, want_info);
+
+ /*
+ * Call the mock and verify the results.
+ */
+ got_st = hostname_to_sockaddr(hostname, (char *) 0, 0, &got_info);
+ if (got_st != want_st) {
+ ptest_error(t, "hostname_to_sockaddr status: got %d, want %d",
+ got_st, want_st);
+ } else if (!eq_addrinfo(t, "hostname_to_sockaddr addrinfo",
+ got_info, want_info)) {
+ /* already logged by eq_addrinfo() */
+ }
+
+ /*
+ * Clean up.
+ */
+ freeaddrinfo(want_info);
+ if (got_info)
+ freeaddrinfo(got_info);
+}
+
+
+static void test_hostaddr_to_sockaddr_host(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ int got_st, want_st = 0;
+ struct addrinfo *got_info, *want_info;
+ struct addrinfo req_hints;
+ const char *req_hostaddr = "168.100.3.2";
+
+ /*
+ * Set up expectations.
+ */
+ memset(&req_hints, 0, sizeof(req_hints));
+ req_hints.ai_family = PF_INET;
+ want_info = make_addrinfo(&req_hints, (char *) 0, req_hostaddr, 0);
+ req_hints.ai_family = inet_proto_info()->ai_family;
+ req_hints.ai_socktype = SOCK_STREAM; /* XXX */
+ req_hints.ai_flags = AI_NUMERICHOST;
+ expect_getaddrinfo(1, want_st, req_hostaddr, (char *) 0,
+ &req_hints, want_info);
+
+ /*
+ * Call the mock indirectly, and verify the results.
+ */
+ got_st = hostaddr_to_sockaddr(req_hostaddr, (char *) 0, 0, &got_info);
+ if (got_st != want_st) {
+ ptest_error(t, "hostaddr_to_sockaddr status: got %d, want %d",
+ got_st, want_st);
+ } else if (!eq_addrinfo(t, "hostname_to_sockaddr addrinfo",
+ got_info, want_info)) {
+ /* already logged by eq_addrinfo() */
+ }
+
+ /*
+ * Clean up.
+ */
+ freeaddrinfo(want_info);
+ if (got_info)
+ freeaddrinfo(got_info);
+}
+
+static void test_hostname_to_sockaddr_nxhost(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ int got_st, want_st = EAI_NONAME;
+ struct addrinfo *got_info = 0, *want_info = 0;
+ struct addrinfo req_hints;
+ const char *hostname = "null.porcupine.org";
+
+ inet_proto_init(tp->testname, "all");
+
+ /*
+ * Set up expectations.
+ */
+ memset(&req_hints, 0, sizeof(req_hints));
+ req_hints.ai_family = inet_proto_info()->ai_family;
+ req_hints.ai_socktype = SOCK_STREAM; /* XXX */
+ expect_getaddrinfo(1, want_st, hostname, (char *) 0, &req_hints, want_info);
+
+ /*
+ * Call the mock and verify the results.
+ */
+ got_st = hostname_to_sockaddr(hostname, (char *) 0, 0, &got_info);
+ if (got_st != want_st) {
+ ptest_error(t, "hostname_to_sockaddr status: got %d, want %d",
+ got_st, want_st);
+ } else if (!eq_addrinfo(t, "hostname_to_sockaddr addrinfo",
+ got_info, want_info)) {
+ /* already logged by eq_addrinfo() */
+ }
+
+ /*
+ * Clean up.
+ */
+ if (got_info)
+ freeaddrinfo(got_info);
+}
+
+ /*
+ * Test cases.
+ */
+const PTEST_CASE ptestcases[] = {
+ {
+ /* name */ "test hostname_to_sockaddr host only",
+ /* action */ test_hostname_to_sockaddr_host,
+ },
+ {
+ /* name */ "test hostname_to_sockaddr v4host only",
+ /* action */ test_hostname_to_sockaddr_v4host,
+ },
+ {
+ /* name */ "test hostaddr_to_sockaddr host only",
+ /* action */ test_hostaddr_to_sockaddr_host,
+ },
+ {
+ /* name */ "test hostname_to_sockaddr non-existent host only",
+ /* action */ test_hostname_to_sockaddr_nxhost,
+ },
+ /* TODO: sockadddr_to_hostaddr, sockaddr_to_hostname. */
+};
+
+#include <ptest_main.h>
if (len < 0)
msg_panic("mystrndup: requested length %ld", (long) len);
#ifndef NO_SHARED_EMPTY_STRINGS
- if (*str == 0)
+ if (*str == 0 || /* fix 20220615 */ len == 0)
return ((char *) empty_string);
#endif
if ((cp = memchr(str, 0, len)) != 0)
--- /dev/null
+ /*
+ * Tests to verify malloc sanity checks. See comments in ptest_main.h for a
+ * documented example. The test code depends on the real mymalloc library,
+ * so we can 't do destructive tests.
+ */
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <string.h>
+
+ /*
+ * Utility library.
+ */
+#include <msg.h>
+#include <mymalloc.h>
+
+ /*
+ * Test library.
+ */
+#include <ptest.h>
+
+ /*
+ * See <ptest_main.h>
+ */
+typedef struct PTEST_CASE {
+ const char *testname; /* Human-readable description */
+ void (*action) (PTEST_CTX *, const struct PTEST_CASE *);
+} PTEST_CASE;
+
+/* Test functions. */
+
+static void test_mymalloc_normal(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ void *ptr;
+
+ ptr = mymalloc(100);
+ myfree(ptr);
+}
+
+static void test_mymalloc_panic_too_small(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ expect_ptest_log_event(t, "panic: mymalloc: requested length 0");
+ (void) mymalloc(0);
+ ptest_fatal(t, "mymalloc(0) returned");
+}
+
+static void test_mymalloc_fatal_out_of_mem(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ if (sizeof(size_t) <= 4)
+ ptest_skip(t);
+ expect_ptest_log_event(t, "fatal: mymalloc: insufficient memory for");
+ (void) mymalloc(SSIZE_T_MAX - 100);
+ ptest_fatal(t, "mymalloc(SSIZE_T_MAX-100) returned");
+}
+
+static void test_myfree_panic_double_free(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ void *ptr;
+
+ expect_ptest_log_event(t, "panic: myfree: corrupt or unallocated memory block");
+ ptr = mymalloc(100);
+ myfree(ptr);
+ /* The next call unavoidably reads unallocated memory */
+ myfree(ptr);
+ ptest_fatal(t, "double myfree(_) returned");
+}
+
+static void test_myfree_panic_null(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ expect_ptest_log_event(t, "panic: myfree: null pointer input");
+ myfree((void *) 0);
+ ptest_fatal(t, "myfree(0) returned");
+}
+
+static void test_myrealloc_normal(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ void *ptr;
+
+ ptr = mymalloc(100);
+ ptr = myrealloc(ptr, 200);
+ myfree(ptr);
+}
+
+static void test_myrealloc_panic_too_small(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ void *ptr;
+
+ expect_ptest_log_event(t, "panic: myrealloc: requested length 0");
+ ptr = mymalloc(100);
+ ptest_defer(t, myfree, ptr);
+ (void) myrealloc(ptr, 0);
+ ptest_fatal(t, "myrealloc(_, 0) returned");
+}
+
+static void test_myrealloc_fatal_out_of_mem(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ void *ptr;
+
+ if (sizeof(size_t) <= 4)
+ ptest_skip(t);
+
+ /*
+ * Unlike the previous test, this test can't use test_defer(t, myfree,
+ * ptr), because myrealloc() clears the memory block's signature field
+ * before it calls realloc().
+ */
+ expect_ptest_log_event(t, "fatal: myrealloc: insufficient memory for");
+ ptr = mymalloc(100);
+ (void) myrealloc(ptr, SSIZE_T_MAX - 100);
+ ptest_fatal(t, "myrealloc(_, SSIZE_T_MAX-100) returned");
+}
+
+static void test_myrealloc_panic_unallocated(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ void *ptr;
+
+ expect_ptest_log_event(t, "panic: myrealloc: corrupt or unallocated memory block");
+ ptr = mymalloc(100);
+ myfree(ptr);
+ ptr = myrealloc(ptr, 200);
+ ptest_fatal(t, "myrealloc() after free() returned");
+}
+
+static void test_myrealloc_panic_null(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ expect_ptest_log_event(t, "panic: myrealloc: null pointer input");
+ (void) myrealloc((void *) 0, 200);
+ ptest_fatal(t, "myrealloc(0, _) returned");
+}
+
+static void test_mystrdup_normal(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ void *ptr;
+
+ ptr = mystrdup("foo");
+ myfree(ptr);
+}
+
+static void test_mystrdup_panic_null(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ expect_ptest_log_event(t, "panic: mystrdup: null pointer argument");
+ (void) mystrdup((char *) 0);
+ ptest_fatal(t, "mystrdup(0) returned");
+}
+
+static void test_mystrdup_static_empty(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ char *want;
+ char *got;
+
+ /*
+ * Repeated mystrdup("") produce the same result.
+ */
+ want = mystrdup("");
+ got = mystrdup("");
+ if (got != want)
+ ptest_error(t, "mystrndup: empty string results differ: got %p, want %p",
+ got, want);
+
+ /*
+ * myfree() is a NOOP.
+ */
+ myfree(want);
+ myfree(got);
+}
+
+static void test_mystrndup_normal_short(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ char *want = "foo";
+ char *got;
+
+ got = mystrndup("foo", 5);
+ if (strcmp(got, want) != 0)
+ ptest_error(t, "mystrndup: got '%s', want '%s'", got, want);
+ myfree(got);
+}
+
+static void test_mystrndup_normal_long(PTEST_CTX *t,
+ const PTEST_CASE *tp)
+{
+ char *want = "fooba";
+ char *got;
+
+ got = mystrndup("foobar", 5);
+ if (strcmp(got, want) != 0)
+ ptest_error(t, "mystrndup: got '%s', want '%s'", got, want);
+ myfree(got);
+}
+
+static void test_mystrndup_panic_null(PTEST_CTX *t,
+ const PTEST_CASE *tp)
+{
+ expect_ptest_log_event(t, "panic: mystrndup: null pointer argument");
+ (void) mystrndup((char *) 0, 5);
+ ptest_fatal(t, "mystrndup(0, _) returned");
+}
+
+static void test_mystrndup_panic_too_small(PTEST_CTX *t,
+ const PTEST_CASE *tp)
+{
+ expect_ptest_log_event(t, "panic: mystrndup: requested length -1");
+ (void) mystrndup("foo", -1);
+ ptest_fatal(t, "mystrndup(0, -1) returned");
+}
+
+static void test_mystrndup_static_empty(PTEST_CTX *t,
+ const PTEST_CASE *tp)
+{
+ char *want;
+ char *got;
+
+ /*
+ * Different ways to save an empty string produce the same result.
+ */
+ want = mystrndup("", 10);
+ got = mystrndup("foo", 0);
+ if (got != want)
+ ptest_error(t, "mystrndup: empty string results differ: got %p, want %p",
+ got, want);
+
+ /*
+ * myfree() is a NOOP.
+ */
+ myfree(want);
+ myfree(got);
+}
+
+static void test_mymemdup_normal(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ void *ptr;
+
+ ptr = mymemdup("abcdef", 5);
+ myfree(ptr);
+}
+
+static void test_mymemdup_panic_null(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ expect_ptest_log_event(t, "panic: mymemdup: null pointer argument");
+ (void) mymemdup((void *) 0, 100);
+ ptest_fatal(t, "mymemdup(0, _) returned");
+}
+
+static void test_mymemdup_panic_too_small(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ expect_ptest_log_event(t, "panic: mymalloc: requested length 0");
+ (void) mymemdup("abcdef", 0);
+ ptest_fatal(t, "mymemdup(_, 0) returned");
+}
+
+static void test_mymemdup_fatal_out_of_mem(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ if (sizeof(size_t) <= 4)
+ ptest_skip(t);
+ expect_ptest_log_event(t, "fatal: mymalloc: insufficient memory for");
+ (void) mymemdup("abcdef", SSIZE_T_MAX - 100);
+ ptest_fatal(t, "mymemdup(_, SSIZE_T_MAX-100) returned");
+}
+
+const PTEST_CASE ptestcases[] = {
+ {"mymalloc + myfree normal case", test_mymalloc_normal,
+ },
+ {"mymalloc panic for too small request", test_mymalloc_panic_too_small,
+ },
+ {"mymalloc fatal for out of memory", test_mymalloc_fatal_out_of_mem,
+ },
+ {"myfree panic for double free", test_myfree_panic_double_free,
+ },
+ {"myfree panic for null input", test_myfree_panic_null,
+ },
+ {"myrealloc + myfree normal case", test_myrealloc_normal,
+ },
+ {"myrealloc panic for too small request", test_myrealloc_panic_too_small,
+ },
+ {"myrealloc fatal for out of memory", test_myrealloc_fatal_out_of_mem,
+ },
+ {"myrealloc panic for unallocated input", test_myrealloc_panic_unallocated,
+ },
+ {"myrealloc panic for null input", test_myrealloc_panic_null,
+ },
+ {"mystrdup + myfree normal case", test_mystrdup_normal,
+ },
+ {"mystrdup panic for null input", test_mystrdup_panic_null,
+ },
+ {"mystrdup static result for empty string", test_mystrdup_static_empty,
+ },
+ {"mystrndup + myfree normal short", test_mystrndup_normal_short,
+ },
+ {"mystrndup + myfree normal long", test_mystrndup_normal_long,
+ },
+ {"mystrndup panic for null input", test_mystrndup_panic_null,
+ },
+ {"mystrndup panic for for too small size", test_mystrndup_panic_too_small,
+ },
+ {"mystrndup static result for empty string", test_mystrndup_static_empty,
+ },
+ {"mymemdup normal case", test_mymemdup_normal,
+ },
+ {"mymemdup panic for null input", test_mymemdup_panic_null,
+ },
+ {"mymemdup panic for too small request", test_mymemdup_panic_too_small,
+ },
+ {"mymemdup fatal for out of memory", test_mymemdup_fatal_out_of_mem,
+ },
+};
+
+#include <ptest_main.h>
*src = cp;
return (start);
}
-
-#ifdef TEST
-
- /*
- * Test program.
- */
-#include "msg.h"
-#include "mymalloc.h"
-
- /*
- * The following needs to be large enough to include a null terminator in
- * every testcase.expected field.
- */
-#define EXPECT_SIZE 5
-
-struct testcase {
- const char *action;
- const char *input;
- const char *expected[EXPECT_SIZE];
-};
-static const struct testcase testcases[] = {
- {"mystrtok", ""},
- {"mystrtok", " foo ", {"foo"}},
- {"mystrtok", " foo bar ", {"foo", "bar"}},
- {"mystrtokq", ""},
- {"mystrtokq", "foo bar", {"foo", "bar"}},
- {"mystrtokq", "{ bar } ", {"{ bar }"}},
- {"mystrtokq", "foo { bar } baz", {"foo", "{ bar }", "baz"}},
- {"mystrtokq", "foo{ bar } baz", {"foo{ bar }", "baz"}},
- {"mystrtokq", "foo { bar }baz", {"foo", "{ bar }baz"}},
- {"mystrtokdq", ""},
- {"mystrtokdq", " foo ", {"foo"}},
- {"mystrtokdq", " foo bar ", {"foo", "bar"}},
- {"mystrtokdq", " foo\\ bar ", {"foo\\ bar"}},
- {"mystrtokdq", " foo \\\" bar", {"foo", "\\\"", "bar"}},
- {"mystrtokdq", " foo \" bar baz\" ", {"foo", "\" bar baz\""}},
-};
-
-int main(void)
-{
- const struct testcase *tp;
- char *actual;
- int pass;
- int fail;
- int match;
- int n;
-
-#define NUM_TESTS sizeof(testcases)/sizeof(testcases[0])
-#define STR_OR_NULL(s) ((s) ? (s) : "null")
-
- for (pass = fail = 0, tp = testcases; tp < testcases + NUM_TESTS; tp++) {
- char *saved_input = mystrdup(tp->input);
- char *cp = saved_input;
-
- msg_info("RUN test case %ld %s >%s<",
- (long) (tp - testcases), tp->action, tp->input);
-#if 0
- msg_info("action=%s", tp->action);
- msg_info("input=%s", tp->input);
- for (n = 0; tp->expected[n]; tp++)
- msg_info("expected[%d]=%s", n, tp->expected[n]);
-#endif
-
- for (n = 0; n < EXPECT_SIZE; n++) {
- if (strcmp(tp->action, "mystrtok") == 0) {
- actual = mystrtok(&cp, CHARS_SPACE);
- } else if (strcmp(tp->action, "mystrtokq") == 0) {
- actual = mystrtokq(&cp, CHARS_SPACE, CHARS_BRACE);
- } else if (strcmp(tp->action, "mystrtokdq") == 0) {
- actual = mystrtokdq(&cp, CHARS_SPACE);
- } else {
- msg_panic("invalid command: %s", tp->action);
- }
- if ((match = (actual && tp->expected[n]) ?
- (strcmp(actual, tp->expected[n]) == 0) :
- (actual == tp->expected[n])) != 0) {
- if (actual == 0) {
- msg_info("PASS test %ld", (long) (tp - testcases));
- pass++;
- break;
- }
- } else {
- msg_warn("expected: >%s<, got: >%s<",
- STR_OR_NULL(tp->expected[n]), STR_OR_NULL(actual));
- msg_info("FAIL test %ld", (long) (tp - testcases));
- fail++;
- break;
- }
- }
- if (n >= EXPECT_SIZE)
- msg_panic("need to increase EXPECT_SIZE");
- myfree(saved_input);
- }
- return (fail > 0);
-}
-
-#endif
+++ /dev/null
-unknown: RUN test case 0 mystrtok ><
-unknown: PASS test 0
-unknown: RUN test case 1 mystrtok > foo <
-unknown: PASS test 1
-unknown: RUN test case 2 mystrtok > foo bar <
-unknown: PASS test 2
-unknown: RUN test case 3 mystrtokq ><
-unknown: PASS test 3
-unknown: RUN test case 4 mystrtokq >foo bar<
-unknown: PASS test 4
-unknown: RUN test case 5 mystrtokq >{ bar } <
-unknown: PASS test 5
-unknown: RUN test case 6 mystrtokq >foo { bar } baz<
-unknown: PASS test 6
-unknown: RUN test case 7 mystrtokq >foo{ bar } baz<
-unknown: PASS test 7
-unknown: RUN test case 8 mystrtokq >foo { bar }baz<
-unknown: PASS test 8
-unknown: RUN test case 9 mystrtokdq ><
-unknown: PASS test 9
-unknown: RUN test case 10 mystrtokdq > foo <
-unknown: PASS test 10
-unknown: RUN test case 11 mystrtokdq > foo bar <
-unknown: PASS test 11
-unknown: RUN test case 12 mystrtokdq > foo\ bar <
-unknown: PASS test 12
-unknown: RUN test case 13 mystrtokdq > foo \" bar<
-unknown: PASS test 13
-unknown: RUN test case 14 mystrtokdq > foo " bar baz" <
-unknown: PASS test 14
--- /dev/null
+ /*
+ * Test program to exercise mystrtok.c. See ptest_main.h for a documented
+ * example.
+ */
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <string.h>
+
+ /*
+ * Utility library.
+ */
+#include <msg.h>
+#include <mymalloc.h>
+#include <stringops.h>
+
+ /*
+ * Test library.
+ */
+#include <ptest.h>
+
+ /*
+ * The following needs to be large enough to include a null terminator in
+ * every ptestcase.want field.
+ */
+#define WANT_SIZE 5
+
+typedef struct PTEST_CASE {
+ const char *testname;
+ void (*action) (PTEST_CTX *, const struct PTEST_CASE *);
+ const char *fname;
+ const char *input;
+ const char *want[WANT_SIZE];
+} PTEST_CASE;
+
+#define STR_OR_NULL(s) ((s) ? (s) : "null")
+
+static void tester(PTEST_CTX *t, const struct PTEST_CASE *tp)
+{
+ char *got;
+ int match;
+ int n;
+ char *saved_input = mystrdup(tp->input);
+ char *cp = saved_input;
+
+ for (n = 0; n < WANT_SIZE; n++) {
+ if (strcmp(tp->fname, "mystrtok") == 0) {
+ got = mystrtok(&cp, CHARS_SPACE);
+ } else if (strcmp(tp->fname, "mystrtokq") == 0) {
+ got = mystrtokq(&cp, CHARS_SPACE, CHARS_BRACE);
+ } else if (strcmp(tp->fname, "mystrtokdq") == 0) {
+ got = mystrtokdq(&cp, CHARS_SPACE);
+ } else {
+ msg_panic("invalid function name: %s", tp->fname);
+ }
+ if ((match = (got && tp->want[n]) ?
+ (strcmp(got, tp->want[n]) == 0) :
+ (got == tp->want[n])) != 0) {
+ if (got == 0) {
+ break;
+ }
+ } else {
+ ptest_error(t, "got '%s', want '%s'",
+ STR_OR_NULL(got), STR_OR_NULL(tp->want[n]));
+ break;
+ }
+ }
+ if (n >= WANT_SIZE)
+ msg_panic("need to increase WANT_SIZE");
+ myfree(saved_input);
+}
+
+static const PTEST_CASE ptestcases[] = {
+ {"mystrtok empty", tester,
+ "mystrtok", ""},
+ {"mystrtok > foo <", tester,
+ "mystrtok", " foo ", {"foo"}},
+ {"mystrtok > foo bar <", tester,
+ "mystrtok", " foo bar ", {"foo", "bar"}},
+ {"mystrtokq empty", tester,
+ "mystrtokq", ""},
+ {"mystrtokq >foo bar<", tester,
+ "mystrtokq", "foo bar", {"foo", "bar"}},
+ {"mystrtokq >{ bar }<", tester,
+ "mystrtokq", "{ bar } ", {"{ bar }"}},
+ {"mystrtokq >foo { bar } baz<", tester,
+ "mystrtokq", "foo { bar } baz", {"foo", "{ bar }", "baz"}},
+ {"mystrtokq >foo{ bar } baz<", tester,
+ "mystrtokq", "foo{ bar } baz", {"foo{ bar }", "baz"}},
+ {"mystrtokq >foo { bar }baz<", tester,
+ "mystrtokq", "foo { bar }baz", {"foo", "{ bar }baz"}},
+ {"mystrtokdq empty", tester,
+ "mystrtokdq", ""},
+ {"mystrtokdq > foo <", tester,
+ "mystrtokdq", " foo ", {"foo"}},
+ {"mystrtokdq > foo bar <", tester,
+ "mystrtokdq", " foo bar ", {"foo", "bar"}},
+ {"mystrtokdq > foo\\ bar <", tester,
+ "mystrtokdq", " foo\\ bar ", {"foo\\ bar"}},
+ {"mystrtokdq > foo \\\" bar<", tester,
+ "mystrtokdq", " foo \\\" bar", {"foo", "\\\"", "bar"}},
+ {"mystrtokdq > foo \" bar baz\" <", tester,
+ "mystrtokdq", " foo \" bar baz\" ", {"foo", "\" bar baz\""}},
+};
+
+#include <ptest_main.h>
/* Enable case-insensitive matching.
/* This feature is not enabled by default when calling name_mask();
/* it has no effect with str_name_mask().
+/* .IP NAME_MASK_NULL
+/* When converting from mask to string, output "0" when the
+/* input mask is empty.
/* .IP NAME_MASK_COMMA
/* Use comma instead of space when converting a mask to string.
/* .IP NAME_MASK_PIPE
}
if ((len = VSTRING_LEN(buf)) > 0)
vstring_truncate(buf, len - 1);
+ else if (flags & NAME_MASK_NULL)
+ vstring_strcat(buf, "0");
VSTRING_TERMINATE(buf);
return (STR(buf));
/* long_name_mask_delim_opt - compute mask corresponding to list of names */
long long_name_mask_delim_opt(const char *context,
- const LONG_NAME_MASK * table,
+ const LONG_NAME_MASK *table,
const char *names, const char *delim,
int flags)
{
/* str_long_name_mask_opt - mask to string */
const char *str_long_name_mask_opt(VSTRING *buf, const char *context,
- const LONG_NAME_MASK * table,
+ const LONG_NAME_MASK *table,
long mask, int flags)
{
const char *myname = "name_mask";
#define NAME_MASK_NUMBER (1<<5)
#define NAME_MASK_WARN (1<<6)
#define NAME_MASK_IGNORE (1<<7)
+#define NAME_MASK_NULL (1<<8)
#define NAME_MASK_REQUIRED \
(NAME_MASK_FATAL | NAME_MASK_RETURN | NAME_MASK_WARN | NAME_MASK_IGNORE)
+++ /dev/null
-\a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
-\1\2\3\4\5\6\7\8\9
-\1234\2345\3456\4567
-rcpt to:<wietse@\317\200.porcupine.org>
+++ /dev/null
-0000000 \a \b c d e \f g h i j k l m \n o p
- 007 010 143 144 145 014 147 150 151 152 153 154 155 012 157 160
-0000020 q \r s \t u \v w x y z \n 001 002 003 004 005
- 161 015 163 011 165 013 167 170 171 172 012 001 002 003 004 005
-0000040 006 \a 8 9 \n S 4 234 5 345 6 . 7 \n r c
- 006 007 070 071 012 123 064 234 065 345 066 056 067 012 162 143
-0000060 p t t o : < w i e t s e @ π **
- 160 164 040 164 157 072 074 167 151 145 164 163 145 100 317 200
-0000100 . p o r c u p i n e . o r g > \n
- 056 160 157 162 143 165 160 151 156 145 056 157 162 147 076 012
-0000120
--- /dev/null
+ /*
+ * Test program to exercise unescape.c. See ptest_main.h for a documented
+ * example.
+ */
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <string.h>
+
+ /*
+ * Utility library
+ */
+#include <stringops.h>
+#include <msg.h>
+
+ /*
+ * Test library.
+ */
+#include <ptest.h>
+
+typedef struct PTEST_CASE {
+ const char *testname; /* Human-readable description */
+ void (*action) (PTEST_CTX *, const struct PTEST_CASE *);
+ const char *input;
+ const char *want;
+} PTEST_CASE;
+
+ /*
+ * SLMs.
+ */
+#define STR vstring_str
+
+static char *to_octal_string(VSTRING *buf, const char *str)
+{
+ const unsigned char *cp;
+
+ VSTRING_RESET(buf);
+ for (cp = (const unsigned char *) str; *cp; cp++) {
+ vstring_sprintf_append(buf, "%03o", *cp);
+ if (cp[1])
+ vstring_strcat(buf, " ");
+ }
+ VSTRING_TERMINATE(buf);
+ return (STR(buf));
+}
+
+static void test_unescape(PTEST_CTX *t, const PTEST_CASE *tp)
+{
+ VSTRING *got, *got_octal, *want_octal;;
+
+ got = vstring_alloc(100);
+ got_octal = vstring_alloc(100);
+ want_octal = vstring_alloc(100);
+
+ unescape(got, tp->input);
+ if (strcmp(STR(got), tp->want) != 0)
+ ptest_error(t, "unescape got '%s' want '%s'",
+ to_octal_string(got_octal, STR(got)),
+ to_octal_string(want_octal, tp->want));
+ vstring_free(got);
+ vstring_free(got_octal);
+ vstring_free(want_octal);
+}
+
+static const PTEST_CASE ptestcases[] = {
+ {
+ /* name */ "escape lowecase a-z",
+ /* action */ test_unescape,
+ /* input */ "\\a\\b\\c\\d\\e\\f\\g\\h\\i\\j\\k\\l\\m\\n\\o\\p\\q\\r\\s\\t\\u\\v\\w\\x\\y\\z",
+ /* want */ "\a\bcde\fghijklm\nopq\rs\tu\vwxyz",
+ }, {
+ /* name */ "escape digits 0-9",
+ /* action */ test_unescape,
+ /* input */ "\\1\\2\\3\\4\\5\\6\\7\\8\\9",
+ /* want */ "\001\002\003\004\005\006\00789",
+ }, {
+ /* name */ "\\nnn plus digit",
+ /* action */ test_unescape,
+ /* input */ "\\1234\\2345\\3456\\04567",
+ /* want */ "\1234\2345\3456\04567",
+ }, {
+ /* name */ "non-ascii email",
+ /* action */ test_unescape,
+ /* input */ "rcpt to:<wietse@\\317\\200.porcupine.org>",
+ /* want */ "rcpt to:<wietse@\317\200.porcupine.org>",
+ },
+};
+
+ /*
+ * Test library.
+ */
+#include <ptest_main.h>
--- /dev/null
+/*++
+/* NAME
+/* wrap_netdb 3
+/* SUMMARY
+/* mockable netdb wrappers
+/* SYNOPSIS
+/* #include <wrap_netdb.h>
+/*
+/* int wrap_getaddrinfo(
+/* const char *hostname,
+/* const char *servname,
+/* const struct addrinfo *hints,
+/* struct addrinfo **res)
+/*
+/* void wrap_freeaddrinfo(struct addrinfo *ai)
+/*
+/* int wrap_getnameinfo(
+/* const struct sockaddr *sa,
+/* socklen_t salen,
+/* char *host,
+/* size_t hostlen,
+/* char *serv,
+/* size_t servlen,
+/* int flags)
+/*
+/* struct servent *wrap_getservbyname(
+/* const char *name,
+/* const char *proto)
+/*
+/* struct servent *wrap_getservbyport(
+/* int port,
+/* const char *proto)
+/* DESCRIPTION
+/* This module is a NOOP when the NO_MOCK_WRAPPERS macro is
+/* defined.
+/*
+/* This code implements a workaround for inconsistencies in
+/* netdb.h header files, that can break test mock functions
+/* that have the same name as a system library function.
+/*
+/* For example, BSD and older Linux getnameinfo() implementations
+/* use size_t for the hostlen and servlen arguments, but GLIBC
+/* 2.2 and later use socklen_t instead; those two types have
+/* different sizes on LP64 systems. For a rationale why those
+/* types were changed, see
+/* https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xsh_chap02.html#tag_22_02_10_06
+/*
+/* By default, 1) the header file of this module redirects
+/* netdb function calls by prepending a "wrap_" name prefix
+/* to netdb function names, 2) the code of this module implements
+/* functions with "wrap_" name prefixes that forward redirected
+/* calls to the real netdb functions, while taking care of any
+/* necessary type incompatibilities, and 3) test mock functions
+/* use the "wrap_" prefixed function names instead of the netdb
+/* function names. Build with -DNO_MOCK_WRAPPERS to avoid
+/* this workaround.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <wrap_netdb.h>
+
+#ifndef NO_MOCK_WRAPPERS
+
+/* wrap_getaddrinfo - wrap getaddrinfo() with stable internal API */
+
+int wrap_getaddrinfo(const char *hostname, const char *servname,
+ const struct addrinfo *hints,
+ struct addrinfo **res)
+{
+#undef getaddrinfo
+ return (getaddrinfo(hostname, servname, hints, res));
+}
+
+/* wrap_freeaddrinfo - wrap freeaddrinfo() with stable internal API */
+
+void wrap_freeaddrinfo(struct addrinfo *ai)
+{
+#undef freeaddrinfo
+ freeaddrinfo(ai);
+}
+
+/* wrap_getnameinfo - wrap getnameinfo() with stable internal API */
+
+int wrap_getnameinfo(const struct sockaddr *sa, socklen_t salen,
+ char *host, size_t hostlen,
+ char *serv, size_t servlen, int flags)
+{
+#undef getnameinfo
+ return (getnameinfo(sa, salen, host, hostlen, serv, servlen, flags));
+}
+
+/* wrap_getservbyname - wrap getservbyname() with stable internal API */
+
+struct servent *wrap_getservbyname(const char *name, const char *proto)
+{
+#undef getservbyname
+ return (getservbyname(name, proto));
+}
+
+/* wrap_getservbyport - wrap getservbyport() with stable internal API */
+
+struct servent *wrap_getservbyport(int port, const char *proto)
+{
+#undef getservbyport
+ return (getservbyport(port, proto));
+}
+
+/* wrap_setservent - wrap setservent() with stable internal API */
+
+void wrap_setservent(int stayopen)
+{
+#undef setservent
+ return (setservent(stayopen));
+}
+
+/* wrap_endservent - wrap endservent() with stable internal API */
+
+void wrap_endservent(void)
+{
+#undef endservent
+ return (endservent());
+}
+
+#endif
--- /dev/null
+#ifndef _WRAP_NETDB_H_INCLUDED_
+#define _WRAP_NETDB_H_INCLUDED_
+
+/*++
+/* NAME
+/* wrap_netdb 3h
+/* SUMMARY
+/* mockable netdb wrappers
+/* SYNOPSIS
+/* #include <wrap_netdb.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * System library
+ */
+#include <sys_defs.h>
+#include <netdb.h>
+
+ /*
+ * External interface.
+ */
+#ifndef NO_MOCK_WRAPPERS
+extern int wrap_getaddrinfo(const char *, const char *,
+ const struct addrinfo *,
+ struct addrinfo **);
+extern void wrap_freeaddrinfo(struct addrinfo *);
+extern int wrap_getnameinfo(const struct sockaddr *, socklen_t, char *,
+ size_t, char *, size_t, int);
+
+#define getaddrinfo wrap_getaddrinfo
+#define freeaddrinfo wrap_freeaddrinfo
+#define getnameinfo wrap_getnameinfo
+
+extern struct servent *wrap_getservbyname(const char *, const char *);
+extern struct servent *wrap_getservbyport(int, const char *);
+extern void wrap_setservent(int);
+extern void wrap_endservent(void);
+
+#define getservbyname wrap_getservbyname
+#define getservbyport wrap_getservbyport
+#define setservent wrap_setservent
+#define endservent wrap_endservent
+#endif
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+#endif
xsasl_dovecot_server.o: ../../include/vstream.h
xsasl_dovecot_server.o: ../../include/vstring.h
xsasl_dovecot_server.o: ../../include/vstring_vstream.h
+xsasl_dovecot_server.o: ../../include/wrap_netdb.h
xsasl_dovecot_server.o: xsasl.h
xsasl_dovecot_server.o: xsasl_dovecot.h
xsasl_dovecot_server.o: xsasl_dovecot_server.c