[v2.0.0] Merge branch 'bleeding' (Version release)
This commit is contained in:
commit
a0af6a0af1
155 changed files with 4579 additions and 764 deletions
|
@ -1,6 +1,6 @@
|
|||
[bumpversion]
|
||||
current_version = 1.3.1
|
||||
commit = True
|
||||
commit = False
|
||||
|
||||
[bumpversion:file:CMakeLists.txt]
|
||||
|
||||
|
|
|
@ -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
|
||||
)
|
|
@ -1,4 +0,0 @@
|
|||
#!/bin/sh
|
||||
curl -O https://bootstrap.pypa.io/get-pip.py
|
||||
python3 get-pip.py
|
||||
rm -f get-pip.py
|
31
.cmake/Modules/FindDyncall.cmake
Normal file
31
.cmake/Modules/FindDyncall.cmake
Normal 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)
|
56
.cmake/Modules/Submodules.cmake
Normal file
56
.cmake/Modules/Submodules.cmake
Normal 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
15
.gitignore
vendored
|
@ -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
9
.gitmodules
vendored
Normal 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
|
17
.travis.yml
17
.travis.yml
|
@ -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
|
||||
|
|
|
@ -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
44
CONTRIBUTING.md
Normal 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
|
23
ChangeLog
23
ChangeLog
|
@ -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
|
||||
|
|
54
README.md
54
README.md
|
@ -2,12 +2,13 @@
|
|||
<img src="doc/criterion-title.png" height="96" alt="Criterion Logo" />
|
||||
=========
|
||||
|
||||
[](https://travis-ci.org/Snaipe/Criterion)
|
||||
[](https://travis-ci.org/Snaipe/Criterion)
|
||||
[](https://ci.appveyor.com/project/Snaipe/Criterion/branch/bleeding)
|
||||
[](https://coveralls.io/r/Snaipe/Criterion?branch=bleeding)
|
||||
[](https://github.com/Snaipe/Criterion/blob/master/LICENSE)
|
||||
[](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.
|
||||
|
||||

|
||||
|
||||
|
@ -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: [](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
|
||||
|
|
49
appveyor.yml
49
appveyor.yml
|
@ -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
1
dependencies/dyncall
vendored
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 68c57f664d4fabbc5b80327fbf5661a3a5a51e06
|
1
dependencies/libcsptr
vendored
Submodule
1
dependencies/libcsptr
vendored
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 2762164acfaa712fea7dec6ed760ff88f7d2e026
|
1
dependencies/wingetopt
vendored
Submodule
1
dependencies/wingetopt
vendored
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 76a5d1ab15f684d4c9479a32624d65b3bd1a726b
|
27
dev/FindCriterion.cmake
Normal file
27
dev/FindCriterion.cmake
Normal 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
144
doc/assert.rst
Normal 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``.
|
||||
=============================================================================== ============================================================================ ===========================================
|
||||
|
|
@ -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``.
|
||||
|
|
|
@ -7,7 +7,9 @@ Criterion
|
|||
intro
|
||||
setup
|
||||
starter
|
||||
assert
|
||||
hooks
|
||||
env
|
||||
theories
|
||||
internal
|
||||
faq
|
||||
|
|
|
@ -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
|
||||
-------------------------------------
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
242
doc/theories.rst
Normal 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``.
|
||||
|
||||
|
|
@ -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_ */
|
||||
|
|
43
include/criterion/asprintf-compat.h
Normal file
43
include/criterion/asprintf-compat.h
Normal 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_ */
|
|
@ -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__)
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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_ */
|
||||
|
|
125
include/criterion/designated-initializer-compat.h
Normal file
125
include/criterion/designated-initializer-compat.h
Normal 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_ */
|
|
@ -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_ */
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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;) \
|
||||
|
|
73
include/criterion/preprocess.h
Normal file
73
include/criterion/preprocess.h
Normal 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_ */
|
235
include/criterion/redirect.h
Normal file
235
include/criterion/redirect.h
Normal 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_ */
|
|
@ -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;
|
||||
|
|
145
include/criterion/theories.h
Normal file
145
include/criterion/theories.h
Normal 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_ */
|
|
@ -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_ */
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
# List of source files which contain translatable strings.
|
||||
src/log/normal.c
|
||||
src/i18n.c
|
||||
|
|
109
po/fr.po
109
po/fr.po
|
@ -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`."
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
|
@ -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
90
samples/asserts.cc
Normal 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
8
samples/description.cc
Normal 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
14
samples/fixtures.cc
Normal 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
21
samples/more-suites.cc
Normal 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) {}
|
|
@ -1,6 +1,7 @@
|
|||
[[0;34m----[0m] [0;1masserts.c[0m:[0;31m11[0m: Assertion failed: assert is fatal, expect isn't
|
||||
[[0;34m----[0m] [0;1masserts.c[0m:[0;31m12[0m: Assertion failed: This assert runs
|
||||
[[0;31mFAIL[0m] asserts::base: (0.00s)
|
||||
[[0;34m----[0m] [0;1masserts.c[0m:[0;31m20[0m: Assertion failed: The conditions for this test were not met.
|
||||
[[0;34m----[0m] [0;1masserts.c[0m:[0;31m17[0m: Assertion failed: You can fail an assertion with a message from anywhere
|
||||
[[0;34m----[0m] [0;1masserts.c[0m:[0;31m18[0m: Assertion failed: The conditions for this assertion were not met.
|
||||
[[0;31mFAIL[0m] asserts::old_school: (0.00s)
|
||||
[[0;34m====[0m] [0;1mSynthesis: Tested: [0;34m6[0;1m | Passing: [0;32m4[0;1m | Failing: [0;31m2[0;1m | Crashing: [0;31m0[0;1m [0m
|
11
samples/outputs/asserts.cc.bin.err.expected
Normal file
11
samples/outputs/asserts.cc.bin.err.expected
Normal file
|
@ -0,0 +1,11 @@
|
|||
[[0;34m----[0m] [0;1masserts.cc[0m:[0;31m83[0m: Assertion failed: The expression (&s1)[0 .. 2] == (&s2)[0 .. 2] is false.
|
||||
[[0;31mFAIL[0m] asserts::array: (0.00s)
|
||||
[[0;34m----[0m] [0;1masserts.cc[0m:[0;31m13[0m: Assertion failed: assert is fatal, expect isn't
|
||||
[[0;34m----[0m] [0;1masserts.cc[0m:[0;31m14[0m: Assertion failed: This assert runs
|
||||
[[0;31mFAIL[0m] asserts::base: (0.00s)
|
||||
[[0;34m----[0m] [0;1masserts.cc[0m:[0;31m89[0m: Assertion failed: The statement `throw std::exception()` did not throw an instance of the `std::bad_alloc` exception.
|
||||
[[0;31mFAIL[0m] asserts::exception: (0.00s)
|
||||
[[0;34m----[0m] [0;1masserts.cc[0m:[0;31m19[0m: Assertion failed: You can fail an assertion with a message from anywhere
|
||||
[[0;34m----[0m] [0;1masserts.cc[0m:[0;31m20[0m: Assertion failed: The conditions for this assertion were not met.
|
||||
[[0;31mFAIL[0m] asserts::old_school: (0.00s)
|
||||
[[0;34m====[0m] [0;1mSynthesis: Tested: [0;34m7[0;1m | Passing: [0;32m3[0;1m | Failing: [0;31m4[0;1m | Crashing: [0;31m0[0;1m [0m
|
|
@ -1,3 +1,3 @@
|
|||
[[0;34m----[0m] [0;1mdescription.c[0m:[0;31m4[0m: Assertion failed: 0
|
||||
[[0;34m----[0m] [0;1mdescription.c[0m:[0;31m4[0m: Assertion failed: The expression 0 is false.
|
||||
[[0;31mFAIL[0m] misc::failing: (0.00s)
|
||||
[[0;34m====[0m] [0;1mSynthesis: Tested: [0;34m1[0;1m | Passing: [0;32m0[0;1m | Failing: [0;31m1[0;1m | Crashing: [0;31m0[0;1m [0m
|
3
samples/outputs/description.cc.bin.err.expected
Normal file
3
samples/outputs/description.cc.bin.err.expected
Normal file
|
@ -0,0 +1,3 @@
|
|||
[[0;34m----[0m] [0;1mdescription.cc[0m:[0;31m4[0m: Assertion failed: The expression 0 is false.
|
||||
[[0;31mFAIL[0m] misc::failing: (0.00s)
|
||||
[[0;34m====[0m] [0;1mSynthesis: Tested: [0;34m1[0;1m | Passing: [0;32m0[0;1m | Failing: [0;31m1[0;1m | Crashing: [0;31m0[0;1m [0m
|
1
samples/outputs/fixtures.cc.bin.err.expected
Normal file
1
samples/outputs/fixtures.cc.bin.err.expected
Normal file
|
@ -0,0 +1 @@
|
|||
[[0;34m====[0m] [0;1mSynthesis: Tested: [0;34m1[0;1m | Passing: [0;32m1[0;1m | Failing: [0;31m0[0;1m | Crashing: [0;31m0[0;1m [0m
|
2
samples/outputs/fixtures.cc.bin.out.expected
Normal file
2
samples/outputs/fixtures.cc.bin.out.expected
Normal file
|
@ -0,0 +1,2 @@
|
|||
Runs before the test
|
||||
Runs after the test
|
3
samples/outputs/other-crashes.cc.bin.err.expected
Normal file
3
samples/outputs/other-crashes.cc.bin.err.expected
Normal file
|
@ -0,0 +1,3 @@
|
|||
[[0;34m----[0m] [0;1mWarning! The test `misc::setup_crash` crashed during its setup or teardown.[0m
|
||||
[[0;34m----[0m] [0;1mWarning! The test `misc::teardown_crash` crashed during its setup or teardown.[0m
|
||||
[[0;34m====[0m] [0;1mSynthesis: Tested: [0;34m2[0;1m | Passing: [0;32m1[0;1m | Failing: [0;31m1[0;1m | Crashing: [0;31m1[0;1m [0m
|
1
samples/outputs/redirect.c.bin.err.expected
Normal file
1
samples/outputs/redirect.c.bin.err.expected
Normal file
|
@ -0,0 +1 @@
|
|||
[[0;34m====[0m] [0;1mSynthesis: Tested: [0;34m2[0;1m | Passing: [0;32m2[0;1m | Failing: [0;31m0[0;1m | Crashing: [0;31m0[0;1m [0m
|
0
samples/outputs/redirect.c.bin.out.expected
Normal file
0
samples/outputs/redirect.c.bin.out.expected
Normal file
1
samples/outputs/redirect.cc.bin.err.expected
Normal file
1
samples/outputs/redirect.cc.bin.err.expected
Normal file
|
@ -0,0 +1 @@
|
|||
[[0;34m====[0m] [0;1mSynthesis: Tested: [0;34m2[0;1m | Passing: [0;32m2[0;1m | Failing: [0;31m0[0;1m | Crashing: [0;31m0[0;1m [0m
|
0
samples/outputs/redirect.cc.bin.out.expected
Normal file
0
samples/outputs/redirect.cc.bin.out.expected
Normal file
|
@ -1,3 +1,3 @@
|
|||
[[0;34m----[0m] [0;1mreport.c[0m:[0;31m5[0m: Assertion failed: 0
|
||||
[[0;34m----[0m] [0;1mreport.c[0m:[0;31m5[0m: Assertion failed: The expression 0 is false.
|
||||
[[0;31mFAIL[0m] sample::test: (0.00s)
|
||||
[[0;34m====[0m] [0;1mSynthesis: Tested: [0;34m1[0;1m | Passing: [0;32m0[0;1m | Failing: [0;31m1[0;1m | Crashing: [0;31m0[0;1m [0m
|
3
samples/outputs/report.cc.bin.err.expected
Normal file
3
samples/outputs/report.cc.bin.err.expected
Normal file
|
@ -0,0 +1,3 @@
|
|||
[[0;34m----[0m] [0;1mreport.cc[0m:[0;31m5[0m: Assertion failed: The expression 0 is false.
|
||||
[[0;31mFAIL[0m] sample::test: (0.00s)
|
||||
[[0;34m====[0m] [0;1mSynthesis: Tested: [0;34m1[0;1m | Passing: [0;32m0[0;1m | Failing: [0;31m1[0;1m | Crashing: [0;31m0[0;1m [0m
|
4
samples/outputs/report.cc.bin.out.expected
Normal file
4
samples/outputs/report.cc.bin.out.expected
Normal file
|
@ -0,0 +1,4 @@
|
|||
criterion_init
|
||||
testing test in category sample
|
||||
Asserts: [1 passed, 1 failed, 2 total]
|
||||
criterion_fini
|
0
samples/outputs/signal.c.bin.out.expected
Normal file
0
samples/outputs/signal.c.bin.out.expected
Normal file
4
samples/outputs/signal.cc.bin.err.expected
Normal file
4
samples/outputs/signal.cc.bin.err.expected
Normal file
|
@ -0,0 +1,4 @@
|
|||
[[0;34m----[0m] [0;1msignal.cc[0m:[0;31m16[0m: Unexpected signal caught below this line!
|
||||
[[0;31mFAIL[0m] simple::uncaught: CRASH!
|
||||
[[0;31mFAIL[0m] simple::wrong_signal: (0.00s)
|
||||
[[0;34m====[0m] [0;1mSynthesis: Tested: [0;34m3[0;1m | Passing: [0;32m1[0;1m | Failing: [0;31m2[0;1m | Crashing: [0;31m1[0;1m [0m
|
0
samples/outputs/signal.cc.bin.out.expected
Normal file
0
samples/outputs/signal.cc.bin.out.expected
Normal file
|
@ -1,3 +1,3 @@
|
|||
[[0;34m----[0m] [0;1msimple.c[0m:[0;31m4[0m: Assertion failed: 0
|
||||
[[0;34m----[0m] [0;1msimple.c[0m:[0;31m4[0m: Assertion failed: The expression 0 is false.
|
||||
[[0;31mFAIL[0m] misc::failing: (0.00s)
|
||||
[[0;34m====[0m] [0;1mSynthesis: Tested: [0;34m2[0;1m | Passing: [0;32m1[0;1m | Failing: [0;31m1[0;1m | Crashing: [0;31m0[0;1m [0m
|
0
samples/outputs/simple.c.bin.out.expected
Normal file
0
samples/outputs/simple.c.bin.out.expected
Normal file
3
samples/outputs/simple.cc.bin.err.expected
Normal file
3
samples/outputs/simple.cc.bin.err.expected
Normal file
|
@ -0,0 +1,3 @@
|
|||
[[0;34m----[0m] [0;1msimple.cc[0m:[0;31m4[0m: Assertion failed: The expression 0 is false.
|
||||
[[0;31mFAIL[0m] misc::failing: (0.00s)
|
||||
[[0;34m====[0m] [0;1mSynthesis: Tested: [0;34m2[0;1m | Passing: [0;32m1[0;1m | Failing: [0;31m1[0;1m | Crashing: [0;31m0[0;1m [0m
|
0
samples/outputs/simple.cc.bin.out.expected
Normal file
0
samples/outputs/simple.cc.bin.out.expected
Normal file
1
samples/outputs/suites.c.bin.err.expected
Normal file
1
samples/outputs/suites.c.bin.err.expected
Normal file
|
@ -0,0 +1 @@
|
|||
[[0;34m====[0m] [0;1mSynthesis: Tested: [0;34m2[0;1m | Passing: [0;32m2[0;1m | Failing: [0;31m0[0;1m | Crashing: [0;31m0[0;1m [0m
|
0
samples/outputs/suites.c.bin.out.expected
Normal file
0
samples/outputs/suites.c.bin.out.expected
Normal file
1
samples/outputs/suites.cc.bin.err.expected
Normal file
1
samples/outputs/suites.cc.bin.err.expected
Normal file
|
@ -0,0 +1 @@
|
|||
[[0;34m====[0m] [0;1mSynthesis: Tested: [0;34m2[0;1m | Passing: [0;32m2[0;1m | Failing: [0;31m0[0;1m | Crashing: [0;31m0[0;1m [0m
|
0
samples/outputs/suites.cc.bin.out.expected
Normal file
0
samples/outputs/suites.cc.bin.out.expected
Normal file
52
samples/redirect.c
Normal file
52
samples/redirect.c
Normal 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
52
samples/redirect.cc
Normal 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");
|
||||
}
|
|
@ -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
26
samples/report.cc
Normal 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
19
samples/signal.cc
Normal 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
9
samples/simple.cc
Normal 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
9
samples/suites.cc
Normal file
|
@ -0,0 +1,9 @@
|
|||
#include <criterion/criterion.h>
|
||||
|
||||
Test(first_suite, test) {
|
||||
cr_assert(1);
|
||||
}
|
||||
|
||||
Test(second_suite, test) {
|
||||
cr_assert(1);
|
||||
}
|
13
samples/tests/CMakeLists.txt
Normal file
13
samples/tests/CMakeLists.txt
Normal 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}")
|
|
@ -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
24
samples/tests/exit.c
Normal 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
24
samples/tests/exit.cc
Normal 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
Loading…
Add table
Reference in a new issue