diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 73 | ||||
-rw-r--r-- | src/Makefile.in | 601 | ||||
-rw-r--r-- | src/check.c | 405 | ||||
-rw-r--r-- | src/check.h | 418 | ||||
-rw-r--r-- | src/check.h.in | 418 | ||||
-rw-r--r-- | src/check_error.c | 67 | ||||
-rw-r--r-- | src/check_error.h | 33 | ||||
-rw-r--r-- | src/check_impl.h | 117 | ||||
-rw-r--r-- | src/check_list.c | 141 | ||||
-rw-r--r-- | src/check_list.h | 56 | ||||
-rw-r--r-- | src/check_log.c | 403 | ||||
-rw-r--r-- | src/check_log.h | 51 | ||||
-rw-r--r-- | src/check_msg.c | 200 | ||||
-rw-r--r-- | src/check_msg.h | 36 | ||||
-rw-r--r-- | src/check_pack.c | 426 | ||||
-rw-r--r-- | src/check_pack.h | 76 | ||||
-rw-r--r-- | src/check_print.c | 165 | ||||
-rw-r--r-- | src/check_print.h | 30 | ||||
-rw-r--r-- | src/check_run.c | 573 | ||||
-rw-r--r-- | src/check_str.c | 132 | ||||
-rw-r--r-- | src/check_str.h | 42 |
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 */ |