Permalink
Browse files

asserts: Implemented new composable assertion API.

This proposal implements assertions as composable sub-functions
for the `cr_assert` and `cr_expect` macros.

For instance, instead of having `cr_assert_eq(1, 2)`, the user can either
use `cr_assert(eq(1, 2))` or `cr_assert(eq(i32, 1, 2))`. This has the
advantage of simplifying the implementation of the assert macro, but
also brings to the table an improved correctness by letting the user enforce
the type of operands with a type tag, and the possibility to
pretty-print and natively compare user types without c11 or compiler-specific
constructs like _Generic or __builtin_types_compatible_p.

This also lets us handle properly special comparison cases like
ulp-based equality for IEEE floats.

Fixes #165, #182.
  • Loading branch information...
Snaipe committed Jul 1, 2017
1 parent 710d930 commit d258a8b67c9c26ad21d8990b028e128d154ce78f
Showing with 5,523 additions and 739 deletions.
  1. +14 −5 .cmake/Modules/Capabilities.cmake
  2. +33 −0 .cmake/Modules/FindLibgit2.cmake
  3. +13 −13 .cmake/Modules/Submodules.cmake
  4. +3 −3 .githooks/pre-commit
  5. +52 −12 CMakeLists.txt
  6. +1 −0 appveyor.yml
  7. +1 −1 dependencies/nanopb
  8. +1 −1 doc/Doxyfile
  9. +29 −0 doc/_static/style.css
  10. +10 −32 doc/assert.rst
  11. +8 −6 doc/conf.py
  12. +7 −0 include/criterion/internal/asprintf-compat.h
  13. +93 −0 include/criterion/internal/assert/complex.h
  14. +101 −0 include/criterion/internal/assert/exceptions.h
  15. +146 −0 include/criterion/internal/assert/ieee.h
  16. +56 −0 include/criterion/internal/assert/memory.h
  17. +428 −0 include/criterion/internal/assert/op.h
  18. +67 −0 include/criterion/internal/assert/op.hxx
  19. +349 −0 include/criterion/internal/assert/tag.h
  20. +279 −0 include/criterion/internal/assert/tostr.h
  21. +65 −0 include/criterion/internal/assert/types.h
  22. +84 −0 include/criterion/internal/capabilities.h
  23. +26 −3 include/criterion/internal/deprecation.h
  24. +64 −64 include/criterion/internal/designated-initializer-compat.h
  25. +193 −0 include/criterion/internal/new_asserts.h
  26. +40 −3 include/criterion/internal/preprocess.h
  27. +21 −0 include/criterion/logging.h
  28. +441 −0 include/criterion/new/assert.h
  29. +64 −0 include/criterion/new/memory.h
  30. +44 −20 po/de.po
  31. +45 −21 po/fr.po
  32. +5 −2 samples/CMakeLists.txt
  33. +57 −42 samples/asserts.c
  34. +55 −62 samples/asserts.cc
  35. +122 −46 samples/tests/failmessages.c
  36. +127 −54 samples/tests/failmessages.cc
  37. 0 samples/tests/flood.c
  38. +9 −2 src/CMakeLists.txt
  39. +96 −0 src/capi/specifiers.c
  40. +3 −1 src/common.h
  41. +106 −0 src/compat/basename.c
  42. +6 −0 src/compat/basename.h
  43. +64 −0 src/compat/strtok.c
  44. +6 −2 src/compat/strtok.h
  45. +5 −2 src/config.h.in
  46. +241 −0 src/core/assert.c
  47. +51 −0 src/core/client.c
  48. +1 −1 src/core/theories.c
  49. +1 −1 src/io/xml.c
  50. +1 −1 src/log/logging.c
  51. +205 −24 src/log/normal.c
  52. +10 −0 src/mutex.h
  53. +19 −10 src/protocol/criterion.options
  54. +38 −11 src/protocol/criterion.pb.c
  55. +87 −6 src/protocol/criterion.pb.h
  56. +26 −0 src/protocol/criterion.proto
  57. +1 −1 src/protocol/messages.c
  58. +72 −0 src/string/diff.c
  59. +39 −0 src/string/diff.h
  60. +61 −27 src/{io/asprintf.c → string/fmt.c}
  61. +35 −0 src/string/fmt.h
  62. +76 −0 src/string/xxd.c
  63. +7 −6 src/{io/asprintf.h → string/xxd.h}
  64. +824 −101 test/cram/asserts.t
  65. +35 −11 test/cram/core.t
  66. +10 −4 test/cram/fail-fast.t
  67. +0 −1 test/cram/help.t
  68. +10 −10 test/cram/json.t
  69. +180 −72 test/cram/parameterized.t
  70. +34 −37 test/cram/pattern.t
  71. +4 −6 test/cram/tap.t
  72. +8 −2 test/cram/theories.t
  73. +8 −10 test/cram/xml.t
