From 0b5880caac838db6b91aadd873aa923e04c88e19 Mon Sep 17 00:00:00 2001 From: Packit Date: Sep 30 2020 16:32:30 +0000 Subject: check-0.12.0 base --- diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..63bb9fb --- /dev/null +++ b/.editorconfig @@ -0,0 +1,14 @@ +# EditorConfig +# http://EditorConfig.org + +# top-most EditorConfig file +root = true + +# LF end-of-line, insert an empty new line and UTF-8 +[*] +end_of_line = lf +insert_final_newline = true +charset = utf-8 + +[makefile,Makefile] +indent_style = tab diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5322588 --- /dev/null +++ b/.gitignore @@ -0,0 +1,87 @@ +# Temp files +*~ +*.bak +*.backup +\#* +.\#* +*\# +*.sav +*.save +*.autosav +*.autosave +*.swp +*.swap + +# Generated binaries +*.o +*.lo +*.la +*.Po +*.Plo + +# Generated folders +bin/ +build/ +release/ +debug/ + +# CMake +CMakeCache.txt +CMakeFiles/ +CTestTestfile.cmake +DartConfiguration.tcl +Testing/ +check_error_linenums_seRbql +check_test_names__e1JTIe +cmake_install.cmake +lib/CMakeFiles/ +lib/cmake_install.cmake +lib/libcompat.a +src/CMakeFiles/ +src/cmake_install.cmake +src/libcheck.a +tests/CMakeFiles/ +tests/CTestTestfile.cmake +tests/check_check +tests/check_check_export +tests/check_nofork +tests/check_nofork_teardown +tests/cmake_install.cmake + +build-aux +Makefile.in +Makefile +.libs +INSTALL +SVNChangeLog +aclocal.m4 +autom4te.cache/ +build-aus +check.pc +check_stdint.h +test.out +config.h +config.log +config.status +configure +check.info +*.diff +libtool +libtool.m4 +ltoptions.m4 +ltsugar.m4 +ltversion.m4 +version.texi +lt~obsolete.m4 +check.h +exported.sym +stamp-h1 +stamp-vti +test_vars +tests/ex_output +tests/test.xml +tests/*.log +tests/*.sh.trs +tests/*.tap +checkmk/*.log +checkmk/test/*.log diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..cc73fc9 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,55 @@ +# Copyright (C) 2016 Branden Archer +# Copyright (C) 2016 Joshua D. Boyd +# +# 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. + + +language: c + +os: + - linux + - osx + +compiler: + - gcc + - clang + +env: + - USE_CMAKE=YES + - USE_CMAKE=NO + +addons: + apt: + packages: + - texinfo + +matrix: + exclude: + # There have been sporadic unit test failures with + # timeout tests on OSX using CMake. Until these are + # resolved, skipping these tests. + - os: osx + env: USE_CMAKE=YES + +script: + - mkdir build + - cd build + - if [ $USE_CMAKE == 'YES' ] ; then cmake .. ; fi + - if [ $USE_CMAKE == 'NO' ] ; then pushd .. ; autoreconf -i ; popd; fi + - if [ $USE_CMAKE == 'NO' ] ; then ../configure ; fi + - make + - if [ $USE_CMAKE == 'YES' ] ; then ctest -V ; fi + - if [ $USE_CMAKE == 'NO' ] ; then make check ; fi diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..229c8d1 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,127 @@ +Maintainers: + Fredrik Hugosson | hugo303 + Chris Pickett | cpickett + Branden Archer | amalec + Sven Neumann | neo23 + +Committers: + Robert Collins | rbcollins + (subunit support) + Micah Cowan | micahcowan + (checkmk tool, docs and tests) + Zdenek Crha | zdenekc + (new Check API docs, fixes, and tests) + Mateusz Loskot | mloskot + (msvc port #2) + Jose E. Marchesi | jemarch + (selective testing support) + +Contributors: + Cesar Ballardini + (signals) + Anthony G. Basile + (fix configure.ac and strsignal()) + Friedrich Beckmann + (mingw and msvc port #1) + Frank Bergmann + (WIN32 tmpfile workaround) + Joshua Boyd + (travis testing with both build systems, cmake fixes) + Ross Burton + (pkg-config patch) + Bogdan Cristea + (eclipse support in contrib dir) + Lucas Di Pentima + (signals) + Torok Edwin + (strsignal and build fixes) + Daniel Gollub + (pthreads support) + Roland Illig + (varargs and strsignal portability fixes) + Elmir Jagudin + (well-formed XML and log file via env variables) + Jerry James + (cleanup compiler warnings) + Jon Kowal + (deadlock on thread cancellation fix) + Robert Lemmen + (gcov description in manual) + Loic Martin + (AM_PATH_CHECK patch) + Roy Merkel + (specified test exit value) + Gilgamesh Nootebos + (bug fixes) + Diego Elio Petteno + (autoconf patch for 64-bit safe code) + Frederic Peters + (XML output) + Dietmar Petras + (bug fixes) + Rick Poyner + (pipe handling, bug fixes) + Bernhard Reiter + (configure issues) + Pavol Rusnak + (memory location comparison macros ck_assert_mem_*) + Neil Spring + (const fixes) + Roland Stigge + (bug fix: allow fail inside setup) + Sebastian Rasmussen + (duration bug fix, 64-bit API fix) + Martin Willers + (rename check's internal list API to start with check_) + bross + (patches for msys/mingw32 support) + Pino Toscano + (GNU/Hurd support for subsecond timeouts) + lod + (compiler warning) + Bill Kolokithas + (more checkmk directives) + Julien Godin + (configure.ac patch for Check example) + Kosma Moczek + (fix for string formatting in ck_assert_*() methods with %) + Tim Müller + (Use _exit() instead of exit() on _ck_assert_failed()) + Georg Sauthoff + (Solaris support, misc autotools fixes) + forest + (AIX and Solaris support) + Michael Piszczek + (misc cleanup) + Stewart Brodie + (bug fix: no fork mode failure reporting with teardowns) + Michał Dębski + (Use mkstemp() if available instead of tmpfile() or tempnam()) + Sebastian Dröge + (Kill running tests if SIGTERM or SIGINT are caught in test runner) + Matt Clarkson + (Fix CMake checks using time.h for MinGW and MSVC) + Mario Sanchez Prada + (configure.ac cleanup) + Tobias Frost + (strip timestamps from examples to enable reproducible builds) + James Morris + (checkmk regex update for Solaris support) + Mick Beaver + (Visual Studio 2015 build fixes) + Jan Pokorny + (corner case segfault fix) + Dotsenko Andrey Nikolaevich + (floating point comparison macros) + bel2125 + (AppVeyor build with multiple Visual Studio versions, + test source code compliance to C89/C90 standard, + substitution functions for floating point functions missing + in older C standard libraries) + +Anybody who has contributed code to Check or Check's build system is +considered an author. Submit a pull request of this file or send +a patch to . diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..0d66a5d --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,368 @@ +# +# Check: a unit test framework for C +# +# Copyright (C) 2011 Mateusz Loskot +# 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. +# +project(check C) + +cmake_minimum_required(VERSION 2.8 FATAL_ERROR) +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +macro(extract_version file setting_name) + file(STRINGS ${file} VERSION_NUMBER REGEX "^${setting_name}") + string(REPLACE "=" ";" VERSION_NUMBER_LIST ${VERSION_NUMBER}) + list(GET VERSION_NUMBER_LIST 1 ${setting_name}) +endmacro(extract_version) + +extract_version(configure.ac CHECK_MAJOR_VERSION) +extract_version(configure.ac CHECK_MINOR_VERSION) +extract_version(configure.ac CHECK_MICRO_VERSION) + +set(CHECK_VERSION + "${CHECK_MAJOR_VERSION}.${CHECK_MINOR_VERSION}.${CHECK_MICRO_VERSION}") + +set(MEMORY_LEAKING_TESTS_ENABLED 1) + +############################################################################### +# Set build features +set(CMAKE_BUILD_TYPE Debug) + +############################################################################### +# Option +option(CHECK_ENABLE_TESTS + "Enable the compilation and running of Check's unit tests" ON) + +############################################################################### +# Check system and architecture +if(WIN32) + if(MSVC60) + set(WINVER 0x0400) + else() + set(WINVER 0x0500) + endif() + set(_WIN32_WINNT ${WINVER}) +endif(WIN32) + +if(MSVC) + add_definitions(-D_CRT_SECURE_NO_DEPRECATE) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) + add_definitions(-D_CRT_NONSTDC_NO_WARNINGS) +endif(MSVC) + +############################################################################### +include(CheckCSourceCompiles) +include(CheckCSourceRuns) +include(CheckFunctionExists) +include(CheckIncludeFile) +include(CheckIncludeFiles) +include(CheckLibraryExists) +include(CheckStructMember) +include(CheckSymbolExists) +include(CheckTypeExists) +include(CheckTypeSize) + +############################################################################### +# Check headers +set(INCLUDES "") +macro(ck_check_include_file header var) + check_include_files("${INCLUDES};${header}" ${var}) + if(${var}) + set(INCLUDES ${INCLUDES} ${header}) + endif(${var}) +endmacro(ck_check_include_file) + +# Some FreeBSD headers assume sys/types.h was already included. +ck_check_include_file("sys/types.h" HAVE_SYS_TYPES_H) + +# Alphabetize the rest unless there's a compelling reason +ck_check_include_file("errno.h" HAVE_ERRNO_H) +ck_check_include_file("inttypes.h" HAVE_INTTYPES_H) +ck_check_include_file("limits.h" HAVE_LIMITS_H) +ck_check_include_file("regex.h" HAVE_REGEX_H) +ck_check_include_file("signal.h" HAVE_SIGNAL_H) +ck_check_include_file("stdarg.h" HAVE_STDARG_H) +ck_check_include_file("stdint.h" HAVE_STDINT_H) +ck_check_include_file("stdlib.h" HAVE_STDLIB_H) +ck_check_include_file("string.h" HAVE_STRING_H) +ck_check_include_file("strings.h" HAVE_STRINGS_H) +ck_check_include_file("sys/time.h" HAVE_SYS_TIME_H) +ck_check_include_file("time.h" HAVE_TIME_H) + +############################################################################### +# Check functions +check_function_exists(fork HAVE_FORK) +check_function_exists(getline HAVE_GETLINE) +check_function_exists(getpid HAVE_GETPID) +check_function_exists(gettimeofday HAVE_GETTIMEOFDAY) +check_function_exists(localtime_r HAVE_DECL_LOCALTIME_R) +check_function_exists(malloc HAVE_MALLOC) +check_function_exists(mkstemp HAVE_MKSTEMP) +check_function_exists(realloc HAVE_REALLOC) +check_function_exists(setenv HAVE_DECL_SETENV) +check_function_exists(sigaction HAVE_SIGACTION) +check_function_exists(strdup HAVE_DECL_STRDUP) +check_function_exists(strsignal HAVE_DECL_STRSIGNAL) +check_function_exists(_getpid HAVE__GETPID) +check_function_exists(_strdup HAVE__STRDUP) +if (HAVE_REGEX_H) + check_function_exists(regcomp HAVE_REGCOMP) + check_function_exists(regexec HAVE_REGEXEC) +endif() + +# printf related checks +check_function_exists(snprintf HAVE_SNPRINTF_FUNCTION) +check_function_exists(vsnprintf HAVE_VSNPRINTF_FUNCTION) +check_symbol_exists(snprintf stdio.h HAVE_SNPRINTF_SYMBOL) +check_symbol_exists(vsnprintf stdio.h HAVE_VSNPRINTF_SYMBOL) + +if(NOT HAVE_SNPRINTF_FUNCTION AND NOT HAVE_SNPRINTF_SYMBOL) + add_definitions(-Dsnprintf=rpl_snprintf) + set(snprintf rpl_snprintf) + add_definitions(-Dvsnprintf=rpl_vsnprintf) + set(vsnprintf rpl_vsnprintf) +else(NOT HAVE_SNPRINTF_FUNCTION AND NOT HAVE_SNPRINTF_SYMBOL) + set(HAVE_SNPRINTF 1) + add_definitions(-DHAVE_SNPRINTF=1) + set(HAVE_VSNPRINTF 1) + add_definitions(-DHAVE_VSNPRINTF=1) +endif(NOT HAVE_SNPRINTF_FUNCTION AND NOT HAVE_SNPRINTF_SYMBOL) + +if(HAVE_FORK) + add_definitions(-DHAVE_FORK=1) + set(HAVE_FORK 1) +else(HAVE_FORK) + add_definitions(-DHAVE_FORK=0) + set(HAVE_FORK 0) +endif(HAVE_FORK) + +if(HAVE_MKSTEMP) + add_definitions(-DHAVE_MKSTEMP=1) + set(HAVE_MKSTEMP 1) +else(HAVE_MKSTEMP) + add_definitions(-DHAVE_MKSTEMP=0) + set(HAVE_MKSTEMP 0) +endif(HAVE_MKSTEMP) + +if(HAVE_REGEX_H AND HAVE_REGCOMP AND HAVE_REGEXEC) + add_definitions(-DHAVE_REGEX=1) + set(HAVE_REGEX 1) + add_definitions(-DENABLE_REGEX=1) + set(ENABLE_REGEX 1) +endif() + + +############################################################################### +# Check defines +set(headers "limits.h") + +if(HAVE_STDINT_H) + list(APPEND headers "stdint.h") +endif(HAVE_STDINT_H) + +if(HAVE_INTTYPES_H) + list(APPEND headers "inttypes.h") +endif(HAVE_INTTYPES_H) + +check_symbol_exists(INT64_MAX "${headers}" HAVE_INT64_MAX) +check_symbol_exists(INT64_MIN "${headers}" HAVE_INT64_MIN) +check_symbol_exists(UINT32_MAX "${headers}" HAVE_UINT32_MAX) +check_symbol_exists(UINT64_MAX "${headers}" HAVE_UINT64_MAX) +check_symbol_exists(SIZE_MAX "${headers}" HAVE_SIZE_MAX) +check_symbol_exists(SSIZE_MAX "limits.h" HAVE_SSIZE_MAX) + +############################################################################### +# Check struct members + +# Check for tv_sec in struct timeval +if(NOT HAVE_SYS_TIME_H) + if(MSVC) + check_struct_member("struct timeval" tv_sec "Winsock2.h" HAVE_STRUCT_TIMEVAL_TV_SEC) + check_struct_member("struct timeval" tv_usec "Winsock2.h" HAVE_STRUCT_TIMEVAL_TV_USEC) + check_struct_member("struct timespec" tv_sec "Winsock2.h" HAVE_WINSOCK2_H_STRUCT_TIMESPEC_TV_SEC) + check_struct_member("struct timespec" tv_sec "time.h" HAVE_TIME_H_STRUCT_TIMESPEC_TV_SEC) + check_struct_member("struct itimerspec" it_value "Winsock2.h" HAVE_STRUCT_ITIMERSPEC_IT_VALUE) + + if(NOT HAVE_WINSOCK2_H_STRUCT_TIMESPEC_TV_SEC AND NOT HAVE_TIME_H_STRUCT_TIMESPEC_TV_SEC) + add_definitions(-DSTRUCT_TIMESPEC_DEFINITION_MISSING=1) + set(STRUCT_TIMESPEC_DEFINITION_MISSING 1) + endif(NOT HAVE_WINSOCK2_H_STRUCT_TIMESPEC_TV_SEC AND NOT HAVE_TIME_H_STRUCT_TIMESPEC_TV_SEC) + + if(NOT HAVE_STRUCT_ITIMERSPEC_IT_VALUE) + add_definitions(-DSTRUCT_ITIMERSPEC_DEFINITION_MISSING=1) + set(STRUCT_ITIMERSPEC_DEFINITION_MISSING 1) + endif(NOT HAVE_STRUCT_ITIMERSPEC_IT_VALUE) + endif(MSVC) +endif(NOT HAVE_SYS_TIME_H) + +# OSX has sys/time.h, but it still lacks itimerspec +if(HAVE_SYS_TIME_H) + check_struct_member("struct itimerspec" it_value "sys/time.h" HAVE_STRUCT_ITIMERSPEC_IT_VALUE) + if(NOT HAVE_STRUCT_ITIMERSPEC_IT_VALUE) + add_definitions(-DSTRUCT_ITIMERSPEC_DEFINITION_MISSING=1) + set(STRUCT_ITIMERSPEC_DEFINITION_MISSING 1) + endif(NOT HAVE_STRUCT_ITIMERSPEC_IT_VALUE) +endif(HAVE_SYS_TIME_H) + +############################################################################### +# Check for integer types +check_type_size("short" SIZE_OF_SHORT) +check_type_size("int" SIZE_OF_INT) +check_type_size("long" SIZE_OF_LONG) +check_type_size("long long" SIZE_OF_LONG_LONG) + +check_type_size("unsigned short" SIZE_OF_UNSIGNED_SHORT) +check_type_size("unsigned" SIZE_OF_UNSIGNED) +check_type_size("unsigned long" SIZE_OF_UNSIGNED_LONG) +check_type_size("unsigned long long" SIZE_OF_UNSIGNED_LONG_LONG) + +check_type_size("__int64" __INT64) +check_type_size("unsigned __int64" UNSIGNED___INT64) + +check_type_size(int16_t INT16_T) +check_type_size(int32_t INT32_T) +check_type_size(int64_t INT64_T) +check_type_size(intmax_t INTMAX_T) +check_type_size(uint8_t UINT8_T) +check_type_size(uint16_t UINT16_T) +check_type_size(uint32_t UINT32_T) +check_type_size(uint64_t UINT64_T) +check_type_size(uintmax_t UINTMAX_T) + +# +set(CMAKE_EXTRA_INCLUDE_FILES time.h) +check_type_size(clock_t CLOCK_T) +if(NOT HAVE_CLOCK_T) + set(clock_t int) +endif(NOT HAVE_CLOCK_T) +unset(CMAKE_EXTRA_INCLUDE_FILES) +# +set(CMAKE_EXTRA_INCLUDE_FILES time.h) +check_type_size(clockid_t CLOCKID_T) +if(NOT HAVE_CLOCKID_T) + set(clockid_t int) +endif(NOT HAVE_CLOCKID_T) +unset(CMAKE_EXTRA_INCLUDE_FILES) +# +check_type_size(size_t SIZE_T) +if(NOT HAVE_SIZE_T) + if("${CMAKE_SIZEOF_VOID_P}" EQUAL 8) + set(size_t "uint64_t") + else("${CMAKE_SIZEOF_VOID_P}" EQUAL 8) + set(size_t "uint32_t") + endif("${CMAKE_SIZEOF_VOID_P}" EQUAL 8) +endif(NOT HAVE_SIZE_T) +# +check_type_size(ssize_t SSIZE_T) +if(NOT HAVE_SSIZE_T) + if("${CMAKE_SIZEOF_VOID_P}" EQUAL 8) + set(ssize_t "int64_t") + else("${CMAKE_SIZEOF_VOID_P}" EQUAL 8) + set(ssize_t "long") + endif("${CMAKE_SIZEOF_VOID_P}" EQUAL 8) +endif(NOT HAVE_SSIZE_T) +# +check_type_size(pid_t PID_T) +if(NOT HAVE_PID_T) + if(WIN32) + set(pid_t "int") + else(WIN32) + MESSAGE(FATAL_ERROR "pid_t doesn't exist on this platform?") + endif(WIN32) +endif(NOT HAVE_PID_T) +# +set(CMAKE_EXTRA_INCLUDE_FILES time.h) +check_type_size(timer_t TIMER_T) +if(NOT HAVE_TIMER_T) + set(timer_t int) +endif(NOT HAVE_TIMER_T) +unset(CMAKE_EXTRA_INCLUDE_FILES) + +############################################################################### +# Check libraries + +check_library_exists(m floor "" HAVE_LIBM) +if (HAVE_LIBM) + set (LIBM "m") +endif (HAVE_LIBM) + +check_library_exists(rt clock_gettime "" HAVE_LIBRT) +if (HAVE_LIBRT) + set(LIBRT "rt") + ADD_DEFINITIONS(-DHAVE_LIBRT=1) +endif (HAVE_LIBRT) + +check_library_exists(subunit subunit_test_start "" HAVE_SUBUNIT) +if (HAVE_SUBUNIT) + set(SUBUNIT "subunit") + set(ENABLE_SUBUNIT 1) + add_definitions(-DENABLE_SUBUNIT=1) +else(HAVE_SUBUNIT) + set(ENABLE_SUBUNIT 0) + add_definitions(-DENABLE_SUBUNIT=0) +endif (HAVE_SUBUNIT) + +############################################################################### +# Generate "config.h" from "cmake/config.h.cmake" +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/config.h.in + ${CMAKE_CURRENT_BINARY_DIR}/config.h) +include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}) +add_definitions(-DHAVE_CONFIG_H) +set(CONFIG_HEADER ${CMAKE_CURRENT_BINARY_DIR}/config.h) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/check_stdint.h.in + ${CMAKE_CURRENT_BINARY_DIR}/check_stdint.h) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/check_stdint.h DESTINATION include) + +############################################################################### +# Subdirectories +add_subdirectory(lib) +add_subdirectory(src) + +############################################################################### +# Unit tests +if (CHECK_ENABLE_TESTS) + add_subdirectory(tests) + enable_testing() + add_test(NAME check_check COMMAND check_check) + add_test(NAME check_check_export COMMAND check_check_export) + + # Only offer to run shell scripts if we may have a working interpreter + if(UNIX OR MINGW OR MSYS) + add_test(NAME test_output.sh + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/tests + COMMAND sh ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_output.sh) + add_test(NAME test_log_output.sh + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/tests + COMMAND sh ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_log_output.sh) + add_test(NAME test_xml_output.sh + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/tests + COMMAND sh ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_xml_output.sh) + add_test(NAME test_tap_output.sh + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/tests + COMMAND sh ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_tap_output.sh) + add_test(NAME test_check_nofork.sh + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/tests + COMMAND sh ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_check_nofork.sh) + add_test(NAME test_check_nofork_teardown.sh + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/tests + COMMAND sh ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_check_nofork_teardown.sh) + add_test(NAME test_set_max_msg_size.sh + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/tests + COMMAND sh ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_set_max_msg_size.sh) + endif(UNIX OR MINGW OR MSYS) +endif() diff --git a/COPYING.LESSER b/COPYING.LESSER new file mode 100644 index 0000000..2d2d780 --- /dev/null +++ b/COPYING.LESSER @@ -0,0 +1,510 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations +below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it +becomes a de-facto standard. To achieve this, non-free programs must +be allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control +compilation and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least + three years, to give the same user the materials specified in + Subsection 6a, above, for a charge no more than the cost of + performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply, and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License +may add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms +of the ordinary General Public License). + + To apply these terms, attach the following notices to the library. +It is safest to attach them to the start of each source file to most +effectively convey the exclusion of warranty; and each file should +have at least the "copyright" line and a pointer to where the full +notice is found. + + + + Copyright (C) + + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the library, +if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James + Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..689437e --- /dev/null +++ b/ChangeLog @@ -0,0 +1,1176 @@ +IT IS NOT NECESSARY TO UPDATE THIS FILE. + +PLEASE MAKE SURE TO LEAVE A GOOD SVN COMMIT MESSAGE. + +2010-04-08 Micah Cowan + + * configure.ac: Determine at configure time, how many + backslashes are needed in the second argument to Awk's built-in + "gsub" function in order to generate two backslashes. + + * checkmk/checkmk.in: Replaced POSIX character-classes + with (roughly) equivalent character groups from pre-POSIX + syntax, to support pre-POSIX awk implementations. + (string_encode): Use configure-substituted AWK_GSUB_DBL_BSLASH + to determine how to substitute a doubled backslash in gsub. + +2010-04-03 Micah Cowan + + * checkmk/*: Added Awk program "checkmk", for eliminating + boilerplate work when writing unit test modules. Includes + documentation and tests. + + * Makefile.am (SUBDIRS): Added checkmk. + + * configure.ac: Added extra awk-detection logic for checkmk. + + * NEWS: Updated with news about checkmk. + + * AUTHORS (Patches): Added myself. + +2010-02-17 Jose E. Marchesi + + * tests/check_check_selective.c (make_selective_suite): New + function. + (selective_setup): New function. + (selective_teardown): New function. + New tests 'test_srunner_run_run_all, 'test_srunner_run_suite', + 'test_srunner_run_no_suite', test_srunner_run_tcase', + 'test_srunner_no_tcase', 'test_srunner_suite_tcase', + 'test_srunner_suite_no_tcase', 'test_srunner_run_suite_env', + 'test_srunner_run_no_suite_env', 'test_srunner_run_tcase_env', + 'test_srunner_run_no_tcase_env', 'test_srunner_suite_tcase_env', + 'test_srunner_suite_no_tcase_env'. + + * tests/Makefile.am (check_check_SOURCES): Add + 'check_check_selective.c'. + + * tests/check_check_selective.c: New file. + + * tests/check_check_main.c (main): Add the selective_suite to the + master suite. + +2010-02-10 Jose E. Marchesi + + * doc/check.texi (SRunner Output): Document 'srunner_run' and the + usage of CK_RUN_CASE and CK_RUN_SUITE environment variables. + + * src/check_run.c (srunner_run): Use values of environment + variables CK_RUN_CASE and CK_RUN_SUITE. + +2010-02-02 Jose E. Marchesi + + * src/check.c (suite_tcase): New function that determines whether + a a given test suite contains a test case named after a given + string. + + * src/check_run.c (srunner_run): New function, renamed from + 'srunner_run_all', allowing selective running of an specific test + suite and/or test case. + (srunner_run_all): New function, invoking srunner_run internally + to provide backwards compatibility. + + * src/check.h.in: Add prototype for srunner_run. + +2005-12-16 hugo303 + + * src/check_pack.c: Fixed buggy eprintf string. + +2005-10-31 hugo303 + + * src/check_list.c, tests/check_list.c, tests/check_check_fixture.c: + Fixed sourceforge bug #1327225, Two teardown checked fixtures + segfaults. Originated in a pointer arithmetic bug in a memmove() + call in list_add_front() in src/check_list.c. + +2005-09-30 hugo303 + + * doc/tutorial.sgml: Updated with a section about looping tests. + +2005-09-30 hugo303 + + * src/check.c, src/check.h.in, src/check_impl.h, src/check_print.c, + src/check_run.c, src/check_str.c, tests/Makefile.am, + tests/check_check_fixture.c, tests/check_check_master.c, + tests/ex_xml_output.c, tests/test_log_output.sh, tests/test_output.sh, + tests/test_xml_output.sh: + + Added a new kind of test, looping tests, which are called with a new + context for each loop iteration. This makes them ideal for table based + tests. Previously, with the loop in the test itself, only the first + error was caught and then the test would exit. Now all errors are + shown at once which should help in debugging. + +2005-09-15 hugo303 + + * configure.in, tests/check_check_sub.c, tests/check_check.h, + tests/check_check_master.c, tests/Makefile.am: + Added possibility to turn off timeout tests through configure option + --enable-timeout-tests=no + +2005-09-15 hugo303 + + * src/Makefile.am: Improved coverage analysis by running all tests + before compiling result. Added gcc3.3 coverage bug workaround. + +2005-09-15 hugo303 + + * tests/check_check_sub.c, tests/check_check_master.c: + Added testing of timeout set through environment variable. + +2005-09-07 hugo303 + + *configure.in, src/Makefile.am, tests/Makefile.am: Added gcov/lcov + support. Enable with 'autogen.sh --enable-gcov'. + Run with 'cd src && make lcov'. + +2005-08-30 hugo303 + + * debian/README.Debian, debian/compat, debian/docs, + debian/example_makefile, debian/examples, debian/watch: + Added new debian files, missed in the checkin of the debian patch. + +2005-08-30 hugo303 + + * NEWS: Checked in forgotten updated NEWS file. + +2005-08-22 hugo303 + + * debian/changelog, debian/check.doc-base.tut, debian/check.docs, + debian/check.postinst.debhelper, debian/check.prerm.debhelper, + debian/control, debian/copyright, debian/dirs, debian/rules: + + Applied patch for debian files received from check debian + maintainer Robert Lemmen. + +2005-08-22 hugo303 + + * src/check.h.in: Added include of stddef.h for NULL definition + +2005-08-22 hugo303 + + * doc/tutorial.sgml: Fixed sourceforge bug #1216502 + +2005-07-19 hugo303 + + * tests/check_check_master.c, tests/check_check_msg.c, + tests/check_check_sub.c, src/check.c, src/check.h.in, + src/check_msg.c, src/check_msg.h, src/check_run.c: + + Refactored messaging to use the new tmpfile() method all the way, + removing the message keys, pipes, pipe entries and pipe list. This + makes the messaging work with forking tests, and also with threading + tests on linux 2.4 (on 2.6 it already worked). Added check_fork and + check_waitpid_and_exit to be used for forking tests. + +2005-05-26 hugo303 + + * debian/Makefile.am: Removed 'files' file from DIST + +2005-03-29 hugo303 + + * src/check.h.in: Fixed compatibility with gcc 2.95.3 according + to sourceforge patch #1161654. + +2005-03-02 hugo303 + + * src/check.h.in: Added define for NULL if needed. + +2005-03-01 hugo303 + + * src/check_run.c, tests/check_check_master.c: Changed timeout + error message according to sourceforge feature request #1121452. + +2005-02-28 hugo303 + + * debian/files: Removed this auto generated file. + +2005-02-28 hugo303 + + * rpm/check.spec.in: Added patch for x86_64 arch (fc3). + +2005-02-28 hugo303 + + * tests/ex_xml_output.c, tests/ex_log_output.c, tests/ex_output.c, + src/check_log.c: + Fixed memory leaks. + +2005-01-04 hugo303 + + * check.m4, config.h.in, configure.in, src/check_pack.c: Fixed + quoting and added configure test for stdint.h. + +2005-01-04 hugo303 + + * tests/check_check_master.c: Made failure messages more helpful. + +2004-11-12 hugo303 + + * debian/check.dirs, debian/control, debian/rules: Fixed building + with gcc3. Removed empty money dir from docs. + +2004-11-10 hugo303 + + * Makefile.am, rpm/check.spec.in, rpm/Makefile.am: Fixed so + distributions build without trouble. + +2004-11-09 hugo303 + + * src/check_run.c, tests/check_check_master.c: Use strsignal + to print describing text for signals. + +2004-11-09 hugo303 + + * doc/tutorial.sgml: Documented signals handling and timeouts. + +2004-11-09 hugo303 + + * tests/check_check_master.c src/check.h.in: + Changed failure message for fail_if. + +2004-11-09 hugo303 + + * src/check.c, src/check.h.in, src/check_impl.h, src/check_run.c, + tests/check_check_master.c, tests/check_check_sub.c: + Added support for timeouts on tests, enabling detection of + eternal loops as errors. + +2004-11-08 hugo303 + + * src/check.c, src/check.h.in, src/check_impl.h, src/check_run.c, + tests/check_check_master.c, tests/check_check_sub.c: + Added support for testing on expected signals. Implementation + courtesy of Lucas Di Pentima and Cesar Ballardini. Also cleaned + up the test verification to simplify merging of new tests. + +2004-11-04 hugo303 + + * src/check.c, src/check_list.c, src/check_list.h, src/check_log.c, + src/check_msg.c, tests/check_list.c: + Changed name on function list_create to check_list_create to avoid + name clash. + +2004-11-04 hugo303 + + * src/check.c, src/check.h.in, tests/check_check_master.c, + tests/check_check_sub.c: Applied ANSI C99 patch (#1047014) + +2004-08-20 hugo303 + + * doc/tutorial.sgml: Updated with new features. + +2004-08-18 hugo303 + + * src/check.c, src/check.h.in, src/check_impl.h, src/check_log.c, + src/check_log.h, src/check_print.c, src/check_print.h, + src/check_run.c, tests/Makefile.am, tests/check_check_log.c, + tests/ex_xml_output.c, tests/test_xml_output.sh: + Added support for XML output of the test results, courtesy of + Frederic Peters. + +2004-08-18 hugo303 + + * src/check_run.c, tests/check_check_fixture.c: Fixed setup bug + from forum, failure in setup did not abort test in nofork mode. + Added test cases for bug. + +2004-08-17 hugo303 + + * src/check_pack.c: Use stdint.h for specific sized type. + * src/check.c, src/check.h.in, tests/check_check_master.c, + tests/check_check_sub.c, ChangeLog + Applied varargs patch (#933411) and added test cases. + * src/check.h.in tests/check_check_master.c tests/check_check_sub.c: + Applied fail_if (#709167) patch. + +2004-08-16 hugo303 + + * doc/tutorial.sgml: Applied 'newbies' patch #995028 for autoconf doc. + * rpm/check.spec.in: Applied doc patch #995028 from Bill Barnard. + +2004-06-04 hugo303 + + * tests/: test_log_output.sh test_output.sh: Fixed portability + problem by changing == to =. + +2004-05-26 hugo303 + + * rpm/check.spec.in: Changed copyright. + +2004-05-25 hugo303 + + * src/check_run.c: Applied patch 796705. Replacing _exit with exit. + +2004-05-25 hugo303 + + * src/check.c tests/check_check_master.c tests/check_check_sub.c: + Applied patch for bug 793671. + +2004-05-17 10:44 hugo303 + + * Released 0.9.0. See NEWS file for changes. + +2002-10-16 13:47 neo23 + + * AUTHORS, ChangeLog, configure.in: Bumped version number to 0.8.4. + Updated AUTHORS and ChangeLog. + +2002-10-16 13:39 neo23 + + * src/check_msg.c, tests/check_check_msg.c: Applied a patch from + Rick Poyner that changes the pipe used for IPC to use a temporary + file instead of stdin/stdout. This fixes the long-standing problem + that the pipe used to fill up when too many fail_unless() were + used. (#482012). + +2002-10-09 18:57 neo23 + + * src/check.h.in: Applied a patch from Rick Poyner that fixes a + typo which broke check for C++ compilers (bug #601397). + +2002-08-16 19:41 neo23 + + * src/: check.c, check_msg.c, check_msg.h, check_pack.c, + check_pack.h: Applied a patch from Dietmar Petras + that plugs some memory leaks. + +2002-07-10 04:37 neo23 + + * .cvsignore, autogen.sh: Call aclocal from autogen.sh. + +2002-07-10 04:32 neo23 + + * aclocal.m4, depcomp, install-sh, missing, mkinstalldirs: Removed + files generated by automake. + +2002-06-16 14:25 neo23 + + * debian/changelog: applied patch from Arien Malec to fix build of + Debian packages + +2002-05-24 17:04 neo23 + + * ChangeLog: Made 0.8.3 Release. + +2002-05-24 17:00 neo23 + + * NEWS, doc/tutorial.lyx, rpm/check.spec.in: Added check.m4 to the + spec file. Updated NEWS. Updated the date of the tutorial. + +2002-05-24 16:35 neo23 + + * debian/: check.dirs, check.files, control: Added check.m4 to + debian rules. Changed the maintainer entry. + +2002-05-23 17:08 neo23 + + * doc/tutorial.lyx: Mention that EXIT_SUCCESS and EXIT_FAILURE are + defined in stdlib.h. Suggested by Russell Reed in bug #547129. + +2002-05-10 14:01 neo23 + + * src/check_msg.c: Declared local functions static (based on a + patch from Gilgamesh Nootebos). + +2002-05-03 13:58 neo23 + + * src/Makefile.am, src/check.c, src/check_error.c, + src/check_list.c, src/check_list.h, src/check_log.c, + src/check_msg.c, src/check_pack.c, src/check_print.c, + src/check_run.c, src/check_str.c, src/list.c, src/list.h, + tests/check_list.c: Renamed list.[ch] to check_list.[ch] for + consistency. Include config.h from all over the place, cleaned up + includes. + +2002-05-02 10:34 neo23 + + * src/check_pack.c, tests/check_check_log.c: Removed compiler + warnings mentioned in bug #547126. + +2002-05-02 10:27 neo23 + + * src/check_print.c, tests/check_check_msg.c: Don't include + "error.h" (bug #546175 small cygwin portability problem). + +2002-04-16 19:33 neo23 + + * doc/tutorial.lyx: Changed date to that of the latest release. + Added a name to an internal reference so that we get a working link + in the generated HTML. + +2002-04-15 18:47 neo23 + + * check.m4, configure.in: Fixed check.m4 so that --without-check is + a valid option to disable check. Bumped version number to 0.8.3. + +2002-04-15 12:58 neo23 + + * ChangeLog: Updated ChangeLog. + +2002-04-15 12:57 neo23 + + * NEWS, README: Made 0.8.2 Release. + +2002-04-14 18:59 neo23 + + * src/check_msg.c: Applied a patch from Arien that makes the pipe + nonblocking. This doesn't solve #482012 but makes it more obvious + what is going wrong if the pipe fills up. + +2002-04-12 12:50 neo23 + + * doc/tutorial.lyx: Use #include rather than #import (bug #484564). + +2002-04-12 12:34 neo23 + + * ChangeLog: Updated ChangeLog. + +2002-04-12 12:33 neo23 + + * AUTHORS, doc/tutorial.lyx: Document the fact that you can now use + NULL as msg argument for fail_unless(). + +2002-04-12 11:54 neo23 + + * config.h.in, configure.in, src/Makefile.am, src/check.c, + src/check_impl.h, src/check_magic.h, src/check_msg.c, + src/check_pack.c, src/check_pack.h, src/check_run.c, + src/check_str.c, src/check_str.h, tests/Makefile.am, + tests/check_check_fixture.c, tests/check_check_master.c, + tests/check_check_msg.c, tests/check_check_pack.c: Removed + limitations on line number, message and buffer sizes (bug #478233) + by changing the way we send integers over the pipe. Instead of + strings, integers are now send as 4 bytes. This allows the pack + routine to easily calculate the message size so that we can + allocate the needed buffer there. Made a union out of the + different Msg structs to clean up the internal API. Also introduced + the internal function ck_strdup_printf(), a simple wrapper around + sprintf() that allocates enough space to hold the resulting string. + +2002-04-10 13:11 neo23 + + * AUTHORS, NEWS, configure.in, src/check.c, src/check.h.in, + src/check_error.c, src/check_error.h, src/check_impl.h, + src/check_log.c, src/check_msg.c, src/check_msg.h, + src/check_pack.c, src/check_run.c, src/check_str.c, src/list.c, + src/list.h, tests/check_check_fixture.c, tests/check_check_fork.c, + tests/check_check_master.c, tests/check_check_pack.c, + tests/check_list.c: Applied a slightly modified version of a patch + from Neil Spring that declares strings + as const where applicable. It also changes our CFLAGS to be much + stricter and removes the warnings introduced by -Wwrite-strings. + This allows building other check tests with -Wwrite-strings without + heaping gobs of compiler warnings. + +2002-03-28 20:12 neo23 + + * ChangeLog: Updated ChangeLog. + +2002-03-28 19:37 neo23 + + * src/check.c, src/check.h.in, tests/check_check_master.c, + tests/check_check_sub.c: Allow fail_unless() to be called with a + NULL msg and substitute a reasonable error message in that case. + Bail out if NULL is passed to _fail_unless() to avoid possible + confusion. + + Added a test case that calls fail_unless() with msg=NULL. + +2002-03-28 19:19 neo23 + + * Makefile.am, README, autogen.sh, check.m4, configure.in, + doc/tutorial.lyx, doc/money/.cvsignore, + doc/money/Makefile.am.money, doc/money/aclocal.m4, + doc/money/configure.in.money, rpm/.cvsignore, rpm/Makefile.am, + rpm/check.spec, rpm/check.spec.in, src/.cvsignore, src/Makefile.am, + src/check.c, src/check.h, src/check.h.in, tests/.cvsignore: Changed + autogen.sh to bail out if necessary tools can't be found instead of + proceeding to the version checks. + + Document use of autogen.sh in README. + + Generate check.spec from check.spec.in to it automatically gets the + correct version number. + + Generate check.h from chech.h.in and include Check version + information. + + Compile Check version number into the library to allow for runtime + version checks. + + Added the m4 script check.m4 that allows to easily integrate Check + into projects using autoconf/automake. It does version checking and + also assures that header and library versions match. + + Document the use of check.m4 and the AM_PATH_CHECK() macro in the + tutorial. Adapted example Makefile.am and configure.in and added a + missing .cvsignore file. + +2002-03-27 02:21 amalec + + * src/Makefile.in, tests/Makefile.in: Complete CVS cleanup + +2002-03-27 02:18 amalec + + * .cvsignore, Makefile.am, Makefile.in, autogen.sh, configure, + debian/.cvsignore, debian/Makefile.in, doc/.cvsignore, + doc/Makefile.in, doc/money/Makefile.in, rpm/.cvsignore, + rpm/Makefile.in, src/.cvsignore, tests/.cvsignore: Cleaned up CVS + to remove all autofoo generated files, included an autogen.sh + bootstrap file. Changes at the suggestion of Sven Neumann + +2002-03-02 02:42 amalec + + * ChangeLog: Update ChangeLog + +2002-03-02 02:42 amalec + + * debian/changelog, debian/files, rpm/check.spec, src/Makefile.am, + src/Makefile.in, src/check.c, src/check_error.c, src/check_error.h, + src/check_log.c, src/check_msg.c, src/check_pack.c, + src/check_run.c, src/check_str.c, src/error.c, src/error.h, + src/list.c, tests/check_check_fixture.c, tests/check_check_pack.c: + Moved error.[hc] to check_error.[hc], and fixed bug in running + checked setup in nofork mode. + +2002-02-28 03:02 amalec + + * COPYING, configure, configure.in, src/check.c, src/check.h, + src/check_impl.h, src/check_log.c, src/check_log.h, + src/check_magic.h, src/check_msg.c, src/check_msg.h, + src/check_pack.c, src/check_pack.h, src/check_print.c, + src/check_print.h, src/check_run.c, src/check_str.c, + src/check_str.h, src/error.c, src/error.h, src/list.c, src/list.h: + Changed license to LGPL + +2001-10-26 01:19 amalec + + * ChangeLog: Update ChangeLog + +2001-10-26 01:18 amalec + + * AUTHORS: Update AUTHORS to give credit to key contributors + +2001-10-26 01:12 amalec + + * configure, configure.in: Clarified configuration warning on doc + building + +2001-10-26 00:51 amalec + + * ChangeLog: Updating ChangeLog prior to release + +2001-10-26 00:45 amalec + + * src/check_run.c, tests/check_check_pack.c: Fixed some missing + header includes + +2001-10-26 00:25 amalec + + * src/check_pack.c: Fix packing of NULL strings (causing problems + under Solaris) + +2001-10-26 00:17 amalec + + * tests/check_check_pack.c: Minor change to pack tests to ensure + that tests don't pass accidentally + +2001-10-25 02:45 amalec + + * ChangeLog: Updated ChangeLog + +2001-10-25 02:44 amalec + + * depcomp: Added new automake file + +2001-10-25 02:43 amalec + + * NEWS, doc/index.html, doc/money/check_money.c, + tests/check_check_sub.c: Added comments on string functions to + NEWS, cleaned up money example, and fixed a signal unit test so + that it will pass under cygwin + +2001-10-24 19:25 amalec + + * Makefile.in, NEWS, aclocal.m4, configure, debian/Makefile.in, + debian/changelog, debian/files, doc/Makefile.am, doc/Makefile.in, + doc/tutorial.lyx, doc/money/Makefile.in, rpm/Makefile.in, + rpm/check.spec, src/Makefile.am, src/Makefile.in, src/check.h, + src/check_log.c, src/check_msg.c, src/check_msg.h, + src/check_print.c, src/check_run.c, tests/Makefile.am, + tests/Makefile.in, tests/check_check_fixture.c, + tests/check_check_fork.c, tests/check_check_limit.c, + tests/check_check_main.c, tests/check_check_master.c, + tests/check_stress.c, tests/ex_log_output.c, tests/ex_output.c, + tests/test_log_output.sh, tests/test_output.sh: Documentation + updates + +2001-10-23 01:57 amalec + + * src/check_msg.c, src/check_pack.c, src/check_pack.h, + tests/check_check_pack.c: Removed old ppunpack, renamed new_*, and + updated callers + +2001-10-23 01:26 amalec + + * src/check_msg.c, src/check_msg.h, src/check_pack.c, + src/check_run.c, tests/check_check_master.c, + tests/check_check_msg.c, tests/check_check_pack.c: Moved Check to + use new internal ppack routine, and fixed a nasty bug + +2001-10-20 01:27 amalec + + * src/check_msg.c, src/check_msg.h, src/check_pack.c, + tests/check_check_msg.c, tests/check_check_pack.c: New version of + receive_test_result passes unit tests + +2001-10-19 20:44 amalec + + * src/check_pack.c, src/check_pack.h, tests/check_check_fixture.c, + tests/check_check_pack.c: Changed punpack to return test and + fixture locs to preserve test information when teardown messages + are sent + +2001-10-17 03:15 amalec + + * src/check_run.c, tests/check_check_fixture.c: Checked setup + passes unit tests + +2001-10-13 18:13 amalec + + * src/Makefile.am, src/Makefile.in, src/check.c, src/check_msg.c, + src/check_msg.h, src/check_run.c, tests/check_check_msg.c: Replace + previous messaging implementation files with new module + +2001-10-13 08:05 amalec + + * src/check.c, src/check.h, src/check_log.c, src/check_msg.c, + src/check_pack.c, src/check_run.c, src/check_str.c, src/error.c, + src/error.h, tests/check_check_master.c, tests/test_log_output.sh, + tests/test_output.sh: Fully implemented new messaging back-end + based on pipes + +2001-10-10 20:01 amalec + + * Makefile.in, aclocal.m4, configure, debian/Makefile.in, + doc/Makefile.in, doc/money/Makefile.in, rpm/Makefile.in, + src/Makefile.am, src/Makefile.in, src/check.c, src/check_impl.h, + src/check_pack.c, tests/Makefile.in, tests/check_check_msg.c, + tests/check_check_pack.c: Updated messaging tests to use new + infrastructure + +2001-10-04 23:55 amalec + + * src/check.c, src/check.h, src/check_impl.h, src/check_pack.c, + src/check_pack.h, tests/check_check_pack.c: Completed + implementation of check_pack + +2001-10-02 17:38 amalec + + * doc/index.html, doc/tutorial.lyx, src/Makefile.am, + src/Makefile.in, src/check.c, src/check.h, src/check_magic.h, + src/check_msg.h, src/check_pack.c, src/check_pack.h, + tests/Makefile.am, tests/Makefile.in, tests/check_check.h, + tests/check_check_fixture.c, tests/check_check_fork.c, + tests/check_check_limit.c, tests/check_check_main.c, + tests/check_check_master.c, tests/check_check_msg.c, + tests/check_check_pack.c: First generation packing code as the + infrastructure to revising message passing between processes, to + accomodate context messages + +2001-09-28 02:20 amalec + + * src/check.c, src/check.h, src/check_impl.h, src/check_run.c, + src/list.c, src/list.h, tests/check_check_fixture.c, + tests/check_check_fork.c, tests/check_check_limit.c, + tests/check_check_master.c, tests/check_check_msg.c: Added + framework for support of checked fixture functions + +2001-09-27 18:08 amalec + + * src/: check.c, check_run.c: Refactored failure info functions + +2001-09-19 02:14 amalec + + * src/check.c, src/check.h, src/check_impl.h, src/check_magic.h, + src/check_msg.c, src/check_msg.h, src/check_print.c, + src/check_run.c, src/check_str.c, tests/Makefile.am, + tests/Makefile.in, tests/check_check.h, + tests/check_check_fixture.c, tests/check_check_main.c, + tests/check_check_master.c: Setup failure is working and partially + tested + +2001-09-15 01:15 amalec + + * tests/: check_check.h, check_check_fork.c, check_check_main.c: + Completed implementation of CK_NOFORK + +2001-09-08 00:12 amalec + + * src/: check_impl.h, check_msg.c, check_msg.h, check_run.c: + Implemented nofork mode + +2001-09-06 20:10 amalec + + * Doxyfile, configure.in, src/check.h, src/check_impl.h, + src/check_log.c, src/check_log.h, src/check_print.c, + src/check_print.h, src/check_run.c, tests/Makefile.am, + tests/Makefile.in, tests/check_check.h, tests/check_check_main.c: + Added initial control functions to control forking + +2001-09-05 18:48 amalec + + * src/check.c, src/check_msg.c, src/check_msg.h, src/check_run.c, + tests/check_check_msg.c: Completely abstracted the details of + messaging behind check_msg.c + +2001-09-01 02:12 amalec + + * src/: check.c, check_msg.c, check_msg.h, check_run.c: Ensure that + each subprocesses alloc the correct msg queue + +2001-08-30 03:00 amalec + + * src/check.c, src/check.h, src/check_msg.c, src/check_msg.h, + src/check_run.c, tests/check_check_msg.c: Eliminated passing of + msqid in unit tests + +2001-08-29 02:49 amalec + + * src/check_print.c, src/check_str.c, tests/check_check_limit.c: + Added test checking running empty suites + +2001-08-28 19:06 amalec + + * src/check_magic.h: Moved magic values to separate header + +2001-08-28 19:04 amalec + + * src/Makefile.am, src/Makefile.in, src/check.h, src/check_impl.h, + src/check_print.c, src/check_str.c, src/check_str.h, + tests/check_check_master.c, tests/check_check_msg.c: Separated + printing from string formating functions to allow better testing. + +2001-08-28 02:18 amalec + + * configure, configure.in, src/check_msg.c, src/check_msg.h, + src/check_run.c, tests/Makefile.am, tests/Makefile.in, + tests/check_check.h, tests/check_check_main.c, + tests/check_check_msg.c: Use pid/ppid as message queue key, + preliminary to removing _msqid from unit test functions + +2001-08-23 23:26 amalec + + * ChangeLog: Final ChangeLog for 0.7.3 release + +2001-08-23 23:25 amalec + + * NEWS: Document 0.7.3 in NEWS + +2001-08-23 23:13 amalec + + * debian/changelog: This time, fix debian changelog correctly + +2001-08-23 23:10 amalec + + * debian/changelog: Fixed maintainer email in debian changelog + +2001-08-23 01:08 amalec + + * ChangeLog, acinclude.m4, aclocal.m4, configure, configure.in, + debian/changelog, debian/check.doc-base.tut, debian/files, + rpm/check.spec: Updated acinclude.m4 to increase portability; fixed + a minor packaging bug in debian doc-base files + +2001-08-18 07:28 amalec + + * ChangeLog, doc/index.html: index.html changes + +2001-08-18 07:24 amalec + + * INSTALL, NEWS: NEWS and INSTALL changes + +2001-08-18 07:15 amalec + + * Doxyfile, configure, configure.in, + debian/check.postinst.debhelper, debian/check.prerm.debhelper, + debian/files, doc/Makefile.in, doc/tutorial.lyx, rpm/Makefile.am, + rpm/Makefile.in, rpm/check.spec, src/check.c, src/check.h, + src/check_log.c, src/check_msg.c, src/check_print.c, + src/check_run.c, tests/check_check_log.c, + tests/check_check_master.c, tests/check_check_msg.c, + tests/check_list.c, tests/check_stress.c, tests/ex_log_output.c, + tests/ex_output.c: Bug fixes and assorted cleanup prior to release + +2001-08-18 01:16 amalec + + * doc/money/: Makefile.am, Makefile.in: Added money example + Makefiles to CVS + +2001-08-18 01:13 amalec + + * doc/: Makefile.am, example.lyx, tutorial.lyx: Moved example.lyx + to tutorial.lyx + +2001-08-16 02:47 amalec + + * acinclude.m4, debian/Makefile.am, debian/Makefile.in, + debian/check.docs: Added leftover stuff in debian directory, + acinclude.m4 + +2001-08-16 02:45 amalec + + * Makefile.am, Makefile.in, aclocal.m4, configure, configure.in, + debian/check.doc-base.tut, debian/control, debian/docs, + doc/Makefile.am, doc/Makefile.in, doc/money/AUTHORS, + doc/money/COPYING, doc/money/ChangeLog, doc/money/INSTALL, + doc/money/Makefile.am, doc/money/Makefile.am.money, + doc/money/Makefile.in, doc/money/NEWS, doc/money/README, + doc/money/config.h.in, doc/money/configure, doc/money/configure.in, + doc/money/configure.in.money, doc/money/stamp-h.in, + rpm/Makefile.in, rpm/check.spec, src/Makefile.in, + tests/Makefile.in: Added configure check for Lyx with Linuxdoc + +2001-08-06 22:45 amalec + + * rpm/Makefile.in: Added rpm/Makefile.in + +2001-08-06 22:44 amalec + + * Makefile.am, Makefile.in, configure, configure.in, + debian/changelog, debian/check.dirs, debian/check.files, + debian/rules, doc/Makefile.am, doc/Makefile.in, doc/index.html, + doc/money/AUTHORS, doc/money/COPYING, doc/money/ChangeLog, + doc/money/NEWS, doc/money/README, rpm/check.spec: Can now build + complete debs + +2001-08-04 07:40 amalec + + * debian/README.Debian: Don't need README.Debian + +2001-08-04 07:26 amalec + + * debian/README.Debian, debian/changelog, debian/check.dirs, + debian/check.files, debian/check.postinst.debhelper, + debian/check.prerm.debhelper, debian/control, debian/copyright, + debian/dirs, debian/docs, debian/files, debian/rules, + doc/Makefile.am, doc/index.html: Added preliminary debian packaging + files + +2001-08-03 03:05 amalec + + * Makefile.am, Makefile.in, aclocal.m4, configure, configure.in, + doc/index.html, rpm/Makefile.am, rpm/buildrpm.sh: Added automatic + building of RPMs + +2001-07-31 18:51 amalec + + * doc/index.html: Update index.html for final release to main Check + website. + +2001-07-31 03:08 amalec + + * ChangeLog: Update ChangeLog + +2001-07-31 03:08 amalec + + * NEWS, configure, configure.in, doc/example.lyx, rpm/buildrpm.sh, + rpm/check.spec, tests/Makefile.am, tests/Makefile.in, + tests/ex_log_output.c, tests/test_log_output.sh: Update NEWS, docs, + and rpm building + +2001-07-30 22:10 amalec + + * ChangeLog: Update ChangeLog + +2001-07-30 22:10 amalec + + * doc/Makefile.in, tests/ex_log_output.c: Add neglected files + +2001-07-30 22:08 amalec + + * src/Makefile.am, src/Makefile.in, src/check_impl.h, + src/check_log.c, src/check_log.h, src/check_print.c, + src/check_print.h, src/check_run.c, tests/test_log_output.sh: + Reorganized printing and logging functions and implemented more + sophisticated logging + +2001-07-25 23:26 amalec + + * Makefile.in, aclocal.m4, config.h.in, configure, + doc/money/aclocal.m4, doc/money/config.h.in, doc/money/configure, + src/Makefile.in, tests/Makefile.in, tests/test_log_output.sh: Added + log tests + +2001-07-11 22:46 amalec + + * NEWS, README, doc/example.lyx, rpm/check.spec, src/check.h, + tests/check_check_log.c, tests/check_check_main.c: Updated docs + +2001-07-11 01:29 amalec + + * ChangeLog: Update ChangeLog + +2001-07-11 01:28 amalec + + * src/Makefile.in, src/check_log.c, tests/check_check.h, + tests/check_check_log.c, tests/check_check_master.c, + tests/check_check_sub.c, tests/test_output.sh: Completed testing + for multiple suite running, and reorganized files + +2001-07-11 01:26 amalec + + * src/: check_log.c, check_log.h: Commit file changes + +2001-07-11 01:25 amalec + + * src/: Makefile.am, check.h, check_run.c: Moved check_log.h + functions into check.h + +2001-07-10 02:10 amalec + + * ChangeLog: Commit ChangeLog + +2001-07-10 02:09 amalec + + * src/check.c, src/check.h, src/check_impl.h, src/check_run.c, + src/list.h, tests/Makefile.am, tests/Makefile.in, + tests/check_check.h, tests/check_check_log.c, + tests/check_check_main.c, tests/check_check_master.c, + tests/check_check_msg.c, tests/check_check_sub.c, + tests/check_list.c: Completed test for initial logging feature, and + added feature to run multiple suites through an SRunner + +2001-06-30 03:27 amalec + + * src/Makefile.in, src/check.h, src/check_impl.h, src/check_log.h, + src/check_run.c, tests/check_check_log.c, tests/test_output.sh: + Restructured printing to allow for logging function + +2001-06-29 02:40 amalec + + * src/: Makefile.am, Makefile.in: Add check_log.c to Makefile.am + +2001-06-29 02:33 amalec + + * tests/: Makefile.am, Makefile.in: Complete move of + check_check_log.c -- this time for real... + +2001-06-29 02:31 amalec + + * Doxyfile, src/check_log.h, tests/Makefile.am, tests/Makefile.in: + Complete move of check_check_log.c + +2001-06-29 02:30 amalec + + * tests/: Makefile.am, check_check_log.c, check_log.c: Moved + check_log.c to check_check_log.c + +2001-06-29 00:56 amalec + + * doc/money/stamp-h: Removed stamp-h + +2001-06-29 00:51 amalec + + * src/check_log.h, tests/check_log.c: Added skeleton files for + check logging + +2001-06-29 00:33 amalec + + * Doxyfile, configure, configure.in, src/check.h, + tests/Makefile.am, tests/Makefile.in: Additional doxygenation of + check.h + +2001-06-27 20:27 amalec + + * ChangeLog: Updated ChangeLog + +2001-06-27 20:25 amalec + + * configure, rpm/check.spec: Updated check.spec + +2001-06-27 20:21 amalec + + * ChangeLog: Update ChangeLog + +2001-06-27 20:20 amalec + + * NEWS, configure.in, doc/example.lyx, doc/money/check_money.c, + doc/money/configure, doc/money/configure.in, src/check.h, + src/check_run.c, tests/check_check_main.c, + tests/check_check_master.c, tests/check_check_msg.c, + tests/check_list.c, tests/check_stress.c: Completed + srunner_results, and added unit tests; changed srunner_nfailed to + srunner_ntests_failed and changed documentation. + +2001-06-27 00:51 amalec + + * Doxyfile, doc/example.lyx, src/check.h, src/check_run.c, + tests/Makefile.am, tests/Makefile.in, tests/check_check.c, + tests/check_check.h, tests/check_check_main.c, + tests/check_check_master.c, tests/check_check_msg.c, + tests/check_check_sub.c, tests/check_list.c, tests/check_stress.c: + Fixed a bug in srunner_failures, fixed a typo in the tutorial + documentation (thanks to Michael Tucker), and refactored + check_check + +2001-06-22 03:16 amalec + + * ChangeLog: Update ChangeLog + +2001-06-22 03:15 amalec + + * NEWS, doc/Makefile.am, doc/example.lyx, doc/index.html, + rpm/check.spec, tests/Makefile.am, tests/Makefile.in: Specfile + changes, updates to NEWS + +2001-06-22 02:37 amalec + + * ChangeLog: Update ChangeLog + +2001-06-22 02:36 amalec + + * src/check.h, src/check_run.c, tests/Makefile.am, + tests/Makefile.in, tests/check_check.c, tests/ex_output.c, + tests/test_output.sh: Changed test output, added end-to-end test, + and removed redundant field from TestResult struct + +2001-06-19 22:01 amalec + + * ChangeLog: Update changelog + +2001-06-19 21:59 amalec + + * src/check.h, src/check_run.c, tests/check_check.c: Added + accessors for TestResult and expanded unit test + +2001-06-12 19:29 amalec + + * ChangeLog: Updated ChangeLog + +2001-06-12 19:28 amalec + + * configure, configure.in, src/check.h, src/check_run.c, + tests/check_check.c: Added new tests for line number + +2001-06-04 19:58 amalec + + * ChangeLog, doc/index.html: Added homepage file in doc directory, + and updated change log + +2001-06-04 19:08 amalec + + * doc/Makefile.am, doc/example.lyx, rpm/check.spec: Cleaned up spec + file for RPM packaging + +2001-06-04 01:50 amalec + + * Makefile.am, Makefile.in, configure, configure.in, + doc/Makefile.am, rpm/check.spec: Added RPM spec file and added + additional documentation files + +2001-06-01 17:46 amalec + + * ChangeLog: Updated ChangeLog + +2001-06-01 17:44 amalec + + * Makefile.in, src/Makefile.in, src/check.c, src/check.h, + src/check_impl.h, src/check_msg.c, src/check_msg.h, + src/check_run.c, src/error.c, src/error.h, src/list.c, src/list.h, + tests/Makefile.in: GNUified source files with copyright notice + +2001-06-01 17:33 amalec + + * aclocal.m4, configure, configure.in, doc/Makefile.am, + doc/example.lyx: Made building docs conditional on presence of lyx + and sgml2html + +2001-06-01 00:35 amalec + + * ChangeLog: Update ChangeLog + +2001-06-01 00:34 amalec + + * configure.in, doc/Makefile.am: Modified Makefile.am to include + docs in dist + +2001-06-01 00:26 amalec + + * ChangeLog, Makefile.am, Makefile.in, aclocal.m4, configure, + configure.in, doc/Makefile.am, src/Makefile.in, tests/Makefile.in: + Added Automake support to create and install documentation + +2001-05-31 23:30 amalec + + * doc/money/: config.h, config.log, config.status: Removed unneded + files + +2001-05-31 17:37 amalec + + * ChangeLog, ChangeLogOld: Updated change logs + +2001-05-31 17:35 amalec + + * doc/example.lyx: Commit changes to example, get things in synch + +2001-05-31 17:32 amalec + + * doc/money/: COPYING, ChangeLog, INSTALL, Makefile.am, + Makefile.in, NEWS, README, aclocal.m4, check_money.c, config.h, + config.h.in, config.log, config.status, configure, configure.in, + money.c, money.h, stamp-h, stamp-h.in: Hopefully finally solved CVS + problems and commited changes to money example and example.lyx + +2001-05-31 01:48 amalec + + * doc/money/AUTHORS: Trying to commit added files... + +2001-05-31 01:45 amalec + + * doc/example.lyx: Cleaning up CVS.. + +2001-05-31 01:37 amalec + + * ChangeLogOld: Trying to update documentation and change log, and + statisfy CVS... + +2001-05-31 01:34 amalec + + * ChangeLog: Refined documentation, and moved old change log + information to ChangeLogOld + +2001-05-31 00:44 amalec + + * doc/example.lyx: Added complete example to accompany + documentation + +2001-05-30 05:25 amalec + + * Makefile.in: Added example and expanded documentation + +2001-05-30 00:42 amalec + + * AUTHORS, Makefile.in, README, stamp-h.in, COPYING, ChangeLog, + INSTALL, Makefile.am, NEWS, aclocal.m4, config.h.in, configure, + configure.in, install-sh, missing, mkinstalldirs, src/Makefile.am, + src/Makefile.in, src/check.c, src/check.h, src/check_impl.h, + src/check_run.c, doc/example.lyx, src/check_msg.c, src/check_msg.h, + src/error.c, src/error.h, src/list.c, src/list.h, + tests/Makefile.am, tests/Makefile.in, tests/check_check.c, + tests/check_check_msg.c, tests/check_list.c, tests/check_stress.c: + Initial revision + +2001-05-30 00:42 amalec + + * AUTHORS, Makefile.in, README, stamp-h.in, COPYING, ChangeLog, + INSTALL, Makefile.am, NEWS, aclocal.m4, config.h.in, configure, + configure.in, install-sh, missing, mkinstalldirs, src/Makefile.am, + src/Makefile.in, src/check.c, src/check.h, src/check_impl.h, + src/check_run.c, doc/example.lyx, src/check_msg.c, src/check_msg.h, + src/error.c, src/error.h, src/list.c, src/list.h, + tests/Makefile.am, tests/Makefile.in, tests/check_check.c, + tests/check_check_msg.c, tests/check_list.c, tests/check_stress.c: + Import into Sourceforge. Previous CVS version information resides + on Arien's local machine + diff --git a/HACKING b/HACKING new file mode 100644 index 0000000..e0cd7f2 --- /dev/null +++ b/HACKING @@ -0,0 +1,213 @@ +Coding Standards +================ + +Please try and stick to the GNU coding standards. A lot of hard work +went into making Check compatible with the standards, and would be +nice if that work didn't erode. I decided on the standards because +they work well for a lot of programs much bigger than Check. Ok, +since you're wondering, the advantages of sticking to the standards +are three-fold: + + 1) consistent style within the project + + 2) being familiar with the standards lets you work on lots of + different GNU standards-compliant projects pretty easily + + 3) it reduces the number of decisions that must be made + +Release Process +=============== + +To create a release one will need to be a member of the libcheck organization +on GitHub. If you are not a member, a current member can add you +by going to: + https://github.com/orgs/libcheck/people +and submitting an invite. + +1) To create a release, start in a configured in-place +checkout of the Check project: + +$ git clone https://github.com/libcheck/check.git +$ cd check + +2) Determine the version of Check to release, and update +the configure.ac script: + +AC_INIT([Check], [0.10.1], [check-devel at lists dot sourceforge dot net]) +CHECK_MAJOR_VERSION=0 +CHECK_MINOR_VERSION=10 +CHECK_MICRO_VERSION=1 + +(Remember to update both the AC_INIT line and each of the CHECK_*_VERSION fields). + +3) Update the header in the NEWS file to mention the release: + +Sun Aug 2, 2015: Released Check 0.10.1 + 2015-08-02 19:21:14 +0000 + based on hash f399542eeceb97703bca496b68bb39044e8baa01 + +4) Update index.html mentioning the release. Look for the following: + + +5) Attempt to build the release locally + +$ autoreconf -i +$ ./configure +$ make distcheck + +If this passes, a tarball with the current release number will be in the current +directory. Make note of this, as it will be uploaded to GitHub later. + +6) Commit the changes to configure.ac, NEWS, and index.html to the Check project's +master branch, with the commit message: +"Update for release" + +7) Log On to GitHub and navigate to: + +https://github.com/libcheck/check/releases + +Click "Draft a New Release". + +Enter the release version to the Tag Version box, and enter the +git hash into the Target selector. + +Fill in the Release Title field. + +Describe the release with something similar to the following: +===== + +Please test it out and report any problems you might have. + +Changes: + +===== + +Attach the tarball for the release, then publish the release. + +8) Use the following template to announce the release via email: +===== +Subject: check-X.Y.Z released +Hi, + + +Please test it out and report any problems you might have. + +https://github.com/libcheck/check/releases + +Thanks, +`whoami` + + +===== + +9) Update the development header in the NEWS file and commit the result. + +10) Push updated website (see section below) + +Congratulations, you are done! + + +Update website +============== + +The Check website is automatically hosted from the contents of +the gh-pages branch in the Check git repository. To update +the website, merge the contents of the master branch into +the gh-pages branch. + +To update the generated documentation for the website: + +$ git remote -v +github https://github.com/libcheck/check.git (fetch) +github https://github.com/libcheck/check.git (push) +$ git fetch github +$ git checkout github/gh-pages -b gh-pages +Branch gh-pages set up to track remote branch gh-pages from github. +Switched to a new branch 'gh-pages' +$ git merge github/master +First, rewinding head to replay your work on top of it... +Fast-forwarded gh-pages to github/master. +$ autoreconf -i +$ ./configure +$ make clean +$ make +$ make doc/check_html +$ make doc/doxygen +$ git add doc +$ git commit -m “Update documentation” +$ git push github gh-pages:gh-pages + + +Automatic building of pull requests +=============== + +The GitHub project is configured to build pull requests either when +asked or automatically. This is done using the GitHub Pull Request +Builder Plugin. Documentation here: + + https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin + +When a new pull request is opened in the project and the author of the pull request +isn't white-listed, builder will ask "Can one of the admins verify this patch?". + +An admin can add one of the following comments to the pull request: + "ok to test" to accept this pull request for testing + "test this please" for a one time test run + "add to whitelist" to add the author to the whitelist + +If the build fails for other various reasons you can rebuild. + + "retest this please" to start a new build + +When a build is triggered a job on the Jenkins instance will start: + + https://check.ci.cloudbees.com/job/github-merge-builder/ + +When complete, a comment will be added to the pull request, informing +of the result. + +An admin can be added to the Jenkins instance by adding a username +to the "Admin list" setting under the "GitHub Pull Request Builder" +section here: + + https://check.ci.cloudbees.com/configure + +This works because there is a user in the libcheck organization, +"check-builder", which the Jenkins instance uses to install a +git hook and push comments to pull requests. + + +Using gcov +=============== + +The gcov tool can be used to determine the unit test coverage in Check +itself. This is currently supported on GNU/Linux only. To enable the +necessary build time flags, add the following argument to the +configure script: + + --enable-gcov + +Once the unit tests have been run with + +$ make check + +assuming the terminal is in the top src directory, the following will +generate summary information using gcov: + +$ cp src/*.c src/.libs/ +$ cd src/.libs +$ for file in `ls *.c`; do + gcov -f $file > $file.gcov.summary.txt + mv $file.gcov $file.gcov.txt + done + +The *.gcov.txt files will contain the source code annotated with +the number of times each line was executed. The .*gcov.summary.txt +files will contain a line execution summary per function. + +To determine the line execution summary for all of Check, either +the gcovr tool can be used, or the following quick-and-dirty script: + +$ for file in ls *.summary.txt; do cat $file; done \ + | grep "Lines executed" | cut -d ":" -f 2 | tr -d "%" \ + | awk '{checked+=$1*$3/100; total+=$3} END {print checked/total*100}' diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..27d2531 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,58 @@ +## Process this file with automake to produce Makefile.in + +## run tests after everything else + +SUBDIRS = lib src doc . checkmk tests + +## FIXME: maybe we don't need this line + +AM_MAKEINFOFLAGS = -I$(top_srcdir)/doc/example + +## what to clean + +CLEANFILES = *~\ + $(PACKAGE)-$(VERSION).tar.gz\ + ChangeLog.bak + +## what additional things to distribute + +include_HEADERS = check_stdint.h + +EXTRA_DIST = check.pc.in $(m4data_DATA) xml/check_unittest.xslt \ + CMakeLists.txt src/CMakeLists.txt tests/CMakeLists.txt lib/CMakeLists.txt \ + cmake + +## install docs +docdir = $(datadir)/doc/$(PACKAGE) +doc_DATA = ChangeLog NEWS README COPYING.LESSER + +## install check.m4 with AM_PATH_CHECK in it +m4datadir = $(datadir)/aclocal +m4data_DATA = check.m4 + +## install check.pc +pcdatadir = $(libdir)/pkgconfig +pcdata_DATA = check.pc + +DISTCLEANFILES = check_stdint.h + +ACLOCAL_AMFLAGS = -I m4 + +README: + fgrep -v "Build Status]" $(top_srcdir)/README.md > $@ + +doc/check_html: + $(MAKE) -C doc check_html + +doc/doxygen: + $(MAKE) -C doc doxygen + +# check we can do a clean build, including docs. +# perhaps we should check for out of date (svn st -u) and modified files. +prereleasecheck: doc/check_html doc/doxygen + -$(MAKE) distclean + autoreconf -i && ./configure \ + && ulimit -c 0 && \ + $(MAKE) distcheck + +.PHONY: prereleasecheck diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..a3b62c1 --- /dev/null +++ b/NEWS @@ -0,0 +1,625 @@ +Fri Oct 20, 2017: Released Check 0.12.0 + 2017-10-20 10:00:00 +0000 + based on hash c472c743d7c9f01ae9ea6a0e8e08132251b62abd + +* Fix out-of-tree builds with CMake. + Issue #86 + +* Fix issue found with Clang regarding invalid suffix on a literal + Issue #110 + +* Check now responds to a few errors in a more clear way when it cannot run tests. + PR #122, #123 + +* Fix missing pid_t definition in check.h on Windows + Issue #78 + +* The maximum message size of check assertions is now configurable. + Issue #127 + +* Check support added for Visual Studios 2010, 2012, 2013, 2015, and 2017 both for x86/64 and ARM. + PR #129, Issue #125 + +* Changed license of example CMake files to BSD (was previously LGPL). + Issue #131 + +* Fix issue with floating point macros on MinGW + Issue #101 + + +Sat Dec 17, 2016: Released Check 0.11.0 + 2016-12-17 15:00:00 +0000 + based on hash 7c9cfb4b13124b93a63e60b3c681c2bf4f2723ce + +* Avoid issue in unit test output checking where a shell's built-in printf + command does not work properly, but the printf program itself is correct. + +* Emit only valid XML characters in XML logging (assumes ASCII encoding). + Bug #103 + +* Add LGPL header to files where it was missing; update FSF address in LGPL headers + Bug #110 + +* Strip timestamps from examples using filterdiff if available. This + allow build output to be reproducible. + Bug #112 + +* Use double slash for regular expressions in checkmk for better Solaris support. + +* Improve CMake build files for better Visual Studio 2015 support. + Pull Request #19 + +* Fix potential SIGSEGV in Check related to the disk filling up during a test. + Pull Request #21 + +* Support added for applying tags to test cases and selectively running + test cases based on tags. + Pull Request #44 + +* Macros for comparing memory regions (ck_assert_mem_eq, ck_assert_mem_ne) + have been added. + Pull Request #64 + +* Macros for comparing floating point numbers have been added. + Pull Request #69 + +* Macros for comparing string, but allowing for NULL (ck_assert_pstr_eq, + ck_assert_pstr_ne) have been added. + Pull Request #80 + +* Macros for checking if a pointer is NULL or not have been added. + Pull Request #87 + + +Sun Aug 2, 2015: Released Check 0.10.0 + based on r1217 (2015-08-02 19:21:14 +0000) + +* CMake on MinGW and MSVC was unable to find time related types because + time.h was not included. This header is now included for the checks. + Patch #53. + +* If the test runner process catches a SIGTERM or SIGINT signal the running + tests are now also killed. + Patch #52. + +* If Check is compiled without support for fork(), the behavior of + functions which require fork() to be useful have been changed. + Functions that attempt to set CK_FORK mode are no-ops, + check_fork() returns in failure, and check_waitpid_and_exit() + exits in failure. + +* Add space around operators in assert messages for readability. + Bug #102. + +* Use mkstemp() if available instead of tmpfile() or tempnam(). + Patch #51. + +* Fix issue with string formatting in ck_assert(), where using + the % operator would be interpreted as a string formatter. Bug #96. + +* In nofork mode, the location of a failed assertion within a test + case was lost if that test case has a checked teardown fixture + (even if that fixture function is empty). This is now fixed. + Bug #99 + + +Sat July 26, 2014: Released Check 0.9.14 + based on r1174 (2014-07-03 18:43:49 +0000) + +* Changes to (unofficially for now) support Solaris and AIX platforms. + +* Fix issue with checked teardown functions in CK_NOFORK mode. If + the teardown function called an assertion that failed, an + infinate loop would result. Bug#98. As a result of the change, for now + checked teardown functions that fail in CK_NOFORK mode will + not cause the test to fail. + +* Allow checked fixtures when compiled without fork(). Previously + such setup/teardown functions were disabled, as the full contract + for checked fixtures could not be honored. Checked fixtures + in CK_NOFORK mode are now closer to the contract, and are now + enabled. + +* Various code cleanup, including changes for compiling Check on + c++ compilers Clang and g++ (which are less forgiving than their + c counterparts). + +* Re-enable internal unit tests, which verify which line numbers are + reported for unit test failures. (The tests were unintentionally + disabled in a previous release). + + +Fri May 30, 2014: Released Check 0.9.13 + based on r1137 (2014-05-26 21:03:09 +0000) + +* When a test assertion fails, exit() was invoked. This results in any + registered exit handlers being invoked. A test should not be relied + upon to clean up if it fails. Instead, _exit() will be used to signal + a test failure, to prevent exit handlers from being invoked. + +* Fix issue with string formatting in ck_assert_(u)int_* calls, where using + the % operator would be interpreted as a string formatter. Bug #96. + +* If the LOG/XML/TAP file name is set to "-" either through the + srunner_set_log() srunner_set_xml() or srunner_set_tap() calls + or through the related environment variables, the logged data will be + printed to stdout instead of a file. This is mainly to support using TAP + for fixtures which expect the results to be reported via stdout. However, + it is available via all of Check's logging modalities. + +* For CMake builds, check_stdint.h was not being installed. This is now + fixed. + +* Check's example under doc/example now also works for CMake projects + using Visual Studios and MSVC. This includes an example CMake + configuration. + + +Mon Jan 20, 2014: Released Check 0.9.12 + based on r1054 (2014-01-16 23:08:03 +0000) + +* Additional unit tests created for internal and external Check + APIs. + +* Check now compiled on Windows using MSVC when using CMake and + NMake. All unit tests pass, though shell script based ones need + to be run in the MSYS environment. + +* Check now compiles on Windows using Visual Studio 10 + when using CMake. check_check passes when run from Visual Studios. + +* Always capture the start and end times of tests when using + NO_FORK mode. Previously the end time was not captured, + resulting in arbitrary durations being recorded when tests + failed. Bug #87. + +* Added additional configure script checks for support of + timer_create() on the target system. This allows for + OpenBSD to compile and run all Check's unit tests successfully. + +* Added a unit test, check_mem_leaks, which can be used against + valgrind to test for memory leaks. No memory leaks were found. + +* Added tcase_add_loop_test support in checkm. Patch from patches #46. + +* Add support for logging in Test Anything Protocol (TAP) format. + +* Refactor Check's assertions to be more like the assert() call in + assert.h, in that static source code analyzers can use gcc attributes + in the header to make assumptions about the flow of the code. See + feature request #29. + +* fix ck_assert_ptr_* causing const compilation warnings. Patch from + bug #91. + +Wed, Nov 4, 2013: Released Check 0.9.11 + based on r856 (2013-11-04 02:09:21 +0000) + +* Check's unit tests pass when compiled out of the source tree. + +* Check compiles for Windows using the MinGW/msys environment (without using fork), and all unit tests pass. + +* Check compiles for Windows using the Cygwin environment, and all unit tests pass. + +* Check compiles for Windows using MinGW in Linux (without using fork), and all unit tests pass using wine 1.4. + +* Check compiles for Windows using MinGW-w64 in Linux (without using fork), and all unit tests pass using wine 1.4. + +* On systems without timer_settimer, use setitimer (if available) to get + subsecond unit test timeouts. If setitimer is unavailable, fallback + on alarm. + +Thu, Apr 18, 2013: Released Check 0.9.10 + based on r743 (2013-04-18 11:27:03 +0200) + +* Support 64bit int for __ck_assert_int. Patch from bug #3599471 + +* Add equivalent uint variants for __ck_assert_int. Patch from bug #3600433. + +* Detect if the system has a C99 compliant version of the printf related + functions for check to use, and if not use an implementation provided by + check. + +* Updated HACKING and release procedure in Makefile.am. + +* Detect if the system has clock_gettime() available, and if not use an + implementation provided by check. clock_gettime() is used to measure + test durations. The implementation for OSX uses OSX specific system calls + to get the time. For all other systems, clock_gettime() does nothing. + +* Updated documentation in check.h to reference new check API. + +* Remove usage of deprecated fail(), fail_if(), and fail_unless() calls from + check's unit tests. + +* Fix implementation of putenv in check's libcompat for systems that do not + provide it. + +* Fix implementation of unsettenv in check's libcompat for systems that do + not provide it. + +* Improvements to the new Check API: new comparison functions for pointers: + ck_assert_ptr_(eq|ne). + +* Test timeouts can now be in nanosecond precision. The tcase_set_timeout + call, and CK_DEFAULT_TIMEOUT and CK_TIMEOUT_MULTIPLIER environment + variables now can accept floating point arguments. + +* Cleanup compile warnings, patch #3579199 on SF. + +* Renamed Check's internal list functions to start with check_, patch #3448601 on SF. + +Mon, Oct 22, 2012: Released Check 0.9.9 + based on r637 (2012-10-22 13:54:14 +0200) + +* Measure test duration and print in XML output. + Feature request #3521371 on SF, but reimplemented. + +* Added contrib/XML_for_JUnit.xsl from feature request #3521371 on SF. + +* Added support for setting log files via environment variables. + Patch #3576713 on SF. + +* Added better pkg-config and subunit support, patch #3417041 on SF. + +* Make tests/test_vars.in bourne shell compatible, bug #3472578 on SF. + +* Added ck_ prefix to mutex_lock variable, to avoid name clash on Solaris. + Solves bug #3472574 on SF. + +* In autoconf, request system extensions to generate 64-bit safe code, + solution from patch #2803433 on SF. + +* Fix for mutex deadlock when killing threads, patch #3564640 on SF. + +* Make XML output well-formed, solution from patch #3575642 on SF. + Solves bug #3485651 also. + +* Fix buggy duration calculation, bug #3575451 on SF. + +* A more complete CMake / MSVC patch for those interested in pursuing + Windows development with Check and Visual Studio. See + patches/mloskot.windows.patch. + +* Added instructions for improving the speed and output of `make + check' when using Automake. See contrib/improved_make_check/. + +* Added a chapter in the documentation for selective running of tests. + +* Changed how the message pipe is read. Before, the whole file was copied to + RAM with realloc, giving problems with huge allocations for repetetive + tests, the problem was visible for a specific GStreamer test case. + +* Improvements to the new Check API: documentation, macros that allow + multiple evaluation, unit tests, and new + ck_assert_(str|int)_(lt|le|gt|ge) comparison functions. + +* Made the new Check API primary and use it to define macros from old Check API + +* Added checkmk, a tool for reducing "boilerplate coding" when writing + unit tests with check. + +* Added xslt link to xml output, added display of iteration field into xslt + stylesheet and moved it to directory accessible from web page root + +* Added longjmp to fail function to ensure that no code will be executed in test + function after failed assertion + +* Fix dead assignments and several possible NULL pointer dereferences + +Tue, Sep 22, 2009: Released Check 0.9.8 + based on r559 (2009-09-23 21:00). + +* Fix CHECK_MICRO_VERSION, left at 6 in 0.9.7 by mistake. + +Tue, Sep 22, 2009: Released Check 0.9.7 + based on r552 (2009-09-22 09:26). + +* Added CK_SUBUNIT support for outputting test information in the subunit wire + protocol. See the check manual for more information. (Contributed by Robert + Collins). + +* Added code and tests for timeout scaling via environment variable. + Feature requested in tracker item #1549835 on sourceforge. + +* Added documentation for testing exit values with tcase_add_exit_test(). + +* Add make_macros perl script from somebody (who?) + +* add type to check_type error message + +* add contrib dir with xslt transform + +* function exist testing support (patch #1726574). + +* introduce HAVE_WORKING_SETENV to protect tc_timeout_env usage + +* support running tests with multiple pthreads (Daniel Gollub, closes 1391527) + +* partial MSYS/MinGW support + +Mon, Dec 29, 2008: Released Check 0.9.6 + based on r453 (2008-12-01 22:14:15). + +* 'make distcheck' does not work out of the box. Disable the two + top lines in doc/Makefile.am and it shall pass. Will have to + be fixed later. + +* add call to AC_REPLACE_FUNCS([strsignal]) +* add new rpl_strsignal following rpl_(re)malloc template, body + of function due to Roland Illig + -- hopefully closes 1629755 + +* add missing NULL argument to fail* varargs macro calls +* define incorrect tests for __GNUC__ only + -- both per Roland Illig in bug 1677391 + +* define CK_ATTRIBUTE_UNUSED for GCC >= 2.95, closing: + [ 1674626 ] compile error with non defined __attribute__ compiler + +* Fixed error in documentation example Makefile.am, bug #1888237 + +* Fixed spelling (patch #1652630) + +* Handle NULL in srunner_add_suite(). Fixes #1624887 + +* add CK_FORK_GETENV to enum fork_status and delete CK_FORK_UNSPECIFIED + +* call strdup on result from strsignal to avoid clobbering it +* add Torok Edwin to AUTHORS + +* add CK_TEST_RESULT_INVALID to enum test_result + +* add CK_CTX_INVALID to ck_result_ctx and don't use -1 anymore + +* count checks in setup() as well; patch due to Roland Stigge + +* use int __attribute__((unused)) _i instead of + int _i __attribute__((unused)) + per gcc-3.3.5 request from Sebastian Trahm + +* rename signal to _signal in _tcase_add_test to avoid a + symbol clash with /usr/include/sys/signal.h on OS X. + +* define rpl_malloc and rpl_realloc for platforms where + !malloc(0) and !realloc(0,0), such as AIX, because configure + goes and redefines malloc/realloc in this case... + +* SVNChangeLog patch from Robert Collins + +* Incorporated patch from Debian for debian bug #395466. This fixes + 'AM_PATH_CHECK causes "possibly undefined macro" errors'. + +* Added new Check fail API. Implemented on top of fail_unless. Future + versions will reverse this so fail_unless is implemented on top of the + ck_assert API. This API is not documented yet, will probably not be fully + released until 0.9.8, when it will be possible to choose API. + +Tue, Nov 21, 2006: Released Check 0.9.5 + +* Fixed code coverage support to work with gcc4 and buggy libtool. + +* Changed loop test iteration variable from i to _i. Added example of + loop test usage to documentation. + +* Fixed distcheck target by adding SVNChangeLog to EXTRA_DIST. + +* Fixed signal string problem in tests. Strings differed between + OSes, now we use strsignal(). Fixes Sourceforge bug #1539828. + +* Fixed problem with process group ID, especially visible on Solaris + and LynxOS. Fixes Sourceforge bugs #1407360 and #1539828. + +Fri, Oct 13, 2006: Released Check 0.9.4 + +* Updated manual and converted from DocBook to Texinfo. + +* Added pkg-config support. + +* Added Libtool support to build both static and shared libraries. + +* Removed debian/ and rpm/ directories for building packages. + Downstream maintainers can easily handle this. + +* Updated GNU Build System to use modern Autotools. + +* Fixed sourceforge bug #1327225, two teardown checked fixtures + segfaults. + +* Added a new kind of test, looping tests, which are called with a new + context for each loop iteration. This makes them ideal for table + based tests. Previously, with the loop in the test itself, only the + first error was caught and then the test would exit. Now all errors + are shown at once which should help in debugging + +* Added possibility to turn off timeout tests in check's own unit tests + through configure option --disable-timeout-tests. + +* Added coverage analysis for check's own unit tests. + +Thu, Aug 25, 2005: Released Check 0.9.3 + +Applied debian patches from debian maintainer. + +Fixed documentation bug #1216502. + +gcc 2.95.3 compatibility fixed (patch #1161654, bug #1211672). + +Messaging refactored to make it work with forking tests, and also with +threading tests on linux 2.4. Added check_fork and check_waitpid_and_exit +to be used for forking tests. (bug # 1233585) + +Timeout error message changed (feature request #1121452, bug #1160305). + +Fix check.spec for fc3 x86_64 (patch #1111782) + + +Fri, Nov 12, 2004: Released Check 0.9.2 + +Use strsignal to print describing text for signals. +Documented signals handling and timeouts. +Changed failure message for fail_if. +Added support for timeouts on tests, enabling detection of eternal loops. +Changed name on function list_create to check_list_create to avoid name clash. +Applied ANSI C99 patch (#1047014) for macro var args. +Cleaned up the self test verification to simplify merging of new tests. +Fixed debian and rpm targets + +Added support for testing on expected signals. Implementation courtesy of +Lucas Di Pentima and Cesar Ballardini. + + +Fri, Sep 3, 2004: Released Check 0.9.1 + +Updated tutorial with new features. +Added support for XML output of the test results, courtesy of Frederic Peters. +Fixed setup bug from forum, failure in setup did not abort test in nofork mode. +Applied varargs patch (#933411) and added test cases. +Applied fail_if (#709167) patch. +Applied 'newbies' patch #995028 for autoconf doc. +Applied doc patch #995028 from Bill Barnard. +Fixed portability problems tests by changing == to =. +Changed copyright according to bug report. +Applied patch 796705. Replacing _exit with exit. +Applied patch for bug 793671. + + +Mon, May 17, 2004: Released Check 0.9.0 + +Run fixture teardowns in reverse order to setup +Plugged some memory leaks. +Added test name to log outputs. +Applied patch (802160) for distcheck bug (579604). +Fixed log printouts for nofork mode. +Updated documentation and converted to DocBook. + +Added a new print mode, CK_ENV, that gets the print mode from the +environment variable CK_VERBOSITY. + +Made tcase_free and suite_free static. This may break existing test +programs. Everything is now freed when srunner_free is called. + + +Mon Oct 21, 2002: Released Check 0.8.4 + +Fixed pipe issues. +Allow to use check.h from C++. +Plugged some memory leaks. + + +Fri May 24, 2002: Released Check 0.8.3 + +Fixed various build problems. Fixed a problem with check.m4. +Documentation updates. + + +Mon Apr 15, 2002: Released Check 0.8.2 + +Added version information to headers and library. Added an autoconf +macro to easily integrate check into projects that use autoconf. + +Removed limitations on line number, message and buffer sizes. + +Declared constant string parameters as const. + + +Sat Mar 2, 2002: Released Check 0.8.1 + +Changed license to LGPL. + +Fixed bug in running checked setup in nofork mode. + + +Wed Oct 24, 2001: Released Check 0.8.0 + +Support running in a nofork mode. Defined a checked fixture as well as +an unchecked fixture, support failing in checked and uncheck fixture +functions, and errors in checked fixture functions. Rewrote the +back-end to use pipes, rather than message queues. + +Reimplemented printing functions in terms of string formatting +functions, to allow better testing of output without full end-to-end +testing. + +Renamed some public constants to use the CK_ naming convention. This +will break existing test programs. + +Documented the new features, and changed the distribution to include +sgml and html files, as well as lyx files, as many people don't have +lyx. + + +Thu Aug 23, 2001: Released Check 0.7.3 + +Fixed the Autoconf Lyx check in acinclude.m4 so that configure works +on Solaris systems (and hopefully others), and cleaned up a minor +problem in Debian packaging. + + +Fri Aug 17, 2001: Released Check 0.7.2 + +Automated RPM packaging, and included debian packaging. The makefiles +now has an rpm target (the RPMFLAGS variable can be set to add +additional flags to RPM). Debian packages are built the ordinary way +(dpkg-buildpackage). + +Moved the example*.* files to tutorial*.*, since the docs really are +tutorials. Beefed up the tutorial docs to add clarity to the behavior +of fixture setup/teardown (based on a helpful critique by Fred Drake), +and to document the static nature of unit tests demanded by the bug +fix below. + +Many bugfixes: added -Wall to the CCFLAGS for gcc, and fixed a mess of +warnings that resulted. Changed a bizarre naming mismatch in +tcase_set_fixture (masked by the lack of compile warnings), and made +unit tests static (both bugfixes suggested by Fred Drake). Also added +a more sophisticated test of Lyx to (hopefully) ensure that Lyx +supports linuxdoc (but it's not clear to me how to test that for +sure). + + +Wed Jul 30, 2001: Released Check 0.7.1 + +Reorganized printing and logging functions to allow for a less +primitive logging function. Logging is now documented in the tutorial +documentation. + + +Wed Jul 11, 2001: Released Check 0.7.0 + +Included a primitive logging function (at the moment, it only prints a +copy of the CRVERBOSE output to the log file), added the ability for +an SRunner to run multiple suites (and reorganized the Check tests to +take advantage of that), and added the magic to allow Check to be used +with C++. + +Also added Doxygen markup to the header file, but I'm not terribly +satisfied withe clarity of the output. I may switch to CWEB... Next +release should include API docs and improved logging, if nothing else +comes up... + + +Wed Jun 27, 2001: Released Check 0.6.1 + +Bug fix for srunner_failures (bad version actually returned all +results), added srunner_results to do what srunner_failures used to +do, and added corrected unit tests for both. + +Also changed the API for reporting the number of failed tests from +srunner_nfailed to srunner_ntests_failed, to harmonized better with +new function srunner_ntests_run. This unfortunately may break some +unit tests slightly -- that's why the major release number is 0 :-) + + +Thu Jun 21, 2001: Released Check 0.6.0 + +Features improved unit test reporting options, more complete unit +tests, and end-to-end test, and a full API into TestResults + + +Check 0.5.2 +Minor edits +Check 0.5.1 +GPL compliance release +Check 0.5.0 +Initial public release diff --git a/README.md b/README.md new file mode 100644 index 0000000..6196d30 --- /dev/null +++ b/README.md @@ -0,0 +1,57 @@ +# About Check + +[![Travis Build Status](https://travis-ci.org/libcheck/check.svg?branch=master)](https://travis-ci.org/libcheck/check) +[![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/github/libcheck/check?svg=true)](https://ci.appveyor.com/project/libcheck/check/branch/master) + + +Check is a unit testing 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. + +See https://libcheck.github.io/check for more information, including a +tutorial. The tutorial is also available as `info check`. + +# Installation + +Check has the following dependencies: + +* [automake](https://www.gnu.org/software/automake/)-1.9.6 (1.11.3 on OS X if you are using /usr/bin/ar) +* [autoconf](https://www.gnu.org/software/autoconf/)-2.59 +* [libtool](https://www.gnu.org/software/libtool/)-1.5.22 +* [pkg-config](https://www.freedesktop.org/wiki/Software/pkg-config/)-0.20 +* [texinfo](https://www.gnu.org/software/texinfo/)-4.7 (for documentation) +* tetex-bin (or any texinfo-compatible TeX installation, for documentation) +* POSIX [sed](https://en.wikipedia.org/wiki/Sed) + +The versions specified may be higher than those actually needed. + +## autoconf + + $ autoreconf --install + $ ./configure + $ make + $ make check + +in this directory to set everything up. autoreconf calls all of the +necessary tools for you, like autoconf, automake, autoheader, etc. If +you ever change something during development, run autoreconf again +(without --install), and it will perform the minimum set of actions +necessary. + +## cmake + + $ mkdir build + $ cd build + $ cmake ../ + $ make + $ CTEST_OUTPUT_ON_FAILURE=1 make test + +# Linking against Check + +Check uses variadic macros in check.h, and the strict C90 options for +gcc will complain about this. In gcc 4.0 and above you can turn this +off explicitly with `-Wno-variadic-macros`. In a future API it would be +nice to eliminate these macros. diff --git a/THANKS b/THANKS new file mode 100644 index 0000000..4b47bc8 --- /dev/null +++ b/THANKS @@ -0,0 +1,10 @@ +Design suggestions: + Fred Drake (checked fixture functions) + Jim O'Leary (forkless mode) + +Downstream maintainers: + Robert Lemmen (Debian) + Tom 'spot' Callaway (Fedora Extras) + +If you helped out with Check in some way and would like to be listed +here, send a patch to . diff --git a/TODO b/TODO new file mode 100644 index 0000000..3ecf60a --- /dev/null +++ b/TODO @@ -0,0 +1,153 @@ +TODO +==== + +The following are considered bugs in Check. If you have a fix, please +post it in the patch tracker on http://sourceforge.net/projects/check +or send it to . Bug +fixing is considered more important than feature requests at this +point. Please check the Sourceforge trackers before submitting. + +Documentation +============= + +[0.9.4] * Convert to info format and update. +[0.9.4] * Remove old SGML documentation. +[0.9.4] * Fix building of documentation that relies on diff +[0.9.4] * Add html generation of Texinfo docs. +[0.9.4] * Create initial and final versions of money example. +[0.9.4] * Update tutorial so that it works with modern tools. +[0.9.5] * Clarify looping tests and give example of usage. +[ ] * Document pkg-config usage, note that old macro usage is not recommended. +[0.9.9] * Document selective running of tests with CK_RUN_SUITE and CK_RUN_CASE + environment variables. + +Interface +========= + +[ ] * Change check not to clobber things in the global namespace. + Prepend CHECK_ to all constants, check_ to all exported symbols, + and _check to all internal functions. Currently fail() is + causing a problem. Deprecate the old API in a nice way. + +Build issues: +============= + +[ ] * Add AC_PROG_CC_C99 in configure.ac when autoconf2.60b is + commonly availabe. Add checks in src/check.h.in for macro + varargs support. +[0.9.4] * Convert Check to use Libtool +[ ] * Figure out if we need stamp-h.in or not +[ ] * use AC_CONFIG_MACRO_DIR([m4]) and create an m4/ dir for check.m4 + aclocaldir = $(datadir)/aclocal + aclocal_DATA = mymacro.m4 myothermacro.m4 + ACLOCAL_AMFLAGS = -I m4 # put in top-level Makefile.am +[ ] * Fix overriding CFLAGS in configure.ac +[ ] * Use AC_DEFINE to define version number stuff? +[ ] * Change MICRO to ALPHA? probably not +[ ] * Add std-options to AM_INIT_AUTOMAKE +[ ] * Investigate subdir-objects option to AM_INIT_AUTOMAKE +[ ] * Use filename-length-max=99 in AM_INIT_AUTOMAKE +[0.9.4] * Make sure libcheck.(l)a works as a dependency, don't call $(MAKE) +[0.9.4] * Build tests/ dirs after everything else +[0.9.4] * Fix AM_PATH_CHECK by deprecating it; use pkg-config instead +[0.9.6] * make Check pass its own unit tests: make (dist)check can fail. +[ ] * Make the docs pass 'make distcheck' +[ ] * use stricter CFLAGS for compiling Check +[ ] * use ax_cflags_gcc_option to add to CFLAGS to Check +[ ] * prune unused checks from configure.ac + +Check source code: +============ + +[ ] * Eliminate abbreviations like nf for number_failed +[0.9.13] * Run indent on everything, make sure it works well. +[ ] * Fix START_TEST/END_TEST to look like valid C code. +[ ] * Document things way more. +[ ] * Create check.h automatically using makeheaders.c (not sure) +[ ] * Eliminate check_ prefix from files in src/ ... not needed + +Internal Check tests +====================== + +[0.9.3] * Use gcov to test and expand coverage of existing unit tests +[ ] * Increase tests for more non-public modules +[0.8.0] * Refactor to allow better unit testing of printing functionality. +[ ] * Document things way more. +[ ] * Clarify what all the different tests mean, whether they are + meant to fail or not --- setting all CK_SILENT to CK_VERBOSE + makes it seem like there are lots of errors being produced! +[ ] * Fix timeout tests. Currently, on some processors, a test that + asserts no timeout within 2 seconds fails unless the default + timeout is set to 4 or more seconds. A higher resolution + might help, and there could also be issues with multiple + processes on SMP machines. + +Packaging +========= + +[0.7.2] * Automate RPM production +[0.7.2] * Debian packaging +[0.9.2] * Get Check into Debian Sid +[0.9.4] * Eliminate .deb and .rpm packaging for vendors --- not necessary + + + +The following enhancements are being considered for Check. Please +send an email to if you +would like to assist in any of these, or if you would like to suggest +additional enhancements. Also please check the various trackers at +the Check project website. + +Printing and Logging +==================== + +[ ] * Allow unit test output (stdout and stderr) to be captured and logged +[0.9.1] * Add XML as option for test output +[ ] * Open the API for printing/logging customization +[ ] * JUnit-style UI? + +Unit test writing +================= + +[0.8.0] * Allow fail and friends to be used within fixture + setup/teardown functions +[0.8.0] * Allow forkless running of suites, to allow debugging +[0.9.2] * Allow unit tests that expect signals +[ ] * Allow unit tests to write to the log +[ ] * Allow unit tests that expect output (see stdout logging above) (but + maybe perl/sh/expect/dejagnu are better tools) +[ ] * Autoproduce unit testing framework from header files +[ ] * Count the number of START_TEST macros and check that each function + is added to some suite; issue a warning message otherwise. Maybe the + best way to do this is to put each function onto a list or + table as its defined, and then remove it once its added + somewhere. Then, when finished, print out what remains on the list / + in the table. This might require some ugly macro hackery... +[ ] * Better macro for START_TEST. It would be nice to pass in + three separate arguments, something like: + 1) a numeric ID for the tests function + 2) the exact name of the function being tested + 3) the name of the feature in (2) being tested for +[ ] * Find a way to create setup/teardown macros such that global + variables aren't necessary, and they're really just blocks + that get added at the beginning and ending of tests. +[ ] * Some mechanism to profile execution times, and assert that the time + a test takes to complete scales according to some big-O notation. +[ ] * Fork entire test cases, and then fork individual tests from + within each test case, so that unchecked fixtures can in + fact do unsafe things without bringing down the entire test + program. + +Check Internals +=============== + +[0.8.0] * Implement message passing between unit test and test + programs using pipes, rather than SysV IPC, to allow support + under cygwin. +[ ] * Abstract the forking and message passing implementation to + allow Win32 compatibility. +[0.9.12] * Incorporate existing Win32 support as mentioned here: + http://opendarwin.org/pipermail/cvs-libfoundation-all/2005-March/000177.html +[0.9.11] * Get Cygwin to work, with forking +[0.9.11] * Get MinGW to work, even without forking +[0.9.12] * Get MSVC to work, even without forking diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..ec46360 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,220 @@ +# This is the configuration file for AppVeyor builds. +# Look at the following for reference: +# https://www.appveyor.com/docs/appveyor-yml + +# Notes: +# - Minimal appveyor.yml file is an empty file. All sections are optional. +# - Indent each level of configuration with 2 spaces. Do not use tabs! +# - All section names are case-sensitive. +# - Section names should be unique on each level. + +#---------------------------------# +# general configuration # +#---------------------------------# + +# version format +version: 1.0.{build} + +#---------------------------------# +# environment configuration # +# and build matrix # +#---------------------------------# + +environment: + vsversion: none + arch: default + matrix: + # Visual Studio builds +# - platform: vs +# vsversion: 2008 +# arch: x86 + - platform: vs + vsversion: 2010 + arch: x86 + - platform: vs + vsversion: 2012 + arch: x86 + - platform: vs + vsversion: 2013 + arch: x86 + - platform: vs + vsversion: 2015 + arch: x86 + - platform: vs + vsversion: 2017 + arch: x86 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + - platform: vs + vsversion: 2010 + arch: x64 + - platform: vs + vsversion: 2012 + arch: x64 + - platform: vs + vsversion: 2013 + arch: x64 + - platform: vs + vsversion: 2015 + arch: x64 + - platform: vs + vsversion: 2017 + arch: x64 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + - platform: vs + vsversion: 2012 + arch: ARM + - platform: vs + vsversion: 2013 + arch: ARM + - platform: vs + vsversion: 2015 + arch: ARM + - platform: vs + vsversion: 2017 + arch: ARM + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + # Other compilers than Visual Studio + - platform: msvc + - platform: cygwin + - platform: mingw32 + - platform: mingw64msys + +# clone directory +clone_folder: c:\projects\check + +# build Configuration, i.e. Debug, Release, etc. +configuration: Release + + +#---------------------------------# +# scripts that are called at # +# the very beginning, before # +# repo cloning # +#---------------------------------# + +init: + - git config --global core.autocrlf input + + +#---------------------------------# +# scripts to run before build # +#---------------------------------# + +before_build: + - cd c:\projects\check + - echo Directory before starting build... + - dir + - echo Starting pre-build step... + # Remove the following from the path, as it will interfere with + # the MinGW builds + - set PATH=%PATH:C:\Program Files\Git\usr\bin;=% + - if %platform%==msvc call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" + - if %platform%==msvc cmake -G "NMake Makefiles" -DCMAKE_INSTALL_PREFIX=%P% + - if %platform%==vs ( + set "makecommand=Visual Studio" + ) + - set "vcx=false" + - set "vcs=false" + - if %platform%==vs ( + set "vcx=true" + ) + - if %vsversion%==2005 ( + set "vcs=true" + ) + - if %vsversion%==2008 ( + set "vcs=true" + ) + - if %vcs%==true ( + set "vcx=false" + ) + - if %vsversion%==2005 ( + set "makecommand=%makecommand% 8 %vsversion%" + ) + - if %vsversion%==2008 ( + set "makecommand=%makecommand% 9 %vsversion%" + ) + - if %vsversion%==2010 ( + set "makecommand=%makecommand% 10 %vsversion%" + ) + - if %vsversion%==2012 ( + set "makecommand=%makecommand% 11 %vsversion%" + ) + - if %vsversion%==2013 ( + set "makecommand=%makecommand% 12 %vsversion%" + ) + - if %vsversion%==2015 ( + set "makecommand=%makecommand% 14 %vsversion%" + ) + - if %vsversion%==2017 ( + set "makecommand=%makecommand% 15 %vsversion%" + ) + - if %arch%==x64 ( + set "makecommand=%makecommand% Win64" + ) + - if %arch%==ARM ( + set "makecommand=%makecommand% ARM" + ) + - if %platform%==vs cmake -G "%makecommand%" -DCMAKE_INSTALL_PREFIX=%P% + - if %platform%==cygwin set PATH=C:\cygwin\bin;%PATH% + - if %platform%==cygwin bash -c "autoreconf -i" + - if %platform%==cygwin bash -c "./configure" + - if %platform%==mingw32 set PATH=C:\MinGW\bin;%PATH% + - if %platform%==mingw32 cmake -G "MinGW Makefiles" -DCMAKE_INSTALL_PREFIX=%P% + - if %platform%==mingw64msys set PATH=C:\msys64\mingw64\bin;C:\msys64\usr\bin;%PATH% + - if %platform%==mingw64msys bash -c "autoreconf -i" + - if %platform%==mingw64msys bash -c "./configure" + + +#---------------------------------# +# build code and unit tests # +#---------------------------------# + +build_script: + - echo Directory before running build step... + - dir + - echo Building code... + - if %platform%==msvc nmake + - if %platform%==cygwin bash -c "make" + - if %platform%==mingw32 mingw32-make + - if %platform%==mingw64msys bash -c "make" + - if %vcx%==true msbuild /p:Platform=%arch% "ALL_BUILD.vcxproj" + # Build for VS2008 (prior to the vsxproj file format), only 32 bit + # Options see https://msdn.microsoft.com/en-us/library/ms164311.aspx + - if %vcs%==true msbuild /p:Configuration=Release /p:Platform=Win32 /nologo /v:d "check.sln" + + +#---------------------------------# +# run unit test for all x86 # +# and x64 architecture builds # +#---------------------------------# + +test_script: + - set "testplatform=%platform%" + # Can not run ARM builds on x86/x64 build images + - if %arch%==ARM ( + set "testplatform=none" + ) + - echo Project directory before running test step... + - dir + - echo tests directory before running test step... + - dir tests + - echo Running unit tests... + - if %testplatform%==msvc nmake test VERBOSE=1 CTEST_OUTPUT_ON_FAILURE=TRUE + - if %testplatform%==vs ctest --extra-verbose -C Release + - if %testplatform%==cygwin bash -c "make check" + - if %testplatform%==mingw32 tests\check_check.exe + - if %testplatform%==mingw64msys bash -c "tests/check_check" + - if %testplatform%==none echo Can not test for %arch% here + + +#---------------------------------# +# build and test completed # +#---------------------------------# + +on_finish: + - echo Project directory after running tests... + - dir + - echo tests directory after running tests... + - dir tests + - if %platform%==cygwin bash -c "cat tests/test-suite.log || true" + diff --git a/check.m4 b/check.m4 new file mode 100644 index 0000000..9515ae0 --- /dev/null +++ b/check.m4 @@ -0,0 +1,132 @@ +dnl AM_PATH_CHECK([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) +dnl Test for check, and define CHECK_CFLAGS and CHECK_LIBS +dnl + +AC_DEFUN([AM_PATH_CHECK], +[ + AC_MSG_WARN([A@&t@M_PATH_CHECK() is deprecated]) + AC_MSG_WARN([[use P@&t@KG_CHECK_MODULES([CHECK], [check >= 0.9.4]) instead]]) + AC_ARG_WITH([check], + [ --with-check=PATH prefix where check is installed [default=auto]]) + + min_check_version=ifelse([$1], ,0.8.2,$1) + + AC_MSG_CHECKING(for check - version >= $min_check_version) + + if test x$with_check = xno; then + AC_MSG_RESULT(disabled) + ifelse([$3], , AC_MSG_ERROR([disabling check is not supported]), [$3]) + else + if test "x$with_check" != x; then + CHECK_CFLAGS="-I$with_check/include" + CHECK_LIBS="-L$with_check/lib -lcheck" + else + CHECK_CFLAGS="" + CHECK_LIBS="-lcheck" + fi + + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + + CFLAGS="$CFLAGS $CHECK_CFLAGS" + LIBS="$CHECK_LIBS $LIBS" + + rm -f conf.check-test + AC_COMPILE_IFELSE([AC_LANG_SOURCE([AC_INCLUDES_DEFAULT([]) +#include + +int main () +{ + int major, minor, micro; + char *tmp_version; + + system ("touch conf.check-test"); + + /* HP/UX 9 (%@#!) writes to sscanf strings */ + tmp_version = strdup("$min_check_version"); + if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { + printf("%s, bad version string\n", "$min_check_version"); + return 1; + } + + if ((CHECK_MAJOR_VERSION != check_major_version) || + (CHECK_MINOR_VERSION != check_minor_version) || + (CHECK_MICRO_VERSION != check_micro_version)) + { + printf("\n*** The check header file (version %d.%d.%d) does not match\n", + CHECK_MAJOR_VERSION, CHECK_MINOR_VERSION, CHECK_MICRO_VERSION); + printf("*** the check library (version %d.%d.%d).\n", + check_major_version, check_minor_version, check_micro_version); + return 1; + } + + if ((check_major_version > major) || + ((check_major_version == major) && (check_minor_version > minor)) || + ((check_major_version == major) && (check_minor_version == minor) && (check_micro_version >= micro))) + { + return 0; + } + else + { + printf("\n*** An old version of check (%d.%d.%d) was found.\n", + check_major_version, check_minor_version, check_micro_version); + printf("*** You need a version of check being at least %d.%d.%d.\n", major, minor, micro); + printf("***\n"); + printf("*** If you have already installed a sufficiently new version, this error\n"); + printf("*** probably means that the wrong copy of the check library and header\n"); + printf("*** file is being found. Rerun configure with the --with-check=PATH option\n"); + printf("*** to specify the prefix where the correct version was installed.\n"); + } + + return 1; +} +])],, no_check=yes, [echo $ac_n "cross compiling; assumed OK... $ac_c"]) + + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + + if test "x$no_check" = x ; then + AC_MSG_RESULT(yes) + ifelse([$2], , :, [$2]) + else + AC_MSG_RESULT(no) + if test -f conf.check-test ; then + : + else + echo "*** Could not run check test program, checking why..." + CFLAGS="$CFLAGS $CHECK_CFLAGS" + LIBS="$CHECK_LIBS $LIBS" + AC_TRY_LINK([ +#include +#include + +#include +], , [ echo "*** The test program compiled, but did not run. This usually means" + echo "*** that the run-time linker is not finding check. You'll need to set your" + echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" + echo "*** to the installed location Also, make sure you have run ldconfig if that" + echo "*** is required on your system" + echo "***" + echo "*** If you have an old version installed, it is best to remove it, although" + echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"], + [ echo "*** The test program failed to compile or link. See the file config.log for" + echo "*** the exact error that occured." ]) + + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + + CHECK_CFLAGS="" + CHECK_LIBS="" + + rm -f conf.check-test + ifelse([$3], , AC_MSG_ERROR([check not found]), [$3]) + fi + + AC_SUBST(CHECK_CFLAGS) + AC_SUBST(CHECK_LIBS) + + rm -f conf.check-test + + fi +]) diff --git a/check.pc.in b/check.pc.in new file mode 100644 index 0000000..9aa76f0 --- /dev/null +++ b/check.pc.in @@ -0,0 +1,13 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: Check +Description: A unit test framework for C +URL: https://libcheck.github.io/check/ +Version: @VERSION@ +Requires.private: @LIBSUBUNIT_PC@ +Libs: -L${libdir} -lcheck +Libs.private: @GCOV_LIBS@ @PTHREAD_LIBS@ @LIBS@ +Cflags: -I${includedir} @PTHREAD_CFLAGS@ diff --git a/checkmk/Makefile.am b/checkmk/Makefile.am new file mode 100644 index 0000000..8a3aba9 --- /dev/null +++ b/checkmk/Makefile.am @@ -0,0 +1,14 @@ +if INSTALL_CHECKMK +bin_SCRIPTS = checkmk +TESTS = test/check_checkmk +endif +EXTRA_DIST = test examples doc/checkmk.1 +CONFIG_STATUS_DEPENDENCIES = checkmk.in + +man_MANS = doc/checkmk.1 + +clean-local: + rm -rf test.out + +dist-hook: + rm -rf `find $(distdir)/ -name '.svn'` diff --git a/checkmk/README b/checkmk/README new file mode 100644 index 0000000..1bde91c --- /dev/null +++ b/checkmk/README @@ -0,0 +1,17 @@ +======= +checkmk +======= + +Written by Micah J Cowan. + +Translates concise versions of test suites into C programs +suitable suitable for use with the Check unit test framework. + +See the source code in checkmk.in (checkmk when installed) for terms of +distribution (scaled-down version of the modified BSD license). + +To see how it works, try running checkmk on the example files, +basic_complete.ts and multiple_everything.ts: + checkmk basic_complete.ts > basic_complete.c + cc -o basic basic_complete.c -lcheck + ./basic diff --git a/checkmk/checkmk.in b/checkmk/checkmk.in new file mode 100644 index 0000000..2100274 --- /dev/null +++ b/checkmk/checkmk.in @@ -0,0 +1,574 @@ +#! @AWK_PATH@ -f +# @configure_input@ + +# checkmk - translate more concise versions of test suite specifications +# into C programs suitable for use with the Check unit test +# framework. + +# -- LICENSE -- +# +# Written by Micah Cowan +# Copyright (c) 2006, 2010 Micah Cowan +# +# Redistribution of this program in any form, with or without +# modifications, is permitted, provided that the above copyright is +# retained in distributions of this program in source form. +# +# (This is a free, non-copyleft license compatible with pretty much any +# other free or proprietary license, including the GPL. It's essentially +# a scaled-down version of the "modified" BSD license.) + +BEGIN { + progname="checkmk"; + is_stdin=0; + outfname="/dev/stdout"; + + # Tokens + pp_ws = "[ \\t\\f\\v\\r\\n]+"; + pp_ws_op = "[ \\t\\f\\v\\r\\n]*"; + pp_digit = "[0-9]+" + pp_prefix = pp_ws_op "#" pp_ws_op; + pp_sep = "[ \\t\\f\\v\\r\\n]+"; + pp_name = ".+"; + pp_hex_quad = "[A-F0-9a-f][A-F0-9a-f][A-F0-9a-f][A-F0-9a-f]" + pp_ucn = "\\\\(u" pp_hex_quad "|U" pp_hex_quad pp_hex_quad ")"; + pp_test_name = "([A-Za-z_]|" pp_ucn ")([A-Za-z0-9_]|" pp_ucn ")*"; + pp_tag = "([Ss][Uu][Ii][Tt][Ee]|[Tt][Cc][Aa][Ss][Ee])"; + pp_test_tag = "[Tt][Ee][Ss][Tt]"; + pp_main_pre_tag = "[Mm][Aa][Ii][Nn]-[Pp][Rr][Ee]"; + pp_main_post_tag = "[Mm][Aa][Ii][Nn]-[Pp][Oo][Ss][Tt]"; + + # Tests with arguments + pp_test_exit_tag = "[Tt][Ee][Ss][Tt]-[Ee][Xx][Ii][Tt]" pp_ws_op "[(]" \ + pp_ws_op "[+-]?" pp_ws_op pp_digit pp_ws_op "[)]"; + + pp_test_signal_tag = "[Tt][Ee][Ss][Tt]-[Ss][Ii][Gg][Nn][Aa][Ll]" pp_ws_op \ + "[(]" pp_ws_op "[+-]?" pp_ws_op pp_digit pp_ws_op "[)]"; + + pp_test_loop_tag = "[Tt][Ee][Ss][Tt]-[Ll][Oo][Oo][Pp]" pp_ws_op "[(]" \ + pp_ws_op "[+-]?" pp_ws_op pp_digit pp_ws_op "[,]" pp_ws_op \ + "[+-]?" pp_ws_op pp_digit pp_ws_op "[)]"; + + pp_test_loop_exit_tag = "[Tt][Ee][Ss][Tt]-[Ll][Oo][Oo][Pp]-[Ee][Xx][Ii][Tt]" \ + pp_ws_op "[(]" pp_ws_op "[+-]?" pp_ws_op pp_digit pp_ws_op \ + "[,]" pp_ws_op "[+-]?" pp_ws_op pp_digit pp_ws_op "[,]" \ + pp_ws_op "[+-]?" pp_ws_op pp_digit pp_ws_op "[)]"; + + pp_test_loop_signal_tag = "[Tt][Ee][Ss][Tt]-[Ll][Oo][Oo][Pp]-[Ss][Ii][Gg]" \ + "[Nn][Aa][Ll]" pp_ws_op "[(]" pp_ws_op "[+-]?" pp_ws_op pp_digit \ + pp_ws_op "[,]" pp_ws_op "[+-]?" pp_ws_op pp_digit pp_ws_op \ + "[,]" pp_ws_op "[+-]?" pp_ws_op pp_digit pp_ws_op "[)]"; + + pp_suite_or_tcase_line = "^" pp_prefix pp_tag pp_ws pp_name "$"; + pp_test_line_prefix = "^" pp_prefix pp_test_tag pp_ws; + pp_test_exit_line_prefix = "^" pp_prefix pp_test_exit_tag pp_ws; + pp_test_signal_line_prefix = "^" pp_prefix pp_test_signal_tag pp_ws; + pp_test_loop_line_prefix = "^" pp_prefix pp_test_loop_tag pp_ws; + pp_test_loop_exit_line_prefix = "^" pp_prefix pp_test_loop_exit_tag pp_ws; + pp_test_loop_signal_line_prefix = "^" pp_prefix pp_test_loop_signal_tag pp_ws; + pp_test_line = pp_test_line_prefix pp_name pp_ws_op "$"; + pp_test_exit_line = pp_test_exit_line_prefix pp_name pp_ws_op "$"; + pp_test_signal_line = pp_test_signal_line_prefix pp_name pp_ws_op "$"; + pp_test_loop_line = pp_test_loop_line_prefix pp_name pp_ws_op "$"; + pp_test_loop_exit_line = pp_test_loop_exit_line_prefix pp_name pp_ws_op "$"; + pp_test_loop_signal_line = pp_test_loop_signal_line_prefix pp_name pp_ws_op "$"; + pp_main_pre_line = "^" pp_prefix pp_main_pre_tag pp_ws_op "$"; + pp_main_post_line = "^" pp_prefix pp_main_post_tag pp_ws_op "$"; + + # Global vars + in_test = needs_line_decl = 0; + cur_suite = cur_tcase = "Core"; + cur_test = ""; + exit_okay = start = 1; + num_cur_tcases = num_cur_tests = 0; + test_type = num_tests = 0; + arg1 = 0; + arg2 = 1; + arg3 = 2; + test_name = 0; + test_type_flag = 1; +} + +# Run on the first line of the input file. +start { + print_boilerplate(); + start = 0; +} + +# (Executed every line:) +{ + print_line = 1; +} + +$0 ~ pp_suite_or_tcase_line { + if (in_main()) + in_main_error(); + + # Skip to the start of the tag ("suite" or "tcase"). + match($0, pp_prefix); + rol = substr($0, RLENGTH+1); + + # Save away the tag. + match(rol, "^" pp_tag); + tag = substr(rol, 1, RLENGTH); + + # Advance past the ws following tag. + rol = substr(rol, RLENGTH+1); + match(rol, pp_ws); + rol = substr(rol, RLENGTH+1); + + # The suite or tcase name is the rest of the line, minus any + # trailing ws. + if (match(rol, pp_ws "$")) { + name = substr(rol, 1, RSTART-1); + } else { + name = rol; + } + + if (tolower(tag) == "suite") { + # Does this suite already exist? + if ((name, 0) in suite_tcase_map) { + error_with_line("Suite \"" name "\" already exists."); + } + cur_suite = name; + num_cur_tcases = 0; + } + else if ((name, 0, 0) in tcase_test_map) { + error_with_line("Test Case \"" name "\" already exists."); + } + cur_tcase = name; + num_cur_tests = 0; + + finish_test(); + print_line = 0; + if (!clean_mode) + needs_line_decl = 1; +} + +$0 ~ pp_test_line { + + # Pre checks + test_pre(); + + # Get the test name + match($0, pp_test_line_prefix) + cur_test = substr($0, RLENGTH+1); + + # Remove trailing ws. + sub(pp_ws_op "$", "", cur_test); + + # Check for duplicate tests / cases and valid names + duplicate_check(); + + # Boilerplate printing code + test_post(); + + # Set type before calling register + test_type = 0; + register_test(); + + print_line = 0; + in_test = 1; +} + +$0 ~ pp_test_loop_line { + + test_pre(); + + match($0, pp_test_loop_line_prefix) + cur_test = substr($0, RLENGTH+1); + sub(pp_ws_op "$", "", cur_test); + + duplicate_check(); + + # Split the line into an array to extract the arguments + split($0, arr, pp_ws_op "[(),]" pp_ws_op); + + # Eliminate possible whitespace between sign and numbers + gsub(pp_ws_op, "", arr[2]); + gsub(pp_ws_op, "", arr[3]); + + test_post(); + + test_type = 1; + register_test(); + + print_line = 0; + in_test = 1; +} + +$0 ~ pp_test_exit_line { + + test_pre(); + + match($0, pp_test_exit_line_prefix) + cur_test = substr($0, RLENGTH+1); + sub(pp_ws_op "$", "", cur_test); + + duplicate_check(); + + split($0, arr, pp_ws_op "[(),]" pp_ws_op); + gsub(pp_ws_op, "", arr[2]); + + test_post(); + + test_type = 2; + register_test(); + + print_line = 0; + in_test = 1; +} + +$0 ~ pp_test_signal_line { + + test_pre(); + + match($0, pp_test_signal_line_prefix) + cur_test = substr($0, RLENGTH+1); + sub(pp_ws_op "$", "", cur_test); + + duplicate_check(); + + split($0, arr, pp_ws_op "[(),]" pp_ws_op); + gsub(pp_ws_op, "", arr[2]); + + test_post(); + + test_type = 3; + register_test(); + + print_line = 0; + in_test = 1; +} + +$0 ~ pp_test_loop_exit_line { + + test_pre(); + + match($0, pp_test_loop_exit_line_prefix) + cur_test = substr($0, RLENGTH+1); + sub(pp_ws_op "$", "", cur_test); + + duplicate_check(); + + split($0, arr, pp_ws_op "[(),]" pp_ws_op); + gsub(pp_ws_op, "", arr[2]); + gsub(pp_ws_op, "", arr[3]); + gsub(pp_ws_op, "", arr[4]); + + test_post(); + + test_type = 4; + register_test(); + + print_line = 0; + in_test = 1; +} + +$0 ~ pp_test_loop_signal_line { + + test_pre(); + + match($0, pp_test_loop_signal_line_prefix) + cur_test = substr($0, RLENGTH+1); + sub(pp_ws_op "$", "", cur_test); + + duplicate_check(); + + split($0, arr, pp_ws_op "[(),]" pp_ws_op); + gsub(pp_ws_op, "", arr[2]); + gsub(pp_ws_op, "", arr[3]); + gsub(pp_ws_op, "", arr[4]); + + test_post(); + + test_type = 5; + register_test(); + + print_line = 0; + in_test = 1; +} + +$0 ~ pp_main_pre_line { + main_pre(); + + print ""; + print " /* User-specified pre-run code */"; + + if (!clean_mode) + needs_line_decl = 1; + print_line = 0; +} + +$0 ~ pp_main_post_line { + main_post(); + + print ""; + print " /* User-specified post-run code */"; + + if (!clean_mode) + needs_line_decl = 1; + print_line = 0; +} + +print_line { + if (/[^ \t\f\v\r\n]/ && needs_line_decl && !clean_mode) { + print "#line " FNR; + needs_line_decl = 0; + } + print; +} + +END { + if (!exit_okay) { + # We're exiting due to an error. Don't do anything else. + } + else if (num_tests) { + if (!main_post_done) { + main_post(); + print ""; + print " return nf == 0 ? 0 : 1;"; + } + print "}"; + } + else { + error("Expected at least one #test line."); + } +} + +### Functions ### + +function test_pre() +{ + if (in_main()) + in_main_error(); + + if (in_test) { + finish_test(); + print ""; + } + ++num_tests; +} + +function duplicate_check() +{ + # Confirm that the test name is a valid C identifier. + if (!match(cur_test, "^" pp_test_name "$")) { + error_with_line("Malformed test name \"" cur_test \ + "\" (must be a C identifier)."); + } + + # Verify that it has not already been used. + if (cur_test in test_registry) { + error_with_line("Test \"" cur_test "\" already exists."); + } + + # Verify that any implied test case is not a repeat. + if (num_cur_tests == 0 && (cur_tcase, 0, 0) in tcase_test_map) { + error_with_line("Test Case \"" name "\" already exists."); + } +} + +function test_post() +{ + print "START_TEST(" cur_test ")"; + print "{"; + if (!clean_mode) + print "#line " FNR+1; + + needs_line_decl = 0; +} + +function main_post() +{ + if (main_post_done) + error_with_line("main-post specified multiple times."); + if (!main_pre_done) + main_pre(); + main_post_done = 1; + + print ""; + + print_runner_bindings(); + + print ""; + print " srunner_run_all(sr, CK_ENV);"; + print " nf = srunner_ntests_failed(sr);"; + print " srunner_free(sr);"; +} + +function in_main() +{ + return main_pre_done || main_post_done; +} + +function in_main_error() +{ + error_with_line("Cannot specify tests after main-pre or main-post."); +} + +function main_pre() +{ + if (main_post_done) + error_with_line("main-pre specified after main-post."); + if (main_pre_done) + error_with_line("main-pre specified multiple times."); + main_pre_done = 1; + finish_test(); + print ""; + print "int main(void)"; + print "{"; + + print_main_declarations(); +} + +function suite_var_name(num) +{ + return "s" num+1; +} + +function tcase_var_name(snum, tcnum) +{ + return "tc" snum+1 "_" tcnum+1; +} + +function print_main_declarations() +{ + for (i=0; i != num_suites; ++i) { + s = suite_names[i]; + svar = suite_var_name(i); + print " Suite *" svar " = suite_create(" string_encode(s) ");"; + for (j=0; j != suite_num_tcases[s]; ++j) { + tc = suite_tcase_map[s, j]; + tcvar = tcase_var_name(i, j); + print " TCase *" tcvar " = tcase_create(" \ + string_encode(tc) ");"; + } + } + print " SRunner *sr = srunner_create(s1);"; + print " int nf;"; +} + +function string_encode(raw) +{ + # The next line might look funny, but remember that the first + # argument will go through both string interpolation /and/ regex + # interpolation, so the backslashes must be double-escaped. The + # substitution string is supposed to result in an actual + # double-backslash. + gsub("\\\\", "@AWK_GSUB_DBL_BSLASH@", raw); + gsub("\"", "\\\"", raw); + return "\"" raw "\""; +} + +function print_runner_bindings() +{ + for (i=0; i != num_suites; ++i) { + s = suite_names[i]; + svar = suite_var_name(i); + for (j=0; j != suite_num_tcases[s]; ++j) { + tc = suite_tcase_map[s, j]; + tcvar = tcase_var_name(i, j); + print " suite_add_tcase(" svar ", " tcvar ");"; + for (k=0; k != tcase_num_tests[tc]; ++k) { + t = tcase_test_map[tc, k, test_name]; + test_type = tcase_test_map[tc, k, test_type_flag]; + if (test_type == 0) { + print " tcase_add_test(" tcvar ", " t ");"; + } + else if (test_type == 1) { + print " tcase_add_loop_test(" tcvar ", " t ", " \ + test_parameters[t, arg1] ", " test_parameters[t, arg2] \ + ");"; + } + else if (test_type == 2) { + print " tcase_add_exit_test(" tcvar ", " t ", " \ + test_parameters[t, arg1] ");"; + } + else if (test_type == 3) { + print " tcase_add_test_raise_signal(" tcvar ", " t ", " \ + test_parameters[t, arg1] ");"; + } + else if (test_type == 4) { + print " tcase_add_loop_exit_test(" tcvar ", " t ", " \ + test_parameters[t, arg1] ", " test_parameters[t, arg2] \ + ", " test_parameters[t, arg3] ");"; + } + else if (test_type == 5) { + print " tcase_add_loop_test_raise_signal(" tcvar ", " t \ + ", " test_parameters[t, arg1] ", " test_parameters[t, arg2] \ + ", " test_parameters[t, arg3] ");"; + } + } + } + } + if (num_suites > 1) { + print ""; + for (i=1; i != num_suites; ++i) { + svar = suite_var_name(i); + print " srunner_add_suite(sr, " svar ");"; + } + } +} + +function register_test() +{ + if (num_cur_tcases == 0) { + suite_names[num_suites++] = cur_suite; + } + if (num_cur_tests == 0) { + suite_tcase_map[cur_suite, num_cur_tcases++] = cur_tcase; + suite_num_tcases[cur_suite] = num_cur_tcases; + } + tcase_test_map[cur_tcase, num_cur_tests, test_name] = cur_test; + tcase_test_map[cur_tcase, num_cur_tests++, test_type_flag] = test_type; + tcase_num_tests[cur_tcase] = num_cur_tests; + test_registry[cur_test] = 1; + + # Store arguments to array + test_parameters[cur_test, arg1] = arr[2]; + test_parameters[cur_test, arg2] = arr[3]; + test_parameters[cur_test, arg3] = arr[4]; +} + +function finish_test() +{ + if (in_test) { + in_test = 0; + print "}"; + print "END_TEST"; + } +} + +function print_boilerplate() +{ + print "/*"; + print " * DO NOT EDIT THIS FILE. Generated by " progname "."; + if (!FILENAME || FILENAME == "-") { + clean_mode=1; + is_stdin=1; + } + if (is_stdin) + srcfile = "(standard input)"; + else + srcfile = "\"" FILENAME "\""; + print " * Edit the original source file " srcfile " instead."; + print " */"; + print ""; + print "#include "; + print ""; + if (!clean_mode) + print "#line 1 " string_encode(FILENAME) +} + +function error_with_line(err) +{ + error((is_stdin ? "(standard input)" : FILENAME) " line " FNR ": " err); +} + +function error(err) +{ + print progname ": " err > "/dev/stderr"; + exit_okay = 0; + exit 1; +} diff --git a/checkmk/doc/checkmk.1 b/checkmk/doc/checkmk.1 new file mode 100644 index 0000000..febaec6 --- /dev/null +++ b/checkmk/doc/checkmk.1 @@ -0,0 +1,569 @@ +.\" This manpage has been automatically generated by docbook2man +.\" from a DocBook document. This tool can be found at: +.\" +.\" Please send any bug reports, improvements, comments, patches, +.\" etc. to Steve Cheng . +.TH "CHECKMK" "1" "09 February 2010" "" "" + +.SH NAME +checkmk \- Awk script for generating C unit tests for use with the Check unit testing framework. +.SH SYNOPSIS + +\fBcheckmk\fR [ \fBclean_mode=1\fR ] [ \fB\fIinput-file\fB\fR ] + +.SH "DESCRIPTION" +.PP +Generate C-language source files containing unit tests for use +with the Check unit testing framework. The aim of this script is +to automate away some of the typical boilerplate one must write when +writing a test suite using Check: specifically, the instantiation of +an SRunner, Suite(s), and TCase(s), and the building of +relationships between these objects and the test functions. +.PP +This tool is intended to be used by those who are familiar +with the Check unit testing framework. Familiarity with the +framework will be assumed throughout this manual. +.PP +The Check framework, along with information regarding it, is +available at http://check.sourceforge.net/ \&. +.PP +The \fIinput-file\fR argument to +\fBcheckmk\fR uses a simple, C-preprocessor-like +syntax to declare test functions, and to describe their +relationships to Suites and TCases in Check. +\fBcheckmk\fR then uses this information to +automatically write a \fBmain()\fR function +containing all of the necessary declarations, and whatever code is +needed to run the test suites. The final C-language output is +printed to \fBcheckmk\fR\&'s standard output. +.PP +Facilities are provided for the insertion of user code into +the generated \fBmain()\fR function, to provide for +the use of logging, test fixtures or specialized exit values. +.PP +While it is possible to omit the +\fIinput-file\fR argument to +\fBcheckmk\fR and provide the input file on +\fBcheckmk\fR\&'s standard input instead, it is generally +recommended to provide it as an argument. Doing this allows +\fBcheckmk\fR to be aware of the file's name, to place +references to it in the initial comments of the C-language output, +and to intersperse C #line directives throughout, to +facilitate in debugging problems by directing the user to the +original input file. +.SH "OPTIONS" +.PP +The only officially supported option is specifying a true +value (using Awk's definition for "true") for the variable +\fBclean_mode\fR\&. This causes \fBcheckmk\fR +not to place appropriate #line directives in the +source code, which some might find to be unnecessary clutter. +.PP +The author recommends against the use of this option, as it +will cause C compilers and debugging tools to refer to lines in the +automatically generated output, rather than the original input files +to \fBcheckmk\fR\&. This would encourage users to edit the +output files instead of the original input files, would make it +difficult for intelligent editors or IDEs to pull up the right file +to edit, and could result in the fixes being overwritten when the +output files are regenerated. +.PP +#line directives are automatically +supressed when the input file is provided on standard input +instead of as a command-line argument. +.SH "BASIC EXAMPLE" +.PP +In its most basic form, an input file can be simply a +prologue and a test function. Anything that appears before the +first test function is in the prologue, and will be copied into +the output verbatim. The test function is begun by a line in the +form: + +.nf +#test \fItest_name\fR +.fi +.PP +Where \fItest_name\fR is the name of +your test function. This will be used to name a C function, so +it must be a valid C identifier. +.PP +Here is a small, complete example: + +.nf +-------------------------------------------------- +/* A complete test example */ + +#include + +#test the_test + int nc; + const char msg[] = "\\n\\n Hello, world!\\n"; + + nc = printf("%s", msg); + ck_assert(nc == (sizeof(msg) - 1)); /* for terminating NUL. */ +-------------------------------------------------- +.fi +.PP +If you place the above into a file named +\fIbasic_complete.ts\fR and process it using the +following command: +.PP +\fB$ checkmk basic_complete.ts > basic_complete.c\fR +.PP +\fIbasic_complete.c\fR +will contain output similar to: + +.nf +-------------------------------------------------- +/* + * DO NOT EDIT THIS FILE. Generated by checkmk. + * Edit the original source file "in" instead. + */ + +#include + +/* A complete test example */ + +#include + +START_TEST(the_test) +{ + int nc; + const char msg[] = "\\n\\n Hello, world!\\n"; + + nc = printf("%s", msg); + ck_assert(nc == (sizeof(msg) - 1)); /* for terminating NUL. */ +} +END_TEST + +int main(void) +{ + Suite *s1 = suite_create("Core"); + TCase *tc1_1 = tcase_create("Core"); + SRunner *sr = srunner_create(s1); + int nf; + + suite_add_tcase(s1, tc1_1); + tcase_add_test(tc1_1, the_test); + + srunner_run_all(sr, CK_ENV); + nf = srunner_ntests_failed(sr); + srunner_free(sr); + + return nf == 0 ? 0 : 1; +} +-------------------------------------------------- +.fi +.PP +In real usage, \fIbasic_complete.c\fR would +also contain #line directives. +.SH "DIRECTIVE SUMMARY" +.PP +Here is a complete summary of all the C-preprocessor-style +directives that are understood by \fBcheckmk\fR\&. See +below for more details. + +.nf +# test \fItest_name\fR +# test-signal(\fIsignal\fR) \fItest_name\fR +# test-exit(\fIexit_code\fR) \fItest_name\fR +# test-loop(\fIstart\fR, \fIend\fR) \fItest_name\fR +# test-loop-signal(\fIsignal\fR, \fIstart\fR, \fIend\fR) \fItest_name\fR +# test-loop-exit(\fIexit_code\fR, \fIstart\fR, \fIend\fR) \fItest_name\fR +# suite \fITestSuiteName\fR +# tcase \fITestCaseName\fR +# main-pre +# main-post +.fi +.PP +All directives are case-insensitive. Whitespace may appear +at the beginning of the line before the #, +between the # and the directive, between the +directive and any argument, and at the end of the line. +.SH "TEST-DEFINING DIRECTIVES" +.PP +Here is a more detailed explanation of the directives that may be +used to define test functions and their containers. +.SS "TEST FUNCTIONS" + +.nf +# test \fItest_name\fR +# test-signal(\fIsignal\fR) \fItest_name\fR +# test-exit(\fIexit_code\fR) \fItest_name\fR +# test-loop(\fIstart\fR, \fIend\fR) \fItest_name\fR +# test-loop-signal(\fIsignal\fR, \fIstart\fR, \fIend\fR) \fItest_name\fR +# test-loop-exit(\fIexit_code\fR, \fIstart\fR, \fIend\fR) \fItest_name\fR +.fi +.PP +These are the most basic directives for creating a template +for input to \fBcheckmk\fR\&. They are the only +directives that are required: there must be at least one +#test* directive appearing in the template, or +\fBcheckmk\fR will fail with an error message. The +#test* directives may be specified several times, +each one beginning the definition of a new test function. +.PP +The \fItest_name\fR argument will be +used as the name of a test function in the C-language output, so +it must be a valid C identifier. That is, it must begin with an +alphabetic character or the underscore (_), +followed by optional alpha-numeric characters and/or +underscores. +.PP +Universal Character Names (introduced in C99) are also +allowed, of the form \\uXXXX or +\\UXXXXXXXX, where the X\&'s +represent hexadecimal digits. +.PP +It is an error to specify the same +\fItest_name\fR in more than one +#test* directive, regardless of whether they +are associated with different test cases or suites. +.PP +See CHECKMK +IDENTIFIERS for the list of identifiers which should be +avoided for use as test function names. +.SS "TEST SUITES" + +.nf +# suite \fITestSuiteName\fR +.fi +.PP +This directive specifies the name of the test suite +(\fBSuite\fR object in the Check test +framework) to which all future test cases (and their test +functions) will be added. +.PP +The \fITestSuiteName\fR is a text +string, and may contain any sort of characters at all (other +than ASCII NUL character, and the newline, which would terminate +the directive). Any leading or trailing whitespace will be omitted +from the test suite name. +.PP +Starting a new test suite also begins a new test case, whose +name is identical to the new test suite. This test case name may be +overridden by a subsequent #tcase directive. +.PP +Note that a \fBSuite\fR object won't +actually be defined by \fBcheckmk\fR in the C +output, unless it is followed at some point by a +#test directive (without an intervening +#suite). It is not an error for a +#suite to have no associated +#test\&'s; the #suite (and any +associated #tcase\&'s) simply won't result in any +action on the part of \fBcheckmk\fR (and would +therefore be useless). +.PP +It is an error for a #suite directive to +specify the same (case sensitive) suite multiple times, unless the +previous uses were not instantiated by the presence of at least +one associated #test directive. +.PP +If you do not specify a #suite directive +before the first #test directive, +\fBcheckmk\fR performs the equivalent of an +implicit #suite directive, with the string +"Core" as the value for +\fITestSuiteName\fR (this also implies a +"Core" test case object). This is demonstrated +above in BASIC EXAMPLE\&. +.SS "TEST CASES" + +.nf +# tcase \fITestCaseName\fR +.fi +.PP +This directive specifies the name of the test case +(\fBTCase\fR object in the Check test +framework) to which all future test functions will be added. +.PP +The #tcase works very in a way very +similar to #suite\&. The +\fITestCaseName\fR is a text string, and +may contain arbitrary characters; and a +\fBTCase\fR object won't actually be defined +unless it is followed by an associated +#test directive. +.PP +It is an error for a #tcase directive to +specify the same (case sensitive) test case multiple times, unless the +previous uses were not instantiated by the presence of at least +one associated #test directive. +.PP +See also the #suite directive, described +above. +.SH "USER CODE IN MAIN()" +.PP +The C \fBmain()\fR is automatically generated +by \fBcheckmk\fR, defining the necessary +\fBSRunner\fR\&'s, \fBSuite\fR\&'s, +and\~\fBTCase\fR\&'s required by the +test-defining directives specified by the user. +.PP +For most situations, this completely automated +\fBmain()\fR is quite suitable as-is. However, +there are situations where one might wish to add custom code to +the \fBmain()\fR\&. For instance, if the user wishes +to: +.TP 0.2i +\(bu +change the test timeout value via +\fBtcase_set_timeout()\fR, +.TP 0.2i +\(bu +specify Check's "no-fork-mode" via +\fBsrunner_set_fork_status()\fR, +.TP 0.2i +\(bu +set up test fixtures for some test cases, via +\fBtcase_add_checked_fixture()\fR +or\~\fBtcase_add_unchecked_fixture()\fR, +.TP 0.2i +\(bu +set up test logging for the suite +runner, via \fBsrunner_set_log()\fR +or\~\fBsrunner_set_xml()\fR, or +.TP 0.2i +\(bu +perform custom wrap-up after the test suites have +been run. +.PP +For these purposes, the #main-pre +and\~#main-post directives have been +provided. +.SS "MAIN() PROLOGUE" + +.nf +# main-pre +.fi +.PP +The text following this directive will be placed verbatim +into the body of the generated \fBmain()\fR +function, just after \fBcheckmk\fR\&'s own local +variable declarations, and before any test running has taken +place (indeed, before even the relationships between the tests, +test cases, and test suites have been set up, though that +fact shouldn't make much difference). Since +\fBcheckmk\fR has only just finished making its +declarations, it is permissible, even under strict 1990 ISO C +guidelines, to make custom variable declarations here. +.PP +Unlike the previously-described directives, +#main-pre may be specified at most once. It may +not be preceded by the #main-post directive, +and no #suite, #tcase, +or #test directive may appear after it. +.PP +#main-pre is a good place to tweak +settings or set up test fixtures. Of course, in order to do so, +you need to know what names \fBcheckmk\fR has used +to instantiate the \fBSRunner\fR\&'s, +\fBSuite\fR\&'s, +and\~\fBTCase\fR\&'s. +.SS "CHECKMK IDENTIFIERS" +.PP +Pointers to \fBSuite\fR\&'s are declared +using the pattern +s\fIX\fR, where +\fIX\fR is a number +that starts at 1, and is incremented for each subsequent +#suite directive. +s1 always exists, and contains the test +function declared by the first #test +directive. If that directive was not preceded by a +#suite, it will be given the name "Core". +.PP +Pointers to \fBTCase\fR\&'s are declared +using the pattern +tc\fIX\fR_\fIY\fR, +where \fIX\fR corresponds to the number +used for the name of the \fBSuite\fR that +will contain this \fBTCase\fR; and +\fIY\fR is a number that starts at 1 for +each new \fBSuite\fR, and is incremented for +each \fBTCase\fR in that +\fBSuite\fR\&. +.PP +A pointer to \fBSRunner\fR is declared +using the identifier sr; there is also an +integer named nf which holds the number of +test failures (after the tests have run). +.PP +For obvious reasons, the user should not attempt to +declare local identifiers in \fBmain()\fR, or +define any macros or test functions, whose names might +conflict with the local variable names used by +\fBcheckmk\fR\&. To summarize, these names are: + +s\fIX\fR + +tc\fIX\fR_\fIY\fR + +sr + +nf\&. +.SS "MAIN() EPILOGUE" + +.nf +# main-post +.fi +.PP +Though it is not as useful, \fBcheckmk\fR also +provides a #main-post directive to insert +custom code at the end of \fBmain()\fR, after the +tests have run. This could be used to clean up resources that +were allocated in the prologue, or to print information about +the failed tests, or to provide a custom exit status +code. +.PP +Note that, if you make use of this directive, +\fBcheckmk\fR will \fBnot\fR provide a +return statement: you will need +to provide one yourself. +.PP +The #main-post directive may not be +followed by any other directives recognized by +\fBcheckmk\fR\&. +.SH "COMPREHENSIVE EXAMPLE" +.PP +Now that you've gotten the detailed descriptions of the +various directives, let's see it all put to action with this +fairly comprehensive template. + +.nf +-------------------------------------------------- +#include "mempool.h" /* defines MEMPOOLSZ, prototypes for + mempool_init() and mempool_free() */ + +void *mempool; + +void mp_setup(void) +{ + mempool = mempool_init(MEMPOOLSZ); + ck_assert_msg(mempool != NULL, "Couldn't allocate mempool."); +} + +void mp_teardown(void) +{ + mempool_free(mempool); +} + +/* end of prologue */ + +#suite Mempool + +#tcase MP Init + +#test mempool_init_zero_test + mempool = mempool_init(0); + ck_assert_msg(mempool == NULL, "Allocated a zero-sized mempool!"); + ck_assert_msg(mempool_error(), "Didn't get an error for zero alloc."); + +/* "MP Util" TCase uses checked fixture. */ +#tcase MP Util + +#test mempool_copy_test + void *cp = mempool_copy(mempool); + ck_assert_msg(cp != NULL, "Couldn't perform mempool copy."); + ck_assert_msg(cp != mempool, "Copy returned original pointer!"); + +#test mempool_size_test + ck_assert(mempool_getsize(mempool) == MEMPOOLSZ); + +#main-pre + tcase_add_checked_fixture(tc1_2, mp_setup, mp_teardown); + srunner_set_log(sr, "mplog.txt"); + +#main-post + if (nf != 0) { + printf("Hey, something's wrong! %d whole tests failed!\\n", nf); + } + return 0; /* Harness checks for output, always return success + regardless. */ +-------------------------------------------------- +.fi +.PP +Plugging this into \fBcheckmk\fR, we'll get +output roughly like the following: + +.nf +-------------------------------------------------- +/* + * DO NOT EDIT THIS FILE. Generated by checkmk. + * Edit the original source file "comprehensive.ts" instead. + */ + +#include + +#include "mempool.h" + +void *mempool; + +void mp_setup(void) +{ +\&... +} + +void mp_teardown(void) +{ +\&... +} + +/* end of prologue */ + +START_TEST(mempool_init_zero_test) +{ +\&... +} +END_TEST + +START_TEST(mempool_copy_test) +{ +\&... +} +END_TEST + +START_TEST(mempool_size_test) +{ +\&... +} +END_TEST + +int main(void) +{ + Suite *s1 = suite_create("Mempool"); + TCase *tc1_1 = tcase_create("MP Init"); + TCase *tc1_2 = tcase_create("MP Util"); + SRunner *sr = srunner_create(s1); + int nf; + + /* User-specified pre-run code */ + tcase_add_checked_fixture(tc1_2, mp_setup, mp_teardown); + srunner_set_log(sr, "mplog.txt"); + + suite_add_tcase(s1, tc1_1); + tcase_add_test(tc1_1, mempool_init_zero_test); + suite_add_tcase(s1, tc1_2); + tcase_add_test(tc1_2, mempool_copy_test); + tcase_add_test(tc1_2, mempool_size_test); + + srunner_run_all(sr, CK_ENV); + nf = srunner_ntests_failed(sr); + srunner_free(sr); + + /* User-specified post-run code */ + if (nf != 0) { + printf("Hey, something's wrong! %d whole tests failed!\\n", nf); + } + return 0; /* Harness checks for output, always return success + regardless. */ +} +-------------------------------------------------- +.fi +.SH "AUTHOR" +.PP +\fBcheckmk\fR and this manual were written +by Micah J Cowan. +.PP +Copyright (C) 2006, 2010 Micah J Cowan. diff --git a/checkmk/doc/checkmk.sgml b/checkmk/doc/checkmk.sgml new file mode 100644 index 0000000..feff9a5 --- /dev/null +++ b/checkmk/doc/checkmk.sgml @@ -0,0 +1,593 @@ + + + + + checkmk + 1 + + + + checkmk + Awk script for generating C unit tests for use with the + Check unit testing framework. + + + + + checkmk + + input-file + + + + + Description + + Generate C-language source files containing unit tests for use + with the Check unit testing framework. The aim of this script is + to automate away some of the typical boilerplate one must write when + writing a test suite using Check: specifically, the instantiation of + an SRunner, Suite(s), and TCase(s), and the building of + relationships between these objects and the test functions. + + This tool is intended to be used by those who are familiar + with the Check unit testing framework. Familiarity with the + framework will be assumed throughout this manual. + + The Check framework, along with information regarding it, is + available at http://check.sourceforge.net/. + + The input-file argument to + checkmk uses a simple, C-preprocessor-like + syntax to declare test functions, and to describe their + relationships to Suites and TCases in Check. + checkmk then uses this information to + automatically write a main() function + containing all of the necessary declarations, and whatever code is + needed to run the test suites. The final C-language output is + printed to checkmk's standard output. + + Facilities are provided for the insertion of user code into + the generated main() function, to provide for + the use of logging, test fixtures or specialized exit values. + + While it is possible to omit the + input-file argument to + checkmk and provide the input file on + checkmk's standard input instead, it is generally + recommended to provide it as an argument. Doing this allows + checkmk to be aware of the file's name, to place + references to it in the initial comments of the C-language output, + and to intersperse C #line directives throughout, to + facilitate in debugging problems by directing the user to the + original input file. + + + + Options + + The only officially supported option is specifying a true + value (using Awk's definition for "true") for the variable + . This causes checkmk + not to place appropriate #line directives in the + source code, which some might find to be unnecessary clutter. + + The author recommends against the use of this option, as it + will cause C compilers and debugging tools to refer to lines in the + automatically generated output, rather than the original input files + to checkmk. This would encourage users to edit the + output files instead of the original input files, would make it + difficult for intelligent editors or IDEs to pull up the right file + to edit, and could result in the fixes being overwritten when the + output files are regenerated. + + #line directives are automatically + supressed when the input file is provided on standard input + instead of as a command-line argument. + + + + Basic Example + + In its most basic form, an input file can be simply a + prologue and a test function. Anything that appears before the + first test function is in the prologue, and will be copied into + the output verbatim. The test function is begun by a line in the + form: + + #test test_name + + Where test_name is the name of + your test function. This will be used to name a C function, so + it must be a valid C identifier. + + Here is a small, complete example: + + + +#test the_test + int nc; + const char msg[] = "\n\n Hello, world!\n"; + + nc = printf("%s", msg); + fail_unless(nc == (sizeof msg + - 1) /* for terminating NUL. */ + ); +-------------------------------------------------- +]]> + + If you place the above into a file named + basic_complete.ts and process it using the + following command: + + $ checkmk basic_complete.ts > basic_complete.c + + basic_complete.c + will contain output similar to: + + + +/* A complete test example */ + +#include + +START_TEST(the_test) +{ + int nc; + const char msg[] = "\n\n Hello, world!\n"; + + nc = printf("%s", msg); + fail_unless(nc == (sizeof msg + - 1) /* for terminating NUL. */ + ); +} +END_TEST + +int main(void) +{ + Suite *s1 = suite_create("Core"); + TCase *tc1_1 = tcase_create("Core"); + SRunner *sr = srunner_create(s1); + int nf; + + suite_add_tcase(s1, tc1_1); + tcase_add_test(tc1_1, the_test); + + srunner_run_all(sr, CK_ENV); + nf = srunner_ntests_failed(sr); + srunner_free(sr); + + return nf == 0 ? 0 : 1; +} +-------------------------------------------------- +]]> + + In real usage, basic_complete.c would + also contain #line directives. + + + + Directive Summary + + Here is a complete summary of all the C-preprocessor-style + directives that are understood by checkmk. See + below for more details. + + # test test_name +# suite TestSuiteName +# tcase TestCaseName +# main-pre +# main-post + + All directives are case-insensitive. Whitespace may appear + at the beginning of the line before the #, + between the # and the directive, between the + directive and any argument, and at the end of the line. + + + + Test-Defining Directives + + Here is a more detailed explanation of the directives that may be + used to define test functions and their containers. + + + Test Functions + + # test test_name + + This is the most basic directive for creating a template + for input to checkmk. It is the only + directive that is required: there must be at least one + #test directive appearing in the template, or + checkmk will fail with an error message. The + #test directive may be specified several times, + each one beginning the definition of a new test function. + + The test_name argument will be + used as the name of a test function in the C-language output, so + it must be a valid C identifier. That is, it must begin with an + alphabetic character or the underscore (_), + followed by optional alpha-numeric characters and/or + underscores. + + Universal Character Names (introduced in C99) are also + allowed, of the form \uXXXX or + \UXXXXXXXX, where the X's + represent hexadecimal digits. + + It is an error to specify the same + test_name in more than one + #test directive, regardless of whether they + are associated with different test cases or suites. + + See CHECKMK + IDENTIFIERS for the list of identifiers which should be + avoided for use as test function names. + + + + Test Suites + + # suite TestSuiteName + + This directive specifies the name of the test suite + (Suite object in the Check test + framework) to which all future test cases (and their test + functions) will be added. + + The TestSuiteName is a text + string, and may contain any sort of characters at all (other + than ASCII NUL character, and the newline, which would terminate + the directive). Any leading or trailing whitespace will be omitted + from the test suite name. + + Starting a new test suite also begins a new test case, whose + name is identical to the new test suite. This test case name may be + overridden by a subsequent #tcase directive. + + Note that a Suite object won't + actually be defined by checkmk in the C + output, unless it is followed at some point by a + #test directive (without an intervening + #suite). It is not an error for a + #suite to have no associated + #test's; the #suite (and any + associated #tcase's) simply won't result in any + action on the part of checkmk (and would + therefore be useless). + + It is an error for a #suite directive to + specify the same (case sensitive) suite multiple times, unless the + previous uses were not instantiated by the presence of at least + one associated #test directive. + + If you do not specify a #suite directive + before the first #test directive, + checkmk performs the equivalent of an + implicit #suite directive, with the string + "Core" as the value for + TestSuiteName (this also implies a + "Core" test case object). This is demonstrated + above in BASIC EXAMPLE. + + + + Test Cases + + # tcase TestCaseName + + This directive specifies the name of the test case + (TCase object in the Check test + framework) to which all future test functions will be added. + + The #tcase works very in a way very + similar to #suite. The + TestCaseName is a text string, and + may contain arbitrary characters; and a + TCase object won't actually be defined + unless it is followed by an associated + #test directive. + + It is an error for a #tcase directive to + specify the same (case sensitive) test case multiple times, unless the + previous uses were not instantiated by the presence of at least + one associated #test directive. + + See also the #suite directive, described + above. + + + + + User Code In <function>main()</function> + + The C main() is automatically generated + by checkmk, defining the necessary + SRunner's, Suite's, + and TCase's required by the + test-defining directives specified by the user. + + For most situations, this completely automated + main() is quite suitable as-is. However, + there are situations where one might wish to add custom code to + the main(). For instance, if the user wishes + to: + + + change the test timeout value via + tcase_set_timeout(), + + specify Check's "no-fork-mode" via + srunner_set_fork_status(), + + set up test fixtures for some test cases, via + tcase_add_checked_fixture() + or tcase_add_unchecked_fixture(), + + set up test logging for the suite + runner, via srunner_set_log() + or srunner_set_xml(), or + + perform custom wrap-up after the test suites have + been run. + + + For these purposes, the #main-pre + and #main-post directives have been + provided. + + + Main() Prologue + + # main-pre + + The text following this directive will be placed verbatim + into the body of the generated main() + function, just after checkmk's own local + variable declarations, and before any test running has taken + place (indeed, before even the relationships between the tests, + test cases, and test suites have been set up, though that + fact shouldn't make much difference). Since + checkmk has only just finished making its + declarations, it is permissible, even under strict 1990 ISO C + guidelines, to make custom variable declarations here. + + Unlike the previously-described directives, + #main-pre may be specified at most once. It may + not be preceded by the #main-post directive, + and no #suite, #tcase, + or #test directive may appear after it. + + #main-pre is a good place to tweak + settings or set up test fixtures. Of course, in order to do so, + you need to know what names checkmk has used + to instantiate the SRunner's, + Suite's, + and TCase's. + + + <command>checkmk</command> Identifiers + + Pointers to Suite's are declared + using the pattern + sX, where + X is a number + that starts at 1, and is incremented for each subsequent + #suite directive. + s1 always exists, and contains the test + function declared by the first #test + directive. If that directive was not preceded by a + #suite, it will be given the name "Core". + + Pointers to TCase's are declared + using the pattern + tcX_Y, + where X corresponds to the number + used for the name of the Suite that + will contain this TCase; and + Y is a number that starts at 1 for + each new Suite, and is incremented for + each TCase in that + Suite. + + A pointer to SRunner is declared + using the identifier sr; there is also an + integer named nf which holds the number of + test failures (after the tests have run). + + For obvious reasons, the user should not attempt to + declare local identifiers in main(), or + define any macros or test functions, whose names might + conflict with the local variable names used by + checkmk. To summarize, these names are: + + + sX + tcX_Y + sr + nf + . + + + + + Main() Epilogue + + # main-post + + Though it is not as useful, checkmk also + provides a #main-post directive to insert + custom code at the end of main(), after the + tests have run. This could be used to clean up resources that + were allocated in the prologue, or to print information about + the failed tests, or to provide a custom exit status + code. + + Note that, if you make use of this directive, + checkmk will not provide a + return statement: you will need + to provide one yourself. + + The #main-post directive may not be + followed by any other directives recognized by + checkmk. + + + + + Comprehensive Example + + Now that you've gotten the detailed descriptions of the + various directives, let's see it all put to action with this + fairly comprehensive template. + + + + Plugging this into checkmk, we'll get + output roughly like the following: + + + +#include "mempool.h" + +void *mempool; + +void mp_setup(void) +{ + ... +} + +void mp_teardown(void) +{ + ... +} + +/* end of prologue */ + +START_TEST(mempool_init_zero_test) +{ + ... +} +END_TEST + +START_TEST(mempool_copy_test) +{ + ... +} +END_TEST + +START_TEST(mempool_size_test) +{ + ... +} +END_TEST + +int main(void) +{ + Suite *s1 = suite_create("Mempool"); + TCase *tc1_1 = tcase_create("MP Init"); + TCase *tc1_2 = tcase_create("MP Util"); + SRunner *sr = srunner_create(s1); + int nf; + + /* User-specified pre-run code */ + tcase_add_checked_fixture(tc1_2, mp_setup, mp_teardown); + srunner_set_log(sr, "mplog.txt"); + + suite_add_tcase(s1, tc1_1); + tcase_add_test(tc1_1, mempool_init_zero_test); + suite_add_tcase(s1, tc1_2); + tcase_add_test(tc1_2, mempool_copy_test); + tcase_add_test(tc1_2, mempool_size_test); + + srunner_run_all(sr, CK_ENV); + nf = srunner_ntests_failed(sr); + srunner_free(sr); + + /* User-specified post-run code */ + if (nf != 0) { + printf("Hey, something's wrong! %d whole tests failed!\n", nf); + } + return 0; /* Harness checks for output, always return success + regardless. */ +} +-------------------------------------------------- +]]> + + + + Author + + checkmk and this manual were written + by Micah J Cowan. + + Copyright (C) 2006, 2010 Micah J Cowan. + + diff --git a/checkmk/doc/manpage.links b/checkmk/doc/manpage.links new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/checkmk/doc/manpage.links diff --git a/checkmk/doc/manpage.refs b/checkmk/doc/manpage.refs new file mode 100644 index 0000000..16ffc79 --- /dev/null +++ b/checkmk/doc/manpage.refs @@ -0,0 +1,4 @@ +{ + '' => '', + '' => '' +} diff --git a/checkmk/examples/basic_complete.ts b/checkmk/examples/basic_complete.ts new file mode 120000 index 0000000..db942cc --- /dev/null +++ b/checkmk/examples/basic_complete.ts @@ -0,0 +1 @@ +../test/basic_complete/in \ No newline at end of file diff --git a/checkmk/examples/multiple_everything.ts b/checkmk/examples/multiple_everything.ts new file mode 120000 index 0000000..8a73ea1 --- /dev/null +++ b/checkmk/examples/multiple_everything.ts @@ -0,0 +1 @@ +../test/multiple_everything/in \ No newline at end of file diff --git a/checkmk/test/argument_ws/in b/checkmk/test/argument_ws/in new file mode 100644 index 0000000..9dc1572 --- /dev/null +++ b/checkmk/test/argument_ws/in @@ -0,0 +1,84 @@ +#test-exit(0) test1 + ck_assert(0 == 0); + #test-exit (1) test2 + ck_assert(1 == 0); + #test-exit ( 0) test3 + ck_assert(1 == 0); + #test-exit ( +0 ) test4 + ck_assert(1 == 0); + #test-exit ( -1 ) test5 + ck_assert(1 == 0); + #test-exit ( - 1 ) test6 + ck_assert(1 == 0); + #test-exit (- 0 ) test7 + ck_assert(1 == 0); + #test-exit ( + 1 ) test8 + ck_assert(1 == 0); + +#test-signal(0) test9 + ck_assert(0 == 0); + #test-signal (1) test10 + ck_assert(1 == 0); + #test-signal ( 0) test11 + ck_assert(1 == 0); + #test-signal ( +0 ) test12 + ck_assert(1 == 2); + #test-signal ( -1 ) test13 + ck_assert(1 == 0); + #test-signal ( - 1 ) test14 + ck_assert(1 == 0); + #test-signal (- 0 ) test15 + ck_assert(1 == 0); + #test-signal ( + 1 ) test16 + ck_assert(1 == 0); + +#test-loop(0,2) test17 + ck_assert(0 == 0); + #test-loop (1 ,0) test18 + ck_assert(1 == 0); + #test-loop ( 0 , 1) test19 + ck_assert(1 == 1); + #test-loop ( +0 , -2) test20 + ck_assert(1 == 0); + #test-loop ( -1 ,+ 3) test21 + ck_assert(1 == 0); + #test-loop ( - 1, + 2 ) test22 + ck_assert(1 == 0); + #test-loop (- 0 , - 2) test23 + ck_assert(1 == 0); + #test-loop ( + 1 , - 3 ) test24 + ck_assert(1 == 1); + +#test-loop-exit(1,0,2) test25 + ck_assert(0 == 1); + #test-loop-exit ( 2,1 ,0) test26 + ck_assert(1 == 0); + #test-loop-exit ( 2 ,0 , 1) test27 + ck_assert(1 == 0); + #test-loop-exit ( -1 , +0 , -2) test28 + ck_assert(1 == 0); + #test-loop-exit ( - 3 , -1 ,+ 3) test29 + ck_assert(1 == 1); + #test-loop-exit ( + 0, - 1, + 2 ) test30 + ck_assert(1 == 0); + #test-loop-exit (- 4 ,- 0 , - 2) test31 + ck_assert(1 == 0); + #test-loop-exit ( +2 , + 1 , - 3 ) test32 + ck_assert(1 == 0); + +#test-loop-signal(1,0,2) test33 + ck_assert(0 == 0); + #test-loop-signal ( 2,1 ,0) test34 + ck_assert(1 == 0); + #test-loop-signal ( 2 ,0 , 1) test35 + ck_assert(1 == 1); + #test-loop-signal ( -1 , +0 , -2) test36 + ck_assert(1 == 0); + #test-loop-signal ( - 3 , -1 ,+ 3) test37 + ck_assert(1 == 0); + #test-loop-signal ( + 0, - 1, + 2 ) test38 + ck_assert(1 == 0); + #test-loop-signal (- 4 ,- 0 , - 2) test39 + ck_assert(1 == 0); + #test-loop-signal ( +2 , + 1 , - 3 ) test40 + ck_assert(1 == 1); \ No newline at end of file diff --git a/checkmk/test/argument_ws/x_output b/checkmk/test/argument_ws/x_output new file mode 100644 index 0000000..59d5556 --- /dev/null +++ b/checkmk/test/argument_ws/x_output @@ -0,0 +1,347 @@ +/* + * DO NOT EDIT THIS FILE. Generated by checkmk. + * Edit the original source file "in" instead. + */ + +#include + +#line 1 "in" +START_TEST(test1) +{ +#line 2 + ck_assert(0 == 0); +} +END_TEST + +START_TEST(test2) +{ +#line 4 + ck_assert(1 == 0); +} +END_TEST + +START_TEST(test3) +{ +#line 6 + ck_assert(1 == 0); +} +END_TEST + +START_TEST(test4) +{ +#line 8 + ck_assert(1 == 0); +} +END_TEST + +START_TEST(test5) +{ +#line 10 + ck_assert(1 == 0); +} +END_TEST + +START_TEST(test6) +{ +#line 12 + ck_assert(1 == 0); +} +END_TEST + +START_TEST(test7) +{ +#line 14 + ck_assert(1 == 0); +} +END_TEST + +START_TEST(test8) +{ +#line 16 + ck_assert(1 == 0); + +} +END_TEST + +START_TEST(test9) +{ +#line 19 + ck_assert(0 == 0); +} +END_TEST + +START_TEST(test10) +{ +#line 21 + ck_assert(1 == 0); +} +END_TEST + +START_TEST(test11) +{ +#line 23 + ck_assert(1 == 0); +} +END_TEST + +START_TEST(test12) +{ +#line 25 + ck_assert(1 == 2); +} +END_TEST + +START_TEST(test13) +{ +#line 27 + ck_assert(1 == 0); +} +END_TEST + +START_TEST(test14) +{ +#line 29 + ck_assert(1 == 0); +} +END_TEST + +START_TEST(test15) +{ +#line 31 + ck_assert(1 == 0); +} +END_TEST + +START_TEST(test16) +{ +#line 33 + ck_assert(1 == 0); + +} +END_TEST + +START_TEST(test17) +{ +#line 36 + ck_assert(0 == 0); +} +END_TEST + +START_TEST(test18) +{ +#line 38 + ck_assert(1 == 0); +} +END_TEST + +START_TEST(test19) +{ +#line 40 + ck_assert(1 == 1); +} +END_TEST + +START_TEST(test20) +{ +#line 42 + ck_assert(1 == 0); +} +END_TEST + +START_TEST(test21) +{ +#line 44 + ck_assert(1 == 0); +} +END_TEST + +START_TEST(test22) +{ +#line 46 + ck_assert(1 == 0); +} +END_TEST + +START_TEST(test23) +{ +#line 48 + ck_assert(1 == 0); +} +END_TEST + +START_TEST(test24) +{ +#line 50 + ck_assert(1 == 1); + +} +END_TEST + +START_TEST(test25) +{ +#line 53 + ck_assert(0 == 1); +} +END_TEST + +START_TEST(test26) +{ +#line 55 + ck_assert(1 == 0); +} +END_TEST + +START_TEST(test27) +{ +#line 57 + ck_assert(1 == 0); +} +END_TEST + +START_TEST(test28) +{ +#line 59 + ck_assert(1 == 0); +} +END_TEST + +START_TEST(test29) +{ +#line 61 + ck_assert(1 == 1); +} +END_TEST + +START_TEST(test30) +{ +#line 63 + ck_assert(1 == 0); +} +END_TEST + +START_TEST(test31) +{ +#line 65 + ck_assert(1 == 0); +} +END_TEST + +START_TEST(test32) +{ +#line 67 + ck_assert(1 == 0); + +} +END_TEST + +START_TEST(test33) +{ +#line 70 + ck_assert(0 == 0); +} +END_TEST + +START_TEST(test34) +{ +#line 72 + ck_assert(1 == 0); +} +END_TEST + +START_TEST(test35) +{ +#line 74 + ck_assert(1 == 1); +} +END_TEST + +START_TEST(test36) +{ +#line 76 + ck_assert(1 == 0); +} +END_TEST + +START_TEST(test37) +{ +#line 78 + ck_assert(1 == 0); +} +END_TEST + +START_TEST(test38) +{ +#line 80 + ck_assert(1 == 0); +} +END_TEST + +START_TEST(test39) +{ +#line 82 + ck_assert(1 == 0); +} +END_TEST + +START_TEST(test40) +{ +#line 84 + ck_assert(1 == 1); +} +END_TEST + +int main(void) +{ + Suite *s1 = suite_create("Core"); + TCase *tc1_1 = tcase_create("Core"); + SRunner *sr = srunner_create(s1); + int nf; + + suite_add_tcase(s1, tc1_1); + tcase_add_exit_test(tc1_1, test1, 0); + tcase_add_exit_test(tc1_1, test2, 1); + tcase_add_exit_test(tc1_1, test3, 0); + tcase_add_exit_test(tc1_1, test4, +0); + tcase_add_exit_test(tc1_1, test5, -1); + tcase_add_exit_test(tc1_1, test6, -1); + tcase_add_exit_test(tc1_1, test7, -0); + tcase_add_exit_test(tc1_1, test8, +1); + tcase_add_test_raise_signal(tc1_1, test9, 0); + tcase_add_test_raise_signal(tc1_1, test10, 1); + tcase_add_test_raise_signal(tc1_1, test11, 0); + tcase_add_test_raise_signal(tc1_1, test12, +0); + tcase_add_test_raise_signal(tc1_1, test13, -1); + tcase_add_test_raise_signal(tc1_1, test14, -1); + tcase_add_test_raise_signal(tc1_1, test15, -0); + tcase_add_test_raise_signal(tc1_1, test16, +1); + tcase_add_loop_test(tc1_1, test17, 0, 2); + tcase_add_loop_test(tc1_1, test18, 1, 0); + tcase_add_loop_test(tc1_1, test19, 0, 1); + tcase_add_loop_test(tc1_1, test20, +0, -2); + tcase_add_loop_test(tc1_1, test21, -1, +3); + tcase_add_loop_test(tc1_1, test22, -1, +2); + tcase_add_loop_test(tc1_1, test23, -0, -2); + tcase_add_loop_test(tc1_1, test24, +1, -3); + tcase_add_loop_exit_test(tc1_1, test25, 1, 0, 2); + tcase_add_loop_exit_test(tc1_1, test26, 2, 1, 0); + tcase_add_loop_exit_test(tc1_1, test27, 2, 0, 1); + tcase_add_loop_exit_test(tc1_1, test28, -1, +0, -2); + tcase_add_loop_exit_test(tc1_1, test29, -3, -1, +3); + tcase_add_loop_exit_test(tc1_1, test30, +0, -1, +2); + tcase_add_loop_exit_test(tc1_1, test31, -4, -0, -2); + tcase_add_loop_exit_test(tc1_1, test32, +2, +1, -3); + tcase_add_loop_test_raise_signal(tc1_1, test33, 1, 0, 2); + tcase_add_loop_test_raise_signal(tc1_1, test34, 2, 1, 0); + tcase_add_loop_test_raise_signal(tc1_1, test35, 2, 0, 1); + tcase_add_loop_test_raise_signal(tc1_1, test36, -1, +0, -2); + tcase_add_loop_test_raise_signal(tc1_1, test37, -3, -1, +3); + tcase_add_loop_test_raise_signal(tc1_1, test38, +0, -1, +2); + tcase_add_loop_test_raise_signal(tc1_1, test39, -4, -0, -2); + tcase_add_loop_test_raise_signal(tc1_1, test40, +2, +1, -3); + + srunner_run_all(sr, CK_ENV); + nf = srunner_ntests_failed(sr); + srunner_free(sr); + + return nf == 0 ? 0 : 1; +} diff --git a/checkmk/test/basic_complete/in b/checkmk/test/basic_complete/in new file mode 100644 index 0000000..a296f93 --- /dev/null +++ b/checkmk/test/basic_complete/in @@ -0,0 +1,16 @@ +/* A complete test example */ + +#include + +# suite The Suite + +# tcase The Test Case + +# test the_test + int nc; + const char msg[] = "\n\n Hello, world!\n"; + + nc = printf("%s", msg); + fail_unless(nc == (sizeof msg + - 1) /* for terminating NUL. */ + ); diff --git a/checkmk/test/basic_complete/x_output b/checkmk/test/basic_complete/x_output new file mode 100644 index 0000000..77cff13 --- /dev/null +++ b/checkmk/test/basic_complete/x_output @@ -0,0 +1,43 @@ +/* + * DO NOT EDIT THIS FILE. Generated by checkmk. + * Edit the original source file "in" instead. + */ + +#include + +#line 1 "in" +/* A complete test example */ + +#include + + + +START_TEST(the_test) +{ +#line 10 + int nc; + const char msg[] = "\n\n Hello, world!\n"; + + nc = printf("%s", msg); + fail_unless(nc == (sizeof msg + - 1) /* for terminating NUL. */ + ); +} +END_TEST + +int main(void) +{ + Suite *s1 = suite_create("The Suite"); + TCase *tc1_1 = tcase_create("The Test Case"); + SRunner *sr = srunner_create(s1); + int nf; + + suite_add_tcase(s1, tc1_1); + tcase_add_test(tc1_1, the_test); + + srunner_run_all(sr, CK_ENV); + nf = srunner_ntests_failed(sr); + srunner_free(sr); + + return nf == 0 ? 0 : 1; +} diff --git a/checkmk/test/between_the_lines/in b/checkmk/test/between_the_lines/in new file mode 100644 index 0000000..c72d58e --- /dev/null +++ b/checkmk/test/between_the_lines/in @@ -0,0 +1,12 @@ +int foo; + +#suite A + +int bar; + +#tcase B + +int baz; + +#test C + fail_unless(foo | bar | baz == 0); diff --git a/checkmk/test/between_the_lines/x_output b/checkmk/test/between_the_lines/x_output new file mode 100644 index 0000000..d64c4b8 --- /dev/null +++ b/checkmk/test/between_the_lines/x_output @@ -0,0 +1,41 @@ +/* + * DO NOT EDIT THIS FILE. Generated by checkmk. + * Edit the original source file "in" instead. + */ + +#include + +#line 1 "in" +int foo; + + +#line 5 +int bar; + + +#line 9 +int baz; + +START_TEST(C) +{ +#line 12 + fail_unless(foo | bar | baz == 0); +} +END_TEST + +int main(void) +{ + Suite *s1 = suite_create("A"); + TCase *tc1_1 = tcase_create("B"); + SRunner *sr = srunner_create(s1); + int nf; + + suite_add_tcase(s1, tc1_1); + tcase_add_test(tc1_1, C); + + srunner_run_all(sr, CK_ENV); + nf = srunner_ntests_failed(sr); + srunner_free(sr); + + return nf == 0 ? 0 : 1; +} diff --git a/checkmk/test/case_insensitive_pp/in b/checkmk/test/case_insensitive_pp/in new file mode 100644 index 0000000..89ab9a5 --- /dev/null +++ b/checkmk/test/case_insensitive_pp/in @@ -0,0 +1,16 @@ +/* Test case-insensitive directives. */ + +#include + +# SuiTe The Suite + +# tCaSe The Test Case + +# teSt the_test + int nc; + const char msg[] = "\n\n Hello, world!\n"; + + nc = printf("%s", msg); + fail_unless(nc == (sizeof msg + - 1) /* for terminating NUL. */ + ); diff --git a/checkmk/test/case_insensitive_pp/x_output b/checkmk/test/case_insensitive_pp/x_output new file mode 100644 index 0000000..af11f07 --- /dev/null +++ b/checkmk/test/case_insensitive_pp/x_output @@ -0,0 +1,43 @@ +/* + * DO NOT EDIT THIS FILE. Generated by checkmk. + * Edit the original source file "in" instead. + */ + +#include + +#line 1 "in" +/* Test case-insensitive directives. */ + +#include + + + +START_TEST(the_test) +{ +#line 10 + int nc; + const char msg[] = "\n\n Hello, world!\n"; + + nc = printf("%s", msg); + fail_unless(nc == (sizeof msg + - 1) /* for terminating NUL. */ + ); +} +END_TEST + +int main(void) +{ + Suite *s1 = suite_create("The Suite"); + TCase *tc1_1 = tcase_create("The Test Case"); + SRunner *sr = srunner_create(s1); + int nf; + + suite_add_tcase(s1, tc1_1); + tcase_add_test(tc1_1, the_test); + + srunner_run_all(sr, CK_ENV); + nf = srunner_ntests_failed(sr); + srunner_free(sr); + + return nf == 0 ? 0 : 1; +} diff --git a/checkmk/test/check_checkmk b/checkmk/test/check_checkmk new file mode 100755 index 0000000..1f0120e --- /dev/null +++ b/checkmk/test/check_checkmk @@ -0,0 +1,143 @@ +#!/usr/bin/env sh + +TESTS_RUN=0 +TESTS_PASSED=0 +TESTS_FAILED=0 + +TEST_DIRS='empty_input pass_thru single_test_line basic_complete' +TEST_DIRS="$TEST_DIRS multiple_everything between_the_lines" +TEST_DIRS="$TEST_DIRS repeated_suites repeated_tcases repeated_tests" +TEST_DIRS="$TEST_DIRS not_really_repeated tcase_implied_repeat" +TEST_DIRS="$TEST_DIRS case_insensitive_pp trailing_ws non_word_chars" +TEST_DIRS="$TEST_DIRS test_chars num_start_test_name" +TEST_DIRS="$TEST_DIRS no_args clean_mode declarations test_after_main_pre" +TEST_DIRS="$TEST_DIRS main_pre_multiple main_post main_pre_after_post" +TEST_DIRS="$TEST_DIRS test_after_main_post main_post_multiple ucn" +TEST_DIRS="$TEST_DIRS invalid_ucn argument_ws repeated_argument_tests" + +check_dir() { + status=0 + + checkmkdir=$PWD + outdir="test.out/$1" + testdir="$srcdir/test/$1" + + if ! mkdir -p "$outdir" + then + echo "Couldn't make path \"$outdir\"!" + fi + outdir=$(cd "$outdir" && pwd) + + if ! cd "$testdir" + then + echo "Couldn't chdir to \"$testdir\"!" + fi + + # set up expected input/output file names + infname=in + outfname="$outdir/output" + errfname="$outdir/err" + diffname="$outdir/diff" + errdiffname="$outdir/err-diff" + CHECKMK="$checkmkdir/checkmk" + checkmk_cmd='"$CHECKMK" "$infname" > "$outfname" 2>"$errfname"' + + rm -f "$outfname" "$errfname" "$diffname" "$errdiffname" + + # source local versions, if available. + [ -r ./cmd ] && . ./cmd + + # Check output. + eval "$checkmk_cmd" + ckstat=$? + + if ! diff -c "x_output" "$outfname" > "$diffname" + then + echo "Unexpected output differences:" + cat "$diffname" + status=1 + fi + + # Check stderr. + if [ -s x_err ] + then + if ! diff -c "x_err" "$errfname" > "$errdiffname" + then + echo "Unexpected error differences:" + cat "$errdiffname" + status=1 + fi + elif [ -s err ] + then + echo "Unexpected text from standard error:" + echo "------------------------------------" + cat "$errfname" + echo "------------------------------------" + status=1 + fi + + # Check status. + xstat=0 + if [ -e "x_exit" ] + then + xstat=`cat x_exit` + elif [ -s "x_err" ] + then + xstat=1 + fi + + if [ $xstat != $ckstat ] + then + echo "Expected exit status of $xstat, but got $ckstat." + status=1 + fi + + return $status +} + +pass_dir() { + echo "Test $1 passed." + TESTS_PASSED=$(($TESTS_PASSED+1)) +} + +fail_dir() { + echo "Test $1 FAILED." + TESTS_FAILED=$(($TESTS_FAILED+1)) +} + +echo "These are the tests for the checkmk program." +echo +echo "====================" +echo " Test Run Start" +echo "====================" +echo + +for dir in $TEST_DIRS +do + echo "Running test $dir..." + if ( check_dir $dir ) + then + pass_dir $dir + else + fail_dir $dir + fi + TESTS_RUN=$(($TESTS_RUN+1)) + echo +done + +echo "====================" +echo " Test Run Complete" +echo "====================" +echo "Total: $TESTS_RUN" +echo "Passed: $TESTS_PASSED" +echo "Failed: $TESTS_FAILED" + +if [ "$TESTS_FAILED" -gt 0 ] +then + echo + echo "****************************************" + echo " TEST RUN FAILED!!!!" + echo "****************************************" + exit 1; +fi +echo diff --git a/checkmk/test/clean_mode/cmd b/checkmk/test/clean_mode/cmd new file mode 100644 index 0000000..d88410f --- /dev/null +++ b/checkmk/test/clean_mode/cmd @@ -0,0 +1 @@ +checkmk_cmd='"$CHECKMK" clean_mode=1 "$infname" > "$outfname" 2>"$errfname"' diff --git a/checkmk/test/clean_mode/in b/checkmk/test/clean_mode/in new file mode 100644 index 0000000..a296f93 --- /dev/null +++ b/checkmk/test/clean_mode/in @@ -0,0 +1,16 @@ +/* A complete test example */ + +#include + +# suite The Suite + +# tcase The Test Case + +# test the_test + int nc; + const char msg[] = "\n\n Hello, world!\n"; + + nc = printf("%s", msg); + fail_unless(nc == (sizeof msg + - 1) /* for terminating NUL. */ + ); diff --git a/checkmk/test/clean_mode/x_output b/checkmk/test/clean_mode/x_output new file mode 100644 index 0000000..3dff645 --- /dev/null +++ b/checkmk/test/clean_mode/x_output @@ -0,0 +1,41 @@ +/* + * DO NOT EDIT THIS FILE. Generated by checkmk. + * Edit the original source file "in" instead. + */ + +#include + +/* A complete test example */ + +#include + + + +START_TEST(the_test) +{ + int nc; + const char msg[] = "\n\n Hello, world!\n"; + + nc = printf("%s", msg); + fail_unless(nc == (sizeof msg + - 1) /* for terminating NUL. */ + ); +} +END_TEST + +int main(void) +{ + Suite *s1 = suite_create("The Suite"); + TCase *tc1_1 = tcase_create("The Test Case"); + SRunner *sr = srunner_create(s1); + int nf; + + suite_add_tcase(s1, tc1_1); + tcase_add_test(tc1_1, the_test); + + srunner_run_all(sr, CK_ENV); + nf = srunner_ntests_failed(sr); + srunner_free(sr); + + return nf == 0 ? 0 : 1; +} diff --git a/checkmk/test/declarations/in b/checkmk/test/declarations/in new file mode 100644 index 0000000..921d7a5 --- /dev/null +++ b/checkmk/test/declarations/in @@ -0,0 +1,19 @@ +/* A complete test example */ + +#include + +# suite The Suite + +# tcase The Test Case + +# test the_test + int nc; + const char msg[] = "\n\n Hello, world!\n"; + + nc = printf("%s", msg); + fail_unless(nc == (sizeof msg + - 1) /* for terminating NUL. */ + ); + +# main-pre + int declare_me = 0; diff --git a/checkmk/test/declarations/x_output b/checkmk/test/declarations/x_output new file mode 100644 index 0000000..a819ce8 --- /dev/null +++ b/checkmk/test/declarations/x_output @@ -0,0 +1,48 @@ +/* + * DO NOT EDIT THIS FILE. Generated by checkmk. + * Edit the original source file "in" instead. + */ + +#include + +#line 1 "in" +/* A complete test example */ + +#include + + + +START_TEST(the_test) +{ +#line 10 + int nc; + const char msg[] = "\n\n Hello, world!\n"; + + nc = printf("%s", msg); + fail_unless(nc == (sizeof msg + - 1) /* for terminating NUL. */ + ); + +} +END_TEST + +int main(void) +{ + Suite *s1 = suite_create("The Suite"); + TCase *tc1_1 = tcase_create("The Test Case"); + SRunner *sr = srunner_create(s1); + int nf; + + /* User-specified pre-run code */ +#line 19 + int declare_me = 0; + + suite_add_tcase(s1, tc1_1); + tcase_add_test(tc1_1, the_test); + + srunner_run_all(sr, CK_ENV); + nf = srunner_ntests_failed(sr); + srunner_free(sr); + + return nf == 0 ? 0 : 1; +} diff --git a/checkmk/test/empty_input/in b/checkmk/test/empty_input/in new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/checkmk/test/empty_input/in diff --git a/checkmk/test/empty_input/x_err b/checkmk/test/empty_input/x_err new file mode 100644 index 0000000..f55516b --- /dev/null +++ b/checkmk/test/empty_input/x_err @@ -0,0 +1 @@ +checkmk: Expected at least one #test line. diff --git a/checkmk/test/empty_input/x_output b/checkmk/test/empty_input/x_output new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/checkmk/test/empty_input/x_output diff --git a/checkmk/test/invalid_ucn/in b/checkmk/test/invalid_ucn/in new file mode 100644 index 0000000..90a0a5d --- /dev/null +++ b/checkmk/test/invalid_ucn/in @@ -0,0 +1,16 @@ +/* A complete test example */ + +#include + +# suite The Suite + +# tcase The Test Case + +# test the_\u4ECA\u65E5\u306_test + int nc; + const char msg[] = "\n\n Hello, world!\n"; + + nc = printf("%s", msg); + fail_unless(nc == (sizeof msg + - 1) /* for terminating NUL. */ + ); diff --git a/checkmk/test/invalid_ucn/x_err b/checkmk/test/invalid_ucn/x_err new file mode 100644 index 0000000..78d0160 --- /dev/null +++ b/checkmk/test/invalid_ucn/x_err @@ -0,0 +1 @@ +checkmk: in line 9: Malformed test name "the_\u4ECA\u65E5\u306_test" (must be a C identifier). diff --git a/checkmk/test/invalid_ucn/x_output b/checkmk/test/invalid_ucn/x_output new file mode 100644 index 0000000..f3df163 --- /dev/null +++ b/checkmk/test/invalid_ucn/x_output @@ -0,0 +1,14 @@ +/* + * DO NOT EDIT THIS FILE. Generated by checkmk. + * Edit the original source file "in" instead. + */ + +#include + +#line 1 "in" +/* A complete test example */ + +#include + + + diff --git a/checkmk/test/main_post/in b/checkmk/test/main_post/in new file mode 100644 index 0000000..fb1595d --- /dev/null +++ b/checkmk/test/main_post/in @@ -0,0 +1,19 @@ +/* A complete test example */ + +#include + +# suite The Suite + +# tcase The Test Case + +# test the_test + int nc; + const char msg[] = "\n\n Hello, world!\n"; + + nc = printf("%s", msg); + fail_unless(nc == (sizeof msg + - 1) /* for terminating NUL. */ + ); + +# main-post + return 0; /* Always report success. */ diff --git a/checkmk/test/main_post/x_output b/checkmk/test/main_post/x_output new file mode 100644 index 0000000..2f499f9 --- /dev/null +++ b/checkmk/test/main_post/x_output @@ -0,0 +1,46 @@ +/* + * DO NOT EDIT THIS FILE. Generated by checkmk. + * Edit the original source file "in" instead. + */ + +#include + +#line 1 "in" +/* A complete test example */ + +#include + + + +START_TEST(the_test) +{ +#line 10 + int nc; + const char msg[] = "\n\n Hello, world!\n"; + + nc = printf("%s", msg); + fail_unless(nc == (sizeof msg + - 1) /* for terminating NUL. */ + ); + +} +END_TEST + +int main(void) +{ + Suite *s1 = suite_create("The Suite"); + TCase *tc1_1 = tcase_create("The Test Case"); + SRunner *sr = srunner_create(s1); + int nf; + + suite_add_tcase(s1, tc1_1); + tcase_add_test(tc1_1, the_test); + + srunner_run_all(sr, CK_ENV); + nf = srunner_ntests_failed(sr); + srunner_free(sr); + + /* User-specified post-run code */ +#line 19 + return 0; /* Always report success. */ +} diff --git a/checkmk/test/main_post_multiple/in b/checkmk/test/main_post_multiple/in new file mode 100644 index 0000000..e61ab55 --- /dev/null +++ b/checkmk/test/main_post_multiple/in @@ -0,0 +1,22 @@ +/* A complete test example */ + +#include + +# suite The Suite + +# tcase The Test Case + +# test the_test + int nc; + const char msg[] = "\n\n Hello, world!\n"; + + nc = printf("%s", msg); + fail_unless(nc == (sizeof msg + - 1) /* for terminating NUL. */ + ); + +# main-post + return 0; /* Always report success. */ + +# main-post + return 0; /* We really want success, so we'll specify it twice! */ diff --git a/checkmk/test/main_post_multiple/x_err b/checkmk/test/main_post_multiple/x_err new file mode 100644 index 0000000..a0634d9 --- /dev/null +++ b/checkmk/test/main_post_multiple/x_err @@ -0,0 +1 @@ +checkmk: in line 21: main-post specified multiple times. diff --git a/checkmk/test/main_post_multiple/x_output b/checkmk/test/main_post_multiple/x_output new file mode 100644 index 0000000..fc7b9d2 --- /dev/null +++ b/checkmk/test/main_post_multiple/x_output @@ -0,0 +1,46 @@ +/* + * DO NOT EDIT THIS FILE. Generated by checkmk. + * Edit the original source file "in" instead. + */ + +#include + +#line 1 "in" +/* A complete test example */ + +#include + + + +START_TEST(the_test) +{ +#line 10 + int nc; + const char msg[] = "\n\n Hello, world!\n"; + + nc = printf("%s", msg); + fail_unless(nc == (sizeof msg + - 1) /* for terminating NUL. */ + ); + +} +END_TEST + +int main(void) +{ + Suite *s1 = suite_create("The Suite"); + TCase *tc1_1 = tcase_create("The Test Case"); + SRunner *sr = srunner_create(s1); + int nf; + + suite_add_tcase(s1, tc1_1); + tcase_add_test(tc1_1, the_test); + + srunner_run_all(sr, CK_ENV); + nf = srunner_ntests_failed(sr); + srunner_free(sr); + + /* User-specified post-run code */ +#line 19 + return 0; /* Always report success. */ + diff --git a/checkmk/test/main_pre_after_post/in b/checkmk/test/main_pre_after_post/in new file mode 100644 index 0000000..b6822fb --- /dev/null +++ b/checkmk/test/main_pre_after_post/in @@ -0,0 +1,22 @@ +/* A complete test example */ + +#include + +# suite The Suite + +# tcase The Test Case + +# test the_test + int nc; + const char msg[] = "\n\n Hello, world!\n"; + + nc = printf("%s", msg); + fail_unless(nc == (sizeof msg + - 1) /* for terminating NUL. */ + ); + +# main-post + return 0; /* Always report success. */ + +# main-pre + int declare_me = 0; diff --git a/checkmk/test/main_pre_after_post/x_err b/checkmk/test/main_pre_after_post/x_err new file mode 100644 index 0000000..a6fc75b --- /dev/null +++ b/checkmk/test/main_pre_after_post/x_err @@ -0,0 +1 @@ +checkmk: in line 21: main-pre specified after main-post. diff --git a/checkmk/test/main_pre_after_post/x_output b/checkmk/test/main_pre_after_post/x_output new file mode 100644 index 0000000..fc7b9d2 --- /dev/null +++ b/checkmk/test/main_pre_after_post/x_output @@ -0,0 +1,46 @@ +/* + * DO NOT EDIT THIS FILE. Generated by checkmk. + * Edit the original source file "in" instead. + */ + +#include + +#line 1 "in" +/* A complete test example */ + +#include + + + +START_TEST(the_test) +{ +#line 10 + int nc; + const char msg[] = "\n\n Hello, world!\n"; + + nc = printf("%s", msg); + fail_unless(nc == (sizeof msg + - 1) /* for terminating NUL. */ + ); + +} +END_TEST + +int main(void) +{ + Suite *s1 = suite_create("The Suite"); + TCase *tc1_1 = tcase_create("The Test Case"); + SRunner *sr = srunner_create(s1); + int nf; + + suite_add_tcase(s1, tc1_1); + tcase_add_test(tc1_1, the_test); + + srunner_run_all(sr, CK_ENV); + nf = srunner_ntests_failed(sr); + srunner_free(sr); + + /* User-specified post-run code */ +#line 19 + return 0; /* Always report success. */ + diff --git a/checkmk/test/main_pre_multiple/in b/checkmk/test/main_pre_multiple/in new file mode 100644 index 0000000..e7e30da --- /dev/null +++ b/checkmk/test/main_pre_multiple/in @@ -0,0 +1,22 @@ +/* A complete test example */ + +#include + +# suite The Suite + +# tcase The Test Case + +# test the_test + int nc; + const char msg[] = "\n\n Hello, world!\n"; + + nc = printf("%s", msg); + fail_unless(nc == (sizeof msg + - 1) /* for terminating NUL. */ + ); + +# main-pre + int declare_me = 0; + +# main-pre + int oh_wait_declare_me_too; diff --git a/checkmk/test/main_pre_multiple/x_err b/checkmk/test/main_pre_multiple/x_err new file mode 100644 index 0000000..69c3c02 --- /dev/null +++ b/checkmk/test/main_pre_multiple/x_err @@ -0,0 +1 @@ +checkmk: in line 21: main-pre specified multiple times. diff --git a/checkmk/test/main_pre_multiple/x_output b/checkmk/test/main_pre_multiple/x_output new file mode 100644 index 0000000..aa9e38e --- /dev/null +++ b/checkmk/test/main_pre_multiple/x_output @@ -0,0 +1,39 @@ +/* + * DO NOT EDIT THIS FILE. Generated by checkmk. + * Edit the original source file "in" instead. + */ + +#include + +#line 1 "in" +/* A complete test example */ + +#include + + + +START_TEST(the_test) +{ +#line 10 + int nc; + const char msg[] = "\n\n Hello, world!\n"; + + nc = printf("%s", msg); + fail_unless(nc == (sizeof msg + - 1) /* for terminating NUL. */ + ); + +} +END_TEST + +int main(void) +{ + Suite *s1 = suite_create("The Suite"); + TCase *tc1_1 = tcase_create("The Test Case"); + SRunner *sr = srunner_create(s1); + int nf; + + /* User-specified pre-run code */ +#line 19 + int declare_me = 0; + diff --git a/checkmk/test/multiple_everything/in b/checkmk/test/multiple_everything/in new file mode 100644 index 0000000..fbe4518 --- /dev/null +++ b/checkmk/test/multiple_everything/in @@ -0,0 +1,47 @@ +/* Multiple everything... */ + +#include +#include +#include + +void print_message(const char *msg, size_t msgsz) +{ + int nc; + + nc = printf("%s", msg); + fail_unless(nc == msgsz, "failed to print completely: %s", + strerror(errno)); +} + +# suite A Suite + +# tcase A Test Case + +# test hello_world + const char msg[] = "Hello, world!\n"; + print_message(msg, sizeof msg - 1); + +# test neverending_story + const char msg[] = "Bastian Balthazar Bux\n"; + print_message(msg, sizeof msg - 1); + +# tcase Another Test Case + +# test math_problem + fail_unless(1 + 1 == 2, "Something's broken..."); + +# suite Another Suite + +# tcase A Test Case for Another Suite + +# test more_math + fail_unless(2/2 == 1, "Another weird math result"); + +# tcase A Basket Case + +# test weave + int i; + const char msg[] = "###\n"; + + for (i=0; i != 3; ++i) + print_message(row, sizeof row - 1); diff --git a/checkmk/test/multiple_everything/x_output b/checkmk/test/multiple_everything/x_output new file mode 100644 index 0000000..dc24cae --- /dev/null +++ b/checkmk/test/multiple_everything/x_output @@ -0,0 +1,100 @@ +/* + * DO NOT EDIT THIS FILE. Generated by checkmk. + * Edit the original source file "in" instead. + */ + +#include + +#line 1 "in" +/* Multiple everything... */ + +#include +#include +#include + +void print_message(const char *msg, size_t msgsz) +{ + int nc; + + nc = printf("%s", msg); + fail_unless(nc == msgsz, "failed to print completely: %s", + strerror(errno)); +} + + + +START_TEST(hello_world) +{ +#line 21 + const char msg[] = "Hello, world!\n"; + print_message(msg, sizeof msg - 1); + +} +END_TEST + +START_TEST(neverending_story) +{ +#line 25 + const char msg[] = "Bastian Balthazar Bux\n"; + print_message(msg, sizeof msg - 1); + +} +END_TEST + +START_TEST(math_problem) +{ +#line 31 + fail_unless(1 + 1 == 2, "Something's broken..."); + +} +END_TEST + + +START_TEST(more_math) +{ +#line 38 + fail_unless(2/2 == 1, "Another weird math result"); + +} +END_TEST + +START_TEST(weave) +{ +#line 43 + int i; + const char msg[] = "###\n"; + + for (i=0; i != 3; ++i) + print_message(row, sizeof row - 1); +} +END_TEST + +int main(void) +{ + Suite *s1 = suite_create("A Suite"); + TCase *tc1_1 = tcase_create("A Test Case"); + TCase *tc1_2 = tcase_create("Another Test Case"); + Suite *s2 = suite_create("Another Suite"); + TCase *tc2_1 = tcase_create("A Test Case for Another Suite"); + TCase *tc2_2 = tcase_create("A Basket Case"); + SRunner *sr = srunner_create(s1); + int nf; + + suite_add_tcase(s1, tc1_1); + tcase_add_test(tc1_1, hello_world); + tcase_add_test(tc1_1, neverending_story); + suite_add_tcase(s1, tc1_2); + tcase_add_test(tc1_2, math_problem); + suite_add_tcase(s2, tc2_1); + tcase_add_test(tc2_1, more_math); + suite_add_tcase(s2, tc2_2); + tcase_add_test(tc2_2, weave); + + srunner_add_suite(sr, s2); + + srunner_run_all(sr, CK_ENV); + nf = srunner_ntests_failed(sr); + srunner_free(sr); + + return nf == 0 ? 0 : 1; +} diff --git a/checkmk/test/name_enc/cmd b/checkmk/test/name_enc/cmd new file mode 100644 index 0000000..70e8dad --- /dev/null +++ b/checkmk/test/name_enc/cmd @@ -0,0 +1 @@ +infname='\aa"' diff --git a/checkmk/test/name_enc/x_output b/checkmk/test/name_enc/x_output new file mode 100644 index 0000000..8492414 --- /dev/null +++ b/checkmk/test/name_enc/x_output @@ -0,0 +1,43 @@ +/* + * DO NOT EDIT THIS FILE. Generated by checkmk. + * Edit the original source file "\aa"" instead. + */ + +#include + +#line 1 "\\aa\"" +/* A complete test example */ + +#include + + + +START_TEST(the_test) +{ +#line 10 + int nc; + const char msg[] = "\n\n Hello, world!\n"; + + nc = printf("%s", msg); + fail_unless(nc == (sizeof msg + - 1) /* for terminating NUL. */ + ); +} +END_TEST + +int main(void) +{ + Suite *s1 = suite_create("The Suite"); + TCase *tc1_1 = tcase_create("The Test Case"); + SRunner *sr = srunner_create(s1); + int nf; + + suite_add_tcase(s1, tc1_1); + tcase_add_test(tc1_1, the_test); + + srunner_run_all(sr, CK_ENV); + nf = srunner_ntests_failed(sr); + srunner_free(sr); + + return nf == 0 ? 0 : 1; +} diff --git a/checkmk/test/no_args/cmd b/checkmk/test/no_args/cmd new file mode 100644 index 0000000..a84be22 --- /dev/null +++ b/checkmk/test/no_args/cmd @@ -0,0 +1 @@ +checkmk_cmd='"$CHECKMK" < "$infname" > "$outfname" 2>"$errfname"' diff --git a/checkmk/test/no_args/in b/checkmk/test/no_args/in new file mode 100644 index 0000000..b490712 --- /dev/null +++ b/checkmk/test/no_args/in @@ -0,0 +1,22 @@ +/* A complete test example */ + +#include + +# suite The Suite + +# tcase The Test Case + +# test the_test + int nc; + const char msg[] = "\n\n Hello, world!\n"; + + nc = printf("%s", msg); + fail_unless(nc == (sizeof msg + - 1) /* for terminating NUL. */ + ); + +#main-pre + int fooyah; + +#main-post + return nf; diff --git a/checkmk/test/no_args/x_output b/checkmk/test/no_args/x_output new file mode 100644 index 0000000..774a5f6 --- /dev/null +++ b/checkmk/test/no_args/x_output @@ -0,0 +1,47 @@ +/* + * DO NOT EDIT THIS FILE. Generated by checkmk. + * Edit the original source file (standard input) instead. + */ + +#include + +/* A complete test example */ + +#include + + + +START_TEST(the_test) +{ + int nc; + const char msg[] = "\n\n Hello, world!\n"; + + nc = printf("%s", msg); + fail_unless(nc == (sizeof msg + - 1) /* for terminating NUL. */ + ); + +} +END_TEST + +int main(void) +{ + Suite *s1 = suite_create("The Suite"); + TCase *tc1_1 = tcase_create("The Test Case"); + SRunner *sr = srunner_create(s1); + int nf; + + /* User-specified pre-run code */ + int fooyah; + + + suite_add_tcase(s1, tc1_1); + tcase_add_test(tc1_1, the_test); + + srunner_run_all(sr, CK_ENV); + nf = srunner_ntests_failed(sr); + srunner_free(sr); + + /* User-specified post-run code */ + return nf; +} diff --git a/checkmk/test/non_word_chars/in b/checkmk/test/non_word_chars/in new file mode 100644 index 0000000..63de648 --- /dev/null +++ b/checkmk/test/non_word_chars/in @@ -0,0 +1,16 @@ +/* Non-word characters */ + +#include + +# suite The Suite (of Test Cases/\TCases) + +# tcase The "Test Case" + +# test the_test + int nc; + const char msg[] = "\n\n Hello, world!\n"; + + nc = printf("%s", msg); + fail_unless(nc == (sizeof msg + - 1) /* for terminating NUL. */ + ); diff --git a/checkmk/test/non_word_chars/x_output b/checkmk/test/non_word_chars/x_output new file mode 100644 index 0000000..93e0406 --- /dev/null +++ b/checkmk/test/non_word_chars/x_output @@ -0,0 +1,43 @@ +/* + * DO NOT EDIT THIS FILE. Generated by checkmk. + * Edit the original source file "in" instead. + */ + +#include + +#line 1 "in" +/* Non-word characters */ + +#include + + + +START_TEST(the_test) +{ +#line 10 + int nc; + const char msg[] = "\n\n Hello, world!\n"; + + nc = printf("%s", msg); + fail_unless(nc == (sizeof msg + - 1) /* for terminating NUL. */ + ); +} +END_TEST + +int main(void) +{ + Suite *s1 = suite_create("The Suite (of Test Cases/\\TCases)"); + TCase *tc1_1 = tcase_create("The \"Test Case\""); + SRunner *sr = srunner_create(s1); + int nf; + + suite_add_tcase(s1, tc1_1); + tcase_add_test(tc1_1, the_test); + + srunner_run_all(sr, CK_ENV); + nf = srunner_ntests_failed(sr); + srunner_free(sr); + + return nf == 0 ? 0 : 1; +} diff --git a/checkmk/test/not_really_repeated/in b/checkmk/test/not_really_repeated/in new file mode 100644 index 0000000..6b5a9fc --- /dev/null +++ b/checkmk/test/not_really_repeated/in @@ -0,0 +1,25 @@ +/* Test that repeated suites/tcases are only disallowed when they've + * actually been used in defining a test. */ + +# suite Foo + +# tcase Bar + +/* But no test... */ + +# suite Baz + +# tcase Quux + +# test quuux + const char msg[] = "Howdy doody!\n"; + int nc = printf(msg); + + fail_unless(nc == sizeof msg - 1); + +# suite Foo + +# tcase Bar + +# test huh + fail_unless(ALLOWED_AFTER_ALL); diff --git a/checkmk/test/not_really_repeated/x_output b/checkmk/test/not_really_repeated/x_output new file mode 100644 index 0000000..bd9d4f3 --- /dev/null +++ b/checkmk/test/not_really_repeated/x_output @@ -0,0 +1,59 @@ +/* + * DO NOT EDIT THIS FILE. Generated by checkmk. + * Edit the original source file "in" instead. + */ + +#include + +#line 1 "in" +/* Test that repeated suites/tcases are only disallowed when they've + * actually been used in defining a test. */ + + + +#line 8 +/* But no test... */ + + + +START_TEST(quuux) +{ +#line 15 + const char msg[] = "Howdy doody!\n"; + int nc = printf(msg); + + fail_unless(nc == sizeof msg - 1); + +} +END_TEST + + +START_TEST(huh) +{ +#line 25 + fail_unless(ALLOWED_AFTER_ALL); +} +END_TEST + +int main(void) +{ + Suite *s1 = suite_create("Baz"); + TCase *tc1_1 = tcase_create("Quux"); + Suite *s2 = suite_create("Foo"); + TCase *tc2_1 = tcase_create("Bar"); + SRunner *sr = srunner_create(s1); + int nf; + + suite_add_tcase(s1, tc1_1); + tcase_add_test(tc1_1, quuux); + suite_add_tcase(s2, tc2_1); + tcase_add_test(tc2_1, huh); + + srunner_add_suite(sr, s2); + + srunner_run_all(sr, CK_ENV); + nf = srunner_ntests_failed(sr); + srunner_free(sr); + + return nf == 0 ? 0 : 1; +} diff --git a/checkmk/test/num_start_test_name/in b/checkmk/test/num_start_test_name/in new file mode 100644 index 0000000..b750e06 --- /dev/null +++ b/checkmk/test/num_start_test_name/in @@ -0,0 +1,6 @@ +/* Ensure that test names starting with digits are refused. */ + +# suite The Suite +# tcase The Test Case +# test 1nsane + fail_if(SANE); diff --git a/checkmk/test/num_start_test_name/x_err b/checkmk/test/num_start_test_name/x_err new file mode 100644 index 0000000..98f81e8 --- /dev/null +++ b/checkmk/test/num_start_test_name/x_err @@ -0,0 +1 @@ +checkmk: in line 5: Malformed test name "1nsane" (must be a C identifier). diff --git a/checkmk/test/num_start_test_name/x_output b/checkmk/test/num_start_test_name/x_output new file mode 100644 index 0000000..eca31fb --- /dev/null +++ b/checkmk/test/num_start_test_name/x_output @@ -0,0 +1,10 @@ +/* + * DO NOT EDIT THIS FILE. Generated by checkmk. + * Edit the original source file "in" instead. + */ + +#include + +#line 1 "in" +/* Ensure that test names starting with digits are refused. */ + diff --git a/checkmk/test/pass_thru/in b/checkmk/test/pass_thru/in new file mode 100644 index 0000000..012bc7d --- /dev/null +++ b/checkmk/test/pass_thru/in @@ -0,0 +1,11 @@ +/* + * While a line such as + * +#define MY_VALUE 1 + * + * will be passed; a line such as + * +#suite "Sweet" + * + * will not be. + */ diff --git a/checkmk/test/pass_thru/x_err b/checkmk/test/pass_thru/x_err new file mode 100644 index 0000000..f55516b --- /dev/null +++ b/checkmk/test/pass_thru/x_err @@ -0,0 +1 @@ +checkmk: Expected at least one #test line. diff --git a/checkmk/test/pass_thru/x_output b/checkmk/test/pass_thru/x_output new file mode 100644 index 0000000..7193998 --- /dev/null +++ b/checkmk/test/pass_thru/x_output @@ -0,0 +1,19 @@ +/* + * DO NOT EDIT THIS FILE. Generated by checkmk. + * Edit the original source file "in" instead. + */ + +#include + +#line 1 "in" +/* + * While a line such as + * +#define MY_VALUE 1 + * + * will be passed; a line such as + * +#line 9 + * + * will not be. + */ diff --git a/checkmk/test/repeated_argument_tests/in b/checkmk/test/repeated_argument_tests/in new file mode 100644 index 0000000..07947d4 --- /dev/null +++ b/checkmk/test/repeated_argument_tests/in @@ -0,0 +1,10 @@ +/* Fail when tests with identical name are detected */ + +#test-loop(1,4) test1 + ck_assert(1 == 1); +#test-signal(-1) test2 + ck_assert(1 == 1); +#suite secondary +#tcase second +#test-loop-exit(1, 1, 5) test2 + ck_assert(1 == 1); diff --git a/checkmk/test/repeated_argument_tests/x_err b/checkmk/test/repeated_argument_tests/x_err new file mode 100644 index 0000000..8f642cb --- /dev/null +++ b/checkmk/test/repeated_argument_tests/x_err @@ -0,0 +1 @@ +checkmk: in line 9: Test "test2" already exists. diff --git a/checkmk/test/repeated_argument_tests/x_output b/checkmk/test/repeated_argument_tests/x_output new file mode 100644 index 0000000..671308c --- /dev/null +++ b/checkmk/test/repeated_argument_tests/x_output @@ -0,0 +1,23 @@ +/* + * DO NOT EDIT THIS FILE. Generated by checkmk. + * Edit the original source file "in" instead. + */ + +#include + +#line 1 "in" +/* Fail when tests with identical name are detected */ + +START_TEST(test1) +{ +#line 4 + ck_assert(1 == 1); +} +END_TEST + +START_TEST(test2) +{ +#line 6 + ck_assert(1 == 1); +} +END_TEST diff --git a/checkmk/test/repeated_suites/in b/checkmk/test/repeated_suites/in new file mode 100644 index 0000000..c040a29 --- /dev/null +++ b/checkmk/test/repeated_suites/in @@ -0,0 +1,10 @@ +/* Don't let suite names repeat. */ + +# suite Halibut + +# tcase Salmon + +# test ella + fail_if(food_poisoned); + +# suite Halibut diff --git a/checkmk/test/repeated_suites/x_err b/checkmk/test/repeated_suites/x_err new file mode 100644 index 0000000..7680dc8 --- /dev/null +++ b/checkmk/test/repeated_suites/x_err @@ -0,0 +1 @@ +checkmk: in line 10: Suite "Halibut" already exists. diff --git a/checkmk/test/repeated_suites/x_output b/checkmk/test/repeated_suites/x_output new file mode 100644 index 0000000..0946b89 --- /dev/null +++ b/checkmk/test/repeated_suites/x_output @@ -0,0 +1,17 @@ +/* + * DO NOT EDIT THIS FILE. Generated by checkmk. + * Edit the original source file "in" instead. + */ + +#include + +#line 1 "in" +/* Don't let suite names repeat. */ + + + +START_TEST(ella) +{ +#line 8 + fail_if(food_poisoned); + diff --git a/checkmk/test/repeated_tcases/in b/checkmk/test/repeated_tcases/in new file mode 100644 index 0000000..eafd237 --- /dev/null +++ b/checkmk/test/repeated_tcases/in @@ -0,0 +1,12 @@ +/* Don't let test case names repeat. */ + +# suite Mozart + +# tcase Chopin + +# test sticks + fail_if(DEAD_COMPOSERS); + +# suite Rachmaninoff + +# tcase Chopin diff --git a/checkmk/test/repeated_tcases/x_err b/checkmk/test/repeated_tcases/x_err new file mode 100644 index 0000000..141eb10 --- /dev/null +++ b/checkmk/test/repeated_tcases/x_err @@ -0,0 +1 @@ +checkmk: in line 12: Test Case "Chopin" already exists. diff --git a/checkmk/test/repeated_tcases/x_output b/checkmk/test/repeated_tcases/x_output new file mode 100644 index 0000000..cc800e8 --- /dev/null +++ b/checkmk/test/repeated_tcases/x_output @@ -0,0 +1,20 @@ +/* + * DO NOT EDIT THIS FILE. Generated by checkmk. + * Edit the original source file "in" instead. + */ + +#include + +#line 1 "in" +/* Don't let test case names repeat. */ + + + +START_TEST(sticks) +{ +#line 8 + fail_if(DEAD_COMPOSERS); + +} +END_TEST + diff --git a/checkmk/test/repeated_tests/in b/checkmk/test/repeated_tests/in new file mode 100644 index 0000000..1f96ff3 --- /dev/null +++ b/checkmk/test/repeated_tests/in @@ -0,0 +1,15 @@ +/* Can't use the same test name multiple times. */ + +# suite Foo + +# tcase Bar + +# test repeat + fail_if(MISERABLY); + +# suite Baz + +# tcase Quux + +# test repeat + fail_if(DONT_TRY_TRY_AGAIN); diff --git a/checkmk/test/repeated_tests/x_err b/checkmk/test/repeated_tests/x_err new file mode 100644 index 0000000..fb9cf50 --- /dev/null +++ b/checkmk/test/repeated_tests/x_err @@ -0,0 +1 @@ +checkmk: in line 14: Test "repeat" already exists. diff --git a/checkmk/test/repeated_tests/x_output b/checkmk/test/repeated_tests/x_output new file mode 100644 index 0000000..21c1022 --- /dev/null +++ b/checkmk/test/repeated_tests/x_output @@ -0,0 +1,21 @@ +/* + * DO NOT EDIT THIS FILE. Generated by checkmk. + * Edit the original source file "in" instead. + */ + +#include + +#line 1 "in" +/* Can't use the same test name multiple times. */ + + + +START_TEST(repeat) +{ +#line 8 + fail_if(MISERABLY); + +} +END_TEST + + diff --git a/checkmk/test/single_test_line/in b/checkmk/test/single_test_line/in new file mode 100644 index 0000000..b8da8dd --- /dev/null +++ b/checkmk/test/single_test_line/in @@ -0,0 +1 @@ +# test test_name diff --git a/checkmk/test/single_test_line/x_output b/checkmk/test/single_test_line/x_output new file mode 100644 index 0000000..e335bb6 --- /dev/null +++ b/checkmk/test/single_test_line/x_output @@ -0,0 +1,30 @@ +/* + * DO NOT EDIT THIS FILE. Generated by checkmk. + * Edit the original source file "in" instead. + */ + +#include + +#line 1 "in" +START_TEST(test_name) +{ +#line 2 +} +END_TEST + +int main(void) +{ + Suite *s1 = suite_create("Core"); + TCase *tc1_1 = tcase_create("Core"); + SRunner *sr = srunner_create(s1); + int nf; + + suite_add_tcase(s1, tc1_1); + tcase_add_test(tc1_1, test_name); + + srunner_run_all(sr, CK_ENV); + nf = srunner_ntests_failed(sr); + srunner_free(sr); + + return nf == 0 ? 0 : 1; +} diff --git a/checkmk/test/tcase_implied_repeat/in b/checkmk/test/tcase_implied_repeat/in new file mode 100644 index 0000000..e80a15e --- /dev/null +++ b/checkmk/test/tcase_implied_repeat/in @@ -0,0 +1,18 @@ +/* Make sure we catch implied tcase repeats (via same name as suite) */ + +# suite Lady + +# tcase Luck + +# test song + fail_unless("be a lady tonight"); + +# suite Luck + +/* It's fine for a suite and tcase name to collide... + but the suite name implies a tcase name of the same value until we + override it. */ + +# test uh_oh + /* Uh-oh! Now we're using the implied tcase Luck, which already + * exists! */ diff --git a/checkmk/test/tcase_implied_repeat/x_err b/checkmk/test/tcase_implied_repeat/x_err new file mode 100644 index 0000000..cf3724d --- /dev/null +++ b/checkmk/test/tcase_implied_repeat/x_err @@ -0,0 +1 @@ +checkmk: in line 16: Test Case "Luck" already exists. diff --git a/checkmk/test/tcase_implied_repeat/x_output b/checkmk/test/tcase_implied_repeat/x_output new file mode 100644 index 0000000..a8e1cb7 --- /dev/null +++ b/checkmk/test/tcase_implied_repeat/x_output @@ -0,0 +1,25 @@ +/* + * DO NOT EDIT THIS FILE. Generated by checkmk. + * Edit the original source file "in" instead. + */ + +#include + +#line 1 "in" +/* Make sure we catch implied tcase repeats (via same name as suite) */ + + + +START_TEST(song) +{ +#line 8 + fail_unless("be a lady tonight"); + +} +END_TEST + +#line 12 +/* It's fine for a suite and tcase name to collide... + but the suite name implies a tcase name of the same value until we + override it. */ + diff --git a/checkmk/test/test_after_main_post/in b/checkmk/test/test_after_main_post/in new file mode 100644 index 0000000..d7cad0f --- /dev/null +++ b/checkmk/test/test_after_main_post/in @@ -0,0 +1,22 @@ +/* A complete test example */ + +#include + +# suite The Suite + +# tcase The Test Case + +# test the_test + int nc; + const char msg[] = "\n\n Hello, world!\n"; + + nc = printf("%s", msg); + fail_unless(nc == (sizeof msg + - 1) /* for terminating NUL. */ + ); + +# main-post + return 0; /* Always report success. */ + +# test uh_oh + fail("Phooey"); diff --git a/checkmk/test/test_after_main_post/x_err b/checkmk/test/test_after_main_post/x_err new file mode 100644 index 0000000..fae513c --- /dev/null +++ b/checkmk/test/test_after_main_post/x_err @@ -0,0 +1 @@ +checkmk: in line 21: Cannot specify tests after main-pre or main-post. diff --git a/checkmk/test/test_after_main_post/x_output b/checkmk/test/test_after_main_post/x_output new file mode 100644 index 0000000..fc7b9d2 --- /dev/null +++ b/checkmk/test/test_after_main_post/x_output @@ -0,0 +1,46 @@ +/* + * DO NOT EDIT THIS FILE. Generated by checkmk. + * Edit the original source file "in" instead. + */ + +#include + +#line 1 "in" +/* A complete test example */ + +#include + + + +START_TEST(the_test) +{ +#line 10 + int nc; + const char msg[] = "\n\n Hello, world!\n"; + + nc = printf("%s", msg); + fail_unless(nc == (sizeof msg + - 1) /* for terminating NUL. */ + ); + +} +END_TEST + +int main(void) +{ + Suite *s1 = suite_create("The Suite"); + TCase *tc1_1 = tcase_create("The Test Case"); + SRunner *sr = srunner_create(s1); + int nf; + + suite_add_tcase(s1, tc1_1); + tcase_add_test(tc1_1, the_test); + + srunner_run_all(sr, CK_ENV); + nf = srunner_ntests_failed(sr); + srunner_free(sr); + + /* User-specified post-run code */ +#line 19 + return 0; /* Always report success. */ + diff --git a/checkmk/test/test_after_main_pre/in b/checkmk/test/test_after_main_pre/in new file mode 100644 index 0000000..1bdecfd --- /dev/null +++ b/checkmk/test/test_after_main_pre/in @@ -0,0 +1,22 @@ +/* A complete test example */ + +#include + +# suite The Suite + +# tcase The Test Case + +# test the_test + int nc; + const char msg[] = "\n\n Hello, world!\n"; + + nc = printf("%s", msg); + fail_unless(nc == (sizeof msg + - 1) /* for terminating NUL. */ + ); + +# main-pre + int declare_me = 0; + +# test uh_oh + fail("Phooey"); diff --git a/checkmk/test/test_after_main_pre/x_err b/checkmk/test/test_after_main_pre/x_err new file mode 100644 index 0000000..fae513c --- /dev/null +++ b/checkmk/test/test_after_main_pre/x_err @@ -0,0 +1 @@ +checkmk: in line 21: Cannot specify tests after main-pre or main-post. diff --git a/checkmk/test/test_after_main_pre/x_output b/checkmk/test/test_after_main_pre/x_output new file mode 100644 index 0000000..aa9e38e --- /dev/null +++ b/checkmk/test/test_after_main_pre/x_output @@ -0,0 +1,39 @@ +/* + * DO NOT EDIT THIS FILE. Generated by checkmk. + * Edit the original source file "in" instead. + */ + +#include + +#line 1 "in" +/* A complete test example */ + +#include + + + +START_TEST(the_test) +{ +#line 10 + int nc; + const char msg[] = "\n\n Hello, world!\n"; + + nc = printf("%s", msg); + fail_unless(nc == (sizeof msg + - 1) /* for terminating NUL. */ + ); + +} +END_TEST + +int main(void) +{ + Suite *s1 = suite_create("The Suite"); + TCase *tc1_1 = tcase_create("The Test Case"); + SRunner *sr = srunner_create(s1); + int nf; + + /* User-specified pre-run code */ +#line 19 + int declare_me = 0; + diff --git a/checkmk/test/test_chars/in b/checkmk/test/test_chars/in new file mode 100644 index 0000000..6405228 --- /dev/null +++ b/checkmk/test/test_chars/in @@ -0,0 +1,8 @@ +/* tests shouldn't allow non-identifier characters. */ + +# suite The Suite + +# tcase The Test Case + +# test test@me + fail_if(GOT_HERE); diff --git a/checkmk/test/test_chars/x_err b/checkmk/test/test_chars/x_err new file mode 100644 index 0000000..4660d56 --- /dev/null +++ b/checkmk/test/test_chars/x_err @@ -0,0 +1 @@ +checkmk: in line 7: Malformed test name "test@me" (must be a C identifier). diff --git a/checkmk/test/test_chars/x_output b/checkmk/test/test_chars/x_output new file mode 100644 index 0000000..a84be49 --- /dev/null +++ b/checkmk/test/test_chars/x_output @@ -0,0 +1,12 @@ +/* + * DO NOT EDIT THIS FILE. Generated by checkmk. + * Edit the original source file "in" instead. + */ + +#include + +#line 1 "in" +/* tests shouldn't allow non-identifier characters. */ + + + diff --git a/checkmk/test/trailing_ws/in b/checkmk/test/trailing_ws/in new file mode 100644 index 0000000..ac6df5d --- /dev/null +++ b/checkmk/test/trailing_ws/in @@ -0,0 +1,16 @@ +/* A complete test example (with trailing whitespace) */ + +#include + +# suite The Suite + +# tcase The Test Case + +# test the_test + int nc; + const char msg[] = "\n\n Hello, world!\n"; + + nc = printf("%s", msg); + fail_unless(nc == (sizeof msg + - 1) /* for terminating NUL. */ + ); diff --git a/checkmk/test/trailing_ws/x_output b/checkmk/test/trailing_ws/x_output new file mode 100644 index 0000000..7822e90 --- /dev/null +++ b/checkmk/test/trailing_ws/x_output @@ -0,0 +1,43 @@ +/* + * DO NOT EDIT THIS FILE. Generated by checkmk. + * Edit the original source file "in" instead. + */ + +#include + +#line 1 "in" +/* A complete test example (with trailing whitespace) */ + +#include + + + +START_TEST(the_test) +{ +#line 10 + int nc; + const char msg[] = "\n\n Hello, world!\n"; + + nc = printf("%s", msg); + fail_unless(nc == (sizeof msg + - 1) /* for terminating NUL. */ + ); +} +END_TEST + +int main(void) +{ + Suite *s1 = suite_create("The Suite"); + TCase *tc1_1 = tcase_create("The Test Case"); + SRunner *sr = srunner_create(s1); + int nf; + + suite_add_tcase(s1, tc1_1); + tcase_add_test(tc1_1, the_test); + + srunner_run_all(sr, CK_ENV); + nf = srunner_ntests_failed(sr); + srunner_free(sr); + + return nf == 0 ? 0 : 1; +} diff --git a/checkmk/test/ucn/in b/checkmk/test/ucn/in new file mode 100644 index 0000000..565f6b0 --- /dev/null +++ b/checkmk/test/ucn/in @@ -0,0 +1,16 @@ +/* A complete test example */ + +#include + +# suite The Suite + +# tcase The Test Case + +# test the_\u4ECA\u65E5\u306F_test + int nc; + const char msg[] = "\n\n Hello, world!\n"; + + nc = printf("%s", msg); + fail_unless(nc == (sizeof msg + - 1) /* for terminating NUL. */ + ); diff --git a/checkmk/test/ucn/x_output b/checkmk/test/ucn/x_output new file mode 100644 index 0000000..3092d0a --- /dev/null +++ b/checkmk/test/ucn/x_output @@ -0,0 +1,43 @@ +/* + * DO NOT EDIT THIS FILE. Generated by checkmk. + * Edit the original source file "in" instead. + */ + +#include + +#line 1 "in" +/* A complete test example */ + +#include + + + +START_TEST(the_\u4ECA\u65E5\u306F_test) +{ +#line 10 + int nc; + const char msg[] = "\n\n Hello, world!\n"; + + nc = printf("%s", msg); + fail_unless(nc == (sizeof msg + - 1) /* for terminating NUL. */ + ); +} +END_TEST + +int main(void) +{ + Suite *s1 = suite_create("The Suite"); + TCase *tc1_1 = tcase_create("The Test Case"); + SRunner *sr = srunner_create(s1); + int nf; + + suite_add_tcase(s1, tc1_1); + tcase_add_test(tc1_1, the_\u4ECA\u65E5\u306F_test); + + srunner_run_all(sr, CK_ENV); + nf = srunner_ntests_failed(sr); + srunner_free(sr); + + return nf == 0 ? 0 : 1; +} diff --git a/cmake/CheckHeaderDirent.cmake b/cmake/CheckHeaderDirent.cmake new file mode 100644 index 0000000..e9a7ea8 --- /dev/null +++ b/cmake/CheckHeaderDirent.cmake @@ -0,0 +1,32 @@ +# - Check if the system has the specified type +# CHECK_HEADER_DIRENT (HEADER1 HEARDER2 ...) +# +# HEADER - the header(s) where the prototype should be declared +# +# The following variables may be set before calling this macro to +# modify the way the check is run: +# +# CMAKE_REQUIRED_FLAGS = string of compile command line flags +# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar) +# CMAKE_REQUIRED_INCLUDES = list of include directories +# Copyright (c) 2009, Michihiro NAKAJIMA +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + + +INCLUDE(CheckTypeExists) + +MACRO (CHECK_HEADER_DIRENT) + CHECK_TYPE_EXISTS("DIR *" dirent.h HAVE_DIRENT_H) + IF(NOT HAVE_DIRENT_H) + CHECK_TYPE_EXISTS("DIR *" sys/ndir.h HAVE_SYS_NDIR_H) + IF(NOT HAVE_SYS_NDIR_H) + CHECK_TYPE_EXISTS("DIR *" ndir.h HAVE_NDIR_H) + IF(NOT HAVE_NDIR_H) + CHECK_TYPE_EXISTS("DIR *" sys/dir.h HAVE_SYS_DIR_H) + ENDIF(NOT HAVE_NDIR_H) + ENDIF(NOT HAVE_SYS_NDIR_H) + ENDIF(NOT HAVE_DIRENT_H) +ENDMACRO (CHECK_HEADER_DIRENT) + diff --git a/cmake/CheckStructMember.cmake b/cmake/CheckStructMember.cmake new file mode 100644 index 0000000..05ddb3a --- /dev/null +++ b/cmake/CheckStructMember.cmake @@ -0,0 +1,43 @@ +# - Check if the given struct or class has the specified member variable +# CHECK_STRUCT_MEMBER (STRUCT MEMBER HEADER VARIABLE) +# +# STRUCT - the name of the struct or class you are interested in +# MEMBER - the member which existence you want to check +# HEADER - the header(s) where the prototype should be declared +# VARIABLE - variable to store the result +# +# The following variables may be set before calling this macro to +# modify the way the check is run: +# +# CMAKE_REQUIRED_FLAGS = string of compile command line flags +# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar) +# CMAKE_REQUIRED_INCLUDES = list of include directories + +# Copyright (c) 2006, Alexander Neundorf, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + + +INCLUDE(CheckCSourceCompiles) + +MACRO (CHECK_STRUCT_MEMBER _STRUCT _MEMBER _HEADER _RESULT) + SET(_INCLUDE_FILES) + FOREACH (it ${_HEADER}) + SET(_INCLUDE_FILES "${_INCLUDE_FILES}#include <${it}>\n") + ENDFOREACH (it) + + SET(_CHECK_STRUCT_MEMBER_SOURCE_CODE " +${_INCLUDE_FILES} +int main() +{ + static ${_STRUCT} tmp; + if (sizeof(tmp.${_MEMBER})) + return 0; + return 0; +} +") + CHECK_C_SOURCE_COMPILES("${_CHECK_STRUCT_MEMBER_SOURCE_CODE}" ${_RESULT}) + +ENDMACRO (CHECK_STRUCT_MEMBER) + diff --git a/cmake/CheckTypeExists.cmake b/cmake/CheckTypeExists.cmake new file mode 100644 index 0000000..b05234f --- /dev/null +++ b/cmake/CheckTypeExists.cmake @@ -0,0 +1,42 @@ +# - Check if the system has the specified type +# CHECK_TYPE_EXISTS (TYPE HEADER VARIABLE) +# +# TYPE - the name of the type or struct or class you are interested in +# HEADER - the header(s) where the prototype should be declared +# VARIABLE - variable to store the result +# +# The following variables may be set before calling this macro to +# modify the way the check is run: +# +# CMAKE_REQUIRED_FLAGS = string of compile command line flags +# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar) +# CMAKE_REQUIRED_INCLUDES = list of include directories +# Copyright (c) 2009, Michihiro NAKAJIMA +# Copyright (c) 2006, Alexander Neundorf, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + + +INCLUDE(CheckCSourceCompiles) + +MACRO (CHECK_TYPE_EXISTS _TYPE _HEADER _RESULT) + SET(_INCLUDE_FILES) + FOREACH (it ${_HEADER}) + SET(_INCLUDE_FILES "${_INCLUDE_FILES}#include <${it}>\n") + ENDFOREACH (it) + + SET(_CHECK_TYPE_EXISTS_SOURCE_CODE " +${_INCLUDE_FILES} +int main() +{ + static ${_TYPE} tmp; + if (sizeof(tmp)) + return 0; + return 0; +} +") + CHECK_C_SOURCE_COMPILES("${_CHECK_TYPE_EXISTS_SOURCE_CODE}" ${_RESULT}) + +ENDMACRO (CHECK_TYPE_EXISTS) + diff --git a/cmake/check_stdint.h.in b/cmake/check_stdint.h.in new file mode 100644 index 0000000..ab467c1 --- /dev/null +++ b/cmake/check_stdint.h.in @@ -0,0 +1,6 @@ +#ifndef _CHECK_CHECK_STDINT_H +#define _CHECK_CHECK_STDINT_H 1 +#ifdef HAVE_STDINT_H +#include +#endif +#endif diff --git a/cmake/config.h.in b/cmake/config.h.in new file mode 100644 index 0000000..aaa447f --- /dev/null +++ b/cmake/config.h.in @@ -0,0 +1,410 @@ +/*-*- mode:C; -*- */ +/* config.h. Generated from build/cmake/config.h.in by cmake configure */ +/* + * Check: a unit test framework for C + * + * Copyright (C) 2011 Mateusz Loskot + * 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. + */ + +#if defined(__osf__) +# define _OSF_SOURCE +#endif + +/* + * Ensure we have C99-style int64_t, etc, all defined. + */ + +/* First, we need to know if the system has already defined them. */ +#cmakedefine HAVE_INT16_T +#cmakedefine HAVE_INT32_T +#cmakedefine HAVE_INT64_T +#cmakedefine HAVE_INTMAX_T + +#cmakedefine HAVE_UINT8_T +#cmakedefine HAVE_UINT16_T +#cmakedefine HAVE_UINT32_T +#cmakedefine HAVE_UINT64_T +#cmakedefine HAVE_UINTMAX_T + +/* We might have the types we want under other spellings. */ +#cmakedefine HAVE___INT64 +#cmakedefine HAVE_U_INT64_T +#cmakedefine HAVE_UNSIGNED___INT64 + +/* The sizes of various standard integer types. */ +@SIZE_OF_SHORT_CODE@ +@SIZE_OF_INT_CODE@ +@SIZE_OF_LONG_CODE@ +@SIZE_OF_LONG_LONG_CODE@ +@SIZE_OF_UNSIGNED_SHORT_CODE@ +@SIZE_OF_UNSIGNED_CODE@ +@SIZE_OF_UNSIGNED_LONG_CODE@ +@SIZE_OF_UNSIGNED_LONG_LONG_CODE@ + +/* + * If we lack int64_t, define it to the first of __int64, int, long, and long long + * that exists and is the right size. + */ +#if !defined(HAVE_INT64_T) && defined(HAVE___INT64) +typedef __int64 int64_t; +#define HAVE_INT64_T +#endif + +#if !defined(HAVE_INT64_T) && SIZE_OF_INT == 8 +typedef int int64_t; +#define HAVE_INT64_T +#endif + +#if !defined(HAVE_INT64_T) && SIZE_OF_LONG == 8 +typedef long int64_t; +#define HAVE_INT64_T +#endif + +#if !defined(HAVE_INT64_T) && SIZE_OF_LONG_LONG == 8 +typedef long long int64_t; +#define HAVE_INT64_T +#endif + +#if !defined(HAVE_INT64_T) +#error No 64-bit integer type was found. +#endif + +/* + * Similarly for int32_t + */ +#if !defined(HAVE_INT32_T) && SIZE_OF_INT == 4 +typedef long int32_t; +#define HAVE_INT32_T +#endif + +#if !defined(HAVE_INT32_T) && SIZE_OF_LONG == 4 +typedef long int32_t; +#define HAVE_INT32_T +#endif + +#if !defined(HAVE_INT32_T) +#error No 32-bit integer type was found. +#endif + +/* + * Similarly for int16_t + */ +#if !defined(HAVE_INT16_T) && SIZE_OF_INT == 2 +typedef int int16_t; +#define HAVE_INT16_T +#endif + +#if !defined(HAVE_INT16_T) && SIZE_OF_SHORT == 2 +typedef short int16_t; +#define HAVE_INT16_T +#endif + +#if !defined(HAVE_INT16_T) +#error No 16-bit integer type was found. +#endif + +/* + * Similarly for uint64_t + */ +#if !defined(HAVE_UINT64_T) && defined(HAVE_UNSIGNED___INT64) +typedef unsigned __int64 uint64_t; +#define HAVE_UINT64_T +#endif + +#if !defined(HAVE_UINT64_T) && SIZE_OF_UNSIGNED == 8 +typedef unsigned uint64_t; +#define HAVE_UINT64_T +#endif + +#if !defined(HAVE_UINT64_T) && SIZE_OF_UNSIGNED_LONG == 8 +typedef unsigned long uint64_t; +#define HAVE_UINT64_T +#endif + +#if !defined(HAVE_UINT64_T) && SIZE_OF_UNSIGNED_LONG_LONG == 8 +typedef unsigned long long uint64_t; +#define HAVE_UINT64_T +#endif + +#if !defined(HAVE_UINT64_T) +#error No 64-bit unsigned integer type was found. +#endif + + +/* + * Similarly for uint32_t + */ +#if !defined(HAVE_UINT32_T) && SIZE_OF_UNSIGNED == 4 +typedef unsigned uint32_t; +#define HAVE_UINT32_T +#endif + +#if !defined(HAVE_UINT32_T) && SIZE_OF_UNSIGNED_LONG == 4 +typedef unsigned long uint32_t; +#define HAVE_UINT32_T +#endif + +#if !defined(HAVE_UINT32_T) +#error No 32-bit unsigned integer type was found. +#endif + +/* + * Similarly for uint16_t + */ +#if !defined(HAVE_UINT16_T) && SIZE_OF_UNSIGNED == 2 +typedef unsigned uint16_t; +#define HAVE_UINT16_T +#endif + +#if !defined(HAVE_UINT16_T) && SIZE_OF_UNSIGNED_SHORT == 2 +typedef unsigned short uint16_t; +#define HAVE_UINT16_T +#endif + +#if !defined(HAVE_UINT16_T) +#error No 16-bit unsigned integer type was found. +#endif + +/* + * Similarly for uint8_t + */ +#if !defined(HAVE_UINT8_T) +typedef unsigned char uint8_t; +#define HAVE_UINT8_T +#endif + +#if !defined(HAVE_UINT16_T) +#error No 8-bit unsigned integer type was found. +#endif + +/* Define intmax_t and uintmax_t if they are not already defined. */ +#if !defined(HAVE_INTMAX_T) +typedef int64_t intmax_t; +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#endif + +#if !defined(HAVE_UINTMAX_T) +typedef uint64_t uintmax_t; +#endif + +/* Define to 1 if you have the declaration of `INT64_MAX', and to 0 if you + don't. */ +#cmakedefine HAVE_DECL_INT64_MAX 1 + +/* Define to 1 if you have the declaration of `INT64_MIN', and to 0 if you + don't. */ +#cmakedefine HAVE_DECL_INT64_MIN 1 + +/* Define to 1 if you have the declaration of `SIZE_MAX', and to 0 if you + don't. */ +#cmakedefine HAVE_DECL_SIZE_MAX 1 + +/* Define to 1 if you have the declaration of `SSIZE_MAX', and to 0 if you + don't. */ +#cmakedefine HAVE_DECL_SSIZE_MAX 1 + +/* Define to 1 if you have the declaration of `UINT32_MAX', and to 0 if you + don't. */ +#cmakedefine HAVE_DECL_UINT32_MAX 1 + +/* Define to 1 if you have the declaration of `UINT64_MAX', and to 0 if you + don't. */ +#cmakedefine HAVE_DECL_UINT64_MAX 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_ERRNO_H 1 + +/* Define to 1 if you have the `fork' function. */ +#cmakedefine HAVE_FORK 1 + +/* Define to 1 if you have the `getpid' function. */ +#cmakedefine HAVE_GETPID 1 + +/* Define to 1 if you have the `gettimeofday' function. */ +#cmakedefine HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_LIMITS_H 1 + +/* Define to 1 if you have the `localtime_r' function. */ +#cmakedefine HAVE_DECL_LOCALTIME_R 1 + +/* Define to 1 if you have the `localtime_s' function. */ +#cmakedefine HAVE_LOCALTIME_S 1 + +/* Define to 1 if the system has the type `long long int'. */ +#cmakedefine HAVE_LONG_LONG_INT 1 + +/* Define to 1 if you have the `malloc' function. */ +#cmakedefine HAVE_MALLOC 1 + +/* Define to 1 if you have the `realloc' function. */ +#cmakedefine HAVE_REALLOC 1 + +/* Define to 1 if you have the `setenv' function. */ +#cmakedefine HAVE_DECL_SETENV 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SIGNAL_H 1 + +/* Define to 1 if you have the 'sigaction' function. */ +#cmakedefine HAVE_SIGACTION 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STDARG_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strdup' function. */ +#cmakedefine HAVE_DECL_STRDUP 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STRING_H 1 + +/* Define to 1 if you have the `strsignal' function. */ +#cmakedefine HAVE_DECL_STRSIGNAL 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_TIME_H 1 + +/* Define to 1 if the system has the type `unsigned long long'. */ +#cmakedefine HAVE_UNSIGNED_LONG_LONG 1 + +/* Define to 1 if the system has the type `unsigned long long int'. */ +#cmakedefine HAVE_UNSIGNED_LONG_LONG_INT 1 + +/* Define to 1 if the system has the type `wchar_t'. */ +#cmakedefine HAVE_WCHAR_T 1 + +/* Define to 1 if you have the `_getpid' function. */ +#cmakedefine HAVE__GETPID 1 + +/* Define to 1 if you have the `_localtime64_s' function. */ +#cmakedefine HAVE__LOCALTIME64_S 1 + +/* Define to 1 if you have the `_strdup' function. */ +#cmakedefine HAVE__STRDUP 1 + +/* Version number of Check */ +#cmakedefine CHECK_VERSION "${CHECK_MAJOR_VERSION}.${CHECK_MINOR_VERSION}.${CHECK_MICRO_VERSION}" + +/* The size of `wchar_t', as computed by sizeof. */ +#cmakedefine SIZEOF_WCHAR_T ${SIZEOF_WCHAR_T} + +/* Define to 1 if strerror_r returns char *. */ +#cmakedefine STRERROR_R_CHAR_P 1 + +/* Define to 1 if you can safely include both and . */ +#cmakedefine TIME_WITH_SYS_TIME 1 + +/* + * Some platform requires a macro to use extension functions. + */ +#cmakedefine SAFE_TO_DEFINE_EXTENSIONS 1 +#ifdef SAFE_TO_DEFINE_EXTENSIONS +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +# define _ALL_SOURCE 1 +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif +/* Enable threading extensions on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# define _POSIX_PTHREAD_SEMANTICS 1 +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# define _TANDEM_SOURCE 1 +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# define __EXTENSIONS__ 1 +#endif +#endif /* SAFE_TO_DEFINE_EXTENSIONS */ + +/* Number of bits in a file offset, on hosts where this is settable. */ +#cmakedefine _FILE_OFFSET_BITS ${_FILE_OFFSET_BITS} + +/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ +#cmakedefine _LARGEFILE_SOURCE 1 + +/* Define for large files, on AIX-style hosts. */ +#cmakedefine _LARGE_FILES ${_LARGE_FILES} + +/* Define for Windows to use Windows 2000+ APIs. */ +#cmakedefine _WIN32_WINNT ${_WIN32_WINNT} +#cmakedefine WINVER ${WINVER} + +/* Define to empty if `const' does not conform to ANSI C. */ +#cmakedefine const ${const} + +/* Define to `int' if doesn't define. */ +#cmakedefine clockid_t ${clockid_t} + +/* Define to `int' if doesn't define. */ +#cmakedefine gid_t ${gid_t} + +/* Define to `unsigned long' if does not define. */ +#cmakedefine id_t ${id_t} + +/* Define to `int' if does not define. */ +#cmakedefine mode_t ${mode_t} + +/* Define to `long long' if does not define. */ +#cmakedefine off_t ${off_t} + +/* Define to `int' if doesn't define. */ +#cmakedefine pid_t ${pid_t} + +/* Define to `unsigned int' if does not define. */ +#cmakedefine size_t ${size_t} + +/* Define to `int' if does not define. */ +#cmakedefine ssize_t ${ssize_t} + +/* Define to `int' if does not define. */ +#cmakedefine timer_t ${timer_t} + +/* Define to `int' if doesn't define. */ +#cmakedefine uid_t ${uid_t} + +/* Define to `int' if does not define. */ +#cmakedefine intptr_t ${intptr_t} + +/* Define to `unsigned int' if does not define. */ +#cmakedefine uintptr_t ${uintptr_t} diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..929fcf3 --- /dev/null +++ b/configure.ac @@ -0,0 +1,430 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +# Prelude. +AC_PREREQ([2.59]) + +AC_INIT([Check], [0.12.0], [check-devel at lists dot sourceforge dot net]) +CHECK_MAJOR_VERSION=0 +CHECK_MINOR_VERSION=12 +CHECK_MICRO_VERSION=0 +CHECK_VERSION=$CHECK_MAJOR_VERSION.$CHECK_MINOR_VERSION.$CHECK_MICRO_VERSION + +# unique source file --- primitive safety check +AC_CONFIG_SRCDIR([src/check.c]) + +# place where extra autoconf macros are kept +AC_CONFIG_MACRO_DIR([m4]) + +# place where portability library functions are kept +AC_CONFIG_LIBOBJ_DIR([lib]) + +# really severe build strictness +AM_INIT_AUTOMAKE([-Wall gnits 1.11.2]) +# Change to using into-in-builddir in the future: +#AM_INIT_AUTOMAKE([info-in-builddir -Wall -Werror gnits 1.14]) + +# define things like _GNU_SOURCE appropriately +# From patch 2803433, request system extensions to generate 64-bit safe code +AC_USE_SYSTEM_EXTENSIONS + +AC_SUBST(CHECK_MAJOR_VERSION) +AC_SUBST(CHECK_MINOR_VERSION) +AC_SUBST(CHECK_MICRO_VERSION) +AC_SUBST(CHECK_VERSION) + +# Configure options. +# allow `./configure --enable-silent-rules' and `make V=0' +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([no])]) + +AC_ARG_ENABLE(gcov, +AC_HELP_STRING([--enable-gcov], + [turn on test coverage @<:@default=no@:>@]), +[case "${enableval}" in + yes) enable_gcov=true ;; + no) enable_gcov=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-gcov) ;; +esac], [enable_gcov=false ]) + +if test x$enable_gcov = xtrue ; then + if test x"$GCC" != xyes; then + AC_MSG_ERROR([gcov only works if gcc is used]) + fi + + GCOV_CFLAGS="-fprofile-arcs -ftest-coverage" + AC_SUBST(GCOV_CFLAGS) + + dnl libtool 1.5.22 and lower strip -fprofile-arcs from the flags + dnl passed to the linker, which is a bug; -fprofile-arcs implicitly + dnl links in -lgcov, so we do it explicitly here for the same effect + GCOV_LIBS=-lgcov + AC_SUBST(GCOV_LIBS) +fi + +AM_CONDITIONAL(ENABLE_GCOV, test x"$enable_gcov" = "xtrue") + +AC_ARG_ENABLE(timeout-tests, +AC_HELP_STRING([--enable-timeout-tests], + [turn on timeout tests @<:@default=yes@:>@]), +[case "${enableval}" in + yes) enable_timeout_tests=true ;; + no) enable_timeout_tests=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-timeout-tests) ;; +esac], [enable_timeout_tests=true ]) + +AM_CONDITIONAL(NO_TIMEOUT_TESTS, test x"$enable_timeout_tests" = "xfalse") + +AC_ARG_ENABLE(subunit, +AC_HELP_STRING([--enable-subunit], + [enable support for the subunit test protocol @<:@default=autodetect@:>@]), +[case "${enableval}" in + yes) + enable_subunit=true + echo "Enabled subunit support" + ;; + no) + enable_subunit=false + echo "Disabled subunit support" + ;; + autodetect) + echo "Subunit support will enable automatically." + ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-subunit) ;; +esac], +[echo "Subunit support will enable automatically." + enable_subunit=autodetect]) + +AC_ARG_ENABLE(fork, +AC_HELP_STRING([--enable-fork], + [enable support for fork @<:@default=autodetect@:>@]), +[case "${enableval}" in + yes) enable_fork=true ;; + no) enable_fork=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-fork) ;; +esac], [enable_fork=true ]) + +AC_ARG_ENABLE(snprintf-replacement, +AC_HELP_STRING([--enable-snprintf-replacement], + [enable check snprintf replacement, (even if the system provides a C99 compliant version) @<:@default=autodetect@:>@]), +[case "${enableval}" in + yes) enable_snprintf_replacement=true ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-snprintf-replacement) ;; +esac], [enable_snprintf_replacement=autodetect ]) + +AC_ARG_ENABLE(timer-replacement, +AC_HELP_STRING([--enable-timer-replacement], + [enable check timer replacement, (even if the system provides timer_create, timer_settime, and timer_delete) @<:@default=autodetect@:>@]), +[case "${enableval}" in + yes) enable_timer_replacement=true ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-timer-replacement) ;; +esac], [enable_timer_replacement=autodetect ]) + + +# Checks for programs. +AC_PROG_SED +AC_PROG_AWK +AC_PROG_CC +# Automake wants this for per-target CFLAGS +AM_PROG_CC_C_O +AC_PROG_INSTALL +AC_PROG_LN_S +# for non-POSIX archivers like the one on OS X +# use m4_ifdef to work on older automake (1.11) +m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) +AC_PROG_LIBTOOL + +# initialize libtool to build .la files +LT_INIT + +# add these options to CFLAGS if the compiler supports them +AC_DEFUN([AX_CFLAGS_ADD],[AX_C_CHECK_FLAG($1, , , CFLAGS="$CFLAGS $1")]) +# Do not use the -ansi flag, currently there is a bug in MinGW/MinGW-w64 +# which prevents Check from compiling. Add after this is resolved: +# sourceforge.net/p/mingw/bugs/2024 +#AX_CFLAGS_WARN_ALL_ANSI +# Do not use the -pedantic flag, as on solaris it has a different +# meaning than on gcc. Using the flag causes the build to fail. +AX_CFLAGS_ADD([-Wextra]) +AX_CFLAGS_ADD([-Wstrict-prototypes]) +AX_CFLAGS_ADD([-Wmissing-prototypes]) +AX_CFLAGS_ADD([-Wwrite-strings]) +AX_CFLAGS_ADD([-Wno-variadic-macros]) +AX_CFLAGS_ADD([-Wimport]) +AX_CFLAGS_ADD([-Wfatal-errors]) +AX_CFLAGS_ADD([-Wformat=2]) +AX_CFLAGS_ADD([-Winit-self]) +AX_CFLAGS_ADD([-Wmissing-include-dirs]) +AX_CFLAGS_ADD([-Wswitch-default]) +AX_CFLAGS_ADD([-Wunknown-pragmas]) +# The following flag is to enable C99 support on AIX, which is +# necessary for variable macros in check.h +case "${host_os}" in + *aix*) + if ! test "$GCC" = "yes"; then + AX_CFLAGS_ADD([-qlanglvl=stdc99]) + fi + ;; + *) + ;; +esac + +AC_CHECK_PROGS(GCOV, gcov, false) +AC_CHECK_PROGS(LCOV, lcov, false) +AC_CHECK_PROGS(GENHTML, genhtml, false) +AC_CHECK_PROGS(TEX, tex, false) +if test "$TEX" = "false"; then + # Make it [somewhat] clear to maintainers that tex is missing. Not an error + # though because 'make install' (which users need) does not build the docs + # anyway. + AC_MSG_WARN(tex not installed: cannot rebuild HTML documentation.) +fi +AC_CHECK_PROGS(FILTERDIFF, filterdiff, false) +if test "$FILTERDIFF" = "false"; then + # Make it [somewhat] clear to maintainers that filterdiff is missing. + # This is not an error, but will prevent builds from being + # reproducible. + AC_MSG_WARN(filterdiff not installed; build will not be reproducible.) +fi + +AM_CONDITIONAL(USE_FILTERDIFF, [test x"$FILTERDIFF" = x"filterdiff"]) + +# Checks for pthread implementation. +ACX_PTHREAD +CC="$PTHREAD_CC" + +# Check if floor is in the math library, and if so add -lm to LIBS +AC_CHECK_LIB([m], [floor]) + +# Check if clock_gettime, timer_create, timer_settime, and timer_delete are available in lib rt, and if so, +# add -lrt to LIBS +AC_CHECK_LIB([rt], [clock_gettime, timer_create, timer_settime, timer_delete]) + +# check that struct timespec is defined in time.h. If not, we need to +# define it in libcompat.h. Note the optional inclusion of pthread.h. +# On MinGW and MinGW-w64, the pthread.h file contains the timespec +# definition. +AC_CHECK_MEMBERS([struct timespec.tv_sec, struct timespec.tv_nsec], [], [AC_DEFINE_UNQUOTED(STRUCT_TIMESPEC_DEFINITION_MISSING, 1, "Need to define the timespec structure")], [ +#include +#if defined(HAVE_PTHREAD) +#include +#endif /* HAVE_PTHREAD */ +]) + +# check that struct itimerspec is defined in time.h. If not, we need to +# define it in libcompat.h. Note the optional inclusion of pthread.h. +# On MinGW and MinGW-w64, the pthread.h file contains the itimerspec +# definition. +AC_CHECK_MEMBERS([struct itimerspec.it_interval, struct itimerspec.it_value], [], [AC_DEFINE_UNQUOTED(STRUCT_ITIMERSPEC_DEFINITION_MISSING, 1, "Need to define the itimerspec structure")], [ +#include +#if defined(HAVE_PTHREAD) +#include +#endif /* HAVE_PTHREAD */ +]) + +# Checks for header files. +AC_HEADER_STDC +AC_HEADER_SYS_WAIT +AC_CHECK_HEADERS([fcntl.h stddef.h stdlib.h string.h sys/time.h unistd.h]) +AX_CREATE_STDINT_H(check_stdint.h) + +AS_IF([test x"$enable_subunit" != "xfalse" && test x"$enable_subunit" != "xtrue"], [ + PKG_CHECK_EXISTS([libsubunit], [:], [enable_subunit=false]) + ]) +AS_IF([test x"$enable_subunit" != "xfalse"], [ + PKG_CHECK_MODULES([LIBSUBUNIT], [libsubunit]) + ]) +if test "xfalse" = x"$enable_subunit"; then +ENABLE_SUBUNIT="0" +LIBSUBUNIT_PC="" +else +ENABLE_SUBUNIT="1" +LIBSUBUNIT_PC="libsubunit" +fi +AC_SUBST(ENABLE_SUBUNIT) +AC_SUBST([LIBSUBUNIT_PC]) +AC_DEFINE_UNQUOTED(ENABLE_SUBUNIT, $ENABLE_SUBUNIT, [Subunit protocol result output]) + +AM_CONDITIONAL(SUBUNIT, test x"$enable_subunit" != "xfalse") + +# Check for POSIX regular expressions support. +AC_CHECK_HEADERS([regex.h], HAVE_REGEX_H=1, HAVE_REGEX_H=0) + +if test "x$HAVE_REGEX_H" = "x1"; then + AC_CHECK_FUNCS([regcomp regexec], HAVE_REGEX=1, HAVE_REGEX=0) +else + HAVE_REGEX=0 +fi +AC_SUBST(HAVE_REGEX) +AC_DEFINE_UNQUOTED(HAVE_REGEX, $HAVE_REGEX, "Regular expressions are supported") + +if test "x$HAVE_REGEX" = "x1"; then + ENABLE_REGEX="1" +else + ENABLE_REGEX="0" +fi +AC_SUBST(ENABLE_REGEX) +AC_DEFINE_UNQUOTED(ENABLE_REGEX, $ENABLE_REGEX, "Regular expressions are supported and enabled") + +# Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_TYPE_INTMAX_T +AC_TYPE_UINTMAX_T +AC_TYPE_UINT32_T +AC_HEADER_TIME +AC_STRUCT_TM + +AC_CHECK_SIZEOF(int, 4) +AC_CHECK_SIZEOF(short, 2) +AC_CHECK_SIZEOF(long, 4) + +# The following two checks will attempt to include pthread.h. The +# reason is MinGW and MinGW-w64 have been known to put the time +# related definitions in the pthread headers. Without include +# pthread.h, these checks may mistakenly fail to find the +# definitions. +AC_CHECK_TYPE(clockid_t, [], [AC_DEFINE([clockid_t], [int], [clockid_t])], [ +AC_INCLUDES_DEFAULT +#if defined(HAVE_PTHREAD) +#include +#endif /* HAVE_PTHREAD */ +]) +AC_CHECK_TYPE(timer_t, [], [AC_DEFINE([timer_t], [int], [timer_t])], [ +AC_INCLUDES_DEFAULT +#if defined(HAVE_PTHREAD) +#include +#endif /* HAVE_PTHREAD */ +]) + +# Checks for library functions. +AC_FUNC_MALLOC +AC_FUNC_REALLOC + +# Check if the timer_create(), timer_settime(), and timer_delete() +# functions on the system are available and suitable, or need to be +# replaced with Check's replacement of these functions. +HW_LIBRT_TIMERS + +# The following checks will replace missing functions from libcompat +AC_REPLACE_FUNCS([alarm clock_gettime getline gettimeofday localtime_r strdup strsignal]) +AC_CHECK_DECLS([alarm, clock_gettime, getline, gettimeofday, localtime_r, strdup, strsignal]) + +# The following checks are to only detect if the functions exist, but +# not replace them +AC_CHECK_DECLS([setenv]) + +AC_CHECK_FUNCS([setitimer]) + +# Checks for functions not available in Windows +if test "xtrue" = x"$enable_fork"; then + AC_CHECK_FUNCS([fork], HAVE_FORK=1, HAVE_FORK=0) +else + HAVE_FORK=0 +fi +AC_SUBST(HAVE_FORK) +AC_CHECK_FUNCS([sigaction]) +AC_CHECK_FUNCS([mkstemp]) + +# Check if the system's snprintf (and its variations) are C99 compliant. +# If they are not, use the version in libcompat. +HW_FUNC_VSNPRINTF +HW_FUNC_SNPRINTF + +# Check for whether we can install checkmk (we have a usable awk) +AC_ARG_VAR([AWK_PATH],[Awk interpreter command]) +AC_PATH_PROG(AWK_PATH, $AWK, [*NO AWK*]) +AM_CONDITIONAL([INSTALL_CHECKMK], [test "x$AWK_PATH" != 'x*NO AWK*']) + +# Certain awk implementations disagree with each other on how to +# substitute doubled backslashes in gsub() +AC_SUBST(AWK_GSUB_DBL_BSLASH, '\\\\') + +AS_IF([test "x$AWK_PATH" = 'x*NO AWK*'], + [AC_MSG_WARN([Couldn't find a usable awk; won't install checkmk.])], + + # Determine correct number of backslashes for gsub's replacement + # value. + [AS_IF([echo '\' | + "$AWK_PATH" '{ gsub("\\\\", "\\\\", $0); print }' | + grep '^\\$' >/dev/null 2>&1], AWK_GSUB_DBL_BSLASH='\\\\\\\\') + AC_CONFIG_FILES(checkmk/checkmk) + AC_CONFIG_COMMANDS([checkmk-x], [chmod +x checkmk/checkmk])]) + +# Output files +AC_CONFIG_HEADERS([config.h]) + +AC_CONFIG_FILES([check.pc + Makefile + checkmk/Makefile + doc/Makefile + lib/Makefile + src/check.h + src/Makefile + tests/Makefile + tests/test_vars]) + +AC_OUTPUT + +# Finally, print a summary of the Check's compile options + +echo +echo "==========================================" +echo "Summary of Check $CHECK_MAJOR_VERSION.$CHECK_MINOR_VERSION.$CHECK_MICRO_VERSION options:" +echo + +if test "x0" = x"$HAVE_FORK"; then + result="no" +else + result="yes" +fi +echo "fork mode ............................ $result" + +case "$hw_cv_librt_timers_posix" in + "yes") + result="no" + ;; + "no") + result="yes" + ;; + *) + # The AC_REPLACE_FUNCS macro was invoked, + # meaning we are cross compiling. + if test "xno" = x"$ac_cv_func_timer_create"; then + result="yes" + else + result="no" + fi + ;; +esac +echo "high resolution timer replacement .... $result" + +if test "xno" = x"$hw_cv_func_snprintf_c99"; then + result="yes" +else + result="no" +fi +echo "snprintf replacement ................. $result" + +if test "xfalse" = x"$enable_subunit"; then + result="no" +else + result="yes" +fi +echo "subunit support....................... $result" + +if test "xtrue" = x"$enable_timeout_tests"; then + result="yes" +else + result="no" +fi +echo "timeout unit tests ................... $result" + +if test "x0" = x"$ENABLE_REGEX"; then + result="no" +else + result="yes" +fi +echo "POSIX regular expressions ............ $result" + +echo "==========================================" diff --git a/contrib/XML_for_JUnit.xsl b/contrib/XML_for_JUnit.xsl new file mode 100644 index 0000000..16f184b --- /dev/null +++ b/contrib/XML_for_JUnit.xsl @@ -0,0 +1,33 @@ + + + + + + + + + + + + 0 + + + + + + + + + + + + + + + + + + / + + + diff --git a/contrib/check_unittest.txt b/contrib/check_unittest.txt new file mode 100644 index 0000000..74d997a --- /dev/null +++ b/contrib/check_unittest.txt @@ -0,0 +1,13 @@ +An XSLT stylesheet to transform Check its XML output to HTML + +Bart van Kuik - bkuik +2006-03-16 + +This is an XSLT stylesheet to transform Check its XML +output to HTML. It's very basic and could probably be a +lot shorter. The HTML that is output isn't very +standards compliant either, but it works. + +You can generate such a report on the commandline with a quick + +$ xsltproc check_unittest.xslt check_output.xml > report.html diff --git a/contrib/eclipse/README b/contrib/eclipse/README new file mode 100644 index 0000000..b1e9a19 --- /dev/null +++ b/contrib/eclipse/README @@ -0,0 +1,16 @@ +Eclipse template for creating unit tests with check framework + +The template has been tested with Eclipse Helios CDT. Note that check +framework should be installed first and the check library should be +found in system path. + +Installation: + +From the "New Source File" dialog, press "Configure...", then +"Import..." and select the template XML file +(e.g. check_template_eclipse_helios.xml). The template should appear +under "C Source File" tree as "C source template with check unit +testing" in "Preferences" dialog. + +The newly installed template should be available when creating a "New +Source File" in "Template" combo box. diff --git a/contrib/eclipse/check_template_eclipse_helios.xml b/contrib/eclipse/check_template_eclipse_helios.xml new file mode 100644 index 0000000..b25dda7 --- /dev/null +++ b/contrib/eclipse/check_template_eclipse_helios.xml @@ -0,0 +1,33 @@ + \ No newline at end of file diff --git a/contrib/improved_make_check/COPYING b/contrib/improved_make_check/COPYING new file mode 100644 index 0000000..623b625 --- /dev/null +++ b/contrib/improved_make_check/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/contrib/improved_make_check/README b/contrib/improved_make_check/README new file mode 100644 index 0000000..2224b7e --- /dev/null +++ b/contrib/improved_make_check/README @@ -0,0 +1,34 @@ +The `check.mk' file in this directory will improve the behaviour of +`make check' when using Automake. If you create one test program for +each module you are testing in your program, then this will do this +following: + +1) Allow tests to be compiled and run in parallel +2) Only recompile and rerun test programs when the sources change +3) Produce a .log file with the output from each test +4) Only display the contents of .log files for failed tests +5) Print either a red or green status message at the end according to +whether some tests failed or all tests passed + +Modifications to your project should be minimal. A working example +can be found in libspmt, here: + +https://svn.sable.mcgill.ca/sable/spmt/libspmt/tests/ + +First, copy check.mk to trunk/build-aux/check.mk + +Second, add the following lines to tests/Makefile.am after `TESTS' and +`check_PROGRAMS' are defined: + +----- +# quiet errors re: check.mk not knowing how to create .log +.log: + +LAZY_TEST_SUITE = 1 +TEST_LOGS = $(TESTS:=.log) + +# improved make check +include $(top_srcdir)/build-aux/check.mk +----- + +Third, rebuild and test with `make check'. diff --git a/contrib/improved_make_check/check.mk b/contrib/improved_make_check/check.mk new file mode 100644 index 0000000..2c8dc0c --- /dev/null +++ b/contrib/improved_make_check/check.mk @@ -0,0 +1,216 @@ +## The original version of this file comes from vaucanson-1.1.1. It +## was later modified as part of libspmt. Although it is released +## under the GPL, it only affects the build process, and so does not +## change the license of projects that use it, much like Automake +## which is also under the GPL, or Check which is under the LGPL. + +## Vaucanson, a generic library for finite state machines. +## Copyright (C) 2006, 2007 The Vaucanson Group. +## +## libspmt, a library for speculative multithreading. +## Copyright (C) 2008 Chris Pickett +## +## Check, a unit testing framework for C. +## Copyright (C) 2012 The Check Project. +## +## The Vaucanson Group consists of the people listed in the `AUTHORS' +## file distributed with Vaucanson. The Check Project consists of the +## people listed in the `AUTHORS' file distributed with Check. +## +## This program is free software; you can redistribute it and/or +## modify it under the terms of the GNU General Public License +## as published by the Free Software Foundation; either version 2 +## of the License, or (at your option) any later version. +## +## The complete GNU General Public Licence Notice can be found as the +## `COPYING' file in this directory. + +## Override the definition from Automake to generate a log file with +## failed tests. It also supports parallel make checks. +## +## This file provides special support for "unit tests", that is to +## say, tests that (once run) no longer need to be re-compiled and +## re-run at each "make check", unless their sources changed. To +## enable unit-test supports, define LAZY_TEST_SUITE. In such a +## setting, that heavily relies on correct dependencies, its users may +## prefer to define EXTRA_PROGRAMS instead of check_PROGRAMS, because +## it allows intertwined compilation and execution of the tests. +## Sometimes this helps catching errors earlier (you don't have to +## wait for all the tests to be compiled). +## +## Define TEST_SUITE_LOG to be the name of the global log to create. +## Define TEST_LOGS to the set of logs to include in it. It defaults +## to $(TESTS:.test=.log). + +## We use GNU Make extensions (%-rules), and override check-TESTS. +AUTOMAKE_OPTIONS = -Wno-portability -Wno-override + +# Restructured Text title and section. +am__rst_title = sed 's/.*/ & /;h;s/./=/g;p;x;p;g;p;s/.*//' +am__rst_section = sed 'p;s/./=/g;' + +# Put stdin (possibly several lines separated by ". ") in a box. +am__text_box = $(AWK) '{gsub ("\\. ", "\n"); print $$0; }' | \ +$(AWK) ' \ +max < length($$0) { \ + final= final (final ? "\n" : "") " " $$0; \ + max = length($$0); \ +} \ +END { \ + for (i = 0; i < max + 2 ; ++i) \ + line = line "="; \ + print line; \ + print final; \ + print line; \ +}' + +# If stdout is a tty, use colors. If test -t is not supported, then +# this fails; a conservative approach. Of course do not redirect +# stdout here, just stderr... +am__tty_colors = \ +if test -t 1 2>/dev/null; then \ + red=''; \ + grn=''; \ + blu=''; \ + std=''; \ +fi + +# To be inserted before the command running the test. Stores in $dir +# the directory containing $<, and passes the TEST_ENVIRONMENT. +am__check_pre = \ +if test -f ./$<; then dir=./; \ +elif test -f $<; then dir=; \ +else dir="$(srcdir)/"; fi; \ +$(TESTS_ENVIRONMENT) + +# To be appended to the command running the test. Handles the stdout +# and stderr redirection, and catch the exit status. +am__check_post = \ +>$@-t 2>&1; \ +estatus=$$?; \ +$(am__tty_colors); \ +case $$estatus:" $(XFAIL_TESTS) " in \ + 0:*" $$(basename $<) "*) col=$$red; res=XPASS;; \ + 0:*) col=$$grn; res=PASS ;; \ + 77:*) col=$$blu; res=SKIP ;; \ + *:*" $$(basename $<) "*) col=$$grn; res=XFAIL;; \ + *:*) col=$$red; res=FAIL ;; \ +esac; \ +echo "$$res: $$(basename $<)" | \ + $(am__rst_section) >$@; \ +cat $@-t >>$@; \ +rm $@-t + +# From a test file to a log file. +# Do not use a regular `.test.log:' rule here, since in that case the +# following rule (without incoming extension) will mask this one. +%.log: %.test + @$(am__check_pre) $${dir}$< $(am__check_post) + +# The exact same commands, but for programs. +%.log: %$(EXEEXT) + @$(am__check_pre) $${dir}$< $(am__check_post) + +TEST_LOGS ?= $(TESTS:.test=.log) +TEST_SUITE_LOG = test-suite.log + +$(TEST_SUITE_LOG): $(TEST_LOGS) + @results=$$(for f in $(TEST_LOGS); do sed 1q $$f; done); \ + all=$$(echo "$$results" | wc -l | sed -e 's/^[ \t]*//'); \ + fail=$$(echo "$$results" | grep -c '^FAIL'); \ + pass=$$(echo "$$results" | grep -c '^PASS'); \ + skip=$$(echo "$$results" | grep -c '^SKIP'); \ + xfail=$$(echo "$$results" | grep -c '^XFAIL'); \ + xpass=$$(echo "$$results" | grep -c '^XPASS'); \ + case fail=$$fail:xfail=$$xfail:xpass=$$xpass in \ + fail=0:xfail=0:xpass=*) \ + msg="All $$all tests passed. ";; \ + fail=0:xfail=*:xpass=*) \ + msg="All $$all tests behaved as expected"; \ + msg="$$msg ($$xfail expected failures). ";; \ + fail=*:xfail=*:xpass=0) \ + msg="$$fail of $$all tests failed. ";; \ + fail=*:xfail=*:xpass=*) \ + msg="$$fail of $$all tests did not behave as expected"; \ + msg="$$msg ($$xpass unexpected passes). ";; \ + *) \ + echo >&2 "incorrect case"; exit 4;; \ + esac; \ + if test "$$skip" -ne 0; then \ + msg="$$msg($$skip tests were not run). "; \ + fi; \ + if test "$$fail" -ne 0; then \ + { \ + for f in $(TEST_LOGS); \ + do \ + case $$(sed 1q $$f) in \ + SKIP:*|PASS:*|XFAIL:*);; \ + *) echo; cat $$f;; \ + esac; \ + done; \ + } >$(TEST_SUITE_LOG).tmp; \ + mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \ + if test -n "$(PACKAGE_BUGREPORT)"; then \ + msg="$${msg}Please report to $(PACKAGE_BUGREPORT). "; \ + fi; \ + fi; \ + $(am__tty_colors); \ + if test "$$fail" -ne 0; then \ + cat $(TEST_SUITE_LOG); \ + fi; \ + if test "$$fail" -eq 0; then echo $$grn; else echo $$red; fi; \ + echo "$$msg" | $(am__text_box); \ + echo $$std; \ + test "$$fail" -eq 0 + +# 1) remove $(TEST_LOGS) if LAZY_TEST_SUITE is not defined to force recreation +# 2) always remove $(TEST_SUITE_LOG) so that output is generated regardless +# 3) run all the tests +check-TESTS: + @if test -z '$(LAZY_TEST_SUITE)'; then \ + rm -f $(TEST_LOGS); \ + fi + rm -f $(TEST_SUITE_LOG) + @$(MAKE) $(TEST_SUITE_LOG) + + +## -------------- ## +## Produce HTML. ## +## -------------- ## + +TEST_SUITE_HTML = $(TEST_SUITE_LOG:.log=.html) + +%.html: %.log + @for r2h in $(RST2HTML) $$RST2HTML rst2html rst2html.py; \ + do \ + if ($$r2h --version) >/dev/null 2>&1; then \ + R2H=$$r2h; \ + fi; \ + done; \ + if test -z "$$R2H"; then \ + echo >&2 "cannot find rst2html, cannot create $@"; \ + exit 2; \ + fi; \ + $$R2H $< >$@.tmp + mv $@.tmp $@ + +# Be sure to run check-TESTS first, and then to convert the result. +# Beware of concurrent executions. And expect check-TESTS to fail. +check-html: + @if $(MAKE) $(AM_MAKEFLAGS) check-TESTS; then :; else \ + rv=$?; \ + $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_HTML); \ + exit $$rv; \ + fi + +.PHONY: check-html + + +## ------- ## +## Clean. ## +## ------- ## + +check-clean: check-clean-local + rm -f $(CHECK_CLEANFILES) $(TEST_SUITE_LOG) $(TEST_SUITE_HTML) $(TEST_LOGS) +.PHONY: check-clean check-clean-local +clean-local: check-clean diff --git a/contrib/make_macros b/contrib/make_macros new file mode 100644 index 0000000..497aa68 --- /dev/null +++ b/contrib/make_macros @@ -0,0 +1,302 @@ +#!/usr/bin/perl + +# Purpose: +# Generates Assert/Fail macros for use with check. +# +# Usage: +# make_macros macros.in > macros.h +# +# macros.in: one or more lines containing... +# Assert +# Assert_(|not)(Success|Error|Failure|NULL|True|False|Same) +# Fail_(if|unless)(Success|Error|Failure|NULL|True|False|Same) +# Assert_(|not)(0[0-7]+|0x[0-9A-Fa-f]+|0b[01]+|[1-9][0-9]+) +# Fail_(if|unless)(0[0-7]+|0x[0-9A-Fa-f]+|0b[01]+|[1-9][0-9]+) +# Assert_(|not)(LT|LE|EQ|GE|GT|NE) +# Fail_(if|unless)(LT|LE|EQ|GE|GT|NE) +# Assert_(|not){Type}(LT|LE|EQ|GE|GT|NE) +# Fail_(if|unless){Type}(LT|LE|EQ|GE|GT|NE) +# {Type}_compare +# +# Example: +# echo -e 'Assert_notNULL\nAssertStringEQ' | make_macros > macros.h +# +# #include "macros.h" +# ... +# char *foo; +# Assert_notNULL( foo = strdup( "foo" ) , NULL ); +# Assert_StringEQ( foo, "foo", NULL ); +# +# author: unknown... if you know, please correct or email check-devel + +use warnings; +use strict; + +use Switch 'Perl6'; +use Text::Wrap; + +our %need; +our %include; +our %macros; + +sub make_macro { + my ($name, $fh) = @_; + my ($condition) = $name; + + my ($failIf, $failUnless, $assertNot, $assert); + for ($condition) { + $failIf = 1, next if s/^ Fail_ if ([A-Z0-9]?) /$1/x; + $failUnless = 1, next if s/^ Fail_ unless ([A-Z0-9]?) /$1/x; + $assertNot = 1, next if s/^ Assert_ not ([A-Z0-9] ) /$1/x; + $assert = 1, next if s/^ Assert_ (. ) /$1/x; + $assert = 1, next if s/^ Assert $//x; + print $fh "#error don't know how to make ${name}\n\n"; + return; + } + + my ($invert) = 0; + foreach ($failIf, $assertNot) { + $invert = !$invert if $_; + } + + my $type = ""; + if ($condition =~ s/(LT|LE|EQ|GE|GT|NE)$//) { + $type = $condition; + $condition = $1; + } + $type = "Number" unless length $type; + + my (@args) = qw( expr ); + my ($expr) = qw( (expr) ); + my ($msg); + my ($doc); + my (%argdocs) = ( + expr => "The expression to test." + ); + + my ($not) = sub { $invert ? "not " : "" }; + my ($Not) = sub { $invert ? "" : "not " }; + my ($EQ) = sub { $invert ? "!=" : "==" }; + my ($NE) = sub { $invert ? "==" : "!=" }; + + given ($condition) { + when "" { + unless ( $invert ) { + $doc = "Asserts that \@p expr is true."; + $msg = "Assertion '\"#expr\"' failed."; + } else { + $doc = "Asserts that \@p expr is false."; + $msg = "Negative assertion '\"#expr\"' failed"; + } + } + when [qw(Error error Failure failure Success success)] { + $invert = !$invert when [qw(Success success)]; + unless ( $invert ) { + $doc = "Asserts that \@p expr failed."; + $msg = "'\"#expr\"' did not fail"; + } else { + $doc = "Asserts that \@p expr did not fail."; + $msg = "'\"#expr\"' failed"; + } + $invert = !$invert; + } + when [qw(True true False false)] { + $invert = !$invert when "false"; + $doc = "Asserts that \@p expr is ".( $invert ? "false" : "true" )."."; + $msg = "'\"#expr\"' was " . ( $invert ? "true" : "false" ); + } + when "NULL" { + $msg = "'\"#expr\"' was ".&$Not."NULL"; + $doc = "Asserts that \@p expr is ".&$not."NULL"; + $expr = "(expr) ".&$EQ." NULL"; + $invert = 0; + $include{"stddef.h"} = 1; + } + when m/^(?:[1-9]\d*|0x[0-9A-Fa-f]+|0b[01]+|0[0-7]+)$/x { + $msg = "'\"#expr\"' was ".&$Not."equal to $condition"; + $doc = "Asserts that \@p expr is ".&$not."equal to $condition."; + $condition = oct($condition) if $condition =~ /^0/; + $expr = "(expr) ".&$EQ." $condition"; + $invert = 0; + } + when [qw(GT GE LT LE EQ NE Equal equal)] { + my $op; + given ( $condition ) { + $op = [ "less than" , "<" ] when "LT"; + $op = [ "less than that or equal to", "<=" ] when "LE"; + $op = [ "equal to" , "==" ] when ["EQ", "Equal", "equal", "NE"]; + $op = [ "greater than or equal to" , ">=" ] when "GE"; + $op = [ "greater than" , ">" ] when "GT"; + }; + $invert = !$invert when "NE"; + @args = ( $type."1", $type."2" ); + %argdocs = ( + $type."1" => "The expression to test.", + $type."2" => "The test value." + ); + $msg = "'\"#$args[0]\"' is ".&$Not.$op->[0]." '\"#$args[1]\"'"; + $doc = "Asserts that \@p $args[0] is ".&$not.$op->[0]." \@p $args[1]."; + $expr = "(${type}_compare( $args[0], $args[1] ) ".$op->[1]." 0)"; + $need{$type."_compare"} = 1; + } + when [qw(Same same)] { + @args = qw( arg1 arg2 ); + %argdocs = ( + arg1 => "The expression to test.", + arg2 => "The expected value." + ); + $msg = "'\"#arg1\"' and '\"#arg2\"' are ".&$Not."the same"; + $msg = "Asserts that \@p arg1 and \@p arg2 are ".&$not."the same"; + $expr = "(arg1) ".&$EQ." (arg2)"; + $invert = 0; + } + default { + print $fh "#error don't know how to make ${name}\n\n"; + return; + } + } + + if ($invert) { + $expr = "!$expr"; + } + + if ($doc) { + print $fh "/**\n"; + print $fh wrap(" * "," * ","$doc\n"); + my ($maxlength) = 3; + foreach (keys %argdocs) { + $maxlength = length $_ if length $_ > $maxlength; + } + my ($indent) = " " x ($maxlength + 1 + 7); + foreach (keys %argdocs) { + print $fh wrap(" * ", + " * $indent", + "\@param $_ ".(" " x ($maxlength - length $_)). + "$argdocs{$_}\n"); + } + print $fh wrap(" * ", + " * $indent", + "\@param ... ".(" " x ($maxlength - 3)). + "An optional message to indicate the assertion failed; ". + "Omit for a default message.\n"); + + print $fh " */\n"; + } + print $fh "#define ${name}(",(join ", ", @args, '...'),") \\\n"; + print $fh " _ck_assert_msg( $expr, __FILE__, __LINE__, \\\n"; + print $fh " \"$msg\", ## __VA_ARGS__, NULL)\n"; + print $fh "\n"; + + $macros{$name} = 1; +} + +sub make_compare { + my ($name, $fh) = @_; + my ($type) = $name; + $type =~ s/_compare$//; + + my ($expr); + my ($warning); + my ($ord); + my (@name) = ( "", "" ); + + given ($type) { + when "Number" { + $expr = "( ${type}1 - ${type}2 )"; + $ord = "is"; + } + when "String" { + $expr = "strcmp( ${type}1, ${type}2 )"; + $include{"string.h"} = 1; + $ord = "is"; + } + default { + $expr = "memcmp( ${type}1, ${type}2, sizeof( ${type} ) )"; + $include{"string.h"} = 1; + $ord = "are"; + @name = ( "'s bytes ", "'s" ); + $warning = "This compares \@p ${type}1 and \@p ${type}2 " + . "byte-for-byte, this is probably not what you want " + . "for all but the simplest of structures."; + } + } + + print $fh "/**\n"; + print $fh " * Compares \@p ${type}1 and \@p ${type}2.\n"; + print $fh wrap(" * "," * ",$warning . "\n") if $warning; + print $fh " * \@param ${type}1 The first ${type}.\n"; + print $fh " * \@param ${type}2 The second ${type}.\n"; + my (%val_name) = ( + ">0" => "greater than", + "0 " => "equal to", + "<0" => "less than", + ); + while (my ($val, $name) = each %val_name) { + print $fh " * \@retval $val If \@p ${type}1 $name[0]$ord $name \@p ${type}2 $name[1].\n"; + } + print $fh " */\n"; + print $fh "#define ${type}_compare(${type}1, ${type}2) \\\n"; + print $fh " $expr\n"; + print $fh "\n"; + $macros{$name} = 1; +} + +my $INCLUDES = ''; +open my $includes, ">", \$INCLUDES or die; + +my $MACROS = ''; +open my $macros, ">", \$MACROS or die; + +my $MACROS2 = ''; +open my $macros2, ">", \$MACROS2 or die; + +while (<>) { + chomp; + make_macro( $_, $macros2 ) if /^(?:Assert|Fail)/; + make_compare( $_, $macros ) if /_compare$/; +} + +foreach my $need (keys %need) { + given ($need) { + when /^(?:String|Number)_compare$/ { + make_compare( $need, $macros ); + delete $need{$need}; + } + } +} + +foreach my $macro (keys %macros) { + delete $need{$macro}; +} + +if (scalar %need) { + print $includes "/* needed functions/macros:\n"; + foreach my $need (keys %need) { + if ($need =~ /^(.*)_compare$/) { + print $includes " * int $need(${1}1,${1}2);\n"; + } else { + print $includes " * $need\n"; + } + } + print $includes " */\n\n"; +} + +foreach my $include (keys %include) { + print $includes "#include <$include>\n"; +} + +print <<'END'; +#ifndef _CHECK_MACROS_H +#define _CHECK_MACROS_H + +END +print $INCLUDES; +print "\n"; +print $MACROS; +print $MACROS2; +print <<'END'; + +#endif /* _CHECK_MACROS_H */ +END + + diff --git a/doc/.cvsignore b/doc/.cvsignore new file mode 100644 index 0000000..f6773c8 --- /dev/null +++ b/doc/.cvsignore @@ -0,0 +1,4 @@ +Makefile +Makefile.in +tutorial.sgml +tutorial*.html diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000..2710972 --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,148 @@ +## Process this file with automake to produce Makefile.in + +info_TEXINFOS = check.texi +check_TEXINFOS = fdl.texi + +check_html: $(srcdir)/check.texi + texi2html --output=check_html --top-file=index.html --split=chapter check.texi + +doxygen: + doxygen $(srcdir)/doxygen.conf + +## we need to include several diffs as we evolve the example in the +## tutorial. this means we'll generate them from the example source. + +$(srcdir)/check.texi: money.1-2.h.diff \ + money.1-3.c.diff \ + money.3-4.c.diff \ + money.4-5.c.diff \ + money.5-6.c.diff \ + check_money.1-2.c.diff \ + check_money.2-3.c.diff \ + check_money.3-6.c.diff \ + check_money.6-7.c.diff + +eg_root = $(top_srcdir)/doc/example +eg_src = $(eg_root)/src +eg_tests = $(eg_root)/tests + +# If the filterdiff tool is available, use it to filter timestamps +# from diff files. Otherwise, the timestamps change between builds +# and the built output will not be reproducible +if USE_FILTERDIFF + filter_timestapms = | filterdiff --remove-timestamps +else + filter_timestapms = +endif + +## now a rule for each diff. the redundancy here can probably be +## parameterized, but I don't know how. if you know, please tell us! + +# diff returns 1 if there is a difference, but we don't want make to +# think that means there is an error +money.1-2.h.diff: $(eg_src)/money.1.h $(eg_src)/money.2.h + cd $(eg_root); \ + diff -U 100 src/money.1.h src/money.2.h ${filter_timestapms} > @abs_builddir@/$@ || test $$? -eq 1; \ + cd -; + +money.1-3.c.diff: $(eg_src)/money.1.c $(eg_src)/money.3.c + cd $(eg_root); \ + diff -U 100 src/money.1.c src/money.3.c ${filter_timestapms} > @abs_builddir@/$@ || test $$? -eq 1; \ + cd -; + +money.3-4.c.diff: $(eg_src)/money.3.c $(eg_src)/money.4.c + cd $(eg_root); \ + diff -U 100 src/money.3.c src/money.4.c ${filter_timestapms} > @abs_builddir@/$@ || test $$? -eq 1; \ + cd -; + +money.4-5.c.diff: $(eg_src)/money.4.c $(eg_src)/money.5.c + cd $(eg_root); \ + diff -U 100 src/money.4.c src/money.5.c ${filter_timestapms} > @abs_builddir@/$@ || test $$? -eq 1; \ + cd -; + +money.5-6.c.diff: $(eg_src)/money.5.c $(eg_src)/money.6.c + cd $(eg_root); \ + diff -U 100 src/money.5.c src/money.6.c ${filter_timestapms} > @abs_builddir@/$@ || test $$? -eq 1; \ + cd -; + +check_money.1-2.c.diff: $(eg_tests)/check_money.1.c $(eg_tests)/check_money.2.c + cd $(eg_root); \ + diff -U 100 tests/check_money.1.c tests/check_money.2.c ${filter_timestapms} > @abs_builddir@/$@ || test $$? -eq 1; \ + cd -; + +check_money.2-3.c.diff: $(eg_tests)/check_money.2.c $(eg_tests)/check_money.3.c + cd $(eg_root); \ + diff -U 100 tests/check_money.2.c tests/check_money.3.c ${filter_timestapms} > @abs_builddir@/$@ || test $$? -eq 1; \ + cd -; + +check_money.3-6.c.diff: $(eg_tests)/check_money.3.c $(eg_tests)/check_money.6.c + cd $(eg_root); \ + diff -U 100 tests/check_money.3.c tests/check_money.6.c ${filter_timestapms} > @abs_builddir@/$@ || test $$? -eq 1; \ + cd -; + +check_money.6-7.c.diff: $(eg_tests)/check_money.6.c $(eg_tests)/check_money.7.c + cd $(eg_root); \ + diff -U 100 tests/check_money.6.c tests/check_money.7.c ${filter_timestapms} > @abs_builddir@/$@ || test $$? -eq 1; \ + cd -; + +# explicitly list every file in the example. + +example_docs = example/Makefile.am \ + example/README \ + example/configure.ac + +example_src_docs = example/src/Makefile.am \ + example/src/main.c \ + example/src/money.c \ + example/src/money.h \ + example/src/money.1.h \ + example/src/money.2.h \ + example/src/money.1.c \ + example/src/money.3.c \ + example/src/money.4.c \ + example/src/money.5.c \ + example/src/money.6.c + +example_tests_docs = example/tests/Makefile.am \ + example/tests/check_money.c \ + example/tests/check_money.1.c \ + example/tests/check_money.2.c \ + example/tests/check_money.3.c \ + example/tests/check_money.6.c \ + example/tests/check_money.7.c + +example_cmake = example/CMakeLists.txt \ + example/src/CMakeLists.txt \ + example/tests/CMakeLists.txt \ + example/cmake/config.h.in \ + example/cmake/COPYING-CMAKE-SCRIPTS.txt \ + example/cmake/FindCheck.cmake + +## what to clean + +CLEANFILES = *~ *.diff + +clean-local: + rm -rf check_html + rm -rf doxygen +## what to distribute + +EXTRA_DIST = $(example_docs) \ + $(example_src_docs) \ + $(example_tests_docs) \ + $(example_cmake) + +## what to install + +docdir = $(datadir)/doc/$(PACKAGE) + +# install money example + +exampledir = $(docdir)/example +example_DATA = $(example_docs) + +examplesrcdir = $(docdir)/example/src +examplesrc_DATA = $(example_src_docs) + +exampletestsdir = $(docdir)/example/tests +exampletests_DATA = $(example_tests_docs) diff --git a/doc/check.texi b/doc/check.texi new file mode 100644 index 0000000..0630906 --- /dev/null +++ b/doc/check.texi @@ -0,0 +1,2305 @@ +\input texinfo @c -*-texinfo-*- +@c %**start of header +@setfilename check.info +@include version.texi +@settitle Check @value{VERSION} +@syncodeindex fn cp +@syncodeindex tp cp +@syncodeindex vr cp +@c %**end of header + +@copying +This manual is for Check +(version @value{VERSION}, @value{UPDATED}), +a unit testing framework for C. + +Copyright @copyright{} 2001--2014 Arien Malec, Branden Archer, Chris Pickett, +Fredrik Hugosson, and Robert Lemmen. + +@quotation +Permission is granted to copy, distribute and/or modify this document +under the terms of the @acronym{GNU} Free Documentation License, +Version 1.2 or any later version published by the Free Software +Foundation; with no Invariant Sections, no Front-Cover texts, and no +Back-Cover Texts. A copy of the license is included in the section +entitled ``@acronym{GNU} Free Documentation License.'' +@end quotation +@end copying + +@dircategory Software development +@direntry +* Check: (check)Introduction. +@end direntry + +@titlepage +@title Check +@subtitle A Unit Testing Framework for C +@subtitle for version @value{VERSION}, @value{UPDATED} +@author Arien Malec +@author Branden Archer +@author Chris Pickett +@author Fredrik Hugosson +@author Robert Lemmen +@author Robert Collins + +@c The following two commands start the copyright page. +@page +@vskip 0pt plus 1filll +@insertcopying +@end titlepage + +@c Output the table of contents at the beginning. +@contents + +@ifnottex +@node Top, Introduction, (dir), (dir) +@top Check + +@insertcopying + +Please send corrections to this manual to +@email{check-devel AT lists.sourceforge.net}. We'd prefer it if you can +send a unified diff (@command{diff -u}) against the +@file{doc/check.texi} file that ships with Check, but if that is not +possible something is better than nothing. +@end ifnottex + +@menu +* Introduction:: +* Unit Testing in C:: +* Tutorial:: +* Advanced Features:: +* Supported Build Systems:: +* Conclusion and References:: +* Environment Variable Reference:: +* Copying This Manual:: +* Index:: + +@detailmenu + --- The Detailed Node Listing --- + +Unit Testing in C + +* Other Frameworks for C:: + +Tutorial: Basic Unit Testing + +* How to Write a Test:: +* Setting Up the Money Build Using Autotools:: +* Setting Up the Money Build Using CMake:: +* Test a Little:: +* Creating a Suite:: +* SRunner Output:: + +Advanced Features + +* Convenience Test Functions:: +* Running Multiple Cases:: +* No Fork Mode:: +* Test Fixtures:: +* Multiple Suites in one SRunner:: +* Selective Running of Tests:: +* Testing Signal Handling and Exit Values:: +* Looping Tests:: +* Test Timeouts:: +* Determining Test Coverage:: +* Finding Memory Leaks:: +* Test Logging:: +* Subunit Support:: + +Test Fixtures + +* Test Fixture Examples:: +* Checked vs Unchecked Fixtures:: + +Test Logging + +* XML Logging:: +* TAP Logging:: + +Environment Variable Reference + +Copying This Manual + +* GNU Free Documentation License:: License for copying this manual. + +@end detailmenu +@end menu + +@node Introduction, Unit Testing in C, Top, Top +@chapter Introduction +@cindex introduction + +Check is a unit testing framework for C. It was inspired by similar +frameworks that currently exist for most programming languages; the +most famous example being @uref{http://www.junit.org, JUnit} for Java. +There is a list of unit test frameworks for multiple languages at +@uref{http://www.xprogramming.com/software.htm}. Unit testing has a +long history as part of formal quality assurance methodologies, but +has recently been associated with the lightweight methodology called +Extreme Programming. In that methodology, the characteristic practice +involves interspersing unit test writing with coding (``test a +little, code a little''). While the incremental unit test/code +approach is indispensable to Extreme Programming, it is also +applicable, and perhaps indispensable, outside of that methodology. + +The incremental test/code approach provides three main benefits to the +developer: + +@enumerate +@item +Because the unit tests use the interface to the unit being tested, +they allow the developer to think about how the interface should be +designed for usage early in the coding process. + +@item +They help the developer think early about aberrant cases, and code +accordingly. + +@item +By providing a documented level of correctness, they allow the +developer to refactor (see @uref{http://www.refactoring.com}) +aggressively. +@end enumerate + +That third reason is the one that turns people into unit testing +addicts. There is nothing so satisfying as doing a wholesale +replacement of an implementation, and having the unit tests reassure +you at each step of that change that all is well. It is like the +difference between exploring the wilderness with and without a good +map and compass: without the proper gear, you are more likely to +proceed cautiously and stick to the marked trails; with it, you can +take the most direct path to where you want to go. + +Look at the Check homepage for the latest information on Check: +@uref{http://check.sourceforge.net}. + +The Check project page is at: +@uref{http://sourceforge.net/projects/check/}. + +@node Unit Testing in C, Tutorial, Introduction, Top +@chapter Unit Testing in C +@ C unit testing + +The approach to unit testing frameworks used for Check originated with +Smalltalk, which is a late binding object-oriented language supporting +reflection. Writing a framework for C requires solving some special +problems that frameworks for Smalltalk, Java or Python don't have to +face. In all of those language, the worst that a unit test can do is +fail miserably, throwing an exception of some sort. In C, a unit test +is just as likely to trash its address space as it is to fail to meet +its test requirements, and if the test framework sits in the same +address space, goodbye test framework. + +To solve this problem, Check uses the @code{fork()} system call to +create a new address space in which to run each unit test, and then +uses message queues to send information on the testing process back to +the test framework. That way, your unit test can do all sorts of +nasty things with pointers, and throw a segmentation fault, and the +test framework will happily note a unit test error, and chug along. + +The Check framework is also designed to play happily with common +development environments for C programming. The author designed Check +around Autoconf/Automake (thus the name Check: @command{make check} is +the idiom used for testing with Autoconf/Automake). Note however that +Autoconf/Automake are NOT necessary to use Check; any build system +is sufficient. The test failure messages thrown up by Check use the +common idiom of @samp{filename:linenumber:message} used by @command{gcc} +and family to report problems in source code. With (X)Emacs, the output +of Check allows one to quickly navigate to the location of the unit test +that failed; presumably that also works in VI and IDEs. + +@menu +* Other Frameworks for C:: +@end menu + +@node Other Frameworks for C, , Unit Testing in C, Unit Testing in C +@section Other Frameworks for C +@cindex other frameworks +@cindex frameworks + +The authors know of the following additional unit testing frameworks +for C: + +@table @asis + +@item AceUnit +AceUnit (Advanced C and Embedded Unit) bills itself as a comfortable C +code unit test framework. It tries to mimic JUnit 4.x and includes +reflection-like capabilities. AceUnit can be used in resource +constraint environments, e.g. embedded software development, and +importantly it runs fine in environments where you cannot include a +single standard header file and cannot invoke a single standard C +function from the ANSI / ISO C libraries. It also has a Windows port. +It does not use forks to trap signals, although the authors have +expressed interest in adding such a feature. See the +@uref{http://aceunit.sourceforge.net/, AceUnit homepage}. + +@item GNU Autounit +Much along the same lines as Check, including forking to run unit tests +in a separate address space (in fact, the original author of Check +borrowed the idea from @acronym{GNU} Autounit). @acronym{GNU} Autounit +uses GLib extensively, which means that linking and such need special +options, but this may not be a big problem to you, especially if you are +already using GTK or GLib. See the @uref{http://autounit.tigris.org/, +GNU Autounit homepage}. + +@item cUnit +Also uses GLib, but does not fork to protect the address space of unit +tests. See the +@uref{http://web.archive.org/web/*/http://people.codefactory.se/~spotty/cunit/, +archived cUnit homepage}. + +@item CUnit +Standard C, with plans for a Win32 GUI implementation. Does not +currently fork or otherwise protect the address space of unit tests. +In early development. See the @uref{http://cunit.sourceforge.net, +CUnit homepage}. + +@item CuTest +A simple framework with just one .c and one .h file that you drop into +your source tree. See the @uref{http://cutest.sourceforge.net, CuTest +homepage}. + +@item CppUnit +The premier unit testing framework for C++; you can also use it to test C +code. It is stable, actively developed, and has a GUI interface. The +primary reasons not to use CppUnit for C are first that it is quite +big, and second you have to write your tests in C++, which means you +need a C++ compiler. If these don't sound like concerns, it is +definitely worth considering, along with other C++ unit testing +frameworks. See the +@uref{http://cppunit.sourceforge.net/cppunit-wiki, CppUnit homepage}. + +@item embUnit +embUnit (Embedded Unit) is another unit test framework for embedded +systems. This one appears to be superseded by AceUnit. +@uref{https://sourceforge.net/projects/embunit/, Embedded Unit +homepage}. + +@item MinUnit +A minimal set of macros and that's it! The point is to +show how easy it is to unit test your code. See the +@uref{http://www.jera.com/techinfo/jtns/jtn002.html, MinUnit +homepage}. + +@item CUnit for Mr. Ando +A CUnit implementation that is fairly new, and apparently still in +early development. See the +@uref{http://park.ruru.ne.jp/ando/work/CUnitForAndo/html/, CUnit for +Mr. Ando homepage}. +@end table + +This list was last updated in March 2008. If you know of other C unit +test frameworks, please send an email plus description to +@email{check-devel AT lists.sourceforge.net} and we will add the entry +to this list. + +It is the authors' considered opinion that forking or otherwise +trapping and reporting signals is indispensable for unit testing (but +it probably wouldn't be hard to add that to frameworks without that +feature). Try 'em all out: adapt this tutorial to use all of the +frameworks above, and use whichever you like. Contribute, spread the +word, and make one a standard. Languages such as Java and Python are +fortunate to have standard unit testing frameworks; it would be desirable +that C have one as well. + +@node Tutorial, Advanced Features, Unit Testing in C, Top +@chapter Tutorial: Basic Unit Testing + +This tutorial will use the JUnit +@uref{http://junit.sourceforge.net/doc/testinfected/testing.htm, Test +Infected} article as a starting point. We will be creating a library +to represent money, @code{libmoney}, that allows conversions between +different currency types. The development style will be ``test a +little, code a little'', with unit test writing preceding coding. +This constantly gives us insights into module usage, and also makes +sure we are constantly thinking about how to test our code. + +@menu +* How to Write a Test:: +* Setting Up the Money Build Using Autotools:: +* Setting Up the Money Build Using CMake:: +* Test a Little:: +* Creating a Suite:: +* SRunner Output:: +@end menu + +@node How to Write a Test, Setting Up the Money Build Using Autotools, Tutorial, Tutorial +@section How to Write a Test + +Test writing using Check is very simple. The file in which the checks +are defined must include @file{check.h} as so: +@example +@verbatim +#include +@end verbatim +@end example + +The basic unit test looks as follows: +@example +@verbatim +START_TEST (test_name) +{ + /* unit test code */ +} +END_TEST +@end verbatim +@end example + +The @code{START_TEST}/@code{END_TEST} pair are macros that setup basic +structures to permit testing. It is a mistake to leave off the +@code{END_TEST} marker; doing so produces all sorts of strange errors +when the check is compiled. + +@node Setting Up the Money Build Using Autotools, Setting Up the Money Build Using CMake, How to Write a Test, Tutorial +@section Setting Up the Money Build Using Autotools + +Since we are creating a library to handle money, we will first create +an interface in @file{money.h}, an implementation in @file{money.c}, +and a place to store our unit tests, @file{check_money.c}. We want to +integrate these core files into our build system, and will need some +additional structure. To manage everything we'll use Autoconf, +Automake, and friends (collectively known as Autotools) for this +example. Note that one could do something similar with ordinary +Makefiles, or any other build system. It is in the authors' opinion that +it is generally easier to use Autotools than bare Makefiles, and they +provide built-in support for running tests. + +Note that this is not the place to explain how Autotools works. If +you need help understanding what's going on beyond the explanations +here, the best place to start is probably Alexandre Duret-Lutz's +excellent +@uref{http://www.lrde.epita.fr/~adl/autotools.html, +Autotools tutorial}. + +The examples in this section are part of the Check distribution; you +don't need to spend time cutting and pasting or (worse) retyping them. +Locate the Check documentation on your system and look in the +@samp{example} directory. The standard directory for GNU/Linux +distributions should be @samp{/usr/share/doc/check/example}. This +directory contains the final version reached the end of the tutorial. If +you want to follow along, create backups of @file{money.h}, +@file{money.c}, and @file{check_money.c}, and then delete the originals. + +We set up a directory structure as follows: +@example +@verbatim +. +|-- Makefile.am +|-- README +|-- configure.ac +|-- src +| |-- Makefile.am +| |-- main.c +| |-- money.c +| `-- money.h +`-- tests + |-- Makefile.am + `-- check_money.c +@end verbatim +@end example + +Note that this is the output of @command{tree}, a great directory +visualization tool. The top-level @file{Makefile.am} is simple; it +merely tells Automake how to process sub-directories: +@example +@verbatim +SUBDIRS = src . tests +@end verbatim +@end example + +Note that @code{tests} comes last, because the code should be testing +an already compiled library. @file{configure.ac} is standard Autoconf +boilerplate, as specified by the Autotools tutorial and as suggested +by @command{autoscan}. + +@file{src/Makefile.am} builds @samp{libmoney} as a Libtool archive, +and links it to an application simply called @command{main}. The +application's behavior is not important to this tutorial; what's +important is that none of the functions we want to unit test appear in +@file{main.c}; this probably means that the only function in +@file{main.c} should be @code{main()} itself. In order to test the +whole application, unit testing is not appropriate: you should use a +system testing tool like Autotest. If you really want to test +@code{main()} using Check, rename it to something like +@code{_myproject_main()} and write a wrapper around it. + +The primary build instructions for our unit tests are in +@file{tests/Makefile.am}: + +@cartouche +@example +@verbatiminclude example/tests/Makefile.am +@end example +@end cartouche + +@code{TESTS} tells Automake which test programs to run for +@command{make check}. Similarly, the @code{check_} prefix in +@code{check_PROGRAMS} actually comes from Automake; it says to build +these programs only when @command{make check} is run. (Recall that +Automake's @code{check} target is the origin of Check's name.) The +@command{check_money} test is a program that we will build from +@file{tests/check_money.c}, linking it against both +@file{src/libmoney.la} and the installed @file{libcheck.la} on our +system. The appropriate compiler and linker flags for using Check are +found in @code{@@CHECK_CFLAGS@@} and @code{@@CHECK_LIBS@@}, values +defined by the @code{AM_PATH_CHECK} macro. + +Now that all this infrastructure is out of the way, we can get on with +development. @file{src/money.h} should only contain standard C header +boilerplate: + +@cartouche +@example +@verbatiminclude example/src/money.1.h +@end example +@end cartouche + +@file{src/money.c} should be empty, and @file{tests/check_money.c} +should only contain an empty @code{main()} function: + +@cartouche +@example +@verbatiminclude example/tests/check_money.1.c +@end example +@end cartouche + +Create the GNU Build System for the project and then build @file{main} +and @file{libmoney.la} as follows: +@example +@verbatim +$ autoreconf --install +$ ./configure +$ make +@end verbatim +@end example + +(@command{autoreconf} determines which commands are needed in order +for @command{configure} to be created or brought up to date. +Previously one would use a script called @command{autogen.sh} or +@command{bootstrap}, but that practice is unnecessary now.) + +Now build and run the @command{check_money} test with @command{make +check}. If all goes well, @command{make} should report that our tests +passed. No surprise, because there aren't any tests to fail. If you +have problems, make sure to see @ref{Supported Build Systems}. + +This was tested on the isadora distribution of Linux Mint +GNU/Linux in November 2012, using Autoconf 2.65, Automake 1.11.1, +and Libtool 2.2.6b. Please report any problems to +@email{check-devel AT lists.sourceforge.net}. + +@node Setting Up the Money Build Using CMake, Test a Little, Setting Up the Money Build Using Autotools, Tutorial +@section Setting Up the Money Build Using CMake + +Since we are creating a library to handle money, we will first create +an interface in @file{money.h}, an implementation in @file{money.c}, +and a place to store our unit tests, @file{check_money.c}. We want to +integrate these core files into our build system, and will need some +additional structure. To manage everything we'll use CMake for this +example. Note that one could do something similar with ordinary +Makefiles, or any other build system. It is in the authors' opinion that +it is generally easier to use CMake than bare Makefiles, and they +provide built-in support for running tests. + +Note that this is not the place to explain how CMake works. If +you need help understanding what's going on beyond the explanations +here, the best place to start is probably the @uref{http://www.cmake.org, +CMake project's homepage}. + +The examples in this section are part of the Check distribution; you +don't need to spend time cutting and pasting or (worse) retyping them. +Locate the Check documentation on your system and look in the +@samp{example} directory, or look in the Check source. If on a GNU/Linux +system the standard directory should be @samp{/usr/share/doc/check/example}. +This directory contains the final version reached the end of the tutorial. If +you want to follow along, create backups of @file{money.h}, +@file{money.c}, and @file{check_money.c}, and then delete the originals. + +We set up a directory structure as follows: +@example +@verbatim +. +|-- Makefile.am +|-- README +|-- CMakeLists.txt +|-- cmake +| |-- config.h.in +| |-- FindCheck.cmake +|-- src +| |-- CMakeLists.txt +| |-- main.c +| |-- money.c +| `-- money.h +`-- tests + |-- CMakeLists.txt + `-- check_money.c +@end verbatim +@end example + +The top-level @file{CMakeLists.txt} contains the configuration checks +for available libraries and types, and also defines sub-directories +to process. The @file{cmake/FindCheck.cmake} file contains instructions +for locating Check on the system and setting up the build to use it. +If the system does not have pkg-config installed, @file{cmake/FindCheck.cmake} +may not be able to locate Check successfully. In this case, the install +directory of Check must be located manually, and the following line +added to @file{tests/CMakeLists.txt} (assuming Check was installed under +C:\\Program Files\\check: + +@verbatim +set(CHECK_INSTALL_DIR "C:/Program Files/check") +@end verbatim + +Note that @code{tests} comes last, because the code should be testing +an already compiled library. + +@file{src/CMakeLists.txt} builds @samp{libmoney} as an archive, +and links it to an application simply called @command{main}. The +application's behavior is not important to this tutorial; what's +important is that none of the functions we want to unit test appear in +@file{main.c}; this probably means that the only function in +@file{main.c} should be @code{main()} itself. In order to test the +whole application, unit testing is not appropriate: you should use a +system testing tool like Autotest. If you really want to test +@code{main()} using Check, rename it to something like +@code{_myproject_main()} and write a wrapper around it. + +Now that all this infrastructure is out of the way, we can get on with +development. @file{src/money.h} should only contain standard C header +boilerplate: + +@cartouche +@example +@verbatiminclude example/src/money.1.h +@end example +@end cartouche + +@file{src/money.c} should be empty, and @file{tests/check_money.c} +should only contain an empty @code{main()} function: + +@cartouche +@example +@verbatiminclude example/tests/check_money.1.c +@end example +@end cartouche + +Create the CMake Build System for the project and then build @file{main} +and @file{libmoney.la} as follows for Unix-compatible systems: +@example +@verbatim +$ cmake . +$ make +@end verbatim +@end example + +and for MSVC on Windows: +@example +@verbatim +$ cmake -G "NMake Makefiles" . +$ nmake +@end verbatim +@end example + +Now build and run the @command{check_money} test, with either @command{make +test} on a Unix-compatible system or @command{nmake test} if on Windows using MSVC. +If all goes well, the command should report that our tests +passed. No surprise, because there aren't any tests to fail. + +This was tested on Windows 7 using CMake 2.8.12.1 and MSVC 16.00.30319.01/ +Visual Studios 10 in February 2014. Please report any problems to +@email{check-devel AT lists.sourceforge.net}. + +@node Test a Little, Creating a Suite, Setting Up the Money Build Using CMake, Tutorial +@section Test a Little, Code a Little + +The @uref{http://junit.sourceforge.net/doc/testinfected/testing.htm, +Test Infected} article starts out with a @code{Money} class, and so +will we. Of course, we can't do classes with C, but we don't really +need to. The Test Infected approach to writing code says that we +should write the unit test @emph{before} we write the code, and in +this case, we will be even more dogmatic and doctrinaire than the +authors of Test Infected (who clearly don't really get this stuff, +only being some of the originators of the Patterns approach to +software development and OO design). + +Here are the changes to @file{check_money.c} for our first unit test: + +@cartouche +@example +@verbatiminclude check_money.1-2.c.diff +@end example +@end cartouche + +@findex ck_assert_int_eq +@findex ck_assert_str_eq +A unit test should just chug along and complete. If it exits early, +or is signaled, it will fail with a generic error message. (Note: it +is conceivable that you expect an early exit, or a signal and there is +functionality in Check to specifically assert that we should expect a +signal or an early exit.) If we want to get some information +about what failed, we need to use some calls that will point out a failure. +Two such calls are @code{ck_assert_int_eq} (used to determine if two integers +are equal) and @code{ck_assert_str_eq} (used to determine if two null terminated +strings are equal). Both of these functions (actually macros) will signal an error +if their arguments are not equal. + +@findex ck_assert +An alternative to using @code{ck_assert_int_eq} and @code{ck_assert_str_eq} +is to write the expression under test directly using @code{ck_assert}. +This takes one Boolean argument which must be True for the check to pass. +The second test could be rewritten as follows: +@example +@verbatim +ck_assert(strcmp (money_currency (m), "USD") == 0); +@end verbatim +@end example + +@findex ck_assert_msg +@code{ck_assert} will find and report failures, but will not print any +user supplied message in the unit test result. To print a user defined +message along with any failures found, use @code{ck_assert_msg}. The first +argument is a Boolean argument. The remaining arguments support @code{varargs} +and accept @code{printf}-style format strings and arguments. This is especially +useful while debugging. For example, the second test could be rewritten as: +@example +@verbatim +ck_assert_msg(strcmp (money_currency (m), "USD") == 0, + "Was expecting a currency of USD, but found %s", money_currency (m)); +@end verbatim +@end example + +@findex ck_abort +@findex ck_abort_msg +If the Boolean argument is too complicated to elegantly express within +@code{ck_assert()}, there are the alternate functions @code{ck_abort()} +and @code{ck_abort_msg()} that unconditionally fail. The second test inside +@code{test_money_create} above could be rewritten as follows: +@example +@verbatim +if (strcmp (money_currency (m), "USD") != 0) + { + ck_abort_msg ("Currency not set correctly on creation"); + } +@end verbatim +@end example + +For your convenience ck_assert, which does not accept a user supplied message, +substitutes a suitable message for you. (This is also equivalent to +passing a NULL message to ck_assert_msg). So you could also +write a test as follows: +@example +@verbatim +ck_assert (money_amount (m) == 5); +@end verbatim +@end example + +This is equivalent to: +@example +@verbatim +ck_assert_msg (money_amount (m) == 5, NULL); +@end verbatim +@end example + +which will print the file, line number, and the message +@code{"Assertion 'money_amount (m) == 5' failed"} if +@code{money_amount (m) != 5}. + +When we try to compile and run the test suite now using @command{make +check}, we get a whole host of compilation errors. It may seem a bit +strange to deliberately write code that won't compile, but notice what +we are doing: in creating the unit test, we are also defining +requirements for the money interface. Compilation errors are, in a +way, unit test failures of their own, telling us that the +implementation does not match the specification. If all we do is edit +the sources so that the unit test compiles, we are actually making +progress, guided by the unit tests, so that's what we will now do. + +We will patch our header @file{money.h} as follows: + +@cartouche +@example +@verbatiminclude money.1-2.h.diff +@end example +@end cartouche + +Our code compiles now, and again passes all of the tests. However, +once we try to @emph{use} the functions in @code{libmoney} in the +@code{main()} of @code{check_money}, we'll run into more problems, as +they haven't actually been implemented yet. + +@node Creating a Suite, SRunner Output, Test a Little, Tutorial +@section Creating a Suite + +To run unit tests with Check, we must create some test cases, +aggregate them into a suite, and run them with a suite runner. That's +a bit of overhead, but it is mostly one-off. Here's a diff for the +new version of @file{check_money.c}. Note that we include stdlib.h to +get the definitions of @code{EXIT_SUCCESS} and @code{EXIT_FAILURE}. + +@cartouche +@example +@verbatiminclude check_money.2-3.c.diff +@end example +@end cartouche + +Most of the @code{money_suite()} code should be self-explanatory. We are +creating a suite, creating a test case, adding the test case to the +suite, and adding the unit test we created above to the test case. +Why separate this off into a separate function, rather than inline it +in @code{main()}? Because any new tests will get added in +@code{money_suite()}, but nothing will need to change in @code{main()} +for the rest of this example, so main will stay relatively clean and +simple. + +Unit tests are internally defined as static functions. This means +that the code to add unit tests to test cases must be in the same +compilation unit as the unit tests themselves. This provides another +reason to put the creation of the test suite in a separate function: +you may later want to keep one source file per suite; defining a +uniquely named suite creation function allows you later to define a +header file giving prototypes for all the suite creation functions, +and encapsulate the details of where and how unit tests are defined +behind those functions. See the test program defined for Check itself +for an example of this strategy. + +The code in @code{main()} bears some explanation. We are creating a +suite runner object of type @code{SRunner} from the @code{Suite} we +created in @code{money_suite()}. We then run the suite, using the +@code{CK_NORMAL} flag to specify that we should print a summary of the +run, and list any failures that may have occurred. We capture the +number of failures that occurred during the run, and use that to +decide how to return. The @code{check} target created by Automake +uses the return value to decide whether the tests passed or failed. + +Now that the tests are actually being run by @command{check_money}, we +encounter linker errors again we try out @code{make check}. Try it +for yourself and see. The reason is that the @file{money.c} +implementation of the @file{money.h} interface hasn't been created +yet. Let's go with the fastest solution possible and implement stubs +for each of the functions in @code{money.c}. Here is the diff: + +@cartouche +@example +@verbatiminclude money.1-3.c.diff +@end example +@end cartouche + +Note that we @code{#include } to get the definition of +@code{NULL}. Now, the code compiles and links when we run @code{make +check}, but our unit test fails. Still, this is progress, and we can +focus on making the test pass. + +@node SRunner Output, , Creating a Suite, Tutorial +@section SRunner Output + +@findex srunner_run_all +@findex srunner_run +The functions to run tests in an @code{SRunner} are defined as follows: +@example +@verbatim +void srunner_run_all (SRunner * sr, enum print_output print_mode); + +void srunner_run (SRunner *sr, const char *sname, const char *tcname, + enum print_output print_mode); +@end verbatim +@end example + +Those functions do two things: + +@enumerate +@item +They run all of the unit tests for the selected test cases defined for +the selected suites in the SRunner, and collect the results in the +SRunner. The determination of the selected test cases and suites +depends on the specific function used. + +@code{srunner_run_all} will run all the defined test cases of all +defined suites except if the environment variables @code{CK_RUN_CASE} +or @code{CK_RUN_SUITE} are defined. If defined, those variables shall +contain the name of a test suite or a test case, defining in that way +the selected suite/test case. + +@code{srunner_run} will run the suite/case selected by the +@code{sname} and @code{tcname} parameters. A value of @code{NULL} +in some of those parameters means ``any suite/case''. + +@item +They print the results according to the @code{print_mode} specified. +@end enumerate + +For SRunners that have already been run, there is also a separate +printing function defined as follows: +@example +@verbatim +void srunner_print (SRunner *sr, enum print_output print_mode); +@end verbatim +@end example + +The enumeration values of @code{print_output} defined in Check that +parameter @code{print_mode} can assume are as follows: + +@table @code +@vindex CK_SILENT +@item CK_SILENT +Specifies that no output is to be generated. If you use this flag, you +either need to programmatically examine the SRunner object, print +separately, or use test logging (@pxref{Test Logging}.) + +@vindex CK_MINIMAL +@item CK_MINIMAL +Only a summary of the test run will be printed (number run, passed, +failed, errors). + +@vindex CK_NORMAL +@item CK_NORMAL +Prints the summary of the run, and prints one message per failed +test. + +@vindex CK_VERBOSE +@item CK_VERBOSE +Prints the summary, and one message per test (passed or failed) + +@vindex CK_ENV +@vindex CK_VERBOSITY +@item CK_ENV +Gets the print mode from the environment variable @code{CK_VERBOSITY}, +which can have the values "silent", "minimal", "normal", "verbose". If +the variable is not found or the value is not recognized, the print +mode is set to @code{CK_NORMAL}. + +@vindex CK_SUBUNIT +@item CK_SUBUNIT +Prints running progress through the @uref{https://launchpad.net/subunit/, +subunit} test runner protocol. See 'subunit support' under the Advanced Features section for more information. +@end table + +With the @code{CK_NORMAL} flag specified in our @code{main()}, let's +rerun @code{make check} now. The output from the unit test is as follows: +@example +@verbatim +Running suite(s): Money +0%: Checks: 1, Failures: 1, Errors: 0 +check_money.c:9:F:Core:test_money_create:0: Assertion 'money_amount (m)==5' failed: +money_amount (m)==0, 5==5 +FAIL: check_money +===================================================== +1 of 1 test failed +Please report to check-devel AT lists.sourceforge.net +===================================================== +@end verbatim +@end example + +Note that the output from @code{make check} prior to Automake 1.13 will +be the output of the unit test program. Starting with 1.13 Automake will +run all unit test programs concurrently and store the output in +log files. The output listed above should be present in a log file. + +The first number in the summary line tells us that 0% of our tests +passed, and the rest of the line tells us that there was one check in +total, and of those checks, one failure and zero errors. The next +line tells us exactly where that failure occurred, and what kind of +failure it was (P for pass, F for failure, E for error). + +After that we have some higher level output generated by Automake: the +@code{check_money} program failed, and the bug-report address given in +@file{configure.ac} is printed. + +Let's implement the @code{money_amount} function, so that it will pass +its tests. We first have to create a Money structure to hold the +amount, and then implement the function to return the correct amount: + +@cartouche +@example +@verbatiminclude money.3-4.c.diff +@end example +@end cartouche + +We will now rerun make check and@dots{} what's this? The output is +now as follows: +@example +@verbatim +Running suite(s): Money +0%: Checks: 1, Failures: 0, Errors: 1 +check_money.c:5:E:Core:test_money_create:0: (after this point) +Received signal 11 (Segmentation fault) +@end verbatim +@end example + +@findex mark_point +What does this mean? Note that we now have an error, rather than a +failure. This means that our unit test either exited early, or was +signaled. Next note that the failure message says ``after this +point''; This means that somewhere after the point noted +(@file{check_money.c}, line 5) there was a problem: signal 11 (a.k.a. +segmentation fault). The last point reached is set on entry to the +unit test, and after every call to the @code{ck_assert()}, +@code{ck_abort()}, @code{ck_assert_int_*()}, @code{ck_assert_str_*()}, +or the special function @code{mark_point()}. For example, if we wrote some test +code as follows: +@example +@verbatim +stuff_that_works (); +mark_point (); +stuff_that_dies (); +@end verbatim +@end example + +then the point returned will be that marked by @code{mark_point()}. + +The reason our test failed so horribly is that we haven't implemented +@code{money_create()} to create any @code{Money}. We'll go ahead and +implement that, the symmetric @code{money_free()}, and +@code{money_currency()} too, in order to make our unit test pass again, +here is a diff: + +@cartouche +@example +@verbatiminclude money.4-5.c.diff +@end example +@end cartouche + +@node Advanced Features, Supported Build Systems, Tutorial, Top +@chapter Advanced Features + +What you've seen so far is all you need for basic unit testing. The +features described in this section are additions to Check that make it +easier for the developer to write, run, and analyze tests. + +@menu +* Convenience Test Functions:: +* Running Multiple Cases:: +* No Fork Mode:: +* Test Fixtures:: +* Multiple Suites in one SRunner:: +* Selective Running of Tests:: +* Selecting Tests by Suite or Test Case:: +* Selecting Tests Based on Arbitrary Tags:: +* Testing Signal Handling and Exit Values:: +* Looping Tests:: +* Test Timeouts:: +* Determining Test Coverage:: +* Finding Memory Leaks:: +* Test Logging:: +* Subunit Support:: +@end menu + +@node Convenience Test Functions, Running Multiple Cases, Advanced Features, Advanced Features +@section Convenience Test Functions + +Using the @code{ck_assert} function for all tests can lead to lot of +repetitive code that is hard to read. For your convenience Check +provides a set of functions (actually macros) for testing often used +conditions. + +@findex check_set_max_msg_size +@vindex CK_MAX_MSG_SIZE +The typical size of an assertion message is less than 80 bytes. +However, some of the functions listed below can generate very large messages +(up to 4GB allocations were seen in the wild). +To prevent this, a limit is placed on the assertion message size. +This limit is 4K bytes by default. +It can be modified by setting the @code{CK_MAX_MSG_SIZE} environment variable, +or, if it is not set, by invoking the @code{check_set_max_msg_size()} function. +If used, this function must be called, once, before the first assertion. + +@ftable @code +@item ck_abort +Unconditionally fails test with default message. + +@item ck_abort_msg +Unconditionally fails test with user supplied message. + +@item ck_assert +Fails test if supplied condition evaluates to false. + +@item ck_assert_msg +Fails test if supplied condition evaluates to false and displays user +provided message. + +@item ck_assert_int_eq +@itemx ck_assert_int_ne +@itemx ck_assert_int_lt +@itemx ck_assert_int_le +@itemx ck_assert_int_gt +@itemx ck_assert_int_ge + +Compares two signed integer values (@code{intmax_t}) and displays a predefined +message with both the condition and input parameters on failure. The +operator used for comparison is different for each function and is indicated +by the last two letters of the function name. The abbreviations @code{eq}, +@code{ne}, @code{lt}, @code{le}, @code{gt}, and @code{ge} correspond to +@code{==}, @code{!=}, @code{<}, @code{<=}, @code{>}, and @code{>=} +respectively. + +@item ck_assert_uint_eq +@itemx ck_assert_uint_ne +@itemx ck_assert_uint_lt +@itemx ck_assert_uint_le +@itemx ck_assert_uint_gt +@itemx ck_assert_uint_ge + +Similar to @code{ck_assert_int_*}, but compares two unsigned integer values +(@code{uintmax_t}) instead. + +@item ck_assert_float_eq +@itemx ck_assert_float_ne +@itemx ck_assert_float_lt +@itemx ck_assert_float_le +@itemx ck_assert_float_gt +@itemx ck_assert_float_ge + +Compares two floating point numbers (@code{float}) and displays a predefined +message with both the condition and input parameters on failure. +The operator used for comparison is different for each function +and is indicated by the last two letters of the function name. +The abbreviations @code{eq}, @code{ne}, @code{lt}, @code{le}, @code{gt}, +and @code{ge} correspond to @code{==}, @code{!=}, @code{<}, @code{<=}, @code{>}, +and @code{>=} respectively. +Beware using those operators for floating point numbers because of precision +possible loss on every operation on floating point numbers. For example +(1/3)*3==1 would return false, because 1/3==1.333... (or 1.(3) notation +in Europe) and cannot be represented by computer logic. As another example +1.1f in fact could be 1.10000002384185791015625 and 2.1f could be +2.099999904632568359375 because of binary representation of floating +point numbers. +If you have different mathematical operations used on floating point numbers +consider using precision comparisons or integer numbers instead. But in some +cases those operators could be used. For example if you cyclically increment +your floating point number only by positive or only by negative values than +you may use @code{<}, @code{<=}, @code{>} and @code{>=} operators in tests. +If your computations must end up with a certain value than @code{==} and +@code{!=} operators may be used. + +@item ck_assert_double_eq +@itemx ck_assert_double_ne +@itemx ck_assert_double_lt +@itemx ck_assert_double_le +@itemx ck_assert_double_gt +@itemx ck_assert_double_ge + +Similar to @code{ck_assert_float_*}, but compares two double precision +floating point values (@code{double}) instead. + +@item ck_assert_ldouble_eq +@itemx ck_assert_ldouble_ne +@itemx ck_assert_ldouble_lt +@itemx ck_assert_ldouble_le +@itemx ck_assert_ldouble_gt +@itemx ck_assert_ldouble_ge + +Similar to @code{ck_assert_float_*}, but compares two double precision +floating point values (@code{long double}) instead. + +@item ck_assert_float_eq_tol +@itemx ck_assert_float_ne_tol +@itemx ck_assert_float_le_tol +@itemx ck_assert_float_ge_tol + +Compares two floating point numbers (@code{float}) with specified user tolerance +set by the third parameter (@code{float}) and displays a predefined message +with both the condition and input parameters on failure. +The abbreviations @code{eq}, @code{ne}, @code{le}, and @code{ge} correspond +to @code{==}, @code{!=}, @code{<=}, and @code{>=} respectively with acceptable +error (tolerance) specified by the last parameter. +Beware using those functions for floating comparisons because of +(1) errors coming from floating point number representation, +(2) rounding errors, +(3) floating point errors are platform dependent. +Floating point numbers are often internally represented in binary +so they cannot be exact power of 10. All these operators have significant +error in comparisons so use them only if you know what you're doing. +Some assertions could fail on one platform and would be passed on another. +For example expression @code{0.02<=0.01+10^-2} is true by meaning, +but some platforms may calculate it as false. IEEE 754 standard specifies +the floating point number format representation but it does not promise that +the same computation carried out on all hardware will produce the same result. + +@item ck_assert_double_eq_tol +@itemx ck_assert_double_ne_tol +@itemx ck_assert_double_le_tol +@itemx ck_assert_double_ge_tol + +Similar to @code{ck_assert_float_*_tol}, but compares two double precision +floating point values (@code{double}) instead. + +@item ck_assert_ldouble_eq_tol +@itemx ck_assert_ldouble_ne_tol +@itemx ck_assert_ldouble_le_tol +@itemx ck_assert_ldouble_ge_tol + +Similar to @code{ck_assert_float_*_tol}, but compares two double precision +floating point values (@code{long double}) instead. + +@item ck_assert_float_finite + +Checks that a floating point number (@code{float}) is finite and displays +a predefined message with both the condition and input parameter on failure. +Finite means that value cannot be positive infinity, negative infinity +or NaN ("Not a Number"). + +@item ck_assert_double_finite + +Similar to @code{ck_assert_float_finite}, but checks double precision +floating point value (@code{double}) instead. + + +@item ck_assert_ldouble_finite + +Similar to @code{ck_assert_float_finite}, but checks double precision +floating point value (@code{long double}) instead. + +@item ck_assert_float_infinite + +Checks that a floating point number (@code{float}) is infinite and displays +a predefined message with both the condition and input parameter on failure. +Infinite means that value may only be positive infinity or negative infinity. + +@item ck_assert_double_infinite + +Similar to @code{ck_assert_float_infinite}, but checks double precision +floating point value (@code{double}) instead. + +@item ck_assert_ldouble_infinite + +Similar to @code{ck_assert_float_infinite}, but checks double precision +floating point value (@code{long double}) instead. + +@item ck_assert_float_nan + +Checks that a floating point number (@code{float}, @code{double} or +@code{long double} abbreviated as @code{ldouble}) is NaN ("Not a Number") +and displays a predefined message with both the condition and input parameter +on failure. + +@item ck_assert_double_nan + +Similar to @code{ck_assert_float_nan}, but checks double precision +floating point value (@code{double}) instead. + +@item ck_assert_ldouble_nan + +Similar to @code{ck_assert_float_nan}, but checks double precision +floating point value (@code{long double}) instead. + +@item ck_assert_float_nonnan + +Checks that a floating point number (@code{float}) is not NaN ("Not a Number") +and displays a predefined message with both the condition and input parameter +on failure. + +@item ck_assert_double_nonnan + +Similar to @code{ck_assert_float_nonnan}, but checks double precision +floating point value (@code{double}) instead. + +@item ck_assert_ldouble_nonnan + +Similar to @code{ck_assert_float_nonnan}, but checks double precision +floating point value (@code{long double}) instead. + + +@item ck_assert_str_eq +@itemx ck_assert_str_ne +@itemx ck_assert_str_lt +@itemx ck_assert_str_le +@itemx ck_assert_str_gt +@itemx ck_assert_str_ge + +Compares two null-terminated @code{char *} string values, using the +@code{strcmp()} function internally, and displays predefined message +with condition and input parameter values on failure. The comparison +operator is again indicated by last two letters of the function name. +@code{ck_assert_str_lt(a, b)} will pass if the unsigned numerical value +of the character string @code{a} is less than that of @code{b}. +If a NULL pointer is be passed to any comparison macro the check will fail. + +@item ck_assert_pstr_eq +@itemx ck_assert_pstr_ne + +Similar to @code{ck_assert_str_*} macros, but able to check undefined strings. +If a NULL pointer would be passed to a comparison macro it would mean that +a string is undefined. If both strings are undefined @code{ck_assert_pstr_eq} +would pass, but @code{ck_assert_pstr_ne} would fail. If only one of strings is +undefined @code{ck_assert_pstr_eq} macro would fail and @code{ck_assert_pstr_ne} +would pass. + +@item ck_assert_ptr_eq +@itemx ck_assert_ptr_ne + +Compares two pointers and displays predefined message with +condition and values of both input parameters on failure. The operator +used for comparison is different for each function and is indicated by +the last two letters of the function name. The abbreviations @code{eq} and +@code{ne} correspond to @code{==} and @code{!=} respectively. + +@item ck_assert_ptr_null +@itemx ck_assert_ptr_nonnull + +Compares a pointers against null and displays predefined message with +condition and value of the input parameter on failure. +@code{ck_assert_ptr_null} checks that pointer is equal to NULL and +@code{ck_assert_ptr_nonnull} checks that pointer is not equal to NULL. +@code{ck_assert_ptr_nonnull} is highly recommended to use in situations +when a function call can return NULL as error indication (like functions +that use malloc, calloc, strdup, mmap, etc). + +@item ck_assert_mem_eq +@itemx ck_assert_mem_ne +@itemx ck_assert_mem_lt +@itemx ck_assert_mem_le +@itemx ck_assert_mem_gt +@itemx ck_assert_mem_ge + +Compares contents of two memory locations of the given length, using the +@code{memcmp()} function internally, and displays predefined message +with condition and input parameter values on failure. The comparison +operator is again indicated by last two letters of the function name. +@code{ck_assert_mem_lt(a, b)} will pass if the unsigned numerical value +of memory location @code{a} is less than that of @code{b}. + +@item fail +(Deprecated) Unconditionally fails test with user supplied message. + +@item fail_if +(Deprecated) Fails test if supplied condition evaluates to true and +displays user provided message. + +@item fail_unless +(Deprecated) Fails test if supplied condition evaluates to false and +displays user provided message. + + +@end ftable + +@node Running Multiple Cases, No Fork Mode, Convenience Test Functions, Advanced Features +@section Running Multiple Cases + +What happens if we pass @code{-1} as the @code{amount} in +@code{money_create()}? What should happen? Let's write a unit test. +Since we are now testing limits, we should also test what happens when +we create @code{Money} where @code{amount == 0}. Let's put these in a +separate test case called ``Limits'' so that @code{money_suite} is +changed like so: + +@cartouche +@example +@verbatiminclude check_money.3-6.c.diff +@end example +@end cartouche + +Now we can rerun our suite, and fix the problem(s). Note that errors +in the ``Core'' test case will be reported as ``Core'', and errors in +the ``Limits'' test case will be reported as ``Limits'', giving you +additional information about where things broke. + +@cartouche +@example +@verbatiminclude money.5-6.c.diff +@end example +@end cartouche + +@node No Fork Mode, Test Fixtures, Running Multiple Cases, Advanced Features +@section No Fork Mode + +Check normally forks to create a separate address space. This allows +a signal or early exit to be caught and reported, rather than taking +down the entire test program, and is normally very useful. However, +when you are trying to debug why the segmentation fault or other +program error occurred, forking makes it difficult to use debugging +tools. To define fork mode for an @code{SRunner} object, you can do +one of the following: + +@vindex CK_FORK +@findex srunner_set_fork_status +@enumerate +@item +Define the CK_FORK environment variable to equal ``no''. + +@item +Explicitly define the fork status through the use of the following +function: + +@verbatim +void srunner_set_fork_status (SRunner * sr, enum fork_status fstat); +@end verbatim +@end enumerate + +The enum @code{fork_status} allows the @code{fstat} parameter to +assume the following values: @code{CK_FORK} and @code{CK_NOFORK}. An +explicit call to @code{srunner_set_fork_status()} overrides the +@code{CK_FORK} environment variable. + +@node Test Fixtures, Multiple Suites in one SRunner, No Fork Mode, Advanced Features +@section Test Fixtures + +We may want multiple tests that all use the same Money. In such +cases, rather than setting up and tearing down objects for each unit +test, it may be convenient to add some setup that is constant across +all the tests in a test case. Each such setup/teardown pair is called +a @dfn{test fixture} in test-driven development jargon. + +A fixture is created by defining a setup and/or a teardown function, +and associating it with a test case. There are two kinds of test +fixtures in Check: checked and unchecked fixtures. These are defined +as follows: + +@table @asis +@item Checked fixtures +are run inside the address space created by the fork to create the +unit test. Before each unit test in a test case, the @code{setup()} +function is run, if defined. After each unit test, the +@code{teardown()} function is run, if defined. Since they run inside +the forked address space, if checked fixtures signal or otherwise +fail, they will be caught and reported by the @code{SRunner}. A +checked @code{teardown()} fixture will not run if the unit test +fails. + +@item Unchecked fixtures +are run in the same address space as the test program. Therefore they +may not signal or exit, but may use the fail functions. The unchecked +@code{setup()}, if defined, is run before the test case is +started. The unchecked @code{teardown()}, if defined, is run after the +test case is done. An unchecked @code{teardown()} fixture will run even +if a unit test fails. +@end table + +An important difference is that the checked fixtures are run once per +unit test and the unchecked fixtures are run once per test case. +So for a test case that contains @code{check_one()} and +@code{check_two()} unit tests, +@code{checked_setup()}/@code{checked_teardown()} checked fixtures, and +@code{unchecked_setup()}/@code{unchecked_teardown()} unchecked +fixtures, the control flow would be: +@example +@verbatim +unchecked_setup(); +fork(); +checked_setup(); +check_one(); +checked_teardown(); +wait(); +fork(); +checked_setup(); +check_two(); +checked_teardown(); +wait(); +unchecked_teardown(); +@end verbatim +@end example + +@menu +* Test Fixture Examples:: +* Checked vs Unchecked Fixtures:: +@end menu + +@node Test Fixture Examples, Checked vs Unchecked Fixtures, Test Fixtures, Test Fixtures +@subsection Test Fixture Examples + +We create a test fixture in Check as follows: + +@enumerate +@item +Define global variables, and functions to setup and teardown the +globals. The functions both take @code{void} and return @code{void}. +In our example, we'll make @code{five_dollars} be a global created and +freed by @code{setup()} and @code{teardown()} respectively. + +@item +@findex tcase_add_checked_fixture +Add the @code{setup()} and @code{teardown()} functions to the test +case with @code{tcase_add_checked_fixture()}. In our example, this +belongs in the suite setup function @code{money_suite}. + +@item +Rewrite tests to use the globals. We'll rewrite our first to use +@code{five_dollars}. +@end enumerate + +Note that the functions used for setup and teardown do not need to be +named @code{setup()} and @code{teardown()}, but they must take +@code{void} and return @code{void}. We'll update @file{check_money.c} +with the following patch: + +@cartouche +@example +@verbatiminclude check_money.6-7.c.diff +@end example +@end cartouche + +@node Checked vs Unchecked Fixtures, , Test Fixture Examples, Test Fixtures +@subsection Checked vs Unchecked Fixtures + +Checked fixtures run once for each unit test in a test case, and so +they should not be used for expensive setup. However, if a checked +fixture fails and @code{CK_FORK} mode is being used, it will not bring +down the entire framework. + +On the other hand, unchecked fixtures run once for an entire test +case, as opposed to once per unit test, and so can be used for +expensive setup. However, since they may take down the entire test +program, they should only be used if they are known to be safe. + +Additionally, the isolation of objects created by unchecked fixtures +is not guaranteed by @code{CK_NOFORK} mode. Normally, in +@code{CK_FORK} mode, unit tests may abuse the objects created in an +unchecked fixture with impunity, without affecting other unit tests in +the same test case, because the fork creates a separate address space. +However, in @code{CK_NOFORK} mode, all tests live in the same address +space, and side effects in one test will affect the unchecked fixture +for the other tests. + +A checked fixture will generally not be affected by unit test side +effects, since the @code{setup()} is run before each unit test. There +is an exception for side effects to the total environment in which the +test program lives: for example, if the @code{setup()} function +initializes a file that a unit test then changes, the combination of +the @code{teardown()} function and @code{setup()} function must be able +to restore the environment for the next unit test. + +If the @code{setup()} function in a fixture fails, in either checked +or unchecked fixtures, the unit tests for the test case, and the +@code{teardown()} function for the fixture will not be run. A fixture +error will be created and reported to the @code{SRunner}. + +@node Multiple Suites in one SRunner, Selective Running of Tests, Test Fixtures, Advanced Features +@section Multiple Suites in one SRunner + +In a large program, it will be convenient to create multiple suites, +each testing a module of the program. While one can create several +test programs, each running one @code{Suite}, it may be convenient to +create one main test program, and use it to run multiple suites. The +Check test suite provides an example of how to do this. The main +testing program is called @code{check_check}, and has a header file +that declares suite creation functions for all the module tests: +@example +@verbatim +Suite *make_sub_suite (void); +Suite *make_sub2_suite (void); +Suite *make_master_suite (void); +Suite *make_list_suite (void); +Suite *make_msg_suite (void); +Suite *make_log_suite (void); +Suite *make_limit_suite (void); +Suite *make_fork_suite (void); +Suite *make_fixture_suite (void); +Suite *make_pack_suite (void); +@end verbatim +@end example + +@findex srunner_add_suite +The function @code{srunner_add_suite()} is used to add additional +suites to an @code{SRunner}. Here is the code that sets up and runs +the @code{SRunner} in the @code{main()} function in +@file{check_check_main.c}: +@example +@verbatim +SRunner *sr; +sr = srunner_create (make_master_suite ()); +srunner_add_suite (sr, make_list_suite ()); +srunner_add_suite (sr, make_msg_suite ()); +srunner_add_suite (sr, make_log_suite ()); +srunner_add_suite (sr, make_limit_suite ()); +srunner_add_suite (sr, make_fork_suite ()); +srunner_add_suite (sr, make_fixture_suite ()); +srunner_add_suite (sr, make_pack_suite ()); +@end verbatim +@end example + +@node Selective Running of Tests, Testing Signal Handling and Exit Values, Multiple Suites in one SRunner, Advanced Features + +@section Selective Running of Tests + +After adding a couple of suites and some test cases in each, it is +sometimes practical to be able to run only one suite, or one specific +test case, without recompiling the test code. Check provides two ways +to accomplish this, either by specifying a suite or test case by name +or by assigning tags to test cases and specifying one or more tags to +run. + +@menu +* Selecting Tests by Suite or Test Case:: +* Selecting Tests Based on Arbitrary Tags:: +@end menu + +@node Selecting Tests by Suite or Test Case, Selecting Tests Based on Arbitrary Tags, Selective Running of Tests, Selective Running of Tests +@subsection Selecting Tests by Suite or Test Case + +@vindex CK_RUN_SUITE +@vindex CK_RUN_CASE + +There are two environment variables available that offer this +ability, @code{CK_RUN_SUITE} and @code{CK_RUN_CASE}. Just set the +value to the name of the suite and/or test case you want to run. These +environment variables can also be a good integration tool for running +specific tests from within another tool, e.g. an IDE. + +@node Selecting Tests Based on Arbitrary Tags, ,Selecting Tests by Suite or Test Case, Selective Running of Tests +@subsection Selecting Tests Based on Arbitrary Tags + +@vindex CK_INCLUDE_TAGS +@vindex CK_EXCLUDE_TAGS + +It can be useful to dynamically include or exclude groups of tests to +be run based on criteria other than the suite or test case name. For +example, one or more tags can be assigned to test cases. The tags +could indicate if a test runs for a long time, so such tests could be +excluded in order to run quicker tests for a sanity +check. Alternately, tags may be used to indicate which functional +areas test cover. Tests can then be run that include all test cases +for a given set of functional areas. + +In Check, a tag is a string of characters without white space. One or +more tags can be assigned to a test case by using the +@code{tcase_set_tags} function. This function accepts a string, and +multiple tags can be specified by delimiting them with spaces. For +example: + +@example +@verbatim + Suite *s; + + TCase *red, *blue, *purple, *yellow, *black; + + s = suite_create("Check Tag Filtering"); + + red = tcase_create("Red"); + tcase_set_tags(red, "Red"); + suite_add_tcase (s, red); + tcase_add_test(red, red_test1); + + blue = tcase_create("Blue"); + tcase_set_tags(blue, "Blue"); + suite_add_tcase (s, blue); + tcase_add_test(blue, blue_test1); + + purple = tcase_create("Purple"); + tcase_set_tags(purple, "Red Blue"); + suite_add_tcase (s, purple); + tcase_add_test(purple, purple_test1); + +@end verbatim +@end example + +Once test cases are tagged they may be selectively run in one of two ways: + +a) Using Environment Variables + +There are two environment variables available for selecting test cases +based on tags: @code{CK_INCLUDE_TAGS} and +@code{CK_EXCLUDE_TAGS}. These can be set to a space separated list of +tag names. If @code{CK_INCLUDE_TAGS} is set then test cases which +include at least one tag in common with @code{CK_INCLUDE_TAGS} will be +run. If @code{CK_EXCLUDE_TAGS} is set then test cases with one tag in +common with @code{CK_EXCLUDE_TAGS} will not be run. In cases where +both @code{CK_INCLUDE_TAGS} and @code{CK_EXCLUDE_TAGS} match a tag for +a test case the test will be excluded. + +Both @code{CK_INCLUDE_TAGS} and @code{CK_EXCLUDE_TAGS} can be +specified in conjunction with @code{CK_RUN_SUITE} or even +@code{CK_RUN_CASE} in which case they will have the effect of further +narrowing the selection. + +b) Programmatically + +The @code{srunner_run_tagged} function allows one to specify which +tags to run or exclude from a suite runner. This can be used to +programmatically control which test cases may run. + +@node Testing Signal Handling and Exit Values, Looping Tests, Selective Running of Tests, Advanced Features +@section Testing Signal Handling and Exit Values + +@findex tcase_add_test_raise_signal + +To enable testing of signal handling, there is a function +@code{tcase_add_test_raise_signal()} which is used instead of +@code{tcase_add_test()}. This function takes an additional signal +argument, specifying a signal that the test expects to receive. If no +signal is received this is logged as a failure. If a different signal +is received this is logged as an error. + +The signal handling functionality only works in CK_FORK mode. + +@findex tcase_add_exit_test + +To enable testing of expected exits, there is a function +@code{tcase_add_exit_test()} which is used instead of @code{tcase_add_test()}. +This function takes an additional expected exit value argument, +specifying a value that the test is expected to exit with. If the test +exits with any other value this is logged as a failure. If the test exits +early this is logged as an error. + +The exit handling functionality only works in CK_FORK mode. + +@node Looping Tests, Test Timeouts, Testing Signal Handling and Exit Values, Advanced Features +@section Looping Tests + +Looping tests are tests that are called with a new context for each +loop iteration. This makes them ideal for table based tests. If +loops are used inside ordinary tests to test multiple values, only the +first error will be shown before the test exits. However, looping +tests allow for all errors to be shown at once, which can help out +with debugging. + +@findex tcase_add_loop_test +Adding a normal test with @code{tcase_add_loop_test()} instead of +@code{tcase_add_test()} will make the test function the body of a +@code{for} loop, with the addition of a fork before each call. The +loop variable @code{_i} is available for use inside the test function; +for example, it could serve as an index into a table. For failures, +the iteration which caused the failure is available in error messages +and logs. + +Start and end values for the loop are supplied when adding the test. +The values are used as in a normal @code{for} loop. Below is some +pseudo-code to show the concept: +@example +@verbatim +for (_i = tfun->loop_start; _i < tfun->loop_end; _i++) +{ + fork(); /* New context */ + tfun->f(_i); /* Call test function */ + wait(); /* Wait for child to terminate */ +} +@end verbatim +@end example + +An example of looping test usage follows: +@example +@verbatim +static const int primes[5] = {2,3,5,7,11}; + +START_TEST (check_is_prime) +{ + ck_assert (is_prime (primes[_i])); +} +END_TEST + +... + +tcase_add_loop_test (tcase, check_is_prime, 0, 5); +@end verbatim +@end example + +Looping tests work in @code{CK_NOFORK} mode as well, but without the +forking. This means that only the first error will be shown. + +@node Test Timeouts, Determining Test Coverage, Looping Tests, Advanced Features +@section Test Timeouts + +@findex tcase_set_timeout +@vindex CK_DEFAULT_TIMEOUT +@vindex CK_TIMEOUT_MULTIPLIER +To be certain that a test won't hang indefinitely, all tests are run +with a timeout, the default being 4 seconds. If the test is not +finished within that time, it is killed and logged as an error. + +The timeout for a specific test case, which may contain multiple unit +tests, can be changed with the @code{tcase_set_timeout()} function. +The default timeout used for all test cases can be changed with the +environment variable @code{CK_DEFAULT_TIMEOUT}, but this will not +override an explicitly set timeout. Another way to change the timeout +length is to use the @code{CK_TIMEOUT_MULTIPLIER} environment variable, +which multiplies all timeouts, including those set with +@code{tcase_set_timeout()}, with the supplied integer value. All timeout +arguments are in seconds and a timeout of 0 seconds turns off the timeout +functionality. On systems that support it, the timeout can be specified +using a nanosecond precision. Otherwise, second precision is used. + +Test timeouts are only available in CK_FORK mode. + +@node Determining Test Coverage, Finding Memory Leaks, Test Timeouts, Advanced Features +@section Determining Test Coverage + +The term @dfn{code coverage} refers to the extent that the statements +of a program are executed during a run. Thus, @dfn{test coverage} +refers to code coverage when executing unit tests. This information +can help you to do two things: + +@itemize +@item +Write better tests that more fully exercise your code, thereby +improving confidence in it. + +@item +Detect dead code that could be factored away. +@end itemize + +Check itself does not provide any means to determine this test +coverage; rather, this is the job of the compiler and its related +tools. In the case of @command{gcc} this information is easy to +obtain, and other compilers should provide similar facilities. + +Using @command{gcc}, first enable test coverage profiling when +building your source by specifying the @option{-fprofile-arcs} and +@option{-ftest-coverage} switches: +@example +@verbatim +$ gcc -g -Wall -fprofile-arcs -ftest-coverage -o foo foo.c foo_check.c +@end verbatim +@end example + +You will see that an additional @file{.gcno} file is created for each +@file{.c} input file. After running your tests the normal way, a +@file{.gcda} file is created for each @file{.gcno} file. These +contain the coverage data in a raw format. To combine this +information and a source file into a more readable format you can use +the @command{gcov} utility: +@example +@verbatim +$ gcov foo.c +@end verbatim +@end example + +This will produce the file @file{foo.c.gcov} which looks like this: +@example +@verbatim + -: 41: * object */ + 18: 42: if (ht->table[p] != NULL) { + -: 43: /* replaces the current entry */ + #####: 44: ht->count--; + #####: 45: ht->size -= ht->table[p]->size + + #####: 46: sizeof(struct hashtable_entry); +@end verbatim +@end example + +As you can see this is an annotated source file with three columns: +usage information, line numbers, and the original source. The usage +information in the first column can either be '-', which means that +this line does not contain code that could be executed; '#####', which +means this line was never executed although it does contain +code---these are the lines that are probably most interesting for you; +or a number, which indicates how often that line was executed. + +This is of course only a very brief overview, but it should illustrate +how determining test coverage generally works, and how it can help +you. For more information or help with other compilers, please refer +to the relevant manuals. + +@node Finding Memory Leaks, Test Logging, Determining Test Coverage, Advanced Features +@section Finding Memory Leaks + +It is possible to determine if any code under test leaks memory during +a test. Check itself does not have an API for memory leak detection, +however Valgrind can be used against a unit testing program to search +for potential leaks. + +Before discussing memory leak detection, first a "memory leak" should be +better defined. There are two primary definitions of a memory leak: + +@enumerate +@item +Memory that is allocated but not freed before a program terminates. +However, it was possible for the program to free the memory if it had +wanted to. Valgrind refers to these as "still reachable" leaks. +@item +Memory that is allocated, and any reference to the memory is lost. +The program could not have freed the memory. Valgrind refers to these +as "definitely lost" leaks. +@end enumerate + +Valgrind uses the second definition by default when defining a memory leak. +These leaks are the ones which are likely to cause a program issues due +to heap depletion. + +If one wanted to run Valgrind against a unit testing program to determine +if leaks are present, the following invocation of Valgrind will work: + +@example +@verbatim +valgrind --leak-check=full ${UNIT_TEST_PROGRAM} +... +==3979== LEAK SUMMARY: +==3979== definitely lost: 0 bytes in 0 blocks +==3979== indirectly lost: 0 bytes in 0 blocks +==3979== possibly lost: 0 bytes in 0 blocks +==3979== still reachable: 548 bytes in 24 blocks +==3979== suppressed: 0 bytes in 0 blocks +@end verbatim +@end example + +In that example, there were no "definitely lost" memory leaks found. +However, why would there be such a large number of "still reachable" +memory leaks? It turns out this is a consequence of using @code{fork()} +to run a unit test in its own process memory space, which Check does by +default on platforms with @code{fork()} available. + +Consider the example where a unit test program creates one suite with +one test. The flow of the program will look like the following: + +@example +@b{Main process:} @b{Unit test process:} +create suite +srunner_run_all() + fork unit test unit test process created + wait for test start test + ... end test + ... exit(0) + test complete +report result +free suite +exit(0) +@end example + +The unit testing process has a copy of all memory that the main process +allocated. In this example, that would include the suite allocated in +main. When the unit testing process calls @code{exit(0)}, the suite +allocated in @code{main()} is reachable but not freed. As the unit test +has no reason to do anything besides die when its test is finished, and +it has no reasonable way to free everything before it dies, Valgrind +reports that some memory is still reachable but not freed. + +If the "still reachable" memory leaks are a concern, and one required that +the unit test program report that there were no memory leaks regardless +of the type, then the unit test program needs to run without fork. To +accomplish this, either define the @code{CK_FORK=no} environment variable, +or use the @code{srunner_set_fork_status()} function to set the fork mode +as @code{CK_NOFORK} for all suite runners. + +Running the same unit test program by disabling @code{fork()} results +in the following: + +@example +@verbatim +CK_FORK=no valgrind --leak-check=full ${UNIT_TEST_PROGRAM} +... +==4924== HEAP SUMMARY: +==4924== in use at exit: 0 bytes in 0 blocks +==4924== total heap usage: 482 allocs, 482 frees, 122,351 bytes allocated +==4924== +==4924== All heap blocks were freed -- no leaks are possible +@end verbatim +@end example + +@node Test Logging, Subunit Support, Finding Memory Leaks, Advanced Features +@section Test Logging + +@findex srunner_set_log +Check supports an operation to log the results of a test run. To use +test logging, call the @code{srunner_set_log()} function with the name +of the log file you wish to create: +@example +@verbatim +SRunner *sr; +sr = srunner_create (make_s1_suite ()); +srunner_add_suite (sr, make_s2_suite ()); +srunner_set_log (sr, "test.log"); +srunner_run_all (sr, CK_NORMAL); +@end verbatim +@end example + +In this example, Check will write the results of the run to +@file{test.log}. The @code{print_mode} argument to +@code{srunner_run_all()} is ignored during test logging; the log will +contain a result entry, organized by suite, for every test run. Here +is an example of test log output: +@example +@verbatim +Running suite S1 +ex_log_output.c:8:P:Core:test_pass: Test passed +ex_log_output.c:14:F:Core:test_fail: Failure +ex_log_output.c:18:E:Core:test_exit: (after this point) Early exit +with return value 1 +Running suite S2 +ex_log_output.c:26:P:Core:test_pass2: Test passed +Results for all suites run: +50%: Checks: 4, Failures: 1, Errors: 1 +@end verbatim +@end example + +Another way to enable test logging is to use the @code{CK_LOG_FILE_NAME} +environment variable. When set tests will be logged to the specified file name. +If log file is specified with both @code{CK_LOG_FILE_NAME} and +@code{srunner_set_log()}, the name provided to @code{srunner_set_log()} will +be used. + +If the log name is set to "-" either via @code{srunner_set_log()} or +@code{CK_LOG_FILE_NAME}, the log data will be printed to stdout instead +of to a file. + + +@menu +* XML Logging:: +* TAP Logging:: +@end menu + +@node XML Logging, , Test Logging, Test Logging +@subsection XML Logging + +@findex srunner_set_xml +@findex srunner_has_xml +@findex srunner_xml_fname +The log can also be written in XML. The following functions define +the interface for XML logs: +@example +@verbatim +void srunner_set_xml (SRunner *sr, const char *fname); +int srunner_has_xml (SRunner *sr); +const char *srunner_xml_fname (SRunner *sr); +@end verbatim +@end example + +XML output is enabled by a call to @code{srunner_set_xml()} before the tests +are run. Here is an example of an XML log: +@example +@verbatim + + + + 2012-10-19 09:56:06 + + S1 + + . + ex_xml_output.c:10 + test_pass + 0 + 0.000013 + Core + Passed + + + . + ex_xml_output.c:16 + test_fail + 0 + -1.000000 + Core + Failure + + + . + ex_xml_output.c:20 + test_exit + 0 + -1.000000 + Core + Early exit with return value 1 + + + + S2 + + . + ex_xml_output.c:28 + test_pass2 + 0 + 0.000011 + Core + Passed + + + . + ex_xml_output.c:34 + test_loop + 0 + -1.000000 + Core + Iteration 0 failed + + + . + ex_xml_output.c:34 + test_loop + 1 + 0.000010 + Core + Passed + + + . + ex_xml_output.c:34 + test_loop + 2 + -1.000000 + Core + Iteration 2 failed + + + + XML escape " ' < > & tests + + . + ex_xml_output.c:40 + test_xml_esc_fail_msg + 0 + -1.000000 + description " ' < > & + fail " ' < > & message + + + 0.001610 + +@end verbatim +@end example + +XML logging can be enabled by an environment variable as well. If +@code{CK_XML_LOG_FILE_NAME} environment variable is set, the XML test log will +be written to specified file name. If XML log file is specified with both +@code{CK_XML_LOG_FILE_NAME} and @code{srunner_set_xml()}, the name provided +to @code{srunner_set_xml()} will be used. + +If the log name is set to "-" either via @code{srunner_set_xml()} or +@code{CK_XML_LOG_FILE_NAME}, the log data will be printed to stdout instead +of to a file. + +If both plain text and XML log files are specified, by any of above methods, +then check will log to both files. In other words logging in plain text and XML +format simultaneously is supported. + +@node TAP Logging, , Test Logging, Test Logging +@subsection TAP Logging + +@findex srunner_set_tap +@findex srunner_has_tap +@findex srunner_tap_fname +The log can also be written in Test Anything Protocol (TAP) format. +Refer to the @uref{http://podwiki.hexten.net/TAP/TAP.html,TAP Specification} +for information on valid TAP output and parsers of TAP. The following +functions define the interface for TAP logs: +@example +@verbatim +void srunner_set_tap (SRunner *sr, const char *fname); +int srunner_has_tap (SRunner *sr); +const char *srunner_tap_fname (SRunner *sr); +@end verbatim +@end example + +TAP output is enabled by a call to @code{srunner_set_tap()} before the tests +are run. Here is an example of an TAP log: +@example +@verbatim +ok 1 - mytests.c:test_suite_name:my_test_1: Passed +ok 2 - mytests.c:test_suite_name:my_test_2: Passed +not ok 3 - mytests.c:test_suite_name:my_test_3: Foo happened +ok 4 - mytests.c:test_suite_name:my_test_1: Passed +1..4 +@end verbatim +@end example + +TAP logging can be enabled by an environment variable as well. If +@code{CK_TAP_LOG_FILE_NAME} environment variable is set, the TAP test log will +be written to specified file name. If TAP log file is specified with both +@code{CK_TAP_LOG_FILE_NAME} and @code{srunner_set_tap()}, the name provided +to @code{srunner_set_tap()} will be used. + +If the log name is set to "-" either via @code{srunner_set_tap()} or +@code{CK_TAP_LOG_FILE_NAME}, the log data will be printed to stdout instead +of to a file. + +If both plain text and TAP log files are specified, by any of above methods, +then check will log to both files. In other words logging in plain text and TAP +format simultaneously is supported. + + +@node Subunit Support, , Test Logging, Advanced Features +@section Subunit Support + +Check supports running test suites with subunit output. This can be useful to +combine test results from multiple languages, or to perform programmatic +analysis on the results of multiple check test suites or otherwise handle test +results in a programmatic manner. Using subunit with check is very straight +forward. There are two steps: +1) In your check test suite driver pass 'CK_SUBUNIT' as the output mode +for your srunner. +@example +@verbatim +SRunner *sr; +sr = srunner_create (make_s1_suite ()); +srunner_add_suite (sr, make_s2_suite ()); +srunner_run_all (sr, CK_SUBUNIT); +@end verbatim +@end example +2) Setup your main language test runner to run your check based test +executable. For instance using python: +@example +@verbatim + +import subunit + +class ShellTests(subunit.ExecTestCase): + """Run some tests from the C codebase.""" + + def test_group_one(self): + """./foo/check_driver""" + + def test_group_two(self): + """./foo/other_driver""" +@end verbatim +@end example + +In this example, running the test suite ShellTests in python (using any test +runner - unittest.py, tribunal, trial, nose or others) will run +./foo/check_driver and ./foo/other_driver and report on their result. + +Subunit is hosted on launchpad - the @uref{https://launchpad.net/subunit/, +subunit} project there contains bug tracker, future plans, and source code +control details. + +@node Supported Build Systems, Conclusion and References, Advanced Features, Top +@chapter Supported Build Systems +@findex Supported Build Systems + +Check officially supports two build systems: Autotools and CMake. +Primarily it is recommended to use Autotools where possible, as CMake is +only officially supported for Windows. Information on using Check in +either build system follows. + +@menu +* Autotools:: +* CMake:: +@end menu + +@node Autotools, CMake, Supported Build Systems, Supported Build Systems +@section Autotools + +It is recommended to use pkg-config where possible to locate and use +Check in an Autotools project. This can be accomplished by including +the following in the project's @file{configure.ac} file: + +@verbatim + PKG_CHECK_MODULES([CHECK], [check >= MINIMUM-VERSION]) +@end verbatim + +where MINIMUM-VERSION is the lowest version which is sufficient for +the project. For example, to guarantee that at least version 0.9.6 is +available, use the following: + +@verbatim + PKG_CHECK_MODULES([CHECK], [check >= 0.9.6]) +@end verbatim + +An example of a @file{configure.ac} script for a project is +included in the @file{doc/example} directory in Check's source. +This macro should provide everything necessary to integrate Check +into an Autotools project. + +If one does not wish to use pkg-config Check also provides its own +macro, @code{AM_PATH_CHECK()}, which may be used. This macro is +deprecated, but is still included with Check for backwards compatibility. + +The @code{AM_PATH_CHECK()} macro is defined in the file +@file{check.m4} which is installed by Check. It has some optional +parameters that you might find useful in your @file{configure.ac}: +@verbatim +AM_PATH_CHECK([MINIMUM-VERSION, + [ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]]]) +@end verbatim + +@code{AM_PATH_CHECK} does several things: + +@enumerate +@item +It ensures check.h is available + +@item +It ensures a compatible version of Check is installed + +@item +It sets @env{CHECK_CFLAGS} and @env{CHECK_LIBS} for use by Automake. +@end enumerate + +If you include @code{AM_PATH_CHECK()} in @file{configure.ac} and +subsequently see warnings when attempting to create +@command{configure}, it probably means one of the following things: + +@enumerate +@item +You forgot to call @command{aclocal}. @command{autoreconf} will do +this for you. + +@item +@command{aclocal} can't find @file{check.m4}. Here are some possible +solutions: + +@enumerate a +@item +Call @command{aclocal} with @option{-I} set to the location of +@file{check.m4}. This means you have to call both @command{aclocal} and +@command{autoreconf}. + +@item +Add the location of @file{check.m4} to the @samp{dirlist} used by +@command{aclocal} and then call @command{autoreconf}. This means you +need permission to modify the @samp{dirlist}. + +@item +Set @code{ACLOCAL_AMFLAGS} in your top-level @file{Makefile.am} to +include @option{-I DIR} with @code{DIR} being the location of +@file{check.m4}. Then call @command{autoreconf}. +@end enumerate +@end enumerate + + +@node CMake, , Autotools, Supported Build Systems +@section CMake + +Those unable to use Autotools in their project may use CMake instead. +Officially CMake is supported only for Windows. + +Documentation for using CMake is forthcoming. In the meantime, look +at the example CMake project in Check's @file{doc/examples} directory. + + + +@node Conclusion and References, Environment Variable Reference, Supported Build Systems, Top +@chapter Conclusion and References +The tutorial and description of advanced features has provided an +introduction to all of the functionality available in Check. +Hopefully, this is enough to get you started writing unit tests with +Check. All the rest is simply application of what has been learned so +far with repeated application of the ``test a little, code a little'' +strategy. + +For further reference, see Kent Beck, ``Test-Driven Development: By +Example'', 1st ed., Addison-Wesley, 2003. ISBN 0-321-14653-0. + +If you know of other authoritative references to unit testing and +test-driven development, please send us a patch to this manual. + +@node Environment Variable Reference, Copying This Manual, Conclusion and References, Top +@appendix Environment Variable Reference + +This is a reference to environment variables that Check recognized and their use. + +CK_RUN_CASE: Name of a test case, runs only that test. See section @ref{Selective Running of Tests}. + +CK_RUN_SUITE: Name of a test suite, runs only that suite. See section @ref{Selective Running of Tests}. + +CK_INCLUDE_TAGS: String of space separated tags, runs only test cases associated with at least one of the tags, See section @ref{Selecting Tests Based on Arbitrary Tags}. + +CK_EXCLUDE_TAGS: String of space separated tags, runs only test cases not associated with any of the tags, See section @ref{Selecting Tests Based on Arbitrary Tags}. + +CK_VERBOSITY: How much output to emit, accepts: ``silent'', ``minimal'', ``normal'', ``subunit'', or ``verbose''. See section @ref{SRunner Output}. + +CK_FORK: Set to ``no'' to disable using fork() to run unit tests in their own process. This is useful for debugging segmentation faults. See section @ref{No Fork Mode}. + +CK_DEFAULT_TIMEOUT: Override Check's default unit test timeout, a floating value in seconds. ``0'' means no timeout. See section @ref{Test Timeouts}. + +CK_TIMEOUT_MULTIPLIER: A multiplier used against the default unit test timeout. An integer, defaults to ``1''. See section @ref{Test Timeouts}. + +CK_LOG_FILE_NAME: Filename to write logs to. See section @ref{Test Logging}. + +CK_XML_LOG_FILE_NAME: Filename to write XML log to. See section @ref{XML Logging}. + +CK_TAP_LOG_FILE_NAME: Filename to write TAP (Test Anything Protocol) output to. See section @ref{TAP Logging}. + +CK_MAX_MSG_SIZE: Maximal assertion message size. + + +@node Copying This Manual, Index, Environment Variable Reference, Top +@appendix Copying This Manual + +@menu +* GNU Free Documentation License:: License for copying this manual. +@end menu + +@include fdl.texi + +@node Index, , Copying This Manual, Top +@unnumbered Index + +@printindex cp + +@bye diff --git a/doc/doxygen.conf b/doc/doxygen.conf new file mode 100644 index 0000000..44efb7f --- /dev/null +++ b/doc/doxygen.conf @@ -0,0 +1,1781 @@ +# Doxyfile 1.7.6.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" "). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. + +PROJECT_NAME = "Check" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "Unit testing framework for C" + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = doxygen + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding +# "class=itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields will be shown inline in the documentation +# of the scope in which they are defined (i.e. file, namespace, or group +# documentation), provided this scope is documented. If set to NO (the default), +# structs, classes, and unions are shown on a separate page (for HTML and Man +# pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +SYMBOL_CACHE_SIZE = 0 + +# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be +# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given +# their name and scope. Since this can be an expensive process and often the +# same symbol appear multiple times in the code, doxygen keeps a cache of +# pre-resolved symbols. If the cache is too small doxygen will become slower. +# If the cache is too large, memory is wasted. The cache size is given by this +# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. The create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ../src/check.h + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = _* GCC_VERSION* CK_ATTRIBUTE* CK_EXPORT CK_DLL_EXP CHECK_* NULL check_*_version fail* + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# style sheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the style sheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the +# mathjax.org site, so you can quickly see the result without installing +# MathJax, but it is strongly recommended to install a local copy of MathJax +# before deployment. + +MATHJAX_RELPATH = http://www.mathjax.org/mathjax + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load style sheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = YES + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/doc/example/.cvsignore b/doc/example/.cvsignore new file mode 100644 index 0000000..282522d --- /dev/null +++ b/doc/example/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/doc/example/CMakeLists.txt b/doc/example/CMakeLists.txt new file mode 100644 index 0000000..136988c --- /dev/null +++ b/doc/example/CMakeLists.txt @@ -0,0 +1,105 @@ +# Copyright (c) 2017, Branden Archer +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of this project nor the names of its contributors may +# be used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Branden Archer BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +project(money C) + +cmake_minimum_required(VERSION 2.8 FATAL_ERROR) +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +############################################################################### +# Set build features +set(CMAKE_BUILD_TYPE Debug) + +############################################################################### +include(CheckCSourceCompiles) +include(CheckCSourceRuns) +include(CheckFunctionExists) +include(CheckIncludeFile) +include(CheckIncludeFiles) +include(CheckLibraryExists) +include(CheckSymbolExists) +include(CheckTypeSize) + +############################################################################### +# Check headers +set(INCLUDES "") +macro(ck_check_include_file header var) + check_include_files("${INCLUDES};${header}" ${var}) + if(${var}) + set(INCLUDES ${INCLUDES} ${header}) + endif(${var}) +endmacro(ck_check_include_file) + +ck_check_include_file("stdlib.h" HAVE_STDLIB_H) + +############################################################################### +# Check functions +# (Nothing to check for the money example) + +############################################################################### +# Check defines +# (Nothing to check for the money example) + +############################################################################### +# Check struct members +# (Nothing to check for the money example) + +############################################################################### +# Check for integer types +# (The following are used in check.h. Regardless if they are used in +# the project, they will need to be checked in order to use Check). +check_type_size(intmax_t INTMAX_T) +check_type_size(uintmax_t UINTMAX_T) + +check_type_size(pid_t PID_T) +if(NOT HAVE_PID_T) + if(WIN32) + set(pid_t "int") + else(WIN32) + MESSAGE(FATAL_ERROR "pid_t doesn't exist on this platform?") + endif(WIN32) +endif(NOT HAVE_PID_T) + +############################################################################### +# Check libraries + +############################################################################### +# Generate "config.h" from "cmake/config.h.cmake" +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/config.h.in + ${CMAKE_CURRENT_BINARY_DIR}/config.h) +include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}) +add_definitions(-DHAVE_CONFIG_H) +set(CONFIG_HEADER ${CMAKE_CURRENT_BINARY_DIR}/config.h) + +############################################################################### +# Subdirectories +add_subdirectory(src) +add_subdirectory(tests) + +############################################################################### +# Unit tests +enable_testing() +add_test(NAME check_money COMMAND check_money) + diff --git a/doc/example/Makefile.am b/doc/example/Makefile.am new file mode 100644 index 0000000..8376833 --- /dev/null +++ b/doc/example/Makefile.am @@ -0,0 +1,3 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = src . tests \ No newline at end of file diff --git a/doc/example/README b/doc/example/README new file mode 100644 index 0000000..f11245a --- /dev/null +++ b/doc/example/README @@ -0,0 +1,89 @@ +This is the "money example" from the Check tutorial. + +This demonstrates using Check along with one of two build systems: +autotools and CMake. + +======================== +Autotools: + +You need the following programs installed on your system: + -- Autoconf 2.59 + -- Automake 1.9.6 + -- Libtool 1.5.22 + -- Check 0.9.9 + +Somewhat earlier versions of these programs might work. + +Then, do as follows: + +$ autoreconf --install +$ ./configure +$ make +$ make check + +Don't do "make install" unless you want to install the money example. + +money.c and money.h are built as a library. src/main.c:main() is a +client of libmoney.la, just as tests/check_money.c:main() is a client +of libmoney.la + +To use the autotools example in another project, start with the following +files: + + example + |--- configure.ac + |--- Makefile.am + |--- src + | |--- Makefile.am + |--- tests + |--- Makefile.am + +Please send bug reports to check-devel AT lists.sourceforge.net. + +======================== +CMake: + +You need the following programs installed on your system: + -- CMake 2.8 + -- Check 0.9.9 + -- (pkg-config 0.26 is optional) + +Somewhat earlier versions of these programs might work. + +NOTE: If pkg-config is not installed on the system, and MSVC is being used, +the install location of Check must be inserted manually into the +tests/CMakeLists.txt file, by setting the variable CHECK_INSTALL_DIR +to the install location. Look at the tests/CMakeLists.txt file for +a commented out example. + +Then, do as follows for a Unix-compatible shell: + +$ cmake . +$ make +$ make test + +or the following for MSVC: + +$ cmake -G "NMake Makefiles" . +$ nmake +$ nmake test + +Don't do "make install" or "nmake install" unless you want to install the money example. + +money.c and money.h are built as a library. src/main.c:main() is a +client of libmoney.la, just as tests/check_money.c:main() is a client +of libmoney.la + +To use the CMake example in another project, start with the following files: + + example + |--- CMakeFiles.txt + |--- cmake + | |--- config.h.in + | |--- FindCheck.cmake + |--- src + | |--- CMakeFiles.txt + |--- tests + |--- CMakeFiles.txt + +Please send bug reports to check-devel AT lists.sourceforge.net. diff --git a/doc/example/cmake/COPYING-CMAKE-SCRIPTS.txt b/doc/example/cmake/COPYING-CMAKE-SCRIPTS.txt new file mode 100644 index 0000000..53b6b71 --- /dev/null +++ b/doc/example/cmake/COPYING-CMAKE-SCRIPTS.txt @@ -0,0 +1,22 @@ +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/doc/example/cmake/FindCheck.cmake b/doc/example/cmake/FindCheck.cmake new file mode 100644 index 0000000..4392d88 --- /dev/null +++ b/doc/example/cmake/FindCheck.cmake @@ -0,0 +1,57 @@ +# - Try to find the CHECK libraries +# Once done this will define +# +# CHECK_FOUND - system has check +# CHECK_INCLUDE_DIR - the check include directory +# CHECK_LIBRARIES - check library +# +# This configuration file for finding libcheck is originally from +# the opensync project. The originally was downloaded from here: +# opensync.org/browser/branches/3rd-party-cmake-modules/modules/FindCheck.cmake +# +# Copyright (c) 2007 Daniel Gollub +# Copyright (c) 2007 Bjoern Ricks +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + + +INCLUDE( FindPkgConfig ) + +# Take care about check.pc settings +PKG_SEARCH_MODULE( CHECK check ) + +# Look for CHECK include dir and libraries +IF( NOT CHECK_FOUND ) + IF ( CHECK_INSTALL_DIR ) + MESSAGE ( STATUS "Using override CHECK_INSTALL_DIR to find check" ) + SET ( CHECK_INCLUDE_DIR "${CHECK_INSTALL_DIR}/include" ) + SET ( CHECK_INCLUDE_DIRS "${CHECK_INCLUDE_DIR}" ) + FIND_LIBRARY( CHECK_LIBRARY NAMES check PATHS "${CHECK_INSTALL_DIR}/lib" ) + FIND_LIBRARY( COMPAT_LIBRARY NAMES compat PATHS "${CHECK_INSTALL_DIR}/lib" ) + SET ( CHECK_LIBRARIES "${CHECK_LIBRARY}" "${COMPAT_LIBRARY}" ) + ELSE ( CHECK_INSTALL_DIR ) + FIND_PATH( CHECK_INCLUDE_DIR check.h ) + FIND_LIBRARY( CHECK_LIBRARIES NAMES check ) + ENDIF ( CHECK_INSTALL_DIR ) + + IF ( CHECK_INCLUDE_DIR AND CHECK_LIBRARIES ) + SET( CHECK_FOUND 1 ) + IF ( NOT Check_FIND_QUIETLY ) + MESSAGE ( STATUS "Found CHECK: ${CHECK_LIBRARIES}" ) + ENDIF ( NOT Check_FIND_QUIETLY ) + ELSE ( CHECK_INCLUDE_DIR AND CHECK_LIBRARIES ) + IF ( Check_FIND_REQUIRED ) + MESSAGE( FATAL_ERROR "Could NOT find CHECK" ) + ELSE ( Check_FIND_REQUIRED ) + IF ( NOT Check_FIND_QUIETLY ) + MESSAGE( STATUS "Could NOT find CHECK" ) + ENDIF ( NOT Check_FIND_QUIETLY ) + ENDIF ( Check_FIND_REQUIRED ) + ENDIF ( CHECK_INCLUDE_DIR AND CHECK_LIBRARIES ) +ENDIF( NOT CHECK_FOUND ) + +# Hide advanced variables from CMake GUIs +MARK_AS_ADVANCED( CHECK_INCLUDE_DIR CHECK_LIBRARIES ) + diff --git a/doc/example/cmake/config.h.in b/doc/example/cmake/config.h.in new file mode 100644 index 0000000..a66634b --- /dev/null +++ b/doc/example/cmake/config.h.in @@ -0,0 +1,24 @@ +/*-*- mode:C; -*- */ +/* config.h. Generated from build/cmake/config.h.in by cmake configure */ + +/* + * Ensure we have C99-style int64_t, etc, all defined. + */ + +/* First, we need to know if the system has already defined them. */ +#cmakedefine HAVE_INTMAX_T +#cmakedefine HAVE_UINTMAX_T + +/* Define to `int' if doesn't define. */ +#cmakedefine pid_t ${pid_t} + +/* Define intmax_t and uintmax_t if they are not already defined. */ +#if !defined(HAVE_INTMAX_T) +typedef int64_t intmax_t; +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#endif + +#if !defined(HAVE_UINTMAX_T) +typedef uint64_t uintmax_t; +#endif diff --git a/doc/example/configure.ac b/doc/example/configure.ac new file mode 100644 index 0000000..bf630fe --- /dev/null +++ b/doc/example/configure.ac @@ -0,0 +1,40 @@ +# Process this file with autoconf to produce a configure script. + +# Prelude. +AC_PREREQ([2.59]) +AC_INIT([Money], [0.3], [check-devel AT lists.sourceforge.net]) +AM_PROG_AR + +# unique source file --- primitive safety check +AC_CONFIG_SRCDIR([src/money.c]) + +# fairly severe build strictness +# change foreign to gnu or gnits to comply with gnu standards +AM_INIT_AUTOMAKE([-Wall -Werror foreign 1.11.2]) + +# Checks for programs. +AC_PROG_CC +AC_PROG_LIBTOOL + +# Checks for libraries. + +PKG_CHECK_MODULES([CHECK], [check >= 0.9.6]) +AM_PROG_CC_C_O + +# Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS([stdlib.h]) + +# Checks for typedefs, structures, and compiler characteristics. + +# Checks for library functions. +AC_FUNC_MALLOC + +# Output files +AC_CONFIG_HEADERS([config.h]) + +AC_CONFIG_FILES([Makefile + src/Makefile + tests/Makefile]) + +AC_OUTPUT diff --git a/doc/example/src/CMakeLists.txt b/doc/example/src/CMakeLists.txt new file mode 100644 index 0000000..b5e211e --- /dev/null +++ b/doc/example/src/CMakeLists.txt @@ -0,0 +1,24 @@ +set(LIB_SOURCES + money.c +) + +set(MAIN_SOURCES + main.c +) + +set(HEADERS + ${CONFIG_HEADER} + money.h +) + +add_library(money STATIC ${LIB_SOURCES} ${HEADERS}) + +add_executable(main ${HEADERS} ${MAIN_SOURCES}) +target_link_libraries(main money) + +install(TARGETS money + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib) + +install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/money.h DESTINATION include) diff --git a/doc/example/src/Makefile.am b/doc/example/src/Makefile.am new file mode 100644 index 0000000..0ab2add --- /dev/null +++ b/doc/example/src/Makefile.am @@ -0,0 +1,8 @@ +## Process this file with automake to produce Makefile.in + +lib_LTLIBRARIES = libmoney.la +libmoney_la_SOURCES = money.c money.h + +bin_PROGRAMS = main +main_SOURCES = main.c +main_LDADD = libmoney.la diff --git a/doc/example/src/main.c b/doc/example/src/main.c new file mode 100644 index 0000000..382a3e2 --- /dev/null +++ b/doc/example/src/main.c @@ -0,0 +1,31 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "money.h" + +/* only main should be in this file, to make all other functions in + the prograble testable by Check. in order to test main(), use a + whole program testing framework like Autotest. +*/ + +int main(void) +{ + return 0; +} diff --git a/doc/example/src/money.1.c b/doc/example/src/money.1.c new file mode 100644 index 0000000..8e1e65b --- /dev/null +++ b/doc/example/src/money.1.c @@ -0,0 +1,20 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + diff --git a/doc/example/src/money.1.h b/doc/example/src/money.1.h new file mode 100644 index 0000000..3bdd083 --- /dev/null +++ b/doc/example/src/money.1.h @@ -0,0 +1,24 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef MONEY_H +#define MONEY_H + +#endif /* MONEY_H */ diff --git a/doc/example/src/money.2.h b/doc/example/src/money.2.h new file mode 100644 index 0000000..5550c23 --- /dev/null +++ b/doc/example/src/money.2.h @@ -0,0 +1,31 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef MONEY_H +#define MONEY_H + +typedef struct Money Money; + +Money *money_create(int amount, char *currency); +int money_amount(Money * m); +char *money_currency(Money * m); +void money_free(Money * m); + +#endif /* MONEY_H */ diff --git a/doc/example/src/money.3.c b/doc/example/src/money.3.c new file mode 100644 index 0000000..8474a8c --- /dev/null +++ b/doc/example/src/money.3.c @@ -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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include +#include "money.h" + +Money *money_create(int amount, char *currency) +{ + return NULL; +} + +int money_amount(Money * m) +{ + return 0; +} + +char *money_currency(Money * m) +{ + return NULL; +} + +void money_free(Money * m) +{ + return; +} diff --git a/doc/example/src/money.4.c b/doc/example/src/money.4.c new file mode 100644 index 0000000..69a4368 --- /dev/null +++ b/doc/example/src/money.4.c @@ -0,0 +1,47 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include +#include "money.h" + +struct Money +{ + int amount; +}; + +Money *money_create(int amount, char *currency) +{ + return NULL; +} + +int money_amount(Money * m) +{ + return m->amount; +} + +char *money_currency(Money * m) +{ + return NULL; +} + +void money_free(Money * m) +{ + return; +} diff --git a/doc/example/src/money.5.c b/doc/example/src/money.5.c new file mode 100644 index 0000000..5c7f335 --- /dev/null +++ b/doc/example/src/money.5.c @@ -0,0 +1,58 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include +#include "money.h" + +struct Money +{ + int amount; + char *currency; +}; + +Money *money_create(int amount, char *currency) +{ + Money *m = malloc(sizeof(Money)); + + if (m == NULL) + { + return NULL; + } + + m->amount = amount; + m->currency = currency; + return m; +} + +int money_amount(Money * m) +{ + return m->amount; +} + +char *money_currency(Money * m) +{ + return m->currency; +} + +void money_free(Money * m) +{ + free(m); + return; +} diff --git a/doc/example/src/money.6.c b/doc/example/src/money.6.c new file mode 100644 index 0000000..706c38a --- /dev/null +++ b/doc/example/src/money.6.c @@ -0,0 +1,65 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include +#include "money.h" + +struct Money +{ + int amount; + char *currency; +}; + +Money *money_create(int amount, char *currency) +{ + Money *m; + + if (amount < 0) + { + return NULL; + } + + m = malloc(sizeof(Money)); + + if (m == NULL) + { + return NULL; + } + + m->amount = amount; + m->currency = currency; + return m; +} + +int money_amount(Money * m) +{ + return m->amount; +} + +char *money_currency(Money * m) +{ + return m->currency; +} + +void money_free(Money * m) +{ + free(m); + return; +} diff --git a/doc/example/src/money.c b/doc/example/src/money.c new file mode 100644 index 0000000..706c38a --- /dev/null +++ b/doc/example/src/money.c @@ -0,0 +1,65 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include +#include "money.h" + +struct Money +{ + int amount; + char *currency; +}; + +Money *money_create(int amount, char *currency) +{ + Money *m; + + if (amount < 0) + { + return NULL; + } + + m = malloc(sizeof(Money)); + + if (m == NULL) + { + return NULL; + } + + m->amount = amount; + m->currency = currency; + return m; +} + +int money_amount(Money * m) +{ + return m->amount; +} + +char *money_currency(Money * m) +{ + return m->currency; +} + +void money_free(Money * m) +{ + free(m); + return; +} diff --git a/doc/example/src/money.h b/doc/example/src/money.h new file mode 100644 index 0000000..5550c23 --- /dev/null +++ b/doc/example/src/money.h @@ -0,0 +1,31 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef MONEY_H +#define MONEY_H + +typedef struct Money Money; + +Money *money_create(int amount, char *currency); +int money_amount(Money * m); +char *money_currency(Money * m); +void money_free(Money * m); + +#endif /* MONEY_H */ diff --git a/doc/example/tests/CMakeLists.txt b/doc/example/tests/CMakeLists.txt new file mode 100644 index 0000000..1d46e9e --- /dev/null +++ b/doc/example/tests/CMakeLists.txt @@ -0,0 +1,18 @@ +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../src) + +# If pkg-config is not installed on the system, then the +# CHECK_INSTALL_DIR variable must be set to the install +# location of Check. For example, on Windows, this may +# be: C:/Program Files/check +# set(CHECK_INSTALL_DIR "C:/Program Files/check") + +find_package(Check REQUIRED) +include_directories(${CHECK_INCLUDE_DIRS}) +link_directories(${CHECK_LIBRARY_DIRS}) + +set(TEST_SOURCES + check_money.c +) + +add_executable(check_money ${TEST_SOURCES}) +target_link_libraries(check_money money ${CHECK_LIBRARIES}) diff --git a/doc/example/tests/Makefile.am b/doc/example/tests/Makefile.am new file mode 100644 index 0000000..729a610 --- /dev/null +++ b/doc/example/tests/Makefile.am @@ -0,0 +1,7 @@ +## Process this file with automake to produce Makefile.in + +TESTS = check_money +check_PROGRAMS = check_money +check_money_SOURCES = check_money.c $(top_builddir)/src/money.h +check_money_CFLAGS = @CHECK_CFLAGS@ +check_money_LDADD = $(top_builddir)/src/libmoney.la @CHECK_LIBS@ diff --git a/doc/example/tests/check_money.1.c b/doc/example/tests/check_money.1.c new file mode 100644 index 0000000..abfacf1 --- /dev/null +++ b/doc/example/tests/check_money.1.c @@ -0,0 +1,24 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +int main(void) +{ + return 0; +} diff --git a/doc/example/tests/check_money.2.c b/doc/example/tests/check_money.2.c new file mode 100644 index 0000000..148f10f --- /dev/null +++ b/doc/example/tests/check_money.2.c @@ -0,0 +1,38 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include +#include "../src/money.h" + +START_TEST(test_money_create) +{ + Money *m; + + m = money_create(5, "USD"); + ck_assert_int_eq(money_amount(m), 5); + ck_assert_str_eq(money_currency(m), "USD"); + money_free(m); +} +END_TEST + +int main(void) +{ + return 0; +} diff --git a/doc/example/tests/check_money.3.c b/doc/example/tests/check_money.3.c new file mode 100644 index 0000000..733a0da --- /dev/null +++ b/doc/example/tests/check_money.3.c @@ -0,0 +1,65 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include +#include +#include "../src/money.h" + +START_TEST(test_money_create) +{ + Money *m; + + m = money_create(5, "USD"); + ck_assert_int_eq(money_amount(m), 5); + ck_assert_str_eq(money_currency(m), "USD"); + money_free(m); +} +END_TEST + +Suite * money_suite(void) +{ + Suite *s; + TCase *tc_core; + + s = suite_create("Money"); + + /* Core test case */ + tc_core = tcase_create("Core"); + + tcase_add_test(tc_core, test_money_create); + suite_add_tcase(s, tc_core); + + return s; +} + +int main(void) +{ + int number_failed; + Suite *s; + SRunner *sr; + + s = money_suite(); + sr = srunner_create(s); + + srunner_run_all(sr, CK_NORMAL); + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/doc/example/tests/check_money.6.c b/doc/example/tests/check_money.6.c new file mode 100644 index 0000000..e1120c6 --- /dev/null +++ b/doc/example/tests/check_money.6.c @@ -0,0 +1,94 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include +#include +#include "../src/money.h" + +START_TEST(test_money_create) +{ + Money *m; + + m = money_create(5, "USD"); + ck_assert_int_eq(money_amount(m), 5); + ck_assert_str_eq(money_currency(m), "USD"); + money_free(m); +} +END_TEST + +START_TEST(test_money_create_neg) +{ + Money *m = money_create(-1, "USD"); + + ck_assert_msg(m == NULL, + "NULL should be returned on attempt to create with " + "a negative amount"); +} +END_TEST + +START_TEST(test_money_create_zero) +{ + Money *m = money_create(0, "USD"); + + if (money_amount(m) != 0) + { + ck_abort_msg("Zero is a valid amount of money"); + } +} +END_TEST + +Suite * money_suite(void) +{ + Suite *s; + TCase *tc_core; + TCase *tc_limits; + + s = suite_create("Money"); + + /* Core test case */ + tc_core = tcase_create("Core"); + + tcase_add_test(tc_core, test_money_create); + suite_add_tcase(s, tc_core); + + /* Limits test case */ + tc_limits = tcase_create("Limits"); + + tcase_add_test(tc_limits, test_money_create_neg); + tcase_add_test(tc_limits, test_money_create_zero); + suite_add_tcase(s, tc_limits); + + return s; +} + +int main(void) +{ + int number_failed; + Suite *s; + SRunner *sr; + + s = money_suite(); + sr = srunner_create(s); + + srunner_run_all(sr, CK_NORMAL); + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/doc/example/tests/check_money.7.c b/doc/example/tests/check_money.7.c new file mode 100644 index 0000000..e82a0eb --- /dev/null +++ b/doc/example/tests/check_money.7.c @@ -0,0 +1,103 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include +#include +#include "../src/money.h" + +Money *five_dollars; + +void setup(void) +{ + five_dollars = money_create(5, "USD"); +} + +void teardown(void) +{ + money_free(five_dollars); +} + +START_TEST(test_money_create) +{ + ck_assert_int_eq(money_amount(five_dollars), 5); + ck_assert_str_eq(money_currency(five_dollars), "USD"); +} +END_TEST + +START_TEST(test_money_create_neg) +{ + Money *m = money_create(-1, "USD"); + + ck_assert_msg(m == NULL, + "NULL should be returned on attempt to create with " + "a negative amount"); +} +END_TEST + +START_TEST(test_money_create_zero) +{ + Money *m = money_create(0, "USD"); + + if (money_amount(m) != 0) + { + ck_abort_msg("Zero is a valid amount of money"); + } +} +END_TEST + +Suite * money_suite(void) +{ + Suite *s; + TCase *tc_core; + TCase *tc_limits; + + s = suite_create("Money"); + + /* Core test case */ + tc_core = tcase_create("Core"); + + tcase_add_checked_fixture(tc_core, setup, teardown); + tcase_add_test(tc_core, test_money_create); + suite_add_tcase(s, tc_core); + + /* Limits test case */ + tc_limits = tcase_create("Limits"); + + tcase_add_test(tc_limits, test_money_create_neg); + tcase_add_test(tc_limits, test_money_create_zero); + suite_add_tcase(s, tc_limits); + + return s; +} + +int main(void) +{ + int number_failed; + Suite *s; + SRunner *sr; + + s = money_suite(); + sr = srunner_create(s); + + srunner_run_all(sr, CK_NORMAL); + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/doc/example/tests/check_money.c b/doc/example/tests/check_money.c new file mode 100644 index 0000000..b5a3004 --- /dev/null +++ b/doc/example/tests/check_money.c @@ -0,0 +1,105 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include "../src/money.h" + +Money *five_dollars; + +void setup(void) +{ + five_dollars = money_create(5, "USD"); +} + +void teardown(void) +{ + money_free(five_dollars); +} + +START_TEST(test_money_create) +{ + ck_assert_int_eq(money_amount(five_dollars), 5); + ck_assert_str_eq(money_currency(five_dollars), "USD"); +} +END_TEST + +START_TEST(test_money_create_neg) +{ + Money *m = money_create(-1, "USD"); + + ck_assert_msg(m == NULL, + "NULL should be returned on attempt to create with " + "a negative amount"); +} +END_TEST + +START_TEST(test_money_create_zero) +{ + Money *m = money_create(0, "USD"); + + if (money_amount(m) != 0) + { + ck_abort_msg("Zero is a valid amount of money"); + } +} +END_TEST + +Suite * money_suite(void) +{ + Suite *s; + TCase *tc_core; + TCase *tc_limits; + + s = suite_create("Money"); + + /* Core test case */ + tc_core = tcase_create("Core"); + + tcase_add_checked_fixture(tc_core, setup, teardown); + tcase_add_test(tc_core, test_money_create); + suite_add_tcase(s, tc_core); + + /* Limits test case */ + tc_limits = tcase_create("Limits"); + + tcase_add_test(tc_limits, test_money_create_neg); + tcase_add_test(tc_limits, test_money_create_zero); + suite_add_tcase(s, tc_limits); + + return s; +} + +int main(void) +{ + int number_failed; + Suite *s; + SRunner *sr; + + s = money_suite(); + sr = srunner_create(s); + + srunner_run_all(sr, CK_NORMAL); + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/doc/fdl.texi b/doc/fdl.texi new file mode 100644 index 0000000..fe78df8 --- /dev/null +++ b/doc/fdl.texi @@ -0,0 +1,452 @@ + +@node GNU Free Documentation License +@appendixsec GNU Free Documentation License + +@cindex FDL, GNU Free Documentation License +@center Version 1.2, November 2002 + +@display +Copyright @copyright{} 2000,2001,2002 Free Software Foundation, Inc. +51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. +@end display + +@enumerate 0 +@item +PREAMBLE + +The purpose of this License is to make a manual, textbook, or other +functional and useful document @dfn{free} in the sense of freedom: to +assure everyone the effective freedom to copy and redistribute it, +with or without modifying it, either commercially or noncommercially. +Secondarily, this License preserves for the author and publisher a way +to get credit for their work, while not being considered responsible +for modifications made by others. + +This License is a kind of ``copyleft'', which means that derivative +works of the document must themselves be free in the same sense. It +complements the GNU General Public License, which is a copyleft +license designed for free software. + +We have designed this License in order to use it for manuals for free +software, because free software needs free documentation: a free +program should come with manuals providing the same freedoms that the +software does. But this License is not limited to software manuals; +it can be used for any textual work, regardless of subject matter or +whether it is published as a printed book. We recommend this License +principally for works whose purpose is instruction or reference. + +@item +APPLICABILITY AND DEFINITIONS + +This License applies to any manual or other work, in any medium, that +contains a notice placed by the copyright holder saying it can be +distributed under the terms of this License. Such a notice grants a +world-wide, royalty-free license, unlimited in duration, to use that +work under the conditions stated herein. The ``Document'', below, +refers to any such manual or work. Any member of the public is a +licensee, and is addressed as ``you''. You accept the license if you +copy, modify or distribute the work in a way requiring permission +under copyright law. + +A ``Modified Version'' of the Document means any work containing the +Document or a portion of it, either copied verbatim, or with +modifications and/or translated into another language. + +A ``Secondary Section'' is a named appendix or a front-matter section +of the Document that deals exclusively with the relationship of the +publishers or authors of the Document to the Document's overall +subject (or to related matters) and contains nothing that could fall +directly within that overall subject. (Thus, if the Document is in +part a textbook of mathematics, a Secondary Section may not explain +any mathematics.) The relationship could be a matter of historical +connection with the subject or with related matters, or of legal, +commercial, philosophical, ethical or political position regarding +them. + +The ``Invariant Sections'' are certain Secondary Sections whose titles +are designated, as being those of Invariant Sections, in the notice +that says that the Document is released under this License. If a +section does not fit the above definition of Secondary then it is not +allowed to be designated as Invariant. The Document may contain zero +Invariant Sections. If the Document does not identify any Invariant +Sections then there are none. + +The ``Cover Texts'' are certain short passages of text that are listed, +as Front-Cover Texts or Back-Cover Texts, in the notice that says that +the Document is released under this License. A Front-Cover Text may +be at most 5 words, and a Back-Cover Text may be at most 25 words. + +A ``Transparent'' copy of the Document means a machine-readable copy, +represented in a format whose specification is available to the +general public, that is suitable for revising the document +straightforwardly with generic text editors or (for images composed of +pixels) generic paint programs or (for drawings) some widely available +drawing editor, and that is suitable for input to text formatters or +for automatic translation to a variety of formats suitable for input +to text formatters. A copy made in an otherwise Transparent file +format whose markup, or absence of markup, has been arranged to thwart +or discourage subsequent modification by readers is not Transparent. +An image format is not Transparent if used for any substantial amount +of text. A copy that is not ``Transparent'' is called ``Opaque''. + +Examples of suitable formats for Transparent copies include plain +@sc{ascii} without markup, Texinfo input format, La@TeX{} input +format, @acronym{SGML} or @acronym{XML} using a publicly available +@acronym{DTD}, and standard-conforming simple @acronym{HTML}, +PostScript or @acronym{PDF} designed for human modification. Examples +of transparent image formats include @acronym{PNG}, @acronym{XCF} and +@acronym{JPG}. Opaque formats include proprietary formats that can be +read and edited only by proprietary word processors, @acronym{SGML} or +@acronym{XML} for which the @acronym{DTD} and/or processing tools are +not generally available, and the machine-generated @acronym{HTML}, +PostScript or @acronym{PDF} produced by some word processors for +output purposes only. + +The ``Title Page'' means, for a printed book, the title page itself, +plus such following pages as are needed to hold, legibly, the material +this License requires to appear in the title page. For works in +formats which do not have any title page as such, ``Title Page'' means +the text near the most prominent appearance of the work's title, +preceding the beginning of the body of the text. + +A section ``Entitled XYZ'' means a named subunit of the Document whose +title either is precisely XYZ or contains XYZ in parentheses following +text that translates XYZ in another language. (Here XYZ stands for a +specific section name mentioned below, such as ``Acknowledgements'', +``Dedications'', ``Endorsements'', or ``History''.) To ``Preserve the Title'' +of such a section when you modify the Document means that it remains a +section ``Entitled XYZ'' according to this definition. + +The Document may include Warranty Disclaimers next to the notice which +states that this License applies to the Document. These Warranty +Disclaimers are considered to be included by reference in this +License, but only as regards disclaiming warranties: any other +implication that these Warranty Disclaimers may have is void and has +no effect on the meaning of this License. + +@item +VERBATIM COPYING + +You may copy and distribute the Document in any medium, either +commercially or noncommercially, provided that this License, the +copyright notices, and the license notice saying this License applies +to the Document are reproduced in all copies, and that you add no other +conditions whatsoever to those of this License. You may not use +technical measures to obstruct or control the reading or further +copying of the copies you make or distribute. However, you may accept +compensation in exchange for copies. If you distribute a large enough +number of copies you must also follow the conditions in section 3. + +You may also lend copies, under the same conditions stated above, and +you may publicly display copies. + +@item +COPYING IN QUANTITY + +If you publish printed copies (or copies in media that commonly have +printed covers) of the Document, numbering more than 100, and the +Document's license notice requires Cover Texts, you must enclose the +copies in covers that carry, clearly and legibly, all these Cover +Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on +the back cover. Both covers must also clearly and legibly identify +you as the publisher of these copies. The front cover must present +the full title with all words of the title equally prominent and +visible. You may add other material on the covers in addition. +Copying with changes limited to the covers, as long as they preserve +the title of the Document and satisfy these conditions, can be treated +as verbatim copying in other respects. + +If the required texts for either cover are too voluminous to fit +legibly, you should put the first ones listed (as many as fit +reasonably) on the actual cover, and continue the rest onto adjacent +pages. + +If you publish or distribute Opaque copies of the Document numbering +more than 100, you must either include a machine-readable Transparent +copy along with each Opaque copy, or state in or with each Opaque copy +a computer-network location from which the general network-using +public has access to download using public-standard network protocols +a complete Transparent copy of the Document, free of added material. +If you use the latter option, you must take reasonably prudent steps, +when you begin distribution of Opaque copies in quantity, to ensure +that this Transparent copy will remain thus accessible at the stated +location until at least one year after the last time you distribute an +Opaque copy (directly or through your agents or retailers) of that +edition to the public. + +It is requested, but not required, that you contact the authors of the +Document well before redistributing any large number of copies, to give +them a chance to provide you with an updated version of the Document. + +@item +MODIFICATIONS + +You may copy and distribute a Modified Version of the Document under +the conditions of sections 2 and 3 above, provided that you release +the Modified Version under precisely this License, with the Modified +Version filling the role of the Document, thus licensing distribution +and modification of the Modified Version to whoever possesses a copy +of it. In addition, you must do these things in the Modified Version: + +@enumerate A +@item +Use in the Title Page (and on the covers, if any) a title distinct +from that of the Document, and from those of previous versions +(which should, if there were any, be listed in the History section +of the Document). You may use the same title as a previous version +if the original publisher of that version gives permission. + +@item +List on the Title Page, as authors, one or more persons or entities +responsible for authorship of the modifications in the Modified +Version, together with at least five of the principal authors of the +Document (all of its principal authors, if it has fewer than five), +unless they release you from this requirement. + +@item +State on the Title page the name of the publisher of the +Modified Version, as the publisher. + +@item +Preserve all the copyright notices of the Document. + +@item +Add an appropriate copyright notice for your modifications +adjacent to the other copyright notices. + +@item +Include, immediately after the copyright notices, a license notice +giving the public permission to use the Modified Version under the +terms of this License, in the form shown in the Addendum below. + +@item +Preserve in that license notice the full lists of Invariant Sections +and required Cover Texts given in the Document's license notice. + +@item +Include an unaltered copy of this License. + +@item +Preserve the section Entitled ``History'', Preserve its Title, and add +to it an item stating at least the title, year, new authors, and +publisher of the Modified Version as given on the Title Page. If +there is no section Entitled ``History'' in the Document, create one +stating the title, year, authors, and publisher of the Document as +given on its Title Page, then add an item describing the Modified +Version as stated in the previous sentence. + +@item +Preserve the network location, if any, given in the Document for +public access to a Transparent copy of the Document, and likewise +the network locations given in the Document for previous versions +it was based on. These may be placed in the ``History'' section. +You may omit a network location for a work that was published at +least four years before the Document itself, or if the original +publisher of the version it refers to gives permission. + +@item +For any section Entitled ``Acknowledgements'' or ``Dedications'', Preserve +the Title of the section, and preserve in the section all the +substance and tone of each of the contributor acknowledgements and/or +dedications given therein. + +@item +Preserve all the Invariant Sections of the Document, +unaltered in their text and in their titles. Section numbers +or the equivalent are not considered part of the section titles. + +@item +Delete any section Entitled ``Endorsements''. Such a section +may not be included in the Modified Version. + +@item +Do not retitle any existing section to be Entitled ``Endorsements'' or +to conflict in title with any Invariant Section. + +@item +Preserve any Warranty Disclaimers. +@end enumerate + +If the Modified Version includes new front-matter sections or +appendices that qualify as Secondary Sections and contain no material +copied from the Document, you may at your option designate some or all +of these sections as invariant. To do this, add their titles to the +list of Invariant Sections in the Modified Version's license notice. +These titles must be distinct from any other section titles. + +You may add a section Entitled ``Endorsements'', provided it contains +nothing but endorsements of your Modified Version by various +parties---for example, statements of peer review or that the text has +been approved by an organization as the authoritative definition of a +standard. + +You may add a passage of up to five words as a Front-Cover Text, and a +passage of up to 25 words as a Back-Cover Text, to the end of the list +of Cover Texts in the Modified Version. Only one passage of +Front-Cover Text and one of Back-Cover Text may be added by (or +through arrangements made by) any one entity. If the Document already +includes a cover text for the same cover, previously added by you or +by arrangement made by the same entity you are acting on behalf of, +you may not add another; but you may replace the old one, on explicit +permission from the previous publisher that added the old one. + +The author(s) and publisher(s) of the Document do not by this License +give permission to use their names for publicity for or to assert or +imply endorsement of any Modified Version. + +@item +COMBINING DOCUMENTS + +You may combine the Document with other documents released under this +License, under the terms defined in section 4 above for modified +versions, provided that you include in the combination all of the +Invariant Sections of all of the original documents, unmodified, and +list them all as Invariant Sections of your combined work in its +license notice, and that you preserve all their Warranty Disclaimers. + +The combined work need only contain one copy of this License, and +multiple identical Invariant Sections may be replaced with a single +copy. If there are multiple Invariant Sections with the same name but +different contents, make the title of each such section unique by +adding at the end of it, in parentheses, the name of the original +author or publisher of that section if known, or else a unique number. +Make the same adjustment to the section titles in the list of +Invariant Sections in the license notice of the combined work. + +In the combination, you must combine any sections Entitled ``History'' +in the various original documents, forming one section Entitled +``History''; likewise combine any sections Entitled ``Acknowledgements'', +and any sections Entitled ``Dedications''. You must delete all +sections Entitled ``Endorsements.'' + +@item +COLLECTIONS OF DOCUMENTS + +You may make a collection consisting of the Document and other documents +released under this License, and replace the individual copies of this +License in the various documents with a single copy that is included in +the collection, provided that you follow the rules of this License for +verbatim copying of each of the documents in all other respects. + +You may extract a single document from such a collection, and distribute +it individually under this License, provided you insert a copy of this +License into the extracted document, and follow this License in all +other respects regarding verbatim copying of that document. + +@item +AGGREGATION WITH INDEPENDENT WORKS + +A compilation of the Document or its derivatives with other separate +and independent documents or works, in or on a volume of a storage or +distribution medium, is called an ``aggregate'' if the copyright +resulting from the compilation is not used to limit the legal rights +of the compilation's users beyond what the individual works permit. +When the Document is included in an aggregate, this License does not +apply to the other works in the aggregate which are not themselves +derivative works of the Document. + +If the Cover Text requirement of section 3 is applicable to these +copies of the Document, then if the Document is less than one half of +the entire aggregate, the Document's Cover Texts may be placed on +covers that bracket the Document within the aggregate, or the +electronic equivalent of covers if the Document is in electronic form. +Otherwise they must appear on printed covers that bracket the whole +aggregate. + +@item +TRANSLATION + +Translation is considered a kind of modification, so you may +distribute translations of the Document under the terms of section 4. +Replacing Invariant Sections with translations requires special +permission from their copyright holders, but you may include +translations of some or all Invariant Sections in addition to the +original versions of these Invariant Sections. You may include a +translation of this License, and all the license notices in the +Document, and any Warranty Disclaimers, provided that you also include +the original English version of this License and the original versions +of those notices and disclaimers. In case of a disagreement between +the translation and the original version of this License or a notice +or disclaimer, the original version will prevail. + +If a section in the Document is Entitled ``Acknowledgements'', +``Dedications'', or ``History'', the requirement (section 4) to Preserve +its Title (section 1) will typically require changing the actual +title. + +@item +TERMINATION + +You may not copy, modify, sublicense, or distribute the Document except +as expressly provided for under this License. Any other attempt to +copy, modify, sublicense or distribute the Document is void, and will +automatically terminate your rights under this License. However, +parties who have received copies, or rights, from you under this +License will not have their licenses terminated so long as such +parties remain in full compliance. + +@item +FUTURE REVISIONS OF THIS LICENSE + +The Free Software Foundation may publish new, revised versions +of the GNU Free Documentation License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. See +@uref{http://www.gnu.org/copyleft/}. + +Each version of the License is given a distinguishing version number. +If the Document specifies that a particular numbered version of this +License ``or any later version'' applies to it, you have the option of +following the terms and conditions either of that specified version or +of any later version that has been published (not as a draft) by the +Free Software Foundation. If the Document does not specify a version +number of this License, you may choose any version ever published (not +as a draft) by the Free Software Foundation. +@end enumerate + +@page +@appendixsubsec ADDENDUM: How to use this License for your documents + +To use this License in a document you have written, include a copy of +the License in the document and put the following copyright and +license notices just after the title page: + +@smallexample +@group + Copyright (C) @var{year} @var{your name}. + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.2 + or any later version published by the Free Software Foundation; + with no Invariant Sections, no Front-Cover Texts, and no Back-Cover + Texts. A copy of the license is included in the section entitled ``GNU + Free Documentation License''. +@end group +@end smallexample + +If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, +replace the ``with...Texts.'' line with this: + +@smallexample +@group + with the Invariant Sections being @var{list their titles}, with + the Front-Cover Texts being @var{list}, and with the Back-Cover Texts + being @var{list}. +@end group +@end smallexample + +If you have Invariant Sections without Cover Texts, or some other +combination of the three, merge those two alternatives to suit the +situation. + +If your document contains nontrivial examples of program code, we +recommend releasing these examples in parallel under your choice of +free software license, such as the GNU General Public License, +to permit their use in free software. + +@c Local Variables: +@c ispell-local-pdict: "ispell-dict" +@c End: + diff --git a/index.html b/index.html new file mode 100644 index 0000000..59d8e3c --- /dev/null +++ b/index.html @@ -0,0 +1,150 @@ + + + + + + + + + + + + + +Check | Unit testing framework for C + + + + + + + + +
+ +
+ + + + + +
+ +
+ +

Latest Check Release

+ +

+ +Oct 20, 2017: Check 0.12.0 +is now available for download. Check is available under the +LGPL license. New features available in +this release are listed on the NEWS page. +

+ +

About Project

+

+

+

+ +
+ + +
+ +

What is Check?

+ +

+Check is a unit testing 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 both assertion failures +and code errors that cause segmentation faults or other signals can be +caught. Test results are reportable in the following: Subunit, +TAP, XML, and a generic logging format. +

+ +

Supported Platforms

+ +

+Check works on many UNIX compatible environments, such as GNU/Linux, +GNU/Hurd, BSD, and Mac OSX. Windows support is available through the Cygwin, +MinGW, and MinGW-w64 platforms, as well as with MSVC using Visual Studios or +CMake/NMake. If Check is compiled on a platform with some +POSIX functions unavailable (such as fork), Check will disable the +related features but still remain functional. Look at the +Install page for installation instructions +per platform. +

+ +

Support

+ +

+Questions are accepted on the mailing list +check-users@sourceforge.net +and bugs and feature requests can be submitted via the Github +page here. +

+ +

Contributing

+ +

+The authors welcome any and all help with Check, whether through +enhancement requests, bug reports, patches, or documentation. Please visit +the Check project page. +

+ +

+Patches to Check, unless trivial, should be against the master branch, +and should include a full set of unit tests verifying the new behavior. No +functionality goes into Check without unit tests, and submitting a +merge request without automated testing will delay potential acceptable of the patch. +

+ +

+The latest Check source can be browsed +here +or retrieved with git using the following: +

git clone https://github.com/libcheck/check.git
+

+ +
+ + + +
+ + + + diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt new file mode 100644 index 0000000..fabfdf2 --- /dev/null +++ b/lib/CMakeLists.txt @@ -0,0 +1,75 @@ +# +# Check: a unit test framework for C +# Copyright (C) 2011 Mateusz Loskot +# +# 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. +# + + +set(SOURCES libcompat.c) + +set(SOURCES ${SOURCES} fpclassify.c) + +if (NOT HAVE_LIBRT) + set(SOURCES ${SOURCES} clock_gettime.c) + set(SOURCES ${SOURCES} timer_create.c) + set(SOURCES ${SOURCES} timer_delete.c) + set(SOURCES ${SOURCES} timer_settime.c) +endif(NOT HAVE_LIBRT) + +if(NOT HAVE_GETLINE) + set(SOURCES ${SOURCES} getline.c) +endif(NOT HAVE_GETLINE) + +if(NOT HAVE_GETTIMEOFDAY) + set(SOURCES ${SOURCES} gettimeofday.c) +endif(NOT HAVE_GETTIMEOFDAY) + +if(NOT HAVE_DECL_LOCALTIME_R) + set(SOURCES ${SOURCES} localtime_r.c) +endif(NOT HAVE_DECL_LOCALTIME_R) + +if(NOT HAVE_MALLOC) + set(SOURCES ${SOURCES} malloc.c) +endif(NOT HAVE_MALLOC) + +if(NOT HAVE_REALLOC) + set(SOURCES ${SOURCES} realloc.c) +endif(NOT HAVE_REALLOC) + +if(NOT HAVE_SNPRINTF) + set(SOURCES ${SOURCES} snprintf.c) +endif(NOT HAVE_SNPRINTF) + +if(NOT HAVE_DECL_STRDUP AND NOT HAVE__STRDUP) + set(SOURCES ${SOURCES} strdup.c) +endif(NOT HAVE_DECL_STRDUP AND NOT HAVE__STRDUP) + +if(NOT HAVE_DECL_STRSIGNAL) + set(SOURCES ${SOURCES} strsignal.c) +endif(NOT HAVE_DECL_STRSIGNAL) + + +set(HEADERS libcompat.h) + +add_library(compat STATIC ${SOURCES} ${HEADERS}) + +install(TARGETS compat + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib) + +install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/libcompat.h DESTINATION include) diff --git a/lib/Makefile.am b/lib/Makefile.am new file mode 100644 index 0000000..12c4f20 --- /dev/null +++ b/lib/Makefile.am @@ -0,0 +1,6 @@ +## Process this file with automake to produce Makefile.in + +noinst_LTLIBRARIES = libcompat.la +libcompat_la_LDFLAGS = -no-undefined +libcompat_la_SOURCES = libcompat.c libcompat.h fpclassify.c +libcompat_la_LIBADD = $(LTLIBOBJS) $(LTALLOCA) diff --git a/lib/alarm.c b/lib/alarm.c new file mode 100644 index 0000000..0de00e5 --- /dev/null +++ b/lib/alarm.c @@ -0,0 +1,27 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "libcompat.h" + +unsigned int alarm(unsigned int seconds CK_ATTRIBUTE_UNUSED) +{ + assert(0); + return 0; +} diff --git a/lib/clock_gettime.c b/lib/clock_gettime.c new file mode 100644 index 0000000..d9e354d --- /dev/null +++ b/lib/clock_gettime.c @@ -0,0 +1,86 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "libcompat.h" + +#ifdef __APPLE__ +#include +#include +#include +#include +#include +#endif + +#define NANOSECONDS_PER_SECOND 1000000000 + + + +int clock_gettime(clockid_t clk_id CK_ATTRIBUTE_UNUSED, struct timespec *ts) +{ + +#ifdef __APPLE__ + /* Some versions of macOS and iOS do not have clock_gettime, use + * mach_absolute_time */ + + static mach_timebase_info_data_t sTimebaseInfo; + uint64_t rawTime; + uint64_t nanos; + + rawTime = mach_absolute_time(); + + /* + * OS X has a function to convert abs time to nano seconds: AbsoluteToNanoseconds + * However, the function may not be available as we may not have + * access to CoreServices. Because of this, we convert the abs time + * to nano seconds manually. + */ + + /* + * First grab the time base used on the system, if this is the first + * time we are being called. We can check if the value is uninitialized, + * as the denominator will be zero. + */ + if(sTimebaseInfo.denom == 0) + { + (void)mach_timebase_info(&sTimebaseInfo); + } + + /* + * Do the conversion. We hope that the multiplication doesn't + * overflow; the price you pay for working in fixed point. + */ + nanos = rawTime * sTimebaseInfo.numer / sTimebaseInfo.denom; + + /* + * Fill in the timespec container + */ + ts->tv_sec = nanos / NANOSECONDS_PER_SECOND; + ts->tv_nsec = nanos - (ts->tv_sec * NANOSECONDS_PER_SECOND); +#else + /* + * As there is no function to fall back onto to get the current + * time, zero out the time so the caller will have a sane value. + */ + ts->tv_sec = 0; + ts->tv_nsec = 0; +#endif + + return 0; +} diff --git a/lib/fpclassify.c b/lib/fpclassify.c new file mode 100644 index 0000000..2efa3a3 --- /dev/null +++ b/lib/fpclassify.c @@ -0,0 +1,63 @@ +/* Copyright (C) 2017, bel2125 + * + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +/* Note: Within "check", this file uses the LGPL license. + * If you need only this file, you may find a MIT licensed version in + * the "floatmagic" repository of the initial author. + */ + +#include "libcompat.h" + +double DOUBLE_ZERO = 0.0; + +#if defined(NEED_fpclassify) + +#if defined(HAVE_STDINT_H) +#include +typedef uint64_t bitfield64; +#elif defined(_MSC_VER) +typedef unsigned __int64 bitfield64; +#else +typedef unsigned long long bitfield64; +#endif + +static bitfield64 ms = 0x8000000000000000; +static bitfield64 me = 0x7FF0000000000000; +static bitfield64 mf = 0x000FFFFFFFFFFFFF; + +int fpclassify(double d) +{ + bitfield64 *p = (bitfield64 *)&d; + if ((*p & me) != me) { + /* finite */ + if (*p & mf) { + /* finite and not null */ + if (*p & me) { + return FP_NORMAL; + } + return FP_SUBNORMAL; + } + return FP_ZERO; + } + if (*p & mf) { + return FP_NAN; + } + return FP_INFINITE; +} + +#endif + diff --git a/lib/getline.c b/lib/getline.c new file mode 100644 index 0000000..c27da7e --- /dev/null +++ b/lib/getline.c @@ -0,0 +1,59 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "libcompat.h" +#include + +#define INITIAL_SIZE 16 +#define DELIMITER '\n' + +ssize_t getline(char **lineptr, size_t *n, FILE *stream) +{ + ssize_t written = 0; + int character; + + if(*lineptr == NULL || *n < INITIAL_SIZE) + { + free(*lineptr); + *lineptr = (char *)malloc(INITIAL_SIZE); + *n = INITIAL_SIZE; + } + + while( (character = fgetc(stream)) != EOF) + { + written += 1; + if(written >= *n) + { + *n = *n * 2; + *lineptr = realloc(*lineptr, *n); + } + + (*lineptr)[written-1] = character; + + if(character == DELIMITER) + { + break; + } + } + + (*lineptr)[written] = '\0'; + + return written; +} diff --git a/lib/gettimeofday.c b/lib/gettimeofday.c new file mode 100644 index 0000000..e2ee0b1 --- /dev/null +++ b/lib/gettimeofday.c @@ -0,0 +1,48 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "libcompat.h" +#include + +#if defined(_MSC_VER) || defined(__BORLANDC__) +#define EPOCHFILETIME (116444736000000000i64) +#else +#define EPOCHFILETIME (116444736000000000LL) +#endif + +int gettimeofday(struct timeval *tv, void *tz) +{ +#if defined(_MSC_VER) + union + { + __int64 ns100; /*time since 1 Jan 1601 in 100ns units */ + FILETIME ft; + } now; + + GetSystemTimeAsFileTime(&now.ft); + tv->tv_usec = (long)((now.ns100 / 10LL) % 1000000LL); + tv->tv_sec = (long)((now.ns100 - EPOCHFILETIME) / 10000000LL); + return (0); +#else + // Return that there is no implementation of this on the system + errno = ENOSYS; + return -1; +#endif /* _MSC_VER */ +} diff --git a/lib/libcompat.c b/lib/libcompat.c new file mode 100644 index 0000000..e9b654a --- /dev/null +++ b/lib/libcompat.c @@ -0,0 +1,34 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "libcompat.h" + +/* silence warnings about an empty library */ +void ck_do_nothing(void) +{ + assert(0); + + /* + * to silence warning about this function actually + * returning, but being marked as noreturn. assert() + * must be marked as a function that returns. + */ + exit(1); +} diff --git a/lib/libcompat.h b/lib/libcompat.h new file mode 100644 index 0000000..9ec6eb8 --- /dev/null +++ b/lib/libcompat.h @@ -0,0 +1,255 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef LIBCOMPAT_H +#define LIBCOMPAT_H + +#if HAVE_CONFIG_H +#include +#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 */ + +#if GCC_VERSION_AT_LEAST(2,5) +#define CK_ATTRIBUTE_NORETURN __attribute__ ((noreturn)) +#else +#define CK_ATTRIBUTE_NORETURN +#endif /* GCC 2.5 */ + +/* + * Used for MSVC to create the export attribute + * CK_DLL_EXP is defined during the compilation of the library + * on the command line. + */ +#ifndef CK_DLL_EXP +#define CK_DLL_EXP +#endif + +#if defined(_MSC_VER) +#include /* struct timeval, API used in gettimeofday implementation */ +#include /* read, write */ +#include /* getpid */ +#endif /* _MSC_VER */ + +/* defines size_t */ +#include + +/* provides assert */ +#include + +/* defines FILE */ +#include + +/* defines exit() */ +#include + +/* defines NAN, INFINITY, isnan(), isinf(), isfinite() */ +#include + +/* However, some older Visual Studio Versions do not */ +#if !defined(INFINITY) || !defined(NAN) +extern double DOUBLE_ZERO; +#define INFINITY (1.0/DOUBLE_ZERO) +#define NAN (DOUBLE_ZERO/DOUBLE_ZERO) +#endif +#if !defined(isnan) || !defined(isinf) || !defined(isfinite) +#define NEED_fpclassify +extern int fpclassify(double d); +#define FP_INFINITE (1) +#define FP_NAN (2) +#define FP_ZERO (4) +#define FP_NORMAL (8) +#define FP_SUBNORMAL (16) +#define isnan(x) ((fpclassify((double)(x)) & FP_NAN) == FP_NAN) +#define isinf(x) ((fpclassify((double)(x)) & FP_INFINITE) == FP_INFINITE) +#define isfinite(x) ((fpclassify((double)(x)) & (FP_NAN|FP_INFINITE)) == 0) +#endif + + +/* provides localtime and struct tm */ +#ifdef HAVE_SYS_TIME_H +#include +#endif /* !HAVE_SYS_TIME_H */ +#include + +/* declares fork(), _POSIX_VERSION. according to Autoconf.info, + unistd.h defines _POSIX_VERSION if the system is POSIX-compliant, + so we will use this as a test for all things uniquely provided by + POSIX like sigaction() and fork() */ +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef HAVE_SYS_WAIT_H +#include +#endif + +/* declares pthread_create and friends */ +#ifdef HAVE_PTHREAD +#include +#endif + +#ifdef HAVE_STDINT_H +#include +#endif + +/* replacement functions for broken originals */ +#if !HAVE_DECL_ALARM +CK_DLL_EXP unsigned int alarm(unsigned int seconds); +#endif /* !HAVE_DECL_ALARM */ + +#if !HAVE_MALLOC +CK_DLL_EXP void *rpl_malloc(size_t n); +#endif /* !HAVE_MALLOC */ + +#if !HAVE_REALLOC +CK_DLL_EXP void *rpl_realloc(void *p, size_t n); +#endif /* !HAVE_REALLOC */ + +#if !HAVE_GETPID && HAVE__GETPID +#define getpid _getpid +#endif /* !HAVE_GETPID && HAVE__GETPID */ + +#if !HAVE_GETTIMEOFDAY +CK_DLL_EXP int gettimeofday(struct timeval *tv, void *tz); +#endif /* !HAVE_GETTIMEOFDAY */ + +#if !HAVE_DECL_LOCALTIME_R +#if !defined(localtime_r) +CK_DLL_EXP struct tm *localtime_r(const time_t * clock, struct tm *result); +#endif +#endif /* !HAVE_DECL_LOCALTIME_R */ + +#if !HAVE_DECL_STRDUP && !HAVE__STRDUP +CK_DLL_EXP char *strdup(const char *str); +#elif !HAVE_DECL_STRDUP && HAVE__STRDUP +#define strdup _strdup +#endif /* !HAVE_DECL_STRDUP && HAVE__STRDUP */ + +#if !HAVE_DECL_STRSIGNAL +CK_DLL_EXP char *strsignal(int sig); +#endif /* !HAVE_DECL_STRSIGNAL */ + +/* + * On systems where clock_gettime() is not available, or + * on systems where some clocks may not be supported, the + * definition for CLOCK_MONOTONIC and CLOCK_REALTIME may not + * be available. These should define which type of clock + * clock_gettime() should use. We define it here if it is + * not defined simply so the reimplementation can ignore it. + * + * We set the values of these clocks to some (hopefully) + * invalid value, to avoid the case where we define a + * clock with a valid value, and unintentionally use + * an actual good clock by accident. + */ +#ifndef CLOCK_MONOTONIC +#define CLOCK_MONOTONIC -1 +#endif +#ifndef CLOCK_REALTIME +#define CLOCK_REALTIME -1 +#endif + +#ifndef HAVE_LIBRT + +#ifdef STRUCT_TIMESPEC_DEFINITION_MISSING +/* + * The following structure is defined in POSIX 1003.1 for times + * specified in seconds and nanoseconds. If it is not defined in + * time.g, then we need to define it here + */ +struct timespec +{ + time_t tv_sec; + long tv_nsec; +}; +#endif /* STRUCT_TIMESPEC_DEFINITION_MISSING */ + +#ifdef STRUCT_ITIMERSPEC_DEFINITION_MISSING +/* + * The following structure is defined in POSIX.1b for timer start values and intervals. + * If it is not defined in time.h, then we need to define it here. + */ +struct itimerspec +{ + struct timespec it_interval; + struct timespec it_value; +}; +#endif /* STRUCT_ITIMERSPEC_DEFINITION_MISSING */ + +/* + * Do a simple forward declaration in case the struct is not defined. + * In the versions of timer_create in libcompat, sigevent is never + * used. + */ +struct sigevent; + +CK_DLL_EXP int clock_gettime(clockid_t clk_id, struct timespec *ts); +CK_DLL_EXP int timer_create(clockid_t clockid, struct sigevent *sevp, + timer_t * timerid); +CK_DLL_EXP int timer_settime(timer_t timerid, int flags, + const struct itimerspec *new_value, + struct itimerspec *old_value); +CK_DLL_EXP int timer_delete(timer_t timerid); +#endif /* HAVE_LIBRT */ + +/* + * The following checks are to determine if the system's + * snprintf (or its variants) should be replaced with + * the C99 compliant version in libcompat. + */ +#if HAVE_CONFIG_H +#include +#endif +#if HAVE_STDARG_H +#include + +#if !HAVE_VSNPRINTF +CK_DLL_EXP int rpl_vsnprintf(char *, size_t, const char *, va_list); + +#define vsnprintf rpl_vsnprintf +#endif +#if !HAVE_SNPRINTF +CK_DLL_EXP int rpl_snprintf(char *, size_t, const char *, ...); + +#define snprintf rpl_snprintf +#endif +#endif /* HAVE_STDARG_H */ + +#if !HAVE_GETLINE +CK_DLL_EXP ssize_t getline(char **lineptr, size_t *n, FILE *stream); +#endif + +/* silence warnings about an empty library */ +CK_DLL_EXP void ck_do_nothing(void) CK_ATTRIBUTE_NORETURN; + +#endif /* !LIBCOMPAT_H */ diff --git a/lib/localtime_r.c b/lib/localtime_r.c new file mode 100644 index 0000000..540527d --- /dev/null +++ b/lib/localtime_r.c @@ -0,0 +1,41 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "libcompat.h" + +#if !defined(localtime_r) + +struct tm *localtime_r(const time_t * clock, struct tm *result) +{ + struct tm *now = localtime(clock); + + if(now == NULL) + { + return NULL; + } + else + { + *result = *now; + } + + return result; +} + +#endif /* !defined(localtime_r) */ diff --git a/lib/malloc.c b/lib/malloc.c new file mode 100644 index 0000000..8cc0044 --- /dev/null +++ b/lib/malloc.c @@ -0,0 +1,40 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +/* + * AC_FUNC_MALLOC in configure defines malloc to rpl_malloc if + * malloc (0) is NULL to provide GNU compatibility + */ + +#include "libcompat.h" + +/* malloc has been defined to rpl_malloc, so first undo that */ +#undef malloc + +/* this gives us the real malloc to use below */ +void *malloc(size_t n); + +/* force malloc(0) to return a valid pointer */ +void *rpl_malloc(size_t n) +{ + if(n == 0) + n = 1; + return malloc(n); +} diff --git a/lib/realloc.c b/lib/realloc.c new file mode 100644 index 0000000..7d72876 --- /dev/null +++ b/lib/realloc.c @@ -0,0 +1,43 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +/* + * AC_FUNC_REALLOC in configure defines realloc to rpl_realloc if + * realloc (p, 0) or realloc (0, n) is NULL to provide GNU + * compatibility + */ + +#include "libcompat.h" + +/* realloc has been defined to rpl_realloc, so first undo that */ +#undef realloc + +/* this gives us the real realloc to use below */ +void *realloc(void *p, size_t n); + +/* force realloc(p, 0) and realloc (NULL, n) to return a valid pointer */ +void *rpl_realloc(void *p, size_t n) +{ + if(n == 0) + n = 1; + if(p == 0) + return malloc(n); + return realloc(p, n); +} diff --git a/lib/snprintf.c b/lib/snprintf.c new file mode 100644 index 0000000..b91b65c --- /dev/null +++ b/lib/snprintf.c @@ -0,0 +1,2022 @@ +/* $Id: snprintf.c,v 1.9 2008/01/20 14:02:00 holger Exp $ */ + +/* + * Copyright (c) 1995 Patrick Powell. + * + * This code is based on code written by Patrick Powell . + * It may be used for any purpose as long as this notice remains intact on all + * source code distributions. + */ + +/* + * Copyright (c) 2008 Holger Weiss. + * + * This version of the code is maintained by Holger Weiss . + * My changes to the code may freely be used, modified and/or redistributed for + * any purpose. It would be nice if additions and fixes to this file (including + * trivial code cleanups) would be sent back in order to let me include them in + * the version available at . + * However, this is not a requirement for using or redistributing (possibly + * modified) versions of this file, nor is leaving this notice intact mandatory. + */ + +/* + * History + * + * 2008-01-20 Holger Weiss for C99-snprintf 1.1: + * + * Fixed the detection of infinite floating point values on IRIX (and + * possibly other systems) and applied another few minor cleanups. + * + * 2008-01-06 Holger Weiss for C99-snprintf 1.0: + * + * Added a lot of new features, fixed many bugs, and incorporated various + * improvements done by Andrew Tridgell , Russ Allbery + * , Hrvoje Niksic , Damien Miller + * , and others for the Samba, INN, Wget, and OpenSSH + * projects. The additions include: support the "e", "E", "g", "G", and + * "F" conversion specifiers (and use conversion style "f" or "F" for the + * still unsupported "a" and "A" specifiers); support the "hh", "ll", "j", + * "t", and "z" length modifiers; support the "#" flag and the (non-C99) + * "'" flag; use localeconv(3) (if available) to get both the current + * locale's decimal point character and the separator between groups of + * digits; fix the handling of various corner cases of field width and + * precision specifications; fix various floating point conversion bugs; + * handle infinite and NaN floating point values; don't attempt to write to + * the output buffer (which may be NULL) if a size of zero was specified; + * check for integer overflow of the field width, precision, and return + * values and during the floating point conversion; use the OUTCHAR() macro + * instead of a function for better performance; provide asprintf(3) and + * vasprintf(3) functions; add new test cases. The replacement functions + * have been renamed to use an "rpl_" prefix, the function calls in the + * main project (and in this file) must be redefined accordingly for each + * replacement function which is needed (by using Autoconf or other means). + * Various other minor improvements have been applied and the coding style + * was cleaned up for consistency. + * + * 2007-07-23 Holger Weiss for Mutt 1.5.13: + * + * C99 compliant snprintf(3) and vsnprintf(3) functions return the number + * of characters that would have been written to a sufficiently sized + * buffer (excluding the '\0'). The original code simply returned the + * length of the resulting output string, so that's been fixed. + * + * 1998-03-05 Michael Elkins for Mutt 0.90.8: + * + * The original code assumed that both snprintf(3) and vsnprintf(3) were + * missing. Some systems only have snprintf(3) but not vsnprintf(3), so + * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF. + * + * 1998-01-27 Thomas Roessler for Mutt 0.89i: + * + * The PGP code was using unsigned hexadecimal formats. Unfortunately, + * unsigned formats simply didn't work. + * + * 1997-10-22 Brandon Long for Mutt 0.87.1: + * + * Ok, added some minimal floating point support, which means this probably + * requires libm on most operating systems. Don't yet support the exponent + * (e,E) and sigfig (g,G). Also, fmtint() was pretty badly broken, it just + * wasn't being exercised in ways which showed it, so that's been fixed. + * Also, formatted the code to Mutt conventions, and removed dead code left + * over from the original. Also, there is now a builtin-test, run with: + * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm && ./snprintf + * + * 2996-09-15 Brandon Long for Mutt 0.43: + * + * This was ugly. It is still ugly. I opted out of floating point + * numbers, but the formatter understands just about everything from the + * normal C string format, at least as far as I can tell from the Solaris + * 2.5 printf(3S) man page. + */ + +/* + * ToDo + * + * - Add wide character support. + * - Add support for "%a" and "%A" conversions. + * - Create test routines which predefine the expected results. Our test cases + * usually expose bugs in system implementations rather than in ours :-) + */ + +/* + * Usage + * + * 1) The following preprocessor macros should be defined to 1 if the feature or + * file in question is available on the target system (by using Autoconf or + * other means), though basic functionality should be available as long as + * HAVE_STDARG_H and HAVE_STDLIB_H are defined correctly: + * + * HAVE_VSNPRINTF + * HAVE_SNPRINTF + * HAVE_VASPRINTF + * HAVE_ASPRINTF + * HAVE_STDARG_H + * HAVE_STDDEF_H + * HAVE_STDINT_H + * HAVE_STDLIB_H + * HAVE_INTTYPES_H + * HAVE_LOCALE_H + * HAVE_LOCALECONV + * HAVE_LCONV_DECIMAL_POINT + * HAVE_LCONV_THOUSANDS_SEP + * HAVE_LONG_DOUBLE + * HAVE_LONG_LONG_INT + * HAVE_UNSIGNED_LONG_LONG_INT + * HAVE_INTMAX_T + * HAVE_UINTMAX_T + * HAVE_UINTPTR_T + * HAVE_PTRDIFF_T + * HAVE_VA_COPY + * HAVE___VA_COPY + * + * 2) The calls to the functions which should be replaced must be redefined + * throughout the project files (by using Autoconf or other means): + * + * #define vsnprintf rpl_vsnprintf + * #define snprintf rpl_snprintf + * #define vasprintf rpl_vasprintf + * #define asprintf rpl_asprintf + * + * 3) The required replacement functions should be declared in some header file + * included throughout the project files: + * + * #if HAVE_CONFIG_H + * #include + * #endif + * #if HAVE_STDARG_H + * #include + * #if !HAVE_VSNPRINTF + * int rpl_vsnprintf(char *, size_t, const char *, va_list); + * #endif + * #if !HAVE_SNPRINTF + * int rpl_snprintf(char *, size_t, const char *, ...); + * #endif + * #if !HAVE_VASPRINTF + * int rpl_vasprintf(char **, const char *, va_list); + * #endif + * #if !HAVE_ASPRINTF + * int rpl_asprintf(char **, const char *, ...); + * #endif + * #endif + * + * Autoconf macros for handling step 1 and step 2 are available at + * . + */ + +#if HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#if TEST_SNPRINTF +#include /* For pow(3), NAN, and INFINITY. */ +#include /* For strcmp(3). */ +#if defined(__NetBSD__) || \ + defined(__FreeBSD__) || \ + defined(__OpenBSD__) || \ + defined(__NeXT__) || \ + defined(__bsd__) +#define OS_BSD 1 +#elif defined(sgi) || defined(__sgi) +#ifndef __c99 +#define __c99 /* Force C99 mode to get included on IRIX 6.5.30. */ +#endif /* !defined(__c99) */ +#define OS_IRIX 1 +#define OS_SYSV 1 +#elif defined(__svr4__) +#define OS_SYSV 1 +#elif defined(__linux__) +#define OS_LINUX 1 +#endif /* defined(__NetBSD__) || defined(__FreeBSD__) || [...] */ +#if HAVE_CONFIG_H /* Undefine definitions possibly done in config.h. */ +#ifdef HAVE_SNPRINTF +#undef HAVE_SNPRINTF +#endif /* defined(HAVE_SNPRINTF) */ +#ifdef HAVE_VSNPRINTF +#undef HAVE_VSNPRINTF +#endif /* defined(HAVE_VSNPRINTF) */ +#ifdef snprintf +#undef snprintf +#endif /* defined(snprintf) */ +#ifdef vsnprintf +#undef vsnprintf +#endif /* defined(vsnprintf) */ +#else /* By default, we assume a modern system for testing. */ +#ifndef HAVE_STDARG_H +#define HAVE_STDARG_H 1 +#endif /* HAVE_STDARG_H */ +#ifndef HAVE_STDDEF_H +#define HAVE_STDDEF_H 1 +#endif /* HAVE_STDDEF_H */ +#ifndef HAVE_STDINT_H +#define HAVE_STDINT_H 1 +#endif /* HAVE_STDINT_H */ +#ifndef HAVE_STDLIB_H +#define HAVE_STDLIB_H 1 +#endif /* HAVE_STDLIB_H */ +#ifndef HAVE_INTTYPES_H +#define HAVE_INTTYPES_H 1 +#endif /* HAVE_INTTYPES_H */ +#ifndef HAVE_LOCALE_H +#define HAVE_LOCALE_H 1 +#endif /* HAVE_LOCALE_H */ +#ifndef HAVE_LOCALECONV +#define HAVE_LOCALECONV 1 +#endif /* !defined(HAVE_LOCALECONV) */ +#ifndef HAVE_LCONV_DECIMAL_POINT +#define HAVE_LCONV_DECIMAL_POINT 1 +#endif /* HAVE_LCONV_DECIMAL_POINT */ +#ifndef HAVE_LCONV_THOUSANDS_SEP +#define HAVE_LCONV_THOUSANDS_SEP 1 +#endif /* HAVE_LCONV_THOUSANDS_SEP */ +#ifndef HAVE_LONG_DOUBLE +#define HAVE_LONG_DOUBLE 1 +#endif /* !defined(HAVE_LONG_DOUBLE) */ +#ifndef HAVE_LONG_LONG_INT +#define HAVE_LONG_LONG_INT 1 +#endif /* !defined(HAVE_LONG_LONG_INT) */ +#ifndef HAVE_UNSIGNED_LONG_LONG_INT +#define HAVE_UNSIGNED_LONG_LONG_INT 1 +#endif /* !defined(HAVE_UNSIGNED_LONG_LONG_INT) */ +#ifndef HAVE_INTMAX_T +#define HAVE_INTMAX_T 1 +#endif /* !defined(HAVE_INTMAX_T) */ +#ifndef HAVE_UINTMAX_T +#define HAVE_UINTMAX_T 1 +#endif /* !defined(HAVE_UINTMAX_T) */ +#ifndef HAVE_UINTPTR_T +#define HAVE_UINTPTR_T 1 +#endif /* !defined(HAVE_UINTPTR_T) */ +#ifndef HAVE_PTRDIFF_T +#define HAVE_PTRDIFF_T 1 +#endif /* !defined(HAVE_PTRDIFF_T) */ +#ifndef HAVE_VA_COPY +#define HAVE_VA_COPY 1 +#endif /* !defined(HAVE_VA_COPY) */ +#ifndef HAVE___VA_COPY +#define HAVE___VA_COPY 1 +#endif /* !defined(HAVE___VA_COPY) */ +#endif /* HAVE_CONFIG_H */ +#define snprintf rpl_snprintf +#define vsnprintf rpl_vsnprintf +#endif /* TEST_SNPRINTF */ + +#if !HAVE_SNPRINTF || !HAVE_VSNPRINTF +#include /* For NULL, size_t, vsnprintf(3), and vasprintf(3). */ +#ifdef VA_START +#undef VA_START +#endif /* defined(VA_START) */ +#ifdef VA_SHIFT +#undef VA_SHIFT +#endif /* defined(VA_SHIFT) */ +#if HAVE_STDARG_H +#include +#define VA_START(ap, last) va_start(ap, last) +#define VA_SHIFT(ap, value, type) /* No-op for ANSI C. */ +#else /* Assume is available. */ +#include +#define VA_START(ap, last) va_start(ap) /* "last" is ignored. */ +#define VA_SHIFT(ap, value, type) value = va_arg(ap, type) +#endif /* HAVE_STDARG_H */ + +#if !HAVE_VSNPRINTF +#include /* For ERANGE and errno. */ +#include /* For *_MAX. */ +#if HAVE_INTTYPES_H +#include /* For intmax_t (if not defined in ). */ +#endif /* HAVE_INTTYPES_H */ +#if HAVE_LOCALE_H +#include /* For localeconv(3). */ +#endif /* HAVE_LOCALE_H */ +#if HAVE_STDDEF_H +#include /* For ptrdiff_t. */ +#endif /* HAVE_STDDEF_H */ +#if HAVE_STDINT_H +#include /* For intmax_t. */ +#endif /* HAVE_STDINT_H */ + +/* Support for unsigned long long int. We may also need ULLONG_MAX. */ +#ifndef ULONG_MAX /* We may need ULONG_MAX as a fallback. */ +#ifdef UINT_MAX +#define ULONG_MAX UINT_MAX +#else +#define ULONG_MAX INT_MAX +#endif /* defined(UINT_MAX) */ +#endif /* !defined(ULONG_MAX) */ +#ifdef ULLONG +#undef ULLONG +#endif /* defined(ULLONG) */ +#if HAVE_UNSIGNED_LONG_LONG_INT +#define ULLONG unsigned long long int +#ifndef ULLONG_MAX +#define ULLONG_MAX ULONG_MAX +#endif /* !defined(ULLONG_MAX) */ +#else +#define ULLONG unsigned long int +#ifdef ULLONG_MAX +#undef ULLONG_MAX +#endif /* defined(ULLONG_MAX) */ +#define ULLONG_MAX ULONG_MAX +#endif /* HAVE_LONG_LONG_INT */ + +/* Support for uintmax_t. We also need UINTMAX_MAX. */ +#ifdef UINTMAX_T +#undef UINTMAX_T +#endif /* defined(UINTMAX_T) */ +#if defined(HAVE_UINTMAX_T) || defined(uintmax_t) +#define UINTMAX_T uintmax_t +#ifndef UINTMAX_MAX +#define UINTMAX_MAX ULLONG_MAX +#endif /* !defined(UINTMAX_MAX) */ +#else +#define UINTMAX_T ULLONG +#ifdef UINTMAX_MAX +#undef UINTMAX_MAX +#endif /* defined(UINTMAX_MAX) */ +#define UINTMAX_MAX ULLONG_MAX +#endif /* HAVE_UINTMAX_T || defined(uintmax_t) */ + +/* Support for long double. */ +#ifndef LDOUBLE +#if HAVE_LONG_DOUBLE +#define LDOUBLE long double +#else +#define LDOUBLE double +#endif /* HAVE_LONG_DOUBLE */ +#endif /* !defined(LDOUBLE) */ + +/* Support for long long int. */ +#ifndef LLONG +#if HAVE_LONG_LONG_INT +#define LLONG long long int +#else +#define LLONG long int +#endif /* HAVE_LONG_LONG_INT */ +#endif /* !defined(LLONG) */ + +/* Support for intmax_t. */ +#ifndef INTMAX_T +#if defined(HAVE_INTMAX_T) || defined(intmax_t) +#define INTMAX_T intmax_t +#else +#define INTMAX_T LLONG +#endif /* HAVE_INTMAX_T || defined(intmax_t) */ +#endif /* !defined(INTMAX_T) */ + +/* Support for uintptr_t. */ +#ifndef UINTPTR_T +#if defined(HAVE_UINTPTR_T) || defined(uintptr_t) +#define UINTPTR_T uintptr_t +#else +#define UINTPTR_T unsigned long int +#endif /* HAVE_UINTPTR_T || defined(uintptr_t) */ +#endif /* !defined(UINTPTR_T) */ + +/* Support for ptrdiff_t. */ +#ifndef PTRDIFF_T +#if defined(HAVE_PTRDIFF_T) || defined(ptrdiff_t) +#define PTRDIFF_T ptrdiff_t +#else +#define PTRDIFF_T long int +#endif /* HAVE_PTRDIFF_T || defined(ptrdiff_t) */ +#endif /* !defined(PTRDIFF_T) */ + +/* + * We need an unsigned integer type corresponding to ptrdiff_t (cf. C99: + * 7.19.6.1, 7). However, we'll simply use PTRDIFF_T and convert it to an + * unsigned type if necessary. This should work just fine in practice. + */ +#ifndef UPTRDIFF_T +#define UPTRDIFF_T PTRDIFF_T +#endif /* !defined(UPTRDIFF_T) */ + +/* + * We need a signed integer type corresponding to size_t (cf. C99: 7.19.6.1, 7). + * However, we'll simply use size_t and convert it to a signed type if + * necessary. This should work just fine in practice. + */ +#ifndef SSIZE_T +#define SSIZE_T size_t +#endif /* !defined(SSIZE_T) */ + +/* Either ERANGE or E2BIG should be available everywhere. */ +#ifndef ERANGE +#define ERANGE E2BIG +#endif /* !defined(ERANGE) */ +#ifndef EOVERFLOW +#define EOVERFLOW ERANGE +#endif /* !defined(EOVERFLOW) */ + +/* + * Buffer size to hold the octal string representation of UINT128_MAX without + * nul-termination ("3777777777777777777777777777777777777777777"). + */ +#ifdef MAX_CONVERT_LENGTH +#undef MAX_CONVERT_LENGTH +#endif /* defined(MAX_CONVERT_LENGTH) */ +#define MAX_CONVERT_LENGTH 43 + +/* Format read states. */ +#define PRINT_S_DEFAULT 0 +#define PRINT_S_FLAGS 1 +#define PRINT_S_WIDTH 2 +#define PRINT_S_DOT 3 +#define PRINT_S_PRECISION 4 +#define PRINT_S_MOD 5 +#define PRINT_S_CONV 6 + +/* Format flags. */ +#define PRINT_F_MINUS (1 << 0) +#define PRINT_F_PLUS (1 << 1) +#define PRINT_F_SPACE (1 << 2) +#define PRINT_F_NUM (1 << 3) +#define PRINT_F_ZERO (1 << 4) +#define PRINT_F_QUOTE (1 << 5) +#define PRINT_F_UP (1 << 6) +#define PRINT_F_UNSIGNED (1 << 7) +#define PRINT_F_TYPE_G (1 << 8) +#define PRINT_F_TYPE_E (1 << 9) + +/* Conversion flags. */ +#define PRINT_C_CHAR 1 +#define PRINT_C_SHORT 2 +#define PRINT_C_LONG 3 +/*#define PRINT_C_LLONG 4 */ +#define PRINT_C_LDOUBLE 5 +#define PRINT_C_SIZE 6 +#define PRINT_C_PTRDIFF 7 +#define PRINT_C_INTMAX 8 + +#ifndef MAX +#define MAX(x, y) ((x >= y) ? x : y) +#endif /* !defined(MAX) */ +#ifndef CHARTOINT +#define CHARTOINT(ch) (ch - '0') +#endif /* !defined(CHARTOINT) */ +#ifndef ISDIGIT +#define ISDIGIT(ch) ('0' <= (unsigned char)ch && (unsigned char)ch <= '9') +#endif /* !defined(ISDIGIT) */ +#ifndef ISNAN +#define ISNAN(x) (x != x) +#endif /* !defined(ISNAN) */ +#ifndef ISINF +#define ISINF(x) (x != 0.0 && x + x == x) +#endif /* !defined(ISINF) */ + +#ifdef OUTCHAR +#undef OUTCHAR +#endif /* defined(OUTCHAR) */ +#define OUTCHAR(str, len, size, ch) \ +do { \ + if (len + 1 < size) \ + str[len] = ch; \ + (len)++; \ +} while (/* CONSTCOND */ 0) + +static void fmtstr(char *, size_t *, size_t, const char *, int, int, int); +static void fmtint(char *, size_t *, size_t, INTMAX_T, int, int, int, int); +static void fmtflt(char *, size_t *, size_t, LDOUBLE, int, int, int, int *); +static void printsep(char *, size_t *, size_t); +static int getnumsep(int); +static int getexponent(LDOUBLE); +static int convert(UINTMAX_T, char *, size_t, int, int); +static UINTMAX_T cast(LDOUBLE); +static UINTMAX_T myround(LDOUBLE); +static LDOUBLE mypow10(int); + +extern int errno; + +int +rpl_vsnprintf(char *str, size_t size, const char *format, va_list args) +{ + LDOUBLE fvalue; + INTMAX_T value; + unsigned char cvalue; + const char *strvalue; + INTMAX_T *intmaxptr; + PTRDIFF_T *ptrdiffptr; + SSIZE_T *sizeptr; + /* Disabling, as long long is not supported in C90. + LLONG *llongptr; + */ + long int *longptr; + int *intptr; + short int *shortptr; + signed char *charptr; + size_t len = 0; + int overflow = 0; + int base = 0; + int cflags = 0; + int flags = 0; + int width = 0; + int precision = -1; + int state = PRINT_S_DEFAULT; + char ch = *format++; + + /* + * C99 says: "If `n' is zero, nothing is written, and `s' may be a null + * pointer." (7.19.6.5, 2) We're forgiving and allow a NULL pointer + * even if a size larger than zero was specified. At least NetBSD's + * snprintf(3) does the same, as well as other versions of this file. + * (Though some of these versions will write to a non-NULL buffer even + * if a size of zero was specified, which violates the standard.) + */ + if (str == NULL && size != 0) + size = 0; + + while (ch != '\0') + switch (state) { + case PRINT_S_DEFAULT: + if (ch == '%') + state = PRINT_S_FLAGS; + else + OUTCHAR(str, len, size, ch); + ch = *format++; + break; + case PRINT_S_FLAGS: + switch (ch) { + case '-': + flags |= PRINT_F_MINUS; + ch = *format++; + break; + case '+': + flags |= PRINT_F_PLUS; + ch = *format++; + break; + case ' ': + flags |= PRINT_F_SPACE; + ch = *format++; + break; + case '#': + flags |= PRINT_F_NUM; + ch = *format++; + break; + case '0': + flags |= PRINT_F_ZERO; + ch = *format++; + break; + case '\'': /* SUSv2 flag (not in C99). */ + flags |= PRINT_F_QUOTE; + ch = *format++; + break; + default: + state = PRINT_S_WIDTH; + break; + } + break; + case PRINT_S_WIDTH: + if (ISDIGIT(ch)) { + ch = CHARTOINT(ch); + if (width > (INT_MAX - ch) / 10) { + overflow = 1; + goto out; + } + width = 10 * width + ch; + ch = *format++; + } else if (ch == '*') { + /* + * C99 says: "A negative field width argument is + * taken as a `-' flag followed by a positive + * field width." (7.19.6.1, 5) + */ + if ((width = va_arg(args, int)) < 0) { + flags |= PRINT_F_MINUS; + width = -width; + } + ch = *format++; + state = PRINT_S_DOT; + } else + state = PRINT_S_DOT; + break; + case PRINT_S_DOT: + if (ch == '.') { + state = PRINT_S_PRECISION; + ch = *format++; + } else + state = PRINT_S_MOD; + break; + case PRINT_S_PRECISION: + if (precision == -1) + precision = 0; + if (ISDIGIT(ch)) { + ch = CHARTOINT(ch); + if (precision > (INT_MAX - ch) / 10) { + overflow = 1; + goto out; + } + precision = 10 * precision + ch; + ch = *format++; + } else if (ch == '*') { + /* + * C99 says: "A negative precision argument is + * taken as if the precision were omitted." + * (7.19.6.1, 5) + */ + if ((precision = va_arg(args, int)) < 0) + precision = -1; + ch = *format++; + state = PRINT_S_MOD; + } else + state = PRINT_S_MOD; + break; + case PRINT_S_MOD: + switch (ch) { + case 'h': + ch = *format++; + if (ch == 'h') { /* It's a char. */ + ch = *format++; + cflags = PRINT_C_CHAR; + } else + cflags = PRINT_C_SHORT; + break; + case 'l': + ch = *format++; + /* + if (ch == 'l') } + ch = *format++; + cflags = PRINT_C_LLONG; + } else */ + cflags = PRINT_C_LONG; + break; + case 'L': + cflags = PRINT_C_LDOUBLE; + ch = *format++; + break; + case 'j': + cflags = PRINT_C_INTMAX; + ch = *format++; + break; + case 't': + cflags = PRINT_C_PTRDIFF; + ch = *format++; + break; + case 'z': + cflags = PRINT_C_SIZE; + ch = *format++; + break; + default: + /* Lenght modifier is invalid */ + break; + } + state = PRINT_S_CONV; + break; + case PRINT_S_CONV: + switch (ch) { + case 'd': + /* FALLTHROUGH */ + case 'i': + switch (cflags) { + case PRINT_C_CHAR: + value = (signed char)va_arg(args, int); + break; + case PRINT_C_SHORT: + value = (short int)va_arg(args, int); + break; + case PRINT_C_LONG: + value = va_arg(args, long int); + break; + /* + case PRINT_C_LLONG: + value = va_arg(args, LLONG); + break; + */ + case PRINT_C_SIZE: + value = va_arg(args, SSIZE_T); + break; + case PRINT_C_INTMAX: + value = va_arg(args, INTMAX_T); + break; + case PRINT_C_PTRDIFF: + value = va_arg(args, PTRDIFF_T); + break; + default: + value = va_arg(args, int); + break; + } + fmtint(str, &len, size, value, 10, width, + precision, flags); + break; + case 'X': + flags |= PRINT_F_UP; + /* FALLTHROUGH */ + case 'x': + base = 16; + /* FALLTHROUGH */ + case 'o': + if (base == 0) + base = 8; + /* FALLTHROUGH */ + case 'u': + if (base == 0) + base = 10; + flags |= PRINT_F_UNSIGNED; + switch (cflags) { + case PRINT_C_CHAR: + value = (unsigned char)va_arg(args, + unsigned int); + break; + case PRINT_C_SHORT: + value = (unsigned short int)va_arg(args, + unsigned int); + break; + case PRINT_C_LONG: + value = va_arg(args, unsigned long int); + break; + /* + case PRINT_C_LLONG: + value = va_arg(args, ULLONG); + break; + */ + case PRINT_C_SIZE: + value = va_arg(args, size_t); + break; + case PRINT_C_INTMAX: + value = va_arg(args, UINTMAX_T); + break; + case PRINT_C_PTRDIFF: + value = va_arg(args, UPTRDIFF_T); + break; + default: + value = va_arg(args, unsigned int); + break; + } + fmtint(str, &len, size, value, base, width, + precision, flags); + break; + case 'A': + /* Not yet supported, we'll use "%F". */ + /* FALLTHROUGH */ + case 'F': + flags |= PRINT_F_UP; + case 'a': + /* Not yet supported, we'll use "%f". */ + /* FALLTHROUGH */ + case 'f': + if (cflags == PRINT_C_LDOUBLE) + fvalue = va_arg(args, LDOUBLE); + else + fvalue = va_arg(args, double); + fmtflt(str, &len, size, fvalue, width, + precision, flags, &overflow); + if (overflow) + goto out; + break; + case 'E': + flags |= PRINT_F_UP; + /* FALLTHROUGH */ + case 'e': + flags |= PRINT_F_TYPE_E; + if (cflags == PRINT_C_LDOUBLE) + fvalue = va_arg(args, LDOUBLE); + else + fvalue = va_arg(args, double); + fmtflt(str, &len, size, fvalue, width, + precision, flags, &overflow); + if (overflow) + goto out; + break; + case 'G': + flags |= PRINT_F_UP; + /* FALLTHROUGH */ + case 'g': + flags |= PRINT_F_TYPE_G; + if (cflags == PRINT_C_LDOUBLE) + fvalue = va_arg(args, LDOUBLE); + else + fvalue = va_arg(args, double); + /* + * If the precision is zero, it is treated as + * one (cf. C99: 7.19.6.1, 8). + */ + if (precision == 0) + precision = 1; + fmtflt(str, &len, size, fvalue, width, + precision, flags, &overflow); + if (overflow) + goto out; + break; + case 'c': + cvalue = va_arg(args, int); + OUTCHAR(str, len, size, cvalue); + break; + case 's': + strvalue = va_arg(args, char *); + fmtstr(str, &len, size, strvalue, width, + precision, flags); + break; + case 'p': + /* + * C99 says: "The value of the pointer is + * converted to a sequence of printing + * characters, in an implementation-defined + * manner." (C99: 7.19.6.1, 8) + */ + if ((strvalue = (const char *)va_arg(args, void *)) == NULL) + /* + * We use the glibc format. BSD prints + * "0x0", SysV "0". + */ + fmtstr(str, &len, size, "(nil)", width, + -1, flags); + else { + /* + * We use the BSD/glibc format. SysV + * omits the "0x" prefix (which we emit + * using the PRINT_F_NUM flag). + */ + flags |= PRINT_F_NUM; + flags |= PRINT_F_UNSIGNED; + fmtint(str, &len, size, + (UINTPTR_T)strvalue, 16, width, + precision, flags); + } + break; + case 'n': + switch (cflags) { + case PRINT_C_CHAR: + charptr = va_arg(args, signed char *); + *charptr = len; + break; + case PRINT_C_SHORT: + shortptr = va_arg(args, short int *); + *shortptr = len; + break; + case PRINT_C_LONG: + longptr = va_arg(args, long int *); + *longptr = len; + break; + /* + case PRINT_C_LLONG: + llongptr = va_arg(args, LLONG *); + *llongptr = len; + break; + */ + case PRINT_C_SIZE: + /* + * C99 says that with the "z" length + * modifier, "a following `n' conversion + * specifier applies to a pointer to a + * signed integer type corresponding to + * size_t argument." (7.19.6.1, 7) + */ + sizeptr = va_arg(args, SSIZE_T *); + *sizeptr = len; + break; + case PRINT_C_INTMAX: + intmaxptr = va_arg(args, INTMAX_T *); + *intmaxptr = len; + break; + case PRINT_C_PTRDIFF: + ptrdiffptr = va_arg(args, PTRDIFF_T *); + *ptrdiffptr = len; + break; + default: + intptr = va_arg(args, int *); + *intptr = len; + break; + } + break; + case '%': /* Print a "%" character verbatim. */ + OUTCHAR(str, len, size, ch); + break; + default: /* Skip other characters. */ + break; + } + ch = *format++; + state = PRINT_S_DEFAULT; + base = cflags = flags = width = 0; + precision = -1; + break; + default: + /* This is an invalid state, should not get here */ + break; + } +out: + if (len < size) + str[len] = '\0'; + else if (size > 0) + str[size - 1] = '\0'; + + if (overflow || len >= INT_MAX) { + errno = overflow ? EOVERFLOW : ERANGE; + return -1; + } + return (int)len; +} + +static void +fmtstr(char *str, size_t *len, size_t size, const char *value, int width, + int precision, int flags) +{ + int padlen, strln; /* Amount to pad. */ + int noprecision = (precision == -1); + + if (value == NULL) /* We're forgiving. */ + value = "(null)"; + + /* If a precision was specified, don't read the string past it. */ + for (strln = 0; value[strln] != '\0' && + (noprecision || strln < precision); strln++) + continue; + + if ((padlen = width - strln) < 0) + padlen = 0; + if (flags & PRINT_F_MINUS) /* Left justify. */ + padlen = -padlen; + + while (padlen > 0) { /* Leading spaces. */ + OUTCHAR(str, *len, size, ' '); + padlen--; + } + while (*value != '\0' && (noprecision || precision-- > 0)) { + OUTCHAR(str, *len, size, *value); + value++; + } + while (padlen < 0) { /* Trailing spaces. */ + OUTCHAR(str, *len, size, ' '); + padlen++; + } +} + +static void +fmtint(char *str, size_t *len, size_t size, INTMAX_T value, int base, int width, + int precision, int flags) +{ + UINTMAX_T uvalue; + char iconvert[MAX_CONVERT_LENGTH]; + char sign = 0; + char hexprefix = 0; + int spadlen = 0; /* Amount to space pad. */ + int zpadlen = 0; /* Amount to zero pad. */ + int pos; + int separators = (flags & PRINT_F_QUOTE); + int noprecision = (precision == -1); + + if (flags & PRINT_F_UNSIGNED) + uvalue = value; + else { + uvalue = (value >= 0) ? value : -value; + if (value < 0) + sign = '-'; + else if (flags & PRINT_F_PLUS) /* Do a sign. */ + sign = '+'; + else if (flags & PRINT_F_SPACE) + sign = ' '; + } + + pos = convert(uvalue, iconvert, sizeof(iconvert), base, + flags & PRINT_F_UP); + + if (flags & PRINT_F_NUM && uvalue != 0) { + /* + * C99 says: "The result is converted to an `alternative form'. + * For `o' conversion, it increases the precision, if and only + * if necessary, to force the first digit of the result to be a + * zero (if the value and precision are both 0, a single 0 is + * printed). For `x' (or `X') conversion, a nonzero result has + * `0x' (or `0X') prefixed to it." (7.19.6.1, 6) + */ + switch (base) { + case 8: + if (precision <= pos) + precision = pos + 1; + break; + case 16: + hexprefix = (flags & PRINT_F_UP) ? 'X' : 'x'; + break; + default: + /* Invalid base */ + break; + } + } + + if (separators) /* Get the number of group separators we'll print. */ + separators = getnumsep(pos); + + zpadlen = precision - pos - separators; + spadlen = width /* Minimum field width. */ + - separators /* Number of separators. */ + - MAX(precision, pos) /* Number of integer digits. */ + - ((sign != 0) ? 1 : 0) /* Will we print a sign? */ + - ((hexprefix != 0) ? 2 : 0); /* Will we print a prefix? */ + + if (zpadlen < 0) + zpadlen = 0; + if (spadlen < 0) + spadlen = 0; + + /* + * C99 says: "If the `0' and `-' flags both appear, the `0' flag is + * ignored. For `d', `i', `o', `u', `x', and `X' conversions, if a + * precision is specified, the `0' flag is ignored." (7.19.6.1, 6) + */ + if (flags & PRINT_F_MINUS) /* Left justify. */ + spadlen = -spadlen; + else if (flags & PRINT_F_ZERO && noprecision) { + zpadlen += spadlen; + spadlen = 0; + } + while (spadlen > 0) { /* Leading spaces. */ + OUTCHAR(str, *len, size, ' '); + spadlen--; + } + if (sign != 0) /* Sign. */ + OUTCHAR(str, *len, size, sign); + if (hexprefix != 0) { /* A "0x" or "0X" prefix. */ + OUTCHAR(str, *len, size, '0'); + OUTCHAR(str, *len, size, hexprefix); + } + while (zpadlen > 0) { /* Leading zeros. */ + OUTCHAR(str, *len, size, '0'); + zpadlen--; + } + while (pos > 0) { /* The actual digits. */ + pos--; + OUTCHAR(str, *len, size, iconvert[pos]); + if (separators > 0 && pos > 0 && pos % 3 == 0) + printsep(str, len, size); + } + while (spadlen < 0) { /* Trailing spaces. */ + OUTCHAR(str, *len, size, ' '); + spadlen++; + } +} + +static void +fmtflt(char *str, size_t *len, size_t size, LDOUBLE fvalue, int width, + int precision, int flags, int *overflow) +{ + LDOUBLE ufvalue; + UINTMAX_T intpart; + UINTMAX_T fracpart; + UINTMAX_T mask; + const char *infnan = NULL; + char iconvert[MAX_CONVERT_LENGTH]; + char fconvert[MAX_CONVERT_LENGTH]; + char econvert[4]; /* "e-12" (without nul-termination). */ + char esign = 0; + char sign = 0; + int leadfraczeros = 0; + int exponent = 0; + int emitpoint = 0; + int omitzeros = 0; + int omitcount = 0; + int padlen = 0; + int epos = 0; + int fpos = 0; + int ipos = 0; + int separators = (flags & PRINT_F_QUOTE); + int estyle = (flags & PRINT_F_TYPE_E); +#if HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT + struct lconv *lc = localeconv(); +#endif /* HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT */ + + /* + * AIX' man page says the default is 0, but C99 and at least Solaris' + * and NetBSD's man pages say the default is 6, and sprintf(3) on AIX + * defaults to 6. + */ + if (precision == -1) + precision = 6; + + if (fvalue < 0.0) + sign = '-'; + else if (flags & PRINT_F_PLUS) /* Do a sign. */ + sign = '+'; + else if (flags & PRINT_F_SPACE) + sign = ' '; + + if (ISNAN(fvalue)) + infnan = (flags & PRINT_F_UP) ? "NAN" : "nan"; + else if (ISINF(fvalue)) + infnan = (flags & PRINT_F_UP) ? "INF" : "inf"; + + if (infnan != NULL) { + if (sign != 0) + iconvert[ipos++] = sign; + while (*infnan != '\0') + iconvert[ipos++] = *infnan++; + fmtstr(str, len, size, iconvert, width, ipos, flags); + return; + } + + /* "%e" (or "%E") or "%g" (or "%G") conversion. */ + if (flags & PRINT_F_TYPE_E || flags & PRINT_F_TYPE_G) { + if (flags & PRINT_F_TYPE_G) { + /* + * For "%g" (and "%G") conversions, the precision + * specifies the number of significant digits, which + * includes the digits in the integer part. The + * conversion will or will not be using "e-style" (like + * "%e" or "%E" conversions) depending on the precision + * and on the exponent. However, the exponent can be + * affected by rounding the converted value, so we'll + * leave this decision for later. Until then, we'll + * assume that we're going to do an "e-style" conversion + * (in order to get the exponent calculated). For + * "e-style", the precision must be decremented by one. + */ + precision--; + /* + * For "%g" (and "%G") conversions, trailing zeros are + * removed from the fractional portion of the result + * unless the "#" flag was specified. + */ + if (!(flags & PRINT_F_NUM)) + omitzeros = 1; + } + exponent = getexponent(fvalue); + estyle = 1; + } + +again: + /* + * Sorry, we only support 9, 19, or 38 digits (that is, the number of + * digits of the 32-bit, the 64-bit, or the 128-bit UINTMAX_MAX value + * minus one) past the decimal point due to our conversion method. + */ + switch (sizeof(UINTMAX_T)) { + case 16: + if (precision > 38) + precision = 38; + break; + case 8: + if (precision > 19) + precision = 19; + break; + default: + if (precision > 9) + precision = 9; + break; + } + + ufvalue = (fvalue >= 0.0) ? fvalue : -fvalue; + if (estyle) /* We want exactly one integer digit. */ + ufvalue /= mypow10(exponent); + + if ((intpart = cast(ufvalue)) == UINTMAX_MAX) { + *overflow = 1; + return; + } + + /* + * Factor of ten with the number of digits needed for the fractional + * part. For example, if the precision is 3, the mask will be 1000. + */ + mask = mypow10(precision); + /* + * We "cheat" by converting the fractional part to integer by + * multiplying by a factor of ten. + */ + if ((fracpart = myround(mask * (ufvalue - intpart))) >= mask) { + /* + * For example, ufvalue = 2.99962, intpart = 2, and mask = 1000 + * (because precision = 3). Now, myround(1000 * 0.99962) will + * return 1000. So, the integer part must be incremented by one + * and the fractional part must be set to zero. + */ + intpart++; + fracpart = 0; + if (estyle && intpart == 10) { + /* + * The value was rounded up to ten, but we only want one + * integer digit if using "e-style". So, the integer + * part must be set to one and the exponent must be + * incremented by one. + */ + intpart = 1; + exponent++; + } + } + + /* + * Now that we know the real exponent, we can check whether or not to + * use "e-style" for "%g" (and "%G") conversions. If we don't need + * "e-style", the precision must be adjusted and the integer and + * fractional parts must be recalculated from the original value. + * + * C99 says: "Let P equal the precision if nonzero, 6 if the precision + * is omitted, or 1 if the precision is zero. Then, if a conversion + * with style `E' would have an exponent of X: + * + * - if P > X >= -4, the conversion is with style `f' (or `F') and + * precision P - (X + 1). + * + * - otherwise, the conversion is with style `e' (or `E') and precision + * P - 1." (7.19.6.1, 8) + * + * Note that we had decremented the precision by one. + */ + if (flags & PRINT_F_TYPE_G && estyle && + precision + 1 > exponent && exponent >= -4) { + precision -= exponent; + estyle = 0; + goto again; + } + + if (estyle) { + if (exponent < 0) { + exponent = -exponent; + esign = '-'; + } else + esign = '+'; + + /* + * Convert the exponent. The sizeof(econvert) is 4. So, the + * econvert buffer can hold e.g. "e+99" and "e-99". We don't + * support an exponent which contains more than two digits. + * Therefore, the following stores are safe. + */ + epos = convert(exponent, econvert, 2, 10, 0); + /* + * C99 says: "The exponent always contains at least two digits, + * and only as many more digits as necessary to represent the + * exponent." (7.19.6.1, 8) + */ + if (epos == 1) + econvert[epos++] = '0'; + econvert[epos++] = esign; + econvert[epos++] = (flags & PRINT_F_UP) ? 'E' : 'e'; + } + + /* Convert the integer part and the fractional part. */ + ipos = convert(intpart, iconvert, sizeof(iconvert), 10, 0); + if (fracpart != 0) /* convert() would return 1 if fracpart == 0. */ + fpos = convert(fracpart, fconvert, sizeof(fconvert), 10, 0); + + leadfraczeros = precision - fpos; + + if (omitzeros) { + if (fpos > 0) /* Omit trailing fractional part zeros. */ + while (omitcount < fpos && fconvert[omitcount] == '0') + omitcount++; + else { /* The fractional part is zero, omit it completely. */ + omitcount = precision; + leadfraczeros = 0; + } + precision -= omitcount; + } + + /* + * Print a decimal point if either the fractional part is non-zero + * and/or the "#" flag was specified. + */ + if (precision > 0 || flags & PRINT_F_NUM) + emitpoint = 1; + if (separators) /* Get the number of group separators we'll print. */ + separators = getnumsep(ipos); + + padlen = width /* Minimum field width. */ + - ipos /* Number of integer digits. */ + - epos /* Number of exponent characters. */ + - precision /* Number of fractional digits. */ + - separators /* Number of group separators. */ + - (emitpoint ? 1 : 0) /* Will we print a decimal point? */ + - ((sign != 0) ? 1 : 0); /* Will we print a sign character? */ + + if (padlen < 0) + padlen = 0; + + /* + * C99 says: "If the `0' and `-' flags both appear, the `0' flag is + * ignored." (7.19.6.1, 6) + */ + if (flags & PRINT_F_MINUS) /* Left justifty. */ + padlen = -padlen; + else if (flags & PRINT_F_ZERO && padlen > 0) { + if (sign != 0) { /* Sign. */ + OUTCHAR(str, *len, size, sign); + sign = 0; + } + while (padlen > 0) { /* Leading zeros. */ + OUTCHAR(str, *len, size, '0'); + padlen--; + } + } + while (padlen > 0) { /* Leading spaces. */ + OUTCHAR(str, *len, size, ' '); + padlen--; + } + if (sign != 0) /* Sign. */ + OUTCHAR(str, *len, size, sign); + while (ipos > 0) { /* Integer part. */ + ipos--; + OUTCHAR(str, *len, size, iconvert[ipos]); + if (separators > 0 && ipos > 0 && ipos % 3 == 0) + printsep(str, len, size); + } + if (emitpoint) { /* Decimal point. */ +#if HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT + if (lc->decimal_point != NULL && *lc->decimal_point != '\0') + OUTCHAR(str, *len, size, *lc->decimal_point); + else /* We'll always print some decimal point character. */ +#endif /* HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT */ + OUTCHAR(str, *len, size, '.'); + } + while (leadfraczeros > 0) { /* Leading fractional part zeros. */ + OUTCHAR(str, *len, size, '0'); + leadfraczeros--; + } + while (fpos > omitcount) { /* The remaining fractional part. */ + fpos--; + OUTCHAR(str, *len, size, fconvert[fpos]); + } + while (epos > 0) { /* Exponent. */ + epos--; + OUTCHAR(str, *len, size, econvert[epos]); + } + while (padlen < 0) { /* Trailing spaces. */ + OUTCHAR(str, *len, size, ' '); + padlen++; + } +} + +static void +printsep(char *str, size_t *len, size_t size) +{ +#if HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP + struct lconv *lc = localeconv(); + int i; + + if (lc->thousands_sep != NULL) + for (i = 0; lc->thousands_sep[i] != '\0'; i++) + OUTCHAR(str, *len, size, lc->thousands_sep[i]); + else +#endif /* HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP */ + OUTCHAR(str, *len, size, ','); +} + +static int +getnumsep(int digits) +{ + int separators = (digits - ((digits % 3 == 0) ? 1 : 0)) / 3; +#if HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP + int strln; + struct lconv *lc = localeconv(); + + /* We support an arbitrary separator length (including zero). */ + if (lc->thousands_sep != NULL) { + for (strln = 0; lc->thousands_sep[strln] != '\0'; strln++) + continue; + separators *= strln; + } +#endif /* HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP */ + return separators; +} + +static int +getexponent(LDOUBLE value) +{ + LDOUBLE tmp = (value >= 0.0) ? value : -value; + int exponent = 0; + + /* + * We check for 99 > exponent > -99 in order to work around possible + * endless loops which could happen (at least) in the second loop (at + * least) if we're called with an infinite value. However, we checked + * for infinity before calling this function using our ISINF() macro, so + * this might be somewhat paranoid. + */ + while (tmp < 1.0 && tmp > 0.0 && --exponent > -99) + tmp *= 10; + while (tmp >= 10.0 && ++exponent < 99) + tmp /= 10; + + return exponent; +} + +static int +convert(UINTMAX_T value, char *buf, size_t size, int base, int caps) +{ + const char *digits = caps ? "0123456789ABCDEF" : "0123456789abcdef"; + size_t pos = 0; + + /* We return an unterminated buffer with the digits in reverse order. */ + do { + buf[pos++] = digits[value % base]; + value /= base; + } while (value != 0 && pos < size); + + return (int)pos; +} + +static UINTMAX_T +cast(LDOUBLE value) +{ + UINTMAX_T result; + + /* + * We check for ">=" and not for ">" because if UINTMAX_MAX cannot be + * represented exactly as an LDOUBLE value (but is less than LDBL_MAX), + * it may be increased to the nearest higher representable value for the + * comparison (cf. C99: 6.3.1.4, 2). It might then equal the LDOUBLE + * value although converting the latter to UINTMAX_T would overflow. + */ + if (value >= UINTMAX_MAX) + return UINTMAX_MAX; + + result = value; + /* + * At least on NetBSD/sparc64 3.0.2 and 4.99.30, casting long double to + * an integer type converts e.g. 1.9 to 2 instead of 1 (which violates + * the standard). Sigh. + */ + return (result <= value) ? result : result - 1; +} + +static UINTMAX_T +myround(LDOUBLE value) +{ + UINTMAX_T intpart = cast(value); + + return ((value -= intpart) < 0.5) ? intpart : intpart + 1; +} + +static LDOUBLE +mypow10(int exponent) +{ + LDOUBLE result = 1; + + while (exponent > 0) { + result *= 10; + exponent--; + } + while (exponent < 0) { + result /= 10; + exponent++; + } + return result; +} +#endif /* !HAVE_VSNPRINTF */ + +#if !HAVE_SNPRINTF +#if HAVE_STDARG_H +int +rpl_snprintf(char *str, size_t size, const char *format, ...) +#else +int +rpl_snprintf(va_alist) va_dcl +#endif /* HAVE_STDARG_H */ +{ +#if !HAVE_STDARG_H + char *str; + size_t size; + char *format; +#endif /* HAVE_STDARG_H */ + va_list ap; + int len; + + VA_START(ap, format); + VA_SHIFT(ap, str, char *); + VA_SHIFT(ap, size, size_t); + VA_SHIFT(ap, format, const char *); + len = vsnprintf(str, size, format, ap); + va_end(ap); + return len; +} +#endif /* !HAVE_SNPRINTF */ + +#else /* Dummy declaration to avoid empty translation unit warnings. */ +int main(void); +#endif /* !HAVE_SNPRINTF || !HAVE_VSNPRINTF*/ + +#if TEST_SNPRINTF +int +main(void) +{ + const char *float_fmt[] = { + /* "%E" and "%e" formats. */ +#if HAVE_LONG_LONG_INT && !OS_BSD && !OS_IRIX + "%.16e", + "%22.16e", + "%022.16e", + "%-22.16e", + "%#+'022.16e", +#endif /* HAVE_LONG_LONG_INT && !OS_BSD && !OS_IRIX */ + "foo|%#+0123.9E|bar", + "%-123.9e", + "%123.9e", + "%+23.9e", + "%+05.8e", + "%-05.8e", + "%05.8e", + "%+5.8e", + "%-5.8e", + "% 5.8e", + "%5.8e", + "%+4.9e", +#if !OS_LINUX /* glibc sometimes gets these wrong. */ + "%+#010.0e", + "%#10.1e", + "%10.5e", + "% 10.5e", + "%5.0e", + "%5.e", + "%#5.0e", + "%#5.e", + "%3.2e", + "%3.1e", + "%-1.5e", + "%1.5e", + "%01.3e", + "%1.e", + "%.1e", + "%#.0e", + "%+.0e", + "% .0e", + "%.0e", + "%#.e", + "%+.e", + "% .e", + "%.e", + "%4e", + "%e", + "%E", +#endif /* !OS_LINUX */ + /* "%F" and "%f" formats. */ +#if !OS_BSD && !OS_IRIX + "% '022f", + "%+'022f", + "%-'22f", + "%'22f", +#if HAVE_LONG_LONG_INT + "%.16f", + "%22.16f", + "%022.16f", + "%-22.16f", + "%#+'022.16f", +#endif /* HAVE_LONG_LONG_INT */ +#endif /* !OS_BSD && !OS_IRIX */ + "foo|%#+0123.9F|bar", + "%-123.9f", + "%123.9f", + "%+23.9f", + "%+#010.0f", + "%#10.1f", + "%10.5f", + "% 10.5f", + "%+05.8f", + "%-05.8f", + "%05.8f", + "%+5.8f", + "%-5.8f", + "% 5.8f", + "%5.8f", + "%5.0f", + "%5.f", + "%#5.0f", + "%#5.f", + "%+4.9f", + "%3.2f", + "%3.1f", + "%-1.5f", + "%1.5f", + "%01.3f", + "%1.f", + "%.1f", + "%#.0f", + "%+.0f", + "% .0f", + "%.0f", + "%#.f", + "%+.f", + "% .f", + "%.f", + "%4f", + "%f", + "%F", + /* "%G" and "%g" formats. */ +#if !OS_BSD && !OS_IRIX && !OS_LINUX + "% '022g", + "%+'022g", + "%-'22g", + "%'22g", +#if HAVE_LONG_LONG_INT + "%.16g", + "%22.16g", + "%022.16g", + "%-22.16g", + "%#+'022.16g", +#endif /* HAVE_LONG_LONG_INT */ +#endif /* !OS_BSD && !OS_IRIX && !OS_LINUX */ + "foo|%#+0123.9G|bar", + "%-123.9g", + "%123.9g", + "%+23.9g", + "%+05.8g", + "%-05.8g", + "%05.8g", + "%+5.8g", + "%-5.8g", + "% 5.8g", + "%5.8g", + "%+4.9g", +#if !OS_LINUX /* glibc sometimes gets these wrong. */ + "%+#010.0g", + "%#10.1g", + "%10.5g", + "% 10.5g", + "%5.0g", + "%5.g", + "%#5.0g", + "%#5.g", + "%3.2g", + "%3.1g", + "%-1.5g", + "%1.5g", + "%01.3g", + "%1.g", + "%.1g", + "%#.0g", + "%+.0g", + "% .0g", + "%.0g", + "%#.g", + "%+.g", + "% .g", + "%.g", + "%4g", + "%g", + "%G", +#endif /* !OS_LINUX */ + NULL + }; + double float_val[] = { + -4.136, + -134.52, + -5.04030201, + -3410.01234, + -999999.999999, + -913450.29876, + -913450.2, + -91345.2, + -9134.2, + -913.2, + -91.2, + -9.2, + -9.9, + 4.136, + 134.52, + 5.04030201, + 3410.01234, + 999999.999999, + 913450.29876, + 913450.2, + 91345.2, + 9134.2, + 913.2, + 91.2, + 9.2, + 9.9, + 9.96, + 9.996, + 9.9996, + 9.99996, + 9.999996, + 9.9999996, + 9.99999996, + 0.99999996, + 0.99999999, + 0.09999999, + 0.00999999, + 0.00099999, + 0.00009999, + 0.00000999, + 0.00000099, + 0.00000009, + 0.00000001, + 0.0000001, + 0.000001, + 0.00001, + 0.0001, + 0.001, + 0.01, + 0.1, + 1.0, + 1.5, + -1.5, + -1.0, + -0.1, +#if !OS_BSD /* BSD sometimes gets these wrong. */ +#ifdef INFINITY + INFINITY, + -INFINITY, +#endif /* defined(INFINITY) */ +#ifdef NAN + NAN, +#endif /* defined(NAN) */ +#endif /* !OS_BSD */ + 0 + }; + const char *long_fmt[] = { + "foo|%0123ld|bar", +#if !OS_IRIX + "% '0123ld", + "%+'0123ld", + "%-'123ld", + "%'123ld", +#endif /* !OS_IRiX */ + "%123.9ld", + "% 123.9ld", + "%+123.9ld", + "%-123.9ld", + "%0123ld", + "% 0123ld", + "%+0123ld", + "%-0123ld", + "%10.5ld", + "% 10.5ld", + "%+10.5ld", + "%-10.5ld", + "%010ld", + "% 010ld", + "%+010ld", + "%-010ld", + "%4.2ld", + "% 4.2ld", + "%+4.2ld", + "%-4.2ld", + "%04ld", + "% 04ld", + "%+04ld", + "%-04ld", + "%5.5ld", + "%+22.33ld", + "%01.3ld", + "%1.5ld", + "%-1.5ld", + "%44ld", + "%4ld", + "%4.0ld", + "%4.ld", + "%.44ld", + "%.4ld", + "%.0ld", + "%.ld", + "%ld", + NULL + }; + long int long_val[] = { +#ifdef LONG_MAX + LONG_MAX, +#endif /* LONG_MAX */ +#ifdef LONG_MIN + LONG_MIN, +#endif /* LONG_MIN */ + -91340, + 91340, + 341, + 134, + 0203, + -1, + 1, + 0 + }; + const char *ulong_fmt[] = { + /* "%u" formats. */ + "foo|%0123lu|bar", +#if !OS_IRIX + "% '0123lu", + "%+'0123lu", + "%-'123lu", + "%'123lu", +#endif /* !OS_IRiX */ + "%123.9lu", + "% 123.9lu", + "%+123.9lu", + "%-123.9lu", + "%0123lu", + "% 0123lu", + "%+0123lu", + "%-0123lu", + "%5.5lu", + "%+22.33lu", + "%01.3lu", + "%1.5lu", + "%-1.5lu", + "%44lu", + "%lu", + /* "%o" formats. */ + "foo|%#0123lo|bar", + "%#123.9lo", + "%# 123.9lo", + "%#+123.9lo", + "%#-123.9lo", + "%#0123lo", + "%# 0123lo", + "%#+0123lo", + "%#-0123lo", + "%#5.5lo", + "%#+22.33lo", + "%#01.3lo", + "%#1.5lo", + "%#-1.5lo", + "%#44lo", + "%#lo", + "%123.9lo", + "% 123.9lo", + "%+123.9lo", + "%-123.9lo", + "%0123lo", + "% 0123lo", + "%+0123lo", + "%-0123lo", + "%5.5lo", + "%+22.33lo", + "%01.3lo", + "%1.5lo", + "%-1.5lo", + "%44lo", + "%lo", + /* "%X" and "%x" formats. */ + "foo|%#0123lX|bar", + "%#123.9lx", + "%# 123.9lx", + "%#+123.9lx", + "%#-123.9lx", + "%#0123lx", + "%# 0123lx", + "%#+0123lx", + "%#-0123lx", + "%#5.5lx", + "%#+22.33lx", + "%#01.3lx", + "%#1.5lx", + "%#-1.5lx", + "%#44lx", + "%#lx", + "%#lX", + "%123.9lx", + "% 123.9lx", + "%+123.9lx", + "%-123.9lx", + "%0123lx", + "% 0123lx", + "%+0123lx", + "%-0123lx", + "%5.5lx", + "%+22.33lx", + "%01.3lx", + "%1.5lx", + "%-1.5lx", + "%44lx", + "%lx", + "%lX", + NULL + }; + unsigned long int ulong_val[] = { +#ifdef ULONG_MAX + ULONG_MAX, +#endif /* ULONG_MAX */ + 91340, + 341, + 134, + 0203, + 1, + 0 + }; + const char *llong_fmt[] = { + "foo|%0123lld|bar", + "%123.9lld", + "% 123.9lld", + "%+123.9lld", + "%-123.9lld", + "%0123lld", + "% 0123lld", + "%+0123lld", + "%-0123lld", + "%5.5lld", + "%+22.33lld", + "%01.3lld", + "%1.5lld", + "%-1.5lld", + "%44lld", + "%lld", + NULL + }; + LLONG llong_val[] = { +#ifdef LLONG_MAX + LLONG_MAX, +#endif /* LLONG_MAX */ +#ifdef LLONG_MIN + LLONG_MIN, +#endif /* LLONG_MIN */ + -91340, + 91340, + 341, + 134, + 0203, + -1, + 1, + 0 + }; + const char *string_fmt[] = { + "foo|%10.10s|bar", + "%-10.10s", + "%10.10s", + "%10.5s", + "%5.10s", + "%10.1s", + "%1.10s", + "%10.0s", + "%0.10s", + "%-42.5s", + "%2.s", + "%.10s", + "%.1s", + "%.0s", + "%.s", + "%4s", + "%s", + NULL + }; + const char *string_val[] = { + "Hello", + "Hello, world!", + "Sound check: One, two, three.", + "This string is a little longer than the other strings.", + "1", + "", + NULL + }; +#if !OS_SYSV /* SysV uses a different format than we do. */ + const char *pointer_fmt[] = { + "foo|%p|bar", + "%42p", + "%p", + NULL + }; + const char *pointer_val[] = { + *pointer_fmt, + *string_fmt, + *string_val, + NULL + }; +#endif /* !OS_SYSV */ + char buf1[1024], buf2[1024]; + double value, digits = 9.123456789012345678901234567890123456789; + int i, j, r1, r2, failed = 0, num = 0; + +/* + * Use -DTEST_NILS in order to also test the conversion of nil values. Might + * segfault on systems which don't support converting a NULL pointer with "%s" + * and lets some test cases fail against BSD and glibc due to bugs in their + * implementations. + */ +#ifndef TEST_NILS +#define TEST_NILS 0 +#elif TEST_NILS +#undef TEST_NILS +#define TEST_NILS 1 +#endif /* !defined(TEST_NILS) */ +#ifdef TEST +#undef TEST +#endif /* defined(TEST) */ +#define TEST(fmt, val) \ +do { \ + for (i = 0; fmt[i] != NULL; i++) \ + for (j = 0; j == 0 || val[j - TEST_NILS] != 0; j++) { \ + r1 = sprintf(buf1, fmt[i], val[j]); \ + r2 = snprintf(buf2, sizeof(buf2), fmt[i], val[j]); \ + if (strcmp(buf1, buf2) != 0 || r1 != r2) { \ + (void)printf("Results don't match, " \ + "format string: %s\n" \ + "\t sprintf(3): [%s] (%d)\n" \ + "\tsnprintf(3): [%s] (%d)\n", \ + fmt[i], buf1, r1, buf2, r2); \ + failed++; \ + } \ + num++; \ + } \ +} while (/* CONSTCOND */ 0) + +#if HAVE_LOCALE_H + (void)setlocale(LC_ALL, ""); +#endif /* HAVE_LOCALE_H */ + + (void)puts("Testing our snprintf(3) against your system's sprintf(3)."); + TEST(float_fmt, float_val); + TEST(long_fmt, long_val); + TEST(ulong_fmt, ulong_val); + TEST(llong_fmt, llong_val); + TEST(string_fmt, string_val); +#if !OS_SYSV /* SysV uses a different format than we do. */ + TEST(pointer_fmt, pointer_val); +#endif /* !OS_SYSV */ + (void)printf("Result: %d out of %d tests failed.\n", failed, num); + + (void)fputs("Checking how many digits we support: ", stdout); + for (i = 0; i < 100; i++) { + value = pow(10, i) * digits; + (void)sprintf(buf1, "%.1f", value); + (void)snprintf(buf2, sizeof(buf2), "%.1f", value); + if (strcmp(buf1, buf2) != 0) { + (void)printf("apparently %d.\n", i); + break; + } + } + return (failed == 0) ? 0 : 1; +} +#endif /* TEST_SNPRINTF */ + +/* vim: set joinspaces textwidth=80: */ diff --git a/lib/strdup.c b/lib/strdup.c new file mode 100644 index 0000000..d26a99f --- /dev/null +++ b/lib/strdup.c @@ -0,0 +1,27 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "libcompat.h" + +char *strdup(const char *str CK_ATTRIBUTE_UNUSED) +{ + assert(0); + return NULL; +} diff --git a/lib/strsignal.c b/lib/strsignal.c new file mode 100644 index 0000000..012e64d --- /dev/null +++ b/lib/strsignal.c @@ -0,0 +1,29 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "libcompat.h" + +char *strsignal(int sig) +{ + static char signame[40]; + + sprintf(signame, "SIG #%d", sig); + return signame; +} diff --git a/lib/timer_create.c b/lib/timer_create.c new file mode 100644 index 0000000..7058961 --- /dev/null +++ b/lib/timer_create.c @@ -0,0 +1,34 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "libcompat.h" + +int timer_create(clockid_t clockid CK_ATTRIBUTE_UNUSED, + struct sigevent *sevp CK_ATTRIBUTE_UNUSED, + timer_t * timerid CK_ATTRIBUTE_UNUSED) +{ + /* + * The create function does nothing. timer_settime will use + * alarm to set the timer, and timer_delete will stop the + * alarm + */ + + return 0; +} diff --git a/lib/timer_delete.c b/lib/timer_delete.c new file mode 100644 index 0000000..f4235d7 --- /dev/null +++ b/lib/timer_delete.c @@ -0,0 +1,52 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "libcompat.h" + +int timer_delete(timer_t timerid CK_ATTRIBUTE_UNUSED) +{ +#ifdef HAVE_SETITIMER + /* + * If the system does not have timer_settime() but does have + * setitimer() use that instead of alarm(). + */ + struct itimerval interval; + + /* + * Setting values to '0' results in disabling the running timer. + */ + interval.it_value.tv_sec = 0; + interval.it_value.tv_usec = 0; + interval.it_interval.tv_sec = 0; + interval.it_interval.tv_usec = 0; + + return setitimer(ITIMER_REAL, &interval, NULL); +#else + /* + * There is only one timer, that used by alarm. + * Setting alarm(0) will not set a new alarm, and + * will kill the previous timer. + */ + + alarm(0); + + return 0; +#endif +} diff --git a/lib/timer_settime.c b/lib/timer_settime.c new file mode 100644 index 0000000..e1bab0e --- /dev/null +++ b/lib/timer_settime.c @@ -0,0 +1,57 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "libcompat.h" + +int timer_settime(timer_t timerid CK_ATTRIBUTE_UNUSED, + int flags CK_ATTRIBUTE_UNUSED, + const struct itimerspec *new_value, + struct itimerspec *old_value CK_ATTRIBUTE_UNUSED) +{ +#ifdef HAVE_SETITIMER + /* + * If the system does not have timer_settime() but does have + * setitimer() use that instead of alarm(). + */ + struct itimerval interval; + + interval.it_value.tv_sec = new_value->it_value.tv_sec; + interval.it_value.tv_usec = new_value->it_value.tv_nsec / 1000; + interval.it_interval.tv_sec = new_value->it_interval.tv_sec; + interval.it_interval.tv_usec = new_value->it_interval.tv_nsec / 1000; + + return setitimer(ITIMER_REAL, &interval, NULL); +#else + int seconds = new_value->it_value.tv_sec; + + /* + * As the alarm() call has only second precision, if the caller + * specifies partial seconds, we round up to the nearest second. + */ + if(new_value->it_value.tv_nsec > 0) + { + seconds += 1; + } + + alarm(seconds); + + return 0; +#endif +} diff --git a/m4/acx_pthread.html b/m4/acx_pthread.html new file mode 100644 index 0000000..3e36dac --- /dev/null +++ b/m4/acx_pthread.html @@ -0,0 +1,381 @@ + + + + + Autoconf Macro: acx_pthread + + + + + + + + + + + + + +
+ Download M4 + Source + + Macro + History + + Category Index + +
+
+ Search: +
+
+
+
+

+ acx_pthread +

+

+ Synopsis +

+

+ ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +

+

+ Description +

+
+

+ This macro figures out how to build C programs using POSIX threads. It sets + the PTHREAD_LIBS output variable to the threads library and linker flags, + and the PTHREAD_CFLAGS output variable to any special C compiler flags that + are needed. (The user can also force certain compiler flags/libs to be + tested by setting these environment variables.) +

+

+ Also sets PTHREAD_CC to any special C compiler that is needed for + multi-threaded programs (defaults to the value of CC otherwise). (This is + necessary on AIX to use the special cc_r compiler alias.) +

+

+ NOTE: You are assumed to not only compile your program with these flags, + but also link it with them as well. e.g. you should link with $PTHREAD_CC + $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS +

+

+ If you are only building threads programs, you may wish to use these + variables in your default LIBS, CFLAGS, and CC: +

+
+       LIBS="$PTHREAD_LIBS $LIBS"
+       CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+       CC="$PTHREAD_CC"
+
+

+ In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant has a + nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name (e.g. + PTHREAD_CREATE_UNDETACHED on AIX). +

+

+ ACTION-IF-FOUND is a list of shell commands to run if a threads library is + found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it is not + found. If ACTION-IF-FOUND is not specified, the default action will define + HAVE_PTHREAD. +

+

+ Please let the authors know if this macro fails on any platform, or if you + have any other suggestions or comments. This macro was based on work by SGJ + on autoconf scripts for FFTW (http://www.fftw.org/) (with help from M. Frigo), + as well as ac_pthread and hb_pthread macros posted by Alejandro Forero + Cuervo to the autoconf macro repository. We are also grateful for the + helpful feedback of numerous users. +

+
+

+ Author +

+

+ Steven G. Johnson <stevenj@alum.mit.edu> +

+

+ Last Modified +

+

+ 2008-04-12 +

+

+ Cross References +

+

+ group19-xrefs.png + + + + + + + + +

+

+ M4 Source Code +

+
+
+AC_DEFUN([ACX_PTHREAD], [
+AC_REQUIRE([AC_CANONICAL_HOST])
+AC_LANG_SAVE
+AC_LANG_C
+acx_pthread_ok=no
+
+# We used to check for pthread.h first, but this fails if pthread.h
+# requires special compiler flags (e.g. on True64 or Sequent).
+# It gets checked for in the link test anyway.
+
+# First of all, check if the user has set any of the PTHREAD_LIBS,
+# etcetera environment variables, and if threads linking works using
+# them:
+if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
+        save_CFLAGS="$CFLAGS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+        save_LIBS="$LIBS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
+        AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes)
+        AC_MSG_RESULT($acx_pthread_ok)
+        if test x"$acx_pthread_ok" = xno; then
+                PTHREAD_LIBS=""
+                PTHREAD_CFLAGS=""
+        fi
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+fi
+
+# We must check for the threads library under a number of different
+# names; the ordering is very important because some systems
+# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
+# libraries is broken (non-POSIX).
+
+# Create a list of thread flags to try.  Items starting with a "-" are
+# C compiler flags, and other items are library names, except for "none"
+# which indicates that we try without any flags at all, and "pthread-config"
+# which is a program returning the flags for the Pth emulation library.
+
+acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
+
+# The ordering *is* (sometimes) important.  Some notes on the
+# individual items follow:
+
+# pthreads: AIX (must check this before -lpthread)
+# none: in case threads are in libc; should be tried before -Kthread and
+#       other compiler flags to prevent continual compiler warnings
+# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
+# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
+# -pthreads: Solaris/gcc
+# -mthreads: Mingw32/gcc, Lynx/gcc
+# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+#      doesn't hurt to check since this sometimes defines pthreads too;
+#      also defines -D_REENTRANT)
+#      ... -mt is also the pthreads flag for HP/aCC
+# pthread: Linux, etcetera
+# --thread-safe: KAI C++
+# pthread-config: use pthread-config program (for GNU Pth library)
+
+case "${host_cpu}-${host_os}" in
+        *solaris*)
+
+        # On Solaris (at least, for some versions), libc contains stubbed
+        # (non-functional) versions of the pthreads routines, so link-based
+        # tests will erroneously succeed.  (We need to link with -pthreads/-mt/
+        # -lpthread.)  (The stubs are missing pthread_cleanup_push, or rather
+        # a function called by this macro, so we could check for that, but
+        # who knows whether they'll stub that too in a future libc.)  So,
+        # we'll just look for -pthreads and -lpthread first:
+
+        acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags"
+        ;;
+esac
+
+if test x"$acx_pthread_ok" = xno; then
+for flag in $acx_pthread_flags; do
+
+        case $flag in
+                none)
+                AC_MSG_CHECKING([whether pthreads work without any flags])
+                ;;
+
+                -*)
+                AC_MSG_CHECKING([whether pthreads work with $flag])
+                PTHREAD_CFLAGS="$flag"
+                ;;
+
+                pthread-config)
+                AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no)
+                if test x"$acx_pthread_config" = xno; then continue; fi
+                PTHREAD_CFLAGS="`pthread-config --cflags`"
+                PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
+                ;;
+
+                *)
+                AC_MSG_CHECKING([for the pthreads library -l$flag])
+                PTHREAD_LIBS="-l$flag"
+                ;;
+        esac
+
+        save_LIBS="$LIBS"
+        save_CFLAGS="$CFLAGS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+        # Check for various functions.  We must include pthread.h,
+        # since some functions may be macros.  (On the Sequent, we
+        # need a special flag -Kthread to make this header compile.)
+        # We check for pthread_join because it is in -lpthread on IRIX
+        # while pthread_create is in libc.  We check for pthread_attr_init
+        # due to DEC craziness with -lpthreads.  We check for
+        # pthread_cleanup_push because it is one of the few pthread
+        # functions on Solaris that doesn't have a non-functional libc stub.
+        # We try pthread_create on general principles.
+        AC_TRY_LINK([#include <pthread.h>],
+                    [pthread_t th; pthread_join(th, 0);
+                     pthread_attr_init(0); pthread_cleanup_push(0, 0);
+                     pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
+                    [acx_pthread_ok=yes])
+
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+
+        AC_MSG_RESULT($acx_pthread_ok)
+        if test "x$acx_pthread_ok" = xyes; then
+                break;
+        fi
+
+        PTHREAD_LIBS=""
+        PTHREAD_CFLAGS=""
+done
+fi
+
+# Various other checks:
+if test "x$acx_pthread_ok" = xyes; then
+        save_LIBS="$LIBS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        save_CFLAGS="$CFLAGS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+        # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
+        AC_MSG_CHECKING([for joinable pthread attribute])
+        attr_name=unknown
+        for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+            AC_TRY_LINK([#include <pthread.h>], [int attr=$attr; return attr;],
+                        [attr_name=$attr; break])
+        done
+        AC_MSG_RESULT($attr_name)
+        if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
+            AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
+                               [Define to necessary symbol if this constant
+                                uses a non-standard name on your system.])
+        fi
+
+        AC_MSG_CHECKING([if more special flags are required for pthreads])
+        flag=no
+        case "${host_cpu}-${host_os}" in
+            *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";;
+            *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";;
+        esac
+        AC_MSG_RESULT(${flag})
+        if test "x$flag" != xno; then
+            PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
+        fi
+
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+
+        # More AIX lossage: must compile with xlc_r or cc_r
+        if test x"$GCC" != xyes; then
+          AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC})
+        else
+          PTHREAD_CC=$CC
+        fi
+else
+        PTHREAD_CC="$CC"
+fi
+
+AC_SUBST(PTHREAD_LIBS)
+AC_SUBST(PTHREAD_CFLAGS)
+AC_SUBST(PTHREAD_CC)
+
+# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
+if test x"$acx_pthread_ok" = xyes; then
+        ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
+        :
+else
+        acx_pthread_ok=no
+        $2
+fi
+AC_LANG_RESTORE
+])dnl ACX_PTHREAD
+
+
+

+ License +

+
+ Copyright © 2008 Steven G. Johnson + <stevenj@alum.mit.edu> +

+ This program is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. +

+

+ This program 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 General Public License for + more details. +

+

+ You should have received a copy of the GNU General Public License along + with this program. If not, see <http://www.gnu.org/licenses/>. +

+

+ As a special exception, the respective Autoconf Macro's copyright owner + gives unlimited permission to copy, distribute and modify the configure + scripts that are the output of Autoconf when processing the Macro. You need + not follow the terms of the GNU General Public License when using or + distributing such scripts, even though portions of the text of the Macro + appear in them. The GNU General Public License (GPL) does govern all other + use of the material that constitutes the Autoconf Macro. +

+

+ This special exception to the GPL applies to versions of the Autoconf Macro + released by the Autoconf Macro Archive. When you make and distribute a + modified version of the Autoconf Macro, you may extend this special + exception to the GPL to apply to your modified version as well. +

+
+ + diff --git a/m4/acx_pthread.m4 b/m4/acx_pthread.m4 new file mode 100644 index 0000000..eb09f5a --- /dev/null +++ b/m4/acx_pthread.m4 @@ -0,0 +1,275 @@ +# =========================================================================== +# http://autoconf-archive.cryp.to/acx_pthread.html +# =========================================================================== +# +# SYNOPSIS +# +# ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +# +# DESCRIPTION +# +# This macro figures out how to build C programs using POSIX threads. It +# sets the PTHREAD_LIBS output variable to the threads library and linker +# flags, and the PTHREAD_CFLAGS output variable to any special C compiler +# flags that are needed. (The user can also force certain compiler +# flags/libs to be tested by setting these environment variables.) +# +# Also sets PTHREAD_CC to any special C compiler that is needed for +# multi-threaded programs (defaults to the value of CC otherwise). (This +# is necessary on AIX to use the special cc_r compiler alias.) +# +# NOTE: You are assumed to not only compile your program with these flags, +# but also link it with them as well. e.g. you should link with +# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS +# +# If you are only building threads programs, you may wish to use these +# variables in your default LIBS, CFLAGS, and CC: +# +# LIBS="$PTHREAD_LIBS $LIBS" +# CFLAGS="$CFLAGS $PTHREAD_CFLAGS" +# CC="$PTHREAD_CC" +# +# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant +# has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name +# (e.g. PTHREAD_CREATE_UNDETACHED on AIX). +# +# ACTION-IF-FOUND is a list of shell commands to run if a threads library +# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it +# is not found. If ACTION-IF-FOUND is not specified, the default action +# will define HAVE_PTHREAD. +# +# Please let the authors know if this macro fails on any platform, or if +# you have any other suggestions or comments. This macro was based on work +# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help +# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by +# Alejandro Forero Cuervo to the autoconf macro repository. We are also +# grateful for the helpful feedback of numerous users. +# +# LAST MODIFICATION +# +# 2008-04-12 +# +# COPYLEFT +# +# Copyright (c) 2008 Steven G. Johnson +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program 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 General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Macro Archive. When you make and +# distribute a modified version of the Autoconf Macro, you may extend this +# special exception to the GPL to apply to your modified version as well. + +AC_DEFUN([ACX_PTHREAD], [ +AC_REQUIRE([AC_CANONICAL_HOST]) +AC_LANG_SAVE +AC_LANG_C +acx_pthread_ok=no + +# We used to check for pthread.h first, but this fails if pthread.h +# requires special compiler flags (e.g. on True64 or Sequent). +# It gets checked for in the link test anyway. + +# First of all, check if the user has set any of the PTHREAD_LIBS, +# etcetera environment variables, and if threads linking works using +# them: +if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) + AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes) + AC_MSG_RESULT($acx_pthread_ok) + if test x"$acx_pthread_ok" = xno; then + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" + fi + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" +fi + +# We must check for the threads library under a number of different +# names; the ordering is very important because some systems +# (e.g. DEC) have both -lpthread and -lpthreads, where one of the +# libraries is broken (non-POSIX). + +# Create a list of thread flags to try. Items starting with a "-" are +# C compiler flags, and other items are library names, except for "none" +# which indicates that we try without any flags at all, and "pthread-config" +# which is a program returning the flags for the Pth emulation library. + +acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" + +# The ordering *is* (sometimes) important. Some notes on the +# individual items follow: + +# pthreads: AIX (must check this before -lpthread) +# none: in case threads are in libc; should be tried before -Kthread and +# other compiler flags to prevent continual compiler warnings +# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) +# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) +# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) +# -pthreads: Solaris/gcc +# -mthreads: Mingw32/gcc, Lynx/gcc +# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it +# doesn't hurt to check since this sometimes defines pthreads too; +# also defines -D_REENTRANT) +# ... -mt is also the pthreads flag for HP/aCC +# pthread: Linux, etcetera +# --thread-safe: KAI C++ +# pthread-config: use pthread-config program (for GNU Pth library) + +case "${host_cpu}-${host_os}" in + *solaris*) + + # On Solaris (at least, for some versions), libc contains stubbed + # (non-functional) versions of the pthreads routines, so link-based + # tests will erroneously succeed. (We need to link with -pthreads/-mt/ + # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather + # a function called by this macro, so we could check for that, but + # who knows whether they'll stub that too in a future libc.) So, + # we'll just look for -pthreads and -lpthread first: + + acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags" + ;; +esac + +if test x"$acx_pthread_ok" = xno; then +for flag in $acx_pthread_flags; do + + case $flag in + none) + AC_MSG_CHECKING([whether pthreads work without any flags]) + ;; + + -*) + AC_MSG_CHECKING([whether pthreads work with $flag]) + PTHREAD_CFLAGS="$flag" + ;; + + pthread-config) + AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no) + if test x"$acx_pthread_config" = xno; then continue; fi + PTHREAD_CFLAGS="`pthread-config --cflags`" + PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" + ;; + + *) + AC_MSG_CHECKING([for the pthreads library -l$flag]) + PTHREAD_LIBS="-l$flag" + ;; + esac + + save_LIBS="$LIBS" + save_CFLAGS="$CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + + # Check for various functions. We must include pthread.h, + # since some functions may be macros. (On the Sequent, we + # need a special flag -Kthread to make this header compile.) + # We check for pthread_join because it is in -lpthread on IRIX + # while pthread_create is in libc. We check for pthread_attr_init + # due to DEC craziness with -lpthreads. We check for + # pthread_cleanup_push because it is one of the few pthread + # functions on Solaris that doesn't have a non-functional libc stub. + # We try pthread_create on general principles. + AC_TRY_LINK([#include ], + [pthread_t th; pthread_join(th, 0); + pthread_attr_init(0); pthread_cleanup_push(0, 0); + pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], + [acx_pthread_ok=yes]) + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + + AC_MSG_RESULT($acx_pthread_ok) + if test "x$acx_pthread_ok" = xyes; then + break; + fi + + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" +done +fi + +# Various other checks: +if test "x$acx_pthread_ok" = xyes; then + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + + # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. + AC_MSG_CHECKING([for joinable pthread attribute]) + attr_name=unknown + for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do + AC_TRY_LINK([#include ], [int attr=$attr; return attr;], + [attr_name=$attr; break]) + done + AC_MSG_RESULT($attr_name) + if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then + AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name, + [Define to necessary symbol if this constant + uses a non-standard name on your system.]) + fi + + AC_MSG_CHECKING([if more special flags are required for pthreads]) + flag=no + case "${host_cpu}-${host_os}" in + *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; + *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; + esac + AC_MSG_RESULT(${flag}) + if test "x$flag" != xno; then + PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" + fi + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + + # More AIX lossage: must compile with xlc_r or cc_r + if test x"$GCC" != xyes; then + AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC}) + else + PTHREAD_CC=$CC + fi +else + PTHREAD_CC="$CC" +fi + +AC_SUBST(PTHREAD_LIBS) +AC_SUBST(PTHREAD_CFLAGS) +AC_SUBST(PTHREAD_CC) + +# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: +if test x"$acx_pthread_ok" = xyes; then + ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) + : +else + acx_pthread_ok=no + $2 +fi +AC_LANG_RESTORE +])dnl ACX_PTHREAD diff --git a/m4/ax_c_check_flag.html b/m4/ax_c_check_flag.html new file mode 100644 index 0000000..d2cc50e --- /dev/null +++ b/m4/ax_c_check_flag.html @@ -0,0 +1,186 @@ + + + + + Autoconf Macro: ax_c_check_flag + + + + + + + + + + + + + +
+ Download M4 + Source + + Macro + History + + Category Index + +
+
+ Search: +
+
+
+
+

+ ax_c_check_flag +

+

+ Synopsis +

+

+ AX_C_CHECK_FLAG(FLAG-TO-CHECK,[PROLOGUE],[BODY],[ACTION-IF-SUCCESS],[ACTION-IF-FAILURE]) +

+

+ Description +

+
+

+ This macro tests if the C compiler supports the flag FLAG-TO-CHECK. If + successfull execute ACTION-IF-SUCCESS otherwise ACTION-IF-FAILURE. PROLOGUE + and BODY are optional and should be used as in AC_LANG_PROGRAM macro. +

+

+ This code is inspired from KDE_CHECK_COMPILER_FLAG macro. Thanks to Bogdan + Drozdowski <bogdandr@op.pl> for testing and bug fixes. +

+
+

+ Author +

+

+ Francesco Salvestrini <salvestrini@users.sourceforge.net> +

+

+ Last Modified +

+

+ 2007-11-26 +

+

+ Cross References +

+

+ group25-xrefs.png + + + + + + + + + +

+

+ M4 Source Code +

+
+
+AC_DEFUN([AX_C_CHECK_FLAG],[
+  AC_PREREQ([2.61])
+  AC_REQUIRE([AC_PROG_CC])
+  AC_REQUIRE([AC_PROG_SED])
+
+  flag=`echo "$1" | $SED 'y% .=/+-(){}<>:*,%_______________%'`
+
+  AC_CACHE_CHECK([whether the C compiler accepts the $1 flag],
+    [ax_cv_c_check_flag_$flag],[
+
+    AC_LANG_PUSH([C])
+
+    save_CFLAGS="$CFLAGS"
+    CFLAGS="$CFLAGS $1"
+    AC_COMPILE_IFELSE([
+      AC_LANG_PROGRAM([$2],[$3])
+    ],[
+      eval "ax_cv_c_check_flag_$flag=yes"
+    ],[
+      eval "ax_cv_c_check_flag_$flag=no"
+    ])
+
+    CFLAGS="$save_CFLAGS"
+
+    AC_LANG_POP
+
+  ])
+
+  AS_IF([eval "test \"`echo '$ax_cv_c_check_flag_'$flag`\" = yes"],[
+    :
+    $4
+  ],[
+    :
+    $5
+  ])
+])
+
+
+

+ License +

+
+ Copyright © 2007 Francesco + Salvestrini <salvestrini@users.sourceforge.net> +

+ This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. +

+

+ This program 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 General Public License for + more details. +

+

+ You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., 59 + Temple Place - Suite 330, Boston, MA 02111-1307, USA. +

+

+ As a special exception, the respective Autoconf Macro's copyright owner + gives unlimited permission to copy, distribute and modify the configure + scripts that are the output of Autoconf when processing the Macro. You need + not follow the terms of the GNU General Public License when using or + distributing such scripts, even though portions of the text of the Macro + appear in them. The GNU General Public License (GPL) does govern all other + use of the material that constitutes the Autoconf Macro. +

+

+ This special exception to the GPL applies to versions of the Autoconf Macro + released by the Autoconf Macro Archive. When you make and distribute a + modified version of the Autoconf Macro, you may extend this special + exception to the GPL to apply to your modified version as well. +

+
+ + diff --git a/m4/ax_c_check_flag.m4 b/m4/ax_c_check_flag.m4 new file mode 100644 index 0000000..49414be --- /dev/null +++ b/m4/ax_c_check_flag.m4 @@ -0,0 +1,90 @@ +##### http://autoconf-archive.cryp.to/ax_c_check_flag.html +# +# SYNOPSIS +# +# AX_C_CHECK_FLAG(FLAG-TO-CHECK,[PROLOGUE],[BODY],[ACTION-IF-SUCCESS],[ACTION-IF-FAILURE]) +# +# DESCRIPTION +# +# This macro tests if the C compiler supports the flag FLAG-TO-CHECK. +# If successfull execute ACTION-IF-SUCCESS otherwise +# ACTION-IF-FAILURE. PROLOGUE and BODY are optional and should be +# used as in AC_LANG_PROGRAM macro. +# +# This code is inspired from KDE_CHECK_COMPILER_FLAG macro. Thanks to +# Bogdan Drozdowski for testing and bug fixes. +# +# LAST MODIFICATION +# +# 2007-11-26 +# +# COPYLEFT +# +# Copyright (c) 2007 Francesco Salvestrini +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program 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 +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. +# +# As a special exception, the respective Autoconf Macro's copyright +# owner gives unlimited permission to copy, distribute and modify the +# configure scripts that are the output of Autoconf when processing +# the Macro. You need not follow the terms of the GNU General Public +# License when using or distributing such scripts, even though +# portions of the text of the Macro appear in them. The GNU General +# Public License (GPL) does govern all other use of the material that +# constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the +# Autoconf Macro released by the Autoconf Macro Archive. When you +# make and distribute a modified version of the Autoconf Macro, you +# may extend this special exception to the GPL to apply to your +# modified version as well. + +AC_DEFUN([AX_C_CHECK_FLAG],[ + AC_PREREQ([2.61]) + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([AC_PROG_SED]) + + flag=`echo "$1" | $SED 'y% .=/+-(){}<>:*,%_______________%'` + + AC_CACHE_CHECK([whether the C compiler accepts the $1 flag], + [ax_cv_c_check_flag_$flag],[ + + AC_LANG_PUSH([C]) + + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $1" + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([$2],[$3]) + ],[ + eval "ax_cv_c_check_flag_$flag=yes" + ],[ + eval "ax_cv_c_check_flag_$flag=no" + ]) + + CFLAGS="$save_CFLAGS" + + AC_LANG_POP + + ]) + + AS_IF([eval "test \"`echo '$ax_cv_c_check_flag_'$flag`\" = yes"],[ + : + $4 + ],[ + : + $5 + ]) +]) diff --git a/m4/ax_cflags_warn_all_ansi.html b/m4/ax_cflags_warn_all_ansi.html new file mode 100644 index 0000000..74c5b84 --- /dev/null +++ b/m4/ax_cflags_warn_all_ansi.html @@ -0,0 +1,266 @@ + + + + + Autoconf Macro: ax_cflags_warn_all_ansi + + + + + + + + + + + + + +
+ Download M4 + Source + + + Macro History + + Category Index + +
+
+ Search: +
+
+
+
+

+ ax_cflags_warn_all_ansi +

+

+ Synopsis +

+

+ AX_CFLAGS_WARN_ALL_ANSI [(shellvar [,default, [A/NA]])] +

+

+ Description +

+
+

+ Try to find a compiler option that enables most reasonable warnings. This + macro is directly derived from VL_PROG_CC_WARNINGS which is split up into + two AX_CFLAGS_WARN_ALL and + AX_CFLAGS_WARN_ALL_ANSI +

+

+ For the GNU CC compiler it will be -Wall (and -ansi -pedantic) The result + is added to the shellvar being CFLAGS by default. +

+

+ Currently this macro knows about GCC, Solaris C compiler, Digital Unix C + compiler, C for AIX Compiler, HP-UX C compiler, IRIX C compiler, NEC SX-5 + (Super-UX 10) C compiler, and Cray J90 (Unicos 10.0.0.8) C compiler. +

+
+ - $1 shell-variable-to-add-to : CFLAGS
+ - $2 add-value-if-not-found : nothing
+ - $3 action-if-found : add value to shellvariable
+ - $4 action-if-not-found : nothing
+
+
+

+ Author +

+

+ Guido U. Draheim <guidod@gmx.de> +

+

+ Last Modified +

+

+ 2008-04-12 +

+

+ Cross References +

+

+ group8-xrefs.png + + + + + + + + + + + +

+

+ M4 Source Code +

+
+
+AC_DEFUN([AX_CFLAGS_WARN_ALL_ANSI],[dnl
+AS_VAR_PUSHDEF([FLAGS],[CFLAGS])dnl
+AS_VAR_PUSHDEF([VAR],[ac_cv_cflags_warn_all_ansi])dnl
+AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for maximum ansi warnings],
+VAR,[VAR="no, unknown"
+ AC_LANG_SAVE
+ AC_LANG_C
+ ac_save_[]FLAGS="$[]FLAGS"
+# IRIX C compiler:
+#      -use_readonly_const is the default for IRIX C,
+#       puts them into .rodata, but they are copied later.
+#       need to be "-G0 -rdatashared" for strictmode but
+#       I am not sure what effect that has really.         - guidod
+for ac_arg dnl
+in "-pedantic  % -Wall -ansi -pedantic"       dnl   GCC
+   "-xstrconst % -v -Xc"                      dnl Solaris C
+   "-std1      % -verbose -w0 -warnprotos -std1" dnl Digital Unix
+   " % -qlanglvl=ansi -qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" dnl AIX
+   " % -ansi -ansiE -fullwarn"                dnl IRIX
+   "+ESlit     % +w1 -Aa"                     dnl HP-UX C
+   "-Xc        % -pvctl[,]fullmsg -Xc"        dnl NEC SX-5 (Super-UX 10)
+   "-h conform % -h msglevel 2 -h conform"    dnl Cray C (Unicos)
+   #
+do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'`
+   AC_TRY_COMPILE([],[return 0;],
+   [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break])
+done
+ FLAGS="$ac_save_[]FLAGS"
+ AC_LANG_RESTORE
+])
+case ".$VAR" in
+     .ok|.ok,*) m4_ifvaln($3,$3) ;;
+   .|.no|.no,*) m4_ifvaln($4,$4,[m4_ifval($2,[
+        AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"])
+                      m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"])]) ;;
+   *) m4_ifvaln($3,$3,[
+   if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null
+   then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR])
+   else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"])
+                      m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"
+   fi ]) ;;
+esac
+AS_VAR_POPDEF([VAR])dnl
+AS_VAR_POPDEF([FLAGS])dnl
+])
+
+dnl the only difference - the LANG selection... and the default FLAGS
+
+AC_DEFUN([AX_CXXFLAGS_WARN_ALL_ANSI],[dnl
+AS_VAR_PUSHDEF([FLAGS],[CXXFLAGS])dnl
+AS_VAR_PUSHDEF([VAR],[ac_cv_cxxflags_warn_all_ansi])dnl
+AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for maximum ansi warnings],
+VAR,[VAR="no, unknown"
+ AC_LANG_SAVE
+ AC_LANG_CPLUSPLUS
+ ac_save_[]FLAGS="$[]FLAGS"
+# IRIX C compiler:
+#      -use_readonly_const is the default for IRIX C,
+#       puts them into .rodata, but they are copied later.
+#       need to be "-G0 -rdatashared" for strictmode but
+#       I am not sure what effect that has really.         - guidod
+for ac_arg dnl
+in "-pedantic  % -Wall -ansi -pedantic"       dnl   GCC
+   "-xstrconst % -v -Xc"                      dnl Solaris C
+   "-std1      % -verbose -w0 -warnprotos -std1" dnl Digital Unix
+   " % -qlanglvl=ansi -qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" dnl AIX
+   " % -ansi -ansiE -fullwarn"                dnl IRIX
+   "+ESlit     % +w1 -Aa"                     dnl HP-UX C
+   "-Xc        % -pvctl[,]fullmsg -Xc"        dnl NEC SX-5 (Super-UX 10)
+   "-h conform % -h msglevel 2 -h conform"    dnl Cray C (Unicos)
+   #
+do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'`
+   AC_TRY_COMPILE([],[return 0;],
+   [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break])
+done
+ FLAGS="$ac_save_[]FLAGS"
+ AC_LANG_RESTORE
+])
+case ".$VAR" in
+     .ok|.ok,*) m4_ifvaln($3,$3) ;;
+   .|.no|.no,*) m4_ifvaln($4,$4,[m4_ifval($2,[
+        AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"])
+                      m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"])]) ;;
+   *) m4_ifvaln($3,$3,[
+   if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null
+   then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR])
+   else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"])
+                      m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"
+   fi ]) ;;
+esac
+AS_VAR_POPDEF([VAR])dnl
+AS_VAR_POPDEF([FLAGS])dnl
+])
+
+
+

+ License +

+
+ Copyright © 2008 Guido U. Draheim + <guidod@gmx.de> +

+ This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. +

+

+ This program 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 General Public License for + more details. +

+

+ You should have received a copy of the GNU General Public License along + with this program. If not, see <http://www.gnu.org/licenses/>. +

+

+ As a special exception, the respective Autoconf Macro's copyright owner + gives unlimited permission to copy, distribute and modify the configure + scripts that are the output of Autoconf when processing the Macro. You need + not follow the terms of the GNU General Public License when using or + distributing such scripts, even though portions of the text of the Macro + appear in them. The GNU General Public License (GPL) does govern all other + use of the material that constitutes the Autoconf Macro. +

+

+ This special exception to the GPL applies to versions of the Autoconf Macro + released by the Autoconf Macro Archive. When you make and distribute a + modified version of the Autoconf Macro, you may extend this special + exception to the GPL to apply to your modified version as well. +

+
+ + diff --git a/m4/ax_cflags_warn_all_ansi.m4 b/m4/ax_cflags_warn_all_ansi.m4 new file mode 100644 index 0000000..53f21cc --- /dev/null +++ b/m4/ax_cflags_warn_all_ansi.m4 @@ -0,0 +1,154 @@ +# =========================================================================== +# http://autoconf-archive.cryp.to/ax_cflags_warn_all_ansi.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CFLAGS_WARN_ALL_ANSI [(shellvar [,default, [A/NA]])] +# +# DESCRIPTION +# +# Try to find a compiler option that enables most reasonable warnings. +# This macro is directly derived from VL_PROG_CC_WARNINGS which is split +# up into two AX_CFLAGS_WARN_ALL and AX_CFLAGS_WARN_ALL_ANSI +# +# For the GNU CC compiler it will be -Wall (and -ansi -pedantic) The +# result is added to the shellvar being CFLAGS by default. +# +# Currently this macro knows about GCC, Solaris C compiler, Digital Unix C +# compiler, C for AIX Compiler, HP-UX C compiler, IRIX C compiler, NEC +# SX-5 (Super-UX 10) C compiler, and Cray J90 (Unicos 10.0.0.8) C +# compiler. +# +# - $1 shell-variable-to-add-to : CFLAGS +# - $2 add-value-if-not-found : nothing +# - $3 action-if-found : add value to shellvariable +# - $4 action-if-not-found : nothing +# +# LAST MODIFICATION +# +# 2008-04-12 +# +# COPYLEFT +# +# Copyright (c) 2008 Guido U. Draheim +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# This program 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 General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Macro Archive. When you make and +# distribute a modified version of the Autoconf Macro, you may extend this +# special exception to the GPL to apply to your modified version as well. + +AC_DEFUN([AX_CFLAGS_WARN_ALL_ANSI],[dnl +AS_VAR_PUSHDEF([FLAGS],[CFLAGS])dnl +AS_VAR_PUSHDEF([VAR],[ac_cv_cflags_warn_all_ansi])dnl +AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for maximum ansi warnings], +VAR,[VAR="no, unknown" + AC_LANG_SAVE + AC_LANG_C + ac_save_[]FLAGS="$[]FLAGS" +# IRIX C compiler: +# -use_readonly_const is the default for IRIX C, +# puts them into .rodata, but they are copied later. +# need to be "-G0 -rdatashared" for strictmode but +# I am not sure what effect that has really. - guidod +for ac_arg dnl +in "-pedantic % -Wall -ansi -pedantic" dnl GCC + "-xstrconst % -v -Xc" dnl Solaris C + "-std1 % -verbose -w0 -warnprotos -std1" dnl Digital Unix + " % -qlanglvl=ansi -qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" dnl AIX + " % -ansi -ansiE -fullwarn" dnl IRIX + "+ESlit % +w1 -Aa" dnl HP-UX C + "-Xc % -pvctl[,]fullmsg -Xc" dnl NEC SX-5 (Super-UX 10) + "-h conform % -h msglevel 2 -h conform" dnl Cray C (Unicos) + # +do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` + AC_TRY_COMPILE([],[return 0;], + [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) +done + FLAGS="$ac_save_[]FLAGS" + AC_LANG_RESTORE +]) +case ".$VAR" in + .ok|.ok,*) m4_ifvaln($3,$3) ;; + .|.no|.no,*) m4_ifvaln($4,$4,[m4_ifval($2,[ + AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"]) + m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"])]) ;; + *) m4_ifvaln($3,$3,[ + if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null + then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR]) + else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"]) + m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR" + fi ]) ;; +esac +AS_VAR_POPDEF([VAR])dnl +AS_VAR_POPDEF([FLAGS])dnl +]) + +dnl the only difference - the LANG selection... and the default FLAGS + +AC_DEFUN([AX_CXXFLAGS_WARN_ALL_ANSI],[dnl +AS_VAR_PUSHDEF([FLAGS],[CXXFLAGS])dnl +AS_VAR_PUSHDEF([VAR],[ac_cv_cxxflags_warn_all_ansi])dnl +AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for maximum ansi warnings], +VAR,[VAR="no, unknown" + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + ac_save_[]FLAGS="$[]FLAGS" +# IRIX C compiler: +# -use_readonly_const is the default for IRIX C, +# puts them into .rodata, but they are copied later. +# need to be "-G0 -rdatashared" for strictmode but +# I am not sure what effect that has really. - guidod +for ac_arg dnl +in "-pedantic % -Wall -ansi -pedantic" dnl GCC + "-xstrconst % -v -Xc" dnl Solaris C + "-std1 % -verbose -w0 -warnprotos -std1" dnl Digital Unix + " % -qlanglvl=ansi -qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" dnl AIX + " % -ansi -ansiE -fullwarn" dnl IRIX + "+ESlit % +w1 -Aa" dnl HP-UX C + "-Xc % -pvctl[,]fullmsg -Xc" dnl NEC SX-5 (Super-UX 10) + "-h conform % -h msglevel 2 -h conform" dnl Cray C (Unicos) + # +do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` + AC_TRY_COMPILE([],[return 0;], + [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) +done + FLAGS="$ac_save_[]FLAGS" + AC_LANG_RESTORE +]) +case ".$VAR" in + .ok|.ok,*) m4_ifvaln($3,$3) ;; + .|.no|.no,*) m4_ifvaln($4,$4,[m4_ifval($2,[ + AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"]) + m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"])]) ;; + *) m4_ifvaln($3,$3,[ + if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null + then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR]) + else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"]) + m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR" + fi ]) ;; +esac +AS_VAR_POPDEF([VAR])dnl +AS_VAR_POPDEF([FLAGS])dnl +]) diff --git a/m4/ax_create_stdint_h.m4 b/m4/ax_create_stdint_h.m4 new file mode 100644 index 0000000..33a21f8 --- /dev/null +++ b/m4/ax_create_stdint_h.m4 @@ -0,0 +1,727 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_create_stdint_h.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CREATE_STDINT_H [( HEADER-TO-GENERATE [, HEDERS-TO-CHECK])] +# +# DESCRIPTION +# +# the "ISO C9X: 7.18 Integer types " section requires the +# existence of an include file that defines a set of typedefs, +# especially uint8_t,int32_t,uintptr_t. Many older installations will not +# provide this file, but some will have the very same definitions in +# . In other enviroments we can use the inet-types in +# which would define the typedefs int8_t and u_int8_t +# respectivly. +# +# This macros will create a local "_stdint.h" or the headerfile given as +# an argument. In many cases that file will just "#include " or +# "#include ", while in other environments it will provide the +# set of basic 'stdint's definitions/typedefs: +# +# int8_t,uint8_t,int16_t,uint16_t,int32_t,uint32_t,intptr_t,uintptr_t +# int_least32_t.. int_fast32_t.. intmax_t +# +# which may or may not rely on the definitions of other files, or using +# the AC_CHECK_SIZEOF macro to determine the actual sizeof each type. +# +# if your header files require the stdint-types you will want to create an +# installable file mylib-int.h that all your other installable header may +# include. So if you have a library package named "mylib", just use +# +# AX_CREATE_STDINT_H(mylib-int.h) +# +# in configure.ac and go to install that very header file in Makefile.am +# along with the other headers (mylib.h) - and the mylib-specific headers +# can simply use "#include " to obtain the stdint-types. +# +# Remember, if the system already had a valid , the generated +# file will include it directly. No need for fuzzy HAVE_STDINT_H things... +# (oops, GCC 4.2.x has deliberatly disabled its stdint.h for non-c99 +# compilation and the c99-mode is not the default. Therefore this macro +# will not use the compiler's stdint.h - please complain to the GCC +# developers). +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program 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 General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 10 + +AC_DEFUN([AX_CHECK_DATA_MODEL],[ + AC_CHECK_SIZEOF(char) + AC_CHECK_SIZEOF(short) + AC_CHECK_SIZEOF(int) + AC_CHECK_SIZEOF(long) + AC_CHECK_SIZEOF(void*) + ac_cv_char_data_model="" + ac_cv_char_data_model="$ac_cv_char_data_model$ac_cv_sizeof_char" + ac_cv_char_data_model="$ac_cv_char_data_model$ac_cv_sizeof_short" + ac_cv_char_data_model="$ac_cv_char_data_model$ac_cv_sizeof_int" + ac_cv_long_data_model="" + ac_cv_long_data_model="$ac_cv_long_data_model$ac_cv_sizeof_int" + ac_cv_long_data_model="$ac_cv_long_data_model$ac_cv_sizeof_long" + ac_cv_long_data_model="$ac_cv_long_data_model$ac_cv_sizeof_voidp" + AC_MSG_CHECKING([data model]) + case "$ac_cv_char_data_model/$ac_cv_long_data_model" in + 122/242) ac_cv_data_model="IP16" ; n="standard 16bit machine" ;; + 122/244) ac_cv_data_model="LP32" ; n="standard 32bit machine" ;; + 122/*) ac_cv_data_model="i16" ; n="unusual int16 model" ;; + 124/444) ac_cv_data_model="ILP32" ; n="standard 32bit unixish" ;; + 124/488) ac_cv_data_model="LP64" ; n="standard 64bit unixish" ;; + 124/448) ac_cv_data_model="LLP64" ; n="unusual 64bit unixish" ;; + 124/*) ac_cv_data_model="i32" ; n="unusual int32 model" ;; + 128/888) ac_cv_data_model="ILP64" ; n="unusual 64bit numeric" ;; + 128/*) ac_cv_data_model="i64" ; n="unusual int64 model" ;; + 222/*2) ac_cv_data_model="DSP16" ; n="strict 16bit dsptype" ;; + 333/*3) ac_cv_data_model="DSP24" ; n="strict 24bit dsptype" ;; + 444/*4) ac_cv_data_model="DSP32" ; n="strict 32bit dsptype" ;; + 666/*6) ac_cv_data_model="DSP48" ; n="strict 48bit dsptype" ;; + 888/*8) ac_cv_data_model="DSP64" ; n="strict 64bit dsptype" ;; + 222/*|333/*|444/*|666/*|888/*) : + ac_cv_data_model="iDSP" ; n="unusual dsptype" ;; + *) ac_cv_data_model="none" ; n="very unusual model" ;; + esac + AC_MSG_RESULT([$ac_cv_data_model ($ac_cv_long_data_model, $n)]) +]) + +dnl AX_CHECK_HEADER_STDINT_X([HEADERLIST][,ACTION-IF]) +AC_DEFUN([AX_CHECK_HEADER_STDINT_X],[ +AC_CACHE_CHECK([for stdint uintptr_t], [ac_cv_header_stdint_x],[ + ac_cv_header_stdint_x="" # the 1997 typedefs (inttypes.h) + AC_MSG_RESULT([(..)]) + for i in m4_ifval([$1],[$1],[stdint.h inttypes.h sys/inttypes.h sys/types.h]) + do + unset ac_cv_type_uintptr_t + unset ac_cv_type_uint64_t + AC_CHECK_TYPE(uintptr_t,[ac_cv_header_stdint_x=$i],continue,[#include <$i>]) + AC_CHECK_TYPE(uint64_t,[and64="/uint64_t"],[and64=""],[#include<$i>]) + m4_ifvaln([$2],[$2]) break + done + AC_MSG_CHECKING([for stdint uintptr_t]) + ]) +]) + +AC_DEFUN([AX_CHECK_HEADER_STDINT_O],[ +AC_CACHE_CHECK([for stdint uint32_t], [ac_cv_header_stdint_o],[ + ac_cv_header_stdint_o="" # the 1995 typedefs (sys/inttypes.h) + AC_MSG_RESULT([(..)]) + for i in m4_ifval([$1],[$1],[inttypes.h sys/inttypes.h sys/types.h stdint.h]) + do + unset ac_cv_type_uint32_t + unset ac_cv_type_uint64_t + AC_CHECK_TYPE(uint32_t,[ac_cv_header_stdint_o=$i],continue,[#include <$i>]) + AC_CHECK_TYPE(uint64_t,[and64="/uint64_t"],[and64=""],[#include<$i>]) + m4_ifvaln([$2],[$2]) break + break; + done + AC_MSG_CHECKING([for stdint uint32_t]) + ]) +]) + +AC_DEFUN([AX_CHECK_HEADER_STDINT_U],[ +AC_CACHE_CHECK([for stdint u_int32_t], [ac_cv_header_stdint_u],[ + ac_cv_header_stdint_u="" # the BSD typedefs (sys/types.h) + AC_MSG_RESULT([(..)]) + for i in m4_ifval([$1],[$1],[sys/types.h inttypes.h sys/inttypes.h]) ; do + unset ac_cv_type_u_int32_t + unset ac_cv_type_u_int64_t + AC_CHECK_TYPE(u_int32_t,[ac_cv_header_stdint_u=$i],continue,[#include <$i>]) + AC_CHECK_TYPE(u_int64_t,[and64="/u_int64_t"],[and64=""],[#include<$i>]) + m4_ifvaln([$2],[$2]) break + break; + done + AC_MSG_CHECKING([for stdint u_int32_t]) + ]) +]) + +AC_DEFUN([AX_CREATE_STDINT_H], +[# ------ AX CREATE STDINT H ------------------------------------- +AC_MSG_CHECKING([for stdint types]) +ac_stdint_h=`echo ifelse($1, , _stdint.h, $1)` +# try to shortcircuit - if the default include path of the compiler +# can find a "stdint.h" header then we assume that all compilers can. +AC_CACHE_VAL([ac_cv_header_stdint_t],[ +old_CXXFLAGS="$CXXFLAGS" ; CXXFLAGS="" +old_CPPFLAGS="$CPPFLAGS" ; CPPFLAGS="" +old_CFLAGS="$CFLAGS" ; CFLAGS="" +AC_TRY_COMPILE([#include ],[int_least32_t v = 0;], +[ac_cv_stdint_result="(assuming C99 compatible system)" + ac_cv_header_stdint_t="stdint.h"; ], +[ac_cv_header_stdint_t=""]) +if test "$GCC" = "yes" && test ".$ac_cv_header_stdint_t" = "."; then +CFLAGS="-std=c99" +AC_TRY_COMPILE([#include ],[int_least32_t v = 0;], +[AC_MSG_WARN(your GCC compiler has a defunct stdint.h for its default-mode)]) +fi +CXXFLAGS="$old_CXXFLAGS" +CPPFLAGS="$old_CPPFLAGS" +CFLAGS="$old_CFLAGS" ]) + +v="... $ac_cv_header_stdint_h" +if test "$ac_stdint_h" = "stdint.h" ; then + AC_MSG_RESULT([(are you sure you want them in ./stdint.h?)]) +elif test "$ac_stdint_h" = "inttypes.h" ; then + AC_MSG_RESULT([(are you sure you want them in ./inttypes.h?)]) +elif test "_$ac_cv_header_stdint_t" = "_" ; then + AC_MSG_RESULT([(putting them into $ac_stdint_h)$v]) +else + ac_cv_header_stdint="$ac_cv_header_stdint_t" + AC_MSG_RESULT([$ac_cv_header_stdint (shortcircuit)]) +fi + +if test "_$ac_cv_header_stdint_t" = "_" ; then # cannot shortcircuit.. + +dnl .....intro message done, now do a few system checks..... +dnl btw, all old CHECK_TYPE macros do automatically "DEFINE" a type, +dnl therefore we use the autoconf implementation detail CHECK_TYPE_NEW +dnl instead that is triggered with 3 or more arguments (see types.m4) + +inttype_headers=`echo $2 | sed -e 's/,/ /g'` + +ac_cv_stdint_result="(no helpful system typedefs seen)" +AX_CHECK_HEADER_STDINT_X(dnl + stdint.h inttypes.h sys/inttypes.h $inttype_headers, + ac_cv_stdint_result="(seen uintptr_t$and64 in $i)") + +if test "_$ac_cv_header_stdint_x" = "_" ; then +AX_CHECK_HEADER_STDINT_O(dnl, + inttypes.h sys/inttypes.h stdint.h $inttype_headers, + ac_cv_stdint_result="(seen uint32_t$and64 in $i)") +fi + +if test "_$ac_cv_header_stdint_x" = "_" ; then +if test "_$ac_cv_header_stdint_o" = "_" ; then +AX_CHECK_HEADER_STDINT_U(dnl, + sys/types.h inttypes.h sys/inttypes.h $inttype_headers, + ac_cv_stdint_result="(seen u_int32_t$and64 in $i)") +fi fi + +dnl if there was no good C99 header file, do some typedef checks... +if test "_$ac_cv_header_stdint_x" = "_" ; then + AC_MSG_CHECKING([for stdint datatype model]) + AC_MSG_RESULT([(..)]) + AX_CHECK_DATA_MODEL +fi + +if test "_$ac_cv_header_stdint_x" != "_" ; then + ac_cv_header_stdint="$ac_cv_header_stdint_x" +elif test "_$ac_cv_header_stdint_o" != "_" ; then + ac_cv_header_stdint="$ac_cv_header_stdint_o" +elif test "_$ac_cv_header_stdint_u" != "_" ; then + ac_cv_header_stdint="$ac_cv_header_stdint_u" +else + ac_cv_header_stdint="stddef.h" +fi + +AC_MSG_CHECKING([for extra inttypes in chosen header]) +AC_MSG_RESULT([($ac_cv_header_stdint)]) +dnl see if int_least and int_fast types are present in _this_ header. +unset ac_cv_type_int_least32_t +unset ac_cv_type_int_fast32_t +AC_CHECK_TYPE(int_least32_t,,,[#include <$ac_cv_header_stdint>]) +AC_CHECK_TYPE(int_fast32_t,,,[#include<$ac_cv_header_stdint>]) +AC_CHECK_TYPE(intmax_t,,,[#include <$ac_cv_header_stdint>]) + +fi # shortcircut to system "stdint.h" +# ------------------ PREPARE VARIABLES ------------------------------ +if test "$GCC" = "yes" ; then +ac_cv_stdint_message="using gnu compiler "`$CC --version | head -1` +else +ac_cv_stdint_message="using $CC" +fi + +AC_MSG_RESULT([make use of $ac_cv_header_stdint in $ac_stdint_h dnl +$ac_cv_stdint_result]) + +dnl ----------------------------------------------------------------- +# ----------------- DONE inttypes.h checks START header ------------- +AC_CONFIG_COMMANDS([$ac_stdint_h],[ +AC_MSG_NOTICE(creating $ac_stdint_h : $_ac_stdint_h) +ac_stdint=$tmp/_stdint.h + +echo "#ifndef" $_ac_stdint_h >$ac_stdint +echo "#define" $_ac_stdint_h "1" >>$ac_stdint +echo "#ifndef" _GENERATED_STDINT_H >>$ac_stdint +echo "#define" _GENERATED_STDINT_H '"'$PACKAGE $VERSION'"' >>$ac_stdint +echo "/* generated $ac_cv_stdint_message */" >>$ac_stdint +if test "_$ac_cv_header_stdint_t" != "_" ; then +echo "#define _STDINT_HAVE_STDINT_H" "1" >>$ac_stdint +echo "#include " >>$ac_stdint +echo "#endif" >>$ac_stdint +echo "#endif" >>$ac_stdint +else + +cat >>$ac_stdint < +#else +#include + +/* .................... configured part ............................ */ + +STDINT_EOF + +echo "/* whether we have a C99 compatible stdint header file */" >>$ac_stdint +if test "_$ac_cv_header_stdint_x" != "_" ; then + ac_header="$ac_cv_header_stdint_x" + echo "#define _STDINT_HEADER_INTPTR" '"'"$ac_header"'"' >>$ac_stdint +else + echo "/* #undef _STDINT_HEADER_INTPTR */" >>$ac_stdint +fi + +echo "/* whether we have a C96 compatible inttypes header file */" >>$ac_stdint +if test "_$ac_cv_header_stdint_o" != "_" ; then + ac_header="$ac_cv_header_stdint_o" + echo "#define _STDINT_HEADER_UINT32" '"'"$ac_header"'"' >>$ac_stdint +else + echo "/* #undef _STDINT_HEADER_UINT32 */" >>$ac_stdint +fi + +echo "/* whether we have a BSD compatible inet types header */" >>$ac_stdint +if test "_$ac_cv_header_stdint_u" != "_" ; then + ac_header="$ac_cv_header_stdint_u" + echo "#define _STDINT_HEADER_U_INT32" '"'"$ac_header"'"' >>$ac_stdint +else + echo "/* #undef _STDINT_HEADER_U_INT32 */" >>$ac_stdint +fi + +echo "" >>$ac_stdint + +if test "_$ac_header" != "_" ; then if test "$ac_header" != "stddef.h" ; then + echo "#include <$ac_header>" >>$ac_stdint + echo "" >>$ac_stdint +fi fi + +echo "/* which 64bit typedef has been found */" >>$ac_stdint +if test "$ac_cv_type_uint64_t" = "yes" ; then +echo "#define _STDINT_HAVE_UINT64_T" "1" >>$ac_stdint +else +echo "/* #undef _STDINT_HAVE_UINT64_T */" >>$ac_stdint +fi +if test "$ac_cv_type_u_int64_t" = "yes" ; then +echo "#define _STDINT_HAVE_U_INT64_T" "1" >>$ac_stdint +else +echo "/* #undef _STDINT_HAVE_U_INT64_T */" >>$ac_stdint +fi +echo "" >>$ac_stdint + +echo "/* which type model has been detected */" >>$ac_stdint +if test "_$ac_cv_char_data_model" != "_" ; then +echo "#define _STDINT_CHAR_MODEL" "$ac_cv_char_data_model" >>$ac_stdint +echo "#define _STDINT_LONG_MODEL" "$ac_cv_long_data_model" >>$ac_stdint +else +echo "/* #undef _STDINT_CHAR_MODEL // skipped */" >>$ac_stdint +echo "/* #undef _STDINT_LONG_MODEL // skipped */" >>$ac_stdint +fi +echo "" >>$ac_stdint + +echo "/* whether int_least types were detected */" >>$ac_stdint +if test "$ac_cv_type_int_least32_t" = "yes"; then +echo "#define _STDINT_HAVE_INT_LEAST32_T" "1" >>$ac_stdint +else +echo "/* #undef _STDINT_HAVE_INT_LEAST32_T */" >>$ac_stdint +fi +echo "/* whether int_fast types were detected */" >>$ac_stdint +if test "$ac_cv_type_int_fast32_t" = "yes"; then +echo "#define _STDINT_HAVE_INT_FAST32_T" "1" >>$ac_stdint +else +echo "/* #undef _STDINT_HAVE_INT_FAST32_T */" >>$ac_stdint +fi +echo "/* whether intmax_t type was detected */" >>$ac_stdint +if test "$ac_cv_type_intmax_t" = "yes"; then +echo "#define _STDINT_HAVE_INTMAX_T" "1" >>$ac_stdint +else +echo "/* #undef _STDINT_HAVE_INTMAX_T */" >>$ac_stdint +fi +echo "" >>$ac_stdint + + cat >>$ac_stdint <= 199901L +#define _HAVE_UINT64_T +#define _HAVE_LONGLONG_UINT64_T +typedef long long int64_t; +typedef unsigned long long uint64_t; + +#elif !defined __STRICT_ANSI__ +#if defined _MSC_VER || defined __WATCOMC__ || defined __BORLANDC__ +#define _HAVE_UINT64_T +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; + +#elif defined __GNUC__ || defined __MWERKS__ || defined __ELF__ +/* note: all ELF-systems seem to have loff-support which needs 64-bit */ +#if !defined _NO_LONGLONG +#define _HAVE_UINT64_T +#define _HAVE_LONGLONG_UINT64_T +typedef long long int64_t; +typedef unsigned long long uint64_t; +#endif + +#elif defined __alpha || (defined __mips && defined _ABIN32) +#if !defined _NO_LONGLONG +typedef long int64_t; +typedef unsigned long uint64_t; +#endif + /* compiler/cpu type to define int64_t */ +#endif +#endif +#endif + +#if defined _STDINT_HAVE_U_INT_TYPES +/* int8_t int16_t int32_t defined by inet code, redeclare the u_intXX types */ +typedef u_int8_t uint8_t; +typedef u_int16_t uint16_t; +typedef u_int32_t uint32_t; + +/* glibc compatibility */ +#ifndef __int8_t_defined +#define __int8_t_defined +#endif +#endif + +#ifdef _STDINT_NEED_INT_MODEL_T +/* we must guess all the basic types. Apart from byte-adressable system, */ +/* there a few 32-bit-only dsp-systems that we guard with BYTE_MODEL 8-} */ +/* (btw, those nibble-addressable systems are way off, or so we assume) */ + +dnl /* have a look at "64bit and data size neutrality" at */ +dnl /* http://unix.org/version2/whatsnew/login_64bit.html */ +dnl /* (the shorthand "ILP" types always have a "P" part) */ + +#if defined _STDINT_BYTE_MODEL +#if _STDINT_LONG_MODEL+0 == 242 +/* 2:4:2 = IP16 = a normal 16-bit system */ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned long uint32_t; +#ifndef __int8_t_defined +#define __int8_t_defined +typedef char int8_t; +typedef short int16_t; +typedef long int32_t; +#endif +#elif _STDINT_LONG_MODEL+0 == 244 || _STDINT_LONG_MODEL == 444 +/* 2:4:4 = LP32 = a 32-bit system derived from a 16-bit */ +/* 4:4:4 = ILP32 = a normal 32-bit system */ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +#ifndef __int8_t_defined +#define __int8_t_defined +typedef char int8_t; +typedef short int16_t; +typedef int int32_t; +#endif +#elif _STDINT_LONG_MODEL+0 == 484 || _STDINT_LONG_MODEL+0 == 488 +/* 4:8:4 = IP32 = a 32-bit system prepared for 64-bit */ +/* 4:8:8 = LP64 = a normal 64-bit system */ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +#ifndef __int8_t_defined +#define __int8_t_defined +typedef char int8_t; +typedef short int16_t; +typedef int int32_t; +#endif +/* this system has a "long" of 64bit */ +#ifndef _HAVE_UINT64_T +#define _HAVE_UINT64_T +typedef unsigned long uint64_t; +typedef long int64_t; +#endif +#elif _STDINT_LONG_MODEL+0 == 448 +/* LLP64 a 64-bit system derived from a 32-bit system */ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +#ifndef __int8_t_defined +#define __int8_t_defined +typedef char int8_t; +typedef short int16_t; +typedef int int32_t; +#endif +/* assuming the system has a "long long" */ +#ifndef _HAVE_UINT64_T +#define _HAVE_UINT64_T +#define _HAVE_LONGLONG_UINT64_T +typedef unsigned long long uint64_t; +typedef long long int64_t; +#endif +#else +#define _STDINT_NO_INT32_T +#endif +#else +#define _STDINT_NO_INT8_T +#define _STDINT_NO_INT32_T +#endif +#endif + +/* + * quote from SunOS-5.8 sys/inttypes.h: + * Use at your own risk. As of February 1996, the committee is squarely + * behind the fixed sized types; the "least" and "fast" types are still being + * discussed. The probability that the "fast" types may be removed before + * the standard is finalized is high enough that they are not currently + * implemented. + */ + +#if defined _STDINT_NEED_INT_LEAST_T +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +#ifdef _HAVE_UINT64_T +typedef int64_t int_least64_t; +#endif + +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +#ifdef _HAVE_UINT64_T +typedef uint64_t uint_least64_t; +#endif + /* least types */ +#endif + +#if defined _STDINT_NEED_INT_FAST_T +typedef int8_t int_fast8_t; +typedef int int_fast16_t; +typedef int32_t int_fast32_t; +#ifdef _HAVE_UINT64_T +typedef int64_t int_fast64_t; +#endif + +typedef uint8_t uint_fast8_t; +typedef unsigned uint_fast16_t; +typedef uint32_t uint_fast32_t; +#ifdef _HAVE_UINT64_T +typedef uint64_t uint_fast64_t; +#endif + /* fast types */ +#endif + +#ifdef _STDINT_NEED_INTMAX_T +#ifdef _HAVE_UINT64_T +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; +#else +typedef long intmax_t; +typedef unsigned long uintmax_t; +#endif +#endif + +#ifdef _STDINT_NEED_INTPTR_T +#ifndef __intptr_t_defined +#define __intptr_t_defined +/* we encourage using "long" to store pointer values, never use "int" ! */ +#if _STDINT_LONG_MODEL+0 == 242 || _STDINT_LONG_MODEL+0 == 484 +typedef unsigned int uintptr_t; +typedef int intptr_t; +#elif _STDINT_LONG_MODEL+0 == 244 || _STDINT_LONG_MODEL+0 == 444 +typedef unsigned long uintptr_t; +typedef long intptr_t; +#elif _STDINT_LONG_MODEL+0 == 448 && defined _HAVE_UINT64_T +typedef uint64_t uintptr_t; +typedef int64_t intptr_t; +#else /* matches typical system types ILP32 and LP64 - but not IP16 or LLP64 */ +typedef unsigned long uintptr_t; +typedef long intptr_t; +#endif +#endif +#endif + +/* The ISO C99 standard specifies that in C++ implementations these + should only be defined if explicitly requested. */ +#if !defined __cplusplus || defined __STDC_CONSTANT_MACROS +#ifndef UINT32_C + +/* Signed. */ +# define INT8_C(c) c +# define INT16_C(c) c +# define INT32_C(c) c +# ifdef _HAVE_LONGLONG_UINT64_T +# define INT64_C(c) c ## L +# else +# define INT64_C(c) c ## LL +# endif + +/* Unsigned. */ +# define UINT8_C(c) c ## U +# define UINT16_C(c) c ## U +# define UINT32_C(c) c ## U +# ifdef _HAVE_LONGLONG_UINT64_T +# define UINT64_C(c) c ## UL +# else +# define UINT64_C(c) c ## ULL +# endif + +/* Maximal type. */ +# ifdef _HAVE_LONGLONG_UINT64_T +# define INTMAX_C(c) c ## L +# define UINTMAX_C(c) c ## UL +# else +# define INTMAX_C(c) c ## LL +# define UINTMAX_C(c) c ## ULL +# endif + + /* literalnumbers */ +#endif +#endif + +/* These limits are merily those of a two complement byte-oriented system */ + +/* Minimum of signed integral types. */ +# define INT8_MIN (-128) +# define INT16_MIN (-32767-1) +# define INT32_MIN (-2147483647-1) +# define INT64_MIN (-__INT64_C(9223372036854775807)-1) +/* Maximum of signed integral types. */ +# define INT8_MAX (127) +# define INT16_MAX (32767) +# define INT32_MAX (2147483647) +# define INT64_MAX (__INT64_C(9223372036854775807)) + +/* Maximum of unsigned integral types. */ +# define UINT8_MAX (255) +# define UINT16_MAX (65535) +# define UINT32_MAX (4294967295U) +# define UINT64_MAX (__UINT64_C(18446744073709551615)) + +/* Minimum of signed integral types having a minimum size. */ +# define INT_LEAST8_MIN INT8_MIN +# define INT_LEAST16_MIN INT16_MIN +# define INT_LEAST32_MIN INT32_MIN +# define INT_LEAST64_MIN INT64_MIN +/* Maximum of signed integral types having a minimum size. */ +# define INT_LEAST8_MAX INT8_MAX +# define INT_LEAST16_MAX INT16_MAX +# define INT_LEAST32_MAX INT32_MAX +# define INT_LEAST64_MAX INT64_MAX + +/* Maximum of unsigned integral types having a minimum size. */ +# define UINT_LEAST8_MAX UINT8_MAX +# define UINT_LEAST16_MAX UINT16_MAX +# define UINT_LEAST32_MAX UINT32_MAX +# define UINT_LEAST64_MAX UINT64_MAX + + /* shortcircuit*/ +#endif + /* once */ +#endif +#endif +STDINT_EOF +fi + if cmp -s $ac_stdint_h $ac_stdint 2>/dev/null; then + AC_MSG_NOTICE([$ac_stdint_h is unchanged]) + else + ac_dir=`AS_DIRNAME(["$ac_stdint_h"])` + AS_MKDIR_P(["$ac_dir"]) + rm -f $ac_stdint_h + mv $ac_stdint $ac_stdint_h + fi +],[# variables for create stdint.h replacement +PACKAGE="$PACKAGE" +VERSION="$VERSION" +ac_stdint_h="$ac_stdint_h" +_ac_stdint_h=AS_TR_CPP(_$PACKAGE-$ac_stdint_h) +ac_cv_stdint_message="$ac_cv_stdint_message" +ac_cv_header_stdint_t="$ac_cv_header_stdint_t" +ac_cv_header_stdint_x="$ac_cv_header_stdint_x" +ac_cv_header_stdint_o="$ac_cv_header_stdint_o" +ac_cv_header_stdint_u="$ac_cv_header_stdint_u" +ac_cv_type_uint64_t="$ac_cv_type_uint64_t" +ac_cv_type_u_int64_t="$ac_cv_type_u_int64_t" +ac_cv_char_data_model="$ac_cv_char_data_model" +ac_cv_long_data_model="$ac_cv_long_data_model" +ac_cv_type_int_least32_t="$ac_cv_type_int_least32_t" +ac_cv_type_int_fast32_t="$ac_cv_type_int_fast32_t" +ac_cv_type_intmax_t="$ac_cv_type_intmax_t" +]) +]) diff --git a/m4/librt_timers.m4 b/m4/librt_timers.m4 new file mode 100644 index 0000000..f1595e2 --- /dev/null +++ b/m4/librt_timers.m4 @@ -0,0 +1,90 @@ +# HW_HEADER_TIME_H +# ------------------ +# Define HAVE_TIME_H to 1 if is available. +AC_DEFUN([HW_HEADER_TIME_H], +[ + AC_PREREQ([2.60])dnl Older releases should work if AC_CHECK_HEADERS is used. + AC_CHECK_HEADERS_ONCE([time.h]) +])# HW_HEADER_TIME_H + +# HW_LIBRT_TIMERS +# ----------------- +# Set $hw_cv_librt_timers and $hw_cv_librt_timers_posix to "yes" or "no", +# respectively. If the timer_create() function is available and +# POSIX compliant, then the system's timer_create(), timer_settime(), +# and timer_delete() functions are used. Otherwise, make sure +# the replacement functions will be built. +# +# In the case where we are cross compiling, the POSIX detection of +# the timer_create() function is skipped, and instead the usual check +# for the existence of all the timer_* functions is done using +# AC_REPLACE_FUNCS. +# +# If enable_timer_replacement=true, the replacements is forced to be built. +AC_DEFUN([HW_LIBRT_TIMERS], +[ + AC_PREREQ([2.60])dnl 2.59 should work if some AC_TYPE_* macros are replaced. + AC_REQUIRE([HW_HEADER_TIME_H])dnl Our check evaluates HAVE_TIME_H. + + if test "xtrue" != x"$enable_timer_replacement"; then + AC_CHECK_FUNC([timer_create], + [hw_cv_librt_timers=yes], + [hw_cv_librt_timers=no]) + AS_IF([test "$hw_cv_librt_timers" = yes], + [AC_CACHE_CHECK([if timer_create is supported on the system], + [hw_cv_librt_timers_posix], + [AC_RUN_IFELSE( + [AC_LANG_PROGRAM( + [[#if HAVE_TIME_H + #include + #endif + #include + static int test_timer_create() + { + timer_t timerid; + if(timer_create(CLOCK_REALTIME, NULL, &timerid) != 0) + { + /* + On this system, although the function is available, + no meaningful implementation is provided. + */ + if(errno == ENOSYS) + { + return 1; + } + } + return 0; + }]], + [[return test_timer_create();]])], + [hw_cv_librt_timers_posix=yes], + [hw_cv_librt_timers_posix=no], + [hw_cv_librt_timers_posix=autodetect])])], + [hw_cv_librt_timers_posix=no]) + else + hw_cv_librt_timers_posix=no + fi + + # If the system does not have a POSIX timer_create(), then use + # Check's reimplementation of the timer_* calls + AS_IF([test "$hw_cv_librt_timers_posix" = no], + [_HW_LIBRT_TIMERS_REPLACE]) + + # If we are cross compiling, do the normal check for the + # timer_* calls. + AS_IF([test "$hw_cv_librt_timers_posix" = autodetect], + [AC_REPLACE_FUNCS([timer_create timer_settime timer_delete]) + AC_CHECK_DECLS([timer_create, timer_settime, timer_delete])]) +])# HW_LIBRT_TIMERS + +# _HW_LIBRT_TIMERS_REPLACE +# ------------------------ +# Arrange for building timer_create.c, timer_settime.c, and +# timer_delete.c. +AC_DEFUN([_HW_LIBRT_TIMERS_REPLACE], +[ + AS_IF([test "x$_hw_cv_librt_timers_replace_done" != xyes], + [AC_LIBOBJ([timer_create]) + AC_LIBOBJ([timer_settime]) + AC_LIBOBJ([timer_delete]) + _hw_cv_librt_timers_replace_done=yes]) +])# _HW_LIBRT_TIMERS_REPLACE diff --git a/m4/snprintf.m4 b/m4/snprintf.m4 new file mode 100644 index 0000000..e176d17 --- /dev/null +++ b/m4/snprintf.m4 @@ -0,0 +1,263 @@ +# $Id: snprintf.m4,v 1.1.1.1 2008/01/06 03:24:00 holger Exp $ + +# Copyright (c) 2008 Holger Weiss . +# +# This code may freely be used, modified and/or redistributed for any purpose. +# It would be nice if additions and fixes to this file (including trivial code +# cleanups) would be sent back in order to let me include them in the version +# available at . However, this is +# not a requirement for using or redistributing (possibly modified) versions of +# this file, nor is leaving this notice intact mandatory. + +# HW_HEADER_STDARG_H +# ------------------ +# Define HAVE_STDARG_H to 1 if is available. +AC_DEFUN([HW_HEADER_STDARG_H], +[ + AC_PREREQ([2.60])dnl Older releases should work if AC_CHECK_HEADERS is used. + AC_CHECK_HEADERS_ONCE([stdarg.h]) +])# HW_HEADER_STDARG_H + +# HW_HEADER_VARARGS_H +# ------------------- +# Define HAVE_VARARGS_H to 1 if is available. +AC_DEFUN([HW_HEADER_VARARGS_H], +[ + AC_PREREQ([2.60])dnl Older releases should work if AC_CHECK_HEADERS is used. + AC_CHECK_HEADERS_ONCE([varargs.h]) +])# HW_HEADER_VARARGS_H + +# HW_FUNC_VA_COPY +# --------------- +# Set $hw_cv_func_va_copy to "yes" or "no". Define HAVE_VA_COPY to 1 if +# $hw_cv_func_va_copy is set to "yes". Note that it's "unspecified whether +# va_copy and va_end are macros or identifiers declared with external linkage." +# (C99: 7.15.1, 1) Therefore, the presence of va_copy(3) cannot simply "be +# tested with #ifdef", as suggested by the Autoconf manual (5.5.1). +AC_DEFUN([HW_FUNC_VA_COPY], +[ + AC_REQUIRE([HW_HEADER_STDARG_H])dnl Our check evaluates HAVE_STDARG_H. + AC_REQUIRE([HW_HEADER_VARARGS_H])dnl Our check evaluates HAVE_VARARGS_H. + AC_CACHE_CHECK([for va_copy], + [hw_cv_func_va_copy], + [AC_RUN_IFELSE( + [AC_LANG_PROGRAM( + [[#if HAVE_STDARG_H + #include + #elif HAVE_VARARGS_H + #include + #endif]], + [[va_list ap, aq; va_copy(aq, ap);]])], + [hw_cv_func_va_copy=yes], + [hw_cv_func_va_copy=no], + [hw_cv_func_va_copy=no])]) + AS_IF([test "$hw_cv_func_va_copy" = yes], + [AC_DEFINE([HAVE_VA_COPY], [1], + [Define to 1 if you have the `va_copy' function or macro.])]) +])# HW_FUNC_VA_COPY + +# HW_FUNC___VA_COPY +# ----------------- +# Set $hw_cv_func___va_copy to "yes" or "no". Define HAVE___VA_COPY to 1 if +# $hw_cv_func___va_copy is set to "yes". +AC_DEFUN([HW_FUNC___VA_COPY], +[ + AC_REQUIRE([HW_HEADER_STDARG_H])dnl Our check evaluates HAVE_STDARG_H. + AC_REQUIRE([HW_HEADER_VARARGS_H])dnl Our check evaluates HAVE_VARARGS_H. + AC_CACHE_CHECK([for __va_copy], + [hw_cv_func___va_copy], + [AC_RUN_IFELSE( + [AC_LANG_PROGRAM( + [[#if HAVE_STDARG_H + #include + #elif HAVE_VARARGS_H + #include + #endif]], + [[va_list ap, aq; __va_copy(aq, ap);]])], + [hw_cv_func___va_copy=yes], + [hw_cv_func___va_copy=no], + [hw_cv_func___va_copy=no])]) + AS_IF([test "$hw_cv_func___va_copy" = yes], + [AC_DEFINE([HAVE___VA_COPY], [1], + [Define to 1 if you have the `__va_copy' function or macro.])]) +])# HW_FUNC___VA_COPY + +# HW_FUNC_VSNPRINTF +# ----------------- +# Set $hw_cv_func_vsnprintf and $hw_cv_func_vsnprintf_c99 to "yes" or "no", +# respectively. Define HAVE_VSNPRINTF to 1 only if $hw_cv_func_vsnprintf_c99 +# is set to "yes". Otherwise, define vsnprintf to rpl_vsnprintf and make sure +# the replacement function will be built. +# +# If enable_snprintf_replacement=true, the replacement is forced to be built. +AC_DEFUN([HW_FUNC_VSNPRINTF], +[ + AC_PREREQ([2.60])dnl 2.59 should work if some AC_TYPE_* macros are replaced. + AC_REQUIRE([HW_HEADER_STDARG_H])dnl Our check evaluates HAVE_STDARG_H. + + if test "xtrue" != x"$enable_snprintf_replacement"; then + AC_CHECK_FUNC([vsnprintf], + [hw_cv_func_vsnprintf=yes], + [hw_cv_func_vsnprintf=no]) + AS_IF([test "$hw_cv_func_vsnprintf" = yes], + [AC_CACHE_CHECK([whether vsnprintf is C99 compliant], + [hw_cv_func_vsnprintf_c99], + [AC_RUN_IFELSE( + [AC_LANG_PROGRAM( + [[#if HAVE_STDARG_H + #include + #endif + #include + static int testprintf(char *buf, size_t size, const char *format, ...) + { + int result; + va_list ap; + va_start(ap, format); + result = vsnprintf(buf, size, format, ap); + va_end(ap); + return result; + }]], + [[char buf[43]; + if (testprintf(buf, 4, "The answer is %27.2g.", 42.0) != 42 || + testprintf(buf, 0, "No, it's %32zu.", (size_t)42) != 42 || + buf[0] != 'T' || buf[3] != '\0') + return 1;]])], + [hw_cv_func_vsnprintf_c99=yes], + [hw_cv_func_vsnprintf_c99=no], + [hw_cv_func_vsnprintf_c99=no])])], + [hw_cv_func_snprintf_c99=no]) + AS_IF([test "$hw_cv_func_vsnprintf_c99" = yes], + [AC_DEFINE([HAVE_VSNPRINTF], [1], + [Define to 1 if you have a C99 compliant 'vsnprintf' function.])]) + else + hw_cv_func_vsnprintf_c99=no + fi + + AS_IF([test "$hw_cv_func_vsnprintf_c99" = no], + [AC_DEFINE([vsnprintf], [rpl_vsnprintf], + [Define to rpl_vsnprintf if the replacement function should be used.]) + AC_CHECK_HEADERS([inttypes.h locale.h stddef.h stdint.h]) + AC_CHECK_MEMBERS([struct lconv.decimal_point, struct lconv.thousands_sep], + [], [], [#include ]) + AC_TYPE_LONG_DOUBLE + AC_TYPE_LONG_LONG_INT + AC_TYPE_UNSIGNED_LONG_LONG_INT + AC_TYPE_SIZE_T + AC_TYPE_INTMAX_T + AC_TYPE_UINTMAX_T + AC_TYPE_UINTPTR_T + AC_CHECK_TYPES([ptrdiff_t]) + AC_CHECK_FUNCS([localeconv]) + _HW_FUNC_XPRINTF_REPLACE]) +])# HW_FUNC_VSNPRINTF + +# HW_FUNC_SNPRINTF +# ---------------- +# Set $hw_cv_func_snprintf and $hw_cv_func_snprintf_c99 to "yes" or "no", +# respectively. Define HAVE_SNPRINTF to 1 only if $hw_cv_func_snprintf_c99 +# is set to "yes". Otherwise, define snprintf to rpl_snprintf and make sure +# the replacement function will be built. +# +# If enable_snprintf_replacement=true, the replacement is forced to be built. +AC_DEFUN([HW_FUNC_SNPRINTF], +[ + AC_REQUIRE([HW_FUNC_VSNPRINTF])dnl Our snprintf(3) calls vsnprintf(3). + + if test "xtrue" != x"$enable_snprintf_replacement"; then + AC_CHECK_FUNC([snprintf], + [hw_cv_func_snprintf=yes], + [hw_cv_func_snprintf=no]) + AS_IF([test "$hw_cv_func_snprintf" = yes], + [AC_CACHE_CHECK([whether snprintf is C99 compliant], + [hw_cv_func_snprintf_c99], + [AC_RUN_IFELSE( + [AC_LANG_PROGRAM([[#include ]], + [[char buf[43]; + if (snprintf(buf, 4, "The answer is %27.2g.", 42.0) != 42 || + snprintf(buf, 0, "No, it's %32zu.", (size_t)42) != 42 || + buf[0] != 'T' || buf[3] != '\0') + return 1;]])], + [hw_cv_func_snprintf_c99=yes], + [hw_cv_func_snprintf_c99=no], + [hw_cv_func_snprintf_c99=no])])], + [hw_cv_func_snprintf_c99=no]) + else + hw_cv_func_snprintf_c99=no + fi + + AS_IF([test "$hw_cv_func_snprintf_c99" = yes], + [AC_DEFINE([HAVE_SNPRINTF], [1], + [Define to 1 if you have a C99 compliant 'snprintf' function.])], + [AC_DEFINE([snprintf], [rpl_snprintf], + [Define to rpl_snprintf if the replacement function should be used.]) + _HW_FUNC_XPRINTF_REPLACE]) +])# HW_FUNC_SNPRINTF + +# HW_FUNC_VASPRINTF +# ----------------- +# Set $hw_cv_func_vasprintf to "yes" or "no". Define HAVE_VASPRINTF to 1 if +# $hw_cv_func_vasprintf is set to "yes". Otherwise, define vasprintf to +# rpl_vasprintf and make sure the replacement function will be built. +# +# If enable_snprintf_replacement=true, the replacement is forced to be built. +AC_DEFUN([HW_FUNC_VASPRINTF], +[ + AC_REQUIRE([HW_FUNC_VSNPRINTF])dnl Our vasprintf(3) calls vsnprintf(3). + + if test "xtrue" != x"$enable_snprintf_replacement"; then + AC_CHECK_FUNCS([vasprintf], + [hw_cv_func_vasprintf=yes], + [hw_cv_func_vasprintf=no]) + else + hw_cv_func_vasprintf=no + fi + + AS_IF([test "$hw_cv_func_vasprintf" = no], + [AC_DEFINE([vasprintf], [rpl_vasprintf], + [Define to rpl_vasprintf if the replacement function should be used.]) + AC_CHECK_HEADERS([stdlib.h]) + HW_FUNC_VA_COPY + AS_IF([test "$hw_cv_func_va_copy" = no], + [HW_FUNC___VA_COPY]) + _HW_FUNC_XPRINTF_REPLACE]) +])# HW_FUNC_VASPRINTF + +# HW_FUNC_ASPRINTF +# ---------------- +# Set $hw_cv_func_asprintf to "yes" or "no". Define HAVE_ASPRINTF to 1 if +# $hw_cv_func_asprintf is set to "yes". Otherwise, define asprintf to +# rpl_asprintf and make sure the replacement function will be built. +# +# If enable_snprintf_replacement=true, the replacement is forced to be built. +AC_DEFUN([HW_FUNC_ASPRINTF], +[ + AC_REQUIRE([HW_FUNC_VASPRINTF])dnl Our asprintf(3) calls vasprintf(3). + + if test "xtrue" != x"$enable_snprintf_replacement"; then + AC_CHECK_FUNCS([asprintf], + [hw_cv_func_asprintf=yes], + [hw_cv_func_asprintf=no]) + else + hw_cv_func_asprintf=no + fi + + AS_IF([test "$hw_cv_func_asprintf" = no], + [AC_DEFINE([asprintf], [rpl_asprintf], + [Define to rpl_asprintf if the replacement function should be used.]) + _HW_FUNC_XPRINTF_REPLACE]) +])# HW_FUNC_ASPRINTF + +# _HW_FUNC_XPRINTF_REPLACE +# ------------------------ +# Arrange for building snprintf.c. Must be called if one or more of the +# functions provided by snprintf.c are needed. +AC_DEFUN([_HW_FUNC_XPRINTF_REPLACE], +[ + AS_IF([test "x$_hw_cv_func_xprintf_replace_done" != xyes], + [AC_C_CONST + HW_HEADER_STDARG_H + AC_LIBOBJ([snprintf]) + _hw_cv_func_xprintf_replace_done=yes]) +])# _HW_FUNC_XPRINTF_REPLACE + +dnl vim: set joinspaces textwidth=80: diff --git a/src/.cvsignore b/src/.cvsignore new file mode 100644 index 0000000..25ee911 --- /dev/null +++ b/src/.cvsignore @@ -0,0 +1,5 @@ +.deps +Makefile +Makefile.in +libcheck.a +check.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..dae28fc --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,65 @@ +# +# Check: a unit test framework for C +# Copyright (C) 2011 Mateusz Loskot +# 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. +# + +set(SOURCES + 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) + +set(HEADERS + ${CONFIG_HEADER} + ${CMAKE_CURRENT_BINARY_DIR}/check.h + check.h.in + check_error.h + check_impl.h + check_list.h + check_log.h + check_msg.h + check_pack.h + check_print.h + check_str.h) + +configure_file(check.h.in check.h) + +# Enable finding check.h +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +add_library(check STATIC ${SOURCES} ${HEADERS}) +target_link_libraries(check ${LIBM} ${LIBRT} ${SUBUNIT}) + +if(MSVC) + add_definitions(-DCK_DLL_EXP=_declspec\(dllexport\)) +endif (MSVC) + +install(TARGETS check + EXPORT check + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib) + +install(FILES ${CMAKE_BINARY_DIR}/src/check.h DESTINATION include) +install(EXPORT check DESTINATION cmake) diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..22ebde0 --- /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@ $(LIBSUBUNIT_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@ $(LIBSUBUNIT_LIBS) $(top_builddir)/lib/libcompat.la + +libcheckinternal_la_LDFLAGS = -no-undefined +libcheckinternal_la_SOURCES = $(CFILES) $(HFILES) +libcheckinternal_la_LIBADD = @GCOV_LIBS@ @PTHREAD_LIBS@ $(LIBSUBUNIT_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/check.c b/src/check.c new file mode 100644 index 0000000..e42636e --- /dev/null +++ b/src/check.c @@ -0,0 +1,631 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "../lib/libcompat.h" + +#include +#include +#include +#include +#include + +#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 + +/* + * When a process exits either normally, with exit(), or + * by an uncaught signal, The lower 0x377 bits are passed + * to the parent. Of those, only the lower 8 bits are + * returned by the WEXITSTATUS() macro. + */ +#define WEXITSTATUS_MASK 0xFF + +int check_major_version = CHECK_MAJOR_VERSION; +int check_minor_version = CHECK_MINOR_VERSION; +int check_micro_version = CHECK_MICRO_VERSION; + +const char* current_test_name = NULL; + +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 = (Suite *)emalloc(sizeof(Suite)); /* freed in suite_free */ + if(name == NULL) + s->name = ""; + else + s->name = name; + s->tclst = check_list_create(); + return s; +} + +int suite_tcase(Suite * s, const char *tcname) +{ + List *l; + TCase *tc; + + if(s == NULL) + return 0; + + l = s->tclst; + for(check_list_front(l); !check_list_at_end(l); check_list_advance(l)) + { + tc = (TCase *)check_list_val(l); + if(strcmp(tcname, tc->name) == 0) + return 1; + } + + return 0; +} + +static void suite_free(Suite * s) +{ + List *l; + + if(s == NULL) + return; + l = s->tclst; + for(check_list_front(l); !check_list_at_end(l); check_list_advance(l)) + { + tcase_free((TCase *)check_list_val(l)); + } + check_list_free(s->tclst); + free(s); +} + + +TCase *tcase_create(const char *name) +{ + char *env; + double timeout_sec = DEFAULT_TIMEOUT; + + TCase *tc = (TCase *)emalloc(sizeof(TCase)); /*freed in tcase_free */ + + if(name == NULL) + tc->name = ""; + else + tc->name = name; + + env = getenv("CK_DEFAULT_TIMEOUT"); + if(env != NULL) + { + char *endptr = NULL; + double tmp = strtod(env, &endptr); + + if(tmp >= 0 && endptr != env && (*endptr) == '\0') + { + timeout_sec = tmp; + } + } + + env = getenv("CK_TIMEOUT_MULTIPLIER"); + if(env != NULL) + { + char *endptr = NULL; + double tmp = strtod(env, &endptr); + + if(tmp >= 0 && endptr != env && (*endptr) == '\0') + { + timeout_sec = timeout_sec * tmp; + } + } + + tc->timeout.tv_sec = (time_t) floor(timeout_sec); + tc->timeout.tv_nsec = + (long)((timeout_sec - + floor(timeout_sec)) * (double)NANOS_PER_SECONDS); + + 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(); + tc->tags = check_list_create(); + + return tc; +} + +/* + * Helper function to create a list of tags from + * a space separated string. + */ +List *tag_string_to_list(const char *tags_string) +{ + List *list; + char *tags; + char *tag; + + list = check_list_create(); + + if (NULL == tags_string) + { + return list; + } + + tags = strdup(tags_string); + tag = strtok(tags, " "); + while (tag) + { + check_list_add_end(list, strdup(tag)); + tag = strtok(NULL, " "); + } + free(tags); + return list; +} + +void tcase_set_tags(TCase * tc, const char *tags_orig) +{ + /* replace any pre-existing list */ + if (tc->tags) + { + check_list_apply(tc->tags, free); + check_list_free(tc->tags); + } + tc->tags = tag_string_to_list(tags_orig); +} + +static void tcase_free(TCase * tc) +{ + check_list_apply(tc->tflst, free); + check_list_apply(tc->unch_sflst, free); + check_list_apply(tc->ch_sflst, free); + check_list_apply(tc->unch_tflst, free); + check_list_apply(tc->ch_tflst, free); + check_list_apply(tc->tags, free); + check_list_free(tc->tflst); + check_list_free(tc->unch_sflst); + check_list_free(tc->ch_sflst); + check_list_free(tc->unch_tflst); + check_list_free(tc->ch_tflst); + check_list_free(tc->tags); + free(tc); +} + +unsigned int tcase_matching_tag(TCase *tc, List *check_for) +{ + + if (NULL == check_for) + { + return 0; + } + + for(check_list_front(check_for); !check_list_at_end(check_for); + check_list_advance(check_for)) + { + for(check_list_front(tc->tags); !check_list_at_end(tc->tags); + check_list_advance(tc->tags)) + { + if (0 == strcmp((const char *)check_list_val(tc->tags), + (const char *)check_list_val(check_for))) + { + return 1; + } + } + } + return 0; +} + +void suite_add_tcase(Suite * s, TCase * tc) +{ + if(s == NULL || tc == NULL || check_list_contains(s->tclst, tc)) + { + return; + } + + check_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 = (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 = + (WEXITSTATUS_MASK & allowed_exit_value); /* 0 is default successful exit */ + tf->name = name; + check_list_add_end(tc->tflst, tf); +} + +static Fixture *fixture_create(SFun fun, int ischecked) +{ + Fixture *f; + + f = (Fixture *)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) + check_list_add_end(tc->ch_sflst, + fixture_create(setup, ischecked)); + else + check_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) + check_list_add_front(tc->ch_tflst, + fixture_create(teardown, ischecked)); + else + check_list_add_front(tc->unch_tflst, + fixture_create(teardown, ischecked)); + } +} + +void tcase_set_timeout(TCase * tc, double timeout) +{ +#if defined(HAVE_FORK) + if(timeout >= 0) + { + char *env = getenv("CK_TIMEOUT_MULTIPLIER"); + + if(env != NULL) + { + char *endptr = NULL; + double tmp = strtod(env, &endptr); + + if(tmp >= 0 && endptr != env && (*endptr) == '\0') + { + timeout = timeout * tmp; + } + } + + tc->timeout.tv_sec = (time_t) floor(timeout); + tc->timeout.tv_nsec = + (long)((timeout - floor(timeout)) * (double)NANOS_PER_SECONDS); + } +#else + (void)tc; + (void)timeout; + /* Ignoring, as Check is not compiled with fork support. */ +#endif /* HAVE_FORK */ +} + +void tcase_fn_start(const char *fname, const char *file, + int line) +{ + send_ctx_info(CK_CTX_TEST); + send_loc_info(file, line); + + current_test_name = fname; +} + +const char* tcase_name(void) +{ + return current_test_name; +} + +void _mark_point(const char *file, int line) +{ + send_loc_info(file, line); +} + +void _ck_assert_failed(const char *file, int line, const char *expr, ...) +{ + const char *msg; + va_list ap; + char buf[BUFSIZ]; + const char *to_send; + + send_loc_info(file, line); + + va_start(ap, expr); + msg = (const char *)va_arg(ap, char *); + + /* + * If a message was passed, format it with vsnprintf. + * Otherwise, print the expression as is. + */ + if(msg != NULL) + { + vsnprintf(buf, BUFSIZ, msg, ap); + to_send = buf; + } + else + { + to_send = expr; + } + + va_end(ap); + send_failure_info(to_send); + if(cur_fork_status() == CK_FORK) + { +#if defined(HAVE_FORK) && HAVE_FORK==1 + _exit(1); +#endif /* HAVE_FORK */ + } + else + { + longjmp(error_jmp_buffer, 1); + } +} + +SRunner *srunner_create(Suite * s) +{ + SRunner *sr = (SRunner *)emalloc(sizeof(SRunner)); /* freed in srunner_free */ + + sr->slst = check_list_create(); + if(s != NULL) + check_list_add_end(sr->slst, s); + sr->stats = (TestStats *)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->tap_fname = NULL; + sr->loglst = NULL; + +#if defined(HAVE_FORK) + sr->fstat = CK_FORK_GETENV; +#else + /* + * Overriding the default of running tests in fork mode, + * as this system does not have fork() + */ + sr->fstat = CK_NOFORK; +#endif /* HAVE_FORK */ + + return sr; +} + +void srunner_add_suite(SRunner * sr, Suite * s) +{ + if(s == NULL) + return; + + check_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(check_list_front(l); !check_list_at_end(l); check_list_advance(l)) + { + suite_free((Suite *)check_list_val(l)); + } + check_list_free(sr->slst); + + l = sr->resultlst; + for(check_list_front(l); !check_list_at_end(l); check_list_advance(l)) + { + tr = (TestResult *)check_list_val(l); + tr_free(tr); + } + check_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 = (TestResult **)emalloc(sizeof(trarray[0]) * srunner_ntests_failed(sr)); + + rlst = sr->resultlst; + for(check_list_front(rlst); !check_list_at_end(rlst); + check_list_advance(rlst)) + { + TestResult *tr = (TestResult *)check_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 =(TestResult **) emalloc(sizeof(trarray[0]) * srunner_ntests_run(sr)); + + rlst = sr->resultlst; + for(check_list_front(rlst); !check_list_at_end(rlst); + check_list_advance(rlst)) + { + trarray[i++] = (TestResult *)check_list_val(rlst); + } + return trarray; +} + +static int non_pass(int val) +{ + return val != CK_PASS; +} + +TestResult *tr_create(void) +{ + TestResult *tr; + + tr = (TestResult *)emalloc(sizeof(TestResult)); + tr_init(tr); + return 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; + tr->duration = -1; +} + +void tr_free(TestResult * tr) +{ + free(tr->file); + free(tr->msg); + free(tr); +} + + +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 enum fork_status _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; +} + +/** + * Not all systems support the same clockid_t's. This call checks + * if the CLOCK_MONOTONIC clockid_t is valid. If so, that is returned, + * otherwise, CLOCK_REALTIME is returned. + * + * The clockid_t that was found to work on the first call is + * cached for subsequent calls. + */ +clockid_t check_get_clockid() +{ + static clockid_t clockid = -1; + + if(clockid == -1) + { +/* + * Only check if we have librt available. Otherwise, the clockid + * will be ignored anyway, as the clock_gettime() and + * timer_create() functions will be re-implemented in libcompat. + * Worse, if librt and alarm() are unavailable, this check + * will result in an assert(0). + */ +#ifdef HAVE_LIBRT + timer_t timerid; + + if(timer_create(CLOCK_MONOTONIC, NULL, &timerid) == 0) + { + timer_delete(timerid); + clockid = CLOCK_MONOTONIC; + } + else + { + clockid = CLOCK_REALTIME; + } +#else + clockid = CLOCK_MONOTONIC; +#endif + } + + return clockid; +} diff --git a/src/check.h.in b/src/check.h.in new file mode 100644 index 0000000..712caef --- /dev/null +++ b/src/check.h.in @@ -0,0 +1,2288 @@ +/*-*- 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef CHECK_H +#define CHECK_H + +#include +#include +#include +#include + +#include + +/* + 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 */ + +#if GCC_VERSION_AT_LEAST(2,5) +#define CK_ATTRIBUTE_NORETURN __attribute__ ((noreturn)) +#else +#define CK_ATTRIBUTE_NORETURN +#endif /* GCC 2.5 */ + +#include + +#if defined(_MSC_VER) +/* define pid_t for Windows, as it is needed later */ +#define pid_t int +#endif /* _MSC_VER */ + +/* + * Used to create the linker script for hiding lib-local symbols. Shall + * be put directly in front of the exported symbol. + */ +#define CK_EXPORT + +/* + * Used for MSVC to create the export attribute + * CK_DLL_EXP is defined during the compilation of the library + * on the command line. + */ +#ifndef CK_DLL_EXP +#define CK_DLL_EXP +#endif + +/* check version numbers */ + +#define CHECK_MAJOR_VERSION (@CHECK_MAJOR_VERSION@) +#define CHECK_MINOR_VERSION (@CHECK_MINOR_VERSION@) +#define CHECK_MICRO_VERSION (@CHECK_MICRO_VERSION@) + +CK_DLL_EXP extern int CK_EXPORT check_major_version; +CK_DLL_EXP extern int CK_EXPORT check_minor_version; +CK_DLL_EXP extern int CK_EXPORT check_micro_version; + +#ifndef NULL +#define NULL ((void*)0) +#endif + +/** + * 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); + +/** + * Type for a test suite + */ +typedef struct Suite Suite; + +/** + * Creates a test suite with the given name. + * + * Create a suite, which will contain test cases. Once + * created, use suite_add_tcase() to add test cases. + * When finished, create a suite runner from the + * suite using srunner_create() + * + * @param name name of the suite + * + * @return suite + * + * @since 0.6.0 + */ +CK_DLL_EXP Suite *CK_EXPORT suite_create(const char *name); + +/** + * Determines whether a given test suite contains a case named after a + * given string. + * + * @param s suite to check + * @param tcname test case to look for + * + * @return 1 iff the given test case is within the given suite; + * 0 otherwise + * + * @since 0.9.9 + */ +CK_DLL_EXP int CK_EXPORT suite_tcase(Suite * s, const char *tcname); + +/** + * Add a test case to a suite. + * + * Note that if the TCase has already been added attempting + * to add it again will be ignored. + * + * @param s suite to add test case to + * @param tc test case to add to suite + * + * @since 0.6.0 + */ +CK_DLL_EXP void CK_EXPORT suite_add_tcase(Suite * s, TCase * tc); + +/** + * Create a test case. + * + * Once created, tests can be added with the tcase_add_test() + * function, and the test case assigned to a suite with the + * suite_add_tcase() function. + * + * @param name name of the test case + * + * @return test case containing no tests + * + * @since 0.6.0 + * */ +CK_DLL_EXP TCase *CK_EXPORT tcase_create(const char *name); + +/** + * Associate a test case with certain tags. + * Replaces any existing tags with the new set. + * + * @param tc the test case + * + * @param tags string containing arbitrary tags separated by spaces. + * This will be copied. Passing NULL clears all tags. + * + * @since 0.11.0 + * */ +CK_DLL_EXP void CK_EXPORT tcase_set_tags(TCase * tc, + const char *tags); +/** + * Add a test function to a test case + * + * @param tc test case to add test to + * @param tf test function to add to test case + * + * @since 0.6.0 + * */ +#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 + * + * The added test is expected to terminate by throwing the given signal + * + * @param tc test case to add test to + * @param tf test function to add to test case + * @param signal expected signal for test function to throw in order for + * the test to be considered passing + * + * @since 0.9.2 + * */ +#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 + * + * The added test is expected to terminate by exiting with the given value + * + * @param tc test case to add test to + * @param tf test function to add to test case + * @param expected_exit_value exit value for test function to return in + * order for the test to be considered passing + * + * @since 0.9.7 + */ +#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 + * + * 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. + * + * @param tc test case to add test to + * @param tf function to add to test case + * @param s starting index for value "i" in test + * @param e ending index for value "i" in test + * + * @since 0.9.4 + */ +#define tcase_add_loop_test(tc,tf,s,e) \ + _tcase_add_test((tc),(tf),"" # tf "",0,0,(s),(e)) + +/** + * Add a looping test function with signal handling to a test case + * + * 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. + * + * The added test is expected to terminate by throwing the given signal + * + * @param tc test case to add test to + * @param tf function to add to test case + * @param signal expected signal for test function to throw in order for + * the test to be considered passing + * @param s starting index for value "i" in test + * @param e ending index for value "i" in test + * + * @since 0.9.5 + */ +#define tcase_add_loop_test_raise_signal(tc,tf,signal,s,e) \ + _tcase_add_test((tc),(tf),"" # tf "",(signal),0,(s),(e)) + +/** + * Add a looping test function with an expected exit value to a test case + * + * 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. + * + * The added test is expected to terminate by exiting with the given value + * + * @param tc test case to add test to + * @param tf function to add to test case + * @param expected_exit_value exit value for test function to return in + * order for the test to be considered passing + * @param s starting index for value "i" in test + * @param e ending index for value "i" in test + * + * @since 0.9.7 + */ +#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 +*/ +CK_DLL_EXP 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 + * + * Unchecked fixture functions are run at the start and end of the + * test case, and not before and after unit tests. Further, + * unchecked fixture 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. + * + * Note that if a setup function fails, the remaining setup functions + * will be omitted, as will the test case and the teardown functions. + * If a teardown function fails the remaining teardown functins will be + * omitted. + * + * @param tc test case to add unchecked fixture setup/teardown to + * @param setup function to add to be executed before the test case; + * if NULL no setup function is added + * @param teardown function to add to be executed after the test case; + * if NULL no teardown function is added + * @since 0.8.0 + */ +CK_DLL_EXP void CK_EXPORT tcase_add_unchecked_fixture(TCase * tc, SFun setup, + SFun teardown); + +/** + * Add checked fixture setup/teardown functions to a test case + * + * Checked fixture functions are run before and after each unit test inside + * of the address space of the test. Thus, if using CK_FORK + * mode the separate process running the unit test 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. + * + * Note that if a setup function fails, the remaining setup functions + * will be omitted, as will the test and the teardown functions. If a + * teardown function fails the remaining teardown functins will be + * omitted. + * + * @param tc test case to add checked fixture setup/teardown to + * @param setup function to add to be executed before each unit test in + * the test case; if NULL no setup function is added + * @param teardown function to add to be executed after each unit test in + * the test case; if NULL no teardown function is added + * + * @since 0.8.0 +*/ +CK_DLL_EXP 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. + * + * If not set, the default timeout is one assigned at compile time. If + * the environment variable CK_DEFAULT_TIMEOUT is defined and no timeout + * is set, the value in the environment variable is used. + * + * If Check is compile without fork() support this call is ignored, + * as timeouts are not possible. + * + * @param tc test case to assign timeout to + * @param timeout to use, in seconds. If the value contains a decimal + * portion, but no high resolution timer is available, + * the value is rounded up to the nearest second. + * + * @since 0.9.2 + */ +CK_DLL_EXP void CK_EXPORT tcase_set_timeout(TCase * tc, double timeout); + +/* Internal function to mark the start of a test function */ +CK_DLL_EXP void CK_EXPORT tcase_fn_start(const char *fname, const char *file, + int line); + +/** + * Retreive the name of the current running test. This is the name + * of the test passed to START_TEST. This is only valid when called + * from a running test. The value return outside of a running test is + * undefined. + * + * @since 0.11.0 + */ +CK_DLL_EXP const char* CK_EXPORT tcase_name(void); + +/** + * 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 + * + * @since 0.6.0 + */ +#define START_TEST(__testname)\ +static void __testname (int _i CK_ATTRIBUTE_UNUSED)\ +{\ + tcase_fn_start (""# __testname, __FILE__, __LINE__); + +/** + * End a unit test + * + * @since 0.6.0 + */ +#define END_TEST } + +/* + * Fail the test case unless expr is false + * + * This call is deprecated. + */ +#define fail_unless ck_assert_msg + +/* + * Fail the test case if expr is false + * + * This call is deprecated. + * + * NOTE: 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, ...)\ + (expr) ? \ + _ck_assert_failed(__FILE__, __LINE__, "Failure '"#expr"' occurred" , ## __VA_ARGS__, NULL) \ + : _mark_point(__FILE__, __LINE__) + +/* + * Fail the test + * + * This call is deprecated. + */ +#define fail ck_abort_msg + +/* + * This is called whenever an assertion fails. + * Note that it only has the noreturn modifier when + * using fork. If fork is unavailable, the function + * calls longjmp() when a test assertion fails. Marking + * the function as noreturn causes gcc to make assumptions + * which are not valid, as longjmp() is like a return. + */ +#if @HAVE_FORK@ +CK_DLL_EXP void CK_EXPORT _ck_assert_failed(const char *file, int line, + const char *expr, + ...) CK_ATTRIBUTE_NORETURN; +#else +CK_DLL_EXP void CK_EXPORT _ck_assert_failed(const char *file, int line, + const char *expr, ...); +#endif + +/** + * Fail the test if expression is false + * + * @param expr expression to evaluate + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.9.6 + */ +#define ck_assert(expr) ck_assert_msg(expr, NULL) + +/* The space before the comma sign before ## is essential to be compatible + with gcc 2.95.3 and earlier. +*/ +/** + * Fail the test if the expression is false; print message on failure + * + * @param expr expression to evaluate + * @param ... message to print (in printf format) if expression is false + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.9.6 + */ +#define ck_assert_msg(expr, ...) \ + (expr) ? \ + _mark_point(__FILE__, __LINE__) : \ + _ck_assert_failed(__FILE__, __LINE__, "Assertion '"#expr"' failed" , ## __VA_ARGS__, NULL) + +/** + * Unconditionally fail the test + * + * @note Once called, the remaining of the test is aborted + * + * @since 0.9.6 + */ +#define ck_abort() ck_abort_msg(NULL) +/** + * Unconditionally fail the test; print a message + * + * @param ... message to print (in printf format) + * + * @note Once called, the remaining of the test is aborted + * + * @since 0.9.6 + */ +#define ck_abort_msg(...) _ck_assert_failed(__FILE__, __LINE__, "Failed" , ## __VA_ARGS__, NULL) + +/* Signed and unsigned integer comparison macros with improved output compared to ck_assert(). */ +/* OP may be any comparison operator. */ +#define _ck_assert_int(X, OP, Y) do { \ + intmax_t _ck_x = (X); \ + intmax_t _ck_y = (Y); \ + ck_assert_msg(_ck_x OP _ck_y, "Assertion '%s' failed: %s == %jd, %s == %jd", #X" "#OP" "#Y, #X, _ck_x, #Y, _ck_y); \ +} while (0) + +/** + * Check two signed integers to determine if X==Y + * + * If not X==Y, the test fails. + * + * @param X signed integer + * @param Y signed integer to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.9.6 + */ +#define ck_assert_int_eq(X, Y) _ck_assert_int(X, ==, Y) +/** + * Check two signed integers to determine if X!=Y + * + * If not X!=Y, the test fails. + * + * @param X signed integer + * @param Y signed integer to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.9.6 + */ +#define ck_assert_int_ne(X, Y) _ck_assert_int(X, !=, Y) +/** + * Check two signed integers to determine if XY + * + * If not X>Y, the test fails. + * + * @param X signed integer + * @param Y signed integer to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.9.10 + */ +#define ck_assert_int_gt(X, Y) _ck_assert_int(X, >, Y) +/** + * Check two signed integers to determine if X>=Y + * + * If not X>=Y, the test fails. + * + * @param X signed integer + * @param Y signed integer to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.9.10 + */ +#define ck_assert_int_ge(X, Y) _ck_assert_int(X, >=, Y) + +#define _ck_assert_uint(X, OP, Y) do { \ + uintmax_t _ck_x = (X); \ + uintmax_t _ck_y = (Y); \ + ck_assert_msg(_ck_x OP _ck_y, "Assertion '%s' failed: %s == %ju, %s == %ju", #X" "#OP" "#Y, #X, _ck_x, #Y, _ck_y); \ +} while (0) +/** + * Check two unsigned integers to determine if X==Y + * + * If not X==Y, the test fails. + * + * @param X signed integer + * @param Y signed integer to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.9.10 + */ +#define ck_assert_uint_eq(X, Y) _ck_assert_uint(X, ==, Y) +/** + * Check two unsigned integers to determine if X!=Y + * + * If not X!=Y, the test fails. + * + * @param X signed integer + * @param Y signed integer to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.9.10 + */ +#define ck_assert_uint_ne(X, Y) _ck_assert_uint(X, !=, Y) +/** + * Check two unsigned integers to determine if XY + * + * If not X>Y, the test fails. + * + * @param X signed integer + * @param Y signed integer to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.9.10 + */ +#define ck_assert_uint_gt(X, Y) _ck_assert_uint(X, >, Y) +/** + * Check two unsigned integers to determine if X>=Y + * + * If not X>=Y, the test fails. + * + * @param X signed integer + * @param Y signed integer to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.9.10 + */ +#define ck_assert_uint_ge(X, Y) _ck_assert_uint(X, >=, Y) + +/* Number of digits after the decimal point to output via printf */ +#ifndef CK_FLOATING_DIG +# define CK_FLOATING_DIG 6 +#endif /* CK_FLOATING_DIG */ + +/* Floating point number comparison macros with improved output + * compared to ck_assert(). */ +/* OP may be any comparison operator, TP is type, TM is type modifier. */ +#define _ck_assert_floating(X, OP, Y, TP, TM) do { \ + TP _ck_x = (X); \ + TP _ck_y = (Y); \ + ck_assert_msg(_ck_x OP _ck_y, \ + "Assertion '%s' failed: %s == %.*" TM "g, %s == %.*" TM "g", \ + #X" "#OP" "#Y, \ + #X, (int)CK_FLOATING_DIG, _ck_x, \ + #Y, (int)CK_FLOATING_DIG, _ck_y); \ +} while (0) + +/* Check floating point number is finise. */ +/* TP is type, TM is type modifier. */ +#define _ck_assert_floating_finite(X, TP, TM) \ +do { \ + TP _ck_x = (X); \ + ck_assert_msg(isfinite(_ck_x), \ + "Assertion '%s' failed: %s == %.*" TM "g", \ + #X" is finite", \ + #X, (int)CK_FLOATING_DIG, _ck_x); \ +} while (0) + +/* Check floating point number is infinise. */ +/* TP is type, TM is type modifier. */ +#define _ck_assert_floating_infinite(X, TP, TM) \ +do { \ + TP _ck_x = (X); \ + ck_assert_msg(isinf(_ck_x), \ + "Assertion '%s' failed: %s == %.*" TM "g", \ + #X" is infinite", \ + #X, (int)CK_FLOATING_DIG, _ck_x); \ +} while (0) + +/* Check floating point number is "Not a Number". */ +/* TP is type, TM is type modifier. */ +#define _ck_assert_floating_nan(X, TP, TM) \ +do { \ + TP _ck_x = (X); \ + ck_assert_msg(isnan(_ck_x), \ + "Assertion '%s' failed: %s == %.*" TM "g", \ + #X" is NaN", \ + #X, (int)CK_FLOATING_DIG, _ck_x); \ +} while (0) + +/* Check floating point number is not "Not a Number". */ +/* TP is type, TM is type modifier. */ +#define _ck_assert_floating_nonnan(X, TP, TM) \ +do { \ + TP _ck_x = (X); \ + ck_assert_msg(!isnan(_ck_x), \ + "Assertion '%s' failed: %s == %.*" TM "g", \ + #X" is not NaN", \ + #X, (int)CK_FLOATING_DIG, _ck_x); \ +} while (0) + +/* Floating point tolerance comparison macros with improved output + * compared to ck_assert(). */ +/* OP, D can have values: >, -1; <, 1. */ +#define _ck_assert_floating_op_tol(X, OP, Y, T, D, TP, TM) do { \ + TP _ck_x = (X); \ + TP _ck_y = (Y); \ + TP _ck_t = (T); \ + ck_assert_msg((_ck_x - _ck_y) OP _ck_t * (D), \ + "Assertion '%s' failed: %s == %.*" TM "g, %s == %.*" TM "g, %s == %.*" TM "g", \ + #X" "#OP"= "#Y", error < "#T, \ + #X, (int)CK_FLOATING_DIG, _ck_x, \ + #Y, (int)CK_FLOATING_DIG, _ck_y, \ + #T, (int)CK_FLOATING_DIG, _ck_t); \ +} while (0) + +/* Floating point tolerance comparison macros with improved output + * compared to ck_assert(). */ +/* OP can have values: <; >=. */ +#define _ck_assert_floating_absdiff_op_tol(X, Y, OP, T, TP, TM) \ +do { \ + TP _ck_x = (X); \ + TP _ck_y = (Y); \ + TP _ck_t = (T); \ + ck_assert_msg(fabsl(_ck_y - _ck_x) OP _ck_t, \ + "Assertion '%s' failed: %s == %.*" TM "g, %s == %.*" TM "g, %s == %.*" TM "g", \ + "fabsl("#Y" - "#X") "#OP" "#T, \ + #X, (int)CK_FLOATING_DIG, _ck_x, \ + #Y, (int)CK_FLOATING_DIG, _ck_y, \ + #T, (int)CK_FLOATING_DIG, _ck_t); \ +} while (0) + +/** + * Check two single precision floating point numbers to determine if X == Y + * + * If not X == Y, the test fails. + * + * @param X floating point number (float) + * @param Y floating point number (float) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_eq(X, Y) _ck_assert_floating(X, ==, Y, float, "") +/** + * Check two single precision floating point numbers to determine if X != Y + * + * If not X != Y, the test fails. + * + * @param X floating point number (float) + * @param Y floating point number (float) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_ne(X, Y) _ck_assert_floating(X, !=, Y, float, "") +/** + * Check two single precision floating point numbers to determine if X < Y + * + * If not X < Y, the test fails. + * + * @param X floating point number (float) + * @param Y floating point number (float) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_lt(X, Y) _ck_assert_floating(X, <, Y, float, "") +/** + * Check two single precision floating point numbers to determine if X <= Y + * + * If not X <= Y, the test fails. + * + * @param X floating point number (float) + * @param Y floating point number (float) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_le(X, Y) _ck_assert_floating(X, <=, Y, float, "") +/** + * Check two single precision floating point numbers to determine if X > Y + * + * If not X > Y, the test fails. + * + * @param X floating point number (float) + * @param Y floating point number (float) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_gt(X, Y) _ck_assert_floating(X, >, Y, float, "") +/** + * Check two single precision floating point numbers to determine if X >= Y + * + * If not X >= Y, the test fails. + * + * @param X floating point number (float) + * @param Y floating point number (float) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_ge(X, Y) _ck_assert_floating(X, >=, Y, float, "") + +/** + * Check two single precision floating point numbers to determine if X≈Y + * with specified tolerance + * + * If not X ≈ Y with error < T, the test fails. + * + * @param X floating point number (float) + * @param Y floating point number (float) to compare against X + * @param T tolerance (float) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_eq_tol(X, Y, T) _ck_assert_floating_absdiff_op_tol(X, Y, <, T, float, "") + +/** + * Check two single precision floating point numbers to determine if not X≈Y + * with specified tolerance + * + * If X ≈ Y with error < T, the test fails. + * + * @param X floating point number (float) + * @param Y floating point number (float) to compare against X + * @param T tolerance (float) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_ne_tol(X, Y, T) _ck_assert_floating_absdiff_op_tol(X, Y, >=, T, float, "") + +/** + * Check two single precision floating point numbers to determine if X>≈Y + * with specified tolerance + * + * If not X >≈ Y with error < T, the test fails. + * + * @param X floating point number (float) + * @param Y floating point number (float) to compare against X + * @param T tolerance (float) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_ge_tol(X, Y, T) _ck_assert_floating_op_tol(X, >, Y, T, -1, float, "") + +/** + * Check two single precision floating point numbers to determine if X<≈Y + * with specified tolerance + * + * If not X <≈ Y with error < T, the test fails. + * + * @param X floating point number (float) + * @param Y floating point number (float) to compare against X + * @param T tolerance (float) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_le_tol(X, Y, T) _ck_assert_floating_op_tol(X, <, Y, T, 1, float, "") + +/** + * Check that a single precision floating point number is finite; i.e. is + * not +infinity, -infinity, or "Not a Number" (NaN) + * + * If X is +INFINITY or X is -INFINITY, or X is NaN, the test fails. + * + * @param X floating point number (float) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_finite(X) _ck_assert_floating_finite(X, float, "") + +/** + * Check that a single precision floating point number is infinite, + * either +infinity or -infinity + * + * If X is not +INFINITY and X is not -INFINITY, the test fails. + * + * @param X floating point number (float) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_infinite(X) _ck_assert_floating_infinite(X, float, "") + +/** + * Check that a single precision floating point number + * is "Not a Number" (NaN) + * + * If X is not NaN, the test fails. + * + * @param X floating point number (float) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_nan(X) _ck_assert_floating_nan(X, float, "") + +/** + * Check that a single precision floating point number is + * not "Not a Number" (NaN) + * + * If X is NaN, the test fails. + * + * @param X floating point number (float) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_nonnan(X) _ck_assert_floating_nonnan(X, float, "") + +/** + * Check two double precision floating point numbers to determine if X == Y + * + * If not X == Y, the test fails. + * + * @param X floating point number (double) + * @param Y floating point number (double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_eq(X, Y) _ck_assert_floating(X, ==, Y, double, "") +/** + * Check two double precision floating point numbers to determine if X != Y + * + * If not X != Y, the test fails. + * + * @param X floating point number (double) + * @param Y floating point number (double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_ne(X, Y) _ck_assert_floating(X, !=, Y, double, "") +/** + * Check two double precision floating point numbers to determine if X < Y + * + * If not X < Y, the test fails. + * + * @param X floating point number (double) + * @param Y floating point number (double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_lt(X, Y) _ck_assert_floating(X, <, Y, double, "") +/** + * Check two double precision floating point numbers to determine if X <= Y + * + * If not X <= Y, the test fails. + * + * @param X floating point number (double) + * @param Y floating point number (double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_le(X, Y) _ck_assert_floating(X, <=, Y, double, "") +/** + * Check two double precision floating point numbers to determine if X > Y + * + * If not X > Y, the test fails. + * + * @param X floating point number (double) + * @param Y floating point number (double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_gt(X, Y) _ck_assert_floating(X, >, Y, double, "") +/** + * Check two double precision floating point numbers to determine if X >= Y + * + * If not X >= Y, the test fails. + * + * @param X floating point number (double) + * @param Y floating point number (double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_ge(X, Y) _ck_assert_floating(X, >=, Y, double, "") + +/** + * Check two double precision floating point numbers to determine if X≈Y + * with specified tolerance + * + * If not X ≈ Y with error < T, the test fails. + * + * @param X floating point number (double) + * @param Y floating point number (double) to compare against X + * @param T tolerance (double) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_eq_tol(X, Y, T) _ck_assert_floating_absdiff_op_tol(X, Y, <, T, double, "") + +/** + * Check two double precision floating point numbers to determine if not X≈Y + * with specified tolerance + * + * If X ≈ Y with error < T, the test fails. + * + * @param X floating point number (double) + * @param Y floating point number (double) to compare against X + * @param T tolerance (double) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_ne_tol(X, Y, T) _ck_assert_floating_absdiff_op_tol(X, Y, >=, T, double, "") + +/** + * Check two double precision floating point numbers to determine if X>≈Y + * with specified tolerance + * + * If not X >≈ Y with error < T, the test fails. + * + * @param X floating point number (double) + * @param Y floating point number (double) to compare against X + * @param T tolerance (double) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_ge_tol(X, Y, T) _ck_assert_floating_op_tol(X, >, Y, T, -1, double, "") + +/** + * Check two double precision floating point numbers to determine if X<≈Y + * with specified tolerance + * + * If not X <≈ Y with error < T, the test fails. + * + * @param X floating point number (double) + * @param Y floating point number (double) to compare against X + * @param T tolerance (double) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_le_tol(X, Y, T) _ck_assert_floating_op_tol(X, <, Y, T, 1, double, "") + +/** + * Check that a double precision floating point number is finite; i.e. is + * not +infinity, -infinity, or "Not a Number" (NaN) + * + * If X is +INFINITY or X is -INFINITY, or X is NaN, the test fails. + * + * @param X floating point number (double) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_finite(X) _ck_assert_floating_finite(X, double, "") + +/** + * Check that a double precision floating point number is infinite, + * either +infinity or -infinity + * + * If X is not +INFINITY and X is not -INFINITY, the test fails. + * + * @param X floating point number (double) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_infinite(X) _ck_assert_floating_infinite(X, double, "") + +/** + * Check that a double precision floating point number + * is "Not a Number" (NaN) + * + * If X is not NaN, the test fails. + * + * @param X floating point number (double) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_nan(X) _ck_assert_floating_nan(X, double, "") + +/** + * Check that a double precision floating point number is + * not "Not a Number" (NaN) + * + * If X is NaN, the test fails. + * + * @param X floating point number (double) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_nonnan(X) _ck_assert_floating_nonnan(X, double, "") + +/** + * Check two double precision floating point numbers to determine if X == Y + * + * If not X == Y, the test fails. + * + * @param X floating point number (long double) + * @param Y floating point number (long double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_eq(X, Y) _ck_assert_floating(X, ==, Y, long double, "L") +/** + * Check two double precision floating point numbers to determine if X != Y + * + * If not X != Y, the test fails. + * + * @param X floating point number (long double) + * @param Y floating point number (long double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_ne(X, Y) _ck_assert_floating(X, !=, Y, long double, "L") +/** + * Check two double precision floating point numbers to determine if X < Y + * + * If not X < Y, the test fails. + * + * @param X floating point number (long double) + * @param Y floating point number (long double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_lt(X, Y) _ck_assert_floating(X, <, Y, long double, "L") +/** + * Check two double precision floating point numbers to determine if X <= Y + * + * If not X <= Y, the test fails. + * + * @param X floating point number (long double) + * @param Y floating point number (long double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_le(X, Y) _ck_assert_floating(X, <=, Y, long double, "L") +/** + * Check two double precision floating point numbers to determine if X > Y + * + * If not X > Y, the test fails. + * + * @param X floating point number (long double) + * @param Y floating point number (long double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_gt(X, Y) _ck_assert_floating(X, >, Y, long double, "L") +/** + * Check two double precision floating point numbers to determine if X >= Y + * + * If not X >= Y, the test fails. + * + * @param X floating point number (long double) + * @param Y floating point number (long double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_ge(X, Y) _ck_assert_floating(X, >=, Y, long double, "L") + +/** + * Check two double precision floating point numbers to determine if X≈Y + * with specified tolerance + * + * If not X ≈ Y with error < T, the test fails. + * + * @param X floating point number (long double) + * @param Y floating point number (long double) to compare against X + * @param T tolerance (long double) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_eq_tol(X, Y, T) _ck_assert_floating_absdiff_op_tol(X, Y, <, T, long double, "L") + +/** + * Check two double precision floating point numbers to determine if not X≈Y + * with specified tolerance + * + * If X ≈ Y with error < T, the test fails. + * + * @param X floating point number (long double) + * @param Y floating point number (long double) to compare against X + * @param T tolerance (long double) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_ne_tol(X, Y, T) _ck_assert_floating_absdiff_op_tol(X, Y, >=, T, long double, "L") + +/** + * Check two double precision floating point numbers to determine if X>≈Y + * with specified tolerance + * + * If not X >≈ Y with error < T, the test fails. + * + * @param X floating point number (long double) + * @param Y floating point number (long double) to compare against X + * @param T tolerance (long double) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_ge_tol(X, Y, T) _ck_assert_floating_op_tol(X, >, Y, T, -1, long double, "L") + +/** + * Check two double precision floating point numbers to determine if X<≈Y + * with specified tolerance + * + * If not X <≈ Y with error < T, the test fails. + * + * @param X floating point number (long double) + * @param Y floating point number (long double) to compare against X + * @param T tolerance (long double) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_le_tol(X, Y, T) _ck_assert_floating_op_tol(X, <, Y, T, 1, long double, "L") + +/** + * Check that a double precision floating point number is finite; i.e. is + * not +infinity, -infinity, or "Not a Number" (NaN) + * + * If X is +INFINITY or X is -INFINITY, or X is NaN, the test fails. + * + * @param X floating point number (long double) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_finite(X) _ck_assert_floating_finite(X, long double, "L") + +/** + * Check that a double precision floating point number is infinite, + * either +infinity or -infinity + * + * If X is not +INFINITY and X is not -INFINITY, the test fails. + * + * @param X floating point number (long double) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_infinite(X) _ck_assert_floating_infinite(X, long double, "L") + +/** + * Check that a double precision floating point number + * is "Not a Number" (NaN) + * + * If X is not NaN, the test fails. + * + * @param X floating point number (long double) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_nan(X) _ck_assert_floating_nan(X, long double, "L") + +/** + * Check that a double precision floating point number is + * not "Not a Number" (NaN) + * + * If X is NaN, the test fails. + * + * @param X floating point number (long double) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_nonnan(X) _ck_assert_floating_nonnan(X, long double, "L") + +/* String comparison macros with improved output compared to ck_assert() */ +/* OP might be any operator that can be used in '0 OP strcmp(X,Y)' comparison. */ +/* String pointer could be compared againts NULL with == (NULLEQ = 1) and != (NULLNE = 1) operators. */ +/* The x and y parameter swap in strcmp() is needed to handle >, >=, <, <= operators. */ +/* If the x or y parameter is NULL its value will be printed without quotes. */ +#define _ck_assert_str(X, OP, Y, NULLEQ, NULLNE) do { \ + const char* _ck_x = (X); \ + const char* _ck_y = (Y); \ + const char* _ck_x_s; \ + const char* _ck_y_s; \ + const char* _ck_x_q; \ + const char* _ck_y_q; \ + if (_ck_x != NULL) { \ + _ck_x_q = "\""; \ + _ck_x_s = _ck_x; \ + } else { \ + _ck_x_q = ""; \ + _ck_x_s = "(null)"; \ + } \ + if (_ck_y != NULL) { \ + _ck_y_q = "\""; \ + _ck_y_s = _ck_y; \ + } else { \ + _ck_y_q = ""; \ + _ck_y_s = "(null)"; \ + } \ + ck_assert_msg( \ + (NULLEQ && (_ck_x == NULL) && (_ck_y == NULL)) || \ + (NULLNE && ((_ck_x == NULL) || (_ck_y == NULL)) && (_ck_x != _ck_y)) || \ + ((_ck_x != NULL) && (_ck_y != NULL) && (0 OP strcmp(_ck_y, _ck_x))), \ + "Assertion '%s' failed: %s == %s%s%s, %s == %s%s%s", \ + #X" "#OP" "#Y, \ + #X, _ck_x_q, _ck_x_s, _ck_x_q, \ + #Y, _ck_y_q, _ck_y_s, _ck_y_q); \ +} while (0) + +/** + * Check two strings to determine if 0==strcmp(X,Y) + * + * If X or Y is NULL the test failes. + * If (0==strcmp(X,Y)), the test fails. + * + * @param X string + * @param Y string to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.9.6 + */ +#define ck_assert_str_eq(X, Y) _ck_assert_str(X, ==, Y, 0, 0) + +/** + * Check two strings to determine if 0!=strcmp(X,Y) + * + * If X or Y is NULL the test fails. + * If not 0!=strcmp(X,Y), the test fails. + * + * @param X string + * @param Y string to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.9.6 + */ +#define ck_assert_str_ne(X, Y) _ck_assert_str(X, !=, Y, 0, 0) + +/** + * Check two strings to determine if 00) + * + * If X or Y is NULL the test fails. + * If not 0=0) + * + * If X or Y is NULL the test fails. + * If not 0<=strcmp(X,Y), the test fails. + * + * @param X string + * @param Y string to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.9.10 + */ +#define ck_assert_str_le(X, Y) _ck_assert_str(X, <=, Y, 0, 0) + +/** + * Check two strings to determine if 00) + * + * If X or Y is NULL the test fails. + * If not 0, Y, 0, 0) + +/** + * Check two strings to determine if 0>=strcmp(X,Y) (e.g. strcmp(X,Y)<=0) + * + * If X or Y is NULL the test fails. + * If not 0>=strcmp(X,Y), the test fails. + * + * @param X string + * @param Y string to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.9.10 + */ +#define ck_assert_str_ge(X, Y) _ck_assert_str(X, >=, Y, 0, 0) + +/** + * Check two strings to determine if 0==strcmp(X,Y) or if both are undefined + * + * If both X and Y are NULL the test passes. However, if only one is NULL + * the test fails. + * If not ((X==NULL)&&(Y==NULL)) || (0==strcmp(X,Y)), the test fails. + * + * @param X string + * @param Y string to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_pstr_eq(X, Y) _ck_assert_str(X, ==, Y, 1, 0) + +/** + * Check two strings to determine if 0!=strcmp(X,Y) or one of them is undefined + * + * If either X or Y is NULL the test passes, however if both are NULL + * the test fails. + * If not (X!=NULL)&&(Y!=NULL)&&(0!=strcmp(X,Y)), the test fails. + * + * @param X string + * @param Y string to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_pstr_ne(X, Y) _ck_assert_str(X, !=, Y, 0, 1) + +/* Memory location comparison macros with improved output compared to ck_assert() */ +/* OP might be any operator that can be used in '0 OP memcmp(X,Y,L)' comparison */ +/* The x and y parameter swap in memcmp() is needed to handle >, >=, <, <= operators */ +/* Output is limited to CK_MAX_ASSERT_MEM_PRINT_SIZE bytes */ +#ifndef CK_MAX_ASSERT_MEM_PRINT_SIZE +#define CK_MAX_ASSERT_MEM_PRINT_SIZE 64 +#endif + +/* Memory location comparison macros with improved output compared to ck_assert() */ +/* OP might be any operator that can be used in '0 OP memcmp(X,Y,L)' comparison */ +/* The x and y parameter swap in memcmp() is needed to handle >, >=, <, <= operators */ +/* Output is limited to CK_MAX_ASSERT_MEM_PRINT_SIZE bytes */ +#ifndef CK_MAX_ASSERT_MEM_PRINT_SIZE +#define CK_MAX_ASSERT_MEM_PRINT_SIZE 64 +#endif + +#define _ck_assert_mem(X, OP, Y, L) do { \ + const uint8_t* _ck_x = (const uint8_t*)(X); \ + const uint8_t* _ck_y = (const uint8_t*)(Y); \ + size_t _ck_l = (L); \ + char _ck_x_str[CK_MAX_ASSERT_MEM_PRINT_SIZE * 2 + 1]; \ + char _ck_y_str[CK_MAX_ASSERT_MEM_PRINT_SIZE * 2 + 1]; \ + static const char _ck_hexdigits[] = "0123456789abcdef"; \ + size_t _ck_i; \ + size_t _ck_maxl = (_ck_l > CK_MAX_ASSERT_MEM_PRINT_SIZE) ? CK_MAX_ASSERT_MEM_PRINT_SIZE : _ck_l; \ + for (_ck_i = 0; _ck_i < _ck_maxl; _ck_i++) { \ + _ck_x_str[_ck_i * 2 ] = _ck_hexdigits[(_ck_x[_ck_i] >> 4) & 0xF]; \ + _ck_y_str[_ck_i * 2 ] = _ck_hexdigits[(_ck_y[_ck_i] >> 4) & 0xF]; \ + _ck_x_str[_ck_i * 2 + 1] = _ck_hexdigits[_ck_x[_ck_i] & 0xF]; \ + _ck_y_str[_ck_i * 2 + 1] = _ck_hexdigits[_ck_y[_ck_i] & 0xF]; \ + } \ + _ck_x_str[_ck_i * 2] = 0; \ + _ck_y_str[_ck_i * 2] = 0; \ + if (_ck_maxl != _ck_l) { \ + _ck_x_str[_ck_i * 2 - 2] = '.'; \ + _ck_y_str[_ck_i * 2 - 2] = '.'; \ + _ck_x_str[_ck_i * 2 - 1] = '.'; \ + _ck_y_str[_ck_i * 2 - 1] = '.'; \ + } \ + ck_assert_msg(0 OP memcmp(_ck_y, _ck_x, _ck_l), \ + "Assertion '%s' failed: %s == \"%s\", %s == \"%s\"", #X" "#OP" "#Y, #X, _ck_x_str, #Y, _ck_y_str); \ +} while (0) +/** + * Check two memory locations to determine if 0==memcmp(X,Y,L) + * + * If not 0==memcmp(X,Y,L), the test fails. + * + * @param X memory location + * @param Y memory location to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_mem_eq(X, Y, L) _ck_assert_mem(X, ==, Y, L) +/** + * Check two memory locations to determine if 0!=memcmp(X,Y,L) + * + * If not 0!=memcmp(X,Y,L), the test fails. + * + * @param X memory location + * @param Y memory location to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_mem_ne(X, Y, L) _ck_assert_mem(X, !=, Y, L) +/** + * Check two memory locations to determine if 00) + * + * If not 0=0) + * + * If not 0<=memcmp(X,Y,L), the test fails. + * + * @param X memory location + * @param Y memory location to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_mem_le(X, Y, L) _ck_assert_mem(X, <=, Y, L) +/** + * Check two memory locations to determine if 00) + * + * If not 0, Y, L) +/** + * Check two memory locations to determine if 0>=memcmp(X,Y,L) (e.g. memcmp(X,Y,L)<=0) + * + * If not 0>=memcmp(X,Y,L), the test fails. + * + * @param X memory location + * @param Y memory location to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_mem_ge(X, Y, L) _ck_assert_mem(X, >=, Y, L) + +/* Pointer comparison macros with improved output compared to ck_assert(). */ +/* OP may only be == or != */ +#define _ck_assert_ptr(X, OP, Y) do { \ + const void* _ck_x = (X); \ + const void* _ck_y = (Y); \ + ck_assert_msg(_ck_x OP _ck_y, "Assertion '%s' failed: %s == %#x, %s == %#x", #X" "#OP" "#Y, #X, _ck_x, #Y, _ck_y); \ +} while (0) + +/* Pointer against NULL comparison macros with improved output + * compared to ck_assert(). */ +/* OP may only be == or != */ +#define _ck_assert_ptr_null(X, OP) do { \ + const void* _ck_x = (X); \ + ck_assert_msg(_ck_x OP NULL, \ + "Assertion '%s' failed: %s == %#x", \ + #X" "#OP" NULL", \ + #X, _ck_x); \ +} while (0) + +/** + * Check if two pointers are equal. + * + * If the two passed pointers are not equal, the test + * fails. + * + * @param X pointer + * @param Y pointer to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.9.10 + */ +#define ck_assert_ptr_eq(X, Y) _ck_assert_ptr(X, ==, Y) + +/** + * Check if two pointers are not. + * + * If the two passed pointers are equal, the test fails. + * + * @param X pointer + * @param Y pointer to compare against X + * + * @since 0.9.10 + */ +#define ck_assert_ptr_ne(X, Y) _ck_assert_ptr(X, !=, Y) + +/** + * Check if a pointer is equal to NULL. + * + * If X != NULL, the test fails. + * + * @param X pointer to compare against NULL + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ptr_null(X) _ck_assert_ptr_null(X, ==) + +/** + * Check if a pointer is not equal to NULL. + * + * If X == NULL, the test fails. + * + * @param X pointer to compare against NULL + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ptr_nonnull(X) _ck_assert_ptr_null(X, !=) + +/** + * Mark the last point reached in a unit test. + * + * If the test throws a signal or exits, the location noted with the + * failure is the last location of a ck_assert*() or ck_abort() call. + * Use mark_point() to record intermediate locations (useful for tracking down + * crashes or exits). + * + * @since 0.6.0 +*/ +#define mark_point() _mark_point(__FILE__,__LINE__) + +/* Non macro version of #mark_point */ +CK_DLL_EXP void CK_EXPORT _mark_point(const char *file, int line); + +/** + * Enum describing the possible results 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) */ +}; + +/** + * Enum specifying the verbosity of output a 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 CK_VERBOSITY + for what verbosity to use, which can be + either "silent", "minimal", "normal", + or "verbose". If the environment variable + is not set, then CK_NORMAL will be used.*/ +#if @ENABLE_SUBUNIT@ + CK_SUBUNIT, /**< Run as a subunit child process */ +#endif + CK_LAST /**< Not a valid option */ +}; + +/** + * Holds state for a running of a test suite + */ +typedef struct SRunner SRunner; + +/** + * Opaque type for a test failure + */ +typedef struct TestResult TestResult; + +/** + * Enum representing the types of contexts for a test + */ +enum ck_result_ctx +{ + CK_CTX_INVALID, /**< Default value; should not encounter this */ + CK_CTX_SETUP, /**< Setup before a test */ + CK_CTX_TEST, /**< Body of test itself */ + CK_CTX_TEARDOWN /**< Teardown after a test */ +}; + +/** + * Retrieve type of result that the given test result represents. + * + * This is a member of test_result, and can represent a + * pass, failure, or error. + * + * @param tr test result to retrieve result from + * + * @return result of given test + * + * @since 0.6.0 + */ +CK_DLL_EXP int CK_EXPORT tr_rtype(TestResult * tr); + +/** + * Retrieve context in which the result occurred for the given test result. + * + * The types of contents include the test setup, teardown, or the + * body of the test itself. + * + * @param tr test result to retrieve context from + * + * @return context to which the given test result applies + * + * @since 0.8.0 + */ +CK_DLL_EXP enum ck_result_ctx CK_EXPORT tr_ctx(TestResult * tr); + +/** + * Retrieve failure message from test result, if applicable. + * + * @return pointer to a message, if one exists. NULL otherwise. + * + * @since 0.6.0 + */ +CK_DLL_EXP const char *CK_EXPORT tr_msg(TestResult * tr); + +/** + * Retrieve line number at which a failure occurred, if applicable. + * + * @return If the test resulted in a failure, returns the line number + * that the failure occurred on; otherwise returns -1. + * + * @since 0.6.0 + */ +CK_DLL_EXP int CK_EXPORT tr_lno(TestResult * tr); + +/** + * Retrieve file name at which a failure occurred, if applicable. + * + * @return If the test resulted in a failure, returns a string + * containing the name of the file where the failure + * occurred; otherwise returns NULL. + * + * @since 0.6.0 + */ +CK_DLL_EXP const char *CK_EXPORT tr_lfile(TestResult * tr); + +/** + * Retrieve test case name in which a failure occurred, if applicable. + * + * @return If the test resulted in a failure, returns a string + * containing the name of the test suite where the failure + * occurred; otherwise returns NULL. + * + * @since 0.6.0 + */ +CK_DLL_EXP const char *CK_EXPORT tr_tcname(TestResult * tr); + +/** + * Creates a suite runner for the given suite. + * + * Once created, additional suites can be added to the + * suite runner using srunner_add_suite(), and the suite runner can be + * run with srunner_run_all(). Once finished, the suite runner + * must be freed with srunner_free(). + * + * @param s suite to generate a suite runner for + * + * @return suite runner for the given suite + * + * @since 0.6.0 + */ +CK_DLL_EXP SRunner *CK_EXPORT srunner_create(Suite * s); + +/** + * Add an additional suite to a suite runner. + * + * The first suite in a suite runner is always added in srunner_create(). + * This call adds additional suites to a suite runner. + * + * @param sr suite runner to add the given suite + * @param s suite to add to the given suite runner + * + * @since 0.7.0 + */ +CK_DLL_EXP void CK_EXPORT srunner_add_suite(SRunner * sr, Suite * s); + +/** + * Frees a suite runner, including all contained suite and test cases. + * + * This call is responsible for freeing all resources related to a + * suite runner and all contained suites and test cases. Suite and + * test cases need not be freed individually, as this call handles that. + * + * @param sr suite runner to free + * + * @since 0.6.0 + */ +CK_DLL_EXP void CK_EXPORT srunner_free(SRunner * sr); + +/** + * Runs a suite runner and all contained suite, printing results to + * stdout as specified by the print_mode. + * + * In addition to running all suites, if the suite runner has been + * configured to output to a log, that is also performed. + * + * Note that if the CK_RUN_CASE, CK_RUN_SUITE, CK_INCLUDE_TAGS and/or + * CK_EXCLUDE_TAGS environment variables are defined, then only the + * named suites or test cases will run. + * + * @param sr suite runner to run all suites from + * @param print_mode the verbosity in which to report results to stdout + * + * @since 0.6.0 + */ +CK_DLL_EXP void CK_EXPORT srunner_run_all(SRunner * sr, + enum print_output print_mode); + +/** + * Run a specific suite or test case from a suite runner, printing results + * to stdout as specified by the print_mode. + * + * In addition to running any applicable suites or test cases, if the + * suite runner has been configured to output to a log, that is also + * performed. + * + * Note that if the sname and tcname parameters are passed as null + * then the function will fallback to using the environment variables + * CK_RUN_SUITE and CK_RUN_CASE respectively in order to select the + * suite/cases. + * + * Similarly if the CK_INCLUDE_TAGS and/or CK_EXCLUDE_TAGS environment + * variables are defined then these will further filter the test cases + * (see srunner_run_tagged, below). + * + * @param sr suite runner where the given suite or test case must be + * @param sname suite name to run. A NULL means use the value of the + * environment variable CK_RUN_SUITE if set, otherwise run "any/every + * suite". + * @param tcname test case name to run. A NULL means use the value of + * the environment variable CK_RUN_CASE if set, otherwise run + * "any/every case". + * @param print_mode the verbosity in which to report results to stdout + * + * @since 0.9.9 + */ +CK_DLL_EXP void CK_EXPORT srunner_run(SRunner * sr, const char *sname, + const char *tcname, + enum print_output print_mode); + + +/** + * Run a specific suite or test case or testcases with specific tags + * from a suite runner, printing results to stdout as specified by the + * print_mode. + * + * In addition to running any applicable suites or test cases, if the + * suite runner has been configured to output to a log, that is also + * performed. + * + * Note that if sname, tcname, include_tags, exclude_tags parameters + * are passed as NULL then if the environment variables CK_RUN_SUITE, + * CK_RUN_CASE, CK_INCLUDE_TAGS, CK_EXCLUDE_TAGS are defined then these + * values will be used instead. + * + * @param sr suite runner where the given suite or test case must be + * @param sname suite name to run. A NULL means use the value of the + * environment variable CK_RUN_SUITE if set, otherwise run "any/every + * suite". + * @param tcname test case name to run. A NULL means use the value of + * the environment variable CK_RUN_CASE if set, otherwise run + * "any/every case". + * @param include_tags space separate list of tags. Only run test + * cases that share one of these tags. A NULL means use the value of + * the environment variable CK_INCLUDE_TAGS if set, otherwise run + * "any/every test case". + * @param exclude_tags space separate list of tags. Only run test + * cases that do not share one of these tags even if they are selected + * by an included tag. A NULL means use the value of the environment + * variable CK_EXCLUDE_TAGS if set, otherwise run "any/every test + * case". + * @param print_mode the verbosity in which to report results to stdout + * + * @since 0.11.0 + */ +CK_DLL_EXP void CK_EXPORT srunner_run_tagged(SRunner * sr, const char *sname, + const char *tcname, + const char *include_tags, + const char *exclude_tags, + enum print_output print_mode); + +/** + * Retrieve the number of failed tests executed by a suite runner. + * + * This value represents both test failures and errors. + * + * @param sr suite runner to query for all failed tests + * + * @return number of test failures and errors found by the suite runner + * + * @since 0.6.1 + */ +CK_DLL_EXP int CK_EXPORT srunner_ntests_failed(SRunner * sr); + +/** + * Retrieve the total number of tests run by a suite runner. + * + * @param sr suite runner to query for all tests run + * + * @return number of all tests run by the suite runner + * + * @since 0.6.1 + */ +CK_DLL_EXP int CK_EXPORT srunner_ntests_run(SRunner * sr); + +/** + * Return an array of results for all failures found by a suite runner. + * + * Number of results is equal to srunner_nfailed_tests(). + * + * Information about individual results can be queried using: + * tr_rtype(), tr_ctx(), tr_msg(), tr_lno(), tr_lfile(), and tr_tcname(). + * + * Memory is malloc'ed and must be freed; however free the entire structure + * instead of individual test cases. + * + * @param sr suite runner to retrieve results from + * + * @return array of TestResult objects + * + * @since 0.6.0 + */ +CK_DLL_EXP TestResult **CK_EXPORT srunner_failures(SRunner * sr); + +/** + * Return an array of results for all tests run by a suite runner. + * + * Number of results is equal to srunner_ntests_run(), and excludes + * failures due to setup function failure. + * + * Information about individual results can be queried using: + * tr_rtype(), tr_ctx(), tr_msg(), tr_lno(), tr_lfile(), and tr_tcname(). + * + * Memory is malloc'ed and must be freed; however free the entire structure + * instead of individual test cases. + * + * @param sr suite runner to retrieve results from + * + * @return array of TestResult objects + * + * @since 0.6.1 +*/ +CK_DLL_EXP TestResult **CK_EXPORT srunner_results(SRunner * sr); + +/** + * Print the results contained in an SRunner to stdout. + * + * @param sr suite runner to print results for to stdout + * @param print_mode the print_output (verbosity) to use to report + * the result + * + * @since 0.7.0 + */ +CK_DLL_EXP void CK_EXPORT srunner_print(SRunner * sr, + enum print_output print_mode); + +/** + * Set the suite runner to output the result in log format to the + * given file. + * + * Note: log file setting is an initialize only operation -- it should + * be done immediately after SRunner creation, and the log file can't be + * changed after being set. + * + * This setting does not conflict with the other log output types; + * all logging types can occur concurrently if configured. + * + * @param sr suite runner to log results of in log format + * @param fname file name to output log results to + * + * @since 0.7.1 +*/ +CK_DLL_EXP void CK_EXPORT srunner_set_log(SRunner * sr, const char *fname); + +/** + * Checks if the suite runner is assigned a file for log output. + * + * @param sr suite runner to check + * + * @return 1 iff the suite runner currently is configured to output + * in log format; 0 otherwise + * + * @since 0.7.1 + */ +CK_DLL_EXP int CK_EXPORT srunner_has_log(SRunner * sr); + +/** + * Retrieves the name of the currently assigned file + * for log output, if any exists. + * + * @return the name of the log file, or NULL if none is configured + * + * @since 0.7.1 + */ +CK_DLL_EXP const char *CK_EXPORT srunner_log_fname(SRunner * sr); + +/** + * Set the suite runner to output the result in XML format to the + * given file. + * + * Note: XML file setting is an initialize only operation -- it should + * be done immediately after SRunner creation, and the XML file can't be + * changed after being set. + * + * This setting does not conflict with the other log output types; + * all logging types can occur concurrently if configured. + * + * @param sr suite runner to log results of in XML format + * @param fname file name to output XML results to + * + * @since 0.9.1 +*/ +CK_DLL_EXP void CK_EXPORT srunner_set_xml(SRunner * sr, const char *fname); + +/** + * Checks if the suite runner is assigned a file for XML output. + * + * @param sr suite runner to check + * + * @return 1 iff the suite runner currently is configured to output + * in XML format; 0 otherwise + * + * @since 0.9.1 + */ +CK_DLL_EXP int CK_EXPORT srunner_has_xml(SRunner * sr); + +/** + * Retrieves the name of the currently assigned file + * for XML output, if any exists. + * + * @return the name of the XML file, or NULL if none is configured + * + * @since 0.9.1 + */ +CK_DLL_EXP const char *CK_EXPORT srunner_xml_fname(SRunner * sr); + +/** + * Set the suite runner to output the result in TAP format to the + * given file. + * + * Note: TAP file setting is an initialize only operation -- it should + * be done immediately after SRunner creation, and the TAP file can't be + * changed after being set. + * + * This setting does not conflict with the other log output types; + * all logging types can occur concurrently if configured. + * + * @param sr suite runner to log results of in TAP format + * @param fname file name to output TAP results to + * + * @since 0.9.12 +*/ +CK_DLL_EXP void CK_EXPORT srunner_set_tap(SRunner * sr, const char *fname); + +/** + * Checks if the suite runner is assigned a file for TAP output. + * + * @param sr suite runner to check + * + * @return 1 iff the suite runner currently is configured to output + * in TAP format; 0 otherwise + * + * @since 0.9.12 + */ +CK_DLL_EXP int CK_EXPORT srunner_has_tap(SRunner * sr); + +/** + * Retrieves the name of the currently assigned file + * for TAP output, if any exists. + * + * @return the name of the TAP file, or NULL if none is configured + * + * @since 0.9.12 + */ +CK_DLL_EXP const char *CK_EXPORT srunner_tap_fname(SRunner * sr); + +/** + * Enum describing the current fork usage. + */ +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 */ +}; + +/** + * Retrieve the current fork status for the given suite runner + * + * @param sr suite runner to check fork status of + * + * @since 0.8.0 + */ +CK_DLL_EXP enum fork_status CK_EXPORT srunner_fork_status(SRunner * sr); + +/** + * Set the fork status for a given suite runner. + * + * The default fork status is CK_FORK_GETENV, which will look + * for the CK_FORK environment variable, which can be set to + * "yes" or "no". If the environment variable is not present, + * CK_FORK will be used if fork() is available on the system, + * otherwise CK_NOFORK is used. + * + * If set to CK_FORK or CK_NOFORK, the environment variable + * if defined is ignored. + * + * If Check is compiled without support for fork(), attempting + * to set the status to CK_FORK is ignored. + * + * @param sr suite runner to assign the fork status to + * @param fstat fork status to assign + * + * @since 0.8.0 + */ +CK_DLL_EXP void CK_EXPORT srunner_set_fork_status(SRunner * sr, + enum fork_status fstat); + +/** + * Invoke fork() during a test and assign the child to the same + * process group that the rest of the test case uses. + * + * One can invoke fork() directly during a test; however doing so + * may not guarantee that any children processes are destroyed once + * the test finishes. Once a test has completed, all processes in + * the process group will be killed; using this wrapper will prevent + * orphan processes. + * + * If Check is compiled without fork() support this call simply + * return -1 and does nothing. + * + * @return On success, the PID of the child process is returned in + * the parent, and 0 is returned in the child. On failure, + * a value of -1 is returned to the parent process and no + * child process is created. + * + * @since 0.9.3 + */ +CK_DLL_EXP pid_t CK_EXPORT check_fork(void); + +/** + * Wait for the pid and exit. + * + * This is to be used in conjunction with check_fork(). When called, + * will wait for the given process to terminate. If the process + * exited without error, exit(EXIT_SUCCESS) is invoked; otherwise + * exit(EXIT_FAILURE) is invoked. + * + * If Check is compiled without support for fork(), this invokes + * exit(EXIT_FAILURE). + * + * @param pid process to wait for, created by check_fork() + * + * @since 0.9.3 + */ +CK_DLL_EXP void CK_EXPORT check_waitpid_and_exit(pid_t pid) CK_ATTRIBUTE_NORETURN; + +/** + * Set the maximal assertion message size. + * + * This protects the code against unintentional extremely large assertion messages + * (values of up to 4GB were seen in the wild). + * The usual size for a message is less than 80 bytes. + * + * If the environment variable CK_MAX_MSG_SIZE is defined to a positive value, it is used. + * Otherwise, if a positive maximal message size is set via this function, it is used. + * Otherwise, the maximal message size is one assigned at compile time (4K bytes). + * + * @param max_msg_size the maximal assertion message size. + * + * @since 0.12.0 + */ +CK_DLL_EXP void CK_EXPORT check_set_max_msg_size(size_t max_msg_size); + +#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..865e7d5 --- /dev/null +++ b/src/check_error.c @@ -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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "../lib/libcompat.h" + +#include +#include +#include +#include +#include +#include + +#include "check_error.h" + +/** + * Storage for setjmp/longjmp context information used in NOFORK mode + */ +jmp_buf error_jmp_buffer; + + +/* 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..c2c8d34 --- /dev/null +++ b/src/check_error.h @@ -0,0 +1,39 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef ERROR_H +#define ERROR_H + +#include "../lib/libcompat.h" +#include + +extern jmp_buf error_jmp_buffer; + +/* 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, + ...) CK_ATTRIBUTE_NORETURN; +/* 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..bddd186 --- /dev/null +++ b/src/check_impl.h @@ -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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, 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, time.h, & list.h before this header +*/ + +#define US_PER_SEC 1000000 +#define NANOS_PER_SECONDS 1000000000 + +/** calculate the difference in useconds out of two "struct timespec"s */ +#define DIFF_IN_USEC(begin, end) \ + ( (((end).tv_sec - (begin).tv_sec) * US_PER_SEC) + \ + ((end).tv_nsec/1000) - ((begin).tv_nsec/1000) ) + +typedef struct TF +{ + TFun fn; + int loop_start; + int loop_end; + const char *name; + int signal; + signed 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; + struct timespec timeout; + List *tflst; /* list of test functions */ + List *unch_sflst; + List *unch_tflst; + List *ch_sflst; + List *ch_tflst; + List *tags; +}; + +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 */ + int duration; /* duration of this test in microseconds */ + 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); +void tr_free(TestResult * tr); + +enum cl_event +{ + CLINITLOG_SR, /* Initialize log file */ + CLENDLOG_SR, /* Tests are complete */ + CLSTART_SR, /* Suite runner start */ + CLSTART_S, /* Suite start */ + CLEND_SR, /* Suite runner end */ + CLEND_S, /* Suite end */ + CLSTART_T, /* A test case is about to run */ + CLEND_T /* Test case end */ +}; + +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 */ + const char *tap_fname; /* name of tap 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); + +clockid_t check_get_clockid(void); + +unsigned int tcase_matching_tag(TCase *tc, List *check_for); +List *tag_string_to_list(const char *tags_string); + +#endif /* CHECK_IMPL_H */ diff --git a/src/check_list.c b/src/check_list.c new file mode 100644 index 0000000..d93f51c --- /dev/null +++ b/src/check_list.c @@ -0,0 +1,154 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "../lib/libcompat.h" + +#include +#include + +#include "check_list.h" +#include "check_error.h" + + +enum +{ + LINIT = 1, + LGROW = 2 +}; + +struct List +{ + unsigned int n_elts; + unsigned int max_elts; + int current; /* pointer to the current node */ + int last; /* pointer to the node before END */ + void **data; +}; + +static void maybe_grow(List * lp) +{ + if(lp->n_elts >= lp->max_elts) + { + lp->max_elts *= LGROW; + lp->data = (void **)erealloc(lp->data, lp->max_elts * sizeof(lp->data[0])); + } +} + +List *check_list_create(void) +{ + List *lp; + + lp = (List *)emalloc(sizeof(List)); + lp->n_elts = 0; + lp->max_elts = LINIT; + lp->data = (void **)emalloc(sizeof(lp->data[0]) * LINIT); + lp->current = lp->last = -1; + return lp; +} + +void check_list_add_front(List * lp, 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 check_list_add_end(List * lp, void *val) +{ + if(lp == NULL) + return; + maybe_grow(lp); + lp->last++; + lp->n_elts++; + lp->current = lp->last; + lp->data[lp->current] = val; +} + +int check_list_at_end(List * lp) +{ + if(lp->current == -1) + return 1; + return (lp->current > lp->last); +} + +void check_list_front(List * lp) +{ + if(lp->current == -1) + return; + lp->current = 0; +} + + +void check_list_free(List * lp) +{ + if(lp == NULL) + return; + + free(lp->data); + free(lp); +} + +void *check_list_val(List * lp) +{ + if(lp == NULL) + return NULL; + if(lp->current == -1 || lp->current > lp->last) + return NULL; + + return lp->data[lp->current]; +} + +void check_list_advance(List * lp) +{ + if(lp == NULL) + return; + if(check_list_at_end(lp)) + return; + lp->current++; +} + + +void check_list_apply(List * lp, void (*fp) (void *)) +{ + if(lp == NULL || fp == NULL) + return; + + for(check_list_front(lp); !check_list_at_end(lp); check_list_advance(lp)) + fp(check_list_val(lp)); + +} + +int check_list_contains(List * lp, void *val) +{ + for(check_list_front(lp); !check_list_at_end(lp); check_list_advance(lp)) + { + if(check_list_val(lp) == val) + { + return 1; + } + } + + return 0; +} diff --git a/src/check_list.h b/src/check_list.h new file mode 100644 index 0000000..e0b5c8c --- /dev/null +++ b/src/check_list.h @@ -0,0 +1,59 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, 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 check_list_at_end(List * lp); + +/* Position list at front */ +void check_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 check_list_add_front(List * lp, void *val); + +/* Add a value to the end of the list, + positioning newly added value as current value */ +void check_list_add_end(List * lp, void *val); + +/* Give the value of the current node */ +void *check_list_val(List * lp); + +/* Position the list at the next node */ +void check_list_advance(List * lp); + +/* Free a list, but don't free values */ +void check_list_free(List * lp); + +void check_list_apply(List * lp, void (*fp) (void *)); + +/* Return true if the list contains the value, false otherwise */ +int check_list_contains(List * lp, void *val); + + +#endif /* CHECK_LIST_H */ diff --git a/src/check_log.c b/src/check_log.c new file mode 100644 index 0000000..2af8321 --- /dev/null +++ b/src/check_log.c @@ -0,0 +1,557 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "../lib/libcompat.h" + +#include +#include +#include +#if ENABLE_SUBUNIT +#include +#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" + +/* + * If a log file is specified to be "-", then instead of + * opening a file the log output is printed to stdout. + */ +#define STDOUT_OVERRIDE_LOG_FILE_NAME "-" + +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 srunner_log_fname(sr) != NULL; +} + +const char *srunner_log_fname(SRunner * sr) +{ + /* check if log filename have been set explicitly */ + if(sr->log_fname != NULL) + return sr->log_fname; + + return getenv("CK_LOG_FILE_NAME"); +} + + +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 srunner_xml_fname(sr) != NULL; +} + +const char *srunner_xml_fname(SRunner * sr) +{ + /* check if XML log filename have been set explicitly */ + if(sr->xml_fname != NULL) + { + return sr->xml_fname; + } + + return getenv("CK_XML_LOG_FILE_NAME"); +} + +void srunner_set_tap(SRunner * sr, const char *fname) +{ + if(sr->tap_fname) + return; + sr->tap_fname = fname; +} + +int srunner_has_tap(SRunner * sr) +{ + return srunner_tap_fname(sr) != NULL; +} + +const char *srunner_tap_fname(SRunner * sr) +{ + /* check if tap log filename have been set explicitly */ + if(sr->tap_fname != NULL) + { + return sr->tap_fname; + } + + return getenv("CK_TAP_LOG_FILE_NAME"); +} + +void srunner_register_lfun(SRunner * sr, FILE * lfile, int close, + LFun lfun, enum print_output printmode) +{ + Log *l = (Log *)emalloc(sizeof(Log)); + + if(printmode == CK_ENV) + { + printmode = get_env_printmode(); + } + + l->lfile = lfile; + l->lfun = lfun; + l->close = close; + l->mode = printmode; + check_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(check_list_front(l); !check_list_at_end(l); check_list_advance(l)) + { + lg = (Log *)check_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; + + 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 = (Suite *)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: + 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 = (Suite *)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: + break; + case CLSTART_T: + break; + case CLEND_T: + tr = (TestResult *)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 timespec ts_start = { 0, 0 }; + static char t[sizeof "yyyy-mm-dd hh:mm:ss"] = { 0 }; + + if(t[0] == 0) + { + struct timeval inittv; + struct tm now; + + gettimeofday(&inittv, NULL); + clock_gettime(check_get_clockid(), &ts_start); + if(localtime_r((const time_t *)&(inittv.tv_sec), &now) != NULL) + { + strftime(t, sizeof("yyyy-mm-dd hh:mm:ss"), "%Y-%m-%d %H:%M:%S", + &now); + } + } + + switch (evt) + { + case CLINITLOG_SR: + fprintf(file, + "\n" + "\n" + "\n" + " %s\n", t); + break; + case CLENDLOG_SR: + { + struct timespec ts_end = { 0, 0 }; + unsigned long duration; + + /* calculate time the test were running */ + clock_gettime(check_get_clockid(), &ts_end); + duration = (unsigned long)DIFF_IN_USEC(ts_start, ts_end); + fprintf(file, + " %lu.%06lu\n" + "\n", + duration / US_PER_SEC, duration % US_PER_SEC); + } + break; + case CLSTART_SR: + break; + case CLSTART_S: + s = (Suite *)obj; + fprintf(file, + " \n" + " "); + fprint_xml_esc(file, s->name); + fprintf(file, "\n"); + break; + case CLEND_SR: + break; + case CLEND_S: + fprintf(file, " \n"); + break; + case CLSTART_T: + break; + case CLEND_T: + tr = (TestResult *)obj; + tr_xmlprint(file, tr, CK_VERBOSE); + break; + default: + eprintf("Bad event type received in xml_lfun", __FILE__, + __LINE__); + } + +} + +void tap_lfun(SRunner * sr CK_ATTRIBUTE_UNUSED, FILE * file, + enum print_output printmode CK_ATTRIBUTE_UNUSED, void *obj, + enum cl_event evt) +{ + TestResult *tr; + + static int num_tests_run = 0; + + switch (evt) + { + case CLINITLOG_SR: + /* As this is a new log file, reset the number of tests executed */ + num_tests_run = 0; + break; + case CLENDLOG_SR: + /* Output the test plan as the last line */ + fprintf(file, "1..%d\n", num_tests_run); + fflush(file); + break; + case CLSTART_SR: + break; + case CLSTART_S: + break; + case CLEND_SR: + break; + case CLEND_S: + break; + case CLSTART_T: + break; + case CLEND_T: + /* Print the test result to the tap file */ + num_tests_run += 1; + tr = (TestResult *)obj; + fprintf(file, "%s %d - %s:%s:%s: %s\n", + tr->rtype == CK_PASS ? "ok" : "not ok", num_tests_run, + tr->file, tr->tcname, tr->tname, tr->msg); + fflush(file); + break; + default: + eprintf("Bad event type received in tap_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; + char const *name; + + /* assert(printmode == CK_SUBUNIT); */ + + switch (evt) + { + case CLINITLOG_SR: + break; + case CLENDLOG_SR: + break; + case CLSTART_SR: + break; + case CLSTART_S: + break; + case CLEND_SR: + if(printmode > CK_SILENT) + { + fprintf(file, "\n"); + srunner_fprint(file, sr, printmode); + } + break; + case CLEND_S: + break; + case CLSTART_T: + name = (const char *)obj; + subunit_test_start(name); + break; + case CLEND_T: + tr = (TestResult *)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; + case CK_TEST_RESULT_INVALID: + 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 + +static FILE *srunner_open_file(const char *filename) +{ + FILE *f = NULL; + + if(strcmp(filename, STDOUT_OVERRIDE_LOG_FILE_NAME) == 0) + { + f = stdout; + } + else + { + f = fopen(filename, "w"); + if(f == NULL) + { + eprintf("Error in call to fopen while opening file %s:", __FILE__, + __LINE__ - 2, filename); + } + } + return f; +} + +FILE *srunner_open_lfile(SRunner * sr) +{ + FILE *f = NULL; + + if(srunner_has_log(sr)) + { + f = srunner_open_file(srunner_log_fname(sr)); + } + return f; +} + +FILE *srunner_open_xmlfile(SRunner * sr) +{ + FILE *f = NULL; + + if(srunner_has_xml(sr)) + { + f = srunner_open_file(srunner_xml_fname(sr)); + } + return f; +} + +FILE *srunner_open_tapfile(SRunner * sr) +{ + FILE *f = NULL; + + if(srunner_has_tap(sr)) + { + f = srunner_open_file(srunner_tap_fname(sr)); + } + 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, f != stdout, lfile_lfun, print_mode); + } + f = srunner_open_xmlfile(sr); + if(f) + { + srunner_register_lfun(sr, f, f != stdout, xml_lfun, print_mode); + } + f = srunner_open_tapfile(sr); + if(f) + { + srunner_register_lfun(sr, f, f != stdout, tap_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(check_list_front(l); !check_list_at_end(l); check_list_advance(l)) + { + Log *lg = (Log *)check_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); + } + check_list_free(l); + sr->loglst = NULL; +} diff --git a/src/check_log.h b/src/check_log.h new file mode 100644 index 0000000..7223b98 --- /dev/null +++ b/src/check_log.h @@ -0,0 +1,55 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, 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 tap_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); +FILE *srunner_open_tapfile(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..9af8827 --- /dev/null +++ b/src/check_msg.c @@ -0,0 +1,364 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "../lib/libcompat.h" + +#include +#include +#include +#include + +#include "check_error.h" +#include "check.h" +#include "check_list.h" +#include "check_impl.h" +#include "check_msg.h" +#include "check_pack.h" +#include "check_str.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 char *send_file1_name; +static FILE *send_file2; +static char *send_file2_name; + +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("Unable to report test progress or a failure; was an ck_assert or ck_abort function called while not running tests?", __FILE__, __LINE__); + + return NULL; +} + +void send_failure_info(const char *msg) +{ + FailMsg fmsg; + + fmsg.msg = strdup(msg); + ppack(get_pipe(), CK_MSG_FAIL, (CheckMsg *) & fmsg); + free(fmsg.msg); +} + +void send_duration_info(int duration) +{ + DurationMsg dmsg; + + dmsg.duration = duration; + ppack(get_pipe(), CK_MSG_DURATION, (CheckMsg *) & dmsg); +} + +void send_loc_info(const char *file, int line) +{ + LocMsg lmsg; + + lmsg.file = strdup(file); + lmsg.line = line; + ppack(get_pipe(), CK_MSG_LOC, (CheckMsg *) & lmsg); + free(lmsg.file); +} + +void send_ctx_info(enum ck_result_ctx ctx) +{ + CtxMsg cmsg; + + cmsg.ctx = ctx; + ppack(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(fp); + + if(rmsg == NULL) + { + eprintf("Error in call to punpack", __FILE__, __LINE__ - 4); + } + + 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) + { + if(rmsg->failctx != CK_CTX_INVALID) + { + tr->ctx = rmsg->failctx; + } + else + { + tr->ctx = rmsg->lastctx; + } + + 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->duration = rmsg->duration; + tr_set_loc_by_ctx(tr, CK_CTX_TEST, rmsg); + } + + return tr; +} + +void setup_messaging(void) +{ + setup_pipe(); +} + +void teardown_messaging(void) +{ + teardown_pipe(); +} + +/** + * Open a temporary file. + * + * If the file could be unlinked upon creation, the name + * of the file is not returned via 'name'. However, if the + * file could not be unlinked, the name is returned, + * expecting the caller to both delete the file and + * free the 'name' field after the file is closed. + */ +FILE *open_tmp_file(char **name) +{ + FILE *file = NULL; + + *name = NULL; + +#if !HAVE_MKSTEMP + /* Windows does not like tmpfile(). This is likely because tmpfile() + * call unlink() on the file before returning it, to make sure the + * file is deleted when it is closed. The unlink() call also fails + * on Windows if the file is still open. */ + /* also note that mkstemp is apparently a C90 replacement for tmpfile */ + /* perhaps all we need to do on Windows is set TMPDIR to whatever is + stored in TEMP for tmpfile to work */ + /* and finally, the "b" from "w+b" is ignored on OS X, not sure about WIN32 */ + + file = tmpfile(); + if(file == NULL) + { + /* + * The heuristic for selecting a temporary folder is as follows: + * 1) If the TEMP environment variable is defined, use that directory. + * 2) If the P_tmpdir macro is defined, use that directory. + * 3) If the TMPDIR environment variable is defined, use that directory. + * 4) Use the platform defined temporary directory, or the current directory. + */ + char *tmp = getenv("TEMP"); + char *tmp_file = tempnam(tmp, "check_"); + + /* + * Note, tempnam is not enough to get a unique name. Between + * getting the name and opening the file, something else also + * calling tempnam() could get the same name. It has been observed + * on MinGW-w64 builds on Wine that this exact thing happens + * if multiple instances of a unit tests are running concurrently. + * To prevent two concurrent unit tests from getting the same file, + * we append the pid to the file. The pid should be unique on the + * system. + */ + char *uniq_tmp_file = ck_strdup_printf("%s.%d", tmp_file, getpid()); + + file = fopen(uniq_tmp_file, "w+b"); + *name = uniq_tmp_file; + free(tmp_file); + } +#else + /* + * The heuristic for selecting a temporary folder is as follows: + * 1) If the TEMP environment variable is defined, use that directory. + * 2) If the P_tmpdir macro is defined, use that directory. + * 3) If the TMPDIR environment variable is defined, use that directory. + * 4) Use the current directory + */ + + int fd = -1; + const char *tmp_dir = getenv ("TEMP"); +#ifdef P_tmpdir + if (tmp_dir == NULL) + { + tmp_dir = P_tmpdir; + } +#endif /*P_tmpdir*/ + if (tmp_dir == NULL) + { + tmp_dir = getenv ("TMPDIR"); + } + if (tmp_dir == NULL) + { + tmp_dir = "."; + } + + *name = ck_strdup_printf ("%s/check_XXXXXX", tmp_dir); + + if (-1 < (fd = mkstemp (*name))) + { + file = fdopen (fd, "w+b"); + if (0 == unlink (*name) || NULL == file) + { + free (*name); + *name = NULL; + } + } +#endif + return file; +} + +static void setup_pipe(void) +{ + if(send_file1 == NULL) + { + send_file1 = open_tmp_file(&send_file1_name); + if(send_file1 == NULL) + { + eprintf("Unable to create temporary file for communication; may not have permissions to do so", __FILE__, __LINE__ -3); + } + return; + } + if(send_file2 == NULL) + { + send_file2 = open_tmp_file(&send_file2_name); + if(send_file2 == NULL) + { + eprintf("Unable to create temporary file for communication; may not have permissions to do so", __FILE__, __LINE__ -3); + } + return; + } + eprintf("Only one nesting of suite runs supported", __FILE__, __LINE__); +} + +static void teardown_pipe(void) +{ + if(send_file2 != 0) + { + fclose(send_file2); + send_file2 = 0; + if(send_file2_name != NULL) + { + unlink(send_file2_name); + free(send_file2_name); + send_file2_name = NULL; + } + } + else if(send_file1 != 0) + { + fclose(send_file1); + send_file1 = 0; + if(send_file1_name != NULL) + { + unlink(send_file1_name); + free(send_file1_name); + send_file1_name = NULL; + } + } + 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..c66a35a --- /dev/null +++ b/src/check_msg.h @@ -0,0 +1,39 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, 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); +void send_duration_info(int duration); + +TestResult *receive_test_result(int waserror); + +void setup_messaging(void); +void teardown_messaging(void); + +FILE *open_tmp_file(char **name); + +#endif /*CHECK_MSG_NEW_H */ diff --git a/src/check_pack.c b/src/check_pack.c new file mode 100644 index 0000000..0fe1774 --- /dev/null +++ b/src/check_pack.c @@ -0,0 +1,509 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "../lib/libcompat.h" + +#include +#include +#include + +#include "check.h" +#include "check_error.h" +#include "check_list.h" +#include "check_impl.h" +#include "check_pack.h" + +#ifndef HAVE_PTHREAD +#define pthread_mutex_lock(arg) +#define pthread_mutex_unlock(arg) +#define pthread_cleanup_push(f, a) { +#define pthread_cleanup_pop(e) } +#endif + +/* Maximum size for one message in the message stream. */ +static size_t ck_max_msg_size = 0; +#ifndef DEFAULT_MAX_MSG_SIZE +#define DEFAULT_MAX_MSG_SIZE 4096 +#endif +/* This is used to implement a sliding window on the receiving + * side. When sending messages, we assure that no single message + * is bigger than this. + * The usual size for a message is less than 80 bytes. + * All this is done instead of the previous approach to allocate (actually + * continuously reallocate) one big chunk for the whole message stream. + * Problems were seen in the wild with up to 4 GB reallocations. + */ + +void check_set_max_msg_size(size_t max_msg_size) +{ + ck_max_msg_size = max_msg_size; +} + +static size_t get_max_msg_size(void) +{ + size_t value = 0; + char *env = getenv("CK_MAX_MSG_SIZE"); + if (env) + value = (size_t)strtoul(env, NULL, 10); // Cast in case size_t != unsigned long. + if (value == 0) + value = ck_max_msg_size; + if (value == 0) + value = DEFAULT_MAX_MSG_SIZE; + return value; +} + +/* 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 int pack_duration(char **buf, DurationMsg * 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 upack_duration(char **buf, DurationMsg * 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(FILE * fdes, int size, 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, + (pfun) pack_duration +}; + +static upfun upftab[] = { + (upfun) upack_ctx, + (upfun) upack_fail, + (upfun) upack_loc, + (upfun) upack_duration +}; + +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; + + if(buf == NULL) + return -1; + + obuf = buf; + + *type = upack_type(&buf); + + check_type(*type, __FILE__, __LINE__); + + upftab[*type] (&buf, msg); + + return buf - obuf; +} + +static void pack_int(char **buf, int val) +{ + unsigned char *ubuf = (unsigned char *)*buf; + ck_uint32 uval = val; + + ubuf[0] = (unsigned char)((uval >> 24) & 0xFF); + ubuf[1] = (unsigned char)((uval >> 16) & 0xFF); + ubuf[2] = (unsigned char)((uval >> 8) & 0xFF); + ubuf[3] = (unsigned char)(uval & 0xFF); + + *buf += 4; +} + +static int upack_int(char **buf) +{ + unsigned char *ubuf = (unsigned char *)*buf; + ck_uint32 uval; + + uval = + (ck_uint32) ((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 = (char *)emalloc(strsz + 1); + memcpy(val, *buf, strsz); + val[strsz] = 0; + *buf += strsz; + } + else + { + val = (char *)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 = (char *)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 = (enum ck_result_ctx)upack_int(buf); +} + +static int pack_duration(char **buf, DurationMsg * cmsg) +{ + char *ptr; + int len; + + len = 4 + 4; + *buf = ptr = (char *)emalloc(len); + + pack_type(&ptr, CK_MSG_DURATION); + pack_int(&ptr, cmsg->duration); + + return len; +} + +static void upack_duration(char **buf, DurationMsg * cmsg) +{ + cmsg->duration = 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 = (char *)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 = (char *)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 +static pthread_mutex_t ck_mutex_lock = PTHREAD_MUTEX_INITIALIZER; +static void ppack_cleanup(void *mutex) +{ + pthread_mutex_unlock((pthread_mutex_t *)mutex); +} +#endif + +void ppack(FILE * fdes, enum ck_msg_type type, CheckMsg * msg) +{ + char *buf = NULL; + int n; + ssize_t r; + + n = pack(type, &buf, msg); + /* Keep it on the safe side to not send too much data. */ + if(n > get_max_msg_size()) + eprintf("Message string too long", __FILE__, __LINE__ - 2); + + pthread_cleanup_push(ppack_cleanup, &ck_mutex_lock); + pthread_mutex_lock(&ck_mutex_lock); + r = fwrite(buf, 1, n, fdes); + fflush(fdes); + pthread_mutex_unlock(&ck_mutex_lock); + pthread_cleanup_pop(0); + if(r != n) + eprintf("Error in call to fwrite:", __FILE__, __LINE__ - 2); + + free(buf); +} + +static int read_buf(FILE * fdes, int size, char *buf) +{ + int n; + + n = fread(buf, 1, size, fdes); + + if(ferror(fdes)) + { + eprintf("Error in call to fread:", __FILE__, __LINE__ - 4); + } + + return n; +} + +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 = strdup(fmsg->msg); + rmsg->failctx = rmsg->lastctx; + } + else + { + /* Skip subsequent failure messages, only happens for CK_NOFORK */ + } + free(fmsg->msg); + } + else if(type == CK_MSG_DURATION) + { + DurationMsg *cmsg = (DurationMsg *) & msg; + + rmsg->duration = cmsg->duration; + } + 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 = (RcvMsg *)emalloc(sizeof(RcvMsg)); + rmsg->lastctx = CK_CTX_INVALID; + rmsg->failctx = CK_CTX_INVALID; + rmsg->msg = NULL; + rmsg->duration = -1; + 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) +{ + if(rmsg->lastctx == CK_CTX_TEST) + { + free(rmsg->test_file); + rmsg->test_line = line; + rmsg->test_file = strdup(file); + } + else + { + free(rmsg->fixture_file); + rmsg->fixture_line = line; + rmsg->fixture_file = strdup(file); + } +} + +RcvMsg *punpack(FILE * fdes) +{ + int nread, nparse, n; + char *buf; + RcvMsg *rmsg; + + rmsg = rcvmsg_create(); + + /* Allcate a buffer */ + buf = (char *)emalloc(get_max_msg_size() * 2); + /* Fill the buffer from the file */ + nread = read_buf(fdes, get_max_msg_size() * 2, buf); + nparse = nread; + /* While not all parsed */ + while(nparse > 0) + { + /* Parse one message */ + n = get_result(buf, rmsg); + nparse -= n; + if (nparse < 0) + eprintf("Error in call to get_result", __FILE__, __LINE__ - 3); + /* Move remaining data in buffer to the beginning */ + memmove(buf, buf + n, nparse); + /* If EOF has not been seen */ + if(nread > 0) + { + /* Read more data into empty space at end of the buffer */ + nread = read_buf(fdes, n, buf + nparse); + nparse += nread; + } + } + free(buf); + + 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..3d469d2 --- /dev/null +++ b/src/check_pack.h @@ -0,0 +1,84 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef CHECK_PACK_H +#define CHECK_PACK_H + + +enum ck_msg_type +{ + CK_MSG_CTX, + CK_MSG_FAIL, + CK_MSG_LOC, + CK_MSG_DURATION, + 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 struct DurationMsg +{ + int duration; +} DurationMsg; + +typedef union +{ + CtxMsg ctx_msg; + FailMsg fail_msg; + LocMsg loc_msg; + DurationMsg duration_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; + int duration; +} 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(FILE * fdes, enum ck_msg_type type, CheckMsg * msg); +RcvMsg *punpack(FILE * fdes); + +#endif /*CHECK_PACK_H */ diff --git a/src/check_print.c b/src/check_print.c new file mode 100644 index 0000000..35f13b6 --- /dev/null +++ b/src/check_print.c @@ -0,0 +1,246 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "../lib/libcompat.h" + +#include +#include +#include + +#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(check_list_front(resultlst); !check_list_at_end(resultlst); + check_list_advance(resultlst)) + { + TestResult *tr = (TestResult *)check_list_val(resultlst); + + tr_fprint(file, tr, print_mode); + } + return; +} + +void fprint_xml_esc(FILE * file, const char *str) +{ + /* The valid XML characters are as follows: + * #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] + * Characters that are outside of ASCII must be encoded. Further, the + * following special characters: + * " ' < > & + * must be encoded. We assume that the incoming string may be a multibyte + * character. + */ + + for(; *str != '\0'; str++) + { + char next = *str; + + /* handle special characters that must be escaped */ + if(next == '"' || next == '\'' || next == '<' || next == '>' || next == '&') + { + switch (next) + { + case '"': + fputs(""", file); + break; + case '\'': + fputs("'", file); + break; + case '<': + fputs("<", file); + break; + case '>': + fputs(">", file); + break; + case '&': + fputs("&", file); + break; + } + } + /* printable ASCII */ + else if(next >= ' ' && next <= '~') + { + fputc(next, file); + } + /* Non-printable character */ + else if(next == 0x9 || next == 0xA || next == 0xD || + next >= 0x20) + { + fprintf(file, "&#x%X;", next); + } + /* If it did not get printed, it is not a valid XML character*/ + } +} + +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 = NULL; + char *file_name = NULL; + char *slash = NULL; + + switch (tr->rtype) + { + case CK_PASS: + snprintf(result, sizeof(result), "%s", "success"); + break; + case CK_FAILURE: + snprintf(result, sizeof(result), "%s", "failure"); + break; + case CK_ERROR: + snprintf(result, sizeof(result), "%s", "error"); + break; + case CK_TEST_RESULT_INVALID: + default: + abort(); + break; + } + + if(tr->file) + { + slash = strrchr(tr->file, '/'); + if(slash == NULL) + { + slash = strrchr(tr->file, '\\'); + } + + if(slash == NULL) + { + path_name = strdup("."); + 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, " \n", result); + fprintf(file, " %s\n", + (path_name == NULL ? "" : path_name)); + fprintf(file, " %s:%d\n", + (file_name == NULL ? "" : file_name), tr->line); + fprintf(file, " %s\n", tr->tname); + fprintf(file, " %d\n", tr->iter); + fprintf(file, " %d.%06d\n", + tr->duration < 0 ? -1 : tr->duration / US_PER_SEC, + tr->duration < 0 ? 0 : tr->duration % US_PER_SEC); + fprintf(file, " "); + fprint_xml_esc(file, tr->tcname); + fprintf(file, "\n"); + fprintf(file, " "); + fprint_xml_esc(file, tr->msg); + fprintf(file, "\n"); + fprintf(file, " \n"); + + 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..eabd8b9 --- /dev/null +++ b/src/check_print.h @@ -0,0 +1,32 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef CHECK_PRINT_H +#define CHECK_PRINT_H + +/* escape XML special characters (" ' < > &) in str and print to file */ +void fprint_xml_esc(FILE * file, const char *str); +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..da1f40f --- /dev/null +++ b/src/check_run.c @@ -0,0 +1,867 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "../lib/libcompat.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#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, + const char *sname, const char *tcname, + const char *include_tags, + const char *exclude_tags, + 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 TestResult * srunner_run_setup(List * func_list, + enum fork_status fork_usage, const char * test_name, + const char * setup_name); +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 * fixture_list, enum fork_status fork_usage); +static void srunner_run_unchecked_teardown(SRunner * sr, 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, + int duration); +static void set_nofork_info(TestResult * tr); +static char *pass_msg(void); + +#if defined(HAVE_FORK) && HAVE_FORK==1 +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, + signed char allowed_exit_value); +static void set_fork_info(TestResult * tr, int status, int expected_signal, + signed 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 struct sigaction sigint_old_action; +static struct sigaction sigterm_old_action; + +static void CK_ATTRIBUTE_UNUSED sig_handler(int sig_nr) +{ + switch (sig_nr) + { + case SIGALRM: + alarm_received = 1; + killpg(group_pid, SIGKILL); + break; + case SIGTERM: + case SIGINT: + { + pid_t own_group_pid; + int child_sig = SIGTERM; + + if (sig_nr == SIGINT) + { + child_sig = SIGKILL; + sigaction(SIGINT, &sigint_old_action, NULL); + } + else + { + sigaction(SIGTERM, &sigterm_old_action, NULL); + } + + killpg(group_pid, child_sig); + + /* POSIX says that calling killpg(0) + * does not necessarily mean to call it on the callers + * group pid! */ + own_group_pid = getpgrp(); + killpg(own_group_pid, sig_nr); + break; + } + default: + eprintf("Unhandled signal: %d", __FILE__, __LINE__, sig_nr); + break; + } +} +#endif /* HAVE_FORK */ + +#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, + const char *sname, const char *tcname, + const char *include_tags, + const char *exclude_tags, + enum print_output CK_ATTRIBUTE_UNUSED + print_mode) +{ + List *include_tag_lst; + List *exclude_tag_lst; + List *slst; + List *tcl; + TCase *tc; + + slst = sr->slst; + + include_tag_lst = tag_string_to_list(include_tags); + exclude_tag_lst = tag_string_to_list(exclude_tags); + + for(check_list_front(slst); !check_list_at_end(slst); + check_list_advance(slst)) + { + Suite *s = (Suite *)check_list_val(slst); + + if(((sname != NULL) && (strcmp(sname, s->name) != 0)) + || ((tcname != NULL) && (!suite_tcase(s, tcname)))) + continue; + + log_suite_start(sr, s); + + tcl = s->tclst; + + for(check_list_front(tcl); !check_list_at_end(tcl); + check_list_advance(tcl)) + { + tc = (TCase *)check_list_val(tcl); + + if((tcname != NULL) && (strcmp(tcname, tc->name) != 0)) + { + continue; + } + if (include_tags != NULL) + { + if (!tcase_matching_tag(tc, include_tag_lst)) + { + continue; + } + } + if (exclude_tags != NULL) + { + if (tcase_matching_tag(tc, exclude_tag_lst)) + { + continue; + } + } + + srunner_run_tcase(sr, tc); + } + + log_suite_end(sr, s); + } + + check_list_apply(include_tag_lst, free); + check_list_apply(exclude_tag_lst, free); + check_list_free(include_tag_lst); + check_list_free(exclude_tag_lst); +} + +static void srunner_iterate_tcase_tfuns(SRunner * sr, TCase * tc) +{ + List *tfl; + TF *tfun; + TestResult *tr = NULL; + + tfl = tc->tflst; + + for(check_list_front(tfl); !check_list_at_end(tfl); + check_list_advance(tfl)) + { + int i; + + tfun = (TF *)check_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: +#if defined(HAVE_FORK) && HAVE_FORK==1 + tr = tcase_run_tfun_fork(sr, tc, tfun, i); +#else /* HAVE_FORK */ + eprintf("This version does not support fork", __FILE__, + __LINE__); +#endif /* HAVE_FORK */ + break; + case CK_NOFORK: + tr = tcase_run_tfun_nofork(sr, tc, tfun, i); + break; + case CK_FORK_GETENV: + default: + eprintf("Bad fork status in SRunner", __FILE__, __LINE__); + } + + if(NULL != tr) + { + srunner_add_failure(sr, tr); + log_test_end(sr, tr); + } + } + } +} + +static void srunner_add_failure(SRunner * sr, TestResult * tr) +{ + check_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 TestResult * srunner_run_setup(List * fixture_list, enum fork_status fork_usage, + const char * test_name, const char * setup_name) +{ + TestResult *tr = NULL; + Fixture *setup_fixture; + + if(fork_usage == CK_FORK) + { + send_ctx_info(CK_CTX_SETUP); + } + + for(check_list_front(fixture_list); !check_list_at_end(fixture_list); + check_list_advance(fixture_list)) + { + setup_fixture = (Fixture *)check_list_val(fixture_list); + + if(fork_usage == CK_NOFORK) + { + send_ctx_info(CK_CTX_SETUP); + + if(0 == setjmp(error_jmp_buffer)) + { + setup_fixture->fun(); + } + + /* Stop the setup and return the failure in nofork mode. */ + tr = receive_result_info_nofork(test_name, setup_name, 0, -1); + if(tr->rtype != CK_PASS) + { + break; + } + + free(tr->file); + free(tr->msg); + free(tr); + tr = NULL; + } + else + { + setup_fixture->fun(); + } + } + + return tr; +} + +static int srunner_run_unchecked_setup(SRunner * sr, TCase * tc) +{ + TestResult *tr = NULL; + int rval = 1; + + set_fork_status(CK_NOFORK); + tr = srunner_run_setup(tc->unch_sflst, CK_NOFORK, tc->name, "unchecked_setup"); + set_fork_status(srunner_fork_status(sr)); + + if(tr != NULL && tr->rtype != CK_PASS) + { + srunner_add_failure(sr, tr); + rval = 0; + } + + return rval; +} + +static TestResult *tcase_run_checked_setup(SRunner * sr, TCase * tc) +{ + TestResult *tr = srunner_run_setup(tc->ch_sflst, srunner_fork_status(sr), + tc->name, "checked_setup"); + + return tr; +} + +static void srunner_run_teardown(List * fixture_list, enum fork_status fork_usage) +{ + Fixture * fixture; + + for(check_list_front(fixture_list); !check_list_at_end(fixture_list); + check_list_advance(fixture_list)) + { + fixture = (Fixture *)check_list_val(fixture_list); + send_ctx_info(CK_CTX_TEARDOWN); + + if(fork_usage == CK_NOFORK) + { + if(0 == setjmp(error_jmp_buffer)) + { + fixture->fun(); + } + else + { + /* Abort the remaining teardowns */ + break; + } + } + else + { + fixture->fun(); + } + } +} + +static void srunner_run_unchecked_teardown(SRunner * sr, TCase * tc) +{ + srunner_run_teardown(tc->unch_tflst, srunner_fork_status(sr)); +} + +static void tcase_run_checked_teardown(TCase * tc) +{ + srunner_run_teardown(tc->ch_tflst, CK_NOFORK); +} + +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(sr, tc); + } +} + +static TestResult *tcase_run_tfun_nofork(SRunner * sr, TCase * tc, TF * tfun, + int i) +{ + TestResult *tr; + struct timespec ts_start = {0, 0}, ts_end = {0, 0}; + + tr = tcase_run_checked_setup(sr, tc); + if(tr == NULL) + { + clock_gettime(check_get_clockid(), &ts_start); + if(0 == setjmp(error_jmp_buffer)) + { + tfun->fn(i); + } + clock_gettime(check_get_clockid(), &ts_end); + tcase_run_checked_teardown(tc); + return receive_result_info_nofork(tc->name, tfun->name, i, + DIFF_IN_USEC(ts_start, ts_end)); + } + + return tr; +} + +static TestResult *receive_result_info_nofork(const char *tcname, + const char *tname, + int iter, int duration) +{ + TestResult *tr; + + tr = receive_test_result(0); + if(tr == NULL) + { + eprintf("Failed to receive test result", __FILE__, __LINE__); + } + else + { + tr->tcname = tcname; + tr->tname = tname; + tr->iter = iter; + tr->duration = duration; + 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) +{ + return strdup("Passed"); +} + +#if defined(HAVE_FORK) && HAVE_FORK==1 +static TestResult *tcase_run_tfun_fork(SRunner * sr, TCase * tc, TF * tfun, + int i) +{ + pid_t pid_w; + pid_t pid; + int status = 0; + struct timespec ts_start = { 0, 0 }, ts_end ={ 0, 0 }; + + timer_t timerid; + struct itimerspec timer_spec; + TestResult *tr; + + + pid = fork(); + if(pid == -1) + eprintf("Error in call to fork:", __FILE__, __LINE__ - 2); + if(pid == 0) + { + setpgid(0, 0); + group_pid = getpgrp(); + tr = tcase_run_checked_setup(sr, tc); + free(tr); + clock_gettime(check_get_clockid(), &ts_start); + tfun->fn(i); + clock_gettime(check_get_clockid(), &ts_end); + tcase_run_checked_teardown(tc); + send_duration_info(DIFF_IN_USEC(ts_start, ts_end)); + exit(EXIT_SUCCESS); + } + else + { + group_pid = pid; + } + + alarm_received = 0; + + if(timer_create(check_get_clockid(), + NULL /* fire SIGALRM if timer expires */, + &timerid) == 0) + { + /* Set the timer to fire once */ + timer_spec.it_value = tc->timeout; + timer_spec.it_interval.tv_sec = 0; + timer_spec.it_interval.tv_nsec = 0; + if(timer_settime(timerid, 0, &timer_spec, NULL) == 0) + { + do + { + pid_w = waitpid(pid, &status, 0); + } + while(pid_w == -1); + } + else + { + eprintf("Error in call to timer_settime:", __FILE__, __LINE__); + } + + /* If the timer has not fired, disable it */ + timer_delete(timerid); + } + else + { + eprintf("Error in call to timer_create:", __FILE__, __LINE__); + } + + 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, + signed 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__); + } + else + { + 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, + signed char allowed_exit_value) +{ + int was_sig = WIFSIGNALED(status); + int was_exit = WIFEXITED(status); + signed char 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; + if(tr->msg != NULL) + { + free(tr->msg); + } + tr->msg = signal_error_msg(signal_received, signal_expected); + } + else + { + tr->rtype = CK_PASS; + if(tr->msg != NULL) + { + free(tr->msg); + } + tr->msg = pass_msg(); + } + } + else if(signal_expected != 0) + { + /* signal received, but not the expected one */ + tr->rtype = CK_ERROR; + if(tr->msg != NULL) + { + free(tr->msg); + } + tr->msg = signal_error_msg(signal_received, signal_expected); + } + else + { + /* signal received and none expected */ + tr->rtype = CK_ERROR; + if(tr->msg != NULL) + { + free(tr->msg); + } + tr->msg = signal_msg(signal_received); + } + } + else if(signal_expected == 0) + { + if(was_exit && exit_status == allowed_exit_value) + { + tr->rtype = CK_PASS; + if(tr->msg != NULL) + { + free(tr->msg); + } + 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) + { + if(tr->msg != NULL) + { + free(tr->msg); + } + 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 = (char *)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 = (char *)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 = (char *)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 /* HAVE_FORK */ + +enum fork_status srunner_fork_status(SRunner * sr) +{ + if(sr->fstat == CK_FORK_GETENV) + { + char *env = getenv("CK_FORK"); + + if(env == NULL) +#if defined(HAVE_FORK) && HAVE_FORK==1 + return CK_FORK; +#else + return CK_NOFORK; +#endif + if(strcmp(env, "no") == 0) + return CK_NOFORK; +#if defined(HAVE_FORK) && HAVE_FORK==1 + return CK_FORK; +#else /* HAVE_FORK */ + /* Ignoring, as Check is not compiled with fork support. */ + return CK_NOFORK; +#endif /* HAVE_FORK */ + } + return sr->fstat; +} + +void srunner_set_fork_status(SRunner * sr, enum fork_status fstat) +{ +#if !defined(HAVE_FORK) || HAVE_FORK==0 + /* If fork() is unavailable, do not allow a fork mode to be set */ + if(fstat != CK_NOFORK) + { + /* Overriding, as Check is not compiled with fork support. */ + fstat = CK_NOFORK; + } +#endif /* ! HAVE_FORK */ + sr->fstat = fstat; +} + +void srunner_run_all(SRunner * sr, enum print_output print_mode) +{ + srunner_run(sr, NULL, /* All test suites. */ + NULL, /* All test cases. */ + print_mode); +} + +void srunner_run_tagged(SRunner * sr, const char *sname, const char *tcname, + const char *include_tags, const char *exclude_tags, + enum print_output print_mode) +{ +#if defined(HAVE_SIGACTION) && defined(HAVE_FORK) + static struct sigaction sigalarm_old_action; + static struct sigaction sigalarm_new_action; + static struct sigaction sigint_new_action; + static struct sigaction sigterm_new_action; +#endif /* HAVE_SIGACTION && HAVE_FORK */ + + /* Get the selected test suite and test case from the + environment. */ + if(!tcname) + tcname = getenv("CK_RUN_CASE"); + if(!sname) + sname = getenv("CK_RUN_SUITE"); + if(!include_tags) + include_tags = getenv("CK_INCLUDE_TAGS"); + if(!exclude_tags) + exclude_tags = getenv("CK_EXCLUDE_TAGS"); + + if(sr == NULL) + return; + if(print_mode >= CK_LAST) + { + eprintf("Bad print_mode argument to srunner_run_all: %d", + __FILE__, __LINE__, print_mode); + } +#if defined(HAVE_SIGACTION) && defined(HAVE_FORK) + memset(&sigalarm_new_action, 0, sizeof(sigalarm_new_action)); + sigalarm_new_action.sa_handler = sig_handler; + sigaction(SIGALRM, &sigalarm_new_action, &sigalarm_old_action); + + memset(&sigint_new_action, 0, sizeof(sigint_new_action)); + sigint_new_action.sa_handler = sig_handler; + sigaction(SIGINT, &sigint_new_action, &sigint_old_action); + + memset(&sigterm_new_action, 0, sizeof(sigterm_new_action)); + sigterm_new_action.sa_handler = sig_handler; + sigaction(SIGTERM, &sigterm_new_action, &sigterm_old_action); +#endif /* HAVE_SIGACTION && HAVE_FORK */ + srunner_run_init(sr, print_mode); + srunner_iterate_suites(sr, sname, tcname, include_tags, exclude_tags, + print_mode); + srunner_run_end(sr, print_mode); +#if defined(HAVE_SIGACTION) && defined(HAVE_FORK) + sigaction(SIGALRM, &sigalarm_old_action, NULL); + sigaction(SIGINT, &sigint_old_action, NULL); + sigaction(SIGTERM, &sigterm_old_action, NULL); +#endif /* HAVE_SIGACTION && HAVE_FORK */ +} + +void srunner_run(SRunner * sr, const char *sname, const char *tcname, + enum print_output print_mode) +{ + srunner_run_tagged(sr, sname, tcname, NULL, NULL, print_mode); +} + +pid_t check_fork(void) +{ +#if defined(HAVE_FORK) && HAVE_FORK==1 + pid_t pid = fork(); + + /* Set the process to a process group to be able to kill it easily. */ + if(pid >= 0) + { + setpgid(pid, group_pid); + } + return pid; +#else /* HAVE_FORK */ + /* Ignoring, as Check is not compiled with fork support. */ + return -1; +#endif /* HAVE_FORK */ +} + +void check_waitpid_and_exit(pid_t pid CK_ATTRIBUTE_UNUSED) +{ +#if defined(HAVE_FORK) && HAVE_FORK==1 + 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 /* HAVE_FORK */ + /* Ignoring, as Check is not compiled with fork support. */ + exit(EXIT_FAILURE); +#endif /* HAVE_FORK */ +} diff --git a/src/check_str.c b/src/check_str.c new file mode 100644 index 0000000..2ae093f --- /dev/null +++ b/src/check_str.c @@ -0,0 +1,130 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "../lib/libcompat.h" + +#include +#include + +#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_t size = 100; + char *p; + va_list ap; + + p = (char *)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 < (int)size) + return p; + + /* Else try again with more space. */ + if(n > -1) /* C99 conform vsnprintf() */ + size = (size_t) n + 1; /* precisely what is needed */ + else /* glibc 2.0 */ + size *= 2; /* twice the old size */ + + p = (char *)erealloc(p, size); + } +} + +static const char *tr_type_str(TestResult * tr) +{ + if(tr->ctx == CK_CTX_TEST) + { + if(tr->rtype == CK_PASS) + return "P"; + if(tr->rtype == CK_FAILURE) + return "F"; + if(tr->rtype == CK_ERROR) + return "E"; + return NULL; + } + return "S"; +} + +static int percent_passed(TestStats * t) +{ + if(t->n_failed == 0 && t->n_errors == 0) + return 100; + if(t->n_checked == 0) + return 0; + 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..b26eae2 --- /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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, 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 */ diff --git a/tests/.cvsignore b/tests/.cvsignore new file mode 100644 index 0000000..430904f --- /dev/null +++ b/tests/.cvsignore @@ -0,0 +1,8 @@ +.deps +Makefile +Makefile.in +check_check +check_stress +ex_log_output +ex_output +test.log diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..b3d7ab7 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,91 @@ +# +# Check: a unit test framework for C +# +# Copyright (C) 2011 Mateusz Loskot +# 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_directories(${CMAKE_CURRENT_SOURCE_DIR}/../src) +# Enable finding check.h +include_directories(${CMAKE_CURRENT_BINARY_DIR}/../src) + +# For the test_vars.in script, to give the unit test shell script +# runners the location of the source files +set(srcdir "${CMAKE_CURRENT_SOURCE_DIR}") + +if(WIN32) + # CMake uses Unix slashes for everything, but the tests that + # read srcdir expect platform specific slashes. There are two + # slashes because the shell scripts will consume srcdir. + string(REPLACE "/" "\\\\" srcdir "${srcdir}") + set(EXEEXT ".exe") + set(IS_MSVC "1") +endif(WIN32) + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test_vars.in + ${CMAKE_CURRENT_BINARY_DIR}/test_vars) + +include(CTest) + +set(CHECK_CHECK_SOURCES + check_check_exit.c + check_check_fixture.c + check_check_fork.c + check_check_limit.c + check_check_log.c + check_check_log_internal.c + check_check_main.c + check_check_master.c + check_check_msg.c + check_check_pack.c + check_check_selective.c + check_check_sub.c + check_check_tags.c + check_list.c) +set(CHECK_CHECK_HEADERS check_check.h) +add_executable(check_check ${CHECK_CHECK_HEADERS} ${CHECK_CHECK_SOURCES}) +target_link_libraries(check_check check compat) + +set(CHECK_CHECK_EXPORT_SOURCES + check_check_sub.c + check_check_master.c + check_check_log.c + check_check_fork.c + check_check_export_main.c +) +set(CHECK_CHECK_EXPORT_HEADERS check_check.h) +add_executable(check_check_export + ${CHECK_CHECK_EXPORT_HEADERS} + ${CHECK_CHECK_EXPORT_SOURCES}) +target_link_libraries(check_check_export check compat) + +set(EX_OUTPUT_SOURCES ex_output.c) +add_executable(ex_output ${EX_OUTPUT_SOURCES}) +target_link_libraries(ex_output check compat) + +set(CHECK_NOFORK_SOURCES check_nofork.c) +add_executable(check_nofork ${CHECK_NOFORK_SOURCES}) +target_link_libraries(check_nofork check compat) + +set(CHECK_NOFORK_TEARDOWN_SOURCES check_nofork_teardown.c) +add_executable(check_nofork_teardown ${CHECK_NOFORK_TEARDOWN_SOURCES}) +target_link_libraries(check_nofork_teardown check compat) + +set(CHECK_SET_MAX_MSG_SIZE_SOURCES check_set_max_msg_size.c) +add_executable(check_set_max_msg_size ${CHECK_SET_MAX_MSG_SIZE_SOURCES}) +target_link_libraries(check_set_max_msg_size check compat) diff --git a/tests/Makefile.am b/tests/Makefile.am new file mode 100644 index 0000000..4616288 --- /dev/null +++ b/tests/Makefile.am @@ -0,0 +1,102 @@ +## Process this file with automake to produce Makefile.in + +TESTS = \ + check_check_export \ + check_check \ + test_output.sh \ + test_check_nofork.sh \ + test_check_nofork_teardown.sh \ + test_xml_output.sh \ + test_log_output.sh \ + test_set_max_msg_size.sh \ + test_tap_output.sh + +# check_thread_stress is kind of slow. +# add this line back to TESTS to enable check_thread_stress +# check_thread_stress \ +# +# uncomment if check_thread_stress enabled +# XFAIL_TESTS = \ +# check_thread_stress + +noinst_PROGRAMS = \ + check_check_export \ + check_check \ + check_stress \ + check_thread_stress \ + check_nofork \ + check_nofork_teardown \ + check_mem_leaks \ + check_set_max_msg_size \ + ex_output + +EXTRA_DIST = test_output.sh test_check_nofork.sh test_check_nofork_teardown.sh test_log_output.sh test_vars.in test_xml_output.sh test_tap_output.sh test_mem_leaks.sh test_output_strings test_set_max_msg_size.sh + +if NO_TIMEOUT_TESTS +check_check_CFLAGS = -DTIMEOUT_TESTS_ENABLED=0 +check_check_export_CFLAGS = -DTIMEOUT_TESTS_ENABLED=0 +endif + +check_check_export_SOURCES = \ + check_check.h \ + check_check_sub.c \ + check_check_master.c \ + check_check_log.c \ + check_check_fork.c \ + check_check_tags.c \ + check_check_export_main.c +check_check_export_LDADD = $(top_builddir)/src/libcheck.la $(top_builddir)/lib/libcompat.la + +check_check_SOURCES = \ + check_check.h \ + check_list.c \ + check_check_sub.c \ + check_check_master.c \ + check_check_msg.c \ + check_check_log.c \ + check_check_log_internal.c \ + check_check_limit.c \ + check_check_fork.c \ + check_check_fixture.c \ + check_check_pack.c \ + check_check_exit.c \ + check_check_selective.c \ + check_check_tags.c \ + check_check_main.c +check_check_LDADD = $(top_builddir)/src/libcheckinternal.la $(top_builddir)/lib/libcompat.la + +check_mem_leaks_SOURCES = \ + check_mem_leaks.c \ + check_check_log.c \ + check_check_fork.c \ + check_check_exit.c \ + check_check_selective.c \ + check_check_tags.c \ + check_check_sub.c \ + check_check_master.c +check_mem_leaks_LDADD = $(top_builddir)/src/libcheck.la $(top_builddir)/lib/libcompat.la +check_mem_leaks_CFLAGS = -DTIMEOUT_TESTS_ENABLED=0 -DMEMORY_LEAKING_TESTS_ENABLED=0 + +check_set_max_msg_size_SOURCES = \ + check_set_max_msg_size.c +check_set_max_msg_size_LDADD = $(top_builddir)/src/libcheck.la $(top_builddir)/lib/libcompat.la + +check_stress_SOURCES = check_stress.c +check_stress_LDADD = $(top_builddir)/src/libcheck.la $(top_builddir)/lib/libcompat.la + +check_thread_stress_SOURCES = check_thread_stress.c +check_thread_stress_LDADD = $(top_builddir)/src/libcheck.la $(top_builddir)/lib/libcompat.la @PTHREAD_LIBS@ +check_thread_stress_CFLAGS = @PTHREAD_CFLAGS@ + +check_nofork_SOURCES = check_nofork.c +check_nofork_LDADD = $(top_builddir)/src/libcheck.la $(top_builddir)/lib/libcompat.la + +check_nofork_teardown_SOURCES = check_nofork_teardown.c +check_nofork_teardown_LDADD = $(top_builddir)/src/libcheck.la $(top_builddir)/lib/libcompat.la + +ex_output_SOURCES = ex_output.c +ex_output_LDADD = $(top_builddir)/src/libcheck.la $(top_builddir)/lib/libcompat.la + +AM_CPPFLAGS = -I$(top_builddir)/src -I$(top_srcdir)/src + +CLEANFILES = *~ *.log *.xml *.tap test_logfile diff --git a/tests/check_check.h b/tests/check_check.h new file mode 100644 index 0000000..32e49bc --- /dev/null +++ b/tests/check_check.h @@ -0,0 +1,101 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef CHECK_CHECK_H +#define CHECK_CHECK_H + +#ifndef TIMEOUT_TESTS_ENABLED +#define TIMEOUT_TESTS_ENABLED 1 +#endif + +/* + * Certain unit tests are known to leak memory. This + * #define will prevent those unit tests from being built + * if the program is to be used against valgrind. + */ +#ifndef MEMORY_LEAKING_TESTS_ENABLED +#define MEMORY_LEAKING_TESTS_ENABLED 1 +#endif + +extern int sub_ntests; + +void fork_setup (void); +void fork_teardown (void); +void setup_fixture(void); +void teardown_fixture (void); +void setup (void); +void cleanup (void); +Suite *make_sub_suite(void); +Suite *make_sub2_suite(void); +Suite *make_master_suite(void); +Suite *make_list_suite(void); +Suite *make_msg_suite(void); +Suite *make_log_suite(void); +Suite *make_log_internal_suite(void); +Suite *make_limit_suite(void); +Suite *make_fork_suite(void); +Suite *make_fixture_suite(void); +Suite *make_pack_suite(void); +Suite *make_exit_suite(void); +Suite *make_selective_suite(void); +Suite *make_tag_suite(void); + +extern int master_tests_lineno[]; +void init_master_tests_lineno(int num_master_tests); + +/** + * Record a test name. + * + * This is used to record the test names of each test in + * check_check_sub.c. This allows the test name to be written + * in the master_tests table in check_check_master.c and have + * it verified at test time. With this data, one can easily + * determine the name of a failed test. + */ +void record_test_name(const char* test_name); + +/** + * Retrieve the next recorded test which was run, or + * NULL if no further tests are recorded. + */ +char* get_next_test_name(FILE * file); + +/** + * Record a line number for a test which is to fail. + * + * This is used to record the failure line numbers for + * all tests in check_check_sub.c. Simply make this + * call right before an assert to record the proper + * line number. The line number is adjusted +1 internally, + * to account for making this call before the failure. + */ +void record_failure_line_num(const int line); + +/** + * Once the failure file numbers have been recorded + * to file and the file has been rewind(), this + * call will extract the next line number from the + * file. + * + * If there are no more lines to read, -1 is returned. + */ +int get_next_failure_line_num(FILE * file); + +#endif /* CHECK_CHECK_H */ diff --git a/tests/check_check_exit.c b/tests/check_check_exit.c new file mode 100644 index 0000000..9ada4eb --- /dev/null +++ b/tests/check_check_exit.c @@ -0,0 +1,81 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "../lib/libcompat.h" + +#include +#include +#include +#include + +#include "check.h" +#include "check_check.h" + +START_TEST(test_early_exit_normal) +{ + exit(0); + ck_abort_msg("Should've exitted..."); +} +END_TEST + +START_TEST(test_early_exit_with_allowed_error) +{ + exit(-1); + ck_abort_msg("Should've exitted..."); +} +END_TEST + +START_TEST(loop_early_exit_normal) +{ + exit(0); + ck_abort_msg("Should've exitted..."); +} +END_TEST + +START_TEST(loop_early_exit_allowed_exit) +{ + exit(-2); + ck_abort_msg("Should've exitted..."); +} +END_TEST + +START_TEST(loop_early_exit_signal_segv) +{ + raise (SIGSEGV); + ck_abort_msg("Should've exitted..."); +} +END_TEST + +Suite *make_exit_suite(void) +{ + Suite *s; + TCase *tc; + + s = suite_create("Exit"); + tc = tcase_create("Core"); + + suite_add_tcase (s, tc); + tcase_add_test(tc,test_early_exit_normal); + tcase_add_exit_test(tc,test_early_exit_with_allowed_error,-1); + tcase_add_loop_test(tc,loop_early_exit_normal,0,5); + tcase_add_loop_exit_test(tc,loop_early_exit_allowed_exit,-2,0,5); + tcase_add_loop_test_raise_signal(tc, loop_early_exit_signal_segv, SIGSEGV, 0, 5); + return s; +} diff --git a/tests/check_check_export_main.c b/tests/check_check_export_main.c new file mode 100644 index 0000000..0d03581 --- /dev/null +++ b/tests/check_check_export_main.c @@ -0,0 +1,46 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "../lib/libcompat.h" + +#include +#include +#include +#include "check_check.h" + +int main (void) +{ + int n; + SRunner *sr; + + fork_setup(); + setup(); + sr = srunner_create (make_master_suite()); + srunner_add_suite(sr, make_log_suite()); + srunner_add_suite(sr, make_fork_suite()); + + printf ("Ran %d tests in subordinate suite\n", sub_ntests); + srunner_run_all (sr, CK_VERBOSE); + cleanup(); + fork_teardown(); + n = srunner_ntests_failed(sr); + srunner_free(sr); + return (n == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/tests/check_check_fixture.c b/tests/check_check_fixture.c new file mode 100644 index 0000000..a82dd01 --- /dev/null +++ b/tests/check_check_fixture.c @@ -0,0 +1,658 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "../lib/libcompat.h" + +#include +#include +#include +#include +#include +#include "check_error.h" +#include "check_str.h" +#include "check_check.h" + +static char errm[200]; + +static void fixture_sub_setup (void) +{ + ck_abort_msg("Test failure in fixture"); +} + +static SRunner *fixture_sr; + +void setup_fixture (void) +{ + TCase *tc; + Suite *fixture_s; + + fixture_s = suite_create("Fix Sub"); + tc = tcase_create("Fix Sub"); + tcase_add_unchecked_fixture(tc, fixture_sub_setup, NULL); + suite_add_tcase (fixture_s, tc); + fixture_sr = srunner_create(fixture_s); + srunner_run_all(fixture_sr,CK_VERBOSE); +} + +void teardown_fixture (void) +{ + srunner_free(fixture_sr); +} + +START_TEST(test_fixture_fail_counts) +{ + int nrun, nfail; + + nrun = srunner_ntests_run(fixture_sr); + nfail = srunner_ntests_failed(fixture_sr); + + ck_assert_msg (nrun == 1 && nfail == 1, + "Counts for run and fail for fixture failure not correct"); +} +END_TEST + +START_TEST(test_print_counts) +{ + char *srstat = sr_stat_str(fixture_sr); + const char *exp = "0%: Checks: 1, Failures: 1, Errors: 0"; + + ck_assert_msg(strcmp(srstat, exp) == 0, + "SRunner stat string incorrect with setup failure"); + free(srstat); +} +END_TEST + +START_TEST(test_setup_failure_msg) +{ + TestResult **tra; + char *trm; + const char *trmexp = "check_check_fixture.c:36:S:Fix Sub:unchecked_setup:0: Test failure in fixture"; + + tra = srunner_failures(fixture_sr); + trm = tr_str(tra[0]); + free(tra); + + if (strstr(trm, trmexp) == 0) { + snprintf(errm, sizeof(errm), + "Bad setup tr msg (%s)", trm); + + ck_abort_msg (errm); + } + free(trm); +} +END_TEST + +#if defined(HAVE_FORK) && HAVE_FORK==1 +int testval_up; +int testval_down; + +static void sub_ch_setup_norm (void) +{ + testval_up += 2; +} + +static void sub_ch_teardown_norm(void) +{ + testval_down += 2; +} + +START_TEST(test_sub_ch_setup_norm) +{ + if (testval_up == 1) + ck_abort_msg("Setup not run correctly"); + else if (testval_up > 3) + ck_abort_msg("Test side-effects persist across runs"); + testval_up++; +} +END_TEST + +START_TEST(test_ch_setup) +{ + TCase *tc; + Suite *s; + SRunner *sr; + + s = suite_create("Fixture Norm Sub"); + tc = tcase_create("Fixture Norm Sub"); + sr = srunner_create(s); + suite_add_tcase(s, tc); + tcase_add_test(tc,test_sub_ch_setup_norm); + tcase_add_test(tc,test_sub_ch_setup_norm); + tcase_add_checked_fixture(tc,sub_ch_setup_norm,sub_ch_teardown_norm); + srunner_run_all(sr, CK_VERBOSE); + + ck_assert_msg(srunner_ntests_failed(sr) == 0, + "Checked setup not being run correctly"); + + srunner_free(sr); +} +END_TEST + +static void setup_sub_fail (void) +{ + ck_abort_msg("Failed setup"); /* check_check_fixture.c:130 */ +} + +static void teardown_sub_fail (void) +{ + ck_abort_msg("Failed teardown"); +} + +static void setup_sub_signal (void) +{ + mark_point(); + raise(SIGFPE); +} + +static void teardown_sub_signal(void) +{ + mark_point(); + raise(SIGFPE); +} + +START_TEST(test_sub_fail) +{ + ck_abort_msg("Should never run"); +} +END_TEST + +START_TEST(test_sub_pass) +{ + ck_assert_msg(1 == 1, "Always pass"); +} +END_TEST + +START_TEST(test_ch_setup_fail) +{ + TCase *tc; + Suite *s; + SRunner *sr; + TestResult ** tr; + char *strstat; + char *trm; + + s = suite_create("Setup Fail"); + tc = tcase_create("Setup Fail"); + suite_add_tcase(s, tc); + tcase_add_test(tc,test_sub_fail); + tcase_add_checked_fixture(tc,setup_sub_fail, NULL); + sr = srunner_create(s); + srunner_run_all(sr,CK_VERBOSE); + + ck_assert_msg (srunner_ntests_run(sr) == 1, + "Test run counts not correct for checked setup failure"); + ck_assert_msg (srunner_ntests_failed(sr) == 1, + "Failure counts not correct for checked setup failure"); + + strstat= sr_stat_str(sr); + + ck_assert_msg(strcmp(strstat, + "0%: Checks: 1, Failures: 1, Errors: 0") == 0, + "SRunner stat string incorrect with checked setup failure"); + free(strstat); + + tr = srunner_failures(sr); + trm = tr_str(tr[0]); + /* Search for check_check_fixture.c:150 if this fails. */ + if (strstr(trm, + "check_check_fixture.c:150:S:Setup Fail:test_sub_fail:0: Failed setup") + == 0) { + snprintf(errm, sizeof(errm), + "Bad failed checked setup tr msg (%s)", trm); + + ck_abort_msg (errm); + } + free(trm); + free(tr); +} +END_TEST + +START_TEST(test_ch_setup_fail_nofork) +{ + TCase *tc; + Suite *s; + SRunner *sr; + + s = suite_create("Setup Fail Nofork"); + tc = tcase_create("Setup Fail Nofork"); + suite_add_tcase(s, tc); + tcase_add_test(tc, test_sub_fail); + tcase_add_checked_fixture(tc, setup_sub_fail, NULL); + sr = srunner_create(s); + srunner_set_fork_status(sr, CK_NOFORK); + srunner_run_all(sr, CK_VERBOSE); + + ck_assert_msg (srunner_ntests_run(sr) == 1, + "Test run counts not correct for checked setup failure"); + ck_assert_msg (srunner_ntests_failed(sr) == 1, + "Failure counts not correct for checked setup failure"); + srunner_free(sr); +} +END_TEST + +START_TEST(test_ch_setup_fail_nofork_2) +{ + TCase *tc; + Suite *s; + SRunner *sr; + + s = suite_create("Setup Fail Nofork 2"); + tc = tcase_create("Setup Fail Nofork 2"); + suite_add_tcase(s, tc); + tcase_add_test(tc, test_sub_fail); + tcase_add_checked_fixture(tc, sub_ch_setup_norm, NULL); + tcase_add_checked_fixture(tc, setup_sub_fail, NULL); + sr = srunner_create(s); + srunner_set_fork_status(sr, CK_NOFORK); + srunner_run_all(sr, CK_VERBOSE); + + ck_assert_msg (srunner_ntests_run(sr) == 1, + "Test run counts not correct for checked setup failure"); + ck_assert_msg (srunner_ntests_failed(sr) == 1, + "Failure counts not correct for checked setup failure"); + srunner_free(sr); +} +END_TEST + +START_TEST(test_ch_setup_pass_nofork) +{ + TCase *tc; + Suite *s; + SRunner *sr; + + s = suite_create("Setup Pass Multiple fixtures"); + tc = tcase_create("Setup Pass Multiple fixtures"); + suite_add_tcase(s, tc); + tcase_add_test(tc, test_sub_pass); + tcase_add_checked_fixture(tc, sub_ch_setup_norm, sub_ch_teardown_norm); + tcase_add_checked_fixture(tc, sub_ch_setup_norm, sub_ch_teardown_norm); + tcase_add_checked_fixture(tc, sub_ch_setup_norm, sub_ch_teardown_norm); + sr = srunner_create(s); + srunner_set_fork_status(sr, CK_NOFORK); + testval_up = 1; + testval_down = 1; + srunner_run_all(sr, CK_VERBOSE); + ck_assert_msg(testval_up == 7, "Multiple setups failed"); + ck_assert_msg(testval_down == 7, "Multiple teardowns failed"); + + ck_assert_msg (srunner_ntests_run(sr) == 1, + "Test run counts not correct for checked setup failure"); + ck_assert_msg (srunner_ntests_failed(sr) == 0, + "Failure counts not correct for checked setup failure"); + srunner_free(sr); +} +END_TEST + +/* This test currently does not work on Cygwin, as it results in a + * SIGSEGV instead of a SIGFPE. However, a simple program that installs + * a SIGFPE handler then raise(SIGFPE) works as expected. Further + * investigation is necessary. */ +#if !defined(__CYGWIN__) +/* + * This test will fail without fork, as it results in a checked + * fixture raising a signal, which terminates the test runner early. + */ +START_TEST(test_ch_setup_sig) +{ + TCase *tc; + Suite *s; + SRunner *sr; + TestResult **tr; + char *strstat; + char *trm; + + s = suite_create("Setup Sig"); + tc = tcase_create("Setup Sig"); + suite_add_tcase(s, tc); + tcase_add_test(tc,test_sub_fail); + tcase_add_checked_fixture(tc,setup_sub_signal, NULL); + sr = srunner_create(s); + srunner_run_all(sr,CK_VERBOSE); + + ck_assert_msg (srunner_ntests_failed(sr) == 1, + "Failure counts not correct for checked setup signal"); + ck_assert_msg (srunner_ntests_run(sr) == 1, + "Test run counts not correct for checked setup signal"); + + strstat= sr_stat_str(sr); + + ck_assert_msg(strcmp(strstat, + "0%: Checks: 1, Failures: 0, Errors: 1") == 0, + "SRunner stat string incorrect with checked setup signal"); + free(strstat); + + tr = srunner_failures(sr); + trm = tr_str(tr[0]); + + if (strstr(trm, + "check_check_fixture.c:160:S:Setup Sig:test_sub_fail:0: " + "(after this point) Received signal 8") + == 0) { + snprintf(errm, sizeof(errm), + "Msg was (%s)", trm); + + ck_abort_msg (errm); + } + free(trm); + srunner_free(sr); + free(tr); +} +END_TEST +#endif /* !defined(__CYGWIN__) */ + +static void sub_ch_setup_dual_1(void) +{ + ck_assert_msg(testval_up == 1, "Wrong start value"); + testval_up += 2; +} + +static void sub_ch_setup_dual_2(void) +{ + ck_assert_msg(testval_up == 3, "First setup failed"); + testval_up += 3; +} + +START_TEST(test_sub_two_setups) +{ + ck_assert_msg(testval_up == 6, "Multiple setups failed"); +} +END_TEST + +/* + * This test will not work without fork, as checked fixtures are + * not supported + */ +START_TEST(test_ch_setup_two_setups_fork) +{ + TCase *tc; + Suite *s; + SRunner *sr; + + s = suite_create("Fixture Two setups"); + tc = tcase_create("Fixture Two setups"); + sr = srunner_create(s); + suite_add_tcase(s, tc); + tcase_add_test(tc,test_sub_two_setups); + tcase_add_checked_fixture(tc,sub_ch_setup_dual_1,NULL); + tcase_add_checked_fixture(tc,sub_ch_setup_dual_2,NULL); + testval_up = 1; + srunner_run_all(sr, CK_VERBOSE); + + ck_assert_msg(srunner_ntests_failed(sr) == 0, + "Problem with several setups"); + + srunner_free(sr); +} +END_TEST + +START_TEST(test_ch_teardown_fail) +{ + TCase *tc; + Suite *s; + SRunner *sr; + TestResult **tr; + char *strstat; + char *trm; + + s = suite_create("Teardown Fail"); + tc = tcase_create("Teardown Fail"); + suite_add_tcase(s, tc); + tcase_add_test(tc,test_sub_pass); + tcase_add_checked_fixture(tc,NULL, teardown_sub_fail); + sr = srunner_create(s); + srunner_run_all(sr,CK_VERBOSE); + + ck_assert_msg (srunner_ntests_failed(sr) == 1, + "Failure counts not correct for checked teardown failure"); + ck_assert_msg (srunner_ntests_run(sr) == 1, + "Test run counts not correct for checked teardown failure"); + + strstat= sr_stat_str(sr); + + ck_assert_msg(strcmp(strstat, + "0%: Checks: 1, Failures: 1, Errors: 0") == 0, + "SRunner stat string incorrect with checked setup failure"); + free(strstat); + + tr = srunner_failures(sr); + trm = tr_str(tr[0]); + + if (strstr(trm, + "check_check_fixture.c:155:S:Teardown Fail:test_sub_pass:0: Failed teardown") + == 0) { + snprintf(errm, sizeof(errm), + "Bad failed checked teardown tr msg (%s)", trm); + + ck_abort_msg (errm); + } + free(trm); + free(tr); +} +END_TEST + +START_TEST(test_ch_teardown_fail_nofork) +{ + TCase *tc; + Suite *s; + SRunner *sr; + TestResult **tr; + char *strstat; + char *trm; + + s = suite_create("Teardown Fail No Fork"); + tc = tcase_create("Teardown Fail No Fork"); + suite_add_tcase(s, tc); + tcase_add_test(tc,test_sub_pass); + tcase_add_checked_fixture(tc,NULL, teardown_sub_fail); + sr = srunner_create(s); + srunner_set_fork_status(sr, CK_NOFORK); + srunner_run_all(sr,CK_VERBOSE); + + ck_assert_msg (srunner_ntests_failed(sr) == 1, + "Failure counts not correct for checked teardown failure"); + ck_assert_msg (srunner_ntests_run(sr) == 1, + "Test run counts not correct for checked teardown failure"); + + strstat= sr_stat_str(sr); + + ck_assert_msg(strcmp(strstat, + "0%: Checks: 1, Failures: 1, Errors: 0") == 0, + "SRunner stat string incorrect with checked setup failure"); + free(strstat); + + tr = srunner_failures(sr); + trm = tr_str(tr[0]); + + if (strstr(trm, + "check_check_fixture.c:155:S:Teardown Fail No Fork:test_sub_pass:0: Failed teardown") + == 0) { + snprintf(errm, sizeof(errm), + "Bad failed checked teardown tr msg (%s)", trm); + + ck_abort_msg (errm); + } + free(trm); + free(tr); +} +END_TEST + +/* This test currently does not work on Cygwin, as it results in a + * SIGSEGV instead of a SIGFPE. However, a simple program that installs + * a SIGFPE handler then raise(SIGFPE) works as expected. Further + * investigation is necessary. */ +#if !defined(__CYGWIN__) +/* + * This test will fail without fork, as it results in a checked + * fixture raising a signal, which terminates the test runner early. + */ + +START_TEST(test_ch_teardown_sig) +{ + TCase *tc; + Suite *s; + SRunner *sr; + TestResult **tr; + char *strstat; + char *trm; + + s = suite_create("Teardown Sig"); + tc = tcase_create("Teardown Sig"); + suite_add_tcase(s, tc); + tcase_add_test(tc,test_sub_pass); + tcase_add_checked_fixture(tc,NULL, teardown_sub_signal); + sr = srunner_create(s); + srunner_run_all(sr,CK_VERBOSE); + + ck_assert_msg (srunner_ntests_failed(sr) == 1, + "Failure counts not correct for checked teardown signal"); + ck_assert_msg (srunner_ntests_run(sr) == 1, + "Test run counts not correct for checked teardown signal"); + + strstat= sr_stat_str(sr); + + ck_assert_msg(strcmp(strstat, + "0%: Checks: 1, Failures: 0, Errors: 1") == 0, + "SRunner stat string incorrect with checked teardown signal"); + free(strstat); + + tr = srunner_failures(sr); + trm = tr_str(tr[0]); + + if (strstr(trm, + "check_check_fixture.c:166:S:Teardown Sig:test_sub_pass:0: " + "(after this point) Received signal 8") + == 0) { + snprintf(errm, sizeof(errm), + "Bad msg (%s)", trm); + + ck_abort_msg (errm); + } + free(trm); + srunner_free(sr); + free(tr); +} +END_TEST +#endif /* !defined(__CYGWIN__) */ + +/* Teardowns are run in reverse order */ +static void sub_ch_teardown_dual_1(void) +{ + ck_assert_msg(testval_down == 6, "Second teardown failed"); +} + +static void sub_ch_teardown_dual_2(void) +{ + ck_assert_msg(testval_down == 3, "First teardown failed"); + testval_down += 3; +} + +START_TEST(test_sub_two_teardowns) +{ + testval_down += 2; +} +END_TEST + +/* + * This test will not work without fork, as checked fixtures are + * not supported + */ +START_TEST(test_ch_teardown_two_teardowns_fork) +{ + TCase *tc; + Suite *s; + SRunner *sr; + int nr_of_failures; + char errm[1024] = {0}; + + s = suite_create("Fixture Two teardowns"); + tc = tcase_create("Fixture Two teardowns"); + sr = srunner_create(s); + suite_add_tcase(s, tc); + tcase_add_test(tc,test_sub_two_teardowns); + tcase_add_checked_fixture(tc,NULL,sub_ch_teardown_dual_1); + tcase_add_checked_fixture(tc,NULL,sub_ch_teardown_dual_2); + testval_down = 1; + srunner_run_all(sr, CK_VERBOSE); + + nr_of_failures = srunner_ntests_failed(sr); + if (nr_of_failures > 0) { + TestResult **tra = srunner_failures(sr); + int i; + + for (i = 0; i < nr_of_failures; i++) { + char *trm = tr_str(tra[i]); + if (strlen(errm) + strlen(trm) > 1022) { + free(trm); + break; + } + strcat(errm, trm); + strcat(errm, "\n"); + free(trm); + } + free(tra); + } + ck_assert_msg(nr_of_failures == 0, "Problem with several teardowns\n %s", + errm); + + srunner_free(sr); +} +END_TEST +#endif /* HAVE_FORK */ + +Suite *make_fixture_suite (void) +{ + + Suite *s; + TCase *tc; + + s = suite_create("Fixture"); + tc = tcase_create("Core"); + + suite_add_tcase (s, tc); + tcase_add_test(tc,test_fixture_fail_counts); + tcase_add_test(tc,test_print_counts); + tcase_add_test(tc,test_setup_failure_msg); + +#if defined(HAVE_FORK) && HAVE_FORK==1 + /* + * This test assumes that CK_FORK is being used, + * as it tests that side effects from checked + * fixtures do not persist between tests. + */ + tcase_add_test(tc,test_ch_setup); + + tcase_add_test(tc,test_ch_setup_fail); + tcase_add_test(tc,test_ch_setup_fail_nofork); + tcase_add_test(tc,test_ch_setup_fail_nofork_2); + tcase_add_test(tc,test_ch_setup_pass_nofork); +#if !defined(__CYGWIN__) + tcase_add_test(tc,test_ch_setup_sig); +#endif /* !defined(__CYGWIN__) */ + tcase_add_test(tc,test_ch_setup_two_setups_fork); + tcase_add_test(tc,test_ch_teardown_fail); + tcase_add_test(tc,test_ch_teardown_fail_nofork); +#if !defined(__CYGWIN__) + tcase_add_test(tc,test_ch_teardown_sig); +#endif /* !defined(__CYGWIN__) */ + tcase_add_test(tc,test_ch_teardown_two_teardowns_fork); +#endif + + return s; +} diff --git a/tests/check_check_fork.c b/tests/check_check_fork.c new file mode 100644 index 0000000..7961646 --- /dev/null +++ b/tests/check_check_fork.c @@ -0,0 +1,172 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "../lib/libcompat.h" + +#include +#include +#include +#include "check_check.h" + + +static int counter; +static pid_t mypid; + +static void fork_sub_setup (void) +{ + counter = 0; + mypid = getpid(); +} + +START_TEST(test_inc) +{ + counter++; +} +END_TEST + +START_TEST(test_nofork_sideeffects) +{ + ck_assert_msg(counter == 1, + "Side effects not seen across tests"); +} +END_TEST + +START_TEST(test_nofork_pid) +{ + ck_assert_msg(mypid == getpid(), + "Unit test is in a different adresss space from setup code"); +} +END_TEST + +static Suite *make_fork_sub_suite (void) +{ + + Suite *s; + TCase *tc; + + s = suite_create("Fork Sub"); + tc = tcase_create("Core"); + + suite_add_tcase (s, tc); + tcase_add_unchecked_fixture(tc, fork_sub_setup,NULL); + tcase_add_test(tc,test_inc); + tcase_add_test(tc,test_nofork_sideeffects); + tcase_add_test(tc,test_nofork_pid); + + return s; +} + +static SRunner *fork_sr; +static SRunner *fork_dummy_sr; + +void fork_setup (void) +{ + fork_sr = srunner_create(make_fork_sub_suite()); + fork_dummy_sr = srunner_create (make_fork_sub_suite()); + srunner_set_fork_status(fork_sr,CK_NOFORK); + srunner_run_all(fork_sr,CK_VERBOSE); +} + +void fork_teardown (void) +{ + srunner_free(fork_sr); +} + +START_TEST(test_default_fork) +{ +#if defined(HAVE_FORK) && HAVE_FORK == 1 + ck_assert_msg(srunner_fork_status(fork_dummy_sr) == CK_FORK, + "Default fork status not set correctly"); +#else + ck_assert_msg(srunner_fork_status(fork_dummy_sr) == CK_NOFORK, + "Default fork status not set correctly"); +#endif /* HAVE_FORK */ +} +END_TEST + +START_TEST(test_set_nofork) +{ + srunner_set_fork_status(fork_dummy_sr, CK_NOFORK); + ck_assert_msg(srunner_fork_status(fork_dummy_sr) == CK_NOFORK, + "Fork status not changed correctly"); +} +END_TEST + +/* + * The following tests will fail if fork is unavailable, as + * attempting to set the fork mode as anything but + * CK_NOFORK is considered an error. + */ +#if defined(HAVE_FORK) && HAVE_FORK==1 +START_TEST(test_set_fork) +{ + srunner_set_fork_status(fork_dummy_sr, CK_FORK); + ck_assert_msg(srunner_fork_status(fork_dummy_sr) == CK_FORK, + "Fork status not changed correctly"); +} +END_TEST + +START_TEST(test_env) +{ + char envvar[] = "CK_FORK=no"; + putenv(envvar); + ck_assert_msg(srunner_fork_status(fork_dummy_sr) == CK_NOFORK, + "Fork status does not obey environment variable"); +} +END_TEST + +START_TEST(test_env_and_set) +{ + char envvar[] = "CK_FORK=no"; + putenv(envvar); + srunner_set_fork_status(fork_dummy_sr, CK_FORK); + ck_assert_msg(srunner_fork_status(fork_dummy_sr) == CK_FORK, + "Explicit setting of fork status should override env"); +} +END_TEST +#endif /* HAVE_FORK */ + +START_TEST(test_nofork) +{ + ck_assert_msg(srunner_ntests_failed(fork_sr) == 0, + "Errors on nofork test"); +} +END_TEST + +Suite *make_fork_suite(void) +{ + Suite *s; + TCase *tc; + + s = suite_create("Fork"); + tc = tcase_create("Core"); + + suite_add_tcase(s, tc); + tcase_add_test(tc,test_default_fork); + tcase_add_test(tc,test_set_nofork); +#if defined(HAVE_FORK) && HAVE_FORK==1 + tcase_add_test(tc,test_set_fork); + tcase_add_test(tc,test_env); + tcase_add_test(tc,test_env_and_set); +#endif /* HAVE_FORK */ + tcase_add_test(tc,test_nofork); + + return s; +} diff --git a/tests/check_check_limit.c b/tests/check_check_limit.c new file mode 100644 index 0000000..2f38c4a --- /dev/null +++ b/tests/check_check_limit.c @@ -0,0 +1,65 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "../lib/libcompat.h" + +#include +#include +#include +#include "check_check.h" +#include "check_str.h" + + +static SRunner *sr; + +static void limit_setup (void) +{ + Suite *s = suite_create("Empty"); + sr = srunner_create(s); + srunner_run_all(sr, CK_VERBOSE); +} + +static void limit_teardown (void) +{ + srunner_free(sr); +} + +START_TEST(test_summary) +{ + char * string = sr_stat_str(sr); + ck_assert_msg(strcmp(string, + "100%: Checks: 0, Failures: 0, Errors: 0") == 0, + "Bad statistics string for empty suite"); + free(string); +} +END_TEST + +Suite *make_limit_suite (void) +{ + Suite *s = suite_create("Limit"); + TCase *tc = tcase_create("Empty"); + + tcase_add_test(tc,test_summary); + tcase_add_unchecked_fixture(tc,limit_setup,limit_teardown); + + suite_add_tcase(s, tc); + + return s; +} diff --git a/tests/check_check_log.c b/tests/check_check_log.c new file mode 100644 index 0000000..ee36fde --- /dev/null +++ b/tests/check_check_log.c @@ -0,0 +1,315 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "../lib/libcompat.h" + +#include +#include +#include +#include +#include "check_check.h" + +#if HAVE_DECL_SETENV +/* save environment variable's value and set new value */ +static int save_set_env(const char *name, const char *value, + const char **old_value) +{ + *old_value = getenv(name); + return setenv(name, value, 1); +} + +/* restore environment variable's old value, handle cases where + variable must be unset (old value is NULL) */ +static int restore_env(const char *name, const char *old_value) +{ + int res; + if (old_value == NULL) { + res = unsetenv(name); + } else { + res = setenv(name, old_value, 1); + } + return res; +} +#endif /* HAVE_DECL_SETENV */ + +START_TEST(test_set_log) +{ + Suite *s = suite_create("Suite"); + SRunner *sr = srunner_create(s); + + srunner_set_log (sr, "test_log"); + + ck_assert_msg (srunner_has_log (sr), "SRunner not logging"); + ck_assert_msg (strcmp(srunner_log_fname(sr), "test_log") == 0, + "Bad file name returned"); + + srunner_free(sr); +} +END_TEST + +#if HAVE_DECL_SETENV +/* Test enabling logging via environment variable */ +START_TEST(test_set_log_env) +{ + const char *old_val; + Suite *s = suite_create("Suite"); + SRunner *sr = srunner_create(s); + + /* check that setting log file via environment variable works */ + ck_assert_msg(save_set_env("CK_LOG_FILE_NAME", "test_log", &old_val) == 0, + "Failed to set environment variable"); + + ck_assert_msg (srunner_has_log (sr), "SRunner not logging"); + ck_assert_msg (strcmp(srunner_log_fname(sr), "test_log") == 0, + "Bad file name returned"); + + /* check that explicit call to srunner_set_log() + overrides environment variable */ + srunner_set_log (sr, "test2_log"); + + ck_assert_msg (srunner_has_log (sr), "SRunner not logging"); + ck_assert_msg (strcmp(srunner_log_fname(sr), "test2_log") == 0, + "Bad file name returned"); + + /* restore old environment */ + ck_assert_msg(restore_env("CK_LOG_FILE_NAME", old_val) == 0, + "Failed to restore environment variable"); + + srunner_free(sr); +} +END_TEST +#endif /* HAVE_DECL_SETENV */ + +START_TEST(test_no_set_log) +{ + Suite *s = suite_create("Suite"); + SRunner *sr = srunner_create(s); + + ck_assert_msg (!srunner_has_log (sr), "SRunner not logging"); + ck_assert_msg (srunner_log_fname(sr) == NULL, "Bad file name returned"); + + srunner_free(sr); +} +END_TEST + +START_TEST(test_double_set_log) +{ + Suite *s = suite_create("Suite"); + SRunner *sr = srunner_create(s); + + srunner_set_log (sr, "test_log"); + srunner_set_log (sr, "test2_log"); + + ck_assert_msg(strcmp(srunner_log_fname(sr), "test_log") == 0, + "Log file is initialize only and shouldn't be changeable once set"); + + srunner_free(sr); +} +END_TEST + + +START_TEST(test_set_xml) +{ + Suite *s = suite_create("Suite"); + SRunner *sr = srunner_create(s); + + srunner_set_xml (sr, "test_log.xml"); + + ck_assert_msg (srunner_has_xml (sr), "SRunner not logging XML"); + ck_assert_msg (strcmp(srunner_xml_fname(sr), "test_log.xml") == 0, + "Bad file name returned"); + + srunner_free(sr); +} +END_TEST + +#if HAVE_DECL_SETENV +/* Test enabling XML logging via environment variable */ +START_TEST(test_set_xml_env) +{ + const char *old_val; + Suite *s = suite_create("Suite"); + SRunner *sr = srunner_create(s); + + /* check that setting XML log file via environment variable works */ + ck_assert_msg(save_set_env("CK_XML_LOG_FILE_NAME", "test_log.xml", &old_val) == 0, + "Failed to set environment variable"); + + ck_assert_msg (srunner_has_xml (sr), "SRunner not logging XML"); + ck_assert_msg (strcmp(srunner_xml_fname(sr), "test_log.xml") == 0, + "Bad file name returned"); + + /* check that explicit call to srunner_set_xml() + overrides environment variable */ + srunner_set_xml (sr, "test2_log.xml"); + + ck_assert_msg (srunner_has_xml (sr), "SRunner not logging XML"); + ck_assert_msg (strcmp(srunner_xml_fname(sr), "test2_log.xml") == 0, + "Bad file name returned"); + + /* restore old environment */ + ck_assert_msg(restore_env("CK_XML_LOG_FILE_NAME", old_val) == 0, + "Failed to restore environment variable"); + + srunner_free(sr); +} +END_TEST +#endif /* HAVE_DECL_SETENV */ + +START_TEST(test_no_set_xml) +{ + Suite *s = suite_create("Suite"); + SRunner *sr = srunner_create(s); + + ck_assert_msg (!srunner_has_xml (sr), "SRunner not logging XML"); + ck_assert_msg (srunner_xml_fname(sr) == NULL, "Bad file name returned"); + + srunner_free(sr); +} +END_TEST + +START_TEST(test_double_set_xml) +{ + Suite *s = suite_create("Suite"); + SRunner *sr = srunner_create(s); + + srunner_set_xml (sr, "test_log.xml"); + srunner_set_xml (sr, "test2_log.xml"); + + ck_assert_msg(strcmp(srunner_xml_fname(sr), "test_log.xml") == 0, + "XML Log file is initialize only and shouldn't be changeable once set"); + + srunner_free(sr); +} +END_TEST + +START_TEST(test_set_tap) +{ + Suite *s = suite_create("Suite"); + SRunner *sr = srunner_create(s); + + srunner_set_tap (sr, "test_log.tap"); + + ck_assert_msg (srunner_has_tap (sr), "SRunner not logging TAP"); + ck_assert_msg (strcmp(srunner_tap_fname(sr), "test_log.tap") == 0, + "Bad file name returned"); + + srunner_free(sr); +} +END_TEST + +#if HAVE_DECL_SETENV +/* Test enabling TAP logging via environment variable */ +START_TEST(test_set_tap_env) +{ + const char *old_val; + Suite *s = suite_create("Suite"); + SRunner *sr = srunner_create(s); + + /* check that setting XML log file via environment variable works */ + ck_assert_msg(save_set_env("CK_TAP_LOG_FILE_NAME", "test_log.tap", &old_val) == 0, + "Failed to set environment variable"); + + ck_assert_msg (srunner_has_tap (sr), "SRunner not logging TAP"); + ck_assert_msg (strcmp(srunner_tap_fname(sr), "test_log.tap") == 0, + "Bad file name returned"); + + /* check that explicit call to srunner_set_tap() + overrides environment variable */ + srunner_set_tap (sr, "test2_log.tap"); + + ck_assert_msg (srunner_has_tap (sr), "SRunner not logging TAP"); + ck_assert_msg (strcmp(srunner_tap_fname(sr), "test2_log.tap") == 0, + "Bad file name returned"); + + /* restore old environment */ + ck_assert_msg(restore_env("CK_TAP_LOG_FILE_NAME", old_val) == 0, + "Failed to restore environment variable"); + + srunner_free(sr); +} +END_TEST +#endif /* HAVE_DECL_SETENV */ + +START_TEST(test_no_set_tap) +{ + Suite *s = suite_create("Suite"); + SRunner *sr = srunner_create(s); + + ck_assert_msg (!srunner_has_tap (sr), "SRunner not logging TAP"); + ck_assert_msg (srunner_tap_fname(sr) == NULL, "Bad file name returned"); + + srunner_free(sr); +} +END_TEST + +START_TEST(test_double_set_tap) +{ + Suite *s = suite_create("Suite"); + SRunner *sr = srunner_create(s); + + srunner_set_tap (sr, "test_log.tap"); + srunner_set_tap (sr, "test2_log.tap"); + + ck_assert_msg(strcmp(srunner_tap_fname(sr), "test_log.tap") == 0, + "TAP Log file is initialize only and shouldn't be changeable once set"); + + srunner_free(sr); +} +END_TEST + +Suite *make_log_suite(void) +{ + + Suite *s; + TCase *tc_core, *tc_core_xml, *tc_core_tap; + + s = suite_create("Log"); + tc_core = tcase_create("Core"); + tc_core_xml = tcase_create("Core XML"); + tc_core_tap = tcase_create("Core TAP"); + + suite_add_tcase(s, tc_core); + tcase_add_test(tc_core, test_set_log); +#if HAVE_DECL_SETENV + tcase_add_test(tc_core, test_set_log_env); +#endif /* HAVE_DECL_SETENV */ + tcase_add_test(tc_core, test_no_set_log); + tcase_add_test(tc_core, test_double_set_log); + + suite_add_tcase(s, tc_core_xml); + tcase_add_test(tc_core_xml, test_set_xml); +#if HAVE_DECL_SETENV + tcase_add_test(tc_core_xml, test_set_xml_env); +#endif /* HAVE_DECL_SETENV */ + tcase_add_test(tc_core_xml, test_no_set_xml); + tcase_add_test(tc_core_xml, test_double_set_xml); + + suite_add_tcase(s, tc_core_tap); + tcase_add_test(tc_core_tap, test_set_tap); +#if HAVE_DECL_SETENV + tcase_add_test(tc_core_tap, test_set_tap_env); +#endif /* HAVE_DECL_SETENV */ + tcase_add_test(tc_core_tap, test_no_set_tap); + tcase_add_test(tc_core_tap, test_double_set_tap); + + return s; +} + diff --git a/tests/check_check_log_internal.c b/tests/check_check_log_internal.c new file mode 100644 index 0000000..0101432 --- /dev/null +++ b/tests/check_check_log_internal.c @@ -0,0 +1,75 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "../lib/libcompat.h" + +/* Tests for log related stuff in check which need non-exported functions. */ + +#include +#include +#include +#include +#include +#include +#include +#include "check_check.h" + + +#if ENABLE_SUBUNIT +START_TEST(test_init_logging_subunit) +{ + /* init_logging with CK_SUBUNIT sets stdout + * to a subunit function, not any log. + */ + Log * first_log = NULL; + Suite *s = suite_create("Suite"); + SRunner *sr = srunner_create(s); + srunner_init_logging(sr, CK_SUBUNIT); + check_list_front (sr->loglst); + ck_assert_msg (!check_list_at_end(sr->loglst), "No entries in log list"); + first_log = (Log *)check_list_val(sr->loglst); + ck_assert_msg (first_log != NULL, "log is NULL"); + check_list_advance(sr->loglst); + ck_assert_msg(check_list_at_end(sr->loglst), "More than one entry in log list"); + ck_assert_msg(first_log->lfun == subunit_lfun, + "Log function is not the subunit lfun."); + srunner_end_logging(sr); + srunner_free(sr); +} +END_TEST +#endif + +Suite *make_log_internal_suite(void) +{ + Suite *s; + +#if ENABLE_SUBUNIT + TCase *tc_core_subunit; + s = suite_create("Log"); + tc_core_subunit = tcase_create("Core SubUnit"); + suite_add_tcase(s, tc_core_subunit); + tcase_add_test(tc_core_subunit, test_init_logging_subunit); +#else + s = suite_create("Log"); +#endif + + return s; +} + diff --git a/tests/check_check_main.c b/tests/check_check_main.c new file mode 100644 index 0000000..3391493 --- /dev/null +++ b/tests/check_check_main.c @@ -0,0 +1,62 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "../lib/libcompat.h" + +#include +#include +#include +#include "check_check.h" + +int main (void) +{ + int n; + SRunner *sr; + + fork_setup(); + setup_fixture(); + setup(); + + sr = srunner_create (make_master_suite()); + srunner_add_suite(sr, make_list_suite()); + srunner_add_suite(sr, make_msg_suite()); + srunner_add_suite(sr, make_log_suite()); + srunner_add_suite(sr, make_log_internal_suite()); + srunner_add_suite(sr, make_limit_suite()); + srunner_add_suite(sr, make_fork_suite()); + srunner_add_suite(sr, make_fixture_suite()); + srunner_add_suite(sr, make_pack_suite()); + srunner_add_suite(sr, make_tag_suite()); + +#if defined(HAVE_FORK) && HAVE_FORK==1 + srunner_add_suite(sr, make_exit_suite()); +#endif + + srunner_add_suite(sr, make_selective_suite()); + + printf ("Ran %d tests in subordinate suite\n", sub_ntests); + srunner_run_all (sr, CK_VERBOSE); + cleanup(); + fork_teardown(); + teardown_fixture(); + n = srunner_ntests_failed(sr); + srunner_free(sr); + return (n == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/tests/check_check_master.c b/tests/check_check_master.c new file mode 100644 index 0000000..5aedc79 --- /dev/null +++ b/tests/check_check_master.c @@ -0,0 +1,1013 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "../lib/libcompat.h" + +#include +#include +#include +#if ENABLE_REGEX +# include +#endif +#include +#include +#include "check_check.h" + +int sub_nfailed; +int sub_ntests; + +TestResult **tr_fail_array; +TestResult **tr_all_array; + +FILE * test_names_file = NULL; +char * test_names_file_name = NULL; +FILE * line_num_failures = NULL; +char * line_num_failures_file_name = NULL; + +enum ck_test_msg_type_t { +#if ENABLE_REGEX + // For tests with different output on different platforms + CK_MSG_REGEXP, +#endif + // Simple text + CK_MSG_TEXT +}; + +#define MAXSTR 300 + +typedef struct { + const char *tcname; + const char *test_name; + int failure_type; + enum ck_test_msg_type_t msg_type; + const char *msg; +} master_test_t; + +#define SIG_STR_LEN 128 +static char signal_11_str[SIG_STR_LEN]; +static char signal_11_8_str[SIG_STR_LEN]; +static char signal_8_str[SIG_STR_LEN]; + +static master_test_t master_tests[] = { + { "Simple Tests", "test_lno", CK_FAILURE, CK_MSG_TEXT, "Failure expected" }, +#if defined(HAVE_FORK) && HAVE_FORK==1 + { "Simple Tests", "test_mark_lno", CK_ERROR, CK_MSG_TEXT, "Early exit with return value 1" }, +#endif + { "Simple Tests", "test_pass", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Simple Tests", "test_fail_unless", CK_FAILURE, CK_MSG_TEXT, "This test should fail" }, + { "Simple Tests", "test_fail_if_pass", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Simple Tests", "test_fail_if_fail", CK_FAILURE, CK_MSG_TEXT, "This test should fail" }, + { "Simple Tests", "test_fail_null_msg", CK_FAILURE, CK_MSG_TEXT, "Assertion '2 == 3' failed" }, +#if defined(__GNUC__) + { "Simple Tests", "test_fail_no_msg", CK_FAILURE, CK_MSG_TEXT, "Assertion '4 == 5' failed" }, +#endif /* __GNUC__ */ + { "Simple Tests", "test_fail_if_null_msg", CK_FAILURE, CK_MSG_TEXT, "Failure '2 != 3' occurred" }, +#if defined(__GNUC__) + { "Simple Tests", "test_fail_if_no_msg", CK_FAILURE, CK_MSG_TEXT, "Failure '4 != 5' occurred" }, +#endif /* __GNUC__ */ + { "Simple Tests", "test_fail_vararg_msg_1", CK_FAILURE, CK_MSG_TEXT, "3 != 4" }, + { "Simple Tests", "test_fail_vararg_msg_2", CK_FAILURE, CK_MSG_TEXT, "5 != 6" }, + { "Simple Tests", "test_fail_vararg_msg_3", CK_FAILURE, CK_MSG_TEXT, "7 == 7" }, +#if defined(__GNUC__) + { "Simple Tests", "test_fail_empty", CK_FAILURE, CK_MSG_TEXT, "Failed" }, +#endif /* __GNUC__ */ + { "Simple Tests", "test_ck_abort", CK_FAILURE, CK_MSG_TEXT, "Failed" }, + { "Simple Tests", "test_ck_abort_msg", CK_FAILURE, CK_MSG_TEXT, "Failure expected" }, + { "Simple Tests", "test_ck_abort_msg_null", CK_FAILURE, CK_MSG_TEXT, "Failed" }, + { "Simple Tests", "test_ck_assert", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x == y' failed" }, + { "Simple Tests", "test_ck_assert_null", CK_FAILURE, CK_MSG_TEXT, "Assertion '0' failed" }, + { "Simple Tests", "test_ck_assert_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '1%f == 1' failed" }, + { "Simple Tests", "test_ck_assert_int_eq", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x == y' failed: x == 3, y == 4" }, + { "Simple Tests", "test_ck_assert_int_eq_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '3%d == 2%f' failed: 3%d == 1, 2%f == 0" }, + { "Simple Tests", "test_ck_assert_int_ne", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x != y' failed: x == 3, y == 3" }, + { "Simple Tests", "test_ck_assert_int_ne_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '3%d != 3%f' failed: 3%d == 1, 3%f == 1" }, + { "Simple Tests", "test_ck_assert_int_lt", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x < x' failed: x == 2, x == 2" }, + { "Simple Tests", "test_ck_assert_int_lt_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '3%d < 3%f' failed: 3%d == 1, 3%f == 0" }, + { "Simple Tests", "test_ck_assert_int_le", CK_FAILURE, CK_MSG_TEXT, "Assertion 'y <= x' failed: y == 3, x == 2" }, + { "Simple Tests", "test_ck_assert_int_le_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '3%d <= 2%f' failed: 3%d == 1, 2%f == 0" }, + { "Simple Tests", "test_ck_assert_int_gt", CK_FAILURE, CK_MSG_TEXT, "Assertion 'y > y' failed: y == 3, y == 3" }, + { "Simple Tests", "test_ck_assert_int_gt_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '3%d > 3%f' failed: 3%d == 0, 3%f == 1" }, + { "Simple Tests", "test_ck_assert_int_ge", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x >= y' failed: x == 2, y == 3" }, + { "Simple Tests", "test_ck_assert_int_ge_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '3%d >= 4%f' failed: 3%d == 0, 4%f == 1" }, + { "Simple Tests", "test_ck_assert_int_expr", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Simple Tests", "test_ck_assert_uint_eq", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x == y' failed: x == 3, y == 4" }, + { "Simple Tests", "test_ck_assert_uint_eq_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '3%d == 1%f' failed: 3%d == 1, 1%f == 0" }, + { "Simple Tests", "test_ck_assert_uint_ne", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x != y' failed: x == 3, y == 3" }, + { "Simple Tests", "test_ck_assert_uint_ne_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '1%d != 1%f' failed: 1%d == 0, 1%f == 0" }, + { "Simple Tests", "test_ck_assert_uint_lt", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x < x' failed: x == 2, x == 2" }, + { "Simple Tests", "test_ck_assert_uint_lt_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '3%d < 1%f' failed: 3%d == 1, 1%f == 0" }, + { "Simple Tests", "test_ck_assert_uint_le", CK_FAILURE, CK_MSG_TEXT, "Assertion 'y <= x' failed: y == 3, x == 2" }, + { "Simple Tests", "test_ck_assert_uint_le_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '3%d <= 1%f' failed: 3%d == 1, 1%f == 0" }, + { "Simple Tests", "test_ck_assert_uint_gt", CK_FAILURE, CK_MSG_TEXT, "Assertion 'y > y' failed: y == 3, y == 3" }, + { "Simple Tests", "test_ck_assert_uint_gt_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '1%d > 3%f' failed: 1%d == 0, 3%f == 1" }, + { "Simple Tests", "test_ck_assert_uint_ge", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x >= y' failed: x == 2, y == 3" }, + { "Simple Tests", "test_ck_assert_uint_ge_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '1%d >= 3%f' failed: 1%d == 0, 3%f == 1" }, + { "Simple Tests", "test_ck_assert_uint_expr", CK_PASS, CK_MSG_TEXT, "Passed" }, + /* Tests on float macros */ + { "Simple Tests", "test_ck_assert_float_eq", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x == y' failed: x == 1.1, y == 1.2" }, + { "Simple Tests", "test_ck_assert_float_eq_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '3%d == 2%f' failed: 3%d == 1, 2%f == 0" }, + { "Simple Tests", "test_ck_assert_float_ne", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x != y' failed: x == 1.1, y == 1.1" }, + { "Simple Tests", "test_ck_assert_float_ne_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '1%d != 1%f' failed: 1%d == 1, 1%f == 1" }, + { "Simple Tests", "test_ck_assert_float_lt", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x < y' failed: x == 2, y == 1.5" }, + { "Simple Tests", "test_ck_assert_float_lt_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '3%d < 2%f' failed: 3%d == 1, 2%f == 0" }, + { "Simple Tests", "test_ck_assert_float_le", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x <= y' failed: x == 2, y == 1.5" }, + { "Simple Tests", "test_ck_assert_float_le_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '3%d <= 2%f' failed: 3%d == 1, 2%f == 0" }, + { "Simple Tests", "test_ck_assert_float_gt", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x > y' failed: x == 2.5, y == 3" }, + { "Simple Tests", "test_ck_assert_float_gt_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '2%d > 3%f' failed: 2%d == 0, 3%f == 1" }, + { "Simple Tests", "test_ck_assert_float_ge", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x >= y' failed: x == 2.5, y == 3" }, + { "Simple Tests", "test_ck_assert_float_ge_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '2%d >= 3%f' failed: 2%d == 0, 3%f == 1" }, + { "Simple Tests", "test_ck_assert_float_with_expr", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Simple Tests", "test_ck_assert_float_eq_tol", CK_FAILURE, CK_MSG_TEXT, "Assertion 'fabsl(y - x) < t' failed: x == 0.001, y == 0.003, t == 0.001" }, + { "Simple Tests", "test_ck_assert_float_eq_tol_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion 'fabsl(2%f - 3%d) < 2%p' failed: 3%d == 1, 2%f == 0, 2%p == 0" }, + { "Simple Tests", "test_ck_assert_float_ne_tol", CK_FAILURE, CK_MSG_TEXT, "Assertion 'fabsl(y - x) >= t' failed: x == 0.001, y == 0.002, t == 0.01" }, + { "Simple Tests", "test_ck_assert_float_ne_tol_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion 'fabsl(3%f - 3%d) >= 3%p' failed: 3%d == 1, 3%f == 1, 3%p == 1" }, + { "Simple Tests", "test_ck_assert_float_ge_tol", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x >= y, error < t' failed: x == 0.01, y == 0.03, t == 0.01" }, + { "Simple Tests", "test_ck_assert_float_ge_tol_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '2%d >= 3%f, error < 3%p' failed: 2%d == 0, 3%f == 1, 3%p == 1" }, + { "Simple Tests", "test_ck_assert_float_le_tol", CK_FAILURE, CK_MSG_TEXT, "Assertion 'y <= x, error < t' failed: y == 0.03, x == 0.01, t == 0.01" }, + { "Simple Tests", "test_ck_assert_float_le_tol_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '3%d <= 2%f, error < 3%p' failed: 3%d == 1, 2%f == 0, 3%p == 1" }, + { "Simple Tests", "test_ck_assert_float_tol_with_expr", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Simple Tests", "test_ck_assert_float_finite", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x is finite' failed: x == inf" }, + { "Simple Tests", "test_ck_assert_float_finite_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x*(1%d) is finite' failed: x*(1%d) == inf" }, + { "Simple Tests", "test_ck_assert_float_infinite", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x is infinite' failed: x == 0" }, + { "Simple Tests", "test_ck_assert_float_infinite_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '2%d is infinite' failed: 2%d == 0" }, + { "Simple Tests", "test_ck_assert_float_nan", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x is NaN' failed: x == inf" }, + { "Simple Tests", "test_ck_assert_float_nan_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '2%d is NaN' failed: 2%d == 0" }, +#if ENABLE_REGEX + { "Simple Tests", "test_ck_assert_float_nonnan", CK_FAILURE, CK_MSG_REGEXP, "^Assertion 'x is not NaN' failed: x == -?nan$" }, + { "Simple Tests", "test_ck_assert_float_nonnan_with_mod", CK_FAILURE, CK_MSG_REGEXP, "^Assertion '\\(2%s\\)\\*x is not NaN' failed: \\(2%s\\)\\*x == -?nan$" }, +#else + { "Simple Tests", "test_ck_assert_float_nonnan", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Simple Tests", "test_ck_assert_float_nonnan_with_mod", CK_PASS, CK_MSG_TEXT, "Passed" }, +#endif + { "Simple Tests", "test_ck_assert_float_nan_and_inf_with_expr", CK_PASS, CK_MSG_TEXT, "Passed" }, + /* End of tests on float macros */ + /* Tests on double macros */ + { "Simple Tests", "test_ck_assert_double_eq", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x == y' failed: x == 1.1, y == 1.2" }, + { "Simple Tests", "test_ck_assert_double_eq_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '3%d == 2%f' failed: 3%d == 1, 2%f == 0" }, + { "Simple Tests", "test_ck_assert_double_eq_with_promotion", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Simple Tests", "test_ck_assert_double_eq_with_conv", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x == 0.1' failed: x == 0.1, 0.1 == 0.1" }, + { "Simple Tests", "test_ck_assert_double_ne", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x != y' failed: x == 1.1, y == 1.1" }, + { "Simple Tests", "test_ck_assert_double_ne_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '1%d != 1%f' failed: 1%d == 1, 1%f == 1" }, + { "Simple Tests", "test_ck_assert_double_lt", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x < y' failed: x == 2, y == 1.5" }, + { "Simple Tests", "test_ck_assert_double_lt_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '3%d < 2%f' failed: 3%d == 1, 2%f == 0" }, + { "Simple Tests", "test_ck_assert_double_le", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x <= y' failed: x == 2, y == 1.5" }, + { "Simple Tests", "test_ck_assert_double_le_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '3%d <= 2%f' failed: 3%d == 1, 2%f == 0" }, + { "Simple Tests", "test_ck_assert_double_gt", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x > y' failed: x == 2.5, y == 3" }, + { "Simple Tests", "test_ck_assert_double_gt_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '2%d > 3%f' failed: 2%d == 0, 3%f == 1" }, + { "Simple Tests", "test_ck_assert_double_ge", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x >= y' failed: x == 2.5, y == 3" }, + { "Simple Tests", "test_ck_assert_double_ge_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '2%d >= 3%f' failed: 2%d == 0, 3%f == 1" }, + { "Simple Tests", "test_ck_assert_double_with_expr", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Simple Tests", "test_ck_assert_double_eq_tol", CK_FAILURE, CK_MSG_TEXT, "Assertion 'fabsl(y - x) < t' failed: x == 0.001, y == 0.002, t == 0.001" }, + { "Simple Tests", "test_ck_assert_double_eq_tol_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion 'fabsl(2%f - 3%d) < 2%p' failed: 3%d == 1, 2%f == 0, 2%p == 0" }, + { "Simple Tests", "test_ck_assert_double_ne_tol", CK_FAILURE, CK_MSG_TEXT, "Assertion 'fabsl(y - x) >= t' failed: x == 0.001, y == 0.002, t == 0.01" }, + { "Simple Tests", "test_ck_assert_double_ne_tol_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion 'fabsl(3%f - 3%d) >= 3%p' failed: 3%d == 1, 3%f == 1, 3%p == 1" }, + { "Simple Tests", "test_ck_assert_double_ge_tol", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x >= y, error < t' failed: x == 0.01, y == 0.03, t == 0.01" }, + { "Simple Tests", "test_ck_assert_double_ge_tol_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '2%d >= 3%f, error < 3%p' failed: 2%d == 0, 3%f == 1, 3%p == 1" }, + { "Simple Tests", "test_ck_assert_double_le_tol", CK_FAILURE, CK_MSG_TEXT, "Assertion 'y <= x, error < t' failed: y == 0.03, x == 0.01, t == 0.01" }, + { "Simple Tests", "test_ck_assert_double_le_tol_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '3%d <= 2%f, error < 3%p' failed: 3%d == 1, 2%f == 0, 3%p == 1" }, + { "Simple Tests", "test_ck_assert_double_tol_with_expr", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Simple Tests", "test_ck_assert_double_finite", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x is finite' failed: x == inf" }, + { "Simple Tests", "test_ck_assert_double_finite_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x*(1%d) is finite' failed: x*(1%d) == inf" }, + { "Simple Tests", "test_ck_assert_double_infinite", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x is infinite' failed: x == 0" }, + { "Simple Tests", "test_ck_assert_double_infinite_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '2%d is infinite' failed: 2%d == 0" }, + { "Simple Tests", "test_ck_assert_double_nan", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x is NaN' failed: x == inf" }, + { "Simple Tests", "test_ck_assert_double_nan_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '2%d is NaN' failed: 2%d == 0" }, +#if ENABLE_REGEX + { "Simple Tests", "test_ck_assert_double_nonnan", CK_FAILURE, CK_MSG_REGEXP, "^Assertion 'x is not NaN' failed: x == -?nan$" }, + { "Simple Tests", "test_ck_assert_double_nonnan_with_mod", CK_FAILURE, CK_MSG_REGEXP, "^Assertion '\\(2%s\\)\\*x is not NaN' failed: \\(2%s\\)\\*x == -?nan$" }, +#else + { "Simple Tests", "test_ck_assert_double_nonnan", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Simple Tests", "test_ck_assert_double_nonnan_with_mod", CK_PASS, CK_MSG_TEXT, "Passed" }, +#endif + { "Simple Tests", "test_ck_assert_double_nan_and_inf_with_expr", CK_PASS, CK_MSG_TEXT, "Passed" }, + /* End of tests on double macros */ + /* Tests on long double macros */ + { "Simple Tests", "test_ck_assert_ldouble_eq", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x == y' failed: x == 1.1, y == 1.2" }, + { "Simple Tests", "test_ck_assert_ldouble_eq_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '3%d == 2%f' failed: 3%d == 1, 2%f == 0" }, + { "Simple Tests", "test_ck_assert_ldouble_eq_with_promotion", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Simple Tests", "test_ck_assert_ldouble_eq_with_conv", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x == 1.1' failed: x == 1.1, 1.1 == 1.1" }, + { "Simple Tests", "test_ck_assert_ldouble_ne", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x != y' failed: x == 1.1, y == 1.1" }, + { "Simple Tests", "test_ck_assert_ldouble_ne_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '1%d != 1%f' failed: 1%d == 1, 1%f == 1" }, + { "Simple Tests", "test_ck_assert_ldouble_lt", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x < y' failed: x == 2, y == 1.5" }, + { "Simple Tests", "test_ck_assert_ldouble_lt_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '3%d < 2%f' failed: 3%d == 1, 2%f == 0" }, + { "Simple Tests", "test_ck_assert_ldouble_le", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x <= y' failed: x == 2, y == 1.5" }, + { "Simple Tests", "test_ck_assert_ldouble_le_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '3%d <= 2%f' failed: 3%d == 1, 2%f == 0" }, + { "Simple Tests", "test_ck_assert_ldouble_gt", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x > y' failed: x == 2.5, y == 3" }, + { "Simple Tests", "test_ck_assert_ldouble_gt_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '2%d > 3%f' failed: 2%d == 0, 3%f == 1" }, + { "Simple Tests", "test_ck_assert_ldouble_ge", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x >= y' failed: x == 2.5, y == 3" }, + { "Simple Tests", "test_ck_assert_ldouble_ge_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '2%d >= 3%f' failed: 2%d == 0, 3%f == 1" }, + { "Simple Tests", "test_ck_assert_ldouble_with_expr", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Simple Tests", "test_ck_assert_ldouble_eq_tol", CK_FAILURE, CK_MSG_TEXT, "Assertion 'fabsl(y - x) < t' failed: x == 0.001, y == 0.002, t == 0.001" }, + { "Simple Tests", "test_ck_assert_ldouble_eq_tol_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion 'fabsl(2%f - 3%d) < 2%p' failed: 3%d == 1, 2%f == 0, 2%p == 0" }, + { "Simple Tests", "test_ck_assert_ldouble_ne_tol", CK_FAILURE, CK_MSG_TEXT, "Assertion 'fabsl(y - x) >= t' failed: x == 0.001, y == 0.002, t == 0.01" }, + { "Simple Tests", "test_ck_assert_ldouble_ne_tol_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion 'fabsl(3%f - 3%d) >= 3%p' failed: 3%d == 1, 3%f == 1, 3%p == 1" }, + { "Simple Tests", "test_ck_assert_ldouble_ge_tol", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x >= y, error < t' failed: x == 0.01, y == 0.03, t == 0.01" }, + { "Simple Tests", "test_ck_assert_ldouble_ge_tol_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '2%d >= 3%f, error < 3%p' failed: 2%d == 0, 3%f == 1, 3%p == 1" }, + { "Simple Tests", "test_ck_assert_ldouble_le_tol", CK_FAILURE, CK_MSG_TEXT, "Assertion 'y <= x, error < t' failed: y == 0.03, x == 0.01, t == 0.01" }, + { "Simple Tests", "test_ck_assert_ldouble_le_tol_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '3%d <= 2%f, error < 3%p' failed: 3%d == 1, 2%f == 0, 3%p == 1" }, + { "Simple Tests", "test_ck_assert_ldouble_tol_with_expr", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Simple Tests", "test_ck_assert_ldouble_finite", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x is finite' failed: x == inf" }, + { "Simple Tests", "test_ck_assert_ldouble_finite_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x*(1%d) is finite' failed: x*(1%d) == inf" }, + { "Simple Tests", "test_ck_assert_ldouble_infinite", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x is infinite' failed: x == 0" }, + { "Simple Tests", "test_ck_assert_ldouble_infinite_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '2%d is infinite' failed: 2%d == 0" }, + { "Simple Tests", "test_ck_assert_ldouble_nan", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x is NaN' failed: x == inf" }, + { "Simple Tests", "test_ck_assert_ldouble_nan_with_mod", CK_FAILURE, CK_MSG_TEXT, "Assertion '2%d is NaN' failed: 2%d == 0" }, +#if ENABLE_REGEX + { "Simple Tests", "test_ck_assert_ldouble_nonnan", CK_FAILURE, CK_MSG_REGEXP, "^Assertion 'x is not NaN' failed: x == -?nan$" }, + { "Simple Tests", "test_ck_assert_ldouble_nonnan_with_mod", CK_FAILURE, CK_MSG_REGEXP, "^Assertion '\\(2%s\\)\\*x is not NaN' failed: \\(2%s\\)\\*x == -?nan$" }, +#else + { "Simple Tests", "test_ck_assert_ldouble_nonnan", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Simple Tests", "test_ck_assert_ldouble_nonnan_with_mod", CK_PASS, CK_MSG_TEXT, "Passed" }, +#endif + { "Simple Tests", "test_ck_assert_ldouble_nan_and_inf_with_expr", CK_PASS, CK_MSG_TEXT, "Passed" }, + /* End of tests on long double macros */ + { "Simple Tests", "test_percent_n_escaped", CK_FAILURE, CK_MSG_TEXT, "Assertion 'returnsZero(\"%n\") == 1' failed: returnsZero(\"%n\") == 0, 1 == 1" }, + { "Simple Tests", "test_ck_assert_str_eq", CK_FAILURE, CK_MSG_TEXT, "Assertion '\"test1\" == s' failed: \"test1\" == \"test1\", s == \"test2\"" }, + { "Simple Tests", "test_ck_assert_str_eq_with_null", CK_FAILURE, CK_MSG_TEXT, "Assertion 't == s' failed: t == (null), s == (null)" }, + { "Simple Tests", "test_ck_assert_str_ne", CK_FAILURE, CK_MSG_TEXT, "Assertion 't != s' failed: t == \"test2\", s == \"test2\"" }, + { "Simple Tests", "test_ck_assert_str_ne_with_null", CK_FAILURE, CK_MSG_TEXT, "Assertion 't != s' failed: t == \"test\", s == (null)" }, + { "Simple Tests", "test_ck_assert_str_lt", CK_FAILURE, CK_MSG_TEXT, "Assertion 's < s' failed: s == \"test1\", s == \"test1\"" }, + { "Simple Tests", "test_ck_assert_str_lt_with_null", CK_FAILURE, CK_MSG_TEXT, "Assertion 's < t' failed: s == (null), t == \"test\"" }, + { "Simple Tests", "test_ck_assert_str_le", CK_FAILURE, CK_MSG_TEXT, "Assertion 't <= s' failed: t == \"test2\", s == \"test1\"" }, + { "Simple Tests", "test_ck_assert_str_le_with_null", CK_FAILURE, CK_MSG_TEXT, "Assertion 't <= s' failed: t == (null), s == (null)" }, + { "Simple Tests", "test_ck_assert_str_gt", CK_FAILURE, CK_MSG_TEXT, "Assertion 't > t' failed: t == \"test2\", t == \"test2\"" }, + { "Simple Tests", "test_ck_assert_str_gt_with_null", CK_FAILURE, CK_MSG_TEXT, "Assertion 't > s' failed: t == \"test\", s == (null)" }, + { "Simple Tests", "test_ck_assert_str_ge", CK_FAILURE, CK_MSG_TEXT, "Assertion 's >= t' failed: s == \"test1\", t == \"test2\"" }, + { "Simple Tests", "test_ck_assert_str_ge_with_null", CK_FAILURE, CK_MSG_TEXT, "Assertion 's >= t' failed: s == (null), t == (null)" }, + { "Simple Tests", "test_ck_assert_str_expr", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Simple Tests", "test_ck_assert_pstr_eq", CK_FAILURE, CK_MSG_TEXT, "Assertion '\"test1\" == s' failed: \"test1\" == \"test1\", s == \"test\"" }, + { "Simple Tests", "test_ck_assert_pstr_eq_with_null", CK_FAILURE, CK_MSG_TEXT, "Assertion 't == s' failed: t == \"test\", s == (null)" }, + { "Simple Tests", "test_ck_assert_pstr_ne", CK_FAILURE, CK_MSG_TEXT, "Assertion 't != s' failed: t == \"test2\", s == \"test2\"" }, + { "Simple Tests", "test_ck_assert_pstr_ne_with_null", CK_FAILURE, CK_MSG_TEXT, "Assertion 't != s' failed: t == (null), s == (null)" }, + { "Simple Tests", "test_ck_assert_ptr_eq", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x == y' failed: x == 0x1, y == 0x2" }, + { "Simple Tests", "test_ck_assert_ptr_ne", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x != z' failed: x == 0x1, z == 0x1" }, + { "Simple Tests", "test_ck_assert_ptr_null", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x == NULL' failed: x == 0x1" }, + { "Simple Tests", "test_ck_assert_ptr_nonnull", CK_FAILURE, CK_MSG_TEXT, "Assertion 'x != NULL' failed: x == 0" }, + { "Simple Tests", "test_ck_assert_mem_eq", CK_FAILURE, CK_MSG_TEXT, "Assertion '\"\\x00\\x00\\x00\\x00\\x01\" == s' failed: \"\\x00\\x00\\x00\\x00\\x01\" == \"0000000001\", s == \"0000000002\"" }, + { "Simple Tests", "test_ck_assert_mem_ne", CK_FAILURE, CK_MSG_TEXT, "Assertion 't != s' failed: t == \"0000000002\", s == \"0000000002\"" }, + { "Simple Tests", "test_ck_assert_mem_lt", CK_FAILURE, CK_MSG_TEXT, "Assertion 's < s' failed: s == \"0000000001\", s == \"0000000001\"" }, + { "Simple Tests", "test_ck_assert_mem_le", CK_FAILURE, CK_MSG_TEXT, "Assertion 't <= s' failed: t == \"0000000002\", s == \"0000000001\"" }, + { "Simple Tests", "test_ck_assert_mem_gt", CK_FAILURE, CK_MSG_TEXT, "Assertion 't > t' failed: t == \"0000000002\", t == \"0000000002\"" }, + { "Simple Tests", "test_ck_assert_mem_ge", CK_FAILURE, CK_MSG_TEXT, "Assertion 's >= t' failed: s == \"0000000001\", t == \"0000000002\"" }, + { "Simple Tests", "test_ck_assert_mem_zerolen", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Simple Tests", "test_ck_assert_mem_eq_exact", CK_FAILURE, CK_MSG_TEXT, "Assertion 't == s' failed: t == \"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001\", s == \"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002\"" }, + { "Simple Tests", "test_ck_assert_mem_eq_longer", CK_FAILURE, CK_MSG_TEXT, "Assertion 't == s' failed: t == \"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000..\", s == \"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000..\"" }, + +#if defined(HAVE_FORK) && HAVE_FORK==1 + { "Signal Tests", "test_segv", CK_ERROR, CK_MSG_TEXT, signal_11_str }, + { "Signal Tests", "test_segv_pass", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Signal Tests", "test_segv", CK_ERROR, CK_MSG_TEXT, signal_11_8_str }, + { "Signal Tests", "test_non_signal_8", CK_FAILURE, CK_MSG_TEXT, "Early exit with return value 0" }, + { "Signal Tests", "test_fail_unless", CK_FAILURE, CK_MSG_TEXT, "Early exit with return value 1" }, +#if !defined(__CYGWIN__) + { "Signal Tests", "test_fpe", CK_ERROR, CK_MSG_TEXT, signal_8_str }, + { "Signal Tests", "test_mark_point", CK_ERROR, CK_MSG_TEXT, signal_8_str }, +#endif /* !defined(__CYGWIN__) */ +#endif /* HAVE_FORK */ + +#if TIMEOUT_TESTS_ENABLED && defined(HAVE_FORK) && HAVE_FORK==1 +#if HAVE_DECL_SETENV + { "Environment Integer Timeout Tests", "test_eternal_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, + { "Environment Integer Timeout Tests", "test_sleep2_pass", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Environment Integer Timeout Tests", "test_sleep5_pass", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Environment Integer Timeout Tests", "test_sleep9_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, + + { "Environment Double Timeout Tests", "test_eternal_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, +#ifdef HAVE_LIBRT + { "Environment Double Timeout Tests", "test_sleep0_025_pass", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Environment Double Timeout Tests", "test_sleep1_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, +#endif /* HAVE_LIBRT */ + { "Environment Double Timeout Tests", "test_sleep2_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, + { "Environment Double Timeout Tests", "test_sleep5_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, + { "Environment Double Timeout Tests", "test_sleep9_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, +#endif /* HAVE_DECL_SETENV */ + + { "Default Timeout Tests", "test_eternal_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, +#ifdef HAVE_LIBRT + { "Default Timeout Tests", "test_sleep0_025_pass", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Default Timeout Tests", "test_sleep1_pass", CK_PASS, CK_MSG_TEXT, "Passed" }, +#endif /* HAVE_LIBRT */ + { "Default Timeout Tests", "test_sleep2_pass", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Default Timeout Tests", "test_sleep5_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, + { "Default Timeout Tests", "test_sleep9_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, + + { "User Integer Timeout Tests", "test_eternal_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, + { "User Integer Timeout Tests", "test_sleep2_pass", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "User Integer Timeout Tests", "test_sleep5_pass", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "User Integer Timeout Tests", "test_sleep9_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, + + { "User Double Timeout Tests", "test_eternal_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, +#ifdef HAVE_LIBRT + { "User Double Timeout Tests", "test_sleep0_025_pass", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "User Double Timeout Tests", "test_sleep1_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, +#endif /* HAVE_LIBRT */ + { "User Double Timeout Tests", "test_sleep2_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, + { "User Double Timeout Tests", "test_sleep5_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, + { "User Double Timeout Tests", "test_sleep9_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, + +#if HAVE_DECL_SETENV + { "Environment Integer Timeout Scaling Tests", "test_eternal_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, +#ifdef HAVE_LIBRT + { "Environment Integer Timeout Scaling Tests", "test_sleep0_025_pass", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Environment Integer Timeout Scaling Tests", "test_sleep1_pass", CK_PASS, CK_MSG_TEXT, "Passed" }, +#endif /* HAVE_LIBRT */ + { "Environment Integer Timeout Scaling Tests", "test_sleep2_pass", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Environment Integer Timeout Scaling Tests", "test_sleep5_pass", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Environment Integer Timeout Scaling Tests", "test_sleep9_pass", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Environment Integer Timeout Scaling Tests", "test_sleep14_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, + + { "Environment Double Timeout Scaling Tests", "test_eternal_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, +#ifdef HAVE_LIBRT + { "Environment Double Timeout Scaling Tests", "test_sleep0_025_pass", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Environment Double Timeout Scaling Tests", "test_sleep1_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, +#endif /* HAVE_LIBRT */ + { "Environment Double Timeout Scaling Tests", "test_sleep2_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, + { "Environment Double Timeout Scaling Tests", "test_sleep5_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, + { "Environment Double Timeout Scaling Tests", "test_sleep9_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, + { "Environment Double Timeout Scaling Tests", "test_sleep14_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, + + { "Timeout Integer Scaling Tests", "test_eternal_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, +#ifdef HAVE_LIBRT + { "Timeout Integer Scaling Tests", "test_sleep0_025_pass", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Timeout Integer Scaling Tests", "test_sleep1_pass", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Timeout Integer Scaling Tests", "test_sleep2_pass", CK_PASS, CK_MSG_TEXT, "Passed" }, +#endif /* HAVE_LIBRT */ + { "Timeout Integer Scaling Tests", "test_sleep5_pass", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Timeout Integer Scaling Tests", "test_sleep9_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, + + { "Timeout Double Scaling Tests", "test_eternal_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, +#ifdef HAVE_LIBRT + { "Timeout Double Scaling Tests", "test_sleep0_025_pass", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Timeout Double Scaling Tests", "test_sleep1_pass", CK_PASS, CK_MSG_TEXT, "Passed" }, +#endif /* HAVE_LIBRT */ + { "Timeout Double Scaling Tests", "test_sleep2_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, + { "Timeout Double Scaling Tests", "test_sleep5_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, + { "Timeout Double Scaling Tests", "test_sleep9_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, + + { "User Integer Timeout Scaling Tests", "test_eternal_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, +#ifdef HAVE_LIBRT + { "User Integer Timeout Scaling Tests", "test_sleep0_025_pass", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "User Integer Timeout Scaling Tests", "test_sleep1_pass", CK_PASS, CK_MSG_TEXT, "Passed" }, +#endif /* HAVE_LIBRT */ + { "User Integer Timeout Scaling Tests", "test_sleep2_pass", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "User Integer Timeout Scaling Tests", "test_sleep5_pass", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "User Integer Timeout Scaling Tests", "test_sleep9_pass", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "User Integer Timeout Scaling Tests", "test_sleep14_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, + + { "User Double Timeout Scaling Tests", "test_eternal_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, +#ifdef HAVE_LIBRT + { "User Double Timeout Scaling Tests", "test_sleep0_025_pass", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "User Double Timeout Scaling Tests", "test_sleep1_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, +#endif /* HAVE_LIBRT */ + { "User Double Timeout Scaling Tests", "test_sleep2_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, + { "User Double Timeout Scaling Tests", "test_sleep5_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, + { "User Double Timeout Scaling Tests", "test_sleep9_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, + { "User Double Timeout Scaling Tests", "test_sleep14_fail", CK_ERROR, CK_MSG_TEXT, "Test timeout expired" }, +#endif /* HAVE_DECL_SETENV */ +#endif /* TIMEOUT_TESTS_ENABLED && defined(HAVE_FORK) */ + +#if defined(HAVE_FORK) && HAVE_FORK==1 + { "Limit Tests", "test_early_exit", CK_ERROR, CK_MSG_TEXT, "Early exit with return value 1" }, +#endif /* HAVE_FORK */ +#if MEMORY_LEAKING_TESTS_ENABLED + { "Limit Tests", "test_null", CK_FAILURE, CK_MSG_TEXT, "Completed properly" }, +#endif /* MEMORY_LEAKING_TESTS_ENABLED */ + { "Limit Tests", "test_null_2", CK_FAILURE, CK_MSG_TEXT, "Completed properly" }, + +#if defined(HAVE_FORK) && HAVE_FORK==1 + { "Msg and fork Tests", "test_fork1p_pass", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Msg and fork Tests", "test_fork1p_fail", CK_FAILURE, CK_MSG_TEXT, "Expected fail" }, + { "Msg and fork Tests", "test_fork1c_pass", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Msg and fork Tests", "test_fork1c_fail", CK_FAILURE, CK_MSG_TEXT, "Expected fail" }, + { "Msg and fork Tests", "test_fork2_pass", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Msg and fork Tests", "test_fork2_fail", CK_FAILURE, CK_MSG_TEXT, "Expected fail" }, +#endif /* HAVE_FORK */ + +#if defined(HAVE_FORK) && HAVE_FORK==1 +#if MEMORY_LEAKING_TESTS_ENABLED + { "Check Errors Tests", "test_invalid_set_fork_status", CK_FAILURE, CK_MSG_TEXT, "Early exit with return value 2" }, +#endif + { "Check Ignore Exit Handlers", "test_ignore_exit_handlers", CK_FAILURE, CK_MSG_TEXT, "Failed" }, +#endif /* HAVE_FORK */ + + { "Core", "test_srunner", CK_PASS, CK_MSG_TEXT, "Passed" }, + { "Core", "test_2nd_suite", CK_FAILURE, CK_MSG_TEXT, "We failed" } +}; + +static int nr_of_master_tests = sizeof master_tests /sizeof master_tests[0]; + +START_TEST(test_check_nfailures) +{ + int i; + int failed = 0; + + for (i = 0; i < nr_of_master_tests; i++) { + if (master_tests[i].failure_type != CK_PASS) { + failed++; + } + } + ck_assert_msg (sub_nfailed == failed, + "Unexpected number of failures received, %d, expected %d.", + sub_nfailed, failed); +} +END_TEST + +START_TEST(test_check_ntests_run) +{ + ck_assert_msg (sub_ntests == nr_of_master_tests, + "Unexpected number of tests run %d vs expected %d", sub_ntests, nr_of_master_tests); +} +END_TEST + +/** + * Given a string, return a new string that is a copy + * of the original exception that every occurance of + * % is replaced with %%. This escapes the % + * symbol for passing to printf. + * + * The passed in string is not modified. Note though + * that the returned string is allocated memory that + * must be freed by the caller. + */ +char * escape_percent(const char *original, size_t original_size); +char * escape_percent(const char *original, size_t original_size) +{ + /* In the worst case every character is a %*/ + char *result = (char*)malloc(original_size*2); + + size_t read_index; + size_t write_index; + for(read_index = write_index = 0; read_index < original_size; read_index++, write_index++) + { + result[write_index] = original[read_index]; + if(result[write_index] == '%') + { + /* Place a duplicate % next to the one just read, to escape it */ + result[++write_index] = '%'; + } + } + + return result; +} + +START_TEST(test_check_failure_msgs) +{ + int i; + int passed = 0; + const char *got_msg; + const char *expected_msg; + unsigned char not_equal = 0; + char emsg[MAXSTR]; + const char *msg_type_str; + char *emsg_escaped; + int reg_err; + char err_text[256]; + TestResult *tr; +#if ENABLE_REGEX + regex_t re; +#endif + + for (i = 0; i < sub_ntests; i++) { + master_test_t *master_test = &master_tests[i]; + + if (master_test->failure_type == CK_PASS) { + passed++; + continue; + } + + ck_assert_msg(i - passed <= sub_nfailed, NULL); + tr = tr_fail_array[i - passed]; + ck_assert_msg(tr != NULL, NULL); + got_msg = tr_msg(tr); + expected_msg = master_test->msg; + + switch (master_test->msg_type) { + case CK_MSG_TEXT: + if (strcmp(got_msg, expected_msg) != 0) { + not_equal = 1; + } + break; +#if ENABLE_REGEX + case CK_MSG_REGEXP: { + reg_err = regcomp(&re, expected_msg, REG_EXTENDED | REG_NOSUB); + if (reg_err) { + regerror(reg_err, &re, err_text, sizeof(err_text)); + ck_assert_msg(reg_err == 0, + "For test %d:%s:%s Expected regexp '%s', but regcomp returned error '%s'", + i, master_test->tcname, master_test->test_name, expected_msg, + err_text); + } + reg_err = regexec(&re, got_msg, 0, NULL, 0); + regfree(&re); + if (reg_err) { + not_equal = 1; + } + break; + } +#endif /* ENABLE_REGEX */ + } + + if (not_equal) { + switch(master_test->msg_type) { +#if ENABLE_REGEX + case CK_MSG_REGEXP: + msg_type_str = " regexp"; + break; +#endif + default: + msg_type_str = ""; + } + + snprintf(emsg, MAXSTR - 1,"For test %d:%s:%s Expected%s '%s', got '%s'", + i, master_test->tcname, master_test->test_name, msg_type_str, + expected_msg, got_msg); + emsg[MAXSTR - 1] = '\0'; + + /* + * NOTE: ck_abort_msg() will take the passed string + * and feed it to printf. We need to escape any + * '%' found, else they will result in odd formatting + * in ck_abort_msg(). + */ + emsg_escaped = escape_percent(emsg, MAXSTR); + + ck_abort_msg(emsg_escaped); + free(emsg_escaped); + } + } +} +END_TEST + +START_TEST(test_check_failure_lnos) +{ + int i; + int line_no; + int passed = 0; + int failed; + TestResult *tr; + + /* Create list of line numbers where failures occurred */ + rewind(line_num_failures); + + for (i = 0; i < sub_ntests; i++) { + if (master_tests[i].failure_type == CK_PASS) { + passed++; + continue; + } + + failed = i - passed; + + ck_assert_msg(i - passed <= sub_nfailed, NULL); + tr = tr_fail_array[failed]; + ck_assert_msg(tr != NULL, NULL); + line_no = get_next_failure_line_num(line_num_failures); + + if(line_no == -1) + { + ck_abort_msg("Did not find the %dth failure line number for suite %s, msg %s", + (failed+1), tr_tcname(tr), tr_msg(tr)); + } + + if (line_no > 0 && tr_lno(tr) != line_no) { + ck_abort_msg("For test %d (failure %d): Expected lno %d, got %d for suite %s, msg %s", + i, failed, line_no, tr_lno(tr), tr_tcname(tr), tr_msg(tr)); + } + } + + /* At this point, there should be no remaining failures */ + line_no = get_next_failure_line_num(line_num_failures); + ck_assert_msg(line_no == -1, + "No more failure line numbers expected, but found %d", line_no); +} +END_TEST + +START_TEST(test_check_failure_ftypes) +{ + int i; + int passed = 0; + TestResult *tr; + + for (i = 0; i < sub_ntests; i++) { + if (master_tests[i].failure_type == CK_PASS) { + passed++; + continue; + } + + ck_assert_msg(i - passed <= sub_nfailed, NULL); + tr = tr_fail_array[i - passed]; + ck_assert_msg(tr != NULL, NULL); + ck_assert_msg(master_tests[i].failure_type == tr_rtype(tr), + "Failure type wrong for test %d:%s:%s", + i, master_tests[i].tcname, master_tests[i].test_name); + } +} +END_TEST + +START_TEST(test_check_failure_lfiles) +{ + int i; + for (i = 0; i < sub_nfailed; i++) { + TestResult *tr = tr_fail_array[i]; + ck_assert_msg(tr != NULL, NULL); + ck_assert_msg(tr_lfile(tr) != NULL, "Bad file name for test %d", i); + ck_assert_msg(strstr(tr_lfile(tr), "check_check_sub.c") != 0, + "Bad file name for test %d:%s:%s", + i, master_tests[i].tcname, master_tests[i].test_name); + } +} +END_TEST + +START_TEST(test_check_tcnames) +{ + const char *tcname; + tcname = tr_tcname(tr_all_array[_i]); + if (strcmp(tcname, master_tests[_i].tcname) != 0) { + ck_abort_msg("Expected '%s', got '%s' for test %d:%s", + master_tests[_i].tcname, tcname, + _i, master_tests[_i].test_name); + } +} +END_TEST + +START_TEST(test_check_test_names) +{ + int i; + int line_no; + int passed = 0; + int failed; + TestResult *tr; + + rewind(test_names_file); + + for (i = 0; i < sub_ntests; i++) + { + char* test_name = get_next_test_name(test_names_file); + + if(test_name == NULL || strcmp(master_tests[i].test_name, test_name) != 0) + { + ck_abort_msg("Expected test name '%s' but found '%s' for test %d:%s", + master_tests[i].test_name, + (test_name == NULL ? "(null)" : test_name), + i, master_tests[i].tcname); + } + + free(test_name); + } +} +END_TEST + +START_TEST(test_check_all_msgs) +{ + const char *got_msg = tr_msg(tr_all_array[_i]); + master_test_t *master_test = &master_tests[_i]; + const char *expected_msg = master_test->msg; + char emsg[MAXSTR]; + const char *msg_type_str; + char err_text[256]; + int reg_err; + unsigned char not_equal = 0; + char *emsg_escaped; +#if ENABLE_REGEX + regex_t re; +#endif + + switch (master_test->msg_type) { + case CK_MSG_TEXT: + if (strcmp(got_msg, expected_msg) != 0) { + not_equal = 1; + } + break; +#if ENABLE_REGEX + case CK_MSG_REGEXP: { + reg_err = regcomp(&re, expected_msg, REG_EXTENDED | REG_NOSUB); + if (reg_err) { + regerror(reg_err, &re, err_text, sizeof(err_text)); + ck_assert_msg(reg_err == 0, + "For test %d:%s:%s Expected regexp '%s', but regcomp returned error '%s'", + _i, master_test->tcname, master_test->test_name, expected_msg, + err_text); + } + reg_err = regexec(&re, got_msg, 0, NULL, 0); + regfree(&re); + if (reg_err) { + not_equal = 1; + } + break; + } +#endif /* ENABLE_REGEX */ + } + + if (not_equal) { + switch(master_test->msg_type) { +#if ENABLE_REGEX + case CK_MSG_REGEXP: + msg_type_str = " regexp"; + break; +#endif + default: + msg_type_str = ""; + } + + snprintf(emsg, MAXSTR - 1, "For test %i:%s:%s expected%s '%s', got '%s'", + _i, master_test->tcname, master_test->test_name, msg_type_str, + expected_msg, got_msg); + emsg[MAXSTR - 1] = '\0'; + + /* + * NOTE: ck_abort_msg() will take the passed string + * and feed it to printf. We need to escape any + * '%' found, else they will result in odd formatting + * in ck_abort_msg(). + */ + emsg_escaped = escape_percent(emsg, MAXSTR); + + ck_abort_msg(emsg_escaped); + free(emsg_escaped); + } +} +END_TEST + +START_TEST(test_check_all_ftypes) +{ + ck_assert_msg(master_tests[_i].failure_type == tr_rtype(tr_all_array[_i]), + "For test %d:%s:%s failure type wrong, expected %d but got %d", + _i, master_tests[_i].tcname, master_tests[_i].test_name, + master_tests[_i].failure_type, tr_rtype(tr_all_array[_i])); +} +END_TEST + +int test_fixture_val = 0; +static void test_fixture_setup(void) +{ + test_fixture_val = 1; +} + +START_TEST(test_setup) +{ + ck_assert_msg (test_fixture_val == 1, + "Value not setup or changed across tests correctly"); + test_fixture_val = 2; +} +END_TEST + +static void test_fixture_teardown (void) +{ + test_fixture_val = 3; +} + +START_TEST(test_teardown) +{ + ck_assert_msg (test_fixture_val == 3, + "Value not changed correctly in teardown"); +} +END_TEST + + +Suite *make_master_suite (void) +{ + Suite *s; + TCase *tc_core; + TCase *tc_fixture; + TCase *tc_post_teardown; + + s = suite_create("Master"); + tc_core = tcase_create("Core Tests"); + tc_fixture = tcase_create("Fixture Setup Tests"); + suite_add_tcase (s, tc_core); + tcase_add_test (tc_core, test_check_nfailures); + tcase_add_test (tc_core, test_check_ntests_run); + tcase_add_test (tc_core, test_check_failure_msgs); + tcase_add_test (tc_core, test_check_failure_ftypes); + tcase_add_test (tc_core, test_check_failure_lnos); + tcase_add_test (tc_core, test_check_failure_lfiles); + tcase_add_test (tc_core, test_check_test_names); + tcase_add_loop_test (tc_core, test_check_tcnames, 0, sub_ntests); + tcase_add_loop_test (tc_core, test_check_all_msgs, 0, sub_ntests); + tcase_add_loop_test (tc_core, test_check_all_ftypes, 0, nr_of_master_tests); + tcase_add_unchecked_fixture(tc_fixture, test_fixture_setup, + test_fixture_teardown); + /* add the test 3 times to make sure we adequately test + preservation of fixture values across tests, regardless + of the order in which tests are added to the test case */ + tcase_add_test (tc_fixture, test_setup); +#if defined(HAVE_FORK) && HAVE_FORK==1 + /* The remaining test runs only work if fork() is available. */ + tcase_add_test (tc_fixture, test_setup); + tcase_add_test (tc_fixture, test_setup); +#endif /* HAVE_FORK */ + suite_add_tcase (s, tc_fixture); + tc_post_teardown = tcase_create ("Fixture Teardown Tests"); + tcase_add_test (tc_post_teardown, test_teardown); + suite_add_tcase (s, tc_post_teardown); + return s; +} + +static void init_signal_strings(void) +{ + /* strsignal may overwrite the string returned by the previous call */ + char *s8 = strdup(strsignal(8)); + char *s11 = strdup(strsignal(11)); + int n; + n = snprintf(signal_11_str, SIG_STR_LEN, "Received signal 11 (%s)", s11); + assert(n < SIG_STR_LEN); + n = snprintf(signal_11_8_str, SIG_STR_LEN, "Received signal 11 (%s), expected 8 (%s)", s11, s8); + assert(n < SIG_STR_LEN); + n = snprintf(signal_8_str, SIG_STR_LEN, "Received signal 8 (%s)", s8); + assert(n < SIG_STR_LEN); + free(s8); + free(s11); +} + +void setup (void) +{ + Suite *s = make_sub_suite(); + SRunner *sr = srunner_create(s); + + init_signal_strings(); + + /* + * Create files that will contain the test names and line numbers of the failures + * in check_check_sub.c, as they occur. + */ +#if !HAVE_MKSTEMP + test_names_file_name = tempnam(NULL, "check_test_names_"); + test_names_file = fopen(test_names_file_name, "w+b"); + line_num_failures_file_name = tempnam(NULL, "check_error_linenums_"); + line_num_failures = fopen(line_num_failures_file_name, "w+b"); +#else + test_names_file_name = strdup("check_test_names__XXXXXX"); + test_names_file = fdopen(mkstemp(test_names_file_name), "w+b"); + line_num_failures_file_name = strdup("check_error_linenums_XXXXXX"); + line_num_failures = fdopen(mkstemp(line_num_failures_file_name), "w+b"); +#endif + + srunner_add_suite(sr, make_sub2_suite()); + + srunner_run_all(sr, CK_VERBOSE); + tr_fail_array = srunner_failures(sr); + tr_all_array = srunner_results(sr); + sub_nfailed = srunner_ntests_failed(sr); + sub_ntests = srunner_ntests_run(sr); +} + +void cleanup (void) +{ + fclose(line_num_failures); + line_num_failures = NULL; + unlink(line_num_failures_file_name); + free(line_num_failures_file_name); + line_num_failures_file_name = NULL; + + fclose(test_names_file); + test_names_file = NULL; + unlink(test_names_file_name); + free(test_names_file_name); + test_names_file_name = NULL; +} + +void record_test_name(const char* test_name) +{ + int result; + + if(test_names_file == NULL) + { + /* + * The file may not be setup. This may be because some of the tests + * are being reused outside of the master suite. This is OK. + * If the master suite runs and does not find test names it will + * fail as expected. + */ + fprintf(stderr, "Test name file not setup, not reporting test failure"); + return; + } + + fprintf(test_names_file, "%s\n", test_name); + + result = fflush(test_names_file); + if(result != 0) + { + fprintf(stderr, "%s:%d: Error in call to fflush", __FILE__, __LINE__); + exit(1); + } +} + +char* get_next_test_name(FILE * file) +{ + char * line = NULL; + size_t length; + ssize_t written; + + written = getline(&line, &length, file); + /** + * getline() will leave a \n at the end of the line, + * remove it if it is present. + */ + if(written > 0 && line[written-1] == '\n') + { + line[written-1] = '\0'; + } + + return line; +} + +void record_failure_line_num(int linenum) +{ + int to_write; + ssize_t written; + int result; + char string[16]; + + /* + * Because this call will occur right before a failure, + * add +1 so the linenum will be that of the failure + */ + linenum += 1; + + to_write = snprintf(string, sizeof(string), "%d\n", linenum); + if(to_write <= 0) + { + fprintf(stderr, "%s:%d: Error in call to snprintf:", __FILE__, __LINE__); + exit(1); + } + + if(line_num_failures == NULL) + { + /* + * The file may not be setup. This may be because some of the tests + * are being reused outside of the master suite. This is OK. + * If the master suite runs and does not find line numbers it will + * fail as expected. + */ + fprintf(stderr, "Line number file not setup, not reporting test failure line: %s", string); + return; + } + + written = fwrite(string, 1, to_write, line_num_failures); + if(written != to_write) + { + fprintf(stderr, "%s:%d: Error in call to fwrite, wrote %ld instead of %d:", __FILE__, __LINE__, written, to_write); + exit(1); + } + + result = fflush(line_num_failures); + if(result != 0) + { + fprintf(stderr, "%s:%d: Error in call to fflush", __FILE__, __LINE__); + exit(1); + } +} + +int get_next_failure_line_num(FILE * file) +{ + char * line = NULL; + char * end = NULL; + size_t length; + ssize_t written; + int value = -1; + + written = getline(&line, &length, file); + + if(written > 0) + { + /* + * getline() will leave the \n at the end of the parsed line, if + * it is found. Remove this before passing to strtol, so we + * may detect invalid characters by checking for \0 instead + */ + + if(line[written-1] == '\n') + { + line[written-1] = '\0'; + } + + value = strtol(line, &end, 10); + + if(value <= 0 || *end != '\0') + { + fprintf(stderr, "%s:%d: Failed to convert next failure line number, found '%s'\n", + __FILE__, __LINE__, line); + exit(1); + } + } + + free(line); + + return value; +} diff --git a/tests/check_check_msg.c b/tests/check_check_msg.c new file mode 100644 index 0000000..3a1f38a --- /dev/null +++ b/tests/check_check_msg.c @@ -0,0 +1,188 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "../lib/libcompat.h" + +#include +#include +#include + +#include "check.h" +#include "check_msg.h" +#include "check_check.h" +#include "check_list.h" +#include "check_impl.h" + +START_TEST(test_send) +{ + TestResult *tr; + setup_messaging(); + send_ctx_info(CK_CTX_SETUP); + send_loc_info("abc123.c", 10); + send_ctx_info(CK_CTX_TEST); + send_loc_info("abc124.c", 22); + send_loc_info("abc125.c", 25); + send_failure_info("Oops"); + tr = receive_test_result(0); + teardown_messaging(); + + ck_assert_msg (tr != NULL, + "No test result received"); + ck_assert_msg (tr_ctx(tr) == CK_CTX_TEST, + "Bad CTX received"); + ck_assert_msg (strcmp(tr_msg(tr), "Oops") == 0, + "Bad failure msg received"); + ck_assert_msg (strcmp(tr_lfile(tr), "abc125.c") == 0, + "Bad loc file received"); + ck_assert_msg (tr_lno(tr) == 25, + "Bad loc line received"); + if (tr != NULL) + free(tr); +} +END_TEST + +START_TEST(test_send_big) +{ + TestResult *tr; + int i; + + setup_messaging(); + send_ctx_info(CK_CTX_SETUP); + send_loc_info("abc123.c", 10); + for (i = 0; i < 10000; i++) { + send_ctx_info(CK_CTX_TEST); + send_loc_info("abc124.c", i); + } + + tr = receive_test_result(0); + teardown_messaging(); + + ck_assert_msg (tr != NULL, + "No test result received"); + ck_assert_msg (tr_ctx(tr) == CK_CTX_TEST, + "Bad CTX received"); + ck_assert_msg (strcmp(tr_lfile(tr), "abc124.c") == 0, + "Bad loc file received"); + ck_assert_msg (tr_lno(tr) == i -1, + "Bad loc line received"); + if (tr != NULL) + tr_free(tr); +} +END_TEST + + +START_TEST(test_send_test_error) +{ + TestResult *tr; + setup_messaging(); + send_ctx_info(CK_CTX_SETUP); + send_loc_info("abc123.c", 10); + send_ctx_info(CK_CTX_TEST); + send_loc_info("abc124.c", 22); + send_loc_info("abc125.c", 25); + tr = receive_test_result(1); + teardown_messaging(); + + ck_assert_msg (tr != NULL, + "No test result received"); + ck_assert_msg (tr_ctx(tr) == CK_CTX_TEST, + "Bad CTX received"); + ck_assert_msg (strcmp(tr_lfile(tr), "abc125.c") == 0, + "Bad loc file received"); + ck_assert_msg (tr_lno(tr) == 25, + "Bad loc line received"); + if (tr != NULL) + tr_free(tr); +} +END_TEST + +START_TEST(test_send_with_passing_teardown) +{ + TestResult *tr; + setup_messaging(); + send_ctx_info(CK_CTX_SETUP); + send_loc_info("abc123.c", 10); + send_ctx_info(CK_CTX_TEST); + send_loc_info("abc124.c", 22); + send_loc_info("abc125.c", 25); + send_ctx_info(CK_CTX_TEARDOWN); + send_loc_info("abc126.c", 54); + tr = receive_test_result(0); + teardown_messaging(); + + ck_assert_msg (tr != NULL, + "No test result received"); + ck_assert_msg (tr_ctx(tr) == CK_CTX_TEST, + "Bad CTX received"); + ck_assert_msg (tr_msg(tr) == NULL, + "Bad failure msg received"); + ck_assert_msg (strcmp(tr_lfile(tr), "abc125.c") == 0, + "Bad loc file received"); + ck_assert_msg (tr_lno(tr) == 25, + "Bad loc line received"); + if (tr != NULL) + tr_free(tr); +} +END_TEST + +START_TEST(test_send_with_error_teardown) +{ + TestResult *tr; + setup_messaging(); + send_ctx_info(CK_CTX_SETUP); + send_loc_info("abc123.c", 10); + send_ctx_info(CK_CTX_TEST); + send_loc_info("abc124.c", 22); + send_loc_info("abc125.c", 25); + send_ctx_info(CK_CTX_TEARDOWN); + send_loc_info("abc126.c", 54); + tr = receive_test_result(1); + teardown_messaging(); + + ck_assert_msg (tr != NULL, + "No test result received"); + ck_assert_msg (tr_ctx(tr) == CK_CTX_TEARDOWN, + "Bad CTX received"); + ck_assert_msg (tr_msg(tr) == NULL, + "Bad failure msg received"); + ck_assert_msg (strcmp(tr_lfile(tr), "abc126.c") == 0, + "Bad loc file received"); + ck_assert_msg (tr_lno(tr) == 54, + "Bad loc line received"); + if (tr != NULL) + tr_free(tr); +} +END_TEST + + +Suite *make_msg_suite (void) +{ + Suite *s; + TCase *tc; + s = suite_create("Msg"); + tc = tcase_create("Core Tests"); + tcase_add_test(tc, test_send); + tcase_add_test(tc, test_send_big); + tcase_add_test(tc, test_send_test_error); + tcase_add_test(tc, test_send_with_passing_teardown); + tcase_add_test(tc, test_send_with_error_teardown); + suite_add_tcase(s, tc); + return s; +} diff --git a/tests/check_check_pack.c b/tests/check_check_pack.c new file mode 100644 index 0000000..7da7e57 --- /dev/null +++ b/tests/check_check_pack.c @@ -0,0 +1,473 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "../lib/libcompat.h" + +#include +#include +#include + +#include "check.h" +#include "check_pack.h" +#include "check_error.h" +#include "check_check.h" +#include "check_msg.h" + +static char errm[512]; + + +START_TEST(test_pack_fmsg) +{ + FailMsg *fmsg; + char *buf; + enum ck_msg_type type; + + fmsg = (FailMsg *)emalloc (sizeof (FailMsg)); + + fmsg->msg = (char *) "Hello, world!"; + pack (CK_MSG_FAIL, &buf, (CheckMsg *) fmsg); + + fmsg->msg = NULL; + upack (buf, (CheckMsg *) fmsg, &type); + + ck_assert_msg (type == CK_MSG_FAIL, + "Bad type unpacked for FailMsg"); + + ck_assert_msg (fmsg->msg != NULL, + "Unpacked string is NULL, should be Hello, World!"); + + if (strcmp (fmsg->msg, "Hello, world!") != 0) { + snprintf (errm, sizeof(errm), + "Unpacked string is %s, should be Hello, World!", + fmsg->msg); + fail (errm); + } + + free (fmsg->msg); + free (fmsg); + free (buf); +} +END_TEST + +START_TEST(test_pack_loc) +{ + LocMsg *lmsg; + char *buf; + enum ck_msg_type type; + + lmsg =(LocMsg *) emalloc (sizeof (LocMsg)); + lmsg->file = (char *) "abc123.c"; + lmsg->line = 125; + + pack (CK_MSG_LOC, &buf, (CheckMsg *) lmsg); + lmsg->file = NULL; + lmsg->line = 0; + upack (buf, (CheckMsg *) lmsg, &type); + + ck_assert_msg (type == CK_MSG_LOC, + "Bad type unpacked for LocMsg"); + + if (lmsg->line != 125) { + snprintf (errm, sizeof (errm), + "LocMsg line was %d, should be %d", + lmsg->line, 125); + fail (errm); + } + + if (strcmp (lmsg->file, "abc123.c") != 0) { + snprintf (errm, sizeof (errm), + "LocMsg file was %s, should be abc123.c", + lmsg->file); + fail (errm); + } + + free (lmsg->file); + free (lmsg); + free (buf); +} +END_TEST + +START_TEST(test_pack_ctx) +{ + CtxMsg cmsg; + char *buf; + enum ck_msg_type type; + + cmsg.ctx = CK_CTX_SETUP; + pack (CK_MSG_CTX, &buf, (CheckMsg *) &cmsg); + + cmsg.ctx = CK_CTX_TEARDOWN; + upack (buf, (CheckMsg *) &cmsg, &type); + + ck_assert_msg (type == CK_MSG_CTX, + "Bad type unpacked for CtxMsg"); + + if (cmsg.ctx != CK_CTX_SETUP) { + snprintf (errm, sizeof (errm), + "CtxMsg ctx got %d, expected %d", + cmsg.ctx, CK_CTX_SETUP); + fail (errm); + } + + free (buf); +} +END_TEST + + +START_TEST(test_pack_len) +{ + CtxMsg cmsg; + char *buf; + int n = 0; + enum ck_msg_type type; + + cmsg.ctx = CK_CTX_TEST; + n = pack (CK_MSG_CTX, &buf, (CheckMsg *) &cmsg); + ck_assert_msg (n > 0, "Return val from pack not set correctly"); + + /* Value below may change with different implementations of pack */ + ck_assert_msg (n == 8, "Return val from pack not correct"); + n = upack (buf, (CheckMsg *) &cmsg, &type); + if (n != 8) { + snprintf (errm, sizeof (errm), "%d bytes read from upack, should be 8", n); + fail (errm); + } + + free (buf); +} +END_TEST + +START_TEST(test_pack_abuse) +{ + char *buf; + CtxMsg cmsg; + enum ck_msg_type type; + + /* Should report -1 (e.g. invalid) if no buffer is passed */ + ck_assert_int_eq(pack(CK_MSG_CTX, NULL, (CheckMsg *) &cmsg), -1); + + /* Should report 0 (e.g. nothing packed) if no message is passed */ + ck_assert_int_eq(pack(CK_MSG_CTX, &buf, NULL), 0); + + /* Should report -1 (e.g. invalid) if no buffer is passed */ + ck_assert_int_eq(upack(NULL, (CheckMsg *) &cmsg, &type), -1); +} +END_TEST + +START_TEST(test_pack_ctx_limit) +{ + CtxMsg cmsg; + CtxMsg *cmsgp = NULL; + char *buf; + + cmsg.ctx = (enum ck_result_ctx)-1; + pack (CK_MSG_CTX, &buf, (CheckMsg *) &cmsg); + pack (CK_MSG_CTX, &buf, (CheckMsg *) cmsgp); +} +END_TEST + +START_TEST(test_pack_fail_limit) +{ + FailMsg fmsg; + FailMsg *fmsgp = NULL; + char *buf; + enum ck_msg_type type; + + fmsg.msg = (char *) ""; + pack (CK_MSG_FAIL, &buf, (CheckMsg *) &fmsg); + fmsg.msg = NULL; + upack (buf, (CheckMsg *) &fmsg, &type); + free (buf); + ck_assert_msg (fmsg.msg != NULL, + "Empty string not handled properly"); + ck_assert_msg (strcmp (fmsg.msg, "") == 0, + "Empty string not handled properly"); + + free (fmsg.msg); + fmsg.msg = NULL; + + pack (CK_MSG_FAIL, &buf, (CheckMsg *) &fmsg); + pack (CK_MSG_FAIL, &buf, (CheckMsg *) fmsgp); +} +END_TEST + +START_TEST(test_pack_loc_limit) +{ + LocMsg lmsg; + LocMsg *lmsgp = NULL; + char *buf; + enum ck_msg_type type; + + lmsg.file = (char *) ""; + lmsg.line = 0; + pack (CK_MSG_LOC, &buf, (CheckMsg *) &lmsg); + lmsg.file = NULL; + upack (buf, (CheckMsg *) &lmsg, &type); + ck_assert_msg (lmsg.file != NULL, + "Empty string not handled properly"); + ck_assert_msg (strcmp (lmsg.file, "") == 0, + "Empty string not handled properly"); + free (lmsg.file); + lmsg.file = NULL; + + pack (CK_MSG_LOC, &buf, (CheckMsg *) &lmsg); + pack (CK_MSG_LOC, &buf, (CheckMsg *) lmsgp); +} +END_TEST + +/* the ppack probably means 'pipe' pack */ +#if defined(HAVE_FORK) && HAVE_FORK==1 +START_TEST(test_ppack) +{ + FILE * result_file; + char * result_file_name = NULL; + CtxMsg cmsg; + LocMsg lmsg; + FailMsg fmsg; + RcvMsg *rmsg; + + cmsg.ctx = CK_CTX_TEST; + lmsg.file = (char *) "abc123.c"; + lmsg.line = 10; + fmsg.msg = (char *) "oops"; + result_file = open_tmp_file(&result_file_name); + free(result_file_name); + ppack (result_file, CK_MSG_CTX, (CheckMsg *) &cmsg); + ppack (result_file, CK_MSG_LOC, (CheckMsg *) &lmsg); + ppack (result_file, CK_MSG_FAIL, (CheckMsg *) &fmsg); + + rewind(result_file); + rmsg = punpack (result_file); + + ck_assert_msg (rmsg != NULL, + "Return value from ppack should always be malloc'ed"); + ck_assert_msg (rmsg->lastctx == CK_CTX_TEST, + "CTX not set correctly in ppack"); + ck_assert_msg (rmsg->fixture_line == -1, + "Default fixture loc not correct"); + ck_assert_msg (rmsg->fixture_file == NULL, + "Default fixture loc not correct"); + ck_assert_msg (rmsg->test_line == 10, + "Test line not received correctly"); + ck_assert_msg (strcmp(rmsg->test_file,"abc123.c") == 0, + "Test file not received correctly"); + ck_assert_msg (strcmp(rmsg->msg, "oops") == 0, + "Failure message not received correctly"); + + free(rmsg); + fclose(result_file); +} +END_TEST + +START_TEST(test_ppack_noctx) +{ + FILE * result_file; + char * result_file_name = NULL; + LocMsg lmsg; + FailMsg fmsg; + RcvMsg *rmsg; + + lmsg.file = (char *) "abc123.c"; + lmsg.line = 10; + fmsg.msg = (char *) "oops"; + result_file = open_tmp_file(&result_file_name); + free(result_file_name); + ppack (result_file, CK_MSG_LOC, (CheckMsg *) &lmsg); + ppack (result_file, CK_MSG_FAIL, (CheckMsg *) &fmsg); + + rewind(result_file); + rmsg = punpack (result_file); + + ck_assert_msg (rmsg == NULL, + "Result should be NULL with no CTX"); + + if (rmsg != NULL) + free (rmsg); + fclose(result_file); +} +END_TEST + +START_TEST(test_ppack_onlyctx) +{ + FILE * result_file; + char * result_file_name = NULL; + CtxMsg cmsg; + RcvMsg *rmsg; + + cmsg.ctx = CK_CTX_SETUP; + result_file = open_tmp_file(&result_file_name); + free(result_file_name); + ppack (result_file, CK_MSG_CTX, (CheckMsg *) &cmsg); + rewind(result_file); + rmsg = punpack (result_file); + + ck_assert_msg (rmsg != NULL && rmsg->msg == NULL, + "Result message should be NULL with only CTX"); + ck_assert_msg (rmsg->fixture_line == -1, + "Result loc line should be -1 with only CTX"); + ck_assert_msg (rmsg->test_line == -1, + "Result loc line should be -1 with only CTX"); + + if (rmsg != NULL) + free (rmsg); + fclose(result_file); +} +END_TEST + +START_TEST(test_ppack_multictx) +{ + FILE * result_file; + char * result_file_name = NULL; + CtxMsg cmsg; + LocMsg lmsg; + RcvMsg *rmsg; + + cmsg.ctx = CK_CTX_SETUP; + lmsg.line = 5; + lmsg.file = (char *) "abc123.c"; + result_file = open_tmp_file(&result_file_name); + free(result_file_name); + ppack (result_file, CK_MSG_CTX, (CheckMsg *) &cmsg); + ppack (result_file, CK_MSG_LOC, (CheckMsg *) &lmsg); + cmsg.ctx = CK_CTX_TEST; + ppack (result_file, CK_MSG_CTX, (CheckMsg *) &cmsg); + ppack (result_file, CK_MSG_LOC, (CheckMsg *) &lmsg); + cmsg.ctx = CK_CTX_TEARDOWN; + ppack (result_file, CK_MSG_CTX, (CheckMsg *) &cmsg); + rewind(result_file); + rmsg = punpack (result_file); + + ck_assert_msg (rmsg != NULL && rmsg->test_line == 5, + "Test loc not being preserved on CTX change"); + + ck_assert_msg (rmsg->fixture_line == -1, + "Fixture not reset on CTX change"); + + free (rmsg); + fclose(result_file); +} +END_TEST + +START_TEST(test_ppack_nofail) +{ + FILE * result_file; + char * result_file_name = NULL; + CtxMsg cmsg; + LocMsg lmsg; + RcvMsg *rmsg; + + lmsg.file = (char *) "abc123.c"; + lmsg.line = 10; + cmsg.ctx = CK_CTX_SETUP; + result_file = open_tmp_file(&result_file_name); + free(result_file_name); + ppack (result_file, CK_MSG_CTX, (CheckMsg *) &cmsg); + ppack (result_file, CK_MSG_LOC, (CheckMsg *) &lmsg); + rewind (result_file); + rmsg = punpack (result_file); + + ck_assert_msg (rmsg != NULL && rmsg->msg == NULL, + "Failure result should be NULL with no failure message"); + + free (rmsg); + fclose(result_file); +} +END_TEST + +#define BIG_MSG_LEN 1037 + +START_TEST(test_ppack_big) +{ + FILE * result_file; + char * result_file_name = NULL; + CtxMsg cmsg; + LocMsg lmsg; + FailMsg fmsg; + RcvMsg *rmsg; + + cmsg.ctx = CK_CTX_TEST; + lmsg.file = (char *)emalloc (BIG_MSG_LEN); + memset (lmsg.file,'a',BIG_MSG_LEN - 1); + lmsg.file[BIG_MSG_LEN - 1] = '\0'; + lmsg.line = 10; + fmsg.msg = (char *)emalloc (BIG_MSG_LEN); + memset (fmsg.msg, 'a', BIG_MSG_LEN - 1); + fmsg.msg[BIG_MSG_LEN - 1] = '\0'; + result_file = open_tmp_file(&result_file_name); + free(result_file_name); + ppack (result_file, CK_MSG_CTX, (CheckMsg *) &cmsg); + ppack (result_file, CK_MSG_LOC, (CheckMsg *) &lmsg); + ppack (result_file, CK_MSG_FAIL, (CheckMsg *) &fmsg); + rewind (result_file); + rmsg = punpack (result_file); + + ck_assert_msg (rmsg != NULL, + "Return value from ppack should always be malloc'ed"); + ck_assert_msg (rmsg->lastctx == CK_CTX_TEST, + "CTX not set correctly in ppack"); + ck_assert_msg (rmsg->test_line == 10, + "Test line not received correctly"); + ck_assert_msg (strcmp (rmsg->test_file, lmsg.file) == 0, + "Test file not received correctly"); + ck_assert_msg (strcmp (rmsg->msg, fmsg.msg) == 0, + "Failure message not received correctly"); + + free (rmsg); + free (lmsg.file); + free (fmsg.msg); + fclose(result_file); +} +END_TEST +#endif /* HAVE_FORK */ + +Suite *make_pack_suite(void) +{ + + Suite *s; + TCase *tc_core; + TCase *tc_limit; + + s = suite_create ("Pack"); + tc_core = tcase_create ("Core"); + tc_limit = tcase_create ("Limit"); + + suite_add_tcase (s, tc_core); + tcase_add_test (tc_core, test_pack_fmsg); + tcase_add_test (tc_core, test_pack_loc); + tcase_add_test (tc_core, test_pack_ctx); + tcase_add_test (tc_core, test_pack_len); + tcase_add_test (tc_core, test_pack_abuse); +#if defined(HAVE_FORK) && HAVE_FORK==1 + tcase_add_test (tc_core, test_ppack); + tcase_add_test (tc_core, test_ppack_noctx); + tcase_add_test (tc_core, test_ppack_onlyctx); + tcase_add_test (tc_core, test_ppack_multictx); + tcase_add_test (tc_core, test_ppack_nofail); +#endif /* HAVE_FORK */ + suite_add_tcase (s, tc_limit); + tcase_add_test (tc_limit, test_pack_ctx_limit); + tcase_add_test (tc_limit, test_pack_fail_limit); + tcase_add_test (tc_limit, test_pack_loc_limit); +#if defined(HAVE_FORK) && HAVE_FORK==1 + tcase_add_test (tc_limit, test_ppack_big); +#endif /* HAVE_FORK */ + + return s; +} diff --git a/tests/check_check_selective.c b/tests/check_check_selective.c new file mode 100644 index 0000000..31d5083 --- /dev/null +++ b/tests/check_check_selective.c @@ -0,0 +1,362 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "../lib/libcompat.h" + +#include +#include +#include +#include "check_check.h" + +static SRunner *sr; +static int test_tc11_executed; +static int test_tc12_executed; +static int test_tc21_executed; + +static void reset_executed (void) +{ + test_tc11_executed = 0; + test_tc12_executed = 0; + test_tc21_executed = 0; +} + +START_TEST(test_tc11) +{ + test_tc11_executed = 1; +} +END_TEST + +START_TEST(test_tc12) +{ + test_tc12_executed = 1; +} +END_TEST + +START_TEST(test_tc21) +{ + test_tc21_executed = 1; +} +END_TEST + +static void selective_setup (void) +{ + Suite *s1, *s2; + TCase *tc11, *tc12, *tc21; + + /* + * Create a test suite 'suite1' with two test cases 'tcase11' and + * 'tcase12' containing a single test each. + */ + s1 = suite_create ("suite1"); + tc11 = tcase_create ("tcase11"); + tcase_add_test (tc11, test_tc11); + tc12 = tcase_create ("tcase12"); + tcase_add_test (tc12, test_tc12); + suite_add_tcase (s1, tc11); + suite_add_tcase (s1, tc12); + + /* This line intentionally attempts to add an already + * added test case twice, to ensure it is not added + * again. If it was added again, when the test cases + * are freed a double-free failure will occur. */ + suite_add_tcase (s1, tc12); + + /* + * Create a test suite 'suite2' with one test case 'test21' + * containing two tests. + */ + s2 = suite_create ("suite2"); + tc21 = tcase_create ("tcase21"); + tcase_add_test (tc21, test_tc21); + suite_add_tcase (s2, tc21); + + sr = srunner_create (s1); + srunner_add_suite (sr, s2); + srunner_set_fork_status (sr, CK_NOFORK); +} + +static void selective_teardown (void) +{ + srunner_free (sr); +} + + +START_TEST(test_srunner_run_run_all) +{ + /* This test exercises the srunner_run function for the case where + both sname and tcname are NULL. That means to run all the test + cases in all the defined suites. */ + srunner_run (sr, + NULL, /* NULL tsuite name. */ + NULL, /* NULL tcase name. */ + CK_VERBOSE); + + ck_assert_msg (srunner_ntests_run(sr) == 3, + "Not all tests were executed."); + + reset_executed (); +} +END_TEST + +START_TEST(test_srunner_run_suite) +{ + /* This test makes the srunner_run function to run all the test + cases of a existing suite. */ + srunner_run (sr, + "suite1", + NULL, /* NULL tcase name. */ + CK_VERBOSE); + + ck_assert_msg (test_tc11_executed + && test_tc12_executed + && !test_tc21_executed, + "Expected tests were not executed."); + + reset_executed (); +} +END_TEST + +START_TEST(test_srunner_run_no_suite) +{ + /* This test makes the srunner_run function to run all the test + cases of a non-existing suite. */ + srunner_run (sr, + "non-existing-suite", + NULL, /* NULL tcase name. */ + CK_VERBOSE); + + ck_assert_msg (!(test_tc11_executed + || test_tc12_executed + || test_tc21_executed), + "An unexpected test was executed."); + + reset_executed (); +} +END_TEST + +START_TEST(test_srunner_run_tcase) +{ + /* This test makes the srunner_run function to run an specific + existing test case. */ + srunner_run (sr, + NULL, /* NULL suite name. */ + "tcase12", + CK_VERBOSE); + + ck_assert_msg (!test_tc11_executed + && test_tc12_executed + && !test_tc21_executed, + "Expected tests were not executed."); + + reset_executed (); +} +END_TEST + +START_TEST(test_srunner_no_tcase) +{ + /* This test makes the srunner_run function to run a non-existant + test case. */ + srunner_run (sr, + NULL, /* NULL suite name. */ + "non-existant-test-case", + CK_VERBOSE); + + ck_assert_msg (!(test_tc11_executed + || test_tc12_executed + || test_tc21_executed), + "An unexpected test was executed."); + + reset_executed (); +} +END_TEST + +START_TEST(test_srunner_suite_tcase) +{ + /* This test makes the srunner_run function to run a specific test + case of a specific test suite. */ + srunner_run (sr, + "suite2", + "tcase21", + CK_VERBOSE); + + ck_assert_msg (!test_tc11_executed + && !test_tc12_executed + && test_tc21_executed, + "Expected tests were not executed."); + + reset_executed (); +} +END_TEST + +START_TEST(test_srunner_suite_no_tcase) +{ + /* This test makes the srunner_run function to run a non existant + test case of a specific test suite. */ + srunner_run (sr, + "suite1", + "non-existant-test-case", + CK_VERBOSE); + + ck_assert_msg (!(test_tc11_executed + || test_tc12_executed + || test_tc21_executed), + "An unexpected test was executed."); + + reset_executed (); +} +END_TEST + + +#if HAVE_DECL_SETENV +START_TEST(test_srunner_run_suite_env) +{ + /* This test makes the srunner_run_all function to run all the test + cases of a existing suite. */ + setenv ("CK_RUN_SUITE", "suite1", 1); + srunner_run_all (sr, CK_VERBOSE); + + ck_assert_msg (test_tc11_executed + && test_tc12_executed + && !test_tc21_executed, + "Expected tests were not executed."); + + reset_executed (); + unsetenv ("CK_RUN_SUITE"); +} +END_TEST + +START_TEST(test_srunner_run_no_suite_env) +{ + /* This test makes the srunner_run_all function to run all the test + cases of a non-existing suite. */ + setenv ("CK_RUN_SUITE", "non-existing-suite", 1); + srunner_run_all (sr, CK_VERBOSE); + + ck_assert_msg (!(test_tc11_executed + || test_tc12_executed + || test_tc21_executed), + "An unexpected test was executed."); + + reset_executed (); + unsetenv ("CK_RUN_SUITE"); +} +END_TEST + +START_TEST(test_srunner_run_tcase_env) +{ + /* This test makes the srunner_run_all function to run an specific + existing test case. */ + setenv ("CK_RUN_CASE", "tcase12", 1); + srunner_run_all (sr, CK_VERBOSE); + + ck_assert_msg (!test_tc11_executed + && test_tc12_executed + && !test_tc21_executed, + "Expected tests were not executed."); + + reset_executed (); + unsetenv ("CK_RUN_CASE"); +} +END_TEST + +START_TEST(test_srunner_no_tcase_env) +{ + /* This test makes the srunner_run_all function to run a + non-existant test case. */ + setenv ("CK_RUN_CASE", "non-existant-test-case", 1); + srunner_run_all (sr, CK_VERBOSE); + + ck_assert_msg (!(test_tc11_executed + || test_tc12_executed + || test_tc21_executed), + "An unexpected test was executed."); + + reset_executed (); + unsetenv ("CK_RUN_CASE"); +} +END_TEST + +START_TEST(test_srunner_suite_tcase_env) +{ + /* This test makes the srunner_run_all function to run a specific test + case of a specific test suite. */ + setenv ("CK_RUN_SUITE", "suite2", 1); + setenv ("CK_RUN_CASE", "tcase21", 1); + srunner_run_all (sr, CK_VERBOSE); + + ck_assert_msg (!test_tc11_executed + && !test_tc12_executed + && test_tc21_executed, + "Expected tests were not executed."); + + reset_executed (); + unsetenv ("CK_RUN_SUITE"); + unsetenv ("CK_RUN_CASE"); +} +END_TEST + +START_TEST(test_srunner_suite_no_tcase_env) +{ + /* This test makes the srunner_run_all function to run a non + existant test case of a specific test suite. */ + setenv ("CK_RUN_SUITE", "suite1", 1); + setenv ("CK_RUN_CASE", "non-existant-test-case", 1); + srunner_run_all (sr, CK_VERBOSE); + + ck_assert_msg (!(test_tc11_executed + || test_tc12_executed + || test_tc21_executed), + "An unexpected test was executed."); + + reset_executed (); + unsetenv ("CK_RUN_SUITE"); + unsetenv ("CK_RUN_CASE"); +} +END_TEST +#endif /* HAVE_DECL_SETENV */ + +Suite *make_selective_suite (void) +{ + Suite *s = suite_create ("SelectiveTesting"); + TCase *tc = tcase_create ("Core"); + + suite_add_tcase (s, tc); + tcase_add_test (tc, test_srunner_run_run_all); + tcase_add_test (tc, test_srunner_run_suite); + tcase_add_test (tc, test_srunner_run_no_suite); + tcase_add_test (tc, test_srunner_run_tcase); + tcase_add_test (tc, test_srunner_no_tcase); + tcase_add_test (tc, test_srunner_suite_tcase); + tcase_add_test (tc, test_srunner_suite_no_tcase); + +#if HAVE_DECL_SETENV + tcase_add_test (tc, test_srunner_run_suite_env); + tcase_add_test (tc, test_srunner_run_no_suite_env); + tcase_add_test (tc, test_srunner_run_tcase_env); + tcase_add_test (tc, test_srunner_no_tcase_env); + tcase_add_test (tc, test_srunner_suite_tcase_env); + tcase_add_test (tc, test_srunner_suite_no_tcase_env); +#endif /* HAVE_DECL_SETENV */ + + tcase_add_unchecked_fixture (tc, + selective_setup, + selective_teardown); + return s; +} diff --git a/tests/check_check_sub.c b/tests/check_check_sub.c new file mode 100644 index 0000000..a6f8f27 --- /dev/null +++ b/tests/check_check_sub.c @@ -0,0 +1,3376 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "../lib/libcompat.h" + +#include +#include +#include +#include +#include "check_check.h" + + +START_TEST(test_lno) +{ + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_abort_msg("Failure expected"); +} +END_TEST + +#if defined(HAVE_FORK) && HAVE_FORK==1 +START_TEST(test_mark_lno) +{ + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + mark_point(); + exit(EXIT_FAILURE); /* should fail with mark_point above as line */ +} +END_TEST +#endif /* HAVE_FORK */ + +START_TEST(test_pass) +{ + record_test_name(tcase_name()); + + ck_assert_msg(1 == 1, "This test should pass"); + ck_assert_msg(9999, "This test should pass"); +} +END_TEST + +START_TEST(test_fail_unless) +{ + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + fail_unless(1 == 2, "This test should fail"); +} +END_TEST + +START_TEST(test_fail_if_pass) +{ + record_test_name(tcase_name()); + + fail_if(1 == 2, "This test should pass"); + fail_if(0, "This test should pass"); +} +END_TEST + +START_TEST(test_fail_if_fail) +{ + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + fail_if(1 == 1, "This test should fail"); +} +END_TEST + +START_TEST(test_fail_null_msg) +{ + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + fail_unless(2 == 3, NULL); +} +END_TEST + +#if defined(__GNUC__) +START_TEST(test_fail_no_msg) +{ + record_test_name(tcase_name()); + + /* taking out the NULL provokes an ISO C99 warning in GCC */ + record_failure_line_num(__LINE__); + fail_unless(4 == 5, NULL); +} +END_TEST +#endif /* __GNUC__ */ +START_TEST(test_fail_if_null_msg) +{ + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + fail_if(2 != 3, NULL); +} +END_TEST + +#if defined(__GNUC__) +START_TEST(test_fail_if_no_msg) +{ + record_test_name(tcase_name()); + + /* taking out the NULL provokes an ISO C99 warning in GCC */ + record_failure_line_num(__LINE__); + fail_if(4 != 5, NULL); +} +END_TEST +#endif /* __GNUC__ */ +START_TEST(test_fail_vararg_msg_1) +{ + int x = 3; + int y = 4; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + fail_unless(x == y, "%d != %d", x, y); +} +END_TEST + +START_TEST(test_fail_vararg_msg_2) +{ + int x = 5; + int y = 6; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + fail_if(x != y, "%d != %d", x, y); +} +END_TEST + +START_TEST(test_fail_vararg_msg_3) +{ + int x = 7; + int y = 7; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + fail("%d == %d", x, y); +} +END_TEST + +#if defined(__GNUC__) +START_TEST(test_fail_empty) +{ + record_test_name(tcase_name()); + + /* plain fail() doesn't compile with xlc in C mode because of `, ## __VA_ARGS__' problem */ + /* on the other hand, taking out the NULL provokes an ISO C99 warning in GCC */ + record_failure_line_num(__LINE__); + fail(NULL); +} +END_TEST +#endif /* __GNUC__ */ + +START_TEST(test_ck_abort) +{ + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_abort(); +} +END_TEST + +START_TEST(test_ck_abort_msg) +{ + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_abort_msg("Failure expected"); +} +END_TEST + +/* FIXME: perhaps passing NULL to ck_abort_msg should be an error. */ +START_TEST(test_ck_abort_msg_null) +{ + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_abort_msg(NULL); +} +END_TEST + +/* These ck_assert tests are all designed to fail on the last + assertion. */ + +START_TEST(test_ck_assert) +{ + int x = 3; + int y = 3; + + record_test_name(tcase_name()); + + ck_assert(1); + ck_assert(x == y); + y++; + ck_assert(x != y); + record_failure_line_num(__LINE__); + ck_assert(x == y); +} +END_TEST + +START_TEST(test_ck_assert_null) +{ + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert(0); +} +END_TEST + +START_TEST(test_ck_assert_with_mod) +{ + int f = 1; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert(1%f == 1); +} +END_TEST + +START_TEST(test_ck_assert_int_eq) +{ + int x = 3; + int y = 3; + + record_test_name(tcase_name()); + + ck_assert_int_eq(x, y); + y++; + record_failure_line_num(__LINE__); + ck_assert_int_eq(x, y); +} +END_TEST + +START_TEST(test_ck_assert_int_eq_with_mod) +{ + int d = 2; + int f = 1; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_int_eq(3%d, 2%f); +} +END_TEST + +START_TEST(test_ck_assert_int_ne) +{ + int x = 3; + int y = 2; + + record_test_name(tcase_name()); + + ck_assert_int_ne(x, y); + y++; + record_failure_line_num(__LINE__); + ck_assert_int_ne(x, y); +} +END_TEST + +START_TEST(test_ck_assert_int_ne_with_mod) +{ + int d = 2; + int f = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_int_ne(3%d, 3%f); +} +END_TEST + +START_TEST(test_ck_assert_int_lt) +{ + int x = 2; + int y = 3; + + record_test_name(tcase_name()); + + ck_assert_int_lt(x, y); + record_failure_line_num(__LINE__); + ck_assert_int_lt(x, x); +} +END_TEST + +START_TEST(test_ck_assert_int_lt_with_mod) +{ + int d = 2; + int f = 1; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_int_lt(3%d, 3%f); +} +END_TEST + +START_TEST(test_ck_assert_int_le) +{ + int x = 2; + int y = 3; + + record_test_name(tcase_name()); + + ck_assert_int_le(x, y); + ck_assert_int_le(x, x); + record_failure_line_num(__LINE__); + ck_assert_int_le(y, x); +} +END_TEST + +START_TEST(test_ck_assert_int_le_with_mod) +{ + int d = 2; + int f = 1; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_int_le(3%d, 2%f); +} +END_TEST + +START_TEST(test_ck_assert_int_gt) +{ + int x = 2; + int y = 3; + + record_test_name(tcase_name()); + + ck_assert_int_gt(y, x); + record_failure_line_num(__LINE__); + ck_assert_int_gt(y, y); +} +END_TEST + +START_TEST(test_ck_assert_int_gt_with_mod) +{ + int d = 1; + int f = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_int_gt(3%d, 3%f); +} +END_TEST + +START_TEST(test_ck_assert_int_ge) +{ + int x = 2; + int y = 3; + + record_test_name(tcase_name()); + + ck_assert_int_ge(y, x); + ck_assert_int_ge(y, x); + record_failure_line_num(__LINE__); + ck_assert_int_ge(x, y); +} +END_TEST + +START_TEST(test_ck_assert_int_ge_with_mod) +{ + int d = 1; + int f = 3; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_int_ge(3%d, 4%f); +} +END_TEST + +START_TEST(test_ck_assert_int_expr) +{ + int x = 1; + int y = 0; + + record_test_name(tcase_name()); + + ck_assert_int_eq(x, ++y); + ck_assert_int_eq(x, y); +} END_TEST + +START_TEST(test_ck_assert_uint_eq) +{ + unsigned int x = 3; + unsigned int y = 3; + + record_test_name(tcase_name()); + + ck_assert_uint_eq(x, y); + y++; + record_failure_line_num(__LINE__); + ck_assert_uint_eq(x, y); +} +END_TEST + +START_TEST(test_ck_assert_uint_eq_with_mod) +{ + int d = 2; + int f = 1; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_uint_eq(3%d, 1%f); +} +END_TEST + +START_TEST(test_ck_assert_uint_ne) +{ + unsigned int x = 3; + unsigned int y = 2; + + record_test_name(tcase_name()); + + ck_assert_uint_ne(x, y); + y++; + record_failure_line_num(__LINE__); + ck_assert_uint_ne(x, y); +} +END_TEST + +START_TEST(test_ck_assert_uint_ne_with_mod) +{ + int d = 1; + int f = 1; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_uint_ne(1%d, 1%f); +} +END_TEST + +START_TEST(test_ck_assert_uint_lt) +{ + unsigned int x = 2; + unsigned int y = 3; + + record_test_name(tcase_name()); + + ck_assert_uint_lt(x, y); + record_failure_line_num(__LINE__); + ck_assert_uint_lt(x, x); +} +END_TEST + +START_TEST(test_ck_assert_uint_lt_with_mod) +{ + int d = 2; + int f = 1; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_uint_lt(3%d, 1%f); +} +END_TEST + +START_TEST(test_ck_assert_uint_le) +{ + unsigned int x = 2; + unsigned int y = 3; + + record_test_name(tcase_name()); + + ck_assert_uint_le(x, y); + ck_assert_uint_le(x, x); + record_failure_line_num(__LINE__); + ck_assert_uint_le(y, x); +} +END_TEST + +START_TEST(test_ck_assert_uint_le_with_mod) +{ + int d = 2; + int f = 1; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_uint_le(3%d, 1%f); +} +END_TEST + +START_TEST(test_ck_assert_uint_gt) +{ + unsigned int x = 2; + unsigned int y = 3; + + record_test_name(tcase_name()); + + ck_assert_uint_gt(y, x); + record_failure_line_num(__LINE__); + ck_assert_uint_gt(y, y); +} +END_TEST + +START_TEST(test_ck_assert_uint_gt_with_mod) +{ + int d = 1; + int f = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_uint_gt(1%d, 3%f); +} +END_TEST + +START_TEST(test_ck_assert_uint_ge) +{ + unsigned int x = 2; + unsigned int y = 3; + + record_test_name(tcase_name()); + + ck_assert_uint_ge(y, x); + ck_assert_uint_ge(y, x); + record_failure_line_num(__LINE__); + ck_assert_uint_ge(x, y); +} +END_TEST + +START_TEST(test_ck_assert_uint_ge_with_mod) +{ + int d = 1; + int f = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_uint_ge(1%d, 3%f); +} +END_TEST + +START_TEST(test_ck_assert_uint_expr) +{ + unsigned int x = 1; + unsigned int y = 0; + + record_test_name(tcase_name()); + + ck_assert_uint_eq(x, ++y); + ck_assert_uint_eq(x, y); +} END_TEST + +START_TEST(test_ck_assert_float_eq) +{ + float x = 1.1f; + float y = 1.1f; + + record_test_name(tcase_name()); + + ck_assert_float_eq(x, y); + y+=0.1f; + record_failure_line_num(__LINE__); + ck_assert_float_eq(x, y); +} +END_TEST + +START_TEST(test_ck_assert_float_eq_with_mod) +{ + int d = 2; + int f = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_float_eq(3%d, 2%f); +} +END_TEST + +START_TEST(test_ck_assert_float_ne) +{ + float x = 1.1f; + float y = 1.2f; + + record_test_name(tcase_name()); + + ck_assert_float_ne(x, y); + y = x; + record_failure_line_num(__LINE__); + ck_assert_float_ne(x, y); +} +END_TEST + +START_TEST(test_ck_assert_float_ne_with_mod) +{ + int d = 2; + int f = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_float_ne(1%d, 1%f); +} +END_TEST + +START_TEST(test_ck_assert_float_lt) +{ + float x = 2.0f; + float y = 2.5f; + + record_test_name(tcase_name()); + + ck_assert_float_lt(x, y); + y-=1.0f; + record_failure_line_num(__LINE__); + ck_assert_float_lt(x, y); +} +END_TEST + +START_TEST(test_ck_assert_float_lt_with_mod) +{ + int d = 2; + int f = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_float_lt(3%d, 2%f); +} +END_TEST + +START_TEST(test_ck_assert_float_le) +{ + float x = 2.0f; + float y = 2.5f; + + record_test_name(tcase_name()); + + ck_assert_float_le(x, y); + ck_assert_float_le(x, x); + y-=1.0f; + record_failure_line_num(__LINE__); + ck_assert_float_le(x, y); +} +END_TEST + +START_TEST(test_ck_assert_float_le_with_mod) +{ + int d = 2; + int f = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_float_le(3%d, 2%f); +} +END_TEST + +START_TEST(test_ck_assert_float_gt) +{ + float x = 2.5f; + float y = 2.0f; + + record_test_name(tcase_name()); + + ck_assert_float_gt(x, y); + y+=1.0f; + record_failure_line_num(__LINE__); + ck_assert_float_gt(x, y); +} +END_TEST + +START_TEST(test_ck_assert_float_gt_with_mod) +{ + int d = 2; + int f = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_float_gt(2%d, 3%f); +} +END_TEST + +START_TEST(test_ck_assert_float_ge) +{ + float x = 2.5f; + float y = 2.0f; + + record_test_name(tcase_name()); + + ck_assert_float_ge(x, y); + ck_assert_float_ge(x, x); + y+=1.0f; + record_failure_line_num(__LINE__); + ck_assert_float_ge(x, y); +} +END_TEST + +START_TEST(test_ck_assert_float_ge_with_mod) +{ + int d = 2; + int f = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_float_ge(2%d, 3%f); +} +END_TEST + +START_TEST(test_ck_assert_float_with_expr) +{ + float x[] = {NAN, 1.1f, 1.1f, 1.2f, 1.2f, NAN}; + float y = 1.1f; + int i; + + record_test_name(tcase_name()); + + i = 1; + ck_assert_float_eq(x[i++], y); + ck_assert_float_eq(x[i++], y); + + i = 4; + ck_assert_float_ne(x[i--], y); + ck_assert_float_ne(x[i--], y); + + y = 1.15f; + + i = 1; + ck_assert_float_le(x[i++], y); + ck_assert_float_le(x[i++], y); + + i = 1; + ck_assert_float_lt(x[i++], y); + ck_assert_float_lt(x[i++], y); + + i = 4; + ck_assert_float_gt(x[i--], y); + ck_assert_float_gt(x[i--], y); + + i = 4; + ck_assert_float_ge(x[i--], y); + ck_assert_float_ge(x[i--], y); +} +END_TEST + +START_TEST(test_ck_assert_float_eq_tol) +{ + float x = 0.0001f; + float y = 0.0003f; + float t = 0.001f; + + record_test_name(tcase_name()); + + ck_assert_float_eq_tol(x, y, t); + ck_assert_float_eq_tol(x, x, t); + x*=10.0f; + y*=10.0f; + t*=10.0f; + ck_assert_float_eq_tol(x, y, t); + t/=10.0f; + record_failure_line_num(__LINE__); + ck_assert_float_eq_tol(x, y, t); +} +END_TEST + +START_TEST(test_ck_assert_float_eq_tol_with_mod) +{ + int d = 2; + int f = 2; + int p = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_float_eq_tol(3%d, 2%f, 2%p); +} +END_TEST + +START_TEST(test_ck_assert_float_ne_tol) +{ + float x = 0.0001f; + float y = 0.0002f; + float t = 0.0001f; + + record_test_name(tcase_name()); + + ck_assert_float_ne_tol(x, y, t); + x*=10.0f; + y*=10.0f; + t*=10.0f; + ck_assert_float_ne_tol(x, y, t); + t*=10.0f; + record_failure_line_num(__LINE__); + ck_assert_float_ne_tol(x, y, t); +} +END_TEST + +START_TEST(test_ck_assert_float_ne_tol_with_mod) +{ + int d = 2; + int f = 2; + int p = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_float_ne_tol(3%d, 3%f, 3%p); +} +END_TEST + +START_TEST(test_ck_assert_float_ge_tol) +{ + float x = 0.001f; + float y = 0.003f; + float t = 0.001f; + + record_test_name(tcase_name()); + + ck_assert_float_ge_tol(y, x, t); + ck_assert_float_ge_tol(x, x, t); + ck_assert_float_ge_tol(y, y, t); + x*=10.0f; + y*=10.0f; + t*=10.0f; + ck_assert_float_ge_tol(y, x, t); + ck_assert_float_ge_tol(x, x, t); + ck_assert_float_ge_tol(y, y, t); + record_failure_line_num(__LINE__); + ck_assert_float_ge_tol(x, y, t); +} +END_TEST + +START_TEST(test_ck_assert_float_ge_tol_with_mod) +{ + int d = 2; + int f = 2; + int p = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_float_ge_tol(2%d, 3%f, 3%p); +} +END_TEST + +START_TEST(test_ck_assert_float_le_tol) +{ + float x = 0.001f; + float y = 0.003f; + float t = 0.001f; + + record_test_name(tcase_name()); + + ck_assert_float_le_tol(x, y, t); + ck_assert_float_le_tol(x, x, t); + ck_assert_float_le_tol(y, y, t); + x*=10.0f; + y*=10.0f; + t*=10.0f; + ck_assert_float_le_tol(x, y, t); + ck_assert_float_le_tol(x, x, t); + ck_assert_float_le_tol(y, y, t); + record_failure_line_num(__LINE__); + ck_assert_float_le_tol(y, x, t); +} +END_TEST + +START_TEST(test_ck_assert_float_le_tol_with_mod) +{ + int d = 2; + int f = 2; + int p = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_float_le_tol(3%d, 2%f, 3%p); +} +END_TEST + +START_TEST(test_ck_assert_float_tol_with_expr) +{ + float x[] = {NAN, 1.1f, 1.1f, 1.2f, 1.2f, NAN}; + float y = 1.1f; + float t = 0.01f; + int i; + + record_test_name(tcase_name()); + + i = 1; + ck_assert_float_eq_tol(x[i++], y, t); + ck_assert_float_eq_tol(x[i++], y, t); + + i = 4; + ck_assert_float_ne_tol(x[i--], y, t); + ck_assert_float_ne_tol(x[i--], y, t); + + y = 1.15f; + + i = 1; + ck_assert_float_le_tol(x[i++], y, t); + ck_assert_float_le_tol(x[i++], y, t); + + i = 4; + ck_assert_float_ge_tol(x[i--], y, t); + ck_assert_float_ge_tol(x[i--], y, t); +} +END_TEST + +START_TEST(test_ck_assert_float_finite) +{ + float x = 0.0001f; + float t = 1.0f; + + record_test_name(tcase_name()); + + ck_assert_float_finite(x); + // MS VS doesn't allow explicit division by zero + x = 1.0f / (1.0f - t); + record_failure_line_num(__LINE__); + ck_assert_float_finite(x); +} +END_TEST + +START_TEST(test_ck_assert_float_finite_with_mod) +{ + int d = 2; + float t = 1.0f; + float x = 1.0f / (1.0f - t); + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_float_finite(x*(1%d)); +} +END_TEST + +START_TEST(test_ck_assert_float_infinite) +{ + float t = 1.0f; + float x = 1.0f / (1.0f - t); + + record_test_name(tcase_name()); + + ck_assert_float_infinite(x); + x = -1.0f / (1.0f - t); + ck_assert_float_infinite(x); + x = 0.0f; + record_failure_line_num(__LINE__); + ck_assert_float_infinite(x); +} +END_TEST + +START_TEST(test_ck_assert_float_infinite_with_mod) +{ + int d = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_float_infinite(2%d); +} +END_TEST + +START_TEST(test_ck_assert_float_nan) +{ + float t = 1.0f; + float x = 0.0f / (1.0f - t); + + record_test_name(tcase_name()); + + ck_assert_float_nan(x); + x = 1.0f / (1.0f - t); + record_failure_line_num(__LINE__); + ck_assert_float_nan(x); +} +END_TEST + +START_TEST(test_ck_assert_float_nan_with_mod) +{ + int d = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_float_nan(2%d); +} +END_TEST + +START_TEST(test_ck_assert_float_nonnan) +{ + float x = 0.0f; + float t = 1.0f; + + record_test_name(tcase_name()); + + ck_assert_float_nonnan(x); +#if ENABLE_REGEX + x = 0.0f / (1.0f - t); + record_failure_line_num(__LINE__); + ck_assert_float_nonnan(x); +#else + (void)t; /* unused */ +#endif +} +END_TEST + +START_TEST(test_ck_assert_float_nonnan_with_mod) +{ + int s = 2; + float t = 1.0f; + float x; + + record_test_name(tcase_name()); + + ck_assert_float_nonnan(2%s); +#if ENABLE_REGEX + x = 0.0f / (1.0f - t); + record_failure_line_num(__LINE__); + ck_assert_float_nonnan((2%s)*x); +#else + (void)x; /* unused */ + (void)t; /* unused */ +#endif +} +END_TEST + +START_TEST(test_ck_assert_float_nan_and_inf_with_expr) +{ + float x[] = {0.0f, 0.0f, INFINITY, INFINITY, NAN, NAN, 0.0f, 0.0f, NAN}; + int i = 0; + + record_test_name(tcase_name()); + + ck_assert_float_finite(x[i++]); + ck_assert_float_finite(x[i++]); + ck_assert_float_infinite(x[i++]); + ck_assert_float_infinite(x[i++]); + ck_assert_float_nan(x[i++]); + ck_assert_float_nan(x[i++]); + ck_assert_float_nonnan(x[i++]); + ck_assert_float_nonnan(x[i++]); +} +END_TEST + +START_TEST(test_ck_assert_double_eq) +{ + double x = 1.1; + double y = 1.1; + + record_test_name(tcase_name()); + + ck_assert_double_eq(x, y); + y+=0.1; + record_failure_line_num(__LINE__); + ck_assert_double_eq(x, y); +} +END_TEST + +START_TEST(test_ck_assert_double_eq_with_mod) +{ + int d = 2; + int f = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_double_eq(3%d, 2%f); +} +END_TEST + +START_TEST(test_ck_assert_double_eq_with_promotion) +{ + float x = 0.1; + double y = x; + + record_test_name(tcase_name()); + + ck_assert_double_eq(x, y); +} +END_TEST + +START_TEST(test_ck_assert_double_eq_with_conv) +{ + float x = 0.1; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_double_eq(x, 0.1); +} +END_TEST + +START_TEST(test_ck_assert_double_ne) +{ + double x = 1.1; + double y = 1.2; + + record_test_name(tcase_name()); + + ck_assert_double_ne(x, y); + y = x; + record_failure_line_num(__LINE__); + ck_assert_double_ne(x, y); +} +END_TEST + +START_TEST(test_ck_assert_double_ne_with_mod) +{ + int d = 2; + int f = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_double_ne(1%d, 1%f); +} +END_TEST + +START_TEST(test_ck_assert_double_lt) +{ + double x = 2.0; + double y = 2.5; + + record_test_name(tcase_name()); + + ck_assert_double_lt(x, y); + y-=1; + record_failure_line_num(__LINE__); + ck_assert_double_lt(x, y); +} +END_TEST + +START_TEST(test_ck_assert_double_lt_with_mod) +{ + int d = 2; + int f = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_double_lt(3%d, 2%f); +} +END_TEST + +START_TEST(test_ck_assert_double_le) +{ + double x = 2.0; + double y = 2.5; + + record_test_name(tcase_name()); + + ck_assert_double_le(x, y); + ck_assert_double_le(x, x); + y-=1; + record_failure_line_num(__LINE__); + ck_assert_double_le(x, y); +} +END_TEST + +START_TEST(test_ck_assert_double_le_with_mod) +{ + int d = 2; + int f = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_double_le(3%d, 2%f); +} +END_TEST + +START_TEST(test_ck_assert_double_gt) +{ + double x = 2.5; + double y = 2.0; + + record_test_name(tcase_name()); + + ck_assert_double_gt(x, y); + y+=1; + record_failure_line_num(__LINE__); + ck_assert_double_gt(x, y); +} +END_TEST + +START_TEST(test_ck_assert_double_gt_with_mod) +{ + int d = 2; + int f = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_double_gt(2%d, 3%f); +} +END_TEST + +START_TEST(test_ck_assert_double_ge) +{ + double x = 2.5; + double y = 2.0; + + record_test_name(tcase_name()); + + ck_assert_double_ge(x, y); + ck_assert_double_ge(x, x); + y+=1; + record_failure_line_num(__LINE__); + ck_assert_double_ge(x, y); +} +END_TEST + +START_TEST(test_ck_assert_double_ge_with_mod) +{ + int d = 2; + int f = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_double_ge(2%d, 3%f); +} +END_TEST + +START_TEST(test_ck_assert_double_with_expr) +{ + double x[] = {NAN, 1.1, 1.1, 1.2, 1.2, NAN}; + double y = 1.1; + int i; + + record_test_name(tcase_name()); + + i = 1; + ck_assert_double_eq(x[i++], y); + ck_assert_double_eq(x[i++], y); + + i = 4; + ck_assert_double_ne(x[i--], y); + ck_assert_double_ne(x[i--], y); + + y = 1.15; + + i = 1; + ck_assert_double_le(x[i++], y); + ck_assert_double_le(x[i++], y); + + i = 1; + ck_assert_double_lt(x[i++], y); + ck_assert_double_lt(x[i++], y); + + i = 4; + ck_assert_double_gt(x[i--], y); + ck_assert_double_gt(x[i--], y); + + i = 4; + ck_assert_double_ge(x[i--], y); + ck_assert_double_ge(x[i--], y); +} +END_TEST + +START_TEST(test_ck_assert_double_eq_tol) +{ + double x = 0.0001; + double y = 0.0002; + double t = 0.001; + + record_test_name(tcase_name()); + + ck_assert_double_eq_tol(x, y, t); + ck_assert_double_eq_tol(x, x, t); + x*=10; + y*=10; + t*=10; + ck_assert_double_eq_tol(x, y, t); + t/=10; + record_failure_line_num(__LINE__); + ck_assert_double_eq_tol(x, y, t); +} +END_TEST + +START_TEST(test_ck_assert_double_eq_tol_with_mod) +{ + int d = 2; + int f = 2; + int p = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_double_eq_tol(3%d, 2%f, 2%p); +} +END_TEST + +START_TEST(test_ck_assert_double_ne_tol) +{ + double x = 0.0001; + double y = 0.0002; + double t = 0.0001; + + record_test_name(tcase_name()); + + ck_assert_double_ne_tol(x, y, t); + x*=10; + y*=10; + t*=10; + ck_assert_double_ne_tol(x, y, t); + t*=10; + record_failure_line_num(__LINE__); + ck_assert_double_ne_tol(x, y, t); +} +END_TEST + +START_TEST(test_ck_assert_double_ne_tol_with_mod) +{ + int d = 2; + int f = 2; + int p = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_double_ne_tol(3%d, 3%f, 3%p); +} +END_TEST + +START_TEST(test_ck_assert_double_ge_tol) +{ + double x = 0.001; + double y = 0.003; + double t = 0.001; + + record_test_name(tcase_name()); + + ck_assert_double_ge_tol(y, x, t); + ck_assert_double_ge_tol(x, x, t); + ck_assert_double_ge_tol(y, y, t); + x*=10.0; + y*=10.0; + t*=10.0; + ck_assert_double_ge_tol(y, x, t); + ck_assert_double_ge_tol(x, x, t); + ck_assert_double_ge_tol(y, y, t); + record_failure_line_num(__LINE__); + ck_assert_double_ge_tol(x, y, t); +} +END_TEST + +START_TEST(test_ck_assert_double_ge_tol_with_mod) +{ + int d = 2; + int f = 2; + int p = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_double_ge_tol(2%d, 3%f, 3%p); +} +END_TEST + +START_TEST(test_ck_assert_double_le_tol) +{ + double x = 0.001; + double y = 0.003; + double t = 0.001; + + record_test_name(tcase_name()); + + ck_assert_double_le_tol(x, y, t); + ck_assert_double_le_tol(x, x, t); + ck_assert_double_le_tol(y, y, t); + x*=10.0; + y*=10.0; + t*=10.0; + ck_assert_double_le_tol(x, y, t); + ck_assert_double_le_tol(x, x, t); + ck_assert_double_le_tol(y, y, t); + record_failure_line_num(__LINE__); + ck_assert_double_le_tol(y, x, t); +} +END_TEST + +START_TEST(test_ck_assert_double_le_tol_with_mod) +{ + int d = 2; + int f = 2; + int p = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_double_le_tol(3%d, 2%f, 3%p); +} +END_TEST + +START_TEST(test_ck_assert_double_tol_with_expr) +{ + double x[] = {NAN, 1.1, 1.1, 1.2, 1.2, NAN}; + double y = 1.1; + double t = 0.01; + int i; + + record_test_name(tcase_name()); + + i = 1; + ck_assert_double_eq_tol(x[i++], y, t); + ck_assert_double_eq_tol(x[i++], y, t); + + i = 4; + ck_assert_double_ne_tol(x[i--], y, t); + ck_assert_double_ne_tol(x[i--], y, t); + + y = 1.15; + + i = 1; + ck_assert_double_le_tol(x[i++], y, t); + ck_assert_double_le_tol(x[i++], y, t); + + i = 4; + ck_assert_double_ge_tol(x[i--], y, t); + ck_assert_double_ge_tol(x[i--], y, t); +} +END_TEST + +START_TEST(test_ck_assert_double_finite) +{ + double x = 0.0001; + double t = 1; + + record_test_name(tcase_name()); + + ck_assert_double_finite(x); + // MS VS doesn't allow explicit division by zero + x = 1.0 / (1.0 - t); + record_failure_line_num(__LINE__); + ck_assert_double_finite(x); +} +END_TEST + +START_TEST(test_ck_assert_double_finite_with_mod) +{ + int d = 2; + double t = 1; + double x = 1.0 / (1.0 - t); + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_double_finite(x*(1%d)); +} +END_TEST + +START_TEST(test_ck_assert_double_infinite) +{ + double t = 1; + double x = 1.0 / (1.0 - t); + + record_test_name(tcase_name()); + + ck_assert_double_infinite(x); + x = -1.0 / (1.0 - t); + ck_assert_double_infinite(x); + x = 0; + record_failure_line_num(__LINE__); + ck_assert_double_infinite(x); +} +END_TEST + +START_TEST(test_ck_assert_double_infinite_with_mod) +{ + int d = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_double_infinite(2%d); +} +END_TEST + +START_TEST(test_ck_assert_double_nan) +{ + double t = 1; + double x = 0.0 / (1.0 - t); + + record_test_name(tcase_name()); + + ck_assert_double_nan(x); + x = 1.0 / (1.0 - t); + record_failure_line_num(__LINE__); + ck_assert_double_nan(x); +} +END_TEST + +START_TEST(test_ck_assert_double_nan_with_mod) +{ + int d = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_double_nan(2%d); +} +END_TEST + +START_TEST(test_ck_assert_double_nonnan) +{ + double x = 0; + double t = 1; + + record_test_name(tcase_name()); + + ck_assert_double_nonnan(x); +#if ENABLE_REGEX + x = 0.0 / (1.0 - t); + record_failure_line_num(__LINE__); + ck_assert_double_nonnan(x); +#else + (void)t; /* unused */ +#endif +} +END_TEST + +START_TEST(test_ck_assert_double_nonnan_with_mod) +{ + int s = 2; + double t = 1.0; + double x; + + record_test_name(tcase_name()); + + ck_assert_double_nonnan(2%s); +#if ENABLE_REGEX + x = 0.0 / (1.0 - t); + record_failure_line_num(__LINE__); + ck_assert_double_nonnan((2%s)*x); +#else + (void)t; /* unused */ + (void)x; /* unused */ +#endif +} +END_TEST + +START_TEST(test_ck_assert_double_nan_and_inf_with_expr) +{ + double x[] = {0.0, 0.0, INFINITY, INFINITY, NAN, NAN, 0.0, 0.0, NAN}; + int i = 0; + + record_test_name(tcase_name()); + + ck_assert_double_finite(x[i++]); + ck_assert_double_finite(x[i++]); + ck_assert_double_infinite(x[i++]); + ck_assert_double_infinite(x[i++]); + ck_assert_double_nan(x[i++]); + ck_assert_double_nan(x[i++]); + ck_assert_double_nonnan(x[i++]); + ck_assert_double_nonnan(x[i++]); +} +END_TEST + +START_TEST(test_ck_assert_ldouble_eq) +{ + long double x = 1.1l; + long double y = 1.1l; + + record_test_name(tcase_name()); + + ck_assert_ldouble_eq(x, y); + y+=0.1l; + record_failure_line_num(__LINE__); + ck_assert_ldouble_eq(x, y); +} +END_TEST + +START_TEST(test_ck_assert_ldouble_eq_with_mod) +{ + int d = 2; + int f = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_ldouble_eq(3%d, 2%f); +} +END_TEST + +START_TEST(test_ck_assert_ldouble_eq_with_promotion) +{ + float x = 1.1; + long double y = x; + + record_test_name(tcase_name()); + + ck_assert_ldouble_eq(x, y); +} +END_TEST + +START_TEST(test_ck_assert_ldouble_eq_with_conv) +{ + float x = 1.1; + long double y = x; + + record_test_name(tcase_name()); + + ck_assert_ldouble_eq(x, y); + record_failure_line_num(__LINE__); + ck_assert_ldouble_eq(x, 1.1); +} +END_TEST + +START_TEST(test_ck_assert_ldouble_ne) +{ + long double x = 1.1l; + long double y = 1.2l; + + record_test_name(tcase_name()); + + ck_assert_ldouble_ne(x, y); + y = x; + record_failure_line_num(__LINE__); + ck_assert_ldouble_ne(x, y); +} +END_TEST + +START_TEST(test_ck_assert_ldouble_ne_with_mod) +{ + int d = 2; + int f = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_ldouble_ne(1%d, 1%f); +} +END_TEST + +START_TEST(test_ck_assert_ldouble_lt) +{ + long double x = 2.0l; + long double y = 2.5l; + + record_test_name(tcase_name()); + + ck_assert_ldouble_lt(x, y); + y-=1.0l; + record_failure_line_num(__LINE__); + ck_assert_ldouble_lt(x, y); +} +END_TEST + +START_TEST(test_ck_assert_ldouble_lt_with_mod) +{ + int d = 2; + int f = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_ldouble_lt(3%d, 2%f); +} +END_TEST + +START_TEST(test_ck_assert_ldouble_le) +{ + long double x = 2.0l; + long double y = 2.5l; + + record_test_name(tcase_name()); + + ck_assert_ldouble_le(x, y); + ck_assert_ldouble_le(x, x); + y-=1.0l; + record_failure_line_num(__LINE__); + ck_assert_ldouble_le(x, y); +} +END_TEST + +START_TEST(test_ck_assert_ldouble_le_with_mod) +{ + int d = 2; + int f = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_ldouble_le(3%d, 2%f); +} +END_TEST + +START_TEST(test_ck_assert_ldouble_gt) +{ + long double x = 2.5l; + long double y = 2.0l; + + record_test_name(tcase_name()); + + ck_assert_ldouble_gt(x, y); + y+=1.0l; + record_failure_line_num(__LINE__); + ck_assert_ldouble_gt(x, y); +} +END_TEST + +START_TEST(test_ck_assert_ldouble_gt_with_mod) +{ + int d = 2; + int f = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_ldouble_gt(2%d, 3%f); +} +END_TEST + +START_TEST(test_ck_assert_ldouble_ge) +{ + long double x = 2.5l; + long double y = 2.0l; + + record_test_name(tcase_name()); + + ck_assert_ldouble_ge(x, y); + ck_assert_ldouble_ge(x, x); + y+=1.0l; + record_failure_line_num(__LINE__); + ck_assert_ldouble_ge(x, y); +} +END_TEST + +START_TEST(test_ck_assert_ldouble_ge_with_mod) +{ + int d = 2; + int f = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_ldouble_ge(2%d, 3%f); +} +END_TEST + +START_TEST(test_ck_assert_ldouble_with_expr) +{ + long double x[] = {NAN, 1.1l, 1.1l, 1.2l, 1.2l, NAN}; + long double y = 1.1l; + int i; + + record_test_name(tcase_name()); + + i = 1; + ck_assert_ldouble_eq(x[i++], y); + ck_assert_ldouble_eq(x[i++], y); + + i = 4; + ck_assert_ldouble_ne(x[i--], y); + ck_assert_ldouble_ne(x[i--], y); + + y = 1.15l; + + i = 1; + ck_assert_ldouble_le(x[i++], y); + ck_assert_ldouble_le(x[i++], y); + + i = 1; + ck_assert_ldouble_lt(x[i++], y); + ck_assert_ldouble_lt(x[i++], y); + + i = 4; + ck_assert_ldouble_gt(x[i--], y); + ck_assert_ldouble_gt(x[i--], y); + + i = 4; + ck_assert_ldouble_ge(x[i--], y); + ck_assert_ldouble_ge(x[i--], y); +} +END_TEST + +START_TEST(test_ck_assert_ldouble_eq_tol) +{ + long double x = 0.0001l; + long double y = 0.0002l; + long double t = 0.001l; + + record_test_name(tcase_name()); + + ck_assert_ldouble_eq_tol(x, y, t); + ck_assert_ldouble_eq_tol(x, x, t); + x*=10.0l; + y*=10.0l; + t*=10.0l; + ck_assert_ldouble_eq_tol(x, y, t); + t/=10.0l; + record_failure_line_num(__LINE__); + ck_assert_ldouble_eq_tol(x, y, t); +} +END_TEST + +START_TEST(test_ck_assert_ldouble_eq_tol_with_mod) +{ + int d = 2; + int f = 2; + int p = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_ldouble_eq_tol(3%d, 2%f, 2%p); +} +END_TEST + +START_TEST(test_ck_assert_ldouble_ne_tol) +{ + long double x = 0.0001l; + long double y = 0.0002l; + long double t = 0.0001l; + + record_test_name(tcase_name()); + + ck_assert_ldouble_ne_tol(x, y, t); + x*=10.0l; + y*=10.0l; + t*=10.0l; + ck_assert_ldouble_ne_tol(x, y, t); + t*=10.0l; + record_failure_line_num(__LINE__); + ck_assert_ldouble_ne_tol(x, y, t); +} +END_TEST + +START_TEST(test_ck_assert_ldouble_ne_tol_with_mod) +{ + int d = 2; + int f = 2; + int p = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_ldouble_ne_tol(3%d, 3%f, 3%p); +} +END_TEST + +START_TEST(test_ck_assert_ldouble_ge_tol) +{ + long double x = 0.001l; + long double y = 0.003l; + long double t = 0.001l; + + record_test_name(tcase_name()); + + ck_assert_ldouble_ge_tol(y, x, t); + ck_assert_ldouble_ge_tol(x, x, t); + ck_assert_ldouble_ge_tol(y, y, t); + x*=10.0l; + y*=10.0l; + t*=10.0l; + ck_assert_ldouble_ge_tol(y, x, t); + ck_assert_ldouble_ge_tol(x, x, t); + ck_assert_ldouble_ge_tol(y, y, t); + record_failure_line_num(__LINE__); + ck_assert_ldouble_ge_tol(x, y, t); +} +END_TEST + +START_TEST(test_ck_assert_ldouble_ge_tol_with_mod) +{ + int d = 2; + int f = 2; + int p = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_ldouble_ge_tol(2%d, 3%f, 3%p); +} +END_TEST + +START_TEST(test_ck_assert_ldouble_le_tol) +{ + long double x = 0.001l; + long double y = 0.003l; + long double t = 0.001l; + + record_test_name(tcase_name()); + + ck_assert_ldouble_le_tol(x, y, t); + ck_assert_ldouble_le_tol(x, x, t); + ck_assert_ldouble_le_tol(y, y, t); + x*=10.0l; + y*=10.0l; + t*=10.0l; + ck_assert_ldouble_le_tol(x, y, t); + ck_assert_ldouble_le_tol(x, x, t); + ck_assert_ldouble_le_tol(y, y, t); + record_failure_line_num(__LINE__); + ck_assert_ldouble_le_tol(y, x, t); +} +END_TEST + +START_TEST(test_ck_assert_ldouble_le_tol_with_mod) +{ + int d = 2; + int f = 2; + int p = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_ldouble_le_tol(3%d, 2%f, 3%p); +} +END_TEST + +START_TEST(test_ck_assert_ldouble_tol_with_expr) +{ + long double x[] = {NAN, 1.1l, 1.1l, 1.2l, 1.2l, NAN}; + long double y = 1.1l; + long double t = 0.01l; + int i; + + record_test_name(tcase_name()); + + i = 1; + ck_assert_ldouble_eq_tol(x[i++], y, t); + ck_assert_ldouble_eq_tol(x[i++], y, t); + + i = 4; + ck_assert_ldouble_ne_tol(x[i--], y, t); + ck_assert_ldouble_ne_tol(x[i--], y, t); + + y = 1.15l; + + i = 1; + ck_assert_ldouble_le_tol(x[i++], y, t); + ck_assert_ldouble_le_tol(x[i++], y, t); + + i = 4; + ck_assert_ldouble_ge_tol(x[i--], y, t); + ck_assert_ldouble_ge_tol(x[i--], y, t); +} +END_TEST + +START_TEST(test_ck_assert_ldouble_finite) +{ + long double x = 0.0001l; + long double t = 1.0l; + + record_test_name(tcase_name()); + + ck_assert_ldouble_finite(x); + // MS VS doesn't allow explicit division by zero + x = 1.0l / (1.0l - t); + record_failure_line_num(__LINE__); + ck_assert_ldouble_finite(x); +} +END_TEST + +START_TEST(test_ck_assert_ldouble_finite_with_mod) +{ + int d = 2; + long double t = 1.0l; + long double x = 1.0l / (1.0l - t); + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_ldouble_finite(x*(1%d)); +} +END_TEST + +START_TEST(test_ck_assert_ldouble_infinite) +{ + long double t = 1.0l; + long double x = 1.0l / (1.0l - t); + + record_test_name(tcase_name()); + + ck_assert_ldouble_infinite(x); + x = -1.0l / (1.0l - t); + ck_assert_ldouble_infinite(x); + x = 0.0l; + record_failure_line_num(__LINE__); + ck_assert_ldouble_infinite(x); +} +END_TEST + +START_TEST(test_ck_assert_ldouble_infinite_with_mod) +{ + int d = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_ldouble_infinite(2%d); +} +END_TEST + +START_TEST(test_ck_assert_ldouble_nan) +{ + long double t = 1.0l; + long double x = 0.0l / (1.0l - t); + + record_test_name(tcase_name()); + + ck_assert_ldouble_nan(x); + x = 1.0l / (1.0l - t); + record_failure_line_num(__LINE__); + ck_assert_ldouble_nan(x); +} +END_TEST + +START_TEST(test_ck_assert_ldouble_nan_with_mod) +{ + int d = 2; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_ldouble_nan(2%d); +} +END_TEST + +START_TEST(test_ck_assert_ldouble_nonnan) +{ + long double x = 0.0l; + long double t = 1.0l; + + record_test_name(tcase_name()); + + ck_assert_ldouble_nonnan(x); +#if ENABLE_REGEX + x = 0.0l / (1.0l - t); + record_failure_line_num(__LINE__); + ck_assert_ldouble_nonnan(x); +#else + (void)t; /* unused */ +#endif +} +END_TEST + +START_TEST(test_ck_assert_ldouble_nonnan_with_mod) +{ + int s = 2; + long double t = 1.0l; + long double x; + + record_test_name(tcase_name()); + + ck_assert_ldouble_nonnan(2%s); +#if ENABLE_REGEX + x = 0.0l / (1.0l - t); + record_failure_line_num(__LINE__); + ck_assert_ldouble_nonnan((2%s)*x); +#else + (void)t; /* unused */ + (void)x; /* unused */ +#endif +} +END_TEST + +START_TEST(test_ck_assert_ldouble_nan_and_inf_with_expr) +{ + long double x[] = {0.0l, 0.0l, INFINITY, INFINITY, NAN, NAN, 0.0l, 0.0l, NAN}; + int i = 0; + + record_test_name(tcase_name()); + + ck_assert_ldouble_finite(x[i++]); + ck_assert_ldouble_finite(x[i++]); + ck_assert_ldouble_infinite(x[i++]); + ck_assert_ldouble_infinite(x[i++]); + ck_assert_ldouble_nan(x[i++]); + ck_assert_ldouble_nan(x[i++]); + ck_assert_ldouble_nonnan(x[i++]); + ck_assert_ldouble_nonnan(x[i++]); +} +END_TEST + +int returnsZero(const char* argument); +int returnsZero(const char* argument) +{ + (void)argument; + return 0; +} + +START_TEST(test_percent_n_escaped) +{ + record_test_name(tcase_name()); + + /* If the %n is not escaped in the ck macro, then this results in a SEGFAULT */ + record_failure_line_num(__LINE__); + ck_assert_int_eq(returnsZero("%n"), 1); +} END_TEST + +START_TEST(test_ck_assert_str_eq) +{ + const char *s = "test2"; + + record_test_name(tcase_name()); + + ck_assert_str_eq("test2", s); + record_failure_line_num(__LINE__); + ck_assert_str_eq("test1", s); +} +END_TEST + +START_TEST(test_ck_assert_str_eq_with_null) +{ + const char *s = NULL; + const char *t = NULL; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_str_eq(t, s); +} +END_TEST + +START_TEST(test_ck_assert_str_ne) +{ + const char *s = "test2"; + const char *t = "test1"; + + record_test_name(tcase_name()); + + ck_assert_str_ne(t, s); + t = "test2"; + record_failure_line_num(__LINE__); + ck_assert_str_ne(t, s); +} +END_TEST + +START_TEST(test_ck_assert_str_ne_with_null) +{ + const char *s = NULL; + const char *t = "test"; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_str_ne(t, s); +} +END_TEST + +START_TEST(test_ck_assert_str_lt) +{ + const char *s = "test1"; + const char *t = "test2"; + + record_test_name(tcase_name()); + + ck_assert_str_lt(s, t); + record_failure_line_num(__LINE__); + ck_assert_str_lt(s, s); +} +END_TEST + +START_TEST(test_ck_assert_str_lt_with_null) +{ + const char *s = NULL; + const char *t = "test"; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_str_lt(s, t); +} +END_TEST + +START_TEST(test_ck_assert_str_le) +{ + const char *s = "test1"; + const char *t = "test2"; + + record_test_name(tcase_name()); + + ck_assert_str_le(s, t); + ck_assert_str_le(s, s); + record_failure_line_num(__LINE__); + ck_assert_str_le(t, s); +} +END_TEST + +START_TEST(test_ck_assert_str_le_with_null) +{ + const char *s = NULL; + const char *t = NULL; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_str_le(t, s); +} +END_TEST + +START_TEST(test_ck_assert_str_gt) +{ + const char *s = "test1"; + const char *t = "test2"; + + record_test_name(tcase_name()); + + ck_assert_str_gt(t, s); + record_failure_line_num(__LINE__); + ck_assert_str_gt(t, t); +} +END_TEST + +START_TEST(test_ck_assert_str_gt_with_null) +{ + const char *s = NULL; + const char *t = "test"; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_str_gt(t, s); +} +END_TEST + +START_TEST(test_ck_assert_str_ge) +{ + const char *s = "test1"; + const char *t = "test2"; + + record_test_name(tcase_name()); + + ck_assert_str_ge(t, s); + ck_assert_str_ge(t, t); + record_failure_line_num(__LINE__); + ck_assert_str_ge(s, t); +} +END_TEST + +START_TEST(test_ck_assert_str_ge_with_null) +{ + const char *s = NULL; + const char *t = NULL; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_str_ge(s, t); +} +END_TEST + +START_TEST(test_ck_assert_str_expr) +{ + const char *s = "test1"; + const char *t[] = { "test1", "test2" }; + int i = -1; + + record_test_name(tcase_name()); + + ck_assert_str_eq(s, t[++i]); + ck_assert_str_eq(s, t[i]); +} +END_TEST + +START_TEST(test_ck_assert_pstr_eq) +{ + const char *s = "test"; + + record_test_name(tcase_name()); + + ck_assert_pstr_eq("test", s); + ck_assert_pstr_eq(NULL, NULL); + record_failure_line_num(__LINE__); + ck_assert_pstr_eq("test1", s); +} +END_TEST + +START_TEST(test_ck_assert_pstr_eq_with_null) +{ + const char *t = "test"; + const char *s = NULL; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_pstr_eq(t, s); +} +END_TEST + +START_TEST(test_ck_assert_pstr_ne) +{ + const char *t = "test1"; + const char *s = "test2"; + + record_test_name(tcase_name()); + + ck_assert_pstr_ne(t, s); + ck_assert_pstr_ne(t, NULL); + t = "test2"; + record_failure_line_num(__LINE__); + ck_assert_pstr_ne(t, s); +} +END_TEST + +START_TEST(test_ck_assert_pstr_ne_with_null) +{ + const char *s = NULL; + const char *t = NULL; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_pstr_ne(t, s); +} +END_TEST + +START_TEST(test_ck_assert_ptr_eq) +{ + int * x = (int*)0x1; + int * y = (int*)0x2; + + record_test_name(tcase_name()); + + ck_assert_ptr_eq(NULL, NULL); + ck_assert_ptr_eq(x, x); + record_failure_line_num(__LINE__); + ck_assert_ptr_eq(x, y); +} +END_TEST + +START_TEST(test_ck_assert_ptr_ne) +{ + int * x = (int*)0x1; + int * y = (int*)0x2; + int * z = x; + + record_test_name(tcase_name()); + + ck_assert_ptr_ne(x, y); + ck_assert_ptr_ne(x, NULL); + ck_assert_ptr_ne(NULL, y); + record_failure_line_num(__LINE__); + ck_assert_ptr_ne(x, z); +} +END_TEST + +START_TEST(test_ck_assert_ptr_null) +{ + void* x = (void*)0x1; + void* y = NULL; + + record_test_name(tcase_name()); + + ck_assert_ptr_null(y); + record_failure_line_num(__LINE__); + ck_assert_ptr_null(x); +} +END_TEST + +START_TEST(test_ck_assert_ptr_nonnull) +{ + void* x = NULL; + void* y = (void*)0x1; + + record_test_name(tcase_name()); + + ck_assert_ptr_nonnull(y); + record_failure_line_num(__LINE__); + ck_assert_ptr_nonnull(x); +} +END_TEST + +START_TEST(test_ck_assert_mem_eq) +{ + const char *s = "\x00\x00\x00\x00\x02"; + + record_test_name(tcase_name()); + + ck_assert_mem_eq("\x00\x00\x00\x00\x02", s, 5); + record_failure_line_num(__LINE__); + ck_assert_mem_eq("\x00\x00\x00\x00\x01", s, 5); +} +END_TEST + +START_TEST(test_ck_assert_mem_ne) +{ + const char *s = "\x00\x00\x00\x00\x02"; + const char *t = "\x00\x00\x00\x00\x01"; + + record_test_name(tcase_name()); + + ck_assert_mem_ne(t, s, 5); + t = "\x00\x00\x00\x00\x02"; + record_failure_line_num(__LINE__); + ck_assert_mem_ne(t, s, 5); +} +END_TEST + +START_TEST(test_ck_assert_mem_lt) +{ + const char *s = "\x00\x00\x00\x00\x01"; + const char *t = "\x00\x00\x00\x00\x02"; + + record_test_name(tcase_name()); + + ck_assert_mem_lt(s, t, 5); + record_failure_line_num(__LINE__); + ck_assert_mem_lt(s, s, 5); +} +END_TEST + +START_TEST(test_ck_assert_mem_le) +{ + const char *s = "\x00\x00\x00\x00\x01"; + const char *t = "\x00\x00\x00\x00\x02"; + + record_test_name(tcase_name()); + + ck_assert_mem_le(s, t, 5); + ck_assert_mem_le(s, s, 5); + record_failure_line_num(__LINE__); + ck_assert_mem_le(t, s, 5); +} +END_TEST + +START_TEST(test_ck_assert_mem_gt) +{ + const char *s = "\x00\x00\x00\x00\x01"; + const char *t = "\x00\x00\x00\x00\x02"; + + record_test_name(tcase_name()); + + ck_assert_mem_gt(t, s, 5); + record_failure_line_num(__LINE__); + ck_assert_mem_gt(t, t, 5); +} +END_TEST + +START_TEST(test_ck_assert_mem_ge) +{ + const char *s = "\x00\x00\x00\x00\x01"; + const char *t = "\x00\x00\x00\x00\x02"; + + record_test_name(tcase_name()); + + ck_assert_mem_ge(t, s, 5); + ck_assert_mem_ge(t, t, 5); + record_failure_line_num(__LINE__); + ck_assert_mem_ge(s, t, 5); +} +END_TEST + +START_TEST(test_ck_assert_mem_zerolen) +{ + const char *s = "\x00\x00\x00\x00\x02"; + const char *t = "\x00\x00\x00\x00\x01"; + + record_test_name(tcase_name()); + + ck_assert_mem_eq(t, s, 0); +} +END_TEST + +START_TEST(test_ck_assert_mem_eq_exact) +{ + const char *s = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02"; + const char *t = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_mem_eq(t, s, 64); +} +END_TEST + +START_TEST(test_ck_assert_mem_eq_longer) +{ + const char *s = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02"; + const char *t = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__); + ck_assert_mem_eq(t, s, 65); +} +END_TEST + +#if defined(HAVE_FORK) && HAVE_FORK == 1 +START_TEST(test_segv_pass) +{ + record_test_name(tcase_name()); + /* + * This test is to be used when it would otherwise not cause a + * failure. e.g., shen SIGSEGV is expected. + */ + raise (SIGSEGV); +} +END_TEST + +START_TEST(test_segv) +{ + record_test_name(tcase_name()); + record_failure_line_num(__LINE__-4); /* -4 as the failure is reported at START_TEST() */ + raise (SIGSEGV); +} +END_TEST + +/* This test currently does not work on Cygwin, as it results in a + * SIGSEGV instead of a SIGFPE. However, a simple program that installs + * a SIGFPE handler then raise(SIGFPE) works as expected. Further + * investigation is necessary. */ +#if !defined(__CYGWIN__) +START_TEST(test_fpe) +{ + record_test_name(tcase_name()); + record_failure_line_num(__LINE__-4); /* -4 as the failure is reported at START_TEST() */ + raise (SIGFPE); +} +END_TEST +#endif /* !defined(__CYGWIN__) */ + +/* + * This test is to be used when the test is expected to throw signal 8, + * but does not, resulting in a failure. + */ +START_TEST(test_non_signal_8) +{ + record_test_name(tcase_name()); + record_failure_line_num(__LINE__-4); /* -4 as the failure is reported at START_TEST() */ + exit(0); +} +END_TEST + +/* TODO: + unit test running the same suite in succession */ + +/* This test currently does not work on Cygwin, as it results in a + * SIGSEGV instead of a SIGFPE. However, a simple program that installs + * a SIGFPE handler then raise(SIGFPE) works as expected. Further + * investigation is necessary. */ +#if !defined(__CYGWIN__) +START_TEST(test_mark_point) +{ + int i; + record_test_name(tcase_name()); + i = 0; + i++; + mark_point(); + record_failure_line_num(__LINE__-2); /* -2 as the failure is listed as from mark_point() */ + raise(SIGFPE); + ck_abort_msg("Shouldn't reach here"); +} +END_TEST +#endif /* !defined(__CYGWIN__) */ + +#endif /* HAVE_FORK */ + +#if TIMEOUT_TESTS_ENABLED && defined(HAVE_FORK) && HAVE_FORK == 1 +START_TEST(test_eternal_fail) +{ + record_test_name(tcase_name()); + record_failure_line_num(__LINE__-4); /* -4 as the failure is reported at START_TEST() */ + for (;;) + sleep(1); +} +END_TEST + +/* + * Only include sub-second timing tests on systems + * that support librt. + */ +#ifdef HAVE_LIBRT +START_TEST(test_sleep0_025_pass) +{ + record_test_name(tcase_name()); + usleep(25*1000); +} +END_TEST + +START_TEST(test_sleep1_pass) +{ + record_test_name(tcase_name()); + sleep(1); +} +END_TEST + +START_TEST(test_sleep1_fail) +{ + record_test_name(tcase_name()); + record_failure_line_num(__LINE__-4); /* -4 as the failure is reported at START_TEST() */ + sleep(1); +} +END_TEST +#endif /* HAVE_LIBRT */ + +START_TEST(test_sleep2_pass) +{ + record_test_name(tcase_name()); + sleep(2); +} +END_TEST + +START_TEST(test_sleep2_fail) +{ + record_test_name(tcase_name()); + record_failure_line_num(__LINE__-4); /* -4 as the failure is reported at START_TEST() */ + sleep(2); +} +END_TEST + +START_TEST(test_sleep5_pass) +{ + record_test_name(tcase_name()); + sleep(5); +} +END_TEST + +START_TEST(test_sleep5_fail) +{ + record_test_name(tcase_name()); + record_failure_line_num(__LINE__-4); /* -4 as the failure is reported at START_TEST() */ + sleep(5); +} +END_TEST + +START_TEST(test_sleep9_pass) +{ + record_test_name(tcase_name()); + sleep(9); +} +END_TEST + +START_TEST(test_sleep9_fail) +{ + record_test_name(tcase_name()); + record_failure_line_num(__LINE__-4); /* -4 as the failure is reported at START_TEST() */ + sleep(9); +} +END_TEST + +START_TEST(test_sleep14_fail) +{ + record_test_name(tcase_name()); + record_failure_line_num(__LINE__-4); /* -4 as the failure is reported at START_TEST() */ + sleep(14); + exit(3); +} +END_TEST +#endif /* TIMEOUT_TESTS_ENABLED && defined(HAVE_FORK) */ + +#if defined(HAVE_FORK) && HAVE_FORK==1 +START_TEST(test_early_exit) +{ + record_test_name(tcase_name()); + record_failure_line_num(__LINE__-4); /* -4 as the failure is reported at START_TEST() */ + exit(EXIT_FAILURE); +} +END_TEST +#endif /* HAVE_FORK */ + +/* + * The following test will leak memory because it is calling + * APIs inproperly. The leaked memory cannot be free'd, as + * the methods to do so are static. (No user of Check should + * call them directly). + */ +#if MEMORY_LEAKING_TESTS_ENABLED +START_TEST(test_null) +{ + Suite *s; + TCase *tc; + + record_test_name(tcase_name()); + + s = suite_create(NULL); + tc = tcase_create(NULL); + suite_add_tcase (s, NULL); + tcase_add_test (tc, NULL); + srunner_free(srunner_create(NULL)); + srunner_run_all (NULL, (enum print_output)-1); + srunner_free (NULL); + record_failure_line_num(__LINE__); + ck_abort_msg("Completed properly"); +} +END_TEST +#endif /* MEMORY_LEAKING_TESTS_ENABLED */ + +START_TEST(test_null_2) +{ + SRunner *sr = srunner_create(NULL); + + record_test_name(tcase_name()); + + srunner_run_all (sr, CK_NORMAL); + srunner_free (sr); + ck_assert_int_eq(suite_tcase(NULL, NULL), 0); + record_failure_line_num(__LINE__); + ck_abort_msg("Completed properly"); +} +END_TEST + +#if defined(HAVE_FORK) && HAVE_FORK==1 +START_TEST(test_fork1p_pass) +{ + pid_t pid; + + record_test_name(tcase_name()); + + if((pid = fork()) < 0) { + ck_abort_msg("Failed to fork new process"); + } else if (pid > 0) { + ck_assert_msg(1, NULL); + kill(pid, SIGKILL); + } else { + for (;;) { + sleep(1); + } + } +} +END_TEST + +START_TEST(test_fork1p_fail) +{ + pid_t pid; + + record_test_name(tcase_name()); + + if((pid = fork()) < 0) { + ck_abort_msg("Failed to fork new process"); + } else if (pid > 0) { + record_failure_line_num(__LINE__); + ck_abort_msg("Expected fail"); + kill(pid, SIGKILL); + } else { + for (;;) { + sleep(1); + } + } +} +END_TEST + +START_TEST(test_fork1c_pass) +{ + pid_t pid; + + record_test_name(tcase_name()); + + if((pid = check_fork()) < 0) { + ck_abort_msg("Failed to fork new process"); + } else if (pid > 0) { + check_waitpid_and_exit(pid); + } else { + ck_assert_msg(1, NULL); + check_waitpid_and_exit(0); + } +} +END_TEST + +START_TEST(test_fork1c_fail) +{ + pid_t pid; + + record_test_name(tcase_name()); + + if((pid = check_fork()) < 0) { + ck_abort_msg("Failed to fork new process"); + } else if (pid == 0) { + record_failure_line_num(__LINE__); + ck_abort_msg("Expected fail"); + check_waitpid_and_exit(0); + } + check_waitpid_and_exit(pid); +} +END_TEST + +START_TEST(test_fork2_pass) +{ + pid_t pid; + pid_t pid2; + + record_test_name(tcase_name()); + + if((pid = check_fork()) < 0) { + ck_abort_msg("Failed to fork new process"); + } else if (pid > 0) { + if((pid2 = check_fork()) < 0) { + ck_abort_msg("Failed to fork new process"); + } else if (pid2 == 0) { + ck_assert_msg(1, NULL); + check_waitpid_and_exit(0); + } + check_waitpid_and_exit(pid2); + } + check_waitpid_and_exit(pid); +} +END_TEST + +START_TEST(test_fork2_fail) +{ + pid_t pid; + pid_t pid2; + + record_test_name(tcase_name()); + + if((pid = check_fork()) < 0) { + ck_abort_msg("Failed to fork new process"); + } else if (pid > 0) { + if((pid2 = check_fork()) < 0) { + ck_abort_msg("Failed to fork new process"); + } else if (pid2 == 0) { + record_failure_line_num(__LINE__); + ck_abort_msg("Expected fail"); + check_waitpid_and_exit(0); + } + check_waitpid_and_exit(pid2); + ck_abort_msg("Expected fail"); + } + check_waitpid_and_exit(pid); +} +END_TEST +#endif /* HAVE_FORK */ + +#if defined(HAVE_FORK) && HAVE_FORK == 1 +#if MEMORY_LEAKING_TESTS_ENABLED +START_TEST(test_invalid_set_fork_status) +{ + Suite *s1; + TCase *tc1; + SRunner *sr; + + record_test_name(tcase_name()); + + record_failure_line_num(__LINE__-9); /* -9 as the failure is reported at START_TEST() */ + s1 = suite_create ("suite1"); + tc1 = tcase_create ("tcase1"); + tcase_add_test (tc1, test_pass); + sr = srunner_create(s1); + srunner_set_fork_status (sr, (enum fork_status)-1); + srunner_run_all(sr, CK_SILENT); +} +END_TEST +#endif /* MEMORY_LEAKING_TESTS_ENABLED */ +#endif /* HAVE_FORK */ + +START_TEST(test_srunner) +{ + Suite *s; + SRunner *sr; + + record_test_name(tcase_name()); + + s = suite_create("Check Servant3"); + ck_assert_msg(s != NULL, NULL); + sr = srunner_create(NULL); + ck_assert_msg(sr != NULL, NULL); + srunner_add_suite(sr, s); + srunner_free(sr); + + sr = srunner_create(NULL); + ck_assert_msg(sr != NULL, NULL); + srunner_add_suite(sr, NULL); + srunner_free(sr); + + s = suite_create("Check Servant3"); + ck_assert_msg(s != NULL, NULL); + sr = srunner_create(s); + ck_assert_msg(sr != NULL, NULL); + srunner_free(sr); +} +END_TEST + +START_TEST(test_2nd_suite) +{ + record_test_name(tcase_name()); + record_failure_line_num(__LINE__); + ck_abort_msg("We failed"); +} +END_TEST + +Suite *make_sub2_suite(void) +{ + Suite *s = suite_create("Check Servant2"); + TCase *tc = tcase_create("Core"); + suite_add_tcase(s, tc); + tcase_add_test(tc, test_srunner); + tcase_add_test(tc, test_2nd_suite); + + return s; +} + +#if defined(HAVE_FORK) && HAVE_FORK == 1 +void exit_handler(void); +void exit_handler () +{ + /* This exit handler should never be executed */ + while(1) + { + sleep(1); + } +} + +START_TEST(test_ignore_exit_handlers) +{ + int result; + + record_test_name(tcase_name()); + + result = atexit(exit_handler); + if(result != 0) + { + ck_abort_msg("Failed to set an exit handler, test cannot proceed"); + } + record_failure_line_num(__LINE__); + ck_abort(); +} +END_TEST +#endif /* HAVE_FORK */ + +Suite *make_sub_suite(void) +{ + Suite *s; + + TCase *tc_simple; +#if defined(HAVE_FORK) && HAVE_FORK==1 + TCase *tc_signal; +#endif +#if TIMEOUT_TESTS_ENABLED && defined(HAVE_FORK) && HAVE_FORK == 1 +#if HAVE_DECL_SETENV + TCase *tc_timeout_env_int; + TCase *tc_timeout_env_double; +#endif /* HAVE_DECL_SETENV */ + TCase *tc_timeout_default; + TCase *tc_timeout_usr_int; + TCase *tc_timeout_usr_double; +#if HAVE_DECL_SETENV + TCase *tc_timeout_env_scale_int; + TCase *tc_timeout_scale_int; + TCase *tc_timeout_usr_scale_int; + TCase *tc_timeout_env_scale_double; + TCase *tc_timeout_scale_double; + TCase *tc_timeout_usr_scale_double; +#endif /* HAVE_DECL_SETENV */ +#endif /* TIMEOUT_TESTS_ENABLED && defined(HAVE_FORK) */ + TCase *tc_limit; +#if defined(HAVE_FORK) && HAVE_FORK==1 + TCase *tc_messaging_and_fork; + TCase *tc_errors; + TCase *tc_exit_handlers; +#endif + + s = suite_create("Check Servant"); + + tc_simple = tcase_create("Simple Tests"); +#if defined(HAVE_FORK) && HAVE_FORK==1 + tc_signal = tcase_create("Signal Tests"); +#endif /* HAVE_FORK */ +#if TIMEOUT_TESTS_ENABLED && defined(HAVE_FORK) && HAVE_FORK == 1 +#if HAVE_DECL_SETENV + setenv("CK_DEFAULT_TIMEOUT", "6", 1); + tc_timeout_env_int = tcase_create("Environment Integer Timeout Tests"); + unsetenv("CK_DEFAULT_TIMEOUT"); + setenv("CK_DEFAULT_TIMEOUT", "0.5", 1); + tc_timeout_env_double = tcase_create("Environment Double Timeout Tests"); + unsetenv("CK_DEFAULT_TIMEOUT"); +#endif /* HAVE_DECL_SETENV */ + tc_timeout_default = tcase_create("Default Timeout Tests"); + tc_timeout_usr_int = tcase_create("User Integer Timeout Tests"); + tc_timeout_usr_double = tcase_create("User Double Timeout Tests"); +#if HAVE_DECL_SETENV + setenv("CK_TIMEOUT_MULTIPLIER", "2", 1); + tc_timeout_scale_int = tcase_create("Timeout Integer Scaling Tests"); + tc_timeout_usr_scale_int = tcase_create("User Integer Timeout Scaling Tests"); + setenv("CK_DEFAULT_TIMEOUT", "6", 1); + tc_timeout_env_scale_int = tcase_create("Environment Integer Timeout Scaling Tests"); + unsetenv("CK_DEFAULT_TIMEOUT"); + unsetenv("CK_TIMEOUT_MULTIPLIER"); + + setenv("CK_TIMEOUT_MULTIPLIER", "0.35", 1); + tc_timeout_scale_double = tcase_create("Timeout Double Scaling Tests"); + tc_timeout_usr_scale_double = tcase_create("User Double Timeout Scaling Tests"); + setenv("CK_DEFAULT_TIMEOUT", "0.9", 1); + tc_timeout_env_scale_double = tcase_create("Environment Double Timeout Scaling Tests"); + unsetenv("CK_DEFAULT_TIMEOUT"); + unsetenv("CK_TIMEOUT_MULTIPLIER"); +#endif /* HAVE_DECL_SETENV */ +#endif /* TIMEOUT_TESTS_ENABLED && defined(HAVE_FORK) */ + tc_limit = tcase_create("Limit Tests"); +#if defined(HAVE_FORK) && HAVE_FORK==1 + tc_messaging_and_fork = tcase_create("Msg and fork Tests"); + tc_errors = tcase_create("Check Errors Tests"); + tc_exit_handlers = tcase_create("Check Ignore Exit Handlers"); +#endif /* HAVE_FORK */ + + suite_add_tcase (s, tc_simple); +#if defined(HAVE_FORK) && HAVE_FORK==1 + suite_add_tcase (s, tc_signal); +#endif /* HAVE_FORK */ +#if TIMEOUT_TESTS_ENABLED && defined(HAVE_FORK) && HAVE_FORK == 1 +#if HAVE_DECL_SETENV + suite_add_tcase (s, tc_timeout_env_int); + suite_add_tcase (s, tc_timeout_env_double); +#endif /* HAVE_DECL_SETENV */ + suite_add_tcase (s, tc_timeout_default); + suite_add_tcase (s, tc_timeout_usr_int); + suite_add_tcase (s, tc_timeout_usr_double); + +#if HAVE_DECL_SETENV + suite_add_tcase (s, tc_timeout_env_scale_int); + suite_add_tcase (s, tc_timeout_env_scale_double); + suite_add_tcase (s, tc_timeout_scale_int); + suite_add_tcase (s, tc_timeout_scale_double); + suite_add_tcase (s, tc_timeout_usr_scale_int); + suite_add_tcase (s, tc_timeout_usr_scale_double); +#endif /* HAVE_DECL_SETENV */ +#endif /* TIMEOUT_TESTS_ENABLED && defined(HAVE_FORK) */ + suite_add_tcase (s, tc_limit); +#if defined(HAVE_FORK) && HAVE_FORK == 1 + suite_add_tcase (s, tc_messaging_and_fork); + suite_add_tcase (s, tc_errors); + suite_add_tcase (s, tc_exit_handlers); +#endif + + tcase_add_test (tc_simple, test_lno); +#if defined(HAVE_FORK) && HAVE_FORK==1 + tcase_add_test (tc_simple, test_mark_lno); +#endif + tcase_add_test (tc_simple, test_pass); + tcase_add_test (tc_simple, test_fail_unless); + tcase_add_test (tc_simple, test_fail_if_pass); + tcase_add_test (tc_simple, test_fail_if_fail); + tcase_add_test (tc_simple, test_fail_null_msg); +#if defined(__GNUC__) + tcase_add_test (tc_simple, test_fail_no_msg); +#endif /* __GNUC__ */ + tcase_add_test (tc_simple, test_fail_if_null_msg); +#if defined(__GNUC__) + tcase_add_test (tc_simple, test_fail_if_no_msg); +#endif /* __GNUC__ */ + tcase_add_test (tc_simple, test_fail_vararg_msg_1); + tcase_add_test (tc_simple, test_fail_vararg_msg_2); + tcase_add_test (tc_simple, test_fail_vararg_msg_3); +#if defined(__GNUC__) + tcase_add_test (tc_simple, test_fail_empty); +#endif /* __GNUC__ */ + + tcase_add_test (tc_simple, test_ck_abort); + tcase_add_test (tc_simple, test_ck_abort_msg); + tcase_add_test (tc_simple, test_ck_abort_msg_null); + tcase_add_test (tc_simple, test_ck_assert); + tcase_add_test (tc_simple, test_ck_assert_null); + tcase_add_test (tc_simple, test_ck_assert_with_mod); + tcase_add_test (tc_simple, test_ck_assert_int_eq); + tcase_add_test (tc_simple, test_ck_assert_int_eq_with_mod); + tcase_add_test (tc_simple, test_ck_assert_int_ne); + tcase_add_test (tc_simple, test_ck_assert_int_ne_with_mod); + tcase_add_test (tc_simple, test_ck_assert_int_lt); + tcase_add_test (tc_simple, test_ck_assert_int_lt_with_mod); + tcase_add_test (tc_simple, test_ck_assert_int_le); + tcase_add_test (tc_simple, test_ck_assert_int_le_with_mod); + tcase_add_test (tc_simple, test_ck_assert_int_gt); + tcase_add_test (tc_simple, test_ck_assert_int_gt_with_mod); + tcase_add_test (tc_simple, test_ck_assert_int_ge); + tcase_add_test (tc_simple, test_ck_assert_int_ge_with_mod); + tcase_add_test (tc_simple, test_ck_assert_int_expr); + tcase_add_test (tc_simple, test_ck_assert_uint_eq); + tcase_add_test (tc_simple, test_ck_assert_uint_eq_with_mod); + tcase_add_test (tc_simple, test_ck_assert_uint_ne); + tcase_add_test (tc_simple, test_ck_assert_uint_ne_with_mod); + tcase_add_test (tc_simple, test_ck_assert_uint_lt); + tcase_add_test (tc_simple, test_ck_assert_uint_lt_with_mod); + tcase_add_test (tc_simple, test_ck_assert_uint_le); + tcase_add_test (tc_simple, test_ck_assert_uint_le_with_mod); + tcase_add_test (tc_simple, test_ck_assert_uint_gt); + tcase_add_test (tc_simple, test_ck_assert_uint_gt_with_mod); + tcase_add_test (tc_simple, test_ck_assert_uint_ge); + tcase_add_test (tc_simple, test_ck_assert_uint_ge_with_mod); + tcase_add_test (tc_simple, test_ck_assert_uint_expr); + tcase_add_test (tc_simple, test_ck_assert_float_eq); + tcase_add_test (tc_simple, test_ck_assert_float_eq_with_mod); + tcase_add_test (tc_simple, test_ck_assert_float_ne); + tcase_add_test (tc_simple, test_ck_assert_float_ne_with_mod); + tcase_add_test (tc_simple, test_ck_assert_float_lt); + tcase_add_test (tc_simple, test_ck_assert_float_lt_with_mod); + tcase_add_test (tc_simple, test_ck_assert_float_le); + tcase_add_test (tc_simple, test_ck_assert_float_le_with_mod); + tcase_add_test (tc_simple, test_ck_assert_float_gt); + tcase_add_test (tc_simple, test_ck_assert_float_gt_with_mod); + tcase_add_test (tc_simple, test_ck_assert_float_ge); + tcase_add_test (tc_simple, test_ck_assert_float_ge_with_mod); + tcase_add_test (tc_simple, test_ck_assert_float_with_expr); + tcase_add_test (tc_simple, test_ck_assert_float_eq_tol); + tcase_add_test (tc_simple, test_ck_assert_float_eq_tol_with_mod); + tcase_add_test (tc_simple, test_ck_assert_float_ne_tol); + tcase_add_test (tc_simple, test_ck_assert_float_ne_tol_with_mod); + tcase_add_test (tc_simple, test_ck_assert_float_ge_tol); + tcase_add_test (tc_simple, test_ck_assert_float_ge_tol_with_mod); + tcase_add_test (tc_simple, test_ck_assert_float_le_tol); + tcase_add_test (tc_simple, test_ck_assert_float_le_tol_with_mod); + tcase_add_test (tc_simple, test_ck_assert_float_tol_with_expr); + tcase_add_test (tc_simple, test_ck_assert_float_finite); + tcase_add_test (tc_simple, test_ck_assert_float_finite_with_mod); + tcase_add_test (tc_simple, test_ck_assert_float_infinite); + tcase_add_test (tc_simple, test_ck_assert_float_infinite_with_mod); + tcase_add_test (tc_simple, test_ck_assert_float_nan); + tcase_add_test (tc_simple, test_ck_assert_float_nan_with_mod); + tcase_add_test (tc_simple, test_ck_assert_float_nonnan); + tcase_add_test (tc_simple, test_ck_assert_float_nonnan_with_mod); + tcase_add_test (tc_simple, test_ck_assert_float_nan_and_inf_with_expr); + tcase_add_test (tc_simple, test_ck_assert_double_eq); + tcase_add_test (tc_simple, test_ck_assert_double_eq_with_mod); + tcase_add_test (tc_simple, test_ck_assert_double_eq_with_promotion); + tcase_add_test (tc_simple, test_ck_assert_double_eq_with_conv); + tcase_add_test (tc_simple, test_ck_assert_double_ne); + tcase_add_test (tc_simple, test_ck_assert_double_ne_with_mod); + tcase_add_test (tc_simple, test_ck_assert_double_lt); + tcase_add_test (tc_simple, test_ck_assert_double_lt_with_mod); + tcase_add_test (tc_simple, test_ck_assert_double_le); + tcase_add_test (tc_simple, test_ck_assert_double_le_with_mod); + tcase_add_test (tc_simple, test_ck_assert_double_gt); + tcase_add_test (tc_simple, test_ck_assert_double_gt_with_mod); + tcase_add_test (tc_simple, test_ck_assert_double_ge); + tcase_add_test (tc_simple, test_ck_assert_double_ge_with_mod); + tcase_add_test (tc_simple, test_ck_assert_double_with_expr); + tcase_add_test (tc_simple, test_ck_assert_double_eq_tol); + tcase_add_test (tc_simple, test_ck_assert_double_eq_tol_with_mod); + tcase_add_test (tc_simple, test_ck_assert_double_ne_tol); + tcase_add_test (tc_simple, test_ck_assert_double_ne_tol_with_mod); + tcase_add_test (tc_simple, test_ck_assert_double_ge_tol); + tcase_add_test (tc_simple, test_ck_assert_double_ge_tol_with_mod); + tcase_add_test (tc_simple, test_ck_assert_double_le_tol); + tcase_add_test (tc_simple, test_ck_assert_double_le_tol_with_mod); + tcase_add_test (tc_simple, test_ck_assert_double_tol_with_expr); + tcase_add_test (tc_simple, test_ck_assert_double_finite); + tcase_add_test (tc_simple, test_ck_assert_double_finite_with_mod); + tcase_add_test (tc_simple, test_ck_assert_double_infinite); + tcase_add_test (tc_simple, test_ck_assert_double_infinite_with_mod); + tcase_add_test (tc_simple, test_ck_assert_double_nan); + tcase_add_test (tc_simple, test_ck_assert_double_nan_with_mod); + tcase_add_test (tc_simple, test_ck_assert_double_nonnan); + tcase_add_test (tc_simple, test_ck_assert_double_nonnan_with_mod); + tcase_add_test (tc_simple, test_ck_assert_double_nan_and_inf_with_expr); + tcase_add_test (tc_simple, test_ck_assert_ldouble_eq); + tcase_add_test (tc_simple, test_ck_assert_ldouble_eq_with_mod); + tcase_add_test (tc_simple, test_ck_assert_ldouble_eq_with_promotion); + tcase_add_test (tc_simple, test_ck_assert_ldouble_eq_with_conv); + tcase_add_test (tc_simple, test_ck_assert_ldouble_ne); + tcase_add_test (tc_simple, test_ck_assert_ldouble_ne_with_mod); + tcase_add_test (tc_simple, test_ck_assert_ldouble_lt); + tcase_add_test (tc_simple, test_ck_assert_ldouble_lt_with_mod); + tcase_add_test (tc_simple, test_ck_assert_ldouble_le); + tcase_add_test (tc_simple, test_ck_assert_ldouble_le_with_mod); + tcase_add_test (tc_simple, test_ck_assert_ldouble_gt); + tcase_add_test (tc_simple, test_ck_assert_ldouble_gt_with_mod); + tcase_add_test (tc_simple, test_ck_assert_ldouble_ge); + tcase_add_test (tc_simple, test_ck_assert_ldouble_ge_with_mod); + tcase_add_test (tc_simple, test_ck_assert_ldouble_with_expr); + tcase_add_test (tc_simple, test_ck_assert_ldouble_eq_tol); + tcase_add_test (tc_simple, test_ck_assert_ldouble_eq_tol_with_mod); + tcase_add_test (tc_simple, test_ck_assert_ldouble_ne_tol); + tcase_add_test (tc_simple, test_ck_assert_ldouble_ne_tol_with_mod); + tcase_add_test (tc_simple, test_ck_assert_ldouble_ge_tol); + tcase_add_test (tc_simple, test_ck_assert_ldouble_ge_tol_with_mod); + tcase_add_test (tc_simple, test_ck_assert_ldouble_le_tol); + tcase_add_test (tc_simple, test_ck_assert_ldouble_le_tol_with_mod); + tcase_add_test (tc_simple, test_ck_assert_ldouble_tol_with_expr); + tcase_add_test (tc_simple, test_ck_assert_ldouble_finite); + tcase_add_test (tc_simple, test_ck_assert_ldouble_finite_with_mod); + tcase_add_test (tc_simple, test_ck_assert_ldouble_infinite); + tcase_add_test (tc_simple, test_ck_assert_ldouble_infinite_with_mod); + tcase_add_test (tc_simple, test_ck_assert_ldouble_nan); + tcase_add_test (tc_simple, test_ck_assert_ldouble_nan_with_mod); + tcase_add_test (tc_simple, test_ck_assert_ldouble_nonnan); + tcase_add_test (tc_simple, test_ck_assert_ldouble_nonnan_with_mod); + tcase_add_test (tc_simple, test_ck_assert_ldouble_nan_and_inf_with_expr); + tcase_add_test (tc_simple, test_percent_n_escaped); + tcase_add_test (tc_simple, test_ck_assert_str_eq); + tcase_add_test (tc_simple, test_ck_assert_str_eq_with_null); + tcase_add_test (tc_simple, test_ck_assert_str_ne); + tcase_add_test (tc_simple, test_ck_assert_str_ne_with_null); + tcase_add_test (tc_simple, test_ck_assert_str_lt); + tcase_add_test (tc_simple, test_ck_assert_str_lt_with_null); + tcase_add_test (tc_simple, test_ck_assert_str_le); + tcase_add_test (tc_simple, test_ck_assert_str_le_with_null); + tcase_add_test (tc_simple, test_ck_assert_str_gt); + tcase_add_test (tc_simple, test_ck_assert_str_gt_with_null); + tcase_add_test (tc_simple, test_ck_assert_str_ge); + tcase_add_test (tc_simple, test_ck_assert_str_ge_with_null); + tcase_add_test (tc_simple, test_ck_assert_str_expr); + tcase_add_test (tc_simple, test_ck_assert_pstr_eq); + tcase_add_test (tc_simple, test_ck_assert_pstr_eq_with_null); + tcase_add_test (tc_simple, test_ck_assert_pstr_ne); + tcase_add_test (tc_simple, test_ck_assert_pstr_ne_with_null); + tcase_add_test (tc_simple, test_ck_assert_ptr_eq); + tcase_add_test (tc_simple, test_ck_assert_ptr_ne); + tcase_add_test (tc_simple, test_ck_assert_ptr_null); + tcase_add_test (tc_simple, test_ck_assert_ptr_nonnull); + tcase_add_test (tc_simple, test_ck_assert_mem_eq); + tcase_add_test (tc_simple, test_ck_assert_mem_ne); + tcase_add_test (tc_simple, test_ck_assert_mem_lt); + tcase_add_test (tc_simple, test_ck_assert_mem_le); + tcase_add_test (tc_simple, test_ck_assert_mem_gt); + tcase_add_test (tc_simple, test_ck_assert_mem_ge); + tcase_add_test (tc_simple, test_ck_assert_mem_zerolen); + tcase_add_test (tc_simple, test_ck_assert_mem_eq_exact); + tcase_add_test (tc_simple, test_ck_assert_mem_eq_longer); + +#if defined(HAVE_FORK) && HAVE_FORK==1 + tcase_add_test (tc_signal, test_segv); + tcase_add_test_raise_signal (tc_signal, test_segv_pass, 11); /* pass */ + tcase_add_test_raise_signal (tc_signal, test_segv, 8); /* error */ + tcase_add_test_raise_signal (tc_signal, test_non_signal_8, 8); /* fail */ + tcase_add_test_raise_signal (tc_signal, test_fail_unless, 8); /* fail */ +#if !defined(__CYGWIN__) + tcase_add_test (tc_signal, test_fpe); + tcase_add_test (tc_signal, test_mark_point); +#endif /* !defined(__CYGWIN__) */ +#endif /* HAVE_FORK */ + +#if TIMEOUT_TESTS_ENABLED && defined(HAVE_FORK) && HAVE_FORK == 1 +#if HAVE_DECL_SETENV + /* tc_timeout_env_int tests have a timeout of 6 seconds */ + tcase_add_test (tc_timeout_env_int, test_eternal_fail); + tcase_add_test (tc_timeout_env_int, test_sleep2_pass); + tcase_add_test (tc_timeout_env_int, test_sleep5_pass); + tcase_add_test (tc_timeout_env_int, test_sleep9_fail); + + /* tc_timeout_env_double tests have a timeout of 0.5 seconds */ + tcase_add_test (tc_timeout_env_double, test_eternal_fail); +#ifdef HAVE_LIBRT + tcase_add_test (tc_timeout_env_double, test_sleep0_025_pass); + tcase_add_test (tc_timeout_env_double, test_sleep1_fail); +#endif /* HAVE_LIBRT */ + tcase_add_test (tc_timeout_env_double, test_sleep2_fail); + tcase_add_test (tc_timeout_env_double, test_sleep5_fail); + tcase_add_test (tc_timeout_env_double, test_sleep9_fail); +#endif /* HAVE_DECL_SETENV */ + + /* tc_timeout_default tests have a timeout of 4 seconds */ + tcase_add_test (tc_timeout_default, test_eternal_fail); +#ifdef HAVE_LIBRT + tcase_add_test (tc_timeout_default, test_sleep0_025_pass); + tcase_add_test (tc_timeout_default, test_sleep1_pass); +#endif /* HAVE_LIBRT */ + tcase_add_test (tc_timeout_default, test_sleep2_pass); + tcase_add_test (tc_timeout_default, test_sleep5_fail); + tcase_add_test (tc_timeout_default, test_sleep9_fail); + + tcase_set_timeout (tc_timeout_usr_int, 6); + tcase_add_test (tc_timeout_usr_int, test_eternal_fail); + tcase_add_test (tc_timeout_usr_int, test_sleep2_pass); + tcase_add_test (tc_timeout_usr_int, test_sleep5_pass); + tcase_add_test (tc_timeout_usr_int, test_sleep9_fail); + + tcase_set_timeout (tc_timeout_usr_double, 0.5); + tcase_add_test (tc_timeout_usr_double, test_eternal_fail); +#ifdef HAVE_LIBRT + tcase_add_test (tc_timeout_usr_double, test_sleep0_025_pass); + tcase_add_test (tc_timeout_usr_double, test_sleep1_fail); +#endif /* HAVE_LIBRT */ + tcase_add_test (tc_timeout_usr_double, test_sleep2_fail); + tcase_add_test (tc_timeout_usr_double, test_sleep5_fail); + tcase_add_test (tc_timeout_usr_double, test_sleep9_fail); + +#if HAVE_DECL_SETENV + /* tc_timeout_env_scale_int tests have a timeout of 6 (time) * 2 (multiplier) = 12 seconds */ + tcase_add_test (tc_timeout_env_scale_int, test_eternal_fail); +#ifdef HAVE_LIBRT + tcase_add_test (tc_timeout_env_scale_int, test_sleep0_025_pass); + tcase_add_test (tc_timeout_env_scale_int, test_sleep1_pass); +#endif /* HAVE_LIBRT */ + tcase_add_test (tc_timeout_env_scale_int, test_sleep2_pass); + tcase_add_test (tc_timeout_env_scale_int, test_sleep5_pass); + tcase_add_test (tc_timeout_env_scale_int, test_sleep9_pass); + tcase_add_test (tc_timeout_env_scale_int, test_sleep14_fail); + + /* tc_timeout_env_scale_double tests have a timeout of 0.9 (time) * 0.4 (multiplier) = 0.36 seconds */ + tcase_add_test (tc_timeout_env_scale_double, test_eternal_fail); +#ifdef HAVE_LIBRT + tcase_add_test (tc_timeout_env_scale_double, test_sleep0_025_pass); + tcase_add_test (tc_timeout_env_scale_double, test_sleep1_fail); +#endif /* HAVE_LIBRT */ + tcase_add_test (tc_timeout_env_scale_double, test_sleep2_fail); + tcase_add_test (tc_timeout_env_scale_double, test_sleep5_fail); + tcase_add_test (tc_timeout_env_scale_double, test_sleep9_fail); + tcase_add_test (tc_timeout_env_scale_double, test_sleep14_fail); + + /* tc_timeout_scale_int tests have a timeout of 2 * 4 (default) = 8 seconds */ + tcase_add_test (tc_timeout_scale_int, test_eternal_fail); +#ifdef HAVE_LIBRT + tcase_add_test (tc_timeout_scale_int, test_sleep0_025_pass); + tcase_add_test (tc_timeout_scale_int, test_sleep1_pass); + tcase_add_test (tc_timeout_scale_int, test_sleep2_pass); +#endif /* HAVE_LIBRT */ + tcase_add_test (tc_timeout_scale_int, test_sleep5_pass); + tcase_add_test (tc_timeout_scale_int, test_sleep9_fail); + + /* tc_timeout_scale_double tests have a timeout of 4 (default) * 0.3 (multiplier) = 1.6 second */ + tcase_add_test (tc_timeout_scale_double, test_eternal_fail); +#ifdef HAVE_LIBRT + tcase_add_test (tc_timeout_scale_double, test_sleep0_025_pass); + tcase_add_test (tc_timeout_scale_double, test_sleep1_pass); +#endif /* HAVE_LIBRT */ + tcase_add_test (tc_timeout_scale_double, test_sleep2_fail); + tcase_add_test (tc_timeout_scale_double, test_sleep5_fail); + tcase_add_test (tc_timeout_scale_double, test_sleep9_fail); + + setenv("CK_TIMEOUT_MULTIPLIER", "2", 1); + tcase_set_timeout (tc_timeout_usr_scale_int, 6); + unsetenv("CK_TIMEOUT_MULTIPLIER"); + tcase_add_test (tc_timeout_usr_scale_int, test_eternal_fail); +#ifdef HAVE_LIBRT + tcase_add_test (tc_timeout_usr_scale_int, test_sleep0_025_pass); + tcase_add_test (tc_timeout_usr_scale_int, test_sleep1_pass); +#endif /* HAVE_LIBRT */ + tcase_add_test (tc_timeout_usr_scale_int, test_sleep2_pass); + tcase_add_test (tc_timeout_usr_scale_int, test_sleep5_pass); + tcase_add_test (tc_timeout_usr_scale_int, test_sleep9_pass); + tcase_add_test (tc_timeout_usr_scale_int, test_sleep14_fail); + + setenv("CK_TIMEOUT_MULTIPLIER", "0.4", 1); + tcase_set_timeout (tc_timeout_usr_scale_double, 0.9); + unsetenv("CK_TIMEOUT_MULTIPLIER"); + tcase_add_test (tc_timeout_usr_scale_double, test_eternal_fail); +#ifdef HAVE_LIBRT + tcase_add_test (tc_timeout_usr_scale_double, test_sleep0_025_pass); + tcase_add_test (tc_timeout_usr_scale_double, test_sleep1_fail); +#endif /* HAVE_LIBRT */ + tcase_add_test (tc_timeout_usr_scale_double, test_sleep2_fail); + tcase_add_test (tc_timeout_usr_scale_double, test_sleep5_fail); + tcase_add_test (tc_timeout_usr_scale_double, test_sleep9_fail); + tcase_add_test (tc_timeout_usr_scale_double, test_sleep14_fail); +#endif /* HAVE_DECL_SETENV */ +#endif /* TIMEOUT_TESTS_ENABLED && defined(HAVE_FORK) */ + +#if defined(HAVE_FORK) && HAVE_FORK==1 + tcase_add_test (tc_limit, test_early_exit); +#endif /* HAVE_FORK */ +#if MEMORY_LEAKING_TESTS_ENABLED + tcase_add_test (tc_limit, test_null); +#endif /* MEMORY_LEAKING_TESTS_ENABLED */ + tcase_add_test (tc_limit, test_null_2); + +#if defined(HAVE_FORK) && HAVE_FORK==1 + tcase_add_test (tc_messaging_and_fork, test_fork1p_pass); + tcase_add_test (tc_messaging_and_fork, test_fork1p_fail); + tcase_add_test (tc_messaging_and_fork, test_fork1c_pass); + tcase_add_test (tc_messaging_and_fork, test_fork1c_fail); + tcase_add_test (tc_messaging_and_fork, test_fork2_pass); + tcase_add_test (tc_messaging_and_fork, test_fork2_fail); + +#if MEMORY_LEAKING_TESTS_ENABLED + tcase_add_test_raise_signal (tc_errors, test_invalid_set_fork_status, 2); +#endif + + tcase_add_test (tc_exit_handlers, test_ignore_exit_handlers); +#endif /* HAVE_FORK */ + + return s; +} diff --git a/tests/check_check_tags.c b/tests/check_check_tags.c new file mode 100644 index 0000000..e4f485a --- /dev/null +++ b/tests/check_check_tags.c @@ -0,0 +1,763 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +#include "../lib/libcompat.h" + +#include +#include +#include +#include +#include +#include "check_check.h" + +enum { + RED, + BLUE, + PURPLE, + YELLOW, + BLACK, + MAX_TESTS +} test_ids; + +/* + * Flag per test which is set true when that test runs + */ +unsigned int test_executed[MAX_TESTS]; + +static void reset_executed(void) +{ + memset(test_executed, 0, sizeof(test_executed)); +} + +START_TEST(red_test1) +{ + test_executed[RED] = 1; +} +END_TEST + +START_TEST(blue_test1) +{ + test_executed[BLUE] = 1; +} +END_TEST + +START_TEST(purple_test1) +{ + test_executed[PURPLE] = 1; +} +END_TEST + +START_TEST(yellow_test1) +{ + test_executed[YELLOW] = 1; +} +END_TEST + +START_TEST(black_test1) +{ + test_executed[BLACK] = 1; +} +END_TEST + + +static SRunner *make_tagged_testrunner(void) +{ + + SRunner *sr; + Suite *s1, *s2; + + TCase *red, *blue, *purple, *yellow, *black; + + s1 = suite_create("RedBlue Suite"); + + red = tcase_create("Red"); + tcase_set_tags(red, "Red"); + suite_add_tcase (s1, red); + tcase_add_test(red, red_test1); + + blue = tcase_create("Blue"); + tcase_set_tags(blue, "Blue"); + suite_add_tcase (s1, blue); + tcase_add_test(blue, blue_test1); + + s2 = suite_create("PurpleYellowBlack Suite"); + + purple = tcase_create("Purple"); + tcase_set_tags(purple, "Red Blue"); + suite_add_tcase (s2, purple); + tcase_add_test(purple, purple_test1); + + yellow = tcase_create("Yellow"); + tcase_set_tags(yellow, "Yellow"); + suite_add_tcase (s2, yellow); + tcase_add_test(yellow, yellow_test1); + + black = tcase_create("Black"); + suite_add_tcase (s2, black); + tcase_add_test(black, black_test1); + + sr = srunner_create(s1); + srunner_add_suite(sr, s2); + + return sr; +} + +static SRunner *sr = NULL; + +static void tag_test_setup(void) +{ + sr = make_tagged_testrunner(); + srunner_set_fork_status(sr, CK_NOFORK); +} + +static void tag_test_teardown (void) +{ + srunner_free (sr); +} + +/* + * Show that with no filter we run all the tests + */ +START_TEST(null_filter) +{ + reset_executed(); + + srunner_run_tagged(sr, NULL, NULL, NULL, NULL, CK_VERBOSE); + + ck_assert(test_executed[RED]); + ck_assert(test_executed[BLUE]); + ck_assert(test_executed[PURPLE]); + ck_assert(test_executed[YELLOW]); + ck_assert(test_executed[BLACK]); + +} END_TEST + +START_TEST(include_nothing) +{ + reset_executed(); + + srunner_run_tagged(sr, NULL, NULL, "", NULL, CK_VERBOSE); + + ck_assert(!test_executed[RED]); + ck_assert(!test_executed[BLUE]); + ck_assert(!test_executed[PURPLE]); + ck_assert(!test_executed[YELLOW]); + ck_assert(!test_executed[BLACK]); + +} END_TEST + +START_TEST(exclude_nothing) +{ + reset_executed(); + + srunner_run_tagged(sr, NULL, NULL, NULL, "", CK_VERBOSE); + + ck_assert(test_executed[RED]); + ck_assert(test_executed[BLUE]); + ck_assert(test_executed[PURPLE]); + ck_assert(test_executed[YELLOW]); + ck_assert(test_executed[BLACK]); + +} END_TEST + +START_TEST(include_nothing_exclude_nothing) +{ + reset_executed(); + + srunner_run_tagged(sr, NULL, NULL, "", "", CK_VERBOSE); + + ck_assert(!test_executed[RED]); + ck_assert(!test_executed[BLUE]); + ck_assert(!test_executed[PURPLE]); + ck_assert(!test_executed[YELLOW]); + ck_assert(!test_executed[BLACK]); + +} END_TEST + +START_TEST(include_yellow) +{ + reset_executed(); + + srunner_run_tagged(sr, NULL, NULL, "Yellow", NULL, CK_VERBOSE); + + ck_assert(!test_executed[RED]); + ck_assert(!test_executed[BLUE]); + ck_assert(!test_executed[PURPLE]); + ck_assert(test_executed[YELLOW]); + ck_assert(!test_executed[BLACK]); + +} END_TEST + + +START_TEST(include_red) +{ + reset_executed(); + + srunner_run_tagged(sr, NULL, NULL, "Red", NULL, CK_VERBOSE); + + ck_assert(test_executed[RED]); + ck_assert(!test_executed[BLUE]); + ck_assert(test_executed[PURPLE]); + ck_assert(!test_executed[YELLOW]); + ck_assert(!test_executed[BLACK]); + +} END_TEST + +START_TEST(include_red_blue) +{ + reset_executed(); + + srunner_run_tagged(sr, NULL, NULL, "Red Blue", NULL, CK_VERBOSE); + + ck_assert(test_executed[RED]); + ck_assert(test_executed[BLUE]); + ck_assert(test_executed[PURPLE]); + ck_assert(!test_executed[YELLOW]); + ck_assert(!test_executed[BLACK]); + +} END_TEST + +START_TEST(include_red_blue_yellow) +{ + reset_executed(); + + srunner_run_tagged(sr, NULL, NULL, "Red Blue Yellow", NULL, CK_VERBOSE); + + ck_assert(test_executed[RED]); + ck_assert(test_executed[BLUE]); + ck_assert(test_executed[PURPLE]); + ck_assert(test_executed[YELLOW]); + ck_assert(!test_executed[BLACK]); + +} END_TEST + +START_TEST(exclude_yellow) +{ + reset_executed(); + + srunner_run_tagged(sr, NULL, NULL, NULL, "Yellow", CK_VERBOSE); + + ck_assert(test_executed[RED]); + ck_assert(test_executed[BLUE]); + ck_assert(test_executed[PURPLE]); + ck_assert(!test_executed[YELLOW]); + ck_assert(test_executed[BLACK]); + +} END_TEST + +START_TEST(exclude_red) +{ + reset_executed(); + + srunner_run_tagged(sr, NULL, NULL, NULL, "Red", CK_VERBOSE); + + ck_assert(!test_executed[RED]); + ck_assert(test_executed[BLUE]); + ck_assert(!test_executed[PURPLE]); + ck_assert(test_executed[YELLOW]); + ck_assert(test_executed[BLACK]); + +} END_TEST + +START_TEST(exclude_red_blue) +{ + reset_executed(); + + srunner_run_tagged(sr, NULL, NULL, NULL, "Red Blue", CK_VERBOSE); + + ck_assert(!test_executed[RED]); + ck_assert(!test_executed[BLUE]); + ck_assert(!test_executed[PURPLE]); + ck_assert(test_executed[YELLOW]); + ck_assert(test_executed[BLACK]); + +} END_TEST + +START_TEST(exclude_red_blue_yellow) +{ + reset_executed(); + + srunner_run_tagged(sr, NULL, NULL, NULL, "Red Blue Yellow", CK_VERBOSE); + + ck_assert(!test_executed[RED]); + ck_assert(!test_executed[BLUE]); + ck_assert(!test_executed[PURPLE]); + ck_assert(!test_executed[YELLOW]); + ck_assert(test_executed[BLACK]); + +} END_TEST + +#if HAVE_DECL_SETENV + +/* env var driven tests */ + +START_TEST(include_yellow_env) +{ + reset_executed(); + + setenv ("CK_INCLUDE_TAGS", "Yellow", 1); + srunner_run_all(sr, CK_VERBOSE); + + ck_assert(!test_executed[RED]); + ck_assert(!test_executed[BLUE]); + ck_assert(!test_executed[PURPLE]); + ck_assert(test_executed[YELLOW]); + ck_assert(!test_executed[BLACK]); + + unsetenv ("CK_INCLUDE_TAGS"); + +} END_TEST + + +START_TEST(include_red_env) +{ + reset_executed(); + + setenv ("CK_INCLUDE_TAGS", "Red", 1); + srunner_run_all(sr, CK_VERBOSE); + + ck_assert(test_executed[RED]); + ck_assert(!test_executed[BLUE]); + ck_assert(test_executed[PURPLE]); + ck_assert(!test_executed[YELLOW]); + ck_assert(!test_executed[BLACK]); + + unsetenv ("CK_INCLUDE_TAGS"); + +} END_TEST + +START_TEST(include_red_blue_env) +{ + reset_executed(); + + setenv ("CK_INCLUDE_TAGS", "Red Blue", 1); + srunner_run_all(sr, CK_VERBOSE); + + ck_assert(test_executed[RED]); + ck_assert(test_executed[BLUE]); + ck_assert(test_executed[PURPLE]); + ck_assert(!test_executed[YELLOW]); + ck_assert(!test_executed[BLACK]); + + unsetenv ("CK_INCLUDE_TAGS"); + +} END_TEST + +START_TEST(include_red_blue_yellow_env) +{ + reset_executed(); + + setenv ("CK_INCLUDE_TAGS", "Red Blue Yellow", 1); + srunner_run_all(sr, CK_VERBOSE); + + ck_assert(test_executed[RED]); + ck_assert(test_executed[BLUE]); + ck_assert(test_executed[PURPLE]); + ck_assert(test_executed[YELLOW]); + ck_assert(!test_executed[BLACK]); + + unsetenv ("CK_INCLUDE_TAGS"); + +} END_TEST + +START_TEST(exclude_yellow_env) +{ + reset_executed(); + + setenv ("CK_EXCLUDE_TAGS", "Yellow", 1); + srunner_run_all(sr, CK_VERBOSE); + + ck_assert(test_executed[RED]); + ck_assert(test_executed[BLUE]); + ck_assert(test_executed[PURPLE]); + ck_assert(!test_executed[YELLOW]); + ck_assert(test_executed[BLACK]); + + unsetenv ("CK_EXCLUDE_TAGS"); + +} END_TEST + +START_TEST(exclude_red_env) +{ + reset_executed(); + + setenv ("CK_EXCLUDE_TAGS", "Red", 1); + srunner_run_all(sr, CK_VERBOSE); + + ck_assert(!test_executed[RED]); + ck_assert(test_executed[BLUE]); + ck_assert(!test_executed[PURPLE]); + ck_assert(test_executed[YELLOW]); + ck_assert(test_executed[BLACK]); + + unsetenv ("CK_EXCLUDE_TAGS"); + +} END_TEST + +START_TEST(exclude_red_blue_env) +{ + reset_executed(); + + setenv ("CK_EXCLUDE_TAGS", "Red Blue", 1); + srunner_run_all(sr, CK_VERBOSE); + + ck_assert(!test_executed[RED]); + ck_assert(!test_executed[BLUE]); + ck_assert(!test_executed[PURPLE]); + ck_assert(test_executed[YELLOW]); + ck_assert(test_executed[BLACK]); + + unsetenv ("CK_EXCLUDE_TAGS"); + +} END_TEST + +START_TEST(exclude_red_blue_yellow_env) +{ + reset_executed(); + + setenv ("CK_EXCLUDE_TAGS", "Red Blue Yellow", 1); + srunner_run_all(sr, CK_VERBOSE); + + ck_assert(!test_executed[RED]); + ck_assert(!test_executed[BLUE]); + ck_assert(!test_executed[PURPLE]); + ck_assert(!test_executed[YELLOW]); + ck_assert(test_executed[BLACK]); + + unsetenv ("CK_EXCLUDE_TAGS"); + +} END_TEST + +START_TEST(include_red_case_red_env) +{ + reset_executed(); + + setenv ("CK_INCLUDE_TAGS", "Red Yellow", 1); + setenv ("CK_RUN_CASE", "Red", 1); + srunner_run_all(sr, CK_VERBOSE); + + ck_assert(test_executed[RED]); + ck_assert(!test_executed[BLUE]); + ck_assert(!test_executed[PURPLE]); + ck_assert(!test_executed[YELLOW]); + ck_assert(!test_executed[BLACK]); + + unsetenv ("CK_INCLUDE_TAGS"); + unsetenv ("CK_RUN_CASE"); + +} END_TEST + +START_TEST(include_red_case_blue_env) +{ + reset_executed(); + + setenv ("CK_INCLUDE_TAGS", "Red Yellow", 1); + setenv ("CK_RUN_CASE", "Blue", 1); + srunner_run_all(sr, CK_VERBOSE); + + ck_assert(!test_executed[RED]); + ck_assert(!test_executed[BLUE]); + ck_assert(!test_executed[PURPLE]); + ck_assert(!test_executed[YELLOW]); + ck_assert(!test_executed[BLACK]); + + unsetenv ("CK_INCLUDE_TAGS"); + unsetenv ("CK_RUN_CASE"); + +} END_TEST + +START_TEST(exclude_red_case_red_env) +{ + reset_executed(); + + setenv ("CK_EXCLUDE_TAGS", "Red Yellow", 1); + setenv ("CK_RUN_CASE", "Red", 1); + srunner_run_all(sr, CK_VERBOSE); + + ck_assert(!test_executed[RED]); + ck_assert(!test_executed[BLUE]); + ck_assert(!test_executed[PURPLE]); + ck_assert(!test_executed[YELLOW]); + ck_assert(!test_executed[BLACK]); + + unsetenv ("CK_EXCLUDE_TAGS"); + unsetenv ("CK_RUN_CASE"); + +} END_TEST + +START_TEST(exclude_red_case_blue_env) +{ + reset_executed(); + + setenv ("CK_EXCLUDE_TAGS", "Red Yellow", 1); + setenv ("CK_RUN_CASE", "Blue", 1); + srunner_run_all(sr, CK_VERBOSE); + + ck_assert(!test_executed[RED]); + ck_assert(test_executed[BLUE]); + ck_assert(!test_executed[PURPLE]); + ck_assert(!test_executed[YELLOW]); + ck_assert(!test_executed[BLACK]); + + unsetenv ("CK_EXCLUDE_TAGS"); + unsetenv ("CK_RUN_CASE"); + +} END_TEST + +START_TEST(include_red_suite_redblue_env) +{ + reset_executed(); + + setenv ("CK_INCLUDE_TAGS", "Red Yellow", 1); + setenv ("CK_RUN_SUITE", "RedBlue Suite", 1); + srunner_run_all(sr, CK_VERBOSE); + + ck_assert(test_executed[RED]); + ck_assert(!test_executed[BLUE]); + ck_assert(!test_executed[PURPLE]); + ck_assert(!test_executed[YELLOW]); + ck_assert(!test_executed[BLACK]); + + unsetenv ("CK_INCLUDE_TAGS"); + unsetenv ("CK_RUN_SUITE"); + +} END_TEST + +START_TEST(include_red_suite_purpleyellowblack_env) +{ + reset_executed(); + + setenv ("CK_INCLUDE_TAGS", "Red Yellow", 1); + setenv ("CK_RUN_SUITE", "PurpleYellowBlack Suite", 1); + srunner_run_all(sr, CK_VERBOSE); + + ck_assert(!test_executed[RED]); + ck_assert(!test_executed[BLUE]); + ck_assert(test_executed[PURPLE]); + ck_assert(test_executed[YELLOW]); + ck_assert(!test_executed[BLACK]); + + unsetenv ("CK_INCLUDE_TAGS"); + unsetenv ("CK_RUN_SUITE"); + +} END_TEST + +START_TEST(exclude_red_suite_redblue_env) +{ + reset_executed(); + + setenv ("CK_EXCLUDE_TAGS", "Red Yellow", 1); + setenv ("CK_RUN_SUITE", "RedBlue Suite", 1); + srunner_run_all(sr, CK_VERBOSE); + + ck_assert(!test_executed[RED]); + ck_assert(test_executed[BLUE]); + ck_assert(!test_executed[PURPLE]); + ck_assert(!test_executed[YELLOW]); + ck_assert(!test_executed[BLACK]); + + unsetenv ("CK_EXCLUDE_TAGS"); + unsetenv ("CK_RUN_SUITE"); + +} END_TEST + +START_TEST(exclude_red_suite_purpleyellowblack_env) +{ + reset_executed(); + + setenv ("CK_EXCLUDE_TAGS", "Red Yellow", 1); + setenv ("CK_RUN_SUITE", "PurpleYellowBlack Suite", 1); + srunner_run_all(sr, CK_VERBOSE); + + ck_assert(!test_executed[RED]); + ck_assert(!test_executed[BLUE]); + ck_assert(!test_executed[PURPLE]); + ck_assert(!test_executed[YELLOW]); + ck_assert(test_executed[BLACK]); + + unsetenv ("CK_EXCLUDE_TAGS"); + unsetenv ("CK_RUN_SUITE"); + +} END_TEST + + +#endif /* HAVE_DECL_SETENV */ + + +START_TEST(include_red_exclude_red) +{ + reset_executed(); + + srunner_run_tagged(sr, NULL, NULL, "Red", "Red", CK_VERBOSE); + + ck_assert(!test_executed[RED]); + ck_assert(!test_executed[BLUE]); + ck_assert(!test_executed[PURPLE]); + ck_assert(!test_executed[YELLOW]); + ck_assert(!test_executed[BLACK]); + +} END_TEST + +START_TEST(include_red_exclude_blue) +{ + reset_executed(); + + srunner_run_tagged(sr, NULL, NULL, "Red", "Blue", CK_VERBOSE); + + ck_assert(test_executed[RED]); + ck_assert(!test_executed[BLUE]); + ck_assert(!test_executed[PURPLE]); + ck_assert(!test_executed[YELLOW]); + ck_assert(!test_executed[BLACK]); + +} END_TEST + +START_TEST(include_red_include_red) +{ + reset_executed(); + + srunner_run_tagged(sr, NULL, NULL, "Red Red Red", NULL, CK_VERBOSE); + + ck_assert(test_executed[RED]); + ck_assert(!test_executed[BLUE]); + ck_assert(test_executed[PURPLE]); + ck_assert(!test_executed[YELLOW]); + ck_assert(!test_executed[BLACK]); + +} END_TEST + +START_TEST(include_w_spaces) +{ + reset_executed(); + + srunner_run_tagged(sr, NULL, NULL, " Red Blue ", NULL, CK_VERBOSE); + + ck_assert(test_executed[RED]); + ck_assert(test_executed[BLUE]); + ck_assert(test_executed[PURPLE]); + ck_assert(!test_executed[YELLOW]); + ck_assert(!test_executed[BLACK]); + +} END_TEST + +Suite *make_tag_suite(void) +{ + TCase *set_get_tags, *no_filters; + TCase *include_filters, *exclude_filters; +#if HAVE_DECL_SETENV + TCase *include_filters_env, *exclude_filters_env; +#endif /* HAVE_DECL_SETENV */ + TCase *include_exclude_filters, *strange_filters; + TCase *tag_plus_suite_env, *tag_plus_case_env; + Suite *s; + + s = suite_create("Check Tag Filtering"); + + no_filters = tcase_create("no tag filters"); + suite_add_tcase (s, no_filters); + tcase_add_test(no_filters, null_filter); + tcase_add_test(no_filters, include_nothing); + tcase_add_test(no_filters, exclude_nothing); + tcase_add_unchecked_fixture (no_filters, + tag_test_setup, + tag_test_teardown); + + include_filters = tcase_create("include tags"); + suite_add_tcase (s, include_filters); + tcase_add_test(include_filters, include_yellow); + tcase_add_test(include_filters, include_red); + tcase_add_test(include_filters, include_red_blue); + tcase_add_test(include_filters, include_red_blue_yellow); + tcase_add_unchecked_fixture (include_filters, + tag_test_setup, + tag_test_teardown); + + exclude_filters = tcase_create("exclude tags"); + suite_add_tcase (s, exclude_filters); + tcase_add_test(exclude_filters, exclude_yellow); + tcase_add_test(exclude_filters, exclude_red); + tcase_add_test(exclude_filters, exclude_red_blue); + tcase_add_test(exclude_filters, exclude_red_blue_yellow); + tcase_add_unchecked_fixture (exclude_filters, + tag_test_setup, + tag_test_teardown); + +#if HAVE_DECL_SETENV + + include_filters_env = tcase_create("include tags via env"); + suite_add_tcase (s, include_filters_env); + tcase_add_test(include_filters_env, include_yellow_env); + tcase_add_test(include_filters_env, include_red_env); + tcase_add_test(include_filters_env, include_red_blue_env); + tcase_add_test(include_filters_env, include_red_blue_yellow_env); + tcase_add_unchecked_fixture (include_filters_env, + tag_test_setup, + tag_test_teardown); + + exclude_filters_env = tcase_create("exclude tags via env"); + suite_add_tcase (s, exclude_filters_env); + tcase_add_test(exclude_filters_env, exclude_yellow_env); + tcase_add_test(exclude_filters_env, exclude_red_env); + tcase_add_test(exclude_filters_env, exclude_red_blue_env); + tcase_add_test(exclude_filters_env, exclude_red_blue_yellow_env); + tcase_add_unchecked_fixture (exclude_filters_env, + tag_test_setup, + tag_test_teardown); + + tag_plus_suite_env = tcase_create("combining tag filters with suite selection"); + suite_add_tcase (s, tag_plus_suite_env); + tcase_add_test(tag_plus_suite_env, include_red_suite_redblue_env); + tcase_add_test(tag_plus_suite_env, include_red_suite_purpleyellowblack_env); + tcase_add_test(tag_plus_suite_env, exclude_red_suite_redblue_env); + tcase_add_test(tag_plus_suite_env, exclude_red_suite_purpleyellowblack_env); + tcase_add_unchecked_fixture (tag_plus_suite_env, + tag_test_setup, + tag_test_teardown); + + tag_plus_case_env = tcase_create("combining tag filters with case selection"); + suite_add_tcase (s, tag_plus_case_env); + tcase_add_test(tag_plus_case_env, include_red_case_red_env); + tcase_add_test(tag_plus_case_env, include_red_case_blue_env); + tcase_add_test(tag_plus_case_env, exclude_red_case_red_env); + tcase_add_test(tag_plus_case_env, exclude_red_case_blue_env); + tcase_add_unchecked_fixture (tag_plus_case_env, + tag_test_setup, + tag_test_teardown); + +#endif /* HAVE_DECL_SETENV */ + + include_exclude_filters = tcase_create("include and exclude tags"); + suite_add_tcase (s, include_exclude_filters); + tcase_add_test(include_exclude_filters, include_nothing_exclude_nothing); + tcase_add_test(include_exclude_filters, include_red_exclude_blue); + tcase_add_test(include_exclude_filters, include_red_exclude_red); + tcase_add_unchecked_fixture (include_exclude_filters, + tag_test_setup, + tag_test_teardown); + + strange_filters = tcase_create("strange tag filters"); + suite_add_tcase (s, strange_filters); + tcase_add_test(strange_filters, include_red_include_red); + tcase_add_test(strange_filters, include_w_spaces); + tcase_add_unchecked_fixture (strange_filters, + tag_test_setup, + tag_test_teardown); + + return s; +} diff --git a/tests/check_list.c b/tests/check_list.c new file mode 100644 index 0000000..60b8b7f --- /dev/null +++ b/tests/check_list.c @@ -0,0 +1,210 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "../lib/libcompat.h" + +#include +#include + +#include "check.h" +#include "check_list.h" +#include "check_check.h" + +START_TEST(test_create) +{ + List *lp = NULL; + + ck_assert_msg (check_list_val(lp) == NULL, + "Current list value should be NULL for NULL list"); + + lp = check_list_create(); + + ck_assert_msg (check_list_val(lp) == NULL, + "Current list value should be NULL for newly created list"); + + ck_assert_msg (check_list_at_end(lp), + "Newly created list should be at end"); + check_list_advance(lp); + ck_assert_msg (check_list_at_end(lp), + "Advancing a list at end should produce a list at end"); + check_list_free (lp); +} +END_TEST + +START_TEST(test_free) +{ + List *lp = check_list_create(); + char data_abc[] = "abc"; + char data_123[] = "123"; + + check_list_add_end (lp, data_abc); + check_list_add_end (lp, data_123); + check_list_add_end (lp, NULL); + check_list_free (lp); +} +END_TEST + +START_TEST(test_add_end) +{ + List * lp = check_list_create(); + char tval[] = "abc"; + + check_list_add_end (lp, tval); + + ck_assert_msg (check_list_val (lp) != NULL, + "List current val should not be null after new insertion"); + ck_assert_msg (!check_list_at_end (lp), + "List should be at end after new insertion"); + ck_assert_msg (strcmp(tval, (char *) check_list_val (lp)) == 0, + "List current val should equal newly inserted val"); + check_list_free (lp); +} +END_TEST + +START_TEST(test_add_front) +{ + List * lp = check_list_create(); + char tval[] = "abc"; + + check_list_add_front (lp, tval); + + ck_assert_msg (check_list_val (lp) != NULL, + "List current val should not be null after new insertion"); + ck_assert_msg (strcmp(tval, (char *) check_list_val (lp)) == 0, + "List current val should equal newly inserted val"); + check_list_free (lp); +} +END_TEST + +START_TEST(test_add_end_and_next) +{ + List *lp = check_list_create(); + char tval1[] = "abc"; + char tval2[] = "123"; + + check_list_add_end (lp, tval1); + check_list_add_end (lp, tval2); + check_list_front(lp); + ck_assert_msg (strcmp (tval1, (char *)check_list_val (lp)) == 0, + "List head val should equal first inserted val"); + check_list_advance (lp); + ck_assert_msg (!check_list_at_end (lp), + "List should not be at end after two adds and one next"); + ck_assert_msg (strcmp (tval2, (char *)check_list_val (lp)) == 0, + "List val should equal second inserted val"); + check_list_advance(lp); + ck_assert_msg (check_list_at_end (lp), + "List should be at and after two adds and two nexts"); + check_list_free (lp); +} +END_TEST + + +START_TEST(test_add_front_and_next) +{ + List * lp = check_list_create(); + char tval1[] = "abc"; + char tval2[] = "123"; + + check_list_add_front (lp, tval1); + check_list_add_front (lp, tval2); + check_list_front(lp); + ck_assert_msg (strcmp (tval2, (char *)check_list_val (lp)) == 0, + "List head val should equal last inserted val"); + check_list_advance (lp); + ck_assert_msg (!check_list_at_end (lp), + "List should not be at end after two adds and one next"); + ck_assert_msg (strcmp (tval1, (char *)check_list_val (lp)) == 0, + "List val should equal first inserted val"); + check_list_advance(lp); + ck_assert_msg (check_list_at_end (lp), + "List should be at and after two adds and two nexts"); + check_list_free (lp); +} +END_TEST + +START_TEST(test_add_a_bunch) +{ + List *lp; + int i, j; + char tval1[] = "abc"; + char tval2[] = "123"; + for (i = 0; i < 3; i++) { + lp = check_list_create(); + for (j = 0; j < 1000; j++) { + check_list_add_end (lp, tval1); + check_list_add_front (lp, tval2); + } + check_list_free(lp); + } +} +END_TEST + +START_TEST(test_list_abuse) +{ + check_list_advance(NULL); + /* Should not crash */ +} +END_TEST + +START_TEST(test_contains) +{ + List *lp = check_list_create(); + + char otherData[] = "other"; + char goalData[] = "goal"; + int index; + + ck_assert_msg (check_list_contains(lp, goalData) == 0, + "The goal data should not be in the list yet"); + + for(index = 0; index < 10; index++) + { + check_list_add_end (lp, otherData); + ck_assert_msg (check_list_contains(lp, goalData) == 0, + "The goal data should not be in the list yet"); + } + + check_list_add_end (lp, goalData); + ck_assert_msg (check_list_contains(lp, goalData) , + "The goal data should be in the list"); + + check_list_free(lp); +} +END_TEST + +Suite *make_list_suite (void) +{ + Suite *s = suite_create("Lists"); + TCase * tc = tcase_create("Core"); + + suite_add_tcase (s, tc); + tcase_add_test (tc, test_create); + tcase_add_test (tc, test_free); + tcase_add_test (tc, test_add_end); + tcase_add_test (tc, test_add_front); + tcase_add_test (tc, test_add_end_and_next); + tcase_add_test (tc, test_add_front_and_next); + tcase_add_test (tc, test_add_a_bunch); + tcase_add_test (tc, test_list_abuse); + tcase_add_test (tc, test_contains); + + return s; +} diff --git a/tests/check_mem_leaks.c b/tests/check_mem_leaks.c new file mode 100644 index 0000000..4528fb0 --- /dev/null +++ b/tests/check_mem_leaks.c @@ -0,0 +1,90 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +/** + * The purpose of this test is to be used by valgrind to check for + * memory leaks. Each public API that check exports is used at + * least once. Tests which use non-public API, or leak intentionally, + * are not included here. + */ + +#include +#include +#include +#include +#include "config.h" +#include "check_check.h" + +int main () +{ + int n; + SRunner *sr; + + /* + * First, the sub suite is run. This suite has failures which + * are intentional, as the output of the failures is checked + * in check_check_master.c. However, here we do not check if + * the failures are expected. Instead, we just want to run + * them and see if they leak. Because of this, the result + * of the suite is not checked. + */ + sr = srunner_create(make_sub_suite()); + /* + * Enable all logging types, just in case one of them + * leaks memory. + */ + srunner_set_log (sr, "test_mem_leak.log"); + srunner_set_xml (sr, "test_mem_leak.xml"); + srunner_set_tap (sr, "test_mem_leak.tap"); + srunner_run_all(sr, CK_NORMAL); + srunner_free(sr); + + /* Now, the other suite is run. These are all expected to pass. */ + + /* The following setup is necessary for the fork suite */ + fork_setup(); + + sr = srunner_create (make_log_suite()); + srunner_add_suite(sr, make_fork_suite()); + +#if defined(HAVE_FORK) && HAVE_FORK==1 + srunner_add_suite(sr, make_exit_suite()); +#endif + srunner_add_suite(sr, make_tag_suite()); + srunner_add_suite(sr, make_selective_suite()); + + /* + * Enable all logging types, just in case one of them + * leaks memory. + */ + srunner_set_log (sr, "test_mem_leak.log"); + srunner_set_xml (sr, "test_mem_leak.xml"); + srunner_set_tap (sr, "test_mem_leak.tap"); + + srunner_run_all(sr, CK_NORMAL); + + /* Cleanup from the fork suite setup */ + fork_teardown(); + + n = srunner_ntests_failed(sr); + srunner_free(sr); + return (n == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + diff --git a/tests/check_nofork.c b/tests/check_nofork.c new file mode 100644 index 0000000..da2ddd2 --- /dev/null +++ b/tests/check_nofork.c @@ -0,0 +1,84 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "../lib/libcompat.h" + +#include +#include +#include + + +Suite *s; +TCase *tc; +SRunner *sr; + +START_TEST(test_nofork_exit) +{ + char* s = NULL; + + ck_assert(NULL != s); + + /* this test should not crash in nofork mode */ + ck_assert_str_eq("test", s); +} +END_TEST + +#if !defined(HAVE_FORK) || HAVE_FORK == 0 +START_TEST(test_check_fork) +{ + ck_assert_int_eq(-1, check_fork()); +} +END_TEST +#endif + +int main(void) +{ + s = suite_create("NoFork"); + tc = tcase_create("Exit"); + sr = srunner_create(s); + + suite_add_tcase(s, tc); + tcase_add_test(tc, test_nofork_exit); + + srunner_set_fork_status(sr, CK_NOFORK); + srunner_run_all(sr, CK_MINIMAL); + srunner_free(sr); + +#if !defined(HAVE_FORK) || HAVE_FORK == 0 + s = suite_create("NoForkSupport"); + tc = tcase_create("NoFork"); + sr = srunner_create(s); + + /* The following should not fail, but should be ignored */ + srunner_set_fork_status(sr, CK_FORK); + if(srunner_fork_status(sr) != CK_NOFORK) + { + fprintf(stderr, "Call to srunner_set_fork_status() was not ignored\n"); + exit(1); + } + + suite_add_tcase(s, tc); + tcase_add_test(tc, test_check_fork); + srunner_run_all(sr, CK_MINIMAL); + srunner_free(sr); +#endif + + return 0; +} diff --git a/tests/check_nofork_teardown.c b/tests/check_nofork_teardown.c new file mode 100644 index 0000000..6484e32 --- /dev/null +++ b/tests/check_nofork_teardown.c @@ -0,0 +1,82 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "../lib/libcompat.h" + +#include +#include +#include "check.h" + +/** + * This test checks the result if in CK_NOFORK + * mode a unit test fails but a checked teardown + * runs after the failed test. + * + * Previously, the failure would be reported as: + * + * 0%: Checks: 1, Failures: 1, Errors: 0 + * (null):-1:S:tc:will_fail:0: Assertion '0' failed + * + * The reason why this happens is this: the end of the + * message sequence coming down the pipe is CK_MSG_LOC + * (location of failing test), CK_MSG_FAIL, CK_MSG_CTX + * (TEARDOWN). It is this final message that confuses + * things, because rcvmsg_update_ctx() updates + * rmsg->lastctx (which likely is the right thing for it + * to do), which is the ctx value used by the first 'if' + * body in construct_test_result() in its call to + * tr_set_loc_by_ctx(). + * + * After the fix, the test failure should be reported + * as: + * + * 0%: Checks: 1, Failures: 1, Errors: 0 + * check_nofork_teardown.c:33:F:tc:will_fail:0: Assertion '0' failed + */ + +START_TEST( will_fail ) +{ + ck_assert(0); +} +END_TEST + +static void empty_checked_teardown( void ) +{ +} + +int main( void ) +{ + SRunner *sr = srunner_create( NULL ); + Suite *s = suite_create( "bug-99" ); + TCase *tc = tcase_create( "tc" ); + int result; + + srunner_add_suite( sr, s ); + srunner_set_fork_status( sr, CK_NOFORK ); + suite_add_tcase( s, tc ); + tcase_add_checked_fixture( tc, NULL, empty_checked_teardown ); + tcase_add_test( tc, will_fail ); + + srunner_run_all( sr, CK_ENV ); + result = srunner_ntests_failed( sr ) ? EXIT_FAILURE : EXIT_SUCCESS; + srunner_free( sr ); + + return result; +} diff --git a/tests/check_set_max_msg_size.c b/tests/check_set_max_msg_size.c new file mode 100644 index 0000000..6ebfc8e --- /dev/null +++ b/tests/check_set_max_msg_size.c @@ -0,0 +1,74 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +/** + * The purpose of this test is to reduce the maximal assertion message size + * in order to trigger the "Message string too long" error. + */ + +#include +#include +#include +#include +#include "config.h" +#include "check_check.h" + +START_TEST(test_set_max_msg_size) +{ + ck_abort_msg("40 characters of an assertion message..."); +} +END_TEST + + +static Suite *make_set_max_msg_size_suite(void) +{ + Suite *s = suite_create("Check Set Max Msg Size"); + + TCase *tc_set_max_msg_size = tcase_create("Test Set Max Msg Size"); + + suite_add_tcase (s, tc_set_max_msg_size); + + tcase_add_test (tc_set_max_msg_size, test_set_max_msg_size); + + return s; +} + +int main (int argc, char *argv[]) +{ + int n; + SRunner *sr; + + if (argc != 2) { + fprintf(stderr, "usage: %s max-msg-size\n", argv[0]); + return EXIT_FAILURE; + } + + /* + * Run the test suite. This is intended to trigger the "Message is too long" error. + * Actual success/failure is determined by examining the output. + */ + check_set_max_msg_size(32); // 1st call has no effect since + check_set_max_msg_size(atoi(argv[1])); // the 2nd call will override it. + sr = srunner_create(make_set_max_msg_size_suite()); + srunner_run_all(sr, CK_NORMAL); + srunner_free(sr); + return EXIT_SUCCESS; +} + diff --git a/tests/check_stress.c b/tests/check_stress.c new file mode 100644 index 0000000..7f0756e --- /dev/null +++ b/tests/check_stress.c @@ -0,0 +1,84 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "../lib/libcompat.h" + +/* note: this test appears pretty useless, so we aren't including it + in the TESTS variable of Makefile.am */ + +#include +#include +#include + + +Suite *s; +TCase *tc; +SRunner *sr; + +START_TEST(test_pass) +{ + ck_assert_msg(1,"Shouldn't see this message"); +} +END_TEST + +START_TEST(test_fail) +{ + ck_abort_msg("This test fails"); +} +END_TEST + + +static void run (int num_iters) +{ + int i; + s = suite_create ("Stress"); + tc = tcase_create ("Stress"); + sr = srunner_create (s); + suite_add_tcase(s, tc); + + for (i = 0; i < num_iters; i++) { + tcase_add_test (tc, test_pass); + tcase_add_test (tc, test_fail); + } + + srunner_run_all(sr, CK_SILENT); + if (srunner_ntests_failed (sr) != num_iters) { + printf ("Error: expected %d failures, got %d\n", + num_iters, srunner_ntests_failed(sr)); + return; + } + + srunner_free(sr); +} + + +int main(void) +{ + int i; + time_t t1; + int iters[] = {1, 100, 1000, 2000, 4000, 8000, 10000, 20000, 40000, -1}; + + for (i = 0; iters[i] != -1; i++) { + t1 = time(NULL); + run(iters[i]); + printf ("%d, %d\n", iters[i], (int) difftime(time(NULL), t1)); + } + return 0; +} diff --git a/tests/check_thread_stress.c b/tests/check_thread_stress.c new file mode 100644 index 0000000..717e62d --- /dev/null +++ b/tests/check_thread_stress.c @@ -0,0 +1,103 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "../lib/libcompat.h" + +#include +#include +#include + +Suite *s; +TCase *tc; +SRunner *sr; + +#if defined (HAVE_PTHREAD) || defined (HAVE_FORK) +static void * +sendinfo (void *userdata CK_ATTRIBUTE_UNUSED) +{ + unsigned int i; + for (i = 0; i < 999; i++) + { + ck_assert_msg (1, "Shouldn't see this message"); + } + return NULL; +} +#endif /* HAVE_PTHREAD || HAVE_FORK */ + +#ifdef HAVE_PTHREAD +START_TEST (test_stress_threads) +{ + pthread_t a, b; + pthread_create (&a, NULL, sendinfo, (void *) 0xa); + pthread_create (&b, NULL, sendinfo, (void *) 0xb); + + pthread_join (a, NULL); + pthread_join (b, NULL); +} +END_TEST +#endif /* HAVE_PTHREAD */ + +#if defined(HAVE_FORK) && HAVE_FORK==1 +START_TEST (test_stress_forks) +{ + pid_t cpid = fork (); + if (cpid == 0) + { + /* child */ + sendinfo ((void *) 0x1); + exit (EXIT_SUCCESS); + } + else + { + /* parent */ + sendinfo ((void *) 0x2); + } +} +END_TEST +#endif /* HAVE_FORK */ + +int +main (void) +{ + int nf; + s = suite_create ("ForkThreadStress"); + tc = tcase_create ("ForkThreadStress"); + sr = srunner_create (s); + suite_add_tcase (s, tc); + +#ifdef HAVE_PTHREAD + tcase_add_loop_test (tc, test_stress_threads, 0, 100); +#endif /* HAVE_PTHREAD */ + +#if defined(HAVE_FORK) && HAVE_FORK==1 + tcase_add_loop_test (tc, test_stress_forks, 0, 100); +#endif /* HAVE_FORK */ + + srunner_run_all (sr, CK_VERBOSE); + nf = srunner_ntests_failed (sr); + srunner_free (sr); + + /* hack to give us XFAIL on non-posix platforms */ +#ifndef HAVE_FORK + nf++; +#endif /* !HAVE_FORK */ + + return nf ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/tests/ex_output.c b/tests/ex_output.c new file mode 100644 index 0000000..89006cf --- /dev/null +++ b/tests/ex_output.c @@ -0,0 +1,283 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + + + +#include +#include +#include +#include +#include "config.h" + +START_TEST(test_pass) +{ + ck_assert_msg(1 == 1, "Shouldn't see this"); +} +END_TEST + +START_TEST(test_fail) +{ + ck_abort_msg("Failure"); +} +END_TEST + +/* + * This test will fail without fork, as it will result in the + * unit test runniner exiting early. + */ +#if defined(HAVE_FORK) && HAVE_FORK==1 +START_TEST(test_exit) +{ + exit(1); +} +END_TEST +#endif /* HAVE_FORK */ + +/* + * This test will intentionally mess up the unit testing program + * when fork is unavailable. The purpose of including it is to + * ensure that the tap output is correct when a test crashes. + */ +START_TEST(test_abort) +{ + exit(1); +} +END_TEST + +START_TEST(test_pass2) +{ + ck_assert_msg(1 == 1, "Shouldn't see this"); +} +END_TEST + +START_TEST(test_loop) +{ + ck_assert_msg(_i == 1, "Iteration %d failed", _i); +} +END_TEST + +START_TEST(test_xml_esc_fail_msg) +{ + ck_abort_msg("fail \" ' < > & \x9 \xA" "X""\x08"" message"); /* backspace char \x08 deletes the X */ +} +END_TEST + +static Suite *make_log1_suite(void) +{ + Suite *s; + TCase *tc; + + s = suite_create("S1"); + tc = tcase_create("Core"); + suite_add_tcase(s, tc); + tcase_add_test(tc, test_pass); + tcase_add_test(tc, test_fail); +#if defined(HAVE_FORK) && HAVE_FORK==1 + tcase_add_test(tc, test_exit); +#endif /* HAVE_FORK */ + + return s; +} + +static Suite *make_log2_suite(int include_exit_test) +{ + Suite *s; + TCase *tc; + + s = suite_create("S2"); + tc = tcase_create("Core"); + suite_add_tcase(s, tc); + if(include_exit_test == 1) + { + tcase_add_test(tc, test_abort); + } + tcase_add_test(tc, test_pass2); + tcase_add_loop_test(tc, test_loop, 0, 3); + + return s; +} + +/* check that XML special characters are properly escaped in XML log file */ +static Suite *make_xml_esc_suite(void) +{ + Suite *s; + TCase *tc; + + s = suite_create("XML escape \" ' < > & \x9 \xA" "X""\x08"" tests"); /* backspace char \x08 deletes the X */ + tc = tcase_create("description \" ' < > & \x9 \xA" "X""\x08"" end"); /* backspace char \x08 deletes the X */ + suite_add_tcase(s, tc); + + tcase_add_test(tc, test_xml_esc_fail_msg); + + return s; +} + +static void print_usage(void) +{ + printf("Usage: ex_output (CK_SILENT | CK_MINIMAL | CK_NORMAL | CK_VERBOSE | CK_ENV"); +#if ENABLE_SUBUNIT + printf(" | CK_SUBUNIT"); +#endif + printf(")\n"); + printf(" (STDOUT | STDOUT_DUMP | LOG | LOG_STDOUT | TAP | TAP_STDOUT | XML | XML_STDOUT)\n"); + printf(" (NORMAL | EXIT_TEST)\n"); + printf(" If CK_ENV is used, the environment variable CK_VERBOSITY can be set to\n"); + printf(" one of these: silent, minimal, or verbose. If it is not set to these, or\n"); + printf(" if CK_VERBOSITY is not set, then CK_NORMAL will be used\n"); + printf(" If testing the CK_[LOG|TAP_LOG|XML_LOG]_FILE_NAME env var and setting it to '-',\n"); + printf(" then use the following mode: CK_SILENT STDOUT [NORMAL|EXIT_TEST].\n"); +} + +static void run_tests(enum print_output printmode, char *log_type, int include_exit_test) +{ + SRunner *sr; + int dump_everything_to_stdout = 0; + + sr = srunner_create(make_log1_suite()); + srunner_add_suite(sr, make_log2_suite(include_exit_test)); + srunner_add_suite(sr, make_xml_esc_suite()); + + if(strcmp(log_type, "STDOUT") == 0) + { + /* Nothing else to do here */ + } + else if(strcmp(log_type, "STDOUT_DUMP") == 0) + { + /* + * Dump each type to stdout, in addition to printing out + * the configured print level. + */ + dump_everything_to_stdout = 1; + } + else if(strcmp(log_type, "LOG") == 0) + { + srunner_set_log(sr, "test.log"); + } + else if(strcmp(log_type, "LOG_STDOUT") == 0) + { + srunner_set_log(sr, "-"); + } + else if(strcmp(log_type, "TAP") == 0) + { + srunner_set_tap(sr, "test.tap"); + } + else if(strcmp(log_type, "TAP_STDOUT") == 0) + { + srunner_set_tap(sr, "-"); + } + else if(strcmp(log_type, "XML") == 0) + { + srunner_set_xml(sr, "test.xml"); + } + else if(strcmp(log_type, "XML_STDOUT") == 0) + { + srunner_set_xml(sr, "-"); + } + else + { + print_usage(); + exit(EXIT_FAILURE); + } + + srunner_run_all(sr, printmode); + + if(dump_everything_to_stdout) + { + srunner_print(sr, CK_SILENT); + srunner_print(sr, CK_MINIMAL); + srunner_print(sr, CK_NORMAL); + srunner_print(sr, CK_VERBOSE); + srunner_print(sr, CK_ENV); +#if ENABLE_SUBUNIT + /* + * Note that this call does not contribute anything, as + * subunit is not fully considered an 'output mode'. + */ + srunner_print(sr, CK_SUBUNIT); +#endif + } + + srunner_free(sr); +} + +#define OUTPUT_TYPE_ARG 1 +#define LOG_TYPE_ARG 2 +#define INCLUDE_EXIT_TEST_ARG 3 +int main(int argc, char **argv) +{ + enum print_output printmode; + int include_exit_test; + + if(argc != 4) + { + print_usage(); + return EXIT_FAILURE; + } + + if(strcmp(argv[OUTPUT_TYPE_ARG], "CK_SILENT") == 0) + { + printmode = CK_SILENT; + } + else if(strcmp(argv[OUTPUT_TYPE_ARG], "CK_MINIMAL") == 0) + { + printmode = CK_MINIMAL; + } + else if(strcmp(argv[OUTPUT_TYPE_ARG], "CK_NORMAL") == 0) + { + printmode = CK_NORMAL; + } + else if(strcmp(argv[OUTPUT_TYPE_ARG], "CK_VERBOSE") == 0) + { + printmode = CK_VERBOSE; + } + else if(strcmp(argv[OUTPUT_TYPE_ARG], "CK_ENV") == 0) + { + printmode = CK_ENV; + } +#if ENABLE_SUBUNIT + else if(strcmp(argv[OUTPUT_TYPE_ARG], "CK_SUBUNIT") == 0) + { + printmode = CK_SUBUNIT; + } +#endif + else + { + print_usage(); + return EXIT_FAILURE; + } + + if(strcmp(argv[INCLUDE_EXIT_TEST_ARG], "NORMAL") == 0) + { + include_exit_test = 0; + } + else if(strcmp(argv[INCLUDE_EXIT_TEST_ARG], "EXIT_TEST") == 0) + { + include_exit_test = 1; + } + else + { + print_usage(); + return EXIT_FAILURE; + } + + run_tests(printmode, argv[LOG_TYPE_ARG], include_exit_test); + + return EXIT_SUCCESS; +} diff --git a/tests/test_check_nofork.sh b/tests/test_check_nofork.sh new file mode 100755 index 0000000..fda9cd9 --- /dev/null +++ b/tests/test_check_nofork.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env sh + +. ./test_vars + +if [ $HAVE_FORK -eq 1 ]; then +expected="Running suite(s): NoFork +0%: Checks: 1, Failures: 1, Errors: 0" +else +expected="Running suite(s): NoFork +0%: Checks: 1, Failures: 1, Errors: 0 +Running suite(s): NoForkSupport +100%: Checks: 1, Failures: 0, Errors: 0" +fi + +actual=`./check_nofork${EXEEXT} | tr -d "\r"` +if [ x"${expected}" = x"${actual}" ]; then + exit 0 +else + echo "Problem with check_nofork${EXEEXT}" + echo "Expected: " + echo "${expected}" + echo "Got: " + echo "${actual}" + exit 1 +fi diff --git a/tests/test_check_nofork_teardown.sh b/tests/test_check_nofork_teardown.sh new file mode 100755 index 0000000..44cf42c --- /dev/null +++ b/tests/test_check_nofork_teardown.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env sh + +. ./test_vars + +expected="Running suite(s): bug-99 +0%: Checks: 1, Failures: 1, Errors: 0 +${SRCDIR}check_nofork_teardown.c:56:F:tc:will_fail:0: Assertion '0' failed" + +actual=`./check_nofork_teardown${EXEEXT} | tr -d "\r"` +if [ x"${expected}" = x"${actual}" ]; then + exit 0 +else + echo "Problem with check_nofork_teardown${EXEEXT}" + echo "Expected: " + echo "${expected}" + echo "Got: " + echo "${actual}" + exit 1 +fi diff --git a/tests/test_log_output.sh b/tests/test_log_output.sh new file mode 100755 index 0000000..962bf32 --- /dev/null +++ b/tests/test_log_output.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env sh + +OUTPUT_FILE=test.log + +. ./test_vars +. $(dirname $0)/test_output_strings + +test_log_output ( ) { + rm -f ${OUTPUT_FILE} + ./ex_output${EXEEXT} "${1}" "LOG" "NORMAL" > /dev/null + actual=`cat ${OUTPUT_FILE} | tr -d "\r"` + expected=${2} + if [ x"${expected}" != x"${actual}" ]; then + echo "Problem with ex_log_output${EXEEXT} ${1} LOG NORMAL"; + echo "Expected:"; + echo "${expected}"; + echo "Got:"; + echo "${actual}"; + exit 1; + fi + +} + +test_log_output "CK_SILENT" "${expected_log_log}" +test_log_output "CK_MINIMAL" "${expected_log_log}" +test_log_output "CK_NORMAL" "${expected_log_log}" +test_log_output "CK_VERBOSE" "${expected_log_log}" +exit 0 diff --git a/tests/test_mem_leaks.sh b/tests/test_mem_leaks.sh new file mode 100755 index 0000000..44d6d30 --- /dev/null +++ b/tests/test_mem_leaks.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env sh + +UNIT_TEST=./check_mem_leaks +VALGRIND_LOG_FILE=${UNIT_TEST}.valgrind +LEAK_MESSAGE="are definitely lost" + +# This test runs valgrind against the check_mem_leaks unit test +# program, looking for memory leaks. If any are found, "exit 1" +# is invoked, and one must look through the resulting valgrind log +# file for details on the leak. + +rm -f ${VALGRIND_LOG_FILE} +libtool --mode=execute valgrind --leak-check=full ${UNIT_TEST} 2>&1 | tee ${VALGRIND_LOG_FILE} + +NUM_LEAKS=$(grep "${LEAK_MESSAGE}" ${VALGRIND_LOG_FILE} | wc -l) + +if test ${NUM_LEAKS} -gt 0; then + echo "ERROR: ${NUM_LEAKS} memory leaks were detected by valgrind." + echo " Look through ${VALGRIND_LOG_FILE} for details," + echo " searching for \"${LEAK_MESSAGE}\"." + exit 1 +else + echo "No memory leaks found" + exit 0 +fi diff --git a/tests/test_output.sh b/tests/test_output.sh new file mode 100755 index 0000000..c1b31bd --- /dev/null +++ b/tests/test_output.sh @@ -0,0 +1,103 @@ +#!/usr/bin/env sh + +. ./test_vars +. $(dirname $0)/test_output_strings + +# When the ex_output program is run with the STDOUT_DUMP mode, it will +# run with the normal output mode, then dump each output mode using +# srunner_print() in this order: +# CK_SILENT CK_MINIMAL CK_NORMAL CK_VERBOSE CK_ENV CK_SUBUNIT +# note though that CK_SUBUNIT does not output anything, as it is +# not fully considered an 'output mode'. +exp_silent_dump="$exp_minimal_result +$exp_normal_result +$exp_verbose_result" +exp_minimal_dump="$exp_minimal +$exp_minimal_result +$exp_normal_result +$exp_verbose_result +$exp_minimal_result" +exp_normal_dump="$exp_normal +$exp_minimal_result +$exp_normal_result +$exp_verbose_result +$exp_normal_result" +exp_verbose_dump="$exp_verbose +$exp_minimal_result +$exp_normal_result +$exp_verbose_result +$exp_verbose_result" +exp_subunit_dump="$exp_subunit + +$exp_minimal_result +$exp_normal_result +$exp_verbose_result +$exp_normal_result" + +act_silent=`./ex_output${EXEEXT} CK_SILENT STDOUT NORMAL | tr -d "\r"` +act_silent_env=`CK_VERBOSITY=silent ./ex_output${EXEEXT} CK_ENV STDOUT NORMAL | tr -d "\r"` +act_silent_dump_env=`CK_VERBOSITY=silent ./ex_output${EXEEXT} CK_ENV STDOUT_DUMP NORMAL | tr -d "\r"` +act_minimal=`./ex_output${EXEEXT} CK_MINIMAL STDOUT NORMAL | tr -d "\r"` +act_minimal_env=`CK_VERBOSITY=minimal ./ex_output${EXEEXT} CK_ENV STDOUT NORMAL | tr -d "\r"` +act_minimal_dump_env=`CK_VERBOSITY=minimal ./ex_output${EXEEXT} CK_ENV STDOUT_DUMP NORMAL | tr -d "\r"` +act_normal=`./ex_output${EXEEXT} CK_NORMAL STDOUT NORMAL | tr -d "\r"` +act_normal_env=`CK_VERBOSITY=normal CK_VERBOSITY='' ./ex_output${EXEEXT} CK_ENV STDOUT NORMAL | tr -d "\r"` +act_normal_dump_env=`CK_VERBOSITY=normal CK_VERBOSITY='' ./ex_output${EXEEXT} CK_ENV STDOUT_DUMP NORMAL | tr -d "\r"` +act_normal_env_blank=`./ex_output${EXEEXT} CK_ENV STDOUT NORMAL | tr -d "\r"` +act_normal_env_invalid=`CK_VERBOSITY='BLARGS' ./ex_output${EXEEXT} CK_ENV STDOUT NORMAL | tr -d "\r"` +act_verbose=`./ex_output${EXEEXT} CK_VERBOSE STDOUT NORMAL | tr -d "\r"` +act_verbose_env=`CK_VERBOSITY=verbose ./ex_output${EXEEXT} CK_ENV STDOUT NORMAL | tr -d "\r"` +act_verbose_dump_env=`CK_VERBOSITY=verbose ./ex_output${EXEEXT} CK_ENV STDOUT_DUMP NORMAL | tr -d "\r"` +if test 1 -eq $ENABLE_SUBUNIT; then +act_subunit=`./ex_output${EXEEXT} CK_SUBUNIT STDOUT NORMAL | tr -d "\r"` +act_subunit_dump_env=`CK_VERBOSITY=subunit ./ex_output${EXEEXT} CK_SUBUNIT STDOUT_DUMP NORMAL | tr -d "\r"` +fi + +log_stdout=` ./ex_output${EXEEXT} CK_SILENT LOG_STDOUT NORMAL` +log_env_stdout=`CK_LOG_FILE_NAME="-" ./ex_output${EXEEXT} CK_SILENT STDOUT NORMAL` +tap_stdout=` ./ex_output${EXEEXT} CK_SILENT TAP_STDOUT NORMAL` +tap_env_stdout=`CK_TAP_LOG_FILE_NAME="-" ./ex_output${EXEEXT} CK_SILENT STDOUT NORMAL` +xml_stdout=` ./ex_output${EXEEXT} CK_SILENT XML_STDOUT NORMAL | tr -d "\r" | grep -v \ | grep -v \ | grep -v \` +xml_env_stdout=`CK_XML_LOG_FILE_NAME="-" ./ex_output${EXEEXT} CK_SILENT STDOUT NORMAL | tr -d "\r" | grep -v \ | grep -v \ | grep -v \` + +test_output ( ) { + if [ "x${1}" != "x${2}" ]; then + echo "Problem with ex_output${EXEEXT} ${3}"; + echo "Expected:"; + echo "${1}"; + echo "Got:"; + echo "${2}"; + exit 1; + fi + +} + +test_output "$exp_silent" "$act_silent" "CK_SILENT STDOUT NORMAL"; +test_output "$exp_silent" "$act_silent_env" "CK_ENV STDOUT NORMAL"; +test_output "$exp_minimal" "$act_minimal" "CK_MINIMAL STDOUT NORMAL"; +test_output "$exp_minimal" "$act_minimal_env" "CK_ENV STDOUT NORMAL"; +test_output "$exp_normal" "$act_normal" "CK_NORMAL STDOUT NORMAL"; +test_output "$exp_normal" "$act_normal_env" "CK_ENV STDOUT NORMAL"; +test_output "$exp_normal" "$act_normal_env_blank" "CK_ENV STDOUT NORMAL"; +test_output "$exp_normal" "$act_normal_env_invalid" "CK_ENV STDOUT NORMAL"; +test_output "$exp_verbose" "$act_verbose" "CK_VERBOSE STDOUT NORMAL"; +test_output "$exp_verbose" "$act_verbose_env" "CK_ENV STDOUT NORMAL"; + +test_output "$exp_silent_dump" "$act_silent_dump_env" "CK_ENV STDOUT_DUMP NORMAL (for silent)" +test_output "$exp_minimal_dump" "$act_minimal_dump_env" "CK_ENV STDOUT_DUMP NORMAL (for minimal)" +test_output "$exp_normal_dump" "$act_normal_dump_env" "CK_ENV STDOUT_DUMP NORMAL (for normal)" +test_output "$exp_verbose_dump" "$act_verbose_dump_env" "CK_ENV STDOUT_DUMP NORMAL (for verbose)" + +test_output "${expected_log_log}" "${log_stdout}" "CK_SILENT LOG_STDOUT NORMAL" +test_output "${expected_log_log}" "${log_env_stdout}" "CK_SILENT STDOUT NORMAL (with log env = '-')" +test_output "${expected_xml}" "${xml_stdout}" "CK_SILENT XML_STDOUT NORMAL" +test_output "${expected_xml}" "${xml_env_stdout}" "CK_SILENT STDOUT NORMAL (with xml env = '-')" +test_output "${expected_normal_tap}" "${tap_stdout}" "CK_SILENT TAP_STDOUT NORMAL" +test_output "${expected_normal_tap}" "${tap_env_stdout}" "CK_SILENT STDOUT NORMAL (with tap env = '-')" + +if test 1 -eq $ENABLE_SUBUNIT; then + test_output "$exp_subunit" "$act_subunit" "CK_SUBUNIT STDOUT NORMAL"; + test_output "$exp_subunit_dump" "$act_subunit_dump_env" "CK_ENV STDOUT_DUMP NORMAL (for subunit)" +fi + +exit 0 diff --git a/tests/test_output_strings b/tests/test_output_strings new file mode 100644 index 0000000..21751b6 --- /dev/null +++ b/tests/test_output_strings @@ -0,0 +1,336 @@ +#!/usr/bin/env sh + +. ./test_vars + +# Set the 'internal field separator' character to +# something besides whitespace so that the string +# comparisons will work +IFS="~" + +# octal quotes are specified by POSIX, should be thus portable +# (e.g. to Lubuntu builtin printf, Solaris 10 /usr/bin/printf) +tab_nl_X_bs="\11 \12X\10" + +################## +# stdout output +################## +suite_output=`printf "Running suite(s): S1 + S2 + XML escape \" ' < > & $tab_nl_X_bs tests"` + +exp_silent="" + +if [ $HAVE_FORK -eq 1 ]; then +exp_minimal_result="37%: Checks: 8, Failures: 4, Errors: 1" +else +exp_minimal_result="42%: Checks: 7, Failures: 4, Errors: 0" +fi +exp_minimal="$suite_output +$exp_minimal_result" + +if [ $HAVE_FORK -eq 1 ]; then +exp_normal_result=`printf "37%%: Checks: 8, Failures: 4, Errors: 1 +${SRCDIR}ex_output.c:37:F:Core:test_fail:0: Failure +${SRCDIR}ex_output.c:46:E:Core:test_exit:0: (after this point) Early exit with return value 1 +${SRCDIR}ex_output.c:72:F:Core:test_loop:0: Iteration 0 failed +${SRCDIR}ex_output.c:72:F:Core:test_loop:2: Iteration 2 failed +${SRCDIR}ex_output.c:78:F:description \" ' < > & $tab_nl_X_bs end:test_xml_esc_fail_msg:0: fail \" ' < > & $tab_nl_X_bs message"` +else +exp_normal_result=`printf "42%%: Checks: 7, Failures: 4, Errors: 0 +${SRCDIR}ex_output.c:37:F:Core:test_fail:0: Failure +${SRCDIR}ex_output.c:72:F:Core:test_loop:0: Iteration 0 failed +${SRCDIR}ex_output.c:72:F:Core:test_loop:2: Iteration 2 failed +${SRCDIR}ex_output.c:78:F:description \" ' < > & $tab_nl_X_bs end:test_xml_esc_fail_msg:0: fail \" ' < > & $tab_nl_X_bs message"` +fi +exp_normal="$suite_output +$exp_normal_result" + + +if [ $HAVE_FORK -eq 1 ]; then +exp_verbose_result=`printf "37%%: Checks: 8, Failures: 4, Errors: 1 +${SRCDIR}ex_output.c:31:P:Core:test_pass:0: Passed +${SRCDIR}ex_output.c:37:F:Core:test_fail:0: Failure +${SRCDIR}ex_output.c:46:E:Core:test_exit:0: (after this point) Early exit with return value 1 +${SRCDIR}ex_output.c:66:P:Core:test_pass2:0: Passed +${SRCDIR}ex_output.c:72:F:Core:test_loop:0: Iteration 0 failed +${SRCDIR}ex_output.c:72:P:Core:test_loop:1: Passed +${SRCDIR}ex_output.c:72:F:Core:test_loop:2: Iteration 2 failed +${SRCDIR}ex_output.c:78:F:description \" ' < > & $tab_nl_X_bs end:test_xml_esc_fail_msg:0: fail \" ' < > & $tab_nl_X_bs message"` +else +exp_verbose_result=`printf "42%%: Checks: 7, Failures: 4, Errors: 0 +${SRCDIR}ex_output.c:31:P:Core:test_pass:0: Passed +${SRCDIR}ex_output.c:37:F:Core:test_fail:0: Failure +${SRCDIR}ex_output.c:66:P:Core:test_pass2:0: Passed +${SRCDIR}ex_output.c:72:F:Core:test_loop:0: Iteration 0 failed +${SRCDIR}ex_output.c:72:P:Core:test_loop:1: Passed +${SRCDIR}ex_output.c:72:F:Core:test_loop:2: Iteration 2 failed +${SRCDIR}ex_output.c:78:F:description \" ' < > & $tab_nl_X_bs end:test_xml_esc_fail_msg:0: fail \" ' < > & $tab_nl_X_bs message"` +fi +exp_verbose="$suite_output +$exp_verbose_result" + +if [ $HAVE_FORK -eq 1 ]; then +exp_subunit=`printf "test: Core:test_pass +success: Core:test_pass +test: Core:test_fail +failure: Core:test_fail [ +${SRCDIR}ex_output.c:37: Failure +] +test: Core:test_exit +error: Core:test_exit [ +${SRCDIR}ex_output.c:46: (after this point) Early exit with return value 1 +] +test: Core:test_pass2 +success: Core:test_pass2 +test: Core:test_loop +failure: Core:test_loop [ +${SRCDIR}ex_output.c:72: Iteration 0 failed +] +test: Core:test_loop +success: Core:test_loop +test: Core:test_loop +failure: Core:test_loop [ +${SRCDIR}ex_output.c:72: Iteration 2 failed +] +test: description \" ' < > & $tab_nl_X_bs end:test_xml_esc_fail_msg +failure: description \" ' < > & $tab_nl_X_bs end:test_xml_esc_fail_msg [ +${SRCDIR}ex_output.c:78: fail \" ' < > & $tab_nl_X_bs message +]"` +else +exp_subunit=`printf "test: Core:test_pass +success: Core:test_pass +test: Core:test_fail +failure: Core:test_fail [ +${SRCDIR}ex_output.c:37: Failure +] +test: Core:test_pass2 +success: Core:test_pass2 +test: Core:test_loop +failure: Core:test_loop [ +${SRCDIR}ex_output.c:72: Iteration 0 failed +] +test: Core:test_loop +success: Core:test_loop +test: Core:test_loop +failure: Core:test_loop [ +${SRCDIR}ex_output.c:72: Iteration 2 failed +] +test: description \" ' < > & $tab_nl_X_bs end:test_xml_esc_fail_msg +failure: description \" ' < > & $tab_nl_X_bs end:test_xml_esc_fail_msg [ +${SRCDIR}ex_output.c:78: fail \" ' < > & $tab_nl_X_bs message +]"` +fi + +################## +# log output +################## +if [ $HAVE_FORK -eq 1 ]; then +expected_log_log=`printf "Running suite S1 +${SRCDIR}ex_output.c:31:P:Core:test_pass:0: Passed +${SRCDIR}ex_output.c:37:F:Core:test_fail:0: Failure +${SRCDIR}ex_output.c:46:E:Core:test_exit:0: (after this point) Early exit with return value 1 +Running suite S2 +${SRCDIR}ex_output.c:66:P:Core:test_pass2:0: Passed +${SRCDIR}ex_output.c:72:F:Core:test_loop:0: Iteration 0 failed +${SRCDIR}ex_output.c:72:P:Core:test_loop:1: Passed +${SRCDIR}ex_output.c:72:F:Core:test_loop:2: Iteration 2 failed +Running suite XML escape \" ' < > & $tab_nl_X_bs tests +${SRCDIR}ex_output.c:78:F:description \" ' < > & $tab_nl_X_bs end:test_xml_esc_fail_msg:0: fail \" ' < > & $tab_nl_X_bs message +Results for all suites run: +37%%: Checks: 8, Failures: 4, Errors: 1"` +else +expected_log_log=`printf "Running suite S1 +${SRCDIR}ex_output.c:31:P:Core:test_pass:0: Passed +${SRCDIR}ex_output.c:37:F:Core:test_fail:0: Failure +Running suite S2 +${SRCDIR}ex_output.c:66:P:Core:test_pass2:0: Passed +${SRCDIR}ex_output.c:72:F:Core:test_loop:0: Iteration 0 failed +${SRCDIR}ex_output.c:72:P:Core:test_loop:1: Passed +${SRCDIR}ex_output.c:72:F:Core:test_loop:2: Iteration 2 failed +Running suite XML escape \" ' < > & $tab_nl_X_bs tests +${SRCDIR}ex_output.c:78:F:description \" ' < > & $tab_nl_X_bs end:test_xml_esc_fail_msg:0: fail \" ' < > & $tab_nl_X_bs message +Results for all suites run: +42%%: Checks: 7, Failures: 4, Errors: 0"` +fi + +################## +# xml output +################## +if [ $HAVE_FORK -eq 1 ]; then +expected_xml=" + + + + S1 + + ex_output.c:31 + test_pass + 0 + Core + Passed + + + ex_output.c:37 + test_fail + 0 + Core + Failure + + + ex_output.c:46 + test_exit + 0 + Core + Early exit with return value 1 + + + + S2 + + ex_output.c:66 + test_pass2 + 0 + Core + Passed + + + ex_output.c:72 + test_loop + 0 + Core + Iteration 0 failed + + + ex_output.c:72 + test_loop + 1 + Core + Passed + + + ex_output.c:72 + test_loop + 2 + Core + Iteration 2 failed + + + + XML escape " ' < > & X tests + + ex_output.c:78 + test_xml_esc_fail_msg + 0 + description " ' < > & X end + fail " ' < > & X message + + +" +expected_duration_count=9 +else +expected_xml=" + + + + S1 + + ex_output.c:31 + test_pass + 0 + Core + Passed + + + ex_output.c:37 + test_fail + 0 + Core + Failure + + + + S2 + + ex_output.c:66 + test_pass2 + 0 + Core + Passed + + + ex_output.c:72 + test_loop + 0 + Core + Iteration 0 failed + + + ex_output.c:72 + test_loop + 1 + Core + Passed + + + ex_output.c:72 + test_loop + 2 + Core + Iteration 2 failed + + + + XML escape " ' < > & X tests + + ex_output.c:78 + test_xml_esc_fail_msg + 0 + description " ' < > & X end + fail " ' < > & X message + + +" +expected_duration_count=8 +fi + +################## +# tap output +################## +if [ $HAVE_FORK -eq 1 ]; then +expected_normal_tap=`printf "ok 1 - ${SRCDIR}ex_output.c:Core:test_pass: Passed +not ok 2 - ${SRCDIR}ex_output.c:Core:test_fail: Failure +not ok 3 - ${SRCDIR}ex_output.c:Core:test_exit: Early exit with return value 1 +ok 4 - ${SRCDIR}ex_output.c:Core:test_pass2: Passed +not ok 5 - ${SRCDIR}ex_output.c:Core:test_loop: Iteration 0 failed +ok 6 - ${SRCDIR}ex_output.c:Core:test_loop: Passed +not ok 7 - ${SRCDIR}ex_output.c:Core:test_loop: Iteration 2 failed +not ok 8 - ${SRCDIR}ex_output.c:description \" ' < > & $tab_nl_X_bs end:test_xml_esc_fail_msg: fail \" ' < > & $tab_nl_X_bs message +1..8"` +expected_aborted_tap=`printf "ok 1 - ${SRCDIR}ex_output.c:Core:test_pass: Passed +not ok 2 - ${SRCDIR}ex_output.c:Core:test_fail: Failure +not ok 3 - ${SRCDIR}ex_output.c:Core:test_exit: Early exit with return value 1 +not ok 4 - ${SRCDIR}ex_output.c:Core:test_abort: Early exit with return value 1 +ok 5 - ${SRCDIR}ex_output.c:Core:test_pass2: Passed +not ok 6 - ${SRCDIR}ex_output.c:Core:test_loop: Iteration 0 failed +ok 7 - ${SRCDIR}ex_output.c:Core:test_loop: Passed +not ok 8 - ${SRCDIR}ex_output.c:Core:test_loop: Iteration 2 failed +not ok 9 - ${SRCDIR}ex_output.c:description \" ' < > & $tab_nl_X_bs end:test_xml_esc_fail_msg: fail \" ' < > & $tab_nl_X_bs message +1..9"` +else +expected_normal_tap=`printf "ok 1 - ${SRCDIR}ex_output.c:Core:test_pass: Passed +not ok 2 - ${SRCDIR}ex_output.c:Core:test_fail: Failure +ok 3 - ${SRCDIR}ex_output.c:Core:test_pass2: Passed +not ok 4 - ${SRCDIR}ex_output.c:Core:test_loop: Iteration 0 failed +ok 5 - ${SRCDIR}ex_output.c:Core:test_loop: Passed +not ok 6 - ${SRCDIR}ex_output.c:Core:test_loop: Iteration 2 failed +not ok 7 - ${SRCDIR}ex_output.c:description \" ' < > & $tab_nl_X_bs end:test_xml_esc_fail_msg: fail \" ' < > & $tab_nl_X_bs message +1..7"` +# When fork() is unavailable, one of the tests +# will invoke exit() which will terminate the +# unit testing program. In that case, the tap +# results will be incomplete, but the required +# test plan will be missing, signaling that +# something bad happened. +expected_aborted_tap="ok 1 - ${SRCDIR}ex_output.c:Core:test_pass: Passed +not ok 2 - ${SRCDIR}ex_output.c:Core:test_fail: Failure" +fi diff --git a/tests/test_set_max_msg_size.sh b/tests/test_set_max_msg_size.sh new file mode 100755 index 0000000..84a1ef6 --- /dev/null +++ b/tests/test_set_max_msg_size.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env sh + +UNIT_TEST=./check_set_max_msg_size +MAX_MESSAGE_LOG_FILE=${UNIT_TEST}.output +TOO_LONG_MESSAGE="Message string too long" + +# This test reduces the maximal message size using the provided function, +# so that the assertion message becomes too long. +# We set the maximal size to 32, which is shorter than the message. + +rm -f ${MAX_MESSAGE_LOG_FILE} +${UNIT_TEST} 32 2>&1 | tee ${MAX_MESSAGE_LOG_FILE} + +NUM_TOO_LONG_MESSAGES=$(grep "${TOO_LONG_MESSAGE}" ${MAX_MESSAGE_LOG_FILE} | wc -l) + +if test ${NUM_TOO_LONG_MESSAGES} -gt 0; then + echo "Maximal message size was reduced by function call." + rm -f ${MAX_MESSAGE_LOG_FILE} +else + echo "ERROR: Maximal message size was not reduced by function call." + echo "Test output was preserved in ${MAX_MESSAGE_LOG_FILE}" + exit 1 +fi + +rm -f ${MAX_MESSAGE_LOG_FILE} +export CK_MAX_MSG_SIZE=32 +${UNIT_TEST} 4096 2>&1 | tee ${MAX_MESSAGE_LOG_FILE} + +NUM_TOO_LONG_MESSAGES=$(grep "${TOO_LONG_MESSAGE}" ${MAX_MESSAGE_LOG_FILE} | wc -l) + +if test ${NUM_TOO_LONG_MESSAGES} -gt 0; then + echo "Maximal message size was reduced by environment variable." +else + echo "ERROR: Maximal message size was not reduced by environment variable." + echo "Test output was preserved in ${MAX_MESSAGE_LOG_FILE}" + exit 1 +fi + +rm -f ${MAX_MESSAGE_LOG_FILE} +exit 0 diff --git a/tests/test_tap_output.sh b/tests/test_tap_output.sh new file mode 100755 index 0000000..b74b806 --- /dev/null +++ b/tests/test_tap_output.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env sh + +OUTPUT_FILE=test.tap + +. ./test_vars +. $(dirname $0)/test_output_strings + +test_tap_output ( ) { + rm -f ${OUTPUT_FILE} + ./ex_output${EXEEXT} "CK_SILENT" "TAP" "${1}" > /dev/null + actual_tap=`cat ${OUTPUT_FILE} | tr -d "\r"` + expected_tap="${2}" + if [ x"${expected_tap}" != x"${actual_tap}" ]; then + echo "Problem with ex_tap_output${EXEEXT}"; + echo "Expected:"; + echo "${expected_tap}"; + echo + echo "Got:"; + echo "${actual_tap}"; + exit 1; + fi +} + +test_tap_output "NORMAL" "${expected_normal_tap}" +test_tap_output "EXIT_TEST" "${expected_aborted_tap}" + +exit 0 diff --git a/tests/test_vars.in b/tests/test_vars.in new file mode 100644 index 0000000..a0b750b --- /dev/null +++ b/tests/test_vars.in @@ -0,0 +1,20 @@ +# defined to 1 if subunit is enabled +ENABLE_SUBUNIT=@ENABLE_SUBUNIT@ +export ENABLE_SUBUNIT +EXEEXT=@EXEEXT@ +export EXEEXT +HAVE_FORK=@HAVE_FORK@ +export HAVE_FORK + +# path of the tests directory +if [ x"@srcdir@" != x"." ]; then + if [ -z "@IS_MSVC@" -o "@IS_MSVC@" != "1" ]; then + SRCDIR="@srcdir@/" + else + SRCDIR="@srcdir@\\" + fi +else + SRCDIR="" +fi + +export SRCDIR diff --git a/tests/test_xml_output.sh b/tests/test_xml_output.sh new file mode 100755 index 0000000..eef550c --- /dev/null +++ b/tests/test_xml_output.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env sh + +OUTPUT_FILE=test.xml +CK_DEFAULT_TIMEOUT=4 + +. ./test_vars +. $(dirname $0)/test_output_strings + +rm -f ${OUTPUT_FILE} +export CK_DEFAULT_TIMEOUT +./ex_output${EXEEXT} CK_MINIMAL XML NORMAL > /dev/null +actual_xml=`cat ${OUTPUT_FILE} | tr -d "\r" | grep -v \ | grep -v \ | grep -v \` +if [ x"${expected_xml}" != x"${actual_xml}" ]; then + echo "Problem with ex_xml_output${EXEEXT}"; + echo "Expected:"; + echo "${expected_xml}"; + echo "Got:"; + echo "${actual_xml}"; + exit 1; +fi + +actual_duration_count=`grep -c \ ${OUTPUT_FILE}` +if [ x"${expected_duration_count}" != x"${actual_duration_count}" ]; then + echo "Wrong number of elements in ${OUTPUT_FILE}, ${expected_duration_count} vs ${actual_duration_count}"; + exit 1; +fi + +num_durations=`grep "\" ${OUTPUT_FILE} | wc -l` + +i=1 +while [ ${i} -le ${num_durations} ]; do + duration=`grep "\" ${OUTPUT_FILE} | head -n ${i} | tail -n 1 | cut -d ">" -f 2 | cut -d "<" -f 1` + int_duration=`echo $duration | cut -d "." -f 1` + if [ "${int_duration}" -ne "-1" ] && [ "${int_duration}" -gt "${CK_DEFAULT_TIMEOUT}" ]; then + echo "Problem with duration ${duration}; is not valid. Should be -1 or in [0, ${CK_DEFAULT_TIMEOUT}]" + exit 1 + fi + + i=$((i+1)) +done + +if [ ! -z `which xmllint` ]; then + xmllint_output=`xmllint ${OUTPUT_FILE}` + if [ $? -ne 0 ]; then + echo "xmllint found an issue" + echo ${xmllint_output} + exit 1 + fi +fi + +exit 0 diff --git a/web/License.txt b/web/License.txt new file mode 100644 index 0000000..c92228f --- /dev/null +++ b/web/License.txt @@ -0,0 +1,3 @@ +Copyright: Darren Hester 2006, http://www.designsbydarren.com +License: Released Under the "Creative Commons License" +http://creativecommons.org/licenses/by-nc/2.5/ diff --git a/web/css/style.css b/web/css/style.css new file mode 100644 index 0000000..2ccfb85 --- /dev/null +++ b/web/css/style.css @@ -0,0 +1,256 @@ +body { + text-align: center; + margin-top:10px; + margin-bottom:10px; + color:#666666; + background-color: #E0E0E0; +} + +A:link { + COLOR: #0000FF; text-decoration: none; +} +A:visited { + COLOR: #0000FF; text-decoration: none; +} +A:active { + COLOR: #0000FF; text-decoration: none; +} +A:hover { + COLOR: #FF0000; text-decoration: underline; +} + +#page_wrapper { + margin-left: auto; + margin-right: auto; + width: 98%; + text-align: left; + background: #FFFFFF; + border: 8px solid #FFFFFF; +} + +#header_wrapper { + background: #4E7DD1 url('../img/menu_bg.gif') bottom left repeat-x; + margin:0px; padding:0px; +} + +#header { + height: 60px; + padding:15px; + margin:0px; +} + +#header h1 { + margin:0px; + font-family: verdana, arial, sans-serif; + font-size: 28px; + color:#ffffff; + letter-spacing: -1px; +} + +#header h2 { + margin:0px; + font-family: verdana, arial, sans-serif; + font-size: 14px; + color:#B1C6EB; + letter-spacing: 1px; +} + +#left_side { + margin-top: 10px; + float: left; + width: 160px; + background: #F1F6FE url('../img/side_bg.gif') bottom left repeat-x; +} + +#right_side { + margin-top: 10px; + float: right; + width: 250px; + background: #F1F6FE url('../img/side_bg.gif') bottom left repeat-x; +} + +#content { + margin-top: 20px; + margin-bottom: 0px; + margin-left: 180px; + margin-right: 180px; +} + +#footer { + height: 50px; + background-color: #4E7DD1; + clear: both; + text-align: center; + padding-top:12px; + color: #B6CEF9; + font-family: verdana, arial, sans-serif; + font-size: 11px; + line-height: 18px; +} + +#footer A:link { + COLOR: #FFFFFF; text-decoration: none; +} +#footer A:visited { + COLOR: #FFFFFF; text-decoration: none; +} +#footer A:active { + COLOR: #FFFFFF; text-decoration: none; +} +#footer A:hover { + COLOR: #FFFFFF; text-decoration: underline; +} + +#left_side p, #right_side p { + margin:10px;margin-top:15px;margin-bottom:15px; + font-family: verdana, arial, sans-serif; + font-size: 11px; + line-height: 16px; + color: #333333; +} + +#left_side li, #right_side li { + font-family: verdana, arial, sans-serif; + font-size: 11px; + line-height: 16px; + color: #333333; +} + +#left_side h3, #right_side h3 { + margin-top:5px; margin-bottom:10px; margin-left:5px; margin-right:5px; + padding:4px; + font-family: verdana, arial, sans-serif; + font-size: 14px; + font-weight: bold; + line-height: 14px; + color: #FFFFFF; + border:1px solid #0F3974; + background-color: #2153AA; +} + +#left_side h4, #right_side h4 { + margin-top:0px;margin-bottom:0px;margin-left:10px; + font-family: verdana, arial, sans-serif; + font-size: 12px; + font-weight: bold; + line-height: 12px; + color: #2153AA; +} + +#content p { + margin-top:15px; margin-bottom: 15px; + font-family: verdana, arial, sans-serif; + font-size: 12px; + line-height: 18px; + color: #333333; +} + +#content h3 { + margin-top:5px; margin-bottom: 10px; + font-family: verdana, arial, sans-serif; + font-size: 18px; + font-weight: bold; + line-height: 18px; + color: #2153AA; +} + +#content h4 { + margin-top:0px;margin-bottom:0px; + font-family: verdana, arial, sans-serif; + font-size: 14px; + font-weight: bold; + line-height: 12px; + color: #2153AA; +} + +#content ul { + font-family: verdana, arial, sans-serif; + font-size: 12px; + line-height: 18px; + color: #333333; +} + +#navlist +{ + margin-top:1px; + margin-bottom:0px; + text-align:center; + padding: 5px 0; + margin-left: 0; + border-bottom: 1px solid #0F3974; + font: bold 14px Verdana, sans-serif; +} + +#navlist li +{ + list-style: none; + margin: 0; + display: inline; +} + +#navlist li a +{ + color: #F1F6FE; + padding: 5px 15px; + margin-left: 3px; + border: 1px solid #0F3974; + border-bottom: none; + background: #2153AA url('../img/tab_bg.gif') bottom left repeat-x; + text-decoration: none; +} + +#navlist li a:link { color: #F1F6FE; } +#navlist li a:visited { color: #F1F6FE; } + +#navlist li a:hover +{ + color: #FFFFFF; + background: #3364BB; + border-color: #0F3974; +} + +#navlist li a#current +{ + color: #000; + background: #FFFFFF; + border-bottom: 1px solid #FFFFFF; +} + +.float_left { + float: left; + margin-right: 10px; +} + +.float_right { + float: right; + margin-left: 10px; +} + +.featurebox_center { + background-color: #fffff6; + margin:0px; + padding:10px; + border: 1px solid #DFE8F7; + font-family: verdana, arial, sans-serif; + font-size: 11px; + line-height: 18px; + color: #333333; +} + +.featurebox_side { + background-color: #fffff6; + margin:0px;margin-left:10px;margin-right:10px;margin-bottom:15px; + padding:10px; + border: 1px solid #DFE8F7; + font-family: verdana, arial, sans-serif; + font-size: 11px; + line-height: 18px; + color: #333333; +} + +#code { + border: 1px solid #000000; + padding-left:10px; + color: #FFFFFF; + background-color: #000000; +} diff --git a/web/img/Button-Built-on-CB-1.png b/web/img/Button-Built-on-CB-1.png new file mode 100644 index 0000000..b9d0c94 Binary files /dev/null and b/web/img/Button-Built-on-CB-1.png differ diff --git a/web/img/header_bg.gif b/web/img/header_bg.gif new file mode 100644 index 0000000..6a64e8b Binary files /dev/null and b/web/img/header_bg.gif differ diff --git a/web/img/menu_bg.gif b/web/img/menu_bg.gif new file mode 100644 index 0000000..bf0e78a Binary files /dev/null and b/web/img/menu_bg.gif differ diff --git a/web/img/side_bg.gif b/web/img/side_bg.gif new file mode 100644 index 0000000..69676e9 Binary files /dev/null and b/web/img/side_bg.gif differ diff --git a/web/img/tab_bg.gif b/web/img/tab_bg.gif new file mode 100644 index 0000000..457d496 Binary files /dev/null and b/web/img/tab_bg.gif differ diff --git a/web/install.html b/web/install.html new file mode 100644 index 0000000..5cc029b --- /dev/null +++ b/web/install.html @@ -0,0 +1,499 @@ + + + + + + + + + + + + + +Check | Users of Check + + + + + + + + +
+ +
+ + + + + +
+ + +
+ +

Installing Check

+ +

+The following instructions show how one can either install Check from +a package manager or compile from source on one's platform. +

+ + + +
+ + +

Ubuntu/Debian via Aptitude

+

+Ubuntu and Debian both provide a Check package that can be installed. +To install, in a terminal, type: + +

+$ sudo apt-get install check
+
+

+

+ + + +

Fedora via Yum

+

+Fedora provides a Check package that can be installed. To install, +in a terminal, type: + +

+$ sudo yum install check
+
+

+

+ + + +

Arch Linux via Pacman

+

+Arch Linux provides a Check package that can be installed. To install, +in a terminal, type: + +

+$ sudo pacman -S check
+
+

+ + + +

GNU/Linux From Source

+

+Check uses autotools as a build system, and the default steps +work on GNU/Linux systems. After the +latest Check source +has been downloaded and unpacked, open a terminal in the unpacked +directory, then: +

+
+$ ./configure
+$ make
+$ make check
+$ sudo make install
+
+

+If the "make check" step fails, please send an email to Check's +mailing list +and give details as to the failure so it may be investigated and fixed. +

+

+ + + +

Debian GNU/Hurd From Source

+

+Debian GNU/Hurd does not yet provide a package for Check, so it must +be compiled from source. Check uses autotools as a build system, and the +default steps work on Debian GNU/Hurd systems. After the +latest Check source +has been downloaded and unpacked, open a terminal in the unpacked +directory, then: +

+
+$ ./configure
+$ make
+$ make check
+$ sudo make install
+
+

+If the "make check" step fails, please send an email to Check's +mailing list +and give details as to the failure so it may be investigated and fixed. +

+

+ + + +

OSX via MacPorts

+

+MacPorts provides a Check package that can be installed. First, +install MacPorts +if not done already. Then, in a terminal, type: + +

+$ sudo port install check
+
+

+

+ + + +

OSX via Homebrew

+

+Homebrew provides a Check package that can be installed. First, +install Homebrew +if not done already. Then, in a terminal, type: + +

+$ brew install check
+
+

+

+ + + +

OSX From Source

+

+Check uses autotools as a build system, and the default steps +work on OSX systems. You must have Xcode installed. After the +latest Check source +has been downloaded and unpacked, open a terminal in the unpacked +directory, then: +

+
+$ ./configure
+$ make
+$ make check
+$ sudo make install
+
+

+If the "make check" step fails, please send an email to Check's +mailing list +and give details as to the failure so it may be investigated and fixed. +

+

+ + + +

OpenBSD via Packages

+

+OpenBSD provides a Check package that can be installed. To install, +in a terminal, type: + +

+$ sudo pkg_add check
+
+

+

+ + + +

BSD From Source

+

+Check uses autotools as a build system, and the default steps +work when building on the BSD system. Special care is required when +cross compiling, which is described below. +

+After the latest Check source +has been downloaded and unpacked, open a terminal in the unpacked +directory. To compile on the BSD system directly, type: +

+
+$ ./configure
+$ make
+$ make check
+$ sudo make install
+
+

+If the "make check" step fails, please send an email to Check's +mailing list +and give details as to the failure so it may be investigated and fixed. +

+

+Cross compiling for BSD may require an additional configure argument: +--enable-timer-replacement . +Check attempts to use high resolution timers via the timer_create(), +timer_settime(), and timer_delete() functions. For some BSD systems +(e.g. OpenBSD), these functions exist but are non-functional stubs. +If the functions are available, when compiling on the target system the +configure script will verify that the calls are not stubs. If they are +valid, Check will use them. When cross compiling, the validity check +cannot be performed. To prevent Check from using these when cross +compiling for affected BSD systems, add the --enable-timer-replacement +configure option. +

+

+ + + +

Cygwin on Windows via Package Manager

+

+Cygwin provides a Check package that can be installed. To install, +launch the Cygwin setup program, locate the Check package under +the Devel folder, then install. +

+

+ + + +

Cygwin on Windows From Source

+

+Check uses autotools as a build system, and the default steps +work on Cygwin. You must have gcc, and make installed. After the +latest Check source +has been downloaded and unpacked, open a Cygwin terminal in the unpacked +directory, then: +

+
+$ ./configure
+$ make
+$ make check
+$ sudo make install
+
+

+If the "make check" step fails, please send an email to Check's +mailing list +and give details as to the failure so it may be investigated and fixed. +

+

+ + + +

MinGW/MinGW-w64 on Windows From Source

+

+MinGW and MinGW-w64 do not provide a package for Check, so it must be +compiled from source. Check uses autotools as a build system, and the +default steps work on both MinGW and MinGW-w64. Note that because both +MinGW and MinGW-w64 do not provide a fork() alternative, Check's fork +mode will be disabled. After the +latest Check source +has been downloaded and unpacked, open a MSYS terminal in the unpacked +directory, then: +

+
+$ ./configure
+$ make
+$ make check
+$ make install
+
+

+If the "make check" step fails, please send an email to Check's +mailing list +and give details as to the failure so it may be investigated and fixed. +

+

+ + + +

Visual Studios on Windows From Source

+

+Check must be compiled from source for Windows. Note that no fork() +call is available, and Check's fork mode will be disabled. The CMake build system +is supported for compiling Check with Visual Studios, so download +CMake first. +

+

+After the +latest Check source +has been downloaded and unpacked, open the CMake GUI program. Fill in the +"Where is the source code" and "Where to build the binaries" fields to +point to the unpacked location of the Check source, and press the +Configure button. Select the version of Visual Studios to use, and click +"OK". Once the configuration completes, CMake will highlight two settings, +CMAKE_CONFIGURATION_TYPES and CMAKE_INSTALL_PREFIX. You may leave them as +their defaults or modify them. Finally, click "Generate" to create the +Visual Studio project files. +

+

+Open Visual Studios and load the generated project files. The following +is a summary of the important build targets: +

    +
  • ALL_BUILD: Build Check and all unit tests
  • +
  • RUN_TESTS: Execute Check's unit tests
  • +
  • INSTALL: Install Check to the CMAKE_INSTALL_PREFIX location + listed from the CMake GUI
  • +
+

+

+To compile, validate, and install Check, run these three targets from +Visual Studios. Note that the RUN_TESTS target only runs Check's unit +tests which do not require a shell interpreter. The remaining tests must +be run in a MSYS or comparable environment. +

+

+If any of the build targets fail, including the RUN_TESTS target, +please send an email to Check's +mailing list +and give details as to the failure so it may be investigated and fixed. +

+

+ + + + +

MSVC on Windows From Source

+

+Check must be compiled from source for Windows. Note that no fork() +call is available, and Check's fork mode will be disabled. The CMake build system +is supported for compiling Check with Visual Studios, so download +CMake first. +

+

+After the +latest Check source +has been downloaded and unpacked, open a terminal (cmd.exe). If MSVC +is not in the path, execute the bat file in the MSVC install directory +to load it into the path. For example, with Visual Studios 10: +

+
+> C:\Program Files\Microsoft Visual Studios 10.0\VC\vcvarsall.bat
+
+

+Navigate to the unpacked location of the Check source, then: +

+
+> cmake -G "NMake Makefiles" .
+> nmake
+> nmake test
+> nmake install
+
+

+Note that the "nmake test" step only runs Check's unit tests which +do not require a shell interpreter. The remaining tests must be +run in a MSYS or comparable environment. +

+

+If the "make test" step fails, please send an email to Check's +mailing list +and give details as to the failure so it may be investigated and fixed. +

+

+ + + + +

Solaris From Source

+

+Check uses autotools as a build system. The PATH must be setup such that +POSIX versions of tools are found before legacy once. +(see also standards(5) for more details). If the compiler is GCC, setup +the PATH as follows: +

+
+PATH=/usr/xpg6/bin:/usr/xpg4/bin:/usr/ccs/bin:/usr/bin:/sbin:/usr/sbin:/opt/csw/bin
+
+

+Otherwise, for Solaris Studio use the following PATH: +

+
+PATH=/opt/solarisstudio12.3/bin:/usr/xpg6/bin:/usr/xpg4/bin:/usr/ccs/bin:/usr/bin:/sbin:/usr/sbin:/opt/csw/bin
+
+

+Further, ensure that the environment variables LD_LIBRARY_PATH and +LD_LIBRARY_PATH_64 are unset. It is recommended to use OpenCSW packages +(/opt/csw/bin) to get recent versions of required programs. +The configure script will likely find gcc by default; to use Solaris +Studio also set the following environment variable: +

+
+CC=cc
+
+

+After the +latest Check source +has been downloaded and unpacked, open a terminal in the unpacked +directory, then: +

+
+$ ./configure CFLAGS=-m64 LDFLAGS=-m64
+$ gmake
+$ gmake check
+$ gmake install
+
+

+If the "gmake check" step fails, please send an email to Check's +mailing list +and give details as to the failure so it may be investigated and fixed. +

+

+ + + + + +
+ + + +
+ + + + diff --git a/web/users-of-check.html b/web/users-of-check.html new file mode 100644 index 0000000..5e6a846 --- /dev/null +++ b/web/users-of-check.html @@ -0,0 +1,106 @@ + + + + + + + + + + + + + +Check | Users of Check + + + + + + + + +
+ +
+ + + + + +
+ + +
+ +

Projects Using Check

+ + +

+If you're using Check for an open source project and you're not listed +here, please send am email to our mailing list +check-users@sourceforge.net, +and we'll list you promptly. +

+
+ + + +
+ + + + diff --git a/xml/check_unittest.xslt b/xml/check_unittest.xslt new file mode 100644 index 0000000..b8005fe --- /dev/null +++ b/xml/check_unittest.xslt @@ -0,0 +1,93 @@ + + + + + + + + Test results +

+ + + +

Unittests

+ +
+ + + + + + + + Test suite + + + Path + Filename + Test ID + Iteration + Duration + Description + Message + + + + + Test ran at: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + Test duration: seconds + + +
+