[v2.0.0] Merge branch 'bleeding' (Version release)

This commit is contained in:
Snaipe 2015-09-14 04:25:17 +02:00
commit a0af6a0af1
155 changed files with 4579 additions and 764 deletions

View file

@ -1,6 +1,6 @@
[bumpversion]
current_version = 1.3.1
commit = True
commit = False
[bumpversion:file:CMakeLists.txt]

View file

@ -1,14 +0,0 @@
#!/bin/bash
repo="https://github.com/Snaipe/libcsptr.git"
tag="v2.0.4"
mkdir dependencies
git clone --branch ${tag} --depth 1 ${repo} dependencies/libcsptr &&
(
cd dependencies/libcsptr &&
mkdir build &&
cd $_ &&
cmake -DCMAKE_INSTALL_PREFIX=$LOCAL_INSTALL "$@" .. &&
make &&
make install
)

View file

@ -1,4 +0,0 @@
#!/bin/sh
curl -O https://bootstrap.pypa.io/get-pip.py
python3 get-pip.py
rm -f get-pip.py

View file

@ -0,0 +1,31 @@
# Copyright (C) 2015 Franklin "Snaipe" Mathieu.
# Redistribution and use of this file is allowed according to the terms of the MIT license.
# For details see the LICENSE file distributed with Criterion.
# - Find dyncall
# Find the native libcsptr headers and libraries.
#
# DYNCALL_INCLUDE_DIRS - where to find smart_ptr.h, etc.
# DYNCALL_LIBRARIES - List of libraries when using libcsptr.
# DYNCALL_FOUND - True if libcsptr has been found.
# Look for the header file.
FIND_PATH(DYNCALL_INCLUDE_DIR dyncall.h)
# Look for the library.
FIND_LIBRARY(DYNCALL_LIBRARY NAMES dyncall_s)
# Handle the QUIETLY and REQUIRED arguments and set DYNCALL_FOUND to TRUE if all listed variables are TRUE.
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(DYNCALL DEFAULT_MSG DYNCALL_LIBRARY DYNCALL_INCLUDE_DIR)
# Copy the results to the output variables.
IF(DYNCALL_FOUND)
SET(DYNCALL_LIBRARIES ${DYNCALL_LIBRARY})
SET(DYNCALL_INCLUDE_DIRS ${DYNCALL_INCLUDE_DIR})
ELSE(DYNCALL_FOUND)
SET(DYNCALL_LIBRARIES)
SET(DYNCALL_INCLUDE_DIRS)
ENDIF(DYNCALL_FOUND)
MARK_AS_ADVANCED(DYNCALL_INCLUDE_DIRS DYNCALL_LIBRARIES)

View file

@ -0,0 +1,56 @@
if(EXISTS "${PROJECT_SOURCE_DIR}/.gitmodules")
message(STATUS "Updating submodules to their latest/fixed versions")
message(STATUS "(this can take a while, please be patient)")
### set the direcory where the submodules live
set(GIT_SUBMODULES_DIRECTORY dependencies)
### set the directory names of the submodules
set(GIT_SUBMODULES libcsptr dyncall)
### set each submodules's commit or tag that is to be checked out
### (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()
### Then, checkout each submodule to the specified commit
# Note: Execute separate processes here, to make sure each one is run,
# should one crash (because of branch not existing, this, that ... whatever)
foreach(GIT_SUBMODULE ${GIT_SUBMODULES})
if( "${GIT_SUBMODULE_VERSION_${GIT_SUBMODULE}}" STREQUAL "" )
message(STATUS "no specific version given for submodule ${GIT_SUBMODULE}, checking out master")
set(GIT_SUBMODULE_VERSION_${GIT_SUBMODULE} "master")
endif()
if(${GIT_SUBMODULES_CHECKOUT_QUIET})
execute_process(
COMMAND git checkout ${GIT_SUBMODULE_VERSION_${GIT_SUBMODULE}}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/${GIT_SUBMODULES_DIRECTORY}/${GIT_SUBMODULE}
OUTPUT_QUIET
ERROR_QUIET
)
else()
message(STATUS "checking out ${GIT_SUBMODULE}'s commit/tag ${GIT_SUBMODULE_VERSION_${GIT_SUBMODULE}}")
execute_process(
COMMAND git checkout -q ${GIT_SUBMODULE_VERSION_${GIT_SUBMODULE}}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/${GIT_SUBMODULES_DIRECTORY}/${GIT_SUBMODULE}
)
endif()
endforeach(${GIT_SUBMODULE})
endif()

15
.gitignore vendored
View file