@@ -29,16 +29,25 @@ if (I18N AND GETTEXT_FOUND AND LIBINTL_LIB_FOUND)
set (ENABLE_NLS 1)
endif ()

list (APPEND CMAKE_REQUIRED_DEFINITIONS
-D_GNU_SOURCE
-D_CRT_RAND_S
-DVC_EXTRALEAN
-DWIN32_LEAN_AND_MEAN)

# Check for functions

check_function_exists(strtok_s HAVE_STRTOK_S)
check_function_exists(strtok_r HAVE_STRTOK_R)
check_symbol_exists(strtok_s "string.h" HAVE_STRTOK_S)
check_symbol_exists(strtok_r "string.h" HAVE_STRTOK_R)

check_library_exists (anl getaddrinfo_a "" HAVE_GETADDRINFO_A)

check_function_exists(funopen HAVE_FUNOPEN)
check_function_exists(fopencookie HAVE_FOPENCOOKIE)
check_function_exists(open_memstream HAVE_OPEN_MEMSTREAM)
check_symbol_exists(funopen "stdio.h" HAVE_FUNOPEN)
check_symbol_exists(fopencookie "stdio.h" HAVE_FOPENCOOKIE)
check_symbol_exists(open_memstream "stdio.h" HAVE_OPEN_MEMSTREAM)

check_symbol_exists(getcwd "unistd.h" HAVE_GETCWD)
check_symbol_exists(GetCurrentDirectory "windows.h" HAVE_GETCURRENTDIRECTORY)

check_library_exists(rt clock_gettime "time.h" HAVE_CLOCK_GETTIME_RT)
if (HAVE_CLOCK_GETTIME_RT AND NOT HAVE_LIBRT)
@@ -0,0 +1,33 @@
# - Try to find the libgit2 library
# Once done this will define
#
# LIBGIT2_FOUND - System has libgit2
# LIBGIT2_INCLUDE_DIR - The libgit2 include directory
# LIBGIT2_LIBRARIES - The libraries needed to use libgit2
# LIBGIT2_DEFINITIONS - Compiler switches required for using libgit2


# use pkg-config to get the directories and then use these values
# in the FIND_PATH() and FIND_LIBRARY() calls
#FIND_PACKAGE(PkgConfig)
#PKG_SEARCH_MODULE(PC_LIBGIT2 libgit2)

SET(LIBGIT2_DEFINITIONS ${PC_LIBGIT2_CFLAGS_OTHER})

FIND_PATH(LIBGIT2_INCLUDE_DIR NAMES git2.h
HINTS
${PC_LIBGIT2_INCLUDEDIR}
${PC_LIBGIT2_INCLUDE_DIRS}
)

FIND_LIBRARY(LIBGIT2_LIBRARIES NAMES git2
HINTS
${PC_LIBGIT2_LIBDIR}
${PC_LIBGIT2_LIBRARY_DIRS}
)


INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(libgit2 DEFAULT_MSG LIBGIT2_LIBRARIES LIBGIT2_INCLUDE_DIR)

MARK_AS_ADVANCED(LIBGIT2_INCLUDE_DIR LIBGIT2_LIBRARIES)
@@ -12,18 +12,18 @@ set(GIT_SUBMODULES libcsptr dyncall)
### (leave empty if you want master)

### First, get all submodules in
if(${GIT_SUBMODULES_CHECKOUT_QUIET})
execute_process(
COMMAND git submodule update --init --recursive
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
OUTPUT_QUIET
ERROR_QUIET
)
else()
execute_process(
COMMAND git submodule update --init --recursive
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
)
endif()
#if(${GIT_SUBMODULES_CHECKOUT_QUIET})
# execute_process(
# COMMAND git submodule update --init --recursive
# WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
# OUTPUT_QUIET
# ERROR_QUIET
# )
#else()
# execute_process(
# COMMAND git submodule update --init --recursive
# WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
# )
#endif()

endif()
@@ -44,8 +44,6 @@ PARSE_EXTS=true
# FILE_EXTS=".c .h .cpp .hpp"
FILE_EXTS=".c .h .cc .hh .cpp .hpp .hxx"

EXCLUDE_PATTERN="src/protocol/*.pb.*"

##################################################################
# There should be no need to change anything below this line.

