summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am73
-rw-r--r--src/Makefile.in601
-rw-r--r--src/check.c405
-rw-r--r--src/check.h418
-rw-r--r--src/check.h.in418
-rw-r--r--src/check_error.c67
-rw-r--r--src/check_error.h33
-rw-r--r--src/check_impl.h117
-rw-r--r--src/check_list.c141
-rw-r--r--src/check_list.h56
-rw-r--r--src/check_log.c403
-rw-r--r--src/check_log.h51
-rw-r--r--src/check_msg.c200
-rw-r--r--src/check_msg.h36
-rw-r--r--src/check_pack.c426
-rw-r--r--src/check_pack.h76
-rw-r--r--src/check_print.c165
-rw-r--r--src/check_print.h30
-rw-r--r--src/check_run.c573
-rw-r--r--src/check_str.c132
-rw-r--r--src/check_str.h42
21 files changed, 4463 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..da781be
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,73 @@
+## Process this file with automake to produce Makefile.in
+
+lib_LTLIBRARIES = libcheck.la
+noinst_LTLIBRARIES = libcheckinternal.la
+
+include_HEADERS = check.h
+
+EXTRA_DIST = check.h.in
+
+AM_CFLAGS = @GCOV_CFLAGS@ @PTHREAD_CFLAGS@
+
+CFILES =\
+ check.c \
+ check_error.c \
+ check_list.c \
+ check_log.c \
+ check_msg.c \
+ check_pack.c \
+ check_print.c \
+ check_run.c \
+ check_str.c
+
+HFILES =\
+ check.h \
+ check_error.h \
+ check_impl.h \
+ check_list.h \
+ check_log.h \
+ check_msg.h \
+ check_pack.h \
+ check_print.h \
+ check_str.h
+
+
+EXPORT_SYM = exported.sym
+$(EXPORT_SYM): check.h.in
+ sed -n -e 's/^..*CK_EXPORT[[:space:]][[:space:]]*\([[:alnum:]_][[:alnum:]_]*\)..*$$/\1/p' @top_srcdir@/src/check.h.in > $@
+
+libcheck_la_DEPENDENCIES= $(EXPORT_SYM)
+libcheck_la_LDFLAGS = -no-undefined -export-symbols $(EXPORT_SYM)
+libcheck_la_SOURCES = $(CFILES) $(HFILES)
+libcheck_la_LIBADD = @GCOV_LIBS@ @PTHREAD_LIBS@ $(top_builddir)/lib/libcompat.la
+
+libcheckinternal_la_LDFLAGS = -no-undefined
+libcheckinternal_la_SOURCES = $(CFILES) $(HFILES)
+libcheckinternal_la_LIBADD = @GCOV_LIBS@ @PTHREAD_LIBS@ $(top_builddir)/lib/libcompat.la
+
+CLEANFILES = *~ *.gcno $(EXPORT_SYM)
+
+LCOV_INPUT = $(CFILES:%.c=.libs/%.gcda)
+LCOV_OUTPUT = lcov.info
+LCOV_HTML = lcov_html
+LCOV_LCOV = @LCOV@
+LCOV_GENHTML = @GENHTML@
+
+lcov: $(LCOV_HTML)
+
+$(LCOV_INPUT): libcheck.la libcheckinternal.la
+ @$(MAKE) -C $(top_builddir)/tests check
+
+$(LCOV_OUTPUT): $(LCOV_INPUT)
+ $(LCOV_LCOV) --capture --directory . --base-directory . --output-file $@
+
+$(LCOV_HTML): $(LCOV_OUTPUT)
+ -$(RM) -r $@
+ LANG=C $(LCOV_GENHTML) --output-directory $@ --title "Check Code Coverage" --show-details $<
+ @echo "Point a web browser at $(LCOV_HTML)/index.html to see results."
+
+clean-local: lcov-clean
+
+.PHONY: lcov-clean
+lcov-clean:
+ -$(RM) -r $(LCOV_HTML) $(LCOV_OUTPUT)
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 0000000..dfb1168
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,601 @@
+# Makefile.in generated by automake 1.10.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src
+DIST_COMMON = $(include_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in $(srcdir)/check.h.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acx_pthread.m4 \
+ $(top_srcdir)/m4/ax_c_check_flag.m4 \
+ $(top_srcdir)/m4/ax_cflags_warn_all_ansi.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES = check.h
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"
+libLTLIBRARIES_INSTALL = $(INSTALL)
+LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES)
+am__objects_1 = check.lo check_error.lo check_list.lo check_log.lo \
+ check_msg.lo check_pack.lo check_print.lo check_run.lo \
+ check_str.lo
+am__objects_2 =
+am_libcheck_la_OBJECTS = $(am__objects_1) $(am__objects_2)
+libcheck_la_OBJECTS = $(am_libcheck_la_OBJECTS)
+libcheck_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(libcheck_la_LDFLAGS) $(LDFLAGS) -o $@
+libcheckinternal_la_DEPENDENCIES = $(top_builddir)/lib/libcompat.la
+am_libcheckinternal_la_OBJECTS = $(am__objects_1) $(am__objects_2)
+libcheckinternal_la_OBJECTS = $(am_libcheckinternal_la_OBJECTS)
+libcheckinternal_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(libcheckinternal_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(libcheck_la_SOURCES) $(libcheckinternal_la_SOURCES)
+DIST_SOURCES = $(libcheck_la_SOURCES) $(libcheckinternal_la_SOURCES)
+includeHEADERS_INSTALL = $(INSTALL_HEADER)
+HEADERS = $(include_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CHECK_MAJOR_VERSION = @CHECK_MAJOR_VERSION@
+CHECK_MICRO_VERSION = @CHECK_MICRO_VERSION@
+CHECK_MINOR_VERSION = @CHECK_MINOR_VERSION@
+CHECK_VERSION = @CHECK_VERSION@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_SUBUNIT = @ENABLE_SUBUNIT@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCOV = @GCOV@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_LIBS = @GCOV_LIBS@
+GENHTML = @GENHTML@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LCOV = @LCOV@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TEX = @TEX@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+acx_pthread_config = @acx_pthread_config@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+lt_ECHO = @lt_ECHO@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+lib_LTLIBRARIES = libcheck.la
+noinst_LTLIBRARIES = libcheckinternal.la
+include_HEADERS = check.h
+EXTRA_DIST = check.h.in
+AM_CFLAGS = @GCOV_CFLAGS@ @PTHREAD_CFLAGS@
+CFILES = \
+ check.c \
+ check_error.c \
+ check_list.c \
+ check_log.c \
+ check_msg.c \
+ check_pack.c \
+ check_print.c \
+ check_run.c \
+ check_str.c
+
+HFILES = \
+ check.h \
+ check_error.h \
+ check_impl.h \
+ check_list.h \
+ check_log.h \
+ check_msg.h \
+ check_pack.h \
+ check_print.h \
+ check_str.h
+
+EXPORT_SYM = exported.sym
+libcheck_la_DEPENDENCIES = $(EXPORT_SYM)
+libcheck_la_LDFLAGS = -no-undefined -export-symbols $(EXPORT_SYM)
+libcheck_la_SOURCES = $(CFILES) $(HFILES)
+libcheck_la_LIBADD = @GCOV_LIBS@ @PTHREAD_LIBS@ $(top_builddir)/lib/libcompat.la
+libcheckinternal_la_LDFLAGS = -no-undefined
+libcheckinternal_la_SOURCES = $(CFILES) $(HFILES)
+libcheckinternal_la_LIBADD = @GCOV_LIBS@ @PTHREAD_LIBS@ $(top_builddir)/lib/libcompat.la
+CLEANFILES = *~ *.gcno $(EXPORT_SYM)
+LCOV_INPUT = $(CFILES:%.c=.libs/%.gcda)
+LCOV_OUTPUT = lcov.info
+LCOV_HTML = lcov_html
+LCOV_LCOV = @LCOV@
+LCOV_GENHTML = @GENHTML@
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnits src/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnits src/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+check.h: $(top_builddir)/config.status $(srcdir)/check.h.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ if test -f $$p; then \
+ f=$(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \
+ else :; fi; \
+ done
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ p=$(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libcheck.la: $(libcheck_la_OBJECTS) $(libcheck_la_DEPENDENCIES)
+ $(libcheck_la_LINK) -rpath $(libdir) $(libcheck_la_OBJECTS) $(libcheck_la_LIBADD) $(LIBS)
+libcheckinternal.la: $(libcheckinternal_la_OBJECTS) $(libcheckinternal_la_DEPENDENCIES)
+ $(libcheckinternal_la_LINK) $(libcheckinternal_la_OBJECTS) $(libcheckinternal_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_error.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_list.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_log.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_msg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_pack.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_print.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_run.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_str.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-includeHEADERS: $(include_HEADERS)
+ @$(NORMAL_INSTALL)
+ test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)"
+ @list='$(include_HEADERS)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f=$(am__strip_dir) \
+ echo " $(includeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(includedir)/$$f'"; \
+ $(includeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(includedir)/$$f"; \
+ done
+
+uninstall-includeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(include_HEADERS)'; for p in $$list; do \
+ f=$(am__strip_dir) \
+ echo " rm -f '$(DESTDIR)$(includedir)/$$f'"; \
+ rm -f "$(DESTDIR)$(includedir)/$$f"; \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool clean-local \
+ clean-noinstLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-includeHEADERS
+
+install-dvi: install-dvi-am
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libLTLIBRARIES clean-libtool clean-local \
+ clean-noinstLTLIBRARIES ctags distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-includeHEADERS install-info install-info-am \
+ install-libLTLIBRARIES install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-includeHEADERS \
+ uninstall-libLTLIBRARIES
+
+$(EXPORT_SYM): check.h.in
+ sed -n -e 's/^..*CK_EXPORT[[:space:]][[:space:]]*\([[:alnum:]_][[:alnum:]_]*\)..*$$/\1/p' @top_srcdir@/src/check.h.in > $@
+
+lcov: $(LCOV_HTML)
+
+$(LCOV_INPUT): libcheck.la libcheckinternal.la
+ @$(MAKE) -C $(top_builddir)/tests check
+
+$(LCOV_OUTPUT): $(LCOV_INPUT)
+ $(LCOV_LCOV) --capture --directory . --base-directory . --output-file $@
+
+$(LCOV_HTML): $(LCOV_OUTPUT)
+ -$(RM) -r $@
+ LANG=C $(LCOV_GENHTML) --output-directory $@ --title "Check Code Coverage" --show-details $<
+ @echo "Point a web browser at $(LCOV_HTML)/index.html to see results."
+
+clean-local: lcov-clean
+
+.PHONY: lcov-clean
+lcov-clean:
+ -$(RM) -r $(LCOV_HTML) $(LCOV_OUTPUT)
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/check.c b/src/check.c
new file mode 100644
index 0000000..41b9e79
--- /dev/null
+++ b/src/check.c
@@ -0,0 +1,405 @@
+/*
+ * Check: a unit test framework for C
+ * Copyright (C) 2001, 2002 Arien Malec
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "../lib/libcompat.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "check.h"
+#include "check_error.h"
+#include "check_list.h"
+#include "check_impl.h"
+#include "check_msg.h"
+
+#ifndef DEFAULT_TIMEOUT
+#define DEFAULT_TIMEOUT 4
+#endif
+
+int check_major_version = CHECK_MAJOR_VERSION;
+int check_minor_version = CHECK_MINOR_VERSION;
+int check_micro_version = CHECK_MICRO_VERSION;
+
+static int non_pass (int val);
+static Fixture *fixture_create (SFun fun, int ischecked);
+static void tcase_add_fixture (TCase *tc, SFun setup, SFun teardown,
+ int ischecked);
+static void tr_init (TestResult *tr);
+static void suite_free (Suite *s);
+static void tcase_free (TCase *tc);
+
+Suite *suite_create (const char *name)
+{
+ Suite *s;
+ s = emalloc (sizeof(Suite)); /* freed in suite_free */
+ if (name == NULL)
+ s->name = "";
+ else
+ s->name = name;
+ s->tclst = check_list_create();
+ return s;
+}
+
+static void suite_free (Suite *s)
+{
+ List *l;
+ if (s == NULL)
+ return;
+ l = s->tclst;
+ for (list_front(l); !list_at_end(l); list_advance (l)) {
+ tcase_free (list_val(l));
+ }
+ list_free (s->tclst);
+ free(s);
+}
+
+TCase *tcase_create (const char *name)
+{
+ char *env;
+ int timeout = DEFAULT_TIMEOUT;
+ TCase *tc = emalloc (sizeof(TCase)); /*freed in tcase_free */
+ if (name == NULL)
+ tc->name = "";
+ else
+ tc->name = name;
+
+ env = getenv("CK_DEFAULT_TIMEOUT");
+ if (env != NULL) {
+ int tmp = atoi(env);
+ if (tmp >= 0) {
+ timeout = tmp;
+ }
+ }
+
+ env = getenv("CK_TIMEOUT_MULTIPLIER");
+ if (env != NULL) {
+ int tmp = atoi(env);
+ if (tmp >= 0) {
+ timeout = timeout * tmp;
+ }
+ }
+
+ tc->timeout = timeout;
+ tc->tflst = check_list_create();
+ tc->unch_sflst = check_list_create();
+ tc->ch_sflst = check_list_create();
+ tc->unch_tflst = check_list_create();
+ tc->ch_tflst = check_list_create();
+
+ return tc;
+}
+
+
+static void tcase_free (TCase *tc)
+{
+ list_apply (tc->tflst, free);
+ list_apply (tc->unch_sflst, free);
+ list_apply (tc->ch_sflst, free);
+ list_apply (tc->unch_tflst, free);
+ list_apply (tc->ch_tflst, free);
+ list_free(tc->tflst);
+ list_free(tc->unch_sflst);
+ list_free(tc->ch_sflst);
+ list_free(tc->unch_tflst);
+ list_free(tc->ch_tflst);
+
+ free(tc);
+}
+
+void suite_add_tcase (Suite *s, TCase *tc)
+{
+ if (s == NULL || tc == NULL)
+ return;
+ list_add_end (s->tclst, tc);
+}
+
+void _tcase_add_test (TCase *tc, TFun fn, const char *name, int _signal, int allowed_exit_value, int start, int end)
+{
+ TF * tf;
+ if (tc == NULL || fn == NULL || name == NULL)
+ return;
+ tf = emalloc (sizeof(TF)); /* freed in tcase_free */
+ tf->fn = fn;
+ tf->loop_start = start;
+ tf->loop_end = end;
+ tf->signal = _signal; /* 0 means no signal expected */
+ tf->allowed_exit_value = allowed_exit_value; /* 0 is default successful exit */
+ tf->name = name;
+ list_add_end (tc->tflst, tf);
+}
+
+static Fixture *fixture_create (SFun fun, int ischecked)
+{
+ Fixture *f;
+ f = emalloc (sizeof(Fixture));
+ f->fun = fun;
+ f->ischecked = ischecked;
+
+ return f;
+}
+
+void tcase_add_unchecked_fixture (TCase *tc, SFun setup, SFun teardown)
+{
+ tcase_add_fixture(tc,setup,teardown,0);
+}
+
+void tcase_add_checked_fixture (TCase *tc, SFun setup, SFun teardown)
+{
+ tcase_add_fixture (tc,setup,teardown,1);
+}
+
+static void tcase_add_fixture (TCase *tc, SFun setup, SFun teardown,
+ int ischecked)
+{
+ if (setup) {
+ if (ischecked)
+ list_add_end (tc->ch_sflst, fixture_create(setup, ischecked));
+ else
+ list_add_end (tc->unch_sflst, fixture_create(setup, ischecked));
+ }
+
+ /* Add teardowns at front so they are run in reverse order. */
+ if (teardown) {
+ if (ischecked)
+ list_add_front (tc->ch_tflst, fixture_create(teardown, ischecked));
+ else
+ list_add_front (tc->unch_tflst, fixture_create(teardown, ischecked));
+ }
+}
+
+void tcase_set_timeout (TCase *tc, int timeout)
+{
+ if (timeout >= 0) {
+ char *env = getenv("CK_TIMEOUT_MULTIPLIER");
+ if (env != NULL) {
+ int tmp = atoi(env);
+ if (tmp >= 0) {
+ timeout = timeout * tmp;
+ }
+ }
+ tc->timeout = timeout;
+ }
+}
+
+void tcase_fn_start (const char *fname CK_ATTRIBUTE_UNUSED, const char *file, int line)
+{
+ send_ctx_info (CK_CTX_TEST);
+ send_loc_info (file, line);
+}
+
+void _mark_point (const char *file, int line)
+{
+ send_loc_info (file, line);
+}
+
+void _fail_unless (int result, const char *file,
+ int line, const char *expr, ...)
+{
+ const char *msg;
+
+ send_loc_info (file, line);
+ if (!result) {
+ va_list ap;
+ char buf[BUFSIZ];
+
+ va_start(ap,expr);
+ msg = (const char*)va_arg(ap, char *);
+ if (msg == NULL)
+ msg = expr;
+ vsnprintf(buf, BUFSIZ, msg, ap);
+ va_end(ap);
+ send_failure_info (buf);
+ if (cur_fork_status() == CK_FORK) {
+#ifdef _POSIX_VERSION
+ exit(1);
+#endif /* _POSIX_VERSION */
+ }
+ }
+}
+
+SRunner *srunner_create (Suite *s)
+{
+ SRunner *sr = emalloc (sizeof(SRunner)); /* freed in srunner_free */
+ sr->slst = check_list_create();
+ if (s != NULL)
+ list_add_end(sr->slst, s);
+ sr->stats = emalloc (sizeof(TestStats)); /* freed in srunner_free */
+ sr->stats->n_checked = sr->stats->n_failed = sr->stats->n_errors = 0;
+ sr->resultlst = check_list_create();
+ sr->log_fname = NULL;
+ sr->xml_fname = NULL;
+ sr->loglst = NULL;
+ sr->fstat = CK_FORK_GETENV;
+ return sr;
+}
+
+void srunner_add_suite (SRunner *sr, Suite *s)
+{
+ if (s == NULL)
+ return;
+
+ list_add_end(sr->slst, s);
+}
+
+void srunner_free (SRunner *sr)
+{
+ List *l;
+ TestResult *tr;
+ if (sr == NULL)
+ return;
+
+ free (sr->stats);
+ l = sr->slst;
+ for (list_front(l); !list_at_end(l); list_advance(l)) {
+ suite_free(list_val(l));
+ }
+ list_free(sr->slst);
+
+ l = sr->resultlst;
+ for (list_front(l); !list_at_end(l); list_advance(l)) {
+ tr = list_val(l);
+ free(tr->file);
+ free(tr->msg);
+ free(tr);
+ }
+ list_free (sr->resultlst);
+
+ free (sr);
+}
+
+int srunner_ntests_failed (SRunner *sr)
+{
+ return sr->stats->n_failed + sr->stats->n_errors;
+}
+
+int srunner_ntests_run (SRunner *sr)
+{
+ return sr->stats->n_checked;
+}
+
+TestResult **srunner_failures (SRunner *sr)
+{
+ int i = 0;
+ TestResult **trarray;
+ List *rlst;
+ trarray = malloc (sizeof(trarray[0]) * srunner_ntests_failed (sr));
+
+ rlst = sr->resultlst;
+ for (list_front(rlst); !list_at_end(rlst); list_advance(rlst)) {
+ TestResult *tr = list_val(rlst);
+ if (non_pass(tr->rtype))
+ trarray[i++] = tr;
+
+ }
+ return trarray;
+}
+
+TestResult **srunner_results (SRunner *sr)
+{
+ int i = 0;
+ TestResult **trarray;
+ List *rlst;
+
+ trarray = malloc (sizeof(trarray[0]) * srunner_ntests_run (sr));
+
+ rlst = sr->resultlst;
+ for (list_front(rlst); !list_at_end(rlst); list_advance(rlst)) {
+ trarray[i++] = list_val(rlst);
+ }
+ return trarray;
+}
+
+static int non_pass (int val)
+{
+ return val != CK_PASS;
+}
+
+TestResult *tr_create(void)
+{
+ TestResult *tr;
+
+ tr = emalloc (sizeof(TestResult));
+ tr_init (tr);
+ return tr;
+}
+
+void tr_reset(TestResult *tr)
+{
+ tr_init(tr);
+}
+
+static void tr_init (TestResult *tr)
+{
+ tr->ctx = CK_CTX_INVALID;
+ tr->line = -1;
+ tr->rtype = CK_TEST_RESULT_INVALID;
+ tr->msg = NULL;
+ tr->file = NULL;
+ tr->tcname = NULL;
+ tr->tname = NULL;
+}
+
+
+const char *tr_msg (TestResult *tr)
+{
+ return tr->msg;
+}
+
+int tr_lno (TestResult *tr)
+{
+ return tr->line;
+}
+
+const char *tr_lfile (TestResult *tr)
+{
+ return tr->file;
+}
+
+int tr_rtype (TestResult *tr)
+{
+ return tr->rtype;
+}
+
+enum ck_result_ctx tr_ctx (TestResult *tr)
+{
+ return tr->ctx;
+}
+
+const char *tr_tcname (TestResult *tr)
+{
+ return tr->tcname;
+}
+
+static int _fstat = CK_FORK;
+
+void set_fork_status (enum fork_status fstat)
+{
+ if (fstat == CK_FORK || fstat == CK_NOFORK || fstat == CK_FORK_GETENV)
+ _fstat = fstat;
+ else
+ eprintf ("Bad status in set_fork_status", __FILE__, __LINE__);
+}
+
+enum fork_status cur_fork_status (void)
+{
+ return _fstat;
+}
diff --git a/src/check.h b/src/check.h
new file mode 100644
index 0000000..afb42f6
--- /dev/null
+++ b/src/check.h
@@ -0,0 +1,418 @@
+/*-*- mode:C; -*- */
+/*
+ * Check: a unit test framework for C
+ * Copyright (C) 2001, 2002, Arien Malec
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef CHECK_H
+#define CHECK_H
+
+#include <stddef.h>
+#include <string.h>
+
+/* Check: a unit test framework for C
+
+ Check is a unit test framework for C. It features a simple
+ interface for defining unit tests, putting little in the way of the
+ developer. Tests are run in a separate address space, so Check can
+ catch both assertion failures and code errors that cause
+ segmentation faults or other signals. The output from unit tests
+ can be used within source code editors and IDEs.
+
+ Unit tests are created with the START_TEST/END_TEST macro
+ pair. The fail_unless and fail macros are used for creating
+ checks within unit tests; the mark_point macro is useful for
+ trapping the location of signals and/or early exits.
+
+
+ Test cases are created with tcase_create, unit tests are added
+ with tcase_add_test
+
+
+ Suites are created with suite_create; test cases are added
+ with suite_add_tcase
+
+ Suites are run through an SRunner, which is created with
+ srunner_create. Additional suites can be added to an SRunner with
+ srunner_add_suite. An SRunner is freed with srunner_free, which also
+ frees all suites added to the runner.
+
+ Use srunner_run_all to run a suite and print results.
+
+ Macros and functions starting with _ (underscore) are internal and
+ may change without notice. You have been warned!.
+
+*/
+
+
+#ifdef __cplusplus
+#define CK_CPPSTART extern "C" {
+#define CK_CPPEND }
+CK_CPPSTART
+#endif
+
+#if defined(__GNUC__) && defined(__GNUC_MINOR__)
+#define GCC_VERSION_AT_LEAST(major, minor) \
+((__GNUC__ > (major)) || \
+ (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)))
+#else
+#define GCC_VERSION_AT_LEAST(major, minor) 0
+#endif
+
+#if GCC_VERSION_AT_LEAST(2,95)
+#define CK_ATTRIBUTE_UNUSED __attribute__ ((unused))
+#else
+#define CK_ATTRIBUTE_UNUSED
+#endif /* GCC 2.95 */
+
+#include <sys/types.h>
+
+/* Used to create the linker script for hiding lib-local symbols. Shall
+ be put directly in front of the exported symbol. */
+#define CK_EXPORT
+
+/* check version numbers */
+
+#define CHECK_MAJOR_VERSION (0)
+#define CHECK_MINOR_VERSION (9)
+#define CHECK_MICRO_VERSION (8)
+
+extern int CK_EXPORT check_major_version;
+extern int CK_EXPORT check_minor_version;
+extern int CK_EXPORT check_micro_version;
+
+#ifndef NULL
+#define NULL ((void*)0)
+#endif
+
+/* opaque type for a test case
+
+ A TCase represents a test case. Create with tcase_create, free
+ with tcase_free. For the moment, test cases can only be run
+ through a suite
+*/
+typedef struct TCase TCase;
+
+/* type for a test function */
+typedef void (*TFun) (int);
+
+/* type for a setup/teardown function */
+typedef void (*SFun) (void);
+
+/* Opaque type for a test suite */
+typedef struct Suite Suite;
+
+/* Creates a test suite with the given name */
+Suite * CK_EXPORT suite_create (const char *name);
+
+/* Add a test case to a suite */
+void CK_EXPORT suite_add_tcase (Suite *s, TCase *tc);
+
+/* Create a test case */
+TCase * CK_EXPORT tcase_create (const char *name);
+
+/* Add a test function to a test case (macro version) */
+#define tcase_add_test(tc,tf) tcase_add_test_raise_signal(tc,tf,0)
+
+/* Add a test function with signal handling to a test case (macro version) */
+#define tcase_add_test_raise_signal(tc,tf,signal) \
+ _tcase_add_test((tc),(tf),"" # tf "",(signal), 0, 0, 1)
+
+/* Add a test function with an expected exit value to a test case (macro version) */
+#define tcase_add_exit_test(tc, tf, expected_exit_value) \
+ _tcase_add_test((tc),(tf),"" # tf "",0,(expected_exit_value),0,1)
+
+/* Add a looping test function to a test case (macro version)
+
+ The test will be called in a for(i = s; i < e; i++) loop with each
+ iteration being executed in a new context. The loop variable 'i' is
+ available in the test.
+ */
+#define tcase_add_loop_test(tc,tf,s,e) \
+ _tcase_add_test((tc),(tf),"" # tf "",0,0,(s),(e))
+
+/* Signal version of loop test.
+ FIXME: add a test case; this is untested as part of Check's tests.
+ */
+#define tcase_add_loop_test_raise_signal(tc,tf,signal,s,e) \
+ _tcase_add_test((tc),(tf),"" # tf "",(signal),0,(s),(e))
+
+/* allowed exit value version of loop test. */
+#define tcase_add_loop_exit_test(tc,tf,expected_exit_value,s,e) \
+ _tcase_add_test((tc),(tf),"" # tf "",0,(expected_exit_value),(s),(e))
+
+/* Add a test function to a test case
+ (function version -- use this when the macro won't work
+*/
+void CK_EXPORT _tcase_add_test (TCase *tc, TFun tf, const char *fname, int _signal, int allowed_exit_value, int start, int end);
+
+/* Add unchecked fixture setup/teardown functions to a test case
+
+ If unchecked fixture functions are run at the start and end of the
+ test case, and not before and after unit tests. Note that unchecked
+ setup/teardown functions are not run in a separate address space,
+ like test functions, and so must not exit or signal (e.g.,
+ segfault)
+
+ Also, when run in CK_NOFORK mode, unchecked fixture functions may
+ lead to different unit test behavior IF unit tests change data
+ setup by the fixture functions.
+*/
+void CK_EXPORT tcase_add_unchecked_fixture (TCase *tc, SFun setup, SFun teardown);
+
+/* Add fixture setup/teardown functions to a test case
+
+ Checked fixture functions are run before and after unit
+ tests. Unlike unchecked fixture functions, checked fixture
+ functions are run in the same separate address space as the test
+ program, and thus the test function will survive signals or
+ unexpected exits in the fixture function. Also, IF the setup
+ function is idempotent, unit test behavior will be the same in
+ CK_FORK and CK_NOFORK modes.
+
+ However, since fixture functions are run before and after each unit
+ test, they should not be expensive code.
+
+*/
+void CK_EXPORT tcase_add_checked_fixture (TCase *tc, SFun setup, SFun teardown);
+
+/* Set the timeout for all tests in a test case. A test that lasts longer
+ than the timeout (in seconds) will be killed and thus fail with an error.
+ The timeout can also be set globaly with the environment variable
+ CK_DEFAULT_TIMEOUT, the specific setting always takes precedence.
+*/
+void CK_EXPORT tcase_set_timeout (TCase *tc, int timeout);
+
+/* Internal function to mark the start of a test function */
+void CK_EXPORT tcase_fn_start (const char *fname, const char *file, int line);
+
+/* Start a unit test with START_TEST(unit_name), end with END_TEST
+ One must use braces within a START_/END_ pair to declare new variables
+*/
+#define START_TEST(__testname)\
+static void __testname (int _i CK_ATTRIBUTE_UNUSED)\
+{\
+ tcase_fn_start (""# __testname, __FILE__, __LINE__);
+
+/* End a unit test */
+#define END_TEST }
+
+/* Fail the test case unless expr is true */
+/* The space before the comma sign before ## is essential to be compatible
+ with gcc 2.95.3 and earlier.
+*/
+#define fail_unless(expr, ...)\
+ _fail_unless(expr, __FILE__, __LINE__,\
+ "Assertion '"#expr"' failed" , ## __VA_ARGS__, NULL)
+
+/* Fail the test case if expr is true */
+/* The space before the comma sign before ## is essential to be compatible
+ with gcc 2.95.3 and earlier.
+*/
+
+/* FIXME: these macros may conflict with C89 if expr is
+ FIXME: strcmp (str1, str2) due to excessive string length. */
+#define fail_if(expr, ...)\
+ _fail_unless(!(expr), __FILE__, __LINE__,\
+ "Failure '"#expr"' occured" , ## __VA_ARGS__, NULL)
+
+/* Always fail */
+#define fail(...) _fail_unless(0, __FILE__, __LINE__, "Failed" , ## __VA_ARGS__, NULL)
+
+/* Non macro version of #fail_unless, with more complicated interface */
+void CK_EXPORT _fail_unless (int result, const char *file,
+ int line, const char *expr, ...);
+
+/* New check fail API. */
+#define ck_abort() ck_abort_msg(NULL)
+#define ck_abort_msg fail
+#define ck_assert(C) ck_assert_msg(C, NULL)
+#define ck_assert_msg fail_unless
+
+/* Integer comparsion macros with improved output compared to fail_unless(). */
+/* O may be any comparion operator. */
+#define _ck_assert_int(X, O, Y) ck_assert_msg((X) O (Y), "Assertion '"#X#O#Y"' failed: "#X"==%d, "#Y"==%d", X, Y)
+#define ck_assert_int_eq(X, Y) _ck_assert_int(X, ==, Y)
+#define ck_assert_int_ne(X, Y) _ck_assert_int(X, !=, Y)
+
+/* String comparsion macros with improved output compared to fail_unless() */
+#define _ck_assert_str(C, X, O, Y) ck_assert_msg(C, "Assertion '"#X#O#Y"' failed: "#X"==\"%s\", "#Y"==\"%s\"", X, Y)
+#define ck_assert_str_eq(X, Y) _ck_assert_str(!strcmp(X, Y), X, ==, Y)
+#define ck_assert_str_ne(X, Y) _ck_assert_str(strcmp(X, Y), X, !=, Y)
+
+
+/* Mark the last point reached in a unit test
+ (useful for tracking down where a segfault, etc. occurs)
+*/
+#define mark_point() _mark_point(__FILE__,__LINE__)
+
+/* Non macro version of #mark_point */
+void CK_EXPORT _mark_point (const char *file, int line);
+
+/* Result of a test */
+enum test_result {
+ CK_TEST_RESULT_INVALID, /* Default value; should not encounter this */
+ CK_PASS, /* Test passed*/
+ CK_FAILURE, /* Test completed but failed */
+ CK_ERROR /* Test failed to complete
+ (unexpected signal or non-zero early exit) */
+};
+
+/* Specifies the how much output an SRunner should produce */
+enum print_output {
+ CK_SILENT, /* No output */
+ CK_MINIMAL, /* Only summary output */
+ CK_NORMAL, /* All failed tests */
+ CK_VERBOSE, /* All tests */
+ CK_ENV, /* Look at environment var */
+#if 0
+ CK_SUBUNIT, /* Run as a subunit child process */
+#endif
+ CK_LAST
+};
+
+/* Holds state for a running of a test suite */
+typedef struct SRunner SRunner;
+
+/* Opaque type for a test failure */
+typedef struct TestResult TestResult;
+
+/* accessors for tr fields */
+enum ck_result_ctx {
+ CK_CTX_INVALID, /* Default value; should not encounter this */
+ CK_CTX_SETUP,
+ CK_CTX_TEST,
+ CK_CTX_TEARDOWN
+};
+
+/* Type of result */
+int CK_EXPORT tr_rtype (TestResult *tr);
+/* Context in which the result occurred */
+enum ck_result_ctx CK_EXPORT tr_ctx (TestResult *tr);
+/* Failure message */
+const char * CK_EXPORT tr_msg (TestResult *tr);
+/* Line number at which failure occured */
+int CK_EXPORT tr_lno (TestResult *tr);
+/* File name at which failure occured */
+const char * CK_EXPORT tr_lfile (TestResult *tr);
+/* Test case in which unit test was run */
+const char * CK_EXPORT tr_tcname (TestResult *tr);
+
+/* Creates an SRunner for the given suite */
+SRunner * CK_EXPORT srunner_create (Suite *s);
+
+/* Adds a Suite to an SRunner */
+void CK_EXPORT srunner_add_suite (SRunner *sr, Suite *s);
+
+/* Frees an SRunner, all suites added to it and all contained test cases */
+void CK_EXPORT srunner_free (SRunner *sr);
+
+
+/* Test running */
+
+/* Runs an SRunner, printing results as specified (see enum print_output) */
+void CK_EXPORT srunner_run_all (SRunner *sr, enum print_output print_mode);
+
+
+/* Next functions are valid only after the suite has been
+ completely run, of course */
+
+/* Number of failed tests in a run suite. Includes failures + errors */
+int CK_EXPORT srunner_ntests_failed (SRunner *sr);
+
+/* Total number of tests run in a run suite */
+int CK_EXPORT srunner_ntests_run (SRunner *sr);
+
+/* Return an array of results for all failures
+
+ Number of failures is equal to srunner_nfailed_tests. Memory for
+ the array is malloc'ed and must be freed, but individual TestResults
+ must not
+*/
+TestResult ** CK_EXPORT srunner_failures (SRunner *sr);
+
+/* Return an array of results for all run tests
+
+ Number of results is equal to srunner_ntests_run, and excludes
+ failures due to setup function failure.
+
+ Memory is malloc'ed and must be freed, but individual TestResults
+ must not
+*/
+TestResult ** CK_EXPORT srunner_results (SRunner *sr);
+
+
+/* Printing */
+
+/* Print the results contained in an SRunner */
+void CK_EXPORT srunner_print (SRunner *sr, enum print_output print_mode);
+
+
+/* Set a log file to which to write during test running.
+
+ Log file setting is an initialize only operation -- it should be
+ done immediatly after SRunner creation, and the log file can't be
+ changed after being set.
+*/
+void CK_EXPORT srunner_set_log (SRunner *sr, const char *fname);
+
+/* Does the SRunner have a log file? */
+int CK_EXPORT srunner_has_log (SRunner *sr);
+
+/* Return the name of the log file, or NULL if none */
+const char * CK_EXPORT srunner_log_fname (SRunner *sr);
+
+/* Set a xml file to which to write during test running.
+
+ XML file setting is an initialize only operation -- it should be
+ done immediatly after SRunner creation, and the XML file can't be
+ changed after being set.
+*/
+void CK_EXPORT srunner_set_xml (SRunner *sr, const char *fname);
+
+/* Does the SRunner have an XML log file? */
+int CK_EXPORT srunner_has_xml (SRunner *sr);
+
+/* Return the name of the XML file, or NULL if none */
+const char * CK_EXPORT srunner_xml_fname (SRunner *sr);
+
+
+/* Control forking */
+enum fork_status {
+ CK_FORK_GETENV, /* look in the environment for CK_FORK */
+ CK_FORK, /* call fork to run tests */
+ CK_NOFORK /* don't call fork */
+};
+
+/* Get the current fork status */
+enum fork_status CK_EXPORT srunner_fork_status (SRunner *sr);
+
+/* Set the current fork status */
+void CK_EXPORT srunner_set_fork_status (SRunner *sr, enum fork_status fstat);
+
+/* Fork in a test and make sure messaging and tests work. */
+pid_t CK_EXPORT check_fork(void);
+
+/* Wait for the pid and exit. If pid is zero, just exit. */
+void CK_EXPORT check_waitpid_and_exit(pid_t pid);
+
+#ifdef __cplusplus
+CK_CPPEND
+#endif
+
+#endif /* CHECK_H */
diff --git a/src/check.h.in b/src/check.h.in
new file mode 100644
index 0000000..231fdbb
--- /dev/null
+++ b/src/check.h.in
@@ -0,0 +1,418 @@
+/*-*- mode:C; -*- */
+/*
+ * Check: a unit test framework for C
+ * Copyright (C) 2001, 2002, Arien Malec
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef CHECK_H
+#define CHECK_H
+
+#include <stddef.h>
+#include <string.h>
+
+/* Check: a unit test framework for C
+
+ Check is a unit test framework for C. It features a simple
+ interface for defining unit tests, putting little in the way of the
+ developer. Tests are run in a separate address space, so Check can
+ catch both assertion failures and code errors that cause
+ segmentation faults or other signals. The output from unit tests
+ can be used within source code editors and IDEs.
+
+ Unit tests are created with the START_TEST/END_TEST macro
+ pair. The fail_unless and fail macros are used for creating
+ checks within unit tests; the mark_point macro is useful for
+ trapping the location of signals and/or early exits.
+
+
+ Test cases are created with tcase_create, unit tests are added
+ with tcase_add_test
+
+
+ Suites are created with suite_create; test cases are added
+ with suite_add_tcase
+
+ Suites are run through an SRunner, which is created with
+ srunner_create. Additional suites can be added to an SRunner with
+ srunner_add_suite. An SRunner is freed with srunner_free, which also
+ frees all suites added to the runner.
+
+ Use srunner_run_all to run a suite and print results.
+
+ Macros and functions starting with _ (underscore) are internal and
+ may change without notice. You have been warned!.
+
+*/
+
+
+#ifdef __cplusplus
+#define CK_CPPSTART extern "C" {
+#define CK_CPPEND }
+CK_CPPSTART
+#endif
+
+#if defined(__GNUC__) && defined(__GNUC_MINOR__)
+#define GCC_VERSION_AT_LEAST(major, minor) \
+((__GNUC__ > (major)) || \
+ (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)))
+#else
+#define GCC_VERSION_AT_LEAST(major, minor) 0
+#endif
+
+#if GCC_VERSION_AT_LEAST(2,95)
+#define CK_ATTRIBUTE_UNUSED __attribute__ ((unused))
+#else
+#define CK_ATTRIBUTE_UNUSED
+#endif /* GCC 2.95 */
+
+#include <sys/types.h>
+
+/* Used to create the linker script for hiding lib-local symbols. Shall
+ be put directly in front of the exported symbol. */
+#define CK_EXPORT
+
+/* check version numbers */
+
+#define CHECK_MAJOR_VERSION (@CHECK_MAJOR_VERSION@)
+#define CHECK_MINOR_VERSION (@CHECK_MINOR_VERSION@)
+#define CHECK_MICRO_VERSION (@CHECK_MICRO_VERSION@)
+
+extern int CK_EXPORT check_major_version;
+extern int CK_EXPORT check_minor_version;
+extern int CK_EXPORT check_micro_version;
+
+#ifndef NULL
+#define NULL ((void*)0)
+#endif
+
+/* opaque type for a test case
+
+ A TCase represents a test case. Create with tcase_create, free
+ with tcase_free. For the moment, test cases can only be run
+ through a suite
+*/
+typedef struct TCase TCase;
+
+/* type for a test function */
+typedef void (*TFun) (int);
+
+/* type for a setup/teardown function */
+typedef void (*SFun) (void);
+
+/* Opaque type for a test suite */
+typedef struct Suite Suite;
+
+/* Creates a test suite with the given name */
+Suite * CK_EXPORT suite_create (const char *name);
+
+/* Add a test case to a suite */
+void CK_EXPORT suite_add_tcase (Suite *s, TCase *tc);
+
+/* Create a test case */
+TCase * CK_EXPORT tcase_create (const char *name);
+
+/* Add a test function to a test case (macro version) */
+#define tcase_add_test(tc,tf) tcase_add_test_raise_signal(tc,tf,0)
+
+/* Add a test function with signal handling to a test case (macro version) */
+#define tcase_add_test_raise_signal(tc,tf,signal) \
+ _tcase_add_test((tc),(tf),"" # tf "",(signal), 0, 0, 1)
+
+/* Add a test function with an expected exit value to a test case (macro version) */
+#define tcase_add_exit_test(tc, tf, expected_exit_value) \
+ _tcase_add_test((tc),(tf),"" # tf "",0,(expected_exit_value),0,1)
+
+/* Add a looping test function to a test case (macro version)
+
+ The test will be called in a for(i = s; i < e; i++) loop with each
+ iteration being executed in a new context. The loop variable 'i' is
+ available in the test.
+ */
+#define tcase_add_loop_test(tc,tf,s,e) \
+ _tcase_add_test((tc),(tf),"" # tf "",0,0,(s),(e))
+
+/* Signal version of loop test.
+ FIXME: add a test case; this is untested as part of Check's tests.
+ */
+#define tcase_add_loop_test_raise_signal(tc,tf,signal,s,e) \
+ _tcase_add_test((tc),(tf),"" # tf "",(signal),0,(s),(e))
+
+/* allowed exit value version of loop test. */
+#define tcase_add_loop_exit_test(tc,tf,expected_exit_value,s,e) \
+ _tcase_add_test((tc),(tf),"" # tf "",0,(expected_exit_value),(s),(e))
+
+/* Add a test function to a test case
+ (function version -- use this when the macro won't work
+*/
+void CK_EXPORT _tcase_add_test (TCase *tc, TFun tf, const char *fname, int _signal, int allowed_exit_value, int start, int end);
+
+/* Add unchecked fixture setup/teardown functions to a test case
+
+ If unchecked fixture functions are run at the start and end of the
+ test case, and not before and after unit tests. Note that unchecked
+ setup/teardown functions are not run in a separate address space,
+ like test functions, and so must not exit or signal (e.g.,
+ segfault)
+
+ Also, when run in CK_NOFORK mode, unchecked fixture functions may
+ lead to different unit test behavior IF unit tests change data
+ setup by the fixture functions.
+*/
+void CK_EXPORT tcase_add_unchecked_fixture (TCase *tc, SFun setup, SFun teardown);
+
+/* Add fixture setup/teardown functions to a test case
+
+ Checked fixture functions are run before and after unit
+ tests. Unlike unchecked fixture functions, checked fixture
+ functions are run in the same separate address space as the test
+ program, and thus the test function will survive signals or
+ unexpected exits in the fixture function. Also, IF the setup
+ function is idempotent, unit test behavior will be the same in
+ CK_FORK and CK_NOFORK modes.
+
+ However, since fixture functions are run before and after each unit
+ test, they should not be expensive code.
+
+*/
+void CK_EXPORT tcase_add_checked_fixture (TCase *tc, SFun setup, SFun teardown);
+
+/* Set the timeout for all tests in a test case. A test that lasts longer
+ than the timeout (in seconds) will be killed and thus fail with an error.
+ The timeout can also be set globaly with the environment variable
+ CK_DEFAULT_TIMEOUT, the specific setting always takes precedence.
+*/
+void CK_EXPORT tcase_set_timeout (TCase *tc, int timeout);
+
+/* Internal function to mark the start of a test function */
+void CK_EXPORT tcase_fn_start (const char *fname, const char *file, int line);
+
+/* Start a unit test with START_TEST(unit_name), end with END_TEST
+ One must use braces within a START_/END_ pair to declare new variables
+*/
+#define START_TEST(__testname)\
+static void __testname (int _i CK_ATTRIBUTE_UNUSED)\
+{\
+ tcase_fn_start (""# __testname, __FILE__, __LINE__);
+
+/* End a unit test */
+#define END_TEST }
+
+/* Fail the test case unless expr is true */
+/* The space before the comma sign before ## is essential to be compatible
+ with gcc 2.95.3 and earlier.
+*/
+#define fail_unless(expr, ...)\
+ _fail_unless(expr, __FILE__, __LINE__,\
+ "Assertion '"#expr"' failed" , ## __VA_ARGS__, NULL)
+
+/* Fail the test case if expr is true */
+/* The space before the comma sign before ## is essential to be compatible
+ with gcc 2.95.3 and earlier.
+*/
+
+/* FIXME: these macros may conflict with C89 if expr is
+ FIXME: strcmp (str1, str2) due to excessive string length. */
+#define fail_if(expr, ...)\
+ _fail_unless(!(expr), __FILE__, __LINE__,\
+ "Failure '"#expr"' occured" , ## __VA_ARGS__, NULL)
+
+/* Always fail */
+#define fail(...) _fail_unless(0, __FILE__, __LINE__, "Failed" , ## __VA_ARGS__, NULL)
+
+/* Non macro version of #fail_unless, with more complicated interface */
+void CK_EXPORT _fail_unless (int result, const char *file,
+ int line, const char *expr, ...);
+
+/* New check fail API. */
+#define ck_abort() ck_abort_msg(NULL)
+#define ck_abort_msg fail
+#define ck_assert(C) ck_assert_msg(C, NULL)
+#define ck_assert_msg fail_unless
+
+/* Integer comparsion macros with improved output compared to fail_unless(). */
+/* O may be any comparion operator. */
+#define _ck_assert_int(X, O, Y) ck_assert_msg((X) O (Y), "Assertion '"#X#O#Y"' failed: "#X"==%d, "#Y"==%d", X, Y)
+#define ck_assert_int_eq(X, Y) _ck_assert_int(X, ==, Y)
+#define ck_assert_int_ne(X, Y) _ck_assert_int(X, !=, Y)
+
+/* String comparsion macros with improved output compared to fail_unless() */
+#define _ck_assert_str(C, X, O, Y) ck_assert_msg(C, "Assertion '"#X#O#Y"' failed: "#X"==\"%s\", "#Y"==\"%s\"", X, Y)
+#define ck_assert_str_eq(X, Y) _ck_assert_str(!strcmp(X, Y), X, ==, Y)
+#define ck_assert_str_ne(X, Y) _ck_assert_str(strcmp(X, Y), X, !=, Y)
+
+
+/* Mark the last point reached in a unit test
+ (useful for tracking down where a segfault, etc. occurs)
+*/
+#define mark_point() _mark_point(__FILE__,__LINE__)
+
+/* Non macro version of #mark_point */
+void CK_EXPORT _mark_point (const char *file, int line);
+
+/* Result of a test */
+enum test_result {
+ CK_TEST_RESULT_INVALID, /* Default value; should not encounter this */
+ CK_PASS, /* Test passed*/
+ CK_FAILURE, /* Test completed but failed */
+ CK_ERROR /* Test failed to complete
+ (unexpected signal or non-zero early exit) */
+};
+
+/* Specifies the how much output an SRunner should produce */
+enum print_output {
+ CK_SILENT, /* No output */
+ CK_MINIMAL, /* Only summary output */
+ CK_NORMAL, /* All failed tests */
+ CK_VERBOSE, /* All tests */
+ CK_ENV, /* Look at environment var */
+#if @ENABLE_SUBUNIT@
+ CK_SUBUNIT, /* Run as a subunit child process */
+#endif
+ CK_LAST
+};
+
+/* Holds state for a running of a test suite */
+typedef struct SRunner SRunner;
+
+/* Opaque type for a test failure */
+typedef struct TestResult TestResult;
+
+/* accessors for tr fields */
+enum ck_result_ctx {
+ CK_CTX_INVALID, /* Default value; should not encounter this */
+ CK_CTX_SETUP,
+ CK_CTX_TEST,
+ CK_CTX_TEARDOWN
+};
+
+/* Type of result */
+int CK_EXPORT tr_rtype (TestResult *tr);
+/* Context in which the result occurred */
+enum ck_result_ctx CK_EXPORT tr_ctx (TestResult *tr);
+/* Failure message */
+const char * CK_EXPORT tr_msg (TestResult *tr);
+/* Line number at which failure occured */
+int CK_EXPORT tr_lno (TestResult *tr);
+/* File name at which failure occured */
+const char * CK_EXPORT tr_lfile (TestResult *tr);
+/* Test case in which unit test was run */
+const char * CK_EXPORT tr_tcname (TestResult *tr);
+
+/* Creates an SRunner for the given suite */
+SRunner * CK_EXPORT srunner_create (Suite *s);
+
+/* Adds a Suite to an SRunner */
+void CK_EXPORT srunner_add_suite (SRunner *sr, Suite *s);
+
+/* Frees an SRunner, all suites added to it and all contained test cases */
+void CK_EXPORT srunner_free (SRunner *sr);
+
+
+/* Test running */
+
+/* Runs an SRunner, printing results as specified (see enum print_output) */
+void CK_EXPORT srunner_run_all (SRunner *sr, enum print_output print_mode);
+
+
+/* Next functions are valid only after the suite has been
+ completely run, of course */
+
+/* Number of failed tests in a run suite. Includes failures + errors */
+int CK_EXPORT srunner_ntests_failed (SRunner *sr);
+
+/* Total number of tests run in a run suite */
+int CK_EXPORT srunner_ntests_run (SRunner *sr);
+
+/* Return an array of results for all failures
+
+ Number of failures is equal to srunner_nfailed_tests. Memory for
+ the array is malloc'ed and must be freed, but individual TestResults
+ must not
+*/
+TestResult ** CK_EXPORT srunner_failures (SRunner *sr);
+
+/* Return an array of results for all run tests
+
+ Number of results is equal to srunner_ntests_run, and excludes
+ failures due to setup function failure.
+
+ Memory is malloc'ed and must be freed, but individual TestResults
+ must not
+*/
+TestResult ** CK_EXPORT srunner_results (SRunner *sr);
+
+
+/* Printing */
+
+/* Print the results contained in an SRunner */
+void CK_EXPORT srunner_print (SRunner *sr, enum print_output print_mode);
+
+
+/* Set a log file to which to write during test running.
+
+ Log file setting is an initialize only operation -- it should be
+ done immediatly after SRunner creation, and the log file can't be
+ changed after being set.
+*/
+void CK_EXPORT srunner_set_log (SRunner *sr, const char *fname);
+
+/* Does the SRunner have a log file? */
+int CK_EXPORT srunner_has_log (SRunner *sr);
+
+/* Return the name of the log file, or NULL if none */
+const char * CK_EXPORT srunner_log_fname (SRunner *sr);
+
+/* Set a xml file to which to write during test running.
+
+ XML file setting is an initialize only operation -- it should be
+ done immediatly after SRunner creation, and the XML file can't be
+ changed after being set.
+*/
+void CK_EXPORT srunner_set_xml (SRunner *sr, const char *fname);
+
+/* Does the SRunner have an XML log file? */
+int CK_EXPORT srunner_has_xml (SRunner *sr);
+
+/* Return the name of the XML file, or NULL if none */
+const char * CK_EXPORT srunner_xml_fname (SRunner *sr);
+
+
+/* Control forking */
+enum fork_status {
+ CK_FORK_GETENV, /* look in the environment for CK_FORK */
+ CK_FORK, /* call fork to run tests */
+ CK_NOFORK /* don't call fork */
+};
+
+/* Get the current fork status */
+enum fork_status CK_EXPORT srunner_fork_status (SRunner *sr);
+
+/* Set the current fork status */
+void CK_EXPORT srunner_set_fork_status (SRunner *sr, enum fork_status fstat);
+
+/* Fork in a test and make sure messaging and tests work. */
+pid_t CK_EXPORT check_fork(void);
+
+/* Wait for the pid and exit. If pid is zero, just exit. */
+void CK_EXPORT check_waitpid_and_exit(pid_t pid);
+
+#ifdef __cplusplus
+CK_CPPEND
+#endif
+
+#endif /* CHECK_H */
diff --git a/src/check_error.c b/src/check_error.c
new file mode 100644
index 0000000..5ed0c1d
--- /dev/null
+++ b/src/check_error.c
@@ -0,0 +1,67 @@
+/*
+ * Check: a unit test framework for C
+ * Copyright (C) 2001, 2002 Arien Malec
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "../lib/libcompat.h"
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "check_error.h"
+
+
+/* FIXME: including a colon at the end is a bad way to indicate an error */
+void eprintf (const char *fmt, const char *file, int line, ...)
+{
+ va_list args;
+ fflush(stderr);
+
+ fprintf(stderr,"%s:%d: ",file,line);
+ va_start(args, line);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+
+ /*include system error information if format ends in colon */
+ if (fmt[0] != '\0' && fmt[strlen(fmt)-1] == ':')
+ fprintf(stderr, " %s", strerror(errno));
+ fprintf(stderr, "\n");
+
+ exit(2);
+}
+
+void *emalloc (size_t n)
+{
+ void *p;
+ p = malloc(n);
+ if (p == NULL)
+ eprintf("malloc of %u bytes failed:", __FILE__, __LINE__ - 2, n);
+ return p;
+}
+
+void *erealloc (void * ptr, size_t n)
+{
+ void *p;
+ p = realloc (ptr, n);
+ if (p == NULL)
+ eprintf("realloc of %u bytes failed:", __FILE__, __LINE__ - 2, n);
+ return p;
+}
diff --git a/src/check_error.h b/src/check_error.h
new file mode 100644
index 0000000..2e1e211
--- /dev/null
+++ b/src/check_error.h
@@ -0,0 +1,33 @@
+/*
+ * Check: a unit test framework for C
+ * Copyright (C) 2001, 2002 Arien Malec
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef ERROR_H
+#define ERROR_H
+
+/* Include stdlib.h beforehand */
+
+/* Print error message and die
+ If fmt ends in colon, include system error information */
+void eprintf (const char *fmt, const char *file, int line,...);
+/* malloc or die */
+void *emalloc(size_t n);
+void *erealloc(void *, size_t n);
+
+#endif /*ERROR_H*/
diff --git a/src/check_impl.h b/src/check_impl.h
new file mode 100644
index 0000000..907950c
--- /dev/null
+++ b/src/check_impl.h
@@ -0,0 +1,117 @@
+/*
+ * Check: a unit test framework for C
+ * Copyright (C) 2001,2002 Arien Malec
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef CHECK_IMPL_H
+#define CHECK_IMPL_H
+
+
+/* This header should be included by any module that needs
+ to know the implementation details of the check structures
+ Include stdio.h & list.h before this header
+*/
+
+typedef struct TF {
+ TFun fn;
+ int loop_start;
+ int loop_end;
+ const char *name;
+ int signal;
+ unsigned char allowed_exit_value;
+} TF;
+
+struct Suite {
+ const char *name;
+ List *tclst; /* List of test cases */
+};
+
+typedef struct Fixture
+{
+ int ischecked;
+ SFun fun;
+} Fixture;
+
+struct TCase {
+ const char *name;
+ int timeout;
+ List *tflst; /* list of test functions */
+ List *unch_sflst;
+ List *unch_tflst;
+ List *ch_sflst;
+ List *ch_tflst;
+};
+
+typedef struct TestStats {
+ int n_checked;
+ int n_failed;
+ int n_errors;
+} TestStats;
+
+struct TestResult {
+ enum test_result rtype; /* Type of result */
+ enum ck_result_ctx ctx; /* When the result occurred */
+ char *file; /* File where the test occured */
+ int line; /* Line number where the test occurred */
+ int iter; /* The iteration value for looping tests */
+ const char *tcname; /* Test case that generated the result */
+ const char *tname; /* Test that generated the result */
+ char *msg; /* Failure message */
+};
+
+TestResult *tr_create(void);
+void tr_reset(TestResult *tr);
+
+enum cl_event {
+ CLINITLOG_SR,
+ CLENDLOG_SR,
+ CLSTART_SR,
+ CLSTART_S,
+ CLEND_SR,
+ CLEND_S,
+ CLSTART_T, /* A test case is about to run */
+ CLEND_T
+};
+
+typedef void (*LFun) (SRunner *, FILE*, enum print_output,
+ void *, enum cl_event);
+
+typedef struct Log {
+ FILE *lfile;
+ LFun lfun;
+ int close;
+ enum print_output mode;
+} Log;
+
+struct SRunner {
+ List *slst; /* List of Suite objects */
+ TestStats *stats; /* Run statistics */
+ List *resultlst; /* List of unit test results */
+ const char *log_fname; /* name of log file */
+ const char *xml_fname; /* name of xml output file */
+ List *loglst; /* list of Log objects */
+ enum fork_status fstat; /* controls if suites are forked or not
+ NOTE: Don't use this value directly,
+ instead use srunner_fork_status */
+};
+
+
+void set_fork_status(enum fork_status fstat);
+enum fork_status cur_fork_status (void);
+
+#endif /* CHECK_IMPL_H */
diff --git a/src/check_list.c b/src/check_list.c
new file mode 100644
index 0000000..e4a4385
--- /dev/null
+++ b/src/check_list.c
@@ -0,0 +1,141 @@
+/*
+ * Check: a unit test framework for C
+ * Copyright (C) 2001, 2002 Arien Malec
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "../lib/libcompat.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "check_list.h"
+#include "check_error.h"
+
+
+enum {
+ LINIT = 1,
+ LGROW = 2
+};
+
+struct List {
+ int n_elts;
+ int max_elts;
+ int current; /* pointer to the current node */
+ int last; /* pointer to the node before END */
+ const void **data;
+};
+
+static void maybe_grow (List *lp)
+{
+ if (lp->n_elts >= lp->max_elts) {
+ lp->max_elts *= LGROW;
+ lp->data = erealloc (lp->data, lp->max_elts * sizeof(lp->data[0]));
+ }
+}
+
+List *check_list_create (void)
+{
+ List *lp;
+ lp = emalloc (sizeof(List));
+ lp->n_elts = 0;
+ lp->max_elts = LINIT;
+ lp->data = emalloc(sizeof(lp->data[0]) * LINIT);
+ lp->current = lp->last = -1;
+ return lp;
+}
+
+void list_add_front (List *lp, const void *val)
+{
+ if (lp == NULL)
+ return;
+ maybe_grow(lp);
+ memmove(lp->data + 1, lp->data, lp->n_elts * sizeof lp->data[0]);
+ lp->last++;
+ lp->n_elts++;
+ lp->current = 0;
+ lp->data[lp->current] = val;
+}
+
+void list_add_end (List *lp, const void *val)
+{
+ if (lp == NULL)
+ return;
+ maybe_grow(lp);
+ lp->last++;
+ lp->n_elts++;
+ lp->current = lp->last;
+ lp->data[lp->current] = val;
+}
+
+int list_at_end (List *lp)
+{
+ if (lp->current == -1)
+ return 1;
+ else
+ return (lp->current > lp->last);
+}
+
+void list_front (List *lp)
+{
+ if (lp->current == -1)
+ return;
+ lp->current = 0;
+}
+
+
+void list_free (List *lp)
+{
+ if (lp == NULL)
+ return;
+
+ free(lp->data);
+ free (lp);
+}
+
+void *list_val (List *lp)
+{
+ if (lp == NULL)
+ return NULL;
+ if (lp->current == -1 || lp->current > lp->last)
+ return NULL;
+
+ return (void*) lp->data[lp->current];
+}
+
+void list_advance (List *lp)
+{
+ if (lp == NULL)
+ return;
+ if (list_at_end(lp))
+ return;
+ lp->current++;
+}
+
+
+void list_apply (List *lp, void (*fp) (void *))
+{
+ if (lp == NULL || fp == NULL)
+ return;
+
+ for (list_front(lp); !list_at_end(lp); list_advance(lp))
+ fp (list_val(lp));
+
+}
+
+
+
diff --git a/src/check_list.h b/src/check_list.h
new file mode 100644
index 0000000..e40f4f8
--- /dev/null
+++ b/src/check_list.h
@@ -0,0 +1,56 @@
+/*
+ * Check: a unit test framework for C
+ * Copyright (C) 2001, 2002 Arien Malec
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef CHECK_LIST_H
+#define CHECK_LIST_H
+
+typedef struct List List;
+
+/* Create an empty list */
+List * check_list_create (void);
+
+/* Is list at end? */
+int list_at_end (List * lp);
+
+/* Position list at front */
+void list_front(List *lp);
+
+/* Add a value to the front of the list,
+ positioning newly added value as current value.
+ More expensive than list_add_end, as it uses memmove. */
+void list_add_front (List *lp, const void *val);
+
+/* Add a value to the end of the list,
+ positioning newly added value as current value */
+void list_add_end (List *lp, const void *val);
+
+/* Give the value of the current node */
+void *list_val (List * lp);
+
+/* Position the list at the next node */
+void list_advance (List * lp);
+
+/* Free a list, but don't free values */
+void list_free (List * lp);
+
+void list_apply (List *lp, void (*fp) (void *));
+
+
+#endif /* CHECK_LIST_H */
diff --git a/src/check_log.c b/src/check_log.c
new file mode 100644
index 0000000..6176675
--- /dev/null
+++ b/src/check_log.c
@@ -0,0 +1,403 @@
+/*
+ * Check: a unit test framework for C
+ * Copyright (C) 2001, 2002 Arien Malec
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "../lib/libcompat.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <check.h>
+#if HAVE_SUBUNIT_CHILD_H
+#include <subunit/child.h>
+#endif
+
+#include "check_error.h"
+#include "check_list.h"
+#include "check_impl.h"
+#include "check_log.h"
+#include "check_print.h"
+#include "check_str.h"
+
+
+static void srunner_send_evt (SRunner *sr, void *obj, enum cl_event evt);
+
+void srunner_set_log (SRunner *sr, const char *fname)
+{
+ if (sr->log_fname)
+ return;
+ sr->log_fname = fname;
+}
+
+int srunner_has_log (SRunner *sr)
+{
+ return sr->log_fname != NULL;
+}
+
+const char *srunner_log_fname (SRunner *sr)
+{
+ return sr->log_fname;
+}
+
+
+void srunner_set_xml (SRunner *sr, const char *fname)
+{
+ if (sr->xml_fname)
+ return;
+ sr->xml_fname = fname;
+}
+
+int srunner_has_xml (SRunner *sr)
+{
+ return sr->xml_fname != NULL;
+}
+
+const char *srunner_xml_fname (SRunner *sr)
+{
+ return sr->xml_fname;
+}
+
+void srunner_register_lfun (SRunner *sr, FILE *lfile, int close,
+ LFun lfun, enum print_output printmode)
+{
+ Log *l = emalloc (sizeof(Log));
+
+ if (printmode == CK_ENV) {
+ printmode = get_env_printmode();
+ }
+
+ l->lfile = lfile;
+ l->lfun = lfun;
+ l->close = close;
+ l->mode = printmode;
+ list_add_end (sr->loglst, l);
+ return;
+}
+
+void log_srunner_start (SRunner *sr)
+{
+ srunner_send_evt (sr, NULL, CLSTART_SR);
+}
+
+void log_srunner_end (SRunner *sr)
+{
+ srunner_send_evt (sr, NULL, CLEND_SR);
+}
+
+void log_suite_start (SRunner *sr, Suite *s)
+{
+ srunner_send_evt (sr, s, CLSTART_S);
+}
+
+void log_suite_end (SRunner *sr, Suite *s)
+{
+ srunner_send_evt (sr, s, CLEND_S);
+}
+
+void log_test_start (SRunner *sr, TCase * tc, TF * tfun)
+{
+ char buffer[100];
+ snprintf(buffer, 99, "%s:%s", tc->name, tfun->name);
+ srunner_send_evt (sr, buffer, CLSTART_T);
+}
+
+void log_test_end (SRunner *sr, TestResult *tr)
+{
+ srunner_send_evt (sr, tr, CLEND_T);
+}
+
+static void srunner_send_evt (SRunner *sr, void *obj, enum cl_event evt)
+{
+ List *l;
+ Log *lg;
+ l = sr->loglst;
+ for (list_front(l); !list_at_end(l); list_advance(l)) {
+ lg = list_val(l);
+ fflush(lg->lfile);
+ lg->lfun (sr, lg->lfile, lg->mode, obj, evt);
+ fflush(lg->lfile);
+ }
+}
+
+void stdout_lfun (SRunner *sr, FILE *file, enum print_output printmode,
+ void *obj, enum cl_event evt)
+{
+ Suite *s;
+
+ if (printmode == CK_ENV) {
+ printmode = get_env_printmode();
+ }
+
+ switch (evt) {
+ case CLINITLOG_SR:
+ break;
+ case CLENDLOG_SR:
+ break;
+ case CLSTART_SR:
+ if (printmode > CK_SILENT) {
+ fprintf(file, "Running suite(s):");
+ }
+ break;
+ case CLSTART_S:
+ s = obj;
+ if (printmode > CK_SILENT) {
+ fprintf(file, " %s\n", s->name);
+ }
+ break;
+ case CLEND_SR:
+ if (printmode > CK_SILENT) {
+ /* we don't want a newline before printing here, newlines should
+ come after printing a string, not before. it's better to add
+ the newline above in CLSTART_S.
+ */
+ srunner_fprint (file, sr, printmode);
+ }
+ break;
+ case CLEND_S:
+ s = obj;
+ break;
+ case CLSTART_T:
+ break;
+ case CLEND_T:
+ break;
+ default:
+ eprintf("Bad event type received in stdout_lfun", __FILE__, __LINE__);
+ }
+
+
+}
+
+void lfile_lfun (SRunner *sr, FILE *file, enum print_output printmode CK_ATTRIBUTE_UNUSED,
+ void *obj, enum cl_event evt)
+{
+ TestResult *tr;
+ Suite *s;
+
+ switch (evt) {
+ case CLINITLOG_SR:
+ break;
+ case CLENDLOG_SR:
+ break;
+ case CLSTART_SR:
+ break;
+ case CLSTART_S:
+ s = obj;
+ fprintf(file, "Running suite %s\n", s->name);
+ break;
+ case CLEND_SR:
+ fprintf (file, "Results for all suites run:\n");
+ srunner_fprint (file, sr, CK_MINIMAL);
+ break;
+ case CLEND_S:
+ s = obj;
+ break;
+ case CLSTART_T:
+ break;
+ case CLEND_T:
+ tr = obj;
+ tr_fprint(file, tr, CK_VERBOSE);
+ break;
+ default:
+ eprintf("Bad event type received in lfile_lfun", __FILE__, __LINE__);
+ }
+
+
+}
+
+void xml_lfun (SRunner *sr CK_ATTRIBUTE_UNUSED, FILE *file, enum print_output printmode CK_ATTRIBUTE_UNUSED,
+ void *obj, enum cl_event evt)
+{
+ TestResult *tr;
+ Suite *s;
+ static struct timeval inittv, endtv;
+ static char t[sizeof "yyyy-mm-dd hh:mm:ss"] = {0};
+
+ if (t[0] == 0)
+ {
+ struct tm now;
+ gettimeofday(&inittv, NULL);
+ localtime_r(&(inittv.tv_sec), &now);
+ strftime(t, sizeof("yyyy-mm-dd hh:mm:ss"), "%Y-%m-%d %H:%M:%S", &now);
+ }
+
+ switch (evt) {
+ case CLINITLOG_SR:
+ fprintf(file, "<?xml version=\"1.0\"?>\n");
+ fprintf(file, "<testsuites xmlns=\"http://check.sourceforge.net/ns\">\n");
+ fprintf(file, " <datetime>%s</datetime>\n", t);
+ break;
+ case CLENDLOG_SR:
+ gettimeofday(&endtv, NULL);
+ fprintf(file, " <duration>%f</duration>\n",
+ (endtv.tv_sec + (float)(endtv.tv_usec)/1000000) - \
+ (inittv.tv_sec + (float)(inittv.tv_usec/1000000)));
+ fprintf(file, "</testsuites>\n");
+ break;
+ case CLSTART_SR:
+ break;
+ case CLSTART_S:
+ s = obj;
+ fprintf(file, " <suite>\n");
+ fprintf(file, " <title>%s</title>\n", s->name);
+ break;
+ case CLEND_SR:
+ break;
+ case CLEND_S:
+ fprintf(file, " </suite>\n");
+ s = obj;
+ break;
+ case CLSTART_T:
+ break;
+ case CLEND_T:
+ tr = obj;
+ tr_xmlprint(file, tr, CK_VERBOSE);
+ break;
+ default:
+ eprintf("Bad event type received in xml_lfun", __FILE__, __LINE__);
+ }
+
+}
+
+#if ENABLE_SUBUNIT
+void subunit_lfun (SRunner *sr, FILE *file, enum print_output printmode,
+ void *obj, enum cl_event evt)
+{
+ TestResult *tr;
+ Suite *s;
+ char const * name;
+
+ /* assert(printmode == CK_SUBUNIT); */
+
+ switch (evt) {
+ case CLINITLOG_SR:
+ break;
+ case CLENDLOG_SR:
+ break;
+ case CLSTART_SR:
+ break;
+ case CLSTART_S:
+ s = obj;
+ break;
+ case CLEND_SR:
+ if (printmode > CK_SILENT) {
+ fprintf (file, "\n");
+ srunner_fprint (file, sr, printmode);
+ }
+ break;
+ case CLEND_S:
+ s = obj;
+ break;
+ case CLSTART_T:
+ name = obj;
+ subunit_test_start(name);
+ break;
+ case CLEND_T:
+ tr = obj;
+ {
+ char *name = ck_strdup_printf ("%s:%s", tr->tcname, tr->tname);
+ char *msg = tr_short_str (tr);
+ switch (tr->rtype) {
+ case CK_PASS:
+ subunit_test_pass(name);
+ break;
+ case CK_FAILURE:
+ subunit_test_fail(name, msg);
+ break;
+ case CK_ERROR:
+ subunit_test_error(name, msg);
+ break;
+ default:
+ eprintf("Bad result type in subunit_lfun", __FILE__, __LINE__);
+ free(name);
+ free(msg);
+ }
+ }
+ break;
+ default:
+ eprintf("Bad event type received in subunit_lfun", __FILE__, __LINE__);
+ }
+}
+#endif
+
+FILE *srunner_open_lfile (SRunner *sr)
+{
+ FILE *f = NULL;
+ if (srunner_has_log (sr)) {
+ f = fopen(sr->log_fname, "w");
+ if (f == NULL)
+ eprintf ("Error in call to fopen while opening log file %s:", __FILE__, __LINE__ - 2,
+ sr->log_fname);
+ }
+ return f;
+}
+
+FILE *srunner_open_xmlfile (SRunner *sr)
+{
+ FILE *f = NULL;
+ if (srunner_has_xml (sr)) {
+ f = fopen(sr->xml_fname, "w");
+ if (f == NULL)
+ eprintf ("Error in call to fopen while opening xml file %s:", __FILE__, __LINE__ - 2,
+ sr->xml_fname);
+ }
+ return f;
+}
+
+void srunner_init_logging (SRunner *sr, enum print_output print_mode)
+{
+ FILE *f;
+ sr->loglst = check_list_create();
+#if ENABLE_SUBUNIT
+ if (print_mode != CK_SUBUNIT)
+#endif
+ srunner_register_lfun (sr, stdout, 0, stdout_lfun, print_mode);
+#if ENABLE_SUBUNIT
+ else
+ srunner_register_lfun (sr, stdout, 0, subunit_lfun, print_mode);
+#endif
+ f = srunner_open_lfile (sr);
+ if (f) {
+ srunner_register_lfun (sr, f, 1, lfile_lfun, print_mode);
+ }
+ f = srunner_open_xmlfile (sr);
+ if (f) {
+ srunner_register_lfun (sr, f, 2, xml_lfun, print_mode);
+ }
+ srunner_send_evt (sr, NULL, CLINITLOG_SR);
+}
+
+void srunner_end_logging (SRunner *sr)
+{
+ List *l;
+ int rval;
+
+ srunner_send_evt (sr, NULL, CLENDLOG_SR);
+
+ l = sr->loglst;
+ for (list_front(l); !list_at_end(l); list_advance(l)) {
+ Log *lg = list_val(l);
+ if (lg->close) {
+ rval = fclose (lg->lfile);
+ if (rval != 0)
+ eprintf ("Error in call to fclose while closing log file:", __FILE__, __LINE__ - 2);
+ }
+ free (lg);
+ }
+ list_free(l);
+ sr->loglst = NULL;
+}
diff --git a/src/check_log.h b/src/check_log.h
new file mode 100644
index 0000000..3ed38ee
--- /dev/null
+++ b/src/check_log.h
@@ -0,0 +1,51 @@
+/*
+ * Check: a unit test framework for C
+ * Copyright (C) 2001,2002 Arien Malec
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef CHECK_LOG_H
+#define CHECK_LOG_H
+
+void log_srunner_start (SRunner *sr);
+void log_srunner_end (SRunner *sr);
+void log_suite_start (SRunner *sr, Suite *s);
+void log_suite_end (SRunner *sr, Suite *s);
+void log_test_end (SRunner *sr, TestResult *tr);
+void log_test_start (SRunner *sr, TCase *tc, TF *tfun);
+
+void stdout_lfun (SRunner *sr, FILE *file, enum print_output,
+ void *obj, enum cl_event evt);
+
+void lfile_lfun (SRunner *sr, FILE *file, enum print_output,
+ void *obj, enum cl_event evt);
+
+void xml_lfun (SRunner *sr, FILE *file, enum print_output,
+ void *obj, enum cl_event evt);
+
+void subunit_lfun (SRunner *sr, FILE *file, enum print_output,
+ void *obj, enum cl_event evt);
+
+void srunner_register_lfun (SRunner *sr, FILE *lfile, int close,
+ LFun lfun, enum print_output);
+
+FILE *srunner_open_lfile (SRunner *sr);
+FILE *srunner_open_xmlfile (SRunner *sr);
+void srunner_init_logging (SRunner *sr, enum print_output print_mode);
+void srunner_end_logging (SRunner *sr);
+
+#endif /* CHECK_LOG_H */
diff --git a/src/check_msg.c b/src/check_msg.c
new file mode 100644
index 0000000..89edbd5
--- /dev/null
+++ b/src/check_msg.c
@@ -0,0 +1,200 @@
+/*
+ * Check: a unit test framework for C
+ * Copyright (C) 2001 2002, Arien Malec
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "../lib/libcompat.h"
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#include "check_error.h"
+#include "check.h"
+#include "check_list.h"
+#include "check_impl.h"
+#include "check_msg.h"
+#include "check_pack.h"
+
+
+/* 'Pipe' is implemented as a temporary file to overcome message
+ * volume limitations outlined in bug #482012. This scheme works well
+ * with the existing usage wherein the parent does not begin reading
+ * until the child has done writing and exited.
+ *
+ * Pipe life cycle:
+ * - The parent creates a tmpfile().
+ * - The fork() call has the effect of duplicating the file descriptor
+ * and copying (on write) the FILE* data structures.
+ * - The child writes to the file, and its dup'ed file descriptor and
+ * data structures are cleaned up on child process exit.
+ * - Before reading, the parent rewind()'s the file to reset both
+ * FILE* and underlying file descriptor location data.
+ * - When finished, the parent fclose()'s the FILE*, deleting the
+ * temporary file, per tmpfile()'s semantics.
+ *
+ * This scheme may break down if the usage changes to asynchronous
+ * reading and writing.
+ */
+
+static FILE *send_file1;
+static FILE *send_file2;
+
+static FILE * get_pipe(void);
+static void setup_pipe (void);
+static void teardown_pipe (void);
+static TestResult *construct_test_result (RcvMsg *rmsg, int waserror);
+static void tr_set_loc_by_ctx (TestResult *tr, enum ck_result_ctx ctx,
+ RcvMsg *rmsg);
+static FILE * get_pipe(void)
+{
+ if (send_file2 != 0) {
+ return send_file2;
+ }
+
+ if (send_file1 != 0) {
+ return send_file1;
+ }
+
+ eprintf("No messaging setup", __FILE__, __LINE__);
+
+ return NULL;
+}
+
+void send_failure_info(const char *msg)
+{
+ FailMsg fmsg;
+
+ fmsg.msg = (char *) msg;
+ ppack(fileno(get_pipe()), CK_MSG_FAIL, (CheckMsg *) &fmsg);
+}
+
+void send_loc_info(const char * file, int line)
+{
+ LocMsg lmsg;
+
+ lmsg.file = (char *) file;
+ lmsg.line = line;
+ ppack(fileno(get_pipe()), CK_MSG_LOC, (CheckMsg *) &lmsg);
+}
+
+void send_ctx_info(enum ck_result_ctx ctx)
+{
+ CtxMsg cmsg;
+
+ cmsg.ctx = ctx;
+ ppack(fileno(get_pipe()), CK_MSG_CTX, (CheckMsg *) &cmsg);
+}
+
+TestResult *receive_test_result (int waserror)
+{
+ FILE *fp;
+ RcvMsg *rmsg;
+ TestResult *result;
+
+ fp = get_pipe();
+ if (fp == NULL)
+ eprintf ("Error in call to get_pipe",__FILE__, __LINE__ - 2);
+ rewind(fp);
+ rmsg = punpack (fileno(fp));
+ teardown_pipe();
+ setup_pipe();
+
+ result = construct_test_result (rmsg, waserror);
+ rcvmsg_free(rmsg);
+ return result;
+}
+
+static void tr_set_loc_by_ctx (TestResult *tr, enum ck_result_ctx ctx,
+ RcvMsg *rmsg)
+{
+ if (ctx == CK_CTX_TEST) {
+ tr->file = rmsg->test_file;
+ tr->line = rmsg->test_line;
+ rmsg->test_file = NULL;
+ rmsg->test_line = -1;
+ } else {
+ tr->file = rmsg->fixture_file;
+ tr->line = rmsg->fixture_line;
+ rmsg->fixture_file = NULL;
+ rmsg->fixture_line = -1;
+ }
+}
+
+static TestResult *construct_test_result (RcvMsg *rmsg, int waserror)
+{
+ TestResult *tr;
+
+ if (rmsg == NULL)
+ return NULL;
+
+ tr = tr_create();
+
+ if (rmsg->msg != NULL || waserror) {
+ tr->ctx = (cur_fork_status () == CK_FORK) ? rmsg->lastctx : rmsg->failctx;
+ tr->msg = rmsg->msg;
+ rmsg->msg = NULL;
+ tr_set_loc_by_ctx (tr, tr->ctx, rmsg);
+ } else if (rmsg->lastctx == CK_CTX_SETUP) {
+ tr->ctx = CK_CTX_SETUP;
+ tr->msg = NULL;
+ tr_set_loc_by_ctx (tr, CK_CTX_SETUP, rmsg);
+ } else {
+ tr->ctx = CK_CTX_TEST;
+ tr->msg = NULL;
+ tr_set_loc_by_ctx (tr, CK_CTX_TEST, rmsg);
+ }
+
+ return tr;
+}
+
+void setup_messaging(void)
+{
+ setup_pipe();
+}
+
+void teardown_messaging(void)
+{
+ teardown_pipe();
+}
+
+static void setup_pipe(void)
+{
+ if (send_file1 != 0) {
+ if (send_file2 != 0)
+ eprintf("Only one nesting of suite runs supported", __FILE__, __LINE__);
+ send_file2 = tmpfile();
+ } else {
+ send_file1 = tmpfile();
+ }
+}
+
+static void teardown_pipe(void)
+{
+ if (send_file2 != 0) {
+ fclose(send_file2);
+ send_file2 = 0;
+ } else if (send_file1 != 0) {
+ fclose(send_file1);
+ send_file1 = 0;
+ } else {
+ eprintf("No messaging setup", __FILE__, __LINE__);
+ }
+}
+
diff --git a/src/check_msg.h b/src/check_msg.h
new file mode 100644
index 0000000..c4d7f25
--- /dev/null
+++ b/src/check_msg.h
@@ -0,0 +1,36 @@
+/*
+ * Check: a unit test framework for C
+ * Copyright (C) 2001, 2002 Arien Malec
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef CHECK_MSG_NEW_H
+#define CHECK_MSG_NEW_H
+
+
+/* Functions implementing messaging during test runs */
+
+void send_failure_info(const char *msg);
+void send_loc_info(const char *file, int line);
+void send_ctx_info(enum ck_result_ctx ctx);
+
+TestResult *receive_test_result(int waserror);
+
+void setup_messaging(void);
+void teardown_messaging(void);
+
+#endif /*CHECK_MSG_NEW_H */
diff --git a/src/check_pack.c b/src/check_pack.c
new file mode 100644
index 0000000..4fde572
--- /dev/null
+++ b/src/check_pack.c
@@ -0,0 +1,426 @@
+/*
+ * Check: a unit test framework for C
+ * Copyright (C) 2001, 2002 Arien Malec
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "../lib/libcompat.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+#include "check.h"
+#include "check_error.h"
+#include "check_list.h"
+#include "check_impl.h"
+#include "check_pack.h"
+
+#ifdef HAVE_PTHREAD
+pthread_mutex_t lock_mutex = PTHREAD_MUTEX_INITIALIZER;
+#else
+#define pthread_mutex_lock(arg)
+#define pthread_mutex_unlock(arg)
+#endif
+
+/* typedef an unsigned int that has at least 4 bytes */
+typedef uint32_t ck_uint32;
+
+
+static void pack_int (char **buf, int val);
+static int upack_int (char **buf);
+static void pack_str (char **buf, const char *str);
+static char *upack_str (char **buf);
+
+static int pack_ctx (char **buf, CtxMsg *cmsg);
+static int pack_loc (char **buf, LocMsg *lmsg);
+static int pack_fail (char **buf, FailMsg *fmsg);
+static void upack_ctx (char **buf, CtxMsg *cmsg);
+static void upack_loc (char **buf, LocMsg *lmsg);
+static void upack_fail (char **buf, FailMsg *fmsg);
+
+static void check_type (int type, const char *file, int line);
+static enum ck_msg_type upack_type (char **buf);
+static void pack_type (char **buf, enum ck_msg_type type);
+
+static int read_buf (int fdes, char **buf);
+static int get_result (char *buf, RcvMsg *rmsg);
+static void rcvmsg_update_ctx (RcvMsg *rmsg, enum ck_result_ctx ctx);
+static void rcvmsg_update_loc (RcvMsg *rmsg, const char *file, int line);
+static RcvMsg *rcvmsg_create (void);
+void rcvmsg_free (RcvMsg *rmsg);
+
+typedef int (*pfun) (char **, CheckMsg *);
+typedef void (*upfun) (char **, CheckMsg *);
+
+static pfun pftab [] = {
+ (pfun) pack_ctx,
+ (pfun) pack_fail,
+ (pfun) pack_loc
+};
+
+static upfun upftab [] = {
+ (upfun) upack_ctx,
+ (upfun) upack_fail,
+ (upfun) upack_loc
+};
+
+int pack (enum ck_msg_type type, char **buf, CheckMsg *msg)
+{
+ if (buf == NULL)
+ return -1;
+ if (msg == NULL)
+ return 0;
+
+ check_type (type, __FILE__, __LINE__);
+
+ return pftab[type] (buf, msg);
+}
+
+int upack (char *buf, CheckMsg *msg, enum ck_msg_type *type)
+{
+ char *obuf;
+ int nread;
+
+ if (buf == NULL)
+ return -1;
+
+ obuf = buf;
+
+ *type = upack_type (&buf);
+
+ check_type (*type, __FILE__, __LINE__);
+
+ upftab[*type] (&buf, msg);
+
+ nread = buf - obuf;
+ return nread;
+}
+
+static void pack_int (char **buf, int val)
+{
+ unsigned char *ubuf = (unsigned char *) *buf;
+ ck_uint32 uval = val;
+
+ ubuf[0] = (uval >> 24) & 0xFF;
+ ubuf[1] = (uval >> 16) & 0xFF;
+ ubuf[2] = (uval >> 8) & 0xFF;
+ ubuf[3] = uval & 0xFF;
+
+ *buf += 4;
+}
+
+static int upack_int (char **buf)
+{
+ unsigned char *ubuf = (unsigned char *) *buf;
+ ck_uint32 uval;
+
+ uval = ((ubuf[0] << 24) | (ubuf[1] << 16) | (ubuf[2] << 8) | ubuf[3]);
+
+ *buf += 4;
+
+ return (int) uval;
+}
+
+static void pack_str (char **buf, const char *val)
+{
+ int strsz;
+
+ if (val == NULL)
+ strsz = 0;
+ else
+ strsz = strlen (val);
+
+ pack_int (buf, strsz);
+
+ if (strsz > 0) {
+ memcpy (*buf, val, strsz);
+ *buf += strsz;
+ }
+}
+
+static char *upack_str (char **buf)
+{
+ char *val;
+ int strsz;
+
+ strsz = upack_int (buf);
+
+ if (strsz > 0) {
+ val = emalloc (strsz + 1);
+ memcpy (val, *buf, strsz);
+ val[strsz] = 0;
+ *buf += strsz;
+ } else {
+ val = emalloc (1);
+ *val = 0;
+ }
+
+ return val;
+}
+
+static void pack_type (char **buf, enum ck_msg_type type)
+{
+ pack_int (buf, (int) type);
+}
+
+static enum ck_msg_type upack_type (char **buf)
+{
+ return (enum ck_msg_type) upack_int (buf);
+}
+
+
+static int pack_ctx (char **buf, CtxMsg *cmsg)
+{
+ char *ptr;
+ int len;
+
+ len = 4 + 4;
+ *buf = ptr = emalloc (len);
+
+ pack_type (&ptr, CK_MSG_CTX);
+ pack_int (&ptr, (int) cmsg->ctx);
+
+ return len;
+}
+
+static void upack_ctx (char **buf, CtxMsg *cmsg)
+{
+ cmsg->ctx = upack_int (buf);
+}
+
+static int pack_loc (char **buf, LocMsg *lmsg)
+{
+ char *ptr;
+ int len;
+
+ len = 4 + 4 + (lmsg->file ? strlen (lmsg->file) : 0) + 4;
+ *buf = ptr = emalloc (len);
+
+ pack_type (&ptr, CK_MSG_LOC);
+ pack_str (&ptr, lmsg->file);
+ pack_int (&ptr, lmsg->line);
+
+ return len;
+}
+
+static void upack_loc (char **buf, LocMsg *lmsg)
+{
+ lmsg->file = upack_str (buf);
+ lmsg->line = upack_int (buf);
+}
+
+static int pack_fail (char **buf, FailMsg *fmsg)
+{
+ char *ptr;
+ int len;
+
+ len = 4 + 4 + (fmsg->msg ? strlen (fmsg->msg) : 0);
+ *buf = ptr = emalloc (len);
+
+ pack_type (&ptr, CK_MSG_FAIL);
+ pack_str (&ptr, fmsg->msg);
+
+ return len;
+}
+
+static void upack_fail (char **buf, FailMsg *fmsg)
+{
+ fmsg->msg = upack_str (buf);
+}
+
+static void check_type (int type, const char *file, int line)
+{
+ if (type < 0 || type >= CK_MSG_LAST)
+ eprintf ("Bad message type arg %d", file, line, type);
+}
+
+#ifdef HAVE_PTHREAD
+pthread_mutex_t mutex_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+void ppack (int fdes, enum ck_msg_type type, CheckMsg *msg)
+{
+ char *buf;
+ int n;
+ ssize_t r;
+
+ n = pack (type, &buf, msg);
+ pthread_mutex_lock(&mutex_lock);
+ r = write (fdes, buf, n);
+ pthread_mutex_unlock(&mutex_lock);
+ if (r == -1)
+ eprintf ("Error in call to write:", __FILE__, __LINE__ - 2);
+
+ free (buf);
+}
+
+static int read_buf (int fdes, char **buf)
+{
+ char *readloc;
+ int n;
+ int nread = 0;
+ int size = 1;
+ int grow = 2;
+
+ *buf = emalloc(size);
+ readloc = *buf;
+ while (1) {
+ n = read (fdes, readloc, size - nread);
+ if (n == 0)
+ break;
+ if (n == -1)
+ eprintf ("Error in call to read:", __FILE__, __LINE__ - 4);
+
+ nread += n;
+ size *= grow;
+ *buf = erealloc (*buf,size);
+ readloc = *buf + nread;
+ }
+
+ return nread;
+}
+
+
+static int get_result (char *buf, RcvMsg *rmsg)
+{
+ enum ck_msg_type type;
+ CheckMsg msg;
+ int n;
+
+ n = upack (buf, &msg, &type);
+ if (n == -1)
+ eprintf ("Error in call to upack", __FILE__, __LINE__ - 2);
+
+ if (type == CK_MSG_CTX) {
+ CtxMsg *cmsg = (CtxMsg *) &msg;
+ rcvmsg_update_ctx (rmsg, cmsg->ctx);
+ } else if (type == CK_MSG_LOC) {
+ LocMsg *lmsg = (LocMsg *) &msg;
+ if (rmsg->failctx == CK_CTX_INVALID)
+ {
+ rcvmsg_update_loc (rmsg, lmsg->file, lmsg->line);
+ }
+ free (lmsg->file);
+ } else if (type == CK_MSG_FAIL) {
+ FailMsg *fmsg = (FailMsg *) &msg;
+ if (rmsg->msg == NULL)
+ {
+ rmsg->msg = emalloc (strlen (fmsg->msg) + 1);
+ strcpy (rmsg->msg, fmsg->msg);
+ rmsg->failctx = rmsg->lastctx;
+ }
+ else
+ {
+ /* Skip subsequent failure messages, only happens for CK_NOFORK */
+ }
+ free (fmsg->msg);
+ } else
+ check_type (type, __FILE__, __LINE__);
+
+ return n;
+}
+
+static void reset_rcv_test (RcvMsg *rmsg)
+{
+ rmsg->test_line = -1;
+ rmsg->test_file = NULL;
+}
+
+static void reset_rcv_fixture (RcvMsg *rmsg)
+{
+ rmsg->fixture_line = -1;
+ rmsg->fixture_file = NULL;
+}
+
+static RcvMsg *rcvmsg_create (void)
+{
+ RcvMsg *rmsg;
+
+ rmsg = emalloc (sizeof (RcvMsg));
+ rmsg->lastctx = CK_CTX_INVALID;
+ rmsg->failctx = CK_CTX_INVALID;
+ rmsg->msg = NULL;
+ reset_rcv_test (rmsg);
+ reset_rcv_fixture (rmsg);
+ return rmsg;
+}
+
+void rcvmsg_free (RcvMsg *rmsg)
+{
+ free(rmsg->fixture_file);
+ free(rmsg->test_file);
+ free(rmsg->msg);
+ free(rmsg);
+}
+
+static void rcvmsg_update_ctx (RcvMsg *rmsg, enum ck_result_ctx ctx)
+{
+ if (rmsg->lastctx != CK_CTX_INVALID)
+ {
+ free(rmsg->fixture_file);
+ reset_rcv_fixture (rmsg);
+ }
+ rmsg->lastctx = ctx;
+}
+
+static void rcvmsg_update_loc (RcvMsg *rmsg, const char *file, int line)
+{
+ int flen = strlen(file);
+
+ if (rmsg->lastctx == CK_CTX_TEST) {
+ free(rmsg->test_file);
+ rmsg->test_line = line;
+ rmsg->test_file = emalloc (flen + 1);
+ strcpy (rmsg->test_file, file);
+ } else {
+ free(rmsg->fixture_file);
+ rmsg->fixture_line = line;
+ rmsg->fixture_file = emalloc (flen + 1);
+ strcpy (rmsg->fixture_file, file);
+ }
+}
+
+RcvMsg *punpack (int fdes)
+{
+ int nread, n;
+ char *buf;
+ char *obuf;
+ RcvMsg *rmsg;
+
+ nread = read_buf (fdes, &buf);
+ obuf = buf;
+ rmsg = rcvmsg_create ();
+
+ while (nread > 0) {
+ n = get_result (buf, rmsg);
+ nread -= n;
+ buf += n;
+ }
+
+ free (obuf);
+ if (rmsg->lastctx == CK_CTX_INVALID) {
+ free (rmsg);
+ rmsg = NULL;
+ }
+
+ return rmsg;
+}
diff --git a/src/check_pack.h b/src/check_pack.h
new file mode 100644
index 0000000..0b78695
--- /dev/null
+++ b/src/check_pack.h
@@ -0,0 +1,76 @@
+/*
+ * Check: a unit test framework for C
+ * Copyright (C) 2001, 2002 Arien Malec
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef CHECK_PACK_H
+#define CHECK_PACK_H
+
+
+enum ck_msg_type {
+ CK_MSG_CTX,
+ CK_MSG_FAIL,
+ CK_MSG_LOC,
+ CK_MSG_LAST
+};
+
+typedef struct CtxMsg
+{
+ enum ck_result_ctx ctx;
+} CtxMsg;
+
+typedef struct LocMsg
+{
+ int line;
+ char *file;
+} LocMsg;
+
+typedef struct FailMsg
+{
+ char *msg;
+} FailMsg;
+
+typedef union
+{
+ CtxMsg ctx_msg;
+ FailMsg fail_msg;
+ LocMsg loc_msg;
+} CheckMsg;
+
+typedef struct RcvMsg
+{
+ enum ck_result_ctx lastctx;
+ enum ck_result_ctx failctx;
+ char *fixture_file;
+ int fixture_line;
+ char *test_file;
+ int test_line;
+ char *msg;
+} RcvMsg;
+
+void rcvmsg_free (RcvMsg *rmsg);
+
+
+int pack (enum ck_msg_type type, char **buf, CheckMsg *msg);
+int upack (char *buf, CheckMsg *msg, enum ck_msg_type *type);
+
+void ppack (int fdes, enum ck_msg_type type, CheckMsg *msg);
+RcvMsg *punpack (int fdes);
+
+
+#endif /*CHECK_PACK_H */
diff --git a/src/check_print.c b/src/check_print.c
new file mode 100644
index 0000000..dd9000c
--- /dev/null
+++ b/src/check_print.c
@@ -0,0 +1,165 @@
+/*
+ * Check: a unit test framework for C
+ * Copyright (C) 2001, 2002 Arien Malec
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "../lib/libcompat.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "check.h"
+#include "check_list.h"
+#include "check_impl.h"
+#include "check_str.h"
+#include "check_print.h"
+
+static void srunner_fprint_summary (FILE *file, SRunner *sr,
+ enum print_output print_mode);
+static void srunner_fprint_results (FILE *file, SRunner *sr,
+ enum print_output print_mode);
+
+
+void srunner_print (SRunner *sr, enum print_output print_mode)
+{
+ srunner_fprint (stdout, sr, print_mode);
+}
+
+void srunner_fprint (FILE *file, SRunner *sr, enum print_output print_mode)
+{
+ if (print_mode == CK_ENV) {
+ print_mode = get_env_printmode();
+ }
+
+ srunner_fprint_summary (file, sr, print_mode);
+ srunner_fprint_results (file, sr, print_mode);
+}
+
+static void srunner_fprint_summary (FILE *file, SRunner *sr,
+ enum print_output print_mode)
+{
+#if ENABLE_SUBUNIT
+ if (print_mode == CK_SUBUNIT)
+ return;
+#endif
+
+ if (print_mode >= CK_MINIMAL) {
+ char *str;
+
+ str = sr_stat_str (sr);
+ fprintf (file, "%s\n", str);
+ free(str);
+ }
+ return;
+}
+
+static void srunner_fprint_results (FILE *file, SRunner *sr,
+ enum print_output print_mode)
+{
+ List *resultlst;
+
+#if ENABLE_SUBUNIT
+ if (print_mode == CK_SUBUNIT)
+ return;
+#endif
+
+ resultlst = sr->resultlst;
+
+ for (list_front(resultlst); !list_at_end(resultlst); list_advance(resultlst)) {
+ TestResult *tr = list_val(resultlst);
+ tr_fprint (file, tr, print_mode);
+ }
+ return;
+}
+
+void tr_fprint (FILE *file, TestResult *tr, enum print_output print_mode)
+{
+ if (print_mode == CK_ENV) {
+ print_mode = get_env_printmode();
+ }
+
+ if ((print_mode >= CK_VERBOSE && tr->rtype == CK_PASS) ||
+ (tr->rtype != CK_PASS && print_mode >= CK_NORMAL)) {
+ char *trstr = tr_str (tr);
+ fprintf (file,"%s\n", trstr);
+ free(trstr);
+ }
+}
+
+void tr_xmlprint (FILE *file, TestResult *tr, enum print_output print_mode CK_ATTRIBUTE_UNUSED)
+{
+ char result[10];
+ char *path_name;
+ char *file_name;
+ char *slash;
+
+ switch (tr->rtype) {
+ case CK_PASS:
+ strcpy(result, "success");
+ break;
+ case CK_FAILURE:
+ strcpy(result, "failure");
+ break;
+ case CK_ERROR:
+ strcpy(result, "error");
+ break;
+ case CK_TEST_RESULT_INVALID:
+ default:
+ abort ();
+ break;
+ }
+
+ slash = strrchr(tr->file, '/');
+ if (slash == NULL) {
+ path_name = (char*)".";
+ file_name = tr->file;
+ } else {
+ path_name = strdup(tr->file);
+ path_name[slash - tr->file] = 0; /* Terminate the temporary string. */
+ file_name = slash + 1;
+ }
+
+
+ fprintf(file, " <test result=\"%s\">\n", result);
+ fprintf(file, " <path>%s</path>\n", path_name);
+ fprintf(file, " <fn>%s:%d</fn>\n", file_name, tr->line);
+ fprintf(file, " <id>%s</id>\n", tr->tname);
+ fprintf(file, " <iteration>%d</iteration>\n", tr->iter);
+ fprintf(file, " <description>%s</description>\n", tr->tcname);
+ fprintf(file, " <message>%s</message>\n", tr->msg);
+ fprintf(file, " </test>\n");
+
+ if (slash != NULL) {
+ free(path_name);
+ }
+}
+
+enum print_output get_env_printmode (void)
+{
+ char *env = getenv ("CK_VERBOSITY");
+ if (env == NULL)
+ return CK_NORMAL;
+ if (strcmp (env, "silent") == 0)
+ return CK_SILENT;
+ if (strcmp (env, "minimal") == 0)
+ return CK_MINIMAL;
+ if (strcmp (env, "verbose") == 0)
+ return CK_VERBOSE;
+ return CK_NORMAL;
+}
diff --git a/src/check_print.h b/src/check_print.h
new file mode 100644
index 0000000..f4b02da
--- /dev/null
+++ b/src/check_print.h
@@ -0,0 +1,30 @@
+/*
+ * Check: a unit test framework for C
+ * Copyright (C) 2001, 2002 Arien Malec
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef CHECK_PRINT_H
+#define CHECK_PRINT_H
+
+void tr_fprint (FILE *file, TestResult *tr, enum print_output print_mode);
+void tr_xmlprint (FILE *file, TestResult *tr, enum print_output print_mode);
+void srunner_fprint (FILE *file, SRunner *sr, enum print_output print_mode);
+enum print_output get_env_printmode (void);
+
+
+#endif /* CHECK_PRINT_H */
diff --git a/src/check_run.c b/src/check_run.c
new file mode 100644
index 0000000..374bf4a
--- /dev/null
+++ b/src/check_run.c
@@ -0,0 +1,573 @@
+/*
+ * Check: a unit test framework for C
+ * Copyright (C) 2001, 2002 Arien Malec
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "../lib/libcompat.h"
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <signal.h>
+
+#include "check.h"
+#include "check_error.h"
+#include "check_list.h"
+#include "check_impl.h"
+#include "check_msg.h"
+#include "check_log.h"
+
+enum rinfo {
+ CK_R_SIG,
+ CK_R_PASS,
+ CK_R_EXIT,
+ CK_R_FAIL_TEST,
+ CK_R_FAIL_FIXTURE
+};
+
+enum tf_type {
+ CK_FORK_TEST,
+ CK_NOFORK_TEST,
+ CK_NOFORK_FIXTURE
+};
+
+/* all functions are defined in the same order they are declared.
+ functions that depend on forking are gathered all together.
+ non-static functions are at the end of the file. */
+static void srunner_run_init (SRunner *sr, enum print_output print_mode);
+static void srunner_run_end (SRunner *sr, enum print_output print_mode);
+static void srunner_iterate_suites (SRunner *sr,
+ enum print_output print_mode);
+static void srunner_iterate_tcase_tfuns (SRunner *sr, TCase *tc);
+static void srunner_add_failure (SRunner *sr, TestResult *tf);
+static int srunner_run_unchecked_setup (SRunner *sr, TCase *tc);
+static TestResult * tcase_run_checked_setup (SRunner *sr, TCase *tc);
+static void srunner_run_teardown (List *l);
+static void srunner_run_unchecked_teardown (TCase *tc);
+static void tcase_run_checked_teardown (TCase *tc);
+static void srunner_run_tcase (SRunner *sr, TCase *tc);
+static TestResult *tcase_run_tfun_nofork (SRunner *sr, TCase *tc, TF *tf, int i);
+static TestResult *receive_result_info_nofork (const char *tcname,
+ const char *tname,
+ int iter);
+static void set_nofork_info (TestResult *tr);
+static char *pass_msg (void);
+
+#ifdef _POSIX_VERSION
+static TestResult *tcase_run_tfun_fork (SRunner *sr, TCase *tc, TF *tf, int i);
+static TestResult *receive_result_info_fork (const char *tcname,
+ const char *tname,
+ int iter,
+ int status, int expected_signal,
+ unsigned char allowed_exit_value);
+static void set_fork_info (TestResult *tr, int status, int expected_signal,
+ unsigned char allowed_exit_value);
+static char *signal_msg (int sig);
+static char *signal_error_msg (int signal_received, int signal_expected);
+static char *exit_msg (int exitstatus);
+static int waserror (int status, int expected_signal);
+
+static int alarm_received;
+static pid_t group_pid;
+
+static void CK_ATTRIBUTE_UNUSED sig_handler(int sig_nr)
+{
+ switch (sig_nr) {
+ case SIGALRM:
+ alarm_received = 1;
+ killpg(group_pid, SIGKILL);
+ break;
+ default:
+ eprintf("Unhandled signal: %d", __FILE__, __LINE__, sig_nr);
+ break;
+ }
+}
+#endif /* _POSIX_VERSION */
+
+#define MSG_LEN 100
+
+static void srunner_run_init (SRunner *sr, enum print_output print_mode)
+{
+ set_fork_status(srunner_fork_status(sr));
+ setup_messaging();
+ srunner_init_logging (sr, print_mode);
+ log_srunner_start (sr);
+}
+
+static void srunner_run_end (SRunner *sr, enum print_output CK_ATTRIBUTE_UNUSED print_mode)
+{
+ log_srunner_end (sr);
+ srunner_end_logging (sr);
+ teardown_messaging();
+ set_fork_status(CK_FORK);
+}
+
+static void srunner_iterate_suites (SRunner *sr,
+ enum print_output CK_ATTRIBUTE_UNUSED print_mode)
+
+{
+ List *slst;
+ List *tcl;
+ TCase *tc;
+
+ slst = sr->slst;
+
+ for (list_front(slst); !list_at_end(slst); list_advance(slst)) {
+ Suite *s = list_val(slst);
+
+ log_suite_start (sr, s);
+
+ tcl = s->tclst;
+
+ for (list_front(tcl);!list_at_end (tcl); list_advance (tcl)) {
+ tc = list_val (tcl);
+ srunner_run_tcase (sr, tc);
+ }
+
+ log_suite_end (sr, s);
+ }
+}
+
+static void srunner_iterate_tcase_tfuns (SRunner *sr, TCase *tc)
+{
+ List *tfl;
+ TF *tfun;
+ TestResult *tr = NULL;
+
+ tfl = tc->tflst;
+
+ for (list_front(tfl); !list_at_end (tfl); list_advance (tfl)) {
+ int i;
+ tfun = list_val (tfl);
+
+ for (i = tfun->loop_start; i < tfun->loop_end; i++)
+ {
+ log_test_start (sr, tc, tfun);
+ switch (srunner_fork_status(sr)) {
+ case CK_FORK:
+#ifdef _POSIX_VERSION
+ tr = tcase_run_tfun_fork (sr, tc, tfun, i);
+#else /* _POSIX_VERSION */
+ eprintf("This version does not support fork", __FILE__, __LINE__);
+#endif /* _POSIX_VERSION */
+ break;
+ case CK_NOFORK:
+ tr = tcase_run_tfun_nofork (sr, tc, tfun, i);
+ break;
+ default:
+ eprintf("Bad fork status in SRunner", __FILE__, __LINE__);
+ }
+ srunner_add_failure (sr, tr);
+ log_test_end(sr, tr);
+ }
+ }
+}
+
+static void srunner_add_failure (SRunner *sr, TestResult *tr)
+{
+ list_add_end (sr->resultlst, tr);
+ sr->stats->n_checked++; /* count checks during setup, test, and teardown */
+ if (tr->rtype == CK_FAILURE)
+ sr->stats->n_failed++;
+ else if (tr->rtype == CK_ERROR)
+ sr->stats->n_errors++;
+
+}
+
+static int srunner_run_unchecked_setup (SRunner *sr, TCase *tc)
+{
+ TestResult *tr;
+ List *l;
+ Fixture *f;
+ int rval = 1;
+
+ set_fork_status(CK_NOFORK);
+
+ l = tc->unch_sflst;
+
+ for (list_front(l); !list_at_end(l); list_advance(l)) {
+ send_ctx_info(CK_CTX_SETUP);
+ f = list_val(l);
+ f->fun();
+
+ tr = receive_result_info_nofork (tc->name, "unchecked_setup", 0);
+
+ if (tr->rtype != CK_PASS) {
+ srunner_add_failure(sr, tr);
+ rval = 0;
+ break;
+ }
+ free(tr->file);
+ free(tr->msg);
+ free(tr);
+ }
+
+ set_fork_status(srunner_fork_status(sr));
+ return rval;
+}
+
+static TestResult * tcase_run_checked_setup (SRunner *sr, TCase *tc)
+{
+ TestResult *tr = NULL;
+ List *l;
+ Fixture *f;
+ enum fork_status fstat = srunner_fork_status(sr);
+
+ l = tc->ch_sflst;
+ if (fstat == CK_FORK) {
+ send_ctx_info(CK_CTX_SETUP);
+ }
+
+ for (list_front(l); !list_at_end(l); list_advance(l)) {
+ if (fstat == CK_NOFORK) {
+ send_ctx_info(CK_CTX_SETUP);
+ }
+ f = list_val(l);
+ f->fun();
+
+ /* Stop the setup and return the failure if nofork mode. */
+ if (fstat == CK_NOFORK) {
+ tr = receive_result_info_nofork (tc->name, "checked_setup", 0);
+ if (tr->rtype != CK_PASS) {
+ break;
+ }
+
+ free(tr->file);
+ free(tr->msg);
+ free(tr);
+ tr = NULL;
+ }
+ }
+
+ return tr;
+}
+
+static void srunner_run_teardown (List *l)
+{
+ Fixture *f;
+
+ for (list_front(l); !list_at_end(l); list_advance(l)) {
+ f = list_val(l);
+ send_ctx_info(CK_CTX_TEARDOWN);
+ f->fun ();
+ }
+}
+
+static void srunner_run_unchecked_teardown (TCase *tc)
+{
+ srunner_run_teardown(tc->unch_tflst);
+}
+
+static void tcase_run_checked_teardown (TCase *tc)
+{
+ srunner_run_teardown(tc->ch_tflst);
+}
+
+static void srunner_run_tcase (SRunner *sr, TCase *tc)
+{
+ if (srunner_run_unchecked_setup(sr,tc)) {
+ srunner_iterate_tcase_tfuns(sr,tc);
+ srunner_run_unchecked_teardown(tc);
+ }
+}
+
+static TestResult *tcase_run_tfun_nofork (SRunner *sr, TCase *tc, TF *tfun, int i)
+{
+ TestResult *tr;
+
+ tr = tcase_run_checked_setup(sr, tc);
+ if (tr == NULL) {
+ tfun->fn(i);
+ tcase_run_checked_teardown(tc);
+ return receive_result_info_nofork(tc->name, tfun->name, i);
+ }
+
+ return tr;
+}
+
+static TestResult *receive_result_info_nofork (const char *tcname,
+ const char *tname,
+ int iter)
+{
+ TestResult *tr;
+
+ tr = receive_test_result(0);
+ if (tr == NULL)
+ eprintf("Failed to receive test result", __FILE__, __LINE__);
+ tr->tcname = tcname;
+ tr->tname = tname;
+ tr->iter = iter;
+ set_nofork_info(tr);
+
+ return tr;
+}
+
+static void set_nofork_info (TestResult *tr)
+{
+ if (tr->msg == NULL) {
+ tr->rtype = CK_PASS;
+ tr->msg = pass_msg();
+ } else {
+ tr->rtype = CK_FAILURE;
+ }
+}
+
+static char *pass_msg (void)
+{
+ char *msg = emalloc(sizeof("Passed"));
+ strcpy (msg, "Passed");
+ return msg;
+}
+
+#ifdef _POSIX_VERSION
+static TestResult *tcase_run_tfun_fork (SRunner *sr, TCase *tc, TF *tfun, int i)
+{
+ pid_t pid_w;
+ pid_t pid;
+ int status = 0;
+
+ pid = fork();
+ if (pid == -1)
+ eprintf("Error in call to fork:", __FILE__, __LINE__ - 2);
+ if (pid == 0) {
+ setpgid(0, 0);
+ group_pid = getpgrp();
+ tcase_run_checked_setup(sr, tc);
+ tfun->fn(i);
+ tcase_run_checked_teardown(tc);
+ exit(EXIT_SUCCESS);
+ } else {
+ group_pid = pid;
+ }
+
+ alarm_received = 0;
+ alarm(tc->timeout);
+ do {
+ pid_w = waitpid(pid, &status, 0);
+ } while (pid_w == -1);
+
+ killpg(pid, SIGKILL); /* Kill remaining processes. */
+
+ return receive_result_info_fork(tc->name, tfun->name, i, status, tfun->signal, tfun->allowed_exit_value);
+}
+
+static TestResult *receive_result_info_fork (const char *tcname,
+ const char *tname,
+ int iter,
+ int status, int expected_signal,
+ unsigned char allowed_exit_value)
+{
+ TestResult *tr;
+
+ tr = receive_test_result(waserror(status, expected_signal));
+ if (tr == NULL)
+ eprintf("Failed to receive test result", __FILE__, __LINE__);
+ tr->tcname = tcname;
+ tr->tname = tname;
+ tr->iter = iter;
+ set_fork_info(tr, status, expected_signal, allowed_exit_value);
+
+ return tr;
+}
+
+static void set_fork_info (TestResult *tr, int status, int signal_expected, unsigned char allowed_exit_value)
+{
+ int was_sig = WIFSIGNALED(status);
+ int was_exit = WIFEXITED(status);
+ int exit_status = WEXITSTATUS(status);
+ int signal_received = WTERMSIG(status);
+
+ if (was_sig) {
+ if (signal_expected == signal_received) {
+ if (alarm_received) {
+ /* Got alarm instead of signal */
+ tr->rtype = CK_ERROR;
+ tr->msg = signal_error_msg(signal_received, signal_expected);
+ } else {
+ tr->rtype = CK_PASS;
+ tr->msg = pass_msg();
+ }
+ } else if (signal_expected != 0) {
+ /* signal received, but not the expected one */
+ tr->rtype = CK_ERROR;
+ tr->msg = signal_error_msg(signal_received, signal_expected);
+ } else {
+ /* signal received and none expected */
+ tr->rtype = CK_ERROR;
+ tr->msg = signal_msg(signal_received);
+ }
+ } else if (signal_expected == 0) {
+ if (was_exit && exit_status == allowed_exit_value) {
+ tr->rtype = CK_PASS;
+ tr->msg = pass_msg();
+ } else if (was_exit && exit_status != allowed_exit_value) {
+ if (tr->msg == NULL) { /* early exit */
+ tr->rtype = CK_ERROR;
+ tr->msg = exit_msg(exit_status);
+ } else {
+ tr->rtype = CK_FAILURE;
+ }
+ }
+ } else { /* a signal was expected and none raised */
+ if (was_exit) {
+ tr->msg = exit_msg(exit_status);
+ if (exit_status == allowed_exit_value)
+ tr->rtype = CK_FAILURE; /* normal exit status */
+ else
+ tr->rtype = CK_FAILURE; /* early exit */
+ }
+ }
+}
+
+static char *signal_msg (int signal)
+{
+ char *msg = emalloc(MSG_LEN); /* free'd by caller */
+ if (alarm_received) {
+ snprintf(msg, MSG_LEN, "Test timeout expired");
+ } else {
+ snprintf(msg, MSG_LEN, "Received signal %d (%s)",
+ signal, strsignal(signal));
+ }
+ return msg;
+}
+
+static char *signal_error_msg (int signal_received, int signal_expected)
+{
+ char *sig_r_str;
+ char *sig_e_str;
+ char *msg = emalloc (MSG_LEN); /* free'd by caller */
+ sig_r_str = strdup(strsignal(signal_received));
+ sig_e_str = strdup(strsignal(signal_expected));
+ if (alarm_received) {
+ snprintf (msg, MSG_LEN, "Test timeout expired, expected signal %d (%s)",
+ signal_expected, sig_e_str);
+ } else {
+ snprintf (msg, MSG_LEN, "Received signal %d (%s), expected %d (%s)",
+ signal_received, sig_r_str, signal_expected, sig_e_str);
+ }
+ free(sig_r_str);
+ free(sig_e_str);
+ return msg;
+}
+
+static char *exit_msg (int exitval)
+{
+ char *msg = emalloc(MSG_LEN); /* free'd by caller */
+ snprintf (msg, MSG_LEN,
+ "Early exit with return value %d", exitval);
+ return msg;
+}
+
+static int waserror (int status, int signal_expected)
+{
+ int was_sig = WIFSIGNALED (status);
+ int was_exit = WIFEXITED (status);
+ int exit_status = WEXITSTATUS (status);
+ int signal_received = WTERMSIG (status);
+
+ return ((was_sig && (signal_received != signal_expected)) ||
+ (was_exit && exit_status != 0));
+}
+#endif /* _POSIX_VERSION */
+
+enum fork_status srunner_fork_status (SRunner *sr)
+{
+ if (sr->fstat == CK_FORK_GETENV) {
+ char *env = getenv ("CK_FORK");
+ if (env == NULL)
+ return CK_FORK;
+ if (strcmp (env,"no") == 0)
+ return CK_NOFORK;
+ else {
+#ifdef _POSIX_VERSION
+ return CK_FORK;
+#else /* _POSIX_VERSION */
+ eprintf("This version does not support fork", __FILE__, __LINE__);
+ return CK_NOFORK;
+#endif /* _POSIX_VERSION */
+ }
+ } else
+ return sr->fstat;
+}
+
+void srunner_set_fork_status (SRunner *sr, enum fork_status fstat)
+{
+ sr->fstat = fstat;
+}
+
+void srunner_run_all (SRunner *sr, enum print_output print_mode)
+{
+#ifdef _POSIX_VERSION
+ struct sigaction old_action;
+ struct sigaction new_action;
+#endif /* _POSIX_VERSION */
+
+ if (sr == NULL)
+ return;
+ if (print_mode >= CK_LAST)
+ {
+ eprintf ("Bad print_mode argument to srunner_run_all: %d",
+ __FILE__, __LINE__, print_mode);
+ }
+#ifdef _POSIX_VERSION
+ memset(&new_action, 0, sizeof new_action);
+ new_action.sa_handler = sig_handler;
+ sigaction(SIGALRM, &new_action, &old_action);
+#endif /* _POSIX_VERSION */
+ srunner_run_init (sr, print_mode);
+ srunner_iterate_suites (sr, print_mode);
+ srunner_run_end (sr, print_mode);
+#ifdef _POSIX_VERSION
+ sigaction(SIGALRM, &old_action, NULL);
+#endif /* _POSIX_VERSION */
+}
+
+pid_t check_fork (void)
+{
+#ifdef _POSIX_VERSION
+ pid_t pid = fork();
+ /* Set the process to a process group to be able to kill it easily. */
+ setpgid(pid, group_pid);
+ return pid;
+#else /* _POSIX_VERSION */
+ eprintf("This version does not support fork", __FILE__, __LINE__);
+ return 0;
+#endif /* _POSIX_VERSION */
+}
+
+void check_waitpid_and_exit (pid_t pid CK_ATTRIBUTE_UNUSED)
+{
+#ifdef _POSIX_VERSION
+ pid_t pid_w;
+ int status;
+
+ if (pid > 0) {
+ do {
+ pid_w = waitpid(pid, &status, 0);
+ } while (pid_w == -1);
+ if (waserror(status, 0)) {
+ exit(EXIT_FAILURE);
+ }
+ }
+ exit(EXIT_SUCCESS);
+#else /* _POSIX_VERSION */
+ eprintf("This version does not support fork", __FILE__, __LINE__);
+#endif /* _POSIX_VERSION */
+}
diff --git a/src/check_str.c b/src/check_str.c
new file mode 100644
index 0000000..9f7f3d8
--- /dev/null
+++ b/src/check_str.c
@@ -0,0 +1,132 @@
+/*
+ * Check: a unit test framework for C
+ * Copyright (C) 2001, 2002 Arien Malec
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "../lib/libcompat.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "check.h"
+#include "check_list.h"
+#include "check_error.h"
+#include "check_impl.h"
+#include "check_str.h"
+
+static const char *tr_type_str (TestResult *tr);
+static int percent_passed (TestStats *t);
+
+char *tr_str (TestResult *tr)
+{
+ const char *exact_msg;
+ char *rstr;
+
+ exact_msg = (tr->rtype == CK_ERROR) ? "(after this point) ": "";
+
+ rstr = ck_strdup_printf ("%s:%d:%s:%s:%s:%d: %s%s",
+ tr->file, tr->line,
+ tr_type_str(tr), tr->tcname, tr->tname, tr->iter,
+ exact_msg, tr->msg);
+
+ return rstr;
+}
+
+char *tr_short_str (TestResult *tr)
+{
+ const char *exact_msg;
+ char *rstr;
+
+ exact_msg = (tr->rtype == CK_ERROR) ? "(after this point) ": "";
+
+ rstr = ck_strdup_printf ("%s:%d: %s%s",
+ tr->file, tr->line,
+ exact_msg, tr->msg);
+
+ return rstr;
+}
+
+char *sr_stat_str (SRunner *sr)
+{
+ char *str;
+ TestStats *ts;
+
+ ts = sr->stats;
+
+ str = ck_strdup_printf ("%d%%: Checks: %d, Failures: %d, Errors: %d",
+ percent_passed (ts), ts->n_checked, ts->n_failed,
+ ts->n_errors);
+
+ return str;
+}
+
+char *ck_strdup_printf (const char *fmt, ...)
+{
+ /* Guess we need no more than 100 bytes. */
+ int n, size = 100;
+ char *p;
+ va_list ap;
+
+ p = emalloc (size);
+
+ while (1)
+ {
+ /* Try to print in the allocated space. */
+ va_start(ap, fmt);
+ n = vsnprintf (p, size, fmt, ap);
+ va_end(ap);
+ /* If that worked, return the string. */
+ if (n > -1 && n < size)
+ return p;
+
+ /* Else try again with more space. */
+ if (n > -1) /* C99 conform vsnprintf() */
+ size = n+1; /* precisely what is needed */
+ else /* glibc 2.0 */
+ size *= 2; /* twice the old size */
+
+ p = erealloc (p, size);
+ }
+}
+
+static const char *tr_type_str (TestResult *tr)
+{
+ const char *str = NULL;
+ if (tr->ctx == CK_CTX_TEST) {
+ if (tr->rtype == CK_PASS)
+ str = "P";
+ else if (tr->rtype == CK_FAILURE)
+ str = "F";
+ else if (tr->rtype == CK_ERROR)
+ str = "E";
+ } else
+ str = "S";
+
+ return str;
+}
+
+static int percent_passed (TestStats *t)
+{
+ if (t->n_failed == 0 && t->n_errors == 0)
+ return 100;
+ else if (t->n_checked == 0)
+ return 0;
+ else
+ return (int) ( (float) (t->n_checked - (t->n_failed + t->n_errors)) /
+ (float) t->n_checked * 100);
+}
diff --git a/src/check_str.h b/src/check_str.h
new file mode 100644
index 0000000..bd41055
--- /dev/null
+++ b/src/check_str.h
@@ -0,0 +1,42 @@
+/*
+ * Check: a unit test framework for C
+ * Copyright (C) 2001, 2002 Arien Malec
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef CHECK_STR_H
+#define CHECK_STR_H
+
+/* Return a string representation of the given TestResult. Return
+ value has been malloc'd, and must be freed by the caller */
+char *tr_str (TestResult *tr);
+
+/* Return a string representation of the given TestResult message
+ without the test id or result type. This is suitable for separate
+ formatting of the test and the message. Return value has been
+ malloc'd, and must be freed by the caller */
+char *tr_short_str (TestResult *tr);
+
+/* Return a string representation of the given SRunner's run
+ statistics (% passed, num run, passed, errors, failures). Return
+ value has been malloc'd, and must be freed by the caller
+*/
+char *sr_stat_str (SRunner *sr);
+
+char *ck_strdup_printf (const char *fmt, ...);
+
+#endif /* CHECK_STR_H */