@ -3,24 +3,31 @@
!.gitignore
!.bumpversion.cfg
!.ci/*
!.cmake/*
!dev/*
!doc/*
!*.c
!*.cc
!*.h
!*.rst
!samples/tests/*.sh
!*.po
!*.in
!samples/tests/*.sh
!samples/*.expected
!LICENSE
!HEADER
!ChangeLog
CMakeFiles/
!CMakeLists.txt
!.cmake/*
!src/config.h.in
src/config.h
build
*~
*.swp
.*.swp

9
.gitmodules vendored Normal file
View file

@ -0,0 +1,9 @@
[submodule "dependencies/libcsptr"]
path = dependencies/libcsptr
url = https://github.com/Snaipe/libcsptr.git
[submodule "dependencies/dyncall"]
path = dependencies/dyncall
url = https://github.com/Snaipe/dyncall.git
[submodule "dependencies/wingetopt"]
path = dependencies/wingetopt
url = https://github.com/alex85k/wingetopt.git

View file

@ -2,19 +2,32 @@ language: c
os:
- linux
- osx
compiler:
- gcc
- gcc-4.9
sudo: false
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-4.9
- g++-4.9
before_install:
- export GCOV="gcov-4.9"
- export LOCAL_INSTALL="$HOME"
- ".ci/install-libcsptr.sh"
- export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HOME/lib
- export CFLAGS="-g -O0"
- export CXX="g++-4.9"
script:
- mkdir -p build
- cd build
- cmake -DCOVERALLS=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_PREFIX_PATH=$HOME -DCMAKE_INSTALL_PREFIX=criterion-${TRAVIS_TAG} ..
- make
- make criterion_tests
- make test
after_success:
- make coveralls

View file

@ -1,22 +1,49 @@
cmake_minimum_required(VERSION 2.8)
project(Criterion C)
project(Criterion C CXX)
set(MODULE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/.cmake/Modules")
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${MODULE_DIR})
set(LIBCSPTR_DISABLE_TESTS ON)
set(LIBCSPTR_DISABLE_COVERALLS ON)
include(Submodules)
if (MSVC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS=1)
endif ()
add_subdirectory(dependencies/libcsptr/ EXCLUDE_FROM_ALL)
add_subdirectory(dependencies/dyncall/ EXCLUDE_FROM_ALL)
include_directories(
dependencies/libcsptr/include/
dependencies/dyncall/dyncall/
)
if (MSVC)
add_subdirectory(dependencies/wingetopt/ EXCLUDE_FROM_ALL)
include_directories(dependencies/wingetopt/src/)
endif ()
# Project setup & environment variables
enable_testing()
add_subdirectory(samples)
set(PROJECT_VERSION "1.3.1")
set(LOCALEDIR ${CMAKE_INSTALL_PREFIX}/share/locale)
set(GettextTranslate_ALL 1)
set(GettextTranslate_GMO_BINARY 1)
set(MODULE_DIR "${CMAKE_SOURCE_DIR}/.cmake/Modules")
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${MODULE_DIR})
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror -g -std=gnu99")
add_definitions(-DCRITERION_BUILDING_DLL=1)
if (WIN32)
if (NOT MSVC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror -g -std=gnu99")
endif ()
if (MSVC)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SAFESEH:NO")
endif ()
if (WIN32 AND NOT MSVC)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-no-undefined")
endif()
@ -44,7 +71,6 @@ include(CheckLibraryExists)
CHECK_LIBRARY_EXISTS(rt clock_gettime "time.h" HAVE_CLOCK_GETTIME)
find_package(PCRE)
find_package(Libcsptr REQUIRED)
# List sources and headers
@ -71,7 +97,11 @@ set(SOURCE_FILES
src/i18n.h
src/ordered-set.c
src/posix-compat.c
src/theories.c
src/asprintf.c
src/file.c
src/main.c
src/entry.c
)
if (PCRE_FOUND)
@ -94,18 +124,26 @@ set(INTERFACE_FILES
include/criterion/options.h
include/criterion/ordered-set.h
include/criterion/stats.h
include/criterion/theories.h
include/criterion/asprintf-compat.h
include/criterion/designated-initializer-compat.h
include/criterion/preprocess.h
)
# Generate the configure file
configure_file(
"${CMAKE_SOURCE_DIR}/src/config.h.in"
"${CMAKE_SOURCE_DIR}/src/config.h"
"${CMAKE_CURRENT_SOURCE_DIR}/src/config.h.in"
"${CMAKE_CURRENT_SOURCE_DIR}/src/config.h"
)
include_directories(include src ${CSPTR_INCLUDE_DIRS})
include_directories(include src)
add_library(criterion SHARED ${SOURCE_FILES} ${INTERFACE_FILES})
target_link_libraries(criterion ${CSPTR_LIBRARIES})
target_link_libraries(criterion csptr dyncall_s)
if (MSVC)
target_link_libraries(criterion wingetopt)
endif ()
if (HAVE_CLOCK_GETTIME)
target_link_libraries(criterion rt)
@ -130,6 +168,8 @@ install(TARGETS criterion
ARCHIVE DESTINATION lib
)
add_custom_target(uninstall
"${CMAKE_COMMAND}" -P "${CMAKE_MODULE_PATH}/uninstall.cmake"
)
add_custom_target(criterion_tests)
enable_testing()
add_subdirectory(samples)
add_subdirectory(test)

44
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,44 @@
# Contributing
Contributions are welcomed, but must follow a simple set of rules in order to
be merged.
**Please follow these conventions if you want your pull request(s) accepted.**
## General
* Use 4 (four) spaces for indentation.
* No trailing whitespaces.
* 80 chars column limit.
* No trash files. Trash files are by-products of the compilation process, or
generated files that does not need to be under version control.
* Pull requests must compile and work properly.
* Pull requests must pass all tests.
* Pull requests must be mergeable automatically.
* Number of commits in a pull request should be kept to one commit and all
additional commits must be squashed.
* You may have more than one commit in a pull request if the commits are
separate changes, otherwise squash them.
## Translations
* You can contribute new translation files for output messages, on the
condition that you are fluent with the language itself.
* Each correction on existing translations must be followed by a
rationale ("why would the translation be better if the change is applied?")
## Roadmap
.
|- .cmake/: CMake modules
|- dependencies/: dependencies for building libcriterion
|- doc/: Sphinx documentation files
|- include/criterion/: Public API
|- src/: Sources for libcriterion
| `- log/: Output providers, all the output logic in general
|- po/: Translation files, i18n stuff
|- test/: Unit tests for libcriterion
`- samples/: Sample files
|- outputs/: Expected output files for the current samples
`- tests/: Internal regression tests
`- outputs/: Expected output files for the regression tests

View file

@ -1,3 +1,26 @@
2015-09-14 Franklin "Snaipe" Mathieu <franklinmathieu@gmail.com>
* criterion: version 2.0.0
* Breaking: ABI incompatibility with prior versions of criterion. You
**must** recompile your tests.
* Breaking: cr_abort_test(NULL) does not compile anymore.
* Change: Changed all assertion macros to accept a printf format string as a
message.
* Change: Made the API C++11-compatible.
* Change: Made the library ISO C compliant. You can now compile the library
with VC 14+.
* Addition: Added support for theories.
* Addition: Added ability to test the exit status of a test.
* Addition: Added C++11 throw assertions.
* Addition: Added assert message localization.
* Addition: Added test timeouts.
* Addition: Added test standard i/o redirection & file comparison assertions.
* Removal: Removed the deprecated prefixless assertion macros
* Deprecation: Deprecated cr_abort_test.
* Deprecation: cr_{assert,expect}_strings_* and cr_{assert,expect}_arrays_*
are deprecated in favor of cr_{assert,expect}_str_* and
cr_{assert,expect}_arr_* respectively.
2015-08-20 Franklin "Snaipe" Mathieu <franklinmathieu@gmail.com>
* criterion: version 1.3.1

View file

@ -2,12 +2,13 @@
<img src="doc/criterion-title.png" height="96" alt="Criterion Logo" />
=========
[![Build Status](https://travis-ci.org/Snaipe/Criterion.svg?branch=bleeding)](https://travis-ci.org/Snaipe/Criterion)
[![Unix Build Status](https://travis-ci.org/Snaipe/Criterion.svg?branch=bleeding)](https://travis-ci.org/Snaipe/Criterion)
[![Windows Build Status](https://ci.appveyor.com/api/projects/status/github/Snaipe/Criterion?svg=true&branch=bleeding)](https://ci.appveyor.com/project/Snaipe/Criterion/branch/bleeding)
[![Coverage Status](https://coveralls.io/repos/Snaipe/Criterion/badge.svg?branch=bleeding)](https://coveralls.io/r/Snaipe/Criterion?branch=bleeding)
[![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://github.com/Snaipe/Criterion/blob/master/LICENSE)
[![Version](https://img.shields.io/github/tag/Snaipe/Criterion.svg?label=version&style=flat)](https://github.com/Snaipe/Criterion/releases)
A dead-simple, yet extensible, C unit testing framework.
A dead-simple, yet extensible, C and C++ unit testing framework.
![Screencast](./doc/screencast.gif)
@ -23,30 +24,35 @@ This gives the user great control, at the unfortunate cost of simplicity.
Criterion follows the KISS principle, while keeping the control
the user would have with other frameworks:
* [x] C99 and C++11 compatible.
* [x] Tests are automatically registered when declared.
* [x] Implements a xUnit framework structure.
* [x] A default entry point is provided, no need to declare a main
unless you want to do special handling.
* [x] Test are isolated in their own process, crashes and signals can be
reported and tested.
* [x] Unified interface between C and C++: include the criterion header and it *just* works.
* [x] There is a support for theories alongside tests
* [x] Progress and statistics can be followed in real time with report hooks.
* [x] TAP output format can be enabled with an option.
* [x] Runs on Linux, FreeBSD, Mac OS X, and Windows (Compiling with MinGW GCC).
* [x] Runs on Linux, FreeBSD, Mac OS X, and Windows (Compiling with MinGW GCC and Visual Studio 2015+).
## Downloads
* [Linux (x86_64)](https://github.com/Snaipe/Criterion/releases/download/v1.3.1/criterion-1.3.1-linux-x86_64.tar.bz2)
* [OS X (x86_64)](https://github.com/Snaipe/Criterion/releases/download/v1.3.1/criterion-1.3.1-osx-x86_64.tar.bz2)
* [Windows (x86)](https://github.com/Snaipe/Criterion/releases/download/v1.3.1/criterion-1.3.1-windows-x86.tar.bz2)
* [Linux (x86_64)](https://github.com/Snaipe/Criterion/releases/download/v1.3.1/criterion-v1.3.1-linux-x86_64.tar.bz2)
* [OS X (x86_64)](https://github.com/Snaipe/Criterion/releases/download/v1.3.1/criterion-v1.3.1-osx-x86_64.tar.bz2)
* [Windows (x86_64)](https://github.com/Snaipe/Criterion/releases/download/v1.3.1/criterion-v1.3.1-windows-x86_64.tar.bz2)
If you have a different platform, you can still [build the library from source](http://criterion.readthedocs.org/en/latest/setup.html#installation)
## Documentation
## Developer Resources
### Documentation
An online documentation is available on [ReadTheDocs][online-docs]
([PDF][pdf-docs] | [Zip][zip-docs] | [Epub][epub-docs])
## Samples
### Samples
Sample tests can be found in the [sample directory][samples].
@ -57,37 +63,17 @@ Sample tests can be found in the [sample directory][samples].
* [Tests with signals][sample-signal]
* [Using report hooks][sample-report]
## Contributing
### Getting help
Contributions are welcomed, but must follow a simple set of rules in order to
be merged.
Gitter.im chat room: [![Join the chat at https://gitter.im/Snaipe/Criterion](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Snaipe/Criterion?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
**Please follow these conventions if you want your pull request(s) accepted.**
### Misc
### General
* Use 4 (four) spaces for indentation.
* No trailing whitespaces.
* 80 chars column limit.
* No trash files. Trash files are by-products of the compilation process, or
generated files that does not need to be under version control.
* Pull requests must compile and work properly.
* Pull requests must be mergeable automatically.
* Number of commits in a pull request should be kept to one commit and all
additional commits must be squashed.
* You may have more than one commit in a pull request if the commits are
separate changes, otherwise squash them.
### Translations
* You can contribute new translation files for output messages, on the
condition that you are fluent with the language itself.
* Each correction on existing translations must be followed by a
rationale ("why would the translation be better if the change is applied?")
* [CMake find module for Criterion][find-module]
## F.A.Q.
**Q. What's wrong with other test frameworks?**
**Q. What's wrong with other C test frameworks?**
A. I worked with CUnit and Check, and I must say that they do their job
very well -- the only thing that bugs me is that setting up a test
suite from scratch is a pain, it should really be simpler. Most
@ -116,3 +102,5 @@ Logo done by [Greehm](http://www.cargocollective.com/pbouigue)
[sample-fixtures]: ./samples/fixtures.c
[sample-signal]: ./samples/signal.c
[sample-report]: ./samples/report.c
[find-module]: ./dev/FindCriterion.cmake

View file

@ -1,10 +1,10 @@
version: 1.3.1_b{build}-{branch}
os: Windows Server 2012
os: Visual Studio 2015
init:
- git config --global core.autocrlf input
- 'SET PATH=%PATH%;C:\MinGW\msys\1.0\bin;C:\MinGW\bin;%APPVEYOR_BUILD_FOLDER%\bin;%APPVEYOR_BUILD_FOLDER%\build'
- 'SET PATH=C:\MinGW\bin;%PATH%;C:\MinGW\msys\1.0\bin;%APPVEYOR_BUILD_FOLDER%\build;%APPVEYOR_BUILD_FOLDER%\build\Debug'
environment:
COVERALLS_REPO_TOKEN:
@ -13,40 +13,50 @@ environment:
CI_JOB_ID: $(APPVEYOR_JOB_ID)
LOCAL_INSTALL: $(APPVEYOR_BUILD_FOLDER)
GCOV_PREFIX: $(APPVEYOR_BUILD_FOLDER)
matrix:
- COMPILER: mingw
GENERATOR: "MSYS Makefiles"
- COMPILER: msvc
GENERATOR: "Visual Studio 14 2015"
clone_depth: 5
matrix:
fast_finish: true # set this flag to immediately finish build once one of the jobs fails.
platform:
- x86_64
configuration: Release
install:
- ps: $env:RELEASE_NAME = $env:APPVEYOR_REPO_BRANCH -replace "/", "-"
# Hack to make git think it is on the tip of the repo branch
- 'git checkout -B %APPVEYOR_REPO_BRANCH%'
# Install libcsptr
- 'bash -lc "cd $APPVEYOR_BUILD_FOLDER; .ci/install-libcsptr.sh -G \"MSYS Makefiles\"; true"'
# We need to manually make since the above command somehow crashes
- 'cd dependencies/libcsptr/build && make && make install && cd ../../../'
# Configure project
- 'mkdir build && cd build'
- 'cmake -DCMAKE_INSTALL_PREFIX=criterion-%APPVEYOR_REPO_TAG_NAME% -DCMAKE_PREFIX_PATH="%LOCAL_INSTALL%" -DCOVERALLS=ON -DCMAKE_BUILD_TYPE=Debug -G "MSYS Makefiles" ..'
- >
cmake
-Wno-dev
-DCMAKE_INSTALL_PREFIX="criterion-%RELEASE_NAME%"
-DCMAKE_PREFIX_PATH="%LOCAL_INSTALL%"
-G "%GENERATOR%"
..
build_script:
- 'make'
- cmake --build .
after_build:
- 'make install'
- 'bash -lc "cd $APPVEYOR_BUILD_FOLDER; tar -cvjf criterion-${APPVEYOR_REPO_BRANCH}-windows-${PLATFORM}.tar.bz2 -C build criterion-${APPVEYOR_REPO_TAG_NAME}"'
before_deploy:
- ps: |
$archive = "criterion-$env:RELEASE_NAME-windows-$env:COMPILER-$env:PLATFORM"
cmake --build . --target install
7z a -ttar "$archive.tar" "criterion-$env:RELEASE_NAME"
7z a -tbzip2 "../$archive.tar.bz2" "$archive.tar"
Push-AppveyorArtifact "../$archive.tar.bz2"
test_script:
- 'make test || bash -lc "cat $APPVEYOR_BUILD_FOLDER/build/Testing/Temporary/LastTest.log"'
- cmake --build . --target criterion_tests
- ps: try { ctest } catch { type Testing/Temporary/LastTest.log }
after_test:
- 'make coveralls'
#after_test:
# - 'make coveralls'
notifications:
@ -54,14 +64,11 @@ notifications:
to: [franklinmathieu@gmail.com]
on_build_status_changed: true
artifacts:
- path: '**\*.tar.bz2'
deploy:
provider: GitHub
auth_token:
secure: MnZZQeoxBVnpV9GSSvVok5Je0/N2d/fzG4+ITw95/tYSgZ8rleBV23a5sCwAea3r
artifact: 'criterion-$(APPVEYOR_REPO_TAG_NAME)-windows-$(PLATFORM).tar.bz2'
artifact: 'criterion-$(RELEASE_NAME)-windows-$(COMPILER)-$(PLATFORM).tar.bz2'
draft: false
prerelease: false
on:

1
dependencies/dyncall vendored Submodule

@ -0,0 +1 @@
Subproject commit 68c57f664d4fabbc5b80327fbf5661a3a5a51e06

1
dependencies/libcsptr vendored Submodule

@ -0,0 +1 @@
Subproject commit 2762164acfaa712fea7dec6ed760ff88f7d2e026

1
dependencies/wingetopt vendored Submodule

@ -0,0 +1 @@
Subproject commit 76a5d1ab15f684d4c9479a32624d65b3bd1a726b

27
dev/FindCriterion.cmake Normal file
View file

@ -0,0 +1,27 @@
# This file is licensed under the WTFPL version 2 -- you can see the full
# license over at http://www.wtfpl.net/txt/copying/
#
# - Try to find Criterion
#
# Once done this will define
# CRITERION_FOUND - System has LibXml2
# CRITERION_INCLUDE_DIRS - The LibXml2 include directories
# CRITERION_LIBRARIES - The libraries needed to use LibXml2
find_package(PkgConfig)
find_path(CRITERION_INCLUDE_DIR criterion/criterion.h
PATH_SUFFIXES criterion)
find_library(CRITERION_LIBRARY NAMES criterion libcriterion)
set(CRITERION_LIBRARIES ${CRITERION_LIBRARY})
set(CRITERION_INCLUDE_DIRS ${CRITERION_INCLUDE_DIR})
include(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set CRITERION_FOUND to TRUE
# if all listed variables are TRUE
find_package_handle_standard_args(LibXml2 DEFAULT_MSG
CRITERION_LIBRARY CRITERION_INCLUDE_DIR)
mark_as_advanced(CRITERION_INCLUDE_DIR CRITERION_LIBRARY)

144
doc/assert.rst Normal file
View file

@ -0,0 +1,144 @@
.. _assertions-ref:
Assertion reference
===================
This is an exhaustive list of all assertion macros that Criterion provides.
As each ``assert`` macros have an ``expect`` counterpart with the exact same
number of parameters and name suffix, there is no benefit in adding ``expect``
macros to this list. Hence only ``assert`` macros are represented here.
Common Assertions
-----------------
======================================================================= =========================================================================== ===========================================
Macro Passes if and only if Notes
======================================================================= =========================================================================== ===========================================
cr_assert(Condition, [Message, [Args...]]) ``Condition`` is true.
----------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
cr_assert_not(Condition, [Message, [Args...]]) ``Condition`` is false.
----------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
cr_assert_null(Value, [Message, [Args...]]) ``Value`` is ``NULL``.
----------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
cr_assert_not_null(Value, [Message, [Args...]]) ``Value`` is not ``NULL``.
----------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
cr_assert_eq(Actual, Expected, [Message, [Args...]]) ``Actual`` is equal to ``Expected``. Compatible with C++ operator overloading
----------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
cr_assert_neq(Actual, Unexpected, [Message, [Args...]]) ``Actual`` is not equal to ``Unexpected``. Compatible with C++ operator overloading
----------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
cr_assert_lt(Actual, Reference, [Message, [Args...]]) ``Actual`` is less than ``Reference``. Compatible with C++ operator overloading
----------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
cr_assert_leq(Actual, Reference, [Message, [Args...]]) ``Actual`` is less or equal to ``Reference``. Compatible with C++ operator overloading
----------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
cr_assert_gt(Actual, Reference, [Message, [Args...]]) ``Actual`` is greater than ``Reference``. Compatible with C++ operator overloading
----------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
cr_assert_geq(Actual, Reference, [Message, [Args...]]) ``Actual`` is greater or equal to ``Reference``. Compatible with C++ operator overloading
----------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
cr_assert_float_eq(Actual, Expected, Epsilon, [Message, [Args...]]) ``Actual`` is equal to ``Expected`` with a tolerance of ``Epsilon``. Use this to test equality between floats
----------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
cr_assert_float_neq(Actual, Unexpected, Epsilon, [Message, [Args...]]) ``Actual`` is not equal to ``Unexpected`` with a tolerance of ``Epsilon``. Use this to test inequality between floats
======================================================================= =========================================================================== ===========================================
String Assertions
-----------------
Note: these macros are meant to deal with *native* strings, i.e. char arrays.
Most of them won't work on ``std::string`` in C++, with some exceptions -- for
``std::string``, you should use regular comparison assersions, as listed above.
=========================================================== =================================================================== ===========================================
Macro Passes if and only if Notes
=========================================================== =================================================================== ===========================================
cr_assert_str_empty(Value, [Message, [Args...]]) ``Value`` is an empty string. Also works on std::string
----------------------------------------------------------- ------------------------------------------------------------------- -------------------------------------------
cr_assert_str_not_empty(Value, [Message, [Args...]]) ``Value`` is not an empty string. Also works on std::string
----------------------------------------------------------- ------------------------------------------------------------------- -------------------------------------------
cr_assert_str_eq(Actual, Expected, [Message, [Args...]]) ``Actual`` is lexicographically equal to ``Expected``.
----------------------------------------------------------- ------------------------------------------------------------------- -------------------------------------------
cr_assert_str_neq(Actual, Unexpected, [Message, [Args...]]) ``Actual`` is not lexicographically equal to ``Unexpected``.
----------------------------------------------------------- ------------------------------------------------------------------- -------------------------------------------
cr_assert_str_lt(Actual, Reference, [Message, [Args...]]) ``Actual`` is lexicographically less than ``Reference``.
----------------------------------------------------------- ------------------------------------------------------------------- -------------------------------------------
cr_assert_str_leq(Actual, Reference, [Message, [Args...]]) ``Actual`` is lexicographically less or equal to ``Reference``.
----------------------------------------------------------- ------------------------------------------------------------------- -------------------------------------------
cr_assert_str_gt(Actual, Reference, [Message, [Args...]]) ``Actual`` is lexicographically greater than ``Reference``.
----------------------------------------------------------- ------------------------------------------------------------------- -------------------------------------------
cr_assert_str_geq(Actual, Reference, [Message, [Args...]]) ``Actual`` is lexicographically greater or equal to ``Reference``.
=========================================================== =================================================================== ===========================================
Array Assertions
-----------------
=========================================================================== =========================================================================== ===========================================
Macro Passes if and only if Notes
=========================================================================== =========================================================================== ===========================================
cr_assert_arr_eq(Actual, Expected, [Message, [Args...]]) ``Actual`` is byte-to-byte equal to ``Expected``. This should not be used on struct arrays,
consider using ``cr_assert_arr_eq_cmp``
instead.
--------------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
cr_assert_arr_neq(Actual, Unexpected, [Message, [Args...]]) ``Actual`` is not byte-to-byte equal to ``Unexpected``. This should not be used on struct arrays,
consider using ``cr_assert_arr_neq_cmp``
instead.
--------------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
cr_assert_arr_eq_cmp(Actual, Expected, Size, Cmp, [Message, [Args...]]) ``Actual`` is comparatively equal to ``Expected`` Only available in C++ and GNU C99
--------------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
cr_assert_arr_neq_cmp(Actual, Unexpected, Size, Cmp, [Message, [Args...]]) ``Actual`` is not comparatively equal to ``Expected`` Only available in C++ and GNU C99
--------------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
cr_assert_arr_lt_cmp(Actual, Reference, Size, Cmp, [Message, [Args...]]) ``Actual`` is comparatively less than ``Reference`` Only available in C++ and GNU C99
--------------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
cr_assert_arr_leq_cmp(Actual, Reference, Size, Cmp, [Message, [Args...]]) ``Actual`` is comparatively less or equal to ``Reference`` Only available in C++ and GNU C99
--------------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
cr_assert_arr_gt_cmp(Actual, Reference, Size, Cmp, [Message, [Args...]]) ``Actual`` is comparatively greater than ``Reference`` Only available in C++ and GNU C99
--------------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
cr_assert_arr_geq_cmp(Actual, Reference, Size, Cmp, [Message, [Args...]]) ``Actual`` is comparatively greater or equal to ``Reference`` Only available in C++ and GNU C99
=========================================================================== =========================================================================== ===========================================
Exception Assertions
--------------------
The following assertion macros are only defined for C++.
=========================================================================== =========================================================================== ===========================================
Macro Passes if and only if Notes
=========================================================================== =========================================================================== ===========================================
cr_assert_throw(Statement, Exception, [Message, [Args...]]) ``Statement`` throws an instance of ``Exception``.
--------------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
cr_assert_no_throw(Statement, Exception, [Message, [Args...]]) ``Statement`` does not throws an instance of ``Exception``.
--------------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
cr_assert_any_throw(Statement, [Message, [Args...]]) ``Statement`` throws any kind of exception.
--------------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------------------------------
cr_assert_none_throw(Statement, [Message, [Args...]]) ``Statement`` does not throw any exception.
=========================================================================== =========================================================================== ===========================================
File Assertions
---------------
=============================================================================== ============================================================================ ===========================================
Macro Passes if and only if Notes
=============================================================================== ============================================================================ ===========================================
cr_assert_file_contents_eq_str(File, ExpectedContents, [Message, [Args...]]) The contents of ``File`` are equal to the string ``ExpectedContents``.
------------------------------------------------------------------------------- ---------------------------------------------------------------------------- -------------------------------------------
cr_assert_file_contents_neq_str(File, ExpectedContents, [Message, [Args...]]) The contents of ``File`` are not equal to the string ``ExpectedContents``.
------------------------------------------------------------------------------- ---------------------------------------------------------------------------- -------------------------------------------
cr_assert_stdout_eq_str(ExpectedContents, [Message, [Args...]]) The contents of ``stdout`` are equal to the string ``ExpectedContents``.
------------------------------------------------------------------------------- ---------------------------------------------------------------------------- -------------------------------------------
cr_assert_stdout_neq_str(ExpectedContents, [Message, [Args...]]) The contents of ``stdout`` are not equal to the string ``ExpectedContents``.
------------------------------------------------------------------------------- ---------------------------------------------------------------------------- -------------------------------------------
cr_assert_stderr_eq_str(ExpectedContents, [Message, [Args...]]) The contents of ``stderr`` are equal to the string ``ExpectedContents``.
------------------------------------------------------------------------------- ---------------------------------------------------------------------------- -------------------------------------------
cr_assert_stderr_neq_str(ExpectedContents, [Message, [Args...]]) The contents of ``stderr`` are not equal to the string ``ExpectedContents``.
------------------------------------------------------------------------------- ---------------------------------------------------------------------------- -------------------------------------------
cr_assert_file_contents_eq(File, RefFile, [Message, [Args...]]) The contents of ``File`` are equal to the contents of ``RefFile``.
------------------------------------------------------------------------------- ---------------------------------------------------------------------------- -------------------------------------------
cr_assert_file_contents_neq(File, RefFile, [Message, [Args...]]) The contents of ``File`` are not equal to the contents of ``RefFile``.
------------------------------------------------------------------------------- ---------------------------------------------------------------------------- -------------------------------------------
cr_assert_stdout_eq(RefFile, [Message, [Args...]]) The contents of ``stdout`` are equal to the contents of ``RefFile``.
------------------------------------------------------------------------------- ---------------------------------------------------------------------------- -------------------------------------------
cr_assert_stdout_neq(RefFile, [Message, [Args...]]) The contents of ``stdout`` are not equal to the contents of ``RefFile``.
------------------------------------------------------------------------------- ---------------------------------------------------------------------------- -------------------------------------------
cr_assert_stderr_eq(RefFile, [Message, [Args...]]) The contents of ``stderr`` are equal to the contents of ``RefFile``.
------------------------------------------------------------------------------- ---------------------------------------------------------------------------- -------------------------------------------
cr_assert_stderr_neq(RefFile, [Message, [Args...]]) The contents of ``stderr`` are not equal to the contents of ``RefFile``.
=============================================================================== ============================================================================ ===========================================

View file

@ -31,6 +31,7 @@ The flow of the test process goes as follows:
#. ``PRE_INIT``: occurs before a test is initialized.
#. ``PRE_TEST``: occurs after the test initialization, but before the test is run.
#. ``ASSERT``: occurs when an assertion is hit
#. ``THEORY_FAIL``: occurs when a theory iteration fails.
#. ``TEST_CRASH``: occurs when a test crashes unexpectedly.
#. ``POST_TEST``: occurs after a test ends, but before the test finalization.
#. ``POST_FINI``: occurs after a test finalization.
@ -50,6 +51,7 @@ Valid types for each phases are:
* ``struct criterion_suite_set *`` for ``PRE_SUITE``.
* ``struct criterion_test *`` for ``PRE_INIT`` and ``PRE_TEST``.
* ``struct criterion_assert_stats *`` for ``ASSERT``.
* ``struct criterion_theory_stats *`` for ``THEORY_FAIL``.
* ``struct criterion_test_stats *`` for ``POST_TEST``, ``POST_FINI``, and ``TEST_CRASH``.
* ``struct criterion_suite_stats *`` for ``POST_SUITE``.
* ``struct criterion_global_stats *`` for ``POST_ALL``.

View file

@ -7,7 +7,9 @@ Criterion
intro
setup
starter
assert
hooks
env
theories
internal
faq

View file

@ -10,6 +10,13 @@ can define your own main function.
Configuring the test runner
~~~~~~~~~~~~~~~~~~~~~~~~~~~
First and foremost, you need to generate the test set; this is done by calling
``criterion_initialize()``. The function returns a ``struct criterion_test_set *``,
that you need to pass to ``criterion_run_all_tests`` later on.
At the very end of your main, you also need to call ``criterion_finalize`` with
the test set as parameter to free any ressources initialized by criterion earlier.
You'd usually want to configure the test runner before calling it.
Configuration is done by setting fields in a global variable named
``criterion_options`` (include criterion/options.h).
@ -34,12 +41,40 @@ fail_fast bool True iff the test runner
pattern const char * The pattern of the tests that should be executed
=================== ================================== ==============================================================
if you want criterion to provide its own default CLI parameters and environment
variables handling, you can also call ``criterion_handle_args(int argc, char *argv[], bool handle_unknown_arg)``
with the proper ``argc/argv``. ``handle_unknown_arg``, if set to true, is here
to tell criterion to print its usage when an unknown CLI parameter is encountered.
If you want to add your own parameters, you should set it to false.
The function returns 0 if the main should exit immediately, and 1 if it should
continue.
Starting the test runner
~~~~~~~~~~~~~~~~~~~~~~~~
The test runner can be called with ``criterion_run_all_tests``. The function
returns 0 if one test or more failed, 1 otherwise.
Example main
~~~~~~~~~~~~
.. code-block:: c
#include <criterion/criterion.h>
int main(int argc, char *argv[]) {
struct criterion_test_set *tests = criterion_initialize();
if (!criterion_handle_args(argc, argv, true))
return 0;
int result = !criterion_run_all_tests(set);
criterion_finalize(set);
return result;
}
Implementing your own output provider
-------------------------------------

View file

@ -4,28 +4,39 @@ Setup
Prerequisites
-------------
Currently, this library only works under \*nix systems.
The library is supported on Linux, OS X, FreeBSD, and Windows.
To compile the static library and its dependencies, GCC 4.6+ is needed.
The following compilers are supported to compile both the library and the tests:
* GCC 4.9+
* Clang 3.4+
* MSVC 14+ (Included in Visual Studio 2015 or later)
To use the static library, any GNU-C compatible compiler will suffice
(GCC, Clang/LLVM, ICC, MinGW-GCC, ...).
Installation
------------
Building from source
--------------------
.. code-block:: bash
$ git clone https://github.com/Snaipe/Criterion.git && cd Criterion
$ LOCAL_INSTALL=/usr .ci/install-libcsptr.sh
$ mkdir build && cd $_ && cmake -DCMAKE_INSTALL_PATH=/usr ..
$ make && sudo make install
$ mkdir build
$ cd build
$ cmake ..
$ cmake --build .
Installing the library and language files (Linux, OS X, FreeBSD)
----------------------------------------------------------------
From the build directory created above, run with an elevated shell:
.. code-block:: bash
$ make install
Usage
-----
Given a test file named test.c, compile it with `-lcriterion`:
To compile your tests with Criterion, you need to make sure to:
.. code-block:: bash
1. Add the include directory to the header search path
2. Install the library to your library search path
3. Link Criterion to your executable.
$ gcc -o test test.c -lcriterion
This should be all you need.

View file

@ -48,45 +48,8 @@ parameter, and an optional failure message:
cr_assert(strlen("") == 0);
}
On top of those, more assertions are available for common operations:
* ``cr_assert_null(Ptr, [Message])``: passes if Ptr is NULL.
* ``cr_assert_eq(Actual, Expected, [Message])``: passes if Actual == Expected.
* ``cr_assert_lt(Actual, Expected, [Message])``: passes if Actual < Expected.
* ``cr_assert_leq(Actual, Expected, [Message])``: passes if Actual <= Expected.
* ``cr_assert_gt(Actual, Expected, [Message])``: passes if Actual > Expected.
* ``cr_assert_geq(Actual, Expected, [Message])``: passes if Actual >= Expected.
* ``cr_assert_float_eq(Actual, Expected, Epsilon, [Message])``:
passes if Actual == Expected with an error of Epsilon.
* ``cr_assert_arrays_eq(Actual, Expected, Size, [Message])``:
passes if all elements of Actual (from 0 to Size - 1) are equals to those
of Expected.
* ``cr_assert_arrays_eq_cmp(Actual, Expected, Size, Cmp, [Message])``:
Same as ``arrays_eq`` but equality is defined by the result of the binary
Cmp function.
Equality and lexical comparison assertions are also available for strings:
* ``cr_assert_strings_eq(Actual, Expected, [Message])``
* ``cr_assert_strings_lt(Actual, Expected, [Message])``
* ``cr_assert_strings_leq(Actual, Expected, [Message])``
* ``cr_assert_strings_gt(Actual, Expected, [Message])``
* ``cr_assert_strings_geq(Actual, Expected, [Message])``
And some assertions have a logical negative counterpart:
* ``cr_assert_not(Condition, [Message])``
* ``cr_assert_not_null(Ptr, [Message])``
* ``cr_assert_neq(Actual, Unexpected, [Message])``
* ``cr_assert_float_neq(Actual, Unexpected, Epsilon, [Message])``
* ``cr_assert_strings_neq(Actual, Unexpected, [Message])``
* ``cr_assert_arrays_neq(Actual, Unexpected, Size, [Message])``
* ``cr_assert_arrays_neq_cmp(Actual, Unexpected, Size, Cmp, [Message])``
Of course, every ``assert`` has an ``expect`` counterpart.
Please note that ``arrays_(n)eq`` assertions should not be used on padded
structures -- please use ``arrays_(n)eq_cmp`` instead.
On top of those, more assertions are available for common operations. See
:ref:`assertions-ref` for a complete list.
Configuring tests
-----------------
@ -176,6 +139,8 @@ See the `windows exception reference`_ for more details on each exception.
.. _windows exception reference: https://msdn.microsoft.com/en-us/library/windows/desktop/ms679356(v=vs.85).aspx
.. _test-config-ref:
Configuration reference
~~~~~~~~~~~~~~~~~~~~~~~
@ -194,6 +159,8 @@ Parameter Type Description
.disabled bool Disables the test.
------------- --------------- --------------------------------------------------------------
.signal int Expect the test to raise the specified signal.
------------- --------------- --------------------------------------------------------------
.exit_code int Expect the test to exit with the specified status.
============= =============== ==============================================================
Setting up suite-wise configuration

242
doc/theories.rst Normal file
View file

@ -0,0 +1,242 @@
Using theories
==============
`Theories`_ are a powerful tool for test-driven development, allowing you
to test a specific behaviour against all permutations of a set of user-defined
parameters known as "data points".
.. _Theories: http://web.archive.org/web/20110608210825/http://shareandenjoy.saff.net/tdd-specifications.pdf
Adding theories
---------------
Adding theories is done by defining data points and a theory function:
.. code-block:: c
#include <criterion/theories.h>
TheoryDataPoints(suite_name, test_name) = {
DataPoints(Type0, val0, val1, val2, ..., valN),
DataPoints(Type1, val0, val1, val2, ..., valN),
...
DataPoints(TypeN, val0, val1, val2, ..., valN),
}
Theory((Type0 arg0, Type1 arg1, ..., TypeN argN), suite_name, test_name) {
}
``suite_name`` and ``test_name`` are the identifiers of the test suite and
the test, respectively. These identifiers must follow the language
identifier format.
``Type0/arg0`` through ``TypeN/argN`` are the parameter types and names of theory
theory function and are available in the body of the function.
Datapoints are declared in the same number, type, and order than the parameters
inside the ``TheoryDataPoints`` macro, with the ``DataPoints`` macro.
Beware! It is undefined behaviour to not have a matching number and type of
theory parameters and datatypes.
Each ``DataPoints`` must then specify the values that will be used for the
theory parameter it is linked to (``val0`` through ``valN``).
Assertions and invariants
-------------------------
You can use any ``cr_assert`` or ``cr_expect`` macro functions inside the body of a
theory function.
Theory invariants are enforced through the ``cr_assume(Condition)`` macro function:
if ``Condition`` is false, then the current theory iteration aborts without
making the test fail.
On top of those, more ``assume`` macro functions are available for common operations:
======================================================= ====================================================
Macro Description
======================================================= ====================================================
``cr_assume_not(Condition)`` Assumes Condition is false.
------------------------------------------------------- ----------------------------------------------------
``cr_assume_null(Ptr)`` Assumes Ptr is NULL.
------------------------------------------------------- ----------------------------------------------------
``cr_assume_not_null(Ptr)`` Assumes Ptr is not NULL.
------------------------------------------------------- ----------------------------------------------------
``cr_assume_eq(Actual, Expected)`` Assumes Actual == Expected.
------------------------------------------------------- ----------------------------------------------------
``cr_assume_neq(Actual, Unexpected)`` Assumes Actual != Expected.
------------------------------------------------------- ----------------------------------------------------
``cr_assume_lt(Actual, Expected)`` Assumes Actual < Expected.
------------------------------------------------------- ----------------------------------------------------
``cr_assume_leq(Actual, Expected)`` Assumes Actual <= Expected.
------------------------------------------------------- ----------------------------------------------------
``cr_assume_gt(Actual, Expected)`` Assumes Actual > Expected.
------------------------------------------------------- ----------------------------------------------------
``cr_assume_geq(Actual, Expected)`` Assumes Actual >= Expected.
------------------------------------------------------- ----------------------------------------------------
``cr_assume_float_eq(Actual, Expected, Epsilon)`` Assumes Actual == Expected with an error of Epsilon.
------------------------------------------------------- ----------------------------------------------------
``cr_assume_float_neq(Actual, Unexpected, Epsilon)`` Assumes Actual != Expected with an error of Epsilon.
------------------------------------------------------- ----------------------------------------------------
``cr_assume_strings_eq(Actual, Expected)`` Assumes Actual and Expected are the same string.
------------------------------------------------------- ----------------------------------------------------
``cr_assume_strings_neq(Actual, Unexpected)`` Assumes Actual and Expected are not the same string.
------------------------------------------------------- ----------------------------------------------------
``cr_assume_strings_lt(Actual, Expected)`` Assumes Actual is less than Expected
lexicographically.
------------------------------------------------------- ----------------------------------------------------
``cr_assume_strings_leq(Actual, Expected)`` Assumes Actual is less or equal to Expected
lexicographically.
------------------------------------------------------- ----------------------------------------------------
``cr_assume_strings_gt(Actual, Expected)`` Assumes Actual is greater than Expected
lexicographically.
------------------------------------------------------- ----------------------------------------------------
``cr_assume_strings_geq(Actual, Expected)`` Assumes Actual is greater or equal to Expected
lexicographically.
------------------------------------------------------- ----------------------------------------------------
``cr_assume_arrays_eq(Actual, Expected, Size)`` Assumes all elements of Actual (from 0 to Size - 1)
are equals to those of Expected.
------------------------------------------------------- ----------------------------------------------------
``cr_assume_arrays_neq(Actual, Unexpected, Size)`` Assumes one or more elements of Actual (from 0 to
Size - 1) differs from their counterpart in Expected.
======================================================= ====================================================
Configuring theories
--------------------
Theories can optionally recieve configuration parameters to alter the behaviour
of the underlying test; as such, those parameters are the same ones as the ones
of the ``Test`` macro function (c.f. :ref:`test-config-ref`).
Full sample & purpose of theories
---------------------------------
We will illustrate how useful theories are with a simple example using Criterion:
The basics of theories
~~~~~~~~~~~~~~~~~~~~~~
Let us imagine that we want to test if the algebraic properties of integers,
and specifically concerning multiplication, are respected by the C language:
.. code-block:: c
int my_mul(int lhs, int rhs) {
return lhs * rhs;
}
Now, we know that multiplication over integers is commutative, so we first test
that:
.. code-block:: c
#include <criterion/criterion.h>
Test(algebra, multiplication_is_commutative) {
cr_assert_eq(my_mul(2, 3), my_mul(3, 2));
}
However, this test is imperfect, because there is not enough triangulation to
insure that my_mul is indeed commutative. One might be tempted to add more
assertions on other values, but this will never be good enough: commutativity
should work for *any* pair of integers, not just an arbitrary set, but, to be
fair, you cannot just test this behaviour for every integer pair that exists.
Theories purposely bridge these two issues by introducing the concept of
"data point" and by refactoring the repeating logic into a dedicated function:
.. code-block:: c
#include <criterion/theories.h>
TheoryDataPoints(algebra, multiplication_is_commutative) = {
DataPoints(int, [...]),
DataPoints(int, [...]),
};
Theory((int lhs, int rhs), algebra, multiplication_is_commutative) {
cr_assert_eq(my_mul(lhs, rhs), my_mul(rhs, lhs));
}
As you can see, we refactored the assertion into a theory taking two unspecified
integers.
We first define some data points in the same order and type the parameters have,
from left to right: the first ``DataPoints(int, ...)`` will define the set of values passed
to the ``int lhs`` parameter, and the second will define the one passed to ``int rhs``.
Choosing the values of the data point is left to you, but we might as well use
"interesting" values: ``0``, ``-1``, ``1``, ``-2``, ``2``, ``INT_MAX``, and ``INT_MIN``:
.. code-block:: c
#include <limits.h>
TheoryDataPoints(algebra, multiplication_is_commutative) = {
DataPoints(int, 0, -1, 1, -2, 2, INT_MAX, INT_MIN),
DataPoints(int, 0, -1, 1, -2, 2, INT_MAX, INT_MIN),
};
Using theory invariants
~~~~~~~~~~~~~~~~~~~~~~~
The second thing we can test on multiplication is that it is the inverse function
of division. Then, given the division operation:
.. code-block:: c
int my_div(int lhs, int rhs) {
return lhs / rhs;
}
The associated theory is straight-forward:
.. code-block:: c
#include <criterion/theories.h>
TheoryDataPoints(algebra, multiplication_is_inverse_of_division) = {
DataPoints(int, 0, -1, 1, -2, 2, INT_MAX, INT_MIN),
DataPoints(int, 0, -1, 1, -2, 2, INT_MAX, INT_MIN),
};
Theory((int lhs, int rhs), algebra, multiplication_is_inverse_of_division) {
cr_assert_eq(lhs, my_div(my_mul(lhs, rhs), rhs));
}
However, we do have a problem because you cannot have the theory function divide
by 0. For this purpose, we can ``assume`` than ``rhs`` will never be 0:
.. code-block:: c
Theory((int lhs, int rhs), algebra, multiplication_is_inverse_of_division) {
cr_assume(rhs != 0);
cr_assert_eq(lhs, my_div(my_mul(lhs, rhs), rhs));
}
``cr_assume`` will abort the current theory iteration if the condition is not
fulfiled.
Running the test at that point will raise a big problem with the current
implementation of ``my_mul`` and ``my_div``:
.. code-block:: none
[----] theories.c:24: Assertion failed: (a) == (bad_div(bad_mul(a, b), b))
[----] Theory algebra::multiplication_is_inverse_of_division failed with the following parameters: (2147483647, 2)
[----] theories.c:24: Assertion failed: (a) == (bad_div(bad_mul(a, b), b))
[----] Theory algebra::multiplication_is_inverse_of_division failed with the following parameters: (-2147483648, 2)
[----] theories.c:24: Unexpected signal caught below this line!
[FAIL] algebra::multiplication_is_inverse_of_division: CRASH!
The theory shows that ``my_div(my_mul(INT_MAX, 2), 2)`` and ``my_div(my_mul(INT_MIN, 2), 2)``
does not respect the properties for multiplication: it happens that the
behaviour of these two functions is undefined because the operation overflows.
Similarly, the test crashes at the end; debugging shows that the source of the
crash is the divison of INT_MAX by -1, which is undefined.
Fixing this is as easy as changing the prototypes of ``my_mul`` and ``my_div``
to operate on ``long long`` rather than ``int``.

View file

@ -26,6 +26,11 @@
# include "common.h"
NORETURN void criterion_abort_test(void);
CR_BEGIN_C_API
CR_API NORETURN void criterion_abort_test(void);
CR_INLINE static void criterion_continue_test(void) {}
CR_END_C_API
#endif /* !CRITERION_ABORT_H_ */