@@ -109,7 +107,9 @@ do
fi

case "$file" in
$EXCLUDE_PATTERN) continue;
src/protocol/*.pb.*) continue;;
include/*) continue;;
samples/*) continue;;
esac

# escape special characters in the source filename:
@@ -22,19 +22,34 @@ include (Submodules)
include (Capabilities)
include (Subprojects)
include (PackageUtils)
include (CheckCCompilerFlag)

if (NOT WIN32)
check_c_compiler_flag("-fPIC" CC_HAVE_FPIC)
check_c_compiler_flag("-fvisibility=hidden" CC_HAVE_VISIBILITY)

# Linker flags are ignored by check_c_compiler_flag, so we have
# to use this workaround
set (CMAKE_REQUIRED_FLAGS "-Wl,--exclude-libs=ALL")
check_c_compiler_flag("" LINKER_HAS_EXCLUDE_LIBS)
unset (CMAKE_REQUIRED_FLAGS)

if (LINKER_HAS_EXCLUDE_LIBS)
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,--exclude-libs=ALL")
endif ()

if (CC_HAVE_FPIC)
set (PIC_C_FLAGS "-fPIC")
endif ()

if (CC_HAVE_VISIBILITY)
set (VISI_C_FLAGS "-fvisibility=hidden")
else ()
set (PIC_C_FLAGS "")
set (VISI_C_FLAGS "")
endif ()

find_package(Libcsptr)
find_package(Dyncall)
find_package(Nanomsg)
find_package(BoxFort)
find_package(Libgit2)

cr_add_subproject (csptr
GIT "https://github.com/Snaipe/libcsptr#0d52904"
@@ -82,6 +97,26 @@ cr_add_subproject (boxfort PATH dependencies/boxfort
CMAKE
IF NOT BOXFORT_FOUND)

cr_add_subproject (git2
GIT "git://github.com/libgit2/libgit2#v0.25.1"
OPTS
-DBUILD_SHARED_LIBS=OFF
-DBUILD_CLAR=OFF
-DUSE_ICONV=OFF
-DUSE_SSH=OFF
-DUSE_GSSAPI=OFF
-DUSE_OPENSSL=OFF
-DVALGRIND=OFF
-DCURL=OFF
-DWINHTTP=OFF
-DCMAKE_DISABLE_FIND_PACKAGE_HTTP_Parser=TRUE
-DCMAKE_DISABLE_FIND_PACKAGE_ZLIB=TRUE
-DCMAKE_DISABLE_FIND_PACKAGE_Iconv=TRUE
-DCMAKE_DISABLE_FIND_PACKAGE_Security=TRUE
"-DCMAKE_C_FLAGS=${PIC_C_FLAGS} ${VISI_C_FLAGS}"
CMAKE
IF NOT LIBGIT2_FOUND)

add_definitions(-DBXF_STATIC_LIB -DNN_STATIC_LIB)

cr_add_subproject (wingetopt
@@ -137,23 +172,28 @@ cr_link_subproject(criterion csptr STATIC IF NOT CSPTR_FOUND)
cr_link_subproject(criterion nanomsg STATIC IF NOT NANOMSG_FOUND)
cr_link_subproject(criterion dyncall_s STATIC IF NOT DYNCALL_FOUND)
cr_link_subproject(criterion boxfort STATIC IF NOT BOXFORT_FOUND)
cr_link_subproject(criterion git2 STATIC IF NOT LIBGIT2_FOUND)
cr_link_subproject(criterion wingetopt STATIC)

if (CSPTR_FOUND)
include_directories("${CSPTR_INCLUDE_DIRS}")
cr_link_libraries(criterion "${CSPTR_LIBRARIES}")
include_directories(${CSPTR_INCLUDE_DIRS})
cr_link_libraries(criterion ${CSPTR_LIBRARIES})
endif ()
if (NANOMSG_FOUND)
include_directories("${NANOMSG_INCLUDE_DIRS}")
cr_link_libraries(criterion "${NANOMSG_LIBRARIES}" IF NANOMSG_FOUND)
include_directories(${NANOMSG_INCLUDE_DIRS})
cr_link_libraries(criterion ${NANOMSG_LIBRARIES})
endif ()
if (DYNCALL_FOUND)
include_directories("${DYNCALL_INCLUDE_DIRS}")
cr_link_libraries(criterion "${DYNCALL_LIBRARIES}" IF DYNCALL_FOUND)
include_directories(${DYNCALL_INCLUDE_DIRS})
cr_link_libraries(criterion ${DYNCALL_LIBRARIES})
endif ()
if (BOXFORT_FOUND)
include_directories("${BOXFORT_INCLUDE_DIRS}")
cr_link_libraries(criterion "${BOXFORT_LIBRARIES}" IF BOXFORT_FOUND)
include_directories(${BOXFORT_INCLUDE_DIRS})
cr_link_libraries(criterion ${BOXFORT_LIBRARIES})
endif ()
if (LIBGIT2_FOUND)
include_directories(${LIBGIT2_INCLUDE_DIRS})
cr_link_libraries(criterion ${LIBGIT2_LIBRARIES})
endif ()

cr_link_libraries(criterion pthread IF NOT WIN32)
@@ -15,6 +15,7 @@ environment:
- COMPILER: mingw
GENERATOR: "MSYS Makefiles"
BUILD_FLAGS: -j2
CPPFLAGS: -D__USE_MINGW_ANSI_STDIO
- COMPILER: msvc
GENERATOR: "Visual Studio 14 2015 Win64"
CFLAGS: /MP
Submodule nanopb updated 115 files
@@ -2018,7 +2018,7 @@ INCLUDE_FILE_PATTERNS =
# recursively expanded use the := operator instead of the = operator.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.

PREDEFINED = __GNUC__ __cplusplus
PREDEFINED = __GNUC__ __cplusplus CRITERION_DOCGEN

# 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
@@ -23,3 +23,32 @@
.container > dl {
margin-bottom: 0 !important; /* Dirty hack */
}

/* Don't indent group contents */
.group dd {
margin-left: 0;
}

/* Hide ugly group title block & group rubrics */
.group > dt,
p.breathe-sectiondef-title {
display: none;
}

/* Slightly indent content for doxygen entries */
dl.macro > dd {
margin-left: 30px;
}

/* Format parameters better */
.breatheparameterlist {
padding-left: 0;
list-style-type: none;
}

.breatheparameterlist > li > code,
.breatheparameterlist > li > code > .pre {
background: transparent;
font-family: inherit;
font-weight: bold;
}
@@ -12,40 +12,18 @@ macros to this list. Hence only ``assert`` macros are represented here.
All ``assert`` macros may take an optional ``printf`` format string and
parameters.

Base Assertions
-----------------
Assertion API
-------------

.. doxygengroup:: BaseAsserts
.. doxygengroup:: AssertAPI

Common Assertions
-----------------
Assertion Criteria
------------------

.. doxygengroup:: CommonBinAsserts
.. doxygengroup:: CommonUnaryAsserts
.. doxygengroup:: FloatAsserts
.. doxygengroup:: Criteria
.. doxygengroup:: TaggedCriteria

String Assertions
-----------------
Tags
----

.. doxygengroup:: StringAsserts

Wide String Assertions
----------------------

.. doxygengroup:: WideStringAsserts

Array Assertions
-----------------

.. doxygengroup:: ArrayAsserts
.. doxygengroup:: SafeArrCmpAsserts

Exception Assertions
--------------------

.. doxygengroup:: ExceptionAsserts

File Assertions
---------------

.. doxygengroup:: FileAsserts
.. doxygengroup:: Tags
@@ -14,12 +14,10 @@
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'

# hack for readthedocs to cause it to run doxygen first
# https://github.com/rtfd/readthedocs.org/issues/388
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
if on_rtd:
from subprocess import call
call('doxygen')
def generate_doxygen_xml(app):
from subprocess import call
doxdir = os.path.abspath(os.path.dirname(__file__))
call('cd %s; doxygen' % doxdir, shell=True)

# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
@@ -306,3 +304,7 @@
from pygments.lexers.c_cpp import CLexer

lexers['c'] = CLexer(startinline=True)

def setup(app):
# Add hook for building doxygen xml when needed
app.connect("builder-inited", generate_doxygen_xml)
@@ -30,6 +30,8 @@
# include <stdarg.h>
#endif

#include <stddef.h>

#include "common.h"

CR_BEGIN_C_API
@@ -39,6 +41,11 @@ CR_API int cr_asprintf(char **strp, const char *fmt, ...);
CR_API int cr_vasprintf(char **strp, const char *fmt, va_list ap);
CR_API void cr_asprintf_free(char *buf);

CR_API int cri_fmt_bprintf(char **buf, size_t *offset, size_t *sz,
const char *fmt, ...);

CR_API char *cri_strtok_r(char *str, const char *delim, char **saveptr);

CR_END_C_API

#endif /* !CRITERION_ASPRINTF_COMPAT_H_ */
Oops, something went wrong.

0 comments on commit d258a8b

Please sign in to comment.