View file

@ -0,0 +1,43 @@
/*
* The MIT License (MIT)
*
* Copyright © 2015 Franklin "Snaipe" Mathieu <http://snai.pe/>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef CRITERION_ASPRINTF_COMPAT_H_
# define CRITERION_ASPRINTF_COMPAT_H_
# ifdef __cplusplus
# include <cstdarg>
# else
# include <stdarg.h>
# endif
# include "common.h"
CR_BEGIN_C_API
FORMAT(printf, 2, 3)
CR_API int cr_asprintf(char **strp, const char *fmt, ...);
CR_API int cr_vasprintf(char **strp, const char *fmt, va_list ap);
CR_END_C_API
#endif /* !CRITERION_ASPRINTF_COMPAT_H_ */

View file

@ -24,263 +24,598 @@
#ifndef CRITERION_ASSERT_H_
# define CRITERION_ASSERT_H_
# include <string.h>
# include <stdlib.h>
# include <stdbool.h>
# include "preprocess.h"
# include "asprintf-compat.h"
# ifdef __cplusplus
# include <cstring>
# include <cstdlib>
# include <algorithm>
# else
# include <string.h>
# include <stdlib.h>
# include <stdbool.h>
# endif
# include "designated-initializer-compat.h"
# include "types.h"
# include "stats.h"
# include "hooks.h"
# include "event.h"
# include "abort.h"
enum criterion_assert_kind {
NORMAL,
FATAL
};
struct criterion_assert_args {
const char *msg;
const char *default_msg;
int sentinel_;
#ifdef __cplusplus
constexpr criterion_assert_args(const char *msg) : msg(msg), sentinel_(0) {}
constexpr criterion_assert_args(const char *msg, int sentinel_) : msg(msg), sentinel_(sentinel_) {}
#endif
};
# define cr_assert_impl(Kind, Condition, ...) \
do { \
struct criterion_assert_args args = { \
__VA_ARGS__ \
}; \
int passed = !!(Condition); \
struct criterion_assert_stats stat = { \
.kind = (Kind), \
.condition = #Condition, \
.message = args.msg ? args.msg \
: (args.default_msg ? args.default_msg : ""), \
.passed = passed, \
.file = __FILE__, \
.line = __LINE__, \
}; \
send_event(ASSERT, &stat, sizeof (stat)); \
if (!passed && (Kind) == FATAL) \
criterion_abort_test(); \
} while (0)
// Do NOT reorder unless you want to break the ABI
enum criterion_assert_messages {
CRITERION_ASSERT_MSG_FAIL,
CRITERION_ASSERT_MSG_EXPR_FALSE,
CRITERION_ASSERT_MSG_EXPR_AS_STRINGS_FALSE,
CRITERION_ASSERT_MSG_IS_NULL,
CRITERION_ASSERT_MSG_IS_NOT_NULL,
CRITERION_ASSERT_MSG_IS_EMPTY,
CRITERION_ASSERT_MSG_IS_NOT_EMPTY,
CRITERION_ASSERT_MSG_FILE_STR_MATCH,
CRITERION_ASSERT_MSG_FILE_MATCH,
CRITERION_ASSERT_MSG_THROW,
CRITERION_ASSERT_MSG_NO_THROW,
CRITERION_ASSERT_MSG_ANY_THROW,
CRITERION_ASSERT_MSG_NONE_THROW,
};
// Common asserts
CR_BEGIN_C_API
# define cr_abort_test(Message) \
cr_assert(0, \
.default_msg = "The conditions for this test were not met.", \
.msg = (Message) \
)
CR_API char *translate_assert_msg(int msg_index, ...);
# define cr_assert(...) cr_assert_(__VA_ARGS__, .sentinel_ = 0)
CR_END_C_API
# define cr_expect(...) cr_expect_(__VA_ARGS__, .sentinel_ = 0)
# define CR_GET_CONDITION(Condition, ...) Condition
# define CR_GET_CONDITION_STR(Condition, ...) #Condition
# define CR_VA_SKIP(_, ...) __VA_ARGS__
# define cr_assert_(Condition, ...) cr_assert_impl(FATAL, Condition, __VA_ARGS__)
# define cr_expect_(Condition, ...) cr_assert_impl(NORMAL, Condition, __VA_ARGS__)
# ifdef __cplusplus
# define CR_STDN std::
# else
# define CR_STDN
# endif
# define cr_assert_not(...) cr_assert_not_(__VA_ARGS__, .sentinel_ = 0)
# define cr_expect_not(...) cr_expect_not_(__VA_ARGS__, .sentinel_ = 0)
# define CR_TRANSLATE_DEF_MSG__(Arg) \
CR_IDENTITY Arg
# define cr_assert_not_(Condition, ...) \
cr_assert_impl(FATAL, !(Condition), __VA_ARGS__)
# define cr_expect_not_(Condition, ...) \
cr_expect_impl(NORMAL, !(Condition), __VA_ARGS__)
# define CR_TRANSLATE_DEF_MSG_(...) \
CR_EXPAND(translate_assert_msg( \
CR_VA_HEAD(__VA_ARGS__), \
"" CR_TRANSLATE_DEF_MSG__(CR_VA_HEAD(CR_VA_TAIL(__VA_ARGS__))) \
))
// Native asserts
# define CR_INIT_STATS_(BufSize, MsgVar, ...) CR_EXPAND( \
do { \
char *def_msg = CR_EXPAND(CR_TRANSLATE_DEF_MSG_(__VA_ARGS__)); \
char *formatted_msg = NULL; \
int msglen = cr_asprintf(&formatted_msg, \
"" CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__))); \
if (formatted_msg && *formatted_msg) { \
MsgVar = formatted_msg; \
CR_STDN free(def_msg); \
} else { \
MsgVar = def_msg; \
msglen = strlen(def_msg); \
CR_STDN free(formatted_msg); \
} \
\
BufSize = sizeof(struct criterion_assert_stats) \
+ sizeof (size_t) + msglen + 1; \
\
char *buf = (char*) CR_STDN malloc(BufSize); \
stat = (struct criterion_assert_stats*) buf; \
CR_STDN memset(buf, 0, sizeof (struct criterion_assert_stats)); \
buf += sizeof (struct criterion_assert_stats); \
*((size_t*) buf) = msglen + 1; \
buf += sizeof (size_t); \
CR_STDN strcpy(buf, MsgVar); \
CR_STDN free(MsgVar); \
} while (0))
# define cr_assert_op_(Op, Actual, Expected, ...) \
cr_assert_impl(FATAL, (Actual) Op (Expected), __VA_ARGS__)
# define cr_expect_op_(Op, Actual, Expected, ...) \
cr_assert_impl(NORMAL, (Actual) Op (Expected), __VA_ARGS__)
# define cr_assert_eq(...) cr_assert_op_(==, __VA_ARGS__, .sentinel_ = 0)
# define cr_expect_eq(...) cr_expect_op_(==, __VA_ARGS__, .sentinel_ = 0)
# define cr_assert_neq(...) cr_assert_op_(!=, __VA_ARGS__, .sentinel_ = 0)
# define cr_expect_neq(...) cr_expect_op_(!=, __VA_ARGS__, .sentinel_ = 0)
# define cr_assert_lt(...) cr_assert_op_(<, __VA_ARGS__, .sentinel_ = 0)
# define cr_expect_lt(...) cr_expect_op_(<, __VA_ARGS__, .sentinel_ = 0)
# define cr_assert_gt(...) cr_assert_op_(>, __VA_ARGS__, .sentinel_ = 0)
# define cr_expect_gt(...) cr_expect_op_(>, __VA_ARGS__, .sentinel_ = 0)
# define cr_assert_leq(...) cr_assert_op_(<=, __VA_ARGS__, .sentinel_ = 0)
# define cr_expect_leq(...) cr_expect_op_(<=, __VA_ARGS__, .sentinel_ = 0)
# define cr_assert_geq(...) cr_assert_op_(>=, __VA_ARGS__, .sentinel_ = 0)
# define cr_expect_geq(...) cr_expect_op_(>=, __VA_ARGS__, .sentinel_ = 0)
# define cr_assert_null_(Value, ...) \
cr_assert_impl(FATAL, (Value) == NULL, __VA_ARGS__)
# define cr_expect_null_(Value, ...) \
cr_assert_impl(NORMAL, (Value) == NULL, __VA_ARGS__)
# define cr_assert_null(...) cr_assert_null_(__VA_ARGS__, .sentinel_ = 0)
# define cr_expect_null(...) cr_expect_null_(__VA_ARGS__, .sentinel_ = 0)
# define cr_assert_not_null_(Value, ...) \
cr_assert_impl(FATAL, (Value) != NULL, __VA_ARGS__)
# define cr_expect_not_null_(Value, ...) \
cr_assert_impl(NORMAL, (Value) != NULL, __VA_ARGS__)
# define cr_assert_not_null(...) cr_assert_not_null_(__VA_ARGS__, .sentinel_ = 0)
# define cr_expect_not_null(...) cr_expect_not_null_(__VA_ARGS__, .sentinel_ = 0)
// Floating-point asserts
# define cr_assert_float_eq(...) \
cr_assert_float_eq_(__VA_ARGS__, .sentinel_ = 0)
# define cr_expect_float_eq(...) \
cr_expect_float_eq_(__VA_ARGS__, .sentinel_ = 0)
# define cr_assert_float_eq_(Actual, Expected, Epsilon, ...) \
cr_assert_impl(FATAL, (Expected) - (Actual) <= (Epsilon) \
&& (Actual) - (Expected) <= (Epsilon), \
__VA_ARGS__)
# define cr_expect_float_eq_(Actual, Expected, Epsilon, ...) \
cr_assert_impl(NORMAL, (Expected) - (Actual) <= (Epsilon) \
&& (Actual) - (Expected) <= (Epsilon), \
__VA_ARGS__)
# define cr_assert_float_neq(...) \
cr_assert_float_neq_(__VA_ARGS__, .sentinel_ = 0)
# define cr_expect_float_neq(...) \
cr_expect_float_neq_(__VA_ARGS__, .sentinel_ = 0)
# define cr_assert_float_neq_(Actual, Expected, Epsilon, ...) \
cr_assert_impl(FATAL, (Expected) - (Actual) > (Epsilon) \
|| (Actual) - (Expected) > (Epsilon), \
__VA_ARGS__)
# define cr_expect_float_neq_(Actual, Expected, Epsilon, ...) \
cr_assert_impl(NORMAL, (Expected) - (Actual) > (Epsilon) \
|| (Actual) - (Expected) > (Epsilon), \
__VA_ARGS__)
// String asserts
# define cr_assert_strings_(Op, Actual, Expected, ...) \
cr_assert_impl(FATAL, strcmp((Actual), (Expected)) Op 0, __VA_ARGS__)
# define cr_expect_strings_(Op, Actual, Expected, ...) \
cr_assert_impl(NORMAL, strcmp((Actual), (Expected)) Op 0, __VA_ARGS__)
# define cr_assert_strings_eq(...) \
cr_assert_strings_(==, __VA_ARGS__, .sentinel_ = 0)
# define cr_expect_strings_eq(...) \
cr_expect_strings_(==, __VA_ARGS__, .sentinel_ = 0)
# define cr_assert_strings_neq(...) \
cr_assert_strings_(!=, __VA_ARGS__, .sentinel_ = 0)
# define cr_expect_strings_neq(...) \
cr_expect_strings_(!=, __VA_ARGS__, .sentinel_ = 0)
# define cr_assert_strings_gt(...) cr_assert_strings_(>, __VA_ARGS__, .sentinel_ = 0)
# define cr_expect_strings_gt(...) cr_expect_strings_(>, __VA_ARGS__, .sentinel_ = 0)
# define cr_assert_strings_lt(...) cr_assert_strings_(<, __VA_ARGS__, .sentinel_ = 0)
# define cr_expect_strings_lt(...) cr_expect_strings_(<, __VA_ARGS__, .sentinel_ = 0)
# define cr_assert_strings_leq(...) cr_assert_strings_(<=, __VA_ARGS__, .sentinel_ = 0)
# define cr_expect_strings_leq(...) cr_expect_strings_(<=, __VA_ARGS__, .sentinel_ = 0)
# define cr_assert_strings_geq(...) cr_assert_strings_(>=, __VA_ARGS__, .sentinel_ = 0)
# define cr_expect_strings_geq(...) cr_expect_strings_(>=, __VA_ARGS__, .sentinel_ = 0)
// Array asserts
# define cr_assert_arrays_eq(...) \
cr_assert_arrays_eq_(__VA_ARGS__, .sentinel_ = 0)
# define cr_expect_arrays_eq(...) \
cr_expect_arrays_eq_(__VA_ARGS__, .sentinel_ = 0)
# define cr_assert_arrays_neq(...) \
cr_assert_arrays_neq_(__VA_ARGS__, .sentinel_ = 0)
# define cr_expect_arrays_neq(...) \
cr_expect_arrays_neq_(__VA_ARGS__, .sentinel_ = 0)
# define cr_assert_arrays_eq_(A, B, Size, ...) \
cr_assert_impl(FATAL, !memcmp((A), (B), (Size)), \
.default_msg = "Arrays are not equal.", \
__VA_ARGS__)
# define cr_expect_arrays_eq_(A, B, Size, ...) \
cr_assert_impl(NORMAL, !memcmp((A), (B), (Size)), \
.default_msg = "Arrays are not equal.", \
__VA_ARGS__)
# define cr_assert_arrays_neq_(A, B, Size, ...) \
cr_assert_impl(FATAL, memcmp((A), (B), (Size)), \
.default_msg = "Arrays are equal", \
__VA_ARGS__)
# define cr_expect_arrays_neq_(A, B, Size, ...) \
cr_assert_impl(NORMAL, memcmp((A), (B), (Size)), \
.default_msg = "Arrays are equal", \
__VA_ARGS__)
# define CR_FAIL_ABORT_ criterion_abort_test
# define CR_FAIL_CONTINUES_ criterion_continue_test
# ifdef __GNUC__
# define CRIT_ARR_COMPARE_(A, B, Size, Cmp, Result) \
__typeof__(&(A)[0]) first = (A); \
__typeof__(&(B)[0]) second = (B); \
int equals = 1; \
size_t i, size; \
for (i = 0, size = (Size); equals && i < size; ++i) \
equals = equals && !Cmp(first + i, second + i)
// We disable the format-zero-length warning because we use the validity of
// asprintf(out, "") for empty assertion messages
# pragma GCC diagnostic ignored "-Wformat-zero-length"
# endif
# define cr_assert_arrays_eq_cmp_(A, B, Size, Cmp, ...) \
do { \
CRIT_ARR_COMPARE_(A, B, Size, Cmp, equals); \
cr_assert_impl(FATAL, equals, \
.default_msg = "Arrays are not equal", \
__VA_ARGS__); \
# define cr_assert_impl(Fail, Condition, ...) \
do { \
bool passed = !!(Condition); \
\
char *msg = NULL; \
size_t bufsize; \
\
struct criterion_assert_stats *stat; \
CR_EXPAND(CR_INIT_STATS_(bufsize, msg, CR_VA_TAIL(__VA_ARGS__))); \
stat->passed = passed; \
stat->file = __FILE__; \
stat->line = __LINE__; \
\
send_event(ASSERT, stat, bufsize); \
CR_STDN free(stat); \
\
if (!passed) \
Fail(); \
} while (0)
# define cr_expect_arrays_eq_cmp_(A, B, Size, Cmp, ...) \
do { \
CRIT_ARR_COMPARE_(A, B, Size, Cmp, equals); \
cr_assert_impl(NORMAL, equals, \
.default_msg = "Arrays are not equal", \
__VA_ARGS__); \
// Base assertions
# define cr_fail(Fail, ...) \
CR_EXPAND(cr_assert_impl( \
Fail, \
0, \
dummy, \
CRITERION_ASSERT_MSG_FAIL, \
(), \
__VA_ARGS__ \
))
# define cr_assert_fail(...) CR_EXPAND(cr_fail(CR_FAIL_ABORT_, __VA_ARGS__))
# define cr_expect_fail(...) CR_EXPAND(cr_fail(CR_FAIL_CONTINUES_, __VA_ARGS__))
# define cr_assert(...) \
CR_EXPAND(cr_assert_impl( \
CR_FAIL_ABORT_, \
CR_VA_HEAD(__VA_ARGS__), \
dummy, \
CRITERION_ASSERT_MSG_EXPR_FALSE, \
(CR_STR(CR_VA_HEAD(__VA_ARGS__))), \
CR_VA_TAIL(__VA_ARGS__) \
))
# define cr_expect(...) \
CR_EXPAND(cr_assert_impl( \
CR_FAIL_CONTINUES_, \
CR_VA_HEAD(__VA_ARGS__), \
dummy, \
CRITERION_ASSERT_MSG_EXPR_FALSE, \
(CR_STR(CR_VA_HEAD(__VA_ARGS__))), \
CR_VA_TAIL(__VA_ARGS__) \
))
# define cr_assert_not(...) \
CR_EXPAND(cr_assert_impl( \
CR_FAIL_ABORT_, \
!(CR_VA_HEAD(__VA_ARGS__)), \
dummy, \
CRITERION_ASSERT_MSG_EXPR_FALSE, \
(CR_STR(!(CR_VA_HEAD(__VA_ARGS__)))), \
CR_VA_TAIL(__VA_ARGS__) \
))
# define cr_expect_not(...) \
CR_EXPAND(cr_assert_impl( \
CR_FAIL_CONTINUES_, \
!(CR_VA_HEAD(__VA_ARGS__)), \
dummy, \
CRITERION_ASSERT_MSG_EXPR_FALSE, \
(CR_STR(!(CR_VA_HEAD(__VA_ARGS__)))), \
CR_VA_TAIL(__VA_ARGS__) \
))
// Common binary assertions
# define cr_assert_op_(Fail, Op, Actual, Expected, ...) \
CR_EXPAND(cr_assert_impl( \
Fail, \
(Actual) Op (Expected), \
dummy, \
CRITERION_ASSERT_MSG_EXPR_FALSE, \
(CR_STR((Actual) Op (Expected))), \
__VA_ARGS__ \
))
# define cr_assert_op_va_(Fail, Op, ...) \
CR_EXPAND(cr_assert_op_( \
Fail, \
Op, \
CR_VA_HEAD(__VA_ARGS__), \
CR_VA_HEAD(CR_VA_TAIL(__VA_ARGS__)), \
CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__)) \
))
# define cr_assert_eq(...) CR_EXPAND(cr_assert_op_va_(CR_FAIL_ABORT_, ==, __VA_ARGS__))
# define cr_expect_eq(...) CR_EXPAND(cr_assert_op_va_(CR_FAIL_CONTINUES_, ==, __VA_ARGS__))
# define cr_assert_neq(...) CR_EXPAND(cr_assert_op_va_(CR_FAIL_ABORT_, !=, __VA_ARGS__))
# define cr_expect_neq(...) CR_EXPAND(cr_assert_op_va_(CR_FAIL_CONTINUES_, !=, __VA_ARGS__))
# define cr_assert_lt(...) CR_EXPAND(cr_assert_op_va_(CR_FAIL_ABORT_, <, __VA_ARGS__))
# define cr_expect_lt(...) CR_EXPAND(cr_assert_op_va_(CR_FAIL_CONTINUES_, <, __VA_ARGS__))
# define cr_assert_leq(...) CR_EXPAND(cr_assert_op_va_(CR_FAIL_ABORT_, <=, __VA_ARGS__))
# define cr_expect_leq(...) CR_EXPAND(cr_assert_op_va_(CR_FAIL_CONTINUES_, <=, __VA_ARGS__))
# define cr_assert_gt(...) CR_EXPAND(cr_assert_op_va_(CR_FAIL_ABORT_, >, __VA_ARGS__))
# define cr_expect_gt(...) CR_EXPAND(cr_assert_op_va_(CR_FAIL_CONTINUES_, >, __VA_ARGS__))
# define cr_assert_geq(...) CR_EXPAND(cr_assert_op_va_(CR_FAIL_ABORT_, >=, __VA_ARGS__))
# define cr_expect_geq(...) CR_EXPAND(cr_assert_op_va_(CR_FAIL_CONTINUES_, >=, __VA_ARGS__))
// Common unary assertions
# define cr_assert_null_op_(Fail, Op, Msg, Value, ...) \
CR_EXPAND(cr_assert_impl( \
Fail, \
(Value) Op NULL, \
dummy, \
Msg, \
(CR_STR(Value)), \
__VA_ARGS__ \
))
# define cr_assert_null_op_va_(Fail, Op, Msg, ...) \
CR_EXPAND(cr_assert_null_op_( \
Fail, \
Op, \
Msg, \
CR_VA_HEAD(__VA_ARGS__), \
CR_VA_TAIL(__VA_ARGS__) \
))
# define cr_assert_null(...) CR_EXPAND(cr_assert_null_op_va_(CR_FAIL_ABORT_, ==, CRITERION_ASSERT_MSG_IS_NOT_NULL, __VA_ARGS__))
# define cr_expect_null(...) CR_EXPAND(cr_assert_null_op_va_(CR_FAIL_CONTINUES_, ==, CRITERION_ASSERT_MSG_IS_NOT_NULL, __VA_ARGS__))
# define cr_assert_not_null(...) CR_EXPAND(cr_assert_null_op_va_(CR_FAIL_ABORT_, !=, CRITERION_ASSERT_MSG_IS_NULL, __VA_ARGS__))
# define cr_expect_not_null(...) CR_EXPAND(cr_assert_null_op_va_(CR_FAIL_CONTINUES_, !=, CRITERION_ASSERT_MSG_IS_NULL, __VA_ARGS__))
// Floating-point assertions
# define cr_assert_float_eq_op_(Actual, Expected, Epsilon) \
(Expected) - (Actual) <= (Epsilon) && (Actual) - (Expected) <= (Epsilon)
# define cr_assert_float_neq_op_(Actual, Expected, Epsilon) \
(Expected) - (Actual) > (Epsilon) || (Actual) - (Expected) > (Epsilon)
# define cr_assert_float_op_(Fail, Op, Actual, Expected, Epsilon, ...) \
CR_EXPAND(cr_assert_impl( \
Fail, \
Op(Actual, Expected, Epsilon), \
dummy, \
CRITERION_ASSERT_MSG_EXPR_FALSE, \
(CR_STR(Op(Actual, Expected, Epsilon))), \
__VA_ARGS__ \
))
# define cr_assert_float_op_va_(Fail, Op, ...) \
CR_EXPAND(cr_assert_float_op_( \
Fail, \
Op, \
CR_VA_HEAD(__VA_ARGS__), \
CR_VA_HEAD(CR_VA_TAIL(__VA_ARGS__)), \
CR_VA_HEAD(CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__))), \
CR_VA_TAIL(CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__))) \
))
# define cr_assert_float_eq(...) CR_EXPAND(cr_assert_float_op_va_(CR_FAIL_ABORT_, cr_assert_float_eq_op_, __VA_ARGS__))
# define cr_expect_float_eq(...) CR_EXPAND(cr_assert_float_op_va_(CR_FAIL_CONTINUES_, cr_assert_float_eq_op_, __VA_ARGS__))
# define cr_assert_float_neq(...) CR_EXPAND(cr_assert_float_op_va_(CR_FAIL_ABORT_, cr_assert_float_neq_op_, __VA_ARGS__))
# define cr_expect_float_neq(...) CR_EXPAND(cr_assert_float_op_va_(CR_FAIL_CONTINUES_, cr_assert_float_neq_op_, __VA_ARGS__))
// String assertions
# define cr_assert_str_op_empty_(Fail, Op, Msg, Value, ...) \
CR_EXPAND(cr_assert_impl( \
Fail, \
(Value)[0] Op '\0', \
dummy, \
Msg, \
(CR_STR(Value)), \
__VA_ARGS__ \
))
# define cr_assert_str_op_empty_va_(Fail, Op, Msg, ...) \
CR_EXPAND(cr_assert_str_op_empty_( \
Fail, \
Op, \
Msg, \
CR_VA_HEAD(__VA_ARGS__), \
CR_VA_TAIL(__VA_ARGS__) \
))
# define cr_assert_str_empty(...) CR_EXPAND(cr_assert_str_op_empty_va_(CR_FAIL_ABORT_, ==, CRITERION_ASSERT_MSG_IS_NOT_EMPTY, __VA_ARGS__))
# define cr_expect_str_empty(...) CR_EXPAND(cr_assert_str_op_empty_va_(CR_FAIL_CONTINUES_, ==, CRITERION_ASSERT_MSG_IS_NOT_EMPTY, __VA_ARGS__))
# define cr_assert_str_not_empty(...) CR_EXPAND(cr_assert_str_op_empty_va_(CR_FAIL_ABORT_, !=, CRITERION_ASSERT_MSG_IS_EMPTY, __VA_ARGS__))
# define cr_expect_str_not_empty(...) CR_EXPAND(cr_assert_str_op_empty_va_(CR_FAIL_CONTINUES_, !=, CRITERION_ASSERT_MSG_IS_EMPTY, __VA_ARGS__))
# define cr_assert_str_op_(Fail, Op, Actual, Expected, ...) \
CR_EXPAND(cr_assert_impl( \
Fail, \
CR_STDN strcmp((Actual), (Expected)) Op 0, \
dummy, \
CRITERION_ASSERT_MSG_EXPR_AS_STRINGS_FALSE, \
(CR_STR((Actual) Op (Expected))), \
__VA_ARGS__ \
))
# define cr_assert_str_op_va_(Fail, Op, ...) \
CR_EXPAND(cr_assert_str_op_( \
Fail, \
Op, \
CR_VA_HEAD(__VA_ARGS__), \
CR_VA_HEAD(CR_VA_TAIL(__VA_ARGS__)), \
CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__)) \
))
# define cr_assert_str_eq(...) CR_EXPAND(cr_assert_str_op_va_(CR_FAIL_ABORT_, ==, __VA_ARGS__))
# define cr_expect_str_eq(...) CR_EXPAND(cr_assert_str_op_va_(CR_FAIL_CONTINUES_, ==, __VA_ARGS__))
# define cr_assert_str_neq(...) CR_EXPAND(cr_assert_str_op_va_(CR_FAIL_ABORT_, !=, __VA_ARGS__))
# define cr_expect_str_neq(...) CR_EXPAND(cr_assert_str_op_va_(CR_FAIL_CONTINUES_, !=, __VA_ARGS__))
# define cr_assert_str_lt(...) CR_EXPAND(cr_assert_str_op_va_(CR_FAIL_ABORT_, <, __VA_ARGS__))
# define cr_expect_str_lt(...) CR_EXPAND(cr_assert_str_op_va_(CR_FAIL_CONTINUES_, <, __VA_ARGS__))
# define cr_assert_str_leq(...) CR_EXPAND(cr_assert_str_op_va_(CR_FAIL_ABORT_, <=, __VA_ARGS__))
# define cr_expect_str_leq(...) CR_EXPAND(cr_assert_str_op_va_(CR_FAIL_CONTINUES_, <=, __VA_ARGS__))
# define cr_assert_str_gt(...) CR_EXPAND(cr_assert_str_op_va_(CR_FAIL_ABORT_, >, __VA_ARGS__))
# define cr_expect_str_gt(...) CR_EXPAND(cr_assert_str_op_va_(CR_FAIL_CONTINUES_, >, __VA_ARGS__))
# define cr_assert_str_geq(...) CR_EXPAND(cr_assert_str_op_va_(CR_FAIL_ABORT_, >=, __VA_ARGS__))
# define cr_expect_str_geq(...) CR_EXPAND(cr_assert_str_op_va_(CR_FAIL_CONTINUES_, >=, __VA_ARGS__))
// Array assertions
# define cr_assert_mem_op_(Fail, Op, Actual, Expected, Size, ...) \
CR_EXPAND(cr_assert_impl( \
Fail, \
CR_STDN memcmp((Actual), (Expected), (Size)) Op 0, \
dummy, \
CRITERION_ASSERT_MSG_EXPR_FALSE, \
(CR_STR((Actual)[0 .. Size] Op (Expected)[0 .. Size])), \
__VA_ARGS__ \
))
# define cr_assert_mem_op_va_(Fail, Op, ...) \
CR_EXPAND(cr_assert_mem_op_( \
Fail, \
Op, \
CR_VA_HEAD(__VA_ARGS__), \
CR_VA_HEAD(CR_VA_TAIL(__VA_ARGS__)), \
CR_VA_HEAD(CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__))), \
CR_VA_TAIL(CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__))) \
))
# define cr_assert_arr_eq(...) CR_EXPAND(cr_assert_mem_op_va_(CR_FAIL_ABORT_, ==, __VA_ARGS__))
# define cr_expect_arr_eq(...) CR_EXPAND(cr_assert_mem_op_va_(CR_FAIL_CONTINUES_, ==, __VA_ARGS__))
# define cr_assert_arr_neq(...) CR_EXPAND(cr_assert_mem_op_va_(CR_FAIL_ABORT_, !=, __VA_ARGS__))
# define cr_expect_arr_neq(...) CR_EXPAND(cr_assert_mem_op_va_(CR_FAIL_CONTINUES_, !=, __VA_ARGS__))
// Safe array comparison assertions
# if defined(__GNUC__) || defined(__cplusplus)
# ifdef __cplusplus
# define CR_ARR_COMPARE_(A, B, Size, Cmp, Result) \
int Result = std::lexicographical_compare((A), (A) + Size, (B), (B) + Size, Cmp)
# else
# define CR_ARR_COMPARE_(A, B, Size, Cmp, Result) \
__typeof__(&(A)[0]) first = (A); \
__typeof__(&(B)[0]) second = (B); \
int Result = 0; \
size_t i, size; \
for (i = 0, size = (Size); !Result && i < size; ++i) \
Result = Cmp(first + i, second + i)
# endif
# define cr_assert_arr_op_cmp_(Fail, Op, Actual, Expected, Size, Cmp, ...) \
do { \
CR_ARR_COMPARE_(Actual, Expected, Size, Cmp, order); \
CR_EXPAND(cr_assert_impl( \
Fail, \
order Op 0, \
dummy, \
CRITERION_ASSERT_MSG_EXPR_FALSE, \
(CR_STR((Actual)[0 .. Size] Op (Expected)[0 .. Size])), \
__VA_ARGS__ \
)); \
} while (0)
# define cr_assert_arrays_eq_cmp(...) \
cr_assert_arrays_eq_cmp_(__VA_ARGS__, .sentinel_ = 0)
# define cr_expect_arrays_eq_cmp(...) \
cr_expect_arrays_eq_cmp_(__VA_ARGS__, .sentinel_ = 0)
# define cr_assert_arr_op_cmp_va_(Fail, Op, ...) \
CR_EXPAND(cr_assert_arr_op_cmp_( \
Fail, \
Op, \
CR_VA_HEAD(__VA_ARGS__), \
CR_VA_HEAD(CR_VA_TAIL(__VA_ARGS__)), \
CR_VA_HEAD(CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__))), \
CR_VA_HEAD(CR_VA_TAIL(CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__)))), \
CR_VA_TAIL(CR_VA_TAIL(CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__)))) \
))
# define cr_assert_arrays_neq_cmp_(A, B, Size, Cmp, ...) \
do { \
CRIT_ARR_COMPARE_(A, B, Size, Cmp, equals); \
cr_assert_impl(FATAL, !equals, \
.default_msg = "Arrays not equal", \
__VA_ARGS__); \
} while (0)
# define cr_assert_arr_eq_cmp(...) CR_EXPAND(cr_assert_arr_op_cmp_va_(CR_FAIL_ABORT_, ==, __VA_ARGS__))
# define cr_expect_arr_eq_cmp(...) CR_EXPAND(cr_assert_arr_op_cmp_va_(CR_FAIL_CONTINUES_, ==, __VA_ARGS__))
# define cr_expect_arrays_neq_cmp_(A, B, Size, Cmp, ...) \
do { \
CRIT_ARR_COMPARE_(A, B, Size, Cmp, equals); \
cr_assert_impl(NORMAL, equals, \
.default_msg = "Arrays not equal", \
__VA_ARGS__); \
} while (0)
# define cr_assert_arr_neq_cmp(...) CR_EXPAND(cr_assert_arr_op_cmp_va_(CR_FAIL_ABORT_, !=, __VA_ARGS__))
# define cr_expect_arr_neq_cmp(...) CR_EXPAND(cr_assert_arr_op_cmp_va_(CR_FAIL_CONTINUES_, !=, __VA_ARGS__))
# define cr_assert_arrays_neq_cmp(...) \
cr_assert_arrays_eq_cmp_(__VA_ARGS__, .sentinel_ = 0)
# define cr_expect_arrays_neq_cmp(...) \
cr_expect_arrays_eq_cmp_(__VA_ARGS__, .sentinel_ = 0)
# endif /* !__GNUC__ */
# define cr_assert_arr_lt_cmp(...) CR_EXPAND(cr_assert_arr_op_cmp_va_(CR_FAIL_ABORT_, <, __VA_ARGS__))
# define cr_expect_arr_lt_cmp(...) CR_EXPAND(cr_assert_arr_op_cmp_va_(CR_FAIL_CONTINUES_, <, __VA_ARGS__))
// The section below is here for backward compatibility purposes.
// It shall be removed in the text major version of Criterion
# ifndef CRITERION_NO_COMPAT
# define cr_assert_arr_leq_cmp(...) CR_EXPAND(cr_assert_arr_op_cmp_va_(CR_FAIL_ABORT_, <=, __VA_ARGS__))
# define cr_expect_arr_leq_cmp(...) CR_EXPAND(cr_assert_arr_op_cmp_va_(CR_FAIL_CONTINUES_, <=, __VA_ARGS__))
# define CRITERION_ASSERT_DEPRECATED_(Name) CRITERION_ASSERT_DEPRECATED__( \
message \
"The `" #Name "` macro is deprecated, " \
"please use `cr_" #Name "` instead." \
# define cr_assert_arr_gt_cmp(...) CR_EXPAND(cr_assert_arr_op_cmp_va_(CR_FAIL_ABORT_, >, __VA_ARGS__))
# define cr_expect_arr_gt_cmp(...) CR_EXPAND(cr_assert_arr_op_cmp_va_(CR_FAIL_CONTINUES_, >, __VA_ARGS__))
# define cr_assert_arr_geq_cmp(...) CR_EXPAND(cr_assert_arr_op_cmp_va_(CR_FAIL_ABORT_, >=, __VA_ARGS__))
# define cr_expect_arr_geq_cmp(...) CR_EXPAND(cr_assert_arr_op_cmp_va_(CR_FAIL_CONTINUES_, >=, __VA_ARGS__))
# else
# define CRITERION_GNUC_WARN__(Msg) \
_Pragma(#Msg)
# define CRITERION_GNUC_WARN_(Name) CRITERION_GNUC_WARN__( \
message \
"The `" #Name "` macro is only available on GNU C compilers." \
)
# define cr_assert_arr_eq_cmp(...) CRITERION_GNUC_WARN_(cr_assert_arr_eq_cmp) CR_NOOP
# define cr_expect_arr_eq_cmp(...) CRITERION_GNUC_WARN_(cr_expect_arr_eq_cmp) CR_NOOP
# define cr_assert_arr_neq_cmp(...) CRITERION_GNUC_WARN_(cr_assert_arr_neq_cmp) CR_NOOP
# define cr_expect_arr_neq_cmp(...) CRITERION_GNUC_WARN_(cr_expect_arr_neq_cmp) CR_NOOP
# define cr_assert_arr_lt_cmp(...) CRITERION_GNUC_WARN_(cr_assert_arr_lt_cmp) CR_NOOP
# define cr_expect_arr_lt_cmp(...) CRITERION_GNUC_WARN_(cr_expect_arr_lt_cmp) CR_NOOP
# define cr_assert_arr_leq_cmp(...) CRITERION_GNUC_WARN_(cr_assert_arr_leq_cmp) CR_NOOP
# define cr_expect_arr_leq_cmp(...) CRITERION_GNUC_WARN_(cr_expect_arr_leq_cmp) CR_NOOP
# define cr_assert_arr_gt_cmp(...) CRITERION_GNUC_WARN_(cr_assert_arr_gt_cmp) CR_NOOP
# define cr_expect_arr_gt_cmp(...) CRITERION_GNUC_WARN_(cr_expect_arr_gt_cmp) CR_NOOP
# define cr_assert_arr_geq_cmp(...) CRITERION_GNUC_WARN_(cr_assert_arr_geq_cmp) CR_NOOP
# define cr_expect_arr_geq_cmp(...) CRITERION_GNUC_WARN_(cr_expect_arr_geq_cmp) CR_NOOP
# endif
# ifdef __cplusplus
# define cr_assert_throw_abort_(Fail, Msg, MsgArgs, ...) \
CR_EXPAND(cr_assert_impl( \
Fail, \
0, \
dummy, \
Msg, \
MsgArgs, \
CR_VA_TAIL(__VA_ARGS__) \
))
# define cr_assert_throw_(Fail, Statement, Exception, ...) \
try { \
Statement; \
} catch (Exception const &) { \
} catch (...) { \
CR_EXPAND(cr_assert_throw_abort_( \
Fail, \
CRITERION_ASSERT_MSG_NO_THROW, \
(CR_STR(Statement), CR_STR(Exception)), \
__VA_ARGS__)); \
}
# define cr_assert_throw_va_(...) \
CR_EXPAND(cr_assert_throw_( \
CR_VA_HEAD(__VA_ARGS__), \
CR_VA_HEAD(CR_VA_TAIL(__VA_ARGS__)), \
CR_VA_HEAD(CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__))), \
dummy, \
CR_VA_TAIL(CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__))) \
))
# define cr_assert_throw(...) CR_EXPAND(cr_assert_throw_va_(CR_FAIL_ABORT_, __VA_ARGS__))
# define cr_expect_throw(...) CR_EXPAND(cr_assert_throw_va_(CR_FAIL_CONTINUES_, __VA_ARGS__))
# define cr_assert_no_throw_(Fail, Statement, Exception, ...) \
try { \
Statement; \
} catch (Exception const &) { \
CR_EXPAND(cr_assert_throw_abort_( \
Fail, \
CRITERION_ASSERT_MSG_THROW, \
(CR_STR(Statement), CR_STR(Exception)), \
__VA_ARGS__)); \
}
# define cr_assert_no_throw_va_(...) \
CR_EXPAND(cr_assert_no_throw_( \
CR_VA_HEAD(__VA_ARGS__), \
CR_VA_HEAD(CR_VA_TAIL(__VA_ARGS__)), \
CR_VA_HEAD(CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__))), \
dummy, \
CR_VA_TAIL(CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__))) \
))
# define cr_assert_no_throw(...) CR_EXPAND(cr_assert_no_throw_va_(CR_FAIL_ABORT_, __VA_ARGS__))
# define cr_expect_no_throw(...) CR_EXPAND(cr_assert_no_throw_va_(CR_FAIL_CONTINUES_, __VA_ARGS__))
# define cr_assert_any_throw_(Fail, Statement, ...) \
try { \
Statement; \
CR_EXPAND(cr_assert_throw_abort_( \
Fail, \
CRITERION_ASSERT_MSG_ANY_THROW, \
(CR_STR(Statement)), \
__VA_ARGS__)); \
} catch (...) {}
# define cr_assert_any_throw_va_(...) \
CR_EXPAND(cr_assert_any_throw_( \
CR_VA_HEAD(__VA_ARGS__), \
CR_VA_HEAD(CR_VA_TAIL(__VA_ARGS__)), \
dummy, \
CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__)) \
))
# define cr_assert_any_throw(...) CR_EXPAND(cr_assert_any_throw_va_(CR_FAIL_ABORT_, __VA_ARGS__))
# define cr_expect_any_throw(...) CR_EXPAND(cr_assert_any_throw_va_(CR_FAIL_CONTINUES_, __VA_ARGS__))
# define cr_assert_none_throw_(Fail, Statement, ...) \
try { \
Statement; \
} catch (...) { \
CR_EXPAND(cr_assert_throw_abort_( \
Fail, \
CRITERION_ASSERT_MSG_NONE_THROW, \
(CR_STR(Statement)), \
__VA_ARGS__)); \
}
# define cr_assert_none_throw_va_(...) \
CR_EXPAND(cr_assert_none_throw_( \
CR_VA_HEAD(__VA_ARGS__), \
CR_VA_HEAD(CR_VA_TAIL(__VA_ARGS__)), \
dummy, \
CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__)) \
))
# define cr_assert_none_throw(...) CR_EXPAND(cr_assert_none_throw_va_(CR_FAIL_ABORT_, __VA_ARGS__))
# define cr_expect_none_throw(...) CR_EXPAND(cr_assert_none_throw_va_(CR_FAIL_CONTINUES_, __VA_ARGS__))
# endif
// The section below is here for backward compatibility purposes.
// It shall be removed in the next major version of Criterion
# ifndef CRITERION_NO_COMPAT
# define CRITERION_ASSERT_DEPRECATED_(Name) CRITERION_ASSERT_DEPRECATED__( \
message \
("The `" #Name "` macro is deprecated, " \
"please use `cr_" #Name "` instead.") \
)
# define CRITERION_ASSERT_DEPRECATED_B(Name, Newname) \
CRITERION_ASSERT_DEPRECATED__( \
message \
("The `" #Name "` macro is deprecated, " \
"please use `" #Newname "` instead.") \
)
# ifdef _MSC_VER
# define CRITERION_ASSERT_DEPRECATED__(Msg) \
__pragma(Msg)
# else
# define CRITERION_ASSERT_DEPRECATED__(Msg) \
_Pragma(#Msg)
# endif
# ifndef assert
# define assert(...) CRITERION_ASSERT_DEPRECATED_(assert) cr_assert(__VA_ARGS__)
@ -292,6 +627,22 @@ struct criterion_assert_args {
# endif /* !_ASSERT_H */
# endif /* !assert */
// scheduled for removal after 2.0
# define cr_abort_test(Message) CRITERION_ASSERT_DEPRECATED_B(cr_abort_test, cr_assert_fail) cr_assert_fail(Message)
# define cr_assert_strings_eq(...) CRITERION_ASSERT_DEPRECATED_B(cr_assert_strings_eq, cr_assert_str_eq) cr_assert_str_eq(__VA_ARGS__)
# define cr_assert_strings_neq(...) CRITERION_ASSERT_DEPRECATED_B(cr_assert_strings_neq, cr_assert_str_neq) cr_assert_str_neq(__VA_ARGS__)
# define cr_assert_strings_lt(...) CRITERION_ASSERT_DEPRECATED_B(cr_assert_strings_lt, cr_assert_str_lt) cr_assert_str_lt(__VA_ARGS__)
# define cr_assert_strings_leq(...) CRITERION_ASSERT_DEPRECATED_B(cr_assert_strings_leq, cr_assert_str_leq) cr_assert_str_leq(__VA_ARGS__)
# define cr_assert_strings_gt(...) CRITERION_ASSERT_DEPRECATED_B(cr_assert_strings_gt, cr_assert_str_gt) cr_assert_str_gt(__VA_ARGS__)
# define cr_assert_strings_geq(...) CRITERION_ASSERT_DEPRECATED_B(cr_assert_strings_geq, cr_assert_str_geq) cr_assert_str_geq(__VA_ARGS__)
# define cr_assert_arrays_eq(...) CRITERION_ASSERT_DEPRECATED_B(cr_assert_arrays_eq, cr_assert_arr_eq) cr_assert_arr_eq(__VA_ARGS__)
# define cr_assert_arrays_neq(...) CRITERION_ASSERT_DEPRECATED_B(cr_assert_arrays_neq, cr_assert_arr_neq) cr_assert_arr_neq(__VA_ARGS__)
# define cr_assert_arrays_eq_cmp(...) CRITERION_ASSERT_DEPRECATED_B(cr_assert_arrays_eq_cmp, cr_assert_arr_eq_cmp) cr_assert_arr_eq_cmp(__VA_ARGS__)
# define cr_assert_arrays_neq_cmp(...) CRITERION_ASSERT_DEPRECATED_B(cr_assert_arrays_neq_cmp, cr_assert_arr_neq_cmp) cr_assert_arr_neq_cmp(__VA_ARGS__)
// scheduled for removal at 2.0
# define abort_test(Message) CRITERION_ASSERT_DEPRECATED_(abort_test) cr_abort_test(Message)
# define expect(...) CRITERION_ASSERT_DEPRECATED_(expect) cr_expect(__VA_ARGS__)
# define assert_not(...) CRITERION_ASSERT_DEPRECATED_(assert_not) cr_assert_not(__VA_ARGS__)

View file

@ -24,18 +24,58 @@
#ifndef CRITERION_COMMON_H_
# define CRITERION_COMMON_H_
# if defined(_MSC_VER)
# if _MSC_VER < 1900
# error \
Your version of MSVC++ is too old, please compile your tests using \
a c99 compiler, like MinGW or MSVC 14.0+ (Included in visual studio \
2015)
# endif
# endif
# ifndef CR_IS_MSVC
# ifdef _MSC_VER
# define CR_IS_MSVC _MSC_VER
# else
# define CR_IS_MSVC 0
# endif
# endif
# ifdef __cplusplus
# define CR_ATTRIBUTE(Arg) [[gnu::Arg]]
# define CR_BEGIN_C_API extern "C" {
# define CR_END_C_API }
# else
# define CR_ATTRIBUTE(Arg) __attribute__((Arg))
# define CR_BEGIN_C_API
# define CR_END_C_API
# endif
# ifdef __APPLE__
# define SECTION_START_PREFIX __first
# define SECTION_END_PREFIX __last
# define SECTION_START_SUFFIX(Name) __asm("section$start$__DATA$" Name)
# define SECTION_END_SUFFIX(Name) __asm("section$end$__DATA$" Name)
# define SECTION_(Name) __attribute__((section("__DATA," Name)))
# define SECTION_(Name) CR_ATTRIBUTE(section("__DATA," Name))
# define SECTION_SUFFIX_
# elif CR_IS_MSVC
# define SECTION_START_PREFIX __start
# define SECTION_END_PREFIX __stop
# define SECTION_START_SUFFIX(Name)
# define SECTION_END_SUFFIX(Name)
# define SECTION_(Name) \
__pragma(data_seg(push)) \
__pragma(section(Name, read)) \
__declspec(allocate(Name))
# define SECTION_SUFFIX_ \
__pragma(data_seg(pop))
# else
# define SECTION_START_PREFIX __start
# define SECTION_END_PREFIX __stop
# define SECTION_START_SUFFIX(Name)
# define SECTION_END_SUFFIX(Name)
# define SECTION_(Name) __attribute__((section(Name)))
# define SECTION_(Name) CR_ATTRIBUTE(section(Name))
# define SECTION_SUFFIX_
# endif
# define MAKE_IDENTIFIER_(Prefix, Id) MAKE_IDENTIFIER__(Prefix, Id)
@ -56,8 +96,19 @@
Type *const SECTION_START(Name) = &SECTION_START_(Name); \
Type *const SECTION_END(Name) = &SECTION_END_(Name)
# define UNUSED __attribute__((unused))
# define NORETURN __attribute__((noreturn))
# ifdef __GNUC__
# define UNUSED CR_ATTRIBUTE(unused)
# define NORETURN CR_ATTRIBUTE(noreturn)
# define CR_INLINE CR_ATTRIBUTE(always_inline) inline
# elif CR_IS_MSVC
# define UNUSED
# define NORETURN __declspec(noreturn)
# define CR_INLINE __forceinline
# else
# define UNUSED
# define NORETURN
# define CR_INLINE inline
# endif
# ifdef _WIN32
# define SIZE_T_FORMAT "%Iu"
@ -66,9 +117,34 @@
# endif
# ifdef __GNUC__
# define FORMAT(Archetype, Index, Ftc) __attribute__((format(Archetype, Index, Ftc)))
# define FORMAT(Archetype, Index, Ftc) CR_ATTRIBUTE(format(Archetype, Index, Ftc))
# else
# define FORMAT(Archetype, Index, Ftc)
# endif
# if defined _WIN32 || defined __CYGWIN__
# ifdef CRITERION_BUILDING_DLL
# ifdef __GNUC__
# define CR_API CR_ATTRIBUTE(dllexport)
# else
# define CR_API __declspec(dllexport)
# endif
# else
# ifdef __GNUC__
# define CR_API CR_ATTRIBUTE(dllimport)
# else
# define CR_API __declspec(dllimport)
# endif
# endif
# define CR_LOCAL
# else
# if __GNUC__ >= 4
# define CR_API CR_ATTRIBUTE(visibility("default"))
# define CR_LOCAL CR_ATTRIBUTE(visibility("hidden"))
# else
# define CR_API
# define CR_LOCAL
# endif
# endif
#endif /* !CRITERION_COMMON_H_ */

View file

@ -24,49 +24,67 @@
#ifndef CRITERION_H_
# define CRITERION_H_
# include "designated-initializer-compat.h"
# include "common.h"
# include "assert.h"
# include "types.h"
# include "assert.h"
# define IDENTIFIER_(Category, Name, Suffix) \
Category ## _ ## Name ## _ ## Suffix
# define TEST_PROTOTYPE_(Category, Name) \
# ifdef __cplusplus
# define TEST_PROTOTYPE_(Category, Name) \
extern "C" void IDENTIFIER_(Category, Name, impl)(void)
# else
# define TEST_PROTOTYPE_(Category, Name) \
void IDENTIFIER_(Category, Name, impl)(void)
# endif
# define SUITE_IDENTIFIER_(Name, Suffix) \
suite_ ## Name ## _ ## Suffix
# define Test(...) Test_(__VA_ARGS__, .sentinel_ = 0)
# define Test(...) CR_EXPAND(Test_(__VA_ARGS__, .sentinel_ = 0))
# define Test_(Category, Name, ...) \
TEST_PROTOTYPE_(Category, Name); \
struct criterion_test_extra_data IDENTIFIER_(Category, Name, extra) = { \
.identifier_ = #Category "/" #Name, \
.file_ = __FILE__, \
.line_ = __LINE__, \
__VA_ARGS__ \
}; \
struct criterion_test_extra_data IDENTIFIER_(Category, Name, extra) = \
CR_EXPAND(CRITERION_MAKE_STRUCT(struct criterion_test_extra_data, \
.identifier_ = #Category "/" #Name, \
.file_ = __FILE__, \
.line_ = __LINE__, \
__VA_ARGS__ \
)); \
SECTION_("cr_tst") \
const struct criterion_test IDENTIFIER_(Category, Name, meta) = { \
.name = #Name, \
.category = #Category, \
.test = IDENTIFIER_(Category, Name, impl), \
.data = &IDENTIFIER_(Category, Name, extra) \
}; \
struct criterion_test IDENTIFIER_(Category, Name, meta) = { \
#Name, \
#Category, \
IDENTIFIER_(Category, Name, impl), \
&IDENTIFIER_(Category, Name, extra) \
} SECTION_SUFFIX_; \
TEST_PROTOTYPE_(Category, Name)
# define TestSuite(...) TestSuite_(__VA_ARGS__, .sentinel_ = 0)
# define TestSuite(...) CR_EXPAND(TestSuite_(__VA_ARGS__, .sentinel_ = 0))
# define TestSuite_(Name, ...) \
struct criterion_test_extra_data SUITE_IDENTIFIER_(Name, extra) = { \
.file_ = __FILE__, \
.line_ = 0, \
__VA_ARGS__ \
}; \
struct criterion_test_extra_data SUITE_IDENTIFIER_(Name, extra) = \
CR_EXPAND(CRITERION_MAKE_STRUCT(struct criterion_test_extra_data, \
.file_ = __FILE__, \
.line_ = 0, \
__VA_ARGS__ \
)); \
SECTION_("cr_sts") \
const struct criterion_suite SUITE_IDENTIFIER_(Name, meta) = { \
.name = #Name, \
.data = &SUITE_IDENTIFIER_(Name, extra), \
}
struct criterion_suite SUITE_IDENTIFIER_(Name, meta) = { \
#Name, \
&SUITE_IDENTIFIER_(Name, extra), \
} SECTION_SUFFIX_
int criterion_run_all_tests(void);
CR_BEGIN_C_API
CR_API struct criterion_test_set *criterion_initialize(void);
CR_API void criterion_finalize(struct criterion_test_set *tests);
CR_API int criterion_run_all_tests(struct criterion_test_set *tests);
CR_API int criterion_handle_args(int argc, char *argv[], bool handle_unknown_arg);
CR_API void criterion_register_test(struct criterion_test_set *tests,
struct criterion_test *test);
CR_END_C_API
#endif /* !CRITERION_H_ */

View file

@ -0,0 +1,125 @@
/*
* The MIT License (MIT)
*
* Copyright © 2015 Franklin "Snaipe" Mathieu <http://snai.pe/>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef CRITERION_DESIGNATED_INITIALIZER_COMPAT_HH_
# define CRITERION_DESIGNATED_INITIALIZER_COMPAT_HH_
# include "common.h"
# define CRITERION_ARG_LENGTH(...) CR_EXPAND(CRITERION_ARG_LENGTH_(__VA_ARGS__,\
63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45,\
44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26,\
25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6,\
5, 4, 3, 2, 1, 0))
# define CRITERION_ARG_LENGTH_(_63, _62, _61, _60, _59, _58, _57, _56, _55, _54, _53, \
_52, _51, _50, _49, _48, _47, _46, _45, _44, _43, _42, _41, _40, _39, _38, \
_37, _36, _35, _34, _33, _32, _31, _30, _29, _28, _27, _26, _25, _24, _23, \
_22, _21, _20, _19, _18, _17, _16, _15, _14, _13, _12, _11, _10, _9, _8, \
_7, _6, _5, _4, _3, _2, _1, count, ...) count
# define CRITERION_APPLY_1(Macro, ...)
# define CRITERION_APPLY_2(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_1(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_3(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_2(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_4(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_3(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_5(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_4(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_6(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_5(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_7(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_6(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_8(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_7(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_9(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_8(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_10(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_9(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_11(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_10(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_12(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_11(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_13(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_12(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_14(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_13(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_15(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_14(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_16(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_15(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_17(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_16(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_18(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_17(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_19(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_18(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_20(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_19(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_21(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_20(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_22(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_21(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_23(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_22(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_24(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_23(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_25(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_24(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_26(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_25(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_27(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_26(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_28(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_27(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_29(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_28(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_30(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_29(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_31(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_30(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_32(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_31(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_33(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_32(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_34(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_33(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_35(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_34(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_36(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_35(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_37(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_36(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_38(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_37(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_39(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_38(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_40(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_39(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_41(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_40(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_42(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_41(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_43(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_42(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_44(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_43(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_45(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_44(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_46(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_45(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_47(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_46(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_48(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_47(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_49(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_48(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_50(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_49(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_51(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_50(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_52(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_51(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_53(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_52(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_54(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_53(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_55(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_54(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_56(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_55(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_57(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_56(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_58(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_57(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_59(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_58(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_60(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_59(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_61(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_60(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_62(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_61(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_63(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_62(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_64(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_63(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_65(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_64(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY__(Macro, Prefix, n, ...) CR_EXPAND(CRITERION_APPLY_##n(Macro, Prefix, __VA_ARGS__,))
# define CRITERION_APPLY_(Macro, n, Prefix, ...) CR_EXPAND(CRITERION_APPLY__(Macro, Prefix, n, __VA_ARGS__))
# define CRITERION_APPLY(Macro, ...) CR_EXPAND(CRITERION_APPLY_(Macro, CRITERION_ARG_LENGTH(__VA_ARGS__), __VA_ARGS__))
# define CRITERION_ADD_PREFIX_ONCE(Prefix, Field) Prefix Field;
# define CRITERION_ADD_PREFIX(...) \
CR_EXPAND(CRITERION_APPLY(CRITERION_ADD_PREFIX_ONCE, __VA_ARGS__))
# ifdef __cplusplus
# define CRITERION_MAKE_STRUCT(Type, ...) [&]() { \
Type t; \
std::memset(&t, 0, sizeof (t)); \
CR_EXPAND(CRITERION_ADD_PREFIX(t, __VA_ARGS__)) \
return t; \
}()
# else
# define CRITERION_MAKE_STRUCT(Type, ...) { __VA_ARGS__ }
# endif
#endif /* !CRITERION_DESIGNATED_INITIALIZER_COMPAT_HH_ */

View file

@ -24,11 +24,17 @@
#ifndef CRITERION_EVENT_H_
# define CRITERION_EVENT_H_
# include <stddef.h>
# include <stdio.h>
# ifdef __cplusplus
# include <cstddef>
# else
# include <stddef.h>
# endif
# include "common.h"
extern FILE *g_event_pipe;
CR_BEGIN_C_API
void send_event(int kind, void *data, size_t size);
CR_API void send_event(int kind, void *data, size_t size);
CR_END_C_API
#endif /* !CRITERION_EVENT_H_ */

View file

@ -25,6 +25,7 @@
# define CRITERION_HOOKS_H_
# include "common.h"
# include "types.h"
typedef enum {
PRE_ALL,
@ -32,6 +33,7 @@ typedef enum {
PRE_INIT,
PRE_TEST,
ASSERT,
THEORY_FAIL,
TEST_CRASH,
POST_TEST,
POST_FINI,
@ -45,8 +47,13 @@ typedef void (*f_report_hook)();
# define HOOK_IDENTIFIER__(Line, Suffix) HOOK_IDENTIFIER___(Line, Suffix)
# define HOOK_IDENTIFIER___(Line, Suffix) hook_l ## Line ## _ ## Suffix
# define HOOK_PROTOTYPE_ \
# ifdef __cplusplus
# define HOOK_PROTOTYPE_ \
extern "C" void HOOK_IDENTIFIER_(impl)
# else
# define HOOK_PROTOTYPE_ \
void HOOK_IDENTIFIER_(impl)
# endif
// Section abbreviations
# define HOOK_SECTION_PRE_ALL cr_pra
@ -54,6 +61,7 @@ typedef void (*f_report_hook)();
# define HOOK_SECTION_PRE_INIT cr_pri
# define HOOK_SECTION_PRE_TEST cr_prt
# define HOOK_SECTION_ASSERT cr_ast
# define HOOK_SECTION_THEORY_FAIL cr_thf
# define HOOK_SECTION_TEST_CRASH cr_tsc
# define HOOK_SECTION_POST_TEST cr_pot
# define HOOK_SECTION_POST_FINI cr_pof
@ -66,10 +74,26 @@ typedef void (*f_report_hook)();
# define HOOK_SECTION_STRINGIFY_(Sec) HOOK_SECTION_STRINGIFY__(Sec)
# define HOOK_SECTION_STRINGIFY(Kind) HOOK_SECTION_STRINGIFY_(HOOK_SECTION(Kind))
# define HOOK_PARAM_TYPE_PRE_ALL struct criterion_test_set *
# define HOOK_PARAM_TYPE_PRE_SUITE struct criterion_suite_set *
# define HOOK_PARAM_TYPE_PRE_INIT struct criterion_test *
# define HOOK_PARAM_TYPE_PRE_TEST struct criterion_test *
# define HOOK_PARAM_TYPE_ASSERT struct criterion_assert_stats *
# define HOOK_PARAM_TYPE_THEORY_FAIL struct criterion_theory_stats *
# define HOOK_PARAM_TYPE_TEST_CRASH struct criterion_test_stats *
# define HOOK_PARAM_TYPE_POST_TEST struct criterion_test_stats *
# define HOOK_PARAM_TYPE_POST_FINI struct criterion_test_stats *
# define HOOK_PARAM_TYPE_POST_SUITE struct criterion_suite_stats *
# define HOOK_PARAM_TYPE_POST_ALL struct criterion_global_stats *
# define HOOK_PARAM_TYPE(Kind) HOOK_PARAM_TYPE_ ## Kind
# define ReportHook(Kind) \
HOOK_PROTOTYPE_(); \
HOOK_PROTOTYPE_(HOOK_PARAM_TYPE(Kind)); \
SECTION_(HOOK_SECTION_STRINGIFY(Kind)) \
const f_report_hook HOOK_IDENTIFIER_(func) = HOOK_IDENTIFIER_(impl); \
f_report_hook HOOK_IDENTIFIER_(func) = \
(f_report_hook) HOOK_IDENTIFIER_(impl) \
SECTION_SUFFIX_; \
HOOK_PROTOTYPE_
#endif /* !CRITERION_HOOKS_H_ */

View file

@ -24,8 +24,13 @@
#ifndef CRITERION_LOGGING_H_
# define CRITERION_LOGGING_H_
# include <stdbool.h>
# include <stdarg.h>
# ifdef __cplusplus
# include <cstdarg>
using std::va_list;
# else
# include <stdbool.h>
# include <stdarg.h>
# endif
# include "common.h"
# include "ordered-set.h"
# include "stats.h"
@ -52,12 +57,12 @@ struct criterion_prefix_data {
# ifdef CRITERION_LOGGING_COLORS
# define CRIT_COLOR_NORMALIZE(Str) (criterion_options.use_ascii ? "" : Str)
# define CRIT_FG_BOLD "\e[0;1m"
# define CRIT_FG_RED "\e[0;31m"
# define CRIT_FG_GREEN "\e[0;32m"
# define CRIT_FG_GOLD "\e[0;33m"
# define CRIT_FG_BLUE "\e[0;34m"
# define CRIT_RESET "\e[0m"
# define CRIT_FG_BOLD "\33[0;1m"
# define CRIT_FG_RED "\33[0;31m"
# define CRIT_FG_GREEN "\33[0;32m"
# define CRIT_FG_GOLD "\33[0;33m"
# define CRIT_FG_BLUE "\33[0;34m"
# define CRIT_RESET "\33[0m"
# define FG_BOLD CRIT_COLOR_NORMALIZE(CRIT_FG_BOLD)
# define FG_RED CRIT_COLOR_NORMALIZE(CRIT_FG_RED)
@ -67,6 +72,8 @@ struct criterion_prefix_data {
# define RESET CRIT_COLOR_NORMALIZE(CRIT_RESET)
# endif
CR_BEGIN_C_API
extern const struct criterion_prefix_data g_criterion_logging_prefixes[];
# define CRITERION_PREFIX_DASHES (&g_criterion_logging_prefixes[CRITERION_LOGGING_PREFIX_DASHES])
@ -76,13 +83,13 @@ extern const struct criterion_prefix_data g_criterion_logging_prefixes[];
# define CRITERION_PREFIX_PASS (&g_criterion_logging_prefixes[CRITERION_LOGGING_PREFIX_PASS ])
# define CRITERION_PREFIX_FAIL (&g_criterion_logging_prefixes[CRITERION_LOGGING_PREFIX_FAIL ])
void criterion_vlog(enum criterion_logging_level level, const char *msg, va_list args);
CR_API void criterion_vlog(enum criterion_logging_level level, const char *msg, va_list args);
FORMAT(printf, 3, 4)
void criterion_plog(enum criterion_logging_level level, const struct criterion_prefix_data *prefix, const char *msg, ...);
CR_API void criterion_plog(enum criterion_logging_level level, const struct criterion_prefix_data *prefix, const char *msg, ...);
FORMAT(printf, 2, 3)
void criterion_log(enum criterion_logging_level level, const char *msg, ...);
CR_API void criterion_log(enum criterion_logging_level level, const char *msg, ...);
# define criterion_info(...) criterion_log(CRITERION_INFO, __VA_ARGS__)
# define criterion_important(...) criterion_log(CRITERION_IMPORTANT, __VA_ARGS__)
@ -91,22 +98,27 @@ void criterion_log(enum criterion_logging_level level, const char *msg, ...);
# define criterion_pimportant(...) criterion_plog(CRITERION_IMPORTANT, __VA_ARGS__)
struct criterion_output_provider {
void (*log_pre_all )(struct criterion_test_set *set);
void (*log_pre_suite )(struct criterion_suite_set *set);
void (*log_pre_init )(struct criterion_test *test);
void (*log_pre_test )(struct criterion_test *test);
void (*log_assert )(struct criterion_assert_stats *stats);
void (*log_test_crash )(struct criterion_test_stats *stats);
void (*log_other_crash)(struct criterion_test_stats *stats);
void (*log_post_test )(struct criterion_test_stats *stats);
void (*log_post_fini )(struct criterion_test_stats *stats);
void (*log_post_suite )(struct criterion_suite_stats *stats);
void (*log_post_all )(struct criterion_global_stats *stats);
void (*log_pre_all )(struct criterion_test_set *set);
void (*log_pre_suite )(struct criterion_suite_set *set);
void (*log_pre_init )(struct criterion_test *test);
void (*log_pre_test )(struct criterion_test *test);
void (*log_assert )(struct criterion_assert_stats *stats);
void (*log_theory_fail )(struct criterion_theory_stats *stats);
void (*log_test_timeout )(struct criterion_test_stats *stats);
void (*log_test_crash )(struct criterion_test_stats *stats);
void (*log_other_crash )(struct criterion_test_stats *stats);
void (*log_abnormal_exit)(struct criterion_test_stats *stats);
void (*log_post_test )(struct criterion_test_stats *stats);
void (*log_post_fini )(struct criterion_test_stats *stats);
void (*log_post_suite )(struct criterion_suite_stats *stats);
void (*log_post_all )(struct criterion_global_stats *stats);
};
extern struct criterion_output_provider normal_logging;
extern struct criterion_output_provider tap_logging;
CR_END_C_API
#define NORMAL_LOGGING (&normal_logging)
#define TAP_LOGGING (&tap_logging)

View file

@ -38,6 +38,10 @@ struct criterion_options {
bool short_filename;
};
CR_BEGIN_C_API
extern struct criterion_options criterion_options;
CR_END_C_API
#endif /*!CRITERION_OPTIONS_H_ */

View file

@ -40,23 +40,17 @@ struct criterion_ordered_set_node {
char data[0];
};
struct criterion_suite_set {
struct criterion_suite suite;
struct criterion_ordered_set *tests;
};
CR_BEGIN_C_API
struct criterion_test_set {
struct criterion_ordered_set *suites;
size_t tests;
};
struct criterion_ordered_set *new_ordered_set(f_criterion_cmp cmp,
CR_API struct criterion_ordered_set *new_ordered_set(f_criterion_cmp cmp,
void (*dtor)(void *, void *));
void *insert_ordered_set(struct criterion_ordered_set *l,
CR_API void *insert_ordered_set(struct criterion_ordered_set *l,
void *ptr,
size_t size);
CR_END_C_API
# define FOREACH_SET(Elt, Set) \
for (struct criterion_ordered_set_node *n = Set->first; n; n = n->next) \
for (int cond = 1; cond;) \

View file

@ -0,0 +1,73 @@
/*
* The MIT License (MIT)
*
* Copyright © 2015 Franklin "Snaipe" Mathieu <http://snai.pe/>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef CRITERION_PREPROCESS_H_
# define CRITERION_PREPROCESS_H_
# define CR_NOOP do {} while(0)
# ifdef __cplusplus
# define CR_NOTHROW throw()
# else
# define CR_NOTHROW
# endif
# define CR_EXPAND(x) x
# define CR_IDENTITY(...) __VA_ARGS__
# define CR_STR(x) CR_EXPAND(CR_STR_(x))
# define CR_STR_(x) #x
# define CR_VA_TAIL(...) CR_EXPAND(CR_VA_TAIL_HELPER(CR_VA_TAIL_SELECT(__VA_ARGS__), __VA_ARGS__))
# define CR_VA_TAIL_HELPER(N, ...) CR_EXPAND(CR_VA_TAIL_HELPER_(N, __VA_ARGS__))
# define CR_VA_TAIL_HELPER_(N, ...) CR_EXPAND(CR_VA_TAIL_HELPER_##N(__VA_ARGS__))
# define CR_VA_TAIL_HELPER_1(Head)
# define CR_VA_TAIL_HELPER_2(Head, ...) __VA_ARGS__
# define CR_VA_HEAD(...) CR_EXPAND(CR_VA_HEAD_HELPER(CR_VA_TAIL_SELECT(__VA_ARGS__), __VA_ARGS__))
# define CR_VA_HEAD_HELPER(N, ...) CR_EXPAND(CR_VA_HEAD_HELPER_(N, __VA_ARGS__))
# define CR_VA_HEAD_HELPER_(N, ...) CR_EXPAND(CR_VA_HEAD_HELPER_##N(__VA_ARGS__))
# define CR_VA_HEAD_HELPER_1(Head) Head
# define CR_VA_HEAD_HELPER_2(Head, ...) Head
# define CR_VA_TAIL_SELECT(...) CR_EXPAND(CR_VA_TAIL_SELECT64(__VA_ARGS__, \
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
2, 2, 1, _))
# define CR_VA_TAIL_SELECT64( \
_01, _02, _03, _04, _05, _06, _07, _08, _09, _10, \
_11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \
_21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \
_31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \
_41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \
_51, _52, _53, _54, _55, _56, _57, _58, _59, _60, \
_61, _62, _63, X, ...) X
#endif /* !CRITERION_PREPROCESS_H_ */

View file

@ -0,0 +1,235 @@
/*
* The MIT License (MIT)
*
* Copyright © 2015 Franklin "Snaipe" Mathieu <http://snai.pe/>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef CRITERION_REDIRECT_H_
# define CRITERION_REDIRECT_H_
# include "common.h"
# include "assert.h"
# ifdef __cplusplus
# include <cstdio>
# include <memory>
# include <fstream>
# ifdef __GNUC__
# include <ext/stdio_filebuf.h>
# endif
# else
# include <stdio.h>
# endif
CR_BEGIN_C_API
CR_API void cr_redirect_stdout(void);
CR_API void cr_redirect_stderr(void);
CR_API void cr_redirect_stdin(void);
CR_API CR_STDN FILE* cr_get_redirected_stdout(void);
CR_API CR_STDN FILE* cr_get_redirected_stderr(void);
CR_API CR_STDN FILE* cr_get_redirected_stdin(void);
CR_API int cr_file_match_str(CR_STDN FILE* f, const char *str);
CR_API int cr_file_match_file(CR_STDN FILE* f, CR_STDN FILE* ref);
CR_END_C_API
# define cr_assert_redir_op_(Fail, Fun, Op, File, Str, ...) \
CR_EXPAND(cr_assert_impl( \
Fail, \
!(Fun((File), (Str)) Op 0), \
dummy, \
CRITERION_ASSERT_MSG_FILE_STR_MATCH, \
(CR_STR(File), Str), \
__VA_ARGS__ \
))
# define cr_assert_redir_op_va_(Fail, Fun, Op, ...) \
CR_EXPAND(cr_assert_redir_op_( \
Fail, \
Fun, \
Op, \
CR_VA_HEAD(__VA_ARGS__), \
CR_VA_HEAD(CR_VA_TAIL(__VA_ARGS__)), \
CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__)) \
))
# define cr_assert_redir_f_op_(Fail, Fun, Op, File, Ref, ...) \
CR_EXPAND(cr_assert_impl( \
Fail, \
!(Fun((File), (Ref)) Op 0), \
dummy, \
CRITERION_ASSERT_MSG_FILE_MATCH, \
(CR_STR(File), CR_STR(Ref)), \
__VA_ARGS__ \
))
# define cr_assert_redir_f_op_va_(Fail, Fun, Op, ...) \
CR_EXPAND(cr_assert_redir_op_( \
Fail, \
Fun, \
Op, \
CR_VA_HEAD(__VA_ARGS__), \
CR_VA_HEAD(CR_VA_TAIL(__VA_ARGS__)), \
CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__)) \
))
# define cr_assert_file_contents_eq_str(...) CR_EXPAND(cr_assert_redir_op_va_(CR_FAIL_ABORT_, cr_file_match_str, ==, __VA_ARGS__))
# define cr_expect_file_contents_eq_str(...) CR_EXPAND(cr_assert_redir_op_va_(CR_FAIL_CONTINUES_, cr_file_match_str, ==, __VA_ARGS__))
# define cr_assert_file_contents_neq_str(...) CR_EXPAND(cr_assert_redir_op_va_(CR_FAIL_ABORT_, cr_file_match_str, !=, __VA_ARGS__))
# define cr_expect_file_contents_neq_str(...) CR_EXPAND(cr_assert_redir_op_va_(CR_FAIL_CONTINUES_, cr_file_match_str, !=, __VA_ARGS__))
# define cr_assert_file_contents_eq(...) CR_EXPAND(cr_assert_redir_f_op_va_(CR_FAIL_ABORT_, cr_file_match_file, ==, __VA_ARGS__))
# define cr_expect_file_contents_eq(...) CR_EXPAND(cr_assert_redir_f_op_va_(CR_FAIL_CONTINUES_, cr_file_match_file, ==, __VA_ARGS__))
# define cr_assert_file_contents_neq(...) CR_EXPAND(cr_assert_redir_f_op_va_(CR_FAIL_ABORT_, cr_file_match_file, !=, __VA_ARGS__))
# define cr_expect_file_contents_neq(...) CR_EXPAND(cr_assert_redir_f_op_va_(CR_FAIL_CONTINUES_, cr_file_match_file, !=, __VA_ARGS__))
# define cr_assert_stdout_eq_str(...) CR_EXPAND(cr_assert_redir_op_va_(CR_FAIL_ABORT_, cr_file_match_str, ==, cr_get_redirected_stdout(), __VA_ARGS__))
# define cr_expect_stdout_eq_str(...) CR_EXPAND(cr_assert_redir_op_va_(CR_FAIL_CONTINUES_, cr_file_match_str, ==, cr_get_redirected_stdout(), __VA_ARGS__))
# define cr_assert_stdout_neq_str(...) CR_EXPAND(cr_assert_redir_op_va_(CR_FAIL_ABORT_, cr_file_match_str, !=, cr_get_redirected_stdout(), __VA_ARGS__))
# define cr_expect_stdout_neq_str(...) CR_EXPAND(cr_assert_redir_op_va_(CR_FAIL_CONTINUES_, cr_file_match_str, !=, cr_get_redirected_stdout(), __VA_ARGS__))
# define cr_assert_stderr_eq_str(...) CR_EXPAND(cr_assert_redir_op_va_(CR_FAIL_ABORT_, cr_file_match_str, ==, cr_get_redirected_stderr(), __VA_ARGS__))
# define cr_expect_stderr_eq_str(...) CR_EXPAND(cr_assert_redir_op_va_(CR_FAIL_CONTINUES_, cr_file_match_str, ==, cr_get_redirected_stderr(), __VA_ARGS__))
# define cr_assert_stderr_neq_str(...) CR_EXPAND(cr_assert_redir_op_va_(CR_FAIL_ABORT_, cr_file_match_str, !=, cr_get_redirected_stderr(), __VA_ARGS__))
# define cr_expect_stderr_neq_str(...) CR_EXPAND(cr_assert_redir_op_va_(CR_FAIL_CONTINUES_, cr_file_match_str, !=, cr_get_redirected_stderr(), __VA_ARGS__))
# define cr_assert_stdout_eq(...) CR_EXPAND(cr_assert_redir_f_op_va_(CR_FAIL_ABORT_, cr_file_match_file, ==, cr_get_redirected_stdout(), __VA_ARGS__))
# define cr_expect_stdout_eq(...) CR_EXPAND(cr_assert_redir_f_op_va_(CR_FAIL_CONTINUES_, cr_file_match_file, ==, cr_get_redirected_stdout(), __VA_ARGS__))
# define cr_assert_stdout_neq(...) CR_EXPAND(cr_assert_redir_f_op_va_(CR_FAIL_ABORT_, cr_file_match_file, !=, cr_get_redirected_stdout(), __VA_ARGS__))
# define cr_expect_stdout_neq(...) CR_EXPAND(cr_assert_redir_f_op_va_(CR_FAIL_CONTINUES_, cr_file_match_file, !=, cr_get_redirected_stdout(), __VA_ARGS__))
# define cr_assert_stderr_eq(...) CR_EXPAND(cr_assert_redir_f_op_va_(CR_FAIL_ABORT_, cr_file_match_file, ==, cr_get_redirected_stderr(), __VA_ARGS__))
# define cr_expect_stderr_eq(...) CR_EXPAND(cr_assert_redir_f_op_va_(CR_FAIL_CONTINUES_, cr_file_match_file, ==, cr_get_redirected_stderr(), __VA_ARGS__))
# define cr_assert_stderr_neq(...) CR_EXPAND(cr_assert_redir_f_op_va_(CR_FAIL_ABORT_, cr_file_match_file, !=, cr_get_redirected_stderr(), __VA_ARGS__))
# define cr_expect_stderr_neq(...) CR_EXPAND(cr_assert_redir_f_op_va_(CR_FAIL_CONTINUES_, cr_file_match_file, !=, cr_get_redirected_stderr(), __VA_ARGS__))
# ifdef __cplusplus
namespace criterion {
template <typename CharT>
class basic_ofstream : public std::basic_ofstream<CharT> {
public:
basic_ofstream(FILE* f)
# ifdef __GNUC__
: std::ofstream()
, fbuf(new ::__gnu_cxx::stdio_filebuf<CharT>(f, std::ios::out))
# else
: std::ofstream(f)
# endif
, file(f)
{
# ifdef __GNUC__
std::ios::rdbuf(&*fbuf);
# endif
}
void close(void) {
std::basic_ofstream<CharT>::flush();
std::basic_ofstream<CharT>::close();
std::fclose(file);
}
private:
# ifdef __GNUC__
std::unique_ptr<::__gnu_cxx::stdio_filebuf<CharT>> fbuf;
# endif
std::FILE* file;
};
template <typename CharT>
class basic_ifstream : public std::basic_ifstream<CharT> {
public:
basic_ifstream(FILE* f)
# ifdef __GNUC__
: std::ifstream()
, fbuf(new ::__gnu_cxx::stdio_filebuf<CharT>(f, std::ios::in))
# else
: std::ifstream(f)
# endif
, file(f)
{
# ifdef __GNUC__
std::ios::rdbuf(&*fbuf);
# endif
}
void close(void) {
std::basic_ifstream<CharT>::flush();
std::basic_ifstream<CharT>::close();
std::fclose(file);
}
private:
# ifdef __GNUC__
std::unique_ptr<::__gnu_cxx::stdio_filebuf<CharT>> fbuf;
# endif
std::FILE* file;
};
template <typename CharT>
struct get_redirected_out_stream_ {
static inline basic_ofstream<CharT>& call(std::FILE* f) {
static std::unique_ptr<basic_ofstream<CharT>> stream;
if (!stream)
stream.reset(new basic_ofstream<CharT>(f));
return *stream;
}
};
template <typename CharT>
struct get_redirected_in_stream_ {
static inline basic_ifstream<CharT>& call(std::FILE* f) {
static std::unique_ptr<basic_ifstream<CharT>> stream;
if (!stream)
stream.reset(new basic_ifstream<CharT>(f));
return *stream;
}
};
using ofstream = basic_ofstream<char>;
using ifstream = basic_ifstream<char>;
static inline ofstream& get_redirected_cin(void) {
return get_redirected_out_stream_<char>::call(cr_get_redirected_stdin());
}
static inline ifstream& get_redirected_cout(void) {
return get_redirected_in_stream_<char>::call(cr_get_redirected_stdout());
}
static inline ifstream& get_redirected_cerr(void) {
return get_redirected_in_stream_<char>::call(cr_get_redirected_stderr());
}
}
# endif
#endif /* !CRITERION_REDIRECT_H_ */

View file

@ -27,8 +27,6 @@
# include "types.h"
struct criterion_assert_stats {
int kind;
const char *condition;
const char *message;
bool passed;
unsigned line;
@ -44,13 +42,20 @@ struct criterion_test_stats {
int passed_asserts;
int failed_asserts;
int signal;
int exit_code;
float elapsed_time;
bool timed_out;
unsigned progress;
const char *file;
struct criterion_test_stats *next;
};
struct criterion_theory_stats {
const char *formatted_args;
struct criterion_test_stats *stats;
};
struct criterion_suite_stats {
struct criterion_suite *suite;
struct criterion_test_stats *tests;

View file

@ -0,0 +1,145 @@
/*
* The MIT License (MIT)
*
* Copyright © 2015 Franklin "Snaipe" Mathieu <http://snai.pe/>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef CRITERION_THEORIES_H_
# define CRITERION_THEORIES_H_
# ifdef __cplusplus
# include <cstddef>
using std::size_t;
# else
# include <stddef.h>
# endif
# include "criterion.h"
# ifdef __cplusplus
template <typename... T>
constexpr size_t criterion_va_num__(const T &...) {
return sizeof...(T);
}
# endif
CR_BEGIN_C_API
struct criterion_theory_context;
CR_API struct criterion_theory_context* cr_theory_init(void);
CR_API void cr_theory_push_arg(struct criterion_theory_context *ctx, bool is_float, size_t size, void *ptr);
CR_API void cr_theory_free(struct criterion_theory_context *ctx);
CR_API void cr_theory_abort(void);
CR_API int cr_theory_mark(void);
CR_API void cr_theory_reset(struct criterion_theory_context *ctx);
CR_API void cr_theory_call(struct criterion_theory_context *ctx, void (*fnptr)(void));
# define TheoryDataPoints(Category, Name) \
static struct criterion_datapoints IDENTIFIER_(Category, Name, dps)[]
# define TheoryDataPoint(Category, Name) \
(IDENTIFIER_(Category, Name, dps))
# ifdef __cplusplus
# define CR_TH_VA_NUM(Type, ...) criterion_va_num__(__VA_ARGS__)
# define CR_TH_TEMP_ARRAY(Type, ...) []() { static Type arr[] = { __VA_ARGS__ }; return &arr; }()
# else
# define CR_TH_VA_NUM(Type, ...) sizeof ((Type[]) { __VA_ARGS__ }) / sizeof (Type)
# define CR_TH_TEMP_ARRAY(Type, ...) &(Type[]) { __VA_ARGS__ }
# endif
# define DataPoints(Type, ...) { \
sizeof (Type), \
CR_EXPAND(CR_TH_VA_NUM(Type, __VA_ARGS__)), \
#Type, \
CR_EXPAND(CR_TH_TEMP_ARRAY(Type, __VA_ARGS__)), \
}
struct criterion_datapoints {
size_t size;
size_t len;
const char *name;
void *arr;
};
# define CR_NB_DATAPOINTS(Var) \
(sizeof (Var) / sizeof (struct criterion_datapoints))
# define cr_assume(Condition) \
do { \
if (!(Condition)) \
cr_theory_abort(); \
} while (0);
# define cr_assume_not(Condition) cr_assume(!(Condition))
# define cr_assume_op_(Op, Actual, Expected) cr_assume((Actual) Op (Expected))
# define cr_assume_eq(Actual, Expected) cr_assume_op_(==, Actual, Expected)
# define cr_assume_neq(Actual, Expected) cr_assume_op_(!=, Actual, Expected)
# define cr_assume_gt(Actual, Expected) cr_assume_op_(>, Actual, Expected)
# define cr_assume_geq(Actual, Expected) cr_assume_op_(>=, Actual, Expected)
# define cr_assume_lt(Actual, Expected) cr_assume_op_(<, Actual, Expected)
# define cr_assume_leq(Actual, Expected) cr_assume_op_(<=, Actual, Expected)
# define cr_assume_null(Value) cr_assume_eq(Value, NULL)
# define cr_assume_not_null(Value) cr_assume_neq(Value, NULL)
# define cr_assume_float_eq(Actual, Expected, Epsilon) \
cr_assume((Expected) - (Actual) <= (Epsilon) \
&& (Actual) - (Expected) <= (Epsilon))
# define cr_assume_float_neq(Actual, Expected, Epsilon) \
cr_assume((Expected) - (Actual) > (Epsilon) \
|| (Actual) - (Expected) > (Epsilon))
# define cr_assume_strings_op_(Op, Actual, Expected) \
cr_assume(strcmp((Actual), (Expected)) Op 0)
# define cr_assume_strings_eq(Actual, Expected) cr_assume_strings_op_(==, Actual, Expected)
# define cr_assume_strings_neq(Actual, Expected) cr_assume_strings_op_(!=, Actual, Expected)
# define cr_assume_strings_lt(Actual, Expected) cr_assume_strings_op_(<, Actual, Expected)
# define cr_assume_strings_leq(Actual, Expected) cr_assume_strings_op_(<=, Actual, Expected)
# define cr_assume_strings_gt(Actual, Expected) cr_assume_strings_op_(>, Actual, Expected)
# define cr_assume_strings_geq(Actual, Expected) cr_assume_strings_op_(>=, Actual, Expected)
# define cr_assume_arrays_eq(Actual, Expected, Size) cr_assume(!memcmp((A), (B), (Size)))
# define cr_assume_arrays_neq(Actual, Expected, Size) cr_assume(memcmp((A), (B), (Size)))
CR_API void cr_theory_main(struct criterion_datapoints *dps, size_t datapoints, void (*fnptr)(void));
# define CR_VAARG_ID(Suffix, Category, Name, ...) \
IDENTIFIER_(Category, Name, Suffix)
# define Theory(Args, ...) \
void CR_EXPAND(CR_VAARG_ID(theory, __VA_ARGS__,))Args; \
CR_EXPAND(Test_(__VA_ARGS__, .sentinel_ = 0)) { \
cr_theory_main( \
CR_EXPAND(CR_VAARG_ID(dps, __VA_ARGS__,)), \
CR_NB_DATAPOINTS(CR_EXPAND(CR_VAARG_ID(dps, __VA_ARGS__,))), \
(void(*)(void)) CR_EXPAND(CR_VAARG_ID(theory, __VA_ARGS__,)) \
); \
} \
void CR_EXPAND(CR_VAARG_ID(theory, __VA_ARGS__,))Args
CR_END_C_API
#endif /* !CRITERION_THEORIES_H_ */

View file

@ -24,8 +24,13 @@
#ifndef CRITERION_TYPES_H_
# define CRITERION_TYPES_H_
# include <stdbool.h>
# include <stddef.h>
# ifdef __cplusplus
# include <cstddef>
using std::size_t;
# else
# include <stdbool.h>
# include <stddef.h>
# endif
# include "common.h"
struct criterion_test_extra_data {
@ -36,8 +41,10 @@ struct criterion_test_extra_data {
void (*init)(void);
void (*fini)(void);
int signal;
int exit_code;
bool disabled;
const char *description;
float timeout;
void *data;
};
@ -53,6 +60,18 @@ struct criterion_suite {
struct criterion_test_extra_data *data;
};
struct criterion_ordered_set;
struct criterion_suite_set {
struct criterion_suite suite;
struct criterion_ordered_set *tests;
};
struct criterion_test_set {
struct criterion_ordered_set *suites;
size_t tests;
};
typedef void (*f_worker_func)(struct criterion_test *, struct criterion_suite *);
#endif /* !CRITERION_TYPES_H_ */

View file

@ -1,2 +1,3 @@
# List of source files which contain translatable strings.
src/log/normal.c
src/i18n.c

109
po/fr.po
View file

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: criterion 1.0.0\n"
"Report-Msgid-Bugs-To: franklinmathieu+criterion@gmail.com\n"
"POT-Creation-Date: 2015-08-05 11:37+0200\n"
"POT-Creation-Date: 2015-09-14 04:12+0200\n"
"PO-Revision-Date: 2015-04-03 17:58+0200\n"
"Last-Translator: <franklinmathieu@gmail.com>\n"
"Language-Team: French\n"
@ -18,54 +18,65 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: src/log/normal.c:51
#: src/log/normal.c:50
#, c-format
msgid "Criterion v%s\n"
msgstr "Criterion v%s\n"
#: src/log/normal.c:52
#: src/log/normal.c:51
#, c-format
msgid " %s\n"
msgstr " %s\n"
#: src/log/normal.c:55 src/log/normal.c:57
#: src/log/normal.c:54 src/log/normal.c:56
#, c-format
msgid "%1$s::%2$s\n"
msgstr "%1$s::%2$s\n"
#: src/log/normal.c:56
#: src/log/normal.c:55
#, fuzzy, c-format
msgid "%1$s::%2$s: (%3$3.2fs)\n"
msgstr "%1$s::%2$s: (%3$3.2fs)\n"
#: src/log/normal.c:58
#: src/log/normal.c:57
#, c-format
msgid "%1$s::%2$s: Test is disabled\n"
msgstr "%1$s::%2$s: Le test est désactivé\n"
#: src/log/normal.c:59
#: src/log/normal.c:58
#, c-format
msgid "%1$s::%2$s: Suite is disabled\n"
msgstr "%1$s::%2$s: La suite est désactivée\n"
#: src/log/normal.c:60
#: src/log/normal.c:59
#, c-format
msgid "%1$s%2$s%3$s:%4$s%5$d%6$s: Assertion failed: %7$s\n"
msgstr "%1$s%2$s%3$s:%4$s%5$d%6$s: Échec d'assertion: %7$s\n"
#: src/log/normal.c:60
#, fuzzy, c-format
msgid " Theory %1$s::%2$s failed with the following parameters: (%3$s)\n"
msgstr ""
" La théorie %1$s::%2$s a échoué avec les paramètres suivants: (%3$s)\n"
#: src/log/normal.c:61
#, fuzzy, c-format
msgid "%1$s::%2$s: Timed out. (%3$3.2fs)\n"
msgstr "%1$s::%2$s: Délai expiré. (%3$3.2fs)\n"
#: src/log/normal.c:62
#, c-format
msgid "%1$s%2$s%3$s:%4$s%5$u%6$s: Unexpected signal caught below this line!\n"
msgstr ""
"%1$s%2$s%3$s:%4$s%5$u%6$s: Un signal inattendu a été reçu après cette "
"ligne!\n"
#: src/log/normal.c:62
#: src/log/normal.c:63
#, c-format
msgid "%1$s::%2$s: CRASH!\n"
msgstr "%1$s::%2$s: PLANTAGE!\n"
#: src/log/normal.c:63
#: src/log/normal.c:64
#, fuzzy, c-format
msgid ""
"%1$sWarning! The test `%2$s::%3$s` crashed during its setup or teardown."
@ -74,14 +85,22 @@ msgstr ""
"%1$sAttention! Le test `%2$s::%3$s` a planté pendant son initialisation ou "
"sa finalisation.%4$s\n"
#: src/log/normal.c:64
#: src/log/normal.c:65
#, fuzzy, c-format
msgid ""
"%1$sWarning! The test `%2$s::%3$s` exited during its setup or teardown.%4$s\n"
msgstr ""
"%1$sAttention! Le test `%2$s::%3$s` a quitté pendant son initialisation ou "
"sa finalisation.%4$s\n"
#: src/log/normal.c:66
#, c-format
msgid "Running %1$s%2$lu%3$s test from %4$s%5$s%6$s:\n"
msgid_plural "Running %1$s%2$lu%3$s tests from %4$s%5$s%6$s:\n"
msgstr[0] "Lancement de %1$s%2$lu%3$s test dans %4$s%5$s%6$s:\n"
msgstr[1] "Lancement de %1$s%2$lu%3$s tests dans %4$s%5$s%6$s:\n"
#: src/log/normal.c:66
#: src/log/normal.c:68
#, c-format
msgid ""
"%1$sSynthesis: Tested: %2$s%3$lu%4$s | Passing: %5$s%6$lu%7$s | Failing: %8$s"
@ -89,3 +108,69 @@ msgid ""
msgstr ""
"%1$sSynthèse: Testés: %2$s%3$lu%4$s | Validés: %5$s%6$lu%7$s | Échoués: %8$s"
"%9$lu%10$s | Plantages: %11$s%12$lu%13$s %14$s\n"
#: src/i18n.c:13
msgid "The conditions for this assertion were not met."
msgstr "Les conditions de cette assertion n'ont pas été remplies."
#: src/i18n.c:14
#, c-format
msgid "The expression %s is false."
msgstr "L'expression %s est fausse."
#: src/i18n.c:15
#, c-format
msgid "The expression (as strings) %s is false."
msgstr "L'expression (en tant que chaînes de caractères) %s est fausse."
#: src/i18n.c:16
#, c-format
msgid "%s is null."
msgstr "%s est nul."
#: src/i18n.c:17
#, c-format
msgid "%s is not null."
msgstr "%s n'est pas nul."
#: src/i18n.c:18
#, c-format
msgid "%s is empty."
msgstr "%s est vide."
#: src/i18n.c:19
#, c-format
msgid "%s is not empty."
msgstr "%s n'est pas vide."
#: src/i18n.c:20
#, fuzzy, c-format
msgid "The statement `%s` did not throw any exception."
msgstr "L'instruction `%s` n'a pas levé d'exception."
#: src/i18n.c:21
#, fuzzy, c-format
msgid "The statement `%s` threw some exception."
msgstr "L'instruction `%1$s` a levé une exception."
#: src/i18n.c:24
#, c-format
msgid "The file contents of %1$s does not match the string \"%2$s\"."
msgstr ""
"Le contenu du fichier %1$s ne correspond pas à la chaine de caractères \"%2$s"
"\"."
#: src/i18n.c:25
#, fuzzy, c-format
msgid "The file contents of %1$s does not match the contents of %2$s."
msgstr "Le contenu du fichier %1$s ne correspond pas au contenu de %2$s."
#: src/i18n.c:26
#, c-format
msgid "The statement `%1$s` did throw an instance of the `%2$s` exception."
msgstr "L'instruction `%1$s` a levé une instance de l'exception `%2$s`."
#: src/i18n.c:27
#, c-format
msgid "The statement `%1$s` did not throw an instance of the `%2$s` exception."
msgstr "L'instruction `%1$s` n'a pas levé d'instance de l'exception `%2$s`."

View file

@ -1,20 +1,33 @@
project(criterion_samples)
set(CMAKE_C_FLAGS "-std=c99 -Wall -Wextra -pedantic")
if (NOT MSVC)
set(CMAKE_C_FLAGS "-std=c99 -Wall -Wextra -pedantic")
set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wextra -pedantic")
endif ()
include_directories(../include)
set(SAMPLES
signal
report
suites
fixtures
asserts
more-suites
long-messages
description
other-crashes
simple
signal.c
report.c
suites.c
fixtures.c
asserts.c
more-suites.c
description.c
simple.c
theories.c
timeout.c
redirect.c
signal.cc
report.cc
suites.cc
fixtures.cc
asserts.cc
more-suites.cc
description.cc
simple.cc
theories.cc
redirect.cc
)
set(SCRIPTS
@ -22,26 +35,41 @@ set(SCRIPTS
early_exit
verbose
list
pattern
fail_fast
help
)
foreach(sample ${SAMPLES})
add_executable(${sample} ${sample}.c)
target_link_libraries(${sample} criterion)
add_test(${sample} ${sample})
set_property(TEST ${sample} PROPERTY
ENVIRONMENT "CRITERION_ALWAYS_SUCCEED=1"
)
if (HAVE_PCRE)
set(SCRIPTS ${SCRIPTS} pattern)
endif ()
add_test(${sample}_compare sh ${CMAKE_CURRENT_LIST_DIR}/tests/run_test.sh "${CMAKE_CURRENT_LIST_DIR}" . . ${sample})
set_property(TEST ${sample}_compare PROPERTY
ENVIRONMENT "LC_ALL=en_US.utf8"
ENVIRONMENT "CRITERION_ALWAYS_SUCCEED=1"
ENVIRONMENT "CRITERION_SHORT_FILENAME=1"
)
endforeach()
add_custom_target(criterion_samples)
add_dependencies(criterion_tests criterion_samples)
macro(add_samples DIR_ SAMPLES_)
foreach(sample ${SAMPLES_})
add_executable(${sample}.bin EXCLUDE_FROM_ALL ${sample})
add_dependencies(criterion_samples ${sample}.bin)
target_link_libraries(${sample}.bin criterion)
add_test(${sample} ${sample}.bin)
set_property(TEST ${sample} PROPERTY
ENVIRONMENT "CRITERION_ALWAYS_SUCCEED=1"
)
if (NOT MSVC) # we disable the scripted tests when building with MSVC
add_test(${sample}_compare sh ${DIR_}/run_test.sh "${CMAKE_CURRENT_LIST_DIR}/outputs" . . ${sample}.bin)
set_property(TEST ${sample}_compare PROPERTY
ENVIRONMENT "LC_ALL=en_US.utf8"
ENVIRONMENT "CRITERION_ALWAYS_SUCCEED=1"
ENVIRONMENT "CRITERION_SHORT_FILENAME=1"
)
endif ()
endforeach()
endmacro()
add_samples("${CMAKE_CURRENT_LIST_DIR}/tests" "${SAMPLES}")
if (NOT MSVC) # we disable the scripted tests when building with MSVC
foreach(script ${SCRIPTS})
add_test(${script} sh ${CMAKE_CURRENT_LIST_DIR}/tests/${script}.sh)
@ -49,10 +77,14 @@ foreach(script ${SCRIPTS})
ENVIRONMENT "CRITERION_ALWAYS_SUCCEED=1"
)
add_test(${script}_compare sh ${CMAKE_CURRENT_LIST_DIR}/tests/run_test.sh "${CMAKE_CURRENT_LIST_DIR}" . "${CMAKE_CURRENT_LIST_DIR}" tests/${sample})
add_test(${script}_compare sh ${CMAKE_CURRENT_LIST_DIR}/tests/run_test.sh "${CMAKE_CURRENT_LIST_DIR}" . "${CMAKE_CURRENT_LIST_DIR}" tests/${script})
set_property(TEST ${script}_compare PROPERTY
ENVIRONMENT "LC_ALL=en_US.utf8"
ENVIRONMENT "CRITERION_ALWAYS_SUCCEED=1"
ENVIRONMENT "CRITERION_SHORT_FILENAME=1"
)
endforeach()
endif()
add_subdirectory(tests)

View file

@ -1,39 +0,0 @@
BIN_TESTS = \
signal \
report \
suites \
fixtures \
asserts \
more-suites \
long-messages \
description \
other-crashes \
simple
TESTS_ENVIRONMENT = CRITERION_ALWAYS_SUCCEED=1
check_PROGRAMS := $(BIN_TESTS)
CFLAGS = -I$(top_srcdir)/include/ -std=c99 -Wall -Wextra -pedantic
LDADD = -L$(top_srcdir)/ -lcriterion
if ENABLE_RT_TESTS
BIN_TESTS += with-time
with_time_LDADD = $(LDADD) -lrt
endif
SCRIPT_TESTS = tests/tap_test.sh \
tests/early_exit.sh \
tests/verbose.sh \
tests/list.sh \
tests/pattern.sh \
tests/fail_fast.sh \
tests/help.sh
EXTRA_DIST = $(SCRIPT_TESTS)
tests/tap_test.sh: simple signal asserts
tests/early_exit.sh: simple
tests/verbose.sh: simple
tests/help.sh: simple
TESTS = $(BIN_TESTS) $(SCRIPT_TESTS)

View file

@ -6,7 +6,7 @@ Test(asserts, base) {
cr_assert(true, "Assertions may take failure messages");
cr_assert(true, .msg = "You can use explicit named arguments");
cr_assert(true, "Or even %d format string %s", 1, "with parameters");
cr_expect(false, "assert is fatal, expect isn't");
cr_assert(false, "This assert runs");
@ -14,23 +14,24 @@ Test(asserts, base) {
}
Test(asserts, old_school) {
if (false)
cr_abort_test("You can abort the test with a message from anywhere");
cr_abort_test(NULL); // or without a message
cr_expect_fail("You can fail an assertion with a message from anywhere");
cr_assert_fail(); // or without a message
}
Test(asserts, string) {
cr_assert_strings_eq("hello", "hello");
cr_assert_strings_neq("hello", "olleh");
cr_assert_str_empty("");
cr_assert_str_not_empty("foo");
cr_assert_strings_gt("hello", "hell");
cr_assert_strings_geq("hello", "hell");
cr_assert_strings_geq("hello", "hello");
cr_assert_str_eq("hello", "hello");
cr_assert_str_neq("hello", "olleh");
cr_assert_strings_lt("hell", "hello");
cr_assert_strings_leq("hell", "hello");
cr_assert_strings_leq("hello", "hello");
cr_assert_str_gt("hello", "hell");
cr_assert_str_geq("hello", "hell");
cr_assert_str_geq("hello", "hello");
cr_assert_str_lt("hell", "hello");
cr_assert_str_leq("hell", "hello");
cr_assert_str_leq("hello", "hello");
}
Test(asserts, native) {
@ -64,6 +65,10 @@ Test(asserts, array) {
int arr1[] = {1, 2, 3, 4};
int arr2[] = {4, 3, 2, 1};
cr_assert_arr_eq(arr1, arr1, 4);
cr_assert_arr_neq(arr1, arr2, 4);
#ifdef __GNUC__
struct dummy_struct s1[] = {{4, 2}, {2, 4}};
struct dummy_struct s2[2];
memset(s2, 0xFF, sizeof(s2));
@ -72,9 +77,7 @@ Test(asserts, array) {
s2[1].a = 2;
s2[1].b = 4;
cr_assert_arrays_eq(arr1, arr1, 4);
cr_assert_arrays_neq(arr1, arr2, 4);
cr_assert_arrays_neq(s1, s2, 2);
cr_assert_arrays_eq_cmp(s1, s2, 2, eq_dummy);
// cr_assert_arr_eq(s1, s2, 2); not guaranteed to work on structs.
cr_assert_arr_eq_cmp(s1, s2, 2, eq_dummy);
#endif
}

90
samples/asserts.cc Normal file
View file

@ -0,0 +1,90 @@
#include <criterion/criterion.h>
#include <exception>
#include <new>
Test(asserts, base) {
cr_assert(true);
cr_expect(true);
cr_assert(true, "Assertions may take failure messages");
cr_assert(true, "Or even %d format string %s", 1, "with parameters");
cr_expect(false, "assert is fatal, expect isn't");
cr_assert(false, "This assert runs");
cr_assert(false, "This does not");
}
Test(asserts, old_school) {
cr_expect_fail("You can fail an assertion with a message from anywhere");
cr_assert_fail(); // or without a message
}
Test(asserts, string) {
cr_assert_str_empty("");
cr_assert_str_not_empty("foo");
cr_assert_str_eq("hello", "hello");
cr_assert_str_neq("hello", "olleh");
cr_assert_str_gt("hello", "hell");
cr_assert_str_geq("hello", "hell");
cr_assert_str_geq("hello", "hello");
cr_assert_str_lt("hell", "hello");
cr_assert_str_leq("hell", "hello");
cr_assert_str_leq("hello", "hello");
}
Test(asserts, native) {
cr_assert_eq(1, 1);
cr_assert_neq(1, 2);
cr_assert_lt(1, 2);
cr_assert_leq(1, 2);
cr_assert_leq(2, 2);
cr_assert_gt(2, 1);
cr_assert_geq(2, 1);
cr_assert_geq(2, 2);
}
Test(asserts, float) {
cr_assert_neq(0.1 * 0.1, 0.01);
cr_assert_float_eq(0.1 * 0.1, 0.01, 0.001);
}
struct dummy_struct {
char a;
size_t b;
};
int eq_dummy(struct dummy_struct *a, struct dummy_struct *b) {
return a->a != b->a || a->b != b->b;
}
Test(asserts, array) {
int arr1[] = {1, 2, 3, 4};
int arr2[] = {4, 3, 2, 1};
cr_assert_arr_eq(arr1, arr1, 4);
cr_assert_arr_neq(arr1, arr2, 4);
#ifdef __GNUC__
struct dummy_struct s1[] = {{4, 2}, {2, 4}};
struct dummy_struct s2[2];
memset(s2, 0xFF, sizeof(s2));
s2[0].a = 4;
s2[0].b = 2;
s2[1].a = 2;
s2[1].b = 4;
// cr_assert_arrays_eq(&s1, &s2, 2); not guaranteed to work on structs.
cr_assert_arr_eq_cmp(&s1, &s2, 2, eq_dummy);
#endif
}
Test(asserts, exception) {
cr_assert_throw(throw std::exception(), std::exception);
cr_assert_throw(throw std::exception(), std::bad_alloc);
}

8
samples/description.cc Normal file
View file

@ -0,0 +1,8 @@
#include <criterion/criterion.h>
Test(misc, failing, .description = "Just a failing test") {
cr_assert(0);
}
Test(misc, skipped, .description = "This one is skipped", .disabled = true) {
}

14
samples/fixtures.cc Normal file
View file

@ -0,0 +1,14 @@
#include <criterion/criterion.h>
#include <stdio.h>
void setup(void) {
puts("Runs before the test");
}
void teardown(void) {
puts("Runs after the test");
}
Test(simple, fixtures, .init = setup, .fini = teardown) {
cr_assert(1);
}

21
samples/more-suites.cc Normal file
View file

@ -0,0 +1,21 @@
#include <criterion/criterion.h>
void setup_suite(void) {
}
void teardown_suite(void) {
}
TestSuite(suite1, .init = setup_suite, .fini = teardown_suite);
Test(suite1, test) {
cr_assert(1);
}
Test(suite2, test) {
cr_assert(1);
}
TestSuite(disabled, .disabled = true);
Test(disabled, test) {}

View file

@ -1,6 +1,7 @@
[----] asserts.c:11: Assertion failed: assert is fatal, expect isn't
[----] asserts.c:12: Assertion failed: This assert runs
[FAIL] asserts::base: (0.00s)
[----] asserts.c:20: Assertion failed: The conditions for this test were not met.
[----] asserts.c:17: Assertion failed: You can fail an assertion with a message from anywhere
[----] asserts.c:18: Assertion failed: The conditions for this assertion were not met.
[FAIL] asserts::old_school: (0.00s)
[====] Synthesis: Tested: 6 | Passing: 4 | Failing: 2 | Crashing: 0 

View file

@ -0,0 +1,11 @@
[----] asserts.cc:83: Assertion failed: The expression (&s1)[0 .. 2] == (&s2)[0 .. 2] is false.
[FAIL] asserts::array: (0.00s)
[----] asserts.cc:13: Assertion failed: assert is fatal, expect isn't
[----] asserts.cc:14: Assertion failed: This assert runs
[FAIL] asserts::base: (0.00s)
[----] asserts.cc:89: Assertion failed: The statement `throw std::exception()` did not throw an instance of the `std::bad_alloc` exception.
[FAIL] asserts::exception: (0.00s)
[----] asserts.cc:19: Assertion failed: You can fail an assertion with a message from anywhere
[----] asserts.cc:20: Assertion failed: The conditions for this assertion were not met.
[FAIL] asserts::old_school: (0.00s)
[====] Synthesis: Tested: 7 | Passing: 3 | Failing: 4 | Crashing: 0 

View file

@ -1,3 +1,3 @@
[----] description.c:4: Assertion failed: 0
[----] description.c:4: Assertion failed: The expression 0 is false.
[FAIL] misc::failing: (0.00s)
[====] Synthesis: Tested: 1 | Passing: 0 | Failing: 1 | Crashing: 0 

View file

@ -0,0 +1,3 @@
[----] description.cc:4: Assertion failed: The expression 0 is false.
[FAIL] misc::failing: (0.00s)
[====] Synthesis: Tested: 1 | Passing: 0 | Failing: 1 | Crashing: 0 

View file

@ -0,0 +1 @@
[====] Synthesis: Tested: 1 | Passing: 1 | Failing: 0 | Crashing: 0 

View file

@ -0,0 +1,2 @@
Runs before the test
Runs after the test

View file

@ -0,0 +1,3 @@
[----] Warning! The test `misc::setup_crash` crashed during its setup or teardown.
[----] Warning! The test `misc::teardown_crash` crashed during its setup or teardown.
[====] Synthesis: Tested: 2 | Passing: 1 | Failing: 1 | Crashing: 1 

View file

@ -0,0 +1 @@
[====] Synthesis: Tested: 2 | Passing: 2 | Failing: 0 | Crashing: 0 

View file

@ -0,0 +1 @@
[====] Synthesis: Tested: 2 | Passing: 2 | Failing: 0 | Crashing: 0 

View file

@ -1,3 +1,3 @@
[----] report.c:5: Assertion failed: 0
[----] report.c:5: Assertion failed: The expression 0 is false.
[FAIL] sample::test: (0.00s)
[====] Synthesis: Tested: 1 | Passing: 0 | Failing: 1 | Crashing: 0 

View file

@ -0,0 +1,3 @@
[----] report.cc:5: Assertion failed: The expression 0 is false.
[FAIL] sample::test: (0.00s)
[====] Synthesis: Tested: 1 | Passing: 0 | Failing: 1 | Crashing: 0 

View file

@ -0,0 +1,4 @@
criterion_init
testing test in category sample
Asserts: [1 passed, 1 failed, 2 total]
criterion_fini

View file

@ -0,0 +1,4 @@
[----] signal.cc:16: Unexpected signal caught below this line!
[FAIL] simple::uncaught: CRASH!
[FAIL] simple::wrong_signal: (0.00s)
[====] Synthesis: Tested: 3 | Passing: 1 | Failing: 2 | Crashing: 1 

View file

@ -1,3 +1,3 @@
[----] simple.c:4: Assertion failed: 0
[----] simple.c:4: Assertion failed: The expression 0 is false.
[FAIL] misc::failing: (0.00s)
[====] Synthesis: Tested: 2 | Passing: 1 | Failing: 1 | Crashing: 0 

View file

@ -0,0 +1,3 @@
[----] simple.cc:4: Assertion failed: The expression 0 is false.
[FAIL] misc::failing: (0.00s)
[====] Synthesis: Tested: 2 | Passing: 1 | Failing: 1 | Crashing: 0 

View file

@ -0,0 +1 @@
[====] Synthesis: Tested: 2 | Passing: 2 | Failing: 0 | Crashing: 0 

View file

@ -0,0 +1 @@
[====] Synthesis: Tested: 2 | Passing: 2 | Failing: 0 | Crashing: 0 

52
samples/redirect.c Normal file
View file

@ -0,0 +1,52 @@
#include <criterion/criterion.h>
#include <criterion/redirect.h>
#include <stdio.h>
#include <ctype.h>
// Testing stdout/stderr
void redirect_all_std(void) {
cr_redirect_stdout();
cr_redirect_stderr();
}
Test(redirect, test_outputs, .init = redirect_all_std) {
fprintf(stdout, "foo");
fflush(stdout);
cr_assert_stdout_eq_str("foo");
fprintf(stderr, "bar");
fflush(stderr);
cr_assert_stderr_eq_str("bar");
}
// Testing general I/O with sample command-line rot13
char rot13_char(char c) {
return isalpha(c) ? (c - 'a' + 13) % 26 + 'a' : c;
}
void rot13_io(void) {
char buf[512];
size_t read;
while ((read = fread(buf, 1, sizeof (buf), stdin)) > 0) {
for (size_t i = 0; i < read; ++i)
buf[i] = rot13_char(buf[i]);
fwrite(buf, 1, read, stdout);
}
fflush(stdout);
}
Test(redirect, rot13, .init = cr_redirect_stdout) {
FILE* f_stdin = cr_get_redirected_stdin();
fprintf(f_stdin, "the quick brown fox jumps over the lazy dog");
fclose(f_stdin);
rot13_io();
cr_assert_stdout_eq_str("gur dhvpx oebja sbk whzcf bire gur ynml qbt");
}

52
samples/redirect.cc Normal file
View file

@ -0,0 +1,52 @@
#include <criterion/criterion.h>
#include <criterion/redirect.h>
#include <string>
#include <iostream>
#include <fstream>
#include <cctype>
#ifdef __GNUC__
# include <ext/stdio_filebuf.h>
#endif
// Testing stdout/stderr
void redirect_all_std(void) {
cr_redirect_stdout();
cr_redirect_stderr();
}
Test(redirect, test_outputs, .init = redirect_all_std) {
std::cout << "foo" << std::flush;
std::cerr << "bar" << std::flush;
cr_assert_stdout_eq_str("foo");
cr_assert_stderr_eq_str("bar");
}
// Testing general I/O with sample command-line rot13
char rot13_char(char c) {
return std::isalpha(c) ? (c - 'a' + 13) % 26 + 'a' : c;
}
void rot13_io(void) {
std::string s;
std::cin >> s;
for (size_t i = 0; i < s.length(); ++i)
s[i] = rot13_char(s[i]);
std::cout << s << std::flush;
}
Test(redirect, rot13, .init = cr_redirect_stdout) {
auto& f_cin = criterion::get_redirected_cin();
f_cin << "the quick brown fox jumps over the lazy dog";
f_cin.close();
rot13_io();
cr_assert_stdout_eq_str("gur dhvpx oebja sbk whzcf bire gur ynml qbt");
}

View file

@ -15,10 +15,12 @@ ReportHook(POST_TEST)(struct criterion_test_stats *stats) {
stats->passed_asserts, stats->failed_asserts, stats->passed_asserts + stats->failed_asserts);
}
ReportHook(PRE_ALL)() {
ReportHook(PRE_ALL)(struct criterion_test_set *tests) {
(void) tests;
puts("criterion_init");
}
ReportHook(POST_ALL)() {
ReportHook(POST_ALL)(struct criterion_global_stats *stats) {
(void) stats;
puts("criterion_fini");
}

26
samples/report.cc Normal file
View file

@ -0,0 +1,26 @@
#include <stdio.h>
#include <criterion/criterion.h>
Test(sample, test) {
cr_expect(0);
cr_assert(1);
}
ReportHook(PRE_INIT)(struct criterion_test *test) {
printf("testing %s in category %s\n", test->name, test->category);
}
ReportHook(POST_TEST)(struct criterion_test_stats *stats) {
printf("Asserts: [%d passed, %d failed, %d total]\n",
stats->passed_asserts, stats->failed_asserts, stats->passed_asserts + stats->failed_asserts);
}
ReportHook(PRE_ALL)(struct criterion_test_set *tests) {
(void) tests;
puts("criterion_init");
}
ReportHook(POST_ALL)(struct criterion_global_stats *stats) {
(void) stats;
puts("criterion_fini");
}

19
samples/signal.cc Normal file
View file

@ -0,0 +1,19 @@
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <criterion/criterion.h>
Test(simple, caught, .signal = SIGSEGV) {
int *i = NULL;
*i = 42;
}
Test(simple, wrong_signal, .signal = SIGINT) {
int *i = NULL;
*i = 42;
}
Test(simple, uncaught) {
int *i = NULL;
*i = 42;
}

9
samples/simple.cc Normal file
View file

@ -0,0 +1,9 @@
#include <criterion/criterion.h>
Test(misc, failing) {
cr_assert(0);
}
Test(misc, passing) {
cr_assert(1);
}

9
samples/suites.cc Normal file
View file

@ -0,0 +1,9 @@
#include <criterion/criterion.h>
Test(first_suite, test) {
cr_assert(1);
}
Test(second_suite, test) {
cr_assert(1);
}

View file

@ -0,0 +1,13 @@
set(SAMPLES
failmessages.c
exit.c
long-messages.c
other-crashes.c
failmessages.cc
exit.cc
long-messages.cc
other-crashes.cc
)
add_samples("${CMAKE_CURRENT_LIST_DIR}" "${SAMPLES}")

View file

@ -1,2 +1,3 @@
#!/bin/sh
./simple --no-early-exit --always-succeed
./simple.c.bin --no-early-exit --always-succeed
./theories.c.bin --no-early-exit --always-succeed

24
samples/tests/exit.c Normal file
View file

@ -0,0 +1,24 @@
#include <stdio.h>
#include <stdlib.h>
#include <criterion/criterion.h>
Test(exit, normal, .exit_code = 0) {
}
Test(exit, expected_exit, .exit_code = 42) {
exit(42);
}
Test(exit, unexpected_exit) {
exit(127);
}
void do_exit (void) {
exit(127);
}
Test(exit_with_fixtures, init_exits, .init = do_exit) {
}
Test(exit_with_fixtures, fini_exits, .fini = do_exit) {
}

24
samples/tests/exit.cc Normal file
View file

@ -0,0 +1,24 @@
#include <stdio.h>
#include <stdlib.h>
#include <criterion/criterion.h>
Test(exit, normal, .exit_code = 0) {
}
Test(exit, expected_exit, .exit_code = 42) {
exit(42);
}
Test(exit, unexpected_exit) {
exit(127);
}
void do_exit (void) {
exit(127);
}
Test(exit_with_fixtures, init_exits, .init = do_exit) {
}
Test(exit_with_fixtures, fini_exits, .fini = do_exit) {
}

Some files were not shown because too many files have changed in this diff Show more