pax_global_header00006660000000000000000000000064145046117540014521gustar00rootroot0000000000000052 comment=abb74b39545fd7006a44e7b763605b7796e05a6e cgreen-1.6.3/000077500000000000000000000000001450461175400127735ustar00rootroot00000000000000cgreen-1.6.3/.cproject000066400000000000000000000052011450461175400146030ustar00rootroot00000000000000 make all true false true rm -rf build true false true cgreen-1.6.3/.dir-locals.el000066400000000000000000000001161450461175400154220ustar00rootroot00000000000000((c-mode . ( (indent-tabs-mode . nil) (c-basic-offset . 4) ) ) ) cgreen-1.6.3/.gitattributes000066400000000000000000000005721450461175400156720ustar00rootroot00000000000000# Auto detect text files and perform LF normalization * text=auto # Custom for Visual Studio *.cs diff=csharp # Standard to msysgit *.doc diff=astextplain *.DOC diff=astextplain *.docx diff=astextplain *.DOCX diff=astextplain *.dot diff=astextplain *.DOT diff=astextplain *.pdf diff=astextplain *.PDF diff=astextplain *.rtf diff=astextplain *.RTF diff=astextplain cgreen-1.6.3/.github/000077500000000000000000000000001450461175400143335ustar00rootroot00000000000000cgreen-1.6.3/.github/workflows/000077500000000000000000000000001450461175400163705ustar00rootroot00000000000000cgreen-1.6.3/.github/workflows/asciidoctor-docs.yml000066400000000000000000000014501450461175400223440ustar00rootroot00000000000000name: asciidoctor-docs on: push: branches: - master jobs: # This workflow contains a single job called "build" build: # The type of runner that the job will run on runs-on: ubuntu-latest # Steps represent a sequence of tasks that will be executed as part of the job steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - uses: actions/checkout@v3 # Includes the AsciiDoctor GitHub Pages Action to convert adoc files to html and publish to gh-pages branch - name: asciidoctor-ghpages uses: manoelcampos/asciidoctor-ghpages-action@v2.2.4 with: asciidoctor_params: -r asciidoctor-diagram -a VERSION=1.6.0 source_dir: doc post_build: git add -f *.png adoc_file_ext: .asciidoc cgreen-1.6.3/.gitignore000066400000000000000000000002451450461175400147640ustar00rootroot00000000000000build .idea CMakeCache.txt CMakeFiles Testing *.exe *.stackdump *.so build-stamp configure-stamp *~ #*# .#* bin lib valgrind.log gitrevision.h .cgreen-debug-commandscgreen-1.6.3/.project000066400000000000000000000043631450461175400144500ustar00rootroot00000000000000 cgreen org.eclipse.cdt.managedbuilder.core.genmakebuilder clean,full,incremental, ?name? org.eclipse.cdt.make.core.append_environment true org.eclipse.cdt.make.core.autoBuildTarget all org.eclipse.cdt.make.core.buildArguments org.eclipse.cdt.make.core.buildCommand make org.eclipse.cdt.make.core.cleanBuildTarget clean org.eclipse.cdt.make.core.contents org.eclipse.cdt.make.core.activeConfigSettings org.eclipse.cdt.make.core.enableAutoBuild false org.eclipse.cdt.make.core.enableCleanBuild true org.eclipse.cdt.make.core.enableFullBuild true org.eclipse.cdt.make.core.fullBuildTarget all org.eclipse.cdt.make.core.stopOnError true org.eclipse.cdt.make.core.useDefaultBuildCmd true org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder org.eclipse.cdt.core.cnature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.core.ccnature cgreen-1.6.3/.travis.yml000066400000000000000000000037161450461175400151130ustar00rootroot00000000000000language: c dist: focal # Build matrix arch: - amd64 - s390x compiler: - gcc - clang env: - CGREEN_WITH_STATIC_LIBRARY="OFF" - CGREEN_WITH_STATIC_LIBRARY="ON" addons: apt: packages: - cmake - lcov - g++ - valgrind - libxml2-dev before_install: - if [[ $CC == gcc ]] ; then export CXX=g++ ; else export CXX=clang++ ; fi - $CC --version - $CXX --version - gem install coveralls-lcov - if [ "$CC" = "gcc" ]; then export WITH_GCOV=ON; else WITH_GCOV=OFF; fi script: - mkdir -p build - cd build - cmake -DCGREEN_WITH_XML:BOOL=OFF -DCGREEN_WITH_LIBXML2:BOOL=OFF -DCGREEN_WITH_UNIT_TESTS:BOOL=ON -DCGREEN_WITH_STATIC_LIBRARY:BOOL=$CGREEN_WITH_STATIC_LIBRARY -DCGREEN_INTERNAL_WITH_GCOV:BOOL=OFF .. && make -j2 && ctest --output-on-failure - rm -f CMakeCache.txt - cmake -DCGREEN_WITH_UNIT_TESTS:BOOL=ON -DCGREEN_WITH_STATIC_LIBRARY:BOOL=$CGREEN_WITH_STATIC_LIBRARY -DCGREEN_INTERNAL_WITH_GCOV:BOOL=$WITH_GCOV .. && make -j2 && ctest --output-on-failure after_success: - if [ "$CC" = "gcc" ]; then lcov -d tests -d src -d tools -base-directory .. -c -o coverage.info; lcov --remove coverage.info '/usr/*' -o coverage.info; cd ..; coveralls-lcov build/coverage.info; fi notifications: slack: rooms: secure: "Tobw+sqwGWscQo/mnBiO/+CQDMu8of5kXUhFKK1GblxTqxvJGGRVVvjt5ZlYaTyJD6YCzaVAO9hSjMvebnTTIqqP5WFmhpO3Du3khZJhFjzhqfjIUmK4S0rAMs3BBvLTGAUa0Hvnrt1VOkOJUdwdSW8nmnw9uFx3rVCthAOLkQugUY4s8tCc/QHBJPUSqdKntTq9e4bapaMl4gREPFvtneOyN7LQp0JtI/nyrdTVlONaqkPv7M8sEC7a6ec6RK/AiEurp8XczNW0ifTwqCg2y/sLfnRg+wzG1H9sMmzs+Kx7akcGdGzi/rqWRnBDF3mKL4pt8YhmBy/znDnMAR559puRiyz6ZZhlBKRviZrsfQmC0F3IyTZY/S3SjvatT9DrAIsHDLbDNxRxzO0GC+cpkq4HU8VnF4rQ31VVb75igMHzgw3SvDOqsZ3g0jPiBybEi0jVRUzmDWrw7p6qtl5hwQam6dxfmO6xXpwOTqPI9WQEOZeZfOw7eIeEbpB5wJ723z2cEwutoDdConIZElJBKjcjFp5rjR/yG94H/0OEgCmC/JRrdd71BB9vPh4SO40RvKkxV0adY7Xk2vkAxwLFhxS7QIdNfyQBFFEBnR+JFBHE+9XwEH1JmaAbrSYgg0+vVUZPOuqcqvz+9PUTlAb5rqYB97XEbF//5t8URrriuB0=" cgreen-1.6.3/CMakeLists.txt000066400000000000000000000133071450461175400155370ustar00rootroot00000000000000# Required cmake version cmake_minimum_required(VERSION 2.8.12) project(cgreen) if (NOT(CMAKE_MAJOR_VERSION LESS 3) AND APPLE) if(POLICY CMP0042) cmake_policy(SET CMP0042 NEW) # CMake 3.0 to use @rpath on MacOSX libraries endif() endif() find_package (Threads) set(CGREEN_WITH_XML ON CACHE BOOL "Add a simple XML report generator without external dependencies") set(CGREEN_WITH_LIBXML2 ON CACHE BOOL "Add an XML report generator which uses libxml2 for output formatting") if (CGREEN_WITH_LIBXML2) find_package (LibXml2) if (NOT LibXml2_FOUND) set(CGREEN_WITH_LIBXML2 OFF) endif (NOT LibXml2_FOUND) endif (CGREEN_WITH_LIBXML2) enable_testing() # global needed variables set(APPLICATION_NAME ${PROJECT_NAME}) # VERSION: # NOTE: If you change version here, also change in # include/cgreen/cgreen.h unless you write some code that # automatically updates that... set(APPLICATION_VERSION_MAJOR "1") set(APPLICATION_VERSION_MINOR "6") set(APPLICATION_VERSION_PATCH "3") set(APPLICATION_VERSION ${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINOR}.${APPLICATION_VERSION_PATCH}${APPLICATION_VERSION_STATUS}) add_definitions(-DVERSION="${APPLICATION_VERSION}") set(LIBRARY_VERSION ${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINOR}.${APPLICATION_VERSION_PATCH}) set(LIBRARY_SOVERSION ${APPLICATION_VERSION_MAJOR}) # INSTALL: include(GNUInstallDirs) if(MSVC) # these have sensible defaults on other platforms set(CMAKE_INSTALL_BINDIR ".") set(CMAKE_INSTALL_LIBDIR ".") endif(MSVC) # If OSX and using Homebrew use its install prefix find_program(BREW brew) if (BREW) execute_process(COMMAND brew --prefix OUTPUT_VARIABLE CMAKE_INSTALL_PREFIX OUTPUT_STRIP_TRAILING_WHITESPACE) endif() # COMPLETION: set(BASHCOMPLETION_STATUS "Unavailable") find_package(bash-completion QUIET) if(BASH_COMPLETION_FOUND OR UNIX) set(BASHCOMPLETION_STATUS "Available") install(FILES tools/cgreen_completion.bash DESTINATION "${CMAKE_INSTALL_DATADIR}/bash-completion/completions" RENAME "cgreen-runner") install(FILES tools/cgreen_completion.bash DESTINATION "${CMAKE_INSTALL_DATADIR}/bash-completion/completions" RENAME "cgreen-debug") endif() # CMAKE MODULES: # where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/Modules ) # add definitions include(DefineCMakeDefaults) include(DefineCompilerFlags) include(DefineOptions.cmake) include(DefineCPackConfig) # add macros include(MacroAddPlugin) include(MacroCopyFile) # GIT REVISION: # Generate gitrevision.h if Git is available and the .git directory is found. find_program(GIT_EXECUTABLE git DOC "Git version control") mark_as_advanced(GIT_EXECUTABLE) # Find path to .git/logs/HEAD so that the gitrevision.h generation will only # happen on new commits. This is done from $PROJECT_SOURCE_DIR because git rev-parse # doesn't always return an absolute path so need to use get_filename_component() # to get a cross-platform `readlink -f $(git rev-parse --git-path logs/HEAD)` execute_process( COMMAND ${GIT_EXECUTABLE} rev-parse --git-path logs/HEAD WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" OUTPUT_VARIABLE GITDIR OUTPUT_STRIP_TRAILING_WHITESPACE ) if (GITDIR) get_filename_component(GITDIR "${GITDIR}" ABSOLUTE) endif() # config.h checks include(ConfigureChecks.cmake) configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h) # check subdirectories add_subdirectory(src) add_subdirectory(doc) add_subdirectory(include) # Dependency on our own library so we can use CGREEN_LIBRARY in all subdirectories if (CGREEN_WITH_STATIC_LIBRARY) set(CGREEN_LIBRARY ${CGREEN_STATIC_LIBRARY}) else () set(CGREEN_LIBRARY ${CGREEN_SHARED_LIBRARY}) endif() if (CGREEN_WITH_UNIT_TESTS) include(MacroAddUnitTest) include(MacroAddTest) include(MacroAddValgrindTest) add_subdirectory(tests) if (UNIX OR MSYS) # reflective runner only supported on UNIX/binutils platforms add_subdirectory(tools) endif(UNIX OR MSYS) endif (CGREEN_WITH_UNIT_TESTS) # add custom 'check' target to run tests with output-on-failure if (CMAKE_CONFIGURATION_TYPES) add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --force-new-ctest-process --output-on-failure --build-config "$") else() add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --force-new-ctest-process --output-on-failure) endif() IF(CGREEN_INTERNAL_WITH_GCOV) IF(CMAKE_C_COMPILER_ID STREQUAL GNU) include(CodeCoverage) add_custom_target(coverage COMMAND ${LCOV_PATH} --directory . --capture --output-file coverage.info COMMAND ${LCOV_PATH} --remove coverage.info '/usr/*' -o coverage.info COMMAND ${GENHTML_PATH} -o coverage coverage.info ) ENDIF() ELSE() add_custom_target(coverage COMMAND echo "WARNING: Configure CGREEN_INTERNAL_WITH_GCOV to get coverage") ENDIF() #### Begin cgreen package configuration steps. #### # After install other CMake projects can # use find_package( cgreen ) set( CONFIG_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/${APPLICATION_NAME}" ) set( PROJECT_CONFIG_IN "${CMAKE_CURRENT_SOURCE_DIR}/cgreen-config.cmake.in" ) set( VERSION_CONFIG_IN "${CMAKE_CURRENT_SOURCE_DIR}/cgreen-config-version.cmake.in" ) set( PROJECT_CONFIG "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/cgreen-config.cmake" ) set( VERSION_CONFIG "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/cgreen-config-version.cmake" ) configure_file( ${PROJECT_CONFIG_IN} "${PROJECT_CONFIG}" @ONLY ) configure_file( ${VERSION_CONFIG_IN} "${VERSION_CONFIG}" @ONLY ) install(FILES "${PROJECT_CONFIG}" "${VERSION_CONFIG}" DESTINATION "${CONFIG_INSTALL_DIR}" ) #### End cgreen package configuration steps. #### cgreen-1.6.3/CTestConfig.cmake000066400000000000000000000010211450461175400161370ustar00rootroot00000000000000## This file should be placed in the root directory of your project. ## Then modify the CMakeLists.txt file in the root directory of your ## project to incorporate the testing dashboard. ## # The following are required to uses Dart and the Cdash dashboard ## ENABLE_TESTING() ## INCLUDE(CTest) set(CTEST_PROJECT_NAME "CGreen") set(CTEST_NIGHTLY_START_TIME "00:00:00 EST") set(CTEST_DROP_METHOD "http") set(CTEST_DROP_SITE "my.cdash.org") set(CTEST_DROP_LOCATION "/submit.php?project=CGreen") set(CTEST_DROP_SITE_CDASH TRUE) cgreen-1.6.3/ConfigureChecks.cmake000066400000000000000000000006161450461175400170420ustar00rootroot00000000000000include(CheckIncludeFile) include(CheckSymbolExists) include(CheckFunctionExists) include(CheckLibraryExists) include(CheckTypeSize) include(CheckCXXSourceCompiles) set(PACKAGE ${APPLICATION_NAME}) set(VERSION ${APPLICATION_VERSION}) set(DATADIR ${DATA_INSTALL_DIR}) set(LIBDIR ${LIB_INSTALL_DIR}) set(PLUGINDIR "${PLUGIN_INSTALL_DIR}-${LIBRARY_SOVERSION}") set(SYSCONFDIR ${SYSCONF_INSTALL_DIR}) cgreen-1.6.3/DefineOptions.cmake000066400000000000000000000003671450461175400165510ustar00rootroot00000000000000option(CGREEN_WITH_STATIC_LIBRARY "Build with a static library" OFF) option(CGREEN_WITH_UNIT_TESTS "Build unit tests" ON) option(CGREEN_INTERNAL_WITH_GCOV "Build with test coverage instrumentation" OFF) mark_as_advanced(CGREEN_INTERNAL_WITH_GCOV) cgreen-1.6.3/INSTALL.md000066400000000000000000000052461450461175400144320ustar00rootroot00000000000000# Building and Installing Cgreen Here are your alternatives for installing `Cgreen`. ## Install using your distro package manager Cgreen is available for [some Linux distros] (https://repology.org/project/cgreen/versions). If you are on one of those you can do $ sudo apt install cgreen1 or equivalent. Not all distros have an up-to-date version. ## Install pre-built binary There are occassionally pre-built binaries available from [the GitHub repo](https://github.com/cgreen-devs/cgreen/releases). You can download and install these using an appropriate package manager. ## Build from source ### Get source and build Clone the [`Cgreen` repo](https://github.com/cgreen-devs/cgreen) $ git clone https://github.com/cgreen-devs/cgreen or get the source from the same place. Then build it $ cd cgreen $ make The Makefile is mainly for convenience as `Cgreen` is actually built using `CMake`. So you can tweak the build using normal `CMake` settings. You can run some tests using $ make unit $ make test NOTE: to also build the dynamically auto-discovering runner `cgreen-runner`, which `make unit` uses, you need `binutils` as per the description in the README.md. ### Build options You also have some extra options available - build with static libraries - build HTML or PDF documentation To enable any of these use the `CMake` graphical user interface (CMakeSetup on Windows or ccmake on UNIX) to turn these options on or off. Note on CYGWIN: Cygwin is not a WIN32 platform, but it is a DLL-platform where libraries normally goes in the bin directory. Running the self-tests handles this automatically but if you want to use the binaries in the 'build'-tree you can either: 1) install before running the tests and also set your PATH to include "/usr/local/lib" 2) setting the PATH to include the build directory where the libraries are there is a sh-compatible command script to do that for you. From the top of the Cgreen source directory do: . cygwin-setup.sh ### Use directly You can use `Cgreen` from the source tree without actually installing. Just set your compilation includes to include `/include` and link with the built library by pointing the linker to `/build/src/` and use `-lcgreen`. E.g. $ cc ... -I/home/me/cgreen/include ... $ cc ... -L/home/me/cgreen/build/src -lcgreen ... ### Install You can also install `Cgreen` with $ make install which will install `Cgreen` in what `CMake` considers standard locations for your environment. Assuming that is `/usr/local` you should now be able to compile and link using $ cc ... -I/usr/local/include ... $ cc ... -L/usr/local/lib -lcgreen ... cgreen-1.6.3/LICENSE000066400000000000000000000013501450461175400137770ustar00rootroot00000000000000ISC License Copyright (c) [year], [fullname] Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. cgreen-1.6.3/Makefile000066400000000000000000000111061450461175400144320ustar00rootroot00000000000000# This Makefile ensures that the build is made out of source in a # subdirectory called 'build' If it doesn't exist, it is created. # # This Makefile also contains delegation of the most common make commands # # If you have cmake installed you should be able to do: # # make # make test # make install # make package # # That should build Cgreen in the build directory, run some tests, # install it locally and generate a distributable package. ifndef VERBOSE MAKEFLAGS += --no-print-directory endif .PHONY:all all: build-it .PHONY:debug debug: cmake -DCMAKE_BUILD_TYPE:string=Debug -S . -B build $(MAKE) -C build .PHONY:test test: build-it cd build; ctest .PHONY:clean clean: build/Makefile $(MAKE) -C build clean .PHONY:package package: build/Makefile $(MAKE) -C build package .PHONY:install install: build ifeq ($(OS),Msys) # Thanks to https://stackoverflow.com/a/46027426/204658 $(MAKE) -C build install DESTDIR=/ else $(MAKE) -C build install endif # This is kind of a hack to get a quicker and clearer feedback when # developing Cgreen by allowing 'make unit'. Must be updated when new # test libraries or output comparisons are added. # Find out if 'uname -o' works, if it does - use it, otherwise use 'uname -s' UNAMEOEXISTS=$(shell uname -o &>/dev/null; echo $$?) ifeq ($(UNAMEOEXISTS),0) OS=$(shell uname -o) else OS=$(shell uname -s) endif # Set prefix and suffix for shared libraries depending on platform ifeq ($(OS),Darwin) LDPATH=DYLD_LIBRARY_PATH=$(PWD)/build/src PREFIX=lib SUFFIX=.dylib else ifeq ($(OS),Cygwin) LDPATH=PATH=$(PWD)/build/src:"$$PATH" PREFIX=cyg SUFFIX=.dll else ifeq ($(OS),Msys) # This is for Msys "proper" # TODO: handle Msys/Mingw32/64 LDPATH=PATH=$(PWD)/build/src:"$$PATH" PREFIX=msys- SUFFIX=.dll else LDPATH=LD_LIBRARY_PATH=$(PWD)/build/src PREFIX=lib SUFFIX=.so endif # Here are # # 1. tests linked into a library that we run as is # 2. tests linked into a library that we run and compare its normalized output to expected output # TODO: the diff_tools scripts determine prefix and extension by themselves # Would be better if those were arguments, since we do it here anyway # These "diff tools" also normalize the output using replacements DIFF_TOOL=../../tools/cgreen_runner_output_diff XML_DIFF_TOOL=../../tools/cgreen_xml_output_diff DIFF_TOOL_ARGUMENTS = $(1)_tests \ ../../tests \ $(1)_tests.expected .PHONY: unit unit: build-it cd build ; \ $(LDPATH) tools/cgreen-runner -c `find tests -name $(PREFIX)cgreen_c_tests$(SUFFIX)` ; \ r=$$((r + $$?)) ; \ $(LDPATH) tools/cgreen-runner -c `find tests -name $(PREFIX)cgreen_cpp_tests$(SUFFIX)` ; \ r=$$((r + $$?)) ; \ $(LDPATH) tools/cgreen-runner -c `find tools -name $(PREFIX)cgreen_runner_tests$(SUFFIX)` ; \ r=$$((r + $$?)) ; \ cd tests ; \ $(LDPATH) $(XML_DIFF_TOOL) $(call DIFF_TOOL_ARGUMENTS,xml_output) ; \ r=$$((r + $$?)) ; \ $(LDPATH) $(DIFF_TOOL) $(call DIFF_TOOL_ARGUMENTS,assertion_messages) ; \ r=$$((r + $$?)) ; \ $(LDPATH) $(DIFF_TOOL) $(call DIFF_TOOL_ARGUMENTS,mock_messages) ; \ r=$$((r + $$?)) ; \ $(LDPATH) $(DIFF_TOOL) $(call DIFF_TOOL_ARGUMENTS,constraint_messages) ; \ r=$$((r + $$?)) ; \ $(LDPATH) $(DIFF_TOOL) $(call DIFF_TOOL_ARGUMENTS,custom_constraint_messages) ; \ r=$$((r + $$?)) ; \ $(LDPATH) $(DIFF_TOOL) $(call DIFF_TOOL_ARGUMENTS,ignore_messages) ; \ r=$$((r + $$?)) ; \ $(LDPATH) CGREEN_PER_TEST_TIMEOUT=1 $(DIFF_TOOL) $(call DIFF_TOOL_ARGUMENTS,failure_messages) ; \ r=$$((r + $$?)) ; \ exit $$r .PHONY: doc doc: build cmake -DCGREEN_WITH_HTML_DOCS:bool=TRUE -S . -B build cmake --build build cmake -DCGREEN_WITH_HTML_DOCS:bool=False -S . -B build echo open $(PWD)/build/doc/cgreen-guide-en.html pdf: build cmake -DCGREEN_WITH_PDF_DOCS:bool=TRUE -S . -B build cmake --build build cmake -DCGREEN_WITH_PDF_DOCS:bool=FALSE -S . -B build echo open $(PWD)/build/doc/cgreen-guide-en.pdf chunked: doc asciidoctor-chunker build/doc/cgreen-guide-en.html -o docs echo open $(PWD)/docs/index.html .PHONY:valgrind valgrind: build-it @echo -n "Running all tests under Valgrind " @> valgrind.log @for lib in `ls build/tests/$(PREFIX)*_tests$(SUFFIX)` ; \ do \ echo -n "." ; \ LD_LIBRARY_PATH=build/src valgrind --leak-check=full build/tools/cgreen-runner $$lib >> valgrind.log 2>&1 ; \ done @echo grep --with-filename --line-number " lost: " valgrind.log | grep -v " 0 bytes" ; \ if [ $$? -eq 1 ] ; then echo "Nothing lost" ; fi ############# Internal build build/Makefile: ifeq ($(OS),Darwin) cmake -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" -S . -B build #cmake -S . -B build else cmake -S . -B build endif .PHONY:build-it build-it: build $(MAKE) -C build .SILENT: cgreen-1.6.3/README.md000066400000000000000000000160211450461175400142520ustar00rootroot00000000000000[![Build Status](https://app.travis-ci.com/cgreen-devs/cgreen.svg?branch=master)](https://app.travis-ci.com/github/cgreen-devs/cgreen) [![Coverage Status](https://coveralls.io/repos/cgreen-devs/cgreen/badge.svg?branch=master&service=github)](https://coveralls.io/github/cgreen-devs/cgreen?branch=master) ![](https://github.com/cgreen-devs/cgreen/blob/master/doc/logo.png?s=300) Cgreen - The Modern Unit Test and Mocking Framework for C and C++ ================================================================= Do you TDD? In C or C++? Maybe you want to have your tests read out in a fluent fashion? Like this Ensure(Converter, converts_XIV_to_14) { assert_that(convert_roman_to_decimal("XIV"), is_equal_to(14)); } And you want output like this roman_test.c:12: Failure: Converter -> converts_XIV_to_14 Expected [convert_roman_to_decimal("XIV")] to [equal] [14] actual value: [0] expected value: [14] Then *Cgreen* is the thing for you! **TLDR;** The full tutorial is on [github.io](https://cgreen-devs.github.io/cgreen/cgreen-guide-en.html). Or have a look at the [cheat sheet](https://cgreen-devs.github.io/cgreen/cheat-sheet.html). ## What It Is Cgreen is a modern unit test and mocking framework for C and C++. Here are some of Cgreens unique selling points: - fast build, clean code, highly portable - auto-discovery of tests without the abuse of static initializers or globals - extensible without recompiling - fluent, expressive and readable API with the same modern syntax across C and C++ - process isolation for each test preventing intermittent failures and cross-test dependencies - built-in mocking for C, compatible with mockitopp and other C++ mocking libraries - expressive and clear output using the default reporter - fully functional mocks, both strict, loose and learning - mocks with side effects - extensive and expressive constraints for many datatypes - custom constraints can be constructed by user - bdd-flavoured test declarations with Before and After declarations - extensible reporting mechanism - fully composable test suites - a single test can be run in a single process for easier debugging ## Getting It Cgreen is hosted on [GitHub](https://github.com/cgreen-devs/cgreen). As of now there are no pre-built packages to download, but Cgreen is available in [Debian, Fedora and some other package repositories](https://repology.org/project/cgreen/versions), although some are lagging. There are also some other packaging scripts available, not all official: - [PACMAN script](https://github.com/voins/cgreen-pkg) - [MacOS packagesbuild](https://github.com/cgreen-devs/cgreen-macosx-packaging) - [Cygwin package script](https://github.com/cgreen-devs/cgreen-cygport) You can also clone the repository or download the source zip from [GitHub](http://www.github.com/cgreen-devs/cgreen) and build it yourself. ## Building It You need the [CMake](http://www.cmake.org) build system. Most standard C/C++ compilers should work. GCC definitely does. Perl, diff, find and sed are required to run Cgreen's own unit-tests. Most distro will have those already installed. In the root directory run ``make``. That will configure and build the library and the `cgreen-runner`, both supporting both C and C++. See also the documentation. ## Using It Tests are fairly easy write, as shown by the examples in the beginning of this readme. You should probably read the [tutorial](https://cgreen-devs.github.io/cgreen/cgreen-guide-en.html) once before writing your first test, though. Basically you can run your tests in two ways 1. Compile and link all your tests with a test driver (as shown in the fist chapters of the tutorial) 2. Link your tests into separate shared libraries (`.so`, `.dylib` or similar) and run them with the `cgreen-runner` (described in chapter 6 of the tutorial) Option 2 is very handy, you can run multiple libraries in the same run, but also specify single tests that you want to run. And with the completion script available for bash you can get TAB-completion not only for files and options but also for tests inside the libraries. `cgreen-debug` is a small script that you invoke in the same way as the runner but runs a single, specified, test and puts you in the debugger at the start of that test. Awesome! ## Using Cgreen in other CMake projects Once Cgreen is installed you can use ``find_package(cgreen)`` in your CMake projects to get access to useful variables like ``${CGREEN_LIBRARIES}``, ``${CGREEN_EXECUTABLE}`` and ``${CGREEN_INCLUDE_DIRS}``. Version can be specified in ``find_package`` as well. For example, in order to enforce a minimum version of Cgreen in your project use ``find_package(cgreen 1.1.0)`` ## Reading Up! You can read the extensive tutorial directly on [GitHub](https://cgreen-devs.github.io/cgreen/cgreen-guide-en.html). There is a [cheat sheet](https://github.com/cgreen-devs/cgreen/blob/master/doc/cheat-sheet.md) available. You can also build the documentation yourself in HTML and PDF format. Generate it using Asciidoctor, which can be done using the CMake configuration. Of course you need [Asciidoctor](http://www.asciidoctor.org). make doc make pdf (Generating PDF also requires [asciidoctor-pdf](https://asciidoctor.org/docs/asciidoctor-pdf/).) ## License Cgreen is licensed under the ISC License (http://spdx.org/licenses/ISC), sometimes known as the OpenBSD license. If there is no licence agreement with this package please download a version from the location above. You must read and accept that licence to use this software. The file is titled simply LICENSE. ## The Original Version What is it? It's a framework for unit testing, written in C. A tool for C developers writing tests of their own code. If you have used JUnit, or any of the xUnit clones, you will find the concept familiar. In particular the tool supports a range of assertions, composable test suites and setup/teardown facilities. Because of the peculiarities of C programming, each test function is normally run in it's own process. This project is very close in scope to the "Check" unit tester and was initially influenced by it. The main difference from this tool and other xUnit tools, such as "Check", is that test results are not stored. Instead they are streamed to the reporter psuedo-class, one that is easily overridden by the end user. The other main extra feature is the support for writing mock callbacks. This includes generating sequences for return values or parameter expectations. Feedback, queries and request should be put to the cgreen developers through https://github.com/cgreen-devs/cgreen. This tool is basically a spin off from a research project at Wordtracker and would not have happened without the generous financial support of the Wordtracker keyword tool... http://www.wordtracker.com/ Substantial inital work by Marcus Baker . Recent additions by Matt Hargett , Thomas Nilefalk , João Freitas and others. cgreen-1.6.3/cgreen-config-version.cmake.in000066400000000000000000000007111450461175400205720ustar00rootroot00000000000000set(PACKAGE_VERSION "@APPLICATION_VERSION_MAJOR@.@APPLICATION_VERSION_MINOR@.@APPLICATION_VERSION_PATCH@") # Check whether the requested PACKAGE_FIND_VERSION is compatible if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}") set(PACKAGE_VERSION_COMPATIBLE FALSE) else() set(PACKAGE_VERSION_COMPATIBLE TRUE) if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}") set(PACKAGE_VERSION_EXACT TRUE) endif() endif() cgreen-1.6.3/cgreen-config.cmake.in000066400000000000000000000010021450461175400171010ustar00rootroot00000000000000# - Config file for the cgreen package # It defines the following variables # CGREEN_CMAKE_DIR - include directories for cgreen # CGREEN_INCLUDE_DIRS - include directories for cgreen # CGREEN_LIBRARIES - libraries to link against # CGREEN_EXECUTABLE - the cgreen executable get_filename_component( CGREEN_CMAKE_DIRS "${CMAKE_CURRENT_LIST_FILE}" PATH ) # leave this up to cmake find_path(CGREEN_INCLUDE_DIRS NAMES cgreen/cgreen.h) set( CGREEN_LIBRARIES cgreen ) set( CGREEN_EXECUTABLE cgreen-runner ) cgreen-1.6.3/cmake/000077500000000000000000000000001450461175400140535ustar00rootroot00000000000000cgreen-1.6.3/cmake/Modules/000077500000000000000000000000001450461175400154635ustar00rootroot00000000000000cgreen-1.6.3/cmake/Modules/COPYING-CMAKE-SCRIPTS000066400000000000000000000024571450461175400204710ustar00rootroot00000000000000Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. cgreen-1.6.3/cmake/Modules/CodeCoverage.cmake000066400000000000000000000073611450461175400210220ustar00rootroot00000000000000# - Enable Code Coverage # # 2012-01-31, Lars Bilke # # USAGE: # 1. Copy this file into your cmake modules path # 2. Add the following line to your CMakeLists.txt: # INCLUDE(CodeCoverage) # # 3. Use the function SETUP_TARGET_FOR_COVERAGE to create a custom make target # which runs your test executable and produces a lcov code coverage report. # # Check prereqs FIND_PROGRAM( GCOV_PATH gcov ) FIND_PROGRAM( LCOV_PATH lcov ) FIND_PROGRAM( GENHTML_PATH genhtml ) FIND_PROGRAM( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/tests) IF(NOT GCOV_PATH) MESSAGE(FATAL_ERROR "gcov not found! Aborting...") ENDIF() # NOT GCOV_PATH IF(NOT CMAKE_C_COMPILER_ID STREQUAL GNU) MESSAGE(FATAL_ERROR "Compiler is not GNU gcc! Aborting...") ENDIF() IF ( NOT CMAKE_BUILD_TYPE STREQUAL "Debug" ) MESSAGE( WARNING "Code coverage results with an optimised (non-Debug) build may be misleading" ) ENDIF() # NOT CMAKE_BUILD_TYPE STREQUAL "Debug" # Setup compiler options ADD_DEFINITIONS(-fprofile-arcs -ftest-coverage) LINK_LIBRARIES(gcov) # Param _targetname The name of new the custom make target # Param _testrunner The name of the target which runs the tests # Param _outputname lcov output is generated as _outputname.info # HTML report is generated in _outputname/index.html # Optional fourth parameter is passed as arguments to _testrunner # Pass them in list form, e.g.: "-j;2" for -j 2 FUNCTION(SETUP_TARGET_FOR_COVERAGE _targetname _testrunner _outputname) IF(NOT LCOV_PATH) MESSAGE(FATAL_ERROR "lcov not found! Aborting...") ENDIF() # NOT LCOV_PATH IF(NOT GENHTML_PATH) MESSAGE(FATAL_ERROR "genhtml not found! Aborting...") ENDIF() # NOT GENHTML_PATH # Setup target ADD_CUSTOM_TARGET(${_targetname} # Cleanup lcov ${LCOV_PATH} --directory . --zerocounters # Run tests COMMAND ${_testrunner} ${ARGV3} # Capturing lcov counters and generating report COMMAND ${LCOV_PATH} --directory . --capture --output-file ${_outputname}.info COMMAND ${LCOV_PATH} --remove ${_outputname}.info 'tests/*' '/usr/*' --output-file ${_outputname}.info.cleaned COMMAND ${GENHTML_PATH} -o ${_outputname} ${_outputname}.info.cleaned COMMAND ${CMAKE_COMMAND} -E remove ${_outputname}.info ${_outputname}.info.cleaned WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report." ) # Show info where to find the report ADD_CUSTOM_COMMAND(TARGET ${_targetname} POST_BUILD COMMAND ; COMMENT "Open ./${_outputname}/index.html in your browser to view the coverage report." ) ENDFUNCTION() # SETUP_TARGET_FOR_COVERAGE # Param _targetname The name of new the custom make target # Param _testrunner The name of the target which runs the tests # Param _outputname cobertura output is generated as _outputname.xml # Optional fourth parameter is passed as arguments to _testrunner # Pass them in list form, e.g.: "-j;2" for -j 2 FUNCTION(SETUP_TARGET_FOR_COVERAGE_COBERTURA _targetname _testrunner _outputname) IF(NOT PYTHON_EXECUTABLE) MESSAGE(FATAL_ERROR "Python not found! Aborting...") ENDIF() # NOT PYTHON_EXECUTABLE IF(NOT GCOVR_PATH) MESSAGE(FATAL_ERROR "gcovr not found! Aborting...") ENDIF() # NOT GCOVR_PATH ADD_CUSTOM_TARGET(${_targetname} # Run tests ${_testrunner} ${ARGV3} # Running gcovr COMMAND ${GCOVR_PATH} -x -r ${CMAKE_SOURCE_DIR} -e '${CMAKE_SOURCE_DIR}/tests/' -o ${_outputname}.xml WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMENT "Running gcovr to produce Cobertura code coverage report." ) # Show info where to find the report ADD_CUSTOM_COMMAND(TARGET ${_targetname} POST_BUILD COMMAND ; COMMENT "Cobertura code coverage report saved in ${_outputname}.xml." ) ENDFUNCTION() # SETUP_TARGET_FOR_COVERAGE_COBERTURA cgreen-1.6.3/cmake/Modules/DefineCMakeDefaults.cmake000066400000000000000000000015771450461175400222620ustar00rootroot00000000000000# Always include srcdir and builddir in include path # This saves typing ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY} in # about every subdir # since cmake 2.4.0 set(CMAKE_INCLUDE_CURRENT_DIR ON) # Put the include dirs which are in the source or build tree # before all other include dirs, so the headers in the sources # are prefered over the already installed ones # since cmake 2.4.1 set(CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE ON) # Use colored output # since cmake 2.4.0 set(CMAKE_COLOR_MAKEFILE ON) # Define the generic version of the libraries here set(GENERIC_LIB_VERSION "0.1.0") set(GENERIC_LIB_SOVERSION "0") # Set the default build type to release with debug info if (NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." ) endif (NOT CMAKE_BUILD_TYPE) cgreen-1.6.3/cmake/Modules/DefineCPackConfig.cmake000066400000000000000000000043021450461175400217060ustar00rootroot00000000000000include(InstallRequiredSystemLibraries) # For help take a look at: # http://www.cmake.org/Wiki/CMake:CPackConfiguration ### general settings set(CPACK_PACKAGE_NAME ${APPLICATION_NAME}) set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "The modern C/C++ unit testing/mocking framework") set(CPACK_PACKAGE_DESCRIPTION_FILE "${PROJECT_SOURCE_DIR}/README.md") set(CPACK_PACKAGE_VENDOR "The CGreen Development Team") set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE") ### versions set(CPACK_PACKAGE_VERSION_MAJOR ${APPLICATION_VERSION_MAJOR}) set(CPACK_PACKAGE_VERSION_MINOR ${APPLICATION_VERSION_MINOR}) set(CPACK_PACKAGE_VERSION_PATCH ${APPLICATION_VERSION_PATCH}) set(CPACK_PACKAGE_VERSION_STATUS ${APPLICATION_VERSION_STATUS}) set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}${CPACK_PACKAGE_VERSION_STATUS}") ### source generator set(CPACK_SOURCE_GENERATOR "TGZ") set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]svn/;/[.]git/;.gitignore;/build/;tags;cscope.*") set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-src") ### binary generator if (WIN32) ### nsis generator set(CPACK_GENERATOR "NSIS") set(CPACK_NSIS_DISPLAY_NAME ${CPACK_PACKAGE_DESCRIPTION_SUMMARY}) set(CPACK_NSIS_COMPRESSOR "/SOLID zlib") set(CPACK_NSIS_MENU_LINKS "http://cgreen.sourceforge.net" "Cgreen Homepage") set(CPACK_PACKAGE_INSTALL_DIRECTORY ${CPACK_PACKAGE_NAME}) endif() set(CPACK_COMPONENTS_ALL_IN_ONE_PACKAGE 1) set(PACKAGE_NAME ${APPLICATION_NAME}) if (CMAKE_SIZEOF_VOID_P EQUAL 8) set(BITS 64) else() set(BITS 32) endif() set(CPACK_PACKAGE_FILE_NAME ${PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CMAKE_SYSTEM_NAME}${BITS}) set(CPACK_COMPONENT_LIBRARIES_DISPLAY_NAME "Libraries") set(CPACK_COMPONENT_LIBRARIES_DESCRIPTION "Libraries used to build programs which use cgreen") set(CPACK_COMPONENT_HEADERS_DISPLAY_NAME "C/C++ Headers") set(CPACK_COMPONENT_HEADERS_DESCRIPTION "C/C++ header files for use with cgreen") set(CPACK_COMPONENT_HEADERS_DEPENDS libraries) set(CPACK_COMPONENT_APPLICATIONS_GROUP "Runtime") set(CPACK_COMPONENT_LIBRARIES_GROUP "Development") set(CPACK_COMPONENT_HEADERS_GROUP "Development") include(CPack) cgreen-1.6.3/cmake/Modules/DefineCompilerFlags.cmake000066400000000000000000000046141450461175400223340ustar00rootroot00000000000000# define system dependent compiler flags include(CheckCCompilerFlag) set (COMPILER_IS_CLANG FALSE) if (${CMAKE_C_COMPILER_ID} MATCHES "Clang") set (COMPILER_IS_CLANG TRUE) endif (${CMAKE_C_COMPILER_ID} MATCHES "Clang") if (CGREEN_WITH_XML) add_definitions(-DHAVE_XML_REPORTER=1) endif (CGREEN_WITH_XML) if (CGREEN_WITH_LIBXML2) add_definitions(-DHAVE_LIBXML2_REPORTER=1) endif (CGREEN_WITH_LIBXML2) if (UNIX) if (CMAKE_COMPILER_IS_GNUCC OR COMPILER_IS_CLANG) # add_compile_options(-Wall -Wextra -Wunused) # only since CMake 2.8.12, so... add_definitions(-Wall -Wextra -Wunused) if (CGREEN_WITH_LIBXML2) # libxml2 headers depend on ICU library for Unicode support, # but ICU headers do not even compile with C++ 98. set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") else () set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++98") endif (CGREEN_WITH_LIBXML2) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Weffc++") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wstrict-prototypes") if (CGREEN_INTERNAL_WITH_GCOV) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ftest-coverage -fprofile-arcs") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftest-coverage -fprofile-arcs") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_C_FLAGS} -ftest-coverage -fprofile-arcs") endif (CGREEN_INTERNAL_WITH_GCOV) add_definitions(-D_REENTRANT) # for gmtime_r() if (NOT ${CMAKE_SYSTEM_NAME} MATCHES ".*OpenBSD.*") add_definitions(-D_XOPEN_SOURCE) # for popen() and pclose() add_definitions(-D_XOPEN_SOURCE_EXTENDED) # for strdup(), which isn't part of C99 endif() add_definitions(-D__STDC_FORMAT_MACROS) # for PRI*PTR format macros, required by C99 if (NOT CYGWIN) # with -fPIC check_c_compiler_flag("-fPIC" WITH_FPIC) if (WITH_FPIC) # add_compile_options(-fPIC) # Only since CMake 2.8.12, so... add_definitions(-fPIC) endif (WITH_FPIC) endif (NOT CYGWIN) check_c_compiler_flag("-D_FORTIFY_SOURCE=2" WITH_FORTIFY_SOURCE) if (WITH_FORTIFY_SOURCE) add_definitions(-D_FORTIFY_SOURCE=2) endif (WITH_FORTIFY_SOURCE) if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug") add_definitions(-O) endif () endif (CMAKE_COMPILER_IS_GNUCC OR COMPILER_IS_CLANG) endif (UNIX) if (WIN32) if (MSVC) add_definitions(-D_CRT_SECURE_NO_WARNINGS=1) endif (MSVC) endif (WIN32) cgreen-1.6.3/cmake/Modules/DefineRelativeFilePaths.cmake000066400000000000000000000007031450461175400231530ustar00rootroot00000000000000# Source: https://stackoverflow.com/questions/237542/getting-base-name-of-the-source-file-at-compile-time function (cmake_define_relative_file_paths SOURCES) foreach (SOURCE IN LISTS SOURCES) file ( RELATIVE_PATH RELATIVE_SOURCE_PATH ${PROJECT_SOURCE_DIR} ${SOURCE} ) set_source_files_properties ( ${SOURCE} PROPERTIES COMPILE_DEFINITIONS FILENAME="${RELATIVE_SOURCE_PATH}" ) endforeach () endfunction () cgreen-1.6.3/cmake/Modules/FindAsciidoc.cmake000066400000000000000000000017051450461175400210070ustar00rootroot00000000000000# - Find Asciidoc # this module looks for asciidoc and a2x # # ASCIIDOC_EXECUTABLE - the full path to asciidoc # ASCIIDOC_FOUND - If false, don't attempt to use asciidoc. # A2X_EXECUTABLE - the full path to a2x # A2X_FOUND - If false, don't attempt to use a2x. FIND_PROGRAM(ASCIIDOC_EXECUTABLE asciidoc ) MARK_AS_ADVANCED( ASCIIDOC_EXECUTABLE ) IF (NOT ASCIIDOC_EXECUTABLE) SET(ASCIIDOC_FOUND "NO") ELSE (NOT ASCIIDOC_EXECUTABLE) SET(ASCIIDOC_FOUND "YES") ENDIF (NOT ASCIIDOC_EXECUTABLE) IF (NOT ASCIIDOC_FOUND AND Asciidoc_FIND_REQUIRED) MESSAGE(FATAL_ERROR "Could not find asciidoc") ENDIF (NOT ASCIIDOC_FOUND AND Asciidoc_FIND_REQUIRED) FIND_PROGRAM(A2X_EXECUTABLE a2x ) MARK_AS_ADVANCED( A2X_EXECUTABLE ) IF (NOT A2X_EXECUTABLE) SET(A2X_FOUND "NO") ELSE (NOT A2X_EXECUTABLE) SET(A2X_FOUND "YES") ENDIF (NOT A2X_EXECUTABLE) IF (NOT A2X_FOUND AND A2x_FIND_REQUIRED) MESSAGE(FATAL_ERROR "Could not find a2x") ENDIF (NOT A2X_FOUND AND A2x_FIND_REQUIRED) cgreen-1.6.3/cmake/Modules/FindAsciidoctor.cmake000066400000000000000000000017751450461175400215430ustar00rootroot00000000000000# Find Asciidoctor - a better AsciiDoc # # ASCIIDOCTOR_FOUND # ASCIIDOCTORPDF_FOUND # ASCIIDOCTOR_EXECUTABLE # ASCIIDOCTORPDF_EXECUTABLE FIND_PROGRAM(ASCIIDOCTOR_EXECUTABLE asciidoctor) FIND_PROGRAM(ASCIIDOCTORPDF_EXECUTABLE asciidoctor-pdf) MARK_AS_ADVANCED(ASCIIDOCTOR_EXECUTABLE) MARK_AS_ADVANCED(ASCIIDOCTORPDF_EXECUTABLE) IF (NOT ASCIIDOCTOR_EXECUTABLE) SET(ASCIIDOCTOR_FOUND "NO") ELSE (NOT ASCIIDOCTOR_EXECUTABLE) SET(ASCIIDOCTOR_FOUND "YES") ENDIF (NOT ASCIIDOCTOR_EXECUTABLE) IF (NOT ASCIIDOCTORPDF_EXECUTABLE) SET(ASCIIDOCTORPDF_FOUND "NO") ELSE (NOT ASCIIDOCTORPDF_EXECUTABLE) SET(ASCIIDOCTORPDF_FOUND "YES") ENDIF (NOT ASCIIDOCTORPDF_EXECUTABLE) IF (NOT ASCIIDOCTOR_FOUND AND ASCIIDOCTOR_FIND_REQUIRED) MESSAGE(FATAL_ERROR "Could not find asciidoctor") ENDIF (NOT ASCIIDOCTOR_FOUND AND ASCIIDOCTOR_FIND_REQUIRED) IF (NOT ASCIIDOCTORPDF_FOUND AND ASCIIDOCTOR_FIND_REQUIRED) MESSAGE(FATAL_ERROR "Could not find asciidoctor-pdf") ENDIF (NOT ASCIIDOCTORPDF_FOUND AND ASCIIDOCTOR_FIND_REQUIRED) cgreen-1.6.3/cmake/Modules/FindNm.cmake000066400000000000000000000001201450461175400176310ustar00rootroot00000000000000find_program(NM_EXECUTABLE nm) if (NM_EXECUTABLE) set(NM_FOUND TRUE) endif() cgreen-1.6.3/cmake/Modules/FindValgrind.cmake000066400000000000000000000005341450461175400210360ustar00rootroot00000000000000if (NOT Valgrind_FOUND) find_program(Valgrind_EXECUTABLE valgrind) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Valgrind DEFAULT_MSG Valgrind_EXECUTABLE) set(Valgrind_FOUND ${Valgrind_FOUND} CACHE BOOL "Flag whether Valgrind package was found") mark_as_advanced(Valgrind_FOUND Valgrind_EXECUTABLE) endif() cgreen-1.6.3/cmake/Modules/MacroAddCompileFlags.cmake000066400000000000000000000011671450461175400224320ustar00rootroot00000000000000# - MACRO_ADD_COMPILE_FLAGS(target_name flag1 ... flagN) # Copyright (c) 2006, Oswald Buddenhagen, # Copyright (c) 2006, Andreas Schneider, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. macro (MACRO_ADD_COMPILE_FLAGS _target) get_target_property(_flags ${_target} COMPILE_FLAGS) if (_flags) set(_flags ${_flags} ${ARGN}) else (_flags) set(_flags ${ARGN}) endif (_flags) set_target_properties(${_target} PROPERTIES COMPILE_FLAGS ${_flags}) endmacro (MACRO_ADD_COMPILE_FLAGS) cgreen-1.6.3/cmake/Modules/MacroAddLinkFlags.cmake000066400000000000000000000011551450461175400217340ustar00rootroot00000000000000# - MACRO_ADD_LINK_FLAGS(target_name flag1 ... flagN) # Copyright (c) 2006, Oswald Buddenhagen, # Copyright (c) 2006, Andreas Schneider, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. macro (MACRO_ADD_LINK_FLAGS _target) get_target_property(_flags ${_target} LINK_FLAGS) if (_flags) set(_flags "${_flags} ${ARGN}") else (_flags) set(_flags "${ARGN}") endif (_flags) set_target_properties(${_target} PROPERTIES LINK_FLAGS "${_flags}") endmacro (MACRO_ADD_LINK_FLAGS) cgreen-1.6.3/cmake/Modules/MacroAddPlugin.cmake000066400000000000000000000017411450461175400213210ustar00rootroot00000000000000# - MACRO_ADD_PLUGIN(name [WITH_PREFIX] file1 .. fileN) # # Create a plugin from the given source files. # If WITH_PREFIX is given, the resulting plugin will have the # prefix "lib", otherwise it won't. # # Copyright (c) 2006, Alexander Neundorf, # Copyright (c) 2006, Laurent Montel, # Copyright (c) 2006, Andreas Schneider, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. macro (MACRO_ADD_PLUGIN _target_NAME _with_PREFIX) if (${_with_PREFIX} STREQUAL "WITH_PREFIX") set(_first_SRC) else (${_with_PREFIX} STREQUAL "WITH_PREFIX") set(_first_SRC ${_with_PREFIX}) endif (${_with_PREFIX} STREQUAL "WITH_PREFIX") add_library(${_target_NAME} MODULE ${_first_SRC} ${ARGN}) if (_first_SRC) set_target_properties(${_target_NAME} PROPERTIES PREFIX "") endif (_first_SRC) endmacro (MACRO_ADD_PLUGIN _name _sources) cgreen-1.6.3/cmake/Modules/MacroAddTest.cmake000066400000000000000000000007151450461175400210020ustar00rootroot00000000000000# - MACRO_ADD_TEST() # # Calls add_test() with all the but if on Win32 or Cygwin also adds the # directory where the Cgreen library is generated to the path so that it will # be used when running the test # # @thoni56/Thomas Nilefalk 2015-09-13 macro (macro_add_test) add_test(${ARGN}) if (CYGWIN OR WIN32) set_tests_properties(${ARGV1} PROPERTIES ENVIRONMENT PATH=${PROJECT_BINARY_DIR}/src:$ENV{PATH}) endif () endmacro(macro_add_test) cgreen-1.6.3/cmake/Modules/MacroAddUnitTest.cmake000066400000000000000000000024221450461175400216370ustar00rootroot00000000000000# - MACRO_ADD_UNIT_TEST(test_name test_source linklib1 ... linklibN) # Copyright (c) 2007, Daniel Gollub, # Copyright (c) 2007, Andreas Schneider, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. enable_testing() include(CTest) #set(CMAKE_C_FLAGS_PROFILING "-g -O0 -Wall -W -Wshadow -Wunused-variable -Wunused-parameter -Wunused-function -Wunused -Wno-system-headers -Wwrite-strings -fprofile-arcs -ftest-coverage" CACHE STRING "Profiling Compiler Flags") #set(CMAKE_SHARED_LINKER_FLAGS_PROFILING " -fprofile-arcs -ftest-coverage" CACHE STRING "Profiling Linker Flags") #set(CMAKE_MODULE_LINKER_FLAGS_PROFILING " -fprofile-arcs -ftest-coverage" CACHE STRING "Profiling Linker Flags") #set(CMAKE_EXEC_LINKER_FLAGS_PROFILING " -fprofile-arcs -ftest-coverage" CACHE STRING "Profiling Linker Flags") # custom options configure_file(tests/CTestCustom.cmake ${PROJECT_BINARY_DIR}/CTestCustom.cmake COPYONLY) macro (MACRO_ADD_UNIT_TEST _testName _testSource) add_executable(${_testName} ${_testSource}) target_link_libraries(${_testName} ${ARGN}) macro_add_test(NAME ${_testName} COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${_testName}) endmacro (MACRO_ADD_UNIT_TEST) cgreen-1.6.3/cmake/Modules/MacroAddValgrindTest.cmake000066400000000000000000000017361450461175400224750ustar00rootroot00000000000000# - MACRO_ADD_VALGRIND_TEST() # # Calls add_test() with all the but if on Win32 or Cygwin also adds the # directory where the Cgreen library is generated to the path so that it will # be used when running the test # # @thoni56/Thomas Nilefalk 2015-09-13 macro (macro_add_valgrind_test) if (Valgrind_FOUND) set( libname ${CMAKE_FIND_LIBRARY_PREFIXES}${ARGN}${CMAKE_SHARED_LIBRARY_SUFFIX} ) add_test( NAME valgrind_${libname} COMMAND sh -c "LD_LIBRARY_PATH=build/src valgrind --leak-check=full tools/cgreen-runner ${CMAKE_CURRENT_BINARY_DIR}/${libname} 2>1&" WORKING_DIRECTORY ${CMAKE_BINARY_DIR} ) set_tests_properties( valgrind_${libname} PROPERTIES FAIL_REGULAR_EXPRESSION "(definitely|indirectly|possibly) lost: [1-9]" ) if (CYGWIN OR WIN32) set_tests_properties(${ARGV1} PROPERTIES ENVIRONMENT PATH=${PROJECT_BINARY_DIR}/src:$ENV{PATH}) endif () endif () endmacro(macro_add_valgrind_test) cgreen-1.6.3/cmake/Modules/MacroCopyFile.cmake000066400000000000000000000021571450461175400211660ustar00rootroot00000000000000# - macro_copy_file(_src _dst) # Copies a file to ${_dst} only if ${_src} is different (newer) than ${_dst} # # Example: # macro_copy_file(${CMAKE_CURRENT_SOURCE_DIR}/icon.png ${CMAKE_CURRENT_BINARY_DIR}/.) # Copies file icon.png to ${CMAKE_CURRENT_BINARY_DIR} directory # # Copyright (c) 2006-2007 Wengo # Copyright (c) 2006-2008 Andreas Schneider # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING file. macro (macro_copy_file _src _dst) # Removes all path containing .svn or CVS or CMakeLists.txt during the copy if (NOT ${_src} MATCHES ".*\\.svn|CVS|CMakeLists\\.txt.*") if (CMAKE_VERBOSE_MAKEFILE) message(STATUS "Copy file from ${_src} to ${_dst}") endif (CMAKE_VERBOSE_MAKEFILE) # Creates directory if necessary get_filename_component(_path ${_dst} PATH) file(MAKE_DIRECTORY ${_path}) execute_process( COMMAND ${CMAKE_COMMAND} -E copy_if_different ${_src} ${_dst} OUTPUT_QUIET ) endif (NOT ${_src} MATCHES ".*\\.svn|CVS|CMakeLists\\.txt.*") endmacro (macro_copy_file) cgreen-1.6.3/cmake/Modules/MacroEnsureOutOfSourceBuild.cmake000066400000000000000000000012351450461175400240270ustar00rootroot00000000000000# - MACRO_ENSURE_OUT_OF_SOURCE_BUILD() # MACRO_ENSURE_OUT_OF_SOURCE_BUILD() # Copyright (c) 2006, Alexander Neundorf, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. macro (MACRO_ENSURE_OUT_OF_SOURCE_BUILD _errorMessage) string(COMPARE EQUAL "${PROJECT_SOURCE_DIR}" "${PROJECT_BINARY_DIR}" _insource) if (_insource) message(SEND_ERROR "${_errorMessage}") message(FATAL_ERROR "Remove the file CMakeCache.txt in ${PROJECT_SOURCE_DIR} first.") endif (_insource) endmacro (MACRO_ENSURE_OUT_OF_SOURCE_BUILD) cgreen-1.6.3/cmake/Modules/UseDoxygen.cmake000066400000000000000000000127141450461175400205640ustar00rootroot00000000000000# -helper macro to add a "doc" target with CMake build system. # and configure doxy.config.in to doxy.config # # target "doc" allows building the documentation with doxygen/dot on WIN32 and Linux # Creates .chm windows help file if MS HTML help workshop # (available from http://msdn.microsoft.com/workshop/author/htmlhelp) # is installed with its DLLs in PATH. # # # Please note, that the tools, e.g.: # doxygen, dot, latex, dvips, makeindex, gswin32, etc. # must be in path. # # Note about Visual Studio Projects: # MSVS has its own path environment which may differ from the shell. # See "Menu Tools/Options/Projects/VC++ Directories" in VS 7.1 # # author Jan Woetzel 2004-2006 # www.mip.informatik.uni-kiel.de/~jw FIND_PACKAGE(Doxygen) IF (DOXYGEN_FOUND) # click+jump in Emacs and Visual Studio (for doxy.config) (jw) IF (CMAKE_BUILD_TOOL MATCHES "(msdev|devenv)") SET(DOXY_WARN_FORMAT "\"$file($line) : $text \"") ELSE (CMAKE_BUILD_TOOL MATCHES "(msdev|devenv)") SET(DOXY_WARN_FORMAT "\"$file:$line: $text \"") ENDIF (CMAKE_BUILD_TOOL MATCHES "(msdev|devenv)") # we need latex for doxygen because of the formulas FIND_PACKAGE(LATEX) IF (NOT LATEX_COMPILER) MESSAGE(STATUS "latex command LATEX_COMPILER not found but usually required. You will probably get warnings and user inetraction on doxy run.") ENDIF (NOT LATEX_COMPILER) IF (NOT MAKEINDEX_COMPILER) MESSAGE(STATUS "makeindex command MAKEINDEX_COMPILER not found but usually required.") ENDIF (NOT MAKEINDEX_COMPILER) IF (NOT DVIPS_CONVERTER) MESSAGE(STATUS "dvips command DVIPS_CONVERTER not found but usually required.") ENDIF (NOT DVIPS_CONVERTER) FIND_PROGRAM(DOXYGEN_DOT_EXECUTABLE_PATH NAMES dot) IF (DOXYGEN_DOT_EXECUTABLE_PATH) SET(DOXYGEN_DOT_FOUND "YES") ENDIF (DOXYGEN_DOT_EXECUTABLE_PATH) IF (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/doxy.config.in") MESSAGE(STATUS "Generate ${CMAKE_CURRENT_BINARY_DIR}/doxy.config from doxy.config.in") CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/doxy.config.in ${CMAKE_CURRENT_BINARY_DIR}/doxy.config @ONLY ) # use (configured) doxy.config from (out of place) BUILD tree: SET(DOXY_CONFIG "${CMAKE_CURRENT_BINARY_DIR}/doxy.config") ELSE (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/doxy.config.in") # use static hand-edited doxy.config from SOURCE tree: SET(DOXY_CONFIG "${CMAKE_CURRENT_SOURCE_DIR}/doxy.config") IF (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/doxy.config") MESSAGE(STATUS "WARNING: using existing ${CMAKE_CURRENT_SOURCE_DIR}/doxy.config instead of configuring from doxy.config.in file.") ELSE (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/doxy.config") IF (EXISTS "${CMAKE_MODULE_PATH}/doxy.config.in") # using template doxy.config.in MESSAGE(STATUS "Generate ${CMAKE_CURRENT_BINARY_DIR}/doxy.config from doxy.config.in") CONFIGURE_FILE(${CMAKE_MODULE_PATH}/doxy.config.in ${CMAKE_CURRENT_BINARY_DIR}/doxy.config @ONLY ) SET(DOXY_CONFIG "${CMAKE_CURRENT_BINARY_DIR}/doxy.config") ELSE (EXISTS "${CMAKE_MODULE_PATH}/doxy.config.in") # failed completely... MESSAGE(SEND_ERROR "Please create ${CMAKE_CURRENT_SOURCE_DIR}/doxy.config.in (or doxy.config as fallback)") ENDIF(EXISTS "${CMAKE_MODULE_PATH}/doxy.config.in") ENDIF(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/doxy.config") ENDIF(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/doxy.config.in") ADD_CUSTOM_TARGET(doc ${DOXYGEN_EXECUTABLE} ${DOXY_CONFIG} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/doxy.config) # create a windows help .chm file using hhc.exe # HTMLHelp DLL must be in path! # fallback: use hhw.exe interactively IF (WIN32) FIND_PACKAGE(HTMLHelp) IF (HTML_HELP_COMPILER) SET (TMP "${CMAKE_CURRENT_BINARY_DIR}\\doc\\html\\index.hhp") STRING(REGEX REPLACE "[/]" "\\\\" HHP_FILE ${TMP} ) # MESSAGE(SEND_ERROR "DBG HHP_FILE=${HHP_FILE}") ADD_CUSTOM_TARGET(winhelp ${HTML_HELP_COMPILER} ${HHP_FILE}) ADD_DEPENDENCIES (winhelp doc) IF (NOT TARGET_DOC_SKIP_INSTALL) # install windows help? # determine useful name for output file # should be project and version unique to allow installing # multiple projects into one global directory IF (EXISTS "${PROJECT_BINARY_DIR}/doc/html/index.chm") IF (PROJECT_NAME) SET(OUT "${PROJECT_NAME}") ELSE (PROJECT_NAME) SET(OUT "Documentation") # default ENDIF(PROJECT_NAME) IF (${PROJECT_NAME}_VERSION_MAJOR) SET(OUT "${OUT}-${${PROJECT_NAME}_VERSION_MAJOR}") IF (${PROJECT_NAME}_VERSION_MINOR) SET(OUT "${OUT}.${${PROJECT_NAME}_VERSION_MINOR}") IF (${PROJECT_NAME}_VERSION_PATCH) SET(OUT "${OUT}.${${PROJECT_NAME}_VERSION_PATCH}") ENDIF(${PROJECT_NAME}_VERSION_PATCH) ENDIF(${PROJECT_NAME}_VERSION_MINOR) ENDIF(${PROJECT_NAME}_VERSION_MAJOR) # keep suffix SET(OUT "${OUT}.chm") #MESSAGE("DBG ${PROJECT_BINARY_DIR}/doc/html/index.chm \n${OUT}") # create target used by install and package commands INSTALL(FILES "${PROJECT_BINARY_DIR}/doc/html/index.chm" DESTINATION "doc" RENAME "${OUT}" ) ENDIF(EXISTS "${PROJECT_BINARY_DIR}/doc/html/index.chm") ENDIF(NOT TARGET_DOC_SKIP_INSTALL) ENDIF(HTML_HELP_COMPILER) # MESSAGE(SEND_ERROR "HTML_HELP_COMPILER=${HTML_HELP_COMPILER}") ENDIF (WIN32) ENDIF(DOXYGEN_FOUND) cgreen-1.6.3/config.h.cmake000066400000000000000000000013031450461175400154650ustar00rootroot00000000000000/* Name of package */ #cmakedefine PACKAGE "${APPLICATION_NAME}" /* Version number of package */ #cmakedefine VERSION "${APPLICATION_VERSION}" #cmakedefine LOCALEDIR "${LOCALE_INSTALL_DIR}" #cmakedefine DATADIR "${DATADIR}" #cmakedefine LIBDIR "${LIBDIR}" #cmakedefine PLUGINDIR "${PLUGINDIR}" #cmakedefine SYSCONFDIR "${SYSCONFDIR}" /************************** HEADER FILES *************************/ /*************************** FUNCTIONS ***************************/ /*************************** LIBRARIES ***************************/ /**************************** OPTIONS ****************************/ /* Define if building with gcov instrumentation */ #cmakedefine CGREEN_INTERNAL_WITH_GCOV cgreen-1.6.3/contrib/000077500000000000000000000000001450461175400144335ustar00rootroot00000000000000cgreen-1.6.3/contrib/README.contrib000066400000000000000000000006141450461175400167530ustar00rootroot00000000000000All files under this contrib directory are UNSUPPORTED. There were provided by users of Cgreen and were not tested by the authors of Cgreen. Use at your own risk. SCons/ by Kevin Fitch Add a sample demonstrating using cgreen with SCons http://www.scons.org/ upgrade/ by Thomas Nilsson and Colm Dougan Will upgrade a pre-beta version of tests to newer API cgreen-1.6.3/contrib/SCons/000077500000000000000000000000001450461175400154605ustar00rootroot00000000000000cgreen-1.6.3/contrib/SCons/SConstruct000066400000000000000000000023571450461175400175210ustar00rootroot00000000000000env = Environment() # Add the cgreen headers to the include path env.Append(CPPPATH=['../../include', ]) # Build the cgreen library cgreendir = '../../src/' cgreenfiles = """unit.c messaging.c breadcrumb.c reporter.c assertions.c vector.c mocks.c constraint.c parameters.c text_reporter.c""".split() cgreensources = ['../../src/'+f for f in cgreenfiles] cgreenlib = env.StaticLibrary('cgreen', cgreensources) #Build our code to be tested env.Append(CPPPATH=['include']) mainlib = env.StaticLibrary('main', env.Glob('src/*.c')) for test in env.Glob('tests/*.c'): testprog = env.Program(test, LIBS=[cgreenlib, mainlib]) # This is a nasty little hack here. # We run the test twice, the first time is so we can see the output on the # console, and get the results logged. Unfortunately it will not cause the # build to stop on test failures since the result of the command is the # return value of tee, not the tests. So we run it again to catch the # possibly failed return value ... those tests better be repeatable! env.Command(testprog[0].path+'.results', testprog, '$SOURCE 2>&1 | tee $TARGET') env.Command(testprog[0].path+'.results_', testprog, '$SOURCE > $TARGET 2>&1 ') cgreen-1.6.3/contrib/android/000077500000000000000000000000001450461175400160535ustar00rootroot00000000000000cgreen-1.6.3/contrib/android/Android.mk000066400000000000000000000043041450461175400177650ustar00rootroot00000000000000#======================================================================# # Android.mk for CGgreen C++ unit test framework # # (Suggest building as .so and only including lib for debug builds # when running e.g. android instrumented tests) # # Steve Madsen, 10 Aug 2016 #======================================================================# LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := cgreen MY_CGREEN_BASE_PATH := ../.. MY_CGREEN_BASE_PATH_ABS := $(LOCAL_PATH)/$(MY_CGREEN_BASE_PATH) MY_CGREEN_SRC_PATH := $(MY_CGREEN_BASE_PATH)/src LOCAL_SRC_FILES := \ $(MY_CGREEN_SRC_PATH)/cpp_assertions.cpp \ $(MY_CGREEN_SRC_PATH)/cpp_constraint.cpp \ $(MY_CGREEN_SRC_PATH)/local_messaging.cpp LOCAL_SRC_FILES += \ $(MY_CGREEN_SRC_PATH)/assertions.c \ $(MY_CGREEN_SRC_PATH)/boxed_double.c \ $(MY_CGREEN_SRC_PATH)/breadcrumb.c \ $(MY_CGREEN_SRC_PATH)/cdash_reporter.c \ $(MY_CGREEN_SRC_PATH)/cgreen_time.c \ $(MY_CGREEN_SRC_PATH)/constraint.c \ $(MY_CGREEN_SRC_PATH)/constraint_syntax_helpers.c \ $(MY_CGREEN_SRC_PATH)/cute_reporter.c \ $(MY_CGREEN_SRC_PATH)/memory.c \ $(MY_CGREEN_SRC_PATH)/message_formatting.c \ $(MY_CGREEN_SRC_PATH)/mocks.c \ $(MY_CGREEN_SRC_PATH)/parameters.c \ $(MY_CGREEN_SRC_PATH)/posix_cgreen_pipe.c \ $(MY_CGREEN_SRC_PATH)/posix_cgreen_time.c \ $(MY_CGREEN_SRC_PATH)/posix_runner_platform.c \ $(MY_CGREEN_SRC_PATH)/reporter.c \ $(MY_CGREEN_SRC_PATH)/runner.c \ $(MY_CGREEN_SRC_PATH)/string_comparison.c \ $(MY_CGREEN_SRC_PATH)/suite.c \ $(MY_CGREEN_SRC_PATH)/text_reporter.c \ $(MY_CGREEN_SRC_PATH)/utils.c \ $(MY_CGREEN_SRC_PATH)/vector.c \ $(MY_CGREEN_SRC_PATH)/xml_reporter.c LOCAL_C_INCLUDES := \ $(MY_CGREEN_BASE_PATH_ABS)/include \ $(MY_CGREEN_BASE_PATH_ABS)/src LOCAL_EXPORT_C_INCLUDES := \ $(MY_CGREEN_BASE_PATH_ABS) \ $(MY_CGREEN_BASE_PATH_ABS)/include \ $(MY_CGREEN_BASE_PATH_ABS)/src LOCAL_CFLAGS += -O3 -DVERSION="\"OnAndroid\"" # DO_MAKE_DYNAMIC_LIB: boolean-as-int # 0: build .a (static) lib # 1: build .so ("dynamic"/"shared") lib DO_MAKE_DYNAMIC_LIB := 0 ifeq ($(DO_MAKE_DYNAMIC_LIB),1) LOCAL_LDLIBS := -llog include $(BUILD_SHARED_LIBRARY) else include $(BUILD_STATIC_LIBRARY) endif cgreen-1.6.3/contrib/cgreen-mocker/000077500000000000000000000000001450461175400171545ustar00rootroot00000000000000cgreen-1.6.3/contrib/cgreen-mocker/.gitignore000066400000000000000000000000701450461175400211410ustar00rootroot00000000000000double.mock complex_types.mock pycparser .vscode *.mock cgreen-1.6.3/contrib/cgreen-mocker/Makefile000066400000000000000000000016411450461175400206160ustar00rootroot00000000000000all: @echo "Testing..." @echo -n "double... " @./cgreen-mocker.py double.h > double.mock @diff double.mock double.mock.expected @if [ "$$?" -eq 0 ] ; then echo "Ok" ; fi @echo -n "complex_types... " @./cgreen-mocker.py complex_types.h > complex_types.mock @diff complex_types.mock complex_types.mock.expected @if [ "$$?" -eq 0 ] ; then echo "Ok" ; fi @echo -n "simple_types... " @./cgreen-mocker.py simple_types.h > simple_types.mock @diff simple_types.mock simple_types.mock.expected @if [ "$$?" -eq 0 ] ; then echo "Ok" ; fi @echo -n "multiple_types... " @./cgreen-mocker.py multiple_types.h > multiple_types.mock @diff multiple_types.mock multiple_types.mock.expected @if [ "$$?" -eq 0 ] ; then echo "Ok" ; fi @echo -n "multiple_args... " @./cgreen-mocker.py -Da=b -Dc=d multiple_types.h > multiple_args.mock @diff multiple_args.mock multiple_types.mock.expected @if [ "$$?" -eq 0 ] ; then echo "Ok" ; fi cgreen-1.6.3/contrib/cgreen-mocker/cgreen-mocker.py000077500000000000000000000227611450461175400222620ustar00rootroot00000000000000#!/usr/bin/env python # ----------------------------------------------------------------- # cgreen-mocker.py # # Create Cgreen mocks from extern declarations of functions, # typically in a header file. # # Usage: # cgreen-mocker.py { } # # : any 'cpp' directive but most useful is e.g. # "-I " to ensure cpp finds files. # # : file with function declarations that you want # to mock # # Simplistically adapted from pycparser example: func_defs.py # # Since it uses pycparser it will only handle C functions and you will # probably need the pycparsers "fake_libc_include" to avoid parsing # the whole world of libc headers. To use it, make a soft link with # the name 'pycparser' in the directory you are running this from, or # in the directory of 'cgreen-mocker' itself, to the top directory of # the pycparser source, and cgreen-mocker will pick it up # automatically. Or you can point to it using a command line # 'cpp_directive' arg. # # Thanks to @gardenia for the pointer to pycparser! # # https://github.com/eliben/pycparser # # (C) 2016, Thomas Nilefalk # # Using pycparser for printing out all the functions defined in a # C file. # # PyCParser - Copyright (C) 2008-2015, Eli Bendersky # License: BSD # ----------------------------------------------------------------- from __future__ import print_function from pycparser.plyparser import ParseError from pycparser import c_parser, c_ast, parse_file, c_generator from functools import reduce from packaging import version import sys import os import pycparser # This is not required if you've installed pycparser into # your site-packages/ with setup.py sys.path.extend(['.', '..']) # Print on stderr def eprint(*args, **kwargs): print(*args, file=sys.stderr, **kwargs) # A visitor for FuncDef nodes that prints the # Cgreen mock equivalent of the function class FuncDefVisitor(c_ast.NodeVisitor): def __init__(self, filename): self._types = {} self.filename = filename def visit_FuncDecl(self, node): if node.coord.file == self.filename: # Only consider definitions that are in the processed file generator = c_generator.CGenerator() try: print(generator.visit(node), end="") print(" { ") self.should_return(node) print("mock(%s);" % ", ".join(arg_list(node.args))) print("}") print() except Exception as e: print("ERROR: {} - Unexpected AST @ {}:{}:{}:".format(e, node.coord.file, node.coord.line, node.coord.column)) node.show() return def visit_Typedef(self, node): self._types[node.name] = { 'is_pointer': isinstance(node.type, c_ast.PtrDecl), } if self._types[node.name]['is_pointer']: self._types[node.name]['to_class'] = node.type.type.type.names else: self._types[node.name]['to_class'] = None def should_return(self, node): generator = c_generator.CGenerator() type = node.type if is_double_decl(node): print(" return unbox_double(", end="") elif not is_void_decl(node): print(" return %s(" % ("*" if self.is_return_struct_by_value(node) else ""), end="") print(generator.visit(node.type), end="") if version.parse(pycparser.__version__) <= version.parse('2.19') \ and isinstance(node.type, c_ast.PtrDecl) \ or self.is_return_struct_by_value(node): print(" *", end="") print(") ", end="") else: print(" ", end="") def is_return_struct_by_value(self, node): type = node.type return not isinstance(type, c_ast.PtrDecl) and type.type.names[0] in self._types and not self._types[type.type.names[0]]['is_pointer'] def is_return_by_value_pointer(self, node): type = node.type return not isinstance(type, c_ast.PtrDecl) and self._types[type.type.names[0]]['is_pointer'] def arg_list(args): if args != None and len(args.params) > 0: return [el for el in map(parameter_name_or_box_double, filter(lambda x: not is_ellipsis_param(x), args.params)) if el is not None] else: return [] def parameter_name_or_box_double(node): if is_double_decl(node): return "box_double({})".format(node.name) else: return node.name def is_void_decl(node): type = node.type return isinstance(type, c_ast.TypeDecl) and type.type.names == ['void'] def is_double_decl(node): type = node.type return isinstance(type, c_ast.TypeDecl) and type.type.names == ['double'] def is_ellipsis_param(node): return isinstance(node, c_ast.EllipsisParam) def show_func_defs(args): # Note that cpp is used. Provide a path to your own cpp or # make sure one exists in PATH. pycparser_path = None # Try to find a fake_libc # In current directory? if verbose: eprint("Called in {0}".format( os.path.abspath(os.path.dirname(sys.argv[0])))) eprint("Looking for fake_lib in current directory...") if os.path.isdir('pycparser'): pycparser_path = r'./pycparser' else: this_script = os.path.abspath(__file__) if verbose: eprint( "Looking for fake_lib in directory of script ({0})...".format(this_script)) # Look in the directory of this script while os.path.islink(this_script): # If the script is a symlink, resolve it first, recursively... # Note: can only handle absolute symlinks? this_script = os.readlink(this_script) if verbose: eprint( "Script was a symlink, resolving it to '{0}'...".format(this_script)) if os.path.isdir(os.path.join(os.path.dirname(this_script), 'pycparser')): # Yes, there is a pycparser symlink here pycparser_path = os.path.join(os.path.dirname(this_script), 'pycparser') if pycparser_path: pycparser_lib = reduce( os.path.join, [pycparser_path, 'utils', 'fake_libc_include']) if verbose: print("/* Generated with cgreen-mocker and pycparser's fake_libc from %s */" % (pycparser_path)) elif verbose: eprint("Not found") try: options = [ '-I'+pycparser_lib] if pycparser_path else [] if add_gnuisms: # And add some common GNUisms options = options + [ r'-D__gnuc_va_list(c)=', r'-D__attribute__(x)=', r'-D__extension__=', r'-D__restrict=', r'-D__inline=' ] if verbose: eprint("Parsing with options = {0}".format(options)) cpp_args = list(filter(None, options)) ast = parse_file(args[-1], use_cpp=True, cpp_args=cpp_args + args[0:-1]) except ParseError as e: print("ERROR: {} - C99 parse error".format(e)) return print('/* -*- c -*-*/') # Suggest c-mode for Emacs print('#include "%s"' % args[len(args)-1]) print('#include ') print() v = FuncDefVisitor(args[-1]) v.visit(ast) def usage(): print(""" Usage: cgreen-mocker.py { } : any 'cpp' directive but most useful are e.g. "-I " to ensure cpp finds files and "-D " to create an inline define : file with function declarations that you want to mock Cgreen-mocker takes a header file and generates cgreen mocks for all functions in it. It will print the generated mocks to standard output so you can inspect it, or pipe it to a file that can be compiled and linked with your tests. The mocker will only handle functions that are declared in the header file you provide. This is based on the presumtion that the header file represents functions in a unit. Aggregating functions from multiple units into a single header for convenience is not supported. Also the mocker cannot handle data declarations (yet?). If your header does not name some arguments you will not be able to use those arguments in 'expect when' statements, of course. Cgreen-mocker will only generate mocks for the external functions in the file you give as an argument, not those in included files. If cgreen-mocker encounters parse errors and they look like gnu-isms you should get a copy of the source for pycparser (on which cgreen-mocker is built). In it you will find a 'fake_libc_include' which help. Create a symbolic link named 'pycparser' that links to the root of pycparser source and cgreen-mocker will find it itself. You can find pycparser at https://github.com/eliben/pycparser """) if __name__ == "__main__": if len(sys.argv) <= 1: usage() exit(-1) if '-v' in sys.argv: verbose = True sys.argv.remove('-v') else: verbose = False if '-gnu' in sys.argv: add_gnuisms = True sys.argv.remove('-gnu') else: add_gnuisms = False show_func_defs(sys.argv[1:]) cgreen-1.6.3/contrib/cgreen-mocker/complex_types.h000066400000000000000000000003751450461175400222250ustar00rootroot00000000000000typedef struct BasicStruct { int someValue; } BasicStruct; typedef BasicStruct* BasicStructPtr; BasicStruct return_struct_by_value(int i); BasicStructPtr return_pointer_to_struct(char string[]); BasicStruct* direct_return_pointer_to_struct(void); cgreen-1.6.3/contrib/cgreen-mocker/complex_types.mock.expected000066400000000000000000000005271450461175400245260ustar00rootroot00000000000000/* -*- c -*-*/ #include "complex_types.h" #include BasicStruct return_struct_by_value(int i) { return *(BasicStruct *) mock(i); } BasicStructPtr return_pointer_to_struct(char string[]) { return (BasicStructPtr) mock(string); } BasicStruct *direct_return_pointer_to_struct(void) { return (BasicStruct *) mock(); } cgreen-1.6.3/contrib/cgreen-mocker/double.h000066400000000000000000000000471450461175400206000ustar00rootroot00000000000000double return_double(double d, int i); cgreen-1.6.3/contrib/cgreen-mocker/double.mock.expected000066400000000000000000000002301450461175400230740ustar00rootroot00000000000000/* -*- c -*-*/ #include "double.h" #include double return_double(double d, int i) { return unbox_double(mock(box_double(d), i); } cgreen-1.6.3/contrib/cgreen-mocker/multiple_types.h000066400000000000000000000010171450461175400224030ustar00rootroot00000000000000typedef struct Struct1 { int someValue; } Struct1; typedef Struct1* Struct1Ptr; Struct1 return_struct1_by_value(int i); Struct1Ptr return_pointer_to_struct1(char string[]); Struct1* direct_return_pointer_to_struct1(void); typedef struct Struct2 { int someValue; } Struct2; typedef Struct2* Struct2Ptr; Struct2 return_struct2_by_value(int i); Struct2Ptr return_pointer_to_struct2(char string[]); Struct2* direct_return_pointer_to_struct2(void); extern void return_nothing(void); extern int return_int(int ints[]); cgreen-1.6.3/contrib/cgreen-mocker/multiple_types.mock.expected000066400000000000000000000012461450461175400247110ustar00rootroot00000000000000/* -*- c -*-*/ #include "multiple_types.h" #include Struct1 return_struct1_by_value(int i) { return *(Struct1 *) mock(i); } Struct1Ptr return_pointer_to_struct1(char string[]) { return (Struct1Ptr) mock(string); } Struct1 *direct_return_pointer_to_struct1(void) { return (Struct1 *) mock(); } Struct2 return_struct2_by_value(int i) { return *(Struct2 *) mock(i); } Struct2Ptr return_pointer_to_struct2(char string[]) { return (Struct2Ptr) mock(string); } Struct2 *direct_return_pointer_to_struct2(void) { return (Struct2 *) mock(); } void return_nothing(void) { mock(); } int return_int(int ints[]) { return (int) mock(ints); } cgreen-1.6.3/contrib/cgreen-mocker/requirements.txt000066400000000000000000000000251450461175400224350ustar00rootroot00000000000000pycparser packaging cgreen-1.6.3/contrib/cgreen-mocker/simple_types.h000066400000000000000000000001341450461175400220400ustar00rootroot00000000000000int return_int(void); char return_char(char c); char* return_pointer_to_char(char *string); cgreen-1.6.3/contrib/cgreen-mocker/simple_types.mock.expected000066400000000000000000000003771450461175400243530ustar00rootroot00000000000000/* -*- c -*-*/ #include "simple_types.h" #include int return_int(void) { return (int) mock(); } char return_char(char c) { return (char) mock(c); } char *return_pointer_to_char(char *string) { return (char *) mock(string); } cgreen-1.6.3/contrib/rpm/000077500000000000000000000000001450461175400152315ustar00rootroot00000000000000cgreen-1.6.3/contrib/rpm/cgreen.spec000066400000000000000000000062021450461175400173500ustar00rootroot00000000000000# Mini-HOWTO: # # 1. Update gitcommit, gitncommits and gitversion in this file with # data from "git describe --tags". (See below). # # 2. Fetch the latest source archive from github: # # curl -Lo ~/rpmbuild/SOURCES/cgreen-master.zip https://github.com/cgreen-devs/cgreen/archive/master.zip # # 3. Build the source and binary RPMs: # # mock $(rpmbuild -bs cgreen.spec | cut -d" " -f2) # # You could also provide your own source archive if that's what you're # looking for. Make sure to adjust Source0: and the %prep phase # accordingly. # $ git describe --tags # 1.0.0-387-g8130aa7 # | | +--v %define gitcommit g8130aa7 # | +----------v %define gitncommits 387 # +--------------v %define gitversion 1.0.0 Summary: Cgreen is a modern unit test and mocking framework for C and C++. Name: cgreen Version: %{gitversion} Release: %{gitncommits}.%{gitcommit} License: ISC URL: https://github.com/cgreen-devs/cgreen Source0: %{name}-master.zip BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root BuildRequires: cmake %description A modern, portable, cross-language unit testing and mocking framework for C and C++ %prep %setup -q -n cgreen-master %build %cmake . %install rm -rf $RPM_BUILD_ROOT # Don't put things into /usr/lib/cmake on 64-bit systems %if "%{?_lib}" == "lib64" sed -i -e "s@/lib/cmake/cgreen@/lib64/cmake/cgreen@g" cmake_install.cmake %endif %make_install %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root,-) %{_bindir}/cgreen-runner %dir %{_includedir}/cgreen %{_includedir}/cgreen/assertions.h %{_includedir}/cgreen/boxed_double.h %{_includedir}/cgreen/breadcrumb.h %{_includedir}/cgreen/cdash_reporter.h %{_includedir}/cgreen/cgreen.h %{_includedir}/cgreen/cgreen_value.h %{_includedir}/cgreen/constraint.h %{_includedir}/cgreen/constraint_syntax_helpers.h %{_includedir}/cgreen/cpp_assertions.h %{_includedir}/cgreen/cpp_constraint.h %{_includedir}/cgreen/cute_reporter.h %{_includedir}/cgreen/internal/assertions_internal.h %{_includedir}/cgreen/internal/c_assertions.h %{_includedir}/cgreen/internal/cgreen_pipe.h %{_includedir}/cgreen/internal/cgreen_time.h %{_includedir}/cgreen/internal/cpp_assertions.h %{_includedir}/cgreen/internal/function_macro.h %{_includedir}/cgreen/internal/mock_table.h %{_includedir}/cgreen/internal/mocks_internal.h %{_includedir}/cgreen/internal/runner_platform.h %{_includedir}/cgreen/internal/stringify_token.h %{_includedir}/cgreen/internal/suite_internal.h %{_includedir}/cgreen/internal/unit_implementation.h %{_includedir}/cgreen/legacy.h %{_includedir}/cgreen/mocks.h %{_includedir}/cgreen/reporter.h %{_includedir}/cgreen/runner.h %{_includedir}/cgreen/string_comparison.h %{_includedir}/cgreen/suite.h %{_includedir}/cgreen/text_reporter.h %{_includedir}/cgreen/unit.h %{_includedir}/cgreen/vector.h %dir %{_libdir}/cmake/cgreen %{_libdir}/cmake/cgreen/cgreen-config-version.cmake %{_libdir}/cmake/cgreen/cgreen-config.cmake %{_libdir}/libcgreen.so %{_libdir}/libcgreen.so.1 %{_libdir}/libcgreen.so.1.1.0 %{_mandir}/man1/cgreen-runner.1.gz %{_mandir}/man5/cgreen.5.gz %changelog * Tue Feb 6 2018 Karl Mikaelsson - 1.0.0-387.g8130aa7 - Initial build of git master. cgreen-1.6.3/contrib/upgrade/000077500000000000000000000000001450461175400160625ustar00rootroot00000000000000cgreen-1.6.3/contrib/upgrade/upgrade.sh000077500000000000000000000014011450461175400200440ustar00rootroot00000000000000# Perl-script to upgrade from pre-beta versions # Initial version by Colm Dougan, contributed by Thomas Nilsson perl -pi -e 's/\bEnsure\s+(\w+)\s*\(\)/Ensure($1)/' $@ perl -pi -e 's/\bEnsure\s+(\w+)\s*\(void\)/Ensure($1)/' $@ perl -pi -e 's/\bfail\(\)/fail("expected exception")/' $@ perl -pi -e 's/\bexpect_call/expect/' $@ perl -pi -e 's/\bwant\((\w+), ([^)]+)/when($1, is_equal_to($2)/' $@ perl -pi -e 's/\bwill_respond\((\w+),\ ([^,\)]+)/expect($1, will_return($2)/' $@ perl -pi -e 's/\bwill_return\((\w+),\ ([^,\)]+)/expect($1, will_return($2)/' $@ perl -pi -e 's/\bwant_non_null_?\(\"(\w+)\"\)/when($1, is_non_null)/' $@ perl -pi -e 's/\bsetup\(/set_setup(/g' $@ perl -pi -e 's/\bteardown\(/set_teardown(/g' $@ perl -pi -e 's/\bexpect_never\(/never_expect(/g' $@ cgreen-1.6.3/debian/000077500000000000000000000000001450461175400142155ustar00rootroot00000000000000cgreen-1.6.3/debian/README.deb000066400000000000000000000036701450461175400156340ustar00rootroot00000000000000# How to create a quick and dirty .deb Sometimes you need a .deb with a recent version of Cgreen to install for your development. And you don't want, or can't, wait for the package maintainer to keep up... ## Build a package You can build a simple .tar.gz using `make package`. Depending on how `CMake` is configured you will get a couple of tar/zip file that you can start from. Once created they are located in the build directory. Pick one. NB: It seems this does not build the library and `cgreen-runner` correctly wrt. options set. Particularly it does not manage to create a `cgreen-runner` and a library that agrees on support for `libxml2` even if the normal build does. I solved this by simply copying the library and the `cgreen-runner` from a normal build into the packaging directory. ## Prepare a packaging directory Create a separate directory somewhere, say `cgreen-deb`, and extract the selected package there. You should now have a directory like `cgreen-1.6.1_amd64`. Create a new subdirectory `DEBIAN` inside it. Copy the file `debian/control` from the repo to `DEBIAN/control`. Update the `Architecture:` field and ensure that the version is correct. Depending on the packaging the lib-files might have been stored in a subdirectory rather than directly in /lib. For Ubuntu they should be in `/lib/x86_64-linux-gnu`. ## Make the .deb In the examples below `1.6.1` is of course just an example... In the directory where you now have your unpacked package content (in the example above `cgreen-deb`) run $ dpkg-deb --build --root-owner-group cgreen-1.6.1-x86_64-linux-gnu That should create `cgreen-1.6.1_amd64.deb`. ## Test it You can run $ lintian cgreen-1.6.1-x86_64-linux-gnu.deb and try to fix most of the errors and warnings. NOTE we are not making a real distro packaging! Verify that $ sudo dpkg -i cgreen-1.6.1_amd64.deb installs the files correctly. And that $ sudo dpkg -r cgreen removes them. cgreen-1.6.3/debian/control000066400000000000000000000011411450461175400156150ustar00rootroot00000000000000Source: cgreen Section: devel Priority: optional Maintainer: Thomas Nilefalk Depends: libc6 Homepage: https://github.com/cgreen-devs/cgreen Package: cgreen1 Version: 1.6.2 Architecture: amd64 Description: Unit tests and mocking framework for C and C++ A modern unit test and mocking framework for C and C++. Cgreen features - fast build, clean code, highly portable - simple auto-discovery of tests - fluent, expressive and readable API - each test runs in isolation to prevent cross-test dependencies - built-in mocking for C, compatible other C++ mocking libraries cgreen-1.6.3/debian/triggers000066400000000000000000000000321450461175400157610ustar00rootroot00000000000000activate-noawait ldconfig cgreen-1.6.3/doc/000077500000000000000000000000001450461175400135405ustar00rootroot00000000000000cgreen-1.6.3/doc/.gitignore000066400000000000000000000000411450461175400155230ustar00rootroot00000000000000cgreen-guide-en.html html_chunks cgreen-1.6.3/doc/CMakeLists.txt000066400000000000000000000034141450461175400163020ustar00rootroot00000000000000FIND_PACKAGE(Asciidoctor) SET(ASCIIDOC_CONFFILE "${PROJECT_SOURCE_DIR}/doc/cgreen_asciidoc.conf") OPTION(CGREEN_WITH_HTML_DOCS "with HTML output" FALSE) OPTION(CGREEN_WITH_PDF_DOCS "with PDF output" FALSE) IF (CGREEN_WITH_HTML_DOCS AND NOT ASCIIDOCTOR_FOUND) MESSAGE(FATAL_ERROR "Can't produce HTML without 'asciidoctor'") ENDIF (CGREEN_WITH_HTML_DOCS AND NOT ASCIIDOCTOR_FOUND) IF (CGREEN_WITH_PDF_DOCS AND NOT ASCIIDOCTORPDF_FOUND) MESSAGE(FATAL_ERROR "Can't produce PDF without 'asciidoctor-pdf'") ENDIF (CGREEN_WITH_PDF_DOCS AND NOT ASCIIDOCTORPDF_FOUND) IF(CGREEN_WITH_HTML_DOCS OR CGREEN_WITH_PDF_DOCS) FILE(GLOB _docfiles *.asciidoc) FOREACH(_file ${_docfiles}) GET_FILENAME_COMPONENT(_file_we ${_file} NAME_WE) SET(_in "${_file_we}") IF (CGREEN_WITH_HTML_DOCS) SET(_out "${_file_we}.html") ADD_CUSTOM_COMMAND( OUTPUT "${_out}-html" COMMAND ${ASCIIDOCTOR_EXECUTABLE} -a VERSION=${APPLICATION_VERSION} -o ${_out} ${_file} DEPENDS ${_file} COMMENT "asciidoctor ${_in}" ) ADD_CUSTOM_TARGET(${_in}-html ALL echo DEPENDS "${_out}-html" ) ENDIF (CGREEN_WITH_HTML_DOCS) IF (CGREEN_WITH_PDF_DOCS) SET(_out "${_file_we}.pdf") ADD_CUSTOM_COMMAND( OUTPUT "${_out}-pdf" COMMAND ${ASCIIDOCTORPDF_EXECUTABLE} -a toc -a VERSION=${APPLICATION_VERSION} -a docinfo -o ${_out} ${_file} DEPENDS ${_file} COMMENT "asciidoctor-pdf ${_in}" ) ADD_CUSTOM_TARGET(${_in}-pdf ALL echo DEPENDS "${_out}-pdf" ) ENDIF (CGREEN_WITH_PDF_DOCS) ENDFOREACH(_file) ENDIF(CGREEN_WITH_HTML_DOCS OR CGREEN_WITH_PDF_DOCS) IF(UNIX) set(MANPAGES man) INSTALL(DIRECTORY ${MANPAGES} DESTINATION share) ENDIF(UNIX) cgreen-1.6.3/doc/README000066400000000000000000000035501450461175400144230ustar00rootroot00000000000000HOW-TO: Compiling the Cgreen Guide =================================== The Cgreen Guide Book is written using Asciidoctor. Asciidoctor builds upon the asciidoc format, is 100 times faster than the Python asciidoc toolchain and can generate PDF in the same step. Writing in asciidoc(tor) is a wonderful way to write textual docs. Please visit http://www.asciidoctor.org for more information. You also need a source-highlighter as described in (http://asciidoctor.org/docs/asciidoc-syntax-quick-reference/#source-code) There are a number of source examples in the documentation that are automatically included from the `tutorial_src` subdirectory. They are kept separate so that they can be compiled to ensure that they actually are correct. Then all, or a part of, the file can be included. To do that, go to the subdirectory, ensure you have the correct version of cgreen in your path and do `make`. The one drawback of this strategy is that you cannot read the source of the examples in a raw asciidoc-conversion, like on github, since it requires including other files, which is not allowed for security reasons. So we need to generate the documentation and upload it to `cgreen-devs.github.io`. Ensure you have *asciidoctor* installed (`sudo apt install asciidoctor` or similar). It is preferred to generate multi-page HTML, which currently asciidoctor does not do natively yet. There is an extension in the asciidoctor-extension-lab, which I have not tried. [asciidoctor-chunker](https://github.com/wshito/asciidoctor-chunker) works well, but requires installing Roswell (a Common Lisp environment). If you use asciidoctor-chunker, first generate the HTML with asciidoctor asciidoctor cgreen-guide-en.asciidoc -o html/cgreen-guide-en.html then chunk it using asciidoctor-chunker (assuming some convenience links in your path...) asciidoctor-chunker html/cgreen-guide-en.html cgreen-1.6.3/doc/README.asciidoc000066400000000000000000000002461450461175400161770ustar00rootroot00000000000000// Converted to index.html by asciidoctor-ghpages GitHub Action = Cgreen documentation - link:cgreen-guide-en.html[The Guide] - link:cheat-sheet.html[Cheat Sheet] cgreen-1.6.3/doc/avtar.png000066400000000000000000002601541450461175400153730ustar00rootroot00000000000000PNG  IHDRFFJlgAMA a cHRMz&u0`:pQ<heXIfMM*(i>FFOiTXtXML:com.adobe.xmp 1 2 1 2 1459 1 829 YD@IDATx dWq&^mM*T a11 0Y}3#` mӟV c3h $TڪTz͛w3_T{9qċr"K!`!`4 C0 C0/0 C0 1FS0 C0 C#` C0 Ccd?C0 C0<O0 C0 @ڐ0 #PŋAG49RWuY2\^M0c%ɓ44h)KCZ4Pϡ}(!+e!|1j>* O~HVGJ更[n /ޱYZ?!`tuk\?xF?DCƚ-Ni ?y!cq,bGih_1P_;cug텀1FljkW&iӫo7F4 UDU߆.|^ Qjn|e/7w-C2 BBƝ /{1Yģ`}M5GY ` j]. .|;4/,Q"m{{imU{ 6!` _k-V| `TҼn= C`cx @]vjCM2n]lGio!`, c_*jL}ӟ.] ` R(!`D"`Q$,V,P;gmz? _hO1jYCWԲ AmF-C2 `rг0h$VH{ۇ>L[_ZcaFX32kW*31+Ҫob0h1(͜)33"@`wҞ?;"`߶}Ns̵mO|ͫ?!`c짰d.> G!Z2r ׽.g{0 "`QKn̰_gλh[fqQ6?C0ƨ_p3ٱ2Q3д>Cң=8u1!bcbvFǦ6n0ۣv{c6_Cs0ƨseSWb uv ?.;kb1F]Ƕ18S1E1|76#p#?S!`00Ev&C|]~@ sbmuT\eK[_^FLX2 !0p;ڻ>N!`j9yKĩ05`QE&:1 Q,J)j%6Z@NP6ǒ!`Ĩ=Sb(}y5b `l!`LQ`4Cc7UhoLgLQL_M0cz#>{$`PIyG4 _ nɛ*m1(Ƙníyyz<!*'T ?{%6V>wV ]h}8C8Gяͦ()aGj]g!4CT͛1WSzmDC !`2KDqbƒ!`o}RݭF3*v^bJXF\h5KaoULH!$R- C`nul| 1KF؜NjB $_ B\/R]yJSĻ~ש%CvJ-~fo衲0Q-gM2ŜKs-dՃk؜Z.S jeGǺ;9َ Cl%!C]|͇ WOeL k@/7+0zO*lCRR޽Kmf@G#5OkRQ"0y % rj-^"Tfɑ<(JJLjIDDN$t(EwUgHcDе)e#17(&fB?7 CVWtWPA$8|G$OR} 3{)Qo3/h$.ᛀ ? sY %18ǎKuj4Т(?f@32f $C=0UZȣҁE0!LhZ_kfEǺ,iL3iꌲRZyG4ޜ'G9i!.u})6݆,Ad@<ؠA}VmRlvjLb ^+NVt 0VbwWnh; c4?>ˮ}F:Ph[g۴wXE_@SG7Bho.wP֭!fSib%wuw>KS`kU Tqǡ!H~rܕmHWl‘{k0G;$udls@`1Z1F'>"}[Auo|4(.1,?$=3oV~27yMZuc\]nk@7Anefh>Juwbq`7ae(]_FQ\#깺fCj!H ɟ:}JT^3tz䬔9{&h&)۷gE/|Rl?|gI2l~*;hکלgliNTiU/u JаP \q -[F//tKm:d`RdT#5bʇ`CHG/Ò駄igOnɲW핲s$nfRAJ{fR#:hƕM2Cоi^Z'#`>U)U2tPoVF%|@cccRvpƊ#KT6uQ.L2C/e J|Oj/rF^g7m$1'ղo iMb48Kgk{Ň#(Z,076r' 5^ :gȇ?Rƌ>kxfL7{ G0BCc476KƑ%1GoЇi^n'Bc㭷Pa=wj- Ns 5c|mx)QxJ\C *Z_Kl @IKKi||2M'> 4Qt'OϢ"Mi""r*k!%Bڹs n ^Y'} 1쥋BM|1Fschz#\}!׮)uR_:?5 R@H Yih&5G NH0E`VE.qLFg``TH+NR!?T(y#$ecĦ6t ^W]_LKyƅI_ڿ腷ޫ0I=)C>p33O>YMdѽ4zk" 0 V o}Go [޽|+zg!a2_(LL[|}^S-oHH7ć?̞:u߽8Z9OS%ŲY„*KTTZ?*a P\,Ls0jtv9IG+ljڅJ:|>4.t3I5N]vDy5@egּхcԜ_ Dh*sE!~Cj"efm27̖衪 kdZՇW-;6FF<W 破cr]#e)NTYuSй4NS%?=]Vs z¾* 7Vp iQz/Yb1Jf =a8/ѱ#: |C urP4%bolvE]+ڬ(1` -ڭUw￟~{@:(#y*t(ętu-r [!mYn N824J0Wԟ:u=*'Hb\I=I;F&$yR3.+sN~ l<$`p2 g tM(Vι7"ǃJDZ%FB*#3 7bPjfh)~@r fK0qZ?m0V-]x>,HV=8wm 7 6b)Tv* FF dAk[Dq%U\-:/Y 9 쎄I_JޮGLN1bˡyp]p>.sg VKER6^.JfDdjJqe$"Uim 1M%Jɢ絃ή+=+*E)[ta/R^DC>+D|{DS% I,nbt06KA>o'>Z3sp=3G5"x"PMóK9j{&JGSЯ/۠94@ eK ;*`4T h->}ؕbiPڝQ/=3?1w^Cm66qe:w&pvԴ12uXLfY匢r5s9l뼖LfLbT'^zmt/租/LW#rf{WTCq\'ԓRNe)m,-x;)-s¬4o: F$F|PERY+33xmҗ>ƕ}ekcNJ'r?zQPG ߡ`\qN% 84>>JgϞ~NNӇst8ę;eV^/%@ lJNUV48eEDshbb%h˖-&mn|3]=p Z$"ixq@՗r[HאpEYR1FI m`0N9UֱcDŽrw6I>Agȹ(u̖v-|q 3M ѧRaD% 43P۶m }/f3l$UgkCH\KTkfj tZ Sa Sƿ1Ey% :ĚsX"lu_koӜ,#uڍ ]3)9g||'*4]o9G[MUğ6|jæʹ G~R0_)YMo{f˭]h z}RV`{ġahJ (L!9]\-h-$Ab ԊjS'@;fӪ>I[X c%<%KTjo;{iW̰B5ȅԘ :CDžйCtq'R؊ p挔TtKY\wOhHRB2S6ZZbҐ*ݴm }Oi t.([rV.w".I"e.< B#ϵUyʘ(UP^@9:]id*p ̞(/cSkxN]XDVkb݋Zӊ!;̜5(ʭ\N {KhmDdxiґGP./c#?C5pF'G%?^vvEb29']Jr5 /H D&*u^Dr+jZ9t2eJ`hn:WPoؗ[+&D|8p)`tҳ#~l` ¤({{܌1-;60-,6-Cu2sgo sBX>{PO6Fw %윑"AEk!BC"L ?zI8 ul ~BǗhx^m}v%oԝu\%h7 iM}iX\ߓzpB< Dt2+0U_wˎM1 Ąm.y%M2GVy䑦e@k0 [QcE@p@ Ç!E(f_W@ʒjJ B稐 %QR7xKeU[X4p^SW粐'NqM&t!)$Eo2MggpnȈ`D%Bͻ =KHh~>kȞy 0q%!*z?I)6tFg2 u>G;_bkHvo۹x5ϥ.ZwCrMKHr x*u󇱷t… K|`xaZ*+ȵI^[T\Jk@"'JUS*3$G?s4v}DG(0+erj\1آpAW Y+>i-f䃶)2c4Gϡ;BO]tG`BILJ=Lq\1 OGc1#+Q%mz3Js3\N%qO%K8_l9?EҦf!0]c &2Q1*H~_y,27E7v =TSk*S\4)u兴xC$x!2;k]Ա05p3iQ>R&g%t~<]@###A3I_C0`^ sϥhzIC<]~kú肤Dc(cC%m`tKkcdO#@ic&Xߴ␎8;Ncn@6{6# $iDN:ԕbHnBC:v0;}Lw?4 x&8A~7a08D~HHP&c5VUVs5dAU{!cgImA'zCe/6vU<Θg1Kn E 1HےGҰh1'EC'Gޣa!`#/> s⊍)ZEc<,=m*tbڛZ)U@ 1X7%BU6N3#.LӖF0kIz)tr&RTIS ]tDG.pr6O*.,\ae5ުH-єeNnz3((?8q*[+>;$}]Ҿk$bQhKTa٘|IX.KLB0N8aNe95&W7}ފFHEϪn<>fS9ET%"gF@I:)e9z^Ί#I`ZL9& 6+&y砩Kl_TqO^{R[1WYϧ0]~ Cqt{. `R}fseX2.eQ cXN/}߬UU5<'ϗ+ D`2]c~"`F⾡>D#8WS1٘`_\,}G|HG-2(o%^sj`=~`(; a\S:}$cζVq`Pwo?HP)KR.+R^N0`8C4F%vɧQE~t;:g(*;ҺuB;^@U/>!PIwtN,Y yIX< ~K>@"d8L }tijr h_Rg\m_5Bj9OPg;n\6>c&pSV\RxVW`Xۚg3Ә5ڗ zV?- k$0F=`7hfh grfLJzdtfffSacN r!R&MYɄ% k 3 pTLÌ g)2@\/LJ!:#^ه5Am+ '~v$?BFW}/PvܢzHvr Qo–`0=)(;N&S<-ǴP=! a[.ʃPwNJBx|Ȑ#SO9oc4N u`g}̌NFɜ ̉VXz,)!;*%LQwmאҨf2l1xş@SUZW/1ӻ R- -ٍazǵoDwR/rgt/fħܬK,Tn|WkӀ墣>e 7ƊL! x_z0L?W0M85p}qk ֝:ʕ*ݒnok!ϯŠxւi6$TjO^Q3]*#+!, b#b/(1wI,^PP}!*O{R_:9À .'~YCkO=x֒!  u<߆`o'ӚXV";OUA9ՋSf#fwil` ɣ2ÇGͧh:;m>1V.r cUYAtl$V#H_8xC=I+@!h $aMTQeu;Τ2A´ǷI$XK^+Hp]N%=EcdҢy MMu48.wW6/J' s7A12e>u6]*g4&J. Hљ;%Ӟ`e&ۿoLN&T[>S/>Z5^S_m&eֱ;挵){> wd1Bwqd cd?Vck5oXitm!5*OL4b&G"rh`u=VYK0EZHk$lIϱ^J%&f@V27zGTǐp毌K]\ tu˭_j)Cn eX"RUه.IDI|u Ў Ѓwy5}'E6nz֡ cw[%@jhXd'ۅ7 "\ lPfZې\~Gփ!H6vo""D/h[[-WC^(TdC%{ʨ#4De^Q{I{C["Jpr@: \5J='+2r2€ĖԵ*Xry*gK}OHDr&78)_tI@M|/T.ILUo.̤Dj6e6nNR4z$HiþIcফmBܸwRB6j9EK 4{FJ{P $x:q~J)y8II}%4pr+pe)\D^X~FwW_V>G.9H۷ؤE+v~ a,DR-y/[9l]f׶\ύe譱 u 0Fb)M:l˳Pw %ط-CTHn 8 , e F]|!}tf =<_(p+=RŜ/D>* "9M+E<0(ڢĘ$3)Tڬ6b"=c@=֝`+ mr\-6L;`F(C}E ㄅW72)㒊e>8pQ lſu%BVcbjŶh3:D K+<[oӛWsX(0 !6liDžܛ"lr[ "m]pq@bA/' ?Cc=UJsx 4" V$S.»\7|3'I(WXUHʪ'8I~izƝ:[YځR,wNqM!|,,H'"Ie_`N&&'XhpMKt`Н9PTn;&9d,[sTe]zs~[!OYWDX^L"0"֕rG(+kGKoX<[,lz-Ldk0IzbK{0w{a o:q3< 9_YhZ hmrF͊ mZeTY FT~؁HsQeъƍ#4$-%ΈY{-z#yanެnKmosь{iV"+jW|tb;fnk;P*f2/YqgeG~FP8!ÄF$s0,InƩyR|ZJDOIV%>]†_W|"tI;U׎=#%]|?:tH%fDU Qċ  CO`(u G{ƭ̌YW ErKW$j=/~w* @`mtE16u]'2Oi#vJ~4-q榺q6(|jᗇoF_$8Iy]"/]| 2Ec66 C!e/-9o C-O~5J륉;.4qJUI"t ATI9 ga厔AV.Q5?=v,*B!K@i>*xαVp):H;eՙqyU~ NbS>/1Sd"q ”X&vA6B} M׉uePueAg kT[)^#`$x˔)k]v$c4~IV?ouz. ##/~aYlec07MV6d{J8+gI|=|&6Q5mbTف#hjjΖO2Y '1 y@e%(]n]B8WTh"xIJ#Zr%lsT>̬`^H 4U( :ԑ_}],ЮldC``iR;[9!D," hܣn)\PsUԑH~ؠ_$ v w\2%'J"*FHe+qyoK73,83RG1F# n ;,pCQ$O y*U=b#R%$܇\aݬL9? *b *.ӌ]KyWO..]䶗ЕWsxOʏJtS^#U5ezTP.pb⌣4aEOVKJ2˗׸C]J ;`46孱`zܖnE؁4j%QTgĔLXQn۬ϣ pr \Y#$8Q|0F*'ɩK)*T &6]B%>9 rA2&)s@IDAT;?nã$]OW0.PI0(O0 l|zDp0)mIgl2, }-J /xT IlКutj&0f`,@{!bk:[3V$Eoz;  gWqa`Ρ%̒T d l FӰ/-{ԠnTҢm?yTIe )N͟x1 {vvTlQ/ѱY %f 'lu!)yF[")2RU%᠉{pSլ9K%!`HBY-y£1;&zvto{Ȍs"K@ o|ΥC;S`몽`'j(2VJcߺ :pP;P^DwsVȷ* 5x.P>]`2<*]gQ9"˽.TK Om4j~⩕NJ5&$\<Ǫz~B+`B OIs Kcz+_Qur5c.ts&;[0֏orN۔DW8C"NɔI2uځ#MR(.8<ߗgx~inj7N|{.Ō~Y<8 r[=;!zȌEyos:^ !Z4[ nUx&N̠,aJpJOYJi+ j{_>x:7s`0{#iTY#6BK6eIJBUpDWNS"ΉqW& 퐊S'nt˶JU[bx 0ŁzS+H%F𯩮LeQ5ctkNќXE#Z8yW(\cX`nӅ<*̱&ER;e ToHUĔ֭[;M)>9&0j9-{3h[hX8pkKX>`p5])؆"i2t UÔ؃eНVP# 6]. 7~.xnw9KؾȿbA(NC$.v4.No@; ht$0Lq亭oCh;#t;hz6 KZB`kmZiK?G V4/^mH;4ʆ|xrOm=Teo]'*?r?8q`S?2H:n6 4Je?r ca.>R^d{˖Хqe.62ԒQA0;F\^I8p_1U+gaJ)xv@pÍt5H^ԗ>C&w"MB-FH80=N@'M @qZwKonr$i;?^j,fNJY٘( L~l[xK,=6nRQ}k-#TF胡q2 .aI>C'OTOq d8l^'Z^/Bi$|Z*5 QG\}@2~EuL)fv©$3GH8wS_5g*p$u(^yxLFqaRaF}֍n+"M:.VQah^B+iXi*l,C|tɌ$J #[xQe퉐Ftn䧦8+AU!-3lp*^Rr$HE9w/ɯɭOhpp,ez闼)p 5ߤsjdS#m2Aل?Ǻ9oN "6|wLic 2兂eo'ABKI]E6/I|*-ޅInR4w4m!f4(#C 6$lfnu>M?іQw owVs|ʬB%NE0mԟz;BRxI.\~,9%5YEK%t|~^ Xljtg{BT.;NQb?X7Zf%K8ްTѸLL&0(7^^+R<M^^,) gh}v?w*rp`9/؃-,co܉\zM[rF%טpR`?R+jLi/5]T k%)zPnQmy3-?k9?]Ċ0E2)qtÝPvEPAN>%J&b`pwdT`&Ű)bgCK_@lix3.cvj3udf# zb"6;"u2 k\#sT+IJ6l*Yu`d^#xH}&C!{u6˘1ihl5+[Qe atɑ:fRыg3*}PBR }F kH>"͊FvB,eE˂w KM{=mKmn C h9bԩpZgl 9{{I_RUm#k ;aIf(㍆gug/=CCӳ矕|_"$tʐTqBgKt=6EOa/I8% IggetӾeo4ؿݔI8 rVyUARFI`'ǕJƺ ]ή*Cа4nTL-._Oº2Kd˂)yU3tv;%YH)"K~ (2S4=,#<(S`ta/o`~.Hje#TGR5h8" I>52GZ蠜v!=+p[IUJK7~H*B>ܝeԙ>Jw^{uRkDqs P`t3 AϏ.ʜ:^Khߗ\[lVJtȇ>PVr ޽WXER_5 !IdNҏKl(!l[r$iҚ _N:t1pR^U.OjDK1 @䔓0gRnn$ D2WrG聫bkN6^o>ߍEЩ<vb4>sev]}bA6o>Jm8E^Mm8s!: pa4s \vl_8Dlb0#lܺzߺBg;y儸]%U? acȣE  @Q@e,Q/`Sx?-&P y_ ёpNqCuw==Jh6 #킻2F{x2@#S]ocۇ>r.}Z58n?F CĚ125ڥM/{7@"0ѯ TV~SW0nIvR"ljv9)&QED]NQd/P3Mq}U3H:Bэ9E?Y(ey>_H`54u | cTf?;ꔴ_XI~|\QZF@hGP2薲٘V$H+^ LlpN5p*䍫K,! ȶ^)SYn=mپU|ҕEݹ\T%;I4WI:40o~s\]9ֿS2Fe>5ajKCKZQI`?K!_74sr\XTA :l`>h+Q'GY82)+yMͻYԏU(f׸Ew<9EK=bL0_,;̥rqL^(zK_+SatlfTRiVe(%<+303҉]V֮+t^X!`!0/G}tI[e4vD?+5jgY"׺2.@|a~5w-]cJo*=2Ew&9Ib1jg_6bEl?T3gtt$8E)d…HYb.av䆧!j)Hzy.N*!BqF|& P('TS[P/}9x?O*Y5%M3>Kq}Wߕ[^ Omtٽ qxls R,ʥd Ē1~U]|;~07pPb1nq.酻n{SFg], L$7C0G݃sfE )CԸNy%c4v}+N7,mk2 z`@~li1p#wfX4bZM#;hIq#ԽcGG C`P\lNkGxTBȐu.sd*lɟхE3Ǩd9evt䌑,%Nvul^N6BMLjX.uvy`a)7UW^EY+eelO3p)> pcԋD!^'Å ais[H>4eUW|h'Wwm:e6M0 C :m23ne\em8"A(*Y~&"IC11`$*%#F'4-ElJ1yW?v]\Onisx!Jٞ=8uI5s.JG xHQʥiRpQ%!"2QK{h֖]/3ka!`D!,nT]!k3^:n3ѣ~U臼 G!( AwgGw>z)^y!qR!$qb PgRY]hs$D C\;:q** o58p=ٶG]#Y/>*8AA{QԨZ$_ d΋mXZ=wz3lC`,2=NHr#3 6@ZM 5qBv0>ЬuNӱcǤE*̻RST72;xqD/|* Ka<)nr񻪏4N%,wKLQT ?x7-@Q5j> c@WF0>"ƨ04d/ᷰ.51*thM 4 <RSu*KTLyKPS%Zh,s/j2pqkcZM3ss /m0Jxl2Gݙa^r ga)npxD.(AШ.^Wi-E 6t0o;EZKO(GGuT׉ f[n0q|ˬxUw}񦘀rᜎKl(] 8:I4 M M x~>ӻLJ$/)zf&*RYDZTGPn.3'K|1kOcAN1i/2>(*Ix) aԌ`oIErՂQ\놶1$IizHnʍL)G=l]Ήy@-V?HT:NrrC`^z\AWC!â50j{&=3}lxIid!`!b#13_w[o5< C`$/4 R𪡮 |# &ga!{t~TtE AI=Xl$AQ5X[`uk>?CbCw];w"1R!i$t1ݼ&NV[,OeC T>zà]w%CX} oa2 wH{UDe$laMoؤ5;l^F&Gc3gP%Ss\=K%i'ow'evŒ2CPjъ!|myeQykeLʯN}jBC0*2HWoG 'o$[M#p!`@# tWE{6GX#x̂K%*U/H (bK6xV.!$q{J.$ <=raoH>O5̌X$ʺ9wUhuLkŔ|ry/zQBl/yHys'B8)QTl@P4^.l̮-@e9͐KќwzA٫J귦6S_Gw*yJ2M%p,H=kBA^@Yop/ŽڳEB՘ Tlc=x0FdIo{;"[R##6 %"_e)\lh jo|);eᤓ([Asj yr=.~JwRީTP82'I?";TUa)FWe&YLU4p x^ѷrWeyEKa:N>MdiGNڞ!|J1Vi# /_- AY; WXe:c"KKC`+^Fm+B6qlHzOF6yj}\iQTbԓBaAcw7GՁÈ Q2sc'rN~Ӹgz{z)RWICۺx ֳkmg,q&-7a!@+@[bj[f3-Gi;hL+>uI:2~XBx|k_5ghT(X VSVn,l+ΰI( {hhꇨA`DXOY%fxg&e{ck<%o\*2DU/#YX8 R?}\#$ۥnr̾hio㎥50jC0 CX4.13E,n2Kˈ Nj(]6S[E 3w٤8;ʟg/HN}K:Ta.\?*n!?ry)ͷMo|?㵆^mڕN>p{R-He慍zoJ]@foč^Gl#Z8!_47Kk`Ԇ!`!$jj,Ys;hi8 C`P 5*Ra5^bR%FJ=г?О:ϡ>\1)k KM RP&$I4wdNam{f%e2 vRX< ) ё6n(r%/)ܻz# d ],SmN2V 8<&=E$cإ#X]#i4S-.#4Z%m;IQK^Ei.Hui#GmOTEgp >`\.Ġ\Nx sKA5F eU@R{bM7I Pءz((r&al1Pm?V12X̩2jC UEQћUnMV|e&ujSWih"ζ^jqk0 ]=3KA37БQ8aI8H0uc9śxy'ou4 <1t*cY mYYl7R7UKyps K2%Irf̵P %T T@ jѣMYZĜ:7m\Iʳv!C8mMM xns`} M؝tse('idfTΧy# 7&Org$mt%Ts0.7w0"ޛFI\e{TnUTejSm7$4h%NCw92a8,FM3CÙ3 HQ:TK%J*^ʬܗȌw_lKzDn]5i+Kl_%mB|C0#֔;r%w!\}x.LeJ5Z.Qe[T=@  l \Q̓\Ӊ~F]O ykdv6F87&CvIcqzqeƊa!-t4(1DPwBUq< QB9s2jt?yi_*;.¼SahQK<L:MUgQeuxCPےuD'բմloՋˀChMkźDs T:. ܳl)Oo?7 n'~'%W%LE62 񛖘-0DtuCxꃭ.XxD!o_a5nz茄 ,|_6wQo|Ӫ,#~Q`8h`6UjMm TmN{kK4(Hh# :FUzzgo3)Ohi՗߲|!?68#@3@Q‚y6HCG97mfȊn4!r#j?# >1Da\i1{3Ix a4oJ }3T3c8BfSԱqP[m_I;i,Hspl]< ^(q6c0F迧-\}C*1TsEھ}+x@^\p3$Q tFU4d~'؉˔PS%1 $Xv:5&H&I3E)}CD=cMn2H"󍲻T$ϻjg/ڀ:[A!L)C! V3H'$kĶLQ "I^x;܎`qv@2 $)\DJ@``GLrqg9` @  1*''Җirilk&Rh6o pLJ`NyeюbAJ— ,.-؆^df'4wKU3  p|ZULA9<#wZGKıǑP/of"2U9v3p]xLJzC;F-rӐ|odG>՟~>q T93OZn8Oh+k$ض ԡ4N=۟ndȕq񛘘pn&7z9pv:FEj6ЬAgr;-%`` 'X:Ia 4iԅI{~T6{[&|ΆH'NTN:~7Dbe'OU׏47(k5T Ir]1{P o e(Wn aƍ} Z8UJC&3//C&G'Toaô,;ߊ/ JrިagXMr31J]$J̎SBXfxA@iYؽc;4qHw& 6a8!h(>1[<7y$b`C7yW}:$c0XAJ` @ 1yun~{Nc$ xIv?mONDX-!!".0QZ^-֏s n査p}J PI7W{bލJnSsu{w>X+?2Pa \?]JA&c`C M``wH0`02JÚ0QB#rHTPgJwWM#L.V)F!DrYNCKd< 0c*?q``}|1@4RN1&Іu X]"ߝ cm nHaIfŀL½*mpJ{ss˕S9u9݀Gfj7R}2Tھ'uR},l9kOi33rLPgIx*\tܺ%|& sc1wa)bois8@q] ?ԫ ={kT?%4y$XJU]FI 7P_? 6&=Ec:Aٯ[\8]'rt!fR{ Ww\62_1esr)3N 獂?Vڅ | -nJ؍bd[h %3͢+nrri782.fz^a\$Oe񷉅)poyGͦ[X^ݱsɽl[Z(Zu~NU΃|lg"4BnJTvWݶ; (8#dk hsY:8S7kUO,eX(n.#@6V9|睋&A  $H0` zawN%O)y2fc״wiOҐ}0s3?:QaA=Ww(Lj K:{ڝ;N#q)(סHbvjϫqL$KpKg[g}[evjkP ό?4G_w亏̈|qjBIȈQ]`5ZRO\avrnsL0F!aĉ*jS33O*`1&6" rMO_u'Ϝ9}Z#* "?ߞu-<-$im'1 c_%)Fؑ5,Q7Rsdᖆ]r[ܞ]{DtVpz EF zjCM] 3x3Tڐ<l{wd ܧGSB[6$H0` @͆ UOj!h;|]E]Dkf@"Sq4CM; rA9f,כ~J9@x d$jON5QN4#?,dE$ ~8hј ȵT՝) W%趛lMO?#~Pcj$ # zZyGA%m5Ww54X,RW_$µ)bwSP9)'$!M gI"qG0_b1 lg ETh8ia!@IDAT  $/ l juf!fʘzLvfThV`;ɵfケ yn> ^LѶknN;8_.$t`c hakJbW83\ܦ kp<8{m07K~ 8F](pjt93ι3L˵IwuIR&GulV=nl,, >y|&MÆIVyĻ[@Ib-l6+Bg0Cg1kUZ|@Mm@our\Pt?9#R>2yvﬢHʏhZh1Ae7e&M!iKb/pCB%RlсMռ=YAIU隰}Y-ԍS!\|D-Cf3(LQc}&,im(\vS8{&5@ga7ETq}c~N6썔~VpĔ<.^fZn=/~\JZVWz0 ? ?3vgjuv ;z#ak {ǺPqW%4j j|a!' 4;IR6-h*ᴯ:xw[dZjt`^̟!H$9:rS?3 9岋L>;8JK5]֡Jɉ:|ϽKG b,w* ,9{$GB/%<.b"&1eI$@Q:tsbapO]σG,iha`SO>馟Wꪏ}cE wKĊү6Dhb#f";/o$S7;EvH kIUg/n* 1(;M=hD8-2P `-AY)d(A s3&wYpx^ l9 0Ma"D8 $W~<>mjnU d IaՔQ+/ٸpmr<S\'c֧mٱs[%w.]6ϲ裶vr);ݣHk< E/ի.jMoKw˪SOK?ZV"># Gݮ~E N%'ҖBvz  $H0``0@" 5{}kygi߽[0䣏SXkD+ߺ#ZWi Dҽ?7-I f;7]~=jsO+e Ʈ Q{psGM˲QR;0mlW*?/tɲnҴ8ӘKxSCAv>R\p ıf0C 4t[{OXqғN1{niwtq\޸;`D,JJRNttxoePc7 y!i,xJ>\I{WvjI8u" yZbpþ\߶D =Xv|tUc e%ovsOM_DHyе.v.s9[-5R$jO` &uA0 R8wίBM\k-9Kkios׍AŽ9/bޕecK{7=}C6T>d`#u('Frև yk 7'&fK )H r8'^V;ֈ=zm%^=j# 4ī4uQ sQ{JF/h|J{zZ{ _qVX}cu\0o^VuYwh֪[6o޲mK` @jWSkA3pm a4ɟA-NQ+1@bbVx*dSj *Y! sssVN̜Xܣ+Y1:PήcuSݒdʮ#A8Ue\ d500tZ8T#?򅼸ykD9v&*ى7 Qw>f7"qw"ni$0<'Wpcq¥[zz+OFSST}ML/×%+nxby:?1jn~ٰ>~5$)"*rYpi3~`?[ϭF+<`˷hBͣܝو.Q}8$<-{Xpr{UaPl2x"8Jp!EvE(WbpC9%xxr>7(u4""㊬0li)&ܰX3Ā,+^F!zWLmTf܅ $nӱ]/ H6-5 `ωE4~To)ӦjmSϚҷg FLC)+Osٿn0'dޯDՕ[ݫ~VM+aD9dc`684Du*^y\)KrZn5ȹZL쌙v'ƔĽʦ̵0QUj"Ѥ96ڞ0jcu{ҘT3ѨS3]s%ljdiz.{5,%pJ.3wv:p]t̓PB{6 "͉tJ\`]FU-.I9r48lo@O(\u3Y)WVo4W+k{PfUw:~2 CЇDd^ho# 4m*7v(7$29gԥ)A3hM1׾2 NY})Z{?VK+aԀ]w/a]"bLA'js/?,;xuyGq˙&fhT!*%Й6'Zx`~YL~Y/!-2Qܮ]B`b~`/{Ϟ=ޖn&+D~ :DlCQ&Of_4b;]S,fxx 6m_k qoen[\%(IϕJ,r_xQf_ݜw`ԇI~"VbbQ 0Aյlٕ!K8nI17$~hoaNʼn9\VEY\vS$=ovw6kAHM 6ɤ)F(4F4 T\Q^Gmkh(rwPutݟh<ompđK#t`߾#%1 $H0``K`KϬD>buj+qm-56|] ~,O=_ʊ'w9mhPvO.9FMKBEm%ڎ;E̝Pu'62]Et'N]ݘl^+#zo ,pc’džb ',h{60"qYPPccngAR5?GUdyʟ-!teW?D*c߀}g$fx0Vp0(1`87$h%%f>6"յD(b[ص.;G{UEqU[7¨vIj MLkۢlN&zo#㉃N=(`h G|qo=.OPV1l;4^M$I%NݽQ,@[ձI:m?_Uo;';ԩS(LzY=m4Ruc*v۵{\>|D;w'TjՈ1&xQd<wV=íOT`G)6qY-ħGex*B  2yD|!RyJMfpgPjBd?۞ 7<8,?Ꟑ9Ҡ0+0uwi! ?byFv*u[@-BC)9 0QD\3WU7+,ľU # ,Dza$!  $W PMY")E46YWx-WLnĆR-5;)c;gRݚR mbD""/p_bbl?dĕF,Vڮ?&,'/qnCN_tIɖp~G~]m^vZ}+%~/Ͼ➛zQC'+"œAj!f3eZ*aܕ6p̞R8^DRjl5aSnaNe]n#Jvgs$rT,,Nw߶}mw`Gmx<7UoE.6d(컐aפr66ZogБMnS܋[ BaC`W.tSN9BLnyR|?0̆}[v?;3's!#|Λܻ. O,ɧ`$![UDE8oft-i8O5v} \7h7x }bE32m2%<%V BAe2)ISP~͖d_M 0„b-$%G&f" wu eSfbimdSos "OAqid.C9Y?H`3\ujDJKa@+d m+]Gʣ_xˆXn]80b 1PrbLG@/>dIMc2 u|)]s;0~HkP.zq\+Zm%1.5lSf1x>OTO-[o[؏A] ȰۯLԒw1I!!,ۙWvTL%猠{gU;TAA!xԢ >TFdf1 2&;x >XznL],).]"&M[H€Wɵ~9Ylo qB3g9Yo^&q]=ngfdO<9BѱftH8{emv-O3J 6c]k)N[L(]+fW.]O=-' %l 16 r#5љ%D$EB(!{wݣǿ&/$ t6sAtWLN^4OIfLG*I2G7|28cpV w$"P^ 9LEQ%[aO-[<1ڐsXBԠ'v^|oCPVZ;ď_+ E,@^= ?]hBoyO!>M'Cu<QN~+p̋Bh@"">s)q嫀`g2?rٿDsϝt9q "$oYZ7B|NPXCIȺip!+|DCԾ^ؠ۵sK(;=jc08-~Sx/⦴\gn;w}#8 .+qőPg,* M0` @Oʽ?ؖ Fr"r'}猿+11J;ơZxȵem,Ddz"L'K(̎(hw{%ꛪ,a)O YM ADg"_)7s.V5>JϴL&|^yVgapZ] X<6+fK=۬,vkp֫vp\wtt!cy%R#uZ8mlj,maކʤ;'vsb .6e~7"zL2YQX5xw?nTjPxw p%Mn_*:Pw܈Es{~=.Qbܱ ]? ~+C|0ai DΏ&~4;4xHj0*9Ws&ç&7EN{1ķcz >t9'pyZWݹѣU08H2ٹSn?tXzqF8 #ãVߛDg+%W7~Q۴i"JK;{#{]g` @:*3"_1HM q.?@vAVfbBFT[ϜFbsmzHny=>JA7Q%}JP5nZ'a' FڕJjmZڀrx'%!/J4*FC5%Cf\,ied  vS[ӖxPu⭐PU0[vGld&ҟ6x9h.@{&& ix_1fVc oOGZ/|å.j7}Wtm펗ؒW3VfgMxU)f&?BN8֙a7Q80(g7(w@p u'з=*v cQgZM05|D#؇*%9Y<":5pG5h_JDGJi3;wߎ(9^44f03ka %L;qͽFt}k=^i¯LvHlW'`\~{5OQU볔2љW^%&ׅ0zvbrDZeB_`’)~΃tM$V+pCE9(J8zz:CN>Iּ߬/Vm1oi3X4's1$ _}0)|pENu2 3oMgUb_HؙXl:#ܭ{|ZRpۗpVas]8h;##\p[RYuu%Zmdu ԿqZyZ~y\sC(e)K6eDslh;#fyu z>񸔍p}\҇^hл'5ǧMvl#D-,g?$UX/@DBH¨ 鴫(+ӞэH^˟4#uw#Q֫"ЭK֕PF<ǘ/];"~\kK`m&svS7ƁMweeRu& jhRpO M<_h [n`sDr6Ca6ŭ8As[ԙx96,n;7P^(?DZhe6,(0L`~S3J#h7D"*{VɅ,o7f8~Ϙ{$8.̞+'$T3MWEӦATG&paiRZ>Mđ9\HƆü[4=<ݢ @AEYե.-IQ1 tĀ*YD6"䉓~i>)nꊻg7ޟF$^雄܌r<(3krt=o ؙ"dg9/S,9wiW"ߛ>.Tؘ8iPvV"`3Å|w=?'sƊcqV ,?'~Oh{BRU 䣏k Q'">7υt]sh!e-^i&>  $H0 0V{*&dzO,x|%WJl iXs¨QVVCZH#w'ݭQ ]!j}I epcFrY$s$?>ptƜr_>~}ܝwcJuȠ*JYzѬ(_!X]o=wujve@(3U}"GSZ~B6[-g-d g:Bz ^E\+vaK3^rrxPܥT #]xbupFLO+5uX=%.:Q,wBz\qUZN{ {*b=[iܴHGD噗×$;2ElEGk򪚂xs1SUک>.`sChr3~衇\Ttnq B6/vƹER"D&DtMWQO;J6~/ܶ7qh]z1$vFLVMj3z-Fp6O`!a>&69.|^y!y ߌe..9%P:Rt1T!u~~uTU%k/[KjO˪k}CA8F|#ΆU c/J8n{|FfUr؝nNPK SKO(Z7ntk\{ל0J]Qڿw#@ e,Yf֒S<,61R5'sW T,pmmn}upjZp4)cePO ~UPXiKG9ܿsI 6pm>?"~s,}kRrkfs:rJNLI\fMK4÷0a NNBmeŸAɍx{$DH[kN-Ybab :A)$fpY ]L!W"P!| "00=cjH/R![xZi&Meh }#Dqϲ|͗Ʋ\t O ҄M?t)=b*^3ˀP4A.qDUd-'ٺǡ5u'{YUFϬ= (o 6-58J`GkAMz,fڋ[8b4Ԡ+:;Rq/I/?p]EwMr(;d:ExJ)Szrmv* &섛48M؅kFkWmWqw-op|9@~o dfr`WZ)gi6P@&tMcNm%&3ɉY=z  $H0` Zb.\˲6*AmUI8B{M9FS:%#{ 3&D,qr䚻۳ JthxN|[& r7"@? QB `pպwצc4rfT<ڽgr6+Qv23Y7Xt7Vj(m3T|AN+;jڂ"8{ȞqxwEPX X?&݊wEpKƀMKLb\3F^kN$L0` ?[BmտqnT\N`L8F[^w? ˳L>#thw*RT;(jvLc? EΖ w+垽jL.t8-y /l EfhjK&,# [%UdPo91Ei)~t{Ȩ .$ PzQw>P+(qi^.v omMwUscP|űxcRB9d|L%J`q`9uB|.FLMENgeӳ"Z_G?+ WҰO 這윛*+ kMfEIYX=KsӋhLwW?8{˽o"Wr(ulgCo9ΦmQ•Z/6=ƕ!v_ MU("b<0xX@}Pf`Wn!p` Va8ߒq[7s&}ԝ5Y]^~'x )a_D;-neLhΝ`'#[FCų#n_yԧ%`Uo1:~~QQSĮm~n2suRFݐBx]i+PZMpT]JqFBm.0܁~bfpBQ,'<-q?RrvƝL"'Ɣ+IhtӚdYK` -W9wDx|~/>,R^;W-W\'5WF3 \:D+,Iia`c㞿)!{q qa۪Cǧ_]ۯջz_p10a[p|}7_Փ'H0``C0@ؗ>7*D*nr%dۊdD].hk57YJw}N_T| {ʨ8yX'DuJ0NQeuȋ;(ҰzY\s/T74iaP*&8.TzfvybRu^ߤP ,>P=|ٳɒhHf:rlG gmP=ݜ+#4Ӟrz9뷏?pڶg͒z%>wQ]pLZQ##9A2L{ǥ{vy[JMXP5jܕc'=7RNH#r ! ޕr3&\W+ir@i@x:j6%ҝޏF-hrfny+¨۽M~h`={"Dv4QcgR'1HՠH<7mm>&> }E%.D&quM1kJgzV'kDx- Sޜ)oB+$zij-5VHblel̈^M%-sw/?ΞPQVIJzB Q'Q:݂إ6ow1\jM^Q Q' j͚|XףѫUw4Yplf)M ӕ~xBلu3hШ)ԑ+Q&iM٘X\Ck;c$z-u,z] X~,Zb=(-k\-a]wbbt~i2qv:gehm~d!1DL؎dG\5=#p[.6 v^v(ղdbI?Z>Ѩm#w:.Z>inY|ٗ ˜yh%2'ߕWWU(hpa,mp%>Y<$0^#f4SƅoؕڌiUkAB\p.VI H"}~ K7< 7(;k U26}\#UXYf|L:a _rlFzޚn9_LVfO~_/kkI'Ձ}]>:Xؕ_7ѐ0bdמmgGjsl+Y]VP,3,X!ɿ naMFf v3uǛǡp[uDR5paǂKTQ*1iEtѤtj<C46VȷmFB\(=;XeH&r57H+Uaߪ+1UpB@e 8$@QzFq*6ȓ8a:V*Z p6G0h szɫue a47J)Igb^Wd9F~̃)tK&x$ v@BEE'.*[GV::?7ꁭڸV_Z` @ "x?R~J}39nί,}{ dqX[m; .s;%CӔTGp'˝ToBW6̓mQT&'KqYʳΟ?~ zkBk%r<6b24R 9BH5/)yR܉(Ӣrg+P*Ĭ7M<ʽ-va!8>Ԗ73K XBhv5pR sp4NdM*;-6u۰B7}K_r? .z]c}dq]yd:O;я-Mgx}r=|aQ-KJMNN:^!!U :b+ڂ-\O+W.y`UoP(;w]xIW]R3DR(xCvlK$,"WԀkLWdM2ˆD)ISiF"'ԉ@ҊmFWE;LQ ,v4Loh0jb{~p cU+Gxmx# `b17]ɏ^Rٚ7'`!hwfq_ugNwxXo&.(+2Zdox̪ri)=3Y~Ncg? 9=ᚩnm{TqfהK(l<kd3pҲw'2}9/;w ÒLo^a"ӳ$e>HDqX"kAo5}{pC# Sڡ5#v7/^Sx SҺV9FՈ͢lYrXe >|X"҉+ sOQH0``c;gfoGa3ӻ  heZQ4^˿0M5p@;[`@N/+玚\mNgC17ӣo;^2h4]vk2˦(J,C@J^]@~E3@{\g}QP<p<^i Z&!"CS@ǿ"~ w<}a0'{m"I(6;0&;QOZX=""ߩOQҜ(p3c3ǽnԍ"DŽpExkB$eoEN6hF]%UM9>Aŏ9*%{Wb!-S2mΏ4 )t|͋xH.$zQ_[lI#0:S&Lhu(i=!]v#ṁ-y8$|H$27qR `~3iӏ\#oB ŋP3m%y+І~r@׍8̳z K!{4C m!0̄,#·|̒}8J戶V6;=.Lv?ݥ.0Jn?!9J&0nF13i|ZƂ ȇr[mm<'|R;Tngpn 4 )F ՉOH|әcZQ%t2<"uڑ;*RZ}91:/&zkYΆL7,c_ـXC7MC' BAQe]z7AαHIfoEx^($Fd 5A7RJ{j:ciź;)lڡhdƪGԕj/%U]P.Tw>V@ o%&eD/`%q,oFxܺ ACaVKl[+,aLqZIՉRо5M 3ӹꊚiŋ]v3U[KZ#&x+%AsK?E}㙯?Ϥ2 SB=-/lTr 2KHp9DMH8511L'{5׵i!2843` !o")U עOegQkm=؈T[d5UynAёc"k߸6Cpu>>eSfP"X'ѰB jٟ#Q+OS0wJp"9 /&PyWBZ὚@CvU6# rK-d}Tf)"JָKux2L KY,T7f)M5Um\3]Z[Nⶉ:8SZh7ޑ((((083^g[jPݪOvu +x ۾i7 Cp-z+{Ћ y|S'ıwƗ*/$l*Vȭu/B=FW EBⒶ1JʘTk(TiޘҠe^W U(,IV%fn'})q^(?wU= z#ҁ3Bx:[9g!yǽ'rq$F+zZ|ӷth奚c#1lEObck*ݨLIAvGIX^;u(i,$N%~>[ WX]5s|jiȘhID:DqY[b7A}q>t)i. vMtԩ}uF͡*66hsh(E ǽ`5O9 ۪TcЗj %%J~<>.9!3r|AO Oَ̪N;(HxHC4mRP, Εd+lO2GA̜k2V3RK?P"iQu?i\9TYRO^9JFLcjڕ'4~pͳ$=ZڻFt9=0cGפgzyY_Ъdj6Cb_%j/I~LZfl?498oȺY̱(-?Z'[WH.Em iDp _i-xYL~gV M2 \cyRFU#KP;g֛~{3PGdi7&"k'1eIs N>I IE:Urؤ*F9$*_]V;wj^:kKj ZOP W沑h&Bh0UkdoܨV=#?}D*NOy9_S}PK^9B7g Yh3 ktN͌o *Ϊ*5c2!EpvhioL7Vno<{k߼v(]u28Q(?rqaSSvx)vj66uK 5~{Wш ;av {y(*%R*l!z8%֏,hSLh.kkQ L4j VX::Yk3J;xV TΪ-3ƍ>$cq ʪFmhfEtcqi5@9{rY8Y.cjZaQNC80㟗ۏ)jVJqx{LIZ؈'b2"8uRѭTal#rlWjC%{!*j&= a/wvnPKij'?.#"CZغnY!W{ya4ՄH4d]В$R=$׳='ӹN3$(VG҆}{/ۙPeYSge'"\%T&Q]v>rudV C@ q`Dh [-qo?_}Cߏ!1F!](y \0R+gNC͝Sc*`3͂ݹ8X|g-q$9?vTڮ*3vIE?5p&>i53X+d09>&&|,$NKsў}kX"N?O=!s̫~"o 2Ll1:\R>C9FȬ U5堞}PW`zWbĺҹ45\iևL[d>s]K+)*q4Xv?F2Mެ VY`q@A $CN2X7D2Fubl}k3}Za h*Y[m{ŝ^K*r  (?L#bbRŞӒ\V4}yx;RRM2XLKhMQ ܤ8,9L.a̚T1JJ^r-ҨO˧ZJQ?H"0G>wjQP`Ԟhd%\N\.m/S?,icMabz 0(`QkQ6*{鴶üLY#M:mԊ>-SjEu\h4ԉDJQT;yj"9fgՌ7#]+A;w4> 7#+*V}/mN (%J:¨ [ƪ;uihkʨj̥RDzekԪDր׃ ktmA*9v}CF#sVBd=O'`؊w۶:2n41uYVX\JWFtIb;6)R)=aAh͚uvE{oB֪9]1=Y^,jR+b yYHiOx_Rs9mmhdl y%մx0s׳Пr{_Zk|h\Ze^x!1X7 K?y2b+>t[oanBRN;0WvVkIV&nD` Cl2ZS3jOV͖F`v*ya5EDwOw!cct@ڬG#N 냙6%lͶ˪qU@j@bkJA$:kiqk}[$ȀZ{"aƬplѪj̦)Ua¥:nvϥY3=vQ;Fv P ]?߆[5& =ٌMoEg?]lnk 3 GGa@ {Fjek=л)?RMZw DtO^d2 c\NkKNcW^.v{߽c }о3C[AJF 1Gx}_#'='ekue$1.YKD<%>P=VR >:J [ƧD pvKZZ !B#]]w6.t)`!ߠ3Fڭ_Yc^ڳ0P@Ƒ"8 8 8 8 D ;ғ(mt> G]+:.1JXAq=<3O4SE2o)TZpaƞIԽ'v %*mL[;~SZ^na%S*>L7c㘇{8vY CJN{CYL%Ʈ}:w[<_휞^']w3}ǡ8Dg() YPlH鄱I0FHLlǽI5$Gm_v'4&!ycRSsd:Ks% #@16&a45&ң' ˨ 'nVk?k9'e/HAb~5˿v-=eG=H)@Wt3׋@W(@UmJgbPA?2yOe zW +K2:8WR >~ ᩬ\djpPfF%QYD<6zcq+C-S 1,x=W#i||Fy6a0::vhk RIa> U:H 5l%(?_1ElHwO-s~g5z޾#o <68 |_tzqppp<(9ipK_P?( B } UhX~uD{jw4=fd^c3/>̞=4*O8r^.G((7`06m6)zI{뱺PIH|YRSSj693-%Nh4B9zbՎ= ?q}CT nŋZ\;pȤ0JFum0BbQW1Fjd9_7dD~o;C>\5SD=e*؞fUi;v6Q/če4է};`33&'38>2NP䋌n4=7iZ@0l;ӡ_}׃S{QQQ |ֺTC?P:eH_CsCԉk$Ĉr'E=c0)MA%뀕55ZTS!M$z„\bY-6m"q:!=93ZJ& ;m$`[5Pre5V"1pRP)jc8֓| (<I]EKړSר8R$W 3TvUE(>|`񑲗ַLJke<~Օcu!}Pԧinz]l{Dtn^ֹ\Oq8,(Iq7S*TxZR.S98L:QIHbmhbkisݥeH<'m뜊XrTgUCmX"]$+o )5ۀn?k9S:Ћ뢗fZo0F : NU6H-c#hP#$82%ֽWӧ\@IDAT.3jzrZCrڑҩ5]hwT=j]O*0/C HQ L###jjrJ'm!cvcu3?u>YRx[0LPrc;]Q(Q̉5ûjv3Q"< 5P*E0+&h"ې)J'/~;xuG]}IWd,sdf |:@dRAZ\;jn;v>^z~BXC&nU\׹Vq'!b2pn'Onx|W1 ᠤƢo*3IcGGGGS #}RFOw;W(5BH.Z3jP'utclQ}.v|qvm66#3+9ދ+RHc/ֻJ؅V4\*P)N'EwIY:$cՓUsΆX^3; _2-h|T]>C٫ưd]YEX|VRcW^gq[r6^iyvc7~ofoFڹ:]@"Wk/|3n^YWapc7L W([6(q Lm3^v?'Ί]zL.R50 B#VJhɤBAKXTjK #k_{ĪȎy57ЎwWUfUVjN2*e3k&=1TٮA>Ò u姗ƃ| {DUMkѢj29 IFܕűvHVMoJ5 B)0zM cA%zvD}S֐?q|@6&QvRiHݡOU&JJWȈ8kSFG|vEd~lD[0devGcy-:T\3ͫC*e1=CǻILD/։'0xϘ#1d0po uh4!o(U'I`sG2D<)@Cr? QD&& ؄W};S]OHũO L H j R D Bn Q=кN 2FJwRI451, mGU:VGeH`ȸpu8frT "̓6*BtNP;{+>oބѡ"ٍ3d9"Kg#٥2Neҭڰkܑ#̪G6iD9YڰNVdPdiU@ҝ;wJ޳s W#;x$،9q84tȊ֬au~HV}Hea97{PvH:H,Bb boXmOFa^Fm/^ڝ I1F`k1nOQ猧;J5a$UF.gza"5V#Sx2ȺAyɄxah)fI;ƹMJE3YYȗ%}#smCmw{KgzwM6l$xI&%%~`Li#Ԋ9Ӧ )i[[/P*UTYOM޺π"qBLBU&ғ9:/sw{Mgxݽ*c4r3Fΐ{7nzvK2/M*"T3GPWد]8$ mi>3F}속XDh֤np f NIY-Uh|RU; jw "<[!-\Έ(h4;[}sU`kuwNs)5Urv׎ݦ0Z zn{ae$~Flw E m,`v 5VT55 0c̋iwxz%yeu"Bz$Pa)<UeUhq8PV)w8uH>8tSl\ïLuN>E1а(!KAE)+-̭Aou lorŭL?[d_lcQ;٠c%pעR33FZQ'~\ݣ@ӍQ!Xo*Lyq`B'S^PTВyȒ1Fh5JLglicL-ylkw%J{Iĭ/UƳ*3T-Q8c%Jf Y,,ͩc{Ajl?[9h+c͠%Μq!xә׬3B{ur_b'h-`,^s[9% 15 Ĕ0G[?e^y =\~9KLN6L]KO?NJrw>aq4u Fxֈ|($'h5хQGONɃr_vH^<P%9#t^nLѡDPB4=>5hbT@5+Hwx4]qdF, h}o|S7ЊTl~{Q7oFWôG:s((( ,}궠 .sONQ#"90;˟<٩rtU+BÁҋJ0ypELW4O[Ca%ĚW0 Ψ5m>VƘE=@;mIMF.. 2FU%3<{ 9/1J:iy<VRϥ-Ġ`ƴx8VRc0,a+1P+Vǜ3*m.U—ɫc1^ZgqgvferNgz"_ U/ưkilط.+$ @| !B)crw/{ !0*9:x^mN)<7{QvyJ3$BF[Dr%)Afz%-MgA*XH!ofVЧelF4RηuI4(q)c )SOfVo&9ص8IDt@ 9&]rWKv_;͔?DLOklUC}N uk\Z^^V_B/7RjP;U;vv0nffi0V)tVJa͵α][uv0e*lLmӪR p7XH`̌xRK2bPSیTSDJx2ǟV?ǡ kfS 1I&D 0D(#'5eվh$R6X(إ XΪږVdZ;vk\+继vo(h7.WlHԧqR댑۲ӎ1}4Aa]R?K"DE49'C.3H(#WQRR t$CĔdP^C| n~{}Qo]qoj/ngZon 'nc3 F3%c|ټ{PH#r2Ua)1Bbc:-[bQ _M D+{A(IcY1TEd&?T YȚʾL=x4n3&m[jy9Na+3oLZ1U&:ZUWDZ$LX X=:V4F^o^NK8HD0ۙ6(y iV_Ző+;կF ] =aF 屟$x'MbJ>A:rC.MO}IJSAvè(+LJ|$ARD"P"IH DGlfh!)w 0YW0W1߿_Ҏ;T. "1 cxh0۵/jwNcGhP/?Z~PUdč×acfYw;x FK~9iwnd@>Vf xj )YQvLP/9,#iUZXerSY6 !T QXZTGS͝L. 0FX{ X:xRIhpĸ3GGAcE]8gu"չ{?LZfB vx1Nty %Uiy,s^)0fi_*mT-(qxN/%eH JOSǖ~M5@.UГaP*yx3U2A+ia +}w>kֹ-ի3z:)WৈR1)9ru!np|ږ!7|t=[ݦRy-1򼤨e2y|oMB[E>զ&)˵6Z;ӆzhLA`Zk0֗1"d8gy9-7%)a ?vebi@+&0[T CMa8ȹ:q0os#sӘZIfFyWKhgY; *Z n&ݚ?EDd\15mS:Q1(#IFa>P!!EPBX|}CI"E;s>hG'2 3hZ60\:ہ!Yj%fv4 g4.y0<&4N$jn\WT9Yy*3J2cx>~ՁwZ\pA(I9zqyGs{w[c$A`^#!˫Ues:\y/n`f6OLU3F#j%NOKR(++y60'Vcl*Ua T S(àض5A >c?$Щǎ}@lE*>,/W'3d'cd3.wmM^LιkN`%ToKi\#:! aW97$cu|D#9lͦQf輖n\PPvmսJTwe az&1"Qǯ~=2H gZ%ʌ*n j@iQHmlcByƳʣ#K^;unɧhJ(RG?VU=!ip zk^#ϧňq>`e;N?:a#4O}jk{30]ۦ J.{*1rJ =0ݢo|{n ɢ`23B')PeKaiP~F&l:~R)uL$āLnV1M'H RCn7ˁ 8 m 5[AfN8@ MVe`#A{qb7J1$g\rV&fLlZXFTHhNG㟶P؇ ~…ASg?3y5ju]gԠm#A?[,0:_x^Ѱ"hfΧJ˂mKan?;&cC=UU;.aBNW,HO>OB5Wm+aa[Z=Ƭ~OzᎴJk\N?K9)ÏR9,Ͳ4Ў„*4pTIt^V}LeRz " ϫbQj`SAV)-Mõ1^7t.bbEAQA/FR׏_jd}t|bQ;ֽn(rvݣZ=zFU׾> O#ʴw; z%c] tキ]u}~v}!#y]Bv+8tF Z=VcuE >{/:-XKcHVI]kMU])+xx|Ax$L -ʱ6Ԉ%pWL"ffDy&ÙW=E`:hEM2CqhХϮܨ!G=4:j?zcO$"sfǨئMKbÒmt;TAwSKm&X*`~A8R92}IաCL}E5^m6UiG:5} ( Y^^Varm{v9DžZ: 8 6F$:tgo:e;uy \fk_?Fe|[#zKS`?a@vzAPx h!Fp(*ty!eÈz1CY{cɣj_jJj-MTbgթYORHVxq|^$%$))*eJ>h ]ALYj^t՘EG,A8)Y` +8_4CyrRM<1!kA+x_@@'=t+9ׁQ8/mmwlb._'Յ_Psj( #b9~MBv+9úA^ݵ榙j4a^OT&%?8iI`ak]gdDӅV= R߮8`[WΰKb0M(nHxJe3H$,sb};ŒNXClzѸ#gc>|*[R۷K|e%_,*TU <z1Ip,xwxK_hG4Q:w ƈ5h'Eo1vFՍ((o t:6>}mOXkwЩB 0XUܐ 3a&ANL#XoVc[v6i{1xvE"%㻉f"Umn ݎ蔸?oSAz~7ԯm9=:9|IF 0(\k?h4#wG>[%m u1϶Vy U h(!L4Tsg|n٭v4 ^< Ce wqS҂ UeWw*h$$HfXmЩp$Ŕ˜<.+U"V)0{Hړ݃Ym1D4,c<&ͬѹQ(NMwc 3A奔OUv)7hX ٙMQ`8)| n~P, au9QP,`'h".R(Zڵreѣ,CLMNLߪc~+_R?4+KP9QT~$%1 Ԓ! O_SDh pA--.7߬R::qD]w%+?&0lJB0J/d[;ߨ* pS7UR.72ܾ~/K|[e24i+҇ v=2nGQ@NTő!dcֆbP=HEG3zNnn'P=Gܾ/C@P1i`4R G#a4(=0(# "ly[ԒtH| 7Aݘ?۹(0$%U˴JZͨiI;3jnI^[ⱽ=?*6#Ul!'TiS`:2luן~ethD*K=4uPݔr1)nv ?O]q(g^dg{RQ~x( LZqwFr^ Ouu ͭ洃&sT"ߏvWƈҟѰÅ?$poEJ?谇zhw# |s%q 6CTVW7pJ#xl2 OjvhoMEP}"SHTQbT\(թ $ڵW/4S 1Sf$1奐 (b)(u C h4ogΛi{vFz }jzJE4}7}g0~ͱ"~!¡: ^ a GpobbB=S !BȌ(0tg3TgLdX,.ehҘƠ:۹s\>И )К S \![2 c`ie8/w}^kNxS~(&-$I7MsŶE |F I&1?Dx40嚳 -+Gۺhȑ/E7qaJSÞ5nMQ,y-֢喳zatMixm'?y5^ÑϏvmHu[5_ԋs+(aS]x^x:#to05ǺRM4ƭ&(  k3h1l%O=W7'_j}Yo|]_F]Ԇҙn‚i ޥ9mg Oөʧy^R1YHK B.$/J\A}v6~O)!aU4 )čE{}58v%7u||/:ާpr:$mY8VƒF(] 0W[[=󓷴nQZO<0P0F׿4 * U]ݣ v(1P@ 䜚6f&fT6ꢭQLU)(eZ:qH{!J Q>\ʁўBNS#2FՎR> Abm(jk?<Yi`Zc8j@ 9֑~j-:%c7S{nXln'ږH׳Faܶ}%;(۞Yn)h_`Aىف7oy*H1&ü1|^;5 H^ @'Rf,6If2* q}&|DCTȌLL9=>'(k{D}D/ 4 p~vn⎷zlw}*wЦwA~X Q mnw() TatD S-b<:3!j4_eSoR]IeH4LCF+iOC^j> /|vnYE{f֧a8ٟ~saݶE1hA4B28ǡbcP *K_rI\y!tȰZRgGle*ALc% {f%P@_OUz/GYG#=V d*@o/%c,} ;l9zk_s!aZ c4v!$[oQr{Ko7@')p{&}V;n{rh7Q?04 Ӈ5#bf#8arGK<6.#4A+>^XE @c$%˙%U̘xP jFE(Db$YYF70351W۴!35 T,yJUE*sxU*Ī]I7?ӭ7d~Y4ҁG2G?s5w-wg smPwe 1,#d#QoZ=jxuQha0 dT`,@^!Q$; e0F|u159Cq|ܷDյ4qV9-m*0ܶ \O b$#<dJq5rF3>;K#+\Z]̩Jx$|SS*PK5\7MzR/"?O'~?:_g?y@\tWbw^{H=QQ_u0e|a7o܍v $e`s- Nbd`S4@'bI?ɰ;RqJ#TP_VOAJD DN"̤ң뮽*zz⏤AHJMǂfSԇ̘hSG& نhPr5U#jzی:OLtFfb3P8qB#v2dV*:F8tIF@(˩ܜǏ H;t%;"E(b a|}CZDL^{m(ѱR^ %RAJH]NS]MQ`(iQÀNj\y(ZGu Qbq|!.-b4(6#% 9mb} jAsr7 z#D@z/I\nB=D$<_;UɋC Iꟊj*:UXԾgԾ]R9cԈ<e Um/)m2/Fﰫᩫ6/ -dKgC12@I¼:Rn~OYuZO `ܙGqv?TEN1-ƯMصE=i5&i"6vfTRNT3ū6@>WIl%'i:3F Y0g92t¸ah997i0qrxl,?ۧii6HIu\~(?^Y 7`?׃QFkDͣ6B333b@!7},ڀ)bJլj~G KZDf#l[FQ ׄfUivU?N6=\iTxo!õ]0!.27uVrQ}S8qdpف#MWImۧra-\HCv{,UM6N3v1QPY򟒶NVO>{iAL&K{]=ub 9mSI"'ЖV\-W|4|pIs4R-kMP\4% fPU܁jZ)\ "X41#H|4*t~ml[3N3FFoהD Ǒ@kfpۚy ;:QRa.THWnqaIΝ'*g;qz+_Δ5V5~="R#?o$.\ A¿;T{dR\(b񢜧(fdyZ͕uW0rzlW-%5ڀVčiq>,/rNJL%j wR0{ߵ^_DRbD|uq];\PطӴ/G;CtcK~΃G,;w%"i4 [{ Mf-!$ "[#!X%NiM!ΨBTbghVjDEeQeSb*` ISj<&oz'̼5crSuNS r}9P$F6O(F`Qx45 DjZJı z,/?&bTt ӿn=el44w 61FR<@Gs|u((y <կ&J6HsΏn( ! r3h孮x?lgnFlGXɵ11:i|LiB/IZIdYJ^tn*č(0*0FypVIDATTRJ O4C8f=S]К >!ubJIqzޮ$$;1"jo6~){hOѴ[nH˱`>,?L_}Y w{:pGJ¸ā@)Iƈ_*gg;j,V%Gj٨3[ li07{cvV"М??;.}cA=]ѝ[$#aIbyġ !yD52ialIQ٢j`p9t{7 J8$,cW1׊GP uo&2Ee.˪0,B H" qY>K3Xgh$-AƄZ (`pm'=ytOl&= D1r7[}1qgѥGnpMqsI0ѥژ??+RGR i4 6@_+NjDJ @YdS7b"Ǘ<4J1D3sKj$Ѹێ Gq/8pϚx%$VH%cJ}LJWۘ8g<Bщ?dt9GkQa\BF.Saqі$4c7 g;r]ft)/g0)Y bPƨ?2Ki0:!2 ԙ02@IIu*; #&allA"l5MR,[t)^ .jE`ށw=]wQ(0 _" ;ƿSȻjg(p3';<0aTrcp#payƈQ}}jotXT}]{~۩ֻ[nC#ЇUȑ JgeoD'5pGG)]haQa3^m'1GtI0@0FܺOQ(5GG)&1FV2GP:q cD I<9ppX|0T*a6^mW+v]76KGoZ"0ggrØyΏ80.(@catU 1G>S0Ȑ1c3 cDh^OͫrTX9ڥChe/c%Gph-2 cIr4U aU8sUsZ <Ƒ] V9*62Ex= cyh: GgQO^Z˝Hn#>tv(ƈăPBhdQ`) [?Б/r sKi˵ɓ`1F F;!g]';R nK_݋旄 mnk SDs-?Ző,c8KcS_k}N w68}j6wan狜SUY>dkhA_ںLQCXͶo #'5js]gC9Pr!ڊYCkǜ7o #NIɏacrp ЮC9KJS]!7>!Ű6NTG:C4XIܪQ`X(|@QFpҢή V8G)=Z_wLXƈsvRƕpIO+3ӣ cر0i((JC _s~Z;ЌYN6j<  ԥաj?uPqJC~m@3F\w'5jJj(fckRz{'2Ug'r6m3FNj|3ۥLm ~?I8iQg[^FtsF֛1"9ԨxCtr"JٚⰂ~ejmvΊhޯFtF ƈR#9S^O|Q  S|O(=[IE~j2 nM{G@]qC۸ņ1"}\滄.Z3]\N(ma ᧢џs a 4?|mj]OzϞUƈ^RԨ>x77j&ˉ~GohIE~jñ/~y`]EiwVƈ 8o  d 7\QLQcEA52Ǿ2HtI@) s9 c/4RjFw( D)"=g?v!9:$%CT>w.ybU@ o4/bhCr-L(1E4]hPχs<_nҡ_W_DE 5[`SR#) k~RG5y5DÍ(*q.&ڪK>p:w~L%C}0C CC'1~;F^tQ{Em7f(5A)@&#P wq%#^rGWTE4VSE-cD/߽CU_Rro)C졞lԘ"sP!.r[:~\-?*-^T 'm=*dcsyy#*oZ{[ FFs~Rot%~"Sć w 9p ct^ ծ oqD1n*q=@"{~tr9 8 OLOf( O>b`r(k PU_g$i^*Q xTѷPKL}`u_cH戢E(>kEn^$ځ@)n@£37K =cD{7]4RߥN{ocr)׽ۣ;5̱St|Y4Ju):%kTq'M'5et|c{?'v۳a9H@=w 2P+_jSt![_Mpq%QLï%Lgׅj&p@kp1F4>ƝcZeEG{kUgqm5vp*A/s6s6}\( F@O( /Fy wGdsYܥ9Ýn4f0O}rmНuPö(G5(0rˤop#?5pNOO#W'رV4r]Z9,\c䧆9ݶwE R1GAoWBܰuWXt% D 4ԐR-5"$'`mFO-60Qbmlf.`%ʟ"ݬaw,];Ν;$d9svh=3Jf{g ׶[WB`05u2\*dR+Б C]ڛP9sgB }ܕ!ou3Q sJߛf\LVb͡6i㍆)4r݈ `?Qj=TF@Եk)HٿV>P6RLf1 xF2R*#зB` HK$4uXS3B h@Eش0Dtn%3oi-]Y`E-`Z@p¨j//\AM [[T#ԖAZA&0о d BՂ5y((x.$l,eDp@0&Kc UԚ&ȫ@q ʾ喿>by9@@ŰH Z:~Y*Xqj,Q5K4#ѣ^ azk}g̫{= S[zh3W[BqE3z0!+/z5^QhēU\%(rI+H PODPe:waJhWT %@-*9mzU.|0}V\^b WTLp¨zY,kYe4MC ^4QVs< S  jgj -pig4MMPC ,nԘN4t/0¨F]#\#MH 鐂HX'Karg@5!Eb+WM_Jj齯HH%'K`COv׬5Wz{Ò,kSl?\=n/M<ꓦνgsvoVEqQ8 4g-;t3TuS >Dm2~}l&}û`(LnJu$C -a*)S3+E*[b?g%yX+&=Pd=*@~q5_jz4pyhV~'&a3fEbF̜JEPjA *ӗ0§k7Guլ^3/z7asiߙ&z8^H!Ɨl1¨O:⨎pc4FO.ӌ2Ŵ̘lV {^G4 ܨ'ۦx5pQͭ) -9ds皦v2{i7.oJvcNhri G=ҦF.ZcRetd1cL…6OfF67QC>2u7/c^x:EiP@fьqC$ԍk4yr5D#zÑڗo﫛Mm)@ ܧ!|6cw(kF?VM%H/g  .DQl&0Jzs; XFp%Sq GZ@DQ!CFDR8J 4[3pDaT.FƏ!PCQFQ|qTg4Dw&gH(Q5&qo%@@Uώ+! 2$hٯ8ʈ=}EٌC F@e t "0F3đv֞]@<`3MGS $A`TFFmf=9ook6Nkp'4tfG% `-Eӊ51b"՚ L}e)e-J@?y26nz C5qo7f9~KD7/_nU,\"p%si8cW!")eޜ?ďΠmR2ZW)"(DAc)Q>1ʊ2֏?oNf9ySzFwMQ-!=FXRaT H<Q@kH+\Aù! VݒOFjLπ!`\Fڎ(wˆ? [3u-"X[:`]fH@{+'^[ʨ @h4.g DŽի{W Nxt@{>躒ǨJ)K@qHn,/K*'hq9#g@\^%$y؞9ɋtn<$aא넕qKT®[@k5Yf (w1gwy-iTw]Z=pK#mSTiF~|KKo,)r\2sfs5ܒK!XAca $^o֭/L=jJє%Z-3曖r[ z~Ѓ##l=ȑ2}]]Ni'/1 @O@J#+G%o(}I{}3p洹isj NӇDPxx% P'nTFpQ X]0eu7N))5EOS{{ 4ٴ̘14>@@2F| HZ@ *K+Rĉ‘srs BUM߾wbe<<6k=qT^.8O@NAšE]@'/v`p0 l8 ԁҤX◳3IENDB`cgreen-1.6.3/doc/cgreen-guide-en-docinfo.html000066400000000000000000000017751450461175400210150ustar00rootroot00000000000000 Thomas Nilefalk thomas@junovagen.se Marcus Baker lastcraft marcus@lastcraft.com João Freitas joaohf joaohf@gmail.com Cgreen Unit Test for C/C++ language 2009-2012 Cgreen Team Permission to use, copy, modify and distribute. The copyright holders make no representation about the suitability of this document for any purpose. It is provided as is without expressed or implied warranty. cgreen-1.6.3/doc/cgreen-guide-en-docinfo.xml000066400000000000000000000020311450461175400206330ustar00rootroot00000000000000 Marcus Baker lastcraft marcus@lastcraft.com João Freitas joaohf joaohf@gmail.com Thomas Nilefalk thoni56 thomas@junovagen.se Cgreen Unit Test for C language 2012 Cgreen Team Permission to use, copy, modify and distribute. The copyright holders make no representation about the suitability of this document for any purpose. It is provided as is without expressed or implied warranty. cgreen-1.6.3/doc/cgreen-guide-en.asciidoc000066400000000000000000004202651450461175400202070ustar00rootroot00000000000000////////////////////////////////////////////////////////////////////// In this Asciidoc document we use the convention that one sentence is kept on a single line. This creates nice diffs. ////////////////////////////////////////////////////////////////////// :source-highlighter: highlightjs :icons: font :numbered: :toc: left :pp: ++ :title-page: :title-logo-image: logo.png ifdef::env-github[] :tip-caption: :bulb: :note-caption: :information_source: :important-caption: :heavy_exclamation_mark: :caution-caption: :fire: :warning-caption: :warning: endif::[] = Cgreen : Unit Tests, Stubbing and Mocking for C and C++ v{VERSION} - Generated {localdate} == Cgreen Quickstart Guide === What is Cgreen? *Cgreen* is a unit testing framework for the C and C++ software developer, a test automation and software quality assurance tool for programmers and development teams. The tool is completely open source published under the https://github.com/cgreen-devs/cgreen/blob/master/LICENSE[ISC, OpenBSD, license]. Unit testing is a development practice popularised by the agile development community. It is characterised by writing many small tests alongside the normal code. Often the tests are written before the code they are testing, in a tight test-code-refactor loop. Done this way, the practice is known as Test Driven Development. *Cgreen* was designed specifically to support this style of development. Unit tests are written in the same language as the code, in our case C or C++. This avoids the mental overhead of constantly switching language, and also allows you to use any application code in your tests. Here are some of its features: - Fluent API resulting in very readable tests - Expressive and clear output using the default reporter - Fully functional mocks, both strict, loose and learning - Mocks with side effects - Each test runs in its own process for test suite robustness - Automatic discovery and running of tests using dynamic library inspection - Extensive and expressive constraints for many datatypes - Custom constraints can be constructed by user - BDD-flavoured test declarations with Before and After declarations - Extensible reporting mechanism - Fully composable test suites - A single test can be run in a single process for easier debugging *Cgreen* also supports the classic xUnit-style assertions for easy porting from other frameworks. *Cgreen* was initially developed to support C programming, but there is also support for C{pp}. It was initially a spinoff from a research project at Wordtracker and created by Marcus Baker. Significant additions by Matt Hargett and continuous nurturing by Thomas Nilefalk has made *Cgreen* what it is today. === Cgreen - Vanilla or Chocolate? Test driven development (TDD) really catched on when the JUnit framework for Java spread to other langauges, giving us a family of https://en.wikipedia.org/wiki/XUnit[xUnit] tools. *Cgreen* was born in this wave and have many similarities to the xUnit family. But TDD evolved over time and modern thinking and practice is more along the lines of BDD, an acronym for Behaviour Driven Development, made popular by people like Dan North and frameworks like JBehave, RSpec, Cucumber and Jasmine. *Cgreen* follows this trend and has evolved to embrace a BDD-flavoured style of testing. Although the fundamental mechanisms in TDD and 'technical' BDD are much the same, the shift in focus by changing wording from 'tests' to 'behaviour specifications' is very significant. This document will present *Cgreen* using the more modern and better BDD-inspired style. In a later section you can have a peek at the classic xUnit-family TDD API, but you should consider that as outdated. === Installing Cgreen There are two ways to install *Cgreen* in your system. ==== Installing a package The first way is to use packages provided by the *Cgreen* Team and porters for the various operating systems. If your system uses a package manager ('apt', 'yum', 'brew' and so on) there might be a prebuilt package that you can just install using your systems package manager. If no *Cgreen* package is distributed for your system you can download a package from https://github.com/cgreen-devs/cgreen/releases[Cgreen GitHub project]. Install it using the normal procedures for your system. NOTE: At this point there are pre-built packages available for quite a few environments. They are not all using the latest version, though. If you need that, you can still build from source. ==== Installing from source A second way is available for developers and advanced users. Basically this consists of fetching the sources of the project on https://github.com/cgreen-devs/cgreen[GitHub], just click on "Download ZIP", and then compile them. To do this you need the http://www.cmake.org[CMake] build system. Once you have the CMake tool installed, the steps are: ----------------------------------------- $ unzip cgreen-master.zip $ cd cgreen-master $ make $ make test $ make install ----------------------------------------- The initial `make` command will configure the build process and create a separate `build` directory before going there and building using *CMake*. This is called an 'out of source build'. It compiles *Cgreen* from outside the sources directory. This helps the overall file organization and enables multi-target builds from the same sources by leaving the complete source tree untouched. TIP: Experienced users may tweak the build configuration by going to the build subdirectory and use `ccmake ..` to modify the build configuration in that subtree. TIP: The Makefile is just there for convenience, it creates the build directory and invokes *CMake* there, so that you don't have to. This means that experienced *CMake* users can just do as they normally do with a *CMake*-based project instead of invoking `make`. The build process will create a library (on unix called `libcgreen.so`) which can be used in conjunction with the `cgreen.h` header file to compile and link your test code. The created library is installed in the system directories, by default in `/usr/local/lib/`. ==== Your First Test We will start demonstrating the use of *Cgreen* by writing some tests for *Cgreen* itself to confirm that everything is working as it should. Let's start with a simple test module with no tests, called `first_test.c`... [source,c] --------------------------------------- include::tutorial_src/first_tests0.c[] --------------------------------------- This is very unexciting. It just creates an empty test suite and runs it. It's usually easier to proceed in small steps, and this is the smallest one I could think of. The only complication is the `cgreen.h` header file and the mysterious looking "declarations" at the beginning of the file. The BDD flavoured *Cgreen* notation calls for a System Under Test (SUT), or a 'context'. The declarations give a context to the tests and it also makes it more natural to talk about which module or class, the system under test, is actually responsible for the functionality we are describing. In one way we are 'describing', or spec'ing, the functionality of the SUT. That's what the `Describe();` does. And for technical reasons (actually requirements of the C language), you must declare the `BeforeEach()` and `AfterEach()` functions even if they are empty. (You will get strange errors if you don't!) NOTE: We are using the name "Cgreen" as the SUT in these first examples, as *Cgreen* itself is the object or class we want to test or describe. I am assuming you have the *Cgreen* folder in the include search path to ensure compilation works, otherwise you'll need to add that in the compilation command. Then, building this test is, of course, trivial... ----------------------------- $ gcc -c first_test.c $ gcc first_test.o -lcgreen -o first_test $ ./first_test ----------------------------- Invoking the executable should give... ----------------------------- include::tutorial_src/first0.out[] ----------------------------- All of the above rather assumes you are working in a Unix like environment, probably with 'gcc'. The code is pretty much standard C99, so any C compiler should work. *Cgreen* should compile on all systems that support the `sys/msg.h` messaging library. It has been tested on Linux, MacOSX, Cygwin. If you are on Windows we would be glad if you could figure out how to build there. So far we have tried compilation, and shown that the test suite actually runs. Let's add a meaningless test or two so that you can see how it runs... [source,c] ----------------------------- include::tutorial_src/first_tests1.c[] ----------------------------- A test is denoted by the macro `Ensure` which takes an optional context (`Cgreen`) and a, hopefully descriptive, testname (`passes_this_test`). You add the test to your suite using `add_test_with_context()`. On compiling and running, we now get the output... ----------------------------- include::tutorial_src/first1.out[] ----------------------------- The `TextReporter`, created by the call to `create_text_reporter()`, is the easiest way to output the test results. It prints the failures as intelligent and expressive text messages on your console. Of course "0" would never equal "1", but this shows that *Cgreen* presents the value you expect (`[be true]`) __and__ the expression that you want to assert (`[0 == 1]`). We can also see a handy short form for asserting boolean expressions (`assert_that(0 == 1);`). [[tdd_with_cgreen]] === Five Minutes Doing TDD with Cgreen For a more realistic example we need something to test. We'll pretend that we are writing a function to split the words of a sentence in place. It would do this by replacing any spaces with string terminators and returns the number of conversions plus one. Here is an example of what we have in mind... [source,c] ------------------------------- char *sentence = strdup("Just the first test"); word_count = split_words(sentence); ------------------------------- The variable `sentence` should now point at "Just\0the\0first\0test". Not an obviously useful function, but we'll be using it for something more practical later. This time around we'll add a little more structure to our tests. Rather than having the test as a stand alone program, we'll separate the runner from the test cases. That way, multiple test suites of test cases can be included in the `main()` runner file. This makes it less work to add more tests later. Here is the, so far empty, test case in `words_test.c`... [source,c] ------------------------------- include::tutorial_src/words_tests0.c[] ------------------------------- Here is the `all_tests.c` test runner... [source,c] ------------------------------- include::tutorial_src/all_tests.c[] ------------------------------- *Cgreen* has two ways of running tests. The default is to run all tests in their own protected processes. This is what happens if you invoke `run_test_suite()`. All tests are then completely independent since they run in separate processes, preventing a single run-away test from bringing the whole program down with it. It also ensures that one test cannot leave any state to the next, thus forcing you to setup the prerequisites for each test correctly and clearly. Building this scaffolding... ------------------------------- $ gcc -c words_test.c $ gcc -c all_tests.c $ gcc words_test.o all_tests.o -lcgreen -o all_tests ------------------------------- ...and executing the result gives the familiar... ------------------------------- include::tutorial_src/words0.out[] ------------------------------- Note that we get an extra level of output here, we have both `main` and `words_tests`. That's because `all_tests.c` adds the words test suite to its own (named `main` since it was created in the function `main()`). All this scaffolding is pure overhead, but from now on adding tests will be a lot easier. Here is a first test for `split_words()` in `words_test.c`... [source,c] ------------------------------- include::tutorial_src/words_tests1.c[] ------------------------------- The `assert_that()` macro takes two parameters, the value to assert and a constraint. The constraints comes in various forms. In this case we use the probably most common, `is_equal_to()`. With the default `TextReporter` the message is sent to `STDOUT`. To get this to compile we need to create the `words.h` header file... [source,c] ------------------------------- include::tutorial_src/words.h[lines=1] ------------------------------- ...and to get the code to link we need a stub function in `words.c`... [source,c] ------------------------------- include::tutorial_src/words1.c[lines=3..5] ------------------------------- A full build later... ------------------------------- $ gcc -c all_tests.c $ gcc -c words_test.c $ gcc -c words.c $ gcc all_tests.o words_test.o words.o -lcgreen -o all_tests $ ./all_tests ------------------------------- ...and we get the more useful response... ------------------------------- include::tutorial_src/words1.out[] ------------------------------- The breadcrumb trail following the "Failure" text is the nesting of the tests. It goes from the test suites, which can be nested in each other, through the test function, and finally to the message from the assertion. In the language of *Cgreen*, a "failure" is a mismatched assertion, or constraint, and an "exception" occurs when a test fails to complete for any reason, e.g. a segmentation fault. We could get this to pass just by returning the value 4. Doing TDD in really small steps, you would actually do this, but we're not teaching TDD here. Instead we'll go straight to the core of the implementation... [source,c] -------------------------------- include::tutorial_src/words2.c[] -------------------------------- Running it gives... --------------------------------- include::tutorial_src/words2.out[] --------------------------------- There is actually a hidden problem here, but our tests still passed so we'll pretend we didn't notice. So it's time to add another test. We want to confirm that the string is broken into separate words... [source,c] --------------------------------- ... include::tutorial_src/words_tests2.c[lines=10] ... include::tutorial_src/words_tests2.c[lines=15..23] --------------------------------- Sure enough, we get a failure... ---------------------------------- include::tutorial_src/words3.out[] ---------------------------------- Not surprising given that we haven't written the code yet. The fix... [source,c] ---------------------------------- include::tutorial_src/words3.c[] ---------------------------------- ...reveals our previous hack... ---------------------------------- include::tutorial_src/words4.out[] ---------------------------------- Our earlier test now fails, because we have affected the `strlen()` call in our loop. Moving the length calculation out of the loop... [source,c] ---------------------------------- include::tutorial_src/words4.c[lines=3..5] ... include::tutorial_src/words4.c[lines=10..-1] ---------------------------------- ...restores order... ---------------------------------- include::tutorial_src/words5.out[] ---------------------------------- It's nice to keep the code under control while we are actually writing it, rather than debugging later when things are more complicated. That was pretty straight forward. Let's do something more interesting. === What are Mock Functions? The next example is a more realistic extension of our previous attempts. As in real life we first implement something basic and then we go for the functionality that we need. In this case a function that invokes a callback for each word found in a sentence. Something like... [source,c] ---------------------------------- void act_on_word(const char *word, void *memo) { ... } words("This is a sentence", &act_on_word, &memo); ---------------------------------- Here the `memo` pointer is just some accumulated data that the `act_on_word()` callback might work with. Other people will write the `act_on_word()` function and probably many other functions like it. The callback is actually a flex point, and not of interest right now. The function under test is the `words()` function and we want to make sure it walks the sentence correctly, dispatching individual words as it goes. So what calls are made are very important. How do we go about to test this? Let's start with a one word sentence. In this case we would expect the callback to be invoked once with the only word, right? Here is the test for that... [source,c] --------------------------------- include::tutorial_src/words_tests3.c[lines=1..2] ... include::tutorial_src/words_tests3.c[lines=27..38] ... include::tutorial_src/words_tests3.c[lines=41..-1] --------------------------------- What is the funny looking `mock()` function? A mock is basically a programmable object. In C objects are limited to functions, so this is a mock function. The macro `mock()` compares the incoming parameters with any expected values and dispatches messages to the test suite if there is a mismatch. It also returns any values that have been preprogrammed in the test. The test is `invokes_callback_once_for_single_word_sentence()`. It programs the mock function using the `expect()` macro. It expects a single call, and that single call should use the parameters `"Word"` and `NULL`. If they don't match, we will get a test failure. So when the code under test (our `words()` function) calls the injected `mocked_callback()` it in turn will call `mock()` with the actual parameters. Of course, we don't add the mock callback to the test suite, it's not a test. For a successful compile and link, the `words.h` file must now look like... [source,c] ---------------------------- include::tutorial_src/words.h[] ---------------------------- ...and the `words.c` file should have the stub... [source,c] ---------------------------- include::tutorial_src/words5.c[lines=14..15] ---------------------------- This gives us the expected failing test... ---------------------------- include::tutorial_src/words6.out[] ---------------------------- *Cgreen* reports that the callback was never invoked. We can easily get the test to pass by filling out the implementation with... [source,c] ---------------------------- include::tutorial_src/words6.c[lines=14..16] ---------------------------- That is, we just invoke it once with the whole string. This is a temporary measure to get us moving. For now everything should pass, although it doesn't drive much functionality yet. ---------------------------- include::tutorial_src/words7.out[] ---------------------------- That was all pretty conventional, but let's tackle the trickier case of actually splitting the sentence. Here is the test function we will add to `words_test.c`... [source,c] ---------------------------- include::tutorial_src/words_tests4.c[lines=37..43] ---------------------------- Each call is expected in sequence. Any failures, or left-over or extra calls, and we get failures. We can see all this when we run the tests... ---------------------------- include::tutorial_src/words8.out[] ---------------------------- The first failure tells the story. Our little `words()` function called the mock callback with the entire sentence. This makes sense, because that was the hack we did to get to the next test. Although not relevant to this guide, I cannot resist getting these tests to pass. Besides, we get to use the function we created earlier... [source,c] ----------------------------- include::tutorial_src/words7.c[lines=15..29] ----------------------------- And with some work we are rewarded with... ------------------------------ include::tutorial_src/words9.out[] ------------------------------ More work than I like to admit as it took me three goes to get this right. I firstly forgot the `+ 1` added on to `strlen()`, then forgot to swap `sentence` for `word` in the `(*callback)()` call, and finally third time lucky. Of course running the tests each time made these mistakes very obvious. It's taken me far longer to write these paragraphs than it has to write the code. == Building Cgreen test suites *Cgreen* is a tool for building unit tests in the C or C++ languages. These are usually written alongside the production code by the programmer to prevent bugs. Even though the test suites are created by software developers, they are intended to be human readable C code, as part of their function is an executable specification. Used in this way, the test harness delivers constant quality assurance. In other words you'll get less bugs. === Writing Basic Tests *Cgreen* tests are like C, or C++, functions with no parameters and no return value. To signal that they actually are tests we mark them with the `Ensure` macro. Here's an example... [source,c] ----------------------------- include::tutorial_src/strlen_tests1.c[lines=8..10] ----------------------------- The `Ensure` macro takes two arguments (in the BDD style) where the first is the System Under Test (SUT) which must be declared with the `Describe` macro. [source,c] ----------------------------- include::tutorial_src/strlen_tests1.c[lines=4] ----------------------------- The second argument is the test name and can be anything you want as long as it fullfills the rules for an identifier in C and C++. A typical way to choose the named of the tests is what we see here, reading the declaration of the test makes sense since it is almost plain english, "Ensure strlen returns five for 'hello'". No problem understanding what we aim to test, or in TDD lingo, test drive. And it can be viewed as an example from a description of what strlen should be able to do. In a way, extracting all the `Ensure`:s from your test might give you all the documentation you'll need. The call to `assert_that()` is the primary part of an assertion, which is complemented with a constraint, in this case `is_equal_to()`, as a parameter. This makes a very fluent interface to the asserts, that actually reads like English. The general format is then [source, C] --------------- assert_that(actual, ); --------------- NOTE: Sometimes you just want to fail the test explicitly, and there is a function for that too, `fail_test(const char *message)`. And there is a function to explicitly pass, `pass_test(void)`. Assertions send messages to *Cgreen*, which in turn outputs the results. === The Standard Constraints Here are the standard constraints... |========================================================= |*Constraint* |*Passes if actual value/expression...* | _Basic_ | | `is_true` | evaluates to true, buy you can also just leave out the constraint, e.g. `assert_that(found)` if `found` is of boolean type | `is_false` | evaluates to false | `is_null` | equals null | `is_non_null` | is a non null value | `is_not_null` | d:o || | _Integer compatible_ | | `is_equal_to(value)` | '== value' | `is_equal_to_hex(value)` | '== value', but will show values in HEX | `is_not_equal_to(value)` | '!= value' | `is_greater_than(value)` | '> value' | `is_less_than(value)` | '< value' || | _Structs and general data_ | | `is_equal_to_contents_of(pointer, size)` | matches the data pointed to by `pointer` to a size of `size` bytes | `is_not_equal_to_contents_of(pointer, size)` | does not match the data pointed to by `pointer` to a size of `size` bytes || | _Strings_ | | `is_equal_to_string(value)` | are equal when compared using `strcmp()` | `is_not_equal_to_string(value)` | are not equal when compared using `strcmp()` | `contains_string(value)` | contains `value` when evaluated using `strstr()` | `does_not_contain_string(value)` | does not contain `value` when evaluated using `strstr()` | `begins_with_string(value)` | starts with the string `value` | `does_not_begin_with_string(value)` | does not start with the string `value` | `ends_with_string(value)` | ends with the string `value` | `does_not_end_with_string(value)` | does not end with the string `value` || | _Double floats_ | | `is_equal_to_double(value)` | are equal to `value` within the number of significant digits (which you can set with a call to `significant_figures_for_assert_double_are(int figures)`) | `is_not_equal_to_double(value)` | are not equal to `value` within the number of significant digits | `is_less_than_double(value)` | `< value` withing the number of significant digits | `is_greater_than_double(value)` | `> value` within the number of significant digits |========================================================= The boolean assertion macros accept an `int` value. The equality assertions accept anything that can be cast to `intptr_t` and simply perform an `==` operation. The string comparisons are slightly different in that they use the `` library function `strcmp()`. If you use `is_equal_to()` with `char *` pointers then it is the value of the pointers themselves that has to be the same, i.e. the pointers have to point at the same string for the test to pass. The constraints above should be used as the second argument to one of the assertion functions: |========================================================= |*Assertion* |*Description* | `assert_that(expected, constraint)` | Passes if `expected` fullfulls `constraint`, to be used for all assertions except `double` type values | `assert_that_double(expected, constraint)` | Passes if `expected` fullfulls `constraint`, only to be used for assertions on `double` type values |========================================================= WARNING: You cannot use C/C++ string literal concatenation (like `"don't" "use" "string" "concatenation"`) in the parameters to the constraints. If you do, you will get weird error messages about missing arguments to the constraint macros. This is caused by the macros using argument strings to produce nice failure messages. === Asserting C++ Exceptions When you use *CGreen* with C++ there is one extra assertion available: |========================================================= |*Assertion* |*Description* | `assert_throws(exception, expression)` | Passes if evaluating `expression` throws `exception` |========================================================= === BDD Style vs. TDD Style So far we have encouraged the modern BDD style. It has merits that we really want you to benefit from. But you might come across *Cgreen* test in another style, more like the standard TDD style, which is more inline with previous thinking and might be more similar to other frameworks. The only difference, in principle, is the use of the SUT or 'context'. In the BDD style you have it, in the TDD style you don't. [source,c] .BDD style: ----------------------------- include::tutorial_src/strlen_tests2.c[lines=4..16] ----------------------------- <1> The `Describe` macro must name the SUT <2> The `BeforeEach` function... <3> ... and the `AfterEach` functions must exist and name the SUT <4> The test need to name the SUT <5> Adding to the test suite CAUTION: You can only have tests for a single SUT in the same source file. If you use the older pure-TDD style you skip the `Describe` macro, the `BeforeEach` and `AfterEach` functions. You don't need a SUT in the `Ensure()` macro or when you add the test to the suite. [source,c] .TDD style: ----------------------------- include::tutorial_src/strlen_tests3.c[lines=3..12] ----------------------------- <1> No `Describe`, `BeforeEach()` or `AfterEach()` <2> No SUT/context in the `Ensure()` macro <3> No SUT/context in `add_test()` and you should use this function instead of `..with_context()`. TIP: You might think of the TDD style as the BDD style with a default SUT or context. === A Runner The tests are only run by running a test suite in some form. (But see also <>.) We can create and run one especially for this test like so... [source,c] ----------------------------- include::tutorial_src/strlen_tests5.c[lines=12..16] ----------------------------- In case you have spotted that the reference to `returns_five_for_hello` should have an ampersand in front of it, `add_test_with_context()` is actually a macro. The `&` is added automatically. Further more, the `Ensure()`-macro actually mangles the tests name, so it is not actually a function name. (This might also make them a bit difficult to find in the debugger....) To run the test suite, we call `run_test_suite()` on it. So we can just write... [source,c] ----------------------------- include::tutorial_src/strlen_tests5.c[lines=19] ----------------------------- The results of assertions are ultimately delivered as passes and failures to a collection of callbacks defined in a `TestReporter` structure. There is a predefined `TestReporter` in *Cgreen* called the `TextReporter` that delivers messages in plain text like we have already seen. The return value of `run_test_suite()` is a standard C library/Unix exit code that can be returned directly by the `main()` function. The complete test code now looks like... [source,c] ----------------------------- include::tutorial_src/strlen_tests5.c[] ----------------------------- Compiling and running gives... ----------------------------- $ gcc -c strlen_test.c $ gcc strlen_test.o -lcgreen -o strlen_test $ ./strlen_test include::tutorial_src/strlen2.out[] ----------------------------- We can see that the outer test suite is called `our_tests` since it was in `our_tests()` we created the test suite. There are no messages shown unless there are failures. So, let's break our test to see it... [source,c] ----------------------------- include::tutorial_src/strlen_tests6.c[lines=8..10] ----------------------------- ...we'll get the helpful message... ----------------------------- include::tutorial_src/strlen6.out[] ----------------------------- *Cgreen* starts every message with the location of the test failure so that the usual error message identifying tools (like Emacs's `next-error`) will work out of the box. Once we have a basic test scaffold up, it's pretty easy to add more tests. Adding a test of `strlen()` with an empty string for example... [source,c] ----------------------------- ... include::tutorial_src/strlen_tests7.c[lines=12..21] ... ----------------------------- And so on. === BeforeEach and AfterEach It's common for test suites to have a lot of duplicate code, especially when setting up similar tests. Take this database code for example... [source,c] ------------------------------ include::tutorial_src/schema_tests1.c[] ------------------------------ We have already factored out the duplicate code into its own functions `create_schema()` and `drop_schema()`, so things are not so bad. At least not yet. But what happens when we get dozens of tests? For a test subject as complicated as a database http://www.martinfowler.com/eaaCatalog/activeRecord.html[ActiveRecord], having dozens of tests is very likely. We can get *Cgreen* to do some of the work for us by calling these methods before and after each test in the test suite. Here is the new version... [source,c] --------------------------- ... include::tutorial_src/schema_tests2.c[lines=6] ... include::tutorial_src/schema_tests2.c[lines=11..13] ... include::tutorial_src/schema_tests2.c[lines=18..41] ... --------------------------- With this new arrangement *Cgreen* runs the `create_schema()` function before each test, and the `drop_schema()` function after each test. This saves some repetitive typing and reduces the chance of accidents. It also makes the tests more focused. The reason we try so hard to strip everything out of the test functions is the fact that the test suite acts as documentation. In our `person.h` example we can easily see that `Person` has some kind of name property, and that this value must be unique. For the tests to act like a readable specification we have to remove as much mechanical clutter as we can. In this particular case there are more lines that we could move from the tests to `BeforeEach()`: [source,c] --------------------------- include::tutorial_src/schema_tests2.c[lines=25..26] --------------------------- Of course that would require an extra variable, and it might make the tests less clear. And as we add more tests, it might turn out to not be common to all tests. This is a typical judgement call that you often get to make with `BeforeEach()` and `AfterEach()`. NOTE: If you use the pure-TDD notation, not having the test subject named by the `Describe` macro, you can't have the `BeforeEach()` and `AfterEach()` either. In this case you can still run a function before and after every test. Just nominate any `void(void)` function by calling the function `set_setup()` and/or `set_teardown()` with the suite and the function that you want to run before/after each test. In the example above that would be `set_setup(suite, create_schema);` and `set_teardown(suite, drop_schema);`. A couple of details. There is only one `BeforeEach()` and one `AfterEach()` allowed in each `TestSuite`. Also, the `AfterEach()` function might not be run if the test crashes, causing some test interference. This brings us nicely onto the next section... === Each Test in its Own Process Consider this test method... [source,c] ----------------------------- include::tutorial_src/crash_tests1.c[lines=8..11] ----------------------------- Crashes are not something you would normally want to have in a test run. Not least because it will stop you receiving the very test output you need to tackle the problem. To prevent segmentation faults and other problems bringing down the test suites, *Cgreen* runs every test in its own process. Just before calling the `BeforeEach()` (or `setup`) function, *Cgreen* `fork()`:s. The main process waits for the test to complete normally or die. This includes calling the `AfterEach()`(or `teardown`) function, if any. If the test process dies, an exception is reported and the main test process carries on with the next test. For example... [source,c] ----------------------------- include::tutorial_src/crash_tests1.c[] ----------------------------- When built and run, this gives... ----------------------------- include::tutorial_src/crash1.out[] ----------------------------- The normal thing to do in this situation is to fire up the debugger. Unfortunately, the constant `fork()`:ing of *Cgreen* can be one extra complication too many when debugging. It's enough of a problem to find the bug. To get around this, and also to allow the running of one test at a time, *Cgreen* has the `run_single_test()` function. The signatures of the two run methods are... - `int run_test_suite(TestSuite *suite, TestReporter *reporter);` - `int run_single_test(TestSuite *suite, char *test, TestReporter *reporter);` The extra parameter of `run_single_test()`, the `test` string, is the name of the test to select. This could be any test, even in nested test suites (see below). Here is how we would use it to debug our crashing test... [source,c] ----------------------------- include::tutorial_src/crash_tests2.c[lines=13..17] ----------------------------- When run in this way, *Cgreen* will not `fork()`. But see the section on <>. TIP: The function `run()` is a good place to place a breakpoint. The following is a typical session: ----------------------------------- $ gdb crash2 ... (gdb) break main (gdb) run ... (gdb) break run (gdb) continue ... Running "main" (1 tests)... Breakpoint 2, run_the_test_code (suite=suite@entry=0x2003abb0, spec=spec@entry=0x402020 , reporter=reporter@entry=0x2003abe0) at /cygdrive/c/Users/Thomas/Utveckling/Cgreen/cgreen/src/runner.c:270 270 run(spec); (gdb) step run (spec=0x402020 ) at /cygdrive/c/Users/Thomas/Utveckling/Cgreen/cgreen/src/runner.c:217 217 spec->run(); (gdb) step CrashExample__seg_faults_for_null_dereference () at crash_test2.c:9 9 int *p = NULL; (gdb) step 10 (*p)++; (gdb) step Program received signal SIGSEGV, Segmentation fault. 0x004011ea in CrashExample__seg_faults_for_null_dereference () at crash_test2.c:10 10 (*p)++; ----------------------------------- Which shows exactly where the problem is. This deals with the case where your code throws an exception like segmentation fault, but what about a process that fails to complete by getting stuck in a loop? Well, *Cgreen* will wait forever too. But, using the C signal handlers, we can place a time limit on the process by sending it an interrupt. To save us writing this ourselves, *Cgreen* includes the `die_in()` function to help us out. Here is an example of time limiting a test... [source,c] --------------------------- ... include::tutorial_src/crash_tests3.c[lines=8] ... include::tutorial_src/crash_tests3.c[lines=11..23] --------------------------- When executed, the code will slow for a second, and then finish with... --------------------------- include::tutorial_src/crash3.out[] --------------------------- Note that you see the test results as they come in. *Cgreen* streams the results as they happen, making it easier to figure out where the test suite has problems. Of course, if you want to set a general time limit on all your tests, then you can add a `die_in()` to a `BeforeEach()` (or `setup()`) function. *Cgreen* will then apply the limit to each of the tests in that context, of course. Another possibility is the use of an environment variable named `CGREEN_TIMEOUT_PER_TEST` which, if set to a number will apply that timeout to every test run. This will apply to all tests in the same run. [[debugging]] === Debugging *Cgreen* tests *Cgreen* protects itself from being torn down by an exception in a test by `fork()`-ing each test into a separate process. A catastrophic error will then only affect the child process for that specific test and *Cgreen* can catch it, rather than crashing too. It can then report the exception and continue with the next test. ==== No fork, please If you want to debug any of your tests the constant `fork()`-ing might make that difficult or impossible. There are also other circumstances that might require that you don't use `fork()`. There are two ways to make *Cgreen* refrain from `fork()`-ing. *Cgreen* does not `fork()` when only a single test is run by name with the function `run_single_test()`. To debug you can then obviously set a breakpoint at that test (but note that its actual name probably have been mangled). *Cgreen* does some book-keeping before actually getting to the test, so a function easier to find might be the one simply called `run()`. The second way is to define the environment variable `CGREEN_NO_FORK`. If *Cgreen* can get that variable from the environment using `getenv()` it will run the test(s) in the same process. In this case the non-forking applies to *all* tests run, so all test will run in the same process, namely *Cgreen*s main process. WARNING: This might bring your whole test suite down if a single test causes an exception. So it is not a recommended setting for normal use. ==== Debugging with `cgreen-runner` If you use the convenient auto-discovery feature of *Cgreen* (see <>) by running dynamic loadable libraries through `cgreen-runner`, it might be tricky to figure out to where to put breaks and to get them to "take". `cgreen-runner` obviously loads the library (or libraries) with your tests dynamically so the tests are not available before executing the code that loads them. TIP: The function `run()` is a good place to place a breakpoint. ==== `cgreen-debug` For some platforms a utility script, `cgreen-debug`, is installed when you install *Cgreen*. It makes it very convenient to start a debugging session for a particular test. Find out the logical name of the test, which is composed of the Context and the Testname, in the form :. Then just invoke `cgreen-debug` ---- $ cgreen-debug : ---- The script will try to find a debugger, invoke it on the `cgreen-runner` and break on that test. NOTE: Currently it only supports `gdb` and will prefer `cgdb` if that's available. === Building Composite Test Suites The `TestSuite` is a composite structure. This means test suites can be added to test suites, building a tree structure that will be executed in order. Let's combine the `strlen()` tests with the `Person` tests above. Firstly we need to remove the `main()` functions. E.g... [source,c] ---------------------------- include::tutorial_src/suite_strlen_tests.c[lines=8] ... include::tutorial_src/suite_strlen_tests.c[lines=10..12] ... include::tutorial_src/suite_strlen_tests.c[lines=14..-1] ---------------------------- Then we can write a small runner with a new `main()` function... [source,c] ----------------------- include::tutorial_src/suite1.c[] ----------------------- It's usually easier to place the `TestSuite` prototypes directly in the runner source, rather than have lot's of header files. This is the same reasoning that let us drop the prototypes for the test functions in the actual test scripts. We can get away with this, because the tests are more about documentation than encapsulation. As we saw above, we can run a single test using the `run_single_test()` function, and we'd like to be able to do that from the command line. So we added a simple `if` block to take the test name as an optional argument. The entire test suite will be searched for the named test. This trick also saves us a recompile when we debug. When you use the BDD notation you can only have a single test subject (which is actually equivalent of a suite) in a single file because you can only have one `Describe()` macro in each file. But using this strategy you can create composite suites that takes all your tests and run them in one go. CAUTION: Rewrite pending. The next couple of sections does not reflect the current best thinking. They are remnants of the TDD notation. Using BDD notation you would create separate contexts, each in its own file, with separate names, for each of the fixture cases. NOTE: If you use the TDD (non-BDD) notation you can build several test suites in the same file, even nesting them. We can even add mixtures of test functions and test suites to the same parent test suite. Loops will give trouble, however. NOTE: If we do place several suites in the same file, then all the suites will be named the same in the breadcrumb trail in the test message. They will all be named after the function the create call sits in. If you want to get around this, or you just like to name your test suites, you can use `create_named_test_suite()` instead of `create_test_suite()`. This takes a single string parameter. In fact `create_test_suite()` is just a macro that inserts the `__func__` constant into `create_named_test_suite()`. What happens to `setup` and `teardown` functions in a `TestSuite` that contains other `TestSuite`:s? Well firstly, *Cgreen* does not `fork()` when running a suite. It leaves it up to the child suite to `fork()` the individual tests. This means that a `setup` and `teardown` will run in the main process. They will be run once for each child suite. We can use this to speed up our `Person` tests above. Remember we were creating a new connection and closing it again in the fixtures. This means opening and closing a lot of connections. At the slight risk of some test interference, we could reuse the connection accross tests... [source,c] ----------------------- ... static MYSQL *connection; static void create_schema() { mysql_query(connection, "create table people (name, varchar(255) unique)"); } static void drop_schema() { mysql_query(connection, "drop table people"); } Ensure(can_add_person_to_database) { ... } Ensure(cannot_add_duplicate_person) { ... } void open_connection() { connection = mysql_init(NULL); mysql_real_connect(connection, "localhost", "me", "secret", "test", 0, NULL, 0); } void close_connection() { mysql_close(connection); } TestSuite *person_tests() { TestSuite *suite = create_test_suite(); set_setup(suite, create_schema); set_teardown(suite, drop_schema); add_test(suite, can_add_person_to_database); add_test(suite, cannot_add_duplicate_person); TestSuite *fixture = create_named_test_suite("Mysql fixture"); add_suite(fixture, suite); set_setup(fixture, open_connection); set_teardown(fixture, close_connection); return fixture; } ----------------------- The trick here is creating a test suite as a wrapper whose sole purpose is to wrap the main test suite in the fixture. This is our 'fixture' pointer. This code is a little confusing, because we have two sets of fixtures in the same test script. We have the MySQL connection fixture. This will run `open_connection()` and `close_connection()` just once at the beginning and end of the person tests. This is because the `suite` pointer is the only member of `fixture`. We also have the schema fixture, the `create_schema()` and `drop_schema()`, which is run before and after every test. Those are still attached to the inner `suite`. In the real world we would probably place the connection fixture in its own file... [source,c] ----------------------- static MYSQL *connection; MYSQL *get_connection() { return connection; } static void open_connection() { connection = mysql_init(NULL); mysql_real_connect(connection, "localhost", "me", "secret", "test", 0, NULL, 0); } static void close_connection() { mysql_close(connection); } TestSuite *connection_fixture(TestSuite *suite) { TestSuite *fixture = create_named_test_suite("Mysql fixture"); add_suite(fixture, suite); set_setup(fixture, open_connection); set_teardown(fixture, close_connection); return fixture; } ----------------------- This allows the reuse of common fixtures across projects. == Mocking functions with Cgreen When testing you want certainty above all else. Random events destroy confidence in your test suite and force needless extra runs "to be sure". A good test places the system under test into a tightly controlled environment. A test chamber if you like. This makes the tests fast, repeatable and reliable. To create a test chamber for testing code, we have to control any outgoing calls from the code under test. We won't believe our test failure if our code is making calls to the internet for example. The internet can fail all by itself. Not only do we not have total control, but it also means we have to get dependent components working before we can test the higher level code. This makes it difficult to code top down. The solution to this dilemma is to write stub code for the components whilst the higher level code is written. This pollutes the code base with temporary code, and the test isolation disappears when the system is eventually fleshed out. The ideal is to have minimal stubs written for each individual test. *Cgreen* encourages this approach by making such tests easier to write. === The Problem with Streams How would we test the following code...? [source,c] ----------------------- include::tutorial_src/read_paragraph1.c[lines=4..-1] ----------------------- This is a fairly generic stream filter that turns the incoming characters into C string paragraphs. Each call creates one paragraph, returning a pointer to it or returning `NULL` if there is no paragraph. The paragraph has memory allocated to it and the stream is advanced ready for the next call. That's quite a bit of functionality, and there are plenty of nasty boundary conditions. I really want this code tested before I deploy it. The problem is the stream dependency. We could use a real stream, but that will cause all sorts of headaches. It makes the test of our paragraph formatter dependent on a working stream. It means we have to write the stream first, bottom up coding rather than top down. It means we will have to simulate stream failures - not easy. It will also mean setting up external resources. This is more work, will run slower, and could lead to spurious test failures. By contrast, we could write a simulation of the stream for each test, called a "server stub". For example, when the stream is empty nothing should happen. We hopefully get `NULL` from `read_paragraph` when the stream is exhausted. That is, it just returns a steady stream of `EOF`s. Fortunately, this function takes the stream as a parameter. This is called dependency injection and is a very important concept. Thanks to this we can write a small function, a stub, with the same signature, that simulates a real stream, and inject that instead of a real stream, which the production code probably does. NOTE: If the code does not inject the dependency this way we can often compile the stub separately and link with that instead the real stream. In this case your stub will have to have the same name as the original function, of course. (This is sometimes called the linkage seam.) [source,c] ----------------------- include::tutorial_src/stream_tests0.c[lines=6..22] ----------------------- Our simulation is easy here, because our fake stream returns only one value. Things are harder when the function result changes from call to call as a real stream would. Simulating this would mean messing around with static variables and counters that are reset for each test. And of course, we will be writing quite a few stubs. Often a different one for each test. That's a lot of clutter. *Cgreen* can handle this clutter for us by letting us write a single programmable function for all our tests. === Record and Playback We can redo our example by creating a `stream_stub()` function. We can call it anything we want, and since I thought we wanted to have a stubbed stream... [source,c] ----------------------- include::tutorial_src/stream_tests1.c[lines=6..8] ----------------------- Hardly longer that our trivial server stub above, it is just a macro to generate a return value, but we can reuse this in test after test. Let's see how. For our simple example above we just tell it to always return `EOF`... [source,c] ----------------------- include::tutorial_src/stream_tests1.c[lines=1..17] ----------------------- <1> The `always_expect()` macro takes the function name as an argument and also defines the return value using the call to `will_return()`. This is a declaration of an expectation of a call to the stub, and we have told our `stream_stub()` to always return `EOF` when called. Let's see if our production code actually works... ----------------------- include::tutorial_src/stream1.out[] ----------------------- So far, so good. On to the next test. If we want to test a one character line, we have to send the terminating `EOF` or `"\n"` as well as the single character. Otherwise our code will loop forever, giving an infinite line of that character. Here is how we can do this... [source,c] ----------------------- include::tutorial_src/stream_tests2.c[lines=19..25] ----------------------- Unlike the `always_expect()` instruction, `expect()` sets up an expectation of a single call and specifying `will_return()` sets the single return value for just that call. It acts like a record and playback model. Successive expectations map out the return sequence that will be given back once the test proper starts. We'll add this test to the suite and run it... ----------------------- include::tutorial_src/stream2.out[] ----------------------- Oops. Our code under test doesn't work. Already we need a fix... [source,c] ----------------------- include::tutorial_src/read_paragraph2.c[lines=4..19] ----------------------- <1> After moving the indexing here... <2> and here... around a bit everything is fine: ----------------------- include::tutorial_src/stream3.out[] ----------------------- So, how do the *Cgreen* stubs work? Each `expect()` describes one call to the stub and when a call to `will_return()` is included, the return values will be collected and returned in order as the expected calls arrive. The `mock()` macro captures the parameter names, their values and the `__func__` property (the name of the stub function). *Cgreen* can then use these to look up entries in the return list, and also to generate more helpful messages. We can now crank out our tests quite quickly... [source,c] ----------------------- include::tutorial_src/stream_tests3.c[lines=27..33] ----------------------- I've been a bit naughty. As each test runs in its own process, I haven't bothered to free the pointers to the paragraphs. I've just let the operating system do it. Purists may want to add the extra clean up code. I've also used `always_expect()` for the last instruction. Without this, if the stub is given an instruction it does not expect, it will throw a test failure. This is overly restrictive, as our `read_paragraph()` function could quite legitimately call the stream after it had run off of the end. OK, that would be odd behaviour, but that's not what we are testing here. If we were, it would be placed in a test of its own. The `always_expect()` call tells *Cgreen* to keep going after the first three letters, allowing extra calls. As we build more and more tests, they start to look like a specification of the wanted behaviour... [source,c] ----------------------- include::tutorial_src/stream_tests4.c[lines=35..41] ----------------------- ...and just for luck... [source,c] ----------------------- include::tutorial_src/stream_tests4.c[lines=43..46] ----------------------- This time we must not use `always_return()`. We want to leave the stream where it is, ready for the next call to `read_paragraph()`. If we call the stream beyond the line ending, we want to fail. Oops, that was a little too fast. Turns out we are failing anyway... ----------------------- include::tutorial_src/stream5.out[] ----------------------- Clearly we are passing through the line ending. Another fix later... [source,c] ----------------------- include::tutorial_src/read_paragraph3.c[lines=4..20] ----------------------- And we are passing again... ----------------------- include::tutorial_src/stream6.out[] ----------------------- There are no limits to the number of stubbed methods within a test, only that two stubs cannot have the same name. The following will cause problems... [source,c] ----------------------- include::tutorial_src/multiple_streams1.c[lines=10..-1] ----------------------- You __could__ program the same stub to return values for the two streams, but that would make a very brittle test. Since we'd be making it heavily dependent on the exact internal behaviour that we are trying to test, or test drive, it will break as soon as we change that implementation. The test will also become very much harder to read and understand. And we really don't want that. So, it will be necessary to have two stubs to make this test behave, but that's not a problem... [source,c] ----------------------- include::tutorial_src/multiple_streams2.c[lines=10..-1] ----------------------- We now have a way of writing fast, clear tests with no external dependencies. The information flow is still one way though, from stub to the code under test. When our code calls complex procedures, we won't want to pick apart the effects to infer what happened. That's too much like detective work. And why should we? We just want to know that we dispatched the correct information down the line. Things get more interesting when we think of the traffic going the other way, from code to stub. This gets us into the same territory as mock objects. === Setting Expectations on Mock Functions To swap the traffic flow, we'll look at an outgoing example instead. Here is the prewritten production code... [source,c] ----------------------- include::tutorial_src/stream.c[lines=23..32] ----------------------- This is the start of a formatter utility. Later filters will probably break the paragaphs up into justified text, but right now that is all abstracted behind the `void write(void *, char *)` interface. Our current interests are: does it loop through the paragraphs, and does it crash? We could test correct paragraph formation by writing a stub that collects the paragraphs into a `struct`. We could then pick apart that `struct` and test each piece with assertions. This approach is extremely clumsy in C. The language is just not suited to building and tearing down complex edifices, never mind navigating them with assertions. We would badly clutter our tests. Instead we'll test the output as soon as possible, right in the called function... [source,c] ----------------------- ... include::tutorial_src/formatter_tests0.c[lines=12..-1] ... ----------------------- By placing the assertions into the mocked function, we keep the tests minimal. The catch with this method is that we are back to writing individual functions for each test. We have the same problem as we had with hand coded stubs. Again, *Cgreen* has a way to automate this. Here is the rewritten test... [source,c] ----------------------- include::tutorial_src/formatter_tests1.c[lines=10..-1] ----------------------- Where are the assertions? Unlike our earlier stub, `reader()` can now check its parameters. In object oriented circles, an object that checks its parameters as well as simulating behaviour is called a mock object. By analogy `reader()` is a mock function, or mock callback. Using the `expect()` macro, we have set up the expectation that `writer()` will be called just once. That call must have the string `"a"` for the `paragraph` parameter. If the actual value of that parameter does not match, the mock function will issue a failure straight to the test suite. This is what saves us writing a lot of assertions. === Running Tests With Mocked Functions It's about time we actually ran our test... ----------------------- include::tutorial_src/formatter1.out[] ----------------------- Confident that a single character works, we can further specify the behaviour. Firstly an input sequence... [source,c] ----------------------- include::tutorial_src/formatter_tests2.c[lines=25..34] ----------------------- A more intelligent programmer than me would place all these calls in a loop. ------------------------- include::tutorial_src/formatter2.out[] ------------------------- Next, checking an output sequence... [source,c] ----------------------- include::tutorial_src/formatter_tests3.c[lines=36..-1] ----------------------- Again we can se that the `expect()` calls follow a record and playback model. Each one tests a successive call. This sequence confirms that we get `"a"`, `"b"` and `"c"` in order. ----------------------- include::tutorial_src/formatter3.out[] ----------------------- So, why the 5 passes? Each `expect()` with a constrait is actually an assert. It asserts that the call specified is actually made with the parameters given and in the specified order. In this case all the expected calls were made. Then we'll make sure the correct stream pointers are passed to the correct functions. This is a more realistic parameter check... [source,c] ----------------------- include::tutorial_src/formatter_tests4.c[lines=49..-1] ----------------------- ----------------------- include::tutorial_src/formatter4.out[] ----------------------- And finally we'll specify that the writer is not called if there is no paragraph. [source,c] ----------------------- include::tutorial_src/formatter_tests5.c[lines=56..-1] ----------------------- This last test is our undoing... ----------------------- include::tutorial_src/formatter5.out[] ----------------------- Obviously blank lines are still being dispatched to the `writer()`. Once this is pointed out, the fix is obvious... [source,c] ----------------------- include::tutorial_src/stream2.c[lines=23..-1] ----------------------- Tests with `never_expect()` can be very effective at uncovering subtle bugs. ----------------------- include::tutorial_src/formatter6.out[] ----------------------- All done. === Mocks Are... Using mocks is a very handy way to isolate a unit by catching and controlling calls to external units. Depending on your style of coding two schools of thinking have emerged. And of course *Cgreen* supports both! ==== Strict or Loose Mocks The two schools are thinking a bit differently about what mock expectations means. Does it mean that all external calls must be declared and expected? What happens if a call was made to a mock that wasn't expected? And vice versa, if an expected call was not made? Actually, the thinking is not only a school of thought, you might want to switch from one to the other depending on the test. So *Cgreen* allows for that too. By default *Cgreen* mocks are 'strict', which means that a call to an non-expected mock will be considered a failure. So will an expected call that was not fullfilled. You might consider this a way to define a unit through all its exact behaviours towards its neighbours. On the other hand, 'loose' mocks are looser. They allow both unfulfilled expectations and try to handle unexpected calls in a reasonable way. You can use both with in the same suite of tests using the call `cgreen_mocks_are(strict_mocks);` and `cgreen_mocks_are(loose_mocks);` respectively. Typically you would place that call at the beginning of the test, or in a setup or `BeforeEach()` if it applies to all tests in a suite. ==== Learning Mocks Working with legacy code and trying to apply TDD, BDD, or even simply adding some unit tests, is not easy. You're working with unknown code that does unknown things with unknown counterparts. So the first step would be to isolate the unit. We won't go into details on how to do that here, but basically you would replace the interface to other units with mocks. This is a somewhat tedious manual labor, but will result in an isolated unit where you can start applying your unit tests. Once you have your unit isolated in a harness of mocks, we need to figure out which calls it does to other units, now replaced by mocks, in the specific case we are trying to test. This might be complicated, so *Cgreen* can make that a bit simpler. There is a third 'mode' of the *Cgreen* mocks, the __learning mocks__. If you temporarily add the call `cgreen_mocks_are(learning_mocks);` at the beginning of your unit test, the mocks will record all calls and present a list of those calls in order, including the actual parameter values, on the standard output. So let's look at the following example from the *Cgreen* unit tests. It's a bit contorted since the test actually call the mocked functions directly, but I believe it will serve as an example. [source,c] ----- include::tutorial_src/learning_mocks.c[lines=8..-1] ----- We can see the call to `cgreen_mocks_are()` starting the test and setting the mocks into learning mode. If we run this, just as we usually run tests, the following will show up in our terminal: // This needs to be copied and pasted from the output of make in tutorial_src // At least, I couldn't make 'make' capture it into the output file // It ought to be: // include::tutorial_src/learning_mocks.out[] ---- Running "learning_mocks" (1 tests)... LearningMocks -> emit_pastable_code : Learned mocks are expect(string_out, when(p1, is_equal_to(1))); expect(string_out, when(p1, is_equal_to(2))); expect(integer_out); expect(integer_out); expect(string_out, when(p1, is_equal_to(3))); expect(integer_out); Completed "LearningMocks": 0 passes, 0 failures, 0 exceptions. Completed "learning_mocks": 0 passes, 0 failures, 0 exceptions. ---- If this was for real we could just copy this and paste it in place of the call to `cgreen_mocks_are()` and we have all the expectations done. NOTE: Before you can do this you need to implement the mock functions, of course. I.e. write functions that replaces the real functions and instead calls `mock()`. NOTE: If a test fails with an exception, you won't get the learned calls unfortunately. They are collected and printed at the end of the test. This might be improved at some future time. TIP: You can try the `cgreen-mocker` for this, as described in <>. == More on `expect()` and `mock()` === Important Things To Remember About `expect()` and `mock()` Using `expect()` and `mock()` is a very powerful way to isolate your code under test from its dependencies. But it is not always easy to follow what happens, and when. Here are some important things to remember when working with *Cgreen* mocks. - calls to `expect()` collects constraints and any other required information when it is called - this also goes for `will_return()` which will save the value of its parameter _when it is called_ - the actual evaluation and execution of those constraints occur when `mock()` is called in the function named in the `expect()` call(s) - calls to a function specified by the `expect()` calls are evaluated in the same order as the ``expect()``s were executed, but only for that named function - the lexical scope of the first parameter in a `when()` is always inside the mocked function where the `mock()` call is made - the lexical scope of arguments to an `is_equal_to...()` is where that call is made IMPORTANT: In summary, `expect()` does early collection, including evaluation of return value expression, and `mock()` does late evaluation of the constraints collected against the given arguments to `mock()`. [[refactoring-tests]] === Refactoring Tests with Mocks - CAUTION! After a while you are bound to get tests with calls to `expect()`. You might even have common patterns in multiple tests. So your urge to refactor starts to set in. And that is good, go with it, we have tests to rely on. But there are a lot of things going on behind the scenes when you use *Cgreen*, often with the help of some serious macro-magic, so special care needs to be taken when refactoring tests that have `expect()` in them. ==== Renaming The first "gotcha" is when you rename a function that you mock. You are likely to have `expect()`s for that function too. CAUTION: the function name in an `expect()` is "text" so it will not be catched by a refactoring tool. You will need to change the name there manually. ==== Local Variables For example, consider this code [source,c] ----------------------------- Ensure(Readline, can_read_some_characters) { char canned_a = 'a'; char canned_b = 'b'; char canned_c = 'c'; expect(mocked_read, will_set_contents_of_parameter(buf, &canned_a, sizeof(char)), will_return(1)); expect(mocked_read, will_set_contents_of_parameter(buf, &canned_b, sizeof(char)), will_return(1)); expect(mocked_read, will_set_contents_of_parameter(buf, &canned_c, sizeof(char)), will_return(1)); ... ... ----------------------------- It is very tempting to break out the common expect: [source,c] ----------------------------- static void expect_char(char ch) { expect(mocked_read, will_set_contents_of_parameter(buf, &ch, sizeof(char)), will_return(1)); } Ensure(Readline, can_read_some_characters) { char canned_a = 'a'; char canned_b = 'b'; char canned_c = 'c'; expect_char(canned_a); expect_char(canned_b); expect_char(canned_c); ... ... ----------------------------- Much nicer, right? This will most likely lead to a segmentation fault or illegal memory reference, something that can be really tricky to track down. The problem is that when `mocked_read()` is actually called, as an effect of calling something that calls `mocked_read()`, the parameter `ch` to the nicely extracted `expect_char()` does not exist anymore. Good thing that you run the tests after each and every little refactoring, right? Because then you know that it was the extraction you just did that was the cause. Then you can come here and read up on what the problem might be and what to do about it. At first glance the fix might look easy: [source,c] ----------------------------- static void expect_char(char ch) { char saved_ch = ch; expect(mocked_read, will_set_contents_of_parameter(buf, &saved_ch, sizeof(char)), will_return(1)); } Ensure(Readline, can_read_some_characters) { ... ----------------------------- Close! But the local variable is also gone at the call to `mocked_read()`. Of course. Ok, so let's make it static: [source,c] ----------------------------- static void expect_char(char ch) { static char saved_ch = ch; expect(mocked_read, will_set_contents_of_parameter(buf, &saved_ch, sizeof(char)), will_return(1)); } Ensure(Readline, can_read_some_characters) { ... ----------------------------- Ok, so then it must exist. But the problem then becomes the three consequtive calls to `expect_char()`. [source,c] ----------------------------- Ensure(Readline, can_read_some_characters) { char canned_a = 'a'; char canned_b = 'b'; char canned_c = 'c'; expect_char(canned_a); expect_char(canned_b); expect_char(canned_c); ... ... ----------------------------- Each of those have a different actual parameter, which is hard to store in one variable. Even if it is static. The solution is now quite obvious: [source,c] ----------------------------- static void expect_char(char *ch_p) { expect(mocked_read, will_set_contents_of_parameter(buf, ch_p, sizeof(char)), will_return(1)); } Ensure(Readline, can_read_some_characters) { char canned_a = 'a'; char canned_b = 'b'; char canned_c = 'c'; expect_char(&canned_a); expect_char(&canned_b); expect_char(&canned_c); ... ... ----------------------------- By using pointers to the variables in the test, we can ensure that the values are live when the expected call is made. So we don't have to make the character variables used in the test static, because as local variables those will remain live long enough. And this is the moral here, you cannot use local variables in an extracted function as data for a mocked function call. CAUTION: Variables that are to be sent to a mocked function MUST be live at the call to that mocked function. === Other Use Cases For Mocks ==== Out Parameters In C all function parameters are by value so if a function needs to return a value through a parameter that has to be done using a pointer. Typically this is a pointer to the area or variable the function should fill. *Cgreen* provides `will_set_contents_of_parameter()` to handle this use case. For example [source, c] ----------------------- include::tutorial_src/set_contents.c[lines=3..12] ... ----------------------- When the mock for `convert_to_uppercase()` is called it will write the string "UPPER CASE" in the area pointed to by `converted_string`. ==== Setting fields Sometimes you need to set a field in a struct sent by reference to a mocked function. You cannot use the `will_set_contents_of_parameter()` directly since you can't, or even don't want to, know the complete information in the structure. But with a little bit of boilerplate in your mock function you can still write to a single field. In the mock function you need to create a local variable that points to the field you want to update. You can then use this pointer variable in the mock call to supplement the real parameters. This local variable will then be accessible in `expect()` calls as if it was a parameter, and you can use it to wrote data to where it points, which then should be the field in the incoming structure. [source, c] ----------------------- include::tutorial_src/set_field.c[lines=3..18] ... ----------------------- The local variable `field` in the mock function is set to point to the field that we need to update. It is then exposed by including it in the `mock()` call, and `will_set_contents_of_parameter()` will use it to update whatever it points to with the data provided in the `expect()`. NOTE: Both the local variable and the data argument in the call to `will_set_contents_of_parameter()` must be pointers. You cannot use literals as data, except when it is a string literal which as per C convention is converted to a pointer. ==== Side Effects Sometimes returning simple values is not enough. The function that you want to mock might have some side effect, like setting a global error code, or aggregate some data. Let's assume that the `reader` increments a counter every time it gets called and we need to mimic that behaviour. There are many ways to do this, but here is one using the side effect feature. It works by calling a callback function that you provide, allowing you to feed some data to it. We create the "side effect function" which needs to take a single argument which should be a pointer to the "side effect data". You will have to cast that datapointer to the correct type. [source, c] ----------------------- include::tutorial_src/side_effect.c[lines=29..44] ----------------------- === The Mock Macros When specifying behavior of mocks there are three parts. First, how often the specified behaviour or expectation will be executed: |======================================================================= |*Macro* |*Description* |`expect(function, ...)` |Expected once, in the specified order, for the same function |`always_expect(function, ...)`|Expect this behavior from here onwards |`never_expect(function)` |From this point this mocked function must never be called |======================================================================= You can specify constraints and behaviours for each expectation (except for `never_expect()` naturally). A constraint places restrictions on the parameters (and will tell you if the expected restriction was not met), and a behaviour specifies what the mock should do if the parameter constraints are met. A parameter constraint is defined using the `when(parameter, constraint)` macro. It takes two parameters: |================================================= |*Parameter* |*Description* |`parameter` |The name of the parameter to the mock function |`constraint`|A constraint placed on that parameter |================================================= There is a multitude of constraints available (actually, exactly the same as for the assertions we saw earlier): |========================================================================== |*Constraint* |*Type* |`is_equal_to(value)` | Integers |`is_not_equal_to(value)` | Integers |`is_greater_than(value)` | Integers |`is_less_than(value)` | Integers | | |`is_equal_to_contents_of(pointer, size_of_contents)` |Bytes/Structures |`is_not_equal_to_contents_of(pointer, size_of_contents)` |Bytes/Structures || |`is_equal_to_string(value)` |String |`is_not_equal_to_string(value)` |String |`contains_string(value)` |String |`does_not_contain_string(value)` |String |`begins_with_string(value)` |String || |`is_equal_to_double(value)` |Double |`is_not_equal_to_double(value)` |Double |`is_less_than_double(value)` |Double |`is_greater_than_double(value)` |Double |========================================================================== For the double valued constraints you can set the number of significant digits to consider a match with a call to `significant_figures_for_assert_double_are(int figures)`. The <> has a more detailed discussion of the algorithm used for comparing floating point numbers. Then there are a couple of ways to return results from the mocks. They all provide ways to return various types of values through `mock()`. In your mocked function you can then simply return that value, or manipulate it as necessary. |=========================================================================================== |*Macro* |*`mock()` will...* |`will_return(value)` | return `value`, for integer types |`will_return_double(value)` | return `value` as a "boxed double", for double floats (required because of C's type coercion rules which would otherwise convert a double into an int) |`will_return_by_value(struct, size)` | return a pointer to an allocated copy of the `struct` that can be copied and returned by value from the mocked function |`will_set_contents_of_parameter(parameter_name, pointer_to_value, size)`| write `size` bytes from the pointed out value (`pointer_to_value`) into where the referenced out parameter (`parameter_name`) is pointing |`will_capture_parameter(parameter_name, local_variable)` |capture the value of the parameter and store it in the named local variable |`with_side_effect(function, pointer_to_data)` | call the side effect `function` and pass `pointer_to_data` to it |=========================================================================================== NOTE: *`will_return_double()`*: The "boxed double" returned by `mock()` have to be "unboxed" by the caller see <> for details. NOTE: *`will_return_by_value`*: The memory allocated for the copy of the struct returned by `mock()` needs to be deallocated by the caller or it will be lost. You can do this with the code in the `Box` example below. NOTE: *`will_set_contents_of_parameter`*: The data to set must be correct at the time of the call to the mock function, and not be overwritten or released between the call to the `expect()` and the mock function. See <> for details. NOTE: *`will_capture_parameter`*: The local variable to capture the value in must be live at the time of the call to the mock function, so using a local variable in a function called by your test will not work. See <> for details. === Combining Expectations You can combine the expectations for a `mock()` in various ways: [source,c] ----------------------- expect(mocked_file_writer, when(data, is_equal_to(42)), will_return(EOF)); expect(mocked_file_reader, when(file, is_equal_to_contents_of(&FD, sizeof(FD))), when(input, is_equal_to_string("Hello world!"), with_side_effect(&update_counter, &counter), will_set_contents_of_parameter(status, FD_CLOSED, sizeof(bool)))); ----------------------- If multiple `when()` are specified they all need to be fullfilled. You can of course only have one for each of the parameters of your mock function. You can also have multiple `will_set_contents_of_parameter()` in an expectation, one for each reference parameter, but naturally only one `will_return()`. To ensure that a specific call happens `n` times the macro `times(number_times_called)` can be passed as a constraint to a specific call: [source,c] ----------------------- expect(mocked_file_writer, when(data, is_equal_to(42)), times(1)); ----------------------- This feature only works for `expect()`. === Order of constraints When you have multiple constraints in an `expect` the order in which they are executed is not always exactly then order in which they where given. First all constraints are inspected for validity, such as if the parameter name given cannot be found, but primarily to see if the parameters, if any, matche the actual parameters in the call. Then all read-only constraints are processed, followed by constraints that set contents. Finally all side effect constraints are executed. === Order of multiple `expect`s The expections still need to respect the order of calling, so if we call the function `mocker_file_writer` with the following pattern: [source,c] ----------------------- mocked_file_writer(42); mocked_file_writer(42); mocked_file_writer(43); mocked_file_writer(42); ----------------------- The expectation code should look like the following [source,c] ----------------------- expect(mocked_file_writer, when(data, is_equal_to(42)), times(2)); expect(mocked_file_writer, when(data, is_equal_to(43)), times(1)); expect(mocked_file_writer, when(data, is_equal_to(42)), times(1)); ----------------------- === Returning `struct` If the function we are mocking returns structs by value, then our mock function need to do that too. To do this we must use specific return macro, `will_return_by_value()`. Below is some example code using an imaginary struct typedef'ed as `Struct` and a corresponding function, `retrieve_struct()`, which we want to mock. The underlying mechanism of this is that in the test we create the struct that we want to return. The macro `will_return_by_value()` then copies that to a dynamically allocated area, saving it so that a pointer to that area can be returned by `mock()`. [source,c] ----------------------- Struct returned_struct = {...}; expect(retrieve_struct, will_return_by_value(returned_struct, sizeof(Struct)); /* `returned_struct` has been copied to an allocated area */ ----------------------- NOTE: In some future version the `size` argument will be removed from `will_return_by_value()` size since the macro can easily calculate that for you. The mock function will then look like this: [source,c] ----------------------- Struct retrieve_struct() { return *(Struct *)mock(); /* De-reference the returned pointer to the allocated area */ } ----------------------- This would cause a memory leak since the area allocated by the `return_by_value()` macro is not deallocated. And in many scenarious this might not be a big problem, and you could make do with that simple version. In case we wanted to be sure, we should free the area automatically allocated by `will_return_by_value()`. The pointer returned by `mock()` will point to that area. So, here's a better, although slightly more complicated, version: [source,c] ----------------------- Struct retrieve_struct() { Struct *struct_p = (Struct *)mock(); /* Get the pointer */ Struct the_struct = *struct_p; /* Dereference to get a struct */ free(struct_p); /* Deallocate the returned area */ return the_struct; /* Finally we can return the struct by value */ } ----------------------- === Mocking `struct` Parameters Modern C standards allows function parameters to be ``struct``s by value. Since our `mock()` only can handle scalar values this presents a bit of a conundrum. [source,c] ----------------------- include::tutorial_src/struct_parameters.c[lines=11..18] ----------------------- And we also can not compare a non-scalar value with any of the `is_equal_to...()` constraint macros in the `expect()` call. Also remember that the C language does not allow comparing non-scalar values using `==`. There are a couple of ways to handle this and which one to select depends on what you want to do. ==== Checking Single `struct` Fields In an `expect(when())` we probably want to check one, or more, of the fields in the struct. Since `mock()` actually can "mock" anything we can use a normal field expression to access the value we want to check: [source,c] ----------------------- include::tutorial_src/struct_parameters.c[lines=26..28] ----------------------- The trick here is that `mock()` just saves the "name", as a string, given as the argument, in this case "s.i", and pair it with the value of that expression. There is no requirement that the "name" is actually a parameter, it can be anything. The only thing to remember is that the exact same string needs to be used when invoking `when()`: [source,c] ----------------------- include::tutorial_src/struct_parameters.c[lines=35..36] ----------------------- You can do this with as many fields as you need. And there is no (reasonable) limit to how many arguments `mock()` can take, so you can start with the ones that you require and add more as you need them. [source,c] ----------------------- include::tutorial_src/struct_parameters.c[lines=42..55] ----------------------- NOTE: In both example we use an explicit value in `will_return()` instead of the value of the field, "s.i". That is because it is not possible to use the value of a mocked value in `will_return()`. Remember, `expect()` does early collection. At the time of executing it, there is no parameter available, so the value must come from that run-time environment. Also, since we already explicitly know the value, we have to use it in the `when()` clause, there will be no uncertainty of what it should be. The only concern might be duplication of an explicit value, but that is not a big problem in a unittest, clarity over DRY, and you can easily fix that with a suitably named local variable. === Capturing Parameters TBD. == Special Cases === Working with `doubles` We are not talking about http://www.hostettler.net/blog/2014/05/18/fakes-stubs-dummy-mocks-doubles-and-all-that/[test doubles] here, but about values of C/C++ ``double`` type (a.k.a double float.) *Cgreen* is designed to make it easy and natural to write assertions and expectations. Many functions can be used for multiple data types, e.g. `is_equal_to()` applies to all integer type values, actually including pointers. But the C language has its quirks. One of them is the fact that it is impossible to inspect the datatypes of values during run-time. This has e.g. forced the introduction of `is_equal_to_string()` to enable string comparisons. ==== Assertions and Constraints When it comes to double typed values this has spilled over even further. For double typed values we have |========================================================================== | *Constraint* | `is_equal_to_double(value)` | `is_not_equal_to_double(value)` | `is_less_than_double(value)` | `is_greater_than_double(value)` |========================================================================== But there is also the special assert that you must use when asserting doubles |========================================================= | *Assertion* | `assert_that_double(expected, constraint)` |========================================================= and the utility function |==================== | *Utility* | `significant_figures_for_assert_double_are(int figures)` |==================== And of course they are designed to go together. So, if you want to assert an expression yeilding a `double` typed value, you need to combine them: [source,c] ----------------------------- include::tutorial_src/double_tests1.c[lines=11..14] ----------------------------- NOTE: You have to use `assert_that_double()` and `is_equal_to_double()` together. and you would get ----------------------------- include::tutorial_src/double1.out[lines=2..5] ----------------------------- [[double_mocks]] ==== Double Mocks The general mechanism *Cgreen* uses to transport values to and from mock functions is based on the simple idea that most types fit into a "large" integer and can be type converted to and from whatever type you need. Since a `double float` will not fit into the same memory space as an integer *Cgreen* handles that by encapsulating ("boxing") the `double` into an area which is represented by the pointer to it. And that pointer can fit into the integer type value (`intptr_t`) that *Cgreen* uses to transport values into and out of `mock()`. To get the value back you "unbox" it. There are two possible uses of `double` that you need to be aware of 1. When a parameter to the mocked function is of `double` type and needs to be matched in an constraint in an `expect()` call. 2. When the mock function itself should return a `double` type value. In the test you should use the special `double` type constraints and the `will_return_double()` convenience function. In the mock function you will have to take care to box and unbox as required. |================================================================= |*Boxing and unboxing in mock functions* | *Description* | `box_double(double value)` | Wrap the value in an allocated memory area and return a pointer to it | `unbox_double(BoxedDouble *box)` | Unwrap the value by freeing the area and returning the value |================================================================= Here's an example of that: [source,c] ----------------------------- include::tutorial_src/double_tests1.c[lines=16..26] ----------------------------- <1> We can see that the parameter `d` to the mock function, since it is a `double`, it will have to be used as `box_double(d)` in the call to `mock()`. <2> The corresponding `expect()` uses a double constraint. <3> The mock function in this small example also returns a `double`. The `expect()` uses `will_return_double()` so the mock function needs to unbox the return value from `mock()` to be able to return the `double` type value. NOTE: Strange errors may occur if you box and/or unbox or combine `double` constraints incorrectly. [[floating_point_comparison_algorithm]] ==== Details of Floating Point Comparison Algorithm The number of significant digits set with `significant_figures_for_assert_double_are()` specifies a _relative_ tolerance. Cgreen considers two double precision numbers +x+ and +y+ equal if their difference normalized by the larger of the two is smaller than +10^(1 - significant_figures)^+. Mathematically, we check that +|x - y| < max(|x|, |y|) * 10^(1 - significant_figures)^+. Well documented subtleties arise when comparing floating point numbers close to zero using this algorithm. The article https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/[Comparing Floating Point Numbers, 2012 Edition] by Bruce Dawson has an excellent discussion of the issue. The essence of the problem can be appreciated if we consider the special case where +y == 0+. In that case, our condition reduces to +|x| < |x| * 10^(1 - significant_figures)^+. After cancelling +|x|+ this simplifies to +1 < 10^(1 - significant_figures)^+. But this is only true if +significant_figures < 1+. In words this can be summarized by saying that, in a relative sense, _all_ numbers are very different from zero. To circumvent this difficulty we recommend to use a constraint of the following form when comparing numbers close to zero: [source,c] ----------------------- assert_that(fabs(x - y) < abs_tolerance); ----------------------- === Using Cgreen with C{pp} The examples in this guide uses the C langauge to shows how to use *CGreen*. You can also use *CGreen* with C++. NOTE: The following needs expansion and more details as the support for C++ is extended. All you have to do is * Use the `cgreen` namespace by adding `using namespace cgreen;` at the beginning of the file with your tests There is also one extra feature when you use C++, the `assert_throws` function. NOTE: If you use the autodiscovering runner, as described in <>, and thus link your tests into a shared library, don't forget to link it with the same C++ library that was used to create the `cgreen-runner`. == Context, System Under Test & Suites As mentioned earlier, *Cgreen* promotes the behaviour driven style of test driving code. The thinking behind BDD is that we don't really want to test anything, if we just could specify the behaviour of our code and ensure that it actually behaves this way we would be fine. This might seem like an age old dream, but when you think about it, there is actually very little difference in the mechanics from vanillla TDD. First we write how we want it, then implement it. But the small change in wording, from `test´ to `behaviour´, from `test that´ to `ensure that´, makes a huge difference in thinking, and also very often in quality of the resulting code. === The SUT - System Under Test Since BDD talks about behaviour, there has to be something that we can talk about as having that wanted behaviour. This is usually called the SUT, the System Under Test. The "system" might be whatever we are testing, such as a C module ("MUT"), class ("CUT"), object ("OUT"), function ("FUT") or method ("MUT"). We will stick with SUT in this document. To use *Cgreen* in BDD-ish mode you must define a name for it. [source, c] ----------------------- #include Describe(SUT); ----------------------- *Cgreen* supports C++ and there you naturally have the objects and also the Class Under Test. But in plain C you will have to think about what is actually the "class" under test. E.g. in `sort_test.c` you might see [source, c] --------------------- #include Describe(Sorter); Ensure(Sorter, can_sort_an_empty_list) { assert_that(sorter(NULL), is_null); } --------------------- In this example you can clearly see what difference the BDD-ish style makes when it comes to naming. Convention, and natural language, dictates that typical names for what TDD would call tests, now starts with 'can' or 'finds' or other verbs, which makes the specification so much easier to read. Yes, I wrote 'specification'. Because that is how BDD views what TDD basically calls a test suite. The suite specifies the behaviour of a `class´. (That's why some BDD frameworks draw on 'spec', like *RSpec*.) === Contexts and Before and After The complete specification of the behaviour of a SUT might become long and require various forms of setup. When using TDD style you would probably break this up into multiple suites having their own `setup()` and `teardown()`. With BDD-ish style we could consider a suite as a behaviour specification for our SUT 'in a particular context'. E.g. [source, c] ------------------------ #include Describe(shopping_basket_for_returning_customer); Customer *customer; BeforeEach(shopping_basket_for_returning_customer){ customer = create_test_customer(); login(customer); } AfterEach(shopping_basket_for_returning_customer) { logout(customer); destroy_customer(customer); } Ensure(shopping_basket_for_returning_customer, allows_use_of_discounts) { ... } ------------------------ The 'context' would then be `shopping_basket_for_returning_customer`, with the SUT being the shopping basket 'class'. So 'context', 'system under test' and 'suite' are mostly interchangable concepts in *Cgreen* lingo. It's a named group of 'tests' that share the same `BeforeEach` and `AfterEach` and lives in the same source file. [[auto-discovery]] == Automatic Test Discovery === Forgot to Add Your Test? When we write a new test we focus on the details about the test we are trying to write. And writing tests is no trivial matter so this might well take a lot of brain power. So, it comes as no big surprise, that sometimes you write your test and then forget to add it to the suite. When we run it it appears that it passed on the first try! Although this *should* really make you suspicious, sometimes you get so happy that you just continue with churning out more tests and more code. It's not until some (possibly looong) time later that you realize, after much headache and debugging, that the test did not actually pass. It was never even run! There are practices to minimize the risk of this happening, such as always running the test as soon as you can set up the test. This way you will see it fail before trying to get it to pass. But it is still a practice, something we, as humans, might fail to do at some point. Usually this happens when we are most stressed and in need of certainty. === The Solution - the 'cgreen-runner' *Cgreen* gives you a tool to avoid not only the risk of this happening, but also the extra work and extra code. It is called the `cgreen-runner`. The `cgreen-runner` should come with your *Cgreen* installation if your platform supports the technique that is required, which is 'programatic access to dynamic loading of libraries'. This means that a program can load an external library of code into memory and inspect it. Kind of self-inspection, or reflexion. So all you have to do is to build a dynamically loadable library of all tests (and of course your objects under test and other necessary code). Then you can run the `cgreen-runner` and point it to the library. The runner will then load the library, enumerate all tests in it, and run every test. It's automatic, and there is nothing to forget. [[runner]] === Using the Runner Assuming your tests are in `first_test.c` the typical command to build your library using `gcc` would be -------------------------- $ gcc -shared -o first_test.so -fPIC first_test.c -lcgreen -------------------------- The `-fPIC` means to generate 'position independent code' which is required if you want to load the library dynamically. To explicitly state this is required on many platforms. How to build a dynamically loadable shared library might vary a lot depending on your platform. Can't really help you there, sorry! As soon as we have linked it we can run the tests using the `cgreen-runner` by just giving it the shared, dynamically loadable, object library as an argument: ------------------------- $ cgreen-runner first_test.so include::tutorial_src/runner1.out[] ------------------------- More or less exactly the same output as when we ran our first test in the beginning of this quickstart tutorial. We can see that the top level of the tests will be named as the library it was discovered in, and the second level is the context for our System Under Test, in this case 'Cgreen'. We also see that the context is mentioned in the failure message, giving a fairly obvious `Cgreen -> fails_this_test`. Now we can actually delete the main function in our source code. We don't need all this, since the runner will discover all tests automatically. [source,c] ------------------------ include::tutorial_src/first_tests1.c[lines=15..20] ------------------------ It always feel good to delete code, right? We can also select which test to run: ------------------------- $ cgreen-runner first_test.so Cgreen:this_test_should_fail include::tutorial_src/runner2.out[] ------------------------- We recommend the BDD notation to discover tests, and you indicate which context the test we want to run is in. In this example it is `Cgreen` so the test should be refered to as `Cgreen:this_test_should_fail`. If you don't use the BDD notation there is actually a context anyway, it is called `default`. [[runner-options]] === Cgreen Runner Options Once you get the build set up right for the cgreen-runner everything is fairly straight-forward. But you have a few options: --xml :: Instead of messages on stdout with the TextReporter, write results into one XML-file per suite or context, compatible with Hudson/Jenkins CI. The filename(s) will be `-.xml` --suite :: Name the top level suite --no-run:: Don't run the tests --verbose:: Show progress information and list discovered tests --colours:: Use colours (or colors) to emphasis result (requires ANSI-capable terminal) --quiet:: Be more quiet The `verbose` option is particularly handy since it will give you the actual names of all tests discovered. So if you have long test names you can avoid mistyping them by copying and pasting from the output of `cgreen-runner --verbose`. It will also give the mangled name of the test which should make it easier to find in the debugger. Here's an example: ------------------------ include::tutorial_src/runner3.out[] ------------------------ === Selecting Tests To Run You can name a single test to be run by giving it as the last argument on the command line. The name should be in the format `:`. If not obvious you can get that name by using the `--verbose` command option which will show you all tests discovered and both there C/C++ and Cgreen names. Copying the Cgreen name from that output is an easy way to run only that particular test. When a single test is named it is run using `run_single_test()`. As described in <> this means that it is __not__ protected by `fork()`-ing it to run in its own process. The `cgreen-runner` supports selecting tests with limited pattern matching. Using an asterisk as a simple 'match many' symbol you can say things like -------------------- $ cgreen-runner Cgreen:* $ cgreen-runner C*:*this* -------------------- === Multiple Test Libraries You can run tests in multiple libraries in one go by adding them to the `cgreen-runner` command: ----------------------- $ cgreen-runner first_set.so second_set.so ... ----------------------- === Setup, Teardown and Custom Reporters The `cgreen-runner` will only run setup and teardown functions if you use the BDD-ish style with `BeforeEach()` and `AfterEach()` as described above. The runner does not pickup `setup()` and `teardown()` added to suites, because it actually doesn't run suites. It discovers all tests and runs them one by one. The macros required by the BDD-ish style ensures that the corresponding `BeforeEach()` and `AfterEach()` are run before and after each test. CAUTION: The `cgreen-runner` __will__ discover your tests in a shared library even if you don't use the BDD-ish style. But it will not be able to find and run the `setup()` and/or `teardown()` attached to your suite(s). This will probably cause your tests to fail or crash. In case you have non-BDD style tests __without__ any `setup()` and/or `teardown()` you can still use the runner. The default suite/context where the tests live in this case is called `default`. But why don't you convert your tests to BDD notation? This removes the risk of frustrating trouble-shooting when you added `setup()` and `teardown()` and can't understand why they are not run... So, the runner encourages you to use the BDD notation. But since we recommend that you do anyway, that's no extra problem if you are starting out from scratch. But see <> for some easy tips on how to get you there if you already have non-BDD tests. You can choose between the TextReporter, which we have been seeing so far, and the built-in JUnit/Ant compatible XML-reporter using the `--xml` option. But it is not currently possible to use custom reporters as outlined in <> with the runner. If you require another custom reporter you need to resort to the standard, programatic, way of invoking your tests. For now... [[xensure]] === Skipping Tests Sometimes you find that you need to temporarily remove a test, perhaps to do a refactoring when you have a failing test. Ignoring that test will allow you to do the refactoring while still in the green. An old practice is then to comment it out. That is a slightly cumbersome. It is also hazardous habit as there is no indication of a missing test if you forget to uncomment it when you are done. *Cgreen* offers a much better solution. You can just add an 'x' infront of the `Ensure` for the test and that test will be skipped. [source, C] ---------------------------- ... xEnsure(Reader, ...) { ... } ... ---------------------------- With this method, it is a one character change to temporarily ignore, and un-ignore, a test. It is also easily found using text searches through a complete source tree. *Cgreen* will also tally the skipped tests, so it is clearly visible that you have some skipped test when you run them. [[changing_style]] == Changing Style If you already have some TDD style *Cgreen* test suites, it is quite easy to change them over to BDD-ish style. Here are the steps required * Add `Describe(SUT);` * Turn your current setup function into a `BeforeEach()` definition by changing its signature to match the macro, or simply call the existing setup function from the BeforeEach(). If you don't have any setup function you still need to define an empty `BeforeEach()`. * Ditto for `AfterEach()`. * Add the SUT to each `Ensure()` by inserting it as a first parameter. * Change the call to add the tests to `add_test_with_context()` by adding the name of the SUT as the second parameter. * Optionally remove the calls to `set_setup()` and `set_teardown()`. Done. If you want to continue to run the tests using a hand-coded runner, you can do that by keeping the setup and teardown functions and their corresponding `set_`-calls. It's nice that this is a simple process, because you can change over from TDD style to BDD-ish style in small steps. You can convert one source file at a time, by just following the recipe above. Everything will still work as before but your tests and code will likely improve. And once you have changed style you can fully benefit from the automatic discovery of tests as described in <>. [[reporter]] == Changing Cgreen Reporting Replacing the Reporter ~~~~~~~~~~~~~~~~~~~~~~ In every test suite so far, we have run the tests with this line... [source,c] ----------------------- return run_test_suite(our_tests(), create_text_reporter()); ----------------------- We can change the reporting mechanism just by changing this call to create another reporter. [[builtin_reporters]] === Built-in Reporters *Cgreen* has the following built-in reporters that you can choose from when your code runs the test suite. [options="header", cols=4] [options="header", cols=4] |==================================================================================== | Reporter | Purpose | Signature | Note | Text | Human readable, with clear messages | `create_text_reporter(void)` | | XML | ANT/Jenkins compatible | `create_xml_reporter(const char *file_prefix)` | `file_prefix` is the prefix of the XML files generated. | CUTE | CUTE Eclipse-plugin (http://cute-test.org) compatible output | `create_cute_reporter(void)` | | CDash | CMake (http://cmake.org) dashboard | `create_cdash_reporter(CDashInfo *info)` | `info` is a structure defined in `cdash_reporter.h` |==================================================================================== If you write a runner function like in most examples above, you can just substitute which runner to create. If you use the `cgreen-runner` (<>) to dynamically find all your tests you can force it to use the XML-reporter with the `-x ` option. NOTE: Currently `cgreen-runner` only supports the built-in text and XML reporters. === Rolling Our Own Although *Cgreen* has a number of options, there are times when you'd like a different output from the reporter, the CUTE and CDash reporters are examples that grew out of such a need. Perhaps your Continuous Integration server want the result in a different format, or you just don't like the text reporter... Writing your own reporter is supported. And we'll go through how that can be done using an XML-reporter as an example. NOTE: *Cgreen* already has an XML-reporter compatible with ANT/Jenkins, see <>. Here is the code for `create_text_reporter()`... [source,c] ----------------------- TestReporter *create_text_reporter(void) { TestReporter *reporter = create_reporter(); if (reporter == NULL) { return NULL; } reporter->start_suite = &text_reporter_start_suite; reporter->start_test = &text_reporter_start_test; reporter->show_fail = &show_fail; reporter->show_skip = &show_skip; reporter->show_incomplete = &show_incomplete; reporter->finish_test = &text_reporter_finish_test; reporter->finish_suite = &text_reporter_finish; return reporter; } ----------------------- The `TestReporter` structure contains function pointers that control the reporting. When called from `create_reporter()` constructor, these pointers are set up with functions that display nothing. The text reporter code replaces these with something more dramatic, and then returns a pointer to this new object. Thus the `create_text_reporter()` function effectively extends the object from `create_reporter()`. The text reporter only outputs content at the start of the first test, at the end of the test run to display the results, when a failure occurs, and when a test fails to complete. A quick look at the `text_reporter.c` file in *Cgreen* reveals that the overrides just output a message and chain to the versions in `reporter.h`. To change the reporting mechanism ourselves, we just have to know a little about the methods in the `TestReporter` structure. === The TestReporter Structure The *Cgreen* `TestReporter` is a pseudo class that looks something like... [source,c] ----------------------- typedef struct _TestReporter TestReporter; struct _TestReporter { void (*destroy)(TestReporter *reporter); void (*start_suite)(TestReporter *reporter, const char *name, const int count); void (*start_test)(TestReporter *reporter, const char *name); void (*show_pass)(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments); void (*show_skip)(TestReporter *reporter, const char *file, int line); void (*show_fail)(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments); void (*show_incomplete)(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments); void (*assert_true)(TestReporter *reporter, const char *file, int line, int result, const char * message, ...); void (*finish_test)(TestReporter *reporter, const char *file, int line); void (*finish_suite)(TestReporter *reporter, const char *file, int line); int passes; int failures; int exceptions; void *breadcrumb; int ipc; void *memo; void *options; }; ----------------------- The first block are the methods that can be overridden: `void (*destroy)(TestReporter *reporter)`:: This is the destructor for the default structure. If this is overridden, then the overriding function must call `destroy_reporter(TestReporter *reporter)` to finish the clean up. `void (*start_suite)(TestReporter *reporter, const char *name, const int count)`:: This is the first of the callbacks. At the start of each test suite *Cgreen* will call this method on the reporter with the name of the suite being entered and the number of tests in that suite. The default version keeps track of the stack of tests in the `breadcrumb` pointer of `TestReporter`. If you make use of the breadcrumb functions, as the defaults do, then you will need to call `reporter_start_suite()` to keep the book-keeping in sync. `void (*start_test)(TestReporter *reporter, const char *name)`:: At the start of each test *Cgreen* will call this method on the reporter with the name of the test being entered. Again, the default version keeps track of the stack of tests in the `breadcrumb` pointer of `TestReporter`. If you make use of the breadcrumb functions, as the defaults do, then you will need to call `reporter_start_test()` to keep the book-keeping in sync. `void (*show_pass)(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments)`:: This method is initially empty as most reporters see little point in reporting passing tests (but you might do), so there is no need to chain the call to any other function. Besides the pointer to the reporter structure, *Cgreen* also passes the file name of the test, the line number of failed assertion, the message to show and any additional parameters to substitute into the message. The message comes in as `printf()` style format string, and so the variable argument list should match the substitutions. `void (*show_fail)(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments)`:: The partner of `show_pass()`, and the one you'll likely overload first. `void (*show_skip)(TestReporter *reporter, const char *file, int line)`:: This method will be called when a skipped test is encountered, see <>. `void (*show_incomplete)(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments)`:: When a test fails to complete, this is the handler that is called. As it's an unexpected outcome, no message is received, but we do get the name of the test. The text reporter combines this with the breadcrumb to produce the exception report. `void (*assert_true)(TestReporter *reporter, const char *file, int line, int result, const char * message, ...)`:: This is not normally overridden and is really internal. It is the raw entry point for the test messages from the test suite. By default it dispatches the call to either `show_pass()` or `show_fail()`. `void (*finish_test)(TestReporter *reporter, const char *file, int line)`:: The counterpart to the `(*start_test)()` call. It is called on leaving the test. It needs to be chained to the `reporter_finish()` to keep track of the breadcrumb book keeping. `void (*finish_suite)(TestReporter *reporter, const char *file, int line)`:: The counterpart to the `(*start_suite)()` call called on leaving the test suite, and similar to the `(*finish_test)()` if your reporter needs a handle on that event too. The default text reporter chains both this and `(*finish_test)()` to the same function where it figures out if it is the end of the top level suite. If so, it prints the familiar summary of passes and fails. NOTE: The `show_fail()` and `show_pass()` functions are called from the child process, i.e. the isolated process that is `fork()`:ed to run a single test case. All others, notably `start_...()`, `finish_...()`, `show_incomplete()` and `show_skip()` are run in the main (parent) process. This fact might be important since the processes do not share memory. Information is passed from the child to the parent using messaging performed within the `show_...()` functions. The second block is simply resources and book keeping that the reporter can use to liven up the messages... [horizontal] `passes`:: The number of passes so far. `skips`:: The number of tests that has been skipped by the `xEnsure` mechanism (see <>) `failures`:: The number of failures generated so far. `exceptions`:: The number of test functions that have failed to complete so far. `breadcrumb`:: This is a pointer to the list of test names in the stack. The `breadcrumb` pointer is different and needs a little explanation. Basically it is a stack, analogous to the breadcrumb trail you see on websites. Everytime a `start()` handler is invoked, the name is placed in this stack. When a `finish()` message handler is invoked, a name is popped off. There are a bunch of utility functions in `cgreen/breadcrumb.h` that can read the state of this stack. Most useful are `get_current_from_breadcrumb()` which takes the breadcrumb pointer and returns the current test name, and `get_breadcrumb_depth()` which gives the current depth of the stack. A depth of zero means that the test run has finished. If you need to traverse all the names in the breadcrumb, then you can call `walk_breadcrumb()`. Here is the full signature... [source,c] ----------------------- void walk_breadcrumb(Breadcrumb *breadcrumb, void (*walker)(const char *, void *), void *memo); ----------------------- The `void (*walker)(const char *, void *)` is a callback that will be passed the name of the test suite for each level of nesting. It is also passed the `memo` pointer that was passed to the `walk_breadcrumb()` call. You can use this pointer for anything you want, as all *Cgreen* does is pass it from call to call. This is so aggregate information can be kept track of whilst still being reentrant. The last parts of the `TestReporter` structure are... [horizontal] `ipc`:: This is an internal structure for handling the messaging between reporter and test suite. You shouldn't touch this. `memo`:: By contrast, this is a spare pointer for your own expansion. `options`:: A pointer to a reporter specific structure that can be used to set options. E.g. the textreporter defines the structure `TextReporterOptions` which can be used by calling code to define the use of colors when printing passes and failures. You set it with `set_reporter_options(*void)`. === An Example XML Reporter Let's make things real with an example. Suppose we want to send the output from *Cgreen* in XML format, say for storing in a repository or for sending across the network. NOTE: The `cgreen-runner` already has an XML-reporter that you can use if you need to produce Jenkins/ANT compatible XML output. See <>. Suppose also that we have come up with the following format... [source,xml] ----------------------- A failure ----------------------- In other words a simple nesting of tests with only failures encoded. The absence of "fail" XML node is a pass. Here is a test script, `test_as_xml.c` that we can use to construct the above output... [source,c] ----------------------- include::tutorial_src/test_as_xml0.c[] ----------------------- We can't use the auto-discovering `cgreen-runner` (see <>) here since we need to ensure that the nested suites are reported as a nested xml structure. And we're not actually writing real tests, just something that we can use to drive our new reporter. The text reporter is used just to confirm that everything is working. So far it is. ----------------------- include::tutorial_src/test_as_xml0.out[] ----------------------- Our first move is to switch the reporter from text, to our not yet written XML version... [source,c] ----------------------- #include "xml_reporter.h" ... include::tutorial_src/test_as_xml1.c[lines=24..-1] ----------------------- We'll start the ball rolling with the `xml_reporter.h` header file... [source,c] ----------------------- include::tutorial_src/xml_reporter.h[] ----------------------- ...and the simplest possible reporter in `xml_reporter.c`. [source,c] ----------------------- include::tutorial_src/xml_reporter0.c[] ----------------------- One that outputs nothing. ----------------------- $ gcc -c test_as_xml.c $ gcc -c xml_reporter.c $ gcc xml_reporter.o test_as_xml.o -lcgreen -o xml $ ./xml ----------------------- Yep, nothing. Let's add the outer XML tags first, so that we can see *Cgreen* navigating the test suite... [source,c] ----------------------- include::tutorial_src/xml_reporter1.c[] ----------------------- Although chaining to the underlying `reporter_start_*()` and `reporter_finish_*()` functions is optional, I want to make use of some of the facilities later. Our output meanwhile, is making its first tentative steps... [source,xml] ----------------------- include::tutorial_src/test_as_xml1.out[] ----------------------- We don't require an XML node for passing tests, so the `show_fail()` function is all we need... [source,c] ----------------------- ... include::tutorial_src/xml_reporter2.c[lines=18..25] ... include::tutorial_src/xml_reporter2.c[lines=37..-1] ----------------------- We have to use `vprintf()` to handle the variable argument list passed to us. This will probably mean including the `stdarg.h` header as well as `stdio.h`. This gets us pretty close to what we want... [source,xml] ----------------------- include::tutorial_src/test_as_xml2.out[] ----------------------- For completeness we should add a tag for a test that doesn't complete. We'll output this as a failure, although we don't bother with the location this time... [source,c] ----------------------- include::tutorial_src/xml_reporter3.c[lines=27..31] ... include::tutorial_src/xml_reporter3.c[lines=44..-1] ----------------------- All that's left then is the XML declaration and the thorny issue of indenting. Although the indenting is not strictly necessary, it would make the output a lot more readable. Given that the test depth is kept track of for us with the `breadcrumb` object in the `TestReporter` structure, indentation will actually be quite simple. We'll add an `indent()` function that outputs the correct number of tabs... [source,c] ----------------------- include::tutorial_src/xml_reporter4.c[lines=7..12] ----------------------- The `get_breadcrumb_depth()` function just gives the current test depth as recorded in the reporters breadcrumb (from `cgreen/breadcrumb.h`). As that is just the number of tabs to output, the implementation is trivial. We can then use this function in the rest of the code. Here is the complete listing... [source,c] ----------------------- include::tutorial_src/xml_reporter4.c[] ----------------------- And finally the desired output... [source,xml] ----------------------- include::tutorial_src/test_as_xml4.out[] ----------------------- Job done. Possible other reporter customizations include reporters that write to `syslog`, talk to IDE plug-ins, paint pretty printed documents or just return a boolean for monitoring purposes. == Advanced Usage === Custom Constraints Sometimes the built-in constraints that *Cgreen* provide are not sufficient. With *Cgreen* it is possible to create custom constraints, although you will be depending on some internal structures if you do so. Here's how to implement a simple example custom constraint that asserts that the value is bigger than 5. We'll implement this using a static constraint since it does not take any parameter. WARNING: static constraints are a bad idea... First we need the actual compare function: [source,c] ----------------------------- include::tutorial_src/custom_constraint1.c[lines=1..1] include::tutorial_src/custom_constraint1.c[lines=9..12] ----------------------------- And then the static constraint structure, for which we'll need some of *Cgreen*'s internal functions: [source,c] ----------------------------- include::tutorial_src/custom_constraint1.c[lines=2..3] include::tutorial_src/custom_constraint1.c[lines=13..26] ----------------------------- This implementation can use a statically declared `Constraint` structure that is prefilled since it does not need to store the value to be checked. This static custom constraint can then be used directly in the `assert` like this: [source,c] ----------------------------- include::tutorial_src/custom_constraint1.c[lines=28..31] ----------------------------- To create a custom constraint that takes an input parameter, we need to add a function that creates a constraint structure that correctly saves the value to be checked, and, for convenience, a macro. This time we need to dig into how *Cgreen* stores expected values and we'll also make use of *Cgreen*'s utility function `string_dup()`. [source,c] ----------------------------- include::tutorial_src/custom_constraint2.c[lines=2..4] include::tutorial_src/custom_constraint2.c[lines=9..28] ----------------------------- This gives a custom constraint that can be used in the `assert` in the same way as *Cgreen*'s built-in constraints: [source,c] ----------------------------- include::tutorial_src/custom_constraint2.c[lines=31..33] ----------------------------- The last, and definitely more complex, example is a constraint that takes two structures and compares fields in them. The constraint will, given a structure representing a piece and another structure representing a box, check if the piece can fit inside the box using a size field. Assuming two "application" structures with `size` fields: [source,c] ----------------------------- include::tutorial_src/custom_constraint3.c[lines=9..17] ----------------------------- We want to be able to write a test like this: [source,c] ----------------------------- include::tutorial_src/custom_constraint3.c[lines=54..58] ----------------------------- To implement the `can_fit_in_box` constraint we first need a comparer function: [source,c] ----------------------------- include::tutorial_src/custom_constraint3.c[lines=19..22] ----------------------------- And this time we can't rely on *Cgreen*'s checker and message generating function `test_want()` which we used in the previous examples. So we also need a custom function that calls the comparison and formats a possible error message: [source,c] ----------------------------- include::tutorial_src/custom_constraint3.c[lines=24..36] ----------------------------- Finally we'll use both of those in the constraint creating function and add the convenience macro: [source,c] ----------------------------- include::tutorial_src/custom_constraint3.c[lines=38..52] ----------------------------- CAUTION: As stated above, using custom constraints makes your tests vulnurable to changes in *Cgreen*'s internals. Hopefully a method to avoid this will emerge in the future. TIP: You can write custom constraints directly in a test file, but they can of course also be collected into a separately compiled module which is linked with your tests. == Hints and Tips CAUTION: This chapter is intended to contain tips for situations that you might need some help with, but it is nowhere near complete at this time. [[cgreen-mocker]] === `cgreen-mocker` - Automated Mocking Are you starting out with *Cgreen* on a largish legacy system? And there are loads and loads of functions to mock to get a unit under test? You could try the `cgreen-mocker` that is supplied as a contributed part of the *Cgreen* source distribution. It is a Python program that parses C language header files and tries to create a corresponding `.mock` file where each function declaration is replaced with a call to `mock()`. ----------------- Usage: cgreen-mocker.py { } : file with function declarations that you want to mock : any 'cpp' directive but most useful is e.g. "-I " to ensure cpp finds files. ----------------- So given a header file containing lines like [source,c] ---------------------------- extern CgreenValue make_cgreen_integer_value(intptr_t integer); extern CgreenValue make_cgreen_string_value(const char *string); ---------------------------- `cgreen-mocker` will, given that there are no errors, print something like this on the screen: [source,c] ---------------------------- CgreenValue make_cgreen_integer_value(intptr_t integer) { return mock(integer); } CgreenValue make_cgreen_string_value(const char *string) { return mock(string); } ---------------------------- Of course, you would pipe this output to a file. To use `cgreen-mocker` you need Python, and the following packages: * `packaging` -- (https://github.com/pypa/packaging) * `pycparser` -- (https://github.com/eliben/pycparser) These can easily be installed with: ---------------- $ pip install -r requirements.txt ---------------- NOTE: `cgreen-mocker` is an unsupported contribution to the *Cgreen* project by Thomas Nilefalk. === Compiler Error Messages Sometimes you might get cryptic and strange error messages from the compiler. Since *Cgreen* uses some C/C++ macro magic this can happen and the error messages might not be straight forward to interpret. Here are some examples, but the exact messages differ between compilers and versions. |========================================================= |*Compiler error message* |*Probable cause...* |`"contextFor" is undeclared here` | Missing `Describe();` |`undefined reference to 'AfterEach_For_'`| Missing `AfterEach()` |`CgreenSpec______ is undeclared` | Missing test subject/context in the `Ensure` of a BDD style test |`use of undeclared identifier 'contextFor'` | Missing `Describe();` |========================================================= === Signed, Unsigned, Hex and Byte *Cgreen* attempts to handle primitive type comparisons with a single constraint, `is_equal_to()`. This means that it must store the actual and expected values in a form that will accomodate all possible values that primitive types might take, typically an `intptr_t`. This might sometimes cause unexpected comparisons since all actual values will be cast to match `intptr_t`, which is a signed value. E.g. [source, c] ------------------------------ Ensure(Char, can_compare_byte) { char chars[4] = {0xaa, 0xaa, 0xaa, 0}; assert_that(chars[0], is_equal_to(0xaa)); } ------------------------------ On a system which considers `char` to be signed this will cause the following *Cgreen* assertion error: ------------------------------ char_tests.c:11: Failure: Char -> can_compare_byte Expected [chars[0]] to [equal] [0xaa] actual value: [-86] expected value: [170] ------------------------------ This is caused by the C rules forcing an implicit cast of the `signed char` to `intptr_t` by sign-extension. This might not be what you expected. The correct solution, by any standard, is to cast the actual value to `unsigned char` which will then be interpreted correctly. And the test passes. NOTE: Casting to `unsigned` will not always suffice since that is interpreted as `unsigned int` which will cause a sign-extension from the `signed char` and might or might not work depending on the size of `int` on your machine. In order to reveal what really happens you might want to see the actual and expected values in hex. This can easily be done with the `is_equal_to_hex()`. [source, c] ------------------------------ Ensure(Char, can_compare_byte) { char chars[4] = {0xaa, 0xaa, 0xaa, 0}; assert_that(chars[0], is_equal_to_hex(0xaa)); } ------------------------------ This might make the mistake easier to spot: ------------------------------ char_tests.c:11: Failure: Char -> can_compare_byte Expected [chars[0]] to [equal] [0xaa] actual value: [0xfffffffffffffaa] expected value: [0xaa] ------------------------------ === Cgreen and Coverage *Cgreen* is compatible with coverage tools, in particular `gcov`/`lcov`. So generating coverage data for your application should be straight forward. This is what you need to do (using `gcc` or `clang`): - compile with `-ftest-coverage` and `-fprofile-arcs` - run tests - `lcov --directory . --capture --output-file coverage.info` - `genhtml -o coverage coverage.info` Your coverage data will be available in `coverage/index.html`. === Garbled Output If the output from your *Cgreen* based tests appear garbled or duplicated, this can be caused by the way *Cgreen* terminates its test-running child process. In many unix-like environments the termination of a child process should be done with `_exit()`. However, this interfers severily with the ability to collect coverage data. As this is important for many of us, *Cgreen* instead terminates its child process with the much cruder `exit()` (note: no underscore). Under rare circumstances this might have the unwanted effect of output becoming garbled and/or duplicated. If this happens you can change that behaviour using an environment variable `CGREEN_CHILD_EXIT_WITH__EXIT` (note: two underscores). If set, *Cgreen* will terminate its test-running child process with the more POSIX-compliant `_exit()`. But as mentioned before, this is, at least at this point in time, incompatible with collecting coverage data. So, it's coverage __or__ POSIX-correct child exits and guaranteed output consistency. You can't have both... [appendix] == Legacy Style Assertions Cgreen have been around for a while, developed and matured. There is an older style of assertions that was the initial version, a style that we now call the 'legacy style', because it was more aligned with the original, now older, unit test frameworks. If you are not interested in historical artifacts, I recommend that you skip this section. But for completeness of documentation, here are the legacy style assertion macros: |========================================================= |*Assertion* |*Description* | `assert_true(boolean)` | Passes if boolean evaluates true | `assert_false(boolean)` | Fails if boolean evaluates true | `assert_equal(first, second)` | Passes if 'first == second' | `assert_not_equal(first, second)` | Passes if 'first != second' | `assert_string_equal(char *, char *)` | Uses 'strcmp()' and passes if the strings are equal | `assert_string_not_equal(char *, char *)` | Uses 'strcmp()' and fails if the strings are equal |========================================================= Each assertion has a default message comparing the two values. If you want to substitute your own failure messages, then you must use the `*_with_message()` counterparts... |========================================================= |*Assertion* | `assert_true_with_message(boolean, message, ...)` | `assert_false_with_message(boolean, message, ...)` | `assert_equal_with_message(tried, expected, message, ...)` | `assert_not_equal_with_message(tried, unexpected, message, ...)` | `assert_string_equal_with_message(char *, char *, message, ...)` | `assert_string_not_equal_with_message(char *, char *, message, ...)` |========================================================= All these assertions have an additional `char *` message parameter, which is the message you wished to display on failure. If this is set to `NULL`, then the default message is shown instead. The most useful assertion from this group is `assert_true_with_message()` as you can use that to create your own assertion functions with your own messages. Actually the assertion macros have variable argument lists. The failure message acts like the template in `printf()`. We could change the test above to be... [source,c] ----------------------------- include::tutorial_src/strlen_tests4.c[lines=4..8] ----------------------------- This should produce a slightly more user friendly message when things go wrong. But, actually, Cgreens default messages are so good that you are encouraged to skip the legacy style and go for the more modern constraints style assertions. This is particularly true when you use the BDD style test notation. IMPORTANT: We strongly recommend the use of BDD Style notation with constraints based assertions. [appendix] == Release History In this section only the introduction or changes of major features are listed, and thus only MINOR versions. For a detailed log of features, enhancements and bug fixes visit the projects repository on GitHub, https://github.com/cgreen-devs/cgreen. Since 1.4.1 Cgreen has included the following C pre-processer definition variables - `CGREEN_VERSION`, a SemVer string - `CGREEN_VERSION_MAJOR` - `CGREEN_VERSION_MINOR` - `CGREEN_VERSION_PATCH` You can use them to conditionally check for Cgreen features introduced as declared in the following sections. Since 1.2.0 Cgreen has featured a public version variable in the loaded library, `cgreen_library_version`. This is mainly used by the `cgreen-runner` to present version of the loaded library, but it can also be used to check for availability of features in the same way. === 1.6.0 - Reverted use of `libbfd` introduced in 1.5.0 due to portability issues and Debian deeming it to be a serious bug due to `libbfd` not having a stable interface === 1.5.1 - Fixed a problem with `ends_with_string()` which randomly crashed === 1.5.0 - Replaced calling `nm` with BFD library calls, this makes the `cgreen-runner` a bit more fiddly to build on some systems - Introduced `will_capture_parameter()` === 1.4.0 - A memory leak in `will_return_by_value()` was fixed but now requires user deallocation. === 1.3.0 - Renamed CgreenValueType values to avoid clash, now all start with `CGREEN_` === 1.2.0 - Introduced `will_return_by_value()` - Introduced `with_side_effect()` === 1.1.0 None. === 1.0.0 First official non-beta release. [appendix] == License Copyright (c) 2006-2021, Cgreen Development Team and contributors + (https://github.com/cgreen-devs/cgreen/graphs/contributors) Permission to use, copy, modify, and/or distribute this software and its documentation for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies, regardless of form, including printed and compiled. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. [appendix] == Acknowledgements Thanks to - Marcus Baker - initiator and substantial inital work - Matt Hargett - upgrading to the modern BDD-ish syntax - João Freitas - asciidoc documentation and Cmake build system - Thomas Nilefalk - cgreen-runner and current maintainer Thanks also go to @gardenia, @d-meiser, @stevemadsenblippar and others for their contributions. cgreen-1.6.3/doc/cgreen_asciidoc.conf000066400000000000000000000000431450461175400175050ustar00rootroot00000000000000[attributes] toclevels=3 numbered= cgreen-1.6.3/doc/cheat-sheet.md000066400000000000000000000044271450461175400162630ustar00rootroot00000000000000# Cgreen Cheat Sheet ## Pre-amble #include #include Describe( ); BeforeEach( ) {} AfterEach( ) {} ## A test Ensure( , ) { assert_that( ); assert_that( , ); assert_that_double(...); } ## Constraints is_true is_false is_null is_non_null is_equal_to( ) is_equal_to_hex( ) is_not_equal_to( ) is_greater_than( ) is_less_than( ) ### Structs and general data is_equal_to_contents_of( , ) is_not_equal_to_contents_of( , ) ### Strings is_equal_to_string( ) is_not_equal_to_string( ) contains_string( ) does_not_contain_string( ) begins_with_string( ) does_not_begin_with_string( ) ends_with_string( ) does_not_end_with_string( ) ### Floating point values (Doubles) is_equal_to_double( ) is_not_equal_to_double( ) is_less_than_double( ) is_greater_than_double( ) significant_figures_for_assert_double_are( ) ## Mocks ( ) { mock( ); mock( box_double( ) ); return ( ) mock( ); return mock_double( ); } Ensure( ) { expect( {, when(, ) } [, ] [, times( ) ] ); always_expect(...); never_expect(...); } cgreen_mocks_are( strict_mocks | loose_mocks | learning_mocks ); ### Returns will_return( ) will_return_double( ) will_return_by_value( , ) with_side_effect( , ) will_set_contents_of_parameter( , , ) ## C++ namespace cgreen; assert_throws( , ); ## Minimal Makefile all: $(UNIT)_tests.so cgreen-runner $^ $(UNIT)_tests.so: $(UNIT)_tests.o $(UNIT).o $(CC) -shared -o $@ $^ -lcgreen %.o: %.c $(CC) $(CFLAGS) -fPIC -c -o $@ $^ cgreen-1.6.3/doc/doxy.config.in000066400000000000000000001752071450461175400163330ustar00rootroot00000000000000# Doxyfile 1.5.8 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = @APPLICATION_NAME@ # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = @APPLICATION_VERSION@ # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = @CMAKE_CURRENT_BINARY_DIR@ # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, # Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), # Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, # Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, # Spanish, Swedish, and Ukrainian. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = @PROJECT_SOURCE_DIR@ # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = @PROJECT_SOURCE_DIR@ # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = YES # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 2 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it parses. # With this tag you can assign which parser to use for a given extension. # Doxygen has a built-in mapping, but you can override or extend it using this tag. # The format is ext=language, where ext is a file extension, and language is one of # the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, # Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat # .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), # use: inc=Fortran f=C EXTENSION_MAPPING = # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate getter # and setter methods for a property. Setting this option to YES (the default) # will make doxygen to replace the get and set methods by a property in the # documentation. This will only work if the methods are indeed getting or # setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = NO # The SYMBOL_CACHE_SIZE determines the size of the internal cache use to # determine which symbols to keep in memory and which to flush to disk. # When the cache is full, less often used symbols will be written to disk. # For small to medium size projects (<1000 input files) the default value is # probably good enough. For larger projects a too small cache size can cause # doxygen to be busy swapping symbols to and from disk most of the time # causing a significant performance penality. # If the system has enough physical memory increasing the cache will improve the # performance by keeping more symbols in memory. Note that the value works on # a logarithmic scale so increasing the size by one will rougly double the # memory usage. The cache size is given by this formula: # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols SYMBOL_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = NO # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default # anonymous namespace are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = YES # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = YES # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = YES # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = NO # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Namespaces page. # This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by # doxygen. The layout file controls the global structure of the generated output files # in an output format independent way. The create the layout file that represents # doxygen's defaults, run doxygen with the -l option. You can optionally specify a # file name after the option, if omitted DoxygenLayout.xml will be used as the name # of the layout file. LAYOUT_FILE = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = YES # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = @CMAKE_CURRENT_BINARY_DIR@/doxy.log #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = @PROJECT_SOURCE_DIR@/include \ @PROJECT_SOURCE_DIR@/src # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 FILE_PATTERNS = *.cpp \ *.cc \ *.c \ *.h \ *.hh \ *.hpp \ *.dox # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = */.git/* \ */cmake/* \ */doc/* \ */build/* # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = @PROJECT_SOURCE_DIR@/tests \ @PROJECT_SOURCE_DIR@ # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = *.cpp \ *.cc \ *.h \ *.hh \ INSTALL \ DEPENDENCIES \ CHANGELOG \ LICENSE \ LGPL # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = YES # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. # If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. # Doxygen will compare the file name with each pattern and apply the # filter if there is a match. # The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. # Otherwise they will link to the documentation. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = YES # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 2 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = NO # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. GENERATE_DOCSET = NO # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.doxygen.Project # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. CHM_INDEX_ENCODING = # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER # are set, an additional index file will be generated that can be used as input for # Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated # HTML documentation. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can # be used to specify the file name of the resulting .qch file. # The path specified is relative to the HTML output folder. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#namespace QHP_NAMESPACE = # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#virtual-folders QHP_VIRTUAL_FOLDER = doc # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. # For more information please see # http://doc.trolltech.com/qthelpproject.html#custom-filters QHP_CUST_FILTER_NAME = # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see # Qt Help Project / Custom Filters. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's # filter section matches. # Qt Help Project / Filter Attributes. QHP_SECT_FILTER_ATTRS = # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can # be used to specify the location of Qt's qhelpgenerator. # If non-empty doxygen will try to run qhelpgenerator on the generated # .qhp file. QHG_LOCATION = # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to FRAME, a side panel will be generated # containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. Other possible values # for this tag are: HIERARCHIES, which will generate the Groups, Directories, # and Class Hierarchy pages using a tree view instead of an ordered list; # ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which # disables this behavior completely. For backwards compatibility with previous # releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE # respectively. GENERATE_TREEVIEW = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 # Use this tag to change the font size of Latex formulas included # as images in the HTML documentation. The default is 10. Note that # when you change the font size after a successful doxygen run you need # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. FORMULA_FONTSIZE = 10 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = @LATEX_COMPILER@ # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = @MAKEINDEX_COMPILER@ # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4 # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = YES # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = YES # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = YES # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. # This is useful # if you want to understand what is going on. # On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = @CMAKE_CURRENT_BINARY_DIR@/html/@PROJECT_NAME@.TAGFILE # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = YES # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = NO # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = @DOXYGEN_DOT_FOUND@ # By default doxygen will write a font called FreeSans.ttf to the output # directory and reference it in all dot files that doxygen generates. This # font does not include all possible unicode characters however, so when you need # these (or just want a differently looking font) you can specify the font name # using DOT_FONTNAME. You need need to make sure dot is able to find the font, # which can be done by putting it in a standard location or by setting the # DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory # containing the font. DOT_FONTNAME = FreeSans # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. # The default size is 10pt. DOT_FONTSIZE = 10 # By default doxygen will tell dot to use the output directory to look for the # FreeSans.ttf font (which doxygen will put there itself). If you specify a # different font using DOT_FONTNAME you can set the path where dot # can find it using this tag. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = YES # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = YES # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = @DOXYGEN_DOT_EXECUTABLE_PATH@ # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, because dot on Windows does not # seem to support this out of the box. Warning: Depending on the platform used, # enabling this option may lead to badly anti-aliased labels on the edges of # a graph (i.e. they become hard to read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = YES # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Options related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO cgreen-1.6.3/doc/logo.odt000066400000000000000000000446301450461175400152170ustar00rootroot00000000000000PK:P^2 ''mimetypeapplication/vnd.oasis.opendocument.textPK:PConfigurations2/popupmenu/PK:PConfigurations2/progressbar/PK:PConfigurations2/menubar/PK:PConfigurations2/statusbar/PK:PConfigurations2/toolbar/PK:PConfigurations2/images/Bitmaps/PK:PConfigurations2/accelerator/PK:PConfigurations2/floater/PK:PConfigurations2/toolpanel/PK:P manifest.rdf͓n0'Ms,fko٢R&B5@| s(- ,>{GA{z=,mq~(NR^1KiHL܁rņYtlTLu (ArڒSE$̴Mg~E5g *YpbuptM(a>}Gs h M0;T*HEG ?>~hS(溈z*h5;L-w^*ΉMU1 Ͳ=sH8ȃCs')AI|ֆo3 Y- y#D\MA{R!Jŗ/o?|yDȟq_;[Q0(1爰2' \>G DMn8W=f X|\M#Q g\쿏~!a1O^S\Y D_Z',?б'0?KEHS%ߩůGB'́ٺ}zC]R+?Jnv2^όp\Wv:rFFD( އT!P2u7Wh 8~k(owrԎo2IɑB@[I:GUZ=:A7Ap ʹ_.4"Ao*I=wȚd8R#ۈ0TX`wmC׊kT4#ܲbV͉caStu+xә@jq*ZfD' 7:B ~+nZ]=M- PjYIG% d])3p P*CQP*/Dfw2mP-ӓj =k)NOxi(Q|ҥn{jN2Of0'/4F.z+8d 'F=37s1e` IL2U]P'@>ޕQF!1ZT7Iݠ6X_=ɳC">gNuCjYlGrA j` 2[rCE!*T k'`kɮpEB*\|Lp(XEM&o^%㫍z?a> 4wh\Rr~[~TZ0;|,M$\Ƿ8v 3 KdϞ*=U~*EBsz<5m8'um8mӫַ Gu,>A 'Gdd]YBȉo*lBazAq㮘/;yǦ{AH)`d6L$Dc5' <;g@ =&t್m1sԑ3+]v7 }. /rao~d7Dr.:Wk~sr[Z.egСucU$Cbr6K&Ƽ,_ Հ tu=pLIi^^+{2gKzsNүP*qS I\R@tGsoǖ~Km@"cT7Nm{& W@\. 7t. o^r HW@z.)H]v7 lǹҿK\e_mDXvO R&c^אٔt\AF`LdWiߺ]iQ`d0>L~/aM<{6>u_[TE09 H3:YV1ᶾ[ܡ*}ϙ %0UQg➧71 _*ًcۏA$_bZV}D[;7'Y%#6V(|mN~2?`pPCtfF+]|c u\7?xoPKԹB0PK:Pmeta.xml˒0E d  ;.NMv.Yjce@$y}sXgF9=K߯Z`1\4M~iz?)|庋iFJp X aLwNU3J:ɚ`Nj-W5O%KMqG{R(!{\$mL6xz->{^Gikk;տ_rAF59,6Vz6Ƥ~bV =(gkۃ!GfSF9߁滏8m^>bE L@o0Adڨѕ- w>S&,92%D;;j1wj5{rQi5>YSI9n1M/ńF$j;L)@"vRK R&TYVK՞<}W@@h (!NRX*َ_Bپ9:^@;!U">PhTISk@]_m<(6aJ kJSֲ*,.GT!U9˥pEؘ҉32Lmg#cwǘGUÃIzrۤW墴}:D3To.r/PL8Ot>TqߣP2UߧB->҅ܳ#׈2>c` KL!@$ &"yy&ݦvVL>r\Ԁ%: 2+ J39HehRiJld# (re@ۮr$X=h/{h~JGnwLL,z0ۈ=xNp.kd8a&ؒF1=bҰ#( Ǚ5ۯl2ԗmΠ&DxY*5?G倜C! ]qUH8FF+M )~Z;=9Z=6 a(yp$I&z"// E?5v*كg[ҭ}`Kclmp`3 :\i[s»+} S m&CPR7(gzct| Bx_6*yΣbIG| M~«6JͣNޗT|*s?|$^8'Y.zq)o d&ŕ͓6a*|C !F67|9)&,RA)L6 ^@o:TQR+WE~B*rhNsxL){cq&,v+{\(p6vF ӗ6wUd\%-![3("@m:\FYP4/Uy\ݹ (-yv)foT1:n'B&|1lh)'/ڌ\ݦX2BCHёrmYo:w\Ԧ2THRmH;͂cI' 7hT byN%@P,dCI><3EͅM,\0GAɗ+޻-eV_ ܛD{?+ h>ÖYS-ł S}j_ PK!z-PK:P content.xmlX[o6~߯Tl؀Ѳ⦫$Ś6ۀ ْJR_CR%Gr[\H La<-LY]᫋od1BTJ " .t"aDbtR`AubH"KZ4:N6q~[]OLն{)Õ1eEV;IG'ȯLNuep%6brV|ln6f\2rv{++ŝTJ"ʩuxG6|2NaN?E|r|QjrNJs N#EKL **qOdN rvs0i7:8qz)BL'h0C)}>s?&2]rde8+('<ۗW{(cw͔9 h#o缣\R/F@[1 @SM̊ [}z[tĈ8%ԁ|\f >Y:_f)~j|3Pam‡# Mg1 6mH\`Cm_K6+]}(KhťKzU 8>~/PKR~*`PK:Pb[[Thumbnails/thumbnail.pngPNG  IHDRPLTE:429:D47CB?E8ALGVIFNUWISWVdaMfWefeuttt_yf~y}ow}zmx}~}mxžŦɭشĚҗ՜۬ݱỮչ˶ٺ݃܅ޓưǷĽѼ陈噗✪롍짖ﱝ覦䧴鲶ú¬ǵȽIJȴ˹κнƶҾu{ IDATx XTuow]l{ ն y&+MAԺh U$͒*eImWD%#:#̸l8x{ f&÷g>{ܹ{ιRԤ&5IMjRԤ&u?Kk^KWz2@H U%;x^X7)-=린+9[g> .LhҮ"BL2E`LBu@1hMa'GhӄX8;K\HݭЖuD(Ce7=7,.@  M@g0;rrBIxފ oL3>Tw G& Ek?fIUk D?ď `H0[ϔRgi(8-Кc}դXZu-w ډGŭk!rK,',~W>9`S KXAp- Qtg MM}J*KAxjA)ERvNI3Ic-Gxbj4u6*CqkZxU)I!cQ]/a[!^ $5^p;K,GJAPpˬ4 8lQ=υc purՂ{nݙ`E_U[!w-'I;_N烱ȾҠ׆9dTD' q=F&MB[s}MBADrp,jMBKD-{2҄-$gIldgBE|k+Wd]9ħ)͆&rU텕 7b'1k:-N8釽[(8-.Fw+8|Omy.6>b5:4ߗGt΂`Ѳ-OZ槓Yk2>!X CR=/-bݙ>HJ6X]ջ_muA8Dk u}@j5Lۙsؐ3tj#IMSi3X-{ 8~m8;~9?ڽw}[] ͐6{gNVwF"Ux};B~uݷZT/>/CבJ#CXп8"c{o 7>T*0=3ܕ|59}뿻'&G݉޹{ۈ~HxGzCwGS qls5VpJOQ_;V*9 GA};|(2yմ,'hZ+i^wq,ۨÌ!|xla,U#>=;YuԘx1w<0J|`73;{{*]<;A< Uɩg%5Y^Ft9xȚmf$zǿz/7 \PP穌+QyL t1N0bq7^zσ {|8,u`b$o8XNғ|}c1jڳ*ymma5 nY+=c_^8 92AU189$BZe_=SKSa«By0^w*4mW;=1ԝ|G&N:Ş $&x߻jG k13o8 9O>GVOFs1ܔ.&GsXM9/Oz*vf^7ɕR߽ɕD'VMS*Q`RƵ{/m=~Q8';N~-=Lz!}D;zGeIяV/jd'I_wopDF4fUONыf*reܔR9!N90co0jL +am{iZ4ZjoIIfJj銩bY(tα;]"mAvնeVC/V1*^?kg:ʵm{0Y~ܯZFEܞzUʭV*仱 xΔbkN=*b5n>{1vuo^n5{̦"3,dʬOm)/빓eWq334m=ʸcj}?=PRR$H7-]@#ߝPdWjGCmK9jMGrٞ/[mn>aruVv4Oxfkm̕{]Yi< ٬j?UJ_Շu{VyHXhSտ}nc<^;Z-ϻo|"3;FvMSsjSo*zFi䦟.kds#18n~w,> v)ѣN4ӊ))F1K^I/BֈcH[LiCנsuFޭXPJ.u*Tam%yUQLL|TSUSCMw];I\P]ARq~g7r}54QO_ۥ1NpLq흜i^[-}\d2W'߭ssQԩR^U5ܝfy[+Tru31S}PgԡmjqX#Q>40ȲYUF{%GVc_ZusX6΅v!tҊ!Q]KM1DE4Ƒ i!>@Zn;oS"O+[!YZҘl* ڣ?wUq֞.IB_FW*,onJy Ֆ2kZO3\N8G̳;yzvFrC/qMSܗelgEpo֤WW蜇'k̮;('.fn7ϔuφ98+6Ε6ʒBފ0Wmej(vHfͼ=mZ)H0lhrTP׋sU~I&DsX 3z9}߽=g*vo=w9[8ZSm)s_/9>*W0/f7 ;0/fWxH{ٍtmqW!y.|}Tc3+nξYū{"7( Kz ZOm:S9R}[e׆ZZ6cHYŘҘk=r gQSu*}[Q|$[F#o jgJaZҘUo^_|5\zGxr1g._E"3+nfi/SzG'6o4 Ǿޗ>/Ro1]_%գwMQ|:幄]^Řgîzj;;x]і<;_RuY/D._f,ڎ<׮]lE]gs9:.B7UZF UNTt_4GL۷gڧcz7xnՏn3툍{5(9zWxCͷN<}P+_'( ވ#W~N 宗S3_iͽk\/XOG5.cjҷdffm)<.}l;nJ:U#x٤uiNIө S 8M8i+JgIVSyUx%-!vniFUv]{۟KnW.7הKh')@K>uG.jNm 3~ǫe^obn_:QZois$iNk/OSGN?իќSOlGkmվ֭VGsgM(%UKO B̎dN#\߿ acKcүBԄԄe  4~OU3L;.z'3y5\vN~% /A?&F3=0"a{vZUf{CX練Yj||c_IsV^佾W7sgeq<2\ތͲ;:rf;ز٭j+ 0^ h=~r~ы96Us1eZտtG9Tw7}s7lqq^~s-]ʮܝfvK+]W.NL2X6+g_VPfrypqzJ_VL:=mv>J|g_ܣ{: Mݒc]i7vQ%_{l.TU\|(jo.=(>Q].uЎ7-u2v-%mP]!rQw+ec-ʶOo>QҼ݌mV=mH TέHœ%Rrj1.MI/vb& !j7ezqY2s^n9x/~sNn^&]nu}sݹ+|w#Bc3C4M~wҟ*/djbbUb=,nn=G۔*7U錆Թ<V\Nڼ};~k ?fb5ڬ܍:??_^VnGL/$`>7}Sd(wvQ5ֻ}i_=ɟF|EqL1|^++ߍ\>-shyw,r ʍgwҜXm|ӥwӏUyO٥l^=bu{z1'/6lbxڷej)n5ϳaa{V.5;7 p+˭J~^%^  =6(΅xp4ejpp<猳cyzM2:~SioZ\bcF hڪ֚ITmCju[LdS[: ֝EiB*_ qT;^^+*QlZaQ|Ukǎ~~oS>_tyf}|wsެ&Q\;sƥo U7˥Qۇ=zp/ga m=N&as:N5Sԑq\>>ޝ8ѣBTaN\F)/$:QMbcHb)LQDiPK:PMETA-INF/manifest.xml]o0 I#.kJ_!,$rCKXj:U&xP.rۦsZ5S$>fN8X jEAy'0EhڊvA\U2/ 8YbjEВ.$ܞo> stream xKk0 :JCN{e_nV?FMvMNM`tWp0ǚcB'=ʹg5KV-V_Wj^G4 kx$4htr6`̾Kl-vx;"•ڼ0q=/(  NB%K.I%bBw EJRU@v8~[)H]|&n)wuj/M=SbTO&9*w6lM}|<|~2_ endstream endobj 3 0 obj 334 endobj 4 0 obj <> stream JFIFHHC     C   "   }7@"HLO> Jyt9ٜɱ9]Led1γ='؀q1 v>~|Uow֚6j{]-@R _q<.ku4; U*lq'*ha!I4ZX86klmggHl=j8 =T~ݾ,,ڹMpc2nl6U2rՕQ*XI'@ 0p1a"S1ۉuxxJ6W+5L;vK)Sd'u+I][rXw̎`iZViC ʖ`#r d>~ Ůœjy83 aqn]fV'8FGVeP{.KڧڹESaLn|KhKCGRl- RpZARexX=cRds>ʐonO|$oЏN/F dJ9:}GOR"\r>tzm,.01!2A PQ"#bq?dNj?%澔$=\j4q8S^j)zԻMKcOZmxQ"P5"@LEMRWajAW̲XMy'&v)υÎ3_l㄁u&1<%Qgn^cM.iVCUl!!&@Jpʢ}4ޡY.ޑR˵cbl;\\D$jK nq>(ԕ6k*10! 2AP"Ca?ܯj?eurf]/ƪKĕ~fh2K kS&>W HޢE1KI%&nzj&/Rs>OA{A @t9Q DZ]]{[7&6@JZ:O񑙉'7cb6Fvx"wB%- W_OSrݳKeyv}L331&/wf6|. yqSb4zLqv5t?H゠|$PwxkNg6M϶y4H*BL Gkr,SqUl (R5*k\r-RAԴTT"s-uYZA$bB*zoh ~Uh]ӗUݰ.xfjm1nbCw)&b\XkFX7ks}aĩdOḑb߃! D?';e6&HO <<<<<<<<<<9<<5Q 4"{NaG0A<0 4=op-Ьj Pw{8Ov@Yεi/(!1Qq0Aaс P?Cq_ " M)Rg{d̟%DF:yy9xOL׶ .! A9I2s; = Fؾ"d 0NݬsS* {聏K"SA;7ǠhjB b9ORDۺ(mM@398eAA*ٍNs59(!1AQa@q 0p?0DHDGX#ڿxu(rΠx6Ńc>1@w0RLsCkuunΉnB0 D} 2әhSrLnDže%@)eHkƪ`W\(]^^k7ూh`wltPGWSThw!2rUVpO(rhi(e]r+o˩]|y\Fiu\SUaO!Рuܑ_`j{A d@«+ _ieGgѢHa ț<*pupi ķB C!`ȢDCȇD(a8jmZ޹#jq[2Z|=qW B^+m;({K|?0t/6FGPW*8]j= ҿkth m>da.asSWIF㧑J;iuXL&Kta GwF 8Hr˂[^CX\ aۍBVLZ-s4$ȉi*[)@C42CIM7] AED|.{b.@5 g 55|b1œyəPNu.'c4J -DŽLi GZYZi ,$%BTO endstream endobj 6 0 obj <> stream x| t[Wgɒ%ےֵeɒ?,[JN,KĖTIi@4@RZdt(iN0S3>`fx@=Zb}νW$)f[o쫻>g_I<@$bͷ荄\,MGp,>|G}aI8 ~ ) ӌH,t*Crr /gċaX>t-Gd/#D;֟XCFíH5Pd\Zt# Y- sLM0=} gֿ,U uA<0:q?38N4,Z܍> vxVz`Xy=Aѷe݁ΡϢ<}ݏ)spUȻGЧ` sx?<Ρ#Cnh{ -zrmtטr&.|4Z]A3ltTl7twbƯDwoW$gdfm=>wtdxhps{{l{vw47Zj̕2C>7[P*i2D,bh 40N'DFY/ [ P4 v)m@9QR@5fn`W{ E 5Lk"HJ ֞;&i֞p,ϟOBc k()W(Qi$=J{[F2%6۽ {oAI$+!IH /6eFbQfM~{D¢sܹ3 )QeMTy.H RP q{kڎImAbL0/d A,ˇ. 'Npc\@6i2AO㙗ϜfR˧ %Uiwy>7qr1o9<`3y|z{9'^l^^W{ iP"Ͱw"a5Dنn,Ap|,%{hǯJXX.~n2x5l$<߀$#& ts((I&|$A lWBv$@1\Z.c'f{  0w!hw;A v)0 'bgAd z x ^j@dh5zvs9il ~cX!t SL9d.h`CP؋la1da[ Ľmͷx(A@:LOɸSCi0͞a!b!}@cPKf#J5jq{q̹v.bo< .9DGmlDqU&5f(Q+eZ״fUv\cG92[;q1^{ZfN+ڕNu*V4823?R2x|ʱP-Pk{óM`}wҲYo@'QfgH!Yy b/{ԭxs ph}кF#MrZzR际L0%.hMzڲ߲E'[*URqkifG<滛9~}vGTUgd++)mv:ϥ)WLSMy{`0O:?ɶ |NN[\ԭjZ.P2EEhɬWB*[S rM&\_'5M]Ɏc(ԜB0U:u&A/w7C-ᎹӴ!u}7t*AΊEڐ"W+N]> g"9mI ZI+*k:5#LSfp)r\ukR_IyhJuZ=.j&PiFZP!C-P4\c4XsJ =;R4wڇs+2Lk3i2WdnSf)%o %a^7rB(]\v-jjRָҮگ{HL^!PNY6]_G\R HU >ȧ}{W5gH@"Se.SyKSRsAzFVJ!r}gy>'bN5%>ڐˏo/(XESGӷRL+sO :G]*6itdYb)8Q:%5OVN{|/pZqR8jr:Cl\2T['{k3RR~h5F͌uU},0'~ޢE?DY]ix"VeraWu:iʴ˕V>tP! qg+򩁦*ZIwɖ j7nVK6OUwu!TC[8H2 o^a $i:d>TJ9lzBRd}x)Agym\6K}hU -:*i' H+oU"BVROƕm]MŭԃT|=T)OER6Dnag9loSDKҩ>MYqFPX[:{sKqC|۳xh?RK+(ZCi2_2U_>įUr_? O#H85śT%yzDKiRJk=.J :zUVXJVJEgwS|9'}wsK3KH7奉i\Ue;yc߬$M| ȯ,~X,OR唙^}FQEoB$m?<6*ﰿϏG6^8 4 $hQWRDԎ E*daBQ%zfrkyЗѳ<)BDG+h#^ L(#z= {(3Tu'V7EdI5*˗֕v&9*(^/DHDdYЗ$@22[OwL CCVjfP-"a1ʥOa)Ze!q~dp:aJ"yU?S_(YyBJxFRyA:"yX:v!nӐZaSr~+$mn+LU\/W#~kX?ÙHi)f:SaE=< (y%_aEɏy|Q{_*x|QZR< (< (Jb_`5RGxX)x«g: "05(" @!8QXԅEcC0#@ ~T"'@3 nFb p^Kd$,\a79lJZxvg15jFf8D}CGy~.|>n g؁E0+lב5e.K0# ]QY*? yB. ['Hօ]E[OY^"%idAX+mD 7gw9s|cX[#ZR5+jރgk/Q? (6sdq,GOXȍAC*,#k)"sQŌ)Hd"*VX3/8pL}Fk؇3DG4"D4Fx-F2/F/H'N"2E+3FqScX0'Lm|l`8Aq<9͸]\ zq~!o[Yi}Ɩbp[$VJB4j%KՁ5& 'O8=ZpZNyKb6$^B,'k^ +wsU9 UzA^ \9 $Gֳģ9^7˴AXt:IgUb/S]#l&9"|o-K{ t3D;r_E^lJ`\M|.r'09N Z!v VxM4] &wh{˳JvJݜ;'_jۭg WXZʼn|۪N 6kNڷքӅBŏ갟TH[jŞw[Tqy98x ׃IV)Heur}Z&w!C[j,YH XzVzsZn=i%VB? 9H'xM ߖ#~pm\7L=Y!2[U᜸YMپ*Fj^[x4>F4DsYts_Dv2;0B}0l/`*b O!'yaO@,/֎&v6N(!=7TAnaX}NDNR7ٔۥrɆ`4lv~X~)9]F3 z> td.3'0.v"ag_ nѪIٴ_GAr̿fDqb=;o3 mjyhm \})ۍwN-ܶn?ߤ{FȈFcI$ Ux<!Btr{lv,BT#a{F`w`S;ߊ3/u-P ³q'x0] Xpn>c@t9(h`BHBx.c}j`1ֈofv̻gސ/; |u.cx|0.l3ϻ;M6ecᥨ/bqWl|>`l,`3?g8,|`GB]Dd --x)ۦ 1̬ROll<ѣlx4ehx)Ѿb bzcpWUl_41 &xC1;egUv%gcK3 HEXþ(aa]qv6/E16㰇/ffc^70^Fehi1X NH4 cBxkAg!6Jgs1QڬV, WHx.̯Z3(|l8զbKBYȾ.Aqc4F̬?@sD0ܽ`@t1U 4x0Y|q3eXkk R+AV``ȷy)}8> Vq)8\BԁbhDžW;@evā1^vy9SA0lKTi QđcIgq\۔ny6̛xc k82*X,+HZ9+Y0_$,H4b67/7+|?)1A'l(K,6"TbHX (L\ %@glcx(!l/)B-@X, zq|@AŽ\-.e*1mڲ|aO燛ґ[̇^^Br{c^QHa ͸g=@ Yb$aNFQZAXp$ն[%Hb2ewQ},΀27qwY8;:6ke+a\afa$;`'pOّ154:53u ݰnxzd"0uxC> z0v ܓfrc`Ŏv]=1v36:2n{k1؇n8wv < gdtrtΑ^; YW r ޮ>;Y5\/~`.qF=#1A1wj~׸vƱAc#V&nqfyH3nߔ5:BN~/_p}|vlVZͣi.Ձ:ᢩV NH=ߛ -w1E9Q Շ<v½p p͡DR_ j7&Pp.U!ENR tkW:0p tirCO߮,|#?f?Ѭk6}>5jQzJW&+߼xiU?z󗎟r|{pn6.Y_N69>_H'+/%O鿘<fvkOݯ"go?Gs}{L{Ο}'<D'N| ϱ+ʃ+O0+qϝ{89N=xsi􃧟8͜fez'H^ /޽,&~0ꉝzlh$z2*aÞ',G@`ߜgg {|}3oߴ6Mws[g?s{<ݞ񾽞{={%H߰g) xxyI}}2JzCi1yxbȇ4pQ16LPgݶ@Br6<N$)Ó)M2PQ@h|Eݓa$b_p,1~4&6yjP,$AQj1eBb s!_ endstream endobj 7 0 obj 10423 endobj 8 0 obj <> endobj 9 0 obj <> stream x]n0 U( 1qz@N;,Ar9%r\!3#kcy]"̴~f~.;:b-ˈ9E 9Y묵!9!!þ%{.{HlP&tPwpr߷eG*U( endstream endobj 10 0 obj <> endobj 11 0 obj <> stream xY{l[yν%QD=.u%R/%Ѥ(šP:vLe'lŖI7cWYu@"-mWCIuú!ckπ+b}^r"y?'~uCRW/CRz$vƺ־}8څ_4¥+= `O^\.-9@6/@#o KWKOlwVKk]A" O#k=kW߇$׮.b _WP J6l靟<ُ|)-duE=l˧xweK?rՅP8AQ'0.b:ΙƕJ Vq.jt{3J. L.fPx SZR~cK\4tPMoye*|aY 0PҸLL"%RVd\\l/ 9YPx>C)daBúM6jԁCVO$&',)ܙ/qD! bzū2 rDc?̈́snX$C,RI,i=mH%ɞ]MsbˆRپVHHLɅbv:((&Uf |4T=+c/iAYbV[<uxj뵲HmV ieZYI+۩mj[r1M rUIpvMk=+0O^5&vd뇦d~hz}Ԫhmhh(GmGNڄ$pۺՏ3Fl4&(y5]x0{LL+U- T.,,ۘ?[HVsa~M04LN{=Pknr\.3?:@OMi8·D03|G1DhW4tiuIo@,x5 3GxivV4Ė7$7qiJ\x,‹T\RbSBAOSubVT˙Ϟ"=z2%vE)}vN UË@]]Ό w&Y\e< &s⊤D;)!* ! Gmj4'NC>NӦ=19JovTH/+\nb VTJ}dvUO:5y7) f ^JROǤscs4#ؓ6hluCb@gd )?#KI-mN I3ןNtv/Sz*&cIKվ| 떞XGb^y {jŲf~<S!9\| fEw+SxzF g>ך)yŌ9)L#'gC4q<=ZAT@ k9v9<39NpWLx UrKc޵g݄ĹnpŹV}36LH3np 3oMH/L r'ֻc &$]δ_2!6MHJ#.C[ fA=e.7v/8] D܂W J;|!\ ̀$~iZ8J D/˗It5l@ 6` HώobvUjk4M0|DkՋ\EDDHm%"Վôg.Mq6DhD#]Ss3›||ɹ:&+Zىc]UQv31Ho{ƝH/Dɡh|ca|߻FIvw]H.|}z+zC{wdΛz_9*c̮6FzN5)5}XU&Jwpz3Dc7O. ղbGq-5a-jQLLP1|3TfpF×a 3tRh39n{==cF N0ld5b ֋H} ޫ_DžɪaTHksljĪ \s{C _9Yncf[ݽ&s&P9JCR> <.},ے endstream endobj 12 0 obj 3904 endobj 13 0 obj <> endobj 14 0 obj <> stream x]Mn eXHQH^Gu{ c4 ߾N[ yӈK:+zAua j=ֱxS֓ L[S4LQmxAhwt &%70М'", k^e]nQ705E!ysJ՛B,(I\e?%>d>U{1ϾMI5zAyW9r k3\|@v endstream endobj 15 0 obj <> endobj 16 0 obj <> endobj 17 0 obj <> /ProcSet[/PDF/Text/ImageC/ImageI/ImageB] >> endobj 1 0 obj <>/Contents 2 0 R>> endobj 5 0 obj <> endobj 18 0 obj <> endobj 19 0 obj < /Creator /Producer /CreationDate(D:20200414092204+02'00')>> endobj xref 0 20 0000000000 65535 f 0000021267 00000 n 0000000019 00000 n 0000000424 00000 n 0000000444 00000 n 0000021436 00000 n 0000005020 00000 n 0000015528 00000 n 0000015550 00000 n 0000015743 00000 n 0000016159 00000 n 0000016426 00000 n 0000020416 00000 n 0000020438 00000 n 0000020633 00000 n 0000020950 00000 n 0000021125 00000 n 0000021168 00000 n 0000021535 00000 n 0000021632 00000 n trailer < <8041F9AD88CAF6FB09C37B69A6E57914> ] /DocChecksum /D8FD627DFE28A85F382AABFE16FB29F3 >> startxref 21881 %%EOF cgreen-1.6.3/doc/logo.png000066400000000000000000003302321450461175400152110ustar00rootroot00000000000000PNG  IHDR=sRGBgAMA a pHYsodIDATx^ \Wu'z7K-` ۄ$ž301ap<1C?c; f ^ 6Vn!Y-Z{oի'vU[:nz9u<'QN8ZF4>>.j(Ǒ8>HfDn Pr*$ld6Iƣy$Mj lSڜz{p8Elp'lxXHf@C2:d6t<$! lxHf@C2:d6t<$! lxHf@C2:d6t<$! lxHf@C2:( YmxCCfu+f!g5SD\@^_j{j"_ִHT.T;pRunnNѡC4q\G˩pYTX KR5 ]ldGW=L=a=zljWz=/ S~p< 8ܾ&D#?hZMs~s=0ݐ8Ν4s4h'٧WR^NC^d8Hc/@1wu} \{ \vͻW|85̆YolF:1wgu~7hW܋/6'0+ڰ> }F_d\o{= '0k }_H A2f4.!r"k5^A2fぇL5;7Ђ7 eH`ʐ̆ˈx~K:^~5yhd6t\vW0 qmEAZ|Q2! ]KQ {Zx'hImhd6t{A}L6! ];5̆$6X>~̆$6d E.hވ6,d6t~Il8eӪI{Ŧf:$#p{ߍ ;1::O>z0r~Qu86+>Zw)̆i3裴哟@NޫBg|cԿvl8pqG8r+-{׻qHl8mȶuņSGiɛ|nd6()f$ᔪ ~%E` \{Qv! ̮ov|#f `xV9׸8$@C2NΝS}3=eGpRa46to5(;ĕkco0Bo3?y/7=̆iPu| ~qQO0S\ 2HfqezKKu]4+nOs}ٟ&=} l8.c7jz. 0}B2.3?AkC3 0UHfÔtHh~HfT! SR޹^"0 ^?&T2=p*! Sd6УҖO~[L{[| m!ǐs+7b9y+)" 0;AlU&=?:022qoBwazf8 02AͣRȆَGhEO`ad64D{/ʊ,?4SpRad6LPz mSAǦ̎U_zXzʩhW&'mfb߃" po4HfBw8-S{ Nbk1S{0ݜD1ml"{8^^G)3NDN{RD/x4ul2 N+f6 pr_7lf N%̞%8uι;4LFf7YlSkG8Ő̞8pAHaG#Cz}8Rʌ`Hd^KoV^>3STNbǩ2']fJI:ƶӏ0)0=r6ҫdv 8L$g($g$`̞4zf NojZwJ'Q$9YmgMIn۶dQF9n4Ht\5h5gn2ӄgo[Q0&A,QRɼ$VkQ!vfݞJpf5꿤mQ>Hf0ۧL0i߃)8PfdzQt5f y?CAb#H-eF^س>iwdȴ%Q +eBjt>^ 5)Cbhf<]UNfi"t!$: Ϙ)Ԕ>Tqbևu2' 3@yNO)\n?hӗ}lcv:cL.:ٱ$R+wDϓʌt9Nd?(P<\ndݽW*H7IVpIiv\O%5DAHIdJ=rD'l72 o.1͝p^6ZLbQL?u+ߟ/b|{f :vլwMc3݆/)S s逑]"*>UlUr*uVҥroϧ࠴CprRVyV ')gMxm& ?z>$dy]+9|%FGbG^V)jҍ2B^v羓{7qɋ売^'v=|o0=I3MZ\v^C |yw_)[iu3SIfAP'kyvt|4%C4FJ"17>ZJz;$sN^O$MDd9mٸ $C2 lTW_rY>zq{h}J 8qy< l"$;УҦ1S0p\C󮸒9kNEHǞ~]&9 o,?$n1*XG8pBQ76Dcqiڽ4V݇Jߞ{hbR' .s<~U&y}5%}GRĹʦMSA2`Z!xD{/F \:doS^2t聇~H+xΆY:-O'9͵;hh_xyItvoW$cc8=k{:z.S76'kJfWt$ms# 0x#0|͟ G`(ܗ?]|R+y&$%?swh#0;non5u뺦Py'ʐбge}txq [$3d?ɑr˶x2ʘ-kp*tգkw0~|]}#룓eMGG45k飴j{z.^/yn;ԍ G4H?HըF‹/JN I*Mi>iϙ3 /}\ Ţ{9ZV7G I\=)ikgۙ`ZdZ m߃"( %.Qe32 ;*b0S[ROv-IͭhN㜳$I_ Mȋik?+t a5@wweZKd}ȑّk]kLy&IcdvĮKgwU[ڦY1)3k%P5ңFe8bwv}LJ hrrRjaC0xUKtD=48oO}-}Q.Gc~}G+R{V{쇐Aad6C2p(El{ވRS0q#mo#y?t}`c yݧRIN˒u"Hr"'EGLvJ:{ *6$4]&шV jn%OFkǍ]¯ur}iW?2Be=Z\ X/ۭ5ӎ-@cUz}c/8(B:%/?v5m9rjvϣ߽]Ҿp텴`9LҊyU[-kIԊ>:4=d˗d:ݡ'Ymx636_8thcٚ)\s5GPBI9uBxd8'kݶŹæYnU=6G,;/D8Ndt5GTU% NPs$6#Ӛ7gFJm$w>ݶvgN&̞f/eIbAgBIӋ\;~/م?4YtUf :R̖r"fG[j }6ɔb="mH䞞m;ʁŒհJ?~a۵kmݪˈ]O1ifQ(=O_h2!WgOGyy>C;T}?.ǵYNWz>_pӞ\KwֽG^#TZLAщ m]<:U:evqfzp:XrNZֶqu v|!=rQ]JBA/=#}##hxxHڛ-w=yPC#g>/zvYWBHvQ%J52{A2΍ϕ>>f}D=`c]=\q4ML7NhsMz}`-g2GnFgP~1$f͚ }ho~KO(t Qy=6LyםNiF(Nb/COC{6)1;0,}7E>xeNn*p#/\'keټѥrN6fCU&W}$aҧvfz3Y/Mב ?dL9HfL7|3pu0b D%h\b_e_b<rRP"b9D LڈU .a Ts/M|Z3W10@~}|FᙛRk38JeUZߧƾ6Lʌ&5(+Ͼ3R##"Ms4GzɏX<.-%1X m7Yqƨ +ԍM8޴o |j&=ǣd)I_FT*7''Gz̈́bU&Y͇ϫ-.*+ONRZ}480HեEJCSlj. E#Y.#i1'7/L^(l 1mWL8P^dhx|f탏i`6]S^Z{˟S~pL0Ghk/~LA'veg32{=1 US~&}중i]}j5*OHu"J;YR.\֑̖"--#M/ 4t-?̙#ʛRH.c$(i\RʾH}GeۑٖfrH9͖B2ȴk+?e&'/yyn@G$[p2ۖyb;F7~O6%=Buv푯Bϰ%MT'hMGi}lo2.hf<9pgiH"vuu_9L;detC"{ګ?i353>iA$$}S!w:5ƉUP]_ ڐ jMc95 (tB uW1>FCKl+oSv{h(\J>p̽+)H&8gUn)vO-'{9D>)⾥ KiA~DNS ']OO!8G6ZJ?SZNop2?QuO.\j{D,~56GBHgGѦvϐJ=8ֵSrBoAXʄāCCx?8x:$QVe'\fZ?#/}}}400@'yԶ9'< AэU*d3ʌ\\itD6N0tim3c6ʠÌ5M4(z-P@UG !/VHqQ-`ڦE-Q5eJ˥DCʹm6ixuj 8 } @r? n2}HI<&WXNS%VufIoOẗ=i#鄑٧/}ѴtA"Ҹto1Smt. 02$zQtHdC[_VS2 ].)M$JR\[Zȝ7R< ׌L4!*)C&_w=wӾ}~3EQDegQZ0""7j^O3ed=omG1k,g\3G}9E =ytN\i I}EJ4FNVr>!?WꄾA8EzGt%aHߠ:ny ?cds dI4Sgl8R[M [EgB}DgvMstb7uMlx#;$J‡l J{þ 4L!>=:͍Idndm*=q#|S#G'z5ToFrȦt G9Ɖ ]_Go~t4dѥG$R7O|aIr.=yr"ݮ']QR3q%d6ONBe_(Vz*toe'_l8~m̄ BmhZFf$azW)8ՐȆcM;0St̷bQ.2 HaV:22; CڲS hΟISZЎA}HmGaʶ$0mˮgw(fXb"8G\k2GrT)%\"}X&z7H+Fy:&^T8ss!ϓ+VO&*4~$ϘjHdñZg7[U5-~n:λֳ&fZPFIY18\OT'jORѴOHm5CT"kr)6]Oddtf$O.ͣ>O}l8&^Dg}/T]/ϡD}l؍)2::"H"Vmnר"QUQIm#%6$}b bHj-QC<2چmr(Ջwsȅ["y :s% A/e$̩w P۵[lME8d蹺W$wF縛w8IY19 4qJ('◷ %3=z~ ](IVV%"%Syܑ~lmPjǿJ[mZF?8#(5X f6%E_2<3# >[$q] tIh sEG;:qBWu*)v\ iN/p+ ˺<ǿ_NZỌks>^i\b2[STP+;&:DYU Z-R,ΥW2. ɕK0zQ$O7~l8!k菻 %>nQLONkn8~Ԧ1S[M hmXH꼯|W$@j{8$m?CiN=JptPja߿_2Uzsqmjwn[Ffy`sa>jC@YNfDln@rONҜyOsΕG-/-B@k:[d@׀vI>m'_5{mfUSRg:'|֟{|02`F }pÑnõaՂ*UUahz8o;s qHհF[wnx٧?Ķm$=44T#'e OǭIfX9\E|V5-lhԂP}OھKy+$.8z/sZK\^oRQǣž'$۝uK<7S0; }xTL%!Mr?e 6-(3rv}[c1SpԿv8y^˴O·vkRPh+PfԣD[Qih߾}%!xEVG;3pcW.x6| շj""/P+ OnGϵM_%Wգ|=a!xt͒ߓ Ͽ.y%^CyًR9&Nuqq>SR'=ax\:gMԝCsl9G.iy$K94WwI7X*>=VWȆSdu^ӂdˉpa),b PQH,1huF4NHpSHDB;UIKѸٹsp;]%kө-VpYܢD_\p^͗$ךT^q^MgϢN6rWOM][n׽LP59̓_V^$iHߦ&菥m둥cҖDv9z7"lke۷s9D¶Djʘˌč2#6r^gY-T(t?Ri``OI_AJ]%N(6EޙB6gˌȦeķn0Qu# K ,S{/7iVHD =?QM N.?G"N ~f3&}ִf'>}swh)S[Fg\{w;uzn3Gz>)T!6ô:`.ȣcy=r*j;qh_zZh"]5Ǘ>gWR;WЉ[;쿧n%njNnm)RqԚ|+2pQ$H|>Ya`Ts_@"N;>hfbr"2 Ȗ5'!Ypdv.yFtj/SK$q$sʅ9mO@Пbu ՚87Np]KwKs{h[=1^G{~D %8ۨ[iZJ^K1IsќxO#f=QSmqI|_1N:ž:rn#?*,%AZ;[b݂KW^NX+ϓP>W>6ˮ:JDIEEYuWu."cqLGN‘KpqhÉv{֏id2Speo8_fN2#Sߢd~Ɇio.3 [V ܗ]U}KTBKUvNFy|-C!=xȲLP\yLg4;|aМ1*WU j9n+_ Ţ^"m5O=z5ycP$*ol;Tm^g_Wϩ]uԳqE YC 3SpWD6Lo|i4J͉((TpIz]'Zrn5uyKp:!={@_[qkz.7S3o NBfE9֨͑ZB'-!}Drq@}@Wח(O^xDo.G"uU9Kj]!4h|Ln_b(8@ay|қg0QukjZ^;%Vh>_jӡj[KHkdTHITrX rNWT1?G+h1tЫRbpOԹOy H"cDBk9L-u$6w@)p{f NޫB~s:儎_ =58b $I.n+g͖h^]R#zI{f6G€K>7T۱ǘse}64QraBv6ׯ_O6mvnG&s ΚDmGp۶V~<™U)Pg9~bqCoY/oY`SsүKpKG=w;+ir}Xiv9,Sp)r^y'K۫7g0NAУ"} p쵷 ^ky n1lGQ٧YwELtN$Yw馑Y̨r;_~|.։vB޼CU/97 |QȢ.wteI_K;9&*:RWۜ/ ώ@w2aUh026nD"$cBK&8+ak Jp; I*sTҎUpNrI&IH9za uVq=6%QQQaX=_( # f39ͱb Zv-}ٔ77 l5wꜛD6^_C<# };5ӂˋ#] ui^=ue&^D ⇙/l[<ʸ$x:[ܜs5t*7}?]:UvN9Y.s'Igq뜗pUG4ᾬlGOAè ӓLr=ߑd!@'~7h7pRڵfjjxmxN=f}Y=/JHi-tfƶHI32ʗ#|}Giͱ&1_,"Um:J??Ƕ>&jUZ๴K(v3O&yGz|rߴD!3ǥ2[7!?jukBOS.(̕dbo _u/wwv&zZU_)3stN>?'v̅&cu>bq@& y{״dYz˭HdCWX5-Hfge_1Sp2.f /l'9QݤyLq6;::]#/t9qGAZabwHOo{ m|EzB!Obr98È ԺyT1HS~j1x{&,}.x qJb9 rm|:~lDQ#,քODɃt]20裴k S"`:uZ6o57YbKB2#IeFt) Jd\IEgSz!.-$Tt _m<*,ub rU.%zӴ&&&詧 U9͜0$w|Bڜtyׯo{ rUF}o*8^D6gƕ/hWfhZo\:%OqG|\NQ{*[P]@$mTDY=G'~1|} Gnˋ"Qab/x)ߊv|'?D6tWٴי셑-6nxZMM 4q:?5SS_[7MkVp_wï%-kvlC @P]^kz/b(f'TfQPNM\LǥD^xi?v4NUDҸCIN;K~/\*DT#yZuby]BsǘQhQܥ !ό#7oUk_ j(=A-]&+_}%YZ[~u3h̅%}s̜ܛrM9/>7x̫5YUgWf=7~iplZ .Ӛ^=kZǎӈ8H[>3'ˋ _- {m=T]S35==z/wf,3')#l̘}xT.£-'dUTp.pш 9C~G? ݾ>vK-a֙W9e/Z&K@D/vȉqym(k†wCЯzĦN'yg[$^t7;/uҗG#^ֻH{ams9L"_tif < kf5]/q֝ԅ}|EiJNh$㿤 ~!_< xu:HFڀ9V!/vԶD;" G$Yvޜ?\ e[GfjcdAqjWV:Kq,dylaͥROڗ^z>sޙ;[T9sr;J6'7LgZܙzLGmx Sd_Fk@R#=y֯X T(V4HCrīyOm&MiUݐ!i9N.CrUEID[&Jwߔtl'(?)}iO.8ڕ愬$]ʹ:wzNdvF&ӊu\$K_f STվϡ€N@pyAIG^f4wl?PPy/HPi3N?QU㬪o53_E35kG>j…Oo@"f*5µqU #\EaR#'Tb(֯=*Yx=|K2ߖsyĔ }TUҷ{6α:ːu8O~J鎉 s!̂:sK{I4:PO"zj}NjǜijwAo,Sq͑Oj_9ycOcīIxÉtaNhAB99I-o_.ڀ5: .3 C6oIVḫ-S3ˌl_qyNw՜8WKYɪvZUy3$cǤ1_аj AYڅ\|S{mڿ(BArlS598+"sQ4/T4fi5] ouVnig?cp$Q̋=+mУ=w.&/hҥw[t~ˤmw/Xq*#d͹Č^OA/=T$~OiRsN|`2_!WL  E"fYj ?4C6PuoZ3?iZ+>Q<<sx2"[=B8lMg W@H" s<=Y=#OmܸQ"Ty*:Ӽ~KO9xmE 9tl5Nx;x^F\r ]tEb BϓzvmLY>NjGe]kf|i:<*ҁ6{D9VmwƜUNb+'&2~N'˓419NܿJi%t2 yMhsdp7UR~G>:0$ >I#̾袋K/^v\)W3kW8olւI3p $CdvT._2SpVa`NN 0f }6]wOКL\wL\<*6S'AlӜsa4\_+70GBh4Iw\jT\dЕ58t K#?;vm׿IlgB_LJ*xLjE.=js^3z<-V#QYЫlRε/閫ErUvX-?sH*}=ܫz4Ҁ]xsϕ]W片+}Q⒴ ?~xh<,>'L&cJw&֋%kk8Y;iZ1-ك/x.~ҴN\1izldH9E\#*t9S:$vc;i6.Q+xNMߴqrmSڄ+tFYWFd^C6Np^CsjvM=/tU}^-] 10R_|Iy6L~ު\vc*R5᜽}Y̮ w)8<*K.F ִN?ωn£o%z7R}SsSlnqڷo$A akbc;֔~ꛙnfon#{.Xl\k\" Η;0{%XMh> <#<&wLYYfd߃Җ}LXϑ̆Yk?7Qu9q/*-_nN^fl>2#:‹YÊZۜD8jscΨGDsUgyu&~!=MorbBټYo.Z&Q'n.E!E~~1H_Zqּّ]f^=&sr2#m]Rb|1MVJz7qV~F>v/x/fHx|y+;<-c6|yͺd6JAzgKi3u|VWiUWum3-HfjY[)יHNr.5!E&|S[҉@#MC}]wJ=rXS4T2!\% IXE /TSrf&\!lsjf)\:?HsyQӎ@94zLr3^Nf7Eָm_Ŵx,{/#Wo9elfV.IOJ3 ڝ_{>/ٽSͳ}nsn<3dz;Q{쥇=y=%is 6Z:HmxTyˁk-yT6gN8*ӺHNG%D/˝/}<ݖnuQ{NJ~$jrGҗ̇PfN1!Q'.Z^#U#̎fQfޞ>ry:|]F罝~eH[&.TGg$]D3Lkt'L Uˑ89]LLe[?dX̚|{f f Ff9%ݰ|)ں}'M Ղ_eZеL/(qTӜX囌v8ʏ (b W*F%~ /Ж[‡<2aq_Q}_~Xil i ?Α%̣WK${>Q(熟+>Ggn>v3،Of|ǦǢpԿvĹM= cDztO\Ε$tI 8:4-[$ߦロߧZ*č$I0$8],% $_hKD6F]K`َ ? ̑8s Fe QzTU$8mNdGq$|S'[o\>f6|L Ŋ|Դߌ wLTyVӺ{'T2=$i5$OI򵍑徬): ]}YgGGݗ\ͧDQy\~+-[֞ebGyiG9}L_=_,ȣydLBTT[BFh6 1Gf|ӂc1k8ĉ¦1"iƶB?|4fvWfC(VEߋ< 7vUK7G^dp)Ә3N4YOc8O#}#43N5?r!&HRq%9 Gٽ"G-֒r-a.YA󳦂9l n 3 03Cz %ohviBr{kF-eF;wSLT^3p$1UM+KB4'+y Mi^ܪ"i+E*E՚ Dm(12E43;ߦ!o7oO6۷]|Nty -)_Uǯ4^"W̾Y#s֥W7wHf/T6ٺC^W(@c2)eUuZM̓{~w5g(Ok/R'?P76'GX='jsIY:z|3:g$ruչ1$ 0c=iXgZcƎ~Ow) \`*HW5NQ_]3Gfg|MxhrhHmud۾k?H%"G&j$6w# 5QvҾ>Kh K==jX}q̐d)Eb9%_}5 (zيYG= ìzr8G5ZYaɒ:YK:~9u~/]N]j|cŨDKv9"f=%+Xm$?&?-fM3ƌLfG2L?AkC32ʌrdv[ÈEXZKpy ?j2^M-м|;rF8s;mhmܻQ_x;$$WTGYhNr)|MoV ( tg*/O.A{5a \LR5YVrcIf13<&3^%]mF;⋦~N5#Gftim6S0.LuةPZ>#v)6FLr4Im{ӆg6Hhy- =JC932[*~c-f˫T#}cN] 5F9+HV%\!G}riAe 4J9sL|@y~ytv< mF|Gy80S{rfH}!ӂZ`&'8C?\!i}#$vM۶mjz"< nq"aɥ5l[JI=Ἢ Nsny<-qFQ$5m]3VXh Kp"[꟧?0C<ϭ^W4 띫sHCR)q0ULTM .Gc(r y5^jQ$ոJLpRT)*x^^J އ-[ƥS_m+܄y:l 82k03SW@Q|Ow)8ewm`|/ra? 2V] c\zfvP]GQ)W%1!jn8G^xDݿҮVG\@ynB9e8#K~1*cxOn9Cq/f|{qڷ3/s9_Yk5}]Ss+3z%]u. W( i("Ibo!=MrV TOoocRǕ4?'(dFF" g*hb69I[#q&bOs N$PMnUu5Kb1])(.#U^Wy֝mO03/vT}#8q:,| }*2%ӑ53'}6M6kKPcS᪓q^ՑIJrZ^ZAˋ+hY~DO9@y|88n7I#jچ#W82Ô40o3ˆc7^kZ0tZ߲GYĬI`kQ@LZ&&%Ⅽ>t(edozݚ#LJb~[,<=* =KBQ곟>9=Oo~iIe՗KXNdS!0Up9$!Y<|q`]o?Qi[E2f2jc05 .3bd7}FLѠ9#Eˣ}_( 42%;N8=6~io+>Cc.9"Âݖp(jʎV\͌v3uLAKNGC 挪{/JT弬^> } {Ҝi;S:ٽl;ReS~|λރ0͈HdO]ˑ@fE;Igxj˶ԸVrP`t!0qI nu[jY;>z9$ >=_)`b|h U:}6OZdA}2uIt}2e ˤ%"[#6|~䩛+z]:-ոBĮCh~ {\QszW_N#x;jZ\0vUjNs_{mϩ6TG*E[]H-dn$G~R|NǤΡ0kvN8jPI3kΫ";ۊhZ'LeF= mSp8?/7SpQ$ʱj*%<}2C_υ&= ^Σ:׎z~"פBlm +24=PNl4R;dY/mMi֩> PB5~ϰ\P WFyzɘ_*M;-NTƥsr?)_$QTtnLZ[Žʶ{BL5qڙ(}Tyg=L?|a\3-~ A?:szwսk^Ixm;^&R}q{˹-G$韷KC=DAPWh4$}q=O){|Ё d޹wڋ箓+)( b\}UNHyw\2GoN\Nl`iH":gnmd֪6Y͡jF,^Y ~ԖVჯ|ߗI$\31Ýs82=^_ lL1r5)izAߣDpH׏;Zwkm_.qkMFkd1~k>W͆Y~~;sJSg_-6}ͯXxuVt8zlxHOl*;$&qI"*IEEjj]<;Y}8<{`vք~fd-yl>樯IPFsznIGXNbEΙVbyi9ͥ9^seH-#yT*Qkj$Imi~_Ww ׼5`_}]u֓FzZKep&$Nl?Du+Ni2r$ƟOj#Y'<9֯6(C`oU7 0) 4iΔǨ5=b؉(ǥOf@pGH3G/?<<*{Cyז.>9;\҄Nޏz_HJ^dNx3j".8k=IuCN<,tiҡ;'իWSTE=_{#m⫷:V>\ߜ'ErZی.sω7z"it=q#=F=[.02;Kƌ Sa.() ׋H}2e$όP[K JW_@]'#=PW_ˇ^@/Ԏח鐕#h[M d=טt״a!#q(Ib yT'D98C#}v];wJ STi֡4YWN~&S=y 7ˋp2['y<|^g٫Ϧ+WS!_ur ~.,}D7ShZp$3-ueF4zf g?࠙R2".\QQmIԋיU#3*rm:G37K{9z9>>d$gK/M1G J\ߌV#~2;ѓO>)C#=U:n~\N8JTv_{zu \ȩE]KuYZ2HqTnW-I;=|b@[ E7G&*XN^/5+u '_נZ>h;_š,1u)3kiu#>e7'bN6> I/#plܩ}*uf?73eMrpZuU26^gm}}wD)qxf3}8!޶طYۭ|4:Yύ}޶ӏqc5yQq) ;@{}>'^*ԂT4q^S_Go zt][jz+$vaB^K o~HQ[2fv\ê e7fO_8=rnsy^ϧ=ZZ[BB~M-}KΖ(&Gyw,E=O wj~1]~puU2> @[n׽L5QUωFrdaq`aLҊJn'^+ʼniA[щ474Y$V6~em_TՓce3p>۟ZW}.[z%LMc݂iYS|Cs>@8qO5öˇy>gn;f$WpţH!+FCj,%Ϋ~hWzᴒ_r*+~G!k7R<sP_\b5Bя;^E謳ΒGν8GW_uVK햯O WSߏ|^pd6e&UWk_G١ _2='Go%w4w:ju&Zlſ_dH?dd!|Hfkaܾ]z_O[̣f[?e =(yҏ~HjtIfh>b e MK xNdG곯3!tgRKP87ݚds9SI_gh,x>$E(M".l⻱^IJf[:R~mYS,eHf|Q8ɚNR[./Gc'!qHۇwH߽񟥽}][*JJ?ɍ_gtbʹm? @dvFg+[ZE:yR2DJ6Ck{u^&u\ujHV\>iy$m@mS#b?dvyN{9}g4'=C+&:]$ }Mf ^68?DPGsƦjU=upDf/#9 ףztH=ffOO1s>bQG Ii>(u3P&~c]9qief}`w}k?pێNҏ3x`x~O~ۡѡ`FFu{I;#yqA '@=đ|{zVw)?o7(Q_sB.uxz3 cL>_PS#Gsie^,mGI'jCnIm#16Gf׆Oy==sJ"}m6g6@d3Wd:?5Sl>ٵ~=N\dvsr:4::*G8ѳqxMOАN 'cTM| S'jaHخjǜġbJ2lOv]uzNr:0?PlS$zZ=-d³^NԞ.rbOW(h]^bg%>hocY%y[yCB^о{iO7_74i<) <!D$9mElO#V~:s2ۜ_vfRG> y9{GڋTlϞ*e:Mf{W| R93EBuE2jDD4_0S;P$NUsȡ̎i&雜u8NPq2ێҮ{"'d6't"nG FNX9DU_$85wy=DjXZQ>s2{I+.T}\O^}i>^+'%=K$#,\(}WӼN|/[Y]P7O8I_ZO'3N3?V۷ EnI'K'D-/{I|?8:/uYxJvK<%- ;o4Kܾm "Nym{PJnI_m\)+oS(Z"+iu| 3g%U8m˄j您ov]ʌ~hK_58˺JOZ"wt93o%}jQjLO}-2|y͎WV|Q z 8m$v)=І tuXwM"BB@FGE>C(T~N՝;}$\*,_A+W=,] EGd 7Hfv/uHfόdv9QdvmxIwaTFq2ێՍm42twe7=~qE!]!smMY:jE(S[$dDb\O]exUwx35r&ulޞrW?KI͍h%KPOOOY7oi?_>uCϼm(P!5/_|+ݗx9-X(8~ח\@uj}z]6W]SjsP?R5=裴Q;9~,V Ogp~I-y0ZN So(:/z=״` :>(m=R󯸂v}fD"mv;h>G^s%mCt#xߺ~˛? C_W^*ӂ,S1xyҷx`-Tڃ|^H tFF#ӣxZ <7q89#4e㶏A Io[DnJO?+Z޾TYYzпv$RbԛǾ,~?=ͩxu(dիW"k[ͬrTpIcaQGFp}^Я̻>zǥd; z7Q[0Ы{ZOڏ!=»o9C͜J4h?GV} na3KoV^>3]Iu3.#;`j9:>]'/jَvGd3O7'XR )1Y1>POώ?%GyvAqR u"pU}]&869RQ KT)kjrA>0,ZAl.$g3ymހnM$@-3NqbP,J{Yԓ|>O-X?PYn9u+E:sb&FӐ̞>d5?l_o61%vD4A׿Z;w7JU5'Dn&5+yE"u򚿴2J0O'm{5{' UP8;5Dv|][#c(3y~Lu'6أ_u$=_ nBuN33מU7w6x\̞ɿ SSeB<QH(ԍrQ_mmٲ"G oʌi 8U  +Uhf/,lNq#4M5*E4isˍt"&76o6U+(Ρ=KJ{Iq }d.5GL ۄ]''1[Է>89Cz}dVu2^1?{UO:yre}@/bL, 5^^"}iݒ~95 fsK1rn+<.{}n.%WI ]7͏˽z-gf3ğuZW} lw~k]=9f\{ҍ \1Nj7ū?hLݿ-TA=>S ?~]fhk?]GZ/вLٺm lKl=Qwٵaw>mzj5ԧه6l6353ulEb׾JV^$whM/L>K[o3±5K$x?_Q$ pom8&~7hͦ*(I^06%1gR-щI$eFyH8 I=ОnIM'/(D^39߄fy XBd?b ٝ\si;BMp:f =N/uĘ@IM6 *}}j}t< ܹ4g@'Xv9"<-(.޸Jinvd2'|8yHR4OpǬL3|^M3L=M3'v#xby4%%F^-M)c_o3EZץ0 |ҦhCkn?3_@),kז,0SsO ]zy|^ı/c/Ji<Wz!Qagsx|QT5{gn4׬C׮y|ie%IxEgH9UO-W}p9.+S04쩮_8AZyڏT'/ߵՏ[{4SGmKF'5>9 EڝL=Og?,@;d=S3"|_Qu|2{b| u&$6dz0Onl&'9܎ۗ-]rF3$8js*T?! Փ6j&$'=鑾ZR`2zV[ 9dL-wT*Nh3[9VfHMofcGFΤG4a‰3;sy488GI1B/l0"$%SD=jպ]y/ۿ^?׭|WX_5b*I?u+M=ӝȮ͢ 6/?4SJcK/,Hj=U <}ѩ?7w33GY<dd:KtHvPԑa%z͕]-l{Mk.Ӛ~!/o Xv7}ϿIdLSxж?;=_z-o3 SNbo/B~rAϿ=>::~d3W:T7a12vY لFC ?sR=?4yA}>y]HᱲJb#%׋ߪi3ӎ摡GzAzY$e&8`6)W<~[cRI3hԾ[xj޴=߭?ٔr2w岕eWIܳ%ܘ<:ݮw”up~<08Ci}O?_<sbinzdi6`̪=p)]P[%AW _ _ '}Vo\QM9kҥ oxEҖ 92{f>3%Td_9|^|!KXhQrAL%Ȫ;-1=8vxTp9~ /pʯa5XY"U dM}::y~7gGBA|DB`cyWp!Ikmk6-]jQ)K-ާmpp9 % '<c%&TU%xA{8ƞT۱7W3}r%үG+ <g÷ˑy=W?Ds Nv/9S͔l)>i~!3A.=ٌk0mOiTΠc@i¡_:_=hډ=tRio}v4s' Re LҶ($LSDv"Gt i~ttϓwI; *բFG!ZHdp3[eٚwx!FV4^DFoa۴#< XG@|[=1vڰnK^!"uTk'(!j9o?ual>($OXNħ?4sDo%dԇW PJ@X#*/-We91t (/=qpig'`Tb9VEQ3sz^ C6 _ː &ߔ?6OMIXA}؍ERF.^:$Fx$UPoS97͜Haڰ~\IhIIE^Q9-jѬYŬwT%aB^Ob6n0צT+W6MN8%6th]#'G0ģYjC=yxg3}/PgXjK+ouOܡi:}4M 4=495ISch6?:ȃW.33W&lGDޭsa[.[|L5hG4Y4#Ggv> x~y t%4}t8>Bg77瞣gSv__l|{2ڷA5qlI= /w{#įd\ Қkihh޶_ҶhT( E͈GaE:O%/hp8VӚ)3`ְ"aPm%K[G%J U:L9E-t to;<ߢc̒dsw9 }d |$sR1xs2ND1{F0xEf8&0 E/"ꪫ+`Pj"˂5%J[X0b#ćK F2:.jkִRαQQ>a06qgǏg>KO>LgEIo}wtfɌ"->$Wߏ$7G1:>q\|=X/BdĆOmQ,G½r_[Ntkǥ4zѨ<S4( CocCvit,0Y3vM;dݐ_Ǔ ^%elk~fʸoN4Lp[/I)od& A5U?*kՄ"ѥƉJɉۆ1>Q`d|?T%k֘igRS.PUt_s%rۋQ3abۍ˟hv$XOjYx c;jð_Wh6ESޔSU>E}<U Qe\dE;R"f.s~>/HWD>}P&ڛhL<40#Q1P0 e 5>>qLCr7/"n6' YK; rT5b xO s~`Y $G9 r%Lyب{fYC0#wYm Canc10Wx xb9!=:"+]ҳxu_iF6~i[jlZ @Kw0B,D^eTMy5tX^٨'NQLQD'=}=4MЙ3gȲ'yzXѐlǦ\_e\xfWmYޞoM`޷"F HhWRiQ`ns:Yp M[Bha-E*ã5GFUDmNWJ%$ޯӮE'IkԪL#Dqg/op%jiYxbc7W>i)KoM]?>oF'ݟz|4yañ8!zks|k#Φ0kHW_}5KEԿwɲB.OyZDX{BWL<I8qx 5W@ȇ>f.t2a&j)SZ Eh`?b #h02~EʄQx)ÝaS?:C9ۥhiƗ6ݰ&$KR(r']r&\]X>J4j乡27 *"}f3rftNjNH* l,7y[ F !ć aBHIM'h8&؏ǿ/_:-:MҴ5EAπլ@\@#\p[Zrp(>oP&8x׈BPF#`Q񹃢pڴK9n+CBhW2Xǎڨjzawhܠ芑+h}t+hunh^Ee'>.ukv|P=Ԑ}aԐԷɞVC"?[I_Ո ԫ;H+5p\(3lP 3-NzӂL=t/RڪEQ?5%^j>?lorҔN):eq*JRE Aub%‡|v?gfNBâ4ԇWL 3/%=)j'q:\#CFoYчT3 \rʉG84M!bro;)u]T9j1uJ9$0#qDjT!<Ӿ<jHn{ߍÁ?*>uԊY+fxֻi"0P΄> xgJ@ fu_Z ٗ_tܐ &|”žM j 7ҋ[Nx5[:rw~˔懾A}FB¨!{NůIE'}ԔFn͔Jx9eK&+"FFK$""7tr bPb`]9^4_BM^< NӎYum`8E6 #!v%,xv#_6C9ߦ|-xy EU m>6d6 ȏirdDQc2gMQ:G5SD=1Th<7H\c^,!"OiV~H2&hNtz>ѐ;Be!늎#LJgxzSl.%ENMDo,stxr*JoS DG? 3,g ً1"Bi Oߚz6#[X .?0s `!WƦ1T4a k `kU FIgB^@:w>XJx![`-p|tT@h$rs+)Y&U b'TfMF3\^PȲFN]I ., `۳cUQ2LXU\E__YU94q2x T,i4HȲ!gF)u7>`ȗCci6>eǴ)t[ 'Jݰ@oi\ v:qk9G"NJCAɘMyL=8\v2%1q~ux8P2'τu].<_ '֓3|>O[L~aRCD>p|D{{ UKۆl/9U}6}StSk=J fNQV};]7|fN:EBC4Ry~n34|њ7)Ifʢ_EQ: ԐԐ=nGJ YꝭxR2Z:GRᙜdxXo, R:<j#٨i'ŠDrrM^P'<|~bH>E|<*MO$'_6*)55[^6K(q?cQ\E[l~ ~#Ćl{? ,!&6fN4 }Xp#dՓh \~)iڍ4"1Abx=@=c1O‘O^"ÝP2'Ѿ1?;4M1ςQ>Bb=)zDG;Jc1Q^$z %3ۜǴ;p?# K_3v0m$& 7 ۊћ<:3}Ft zE/xB6J2h=N9|OA8z1\ץbH6m  dQ=q”pRujpRV?r*C[c̷:KJ\}X8{<1[.&2]l('S.#u֦̳b7x(Zx_ F> ÞQZ_<7 Yeǐ"9n$v1 a|ծW,bd!{TΔp{5%[z(+^?Ϛ9%mò c tk {)-,*"4sBC,' M =Q12^+ 1^(m硐1ngG\G'~=4Uv NӔm梄t6Y!X9&BkO, 6CVɚvd`͌ʛy?&"'!UQɵMOG}҆73o~6Bߺyh m?ȿSc39?x3{4sif?>6iSMߴ0kN7fNiD@6ϰ- j3>~tk+{h`j`lPEQNQyjqVBa"޸Rq:??jaxLO޿o-xεӉ/I~{e{8`y]yߕf4]v8S1:=:74HgD=lzҘ=7U[o)e8.qfѮ]hݴitTDZve@c,`FYjB)*jhS'c>pB<-D8iO>0zMx"$Q0!8BG8WXʨ iLpz>KǟȖ̔Df;vȱBe[,s,k:R; '%#ț !f~"Æ 7EukrD=^PCvgIS?.7S `Hk=x^"QaOJ1(,>j`h6:E' m[ }N2\(=Ilm4^mXt7_rڳgj5m 2dl$Eظ0& ~ 1aCQ7%qZ >/M%D<ߣj*R*D0p=CwGwsMu#1YѓelyC]d q?{/B[ 1AeS{EFT%S;Cv>oQ.gIx.R]E/.\uZNf+eFLeSR *icFlU?cG8R@Mx**!+I拎10Yx Ho>tle8(2_J!{rE 4%5DF#6Xo^]x~{̜054Ol1Ѝٕ8߾)@A&23TO3sJkn.3s ]H,=,g4OGyaؤ@HDAHۆ}X(糼彲hmq ]VviG~dza$pѴKv%OV%{s %$qt8ntDHN-z-B#r<c9&-v۞T38' >6f|]%p}lF8n&S4e42oS=E]bMU+t_G鞟NS>:qoTiǣɳdըě,4>0,F卒m֊$Y o)6q k&g.@Dž@gxkN`ROVTDS.D8Yg>c#KEy|yğfl=h_o\vSꚓ V`Ԇ!UXXsr"8 <>SϡUh4)*8% c"yH(S"7u$l p:ϳjcLIY(SLIY.j$I ~G$tgt CAÎP, >NZDt dNɇlJ'-F0Ζͬɥ;%Ry9SRFI,4Ӆ@L윛yI`cY`5Åk/өXsq0sBRHum*]Q>6;9Y0g9sFt=g?Yѱc49ࡍ !GpDkI 8Ĝ6_耯 |mxToE3־7{ &˔F4v2֣^0 jRN?࡭m7dnz::1BIϝ&}:gID )LIQEi=l _ISR&Ιkg6<Ċ:&ؠeT ?Ej JR@ 37l&4H2QcvBpn3aM_[A[ϒب6V$%|LIJ(oPlx޲1!(pX,tЮ%t}ttӆD{vS__T,R\܉|l>-SX~ ‰! 'n $ zJ418M#5(]͋GՐ7>R| ._CbWuUǓc4NE<5"t%]z?x5qfQyB>MԌQ\w=ykd<7ewj{ϿIu; zWzo 3ұR ^I7}~915DR141E*JޠtI%SZ= 0`ψ׶ 0f gvEYѭBؘrXPժ|gƘbfad"z+5Cr~ J}?SM4QDUUnBE ,ߨ fv|+ӬRa9~HE>.%eVXHTj |Jtn^pNѩqOґɧEѷ~M0][O=> K ٕ:CgԃsVM M V){+XE q}.s߱r|yQr0fQmA;)`U*g2:Nzņ[ . 3EyV}9/BRLcn_SY:|4b#v]R!*C4%e1ʱ'`=t蝿:*s9+sElJ#Ke@L_7?V$WQ L>))(ʅy\!}KM>))J/~7#f:ͱ.q~Yz=IԸ%>J;;gLܛD,_E4f{gϚw妔r"P 8p;H9rcUlyt7]}բU9K e>/CQDᕊDh՝88/>OAX#KjHX\ע"@%꧐3\7}r|~Ay'? 'M4Mtw~I UkUT+rH "$pJymz>(Il尞hӲBKFhCBy#:7^rEںu}oP|S"$|OC>w~?:/g酏K>+~'$T3%3 SRn%,"qjVg!Q J;b1brH҃W^~3;yt"tߔEl㊍l.E ixpX448D\1QYa6Qaw蜢r|Ȁ Mj\z[)8G'OaY1h芮cC#XzWԩS 9?7aHÝlbGmoכ̜EPX,hdphh3o8־\(qȻe ٗ_Pit,-*h>3nq"ӵSt6<# m /y|"2*1"hW_Zْ' /F:]9eDoC6S 3I5[LV$lV}(M2޻U,5ǭp\/AѱnR/u xkwxvrݨ盎Ӣ̽L/FoŔ^*{֐ &˔%Y,%">^BO޿KFS /Vg o_1U ˆ* 1W7`60 Cg9dQ^_E%K`_x㍴w^)TR !Qv718"j)PE>z~Ѷ;fRMHJQ?# '&Ctl8/$"5{D7`j>kN瑩l)"4" a7վiڱ߄j l/ڿaG8m&&}7_/E)_"*ү Ln8Sgp:_|!:gtoX[e-,q4OE?f7oVSRZ-tk<̜\C c#Ls),mo-Ko9}om҉|,v ,?1Z7DʱC3:VEQEIO*Cf2%e}hx~:/6zx!{}FpaA2:oTW2yP=[0l^fnx)) ՚-8 H g-!fFny(!7ZID11Ы]+{O &EQEmc?K60d_ANd6s,/7%EIĭS*Owg!SR1tG1Wr:Cu%$$ U"zҘ=q],Z!$$ŋsƪKe 0jZn~nڕ ijZ5J'DHj[T-Ui:?M5Bi:NBG'hۖj,yrIe6Y9>4"xݺ/ ORhO!M! dXMMg}}OҟszWe6Kd[>׊n3a_+:En' Y:&ٻϋ=MOҔw)Ȟ[ųTdUd->A -nO˵Cqح8f\MBxNeFmZ3КIVO/Itz dSDT#D T1Gs`7ݰa ӗVtͺkhGT1Q"!y%/^:π/UKyVɎ6nVc\ Ho?L[73֛dB>3oDoB\cgM)6m2tc`6:ڳ1P92ܽj'%3$NrH]+sǤUmh0CQ њh,ނe{Zbh`l@>s7UbE[ &$ٸ+}(nu_]q3(0*"!>{ :]9C35ލPWʱ=vB1Gi›SE_ y=B 44 :cpP j7n]eUx@*76rW"WvyBJ/kEyc|x` Nʹ2h0(*%02j,0{ s-$Քߧ_oAMIY d$Rٌo+|B^N1[lt M@E{4`Ph,ϙOׯ!ntFp{1ccdP|N ,D/I b$hlzLTk~Y46F; h:!fq; ת1ŽջDg6(߷ q Y5B#d 5hb,@\D}8^B<45:q[jC>#w!)SxkH%ͬ]'Q;OmzK|10c=^ٽ?aFC\UfzW[i|l&'&)红ij"BMxC $DZE0\. =Az+z uf|ϗz $<S)V*D?~azGEHCmܴ^YH) (G?$xB2Ff4B>k^W+_Jʛ ~LBG"ŗ6~;a%̃ҩOK6IJ< 39HC֔%}$=̈z΀1ėFЄc`c%9g6)q*@ @E)Uf.\TN4%&SR᭠]'PԈHHyA= wC>ɨ1;8~BRvۢ6`PbZm]?'B\"x*# hJrWn_C7'D<%r5ƺa0( MBa}-r㋪v*VEtndέgsGOgMYS#D,!;pErŐxqR~(%qјhʙi֙4}?|ƇES9LoM;>=>6y)U""Fio9C.45> Y }զwzoi:)(EehE{i{iB_TTdxY=ĒK털I".F5tcځj(,ʹOΝf.YTO0% gJ ow|Ad~-kuʁq>t DXIp`Ȯ=j^`ASRz!g@VC61UVc6On *Phh;DWoj?[*/9mw߬bYMg V{[&l:3moFmi3B XjGU&hrx^=Gt>OsD\yl1;D2c|DQʊk4ID{*4c$zMr[XUުLR-"ߪ#n-8 jn~@PҪ(Fj,ucI #s9 `fND t赢isq6.Bۈ|#||P7B+ T3²vTO#~K6.5sɣstxz篛9EQzĹͺG*x?pXOߚTt  !FzNU@@M*5H 2yl Vy]fVl6~ix^3\3gLI9 -7mJ4YN#ޚ7-{OfCS I`Z1c`1$y $_Ï(gV">2b+4l(=A0uZkF{[d4g DI GYVmQS_X 0-l7\&^FW.>S\3K.U0V腳0h6 uNa?RTգS?/r'✨Tܟ%rx?(OT6V<7Qϑm:PH7. 슈$9g7>_:$Ga*}/ҷ}PiΊėe"#Y!m%rCo4.%Sb[o]lư<>H6vm! red<D|F/}y駶&`Oy_y@X50"^5|rHN;[ءE2H~뮍SStS4sfO%\; StDFV_^F xft18t $ D"ȬǦu惽))4xe#Νf.L9bJJ776`Z cJT#rhr rX<:?ƖJ^Q:@itԔExCXn\D9Ѷ7$ YVH*bQ#GH)8 A8<@L?~^( x[=M.o9 |˕BѱN=E>ԙStnb&''q8ytiV]H<)' *J'$QnسghZ=K 6c, =!-[:׸vhUإ>'ISx8T7}SfNQO 0emo_Z!f@cfX:">AJV?6%CQ o'ɪ&Yz-]2QT}co2$F:z/sJ#i9X,a܄1e詧'|{yPQd;Ȳ+2ʊQMLMг?+!%2\b\ ٳ#9j(_###i&@y@T,ŐI.h)3/xӆ FǁWԓf.%HO-jrn3slfZx5ox#m@|>f.%c " crp={mԘ(8iNSx9SR~0s\f؀ ~-7>3[L)X:"0o/wv(JF7[MI?eJw|H{4fϷotǔOqSp׶,ʻyY6I%a|ƪPCxNwI9p8v]4lq>m>#^W>ղŠS#}r6|ξ&w:/Z!#I+ |7k5R׼\G۳cJS2x84t`Yk?fmZ+6;7MGhABg3U^-fN9r[8J}omz?ts5s馼{74KbgaĞ~ʗ';c`^!;`Ǐn{M% #fXEq X bhGq"P1EŔʹC#ôD(è[-ZĈDPhVhLשavħ-HEc܁3SqK3-^M!gΘmv~nDI4IK—%#Xxc`0{%H7[mzҘ=x[LI?j;@bKbق]F,aU `AӪUn:Zf+ nc3SCX^A`34!i:n?:B^B/h:EL5 |_$# ^ט{N4Wb1QowFa5O2$dfFJ gx skx^3.&5SR.D1SZnDI:7'KIVaF'-6c`ah& c{1I;kJJ=N /1%e/37m;Jjh C9ʛ]{+_D^K488( !w]ōQ;>N.P86Uk$Bx3QR@>AϋT*F:K>3ӤLSW'|ƮzUE,EOkUv-anTr jf~ Eq-t>&zbzؙ̃W8vN'Y:Ɵ$OQ>O;ct4EШVmۭiK !M\hW0,Ƶ!š0DȭwDۇҎiZ[ w)O%LDQ#}u^,!mn) ׭¿>92}(dUf.}TΔw~4w/;) 6o44kߨ!F1Ўnxg@Y,yk^6,Yh1eL20v7mH}6L0[}֋ߚRrIW6XjBCeiAjVA^9O{xWݲ= }bυ c=iC_)c? lQc`t )Q0WmIEXA dѣ>J@#?yTqoG}߿կҝwIjEIaɆxأ ªIr32ϽTXIIxqCSS%UT{eN$4TⱫA[u6)@ ׫ 0:& c`.ƺ {;|ءjVEQweJeyf&RpҀ^'{m5FGj<u s10x)Wbqg 4̞|Ǧ*jVzڨsqZX*jpZ9@<M^%$#mSE7Юᝢ̓itp+#gMQ {6s Q4FEeD  Qq4eQ|Tz|Z'~$zl1zH>J*TyJjPQ6_fqX BC4UBfsh=ڬʣI)Jyq9DA۝'ꈶ6X#hyd+:3ǟ qg+Z<{[ZٟR2Ab;\zzҔF J/!flVaA34TGtr =Y 11n ìާ'ك9`-Fbxm3"1g6j=\Al7CCQi:h27UǾC?GL=HMΌUS:!M窳ds]^ר/͂A;NhUh׸_]d\q*wj/CbMeY6P1bɼ{/{h.4JkyR$*r LY-5!I,3aQ|BM¹sW6M![?&;ʆo^2%WPҫ$ lZjh{̜HZ@72EWQXaj*I"H3)'Q*u>c! Vk" ͑#_$~$Iz8|д؄wj;?x M:fcm ̇/ 锇wu!SJ.ؘ))L^-AC fcŘ8܍]R.9Z.s8QdlتhRTZՎ1Uڊ ,ˡCU3ĭM g2{à R/l4>*|ޑz"2d)>YfQSEN|뛦L`81 L7BJt>Nkf,?%#<7 M30'j;?L) 10_ꙝX٠W6HCHIcoJJSr^ʻ* uxDR5R>T^'rLJ>]]\JWnz57UgdOD,rլȳ]\GT/d-M&Me&I=q6H^Ԯ5K0&yaHA *)(}eOmUv,wENj/d_5R$*5X-X9%~*5T-PyIj|$vlQhsx܆F|?5Y4qwB9m}8$&Bi)wFWf&^"n]{X\$*)?ɷ%0ETD: ER_tp,cxYn̒uJN|xms?RrYs?oJ㦤20h_E>gf,/f,1T fNiȫnI=t 4c¤m ̗zU?N֘Mt|[MIQEI c<`JeL)Tia+_IM ,+I9y0}oFGi"oF$'[ 7s@ :.L@띍{rK7T,uIctƮs"7 ƶ-ŞC,QPM秛Ts+?[$]q'4uUHتREvR&=]ɛ){j~*s9QxTE>_D>[-6J;;D?mt_[ v "B&Q1|vC\n\0FZQ$,kٙ!hkGɥ@fBʱc$$o~,QΒOi #)#t /Y/BONSJ?0ftaY2(D6NƆb-k :7D!)&ʇy1<"HkiVQBDy@`0hE"ZZ-";|P`>a)$DBV1KUW5 ڼ !|iT\l"K4)YA&a[+nTay6B^qq9p<rOp r^^TKTʢ 颁v" iCaoo. :wnBf>5b:\g9\!<:rLELtDZ#hy^@ϟ!E2Ok٫۹s'zkE}}\QQ,b!JKMWWqM) \z)e7WġGY(%)+G| 0̜r!vNmh|HX, !Ff38W]z֘wm($`J?R̥CLII+cG`ԞwR Sm`Kz|oal$&b1\0_,gvR~Oӗk M16%EETčB9g,<' EE˥a*l^.[Cb#CEo\^6ˢ䆡hdpn9q5Ĉ,?fDQU7`C5l|7PQ͗vцfQ6DX^:>"/$͟ !9av0hiEKp<{f[ ,+tDbA;H<Z&ǡ}DW rKSh͈+_pMC2uhCV0l0d5j+ %I-W޽{ΤZ?LsyG?}kf<;߲#XǀҎ,0b=s=xRNгMIQz8(zB?I$)$`5T1HiVWmWO֮YKjMP)~uZM6  BY+>,_H(2|^6_ FB镯|h۶m {ƥEUI/W2l=kJJVw$D-Ei$)F;#b~{͜2_`SCK19t ̟ygg) īoE/g,4y `[Fdȱ1tsrn}FPE\M>*\h;4^,¥xxNtb?5e,?cLo)e;>oJJ։E*$% H^|$'TR1W@RBV/nvB/^,7jVE#a VHovy< 9âAEu"ԍ 8*4*։tCVMW>G`kEPsa>Q*R.̉fjK*ݪ`[/} =?_v6Wo~{$J N4  0vQZHJGol̔M)Oc/5 .L2:V6:ˆd%K~%1{ !JV "*eEp 3*V\(UVH(rൢ{5Ax`\b,*D18o`(K!F h!bB$%$LԘ(KQԘ|ʐDHTؼy]g(N|a(̨9NvXm5\ct.>w'QꋐT*.ټvoMG$S'Sw 'ヒ4sA}uG5RXڔ7qΔE x&5흟y׭T-L \u+y;O~Q*R ~Y۵;{w/=߾l:K SRB@( rq$lIO֥d5dG.:Cˌs)!FnVz6f+wcSC9.E3X-VCkhjCd #x$8J7C#b{󢾾>9 }zu5י9J'02)eorҔe6i W'#V02Hx:I@߾3ЃQz6f6'뵓n|.q>؎"%BG|:>.hx8Ot;㦔\ܾ~Sbd-42qSJ.("d$%~K_L!F^fe@_eTBĒhF,&+)6<>-rQZKkDtźEQաyQTz % ruH慌!:6fG#Cu&5 3R ڬ Ed2TSLIQF%gM=jJJIf1n2\qߓt*Ĉ38dJYzژ]dCJ̴j*zKn!ƍiÆ (P"9Rx$dex\CCbNctUyܧ]PrH y>MLL6n(ҁ6 m"+rrn?k&r~U,;w@N5'1%%)LjE߿ǔuכ,ojb2%i 8M4Ĉ1 %꺮(6B:jÞ7{ 6_#]nw͚TqMIO>aJ(KUS˚7QxzsEǀm:bDQIχ)Wǔ["vq"V^"Sv> md mLElxf>F h|2Ll=FL76 ԍ_7pC,;pY7Ҏi%{c| |m QX9X(̶3B#ٍjo1щP#SO=eJJR|QSRӤ!f6&ptC?q3$c[FB(J7}c( .3 Ģjx2k~>G"k-/_~+ݶ95 ,e;Jբ)i+r-^LJ"g6 z&܊UrOc)w=7KꈌD%@Tɞʉ^qMK~~vkR&i4do'bDI=o.eJE K!N6hcy#]2ڵj]tE!޷laW$Ō?x=#Hcl86mث۲lV+RH[lm߲vlA7njX<ʼn$T$9|IQ=q”N=C(JL)$5ɃdxEMeHYj8-t6ٳ>TE{f` j^M4uuo "~( qȑE!;G?1 I,c@Y)F^u))ש!ycviVSREQMONRzf+cz,'+9-眲\FGu5fM8h; t3[QE{f˦]kA>ߝ۬Gؐ ZU"eѺ`5zjһ_^嵴:Ѷmc\Jghh:o$_`FGt.犀{FbomVD#DM_)i7Oo{k6 "'[&\,"?Oޔ#<"'/k|mg)+[i1xg5"| SJ7=dJt4x#ቒUt (+ ~kX'%)g)eoB*r왩=+G4-p;>oJJLIQN+վ&5U@H-'!:d1Ч18[R6dj!Ds\a& Qqdj5)z `~@d[wxcG%QwF?*JwIC$ziy)I D:҇X=^mJ$˜wKL)h2BSN@5|˧k7nJznMa#CAlL@4&}D_A}[uE?VU*>MOT]chƭQZf77A_ԓ0I>MIQ.zN-4Nrt𶷋OC*(YE@DaTC[4vavLIQEQ,dn)Z8RrчJAH m{E$:olJJx튒$a.eJD(mQ\ro$HhV/dh;ݶ.|8KA~;FaB{۶ɲy9o¼Dq#c  4I̢c`n4ӭzm0caI*-XL=)-/))3Ϙ̟)%JCl 1tx7id(J1pa`WVn׭ Π VC"fQ4))i.9"Y E?.ĐsC}`]C_=]sLz[i`tn1<ǡGDӮ⤐<.mJ{+.vh5X>m31. xxwo)-3l?zȔe$5Jx}MLgv^r)KƩ-})D7V.ye+J7I1)L)L>))̏TRIı6%EQAbfqAY,'ꆷ,Qlc`ahC?*I$l0x[L)T3% m<1 7Xpy!D.Rvm\smbڲ~+ UWiܐH MlϴO&Wͅ&B޾YXXBMU**7K`V0!no)Jd9vN~aO7}VX%ixي}/7m6%EU|NA,:r5(ȫn1%EI1fl?5;fJʊ)leM b!(HNCKD>AG9AdhVw=[E_K[drT(ມB%IOҚѐoQ]q -~nrGҤОdL⺐X25 v*j>تIw*\9ީQ4Xn0 Slk* 'EvOoswE6Z>F%m!WhpeSJ/:<|${kF-DUG@1}4nXTeޱÔIgLIQenXY~릔Ny))4:jJl xDut t˃޷uPPKY1N%'!-jE@BlW6մuVcCF8ux?ږHq8b준s n}4$X۶mmX9QDrd:Y~)z5sƟo|)JvXRc&;yz) DvJV1h/H^o(I&Ql{fT 1f7YaGeYwV}yw%< }"1xR|uM)ٌ?))J?FH1SR bꉚPt ,ˏ&^>+[I82f׬12Ӧ(2^0VV60vL)ٌ!SRő홝OA.g͜Pw_|vɟjrc`iX941񲕄(cΝ]&?nJJ?hQ0Z-PظETiGCA "ѕ/ZўtIymoCRHyG~JDV踢PXEBvpsTsYفC,|~:mCrISR (, l[YE[܋EkS'Gh \M*ޫwce~UobHKS_))?ARÌ~{ԈF8?c`eˇzf_g@e`K2p؛[fxG3'>2Tv˴<"*%*E*Zr< B#Euf8~Ép$Y9YS卒gh+AhXXX,cXP*R/Z_%w.~E{^1V:[R:@3>hI)ܗloQEI)]-N|KfNYHnwޭţc7о_ʻw/[|$A! ;磌L)h,܌?Ygd:].J9apU`>L?&" E S}Kʾ^bJ!!:}Ԕ%[Hx UgI3(5]VShrc`q=gv\FlWJH1k)eM^⤏08W+(gq $|O?/)h4$ko՚Ix֎p\BrH$IDH>)muG> ZHSPn_7o*$ I&X9ln˻4"5 (A>&8OC*6Uto ڻrDe*5pD!ΛQg8?6n)_[SJߊE8[9 @8 N!EX:AaTM7}E~ժ%[(cwmJJaͳBln%<.Fc6OHEbm*Q!S.pDʗށ++hg~ј0f(h2fd:(V ׳ټ_7AH Cs*?KBoRhm1md2YtNr2rcvX~eT 0h"0f)S_KSJIQc.[?g䏏9e.~njJJf$cHJ%6Fjf)OHkkEÅa$Zx{?J KG&[,yRAmFL这>Dm>ɭuYCkբ"=Aq`̄4gV[-)>/fJt{3Sؽx~GbjTI3:1.4nvw `J7nJJaMLDfayd&nzrځ!QW%"^!+o]U9hZEi-7kvVtݦt]Drgr;#uDAhSFP91r7AyϢ|͞%w,sฐ - ]\B8ԃ9On?ONI446~zVّn׸.6D仢 ܧDUe8}gs:Lߢ9ORorͳtg Yl'!t׏5 HlD:f1>4CwAm*m_YHn})e$!ChEQMNlJ'o;=5o(]| UgL)FՀnwvX":ҋ;^;Bi4^#'=fʒXcv'%̇ DB  mֆ+!V4KH?v !yGB >Nű#\FJ %Z-JzqBI=\ǥ칒^w/mb)N?^Rgq;`N[4G>IS]N'(#Lާ1|,c $ $^ #)9D  W8ОzC;쁄yu2%E0gGVжfAFmcq3ʋca"0dCu6M}Ql Ð#8prھ};ر6nSc:0fGbeG.V:EYUY#Ghs'56YIkvJ%63Mc !R( y5 5ƒ zjMyYEg ˔(Dr[n+oPe2/ jЈhhh[bݤR YBVنu̲4i43my4{HЦ<.ǟvbM:/r~rH􊡛{EWCh{2NQ?r[B[_>ї^[!Fo)-E3viPo%!FM)G\:I@^F|-id*J%C΂BGY}Lin&) L$7`JE{e|F.OE *X9Vr(_MhVEa9QX!p,ĭi-!/rgGy*EksX.9-DfHmϱzEVN2s)?Y!Fn2 q>/^'I#Ŕ˾M3(Ped92yĞ<$ژ]޾Ô؃r~1iwW <^֮]K###Xխ1M/6yؖ(v ERQ47Dkֈ(xuިT "eG,^ bEpNs 4Ĉ- _e3$%lF/${. 4%<]t (i'Kt͠^0Y!ď]mHy,q !QMBQiߋс+\.'A՘)2 qG2JOqd'tGW 3&uܡj5J7\Z~hKS;r;+f"i !fHR^iM}~ȧ>iJQSݶ{VұrU'X+PrH3꙽p q|!Fzް,UT؟L7[Qɩ|Ŕ:OiVS #\kJ_EC('%3 f8XtXw'P Eǀ,,ŌۨqC~-ǭyl!e񖬒U`XttȋU{EmT8'Eʻ%r% qR-玳l|;%'h o"jD|G6r0@:Q~bGi׉ *Y#GT&BGeu¼ nZa=e-^mJĿD9[r쓟CJ!FnC%폝5dWj7̥{]>'EzK':M?cw>,P9 Z#u0ͥ|VD&AhkBrw!/œ/+i2Kd`nS.𗦤(JVƑdJ慏!:d斟j*gƿ?FҞ $497=FFKEi̥&nً|^ ʐxcvV^_?DEiGݛAhxhn嵢۶KE=y5< ggFBQ$mG466NGy@率nnFz5իVS`ϻ"|~ j$NJy\6NsnQܝYJ'?aJϙ7%et^ʾ$貜X:͆)unSRCvߒY,:KFe+ 7f,~!]E",”ض-Zim;.Ԥ0=Rdɲ#Ch';}הCB7!tI߭tJy?))M oL)y,3䱜X: ^E}_Ҡ7"EC61(Gp0:XٷRajS.cmVvnU[BkOqQBmtm^xd?d>baZCE7ҖM"7p!:Pxmj9[\ocQ i-<b?=>?i?$tx;]:+l*C%TYޫʍq?ŪSH6Z6NѩO4 p)#~ײ1ĠJ8O$&y;@d{nՠ^ Ȫ!.rtl%9M)9U _u)e))F:#[dؘ[P`05)$ԶNc"QaY׊7HӥkG^L7myȩ94&U%gd|iu\o0 rvAR9VޢZ.)D!Mo7\zlР(GTQ?G8U m5l_UL:00G9>W].旛R68oJC*ƓK&o3ɆZN`o~#5aLj,3dِ t dMt3{rď'%37?fg~+tLQwRwS*΃Y^p#Ԕ&V:~Mrx9Ss]}߻|wR}2%%keCv좉V ?.^pH1 |)elJ@H%Xm۶n8pLBr9RwvH[RV!H2JDPc=FGu]'ZW\GUo 9Bq@y7*c;H 9LjD ag|!$-}W#rk~ꕦ-?y3$Hpd^d) 2?왍LjK70-֨0i2sC@Iy,I oʘ=:S.𗦤(qKFE -[&nxm\ R,r\!DVQZ|>Omܸ1S.{4a^gJч;̃W^$&i)-,$9noߙDl@%aNecx15zf/2,6c k42f[_kJ?))d3Dy~rSH/fn<))I[x 32Wk&SJ&KRz |.wPzYCe+a){ G^z)ewiJB[.yV|@'r*NZԆI4U.u6K"41ʢ갨RdM40tH,(W6L+44Qa֚Z(*[y%O4LФ=Nk!Q\h~zG^F/s_*bo3@ Y9(3f>hV߆>kToH+e}ǔ B~W2s g9i CznIV)Hcx?䖛gLIemG@|$Q"Nu|LY=`n19ze+ߡKA ARv_'^aWA i"+t fyyQ DTa*w n }dQw\! D9?dȲC/r|؎UBP'omo r"V,њPXOhs6#.QMj.z}XJIcx!F@RI-6qLM4Hrw5s{af1$9^:3CR$BlNpJL{ŜySRy26D\0X\^9I699ex>v8&6be iPz)u+ ڇ?eI bdd%Q#Ip l!c;t (+J,KW.]51*/3H$]*VȪ׽Δ˙oJJ+O#/EXel!TωȪxRO`9aEѫ"pf=?'rmQX,U <|hٮ1h>B[,l}̱Ԑhp@|w/PzɄ 0ps&\ 'THw7j[xVԢ]`U#RXK7Ľx)P۞Z9e KL( Hp 9&${y.OM23|ϋmق+FO ,h5f;)#XOOuITݳ>گ[FS=~ K0_^Ҭ K3nlӦ}gloKtβϙѾFnf@qu3ɓ74;$Ԣ*J:5iV_#wޙf@Yl4؄ZAN;!.p9Gzn>>Z[Yf_%U8UF<ۭ q:]pQcxy ԙ~-|u4ʆ+V>*z*`EIOGsY`Q_>zzf۞{.3xL>N~'y1/-c|kD?ƶl bl[nʲ4~[x/֭Y}/~gaD'GʣU#6a,/soǺM}Y/{ _6wbY7t2Z`\_sVWgW|{m/2U͎Qc6:2ѻ3dQ,=MiV_?I3؋==Cx,x<%ϋ-^81w09jY$m)w3G0/|DH,O<4CJu?wɦ%zYud..Q݂ڊਬ_UE;_Y |}#"ub>{Ҫͯqx'閧u1U,yAWcN&iܳ  ca֛?-/[`Q>zm[Ml_#t7xOO߶'z-‰xk}دwI87QE]BLɏbDZ#ZlEj.@RV ?͊EBTvۭ#m3R'Uk12`Wŭ;SϲN|h< zd,G։w| z_-\-`Pvp>~ ~gewt>_Ml9$cbQm 񋅽S,̞^Oh|d#c`vّ=exn>:׳}oGzɑOd==hعwb.ckcy,i#>wxCuNc*7fP./yIOVSV `NeT*il'脸8E P"uXfw<6dV4 \Y*gNEUqᩓ^4+EKf_?4RܷZ*“V eҌ"rev~pŎaT>p; Qzt!V(@gVbݺ#spɲ'WiFM1!=ijfmRd۶|D cߜL嘴l%e-]s̱7{󱠷gAО8&}l֭l϶J(y( ~ƆG˽ #409K# dZ{wfoݚoc0;`1ٍ7C9$;㠥e??q4J}Y@QxҬXTgCkċެE ?b;{J?vz ^1DZ\{ncx 5*^٭:fb$T>ZdٓiI7NYE:]E*y EЭݺvRNUo12U{0W~(^UMt'{:yCeScmv]kкKՂaV#Y.ͨm1>9Ll"[0ј6>gE6&ō1`I-[߻0 xXl[7}Gg~A>U }vfod?[_ fjY>,?9l,U>nmƇ;D6>;iiO*ݪ^ۿfŤ:'SW[fa;ſQ6>* aE)cx[DRuc`| *lZ$Uk-^"6#]H#g?뮴4[D#jhƎѷ/;hؿg0d=cDsXmQx[>wYvȒC/k|DO4>hh|4>l[>&?#|MɶFUv85iV\Q]mcҬƟ}6nU١Ha͏f*3Q쩄ysޛ&TsScfw~ªPHjᐷ=뉿 Zgӏylٲuung?ߟ.7[~4~hhמN_eЭVH/Nն#Ӭ~Ws窽܊_EL.2\TŅhPWliT:;8f /i"^M7~3+z*`8fv}׾6> 2:5{~"cd{q#=K?oGdcLד#b,h|܍=ӣ׶gc)qlH+.Oڹ*;V2zw9z[X#LyNEv,W<{ӣV~/Ӫ}V{Vcn'2~}K[HMM96=| h7VU=z/ΎG ؛@tzE9/rR^#Ӊ^|ݵbjٝs<ͪ1򌴢)֠ȓ]_7&w^՗ Gz?5~{dv>Gg][xf5Gd/9*;ag8Nlɶ|lٖmk=?I;bʃ/ O}2ZoOU١'ݾavDȲ5B5>OU}7wn)oxҴ@9L=OGnꍯϞg!k!"<<"o[\;==YQ4Y/O.co<6ּ>~g"m}.{_EYlm}?(;d|>>-˟\͞i7z193 d>|G;}5֓uk~ϳmY=7'q!W]Esng㢴j=[ccn'qgW+# ('ܝ-ػ;0X\d gO|Si/hDU=Vn"VT>iEy;J⊋EiUl<+_Krc?.\RQ?/tRۓi-sdS|Q|,7opr,bd=X3(ij=^D=Tkw;cY[4 "VyʴjUear7mUdۥT\!.Dg _>_D>.d5ċm>y+>V(wTĶt_;ګ"_DܮeO\<\vz=yGH!w!_ֽ=igK&GĢbz '&CfUҏ#'iLl|KS;9>kn˯u-F ;?hʞzeOխ\gӖ KŇNP'2;=t{N;5l/&yM .{T[l ΩݷcNՓb\Q׮H}l㙧U}~UߒVTU4 _x`L6~4{@>p?psڋ4+cg#BߦS/<ٶhމ>\5>gOf1 [LIٺud z~0Lo9eX=*sN[L{PNy4v?8N*-sdGnݛn|MVUX.4Tqbt]"_UF{{O;U蜽em{kWڌtNZkm5Nq%맟\~2^xCuG[L_~EZA=@Zlqr_lK:Ŧq\Z'9v.B]=oyyiT#[1c*=+.!.%Y;tUU֖_<8>M{Ӧc[|1zLlMkzz&-c&{n'yS'+q_իӪܘV]nkK.uX'ڭ=}wT9SI6 EInm lY~Ip<3u/uwn#dOeS]9Zc@6T*(."WkfǭU}EVVӺkO0{<av֗&{|,۶-h0L6ѳ1MI.j{;96Ya6{5ζ0{ ;fG佯>-1z<*;gZUG>0Ƌ6^KtǝU:yRj.ʦavTLFe|wQMK%:he F阫?-; iUlhW"Njf$ĭq}ݍݳ>Z'q b֥v*]mʱEZAtzSG>4k.hNJ/d˨J;[8c^ 421@XXcn-Fl> ò3JzVJ"D/ x, wQ{8Ng3 W,/Ϟg4?_|62-Yc났'Zx/7~ضmQum_4Md7>7_)+FoG{&2o>-֛75~.3Σ.lcb|<ٞ_5>"2:'ͪ'ZFP?׉ .Jً[^rI|>>&f٭lпjUv0e \xΞ=av/H?R!6T܎)~l1MێL;i\wMKəCCiUMKUI+hUWU{̵*)*1N@UYV 6Ѵj .L+Mk>@)Sgk[);2m=(ߐ }wUpyYf6zN:~+#],mX7h̎MSm iU'g*6.VȎiH[Sy'~[ O# ?_+͎tWlȹeƴj 0fxTՂ`6Zu =vSH(ڇa8=-"ήy_q/;7L#_>m4hϾb,l$^84~4m͢2o?O}.j/滞:z6_Lw0NTOT7=] GS )N8W~ky }+HLWs7Tٮʤ=]P!gyɟϪd79VEm]쵫H<‰0!*l 6_t^;w}1c <9HN?"kr}4/fP<6b'5C#ΞlL&?cats4CxӘ[#wlN)?ut|NG_sO=mz%iQPW|s~7[ t8EwubvFnE}ފhu"kƸE`OZ} f?Si Wf Jzؼ-mol{?!.ؤ30s})]UӉ}EX;SzdXS^m;A`|ͶcSi&i1PU^e+hi Ǚ0;9hݺ,tݵiDU-;iVO1<O)>Ѭ%/I+&.,GvQݖ Ҍnk LBXNLcmm\oOrS^.{5cl" uqw eevA~UEcf&W~qJ3bHGUOUf9![7u Љc -ZMlvmzTf̡g)H:;N=+R{PǍwh]qeoI+f"Wy8#NTPSw/̖0Ƶ:1P=5fcvVeO7[ӗ~[6 ~~}j/Rw'cojZiѻiUMGfѩEM1d:ilji6;fubcl\;1P?<xdno牛f-ݴ 4^:v#/-VHwޞfL-ڝw:fqzӬ5m|m7U;UHCʯ07Bؖ9@ݹ*K8Es0bѴjf$z|YTAbZSEFiڝ_y٭oϞ7Ҫ}'Ҍ:j%[7@0<¼V]G%jL1Pm:zLY;8Vݓܜf2I3sO=V@O*!Z$ L ;Z0sLYv9no6=fP񑑶ndM¼J#>ׯy>@t]3eT($񺧝^‰0{q>xiC4=ys;.J"if~kB=~sCiWff.nm٪x;Q(D` ZQcN}Wf^١LNٻ1 Ҍܘotu}UiUq-Z$13h-0- ؏fL>vn؜Ia}ͷeFܽ>Z'瘫?p MD[Uh+9ʫh@0%h~riep"ލ+TgOAR{ClgŷًavkE dreyE+>V'vVfn9oȫTUXv򌼪X5vk8ʧ@]6D!aˆ m+PevE^0v'mlg>'Lj1@9_Y;$&yUehTwݗnߔV2|ɥi\D{? sM{kEUa(qOEhA 2y'˥yzgGi5@q˦͔݊.ťe;{:{G|i-=VUum=d_Y~E_dq:W|PU6ΓN"0W1Dp{D[&ϛ(u[pAskvލ, ; ziH PZK,'EA<=OJU-$ -7UuzMl=x?}'RWc`~}߻'n9GevcW] U؍_H4ဓNJ+Z%*_zǝy1;?N+⎏/ôj#`Au+ڣ[uDž߃.@z4mڔ⺲PGح-㏯_у9UjUlUvٳٱ/x{BE'.2Uu#ܭzv\0lWߣ59&6PXhTk"(کe1z **90z)>_nկRuv\RU6s׉CYfM3/Uew_FUl_z׳uo4ۻG;rG|]*ڲaC[[lU=ルW`YVjVF3ss؟G?K/;giҥ6O׎?#ޓ[~{BD3>~xdO\ѴjyIxO"lO'jV#>y*r 8BܑVv#܅8:c\*jfJVGT彆Ϧd"T4'.,D{ߥ ^<>h)F^{M vgIIOTvmY{ *{:`5+U#؊j^t7OO5zjDp Q~au${sFT>hQCY%/BUvAE%P;,}e{?OM;訏|ӪB^'N/{"؊P'"{pӼx.4{}fFU+WU9{\ߵ\lNl|g!͙@fc!{CN?=ddžѧr?/Ba*O{Evк]#Ӭw½>#=Ot\}TNy4+~߾-#¢o(l yc uv{1P}##ٽڑ {W'~Ҧ&{Ӫ.^lf+{7SX:XdcojWH~/=xy}I'bna]gSTZfwVNEle֑͛l4+" /UǍ罱Ёv] ̞TfųwܙV#̞_Rliҗ%j+[UNdg0+ lwDe,K)`쪅o|wq㙝K)6tNMV2|5qmZG '~[iES3؛/D`^]Ƽm\@yſllHq)]z)0{m<1~Ʈ"X9/Ia-{ (hAeӦGɶ>l{|pAwa%e<2.smtnZyo/nnR+.O+? 6]W [%US0G٦w_Vy;ٝmf\j|sސVT_>˧mGzJ2sϫO,t˗ٝxʂ3=;oGiQ ;\Z'kҪzAA5uodhz;̫W:ؽBNQP;-UG}|AYDa"tZqAW^-Z4xy8D{.)F]KJܣ56~ĭQ--@Exѫ; #4<_V|sj+=yMi~qq-rкu{kwMw|wAi6)6}|ӝ۰uhsAwS'vkץU7<=ԎүNbG2];}D Ux#n#it+}bc{_}V)+rS|CW| /ݽAENP P?jƿ3;ル+W_'!zGX.f:Y]ф-xh(溴b:&6mji!VP[6mJjYVwoʦbGNm5Fe6@EVvCULƀRGcrK'w`Fډ*.{Sҷ]b60NqnOڴK|]m<K20;ln;/ L]FUv\8_Y[Ilؐݙ;:y>f"P=h F?d":ޚV@1:cTelf Teɋ!.W 0M"j{m#6zf#_1=R^^*(%<>ʦ:~@7t}8gY $B;6s_3c6\kX:䦏ᨏ|E/*;^.j|d;(©+6؍_ʿfʼcSTZT-iV c>Mcs9(ށ4U/tJIl:]74*>*#n']QSOewe?H-lҥiյY5DEv'/ _riQNH3ZnGGӪTeɋ*?6 ,n>{ݗdvT?g>{H_9 `zungӞ^UM+Vd_yUZ7O}S|s? V__;h+Ҥ0SGO3%%4N:Oe6_Y^tJ[Dk<ɋ~lɫ^VMT~QK}Q"MA" Lb?TSY^tٖӪ3c0Cv#^ NQոQK۳vjڊ4ư)`&zAAuu@C/ ;hPvg;[vQi;R/;.JTKa&UŴPQtWvbP\c6eOꜪ ޢ*ij]+>WnLTqN Q]l?DTe޽>:ohȿtPmn\;ѪEQՙNjݨڍ]#>}ΌC`oTeS]9S տ4nMΩ!.̨dnj7wUi=ѫ{ -?A1G U@'F㣣i9Ul1]ՙմbVi]N? ޚDcH+E7_'Q:ɛoJ_2NjfwA']^}کyuoTR|<_x7ectfcEֿRfUv{G@U5TǺP7Yߙ-ykҊ{_}#}?6yz7xY܁ȽhҴzO3[UٱYElؐfѭh=D(w`̔l[U١'vmI֋<ݨt50/}9h]-,E;O\h}qLʦ.UTޑPd}C*=aC֋V"Bw_zv 9b" Uds*g4h_ҭ:+ZWB]0K~BK5ۏoGy '> ƎsG>jG`V"ִz[VT;(6iS-7UgN4av mۥ=bM$ooW$s0>q,:>vv7GI 3JbnwKU١-F06 Oj{ nj=;zaGe{|s ⎊ui03Q}Wf͓7ԕpbEwIHDuO7N4avAE'_TJ~`a;zaGe;; OG_δ9UAuW#}EMYkDѴe0b#|#9vG=odv~D=)N `|0hRM]I]7[XV#|#&.HN=lGOvj^!o<~GM 8.#VU {Teڵit.h1WbnUe\ UL49Jb4;l` YAE< ܘ~ ;.4'`n^!'%36_wmZ)=fӵCY}ǝitK\~9U;Ԯݍv4;‹Ҫڄ%/h%av 3@+ʦ/\Vs+Ϩ݉|ZyGin%'Іd*z\E{ѴꞨRo2}WΓ7ջzjb$+@ !ZEUvuvٹEfoKݢiV ]זjhCk VR]]ebnfۤW6SڌD=Bٵ0B"x[yy0wlTeWM 'eP;(4+-6En:T]1+Vde6̑ h5UtShquצUwʠF-F0fwܙWAD#h@{,;iFVϱ͛lh/R$qb̉F+"bIQjcH^Q) l7+pY Y1LE]v[(U'Yq-[QڋLfTdGҋߕjj>#@mݲ%au򏵨HOvSw*ڌDEvڋ@]cQƐTyg':&.ʮiEA߾-c'@ ]fRh{l!rUm$.G:nQ7+WY1ͧHlz-7Ur*bfuvV(AАAfը`JV(S曜EN"~jF*.UکR$H+о? .*XU+N&@q<#iVmou4Xꢩ1.{oZKiM/H?}ۭy"V<6~ܑ0]DEkTF+A9-?-ڊ@m}iV]=uGg2{d]i63E!L+j$';xƙ^Dʹ5*\,6[9^4bw?UlgAv+Os'ڮVTFklJɨ~e誸;䠗<)uvoGdу⊋@ qg,;ox8hfW*mK}j7O]mٰ!5geOrszi=s'̈*m`ɫ^ ?HjziF -vuQٹ:;ZFG֫_/PR QEaJTiײkoN>{}v'? Hꉾ.M+.n_2)ڈDOGPvin=7WfL5 uKoz~teox駧Gn:>: ,.TH L͜E%Zl0xK3;wj)R|s;sBa\V@UD> Te0yk6Z0_Hxh(= P<×\f8!b3L3Te06B?m"Bcoj~aD#TWnLstRZUARqR@U r;U{'̦DӎP;zL Zly۵@bTVTeӤeg*{ٴEGj3-!6PfiM Mu P]Jʴi$RTBl^gfUw-òR /? L49f?^?pz:<7zuz{92ͪḯ2j|d$SuV[M^򴪗;ӊQMGMչQKEEKO_Y5-eDTl9"l:i;cf̄0P;ZLDp]#žkN63үo{{zEilDLE~ئW,i3BaV@ehU̞0҈6$?lwIT`zj7~SXUx<ᓟJ+ܴb:qBEbL6_wMc\Vt}hs$̦S?ܘbcΥ^2T%̎W/ fOu LU#>jjlJ/Z{1lj\E/;NoX`ުf_s]׾.`Tg_]T:WҊfS9Q=g lpIK^h_g}IZ0VPcx7 ;ll*?mZCMEDz=aCmےyTԗguk#-!֫Ҋ.0;tgj#̦ݼ9OsO6c\/_芪G}.{eegOnD[fu|˖l?~l t7+/?<{+辪+o+-*ul وN[6nLV0CM(:a6ΛA يb{O;5M @azul7"*xKh cA݈bbÁ5(#6N c#2d0h_Nd*;h>ʴ.A6 ecd0hg6lH3`g1TE V)rS|lf@ٙ_9IwY;c?F{ 5;h܉V6ֱG7.4==1'؃cM3hfW]pa~27<hKޝwf@DAp7>ڊq#1Y|NtjlmE:O ѼevGYMW;V|mԎhL49@KolӪ.{k_V9O|SȕGG#'q"'hlӦn͞mӣw+Ϙg/v#ӬtS= ,F֯o+ɞٰ!=#u.0h*mt[T=z凲͛#"!6]g6 tO= ;QSlp!csǼ .R M*#s{!E-7GZ'׬^P(lm~lGOwe[6nL\^o8v]ֿjU(a6q}xyZ0ٲaCud${ncMfFaRfmUy#i@7fPxl݈(a6nft0hѻJ3?a6n,Y*6a6n&ѿRfm1~}Wi@ ((>a6lJ lW~a`ͺ4vO4i@Q \[Zf0յH@Pdl 74U'E&lƍiU/e0mUv/@oKN3L d5^4<(2a6ئMiU?}*@ 5eҬ {}Oʕi@ Fj/wp4Pc##ٖӪ~׮M3N 5̆ iVOi@ Foп4Pc#cN3N 5eҬ!۴)M_2(a6z?(a6ԖҬ׮M3@ 5̆zٽi@F^fԿ4 PC[j^ 2f@ mz,K P.loؿrePl7<( a6s5o3ҿjUPl͛Ӭ(a6L[Eڌ0j-Fڵi@Yf6oJzH3D 5S6#NH3D 53>4%Ve"ٲqcS`P&lM֬K3D 5"β4LP#[6|/K PNlё45k f@lٰ!iJK 5uޕVe#{lf@Y= /O3F Ԇ6#%Y>4@-h1Pnl(7a6P +e&ESi@ &lܐf7삋 f@ g%_2 @ >4+'U3ѐ@MѴ*lwU2yCPu*l|d$SKU;0tǝY`z*S p٪dԇl llHq@.#`ZۑS P/l`83X6J?Ԑ01Dƣ؟u"v7< ]*K.WJ+gOh/r7Vԍl`Znoh(+ڞh/Pol`Zي|#X^ބnE+@?xƙi@] =fAsސVԙ0ثnڂlf3Iwܙ YiW|lv3ѐ36_wM6>:icǾLfs2>2=r凲ouޡvC;\ުoK KO|S-7e[6nL]93.(oa{"Z&g6lFk|yp=f*lfE @-H?@a (:. .SS OPTIONS .TP .B "\-h, \-\-help" Print some usage information and exit. .TP .B "\-d, \-\-debugger" debugger Instead of default (gdb) use .I debugger as the debugger. Allowed values are "gdb", "cgdb", "lldb". .SH "SEE ALSO" cgreen(5) cgreen-runner(1) .PP The full documentation for .B cgreen-debug and .B the Cgreen framework is in the .B Cgreen manual available at .UR https://cgreen-devs.github.io/ GitHub .UE . cgreen-1.6.3/doc/man/man1/cgreen-runner.1000066400000000000000000000036361450461175400200130ustar00rootroot00000000000000.TH CGREEN-RUNNER 1 .SH NAME cgreen-runner \- an auto-discovering runner for the Cgreen unittest and mocking framework .SH SYNOPSIS .B cgreen\-runner [\fB\-\-colour\fR] [\fB\-\-xml\fR \fIprefix\fR] [\fB\-\-suite\fR \fIname\fR] [\fB\-\-verbose\fR] [\fB\-\-no\-run\fR] [\fB\-\-help\fR] ( \fILIBRARY\fR [\fItest\fR] )+ .SH DESCRIPTION .B Cgreen is a framework for creating and running compact and easy-to-read unittests for C and/or C++. After compiling your tests and linking them together with the code/class/subject under test (CUT/SUT) into a shared dynamically loadable \fILIBRARY\fR you can auto-discover and run all tests using the .B cgreen-runner without having to manually add each and every test that you write to a suite programmatically. .PP This makes the TDD cycle even faster and less error-prone, one less thing to remember. .SS "Usage:" Discover and run all, or a single named, cgreen test(s) from one or multiple dynamically loadable library. .PP A single test can be run using the form [:] where can be omitted if there is no context. .SH OPTIONS .TP .BR \-c ", " \-\-colours/colors Use colours to emphasis result (requires ANSI\-capable terminal) .TP .BR \-x ", " \-\-xml " " \fIprefix\fR Instead of messages on stdout, write results into one XML\-file per suite, compatible with Hudson/Jenkins CI. The filename(s) will be '\fIprefix\fR\-.xml' .TP .BI "\-s, \-\-suite " name Give the top level suite .I name instead of the name in the \fILIBRARY\fR. .TP .B "\-n, \-\-no\-run" Don't run the tests. .TP .B "\-v, \-\-verbose" Show progress information during run. .TP .B "\-V, \-\-version" Show version information and exit. .TP .B "\-h, \-\-help" Print some usage information and exit. .SH "SEE ALSO" cgreen(5) .PP The full documentation for .B cgreen-runner and .B the Cgreen framework is in the .B Cgreen manual available at .UR https://github.com/cgreen-devs/cgreen GitHub .UE . cgreen-1.6.3/doc/man/man5/000077500000000000000000000000001450461175400151535ustar00rootroot00000000000000cgreen-1.6.3/doc/man/man5/cgreen.5000066400000000000000000000020631450461175400165050ustar00rootroot00000000000000.mso www.tmac .TH CGREEN 5 .SH NAME cgreen \- a framework for C and C++ unit tests and mocking .SH DESCRIPTION .B Cgreen is a framework for creating and running compact and easy-to-read unittests for C and/or C++. Here are some of its features: .IP \[bu] 2 Fluent API resulting in very readable tests .IP \[bu] Expressive and clear output using the default reporter .IP \[bu] Fully functional mocks, both strict and loose .IP \[bu] Each test runs in its own process for test suite robustness .IP \[bu] Automatic discovery and running of tests using dynamic library inspection .IP \[bu] Extensive and expressive constraints for many datatypes .IP \[bu] BDD-flavoured test declarations with Before and After declarations .IP \[bu] Extensible reporting mechanism .IP \[bu] Fully composable test suites .IP \[bu] An isolated test can be run in a single process for debugging .SH "SEE ALSO" cgreen-runner(1) .PP The full documentation for .B cgreen-runner and .B the Cgreen framework is in the .B Cgreen manual available at .URL https://github.com/cgreen-devs/cgreen GitHub . cgreen-1.6.3/doc/tutorial_src/000077500000000000000000000000001450461175400162525ustar00rootroot00000000000000cgreen-1.6.3/doc/tutorial_src/.gitignore000066400000000000000000000007061450461175400202450ustar00rootroot00000000000000*.o *.so *.exe *.stackdump *.out constraints constraints1 constraints2 crash1 crash2 crash3 double1 first0 first1 schema1 schema2 strlen1 strlen2 strlen3 strlen4 strlen5 strlen6 strlen7 side_effect suite1 test_as_xml0 test_as_xml1 test_as_xml2 test_as_xml3 test_as_xml4 words0 words1 words2 words3 words4 words5 words6 words7 words8 words9 formatter3 formatter4 formatter5 stream_test4 formatter6 custom_constraint1 custom_constraint2 custom_constraint3 cgreen-1.6.3/doc/tutorial_src/Makefile000066400000000000000000000223711450461175400177170ustar00rootroot00000000000000# This Makefile generates source and output that is part of Cgreen # documentation. Files here are included in the asciidoc source so be # careful with what you commit, it might thrash the documentation. In # particular, be aware that non-UTF-8 characters in them (usually) # makes generation of PDF impossible. 'stream2' and 'stream5' might # generate random data as 'actual' values in the output file. That is # the way it is supposed to be to work as documentation examples. # Take care data for those examples is printable but looks random. CFLAGS = -Wall -g .IGNORE : .SILENT : CGREEN_ROOT=../.. # Point to MySQL includes and linking for the MySQL examples ifeq ($(shell uname),Darwin) MYSQL_INCLUDE = /opt/local/include/mysql56/mysql MYSQL_LIB = /opt/local/lib/mysql56/mysql else ifeq ($(shell uname -o),Cygwin) MYSQL_INCLUDE = /usr/include/mysql MYSQL_LIB = /usr/lib else MYSQLROOT = /usr MYSQL_INCLUDE = $(MYSQLROOT)/include/mysql MYSQL_LIB = $(MYSQLROOT)/lib endif endif CGREEN_BIN=$(CGREEN_ROOT)/build CC = gcc -c -g -Wall -I$(CGREEN_ROOT)/include -I$(CGREEN_ROOT)/src -I$(MYSQL_INCLUDE) $(FPIC) LINK = gcc -g LIBDIRS = -L$(CGREEN_BIN)/src -L$(MYSQL_LIB) # Enviroment dependent fixup of the various paths to use bins & libs in this development tree FPIC = -fPIC # required on Linux, Darwin, ... ifeq ($(shell uname),Darwin) LDPATH = DYLD_LIBRARY_PATH="$(CGREEN_BIN)/src:$(MYSQL_LIB)" else ifeq ($(shell uname -o),Cygwin) FPIC= LDPATH = PATH="$(CGREEN_BIN)/src:$(MYSQL_LIB)" else LDPATH = LD_LIBRARY_PATH="$(CGREEN_BIN)/src:$(MYSQL_LIB)" endif endif RUNNER = $(LDPATH) $(CGREEN_BIN)/tools/cgreen-runner all: with_main with_runner special echo echo "NOTE: 'stream2.out' and 'stream5.out' should contain a simulation" echo "NOTE: of random memory as the actual value. Don't commit changes that do" echo "NOTE: not. But also note that PDF generation of the documentation" echo "NOTE: will fail if there are non-UTF-8 characters in them." echo "NOTE: Edit by hand to reasonable values if needed." # Since we have multiple files for the same tutorial example, distinguished by a number, # we need to remove that number from all output REMOVE_NUMBERS=-e 's/\([a-z]\)[0-9]\+\"/\1\"/' -e 's/\([a-z]\)[0-9]\+\.c/\1\.c/' # To minimize the diffs we also need to normalize execution times NORMALIZE_DURATION=-e 's/\ in\ [0-9]\+ms/\ in\ 42ms/g' # And batch that together in one symbol SED=sed $(REMOVE_NUMBERS) $(NORMALIZE_DURATION) with_main: first0 first1 \ words0 words1 words2 words3 words4 words5 words6 words7 words8 words9 \ strlen1 strlen2 strlen3 strlen4 strlen5 strlen6 strlen7 \ double1 \ schema1 schema2 \ crash1 crash2 crash3 \ suite1 \ test_as_xml0 \ test_as_xml1 \ test_as_xml2 \ test_as_xml3 \ test_as_xml4 \ custom_constraint1 \ custom_constraint2 \ custom_constraint3 for f in $^ ; do echo $$f; $(LDPATH) ./$$f | $(SED) > $$f.out; done # Most tests built to run with the runner we can run here, but some need special care # They have their output produced directly in their build rules below and are run using # the 'special' rule with_runner: set_content side_effect stream0 stream1 stream2 stream3 stream4 stream6 \ multiple_streams1 multiple_streams2 \ formatter0 formatter1 formatter2 formatter3 formatter4 formatter5 formatter6 \ struct_parameters for f in $^ ; do echo $$f; $(RUNNER) $$f.so | $(SED) > $$f.out; done special: runner1 runner2 runner3 stream5 learning_mocks clean: rm -f *.exe *.o *.out *.so *.stackdump *~ first_tests0.o: first_tests0.c $(CC) -o $@ -c $^ $(CFLAGS) -Wno-unused-variable first0: first_tests0.o $(LINK) -o $@ $^ $(LIBDIRS) -lcgreen first1: first_tests1.o $(LINK) -o $@ $^ $(LIBDIRS) -lcgreen words_tests0.o: words_tests0.c $(CC) -o $@ -c $^ $(CFLAGS) -Wno-unused-variable words0: all_tests.o words_tests0.o $(LINK) -o $@ $^ $(LIBDIRS) -lcgreen words1: all_tests.o words_tests1.o words1.o $(LINK) -o $@ $^ $(LIBDIRS) -lcgreen words2: all_tests.o words_tests1.o words2.o $(LINK) -o $@ $^ $(LIBDIRS) -lcgreen words3: all_tests.o words_tests2.o words2.o $(LINK) -o $@ $^ $(LIBDIRS) -lcgreen words4: all_tests.o words_tests2.o words3.o $(LINK) -o $@ $^ $(LIBDIRS) -lcgreen words5: all_tests.o words_tests2.o words4.o $(LINK) -o $@ $^ $(LIBDIRS) -lcgreen words6: all_tests.o words_tests3.o words5.o $(LINK) -o $@ $^ $(LIBDIRS) -lcgreen words7: all_tests.o words_tests3.o words6.o $(LINK) -o $@ $^ $(LIBDIRS) -lcgreen words8: all_tests.o words_tests4.o words6.o $(LINK) -o $@ $^ $(LIBDIRS) -lcgreen words9: all_tests.o words_tests4.o words7.o $(LINK) -o $@ $^ $(LIBDIRS) -lcgreen strlen1: strlen_tests1.o $(LINK) -o $@ $^ $(LIBDIRS) -lcgreen strlen2: strlen_tests2.o $(LINK) -o $@ $^ $(LIBDIRS) -lcgreen strlen3: strlen_tests3.o $(LINK) -o $@ $^ $(LIBDIRS) -lcgreen strlen4: strlen_tests4.o $(LINK) -o $@ $^ $(LIBDIRS) -lcgreen strlen5: strlen_tests5.o $(LINK) -o $@ $^ $(LIBDIRS) -lcgreen strlen6: strlen_tests6.o $(LINK) -o $@ $^ $(LIBDIRS) -lcgreen strlen7: strlen_tests7.o $(LINK) -o $@ $^ $(LIBDIRS) -lcgreen double1: double_tests1.o $(LINK) -o $@ $^ $(LIBDIRS) -lcgreen schema1: schema_tests1.o person.h $(LINK) -o $@ $^ $(LIBDIRS) -lcgreen -lmysqlclient schema2: schema_tests2.o person.h $(LINK) -o $@ $^ $(LIBDIRS) -lcgreen -lmysqlclient crash1: crash_tests1.o $(LINK) -o $@ $^ $(LIBDIRS) -lcgreen crash2: crash_tests2.o $(LINK) -o $@ $^ $(LIBDIRS) -lcgreen crash3: crash_tests3.o $(LINK) -o $@ $^ $(LIBDIRS) -lcgreen suite1: suite1.o suite_person_tests.o suite_strlen_tests.o $(LINK) -o $@ $^ $(LIBDIRS) -lcgreen -lmysqlclient test_as_xml0: test_as_xml0.o $(LINK) -o $@ $^ $(LIBDIRS) -lcgreen test_as_xml1: test_as_xml1.o xml_reporter1.o $(LINK) -o $@ $^ $(LIBDIRS) -lcgreen test_as_xml2: test_as_xml1.o xml_reporter2.o $(LINK) -o $@ $^ $(LIBDIRS) -lcgreen test_as_xml3: test_as_xml1.o xml_reporter3.o $(LINK) -o $@ $^ $(LIBDIRS) -lcgreen test_as_xml4: test_as_xml1.o xml_reporter4.o $(LINK) -o $@ $^ $(LIBDIRS) -lcgreen custom_constraint1: custom_constraint1.o $(LINK) -o $@ $^ $(LIBDIRS) -lcgreen custom_constraint2: custom_constraint2.o $(LINK) -o $@ $^ $(LIBDIRS) -lcgreen custom_constraint3: custom_constraint3.o $(LINK) -o $@ $^ $(LIBDIRS) -lcgreen ########################################################### # With runner # # All these examples run using the runner which automatically outputs the file name # Since that includes the example #, which we don't want in the tutorial, we use # sed to remove that number from the file name in the output .PHONY: set_content set_content: stream_tests0.o read_paragraph1.o $(LINK) -shared -o $@.so $^ $(LIBDIRS) -lcgreen .PHONY: side_effect side_effect: stream_tests0.o read_paragraph1.o $(LINK) -shared -o $@.so $^ $(LIBDIRS) -lcgreen .PHONY: stream0 stream0: stream_tests0.o read_paragraph1.o $(LINK) -shared -o $@.so $^ $(LIBDIRS) -lcgreen .PHONY: stream1 stream1: stream_tests1.o read_paragraph1.o $(LINK) -shared -o $@.so $^ $(LIBDIRS) -lcgreen .PHONY: stream2 stream2: stream_tests2.o read_paragraph1.o $(LINK) -shared -o $@.so $^ $(LIBDIRS) -lcgreen .PHONY: stream3 stream3: stream_tests2.o read_paragraph2.o $(LINK) -shared -o $@.so $^ $(LIBDIRS) -lcgreen .PHONY: stream4 stream4: stream_tests3.o read_paragraph2.o $(LINK) -shared -o $@.so $^ $(LIBDIRS) -lcgreen .PHONY: stream5 # This test generates random characters read from memory so we need to tidy that up stream5: stream_tests4.o read_paragraph2.o $(LINK) -shared -o $@.so $^ $(LIBDIRS) -lcgreen $(RUNNER) $@.so | $(SED) > $@.out echo "Trying to remove non-characters from stream5.out" echo "Check manually if the following sed fails:" cp $@.out $@.bak && LANG='' sed -e 's/^[^[[:space:]].*"]/"]/g' $@.bak > $@.bak2 && mv $@.bak2 $@.out rm $@.bak .PHONY: stream6 stream6: stream_tests4.o read_paragraph3.o $(LINK) -shared -o $@.so $^ $(LIBDIRS) -lcgreen .PHONY: multiple_streams1 multiple_streams1: multiple_streams1.o $(LINK) -shared -o $@.so $^ $(LIBDIRS) -lcgreen .PHONY: multiple_streams2 multiple_streams2: multiple_streams2.o $(LINK) -shared -o $@.so $^ $(LIBDIRS) -lcgreen .PHONY: runner1 runner1: first_tests2.o $(LINK) -shared -o first_tests.so $^ $(LIBDIRS) -lcgreen $(RUNNER) first_tests.so | $(SED) > $@.out .PHONY: runner2 runner2: first_tests2.o $(LINK) -shared -o first_tests.so $^ $(LIBDIRS) -lcgreen $(RUNNER) first_tests.so Cgreen:fails_this_test | $(SED) > $@.out .PHONY: runner3 runner3: first_tests2.o $(LINK) -shared -o first_tests.so $^ $(LIBDIRS) -lcgreen $(RUNNER) -v first_tests.so Cgreen:fails_this_test | $(SED) > $@.out .PHONY: formatter0 formatter0: stream1.o formatter_tests0.o $(LINK) -shared -o formatter_tests.so $^ $(LIBDIRS) -lcgreen .PHONY: formatter1 formatter1: stream1.o formatter_tests1.o $(LINK) -shared -o $@.so $^ $(LIBDIRS) -lcgreen formatter2: stream1.o formatter_tests2.o $(LINK) -shared -o $@.so $^ $(LIBDIRS) -lcgreen formatter3: stream1.o formatter_tests3.o $(LINK) -shared -o $@.so $^ $(LIBDIRS) -lcgreen formatter4: stream1.o formatter_tests4.o $(LINK) -shared -o $@.so $^ $(LIBDIRS) -lcgreen formatter5: stream1.o formatter_tests5.o $(LINK) -shared -o $@.so $^ $(LIBDIRS) -lcgreen formatter6: stream2.o formatter_tests5.o $(LINK) -shared -o $@.so $^ $(LIBDIRS) -lcgreen struct_parameters: struct_parameters.o $(LINK) -shared -o $@.so $^ $(LIBDIRS) -lcgreen learning_mocks: learning_mocks.o $(LINK) -shared -o $@.so $^ $(LIBDIRS) -lcgreen $(RUNNER) $@.so cgreen-1.6.3/doc/tutorial_src/README000066400000000000000000000007671450461175400171440ustar00rootroot00000000000000This directory contains source files and output for the examples in the tutorial documentataion. You should run these now and then and make sure that they compile and work. Note however that the guide includes specific lines from certain of these files, so if you change anything you need to be certain that the guide is still correct. On the other hand we will always know that the code in the guide actually works and is correct. You need mysql client header files to make some sources to compile. cgreen-1.6.3/doc/tutorial_src/all_tests.c000066400000000000000000000005101450461175400204040ustar00rootroot00000000000000#include TestSuite *words_tests(); int main(int argc, char **argv) { TestSuite *suite = create_test_suite(); add_suite(suite, words_tests()); if (argc > 1) { return run_single_test(suite, argv[1], create_text_reporter()); } return run_test_suite(suite, create_text_reporter()); } cgreen-1.6.3/doc/tutorial_src/constraints.out000066400000000000000000000001301450461175400213440ustar00rootroot00000000000000Running "main" (1 tests)... "main": 1 pass in 42ms. Completed "main": 1 pass in 42ms. cgreen-1.6.3/doc/tutorial_src/constraints1.out000066400000000000000000000001301450461175400214250ustar00rootroot00000000000000Running "main" (1 tests)... "main": 1 pass in 42ms. Completed "main": 1 pass in 42ms. cgreen-1.6.3/doc/tutorial_src/constraints2.out000066400000000000000000000004271450461175400214370ustar00rootroot00000000000000Running "main" (1 tests)... constraints.c:57: Failure: more_complex_custom_constraint_function Expected [&piece99] to [fit in box] [&box1] at offset: [0] actual value: [0x63] expected value: [0x01] "main": 1 failure in 42ms. Completed "main": 1 failure in 42ms. cgreen-1.6.3/doc/tutorial_src/crash1.out000066400000000000000000000003201450461175400201570ustar00rootroot00000000000000Running "main" (1 test)... crash_tests.c:8: Exception: seg_faults_for_null_dereference Test terminated with signal: Segmentation fault "main": 1 exception in 42ms. Completed "main": 1 exception in 42ms. cgreen-1.6.3/doc/tutorial_src/crash2.out000066400000000000000000000000331450461175400201610ustar00rootroot00000000000000Running "main" (1 test)... cgreen-1.6.3/doc/tutorial_src/crash3.out000066400000000000000000000005301450461175400201640ustar00rootroot00000000000000Running "main" (2 tests)... crash_tests.c:8: Exception: seg_faults_for_null_dereference Test terminated with signal: Segmentation fault crash_tests.c:13: Exception: will_loop_forever Test terminated unexpectedly, likely from a non-standard exception or Posix signal "main": 2 exceptions in 42ms. Completed "main": 2 exceptions in 42ms. cgreen-1.6.3/doc/tutorial_src/crash_tests.c000066400000000000000000000005541450461175400207440ustar00rootroot00000000000000#include #include Ensure(will_seg_fault) { int *p = NULL; (*p)++; } Ensure(will_stall) { die_in(1); while(1) { } } int main(int argc, char **argv) { TestSuite *suite = create_test_suite(); add_test(suite, will_seg_fault); add_test(suite, will_stall); run_test_suite(suite, create_text_reporter()); } cgreen-1.6.3/doc/tutorial_src/crash_tests1.c000066400000000000000000000006651450461175400210300ustar00rootroot00000000000000#include #include Describe(CrashExample); BeforeEach(CrashExample) {} AfterEach(CrashExample) {} Ensure(CrashExample, seg_faults_for_null_dereference) { int *p = NULL; (*p)++; } int main(int argc, char **argv) { TestSuite *suite = create_test_suite(); add_test_with_context(suite, CrashExample, seg_faults_for_null_dereference); return run_test_suite(suite, create_text_reporter()); } cgreen-1.6.3/doc/tutorial_src/crash_tests2.c000066400000000000000000000007311450461175400210230ustar00rootroot00000000000000#include #include Describe(CrashExample); BeforeEach(CrashExample) {} AfterEach(CrashExample) {} Ensure(CrashExample, seg_faults_for_null_dereference) { int *p = NULL; (*p)++; } int main(int argc, char **argv) { TestSuite *suite = create_test_suite(); add_test_with_context(suite, CrashExample, seg_faults_for_null_dereference); return run_single_test(suite, "seg_faults_for_null_dereference", create_text_reporter()); } cgreen-1.6.3/doc/tutorial_src/crash_tests3.c000066400000000000000000000011121450461175400210160ustar00rootroot00000000000000#include #include Describe(CrashExample); BeforeEach(CrashExample) {} AfterEach(CrashExample) {} Ensure(CrashExample, seg_faults_for_null_dereference) { int *p = NULL; (*p)++; } Ensure(CrashExample, will_loop_forever) { die_in(1); while(0 == 0) { } } int main(int argc, char **argv) { TestSuite *suite = create_test_suite(); add_test_with_context(suite, CrashExample, seg_faults_for_null_dereference); add_test_with_context(suite, CrashExample, will_loop_forever); return run_test_suite(suite, create_text_reporter()); } cgreen-1.6.3/doc/tutorial_src/custom_constraint1.c000066400000000000000000000024061450461175400222570ustar00rootroot00000000000000#include #include #include "constraint_internal.h" Describe(TestConstraint); BeforeEach(TestConstraint) {} AfterEach(TestConstraint) {} bool compare_want_greater_than_5(Constraint *constraint, CgreenValue actual) { return actual.value.integer_value > 5; } Constraint static_is_bigger_than_5 = { /* .type */ CGREEN_VALUE_COMPARER_CONSTRAINT, /* .name */ "be bigger than 5", /* .destroy */ destroy_static_constraint, /* .compare */ compare_want_greater_than_5, /* .test */ test_want, /* .format_failure_message_for */ failure_message_for, /* .actual_value_message */ "", /* .expected_value_message */ "", /* .expected_value */ {CGREEN_INTEGER, {5}}, /* .stored_value_name */ "null", /* .parameter_name */ NULL, /* .size_of_stored_value */ 0 }; Ensure(TestConstraint, custom_constraint_using_static_function) { Constraint * is_bigger_than_5 = &static_is_bigger_than_5; assert_that(10, is_bigger_than_5); } int main(int argc, char **argv) { TestSuite *suite = create_test_suite(); add_test_with_context(suite, TestConstraint, custom_constraint_using_static_function); run_test_suite(suite, create_text_reporter()); } cgreen-1.6.3/doc/tutorial_src/custom_constraint1.out000066400000000000000000000001271450461175400226420ustar00rootroot00000000000000Running "main" (1 test)... "main": 1 pass in 42ms. Completed "main": 1 pass in 42ms. cgreen-1.6.3/doc/tutorial_src/custom_constraint2.c000066400000000000000000000025751450461175400222670ustar00rootroot00000000000000#include #include #include "cgreen_value_internal.h" #include "utils.h" Describe(TestConstraint); BeforeEach(TestConstraint) {} AfterEach(TestConstraint) {} bool compare_want_smaller_value(Constraint *constraint, CgreenValue actual) { return actual.value.integer_value < constraint->expected_value.value.integer_value ; } Constraint *create_smaller_than_constraint(intptr_t expected_value, const char *expected_value_name) { Constraint *constraint = create_constraint(); constraint->expected_value = make_cgreen_integer_value(expected_value); constraint->expected_value_name = string_dup(expected_value_name); constraint->type = CGREEN_VALUE_COMPARER_CONSTRAINT; constraint->compare = &compare_want_smaller_value; constraint->execute = &test_want; constraint->name = "be smaller than"; constraint->size_of_expected_value = sizeof(intptr_t); return constraint; } #define is_smaller_than(value) create_smaller_than_constraint(value, #value) Ensure(TestConstraint, custom_constraint_using_a_function_with_arguments_function) { assert_that(9, is_smaller_than(10)); } int main(int argc, char **argv) { TestSuite *suite = create_test_suite(); add_test_with_context(suite, TestConstraint, custom_constraint_using_a_function_with_arguments_function); run_test_suite(suite, create_text_reporter()); } cgreen-1.6.3/doc/tutorial_src/custom_constraint2.out000066400000000000000000000001271450461175400226430ustar00rootroot00000000000000Running "main" (1 test)... "main": 1 pass in 42ms. Completed "main": 1 pass in 42ms. cgreen-1.6.3/doc/tutorial_src/custom_constraint3.c000066400000000000000000000042431450461175400222620ustar00rootroot00000000000000#include #include "cgreen_value_internal.h" #include "utils.h" Describe(TestConstraint); BeforeEach(TestConstraint) {} AfterEach(TestConstraint) {} typedef struct Box { int id; int size; } Box; typedef struct Piece { int id; int size; } Piece; bool compare_piece_and_box_size(Constraint *constraint, CgreenValue actual) { return ((Piece *)actual.value.pointer_value)->size < ((Box*)constraint->expected_value.value.pointer_value)->size ; } static void test_fit_piece(Constraint *constraint, const char *function_name, CgreenValue actual, const char *test_file, int test_line, TestReporter *reporter) { (*reporter->assert_true)( reporter, test_file, test_line, (*constraint->compare)(constraint, actual), "Piece [%f], does not fit in [%f] in function [%s] parameter [%s]", ((Piece *)constraint->expected_value.value.pointer_value)->id, ((Box *)actual.value.pointer_value)->id, function_name, constraint->parameter_name); } Constraint *create_piece_fit_in_box_constraint(intptr_t expected_value, const char *expected_value_name) { Constraint *constraint = create_constraint(); constraint->expected_value = make_cgreen_pointer_value((void*)expected_value); constraint->expected_value_name = string_dup(expected_value_name); constraint->type = CGREEN_CONTENT_COMPARER_CONSTRAINT; constraint->compare = &compare_piece_and_box_size; constraint->execute = &test_fit_piece; constraint->name = "fit in box"; constraint->size_of_expected_value = sizeof(intptr_t); return constraint; } #define can_fit_in_box(box) create_piece_fit_in_box_constraint((intptr_t)box, #box) Ensure(TestConstraint, more_complex_custom_constraint_function) { Box box1 = {.id = 1, .size = 5}; Piece piece99 = {.id = 99, .size = 6}; assert_that(&piece99, can_fit_in_box(&box1)); } int main(int argc, char **argv) { TestSuite *suite = create_test_suite(); add_test_with_context(suite, TestConstraint, more_complex_custom_constraint_function); run_test_suite(suite, create_text_reporter()); } cgreen-1.6.3/doc/tutorial_src/custom_constraint3.out000066400000000000000000000004341450461175400226450ustar00rootroot00000000000000Running "main" (1 test)... custom_constraint.c:57: Failure: more_complex_custom_constraint_function Expected [&piece99] to [fit in box] [&box1] at offset: [0] actual value: [0x63] expected value: [0x01] "main": 1 failure in 42ms. Completed "main": 1 failure in 42ms. cgreen-1.6.3/doc/tutorial_src/double1.out000066400000000000000000000004551450461175400203420ustar00rootroot00000000000000Running "main" (2 tests)... double_tests.c:13: Failure: can_assert_double_values Expected [3.14] to [equal double] [5.0] within [3] significant figures actual value: [3.140000] expected value: [5.000000] "main": 3 passes, 1 failure in 42ms. Completed "main": 3 passes, 1 failure in 42ms. cgreen-1.6.3/doc/tutorial_src/double_tests1.c000066400000000000000000000020001450461175400211630ustar00rootroot00000000000000#include #include #include #define PI 3.1415926 Describe(Doubles); BeforeEach(Doubles) {} AfterEach(Doubles) {} Ensure(Doubles, can_assert_double_values) { significant_figures_for_assert_double_are(3); assert_that_double(3.14, is_equal_to_double(5.0)); } static double double_out(int i, double d) { return unbox_double(mock(i, box_double(d))); // <1> } Ensure(Doubles, can_be_arguments_to_mock_and_returned) { expect(double_out, when(i, is_equal_to(15)), when(d, is_equal_to_double(31.32)), // <2> will_return_double(3.1415926)); // <3> assert_that_double(double_out(15, 31.32), is_equal_to_double(3.1415926)); } int main(int argc, char **argv) { TestSuite *suite = create_test_suite(); add_test_with_context(suite, Doubles, can_assert_double_values); add_test_with_context(suite, Doubles, can_be_arguments_to_mock_and_returned); return run_test_suite(suite, create_text_reporter()); } cgreen-1.6.3/doc/tutorial_src/first0.out000066400000000000000000000000751450461175400202140ustar00rootroot00000000000000Running "main" (0 tests)... Completed "main": No assertions. cgreen-1.6.3/doc/tutorial_src/first1.out000066400000000000000000000002731450461175400202150ustar00rootroot00000000000000Running "main" (2 tests)... first_tests.c:12: Failure: fails_this_test Expected [0 == 1] to [be true] "main": 1 pass, 1 failure in 42ms. Completed "main": 1 pass, 1 failure in 42ms. cgreen-1.6.3/doc/tutorial_src/first_tests0.c000066400000000000000000000003441450461175400210500ustar00rootroot00000000000000#include Describe(Cgreen); BeforeEach(Cgreen) {} AfterEach(Cgreen) {} int main(int argc, char **argv) { TestSuite *suite = create_test_suite(); return run_test_suite(suite, create_text_reporter()); } cgreen-1.6.3/doc/tutorial_src/first_tests1.c000066400000000000000000000007301450461175400210500ustar00rootroot00000000000000#include Describe(Cgreen); BeforeEach(Cgreen) {} AfterEach(Cgreen) {} Ensure(Cgreen, passes_this_test) { assert_that(1 == 1); } Ensure(Cgreen, fails_this_test) { assert_that(0 == 1); } int main(int argc, char **argv) { TestSuite *suite = create_test_suite(); add_test_with_context(suite, Cgreen, passes_this_test); add_test_with_context(suite, Cgreen, fails_this_test); return run_test_suite(suite, create_text_reporter()); } cgreen-1.6.3/doc/tutorial_src/first_tests2.c000066400000000000000000000007301450461175400210510ustar00rootroot00000000000000#include Describe(Cgreen); BeforeEach(Cgreen) {} AfterEach(Cgreen) {} Ensure(Cgreen, passes_this_test) { assert_that(1 == 1); } Ensure(Cgreen, fails_this_test) { assert_that(0 == 1); } int main(int argc, char **argv) { TestSuite *suite = create_test_suite(); add_test_with_context(suite, Cgreen, passes_this_test); add_test_with_context(suite, Cgreen, fails_this_test); return run_test_suite(suite, create_text_reporter()); } cgreen-1.6.3/doc/tutorial_src/formatter0.out000066400000000000000000000000451450461175400210650ustar00rootroot00000000000000Couldn't find library: formatter0.so cgreen-1.6.3/doc/tutorial_src/formatter1.out000066400000000000000000000001461450461175400210700ustar00rootroot00000000000000Running "formatter" (1 test)... "Formatter": 1 pass in 42ms. Completed "formatter": 1 pass in 42ms. cgreen-1.6.3/doc/tutorial_src/formatter2.out000066400000000000000000000001531450461175400210670ustar00rootroot00000000000000Running "formatter" (2 tests)... "Formatter": 2 passes in 42ms. Completed "formatter": 2 passes in 42ms. cgreen-1.6.3/doc/tutorial_src/formatter3.out000066400000000000000000000001531450461175400210700ustar00rootroot00000000000000Running "formatter" (3 tests)... "Formatter": 5 passes in 42ms. Completed "formatter": 5 passes in 42ms. cgreen-1.6.3/doc/tutorial_src/formatter4.out000066400000000000000000000001531450461175400210710ustar00rootroot00000000000000Running "formatter" (4 tests)... "Formatter": 9 passes in 42ms. Completed "formatter": 9 passes in 42ms. cgreen-1.6.3/doc/tutorial_src/formatter5.out000066400000000000000000000004361450461175400210760ustar00rootroot00000000000000Running "formatter" (5 tests)... formatter_tests.c:59: Failure: Formatter -> ignores_empty_paragraphs Mocked function [writer] has an expectation that it will never be called, but it was "Formatter": 9 passes, 1 failure in 42ms. Completed "formatter": 9 passes, 1 failure in 42ms. cgreen-1.6.3/doc/tutorial_src/formatter6.out000066400000000000000000000001551450461175400210750ustar00rootroot00000000000000Running "formatter" (5 tests)... "Formatter": 10 passes in 42ms. Completed "formatter": 10 passes in 42ms. cgreen-1.6.3/doc/tutorial_src/formatter_tests0.c000066400000000000000000000010231450461175400217170ustar00rootroot00000000000000#include #include #include "stream.h" Describe(Formatter); BeforeEach(Formatter) {} AfterEach(Formatter) {} int one_character_stream(void *stream) { return 'a'; } void expect_one_letter_paragraph(void *stream, char *paragraph) { assert_that(paragraph, is_equal_to_string("a")); } Ensure(Formatter, makes_one_letter_paragraph_from_one_character_input) { by_paragraph( &one_character_stream, NULL, &expect_one_letter_paragraph, NULL); } cgreen-1.6.3/doc/tutorial_src/formatter_tests1.c000066400000000000000000000010651450461175400217260ustar00rootroot00000000000000#include #include #include "stream.h" Describe(Formatter); BeforeEach(Formatter) {} AfterEach(Formatter) {} static int reader(void *stream) { return (int)mock(stream); } static void writer(void *stream, char *paragraph) { mock(stream, paragraph); } Ensure(Formatter, makes_one_letter_paragraph_from_one_character_input) { expect(reader, will_return('a')); always_expect(reader, will_return(EOF)); expect(writer, when(paragraph, is_equal_to_string("a"))); by_paragraph(&reader, NULL, &writer, NULL); } cgreen-1.6.3/doc/tutorial_src/formatter_tests2.c000066400000000000000000000017211450461175400217260ustar00rootroot00000000000000#include #include #include "stream.h" Describe(Formatter); BeforeEach(Formatter) {} AfterEach(Formatter) {} static int reader(void *stream) { return (int)mock(stream); } static void writer(void *stream, char *paragraph) { mock(stream, paragraph); } Ensure(Formatter, makes_one_letter_paragraph_from_one_character_input) { expect(reader, will_return('a')); always_expect(reader, will_return(EOF)); expect(writer, when(paragraph, is_equal_to_string("a"))); by_paragraph(&reader, NULL, &writer, NULL); } Ensure(Formatter, makes_one_paragraph_if_no_line_endings) { expect(reader, will_return('a')); expect(reader, will_return(' ')); expect(reader, will_return('b')); expect(reader, will_return(' ')); expect(reader, will_return('c')); always_expect(reader, will_return(EOF)); expect(writer, when(paragraph, is_equal_to_string("a b c"))); by_paragraph(&reader, NULL, &writer, NULL); } cgreen-1.6.3/doc/tutorial_src/formatter_tests3.c000066400000000000000000000027571450461175400217410ustar00rootroot00000000000000#include #include #include "stream.h" Describe(Formatter); BeforeEach(Formatter) {} AfterEach(Formatter) {} static int reader(void *stream) { return (int)mock(stream); } static void writer(void *stream, char *paragraph) { mock(stream, paragraph); } Ensure(Formatter, makes_one_letter_paragraph_from_one_character_input) { expect(reader, will_return('a')); always_expect(reader, will_return(EOF)); expect(writer, when(paragraph, is_equal_to_string("a"))); by_paragraph(&reader, NULL, &writer, NULL); } Ensure(Formatter, makes_one_paragraph_if_no_line_endings) { expect(reader, will_return('a')); expect(reader, will_return(' ')); expect(reader, will_return('b')); expect(reader, will_return(' ')); expect(reader, will_return('c')); always_expect(reader, will_return(EOF)); expect(writer, when(paragraph, is_equal_to_string("a b c"))); by_paragraph(&reader, NULL, &writer, NULL); } Ensure(Formatter, generates_separate_paragraphs_for_line_endings) { expect(reader, will_return('a')); expect(reader, will_return('\n')); expect(reader, will_return('b')); expect(reader, will_return('\n')); expect(reader, will_return('c')); always_expect(reader, will_return(EOF)); expect(writer, when(paragraph, is_equal_to_string("a"))); expect(writer, when(paragraph, is_equal_to_string("b"))); expect(writer, when(paragraph, is_equal_to_string("c"))); by_paragraph(&reader, NULL, &writer, NULL); } cgreen-1.6.3/doc/tutorial_src/formatter_tests4.c000066400000000000000000000034521450461175400217330ustar00rootroot00000000000000#include #include #include "stream.h" Describe(Formatter); BeforeEach(Formatter) {} AfterEach(Formatter) {} static int reader(void *stream) { return (int)mock(stream); } static void writer(void *stream, char *paragraph) { mock(stream, paragraph); } Ensure(Formatter, makes_one_letter_paragraph_from_one_character_input) { expect(reader, will_return('a')); always_expect(reader, will_return(EOF)); expect(writer, when(paragraph, is_equal_to_string("a"))); by_paragraph(&reader, NULL, &writer, NULL); } Ensure(Formatter, makes_one_paragraph_if_no_line_endings) { expect(reader, will_return('a')); expect(reader, will_return(' ')); expect(reader, will_return('b')); expect(reader, will_return(' ')); expect(reader, will_return('c')); always_expect(reader, will_return(EOF)); expect(writer, when(paragraph, is_equal_to_string("a b c"))); by_paragraph(&reader, NULL, &writer, NULL); } Ensure(Formatter, generates_separate_paragraphs_for_line_endings) { expect(reader, will_return('a')); expect(reader, will_return('\n')); expect(reader, will_return('b')); expect(reader, will_return('\n')); expect(reader, will_return('c')); always_expect(reader, will_return(EOF)); expect(writer, when(paragraph, is_equal_to_string("a"))); expect(writer, when(paragraph, is_equal_to_string("b"))); expect(writer, when(paragraph, is_equal_to_string("c"))); by_paragraph(&reader, NULL, &writer, NULL); } Ensure(Formatter, pairs_the_functions_with_the_resources) { expect(reader, when(stream, is_equal_to(1)), will_return('a')); always_expect(reader, when(stream, is_equal_to(1)), will_return(EOF)); expect(writer, when(stream, is_equal_to(2))); by_paragraph(&reader, (void *)1, &writer, (void *)2); } cgreen-1.6.3/doc/tutorial_src/formatter_tests5.c000066400000000000000000000037701450461175400217370ustar00rootroot00000000000000#include #include #include "stream.h" Describe(Formatter); BeforeEach(Formatter) {} AfterEach(Formatter) {} static int reader(void *stream) { return (int)mock(stream); } static void writer(void *stream, char *paragraph) { mock(stream, paragraph); } Ensure(Formatter, makes_one_letter_paragraph_from_one_character_input) { expect(reader, will_return('a')); always_expect(reader, will_return(EOF)); expect(writer, when(paragraph, is_equal_to_string("a"))); by_paragraph(&reader, NULL, &writer, NULL); } Ensure(Formatter, makes_one_paragraph_if_no_line_endings) { expect(reader, will_return('a')); expect(reader, will_return(' ')); expect(reader, will_return('b')); expect(reader, will_return(' ')); expect(reader, will_return('c')); always_expect(reader, will_return(EOF)); expect(writer, when(paragraph, is_equal_to_string("a b c"))); by_paragraph(&reader, NULL, &writer, NULL); } Ensure(Formatter, generates_separate_paragraphs_for_line_endings) { expect(reader, will_return('a')); expect(reader, will_return('\n')); expect(reader, will_return('b')); expect(reader, will_return('\n')); expect(reader, will_return('c')); always_expect(reader, will_return(EOF)); expect(writer, when(paragraph, is_equal_to_string("a"))); expect(writer, when(paragraph, is_equal_to_string("b"))); expect(writer, when(paragraph, is_equal_to_string("c"))); by_paragraph(&reader, NULL, &writer, NULL); } Ensure(Formatter, pairs_the_functions_with_the_resources) { expect(reader, when(stream, is_equal_to(1)), will_return('a')); always_expect(reader, when(stream, is_equal_to(1)), will_return(EOF)); expect(writer, when(stream, is_equal_to(2))); by_paragraph(&reader, (void *)1, &writer, (void *)2); } Ensure(Formatter, ignores_empty_paragraphs) { expect(reader, will_return('\n')); always_expect(reader, will_return(EOF)); never_expect(writer); by_paragraph(&reader, NULL, &writer, NULL); } cgreen-1.6.3/doc/tutorial_src/learning_mocks.c000066400000000000000000000007071450461175400214150ustar00rootroot00000000000000#include #include Describe(LearningMocks); BeforeEach(LearningMocks) {} AfterEach(LearningMocks) {} static int integer_out() { return (int)mock(); } static char *string_out(int p1) { return (char *)mock(p1); } Ensure(LearningMocks, emit_pastable_code) { cgreen_mocks_are(learning_mocks); string_out(1); string_out(2); integer_out(); integer_out(); string_out(3); integer_out(); } cgreen-1.6.3/doc/tutorial_src/multiple_streams1.c000066400000000000000000000005421450461175400220710ustar00rootroot00000000000000#include #include void do_stuff(void *stream1, void *stream2) {} Describe(Streams); BeforeEach(Streams) {} AfterEach(Streams) {} static int stream_stub(void *stream) { return (int)mock(stream); } Ensure(Streams, bad_test) { expect(stream_stub, will_return('a')); do_stuff(&stream_stub, &stream_stub); } cgreen-1.6.3/doc/tutorial_src/multiple_streams1.out000066400000000000000000000003531450461175400224560ustar00rootroot00000000000000Running "multiple_streams" (1 test)... multiple_streams.c:15: Failure: Streams -> bad_test Expected call was not made to mocked function [stream_stub] "Streams": 1 failure in 42ms. Completed "multiple_streams": 1 failure in 42ms. cgreen-1.6.3/doc/tutorial_src/multiple_streams2.c000066400000000000000000000007751450461175400221020ustar00rootroot00000000000000#include #include void do_stuff(void *stream1, void *stream2) {} Describe(Streams); BeforeEach(Streams) {} AfterEach(Streams) {} static int first_stream_stub(void *stream) { return (int)mock(stream); } static int second_stream_stub(void *stream) { return (int)mock(stream); } Ensure(Streams, good_test) { expect(first_stream_stub, will_return('a')); expect(second_stream_stub, will_return('a')); do_stuff(&first_stream_stub, &second_stream_stub); } cgreen-1.6.3/doc/tutorial_src/multiple_streams2.out000066400000000000000000000005571450461175400224650ustar00rootroot00000000000000Running "multiple_streams" (1 test)... multiple_streams.c:19: Failure: Streams -> good_test Expected call was not made to mocked function [first_stream_stub] multiple_streams.c:20: Failure: Streams -> good_test Expected call was not made to mocked function [second_stream_stub] "Streams": 2 failures in 42ms. Completed "multiple_streams": 2 failures in 42ms. cgreen-1.6.3/doc/tutorial_src/person.h000066400000000000000000000005101450461175400177250ustar00rootroot00000000000000#include typedef struct _Person { char *name; } Person; Person *create_person() {return NULL;} Person *find_person_by_name(const char *name) {return NULL;} void set_person_name(Person *person, const char *name) {} char *get_person_name(Person *person) {return NULL;} int save_person(Person *person) { return 1;} cgreen-1.6.3/doc/tutorial_src/person_tests.c000066400000000000000000000031261450461175400211500ustar00rootroot00000000000000#include #include #include #include "person.h" static MYSQL *connection; static void create_schema() { mysql_query(connection, "create table people (name, varchar(255) unique)"); } static void drop_schema() { mysql_query(connection, "drop table people"); } Ensure(can_add_person_to_database) { Person *person = create_person(); set_person_name(person, "Fred"); save_person(person); Person *found = find_person_by_name("Fred"); assert_that(get_person_name(person), is_equal_to_string("Fred")); } Ensure(cannot_add_duplicate_person) { Person *person = create_person(); set_person_name(person, "Fred"); assert_that(save_person(person), is_null); Person *duplicate = create_person(); set_person_name(duplicate, "Fred"); assert_that(save_person(duplicate), is_null); } void open_connection() { connection = mysql_init(NULL); mysql_real_connect(connection, "localhost", "me", "secret", "test", 0, NULL, 0); } void close_connection() { mysql_close(connection); } TestSuite *person_tests() { TestSuite *suite = create_test_suite(); set_setup(suite, create_schema); set_teardown(suite, drop_schema); add_test(suite, can_add_person_to_database); add_test(suite, cannot_add_duplicate_person); TestSuite *fixture = create_named_test_suite("Mysql"); add_suite(fixture, suite); set_setup(fixture, open_connection); set_teardown(fixture, close_connection); return fixture; } int main(int argc, char **argv) { return run_test_suite(person_tests(), create_text_reporter()); } cgreen-1.6.3/doc/tutorial_src/read_paragraph1.c000066400000000000000000000007571450461175400214500ustar00rootroot00000000000000#include #include char *read_paragraph(int (*read)(void *), void *stream) { int buffer_size = 0, length = 0; char *buffer = NULL; int ch; while ((ch = (*read)(stream)) != EOF) { if (++length > buffer_size) { buffer_size += 100; buffer = (char *)realloc(buffer, buffer_size + 1); } if ((buffer[length] = ch) == '\n') { break; } buffer[length + 1] = '\0'; } return buffer; } cgreen-1.6.3/doc/tutorial_src/read_paragraph2.c000066400000000000000000000010511450461175400214350ustar00rootroot00000000000000#include #include char *read_paragraph(int (*read)(void *), void *stream) { int buffer_size = 0, length = 0; char *buffer = NULL; int ch; while ((ch = (*read)(stream)) != EOF) { if (++length > buffer_size) { buffer_size += 100; buffer = (char *)realloc(buffer, buffer_size + 1); } if ((buffer[length - 1] = ch) == '\n') { // <1> break; } buffer[length] = '\0'; // <2> } return buffer; } cgreen-1.6.3/doc/tutorial_src/read_paragraph3.c000066400000000000000000000010241450461175400214360ustar00rootroot00000000000000#include #include char *read_paragraph(int (*read)(void *), void *stream) { int buffer_size = 0, length = 0; char *buffer = NULL; int ch; while ((ch = (*read)(stream)) != EOF) { if (++length > buffer_size) { buffer_size += 100; buffer = (char *)realloc(buffer, buffer_size + 1); } if ((buffer[length - 1] = ch) == '\n') { buffer[--length] = '\0'; break; } buffer[length] = '\0'; } return buffer; } cgreen-1.6.3/doc/tutorial_src/roman_tests.c000066400000000000000000000004241450461175400207540ustar00rootroot00000000000000#include static int convert_roman_to_decimal(char *roman) { return 0; } Describe(Converter); BeforeEach(Converter) {} AfterEach(Converter) {} Ensure(Converter, converts_XIV_to_14) { assert_that(convert_roman_to_decimal("XIV"), is_equal_to(14)); } cgreen-1.6.3/doc/tutorial_src/runner1.out000066400000000000000000000003251450461175400203750ustar00rootroot00000000000000Running "first_tests" (2 tests)... first_tests.c:12: Failure: Cgreen -> fails_this_test Expected [0 == 1] to [be true] "Cgreen": 1 pass, 1 failure in 42ms. Completed "first_tests": 1 pass, 1 failure in 42ms. cgreen-1.6.3/doc/tutorial_src/runner2.out000066400000000000000000000003041450461175400203730ustar00rootroot00000000000000Running "first_tests" (1 test)... first_tests.c:12: Failure: Cgreen -> fails_this_test Expected [0 == 1] to [be true] "Cgreen": 1 failure in 42ms. Completed "first_tests": 1 failure in 42ms. cgreen-1.6.3/doc/tutorial_src/runner3.out000066400000000000000000000006731450461175400204050ustar00rootroot00000000000000Discovered Cgreen:fails_this_test (CgreenSpec__Cgreen__fails_this_test__) Discovered Cgreen:passes_this_test (CgreenSpec__Cgreen__passes_this_test__) Discovered 2 test(s) Opening [first_tests.so] to only run one test: 'Cgreen:fails_this_test' ... Running "first_tests" (1 test)... first_tests.c:12: Failure: Cgreen -> fails_this_test Expected [0 == 1] to [be true] "Cgreen": 1 failure in 42ms. Completed "first_tests": 1 failure in 42ms. cgreen-1.6.3/doc/tutorial_src/schema1.out000066400000000000000000000000001450461175400203120ustar00rootroot00000000000000cgreen-1.6.3/doc/tutorial_src/schema2.out000066400000000000000000000000001450461175400203130ustar00rootroot00000000000000cgreen-1.6.3/doc/tutorial_src/schema_tests1.c000066400000000000000000000031511450461175400211610ustar00rootroot00000000000000#include #include #include #include "person.h" Describe(Person); BeforeEach(Person) {} AfterEach(Person) {} static void create_schema() { MYSQL *connection = mysql_init(NULL); mysql_real_connect(connection, "localhost", "me", "secret", "test", 0, NULL, 0); mysql_query(connection, "create table people (name, varchar(255) unique)"); mysql_close(connection); } static void drop_schema() { MYSQL *connection = mysql_init(NULL); mysql_real_connect(connection, "localhost", "me", "secret", "test", 0, NULL, 0); mysql_query(connection, "drop table people"); mysql_close(connection); } Ensure(Person, can_add_person_to_database) { create_schema(); Person *person = create_person(); set_person_name(person, "Fred"); save_person(person); Person *found = find_person_by_name("Fred"); assert_that(get_person_name(found), is_equal_to_string("Fred")); drop_schema(); } Ensure(Person, cannot_add_duplicate_person) { create_schema(); Person *person = create_person(); set_person_name(person, "Fred"); assert_that(save_person(person), is_true); Person *duplicate = create_person(); set_person_name(duplicate, "Fred"); assert_that(save_person(duplicate), is_false); drop_schema(); } TestSuite *person_tests() { TestSuite *suite = create_test_suite(); add_test_with_context(suite, Person, can_add_person_to_database); add_test_with_context(suite, Person, cannot_add_duplicate_person); return suite; } int main(int argc, char **argv) { return run_test_suite(person_tests(), create_text_reporter()); } cgreen-1.6.3/doc/tutorial_src/schema_tests2.c000066400000000000000000000030731450461175400211650ustar00rootroot00000000000000#include #include #include #include "person.h" static void create_schema() { MYSQL *connection = mysql_init(NULL); mysql_real_connect(connection, "localhost", "me", "secret", "test", 0, NULL, 0); mysql_query(connection, "create table people (name, varchar(255) unique)"); mysql_close(connection); } static void drop_schema() { MYSQL *connection = mysql_init(NULL); mysql_real_connect(connection, "localhost", "me", "secret", "test", 0, NULL, 0); mysql_query(connection, "drop table people"); mysql_close(connection); } Describe(Person); BeforeEach(Person) { create_schema(); } AfterEach(Person) { drop_schema(); } Ensure(Person, can_add_person_to_database) { Person *person = create_person(); set_person_name(person, "Fred"); save_person(person); Person *found = find_person_by_name("Fred"); assert_that(get_person_name(found), is_equal_to_string("Fred")); } Ensure(Person, cannot_add_duplicate_person) { Person *person = create_person(); set_person_name(person, "Fred"); assert_that(save_person(person), is_true); Person *duplicate = create_person(); set_person_name(duplicate, "Fred"); assert_that(save_person(duplicate), is_false); } TestSuite *person_tests() { TestSuite *suite = create_test_suite(); add_test_with_context(suite, Person, can_add_person_to_database); add_test_with_context(suite, Person, cannot_add_duplicate_person); return suite; } int main(int argc, char **argv) { return run_test_suite(person_tests(), create_text_reporter()); } cgreen-1.6.3/doc/tutorial_src/set_contents.c000066400000000000000000000007041450461175400211270ustar00rootroot00000000000000#include #include void convert_to_uppercase(char *converted_string, const char *original_string) { mock(converted_string, original_string); } Ensure(setting_content_of_out_parameter) { expect(convert_to_uppercase, when(original_string, is_equal_to_string("upper case")), will_set_contents_of_parameter(converted_string, "UPPER CASE", 11)); } cgreen-1.6.3/doc/tutorial_src/set_field.c000066400000000000000000000006351450461175400203600ustar00rootroot00000000000000#include #include struct structure { int field; char *string; }; void update_field(struct structure *struct_to_update) { int *field = &struct_to_update->field; mock(struct_to_update, field); } Ensure(setting_field_of_parameter) { int fourty_two = 42; expect(update_field, will_set_contents_of_parameter(field, &fourty_two, sizeof(int))); } cgreen-1.6.3/doc/tutorial_src/side_effect.c000066400000000000000000000022161450461175400206570ustar00rootroot00000000000000#include #include static int reader(void *stream) { return (int)mock(stream); } static void writer(void *stream, char *paragraph) { mock(stream, paragraph); } char *read_paragraph(int (*read)(void *), void *stream); void by_paragraph(int (*read)(void *), void *in, void (*write)(void *, char *), void *out) { while (1) { char *line = read_paragraph(read, in); if ((line == NULL) || (strlen(line) == 0)) { return; } (*write)(out, line); free(line); } } static int stub_stream(void *stream) { return (int)mock(stream); } static void update_counter(void * counter) { *(int*)counter = *(int*)counter + 1; } Ensure(using_side_effect) { int number_of_times_reader_was_called = 0; expect(reader, will_return('\n')); always_expect(reader, will_return(EOF), with_side_effect(&update_counter, &number_of_times_reader_was_called)); never_expect(writer); by_paragraph(&reader, NULL, &writer, NULL); assert_that(number_of_times_reader_was_called, is_equal_to(1)); } cgreen-1.6.3/doc/tutorial_src/stream.c000066400000000000000000000015111450461175400177070ustar00rootroot00000000000000#include #include #include char *read_paragraph(int (*read)(void *), void *stream) { int buffer_size = 0, length = 0; char *buffer = NULL; int ch; while ((ch = (*read)(stream)) != EOF) { if (++length > buffer_size) { buffer_size += 100; buffer = realloc(buffer, buffer_size + 1); } if ((buffer[length - 1] = ch) == '\n') { buffer[--length] = '\0'; break; } buffer[length] = '\0'; } return buffer; } void by_paragraph(int (*read)(void *), void *in, void (*write)(void *, char *), void *out) { while (1) { char *line = read_paragraph(read, in); if ((line == NULL) || (strlen(line) == 0)) { return; } (*write)(out, line); free(line); } } cgreen-1.6.3/doc/tutorial_src/stream.h000066400000000000000000000002251450461175400177150ustar00rootroot00000000000000char *read_paragraph(int (*read)(void *), void *stream); void by_paragraph(int (*read)(void *), void *in, void (*write)(void *, char *), void *out); cgreen-1.6.3/doc/tutorial_src/stream0.out000066400000000000000000000001461450461175400203570ustar00rootroot00000000000000Running "stream" (1 test)... "ParagraphReader": 1 pass in 42ms. Completed "stream": 1 pass in 42ms. cgreen-1.6.3/doc/tutorial_src/stream1.c000066400000000000000000000014601450461175400177730ustar00rootroot00000000000000#include #include #include char *read_paragraph(int (*read)(void *), void *stream) { int buffer_size = 0, length = 0; char *buffer = NULL; int ch; while ((ch = (*read)(stream)) != EOF) { if (++length > buffer_size) { buffer_size += 100; buffer = realloc(buffer, buffer_size + 1); } if ((buffer[length - 1] = ch) == '\n') { buffer[--length] = '\0'; break; } buffer[length] = '\0'; } return buffer; } void by_paragraph(int (*read)(void *), void *in, void (*write)(void *, char *), void *out) { while (1) { char *line = read_paragraph(read, in); if (line == NULL) { return; } (*write)(out, line); free(line); } } cgreen-1.6.3/doc/tutorial_src/stream1.out000066400000000000000000000001461450461175400203600ustar00rootroot00000000000000Running "stream" (1 test)... "ParagraphReader": 1 pass in 42ms. Completed "stream": 1 pass in 42ms. cgreen-1.6.3/doc/tutorial_src/stream2.c000066400000000000000000000015111450461175400177710ustar00rootroot00000000000000#include #include #include char *read_paragraph(int (*read)(void *), void *stream) { int buffer_size = 0, length = 0; char *buffer = NULL; int ch; while ((ch = (*read)(stream)) != EOF) { if (++length > buffer_size) { buffer_size += 100; buffer = realloc(buffer, buffer_size + 1); } if ((buffer[length - 1] = ch) == '\n') { buffer[--length] = '\0'; break; } buffer[length] = '\0'; } return buffer; } void by_paragraph(int (*read)(void *), void *in, void (*write)(void *, char *), void *out) { while (1) { char *line = read_paragraph(read, in); if ((line == NULL) || (strlen(line) == 0)) { return; } (*write)(out, line); free(line); } } cgreen-1.6.3/doc/tutorial_src/stream2.out000066400000000000000000000004741450461175400203650ustar00rootroot00000000000000Running "stream" (2 tests)... stream_tests.c:23: Failure: ParagraphReader -> gives_one_character_line_for_one_character_stream Expected [line] to [equal string] ["a"] actual value: [""] expected to equal: ["a"] "ParagraphReader": 1 pass, 1 failure in 42ms. Completed "stream": 1 pass, 1 failure in 42ms. cgreen-1.6.3/doc/tutorial_src/stream3.out000066400000000000000000000001531450461175400203600ustar00rootroot00000000000000Running "stream" (2 tests)... "ParagraphReader": 2 passes in 42ms. Completed "stream": 2 passes in 42ms. cgreen-1.6.3/doc/tutorial_src/stream4.out000066400000000000000000000001531450461175400203610ustar00rootroot00000000000000Running "stream" (3 tests)... "ParagraphReader": 3 passes in 42ms. Completed "stream": 3 passes in 42ms. cgreen-1.6.3/doc/tutorial_src/stream5.out000066400000000000000000000010741450461175400203650ustar00rootroot00000000000000Running "stream" (5 tests)... stream_tests.c:40: Failure: ParagraphReader -> drops_line_ending_from_word_and_stops Expected [read_paragraph(&stream_stub, ((void *)0))] to [equal string] ["the"] actual value: ["the "] expected to equal: ["the"] stream_tests.c:45: Failure: ParagraphReader -> gives_empty_line_for_single_line_ending Expected [read_paragraph(&stream_stub, ((void *)0))] to [equal string] [""] actual value: [" "] expected to equal: [""] "ParagraphReader": 3 passes, 2 failures in 42ms. Completed "stream": 3 passes, 2 failures in 42ms. cgreen-1.6.3/doc/tutorial_src/stream6.out000066400000000000000000000001531450461175400203630ustar00rootroot00000000000000Running "stream" (5 tests)... "ParagraphReader": 5 passes in 42ms. Completed "stream": 5 passes in 42ms. cgreen-1.6.3/doc/tutorial_src/stream_tests0.c000066400000000000000000000006051450461175400212140ustar00rootroot00000000000000#include #include char *read_paragraph(int (*read)(void *), void *stream); static int empty_stream(void *stream) { return EOF; } Describe(ParagraphReader); BeforeEach(ParagraphReader) {} AfterEach(ParagraphReader) {} Ensure(ParagraphReader, gives_null_when_reading_empty_stream) { assert_that(read_paragraph(&empty_stream, NULL), is_null); } cgreen-1.6.3/doc/tutorial_src/stream_tests1.c000066400000000000000000000007521450461175400212200ustar00rootroot00000000000000#include #include char *read_paragraph(int (*read)(void *), void *stream); static int stream_stub(void *stream) { return (int)mock(stream); } Describe(ParagraphReader); BeforeEach(ParagraphReader) {} AfterEach(ParagraphReader) {} Ensure(ParagraphReader, gives_null_when_reading_empty_stream) { always_expect(stream_stub, will_return(EOF)); // <1> assert_that(read_paragraph(&stream_stub, NULL), is_null); } cgreen-1.6.3/doc/tutorial_src/stream_tests2.c000066400000000000000000000014051450461175400212150ustar00rootroot00000000000000#include #include char *read_paragraph(int (*read)(void *), void *stream); static int stream_stub(void *stream) { return (int)mock(stream); } Describe(ParagraphReader); BeforeEach(ParagraphReader) {} AfterEach(ParagraphReader) {} Ensure(ParagraphReader, gives_null_when_reading_empty_stream) { always_expect(stream_stub, will_return(EOF)); // <1> assert_that(read_paragraph(&stream_stub, NULL), is_null); } Ensure(ParagraphReader, gives_one_character_line_for_one_character_stream) { expect(stream_stub, will_return('a')); expect(stream_stub, will_return(EOF)); char *line = read_paragraph(&stream_stub, NULL); assert_that(line, is_equal_to_string("a")); free(line); } cgreen-1.6.3/doc/tutorial_src/stream_tests3.c000066400000000000000000000021161450461175400212160ustar00rootroot00000000000000#include #include char *read_paragraph(int (*read)(void *), void *stream); static int stream_stub(void *stream) { return (int)mock(stream); } Describe(ParagraphReader); BeforeEach(ParagraphReader) {} AfterEach(ParagraphReader) {} Ensure(ParagraphReader, gives_null_when_reading_empty_stream) { always_expect(stream_stub, will_return(EOF)); // <1> assert_that(read_paragraph(&stream_stub, NULL), is_null); } Ensure(ParagraphReader, gives_one_character_line_for_one_character_stream) { expect(stream_stub, will_return('a')); expect(stream_stub, will_return(EOF)); char *line = read_paragraph(&stream_stub, NULL); assert_that(line, is_equal_to_string("a")); free(line); } Ensure(ParagraphReader, gives_one_word_line_for_one_word_stream) { expect(stream_stub, will_return('t')); expect(stream_stub, will_return('h')); expect(stream_stub, will_return('e')); always_expect(stream_stub, will_return(EOF)); assert_that(read_paragraph(&stream_stub, NULL), is_equal_to_string("the")); } cgreen-1.6.3/doc/tutorial_src/stream_tests4.c000066400000000000000000000031161450461175400212200ustar00rootroot00000000000000#include #include char *read_paragraph(int (*read)(void *), void *stream); static int stream_stub(void *stream) { return (int)mock(stream); } Describe(ParagraphReader); BeforeEach(ParagraphReader) {} AfterEach(ParagraphReader) {} Ensure(ParagraphReader, gives_null_when_reading_empty_stream) { always_expect(stream_stub, will_return(EOF)); // <1> assert_that(read_paragraph(&stream_stub, NULL), is_null); } Ensure(ParagraphReader, gives_one_character_line_for_one_character_stream) { expect(stream_stub, will_return('a')); expect(stream_stub, will_return(EOF)); char *line = read_paragraph(&stream_stub, NULL); assert_that(line, is_equal_to_string("a")); free(line); } Ensure(ParagraphReader, gives_one_word_line_for_one_word_stream) { expect(stream_stub, will_return('t')); expect(stream_stub, will_return('h')); expect(stream_stub, will_return('e')); always_expect(stream_stub, will_return(EOF)); assert_that(read_paragraph(&stream_stub, NULL), is_equal_to_string("the")); } Ensure(ParagraphReader, drops_line_ending_from_word_and_stops) { expect(stream_stub, will_return('t')); expect(stream_stub, will_return('h')); expect(stream_stub, will_return('e')); expect(stream_stub, will_return('\n')); assert_that(read_paragraph(&stream_stub, NULL), is_equal_to_string("the")); } Ensure(ParagraphReader, gives_empty_line_for_single_line_ending) { expect(stream_stub, will_return('\n')); assert_that(read_paragraph(&stream_stub, NULL), is_equal_to_string("")); } cgreen-1.6.3/doc/tutorial_src/strlen1.out000066400000000000000000000001461450461175400203740ustar00rootroot00000000000000Running "our_tests" (1 test)... "our_tests": 1 pass in 42ms. Completed "our_tests": 1 pass in 42ms. cgreen-1.6.3/doc/tutorial_src/strlen2.out000066400000000000000000000001461450461175400203750ustar00rootroot00000000000000Running "our_tests" (1 test)... "our_tests": 1 pass in 42ms. Completed "our_tests": 1 pass in 42ms. cgreen-1.6.3/doc/tutorial_src/strlen3.out000066400000000000000000000001461450461175400203760ustar00rootroot00000000000000Running "our_tests" (1 test)... "our_tests": 1 pass in 42ms. Completed "our_tests": 1 pass in 42ms. cgreen-1.6.3/doc/tutorial_src/strlen4.out000066400000000000000000000001461450461175400203770ustar00rootroot00000000000000Running "our_tests" (1 test)... "our_tests": 1 pass in 42ms. Completed "our_tests": 1 pass in 42ms. cgreen-1.6.3/doc/tutorial_src/strlen5.out000066400000000000000000000001461450461175400204000ustar00rootroot00000000000000Running "our_tests" (1 test)... "our_tests": 1 pass in 42ms. Completed "our_tests": 1 pass in 42ms. cgreen-1.6.3/doc/tutorial_src/strlen6.out000066400000000000000000000003701450461175400204000ustar00rootroot00000000000000Running "our_tests" (1 test)... strlen_tests.c:9: Failure: returns_five_for_hello Expected [strlen("Hiya")] to [equal] [5] actual value: [4] expected value: [5] "our_tests": 1 failure in 42ms. Completed "our_tests": 1 failure in 42ms. cgreen-1.6.3/doc/tutorial_src/strlen7.out000066400000000000000000000004111450461175400203750ustar00rootroot00000000000000Running "our_tests" (2 tests)... strlen_tests.c:9: Failure: returns_five_for_hello Expected [strlen("Hiya")] to [equal] [5] actual value: [4] expected value: [5] "our_tests": 1 pass, 1 failure in 42ms. Completed "our_tests": 1 pass, 1 failure in 42ms. cgreen-1.6.3/doc/tutorial_src/strlen_tests1.c000066400000000000000000000007141450461175400212320ustar00rootroot00000000000000#include #include Describe(Strlen); BeforeEach(Strlen) {} AfterEach(Strlen) {} Ensure(Strlen, returns_five_for_hello) { assert_that(strlen("Hello"), is_equal_to(5)); } TestSuite *our_tests() { TestSuite *suite = create_test_suite(); add_test_with_context(suite, Strlen, returns_five_for_hello); return suite; } int main(int argc, char **argv) { return run_test_suite(our_tests(), create_text_reporter()); } cgreen-1.6.3/doc/tutorial_src/strlen_tests2.c000066400000000000000000000012211450461175400212250ustar00rootroot00000000000000#include #include Describe(Strlen); // <1> BeforeEach(Strlen) {} // <2> AfterEach(Strlen) {} // <3> Ensure(Strlen, returns_five_for_hello) { // <4> assert_that(strlen("Hello"), is_equal_to(5)); } TestSuite *our_tests() { TestSuite *suite = create_test_suite(); add_test_with_context(suite, Strlen, returns_five_for_hello); // <5> return suite; } int main(int argc, char **argv) { return run_test_suite(our_tests(), create_text_reporter()); } cgreen-1.6.3/doc/tutorial_src/strlen_tests3.c000066400000000000000000000007641450461175400212410ustar00rootroot00000000000000#include #include // <1> Ensure(strlen_returns_five_for_hello) { // <2> assert_that(strlen("Hello"), is_equal_to(5)); } TestSuite *our_tests() { TestSuite *suite = create_test_suite(); add_test(suite, strlen_returns_five_for_hello); // <3> return suite; } int main(int argc, char **argv) { return run_test_suite(our_tests(), create_text_reporter()); } cgreen-1.6.3/doc/tutorial_src/strlen_tests4.c000066400000000000000000000007451450461175400212410ustar00rootroot00000000000000#include #include Ensure(strlen_of_hello_is_five) { const char *greeting = "Hello"; int length = strlen(greeting); assert_equal_with_message(length, 5, "[%s] should be 5, but was %d", greeting, length); } TestSuite *our_tests() { TestSuite *suite = create_test_suite(); add_test(suite, strlen_of_hello_is_five); return suite; } int main(int argc, char **argv) { return run_test_suite(our_tests(), create_text_reporter()); } cgreen-1.6.3/doc/tutorial_src/strlen_tests5.c000066400000000000000000000007141450461175400212360ustar00rootroot00000000000000#include #include Describe(Strlen); BeforeEach(Strlen) {} AfterEach(Strlen) {} Ensure(Strlen, returns_five_for_hello) { assert_that(strlen("Hello"), is_equal_to(5)); } TestSuite *our_tests() { TestSuite *suite = create_test_suite(); add_test_with_context(suite, Strlen, returns_five_for_hello); return suite; } int main(int argc, char **argv) { return run_test_suite(our_tests(), create_text_reporter()); } cgreen-1.6.3/doc/tutorial_src/strlen_tests6.c000066400000000000000000000007131450461175400212360ustar00rootroot00000000000000#include #include Describe(Strlen); BeforeEach(Strlen) {} AfterEach(Strlen) {} Ensure(Strlen, returns_five_for_hello) { assert_that(strlen("Hiya"), is_equal_to(5)); } TestSuite *our_tests() { TestSuite *suite = create_test_suite(); add_test_with_context(suite, Strlen, returns_five_for_hello); return suite; } int main(int argc, char **argv) { return run_test_suite(our_tests(), create_text_reporter()); } cgreen-1.6.3/doc/tutorial_src/strlen_tests7.c000066400000000000000000000011521450461175400212350ustar00rootroot00000000000000#include #include Describe(Strlen); BeforeEach(Strlen) {} AfterEach(Strlen) {} Ensure(Strlen, returns_five_for_hello) { assert_that(strlen("Hiya"), is_equal_to(5)); } Ensure(Strlen, returns_zero_for_empty_string) { assert_equal(strlen("\0"), 0); } TestSuite *our_tests() { TestSuite *suite = create_test_suite(); add_test_with_context(suite, Strlen, returns_five_for_hello); add_test_with_context(suite, Strlen, returns_zero_for_empty_string); return suite; } int main(int argc, char **argv) { return run_test_suite(our_tests(), create_text_reporter()); } cgreen-1.6.3/doc/tutorial_src/struct_parameters.c000066400000000000000000000024141450461175400221660ustar00rootroot00000000000000#include #include #include Describe(StructParameters); BeforeEach(StructParameters) {} AfterEach(StructParameters) {} /* This is uncompilable code that is inserted as a non-example typedef struct { int i; char *string; } Struct; int function_taking_struct(Struct s) { return (int)mock(?); } */ typedef struct { int i; char *string; } Struct; int function_checking_a_field(Struct s) { return (int)mock(s.i); } Ensure(StructParameters, can_mock_field_in_parameter) { Struct struct_to_send = { .i = 12, .string = "hello" }; expect(function_checking_a_field, when(s.i, is_equal_to(12)), will_return(12)); assert_that(function_checking_a_field(struct_to_send), is_equal_to(12)); } int function_checking_multiple_fields(Struct s) { return (int)mock(s.i, s.string); } Ensure(StructParameters, can_mock_muultiple_fields_in_parameter) { Struct struct_to_send = { .i = 13, .string = "hello world!" }; expect(function_checking_multiple_fields, when(s.i, is_equal_to(13)), when(s.string, begins_with_string("hello")), will_return(13)); assert_that(function_checking_multiple_fields(struct_to_send), is_equal_to(13)); } cgreen-1.6.3/doc/tutorial_src/suite1.c000066400000000000000000000006051450461175400176310ustar00rootroot00000000000000#include TestSuite *our_tests(); TestSuite *person_tests(); int main(int argc, char **argv) { TestSuite *suite = create_test_suite(); add_suite(suite, our_tests()); add_suite(suite, person_tests()); if (argc > 1) { return run_single_test(suite, argv[1], create_text_reporter()); } return run_test_suite(suite, create_text_reporter()); } cgreen-1.6.3/doc/tutorial_src/suite1.out000066400000000000000000000000001450461175400202030ustar00rootroot00000000000000cgreen-1.6.3/doc/tutorial_src/suite_person_tests.c000066400000000000000000000027231450461175400223630ustar00rootroot00000000000000#include #include #include #include "person.h" static void create_schema() { MYSQL *connection = mysql_init(NULL); mysql_real_connect(connection, "localhost", "me", "secret", "test", 0, NULL, 0); mysql_query(connection, "create table people (name, varchar(255) unique)"); mysql_close(connection); } static void drop_schema() { MYSQL *connection = mysql_init(NULL); mysql_real_connect(connection, "localhost", "me", "secret", "test", 0, NULL, 0); mysql_query(connection, "drop table people"); mysql_close(connection); } Describe(Person); BeforeEach(Person) { create_schema(); } AfterEach(Person) { drop_schema(); } Ensure(Person, can_add_person_to_database) { Person *person = create_person(); set_person_name(person, "Fred"); save_person(person); Person *found = find_person_by_name("Fred"); assert_that(get_person_name(found), is_equal_to_string("Fred")); } Ensure(Person, cannot_add_duplicate_person) { Person *person = create_person(); set_person_name(person, "Fred"); assert_that(save_person(person), is_true); Person *duplicate = create_person(); set_person_name(duplicate, "Fred"); assert_that(save_person(duplicate), is_false); } TestSuite *person_tests() { TestSuite *suite = create_test_suite(); add_test_with_context(suite, Person, can_add_person_to_database); add_test_with_context(suite, Person, cannot_add_duplicate_person); return suite; } cgreen-1.6.3/doc/tutorial_src/suite_strlen_tests.c000066400000000000000000000010061450461175400223550ustar00rootroot00000000000000#include #include Describe(Strlen); BeforeEach(Strlen) {} AfterEach(Strlen) {} Ensure(Strlen, returns_five_for_hello) { assert_that(strlen("Hiya"), is_equal_to(5)); } Ensure(Strlen, returns_zero_for_empty_string) { assert_equal(strlen("\0"), 0); } TestSuite *our_tests() { TestSuite *suite = create_test_suite(); add_test_with_context(suite, Strlen, returns_five_for_hello); add_test_with_context(suite, Strlen, returns_zero_for_empty_string); return suite; } cgreen-1.6.3/doc/tutorial_src/test_as_xml0.c000066400000000000000000000013321450461175400210170ustar00rootroot00000000000000#include Describe(XML_reporter); BeforeEach(XML_reporter) {} AfterEach(XML_reporter) {} Ensure(XML_reporter, reports_a_test_that_passes) { assert_that(1 == 1); } Ensure(XML_reporter, reports_a_test_that_fails) { fail_test("A failure"); } TestSuite *create_test_group() { TestSuite *suite = create_named_test_suite("A Group"); add_test_with_context(suite, XML_reporter, reports_a_test_that_passes); add_test_with_context(suite, XML_reporter, reports_a_test_that_fails); return suite; } int main(int argc, char **argv) { TestSuite *suite = create_named_test_suite("Top Level"); add_suite(suite, create_test_group()); return run_test_suite(suite, create_text_reporter()); } cgreen-1.6.3/doc/tutorial_src/test_as_xml0.out000066400000000000000000000003101450461175400213770ustar00rootroot00000000000000Running "Top Level" (2 tests)... test_as_xml.c:12: Failure: A Group -> reports_a_test_that_fails A failure "A Group": 1 pass, 1 failure in 42ms. Completed "Top Level": 1 pass, 1 failure in 42ms. cgreen-1.6.3/doc/tutorial_src/test_as_xml1.c000066400000000000000000000014111450461175400210160ustar00rootroot00000000000000#include #include #include "xml_reporter.h" Describe(XML_reporter); BeforeEach(XML_reporter) {} AfterEach(XML_reporter) {} Ensure(XML_reporter, reports_a_test_that_passes) { assert_that(1 == 1); } Ensure(XML_reporter, reports_a_test_that_fails) { fail_test("A failure"); } TestSuite *create_test_group() { TestSuite *suite = create_named_test_suite("A Group"); add_test_with_context(suite, XML_reporter, reports_a_test_that_passes); add_test_with_context(suite, XML_reporter, reports_a_test_that_fails); return suite; } int main(int argc, char **argv) { TestSuite *suite = create_named_test_suite("Top Level"); add_suite(suite, create_test_group()); return run_test_suite(suite, create_xml_reporter()); } cgreen-1.6.3/doc/tutorial_src/test_as_xml1.out000066400000000000000000000002431450461175400214050ustar00rootroot00000000000000 cgreen-1.6.3/doc/tutorial_src/test_as_xml2.out000066400000000000000000000003741450461175400214130ustar00rootroot00000000000000 A failure cgreen-1.6.3/doc/tutorial_src/test_as_xml3.out000066400000000000000000000003741450461175400214140ustar00rootroot00000000000000 A failure cgreen-1.6.3/doc/tutorial_src/test_as_xml4.out000066400000000000000000000004321450461175400214100ustar00rootroot00000000000000 A failure cgreen-1.6.3/doc/tutorial_src/words.c000066400000000000000000000011001450461175400175440ustar00rootroot00000000000000#include int split_words(char *sentence) { int i, count = 1, length = strlen(sentence); for (i = 0; i < length; i++) { if (sentence[i] == ' ') { sentence[i] = '\0'; count++; } } return count; } void words(const char *sentence, void (*walker)(const char *, void *), void *memo) { char *words = strdup(sentence); int word_count = split_words(words); char *word = words; while (word_count-- > 0) { (*walker)(word, memo); word = word + strlen(word) + 1; } free(words); } cgreen-1.6.3/doc/tutorial_src/words.h000066400000000000000000000001671450461175400175650ustar00rootroot00000000000000int split_words(char *sentence); void words(const char *sentence, void (*callback)(const char *, void *), void *memo); cgreen-1.6.3/doc/tutorial_src/words0.out000066400000000000000000000001351450461175400202200ustar00rootroot00000000000000Running "main" (0 tests)... "words_tests": No assertions. Completed "main": No assertions. cgreen-1.6.3/doc/tutorial_src/words1.c000066400000000000000000000001071450461175400176330ustar00rootroot00000000000000#include int split_words(char *sentence) { return 0; } cgreen-1.6.3/doc/tutorial_src/words1.out000066400000000000000000000003671450461175400202300ustar00rootroot00000000000000Running "main" (1 test)... words_tests.c:13: Failure: words_tests -> returns_word_count Expected [word_count] to [equal] [4] actual value: [0] expected value: [4] "words_tests": 1 failure in 42ms. Completed "main": 1 failure in 42ms. cgreen-1.6.3/doc/tutorial_src/words2.c000066400000000000000000000002771450461175400176440ustar00rootroot00000000000000#include int split_words(char *sentence) { int i, count = 1; for (i = 0; i < strlen(sentence); i++) { if (sentence[i] == ' ') { count++; } } return count; } cgreen-1.6.3/doc/tutorial_src/words2.out000066400000000000000000000001361450461175400202230ustar00rootroot00000000000000Running "main" (1 test)... "words_tests": 1 pass in 42ms. Completed "main": 1 pass in 42ms. cgreen-1.6.3/doc/tutorial_src/words3.c000066400000000000000000000003311450461175400176340ustar00rootroot00000000000000#include int split_words(char *sentence) { int i, count = 1; for (i = 0; i < strlen(sentence); i++) { if (sentence[i] == ' ') { sentence[i] = '\0'; count++; } } return count; } cgreen-1.6.3/doc/tutorial_src/words3.out000066400000000000000000000004211450461175400202210ustar00rootroot00000000000000Running "main" (2 tests)... words_tests.c:21: Failure: words_tests -> converts_spaces_to_zeroes Expected [comparison] to [equal] [0] actual value: [-32] expected value: [0] "words_tests": 1 pass, 1 failure in 42ms. Completed "main": 1 pass, 1 failure in 42ms. cgreen-1.6.3/doc/tutorial_src/words4.c000066400000000000000000000003521450461175400176400ustar00rootroot00000000000000#include int split_words(char *sentence) { int i, count = 1, length = strlen(sentence); for (i = 0; i < length; i++) { if (sentence[i] == ' ') { sentence[i] = '\0'; count++; } } return count; } cgreen-1.6.3/doc/tutorial_src/words4.out000066400000000000000000000004101450461175400202200ustar00rootroot00000000000000Running "main" (2 tests)... words_tests.c:13: Failure: words_tests -> returns_word_count Expected [word_count] to [equal] [4] actual value: [2] expected value: [4] "words_tests": 1 pass, 1 failure in 42ms. Completed "main": 1 pass, 1 failure in 42ms. cgreen-1.6.3/doc/tutorial_src/words5.c000066400000000000000000000005041450461175400176400ustar00rootroot00000000000000#include int split_words(char *sentence) { int i, count = 1, length = strlen(sentence); for (i = 0; i < length; i++) { if (sentence[i] == ' ') { sentence[i] = '\0'; count++; } } return count; } void words(const char *sentence, void (*callback)(const char *, void *), void *memo) { } cgreen-1.6.3/doc/tutorial_src/words5.out000066400000000000000000000001431450461175400202240ustar00rootroot00000000000000Running "main" (2 tests)... "words_tests": 2 passes in 42ms. Completed "main": 2 passes in 42ms. cgreen-1.6.3/doc/tutorial_src/words6.c000066400000000000000000000005431450461175400176440ustar00rootroot00000000000000#include int split_words(char *sentence) { int i, count = 1, length = strlen(sentence); for (i = 0; i < length; i++) { if (sentence[i] == ' ') { sentence[i] = '\0'; count++; } } return count; } void words(const char *sentence, void (*callback)(const char *, void *), void *memo) { (*callback)(sentence, memo); } cgreen-1.6.3/doc/tutorial_src/words6.out000066400000000000000000000004251450461175400202300ustar00rootroot00000000000000Running "main" (3 tests)... words_tests.c:32: Failure: words_tests -> invokes_callback_once_for_single_word_sentence Expected call was not made to mocked function [mocked_callback] "words_tests": 2 passes, 1 failure in 42ms. Completed "main": 2 passes, 1 failure in 42ms. cgreen-1.6.3/doc/tutorial_src/words7.c000066400000000000000000000010501450461175400176370ustar00rootroot00000000000000#include #include int split_words(char *sentence) { int i, count = 1, length = strlen(sentence); for (i = 0; i < length; i++) { if (sentence[i] == ' ') { sentence[i] = '\0'; count++; } } return count; } void words(const char *sentence, void (*callback)(const char *, void *), void *memo) { char *words = strdup(sentence); int word_count = split_words(words); char *word = words; while (word_count-- > 0) { (*callback)(word, memo); word = word + strlen(word) + 1; } free(words); } cgreen-1.6.3/doc/tutorial_src/words7.out000066400000000000000000000001431450461175400202260ustar00rootroot00000000000000Running "main" (3 tests)... "words_tests": 4 passes in 42ms. Completed "main": 4 passes in 42ms. cgreen-1.6.3/doc/tutorial_src/words8.out000066400000000000000000000014611450461175400202330ustar00rootroot00000000000000Running "main" (4 tests)... words_tests.c:38: Failure: words_tests -> invokes_callback_for_each_word_in_a_phrase Expected [[word] parameter in [mocked_callback]] to [equal string] ["Birds"] actual value: ["Birds of a feather"] expected to equal: ["Birds"] words_tests.c:39: Failure: words_tests -> invokes_callback_for_each_word_in_a_phrase Expected call was not made to mocked function [mocked_callback] words_tests.c:40: Failure: words_tests -> invokes_callback_for_each_word_in_a_phrase Expected call was not made to mocked function [mocked_callback] words_tests.c:41: Failure: words_tests -> invokes_callback_for_each_word_in_a_phrase Expected call was not made to mocked function [mocked_callback] "words_tests": 4 passes, 4 failures in 42ms. Completed "main": 4 passes, 4 failures in 42ms. cgreen-1.6.3/doc/tutorial_src/words9.out000066400000000000000000000001431450461175400202300ustar00rootroot00000000000000Running "main" (4 tests)... "words_tests": 8 passes in 42ms. Completed "main": 8 passes in 42ms. cgreen-1.6.3/doc/tutorial_src/words_tests0.c000066400000000000000000000003641450461175400210610ustar00rootroot00000000000000#include #include #include "words.h" #include Describe(Words); BeforeEach(Words) {} AfterEach(Words) {} TestSuite *words_tests() { TestSuite *suite = create_test_suite(); return suite; } cgreen-1.6.3/doc/tutorial_src/words_tests1.c000066400000000000000000000007361450461175400210650ustar00rootroot00000000000000#include #include "words.h" #include Describe(Words); BeforeEach(Words) {} AfterEach(Words) {} Ensure(Words, returns_word_count) { char *sentence = strdup("Birds of a feather"); int word_count = split_words(sentence); assert_that(word_count, is_equal_to(4)); free(sentence); } TestSuite *words_tests() { TestSuite *suite = create_test_suite(); add_test_with_context(suite, Words, returns_word_count); return suite; } cgreen-1.6.3/doc/tutorial_src/words_tests2.c000066400000000000000000000014621450461175400210630ustar00rootroot00000000000000#include #include "words.h" #include Describe(Words); BeforeEach(Words) {} AfterEach(Words) {} Ensure(Words, returns_word_count) { char *sentence = strdup("Birds of a feather"); int word_count = split_words(sentence); assert_that(word_count, is_equal_to(4)); free(sentence); } Ensure(Words, converts_spaces_to_zeroes) { char *sentence = strdup("Birds of a feather"); split_words(sentence); int comparison = memcmp("Birds\0of\0a\0feather", sentence, strlen(sentence)); assert_that(comparison, is_equal_to(0)); free(sentence); } TestSuite *words_tests() { TestSuite *suite = create_test_suite(); add_test_with_context(suite, Words, returns_word_count); add_test_with_context(suite, Words, converts_spaces_to_zeroes); return suite; } cgreen-1.6.3/doc/tutorial_src/words_tests3.c000066400000000000000000000023101450461175400210550ustar00rootroot00000000000000#include #include #include "words.h" #include Describe(Words); BeforeEach(Words) {} AfterEach(Words) {} Ensure(Words, returns_word_count) { char *sentence = strdup("Birds of a feather"); int word_count = split_words(sentence); assert_that(word_count, is_equal_to(4)); free(sentence); } Ensure(Words, converts_spaces_to_zeroes) { char *sentence = strdup("Birds of a feather"); split_words(sentence); int comparison = memcmp("Birds\0of\0a\0feather", sentence, strlen(sentence)); assert_that(comparison, is_equal_to(0)); free(sentence); } void mocked_callback(const char *word, void *memo) { mock(word, memo); } Ensure(Words, invokes_callback_once_for_single_word_sentence) { expect(mocked_callback, when(word, is_equal_to_string("Word")), when(memo, is_null)); words("Word", &mocked_callback, NULL); } TestSuite *words_tests() { TestSuite *suite = create_test_suite(); add_test_with_context(suite, Words, returns_word_count); add_test_with_context(suite, Words, converts_spaces_to_zeroes); add_test_with_context(suite, Words, invokes_callback_once_for_single_word_sentence); return suite; } cgreen-1.6.3/doc/tutorial_src/words_tests4.c000066400000000000000000000032531450461175400210650ustar00rootroot00000000000000#include #include #include "words.h" #include Describe(Words); BeforeEach(Words) {} AfterEach(Words) {} Ensure(Words, returns_word_count) { char *sentence = strdup("Birds of a feather"); int word_count = split_words(sentence); assert_that(word_count, is_equal_to(4)); free(sentence); } Ensure(Words, converts_spaces_to_zeroes) { char *sentence = strdup("Birds of a feather"); split_words(sentence); int comparison = memcmp("Birds\0of\0a\0feather", sentence, strlen(sentence)); assert_that(comparison, is_equal_to(0)); free(sentence); } void mocked_callback(const char *word, void *memo) { mock(word, memo); } Ensure(Words, invokes_callback_once_for_single_word_sentence) { expect(mocked_callback, when(word, is_equal_to_string("Word")), when(memo, is_null)); words("Word", &mocked_callback, NULL); } Ensure(Words, invokes_callback_for_each_word_in_a_phrase) { expect(mocked_callback, when(word, is_equal_to_string("Birds"))); expect(mocked_callback, when(word, is_equal_to_string("of"))); expect(mocked_callback, when(word, is_equal_to_string("a"))); expect(mocked_callback, when(word, is_equal_to_string("feather"))); words("Birds of a feather", &mocked_callback, NULL); } TestSuite *words_tests() { TestSuite *suite = create_test_suite(); add_test_with_context(suite, Words, returns_word_count); add_test_with_context(suite, Words, converts_spaces_to_zeroes); add_test_with_context(suite, Words, invokes_callback_once_for_single_word_sentence); add_test_with_context(suite, Words, invokes_callback_for_each_word_in_a_phrase); return suite; } cgreen-1.6.3/doc/tutorial_src/xml_reporter.c000066400000000000000000000052051450461175400211420ustar00rootroot00000000000000#include "xml_reporter.h" #include "cgreen/reporter.h" #include "cgreen/breadcrumb.h" #include static void xml_reporter_start_suite(TestReporter *reporter, const char *name, int count); static void xml_reporter_start_test(TestReporter *reporter, const char *name); static void xml_reporter_finish_test(TestReporter *reporter, const char *filename, int line); static void xml_reporter_finish_suite(TestReporter *reporter, const char *filename, int line); static void xml_show_fail(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments); TestReporter *create_xml_reporter() { TestReporter *reporter = create_reporter(); reporter->start_suite = &xml_reporter_start_suite; reporter->start_test = &xml_reporter_start_test; reporter->show_fail = &xml_show_fail; reporter->finish_test = &xml_reporter_finish_test; reporter->finish_suite = &xml_reporter_finish_suite; return reporter; } static indent(TestReporter *reporter) { int depth = get_breadcrumb_depth((CgreenBreadcrumb *)reporter->breadcrumb); while (depth-- > 0) { printf("\t"); } } static void xml_reporter_start_suite(TestReporter *reporter, const char *name, int count) { if (get_breadcrumb_depth((CgreenBreadcrumb *)reporter->breadcrumb) == 0) { printf("\n"); } indent(reporter); printf("\n", name); reporter_start(reporter, name); } static void xml_reporter_start_test(TestReporter *reporter, const char *name) { indent(reporter); printf("\n", name); reporter_start(reporter, name); } static void xml_show_fail(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments) { indent(reporter); printf("\n"); indent(reporter); printf("\t"); vprintf(message, arguments); printf("\n"); indent(reporter); printf("\t\n", file, line); indent(reporter); printf("\n"); } static void xml_show_incomplete(TestReporter *reporter, const char *name) { indent(reporter); printf("\n"); indent(reporter); printf("\tFailed to complete]]>\n"); indent(reporter); printf("\n"); } static void xml_reporter_finish_test(TestReporter *reporter, const char *filename, int line) { reporter_finish_test(reporter, filename, line); indent(reporter); printf("\n"); } static void xml_reporter_finish_suite(TestReporter *reporter, const char *filename, int line) { reporter_finish_suite(reporter, filename, line); indent(reporter); printf("\n"); } cgreen-1.6.3/doc/tutorial_src/xml_reporter.h000066400000000000000000000002101450461175400211360ustar00rootroot00000000000000#ifndef _XML_REPORTER_HEADER_ #define _XML_REPORTER_HEADER_ #include TestReporter *create_xml_reporter(); #endif cgreen-1.6.3/doc/tutorial_src/xml_reporter0.c000066400000000000000000000002461450461175400212220ustar00rootroot00000000000000#include #include "xml_reporter.h" TestReporter *create_xml_reporter() { TestReporter *reporter = create_reporter(); return reporter; } cgreen-1.6.3/doc/tutorial_src/xml_reporter1.c000066400000000000000000000022251450461175400212220ustar00rootroot00000000000000#include #include #include #include "xml_reporter.h" static void xml_reporter_start_suite(TestReporter *reporter, const char *name, int count) { printf("\n", name); reporter_start_suite(reporter, name, count); } static void xml_reporter_start_test(TestReporter *reporter, const char *name) { printf("\n", name); reporter_start_test(reporter, name); } static void xml_reporter_finish_test(TestReporter *reporter, const char *filename, int line, const char *message) { reporter_finish_test(reporter, filename, line, message); printf("\n"); } static void xml_reporter_finish_suite(TestReporter *reporter, const char *filename, int line) { reporter_finish_suite(reporter, filename, line); printf("\n"); } TestReporter *create_xml_reporter() { TestReporter *reporter = create_reporter(); reporter->start_suite = &xml_reporter_start_suite; reporter->start_test = &xml_reporter_start_test; reporter->finish_test = &xml_reporter_finish_test; reporter->finish_suite = &xml_reporter_finish_suite; return reporter; } cgreen-1.6.3/doc/tutorial_src/xml_reporter2.c000066400000000000000000000030321450461175400212200ustar00rootroot00000000000000#include #include #include #include #include "xml_reporter.h" static void xml_reporter_start_suite(TestReporter *reporter, const char *name, int count) { printf("\n", name); reporter_start_suite(reporter, name, count); } static void xml_reporter_start_test(TestReporter *reporter, const char *name) { printf("\n", name); reporter_start_test(reporter, name); } static void xml_show_fail(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments) { printf("\n"); printf("\t"); vprintf(message, arguments); printf("\n"); printf("\t\n", file, line); printf("\n"); } static void xml_reporter_finish_test(TestReporter *reporter, const char *filename, int line, const char *message) { reporter_finish_test(reporter, filename, line, message); printf("\n"); } static void xml_reporter_finish_suite(TestReporter *reporter, const char *filename, int line) { reporter_finish_suite(reporter, filename, line); printf("\n"); } TestReporter *create_xml_reporter() { TestReporter *reporter = create_reporter(); reporter->start_suite = &xml_reporter_start_suite; reporter->start_test = &xml_reporter_start_test; reporter->show_fail = &xml_show_fail; reporter->finish_test = &xml_reporter_finish_test; reporter->finish_suite = &xml_reporter_finish_suite; return reporter; } cgreen-1.6.3/doc/tutorial_src/xml_reporter3.c000066400000000000000000000034501450461175400212250ustar00rootroot00000000000000#include #include #include #include "xml_reporter.h" static void xml_reporter_start_suite(TestReporter *reporter, const char *name, int count) { printf("\n", name); reporter_start_suite(reporter, name, count); } static void xml_reporter_start_test(TestReporter *reporter, const char *name) { printf("\n", name); reporter_start_test(reporter, name); } static void xml_show_fail(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments) { printf("\n"); printf("\t"); vprintf(message, arguments); printf("\n"); printf("\t\n", file, line); printf("\n"); } static void xml_show_incomplete(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments) { printf("\n"); printf("\tFailed to complete\n"); printf("\n"); } static void xml_reporter_finish_test(TestReporter *reporter, const char *filename, int line, const char *message) { reporter_finish_test(reporter, filename, line, message); printf("\n"); } static void xml_reporter_finish_suite(TestReporter *reporter, const char *filename, int line) { reporter_finish_suite(reporter, filename, line); printf("\n"); } TestReporter *create_xml_reporter() { TestReporter *reporter = create_reporter(); reporter->start_suite = &xml_reporter_start_suite; reporter->start_test = &xml_reporter_start_test; reporter->show_fail = &xml_show_fail; reporter->show_incomplete = &xml_show_incomplete; reporter->finish_test = &xml_reporter_finish_test; reporter->finish_suite = &xml_reporter_finish_suite; return reporter; } cgreen-1.6.3/doc/tutorial_src/xml_reporter4.c000066400000000000000000000045011450461175400212240ustar00rootroot00000000000000#include #include #include #include "xml_reporter.h" static void indent(TestReporter *reporter) { int depth = get_breadcrumb_depth((CgreenBreadcrumb *)reporter->breadcrumb); while (depth-- > 0) { printf("\t"); } } static void xml_reporter_start_suite(TestReporter *reporter, const char *name, int count) { if (get_breadcrumb_depth((CgreenBreadcrumb *)reporter->breadcrumb) == 0) { printf("\n"); } indent(reporter); printf("\n", name); reporter_start_suite(reporter, name, count); } static void xml_reporter_start_test(TestReporter *reporter, const char *name) { indent(reporter); printf("\n", name); reporter_start_test(reporter, name); } static void xml_show_fail(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments) { indent(reporter); printf("\n"); indent(reporter); printf("\t"); vprintf(message, arguments); printf("\n"); indent(reporter); printf("\t\n", file, line); indent(reporter); printf("\n"); } static void xml_show_incomplete(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments) { indent(reporter); printf("\n"); indent(reporter); printf("\tFailed to complete\n"); indent(reporter); printf("\n"); } static void xml_reporter_finish_test(TestReporter *reporter, const char *filename, int line, const char *message) { reporter_finish_test(reporter, filename, line, message); indent(reporter); printf("\n"); } static void xml_reporter_finish_suite(TestReporter *reporter, const char *filename, int line) { reporter_finish_suite(reporter, filename, line); indent(reporter); printf("\n"); } TestReporter *create_xml_reporter() { TestReporter *reporter = create_reporter(); reporter->start_suite = &xml_reporter_start_suite; reporter->start_test = &xml_reporter_start_test; reporter->show_fail = &xml_show_fail; reporter->show_incomplete = &xml_show_incomplete; reporter->finish_test = &xml_reporter_finish_test; reporter->finish_suite = &xml_reporter_finish_suite; return reporter; } cgreen-1.6.3/fatify000077500000000000000000000044471450461175400142140ustar00rootroot00000000000000#! /bin/sh # # This script is a part of Cgreen and creates fat versions of # cgreen-runner and libcgreen.dylib which is necessary if you are # using e.g. Homebrew/MacPorts gcc which don't have suppport for fat # binaries built in. # # NOTE: This does not work completely automatic for x86_64/M1 since # Homebrew GCC can only compile for the current architecture. # # Since automatically ensuring that both architectures are built is # currently impossible from a single environment, you have to run this # script once on each architecture. The script will save the built # binaries under descriptive names and if it discovers that binaries # for the other architecture already exists it uses lipo to merge them # into fat binaries. # # At this point there is no way to run this as part of the CMake build # and install, and since the install target of CMake always rebuilds # you can't install them except with manual copying. # # /thoni56 # function buildfor() { rm -rf build make cp build/tools/cgreen-runner cgreen-runner.$1 cp build/src/libcgreen.dylib libcgreen.$1.dylib } arch=`arch` if [ $arch == "arm64" ] ; then buildfor arm64 if [ ! -f libcgreen.x86_64.dylib ] ; then echo "You need to run this aldo in an x86_64 environment to create fat binaries." exit fi else buildfor x86_64 if [ ! -f libcgreen.arm64.dylib ] ; then echo "You need to run this in an arm64 environment to create fat binaries." exit fi fi lipo -create -o cgreen-runner -arch arm64 cgreen-runner.arm64 -arch x86_64 cgreen-runner.x86_64 lipo -create -o libcgreen.dylib -arch arm64 libcgreen.arm64.dylib -arch x86_64 libcgreen.x86_64.dylib if [ -z "$1" ] ; then echo "Fat binaries of cgreen-runner and libcgreen.dylib built:" file cgreen-runner libcgreen.dylib echo "Install with:" echo " sudo cp cgreen-runner /bin/cgreen-runner" echo " sudo cp libcgreen.dylib /lib/libcgreen.dylib" echo echo "If is the same for bin and lib, such as '/usr/local'," echo "you can give that as an argument and the script will do that for you." else echo "Installing fat 'cgreen-runner' in $1/bin and 'libcgreen.dylib' in $1/lib..." sudo cp cgreen-runner $1/bin/cgreen-runner sudo cp libcgreen.dylib $1/lib/libcgreen.dylib fi cgreen-1.6.3/gitrevision.h.in000066400000000000000000000001351450461175400161120ustar00rootroot00000000000000/* This file was autogenerated based from cmake */ #cmakedefine GITREVISION "@GITREVISION@" cgreen-1.6.3/include/000077500000000000000000000000001450461175400144165ustar00rootroot00000000000000cgreen-1.6.3/include/CMakeLists.txt000066400000000000000000000000311450461175400171500ustar00rootroot00000000000000add_subdirectory(cgreen) cgreen-1.6.3/include/cgreen/000077500000000000000000000000001450461175400156615ustar00rootroot00000000000000cgreen-1.6.3/include/cgreen/CMakeLists.txt000066400000000000000000000010031450461175400204130ustar00rootroot00000000000000set(cgreen_HDRS assertions.h boxed_double.h breadcrumb.h cdash_reporter.h cgreen.h cgreen_value.h constraint.h constraint_syntax_helpers.h cpp_assertions.h cpp_constraint.h cute_reporter.h filename.h legacy.h mocks.h string_comparison.h reporter.h runner.h suite.h text_reporter.h unit.h vector.h xml_reporter.h ) install( FILES ${cgreen_HDRS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${APPLICATION_NAME} COMPONENT headers ) add_subdirectory(internal) cgreen-1.6.3/include/cgreen/assertions.h000066400000000000000000000017771450461175400202400ustar00rootroot00000000000000#ifndef ASSERTIONS_HEADER #define ASSERTIONS_HEADER #include "internal/assertions_internal.h" #include "internal/stringify_token.h" #include #include #include #include #ifndef __cplusplus #include #endif #ifdef __cplusplus #include namespace cgreen { extern "C" { #endif /* Modern style asserts using constraints: assert_that(actual, (expected)); assert_that(); */ #define assert_that(...) assert_that_NARG(__VA_ARGS__)(__VA_ARGS__) #define assert_that_double(actual, constraint) assert_that_double_(FILENAME, __LINE__, STRINGIFY_TOKEN(actual), (double)(actual), (constraint)) #define pass_test() assert_true(true) #define fail_test(...) assert_true_with_message(false, __VA_ARGS__) /* Utility: */ int get_significant_figures(void); void significant_figures_for_assert_double_are(int figures); #include #ifdef __cplusplus } } #endif #endif cgreen-1.6.3/include/cgreen/boxed_double.h000066400000000000000000000005701450461175400204670ustar00rootroot00000000000000#ifndef BOXED_DOUBLE_HEADER #define BOXED_DOUBLE_HEADER #include #ifdef __cplusplus namespace cgreen { extern "C" { #endif intptr_t box_double(double d); double as_double(intptr_t boxed_double); double unbox_double(intptr_t boxed_double); typedef union { double value; } BoxedDouble; #ifdef __cplusplus } } #endif #endif /* BOXED_DOUBLE_HEADER */ cgreen-1.6.3/include/cgreen/breadcrumb.h000066400000000000000000000013501450461175400201370ustar00rootroot00000000000000#ifndef BREADCRUMB_HEADER #define BREADCRUMB_HEADER struct CgreenBreadcrumb_ { const char **trail; int depth; int space; }; typedef struct CgreenBreadcrumb_ CgreenBreadcrumb; #ifdef __cplusplus namespace cgreen { extern "C" { #endif CgreenBreadcrumb *create_breadcrumb(void); void destroy_breadcrumb(CgreenBreadcrumb *breadcrumb); void push_breadcrumb(CgreenBreadcrumb *breadcrumb, const char *name); void pop_breadcrumb(CgreenBreadcrumb *breadcrumb); const char *get_current_from_breadcrumb(CgreenBreadcrumb *breadcrumb); int get_breadcrumb_depth(CgreenBreadcrumb *breadcrumb); void walk_breadcrumb(CgreenBreadcrumb *breadcrumb, void (*walker)(const char *, void *), void *memo); #ifdef __cplusplus } } #endif #endif cgreen-1.6.3/include/cgreen/cdash_reporter.h000066400000000000000000000007261450461175400210430ustar00rootroot00000000000000#ifndef CDASH_REPORTER_HEADER #define CDASH_REPORTER_HEADER #include #include #ifdef __cplusplus namespace cgreen { extern "C" { #endif typedef struct CDashInfo_ CDashInfo; struct CDashInfo_ { char *name; char *build; char *type; char *hostname; char *os_name; char *os_platform; char *os_release; char *os_version; }; extern TestReporter *create_cdash_reporter(CDashInfo *cdash); #ifdef __cplusplus } } #endif #endif cgreen-1.6.3/include/cgreen/cgreen.h000066400000000000000000000010001450461175400172640ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #define CGREEN_VERSION "1.6.3" #define CGREEN_VERSION_MAJOR 1 #define CGREEN_VERSION_MINOR 6 #define CGREEN_VERSION_PATCH 3 extern char *cgreen_library_version; extern char *cgreen_library_revision; cgreen-1.6.3/include/cgreen/cgreen_value.h000066400000000000000000000010061450461175400204660ustar00rootroot00000000000000#ifndef CGREEN_VALUE_HEADER #define CGREEN_VALUE_HEADER #include #include typedef enum { CGREEN_INTEGER, CGREEN_STRING, CGREEN_DOUBLE, CGREEN_POINTER, CGREEN_BYVALUE } CgreenValueType; typedef struct { CgreenValueType type; union { intptr_t integer_value; double double_value; void *pointer_value; const char *string_value; } value; size_t value_size; } CgreenValue; #endif cgreen-1.6.3/include/cgreen/constraint.h000066400000000000000000000114221450461175400202160ustar00rootroot00000000000000#ifndef CONSTRAINT_HEADER #define CONSTRAINT_HEADER #include #include #ifndef __cplusplus #include #endif #include #include typedef enum { CGREEN_VALUE_COMPARER_CONSTRAINT, CGREEN_CONTENT_COMPARER_CONSTRAINT, CGREEN_STRING_COMPARER_CONSTRAINT, CGREEN_DOUBLE_COMPARER_CONSTRAINT, CGREEN_RETURN_VALUE_CONSTRAINT, CGREEN_CONTENT_SETTER_CONSTRAINT, CGREEN_RETURN_POINTER_CONSTRAINT, CGREEN_CALL_CONSTRAINT, CGREEN_CALL_COUNTER_CONSTRAINT, CGREEN_RETURN_BY_VALUE_CONSTRAINT, CGREEN_CAPTURE_PARAMETER_CONSTRAINT } ConstraintType; typedef struct Constraint_ Constraint; struct Constraint_ { ConstraintType type; const char *name; void (*destroy)(Constraint *); bool (*compare)(Constraint *, CgreenValue); void (*execute)(Constraint *, const char *, CgreenValue, const char *, int, TestReporter *); char *(*failure_message)(Constraint *, const char *, intptr_t); const char *actual_value_message; const char *expected_value_message; CgreenValue expected_value; const char *expected_value_name; /* for PARAMETER constraints */ const char *parameter_name; size_t size_of_expected_value; /* Side Effect parameters */ void (*side_effect_callback)(void *); void *side_effect_data; }; #ifdef __cplusplus namespace cgreen { extern "C" { #endif Constraint *create_constraint(void); Constraint *create_parameter_constraint_for(const char *parameter_name); bool compare_want_value(Constraint *constraint, CgreenValue actual); bool compare_do_not_want_value(Constraint *constraint, CgreenValue actual); void test_want(Constraint *constraint, const char *function, CgreenValue actual, const char *test_file, int test_line, TestReporter *reporter); void test_constraint(Constraint *constraint, const char *function, intptr_t actual, const char *test_file, int test_line, TestReporter *reporter); Constraint *create_equal_to_value_constraint(intptr_t expected_value, const char *expected_value_name); Constraint *create_equal_to_hexvalue_constraint(intptr_t expected_value, const char *expected_value_name); Constraint *create_not_equal_to_value_constraint(intptr_t expected_value, const char *expected_value_name); Constraint *create_not_null_constraint(void); Constraint *create_is_null_constraint(void); Constraint *create_is_false_constraint(void); Constraint *create_is_true_constraint(void); Constraint *create_greater_than_value_constraint(intptr_t expected_value, const char *expected_value_name); Constraint *create_less_than_value_constraint(intptr_t expected_value, const char *expected_value_name); Constraint *create_equal_to_contents_constraint(void *pointer_to_compare, size_t size_to_compare, const char *compared_pointer_name); Constraint *create_not_equal_to_contents_constraint(void *pointer_to_compare, size_t size_to_compare, const char *compared_pointer_name); Constraint *create_equal_to_string_constraint(const char* expected_value, const char *expected_value_name); Constraint *create_not_equal_to_string_constraint(const char* expected_value, const char *expected_value_name); Constraint *create_contains_string_constraint(const char* expected_value, const char *expected_value_name); Constraint *create_does_not_contain_string_constraint(const char* expected_value, const char *expected_value_name); Constraint *create_begins_with_string_constraint(const char* expected_value, const char *expected_value_name); Constraint *create_does_not_begin_with_string_constraint(const char* expected_value, const char *expected_value_name); Constraint *create_ends_with_string_constraint(const char* expected_value, const char *expected_value_name); Constraint *create_does_not_end_with_string_constraint(const char* expected_value, const char *expected_value_name); Constraint *create_equal_to_double_constraint(double expected_value, const char *expected_value_name); Constraint *create_not_equal_to_double_constraint(double expected_value, const char *expected_value_name); Constraint *create_less_than_double_constraint(double expected_value, const char *expected_value_name); Constraint *create_greater_than_double_constraint(double expected_value, const char *expected_value_name); Constraint *create_return_value_constraint(intptr_t value_to_return); Constraint *create_return_by_value_constraint(intptr_t value_to_return, size_t size); Constraint *create_return_double_value_constraint(double value_to_return); Constraint *create_set_parameter_value_constraint(const char *parameter_name, intptr_t value_to_set, size_t size_to_set); Constraint *create_with_side_effect_constraint(void (*callback)(void *), void *data); Constraint *create_capture_parameter_constraint(const char *parameter_name, void *captured, size_t size_to_capture); #ifdef __cplusplus } } #endif #endif cgreen-1.6.3/include/cgreen/constraint_syntax_helpers.h000066400000000000000000000063151450461175400233530ustar00rootroot00000000000000#ifndef CONSTRAINT_SYNTAX_HELPERS_HEADER #define CONSTRAINT_SYNTAX_HELPERS_HEADER #include #ifdef __cplusplus #include #endif #include /* we normally want to favor delegating functions (for namespacing, * and to avoid confusing symbol/preprocessor conflicts), but for the * intptr_t catch-all type, we need an explicit cast lest we get * warnings-as-errors in newer compilers. also, we need the textual * representation of the expected value and this is the only * reasonable way to do it. */ #define is_equal_to(value) create_equal_to_value_constraint((intptr_t)value, #value) #define is_equal_to_hex(value) create_equal_to_hexvalue_constraint((intptr_t)value, #value) #define is_not_equal_to(value) create_not_equal_to_value_constraint((intptr_t)value, #value) #define is_non_null is_not_null #define is_not_null create_not_null_constraint() #define is_null create_is_null_constraint() #define is_false create_is_false_constraint() #define is_true create_is_true_constraint() #define is_greater_than(value) create_greater_than_value_constraint((intptr_t)value, #value) #define is_less_than(value) create_less_than_value_constraint((intptr_t)value, #value) #define is_equal_to_contents_of(pointer, size_of_contents) create_equal_to_contents_constraint((void *)pointer, size_of_contents, #pointer) #define is_not_equal_to_contents_of(pointer, size_of_contents) create_not_equal_to_contents_constraint((void *)pointer, size_of_contents, #pointer) #define is_equal_to_string(value) create_equal_to_string_constraint(value, #value) #define is_not_equal_to_string(value) create_not_equal_to_string_constraint(value, #value) #define contains_string(value) create_contains_string_constraint(value, #value) #define does_not_contain_string(value) create_does_not_contain_string_constraint(value, #value) #define begins_with_string(value) create_begins_with_string_constraint(value, #value) #define does_not_begin_with_string(value) create_does_not_begin_with_string_constraint(value, #value) #define ends_with_string(value) create_ends_with_string_constraint(value, #value) #define does_not_end_with_string(value) create_does_not_end_with_string_constraint(value, #value) #define is_equal_to_double(value) create_equal_to_double_constraint(value, #value) #define is_not_equal_to_double(value) create_not_equal_to_double_constraint(value, #value) #define is_less_than_double(value) create_less_than_double_constraint(value, #value) #define is_greater_than_double(value) create_greater_than_double_constraint(value, #value) #define with_side_effect(callback, data) create_with_side_effect_constraint(callback, data) #define will_return(value) create_return_value_constraint((intptr_t)value) #define will_return_by_value(value, size) create_return_by_value_constraint((intptr_t)&value, size) #define will_return_double(value) create_return_double_value_constraint(value) #define will_set_contents_of_parameter(parameter_name, pointer_to_value, size) create_set_parameter_value_constraint(#parameter_name, (intptr_t)pointer_to_value, (size_t)size) #define will_capture_parameter(parameter_name, local_variable) create_capture_parameter_constraint(#parameter_name, &local_variable, sizeof(local_variable)) #endif cgreen-1.6.3/include/cgreen/cpp_assertions.h000066400000000000000000000014201450461175400210630ustar00rootroot00000000000000#ifndef CGREEN_CPP_ASSERTIONS_H #define CGREEN_CPP_ASSERTIONS_H #include "internal/stringify_token.h" #define assert_throws(exceptionType, expr) \ try { \ expr; \ fail_test("Expected [" STRINGIFY_TOKEN(expr) "] " \ "to throw [" STRINGIFY_TOKEN(exceptionType) "]"); \ } catch (const exceptionType& ex) { \ pass_test(); \ } catch (const exceptionType* ex) { \ pass_test(); \ } #endif cgreen-1.6.3/include/cgreen/cpp_constraint.h000066400000000000000000000056111450461175400210630ustar00rootroot00000000000000#ifndef CGREEN_CPP_CONSTRAINT #define CGREEN_CPP_CONSTRAINT #include #include namespace cgreen { template class CppConstraint : public Constraint { public: T expected_real_value; bool (*compare)(CppConstraint *, T); }; Constraint *create_equal_to_string_constraint(const std::string& expected_value, const char *expected_value_name); Constraint *create_equal_to_string_constraint(const std::string* expected_value, const char *expected_value_name); Constraint *create_not_equal_to_string_constraint(const std::string& expected_value, const char *expected_value_name); Constraint *create_not_equal_to_string_constraint(const std::string* expected_value, const char *expected_value_name); Constraint *create_contains_string_constraint(const std::string& expected_value, const char *expected_value_name); Constraint *create_contains_string_constraint(const std::string* expected_value, const char *expected_value_name); Constraint *create_does_not_contain_string_constraint(const std::string& expected_value, const char *expected_value_name); Constraint *create_does_not_contain_string_constraint(const std::string* expected_value, const char *expected_value_name); Constraint *create_begins_with_string_constraint(const std::string& expected_value, const char *expected_value_name); Constraint *create_begins_with_string_constraint(const std::string* expected_value, const char *expected_value_name); template bool compare_want_value(CppConstraint *constraint, T actual) { return constraint->expected_real_value == actual; } template bool compare_do_not_want_value(CppConstraint *constraint, T actual) { return !compare_want_value(constraint, actual); } template void test_want_value(CppConstraint *constraint, const char *function, T actual, const char *test_file, int test_line, TestReporter *reporter) { (void)constraint; (void)function; (void)actual; (void)test_file; (void)test_line; (void)reporter; } #include // TODO: add create_equal_to_constraint_ where operator<< output is used for expected_value name template CppConstraint *create_equal_to_value_constraint(CgreenValue cgreen_value, T expected_value, const char *expected_value_name) { CppConstraint *constraint;// = create_cpp_constraint(); constraint = new CppConstraint(); constraint->type = CGREEN_VALUE_COMPARER_CONSTRAINT; (void)cgreen_value; /* Avoid warnings for UNUSED, which it is for now */ constraint->Constraint::compare = &compare_want_value; constraint->execute = &test_want; constraint->name = "equal"; constraint->expected_value = expected_value; constraint->expected_value_name = expected_value_name; constraint->size_of_expected_value = sizeof(intptr_t); constraint->expected_real_value = expected_value; return constraint; } } #endif cgreen-1.6.3/include/cgreen/cute_reporter.h000066400000000000000000000003271450461175400207160ustar00rootroot00000000000000#ifndef CUTE_REPORTER_HEADER #define CUTE_REPORTER_HEADER #include #ifdef __cplusplus extern "C" { #endif extern TestReporter *create_cute_reporter(void); #ifdef __cplusplus } #endif #endif cgreen-1.6.3/include/cgreen/filename.h000066400000000000000000000003161450461175400176120ustar00rootroot00000000000000#ifndef FILENAME_HEADER #define FILENAME_HEADER #ifdef __cplusplus namespace cgreen { extern "C" { #endif #ifndef FILENAME #define FILENAME __FILE__ #endif #ifdef __cplusplus } } #endif #endif cgreen-1.6.3/include/cgreen/internal/000077500000000000000000000000001450461175400174755ustar00rootroot00000000000000cgreen-1.6.3/include/cgreen/internal/CMakeLists.txt000066400000000000000000000006221450461175400222350ustar00rootroot00000000000000set(cgreen_internal_HDRS unit_implementation.h mock_table.h mocks_internal.h suite_internal.h assertions_internal.h c_assertions.h cpp_assertions.h cgreen_pipe.h cgreen_time.h runner_platform.h function_macro.h stringify_token.h ) install( FILES ${cgreen_internal_HDRS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${APPLICATION_NAME}/internal COMPONENT headers ) cgreen-1.6.3/include/cgreen/internal/android_headers/000077500000000000000000000000001450461175400226105ustar00rootroot00000000000000cgreen-1.6.3/include/cgreen/internal/android_headers/androidcompat.h000066400000000000000000000026041450461175400256070ustar00rootroot00000000000000/** * Convert *printf family for display via Android Studio/Eclipse logcat * * Usage * Simply include in cgreen .c/.cpp files containing *printf statements e.g. * ------------------------------------------------------------ * #ifdef __ANDROID__ * #include "cgreen/internal/android_headers/androidcompat.h" * #endif // #ifdef __ANDROID__ * ------------------------------------------------------------ * * Created 9 Aug 2016, Steve Madsen, London UK */ #pragma once #ifdef __ANDROID__ #include #define ANDROID_MODULE_LOG_TAG "CGreenUnitTests" #define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, ANDROID_MODULE_LOG_TAG, __VA_ARGS__) #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, ANDROID_MODULE_LOG_TAG, __VA_ARGS__) #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, ANDROID_MODULE_LOG_TAG, __VA_ARGS__) #define LOGW(...) __android_log_print(ANDROID_LOG_WARN, ANDROID_MODULE_LOG_TAG, __VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, ANDROID_MODULE_LOG_TAG, __VA_ARGS__) #define LOGF(...) __android_log_print(ANDROID_LOG_FATAL, ANDROID_MODULE_LOG_TAG, __VA_ARGS__) // Note: "##" ensures preceding comma will be deleted if "..." empty #define printf(fmt, ...) LOGE(fmt, ##__VA_ARGS__) #define fprintf(stderr, ...) LOGE(__VA_ARGS__) #define vprintf(fmt, ...) LOGE(fmt, ##__VA_ARGS__) #endif // #ifdef __ANDROID__ cgreen-1.6.3/include/cgreen/internal/assertions_internal.h000066400000000000000000000045731450461175400237450ustar00rootroot00000000000000#ifndef ASSERTIONS_INTERNAL_HEADER #define ASSERTIONS_INTERNAL_HEADER #include #include #ifdef __cplusplus #include "cpp_assertions.h" #endif #include "c_assertions.h" #include "stringify_token.h" #ifdef __cplusplus namespace cgreen { extern "C" { #endif //At the cost of duplication, these macros now give more descriptive error messages #define ASSERT_THAT_VA_NUM_ARGS(...) ASSERT_THAT_VA_NUM_ARGS_IMPL_((__VA_ARGS__, _CALLED_WITH_TOO_MANY_ARGS, _constraint, _expression, DummyToFillVaArgs)) #define ASSERT_THAT_VA_NUM_ARGS_IMPL_(tuple) ASSERT_THAT_VA_NUM_ARGS_IMPL tuple #define ASSERT_THAT_VA_NUM_ARGS_IMPL(_1, _2, _3, N, ...) N #define ASSERT_THAT_macro_dispatcher(func, ...) ASSERT_THAT_macro_dispatcher_(func, ASSERT_THAT_VA_NUM_ARGS(__VA_ARGS__)) #define ASSERT_THAT_macro_dispatcher_(func, nargs) ASSERT_THAT_macro_dispatcher__(func, nargs) #define ASSERT_THAT_macro_dispatcher__(func, nargs) ASSERT_THAT_macro_dispatcher___(func, nargs) #define ASSERT_THAT_macro_dispatcher___(func, nargs) func ## nargs #ifdef __GNUC__ #define DEPRECATED __attribute__((deprecated)) #elif defined(_MSC_VER) #define DEPRECATED __declspec(deprecated) #else #pragma message("WARNING: You need to implement DEPRECATED for this compiler") #define DEPRECATED #endif #define assert_that_NARG(...) ASSERT_THAT_macro_dispatcher(assert_that, __VA_ARGS__) #define assert_that_expression(expression) \ assert_core_(FILENAME, __LINE__, STRINGIFY_TOKEN(expression), (expression), is_true); void assert_equal_(const char *file, int line, const char *expression, intptr_t tried, intptr_t expected); void assert_not_equal_(const char *file, int line, const char *expression, intptr_t tried, intptr_t expected); void assert_double_equal_(const char *file, int line, const char *expression, double tried, double expected); void assert_double_not_equal_(const char *file, int line, const char *expression, double tried, double expected); void assert_string_equal_(const char *file, int line, const char *expression, const char *tried, const char *expected); void assert_string_not_equal_(const char *file, int line, const char *expression, const char *tried, const char *expected); void assert_that_double_(const char *file, int line, const char *actual_string, double actual, Constraint *constraint); #ifdef __cplusplus } } #endif #endif cgreen-1.6.3/include/cgreen/internal/c_assertions.h000066400000000000000000000012121450461175400223360ustar00rootroot00000000000000#ifndef C_ASSERTIONS_HEADER #define C_ASSERTIONS_HEADER #include #include #include #include "stringify_token.h" #ifndef __cplusplus #define assert_that_constraint(actual, constraint) assert_core_(FILENAME, __LINE__, STRINGIFY_TOKEN(actual), (intptr_t)(actual), (constraint)) #endif #ifdef __cplusplus extern "C" { #endif void assert_core_(const char *file, int line, const char *actual_string, intptr_t actual, Constraint *constraint); void assert_that_double_(const char *file, int line, const char *expression, double actual, Constraint* constraint); #ifdef __cplusplus } #endif #endif cgreen-1.6.3/include/cgreen/internal/cgreen_pipe.h000066400000000000000000000005671450461175400221360ustar00rootroot00000000000000#ifndef CGREEN_PIPE_HEADER #define CGREEN_PIPE_HEADER #include #ifdef __cplusplus namespace cgreen { extern "C" { #endif int cgreen_pipe_open(int pipes[2]); void cgreen_pipe_close(int p); ssize_t cgreen_pipe_read(int p, void *buf, size_t count); ssize_t cgreen_pipe_write(int p, const void *buf, size_t count); #ifdef __cplusplus } } #endif #endif cgreen-1.6.3/include/cgreen/internal/cgreen_time.h000066400000000000000000000005421450461175400221300ustar00rootroot00000000000000#ifndef CGREEN_TIME_HEADER #define CGREEN_TIME_HEADER #include #ifdef __cplusplus namespace cgreen { extern "C" { #endif uint32_t cgreen_time_get_current_milliseconds(void); uint32_t cgreen_time_duration_in_milliseconds(uint32_t start_time_in_milliseconds, uint32_t end_time_in_milliseconds); #ifdef __cplusplus } } #endif #endif cgreen-1.6.3/include/cgreen/internal/cpp_assertions.h000066400000000000000000000034631450461175400227100ustar00rootroot00000000000000#ifndef INTERNAL_CPP_ASSERTIONS_HEADER #define INTERNAL_CPP_ASSERTIONS_HEADER #include #include #include #include #include #include "stringify_token.h" namespace cgreen { #define assert_that_constraint(actual, constraint) assert_that_(FILENAME, __LINE__, STRINGIFY_TOKEN(actual), actual, constraint) void assert_that_(const char *file, int line, const char *actual_string, const std::string& actual, Constraint *constraint); void assert_that_(const char *file, int line, const char *actual_string, const std::string *actual, Constraint *constraint); void assert_that_(const char *file, int line, const char *actual_string, double actual, Constraint *constraint); // this isn't declared in assertions.h because you can't have overloads for an extern "C"-declared function, so it seems void assert_that_(const char *file, int line, const char *actual_string, intptr_t actual, Constraint *constraint); template void assert_that_(const char *file, int line, const char *actual_string, T actual, Constraint *constraint) { if (typeid(actual) == typeid(std::string&) || typeid(actual) == typeid(const std::string&) || typeid(actual) == typeid(const std::string*) || typeid(actual) == typeid(std::string*)) { assert_that_(file, line, actual_string, reinterpret_cast(actual), constraint); } else if (typeid(actual) == typeid(std::string)) { assert_that_(file, line, actual_string, (const std::string *)&actual, constraint); } else { // TODO: update actual_string with output from operator<< of (T)actual assert_that_(file, line, actual_string, (intptr_t)actual, constraint); } } } #endif cgreen-1.6.3/include/cgreen/internal/function_macro.h000066400000000000000000000003221450461175400226510ustar00rootroot00000000000000// include this header when using the __func__ macro // this is where platforms that don't have C99 __func__ will be handled #ifndef __func__ # ifdef _MSC_VER # define __func__ __FUNCTION__ # endif #endif cgreen-1.6.3/include/cgreen/internal/mock_table.h000066400000000000000000001707701450461175400217620ustar00rootroot00000000000000 #ifndef MOCK_TABLE_HEADER #define MOCK_TABLE_HEADER /* DO NOT EDIT THIS FILE */ /* auto-generated by build_mock_table.pl */ #define MOCK_VA_NUM_ARGS(...) MOCK_VA_NUM_ARGS_IMPL_((__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)) #define MOCK_VA_NUM_ARGS_IMPL_(tuple) MOCK_VA_NUM_ARGS_IMPL tuple #define MOCK_VA_NUM_ARGS_IMPL( \ _1, _2, _3, _4, _5, _6, _7, _8, _9,_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,N,...) N #define MOCK_macro_dispatcher(func, ...) MOCK_macro_dispatcher_(func, MOCK_VA_NUM_ARGS(__VA_ARGS__)) // the three levels of indirection are a work-around for broken variadic macro support in Visual C++ #define MOCK_macro_dispatcher_(func, nargs) MOCK_macro_dispatcher__(func, nargs) #define MOCK_macro_dispatcher__(func, nargs) MOCK_macro_dispatcher___(func, nargs) #define MOCK_macro_dispatcher___(func, nargs) func ## nargs #define PP_NARG(...) MOCK_macro_dispatcher(mock, __VA_ARGS__) //mock1 works for 1 or 0 #define mock1(test_reporter, function_name, mock_file, mock_line, arguments_string, ...)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t)__VA_ARGS__) #define PP_RSEQ_N() \ mock63, mock62, mock61, mock60, mock59, mock58, mock57, mock56, mock55, mock54,\ mock53, mock52, mock51, mock50, mock49, mock48, mock47, mock46, mock45, mock44,\ mock43, mock42, mock41, mock40, mock39, mock38, mock37, mock36, mock35, mock34,\ mock33, mock32, mock31, mock30, mock29, mock28, mock27, mock26, mock25, mock24,\ mock23, mock22, mock21, mock20, mock19, mock18, mock17, mock16, mock15, mock14,\ mock13, mock12, mock11, mock10, mock9, mock8, mock7, mock6, mock5, mock4,\ mock3, mock2, mock_, mock_ #define mock2(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1) #define mock3(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2) #define mock4(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3) #define mock5(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4) #define mock6(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5) #define mock7(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6) #define mock8(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7) #define mock9(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8) #define mock10(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9) #define mock11(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10) #define mock12(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11) #define mock13(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12) #define mock14(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13) #define mock15(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14) #define mock16(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15) #define mock17(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16) #define mock18(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17) #define mock19(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18) #define mock20(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19) #define mock21(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20) #define mock22(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21) #define mock23(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22) #define mock24(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23) #define mock25(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24) #define mock26(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25) #define mock27(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26) #define mock28(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27) #define mock29(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28) #define mock30(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28, (intptr_t) arg29) #define mock31(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28, (intptr_t) arg29, (intptr_t) arg30) #define mock32(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28, (intptr_t) arg29, (intptr_t) arg30, (intptr_t) arg31) #define mock33(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28, (intptr_t) arg29, (intptr_t) arg30, (intptr_t) arg31, (intptr_t) arg32) #define mock34(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28, (intptr_t) arg29, (intptr_t) arg30, (intptr_t) arg31, (intptr_t) arg32, (intptr_t) arg33) #define mock35(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28, (intptr_t) arg29, (intptr_t) arg30, (intptr_t) arg31, (intptr_t) arg32, (intptr_t) arg33, (intptr_t) arg34) #define mock36(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28, (intptr_t) arg29, (intptr_t) arg30, (intptr_t) arg31, (intptr_t) arg32, (intptr_t) arg33, (intptr_t) arg34, (intptr_t) arg35) #define mock37(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28, (intptr_t) arg29, (intptr_t) arg30, (intptr_t) arg31, (intptr_t) arg32, (intptr_t) arg33, (intptr_t) arg34, (intptr_t) arg35, (intptr_t) arg36) #define mock38(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28, (intptr_t) arg29, (intptr_t) arg30, (intptr_t) arg31, (intptr_t) arg32, (intptr_t) arg33, (intptr_t) arg34, (intptr_t) arg35, (intptr_t) arg36, (intptr_t) arg37) #define mock39(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28, (intptr_t) arg29, (intptr_t) arg30, (intptr_t) arg31, (intptr_t) arg32, (intptr_t) arg33, (intptr_t) arg34, (intptr_t) arg35, (intptr_t) arg36, (intptr_t) arg37, (intptr_t) arg38) #define mock40(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28, (intptr_t) arg29, (intptr_t) arg30, (intptr_t) arg31, (intptr_t) arg32, (intptr_t) arg33, (intptr_t) arg34, (intptr_t) arg35, (intptr_t) arg36, (intptr_t) arg37, (intptr_t) arg38, (intptr_t) arg39) #define mock41(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28, (intptr_t) arg29, (intptr_t) arg30, (intptr_t) arg31, (intptr_t) arg32, (intptr_t) arg33, (intptr_t) arg34, (intptr_t) arg35, (intptr_t) arg36, (intptr_t) arg37, (intptr_t) arg38, (intptr_t) arg39, (intptr_t) arg40) #define mock42(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28, (intptr_t) arg29, (intptr_t) arg30, (intptr_t) arg31, (intptr_t) arg32, (intptr_t) arg33, (intptr_t) arg34, (intptr_t) arg35, (intptr_t) arg36, (intptr_t) arg37, (intptr_t) arg38, (intptr_t) arg39, (intptr_t) arg40, (intptr_t) arg41) #define mock43(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28, (intptr_t) arg29, (intptr_t) arg30, (intptr_t) arg31, (intptr_t) arg32, (intptr_t) arg33, (intptr_t) arg34, (intptr_t) arg35, (intptr_t) arg36, (intptr_t) arg37, (intptr_t) arg38, (intptr_t) arg39, (intptr_t) arg40, (intptr_t) arg41, (intptr_t) arg42) #define mock44(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28, (intptr_t) arg29, (intptr_t) arg30, (intptr_t) arg31, (intptr_t) arg32, (intptr_t) arg33, (intptr_t) arg34, (intptr_t) arg35, (intptr_t) arg36, (intptr_t) arg37, (intptr_t) arg38, (intptr_t) arg39, (intptr_t) arg40, (intptr_t) arg41, (intptr_t) arg42, (intptr_t) arg43) #define mock45(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28, (intptr_t) arg29, (intptr_t) arg30, (intptr_t) arg31, (intptr_t) arg32, (intptr_t) arg33, (intptr_t) arg34, (intptr_t) arg35, (intptr_t) arg36, (intptr_t) arg37, (intptr_t) arg38, (intptr_t) arg39, (intptr_t) arg40, (intptr_t) arg41, (intptr_t) arg42, (intptr_t) arg43, (intptr_t) arg44) #define mock46(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28, (intptr_t) arg29, (intptr_t) arg30, (intptr_t) arg31, (intptr_t) arg32, (intptr_t) arg33, (intptr_t) arg34, (intptr_t) arg35, (intptr_t) arg36, (intptr_t) arg37, (intptr_t) arg38, (intptr_t) arg39, (intptr_t) arg40, (intptr_t) arg41, (intptr_t) arg42, (intptr_t) arg43, (intptr_t) arg44, (intptr_t) arg45) #define mock47(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28, (intptr_t) arg29, (intptr_t) arg30, (intptr_t) arg31, (intptr_t) arg32, (intptr_t) arg33, (intptr_t) arg34, (intptr_t) arg35, (intptr_t) arg36, (intptr_t) arg37, (intptr_t) arg38, (intptr_t) arg39, (intptr_t) arg40, (intptr_t) arg41, (intptr_t) arg42, (intptr_t) arg43, (intptr_t) arg44, (intptr_t) arg45, (intptr_t) arg46) #define mock48(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28, (intptr_t) arg29, (intptr_t) arg30, (intptr_t) arg31, (intptr_t) arg32, (intptr_t) arg33, (intptr_t) arg34, (intptr_t) arg35, (intptr_t) arg36, (intptr_t) arg37, (intptr_t) arg38, (intptr_t) arg39, (intptr_t) arg40, (intptr_t) arg41, (intptr_t) arg42, (intptr_t) arg43, (intptr_t) arg44, (intptr_t) arg45, (intptr_t) arg46, (intptr_t) arg47) #define mock49(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28, (intptr_t) arg29, (intptr_t) arg30, (intptr_t) arg31, (intptr_t) arg32, (intptr_t) arg33, (intptr_t) arg34, (intptr_t) arg35, (intptr_t) arg36, (intptr_t) arg37, (intptr_t) arg38, (intptr_t) arg39, (intptr_t) arg40, (intptr_t) arg41, (intptr_t) arg42, (intptr_t) arg43, (intptr_t) arg44, (intptr_t) arg45, (intptr_t) arg46, (intptr_t) arg47, (intptr_t) arg48) #define mock50(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28, (intptr_t) arg29, (intptr_t) arg30, (intptr_t) arg31, (intptr_t) arg32, (intptr_t) arg33, (intptr_t) arg34, (intptr_t) arg35, (intptr_t) arg36, (intptr_t) arg37, (intptr_t) arg38, (intptr_t) arg39, (intptr_t) arg40, (intptr_t) arg41, (intptr_t) arg42, (intptr_t) arg43, (intptr_t) arg44, (intptr_t) arg45, (intptr_t) arg46, (intptr_t) arg47, (intptr_t) arg48, (intptr_t) arg49) #define mock51(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28, (intptr_t) arg29, (intptr_t) arg30, (intptr_t) arg31, (intptr_t) arg32, (intptr_t) arg33, (intptr_t) arg34, (intptr_t) arg35, (intptr_t) arg36, (intptr_t) arg37, (intptr_t) arg38, (intptr_t) arg39, (intptr_t) arg40, (intptr_t) arg41, (intptr_t) arg42, (intptr_t) arg43, (intptr_t) arg44, (intptr_t) arg45, (intptr_t) arg46, (intptr_t) arg47, (intptr_t) arg48, (intptr_t) arg49, (intptr_t) arg50) #define mock52(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28, (intptr_t) arg29, (intptr_t) arg30, (intptr_t) arg31, (intptr_t) arg32, (intptr_t) arg33, (intptr_t) arg34, (intptr_t) arg35, (intptr_t) arg36, (intptr_t) arg37, (intptr_t) arg38, (intptr_t) arg39, (intptr_t) arg40, (intptr_t) arg41, (intptr_t) arg42, (intptr_t) arg43, (intptr_t) arg44, (intptr_t) arg45, (intptr_t) arg46, (intptr_t) arg47, (intptr_t) arg48, (intptr_t) arg49, (intptr_t) arg50, (intptr_t) arg51) #define mock53(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28, (intptr_t) arg29, (intptr_t) arg30, (intptr_t) arg31, (intptr_t) arg32, (intptr_t) arg33, (intptr_t) arg34, (intptr_t) arg35, (intptr_t) arg36, (intptr_t) arg37, (intptr_t) arg38, (intptr_t) arg39, (intptr_t) arg40, (intptr_t) arg41, (intptr_t) arg42, (intptr_t) arg43, (intptr_t) arg44, (intptr_t) arg45, (intptr_t) arg46, (intptr_t) arg47, (intptr_t) arg48, (intptr_t) arg49, (intptr_t) arg50, (intptr_t) arg51, (intptr_t) arg52) #define mock54(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28, (intptr_t) arg29, (intptr_t) arg30, (intptr_t) arg31, (intptr_t) arg32, (intptr_t) arg33, (intptr_t) arg34, (intptr_t) arg35, (intptr_t) arg36, (intptr_t) arg37, (intptr_t) arg38, (intptr_t) arg39, (intptr_t) arg40, (intptr_t) arg41, (intptr_t) arg42, (intptr_t) arg43, (intptr_t) arg44, (intptr_t) arg45, (intptr_t) arg46, (intptr_t) arg47, (intptr_t) arg48, (intptr_t) arg49, (intptr_t) arg50, (intptr_t) arg51, (intptr_t) arg52, (intptr_t) arg53) #define mock55(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28, (intptr_t) arg29, (intptr_t) arg30, (intptr_t) arg31, (intptr_t) arg32, (intptr_t) arg33, (intptr_t) arg34, (intptr_t) arg35, (intptr_t) arg36, (intptr_t) arg37, (intptr_t) arg38, (intptr_t) arg39, (intptr_t) arg40, (intptr_t) arg41, (intptr_t) arg42, (intptr_t) arg43, (intptr_t) arg44, (intptr_t) arg45, (intptr_t) arg46, (intptr_t) arg47, (intptr_t) arg48, (intptr_t) arg49, (intptr_t) arg50, (intptr_t) arg51, (intptr_t) arg52, (intptr_t) arg53, (intptr_t) arg54) #define mock56(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28, (intptr_t) arg29, (intptr_t) arg30, (intptr_t) arg31, (intptr_t) arg32, (intptr_t) arg33, (intptr_t) arg34, (intptr_t) arg35, (intptr_t) arg36, (intptr_t) arg37, (intptr_t) arg38, (intptr_t) arg39, (intptr_t) arg40, (intptr_t) arg41, (intptr_t) arg42, (intptr_t) arg43, (intptr_t) arg44, (intptr_t) arg45, (intptr_t) arg46, (intptr_t) arg47, (intptr_t) arg48, (intptr_t) arg49, (intptr_t) arg50, (intptr_t) arg51, (intptr_t) arg52, (intptr_t) arg53, (intptr_t) arg54, (intptr_t) arg55) #define mock57(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28, (intptr_t) arg29, (intptr_t) arg30, (intptr_t) arg31, (intptr_t) arg32, (intptr_t) arg33, (intptr_t) arg34, (intptr_t) arg35, (intptr_t) arg36, (intptr_t) arg37, (intptr_t) arg38, (intptr_t) arg39, (intptr_t) arg40, (intptr_t) arg41, (intptr_t) arg42, (intptr_t) arg43, (intptr_t) arg44, (intptr_t) arg45, (intptr_t) arg46, (intptr_t) arg47, (intptr_t) arg48, (intptr_t) arg49, (intptr_t) arg50, (intptr_t) arg51, (intptr_t) arg52, (intptr_t) arg53, (intptr_t) arg54, (intptr_t) arg55, (intptr_t) arg56) #define mock58(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28, (intptr_t) arg29, (intptr_t) arg30, (intptr_t) arg31, (intptr_t) arg32, (intptr_t) arg33, (intptr_t) arg34, (intptr_t) arg35, (intptr_t) arg36, (intptr_t) arg37, (intptr_t) arg38, (intptr_t) arg39, (intptr_t) arg40, (intptr_t) arg41, (intptr_t) arg42, (intptr_t) arg43, (intptr_t) arg44, (intptr_t) arg45, (intptr_t) arg46, (intptr_t) arg47, (intptr_t) arg48, (intptr_t) arg49, (intptr_t) arg50, (intptr_t) arg51, (intptr_t) arg52, (intptr_t) arg53, (intptr_t) arg54, (intptr_t) arg55, (intptr_t) arg56, (intptr_t) arg57) #define mock59(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57, arg58)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28, (intptr_t) arg29, (intptr_t) arg30, (intptr_t) arg31, (intptr_t) arg32, (intptr_t) arg33, (intptr_t) arg34, (intptr_t) arg35, (intptr_t) arg36, (intptr_t) arg37, (intptr_t) arg38, (intptr_t) arg39, (intptr_t) arg40, (intptr_t) arg41, (intptr_t) arg42, (intptr_t) arg43, (intptr_t) arg44, (intptr_t) arg45, (intptr_t) arg46, (intptr_t) arg47, (intptr_t) arg48, (intptr_t) arg49, (intptr_t) arg50, (intptr_t) arg51, (intptr_t) arg52, (intptr_t) arg53, (intptr_t) arg54, (intptr_t) arg55, (intptr_t) arg56, (intptr_t) arg57, (intptr_t) arg58) #define mock60(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57, arg58, arg59)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28, (intptr_t) arg29, (intptr_t) arg30, (intptr_t) arg31, (intptr_t) arg32, (intptr_t) arg33, (intptr_t) arg34, (intptr_t) arg35, (intptr_t) arg36, (intptr_t) arg37, (intptr_t) arg38, (intptr_t) arg39, (intptr_t) arg40, (intptr_t) arg41, (intptr_t) arg42, (intptr_t) arg43, (intptr_t) arg44, (intptr_t) arg45, (intptr_t) arg46, (intptr_t) arg47, (intptr_t) arg48, (intptr_t) arg49, (intptr_t) arg50, (intptr_t) arg51, (intptr_t) arg52, (intptr_t) arg53, (intptr_t) arg54, (intptr_t) arg55, (intptr_t) arg56, (intptr_t) arg57, (intptr_t) arg58, (intptr_t) arg59) #define mock61(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57, arg58, arg59, arg60)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28, (intptr_t) arg29, (intptr_t) arg30, (intptr_t) arg31, (intptr_t) arg32, (intptr_t) arg33, (intptr_t) arg34, (intptr_t) arg35, (intptr_t) arg36, (intptr_t) arg37, (intptr_t) arg38, (intptr_t) arg39, (intptr_t) arg40, (intptr_t) arg41, (intptr_t) arg42, (intptr_t) arg43, (intptr_t) arg44, (intptr_t) arg45, (intptr_t) arg46, (intptr_t) arg47, (intptr_t) arg48, (intptr_t) arg49, (intptr_t) arg50, (intptr_t) arg51, (intptr_t) arg52, (intptr_t) arg53, (intptr_t) arg54, (intptr_t) arg55, (intptr_t) arg56, (intptr_t) arg57, (intptr_t) arg58, (intptr_t) arg59, (intptr_t) arg60) #define mock62(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57, arg58, arg59, arg60, arg61)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28, (intptr_t) arg29, (intptr_t) arg30, (intptr_t) arg31, (intptr_t) arg32, (intptr_t) arg33, (intptr_t) arg34, (intptr_t) arg35, (intptr_t) arg36, (intptr_t) arg37, (intptr_t) arg38, (intptr_t) arg39, (intptr_t) arg40, (intptr_t) arg41, (intptr_t) arg42, (intptr_t) arg43, (intptr_t) arg44, (intptr_t) arg45, (intptr_t) arg46, (intptr_t) arg47, (intptr_t) arg48, (intptr_t) arg49, (intptr_t) arg50, (intptr_t) arg51, (intptr_t) arg52, (intptr_t) arg53, (intptr_t) arg54, (intptr_t) arg55, (intptr_t) arg56, (intptr_t) arg57, (intptr_t) arg58, (intptr_t) arg59, (intptr_t) arg60, (intptr_t) arg61) #define mock63(test_reporter, function_name, mock_file, mock_line, arguments_string, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57, arg58, arg59, arg60, arg61, arg62)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, (intptr_t) arg0, (intptr_t) arg1, (intptr_t) arg2, (intptr_t) arg3, (intptr_t) arg4, (intptr_t) arg5, (intptr_t) arg6, (intptr_t) arg7, (intptr_t) arg8, (intptr_t) arg9, (intptr_t) arg10, (intptr_t) arg11, (intptr_t) arg12, (intptr_t) arg13, (intptr_t) arg14, (intptr_t) arg15, (intptr_t) arg16, (intptr_t) arg17, (intptr_t) arg18, (intptr_t) arg19, (intptr_t) arg20, (intptr_t) arg21, (intptr_t) arg22, (intptr_t) arg23, (intptr_t) arg24, (intptr_t) arg25, (intptr_t) arg26, (intptr_t) arg27, (intptr_t) arg28, (intptr_t) arg29, (intptr_t) arg30, (intptr_t) arg31, (intptr_t) arg32, (intptr_t) arg33, (intptr_t) arg34, (intptr_t) arg35, (intptr_t) arg36, (intptr_t) arg37, (intptr_t) arg38, (intptr_t) arg39, (intptr_t) arg40, (intptr_t) arg41, (intptr_t) arg42, (intptr_t) arg43, (intptr_t) arg44, (intptr_t) arg45, (intptr_t) arg46, (intptr_t) arg47, (intptr_t) arg48, (intptr_t) arg49, (intptr_t) arg50, (intptr_t) arg51, (intptr_t) arg52, (intptr_t) arg53, (intptr_t) arg54, (intptr_t) arg55, (intptr_t) arg56, (intptr_t) arg57, (intptr_t) arg58, (intptr_t) arg59, (intptr_t) arg60, (intptr_t) arg61, (intptr_t) arg62) #endif /* MOCK_TABLE_HEADER */ cgreen-1.6.3/include/cgreen/internal/mocks_internal.h000066400000000000000000000032271450461175400226620ustar00rootroot00000000000000#ifndef MOCKS_INTERNAL_H #define MOCKS_INTERNAL_H #include #include #include #include #include #include #ifdef __GNUC__ #define WARN_UNUSED_RESULT __attribute__((warn_unused_result)) #else #define WARN_UNUSED_RESULT #endif #ifdef __cplusplus namespace cgreen { extern "C" { #endif extern void expect_(TestReporter *test_reporter, const char *function, const char *test_file, int test_line, ...); extern void always_expect_(TestReporter *test_reporter, const char *function, const char *test_file, int test_line, ...); extern void never_expect_(TestReporter *test_reporter, const char *function, const char *test_file, int test_line, ...); extern intptr_t mock_(TestReporter *test_reporter, const char *function, const char *mock_file, int mock_line, const char *parameters, ...); /* Warning for unused results from 'when()' helps detecting slip-ups in the expect(): expect(mocked_function, will_return(true)), when(param, is_equal_to(5)); Note the extra parenthesis at the end of the first line. Thanks to the comma operator, this effectively creates a mock expectation which silently ignores the constraints on its parameter(s), and passes the test case. /@awilke */ extern Constraint *when_(const char *parameter, Constraint *constraint) WARN_UNUSED_RESULT; extern Constraint *times_(int number_times_called); extern void clear_mocks(void); extern void tally_mocks(TestReporter *reporter); #ifdef __cplusplus } } #endif #endif cgreen-1.6.3/include/cgreen/internal/runner_platform.h000066400000000000000000000010041450461175400230560ustar00rootroot00000000000000#ifndef RUNNER_PLATFORM_HEADER #define RUNNER_PLATFORM_HEADER #include #include #ifdef __cplusplus namespace cgreen { extern "C" { #endif void run_specified_test_if_child(TestSuite *suite, TestReporter *reporter); void run_test_in_its_own_process(TestSuite *suite, CgreenTest *test, TestReporter *reporter); void die(const char *message, ...); void run_the_test_code(TestSuite *suite, CgreenTest *spec, TestReporter *reporter); #ifdef __cplusplus } } #endif #endif cgreen-1.6.3/include/cgreen/internal/stringify_token.h000066400000000000000000000001561450461175400230660ustar00rootroot00000000000000#ifndef STRINGIFY_TOKEN_HEADER #define STRINGIFY_TOKEN_HEADER #define STRINGIFY_TOKEN(token) #token #endif cgreen-1.6.3/include/cgreen/internal/suite_internal.h000066400000000000000000000015561450461175400227020ustar00rootroot00000000000000#ifndef SUITE_INTERNAL_HEADER #define SUITE_INTERNAL_HEADER #include "cgreen/unit.h" enum {test_function, test_suite}; typedef struct TestSuite_ TestSuite; typedef struct { int type; const char *name; union { CgreenTest *test; TestSuite *suite; } Runnable; } UnitTest; struct TestSuite_ { const char *name; const char* filename; int line; UnitTest *tests; void (*setup)(void); void (*teardown)(void); int size; }; #ifdef __cplusplus namespace cgreen { extern "C" { #endif void do_nothing(void); TestSuite *create_named_test_suite_(const char *name, const char *filename, int line); void add_test_(TestSuite *suite, const char *name, CgreenTest *test); void add_tests_(TestSuite *suite, const char *names, ...); void add_suite_(TestSuite *owner, const char *name, TestSuite *suite); #ifdef __cplusplus } } #endif #endif cgreen-1.6.3/include/cgreen/internal/unit_implementation.h000066400000000000000000000072161450461175400237400ustar00rootroot00000000000000#ifndef UNIT_IMPLEMENTATION_HEADER #define UNIT_IMPLEMENTATION_HEADER #include #ifdef __cplusplus #include #endif #include "stringify_token.h" typedef struct { const char* name; const char* filename; void (*setup)(void); void (*teardown)(void); } CgreenContext; typedef struct { int skip; /* Should test be skipped? */ CgreenContext* context; const char* name; void(*run)(void); const char* filename; int line; } CgreenTest; #define CGREEN_SPEC_PREFIX "CgreenSpec" #define CGREEN_SEPARATOR "__" #define spec_name(contextName, testName) CgreenSpec__##contextName##__##testName##__ //This gives better error messages at the cost of duplication #define ENSURE_VA_NUM_ARGS(...) ENSURE_VA_NUM_ARGS_IMPL_((__VA_ARGS__, _CALLED_WITH_TOO_MANY_ARGUMENTS, WithContextAndSpecificationName, WithSpecificationName, DummyToFillVaArgs)) #define ENSURE_VA_NUM_ARGS_IMPL_(tuple) ENSURE_VA_NUM_ARGS_IMPL tuple #define ENSURE_VA_NUM_ARGS_IMPL(_1, _2, _3, _4, N, ...) N #define ENSURE_macro_dispatcher(func, ...) ENSURE_macro_dispatcher_(func, ENSURE_VA_NUM_ARGS(__VA_ARGS__)) // these levels of indirecton are a work-around for variadic macro deficiencies in Visual C++ 2012 and prior #define ENSURE_macro_dispatcher_(func, nargs) ENSURE_macro_dispatcher__(func, nargs) #define ENSURE_macro_dispatcher__(func, nargs) ENSURE_macro_dispatcher___(func, nargs) #define ENSURE_macro_dispatcher___(func, nargs) func ## nargs #define Ensure_NARG(...) ENSURE_macro_dispatcher(Ensure, __VA_ARGS__) #define EnsureWithContextAndSpecificationName(skip, contextName, specName) \ static void contextName##__##specName (void);\ CgreenTest spec_name(contextName, specName) = { skip, &contextFor##contextName, STRINGIFY_TOKEN(specName), &contextName##__##specName, FILENAME, __LINE__ }; \ static void contextName##__##specName (void) extern CgreenContext defaultContext; #define EnsureWithSpecificationName(skip, specName) \ static void specName (void);\ CgreenTest spec_name(default, specName) = { skip, &defaultContext, STRINGIFY_TOKEN(specName), &specName, FILENAME, __LINE__ }; \ static void specName (void) #define DescribeImplementation(subject) \ static void setup(void); \ static void teardown(void); \ static CgreenContext contextFor##subject = { STRINGIFY_TOKEN(subject), FILENAME, &setup, &teardown }; \ extern void(*BeforeEach_For_##subject)(void); \ extern void(*AfterEach_For_##subject)(void); \ static void setup(void) { \ if (BeforeEach_For_##subject != NULL) BeforeEach_For_##subject(); \ } \ static void teardown(void) { \ if (AfterEach_For_##subject != NULL) AfterEach_For_##subject(); \ } \ typedef struct Dummy_ ## subject { int x; } Dummy_ ## subject ## _t #define BeforeEachImplementation(subject) \ void BeforeEach_For_##subject##_Function(void); \ void(*BeforeEach_For_##subject)(void) = &BeforeEach_For_##subject##_Function; \ void BeforeEach_For_##subject##_Function(void) #define AfterEachImplementation(subject) \ static void AfterEach_For_##subject##_Function(void); \ void(*AfterEach_For_##subject)(void) = &AfterEach_For_##subject##_Function; \ static void AfterEach_For_##subject##_Function(void) #endif cgreen-1.6.3/include/cgreen/internal/windows_headers/000077500000000000000000000000001450461175400226625ustar00rootroot00000000000000cgreen-1.6.3/include/cgreen/internal/windows_headers/inttypes.h000066400000000000000000000175151450461175400247230ustar00rootroot00000000000000// ISO C9x compliant inttypes.h for Microsoft Visual Studio // Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 // // Copyright (c) 2006 Alexander Chemeris // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // 3. The name of the author may be used to endorse or promote products // derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // /////////////////////////////////////////////////////////////////////////////// #ifndef _MSC_VER // [ #error "Use this header only with Microsoft Visual C++ compilers!" #else // _MSC_VER ] #ifndef _MSC_INTTYPES_H_ // [ #define _MSC_INTTYPES_H_ #if _MSC_VER > 1000 #pragma once #endif #include "stdint.h" // 7.8 Format conversion of integer types typedef struct { intmax_t quot; intmax_t rem; } imaxdiv_t; // 7.8.1 Macros for format specifiers #if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198 // The fprintf macros for signed integers are: #define PRId8 "d" #define PRIi8 "i" #define PRIdLEAST8 "d" #define PRIiLEAST8 "i" #define PRIdFAST8 "d" #define PRIiFAST8 "i" #define PRId16 "hd" #define PRIi16 "hi" #define PRIdLEAST16 "hd" #define PRIiLEAST16 "hi" #define PRIdFAST16 "hd" #define PRIiFAST16 "hi" #define PRId32 "I32d" #define PRIi32 "I32i" #define PRIdLEAST32 "I32d" #define PRIiLEAST32 "I32i" #define PRIdFAST32 "I32d" #define PRIiFAST32 "I32i" #define PRId64 "I64d" #define PRIi64 "I64i" #define PRIdLEAST64 "I64d" #define PRIiLEAST64 "I64i" #define PRIdFAST64 "I64d" #define PRIiFAST64 "I64i" #define PRIdMAX "I64d" #define PRIiMAX "I64i" #define PRIdPTR "Id" #define PRIiPTR "Ii" // The fprintf macros for unsigned integers are: #define PRIo8 "o" #define PRIu8 "u" #define PRIx8 "x" #define PRIX8 "X" #define PRIoLEAST8 "o" #define PRIuLEAST8 "u" #define PRIxLEAST8 "x" #define PRIXLEAST8 "X" #define PRIoFAST8 "o" #define PRIuFAST8 "u" #define PRIxFAST8 "x" #define PRIXFAST8 "X" #define PRIo16 "ho" #define PRIu16 "hu" #define PRIx16 "hx" #define PRIX16 "hX" #define PRIoLEAST16 "ho" #define PRIuLEAST16 "hu" #define PRIxLEAST16 "hx" #define PRIXLEAST16 "hX" #define PRIoFAST16 "ho" #define PRIuFAST16 "hu" #define PRIxFAST16 "hx" #define PRIXFAST16 "hX" #define PRIo32 "I32o" #define PRIu32 "I32u" #define PRIx32 "I32x" #define PRIX32 "I32X" #define PRIoLEAST32 "I32o" #define PRIuLEAST32 "I32u" #define PRIxLEAST32 "I32x" #define PRIXLEAST32 "I32X" #define PRIoFAST32 "I32o" #define PRIuFAST32 "I32u" #define PRIxFAST32 "I32x" #define PRIXFAST32 "I32X" #define PRIo64 "I64o" #define PRIu64 "I64u" #define PRIx64 "I64x" #define PRIX64 "I64X" #define PRIoLEAST64 "I64o" #define PRIuLEAST64 "I64u" #define PRIxLEAST64 "I64x" #define PRIXLEAST64 "I64X" #define PRIoFAST64 "I64o" #define PRIuFAST64 "I64u" #define PRIxFAST64 "I64x" #define PRIXFAST64 "I64X" #define PRIoMAX "I64o" #define PRIuMAX "I64u" #define PRIxMAX "I64x" #define PRIXMAX "I64X" #define PRIoPTR "Io" #define PRIuPTR "Iu" #define PRIxPTR "Ix" #define PRIXPTR "IX" // The fscanf macros for signed integers are: #define SCNd8 "d" #define SCNi8 "i" #define SCNdLEAST8 "d" #define SCNiLEAST8 "i" #define SCNdFAST8 "d" #define SCNiFAST8 "i" #define SCNd16 "hd" #define SCNi16 "hi" #define SCNdLEAST16 "hd" #define SCNiLEAST16 "hi" #define SCNdFAST16 "hd" #define SCNiFAST16 "hi" #define SCNd32 "ld" #define SCNi32 "li" #define SCNdLEAST32 "ld" #define SCNiLEAST32 "li" #define SCNdFAST32 "ld" #define SCNiFAST32 "li" #define SCNd64 "I64d" #define SCNi64 "I64i" #define SCNdLEAST64 "I64d" #define SCNiLEAST64 "I64i" #define SCNdFAST64 "I64d" #define SCNiFAST64 "I64i" #define SCNdMAX "I64d" #define SCNiMAX "I64i" #ifdef _WIN64 // [ # define SCNdPTR "I64d" # define SCNiPTR "I64i" #else // _WIN64 ][ # define SCNdPTR "ld" # define SCNiPTR "li" #endif // _WIN64 ] // The fscanf macros for unsigned integers are: #define SCNo8 "o" #define SCNu8 "u" #define SCNx8 "x" #define SCNX8 "X" #define SCNoLEAST8 "o" #define SCNuLEAST8 "u" #define SCNxLEAST8 "x" #define SCNXLEAST8 "X" #define SCNoFAST8 "o" #define SCNuFAST8 "u" #define SCNxFAST8 "x" #define SCNXFAST8 "X" #define SCNo16 "ho" #define SCNu16 "hu" #define SCNx16 "hx" #define SCNX16 "hX" #define SCNoLEAST16 "ho" #define SCNuLEAST16 "hu" #define SCNxLEAST16 "hx" #define SCNXLEAST16 "hX" #define SCNoFAST16 "ho" #define SCNuFAST16 "hu" #define SCNxFAST16 "hx" #define SCNXFAST16 "hX" #define SCNo32 "lo" #define SCNu32 "lu" #define SCNx32 "lx" #define SCNX32 "lX" #define SCNoLEAST32 "lo" #define SCNuLEAST32 "lu" #define SCNxLEAST32 "lx" #define SCNXLEAST32 "lX" #define SCNoFAST32 "lo" #define SCNuFAST32 "lu" #define SCNxFAST32 "lx" #define SCNXFAST32 "lX" #define SCNo64 "I64o" #define SCNu64 "I64u" #define SCNx64 "I64x" #define SCNX64 "I64X" #define SCNoLEAST64 "I64o" #define SCNuLEAST64 "I64u" #define SCNxLEAST64 "I64x" #define SCNXLEAST64 "I64X" #define SCNoFAST64 "I64o" #define SCNuFAST64 "I64u" #define SCNxFAST64 "I64x" #define SCNXFAST64 "I64X" #define SCNoMAX "I64o" #define SCNuMAX "I64u" #define SCNxMAX "I64x" #define SCNXMAX "I64X" #ifdef _WIN64 // [ # define SCNoPTR "I64o" # define SCNuPTR "I64u" # define SCNxPTR "I64x" # define SCNXPTR "I64X" #else // _WIN64 ][ # define SCNoPTR "lo" # define SCNuPTR "lu" # define SCNxPTR "lx" # define SCNXPTR "lX" #endif // _WIN64 ] #endif // __STDC_FORMAT_MACROS ] // 7.8.2 Functions for greatest-width integer types // 7.8.2.1 The imaxabs function #define imaxabs _abs64 // 7.8.2.2 The imaxdiv function // This is modified version of div() function from Microsoft's div.c found // in %MSVC.NET%\crt\src\div.c #ifdef STATIC_IMAXDIV // [ static #else // STATIC_IMAXDIV ][ _inline #endif // STATIC_IMAXDIV ] imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) { imaxdiv_t result; result.quot = numer / denom; result.rem = numer % denom; if (numer < 0 && result.rem > 0) { // did division wrong; must fix up ++result.quot; result.rem -= denom; } return result; } // 7.8.2.3 The strtoimax and strtoumax functions #define strtoimax _strtoi64 #define strtoumax _strtoui64 // 7.8.2.4 The wcstoimax and wcstoumax functions #define wcstoimax _wcstoi64 #define wcstoumax _wcstoui64 #endif // _MSC_VER #endif // _MSC_INTTYPES_H_ ] cgreen-1.6.3/include/cgreen/internal/windows_headers/stdbool.h000066400000000000000000000002521450461175400245000ustar00rootroot00000000000000#ifndef __STDBOOL_H__ #define __STDBOOL_H__ #ifndef __cplusplus typedef unsigned int bool; #define true 1 #define false 0 #endif //__cplusplus #endif //__STDBOOL_H__cgreen-1.6.3/include/cgreen/internal/windows_headers/unistd.h000066400000000000000000000024031450461175400243400ustar00rootroot00000000000000#ifndef _UNISTD_H #define _UNISTD_H 1 /* This file intended to serve as a drop-in replacement for * unistd.h on Windows * Please add functionality as neeeded */ #include #include //CMB - not needed for cgreen! //#include /* getopt from: http://www.pwilson.net/sample.html. */ #include /* for getpid() and the exec..() family */ #define srandom srand #define random rand /* Values for the second argument to access. These may be OR'd together. */ #define R_OK 4 /* Test for read permission. */ #define W_OK 2 /* Test for write permission. */ //#define X_OK 1 /* execute permission - unsupported in windows*/ #define F_OK 0 /* Test for existence. */ #define access _access #define ftruncate _chsize #define ssize_t int #define STDIN_FILENO 0 #define STDOUT_FILENO 1 #define STDERR_FILENO 2 /* should be in some equivalent to */ /* typedef __int8 int8_t; typedef __int16 int16_t; typedef __int32 int32_t; typedef __int64 int64_t; typedef unsigned __int8 uint8_t; typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; typedef unsigned __int64 uint64_t; */ #define pipe(x) _pipe(x,256,0) #endif /* unistd.h */cgreen-1.6.3/include/cgreen/internal/windows_headers/wincompat.h000066400000000000000000000011051450461175400250310ustar00rootroot00000000000000#ifndef __WINCOMPAT_H__ #define __WINCOMPAT_H__ #ifdef _MSC_VER #include "stdarg.h" #include "windows.h" #include "direct.h" #define gmtime_r(x,y) gmtime_s(y,x) typedef int pid_t; #if _MSC_VER < 1900 #define snprintf sprintf_s #endif #define sleep(x) Sleep(x*1000) #define mkdir(x,y) _mkdir(x) #define sched_yield() SleepEx (0,0) #define CGREEN_READ_HANDLE "CGREEN_READ_HANDLE" #define CGREEN_WRITE_HANDLE "CGREEN_WRITE_HANDLE" #define CGREEN_TEST_TO_RUN "CGREEN_TEST_TO_RUN" #ifdef __cplusplus #define PRIdPTR "Id" #endif #endif //_MSC_VER #endif //__WINCOMPAT_H__ cgreen-1.6.3/include/cgreen/legacy.h000066400000000000000000000134001450461175400172740ustar00rootroot00000000000000#ifndef LEGACY_HEADER #define LEGACY_HEADER #include #include "internal/stringify_token.h" #ifdef __cplusplus /* Legacy style asserts (for C++):*/ #define assert_true(result) \ (*cgreen::get_test_reporter()->assert_true)(cgreen::get_test_reporter(), FILENAME, __LINE__, (result), "[" STRINGIFY_TOKEN(result) "] should be true\n", NULL) #define assert_false(result) \ (*cgreen::get_test_reporter()->assert_true)(cgreen::get_test_reporter(), FILENAME, __LINE__, ! (result), "[" STRINGIFY_TOKEN(result) "] should be false\n", NULL) #define assert_equal(tried, expected) \ assert_equal_(FILENAME, __LINE__, STRINGIFY_TOKEN(tried), (intptr_t)(tried), (intptr_t)(expected)) #define assert_not_equal(tried, expected) \ assert_not_equal_(FILENAME, __LINE__, STRINGIFY_TOKEN(tried), (intptr_t)(tried), (intptr_t)(expected)) #define assert_double_equal(tried, expected) \ assert_double_equal_(FILENAME, __LINE__, STRINGIFY_TOKEN(tried), (tried), (expected)) #define assert_double_not_equal(tried, expected) \ assert_double_not_equal_(FILENAME, __LINE__, STRINGIFY_TOKEN(tried), (tried), (expected)) #define assert_string_equal(tried, expected) \ assert_string_equal_(FILENAME, __LINE__, STRINGIFY_TOKEN(tried), (tried), (expected)) #define assert_string_not_equal(tried, expected) \ assert_string_not_equal_(FILENAME, __LINE__, STRINGIFY_TOKEN(tried), (tried), (expected)) #define assert_true_with_message(result, ...) \ (*cgreen::get_test_reporter()->assert_true)(cgreen::get_test_reporter(), FILENAME, __LINE__, (result), __VA_ARGS__) #define assert_false_with_message(result, ...) \ (*cgreen::get_test_reporter()->assert_true)(cgreen::get_test_reporter(), FILENAME, __LINE__, ! (result), __VA_ARGS__) #define assert_equal_with_message(tried, expected, ...) \ (*cgreen::get_test_reporter()->assert_true)(cgreen::get_test_reporter(), FILENAME, __LINE__, ((tried) == (expected)), __VA_ARGS__) #define assert_not_equal_with_message(tried, expected, ...) \ (*cgreen::get_test_reporter()->assert_true)(cgreen::get_test_reporter(), FILENAME, __LINE__, ((tried) != (expected)), __VA_ARGS__) #define assert_double_equal_with_message(tried, expected, ...) \ (*cgreen::get_test_reporter()->assert_true)(cgreen::get_test_reporter(), FILENAME, __LINE__, doubles_are_equal((tried), (expected)), __VA_ARGS__) #define assert_double_not_equal_with_message(tried, expected, ...) \ (*cgreen::get_test_reporter()->assert_true)(cgreen::get_test_reporter(), FILENAME, __LINE__, doubles_are_equal((tried), (expected)), __VA_ARGS__) #define assert_string_equal_with_message(tried, expected, ...) \ (*cgreen::get_test_reporter()->assert_true)(cgreen::get_test_reporter(), FILENAME, __LINE__, strings_are_equal((tried), (expected)), __VA_ARGS__) #define assert_string_not_equal_with_message(tried, expected, ...) \ (*cgreen::get_test_reporter()->assert_true)(cgreen::get_test_reporter(), FILENAME, __LINE__, !strings_are_equal((tried), (expected)), __VA_ARGS__) #else /* Legacy style asserts (for C):*/ #define assert_true(result) \ (*get_test_reporter()->assert_true)(get_test_reporter(), FILENAME, __LINE__, (result), "[" STRINGIFY_TOKEN(result) "] should be true\n", NULL) #define assert_false(result) \ (*get_test_reporter()->assert_true)(get_test_reporter(), FILENAME, __LINE__, ! (result), "[" STRINGIFY_TOKEN(result) "] should be false\n", NULL) #define assert_equal(tried, expected) \ assert_equal_(FILENAME, __LINE__, STRINGIFY_TOKEN(tried), (intptr_t)(tried), (intptr_t)(expected)) #define assert_not_equal(tried, expected) \ assert_not_equal_(FILENAME, __LINE__, STRINGIFY_TOKEN(tried), (intptr_t)(tried), (intptr_t)(expected)) #define assert_double_equal(tried, expected) \ assert_double_equal_(FILENAME, __LINE__, STRINGIFY_TOKEN(tried), (tried), (expected)) #define assert_double_not_equal(tried, expected) \ assert_double_not_equal_(FILENAME, __LINE__, STRINGIFY_TOKEN(tried), (tried), (expected)) #define assert_string_equal(tried, expected) \ assert_string_equal_(FILENAME, __LINE__, STRINGIFY_TOKEN(tried), (tried), (expected)) #define assert_string_not_equal(tried, expected) \ assert_string_not_equal_(FILENAME, __LINE__, STRINGIFY_TOKEN(tried), (tried), (expected)) #define assert_true_with_message(result, ...) \ (*get_test_reporter()->assert_true)(get_test_reporter(), FILENAME, __LINE__, (result), __VA_ARGS__) #define assert_false_with_message(result, ...) \ (*get_test_reporter()->assert_true)(get_test_reporter(), FILENAME, __LINE__, ! (result), __VA_ARGS__) #define assert_equal_with_message(tried, expected, ...) \ (*get_test_reporter()->assert_true)(get_test_reporter(), FILENAME, __LINE__, ((tried) == (expected)), __VA_ARGS__) #define assert_not_equal_with_message(tried, expected, ...) \ (*get_test_reporter()->assert_true)(get_test_reporter(), FILENAME, __LINE__, ((tried) != (expected)), __VA_ARGS__) #define assert_double_equal_with_message(tried, expected, ...) \ (*get_test_reporter()->assert_true)(get_test_reporter(), FILENAME, __LINE__, doubles_are_equal((tried), (expected)), __VA_ARGS__) #define assert_double_not_equal_with_message(tried, expected, ...) \ (*get_test_reporter()->assert_true)(get_test_reporter(), FILENAME, __LINE__, doubles_are_equal((tried), (expected)), __VA_ARGS__) #define assert_string_equal_with_message(tried, expected, ...) \ (*get_test_reporter()->assert_true)(get_test_reporter(), FILENAME, __LINE__, strings_are_equal((tried), (expected)), __VA_ARGS__) #define assert_string_not_equal_with_message(tried, expected, ...) \ (*get_test_reporter()->assert_true)(get_test_reporter(), FILENAME, __LINE__, !strings_are_equal((tried), (expected)), __VA_ARGS__) #endif #endif cgreen-1.6.3/include/cgreen/message_formatting.h000066400000000000000000000007311450461175400217110ustar00rootroot00000000000000#ifndef CGREEN_MESSAGE_FORMATTING_H #define CGREEN_MESSAGE_FORMATTING_H #include #include #ifdef __cplusplus namespace cgreen { extern "C" { #endif char *failure_message_for(Constraint *constraint, const char *actual_string, intptr_t actual); char *validation_failure_message_for(Constraint *constraint, intptr_t actual); bool parameters_are_not_valid_for(Constraint *constraint, intptr_t actual); #ifdef __cplusplus } } #endif #endif cgreen-1.6.3/include/cgreen/messaging.h000066400000000000000000000005431450461175400200110ustar00rootroot00000000000000#ifndef MESSAGING_HEADER #define MESSAGING_HEADER #ifdef __cplusplus namespace cgreen { extern "C" { #endif int start_cgreen_messaging(int tag); void send_cgreen_message(int messaging, int result); int receive_cgreen_message(int messaging); int get_pipe_read_handle(void); int get_pipe_write_handle(void); #ifdef __cplusplus } } #endif #endif cgreen-1.6.3/include/cgreen/mocks.h000066400000000000000000000036051450461175400171520ustar00rootroot00000000000000#ifndef MOCKS_H #define MOCKS_H #include #include #include #include #include #ifdef __cplusplus namespace cgreen { extern "C" { #endif /* Program the mocked functions to expect (or not) calls when parameters match constraints... expect(, when(, ), ... expect(, when(, ), will_return()); */ #define expect(f, ...) expect_(get_test_reporter(), STRINGIFY_TOKEN(f), FILENAME, __LINE__, \ (Constraint *)__VA_ARGS__ +0, (Constraint *)0) #define always_expect(f, ...) always_expect_(get_test_reporter(), STRINGIFY_TOKEN(f), FILENAME, __LINE__, \ (Constraint *)__VA_ARGS__ +0, (Constraint *)0) #define never_expect(f, ...) never_expect_(get_test_reporter(), STRINGIFY_TOKEN(f), FILENAME, __LINE__, \ (Constraint *)__VA_ARGS__ +0, (Constraint *)0) #ifdef _MSC_VER // another workaround for fundamental variadic macro deficiencies in Visual C++ 2012 #define mock(...) PP_NARG(__VA_ARGS__)(get_test_reporter(), __func__, FILENAME, __LINE__, #__VA_ARGS__ "", \ __VA_ARGS__) #else #define mock(...) PP_NARG(__VA_ARGS__)(get_test_reporter(), __func__, FILENAME, __LINE__, #__VA_ARGS__ "", \ __VA_ARGS__ +0) #endif #define when(parameter, constraint) when_(#parameter, constraint) #define times(number_times_called) times_(number_times_called) /* Make Cgreen mocks strict, loose or learning */ typedef enum { strict_mocks = 0, loose_mocks = 1, learning_mocks = 2 } CgreenMockMode; extern void cgreen_mocks_are(CgreenMockMode mode); extern const int UNLIMITED_TIME_TO_LIVE; #ifdef __cplusplus } } #endif #endif cgreen-1.6.3/include/cgreen/reporter.h000066400000000000000000000047501450461175400177020ustar00rootroot00000000000000#ifndef REPORTER_HEADER #define REPORTER_HEADER #include #include #include typedef struct TestReporter_ TestReporter; struct TestReporter_ { void (*destroy)(TestReporter *reporter); void (*start_suite)(TestReporter *reporter, const char *name, const int count); void (*start_test)(TestReporter *reporter, const char *name); void (*show_pass)(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments); void (*show_skip)(TestReporter *reporter, const char *file, int line); void (*show_fail)(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments); void (*show_incomplete)(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments); void (*assert_true)(TestReporter *reporter, const char *file, int line, int result, const char * message, ...); void (*finish_test)(TestReporter *reporter, const char *file, int line, const char *message); void (*finish_suite)(TestReporter *reporter, const char *file, int line); int passes; int failures; int exceptions; int skips; uint32_t duration; int total_passes; int total_failures; int total_exceptions; int total_skips; uint32_t total_duration; CgreenBreadcrumb *breadcrumb; int ipc; void *memo; void *options; }; typedef void TestReportMemo; #ifdef __cplusplus namespace cgreen { extern "C" { #endif TestReporter *create_reporter(void); TestReporter *get_test_reporter(void); void set_reporter_options(TestReporter *reporter, void *options); void setup_reporting(TestReporter *reporter); void destroy_reporter(TestReporter *reporter); void destroy_memo(TestReportMemo *memo); void reporter_start_test(TestReporter *reporter, const char *name); void reporter_start_suite(TestReporter *reporter, const char *name, const int count); void reporter_finish_test(TestReporter *reporter, const char *filename, int line, const char *message); void reporter_finish_suite(TestReporter *reporter, const char *filename, int line); void add_reporter_result(TestReporter *reporter, int result); void send_reporter_exception_notification(TestReporter *reporter); void send_reporter_skipped_notification(TestReporter *reporter); void send_reporter_completion_notification(TestReporter *reporter); #ifdef __cplusplus } } #endif #endif cgreen-1.6.3/include/cgreen/runner.h000066400000000000000000000006031450461175400173420ustar00rootroot00000000000000#ifndef RUNNER_HEADER #define RUNNER_HEADER #include #include #ifdef __cplusplus namespace cgreen { extern "C" { #endif int run_test_suite(TestSuite *suite, TestReporter *reporter); int run_single_test(TestSuite *suite, const char *test, TestReporter *reporter); void die_in(unsigned int seconds); #ifdef __cplusplus } } #endif #endif cgreen-1.6.3/include/cgreen/string_comparison.h000066400000000000000000000005671450461175400216020ustar00rootroot00000000000000#ifndef CGREEN_STRING_COMPARISON_H #define CGREEN_STRING_COMPARISON_H #ifndef __cplusplus #include #endif #include #ifdef __cplusplus namespace cgreen { extern "C" { #endif bool strings_are_equal(const char *tried, const char *expected); bool string_contains(const char *actual, const char *expected); #ifdef __cplusplus } } #endif #endif cgreen-1.6.3/include/cgreen/suite.h000066400000000000000000000023321450461175400171630ustar00rootroot00000000000000#ifndef SUITE_HEADER #define SUITE_HEADER #include "internal/suite_internal.h" #include #include #include #include #ifndef __cplusplus #include #endif #ifdef __cplusplus namespace cgreen { extern "C" { #endif #define create_test_suite() create_named_test_suite_(__func__, FILENAME, __LINE__) #define create_named_test_suite(name) create_named_test_suite_(name, FILENAME, __LINE__) #define add_test(suite, test) add_test_(suite, STRINGIFY_TOKEN(test), &spec_name(default, test)) #define add_test_with_context(suite, context, test) add_test_(suite, STRINGIFY_TOKEN(test), &spec_name(context, test)) #define add_tests(suite, ...) add_tests_(suite, #__VA_ARGS__, (CgreenTest *)__VA_ARGS__) #define add_suite(owner, suite) add_suite_(owner, STRINGIFY_TOKEN(suite), suite) void set_setup(TestSuite *suite, void (*set_up)(void)); void set_teardown(TestSuite *suite, void (*tear_down)(void)); int count_tests(TestSuite *suite); bool has_test(TestSuite *suite, const char *name); bool has_setup(TestSuite *suite); bool has_teardown(TestSuite *suite); void destroy_test_suite(TestSuite *suite); #ifdef __cplusplus } } #endif #endif cgreen-1.6.3/include/cgreen/text_reporter.h000066400000000000000000000007251450461175400207440ustar00rootroot00000000000000#ifndef TEXT_REPORTER_HEADER #define TEXT_REPORTER_HEADER #include #ifndef __cplusplus #include #endif #ifdef __cplusplus namespace cgreen { extern "C" { #endif typedef struct text_reporter_options { bool use_colours; bool quiet_mode; bool inhibit_start_suite_message; bool inhibit_finish_suite_message; } TextReporterOptions; TestReporter *create_text_reporter(void); #ifdef __cplusplus } } #endif #endif cgreen-1.6.3/include/cgreen/unit.h000066400000000000000000000017521450461175400170160ustar00rootroot00000000000000#ifndef UNIT_HEADER #define UNIT_HEADER #include "internal/unit_implementation.h" #ifdef __cplusplus namespace cgreen { extern "C" { #endif /* BDD style: Describe the Subject Under Test, or context, by name */ #define Describe(subject) DescribeImplementation(subject) /* BDD style: Run this before any tests for that SUT or in that context */ #define BeforeEach(subject) BeforeEachImplementation(subject) /* BDD style: Run this after any tests for that SUT or in that context */ #define AfterEach(subject) AfterEachImplementation(subject) /* NOTE if you use BDD style all three of the above are required */ /* Then you must also use the BDD style Ensure(subject, test) */ /* TDD Style: Ensure(testname) {implementation} */ /* BDD Style: Ensure(subject, testname) {implementation} */ #define Ensure(...) Ensure_NARG(0, __VA_ARGS__)(0, __VA_ARGS__) /* Temporarily ignore this test */ #define xEnsure(...) Ensure_NARG(1, __VA_ARGS__)(1, __VA_ARGS__) #ifdef __cplusplus } } #endif #endif cgreen-1.6.3/include/cgreen/vector.h000066400000000000000000000011231450461175400173310ustar00rootroot00000000000000#ifndef VECTOR_HEADER #define VECTOR_HEADER #ifdef __cplusplus namespace cgreen { extern "C" { #endif typedef void (*GenericDestructor)(void *); typedef struct CgreenVector_ CgreenVector; CgreenVector *create_cgreen_vector(GenericDestructor destructor); void destroy_cgreen_vector(CgreenVector *vector); void cgreen_vector_add(CgreenVector *vector, void *item); void *cgreen_vector_remove(CgreenVector *vector, int position); void *cgreen_vector_get(const CgreenVector *vector, int position); int cgreen_vector_size(const CgreenVector *vector); #ifdef __cplusplus } } #endif #endif cgreen-1.6.3/include/cgreen/xml_reporter.h000066400000000000000000000005471450461175400205620ustar00rootroot00000000000000#ifndef _XML_REPORTER_HEADER_ #define _XML_REPORTER_HEADER_ #include "cgreen/reporter.h" #ifndef __cplusplus #include #endif #ifdef __cplusplus namespace cgreen { extern "C" { #endif TestReporter *create_xml_reporter(const char *prefix); TestReporter *create_libxml_reporter(const char *prefix); #ifdef __cplusplus } } #endif #endif cgreen-1.6.3/linux-setup.sh000077500000000000000000000012541450461175400156310ustar00rootroot00000000000000#! /bin/sh # # When you run "make test" CMake obviously runs the correct binraries # from the build directory. But when you want to run a test manually # PATH and LD_LIBRARY_PATH need to be set, and it is tedious and error # prone to remember that all the time. # # The follwing sets up the current shell in the same way, so that a # developer can just source this script and then forget about it. # # Ensure that the script is sourced: if [[ $_ == $0 ]]; then echo "You should really source this, like in '. cygwin-setup.sh'" fi # And here's the meat given that you have the standard build tree export PATH="$PWD/build/tools":$PATH export LD_LIBRARY_PATH="$PWD/build/src":$PATH cgreen-1.6.3/samples/000077500000000000000000000000001450461175400144375ustar00rootroot00000000000000cgreen-1.6.3/samples/CMakeLists.txt000066400000000000000000000001511450461175400171740ustar00rootroot00000000000000include_directories(${CGREEN_PUBLIC_INCLUDE_DIRS} ${PROJECT_BINARY_DIR}) add_executable(sample sample.c) cgreen-1.6.3/samples/Makefile000066400000000000000000000000641450461175400160770ustar00rootroot00000000000000sample: sample.o $(CC) -o sample sample.o -lcgreen cgreen-1.6.3/samples/sample.c000066400000000000000000000125751450461175400160760ustar00rootroot00000000000000#include #include #include #include #include Ensure(these_should_be_true) { assert_true(1); assert_false(1); } Ensure(these_should_be_false) { assert_true(0); assert_false(0); } Ensure(these_should_be_equal) { assert_equal(1, 1); assert_not_equal(1, 1); } Ensure(these_should_not_be_equal) { assert_equal(0, 1); assert_not_equal(0, 1); } Ensure(these_strings_should_match) { assert_string_equal("Hello", "Hello"); assert_string_not_equal("Hello", "Hello"); } Ensure(these_strings_should_not_match) { assert_string_equal("Hello", "hello"); assert_string_not_equal("Hello", "hello"); } TestSuite *assertion_tests() { TestSuite *suite = create_test_suite(); add_test(suite, these_should_be_true); add_test(suite, these_should_be_false); add_test(suite, these_should_be_equal); add_test(suite, these_should_not_be_equal); add_test(suite, these_strings_should_match); add_test(suite, these_strings_should_not_match); return suite; } static int an_integer = 0; void set_up_an_integer() { an_integer = 1; } Ensure(confirm_integer_is_set_up) { assert_equal_with_message(an_integer, 1, "Could not set up the integer"); an_integer = 2; } Ensure(check_again_during_teardown) { assert_equal_with_message(an_integer, 1, "Integer was changed from 1 to %d", an_integer); } TestSuite *fixture_tests() { TestSuite *suite = create_test_suite(); set_setup(suite, set_up_an_integer); set_teardown(suite, check_again_during_teardown); add_test(suite, confirm_integer_is_set_up); return suite; } static void print_something_during_setup() { printf("\tI was called during setup\n"); } Ensure(print_something_during_a_test) { printf("\tI am a test\n"); } static void print_something_during_teardown() { printf("\tI was called during teardown\n"); } TestSuite *visible_test() { TestSuite *suite = create_test_suite(); set_setup(suite, print_something_during_setup); add_test(suite, print_something_during_a_test); set_teardown(suite, print_something_during_teardown); return suite; } static void print_something_during_suite_setup() { printf("I was called during suite setup\n"); } static void print_something_during_suite_teardown() { printf("I was called during suite teardown\n"); } TestSuite *visible_fixtures() { TestSuite *suite = create_test_suite(); set_setup(suite, print_something_during_suite_setup); add_suite(suite, visible_test()); add_suite(suite, visible_test()); set_teardown(suite, print_something_during_suite_teardown); return suite; } int interference = 0; Ensure(create_test_interference) { interference = 1; } Ensure(prove_there_is_no_test_interference) { assert_equal(interference, 0); } Ensure(seg_fault) { int *p = NULL; (*p)++; } Ensure(time_out_in_only_one_second) { die_in(1); sleep(10); } TestSuite *isolation_tests() { TestSuite *suite = create_test_suite(); add_test(suite, create_test_interference); add_test(suite, prove_there_is_no_test_interference); add_test(suite, seg_fault); add_test(suite, time_out_in_only_one_second); return suite; } static void takes_integer(int i) { mock(i); } Ensure(expectation_confirmed) { expect(takes_integer, when(i, is_equal_to(3))); takes_integer(3); } Ensure(expectation_dashed) { expect(takes_integer, when(i, is_equal_to(3))); takes_integer(4); } static void mixed_parameters(int i, char *s) { mock(i, s); } Ensure(confirming_multiple_parameters_multiple_times) { expect(mixed_parameters, when(i, is_equal_to(1)), when(s, is_equal_to_string("Hello"))); expect(mixed_parameters, when(i, is_equal_to(2)), when(s, is_equal_to_string("Goodbye"))); mixed_parameters(1, "Hello"); mixed_parameters(2, "Goodbye"); } Ensure(breaking_multiple_parameters_multiple_times) { expect(mixed_parameters, when(i, is_equal_to(1)), when(s, is_equal_to_string("Hello"))); expect(mixed_parameters, when(i, is_equal_to(2)), when(s, is_equal_to_string("Goodbye"))); mixed_parameters(10, "Helloo"); mixed_parameters(20, "Gooodbye"); } Ensure(uncalled_expectations_should_throw_errors) { expect(mixed_parameters, when(i, is_equal_to(1)), when(s, is_equal_to_string("Hello"))); } Ensure(unexpected_call_should_throw_error) { never_expect(mixed_parameters); mixed_parameters(10, "Helloo"); } TestSuite *mock_tests() { TestSuite *suite = create_test_suite(); add_test(suite, expectation_confirmed); add_test(suite, expectation_dashed); add_test(suite, confirming_multiple_parameters_multiple_times); add_test(suite, breaking_multiple_parameters_multiple_times); add_test(suite, uncalled_expectations_should_throw_errors); add_test(suite, unexpected_call_should_throw_error); return suite; } Ensure(take_so_long_that_ctrl_c_is_needed) { sleep(10); } int main(int argc, char **argv) { TestSuite *suite = create_test_suite(); add_suite(suite, assertion_tests()); add_suite(suite, fixture_tests()); add_suite(suite, visible_fixtures()); add_suite(suite, isolation_tests()); add_suite(suite, mock_tests()); if (argc > 1) { add_test(suite, take_so_long_that_ctrl_c_is_needed); return run_single_test(suite, argv[1], create_text_reporter()); } return run_test_suite(suite, create_text_reporter()); } cgreen-1.6.3/setup.sh000077500000000000000000000043321450461175400144740ustar00rootroot00000000000000#! /bin/sh # # Setup PATH and LD_LIBRARY_PATH for command line work # # When you run "make test" CMake obviously runs the correct binaries # from the build directory. And so does the top level Makefile. But # when you want to run a test manually PATH and LD_LIBRARY_PATH need # to be set, and it is tedious and error prone to remember that all # the time. # # The follwing sets up the current shell in the same way, so that a # developer can just source this script and then always get the ones # in the build tree wihtout thinking about it. # # Ensure that the script is sourced: if [ $_ = $0 ]; then echo "You should really source this, like in '. $0'" fi contains() { string="$1" substring="$2" if test "${string#*$substring}" != "$string" then return 0 # $substring is in $string else return 1 # $substring is not in $string fi } # Add the appropriate directories in the build tree to PATH et al. if contains "$PATH" "$PWD/build/tools" ; then echo "You already have the appropriate directories in your PATH and LD_LIBRARY_PATH." else # And here's the meat given that you have the standard build tree export PATH="$PWD/build/tools":$PATH # On linux we need LD_LIBRARY_PATH... export LD_LIBRARY_PATH="$PWD/build/src":$PATH # MacOS.. export DYLD_LIBRARY_PATH="$PWD/build/src":$PATH # ...but on Cygwin DLL:s are searched using the path... export PATH="$PWD/build/src":$PATH fi # Let's also create symbolic links to build/tools and build/src to emulate typical # FHS include/bin/lib structure. This makes it easy to switch between various versions of # cgreen. E.g. in a Makefile you can do # # CGREEN_ROOT=/usr/local # CGREEN_INCLUDE=$(CGREEN_ROOT)/include # CGREEN_LIB=$(CGREEN_ROOT)/lib # CGREEN_BIN=$(CGREEN_ROOT)/bin # ... # LD_LIBRARY_PATH=$(CGREEN_LIB):. $(CGREEN_BIN)/bin/cgreen-runner # ... # %.so: %.c # g++ -o $@ -shared -g -I$(CGREEN_INCLUDE) -fPIC $^ -L $(CGREEN_LIBDIR) -lcgreen # # To switch to your current development version just change CGREEN_ROOT. # # So simulate that build/tools (where cgreen-runner is) is bin, and build/src (where # the cgreen library is built) is lib [ -e bin ] || ln -s build/tools bin [ -e lib ] || ln -s build/src lib cgreen-1.6.3/src/000077500000000000000000000000001450461175400135625ustar00rootroot00000000000000cgreen-1.6.3/src/CMakeLists.txt000066400000000000000000000130761450461175400163310ustar00rootroot00000000000000# Generate gitrevision.h if (GITREVISION AND GIT_EXECUTABLE) # Allow GITREVISION to be overridden manually / externally. This useful for vendoring. message(INFO, "GITREVISION manually overridden: ${GITREVISION}") else() if (GITDIR AND GIT_EXECUTABLE) # Use the git version if Git is available and the .git directory is found. # NOTE: $GITDIR is determined in top-level CMakeLists.txt execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --always --abbrev=7 --dirty=-modified OUTPUT_VARIABLE GITREVISION OUTPUT_STRIP_TRAILING_WHITESPACE) else() # No version control # e.g. when the software is built from a source tarball message(WARNING "-- Unable to find git, or not a repo. Setting git revision to 'unknown'.") set(GITREVISION "built from unknown git commit") endif() endif() configure_file(${PROJECT_SOURCE_DIR}/gitrevision.h.in ${PROJECT_SOURCE_DIR}/gitrevision.h @ONLY) set(CGREEN_PUBLIC_INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/ ${PROJECT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "cgreen public include directories" ) set(CGREEN_PRIVATE_INCLUDE_DIRS ${PROJECT_BINARY_DIR} ) if (MSVC) LIST(APPEND CGREEN_PRIVATE_INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/../include/cgreen/internal/windows_headers ) endif(MSVC) set(CGREEN_SHARED_LIBRARY cgreen_shared CACHE INTERNAL "cgreen shared library" ) if (WIN32 AND NOT CYGWIN) set(CGREEN_LINK_LIBRARIES winmm.lib ) endif(WIN32 AND NOT CYGWIN) set(cgreen_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/assertions.c ${CMAKE_CURRENT_SOURCE_DIR}/boxed_double.c ${CMAKE_CURRENT_SOURCE_DIR}/breadcrumb.c ${CMAKE_CURRENT_SOURCE_DIR}/cgreen_time.c ${CMAKE_CURRENT_SOURCE_DIR}/cgreen_value.c ${CMAKE_CURRENT_SOURCE_DIR}/constraint.c ${CMAKE_CURRENT_SOURCE_DIR}/cute_reporter.c ${CMAKE_CURRENT_SOURCE_DIR}/cdash_reporter.c ${CMAKE_CURRENT_SOURCE_DIR}/messaging.c ${CMAKE_CURRENT_SOURCE_DIR}/message_formatting.c ${CMAKE_CURRENT_SOURCE_DIR}/mocks.c ${CMAKE_CURRENT_SOURCE_DIR}/parameters.c ${CMAKE_CURRENT_SOURCE_DIR}/reporter.c ${CMAKE_CURRENT_SOURCE_DIR}/runner.c ${CMAKE_CURRENT_SOURCE_DIR}/string_comparison.c ${CMAKE_CURRENT_SOURCE_DIR}/suite.c ${CMAKE_CURRENT_SOURCE_DIR}/text_reporter.c ${CMAKE_CURRENT_SOURCE_DIR}/utils.c ${CMAKE_CURRENT_SOURCE_DIR}/vector.c ) if (CGREEN_WITH_XML) LIST(APPEND cgreen_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/xml_reporter.c) endif (CGREEN_WITH_XML) if (CGREEN_WITH_LIBXML2) LIST(APPEND cgreen_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/libxml_reporter.c) endif (CGREEN_WITH_LIBXML2) if (MSYS) # Msys2 is difficult since it really is three different "OS":es, Msys native, W32 and W64 # To get somewhere, let's use the native Msys2, which actually is Cygwin/UNIX. LIST(APPEND cgreen_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/posix_cgreen_pipe.c ${CMAKE_CURRENT_SOURCE_DIR}/posix_cgreen_time.c ${CMAKE_CURRENT_SOURCE_DIR}/posix_runner_platform.c ) elseif (UNIX OR CYGWIN) LIST(APPEND cgreen_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/posix_cgreen_pipe.c ${CMAKE_CURRENT_SOURCE_DIR}/posix_cgreen_time.c ${CMAKE_CURRENT_SOURCE_DIR}/posix_runner_platform.c ) elseif(WIN32) LIST(APPEND cgreen_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/win32_cgreen_pipe.c ${CMAKE_CURRENT_SOURCE_DIR}/win32_cgreen_time.c ${CMAKE_CURRENT_SOURCE_DIR}/win32_runner_platform.c ) else() message(FATAL_ERROR "Cgreen can currently only be compiled for Linux, Cygwin, MacOSX and Msys2 (native, not MingW versions). Patches are welcome!") endif() SET_SOURCE_FILES_PROPERTIES(${cgreen_SRCS} PROPERTIES LANGUAGE C) set(cgreen_SRCS ${cgreen_SRCS} ${CMAKE_CURRENT_SOURCE_DIR}/cpp_assertions.cpp ${CMAKE_CURRENT_SOURCE_DIR}/cpp_constraint.cpp ) SET_SOURCE_FILES_PROPERTIES(cpp_assertions.cpp cpp_constraint.cpp PROPERTIES LANGUAGE CXX ) include(DefineRelativeFilePaths) cmake_define_relative_file_paths ("${cgreen_SRCS}") include_directories( ${CGREEN_PUBLIC_INCLUDE_DIRS} ${CGREEN_PRIVATE_INCLUDE_DIRS} $<$:${LIBXML2_INCLUDE_DIRS}> ) ### cgreen set(CGREEN_LIBRARY_NAME cgreen) add_library(${CGREEN_SHARED_LIBRARY} SHARED ${cgreen_SRCS} ${PROJECT_SOURCE_DIR}/gitrevision.h) target_link_libraries( ${CGREEN_SHARED_LIBRARY} ${CGREEN_LINK_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${MATH_LIB} ${CMAKE_CXX_IMPLICIT_LINK_LIBRARIES} $<$:${LIBXML2_LIBRARIES}> ) set_target_properties( ${CGREEN_SHARED_LIBRARY} PROPERTIES VERSION ${LIBRARY_VERSION} SOVERSION ${LIBRARY_SOVERSION} OUTPUT_NAME ${CGREEN_LIBRARY_NAME} ) install( TARGETS ${CGREEN_SHARED_LIBRARY} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT libraries ) if (CGREEN_WITH_STATIC_LIBRARY) set(CGREEN_STATIC_LIBRARY cgreen_static CACHE INTERNAL "cgreen static library" ) add_library(${CGREEN_STATIC_LIBRARY} STATIC ${cgreen_SRCS}) target_link_libraries(${CGREEN_STATIC_LIBRARY} ${CGREEN_LINK_LIBRARIES} ${MATH_LIB} ${CMAKE_CXX_IMPLICIT_LINK_LIBRARIES} ) set_target_properties( ${CGREEN_STATIC_LIBRARY} PROPERTIES VERSION ${LIBRARY_VERSION} SOVERSION ${LIBRARY_SOVERSION} OUTPUT_NAME ${CGREEN_LIBRARY_NAME} ) install( TARGETS ${CGREEN_STATIC_LIBRARY} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT libraries ) endif(CGREEN_WITH_STATIC_LIBRARY) cgreen-1.6.3/src/Makefile000066400000000000000000000000541450461175400152210ustar00rootroot00000000000000all: cd ..; make --no-print-directory unit cgreen-1.6.3/src/assertions.c000066400000000000000000000152261450461175400161260ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include "cgreen_value_internal.h" #include "constraint_internal.h" const char *show_null_as_the_string_null(const char *string); void assert_core_(const char *file, int line, const char *actual_string, intptr_t actual, Constraint* constraint) { char *failure_message; if (NULL != constraint && is_not_comparing(constraint)) { (*get_test_reporter()->assert_true)( get_test_reporter(), file, line, false, "Got constraint of type [%s],\n" "\t\tbut they are not allowed for assertions, only in mock expectations.", constraint->name); constraint->destroy(constraint); return; } if (constraint->type == CGREEN_DOUBLE_COMPARER_CONSTRAINT) { (*get_test_reporter()->assert_true)( get_test_reporter(), file, line, false, "Constraints of double type, such as [%s],\n" "\t\tshould only be used with 'assert_that_double()' to ensure proper comparison.", constraint->name); } if (parameters_are_not_valid_for(constraint, actual)) { char *validation_message = validation_failure_message_for(constraint, actual); (*get_test_reporter()->assert_true)( get_test_reporter(), file, line, false, validation_message); constraint->destroy(constraint); free(validation_message); return; } failure_message = constraint->failure_message(constraint, actual_string, actual); (*get_test_reporter()->assert_true)( get_test_reporter(), file, line, (*constraint->compare)(constraint, make_cgreen_integer_value(actual)), failure_message ); constraint->destroy(constraint); free(failure_message); } void assert_that_double_(const char *file, int line, const char *expression, double actual, Constraint* constraint) { BoxedDouble* boxed_actual; if (NULL != constraint && is_not_comparing(constraint)) { (*get_test_reporter()->assert_true)( get_test_reporter(), file, line, false, "Got constraint of type [%s],\n" "\t\tbut they are not allowed for assertions, only in mock expectations.", constraint->name); constraint->destroy(constraint); return; } if (constraint->type != CGREEN_DOUBLE_COMPARER_CONSTRAINT) { (*get_test_reporter()->assert_true)( get_test_reporter(), file, line, false, "Only constraints of double type should be used with 'assert_that_double()'.\n" "\t\tOther types of constraints, such as [%s], will probably fail comparison.", constraint->name); } boxed_actual = (BoxedDouble*)box_double(actual); (*get_test_reporter()->assert_true)(get_test_reporter(), file, line, (*constraint->compare)(constraint, make_cgreen_double_value(actual)), "Expected [%s] to [%s] [%s] within [%d] significant figures\n" "\t\tactual value:\t\t\t[%08f]\n" "\t\texpected value:\t\t\t[%08f]", expression, constraint->name, constraint->expected_value_name, get_significant_figures(), actual, constraint->expected_value.value.double_value); free(boxed_actual); constraint->destroy(constraint); } void assert_equal_(const char *file, int line, const char *expression, intptr_t tried, intptr_t expected) { (*get_test_reporter()->assert_true)( get_test_reporter(), file, line, (tried == expected), "[%s] should be [%d] but was [%d]\n", expression, expected, tried); } void assert_not_equal_(const char *file, int line, const char *expression, intptr_t tried, intptr_t expected) { (*get_test_reporter()->assert_true)( get_test_reporter(), file, line, (tried != expected), "[%s] should not be [%d] but was\n", expression, expected, tried); } void assert_double_equal_(const char *file, int line, const char *expression, double tried, double expected) { (*get_test_reporter()->assert_true)( get_test_reporter(), file, line, doubles_are_equal(tried, expected), "[%s] should be [%f] within %d significant figures but was [%f]\n", expression, expected, get_significant_figures(), tried); } void assert_double_not_equal_(const char *file, int line, const char *expression, double tried, double expected) { (*get_test_reporter()->assert_true)( get_test_reporter(), file, line, ! doubles_are_equal(tried, expected), "[%s] should not be [%f] within %d significant figures but was [%f]\n", expression, expected, get_significant_figures(), tried); } void assert_string_equal_(const char *file, int line, const char *expression, const char *tried, const char *expected) { (*get_test_reporter()->assert_true)( get_test_reporter(), file, line, strings_are_equal(tried, expected), "[%s] should be [%s] but was [%s]\n", expression, show_null_as_the_string_null(expected), show_null_as_the_string_null(tried)); } void assert_string_not_equal_(const char *file, int line, const char *expression, const char *tried, const char *expected) { (*get_test_reporter()->assert_true)( get_test_reporter(), file, line, ! strings_are_equal(tried, expected), "[%s] should not be [%s] but was\n", expression, show_null_as_the_string_null(expected)); } const char *show_null_as_the_string_null(const char *string) { return (string == NULL ? "NULL" : string); } /* vim: set ts=4 sw=4 et cindent: */ cgreen-1.6.3/src/boxed_double.c000066400000000000000000000010141450461175400163550ustar00rootroot00000000000000#include #include #include /* NOTE: while returning BoxedDouble* here seems logical, it forces casts all over the place */ intptr_t box_double(double value) { BoxedDouble *box = (BoxedDouble *) malloc(sizeof(BoxedDouble)); box->value = value; return (intptr_t)box; } double unbox_double(intptr_t box) { double value = as_double(box); free((BoxedDouble *)box); return value; } double as_double(intptr_t box) { return ((BoxedDouble *)box)->value; } cgreen-1.6.3/src/breadcrumb.c000066400000000000000000000031561450461175400160410ustar00rootroot00000000000000#include #include CgreenBreadcrumb *create_breadcrumb(void) { CgreenBreadcrumb *breadcrumb = (CgreenBreadcrumb *) malloc(sizeof(CgreenBreadcrumb)); if (breadcrumb == NULL) { return NULL; } breadcrumb->trail = NULL; breadcrumb->depth = 0; breadcrumb->space = 0; return breadcrumb; } void destroy_breadcrumb(CgreenBreadcrumb *breadcrumb) { free((void*)breadcrumb->trail); free((void*)breadcrumb); } void push_breadcrumb(CgreenBreadcrumb *breadcrumb, const char *name) { breadcrumb->depth++; if (breadcrumb->depth > breadcrumb->space) { const char **tmp; breadcrumb->space++; tmp = (const char**) realloc((void*)breadcrumb->trail, sizeof(const char *) * breadcrumb->space); if (tmp == NULL) { breadcrumb->space--; breadcrumb->depth--; return; } breadcrumb->trail = tmp; } breadcrumb->trail[breadcrumb->depth - 1] = name; } void pop_breadcrumb(CgreenBreadcrumb *breadcrumb) { breadcrumb->depth--; } const char *get_current_from_breadcrumb(CgreenBreadcrumb *breadcrumb) { if (get_breadcrumb_depth(breadcrumb) == 0) { return NULL; } return breadcrumb->trail[breadcrumb->depth - 1]; } int get_breadcrumb_depth(CgreenBreadcrumb *breadcrumb) { return breadcrumb->depth; } void walk_breadcrumb(CgreenBreadcrumb *breadcrumb, void (*walker)(const char *, void *), void *memo) { int i; for (i = 0; i < breadcrumb->depth; i++) { (*walker)(breadcrumb->trail[i], memo); } } /* vim: set ts=4 sw=4 et cindent: */ cgreen-1.6.3/src/cdash_reporter.c000066400000000000000000000262371450461175400167440ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #ifdef __ANDROID__ #include "cgreen/internal/android_headers/androidcompat.h" #endif // #ifdef __ANDROID__ #ifdef _MSC_VER #include #endif #include #include "cdash_reporter_internal.h" typedef time_t Timer(char *strtime); typedef struct { CDashInfo *info; CDashPrinter *printer; CDashVPrinter *vprinter; FILE *stream; time_t begin; time_t startdatetime; time_t enddatetime; time_t teststarted; time_t testfinished; } CDashMemo; static void cdash_destroy_reporter(TestReporter *reporter); static void cdash_reporter_start_suite(TestReporter *reporter, const char *name, const int number_of_tests); static void cdash_reporter_start_test(TestReporter *reporter, const char *name); static void cdash_show_fail(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments); static void cdash_show_pass(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments); static void cdash_show_incomplete(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments); static void cdash_finish_test(TestReporter *reporter, const char *filename, int line, const char *message); static void cdash_finish_suite(TestReporter *reporter, const char *filename, int line); static time_t cdash_build_stamp(char *sbuildstamp, size_t sb); static time_t cdash_current_time(char *strtime); static double cdash_elapsed_time(time_t t1, time_t t2); void set_cdash_reporter_printer(TestReporter *reporter, CDashPrinter *new_printer) { CDashMemo *memo = (CDashMemo *)reporter->memo; memo->printer = new_printer; } void set_cdash_reporter_vprinter(TestReporter *reporter, CDashVPrinter *new_vprinter) { CDashMemo *memo = (CDashMemo *)reporter->memo; memo->vprinter = new_vprinter; } TestReporter *create_cdash_reporter(CDashInfo *info) { TestReporter *reporter; CDashMemo *memo; FILE *fd; char sbuildstamp[15]; char strstart[30]; char reporter_path[255]; int rep_dir, strsize; if (!info) return NULL; reporter = create_reporter(); if (!reporter) return NULL; memo = (CDashMemo *) calloc(1, sizeof(CDashMemo)); if (!memo) return NULL; memo->info = info; memo->begin = cdash_build_stamp(sbuildstamp, 15); reporter->memo = memo; set_cdash_reporter_printer(reporter, fprintf); set_cdash_reporter_vprinter(reporter, vfprintf); rep_dir = mkdir("./Testing", S_IXUSR|S_IRUSR|S_IWUSR|S_IXGRP|S_IRGRP|S_IXOTH); if (rep_dir) { if (errno != EEXIST) { free(memo); return NULL; } } fd = fopen("./Testing/TAG", "w+"); if (fd == NULL) { free(memo); return NULL; } fprintf(fd, "%s\n%s\n", sbuildstamp, memo->info->type); fclose(fd); strsize = snprintf(reporter_path, sizeof(reporter_path) - 1, "./Testing/%s", sbuildstamp); rep_dir = mkdir(reporter_path, S_IXUSR|S_IRUSR|S_IWUSR|S_IXGRP|S_IRGRP|S_IXOTH); if (rep_dir) { if (errno != EEXIST) { free(memo); return NULL; } } snprintf( (char *) (reporter_path + strsize), (255 - strsize), "/Test.xml"); fd = fopen(reporter_path, "w+"); if (fd == NULL) { free(memo); return NULL; } /* now the Test.xml is in place */ memo->stream = fd; memo->startdatetime = cdash_current_time(strstart); memo->printer(memo->stream, "\n" " \n" " \n" " %s\n" " \n" " \n" " \n", memo->info->build, sbuildstamp, memo->info->type, memo->info->name, "Cgreen" VERSION, memo->info->os_name, memo->info->hostname, memo->info->os_release, memo->info->os_version, memo->info->os_platform, strstart); fflush(memo->stream); reporter->destroy = &cdash_destroy_reporter; reporter->start_suite = &cdash_reporter_start_suite; reporter->start_test = &cdash_reporter_start_test; reporter->show_fail = &cdash_show_fail; reporter->show_pass = &cdash_show_pass; reporter->show_incomplete = &cdash_show_incomplete; reporter->finish_test = &cdash_finish_test; reporter->finish_suite = &cdash_finish_suite; reporter->memo = memo; return reporter; } static void cdash_destroy_reporter(TestReporter *reporter) { char endtime[30]; CDashMemo *memo = (CDashMemo *)reporter->memo; memo->enddatetime = cdash_current_time(endtime); memo->printer(memo->stream, " %s\n" " %.2f\n" " \n" "\n", endtime, cdash_elapsed_time(memo->startdatetime, memo->enddatetime)); destroy_reporter(reporter); } static void cdash_reporter_start_suite(TestReporter *reporter, const char *name, const int number_of_tests) { (void)number_of_tests; reporter->passes = 0; reporter->failures = 0; reporter->skips = 0; reporter->exceptions = 0; reporter_start_test(reporter, name); } static void cdash_reporter_start_test(TestReporter *reporter, const char *name) { CDashMemo *memo = (CDashMemo *)reporter->memo; memo->teststarted = cdash_current_time(NULL); reporter_start_test(reporter, name); } static void print_test_header(CDashMemo *memo, const char* status, const char *name, const char* file, int line) { memo->printer(memo->stream, " \n" " %s\n" " %s\n" " %s\n" " at [%s] line [%d]\n", status, name, file, file, file, line); } static void print_results_header(CDashMemo *memo, const char *name, float exectime) { memo->printer(memo->stream, " \n" " \n" " %f\n" " \n" " \n" " Completed\n" " \n" " \n" " %s\n" " \n", exectime, name); } static void print_measurement(CDashMemo *memo, const char* message, va_list arguments) { memo->printer(memo->stream, " \n" " "); if (message == NULL) { memo->printer(memo->stream, "Problem"); } else { memo->vprinter(memo->stream, message, arguments); } memo->printer(memo->stream, "\n" " \n"); } static void print_tail(CDashMemo *memo) { memo->printer(memo->stream, " \n" " \n"); } static void cdash_show_fail(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments) { const char *name; float exectime; CDashMemo *memo; memo = (CDashMemo *)reporter->memo; memo->testfinished = cdash_current_time(NULL); exectime = (float)cdash_elapsed_time(memo->teststarted, memo->testfinished); name = get_current_from_breadcrumb((CgreenBreadcrumb *)reporter->breadcrumb); print_test_header(memo, "failed", name, file, line); print_results_header(memo, name, exectime); print_measurement(memo, message, arguments); print_tail(memo); } static void cdash_show_pass(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments) { double exectime; CDashMemo *memo; const char *name = get_current_from_breadcrumb((CgreenBreadcrumb *)reporter->breadcrumb); (void)message; memo = (CDashMemo *)reporter->memo; memo->testfinished = cdash_current_time(NULL); exectime = cdash_elapsed_time(memo->teststarted, memo->testfinished); print_test_header(memo, "passed", name, file, line); print_results_header(memo, name, exectime); print_measurement(memo, "", arguments); print_tail(memo); } static void cdash_show_incomplete(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments) { const char *name; float exectime; CDashMemo *memo; memo = (CDashMemo *)reporter->memo; memo->testfinished = cdash_current_time(NULL); exectime = (float)cdash_elapsed_time(memo->teststarted, memo->testfinished); name = get_current_from_breadcrumb((CgreenBreadcrumb *)reporter->breadcrumb); print_test_header(memo, "incomplete", name, file, line); print_results_header(memo, name, exectime); print_measurement(memo, message, arguments); print_tail(memo); } static void cdash_finish_test(TestReporter *reporter, const char *filename, int line, const char *message) { reporter_finish_test(reporter, filename, line, message); } static void cdash_finish_suite(TestReporter *reporter, const char *filename, int line) { reporter_finish_test(reporter, filename, line, NULL); reporter->total_passes += reporter->passes; reporter->total_failures += reporter->failures; reporter->total_skips += reporter->skips; reporter->total_exceptions += reporter->exceptions; } static time_t cdash_build_stamp(char *sbuildstamp, size_t sb) { time_t t1; struct tm d1; char s[15]; t1 = time(0); gmtime_r(&t1, &d1); strftime(s, sizeof(s), "%Y%m%d-%H%M", &d1); snprintf(sbuildstamp, sb, "%s", s); return t1; } static time_t cdash_current_time(char *strtime) { time_t t1; struct tm d1; char s[20]; size_t i; t1 = time(0); gmtime_r(&t1, &d1); if(strtime == NULL) return t1; i = strftime(s, 20, "%b %d %H:%M EDT", &d1); strncpy(strtime, s, i+1); return t1; } static double cdash_elapsed_time(time_t t1, time_t t2) { double diff; diff = difftime(t2, t1); return (diff == 0 ? 0 : (diff / 60)); } cgreen-1.6.3/src/cdash_reporter_internal.h000066400000000000000000000007171450461175400206400ustar00rootroot00000000000000#ifndef CDASH_REPORTER_INTERNAL_H #define CDASH_REPORTER_INTERNAL_H #include #ifdef __cplusplus extern "C" { #endif typedef int CDashPrinter(FILE *, const char *format, ...); typedef int CDashVPrinter(FILE *, const char *format, va_list arguments); void set_cdash_reporter_printer(TestReporter *reporter, CDashPrinter *printer); void set_cdash_reporter_vprinter(TestReporter *reporter, CDashVPrinter *vprinter); #ifdef __cplusplus } #endif #endif cgreen-1.6.3/src/cgreen_time.c000066400000000000000000000006021450461175400162050ustar00rootroot00000000000000#include #include "cgreen/internal/cgreen_time.h" uint32_t cgreen_time_duration_in_milliseconds(uint32_t start_time_in_milliseconds, uint32_t end_time_in_milliseconds) { if (end_time_in_milliseconds < start_time_in_milliseconds) { return 0; } return end_time_in_milliseconds - start_time_in_milliseconds; } cgreen-1.6.3/src/cgreen_value.c000066400000000000000000000030641450461175400163700ustar00rootroot00000000000000#include #include #include #include #include static char *stringdup(const char *string) { if (string == NULL) return NULL; else return strcpy((char *)malloc(strlen(string)+1), string); } CgreenValue *create_cgreen_value(CgreenValue value) { CgreenValue *ptr = (CgreenValue*)malloc(sizeof(CgreenValue)); *ptr = value; return ptr; } CgreenValue make_cgreen_integer_value(intptr_t integer) { CgreenValue value = {CGREEN_INTEGER, {0}, sizeof(intptr_t)}; value.value.integer_value = integer; return value; } CgreenValue make_cgreen_string_value(const char *string) { CgreenValue value = {CGREEN_STRING, {0}, sizeof(const char *)}; value.value.string_value = stringdup(string); return value; } CgreenValue make_cgreen_pointer_value(void *pointer) { CgreenValue value = {CGREEN_POINTER, {0}, sizeof(intptr_t)}; value.value.pointer_value = pointer; return value; } CgreenValue make_cgreen_double_value(double d) { CgreenValue value = {CGREEN_DOUBLE, {0}, sizeof(intptr_t)}; value.value.double_value = d; return value; } CgreenValue make_cgreen_by_value(void *pointer, size_t size) { CgreenValue value = {CGREEN_BYVALUE, {0}, size}; value.value.pointer_value = pointer; return value; } void destroy_cgreen_value(CgreenValue value) { if (value.type == CGREEN_STRING) free((void *)value.value.string_value); else if (value.type == CGREEN_BYVALUE) free(value.value.pointer_value); } cgreen-1.6.3/src/cgreen_value_internal.h000066400000000000000000000013141450461175400202650ustar00rootroot00000000000000#ifndef CGREEN_VALUE_INTERNAL_H #define CGREEN_VALUE_INTERNAL_H #include /* CgreenValues are used from some user level tests so must be compilable in C++ */ #ifdef __cplusplus namespace cgreen { extern "C" { #endif extern CgreenValue *create_cgreen_value(CgreenValue value); extern CgreenValue make_cgreen_integer_value(intptr_t integer); extern CgreenValue make_cgreen_string_value(const char *string); extern CgreenValue make_cgreen_double_value(double value); extern CgreenValue make_cgreen_pointer_value(void *ptr); extern CgreenValue make_cgreen_by_value(void *pointer, size_t size); extern void destroy_cgreen_value(CgreenValue value); #ifdef __cplusplus } } #endif #endif cgreen-1.6.3/src/constraint.c000066400000000000000000001024251450461175400161160ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #ifndef __cplusplus #include #endif #include #include #include #ifdef __ANDROID__ #include "cgreen/internal/android_headers/androidcompat.h" #endif // #ifdef __ANDROID__ #ifdef _MSC_VER #include "wincompat.h" #endif #include "constraint_internal.h" #include "parameters.h" #include "utils.h" #include "cgreen_value_internal.h" #ifdef max #undef max #endif #ifdef min #undef min #endif #define max(a,b) ((a) > (b) ? (a) : (b)) #define min(a,b) ((a) > (b) ? (b) : (a)) static int significant_figures = 8; static double absolute_tolerance = DBL_MIN / 1.0e-8; static double accuracy(int significant_figures, double largest); static bool compare_want_greater_value(Constraint *constraint, CgreenValue actual); static bool compare_want_lesser_value(Constraint *constraint, CgreenValue actual); static bool compare_want_contents(Constraint *constraint, CgreenValue actual); static bool compare_do_not_want_contents(Constraint *constraint, CgreenValue actual); static bool compare_true(Constraint *constraint, CgreenValue actual); static void test_true(Constraint *constraint, const char *function, CgreenValue actual, const char *test_file, int test_line, TestReporter *reporter); static bool compare_want_string(Constraint *constraint, CgreenValue actual); static bool compare_do_not_want_string(Constraint *constraint, CgreenValue actual); static bool compare_want_substring(Constraint *constraint, CgreenValue actual); static bool compare_do_not_want_substring(Constraint *constraint, CgreenValue actual); static bool compare_want_beginning_of_string(Constraint *constraint, CgreenValue actual); static bool compare_do_not_want_beginning_of_string(Constraint *constraint, CgreenValue actual); static bool compare_want_end_of_string(Constraint *constraint, CgreenValue actual); static bool compare_do_not_want_end_of_string(Constraint *constraint, CgreenValue actual); static bool compare_want_double(Constraint *constraint, CgreenValue actual); static void test_want_double(Constraint *constraint, const char *function, CgreenValue actual, const char *test_file, int test_line, TestReporter *reporter); static bool compare_do_not_want_double(Constraint *constraint, CgreenValue actual); static void test_do_not_want_double(Constraint *constraint, const char *function, CgreenValue actual, const char *test_file, int test_line, TestReporter *reporter); static bool compare_want_lesser_double(Constraint *constraint, CgreenValue actual); static bool compare_want_greater_double(Constraint *constraint, CgreenValue actual); static void set_contents(Constraint *constraint, const char *function, CgreenValue actual, const char *test_file, int test_line, TestReporter *reporter); static void execute_sideeffect(Constraint *constraint, const char *function, CgreenValue actual, const char *test_file, int test_line, TestReporter *reporter); static void capture_parameter(Constraint *constraint, const char *function, CgreenValue actual, const char *test_file, int test_line, TestReporter *reporter); static const char *default_actual_value_message = "\n\t\tactual value:\t\t\t[%" PRIdPTR "]"; static const char *default_expected_value_message = "\t\texpected value:\t\t\t[%" PRIdPTR "]"; Constraint *create_constraint(void) { Constraint *constraint = (Constraint *)malloc(sizeof(Constraint)); /* TODO: setting this to NULL as an implicit type check :( */ constraint->parameter_name = NULL; constraint->destroy = &destroy_empty_constraint; constraint->failure_message = &failure_message_for; constraint->expected_value_name = NULL; constraint->actual_value_message = default_actual_value_message; constraint->expected_value_message = default_expected_value_message; return constraint; } static Constraint *create_constraint_expecting(CgreenValue expected_value, const char *expected_value_name) { Constraint *constraint = create_constraint(); constraint->expected_value = expected_value; constraint->expected_value_name = string_dup(expected_value_name); return constraint; } void destroy_empty_constraint(Constraint *constraint) { constraint->name = NULL; constraint->parameter_name = NULL; constraint->compare = NULL; constraint->execute = NULL; constraint->destroy = NULL; if (constraint->expected_value_name != NULL) free((void *)constraint->expected_value_name); free(constraint); } void destroy_static_constraint(Constraint *constraint) { /* static constraints helpers (e.g. is_null) act as singletons, and are never destroyed */ (void)constraint; } void destroy_constraint(Constraint *constraint) { if (constraint->destroy != NULL) (*constraint->destroy)(constraint); } void destroy_constraints(va_list constraints) { Constraint *constraint = NULL; while ((constraint = va_arg(constraints, Constraint *)) != (Constraint *)0) { destroy_constraint(constraint); } } bool constraint_is_for_parameter(const Constraint *constraint, const char *parameter) { return !constraint_is_not_for_parameter(constraint, parameter); } bool constraint_is_not_for_parameter(const Constraint *constraint, const char *parameter) { /* TODO: This should not test for types of constraints... Or it actually checks for something else ... */ if (is_not_comparing(constraint) && is_not_content_setting(constraint)) { return true; } return strcmp(constraint->parameter_name, parameter) != 0; } Constraint *create_not_null_constraint(void) { Constraint *constraint = create_constraint_expecting(make_cgreen_integer_value(0), "null"); constraint->type = CGREEN_VALUE_COMPARER_CONSTRAINT; constraint->name = "be non null"; constraint->compare = &compare_do_not_want_value; constraint->execute = &test_want; constraint->actual_value_message = ""; constraint->expected_value_message = ""; return constraint; } Constraint *create_is_null_constraint(void) { Constraint *constraint = create_constraint_expecting(make_cgreen_integer_value(0), "null"); constraint->type = CGREEN_VALUE_COMPARER_CONSTRAINT; constraint->name = "be null"; constraint->compare = &compare_want_value; constraint->execute = &test_want; constraint->actual_value_message = ""; constraint->expected_value_message = ""; return constraint; } Constraint *create_is_false_constraint(void) { Constraint *constraint = create_constraint_expecting(make_cgreen_integer_value(false), "false"); constraint->type = CGREEN_VALUE_COMPARER_CONSTRAINT; constraint->name = "be false"; constraint->compare = &compare_want_value; constraint->execute = &test_want; constraint->actual_value_message = ""; constraint->expected_value_message = ""; return constraint; } Constraint *create_is_true_constraint(void) { Constraint *constraint = create_constraint_expecting(make_cgreen_integer_value(false), "true"); constraint->type = CGREEN_VALUE_COMPARER_CONSTRAINT; constraint->name = "be true"; constraint->compare = &compare_do_not_want_value; constraint->execute = &test_want; constraint->actual_value_message = ""; constraint->expected_value_message = ""; return constraint; } Constraint *create_equal_to_value_constraint(intptr_t expected_value, const char *expected_value_name) { Constraint *constraint = create_constraint_expecting(make_cgreen_integer_value(expected_value), expected_value_name); constraint->type = CGREEN_VALUE_COMPARER_CONSTRAINT; constraint->compare = &compare_want_value; constraint->execute = &test_want; constraint->name = "equal"; constraint->size_of_expected_value = sizeof(intptr_t); return constraint; } Constraint *create_equal_to_hexvalue_constraint(intptr_t expected_value, const char *expected_value_name) { Constraint *constraint = create_constraint_expecting(make_cgreen_integer_value(expected_value), expected_value_name); constraint->type = CGREEN_VALUE_COMPARER_CONSTRAINT; constraint->compare = &compare_want_value; constraint->execute = &test_want; constraint->name = "equal"; constraint->size_of_expected_value = sizeof(intptr_t); constraint->actual_value_message = "\n\t\tactual value:\t\t\t[0x%x]"; constraint->expected_value_message = "\t\texpected value:\t\t\t[0x%x]"; return constraint; } Constraint *create_not_equal_to_value_constraint(intptr_t expected_value, const char *expected_value_name) { Constraint *constraint = create_constraint_expecting(make_cgreen_integer_value(expected_value), expected_value_name); constraint->type = CGREEN_VALUE_COMPARER_CONSTRAINT; constraint->compare = &compare_do_not_want_value; constraint->execute = &test_want; constraint->name = "not equal"; constraint->size_of_expected_value = sizeof(intptr_t); return constraint; } Constraint *create_less_than_value_constraint(intptr_t expected_value, const char *expected_value_name) { Constraint *constraint = create_constraint_expecting(make_cgreen_integer_value(expected_value), expected_value_name); constraint->type = CGREEN_VALUE_COMPARER_CONSTRAINT; constraint->compare = &compare_want_lesser_value; constraint->execute = &test_true; constraint->name = "be less than"; constraint->expected_value_message = "\t\texpected to be less than:\t[%" PRIdPTR "]"; constraint->size_of_expected_value = sizeof(intptr_t); return constraint; } Constraint *create_greater_than_value_constraint(intptr_t expected_value, const char *expected_value_name) { Constraint *constraint = create_constraint_expecting(make_cgreen_integer_value(expected_value), expected_value_name); constraint->type = CGREEN_VALUE_COMPARER_CONSTRAINT; constraint->compare = &compare_want_greater_value; constraint->execute = &test_true; constraint->name = "be greater than"; constraint->expected_value_message = "\t\texpected to be greater than:\t[%" PRIdPTR "]"; constraint->size_of_expected_value = sizeof(intptr_t); return constraint; } Constraint *create_equal_to_contents_constraint(void *pointer_to_compare, size_t size_to_compare, const char *compared_pointer_name) { Constraint *constraint = create_constraint_expecting(make_cgreen_pointer_value(pointer_to_compare), compared_pointer_name); constraint->type = CGREEN_CONTENT_COMPARER_CONSTRAINT; constraint->compare = &compare_want_contents; constraint->execute = &test_want; constraint->name = "equal contents of"; constraint->size_of_expected_value = size_to_compare; return constraint; } Constraint *create_not_equal_to_contents_constraint(void *pointer_to_compare, size_t size_to_compare, const char *compared_pointer_name) { Constraint *constraint = create_constraint_expecting(make_cgreen_pointer_value(pointer_to_compare), compared_pointer_name); constraint->type = CGREEN_CONTENT_COMPARER_CONSTRAINT; constraint->compare = &compare_do_not_want_contents; constraint->execute = &test_want; constraint->name = "not equal contents of"; constraint->size_of_expected_value = size_to_compare; return constraint; } Constraint *create_equal_to_string_constraint(const char* expected_value, const char *expected_value_name) { Constraint *constraint = create_constraint_expecting(make_cgreen_string_value(expected_value), expected_value_name); constraint->type = CGREEN_STRING_COMPARER_CONSTRAINT; constraint->compare = &compare_want_string; constraint->execute = &test_want; constraint->name = "equal string"; constraint->destroy = &destroy_string_constraint; constraint->expected_value_message = "\t\texpected to equal:\t\t[\"%s\"]"; return constraint; } Constraint *create_not_equal_to_string_constraint(const char* expected_value, const char *expected_value_name) { Constraint *constraint = create_constraint_expecting(make_cgreen_string_value(expected_value), expected_value_name); constraint->type = CGREEN_STRING_COMPARER_CONSTRAINT; constraint->compare = &compare_do_not_want_string; constraint->execute = &test_want; constraint->name = "not equal string"; constraint->destroy = &destroy_string_constraint; constraint->expected_value_message = "\t\texpected to not equal:\t[\"%s\"]"; return constraint; } Constraint *create_contains_string_constraint(const char* expected_value, const char *expected_value_name) { Constraint *constraint = create_constraint_expecting(make_cgreen_string_value(expected_value), expected_value_name); constraint->type = CGREEN_STRING_COMPARER_CONSTRAINT; constraint->compare = &compare_want_substring; constraint->execute = &test_want; constraint->name = "contain string"; constraint->destroy = &destroy_string_constraint; constraint->expected_value_message = "\t\texpected to contain:\t\t[\"%s\"]"; return constraint; } Constraint *create_does_not_contain_string_constraint(const char* expected_value, const char *expected_value_name) { Constraint *constraint = create_constraint_expecting(make_cgreen_string_value(expected_value), expected_value_name); constraint->type = CGREEN_STRING_COMPARER_CONSTRAINT; constraint->compare = &compare_do_not_want_substring; constraint->execute = &test_want; constraint->name = "not contain string"; constraint->destroy = &destroy_string_constraint; constraint->expected_value_message = "\t\texpected to not contain:\t[\"%s\"]"; return constraint; } Constraint *create_begins_with_string_constraint(const char* expected_value, const char *expected_value_name) { Constraint *constraint = create_constraint_expecting(make_cgreen_string_value(expected_value), expected_value_name); constraint->type = CGREEN_STRING_COMPARER_CONSTRAINT; constraint->compare = &compare_want_beginning_of_string; constraint->execute = &test_want; constraint->name = "begin with string"; constraint->destroy = &destroy_string_constraint; constraint->expected_value_message = "\t\texpected to begin with:\t\t[\"%s\"]"; return constraint; } Constraint *create_does_not_begin_with_string_constraint(const char* expected_value, const char *expected_value_name) { Constraint *constraint = create_constraint_expecting(make_cgreen_string_value(expected_value), expected_value_name); constraint->type = CGREEN_STRING_COMPARER_CONSTRAINT; constraint->compare = &compare_do_not_want_beginning_of_string; constraint->execute = &test_want; constraint->name = "not begin with string"; constraint->destroy = &destroy_string_constraint; constraint->expected_value_message = "\t\texpected to not begin with:\t[\"%s\"]"; return constraint; } Constraint *create_ends_with_string_constraint(const char* expected_value, const char *expected_value_name) { Constraint *constraint = create_constraint_expecting(make_cgreen_string_value(expected_value), expected_value_name); constraint->type = CGREEN_STRING_COMPARER_CONSTRAINT; constraint->compare = &compare_want_end_of_string; constraint->execute = &test_want; constraint->name = "end with string"; constraint->destroy = &destroy_string_constraint; constraint->expected_value_message = "\t\texpected to end with:\t\t[\"%s\"]"; return constraint; } Constraint *create_does_not_end_with_string_constraint(const char* expected_value, const char *expected_value_name) { Constraint *constraint = create_constraint_expecting(make_cgreen_string_value(expected_value), expected_value_name); constraint->type = CGREEN_STRING_COMPARER_CONSTRAINT; constraint->compare = &compare_do_not_want_end_of_string; constraint->execute = &test_want; constraint->name = "not end with string"; constraint->destroy = &destroy_string_constraint; constraint->expected_value_message = "\t\texpected to not end with:\t[\"%s\"]"; return constraint; } Constraint *create_equal_to_double_constraint(double expected_value, const char *expected_value_name) { Constraint *constraint = create_constraint_expecting(make_cgreen_double_value(expected_value), expected_value_name); constraint->type = CGREEN_DOUBLE_COMPARER_CONSTRAINT; constraint->compare = &compare_want_double; constraint->execute = &test_want_double; constraint->name = "equal double"; constraint->destroy = &destroy_double_constraint; return constraint; } Constraint *create_not_equal_to_double_constraint(double expected_value, const char *expected_value_name) { Constraint *constraint = create_constraint_expecting(make_cgreen_double_value(expected_value), expected_value_name); constraint->type = CGREEN_DOUBLE_COMPARER_CONSTRAINT; constraint->compare = &compare_do_not_want_double; constraint->execute = &test_do_not_want_double; constraint->name = "not equal double"; constraint->destroy = &destroy_double_constraint; return constraint; } Constraint *create_less_than_double_constraint(double expected_value, const char *expected_value_name) { Constraint *constraint = create_constraint_expecting(make_cgreen_double_value(expected_value), expected_value_name); constraint->type = CGREEN_DOUBLE_COMPARER_CONSTRAINT; constraint->compare = &compare_want_lesser_double; constraint->execute = &test_true; constraint->name = "be less than double"; constraint->destroy = &destroy_double_constraint; constraint->expected_value_message = "\t\texpected to be less than:\t[%08f]"; return constraint; } Constraint *create_greater_than_double_constraint(double expected_value, const char *expected_value_name) { Constraint *constraint = create_constraint_expecting(make_cgreen_double_value(expected_value), expected_value_name); constraint->type = CGREEN_DOUBLE_COMPARER_CONSTRAINT; constraint->compare = &compare_want_greater_double; constraint->execute = &test_true; constraint->name = "be greater than double"; constraint->destroy = &destroy_double_constraint; constraint->expected_value_message = "\t\texpected to be greater than:\t[%08f]"; return constraint; } Constraint *create_return_value_constraint(intptr_t value_to_return) { Constraint* constraint = create_constraint(); constraint->type = CGREEN_RETURN_VALUE_CONSTRAINT; constraint->compare = &compare_true; constraint->execute = &test_true; constraint->name = "return value"; constraint->expected_value = make_cgreen_integer_value(value_to_return); return constraint; } Constraint *create_return_by_value_constraint(intptr_t value_to_return, size_t size) { intptr_t actual_return = (intptr_t) malloc(size); memcpy((void*)actual_return, (void*)value_to_return, size); Constraint* constraint = create_constraint(); constraint->type = CGREEN_RETURN_BY_VALUE_CONSTRAINT; constraint->compare = &compare_true; constraint->execute = &test_true; constraint->name = "return by value"; constraint->expected_value = make_cgreen_by_value((void*)actual_return, size); constraint->destroy = &destroy_by_value_constraint; return constraint; } Constraint *create_return_double_value_constraint(double value_to_return) { Constraint* constraint = create_constraint(); constraint->type = CGREEN_RETURN_VALUE_CONSTRAINT; constraint->compare = &compare_true; constraint->execute = &test_true; constraint->name = "return value"; constraint->expected_value = make_cgreen_double_value(value_to_return); return constraint; } Constraint *create_set_parameter_value_constraint(const char *parameter_name, intptr_t value_to_set, size_t size_to_set) { Constraint* constraint = create_constraint(); constraint->type = CGREEN_CONTENT_SETTER_CONSTRAINT; constraint->compare = &compare_true; constraint->execute = &set_contents; constraint->name = "set parameter value"; constraint->expected_value = make_cgreen_integer_value(value_to_set); constraint->size_of_expected_value = size_to_set; constraint->parameter_name = parameter_name; return constraint; } Constraint *create_with_side_effect_constraint(void (*callback)(void *), void *data) { Constraint* constraint = create_constraint(); constraint->type = CGREEN_CALL_CONSTRAINT; constraint->name = "cause side effect"; constraint->side_effect_callback = callback; constraint->side_effect_data = data; constraint->execute = &execute_sideeffect; return constraint; } Constraint *create_capture_parameter_constraint(const char *parameter_name, void *capture_to, size_t size_to_capture) { Constraint* constraint = create_constraint(); constraint->type = CGREEN_CAPTURE_PARAMETER_CONSTRAINT; constraint->compare = &compare_true; constraint->execute = &capture_parameter; constraint->name = "capture parameter"; constraint->expected_value = make_cgreen_pointer_value(capture_to); constraint->size_of_expected_value = size_to_capture; constraint->parameter_name = parameter_name; return constraint; } bool compare_want_value(Constraint *constraint, CgreenValue actual) { return constraint->expected_value.value.integer_value == actual.value.integer_value; } bool compare_do_not_want_value(Constraint *constraint, CgreenValue actual) { return !compare_want_value(constraint, actual); } bool compare_want_greater_value(Constraint *constraint, CgreenValue actual) { return actual.value.integer_value > constraint->expected_value.value.integer_value ; } bool compare_want_lesser_value(Constraint *constraint, CgreenValue actual) { return actual.value.integer_value < constraint->expected_value.value.integer_value; } bool compare_want_contents(Constraint *constraint, CgreenValue actual) { /* We can't inspect the contents of a NULL pointer, so comparison always fails */ /* TODO: This should really be .pointer_value */ if ((void *)actual.value.integer_value == NULL) { return 0; } return 0 == memcmp(constraint->expected_value.value.pointer_value, (void *)actual.value.integer_value, constraint->size_of_expected_value); } bool compare_do_not_want_contents(Constraint *constraint, CgreenValue actual) { /* we can't inspect the contents of a NULL pointer, so comparison always fails */ if ((void *)actual.value.integer_value == NULL) { return 0; } return !compare_want_contents(constraint, actual); } static void set_contents(Constraint *constraint, const char *function, CgreenValue actual, const char *test_file, int test_line, TestReporter *reporter) { char *message; (void)function; /* TODO: should propagate the whole actual */ if (parameters_are_not_valid_for(constraint, actual.value.integer_value)) { message = validation_failure_message_for(constraint, actual.value.integer_value); (*reporter->assert_true)( reporter, test_file, test_line, false, message); free(message); return; } memmove((void *)actual.value.pointer_value, constraint->expected_value.value.pointer_value, constraint->size_of_expected_value); } static void execute_sideeffect(Constraint *constraint, const char *function, CgreenValue actual, const char *test_file, int test_line, TestReporter *reporter) { (void)function; (void)actual; if (constraint->side_effect_callback == NULL) { (*reporter->assert_true)( reporter, test_file, test_line, false, "no side effect function was set"); } (constraint->side_effect_callback)(constraint->side_effect_data); } #define IS_BIG_ENDIAN (!*(unsigned char *)&(uint16_t){1}) static bool bigendian(void) { return IS_BIG_ENDIAN; } static void capture_parameter(Constraint *constraint, const char *function, CgreenValue actual, const char *test_file, int test_line, TestReporter *reporter) { (void)function; (void)test_file; (void)test_line; (void)reporter; if ((sizeof(intptr_t) != constraint->size_of_expected_value) && bigendian()) { // Then the beginning of a smaller value is not stored at the beginning of the actual.value union size_t offset = sizeof(intptr_t) - constraint->size_of_expected_value; // Offset is in bytes so we need to cast &actual.value to that before adding the offset void *start_address = (unsigned char *)&actual.value + offset; memmove(constraint->expected_value.value.pointer_value, start_address, constraint->size_of_expected_value); } else memmove(constraint->expected_value.value.pointer_value, &actual.value, constraint->size_of_expected_value); } void test_want(Constraint *constraint, const char *function, CgreenValue actual, const char *test_file, int test_line, TestReporter *reporter) { char *message; char parameter_name_actual_string[255]; if (parameters_are_not_valid_for(constraint, actual.value.integer_value)) { message = validation_failure_message_for(constraint, actual.value.integer_value); (*reporter->assert_true)( reporter, test_file, test_line, false, message); free(message); return; } snprintf(parameter_name_actual_string, sizeof(parameter_name_actual_string) - 1, "[%s] parameter in [%s]", constraint->parameter_name, function); message = constraint->failure_message(constraint, parameter_name_actual_string, actual.value.integer_value); (*reporter->assert_true)( reporter, test_file, test_line, (*constraint->compare)(constraint, actual), message); free(message); } static bool compare_want_string(Constraint *constraint, CgreenValue actual) { return strings_are_equal(constraint->expected_value.value.string_value, actual.value.string_value); } static bool compare_do_not_want_string(Constraint *constraint, CgreenValue actual) { return !compare_want_string(constraint, actual); } static bool compare_do_not_want_substring(Constraint *constraint, CgreenValue actual) { return !compare_want_substring(constraint, actual); } static bool compare_want_substring(Constraint *constraint, CgreenValue actual) { return string_contains(actual.value.string_value, constraint->expected_value.value.string_value); } const unsigned int NOT_FOUND = UINT_MAX; static unsigned int strpos(const char *haystack, const char *needle) { const char *offset = strstr(haystack, needle); if (offset != NULL) { return offset - haystack; } return NOT_FOUND; } static bool compare_want_beginning_of_string(Constraint *constraint, CgreenValue actual) { return strpos(actual.value.string_value, constraint->expected_value.value.string_value) == 0; } static bool compare_do_not_want_beginning_of_string(Constraint *constraint, CgreenValue actual) { return strpos(actual.value.string_value, constraint->expected_value.value.string_value) != 0; } static bool compare_want_end_of_string(Constraint *constraint, CgreenValue actual) { int match_length = strlen(constraint->expected_value.value.string_value); int start_position = strlen(actual.value.string_value) - match_length; if (start_position < 0) return false; return strcmp(&actual.value.string_value[start_position], constraint->expected_value.value.string_value) == 0; } static bool compare_do_not_want_end_of_string(Constraint *constraint, CgreenValue actual) { return !compare_want_end_of_string(constraint, actual); } // Double static bool compare_want_double(Constraint *constraint, CgreenValue actual) { return doubles_are_equal(constraint->expected_value.value.double_value, actual.value.double_value); } static bool compare_want_lesser_double(Constraint *constraint, CgreenValue actual) { return double_is_lesser(constraint->expected_value.value.double_value, actual.value.double_value); } static bool compare_want_greater_double(Constraint *constraint, CgreenValue actual) { return double_is_greater(constraint->expected_value.value.double_value, actual.value.double_value); } static void test_want_double(Constraint *constraint, const char *function, CgreenValue actual, const char *test_file, int test_line, TestReporter *reporter) { (*reporter->assert_true)( reporter, test_file, test_line, (*constraint->compare)(constraint, actual), "Wanted [%f], but got [%f] in function [%s] parameter [%s]", constraint->expected_value.value.double_value, actual.value.double_value, function, constraint->parameter_name); } static bool compare_do_not_want_double(Constraint *constraint, CgreenValue actual) { return !compare_want_double(constraint, actual); } static void test_do_not_want_double(Constraint *constraint, const char *function, CgreenValue actual, const char *test_file, int test_line, TestReporter *reporter) { (*reporter->assert_true)( reporter, test_file, test_line, (*constraint->compare)(constraint, actual), "Did not want [%f], but got [%f] in function [%s] parameter [%s]", constraint->expected_value.value.double_value, actual.value.double_value, function, constraint->parameter_name); } void destroy_double_constraint(Constraint *constraint) { destroy_empty_constraint(constraint); } void destroy_string_constraint(Constraint *constraint) { destroy_cgreen_value(constraint->expected_value); destroy_empty_constraint(constraint); } void destroy_by_value_constraint(Constraint *constraint) { // TODO: we should return the allocated area, but that conflicts with reporter printing it // Now, how does the string constraints do it? destroy_cgreen_value(constraint->expected_value); destroy_empty_constraint(constraint); } static bool compare_true(Constraint *constraint, CgreenValue actual) { (void)constraint; (void)actual; return true; } static void test_true(Constraint *constraint, const char *function, CgreenValue actual, const char *test_file, int test_line, TestReporter *reporter) { (void)constraint; (void)function; (void)actual; (void)test_file; (void)test_line; (void)reporter; } bool values_are_strings_in(const Constraint *constraint) { return is_string_comparing(constraint) && (constraint->expected_value.value.string_value != NULL); } bool no_expected_value_in(const Constraint *constraint) { return strlen(constraint->expected_value_message) == 0; } bool is_content_comparing(const Constraint *constraint) { return constraint->type == CGREEN_CONTENT_COMPARER_CONSTRAINT; } bool is_content_setting(const Constraint *constraint) { return constraint->type == CGREEN_CONTENT_SETTER_CONSTRAINT; } bool is_not_content_setting(const Constraint *constraint) { return !is_content_setting(constraint); } bool is_string_comparing(const Constraint *constraint) { return constraint->type == CGREEN_STRING_COMPARER_CONSTRAINT; } bool is_double_comparing(const Constraint *constraint) { return constraint->type == CGREEN_DOUBLE_COMPARER_CONSTRAINT; } bool is_comparing(const Constraint *constraint) { return is_string_comparing(constraint) || is_content_comparing(constraint) || is_double_comparing(constraint) || constraint->type == CGREEN_VALUE_COMPARER_CONSTRAINT || constraint->type == CGREEN_CAPTURE_PARAMETER_CONSTRAINT; } bool is_not_comparing(const Constraint *constraint) { return !is_comparing(constraint); } bool is_parameter(const Constraint *constraint) { return is_comparing(constraint) || is_content_setting(constraint); } bool constraint_is_for_parameter_in(const Constraint *constraint, const char *names) { int i; bool found = false; CgreenVector *parameter_names = create_vector_of_names(names); if (!is_parameter(constraint)) return false; for (i = 0; i < cgreen_vector_size(parameter_names); i++) { const char *mock_parameter_name = (const char *)cgreen_vector_get(parameter_names, i); if (constraint_is_for_parameter(constraint, mock_parameter_name)) { found = true; break; } } destroy_cgreen_vector(parameter_names); return found; } bool doubles_are_equal(double tried, double expected) { double abs_diff = fabs(tried - expected); if (abs_diff < absolute_tolerance) return true; return abs_diff < accuracy(significant_figures, max(fabs(tried), fabs(expected))); } bool double_is_lesser(double actual, double expected) { return expected < actual + accuracy(significant_figures, max(actual, expected)); } bool double_is_greater(double actual, double expected) { return expected > actual - accuracy(significant_figures, max(actual, expected)); } static double accuracy(int figures, double largest) { return pow(10.0, 1.0 + floor(log10(fabs(largest))) - figures); } void significant_figures_for_assert_double_are(int figures) { significant_figures = figures; } int get_significant_figures(void) { return significant_figures; } /* vim: set ts=4 sw=4 et cindent: */ cgreen-1.6.3/src/constraint_internal.h000066400000000000000000000033241450461175400200150ustar00rootroot00000000000000#ifndef CONSTRAINT_INTERNAL_H #define CONSTRAINT_INTERNAL_H #include /* constraints internal functions are used from some user level tests so must be compilable in C++ */ #ifdef __cplusplus namespace cgreen { extern "C" { #endif extern void destroy_empty_constraint(Constraint *constraint); extern void destroy_static_constraint(Constraint *constraint); extern void destroy_string_constraint(Constraint *constraint); extern void destroy_double_constraint(Constraint *constraint); extern void destroy_by_value_constraint(Constraint *constraint); extern void destroy_constraint(Constraint *); extern void destroy_constraints(va_list constraints); extern bool no_expected_value_in(const Constraint *constraint); extern bool values_are_strings_in(const Constraint *constraint); extern bool is_content_comparing(const Constraint *constraint); extern bool is_content_setting(const Constraint *constraint); extern bool is_not_content_setting(const Constraint *constraint); extern bool is_string_comparing(const Constraint *constraint); extern bool is_double_comparing(const Constraint *constraint); extern bool is_comparing(const Constraint *constraint); extern bool is_not_comparing(const Constraint *constraint); extern bool is_parameter(const Constraint *); extern bool constraint_is_not_for_parameter(const Constraint *, const char *); extern bool constraint_is_for_parameter(const Constraint *, const char *); extern bool constraint_is_for_parameter_in(const Constraint *, const char *); extern bool doubles_are_equal(double tried, double expected); extern bool double_is_lesser(double actual, double expected); extern bool double_is_greater(double actual, double expected); #ifdef __cplusplus } } #endif #endif cgreen-1.6.3/src/cpp_assertions.cpp000066400000000000000000000033631450461175400173270ustar00rootroot00000000000000#include #include #include #include #include #include #include "constraint_internal.h" namespace cgreen { void assert_that_(const char *file, int line, const char *actual_string, intptr_t actual, Constraint* constraint) { assert_core_(file, line, actual_string, actual, constraint); } void assert_that_(const char *file, int line, const char *actual_string, double actual, Constraint* constraint) { assert_that_double_(file, line, actual_string, actual, constraint); } void assert_that_(const char *file, int line, const char *actual_string, const std::string& actual, Constraint* constraint) { // if they are using a string constraint, they are almost certainly meaning to do a deep comparison if (is_string_comparing(constraint)) { assert_core_(file, line, actual_string, (intptr_t) (actual.c_str()), constraint); return; } assert_that_(file, line, actual_string, (const std::string *) (&actual), constraint); } void assert_that_(const char *file, int line, const char *actual_string, const std::string *actual, Constraint* constraint) { // if they are using a string constraint, they are almost certainly meaning to do a deep comparison if (is_string_comparing(constraint)) { assert_core_(file, line, actual_string, (intptr_t) (actual->c_str()), constraint); return; } assert_core_(file, line, actual_string, (intptr_t) actual, constraint); } } cgreen-1.6.3/src/cpp_constraint.cpp000066400000000000000000000042751450461175400173240ustar00rootroot00000000000000#include #include namespace cgreen { Constraint *create_equal_to_string_constraint(const std::string& expected_value, const char *expected_value_name) { return create_equal_to_string_constraint(expected_value.c_str(), expected_value_name); } Constraint *create_equal_to_string_constraint(const std::string* expected_value, const char *expected_value_name) { return create_equal_to_string_constraint(expected_value->c_str(), expected_value_name); } Constraint *create_not_equal_to_string_constraint(const std::string& expected_value, const char *expected_value_name) { return create_not_equal_to_string_constraint(expected_value.c_str(), expected_value_name); } Constraint *create_not_equal_to_string_constraint(const std::string* expected_value, const char *expected_value_name) { return create_not_equal_to_string_constraint(expected_value->c_str(), expected_value_name); } Constraint *create_contains_string_constraint(const std::string& expected_value, const char *expected_value_name) { return create_contains_string_constraint(expected_value.c_str(), expected_value_name); } Constraint *create_contains_string_constraint(const std::string* expected_value, const char *expected_value_name) { return create_contains_string_constraint(expected_value->c_str(), expected_value_name); } Constraint *create_does_not_contain_string_constraint(const std::string& expected_value, const char *expected_value_name) { return create_does_not_contain_string_constraint(expected_value.c_str(), expected_value_name); } Constraint *create_does_not_contain_string_constraint(const std::string* expected_value, const char *expected_value_name) { return create_does_not_contain_string_constraint(expected_value->c_str(), expected_value_name); } Constraint *create_begins_with_string_constraint(const std::string& expected_value, const char *expected_value_name) { return create_begins_with_string_constraint(expected_value.c_str(), expected_value_name); } Constraint *create_begins_with_string_constraint(const std::string* expected_value, const char *expected_value_name) { return create_begins_with_string_constraint(expected_value->c_str(), expected_value_name); } } cgreen-1.6.3/src/cute_reporter.c000066400000000000000000000135461450461175400166210ustar00rootroot00000000000000#include #include #include #include #include #include "cute_reporter_internal.h" #ifdef __ANDROID__ #include "cgreen/internal/android_headers/androidcompat.h" #endif // #ifdef __ANDROID__ typedef struct { CutePrinter *printer; CuteVPrinter *vprinter; int error_count; // For status within the test case process int previous_error; // For status outside the test case process } CuteMemo; static void cute_start_suite(TestReporter *reporter, const char *name, const int number_of_tests); static void cute_start_test(TestReporter *reporter, const char *name); static void show_fail(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments); static void show_pass(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments); static void cute_failed_to_complete(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments); static void cute_finish_test(TestReporter *reporter, const char *filename, int line, const char *message); static void cute_finish_suite(TestReporter *reporter, const char *filename, int line); void set_cute_reporter_printer(TestReporter *reporter, CutePrinter *new_printer) { CuteMemo *memo = (CuteMemo *)reporter->memo; memo->printer = new_printer; } void set_cute_reporter_vprinter(TestReporter *reporter, CuteVPrinter *new_vprinter) { CuteMemo *memo = (CuteMemo *)reporter->memo; memo->vprinter = new_vprinter; } TestReporter *create_cute_reporter(void) { CuteMemo *memo; TestReporter *reporter; reporter = create_reporter(); if (reporter == NULL) { return NULL; } memo = (CuteMemo *) malloc(sizeof(CuteMemo) + 100); if (memo == NULL) { destroy_reporter(reporter); return NULL; } reporter->memo = memo; set_cute_reporter_printer(reporter, printf); set_cute_reporter_vprinter(reporter, vprintf); reporter->start_suite = &cute_start_suite; reporter->start_test = &cute_start_test; reporter->show_fail = &show_fail; reporter->show_pass = &show_pass; reporter->show_incomplete = &cute_failed_to_complete; reporter->finish_test = &cute_finish_test; reporter->finish_suite = &cute_finish_suite; reporter->memo = memo; return reporter; } static void cute_start_suite(TestReporter *reporter, const char *name, const int number_of_tests) { reporter->passes = 0; reporter->failures = 0; reporter->skips = 0; reporter->exceptions = 0; CuteMemo *memo = (CuteMemo *)reporter->memo; reporter_start_test(reporter, name); memo->printer("#beginning %s %d\n", name, number_of_tests); } static void cute_start_test(TestReporter *reporter, const char *name) { CuteMemo *memo = (CuteMemo *) reporter->memo; memo->error_count = reporter->failures + reporter->exceptions; memo->previous_error = 0; reporter_start_test(reporter, name); memo->printer("#starting %s\n", name); } static void cute_finish_test(TestReporter *reporter, const char *filename, int line, const char *message) { CuteMemo *memo = (CuteMemo *) reporter->memo; const char *name = get_current_from_breadcrumb((CgreenBreadcrumb *)reporter->breadcrumb); reporter_finish_test(reporter, filename, line, message); if (memo->error_count == reporter->failures + reporter->exceptions) { memo->printer("#success %s OK\n", name); } } static void cute_finish_suite(TestReporter *reporter, const char *filename, int line) { const char *name = get_current_from_breadcrumb((CgreenBreadcrumb *)reporter->breadcrumb); CuteMemo *memo = (CuteMemo *)reporter->memo; reporter_finish_test(reporter, filename, line, NULL); reporter->total_passes += reporter->passes; reporter->total_failures += reporter->failures; reporter->total_skips += reporter->skips; reporter->total_exceptions += reporter->exceptions; memo->printer("#ending %s", name); if (get_breadcrumb_depth((CgreenBreadcrumb *) reporter->breadcrumb) == 0) { memo->printer(": %d pass%s, %d failure%s, %d exception%s, %d ms.\n", reporter->total_passes, reporter->total_passes == 1 ? "" : "es", reporter->total_failures, reporter->total_failures == 1 ? "" : "s", reporter->total_exceptions, reporter->total_exceptions == 1 ? "" : "s", reporter->total_duration); } else memo->printer("\n"); } static void show_fail(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments) { CuteMemo *memo = (CuteMemo *) reporter->memo; if (!memo->previous_error) { memo->printer("#failure %s", get_current_from_breadcrumb((CgreenBreadcrumb *) reporter->breadcrumb)); memo->printer(" %s:%d ", file, line); if (message == NULL) { memo->printer(""); } else { memo->vprinter(message, arguments); } memo->printer("\n"); memo->previous_error = 1; } } static void show_pass(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments) { (void) reporter; (void) file; (void) line; (void) message; (void) arguments; } static void cute_failed_to_complete(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments) { CuteMemo *memo = (CuteMemo *)reporter->memo; /* TODO: add additional message to output */ (void)file; (void)line; (void)message; (void)arguments; memo->printer("#error %s failed to complete\n", get_current_from_breadcrumb((CgreenBreadcrumb *)reporter->breadcrumb)); } /* vim: set ts=4 sw=4 et cindent: */ cgreen-1.6.3/src/cute_reporter_internal.h000066400000000000000000000007061450461175400205140ustar00rootroot00000000000000#ifndef CUTE_REPORTER_INTERNAL_H #define CUTE_REPORTER_INTERNAL_H #include #ifdef __cplusplus extern "C" { #endif typedef int CutePrinter(const char *format, ...); typedef int CuteVPrinter(const char *format, va_list arguments); extern void set_cute_reporter_printer(TestReporter *reporter, CutePrinter *printer); extern void set_cute_reporter_vprinter(TestReporter *reporter, CuteVPrinter *vprinter); #ifdef __cplusplus } #endif #endif cgreen-1.6.3/src/libxml_reporter.c000066400000000000000000000414241450461175400171440ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include "libxml_reporter_internal.h" #ifdef __ANDROID__ #include "cgreen/internal/android_headers/androidcompat.h" #endif // #ifdef __ANDROID__ typedef struct { XmlPrinter *printer; int segment_count; } XmlMemo; #define XMLSTRING(x) (BAD_CAST x) static void xml_reporter_start_suite(TestReporter *reporter, const char *name, int count); static void xml_reporter_start_test(TestReporter *reporter, const char *name); static void xml_reporter_finish_test(TestReporter *reporter, const char *filename, int line, const char *message); static void xml_reporter_finish_suite(TestReporter *reporter, const char *filename, int line); static void xml_show_skip(TestReporter *reporter, const char *file, int line); static void xml_show_fail(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments); static void xml_show_incomplete(TestReporter *reporter, const char *filename, int line, const char *message, va_list arguments); static const char *file_prefix; static int default_printer(xmlDocPtr doc); void set_libxml_reporter_printer(TestReporter *reporter, XmlPrinter *printer) { XmlMemo *memo = (XmlMemo*)reporter->memo; memo->printer = printer; } TestReporter *create_libxml_reporter(const char *prefix) { TestReporter *reporter; XmlMemo *memo; reporter = create_reporter(); if (reporter == NULL) { return NULL; } memo = (XmlMemo *) malloc(sizeof(XmlMemo)); if (memo == NULL) { destroy_reporter(reporter); return NULL; } reporter->memo = memo; memo->printer = &default_printer; file_prefix = prefix; reporter->start_suite = &xml_reporter_start_suite; reporter->start_test = &xml_reporter_start_test; reporter->show_fail = &xml_show_fail; reporter->show_skip = &xml_show_skip; reporter->show_incomplete = &xml_show_incomplete; reporter->finish_test = &xml_reporter_finish_test; reporter->finish_suite = &xml_reporter_finish_suite; return reporter; } #ifndef PATH_MAX #define PATH_MAX 4096 #endif static char suite_path[PATH_MAX]; static void print_path_separator_if_needed(int *more_segments) { if (*more_segments > 0) { strcat(suite_path, "/"); (*more_segments)--; } } static void print_path_segment_walker(const char *segment, void *void_memo) { XmlMemo *memo = (XmlMemo *)void_memo; strncat(suite_path, segment, sizeof(suite_path)-strlen(suite_path)-1); print_path_separator_if_needed(&memo->segment_count); } static void strcat_path_segment(const char *segment, void *more_segments) { (void)more_segments; if (suite_path[0] != '\0') strcat(suite_path, "-"); strncat(suite_path, segment, sizeof(suite_path)-strlen(suite_path)-1); } static void add_suite_name(const char *suite_name) { if (suite_path[0] != '\0') strcat(suite_path, "-"); strncat(suite_path, suite_name, sizeof(suite_path)-strlen(suite_path)-1); } #define NESTED_SUITE_MAX 100 struct xml_suite_context { xmlDocPtr doc; xmlNodePtr suite, curTest; FILE* outFile; uint32_t suite_duration; }; static struct xml_suite_context context_stack[NESTED_SUITE_MAX]; static int context_stack_p = 0; /* * The table below is taken from the "Non-restricted characters" section of * https://en.wikipedia.org/wiki/Valid_characters_in_XML */ static bool isNonRestrictedXMLChar(unsigned int c) { return (c == 0x09u || c == 0x0Au || c == 0x0Du || (c >= 0x20u && c <= 0x7Eu) || c == 0x85u || (c >= 0xA0u && c <= 0xD7FFu) || (c >= 0xE000u && c <= 0xFDCFu) || (c >= 0xFDF0u && c <= 0xFFFDu) || (c >= 0x10000u && c <= 0x1FFFDu) || (c >= 0x20000u && c <= 0x2FFFDu) || (c >= 0x30000u && c <= 0x3FFFDu) || (c >= 0x40000u && c <= 0x4FFFDu) || (c >= 0x50000u && c <= 0x5FFFDu) || (c >= 0x60000u && c <= 0x6FFFDu) || (c >= 0x70000u && c <= 0x7FFFDu) || (c >= 0x80000u && c <= 0x8FFFDu) || (c >= 0x90000u && c <= 0x9FFFDu) || (c >= 0xA0000u && c <= 0xAFFFDu) || (c >= 0xB0000u && c <= 0xBFFFDu) || (c >= 0xC0000u && c <= 0xCFFFDu) || (c >= 0xD0000u && c <= 0xDFFFDu) || (c >= 0xE0000u && c <= 0xEFFFDu) || (c >= 0xF0000u && c <= 0xFFFFDu) || (c >= 0x100000u && c <= 0x10FFFD)); } static bool isOverlongUTF8(unsigned int ucs, int len) { return ((ucs <= 0x7f && len > 1) || (ucs <= 0x7ff && len > 2) || (ucs <= 0xffff && len > 3) || (ucs <= 0x10ffff && len > 4)); } /* * Return a copy of the argument prepared to be used as an attribute value. * The produced result is not necessary convertable back to the original set * of bytes. */ static xmlChar* xmlEscapePropValue(const char *str) { size_t len = strlen(str); /* * The worst-case length of the output is 4 times the input length (if * every input byte has to be escaped) plus 1 for the terminating NUL * character */ size_t retLen = len * 4 + 1; xmlChar* ret = xmlMalloc(retLen), *retPos = ret, *retEnd = ret + retLen; if (!ret) { fprintf(stderr, "memory allocation failure in %s\n", __func__); exit(EXIT_FAILURE); } const unsigned char *it = (const unsigned char*)str; const unsigned char *itEnd = it + len; while (*it) { int utfLen = itEnd - it; int ucs = xmlGetUTF8Char(it, &utfLen); if (ucs != -1) { if (!isOverlongUTF8(ucs, utfLen)) { if (isNonRestrictedXMLChar(ucs)) { /* Valid UTF8 sequence of an allowed character */ while (utfLen--) *retPos++ = *it++; } else { xmlStrPrintf(retPos, retEnd - retPos, "&x%x;", ucs); } } else { /* Disallowed character or overlong UTF8, escape entire sequence */ for(int i = 0;i < utfLen;++i) { xmlStrPrintf(retPos, retEnd-retPos, "\\x%.2" PRIx8, *it); retPos += 4; ++it; } } } else { /* Invalid UTF8, escape one byte then try to parse rest of input as UTF8 again */ xmlStrPrintf(retPos, retEnd-retPos, "\\x%.2" PRIx8, *it); retPos += 4; ++it; } } *retPos = '\0'; return ret; } static void xml_reporter_start_suite(TestReporter *reporter, const char *suitename, int count) { char filename[PATH_MAX]; int segment_decrementer = reporter->breadcrumb->depth; XmlMemo *memo = (XmlMemo *)reporter->memo; if (context_stack_p >= NESTED_SUITE_MAX) abort(); struct xml_suite_context *ctx = &context_stack[context_stack_p++]; FILE *out; (void)count; /* UNUSED */ reporter->passes = 0; reporter->failures = 0; reporter->skips = 0; reporter->exceptions = 0; suite_path[0] = '\0'; walk_breadcrumb(reporter->breadcrumb, strcat_path_segment, &segment_decrementer); add_suite_name(suitename); if (snprintf(filename, sizeof(filename), "%s-%s.xml", file_prefix, suite_path) >= (int)sizeof(filename)) { fprintf(stderr, "filename truncated; exceeds PATH_MAX (= %d)\n", PATH_MAX); exit(EXIT_FAILURE); } if (memo->printer == default_printer) { // If we're really printing to files, then open one... out = fopen(filename, "w"); if (!out) { fprintf(stderr, "could not open %s: %s\r\n", filename, strerror(errno)); exit(EXIT_FAILURE); } ctx->outFile = out; } ctx->suite_duration = 0; ctx->doc = xmlNewDoc(XMLSTRING("1.0")); ctx->suite = xmlNewNode(NULL, XMLSTRING("testsuite")); xmlChar *xml_suite_path = xmlEscapePropValue(suite_path); xmlNewProp(ctx->suite, XMLSTRING("name"), xml_suite_path); xmlFree(xml_suite_path); xmlDocSetRootElement(ctx->doc, ctx->suite); reporter_start_suite(reporter, suitename, 0); } /* Accumulate output from the actual test (the "" nodes) in a file since the tests usually are run in a child processes, so there is no simple way to save output from it and then use it in the parent (start_test() and finish_test() are run from parent) */ static FILE *child_output_tmpfile; static xmlTextWriterPtr child_output_writer; static void xml_reporter_start_test(TestReporter *reporter, const char *testname) { XmlMemo *memo = (XmlMemo *)reporter->memo; struct xml_suite_context *ctx = &context_stack[context_stack_p-1]; ctx->curTest = xmlNewChild(ctx->suite, NULL, XMLSTRING("testcase"), NULL); xmlChar *xml_testname = xmlEscapePropValue(testname); xmlNewProp(ctx->curTest, XMLSTRING("name"), xml_testname); xmlFree(xml_testname); memo->segment_count = reporter->breadcrumb->depth - 1; suite_path[0] = '\0'; walk_breadcrumb(reporter->breadcrumb, print_path_segment_walker, memo); xmlChar* xml_suite_path = xmlEscapePropValue(suite_path); xmlNewProp(ctx->curTest, XMLSTRING("classname"), xml_suite_path); xmlFree(xml_suite_path); reporter_start_test(reporter, testname); child_output_tmpfile = tmpfile(); xmlOutputBufferPtr tmpfileBuf = xmlOutputBufferCreateFile(child_output_tmpfile, xmlGetCharEncodingHandler(XML_CHAR_ENCODING_UTF8)); child_output_writer = xmlNewTextWriter(tmpfileBuf); } static void xml_show_skip(TestReporter *reporter, const char *file, int line) { (void)file; (void)line; (void)reporter; xmlTextWriterStartElement(child_output_writer, XMLSTRING("skipped")); xmlTextWriterEndElement(child_output_writer); // xmlTextWriterFlush(child_output_writer); } static xmlChar* xml_secure_vprint(const char *format, va_list ap) { char buf[100]; char *msg = buf; const size_t len = sizeof(buf); va_list ap_store; va_copy(ap_store, ap); int res = vsnprintf(msg, len, format, ap_store); va_end(ap_store); if (res < 0) { fprintf(stderr, "vsnprintf failed in xml_secure_vprint: %s\n", strerror(res)); exit(EXIT_FAILURE); } if ((unsigned)res >= len) { size_t msglen = res+1; msg = malloc(msglen); if (!msg) { fprintf(stderr, "memory allocation failure in xml_secure_vprint\n"); exit(EXIT_FAILURE); } res = vsnprintf(msg, msglen, format, ap); if (res < 0) { free(msg); fprintf(stderr, "vsnprintf failed in xml_secure_vprint: %s\n", strerror(res)); exit(EXIT_FAILURE); } if ((unsigned)res >= msglen) { // What? Did format get longer while allocating msg? free(msg); fprintf(stderr, "vsnprintf failed in xml_secure_vprint: nondeterministic message length\n"); exit(EXIT_FAILURE); } } xmlChar *xml_msg = xmlEscapePropValue(msg); if (msg != buf) free(msg); return xml_msg; } static void xml_show_fail(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments) { (void)reporter; xmlTextWriterStartElement(child_output_writer, XMLSTRING("failure")); xmlChar *xml_str = xml_secure_vprint(message, arguments); xmlTextWriterWriteAttribute(child_output_writer, XMLSTRING("message"), xml_str); xmlFree(xml_str); xmlTextWriterStartElement(child_output_writer, XMLSTRING("location")); xmlChar *xml_file = xmlEscapePropValue(file); xmlTextWriterWriteAttribute(child_output_writer, XMLSTRING("file"), xml_file); xmlFree(xml_file); xmlTextWriterWriteFormatAttribute(child_output_writer, XMLSTRING("line"), "%d", line); xmlTextWriterEndElement(child_output_writer); // xmlTextWriterEndElement(child_output_writer); // xmlTextWriterFlush(child_output_writer); } static xmlAttrPtr xmlFormatProp(xmlNodePtr node, const xmlChar* name, const char *format, ...) { va_list vargs; va_start(vargs, format); xmlChar *xml_str = xml_secure_vprint(format, vargs); va_end(vargs); xmlAttrPtr attr = xmlNewProp(node, name, xml_str); xmlFree(xml_str); return attr; } static void xml_show_incomplete(TestReporter *reporter, const char *filename, int line, const char *message, va_list arguments) { (void)reporter; struct xml_suite_context *ctx = &context_stack[context_stack_p-1]; xmlNodePtr errNode = xmlNewChild(ctx->curTest, NULL, XMLSTRING("error"), NULL); xmlNewProp(errNode, XMLSTRING("type"), XMLSTRING("Fatal")); if (message) { xmlChar *xml_msg = xml_secure_vprint(message, arguments); xmlNewProp(errNode, XMLSTRING("message"), xml_msg); xmlFree(xml_msg); } else { xmlNewProp(errNode, XMLSTRING("message"), XMLSTRING("Test terminated unexpectedly, likely from a non-standard exception or Posix signal")); } xmlNodePtr locNode = xmlNewChild(errNode, NULL, XMLSTRING("location"), NULL); xmlChar *xml_filename = xmlEscapePropValue(filename); xmlNewProp(locNode, XMLSTRING("file"), xml_filename); xmlFree(xml_filename); xmlFormatProp(locNode, XMLSTRING("line"), "%d", line); } static void insert_child_results(struct xml_suite_context *ctx) { char childData[4096]; fseek(child_output_tmpfile, 0, SEEK_SET); size_t pos = 0, ret; while (!feof(child_output_tmpfile)) { ret = fread(childData+pos, 1, sizeof(childData)-pos, child_output_tmpfile); if (ferror(child_output_tmpfile)) { abort(); } pos += ret; } fclose(child_output_tmpfile); if (pos > 0) { childData[pos] = '\0'; xmlNodePtr childLst; if (xmlParseBalancedChunkMemoryRecover(ctx->doc, NULL, NULL, 0, XMLSTRING(childData), &childLst, 1) != 0) { xmlNodePtr errNode = xmlNewChild(ctx->curTest, NULL, XMLSTRING("error"), NULL); xmlNewProp(errNode, XMLSTRING("type"), XMLSTRING("Fatal")); xmlNewProp(errNode, XMLSTRING("message"), XMLSTRING("Test result XML truncated or malformed, " "likely from abnormal process termination")); } xmlAddChildList(ctx->curTest, childLst); } } static void xml_reporter_finish_test(TestReporter *reporter, const char *filename, int line, const char *message) { struct xml_suite_context *ctx = &context_stack[context_stack_p-1]; reporter_finish_test(reporter, filename, line, message); xmlFreeTextWriter(child_output_writer); xmlFormatProp(ctx->curTest, XMLSTRING("time"), "%.5f", (double)reporter->duration/(double)1000); ctx->suite_duration += reporter->duration; insert_child_results(ctx); } static void deleteEmpty(xmlNodePtr elem) { while (elem != NULL) { xmlNodePtr next = elem->next; if (xmlIsBlankNode(elem)) { xmlUnlinkNode(elem); xmlFreeNode(elem); } else if (elem->children) { deleteEmpty(elem->children); } elem = next; } } static int default_printer(xmlDocPtr doc) { struct xml_suite_context *ctx = &context_stack[context_stack_p-1]; xmlOutputBufferPtr outBuf = xmlOutputBufferCreateFile(ctx->outFile, xmlGetCharEncodingHandler(XML_CHAR_ENCODING_UTF8)); xmlSaveFormatFileTo(outBuf, doc, "UTF-8", 1); return 0; } static void xml_reporter_finish_suite(TestReporter *reporter, const char *filename, int line) { XmlMemo *memo = (XmlMemo *)reporter->memo; struct xml_suite_context *ctx = &context_stack[context_stack_p-1]; reporter_finish_suite(reporter, filename, line); reporter->total_passes += reporter->passes; reporter->total_failures += reporter->failures; reporter->total_skips += reporter->skips; reporter->total_exceptions += reporter->exceptions; xmlFormatProp(ctx->suite, XMLSTRING("failures"), "%d", reporter->failures); xmlFormatProp(ctx->suite, XMLSTRING("errors"), "%d", reporter->exceptions); xmlFormatProp(ctx->suite, XMLSTRING("skipped"), "%d", reporter->skips); xmlFormatProp(ctx->suite, XMLSTRING("time"), "%.5f", (double)ctx->suite_duration/(double)1000); deleteEmpty(ctx->suite); memo->printer(ctx->doc); xmlFreeDoc(ctx->doc); if (context_stack_p > 1) { context_stack[context_stack_p-2].suite_duration += ctx->suite_duration; } --context_stack_p; } cgreen-1.6.3/src/libxml_reporter_internal.h000066400000000000000000000005031450461175400210360ustar00rootroot00000000000000#ifndef XML_REPORTER_INTERNAL_H #define XML_REPORTER_INTERNAL_H #include #include #ifdef __cplusplus extern "C" { #endif typedef int XmlPrinter(xmlDocPtr); extern void set_libxml_reporter_printer(TestReporter *reporter, XmlPrinter *printer); #ifdef __cplusplus } #endif #endif cgreen-1.6.3/src/local_messaging.cpp000066400000000000000000000041201450461175400174120ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include namespace cgreen { extern "C" { #define message_content_size(Type) (sizeof(Type) - sizeof(long)) struct CgreenMessage { public: long type; int result; CgreenMessage() : type(0), result(0) {} CgreenMessage(const CgreenMessage& other) : type(other.type), result(other.result) {} CgreenMessage& operator=(const CgreenMessage& other) { if (this == &other) { return *this; } this->type = other.type; this->result = other.result; return *this; } }; class CgreenMessageQueue { public: CgreenMessageQueue(int tag_) : messages(), owner(0), tag(tag_) {} std::stack messages; pid_t owner; int tag; }; static std::vector queues; static int queue_count = 0; static void clean_up_messaging(void); int start_cgreen_messaging(int tag) { if (queue_count == 0) { int atexit_result = atexit(&clean_up_messaging); if (atexit_result != 0) { fprintf(stderr, "could not register clean up code\n"); return -1; } } queue_count++; queues.push_back(CgreenMessageQueue(tag)); return queue_count - 1; } void send_cgreen_message(int messaging, int result) { CgreenMessage* message = new CgreenMessage; message->type = queues[messaging].tag; message->result = result; queues[messaging].messages.push(message); //printf("push type %d result %d\n", message.type, message.result); } int receive_cgreen_message(int messaging) { if (queues[messaging].messages.empty()) { return 0; } CgreenMessage *message; queues[messaging].messages.top(); message = queues[messaging].messages.top(); fflush(stdout); queues[messaging].messages.pop(); int result = message->result; delete message; return result; } static void clean_up_messaging() { queue_count = 0; } } } // namespace cgreen /* vim: set ts=4 sw=4 et cindent: */ cgreen-1.6.3/src/memory.c000066400000000000000000000037521450461175400152450ustar00rootroot00000000000000#include #include #include "memory.h" #define MEMORY_INCREMENT 1024 struct MemoryPool_ { void** blocks; long size; long space; }; static void enlarge(MemoryPool *pool); static int move_to_front(MemoryPool *pool, void *pointer); static void move_up_one(void **blocks, long amount); MemoryPool *create_memory_pool() { MemoryPool *pool = (MemoryPool *)malloc(sizeof(MemoryPool)); if (pool == NULL) { return NULL; } pool->blocks = (void **)malloc(MEMORY_INCREMENT * sizeof(void *)); if (pool->blocks == NULL) { free(pool); return NULL; } pool->size = 0; pool->space = MEMORY_INCREMENT; return pool; } void free_memory_pool(MemoryPool *pool) { long i; for (i = 0; i < pool->size; i++) { free(pool->blocks[i]); } free(pool->blocks); free(pool); } void *memory_pool_allocate(MemoryPool *pool, size_t bytes) { enlarge(pool); return pool->blocks[pool->size++] = malloc(bytes); } void *memory_pool_reallocate(MemoryPool *pool, void *pointer, size_t bytes) { if (! move_to_front(pool, pointer)) { return NULL; } return pool->blocks[0] = realloc(pool->blocks[0], bytes); } static void enlarge(MemoryPool *pool) { if (pool->size == pool->space) { pool->blocks = (void**)realloc(pool->blocks, (pool->space + MEMORY_INCREMENT) * sizeof(void *)); pool->space += MEMORY_INCREMENT; } } static int move_to_front(MemoryPool *pool, void *pointer) { long i; for (i = 1; i < pool->size; i++) { if (pool->blocks[i] == pointer) { move_up_one(pool->blocks, i); pool->blocks[0] = pointer; return 1; } } return 0; } /* static void move_up_one(void **blocks, long amount) { */ /* if (amount == 0) { */ /* return; */ /* } */ /* // FIXME: this doesn't compile and the semantics might be wrong */ /* //memmove(blocks[0], blocks[1], (size_t)(blocks[amount] - blocks[1])); */ /* } */ cgreen-1.6.3/src/memory.h000066400000000000000000000004621450461175400152450ustar00rootroot00000000000000#ifndef MEMORY_HEADER #define MEMORY_HEADER typedef struct MemoryPool_ MemoryPool; MemoryPool *create_memory_pool(); void free_memory_pool(MemoryPool *pool); void *memory_pool_allocate(MemoryPool *pool, size_t bytes); void *memory_pool_reallocate(MemoryPool *pool, void *pointer, size_t bytes); #endif cgreen-1.6.3/src/message_formatting.c000066400000000000000000000246101450461175400176070ustar00rootroot00000000000000#include #include #include #include #ifndef __cplusplus #include #endif #include #include #include #ifdef __ANDROID__ #include "cgreen/internal/android_headers/androidcompat.h" #endif // #ifdef __ANDROID__ #ifdef _MSC_VER #include "wincompat.h" #endif #include "constraint_internal.h" // Handling of percent signs static const char *next_percent_sign(const char *s) { return strchr(s, '%'); } static size_t count_percent_signs(char const *s) { size_t count = 0; char const *p = next_percent_sign(s); while (p != NULL) { count++; p = next_percent_sign(p+1); } return count; } static char *copy_while_doubling_percent_signs(char *string, char const *original) { char *destination = string; const char *source = original; const char *next = next_percent_sign(source); for (; next != NULL; next = next_percent_sign(next+1)) { size_t len = next - source + 1; memcpy(destination, source, len); destination += len; *destination++ = '%'; source = next+1; } strcpy(destination, source); return string; } static char *double_all_percent_signs_in(const char *original) { size_t percent_count = count_percent_signs(original); char *new_string = (char *)malloc(strlen(original) + percent_count + 1); if (new_string == NULL) { return NULL; } copy_while_doubling_percent_signs(new_string, original); return new_string; } static int find_index_of_difference(void *expected, void *actual, size_t size_to_compare) { char *expectedp = expected; char *actualp = actual; while (size_to_compare--) { if (*expectedp++ != *actualp++) { return (int)((void *)actualp - actual)-1; } } return -1; } static bool actual_value_not_necessary_for(Constraint *constraint, const char *actual_string, const char *actual_value_string) { (void)constraint; // UNUSED! return strings_are_equal(actual_string, actual_value_string) || strings_are_equal(actual_string, "true") || strings_are_equal(actual_string, "false"); } bool parameters_are_not_valid_for(Constraint *constraint, intptr_t actual) { char *message = validation_failure_message_for(constraint, actual); bool not_valid = (strlen(message) > 0); free(message); return not_valid; } char *validation_failure_message_for(Constraint *constraint, intptr_t actual) { const char *name_has_incorrect_size_message = "Wanted to compare contents with [%s],\n" "\t\tbut [%ld] was given for the comparison size."; const char *null_used_for_compare_message = "Wanted to compare contents with [%s],\n" "\t\tbut NULL was used for the pointer we wanted to compare to.\n" "\t\tIf you want to explicitly check for null, use the is_null constraint instead."; const char *null_used_for_actual_message = "Wanted to compare contents of [%s] but it had a value of NULL.\n" "\t\tIf you want to explicitly check for null, use the is_null constraint instead."; size_t message_size = strlen(name_has_incorrect_size_message) + strlen(null_used_for_compare_message) + strlen(null_used_for_actual_message) + 512; // just in case char *message = (char *)malloc(message_size); memset(message, 0, message_size); // (void)function; // UNUSED! // if (function != NULL && strlen(function) > 0) { // snprintf(message, message_size - 1, "\tIn mocked function [%s]:\n", function); // } else { // snprintf(message, message_size - 1, "\tIn assertion:\n"); // } if (is_content_comparing(constraint)) { const char *as_string; if (constraint->parameter_name != NULL) { as_string = constraint->parameter_name; } else { as_string = constraint->expected_value_name; } if ((long signed)constraint->size_of_expected_value <= 0) { snprintf(message + strlen(message), message_size - strlen(message) - 1, name_has_incorrect_size_message, as_string, (long signed)constraint->size_of_expected_value); return message; } if ((void *)actual == NULL) { snprintf(message + strlen(message), message_size - strlen(message) - 1, null_used_for_compare_message, as_string); return message; } if (constraint->expected_value.value.pointer_value == NULL) { snprintf(message + strlen(message), message_size - strlen(message) - 1, null_used_for_actual_message, as_string); return message; } } return message; } static bool is_equal_to_string_constraint(Constraint *constraint) { return strstr(constraint->name, "not ") == NULL || strstr(constraint->name, "equal ") == NULL; } /* Formats for printing actual and expected values */ static const char actual_value_string_format[] = "\n\t\tactual value:\t\t\t[\"%s\"]"; static const char expected_value_string_format[] = "[%s]"; static const char constraint_as_string_format[] = "Expected [%s] to [%s]"; static const char at_offset[] = "\n\t\tat offset:\t\t\t[%d]"; static const char expected_content[] = "\n\t\t\tactual value:\t\t[0x%02x]\n\t\t\texpected value:\t\t[0x%02x]"; static void format_actual_string_value(intptr_t actual_value, char *message, size_t message_size) { snprintf(message + strlen(message), message_size - strlen(message) - 1, actual_value_string_format, (const char *)actual_value); } static void format_expected_string_value(Constraint *constraint, char *message, size_t message_size) { snprintf(message + strlen(message), message_size - strlen(message) - 1, constraint->expected_value_message, constraint->expected_value.value.string_value); } char *failure_message_for(Constraint *constraint, const char *actual_string, intptr_t actual_value) { char actual_int_value_string[32]; const char *actual_value_as_string; char *message; size_t message_size = strlen(constraint_as_string_format) + strlen(expected_value_string_format) + strlen(actual_value_string_format) + strlen(at_offset) + strlen(constraint->actual_value_message) + strlen(constraint->expected_value_message) + strlen(constraint->expected_value_name) + strlen(constraint->name) + strlen(actual_string) + 512; // just in case snprintf(actual_int_value_string, sizeof(actual_int_value_string) - 1, "%" PRIdPTR, actual_value); if (values_are_strings_in(constraint)) { message_size += strlen(constraint->expected_value.value.string_value); if (actual_value != (intptr_t)NULL) { message_size += strlen((char *)actual_value); } } message = (char *)malloc(message_size); /* if the actual value expression contains '%' we want it to survive the final expansion with arguments that happens in assert_true() */ actual_value_as_string = double_all_percent_signs_in(actual_string); /* expand the constraint with the actual value in string format... */ snprintf(message, message_size - 1, constraint_as_string_format, actual_value_as_string, constraint->name); free((void*)actual_value_as_string); if (no_expected_value_in(constraint)) { return message; } else strcat(message, " "); /* expand the expected value string for all assertions that have one... */ snprintf(message + strlen(message), message_size - strlen(message) - 1, expected_value_string_format, constraint->expected_value_name); if (actual_value_not_necessary_for(constraint, actual_string, actual_int_value_string)) { /* when the actual string and the actual value are the same, don't print both of them */ /* also, don't print "0" for false and "1" for true */ /* also, don't print expected/actual for contents constraints since that is useless */ return message; } /* for string constraints, print out the strings encountered and not their pointer values */ if (values_are_strings_in(constraint)) { format_actual_string_value(actual_value, message, message_size); if (is_equal_to_string_constraint(constraint)) { strcat(message, "\n"); format_expected_string_value(constraint, message, message_size); } /* The final string may have percent characters, so, since it is later used in a (v)printf, we have to double them */ if (next_percent_sign(message) != NULL) { char *message_with_doubled_percent_signs = double_all_percent_signs_in(message); free(message); message = message_with_doubled_percent_signs; } return message; } /* show difference for contents as a position */ if (is_content_comparing(constraint)) { int difference_index = find_index_of_difference(constraint->expected_value.value.pointer_value, (void *)actual_value, constraint->size_of_expected_value); if (difference_index != -1) { snprintf(message + strlen(message), message_size - strlen(message) - 1, at_offset, difference_index); snprintf(message + strlen(message), message_size - strlen(message) - 1, expected_content, ((char *)actual_value)[difference_index], ((char *)constraint->expected_value.value.pointer_value)[difference_index]); } return message; } /* add the actual value */ snprintf(message + strlen(message), message_size - strlen(message) - 1, constraint->actual_value_message, actual_value); /* add the expected value */ if (strstr(constraint->name, "not ") == NULL) { strcat(message, "\n"); snprintf(message + strlen(message), message_size - strlen(message) - 1, constraint->expected_value_message, constraint->expected_value.value.string_value); } return message; } cgreen-1.6.3/src/messaging.c000066400000000000000000000066141450461175400157120ustar00rootroot00000000000000#include #include #include #include #include #include #include #ifdef __ANDROID__ #include "cgreen/internal/android_headers/androidcompat.h" #endif // #ifdef __ANDROID__ #ifdef _MSC_VER #include //disable warning on windows //'getpid','write': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _getpid, _write #pragma warning(disable:4996) #else #include #endif #define message_content_size(Type) (sizeof(Type) - sizeof(long)) typedef struct CgreenMessageQueue_ { int readpipe; int writepipe; pid_t owner; int tag; } CgreenMessageQueue; typedef struct CgreenMessage_ { long type; int result; } CgreenMessage; static CgreenMessageQueue *queues = NULL; static int queue_count = 0; int get_pipe_read_handle(void) { if (queue_count) { return queues[queue_count - 1].readpipe; } return 0; } int get_pipe_write_handle(void) { if (queue_count) { return queues[queue_count - 1].writepipe; } return 0; } static void clean_up_messaging(void); int start_cgreen_messaging(int tag) { CgreenMessageQueue *tmp; int pipes[2]; int pipe_result; if (queue_count == 0) { int atexit_result = atexit(&clean_up_messaging); if (atexit_result != 0) { fprintf(stderr, "could not register clean up code\n"); return -1; } } tmp = (CgreenMessageQueue *) realloc(queues, sizeof(CgreenMessageQueue) * ++queue_count); if (tmp == NULL) { /* ignoring return value here, as the world is ending anyways */ (void)atexit(&clean_up_messaging); return -1; } queues = tmp; pipe_result = cgreen_pipe_open(pipes); if (pipe_result != 0) { fprintf(stderr, "could not create pipes\n"); return -1; } queues[queue_count - 1].readpipe = pipes[0]; queues[queue_count - 1].writepipe = pipes[1]; queues[queue_count - 1].owner = getpid(); queues[queue_count - 1].tag = tag; return queue_count - 1; } void send_cgreen_message(int messaging, int result) { CgreenMessage *message; message = (CgreenMessage *) malloc(sizeof(CgreenMessage)); if (message == NULL) { return; } memset(message, 0, sizeof(*message)); message->type = queues[messaging].tag; message->result = result; cgreen_pipe_write(queues[messaging].writepipe, message, sizeof(CgreenMessage)); // give the parent a chance to read so that failures are more likely to be output // before the child crashes sched_yield(); free(message); } int receive_cgreen_message(int messaging) { ssize_t received; int result; CgreenMessage *message = (CgreenMessage *) malloc(sizeof(CgreenMessage)); if (message == NULL) { return -1; } received = cgreen_pipe_read(queues[messaging].readpipe, message, sizeof(CgreenMessage)); result = (received > 0 ? message->result : 0); free(message); return result; } static void clean_up_messaging(void) { int i; for (i = 0; i < queue_count; i++) { if (queues[i].owner == getpid()) { cgreen_pipe_close(queues[i].readpipe); cgreen_pipe_close(queues[i].writepipe); } } free(queues); queues = NULL; queue_count = 0; } /* vim: set ts=4 sw=4 et cindent: */ cgreen-1.6.3/src/mocks.c000066400000000000000000001110171450461175400150430ustar00rootroot00000000000000#include #include #include #include #include // TODO: report PC-Lint bug about undeserved 451 #include #include #include #include #include "cgreen_value_internal.h" #include "cgreen/cgreen_value.h" #include "parameters.h" #include "constraint_internal.h" #include "utils.h" #include "runner.h" #ifdef __ANDROID__ #include "cgreen/internal/android_headers/androidcompat.h" #endif // #ifdef __ANDROID__ typedef struct RecordedExpectation_ { const char *function; const char *test_file; int test_line; int time_to_live; CgreenVector *constraints; int number_times_called; /* * Used to record the number of time this particular expectation was triggered. * The main use at this point is to ensure that never_expect only adds itself * as a successful test if it as never been called */ int times_triggered; } RecordedExpectation; const int UNLIMITED_TIME_TO_LIVE = 0x0f314159; static CgreenMockMode cgreen_mocks_are_ = strict_mocks; static CgreenVector *learned_mock_calls = NULL; static CgreenVector *successfully_mocked_calls = NULL; static CgreenVector *global_expectation_queue = NULL; static CgreenVector *create_vector_of_actuals(va_list actuals, int count); static CgreenVector *create_equal_value_constraints_for(CgreenVector *parameter_names, CgreenVector *actual_values); static CgreenVector *create_constraints_vector(void); static RecordedExpectation *create_recorded_expectation(const char *function, const char *test_file, int test_line, CgreenVector *constraints); static CgreenVector *constraints_vector_from_va_list(va_list constraints); static void destroy_expectation(RecordedExpectation *expectation); static void ensure_expectation_queue_exists(void); static void ensure_learned_mock_calls_list_exists(void); static void ensure_successfully_mocked_calls_list_exists(void); static void remove_expectation_for(const char *function); static void trigger_unfulfilled_expectations(CgreenVector *expectation_queue, TestReporter *reporter); static RecordedExpectation *find_expectation(const char *function); static void apply_any_read_only_parameter_constraints(RecordedExpectation *expectation, const char *parameter, CgreenValue actual, TestReporter* test_reporter); static void apply_any_content_setting_parameter_constraints(RecordedExpectation *expectation, const char *parameter, CgreenValue actual, TestReporter* test_reporter); static CgreenValue stored_result_or_default_for(CgreenVector* constraints); static int number_of_parameters_in(const char *parameter_list); static bool is_always_call(RecordedExpectation* expectation); static bool have_always_expectation_for(const char* function); static bool is_never_call(RecordedExpectation* expectation); static bool have_never_call_expectation_for(const char* function); static bool remove_never_call_expectation_for(const char* function); static void report_violated_never_call(TestReporter*, RecordedExpectation*); static void report_unexpected_call(TestReporter*, RecordedExpectation*); static void report_mock_parameter_name_not_found(TestReporter *test_reporter, RecordedExpectation *expectation, const char *parameter); static void destroy_expectation_if_time_to_die(RecordedExpectation *expectation); static bool is_side_effect_constraint(const Constraint *constraint); static void apply_side_effect(TestReporter *test_reporter, const RecordedExpectation *expectation, Constraint *constraint); void cgreen_mocks_are(CgreenMockMode mock_mode) { cgreen_mocks_are_ = mock_mode; } static int number_of_parameters_in(const char *parameter_list) { int count = 1; const char *current = parameter_list; if (strlen(parameter_list) == 0) return 0; while (*current != '\0') { if (*current == ',') count++; current++; } return count; } /* Not used anywhere, but might become handy so make it non-static to avoid warnings */ int number_of_parameter_constraints_in(const CgreenVector* constraints) { int i, parameters = 0; for (i = 0; i < cgreen_vector_size(constraints); i++) { Constraint *constraint = (Constraint *)cgreen_vector_get(constraints, i); if (is_comparing(constraint)) { parameters++; } } return parameters; } static void learn_mock_call_for(const char *function, const char *mock_file, int mock_line, CgreenVector *parameter_names, CgreenVector *actual_values) { CgreenVector *constraints = create_equal_value_constraints_for(parameter_names, actual_values); RecordedExpectation *expectation = create_recorded_expectation(function, mock_file, mock_line, constraints); ensure_learned_mock_calls_list_exists(); cgreen_vector_add(learned_mock_calls, (void*)expectation); } static void handle_missing_expectation_for(const char *function, const char *mock_file, int mock_line, CgreenVector *parameter_names, CgreenVector *actual_values, TestReporter *test_reporter) { RecordedExpectation *expectation; CgreenVector *no_constraints; switch (cgreen_mocks_are_) { case loose_mocks: break; case learning_mocks: learn_mock_call_for(function, mock_file, mock_line, parameter_names, actual_values); break; case strict_mocks: no_constraints = create_constraints_vector(); expectation = create_recorded_expectation(function, mock_file, mock_line, no_constraints); report_unexpected_call(test_reporter, expectation); destroy_expectation(expectation); break; } } static CgreenValue convert_boxed_double_to_cgreen_value(CgreenValue actual) { actual.type = CGREEN_DOUBLE; actual.value.double_value = unbox_double(actual.value.integer_value); return actual; } static bool parameter_is_boxed_double(CgreenVector *double_markers, int i) { return *(bool*)cgreen_vector_get(double_markers, i) == true; } static void convert_boxed_doubles_to_cgreen_values(const char *parameters, CgreenVector *actual_values) { CgreenVector *double_markers; int i; /* Since the caller must use 'box_double()' to pass doubles as arguments to 'mock()' we can know which ones are such parameters to be able to convert them to CgreenValues here */ double_markers = create_vector_of_double_markers_for(parameters); for (i = 0; i < cgreen_vector_size(double_markers); i++) { if (parameter_is_boxed_double(double_markers, i)) { CgreenValue *actual = cgreen_vector_get(actual_values, i); *actual = convert_boxed_double_to_cgreen_value(*actual); } } destroy_cgreen_vector(double_markers); } intptr_t mock_(TestReporter* test_reporter, const char *function, const char *mock_file, int mock_line, const char *parameters, ...) { va_list actuals; CgreenVector *actual_values; CgreenVector *parameter_names; int failures_before_read_only_constraints_executed; int failures_after_read_only_constraints_executed; CgreenValue stored_result; RecordedExpectation *expectation = find_expectation(function); parameter_names = create_vector_of_names(parameters); va_start(actuals, parameters); actual_values = create_vector_of_actuals(actuals, number_of_parameters_in(parameters)); va_end(actuals); convert_boxed_doubles_to_cgreen_values(parameters, actual_values); if (expectation == NULL) { handle_missing_expectation_for(function, mock_file, mock_line, parameter_names, actual_values, test_reporter); destroy_cgreen_vector(actual_values); destroy_cgreen_vector(parameter_names); return 0; } if (is_never_call(expectation)) { expectation->times_triggered++; report_violated_never_call(test_reporter, expectation); destroy_cgreen_vector(actual_values); destroy_cgreen_vector(parameter_names); return 0; } ensure_successfully_mocked_calls_list_exists(); cgreen_vector_add(successfully_mocked_calls, (void*)function); stored_result = stored_result_or_default_for(expectation->constraints); // FIXME: Should verify that return value is not a DOUBLE as `mock_()' can not // return them. There should also be a 'mock_double_()' which does the same except // returning a double. // First check all actual constraints for validity... for (int i = 0; i < cgreen_vector_size(expectation->constraints); i++) { Constraint *constraint = (Constraint *)cgreen_vector_get(expectation->constraints, i); if (constraint->type == CGREEN_CALL_COUNTER_CONSTRAINT) { expectation->number_times_called++; continue; } if (!is_parameter(constraint)) continue; if (!constraint_is_for_parameter_in(constraint, parameters)) { // if expectation parameter name isn't in parameter_names, // fail test and skip applying constraints unlikely to match report_mock_parameter_name_not_found(test_reporter, expectation, constraint->parameter_name); destroy_expectation_if_time_to_die(expectation); destroy_cgreen_vector(actual_values); destroy_cgreen_vector(parameter_names); return stored_result.value.integer_value; } } // Now we can do the read-only constraints. If read-only // constraints aren't matching, content-setting ones might corrupt // memory so apply read-only ones first, and if they don't fail, // then do the deeper constraints failures_before_read_only_constraints_executed = test_reporter->failures; for (int i = 0; i < cgreen_vector_size(parameter_names); i++) { const char* parameter_name = (const char*)cgreen_vector_get(parameter_names, i); CgreenValue actual = *(CgreenValue*)cgreen_vector_get(actual_values, i); apply_any_read_only_parameter_constraints(expectation, parameter_name, actual, test_reporter); } failures_after_read_only_constraints_executed = test_reporter->failures; // And now we can do the content setting constraints... // FIXME: this comparison doesn't work because only parent // processes' pass/fail counts are updated, and even then // only once they read from the pipe if (failures_before_read_only_constraints_executed == failures_after_read_only_constraints_executed) { for (int i = 0; i < cgreen_vector_size(parameter_names); i++) { const char* parameter_name = (const char*)cgreen_vector_get(parameter_names, i); CgreenValue actual = *(CgreenValue*)cgreen_vector_get(actual_values, i); apply_any_content_setting_parameter_constraints(expectation, parameter_name, actual, test_reporter); } } // And finally run all side effects for (int i = 0; i < cgreen_vector_size(expectation->constraints); i++) { Constraint *constraint = (Constraint *)cgreen_vector_get(expectation->constraints, i); if (is_side_effect_constraint(constraint)) { apply_side_effect(test_reporter, expectation, constraint); continue; } } destroy_cgreen_vector(parameter_names); destroy_cgreen_vector(actual_values); expectation->times_triggered++; destroy_expectation_if_time_to_die(expectation); if (stored_result.type == CGREEN_DOUBLE) { #ifdef FUTURE /* TODO: for some future version we should ensure that the user is not trying to return a double through 'mock()' when there is a 'mock_double()' available, which there isn't yet. So then return unbox_double(mock(...)); should be replaced by return mock_double(...); */ test_reporter->assert_true(test_reporter, mock_file, mock_line, false, "Mocked function [%s] have a 'will_return_double()' expectation, " "but 'mock()' cannot return doubles; Use 'mock_double()' instead", function); /* But we'll return it anyway, whatever it becomes is what he will get... */ return stored_result.value.double_value; #else /* ... but for now return a boxed double since the user is probably using return unbox_double(mock(...)); as is the standard way in 1.x */ return box_double(stored_result.value.double_value); #endif } else return stored_result.value.integer_value; } static void apply_side_effect(TestReporter *test_reporter, const RecordedExpectation *expectation, Constraint *constraint) { CgreenValue actual = {}; constraint->execute( constraint, expectation->function, actual, expectation->test_file, expectation->test_line, test_reporter); } static bool is_side_effect_constraint(const Constraint *constraint) { return constraint->type == CGREEN_CALL_CONSTRAINT; } static CgreenVector *create_vector_of_actuals(va_list actuals, int count) { int i; CgreenVector *actual_values = create_cgreen_vector(free); for (i = 0; i < count; i++) { uintptr_t actual = va_arg(actuals, uintptr_t); cgreen_vector_add(actual_values, (void*)create_cgreen_value(make_cgreen_integer_value(actual))); } return actual_values; } static Constraint *create_appropriate_equal_constraint_for(const char *parameter_name, CgreenValue actual) { Constraint *constraint; if (actual.type == CGREEN_DOUBLE) constraint = create_equal_to_double_constraint(actual.value.double_value, parameter_name); else constraint = create_equal_to_value_constraint(actual.value.integer_value, parameter_name); return constraint; } static CgreenVector *create_equal_value_constraints_for(CgreenVector *parameter_names, CgreenVector *actual_values) { int i; CgreenVector *constraints = create_constraints_vector(); for (i = 0; i < cgreen_vector_size(parameter_names); i++) { const char* parameter_name = (const char*)cgreen_vector_get(parameter_names, i); CgreenValue actual = *(CgreenValue*)cgreen_vector_get(actual_values, i); Constraint *constraint = create_appropriate_equal_constraint_for(parameter_name, actual); cgreen_vector_add(constraints, constraint); } return constraints; } Constraint *when_(const char *parameter, Constraint* constraint) { constraint->parameter_name = parameter; return constraint; } void test_times_called(Constraint *constraint, const char *function, CgreenValue actual, const char *test_file, int test_line, TestReporter *reporter) { char *message; char parameter_name_actual_string[255]; snprintf(parameter_name_actual_string, sizeof(parameter_name_actual_string) - 1, "%s", function); message = constraint->failure_message(constraint, parameter_name_actual_string, actual.value.integer_value); (*reporter->assert_true)( reporter, test_file, test_line, (*constraint->compare)(constraint, actual), message); free(message); } Constraint *times_(const int number_times_called) { Constraint * time_constraint = create_constraint(); time_constraint->expected_value = make_cgreen_integer_value(number_times_called); time_constraint->expected_value_name = string_dup("times"); time_constraint->type = CGREEN_CALL_COUNTER_CONSTRAINT; time_constraint->compare = &compare_want_value; time_constraint->execute = &test_times_called; time_constraint->name = "be called"; time_constraint->size_of_expected_value = sizeof(intptr_t); time_constraint->expected_value_message = "\t\texpected to have been called:\t[%" PRIdPTR "] times"; return time_constraint; } static void destroy_expectation_if_time_to_die(RecordedExpectation *expectation) { if (is_always_call(expectation)) { return; } /* TODO: expectation->decrement_time_to_live_if_necessary(); if (expectation->time_to_die()) { ... } */ expectation->time_to_live--; if (expectation->time_to_live <= 0) { remove_expectation_for(expectation->function); destroy_expectation(expectation); } } void expect_(TestReporter* test_reporter, const char *function, const char *test_file, int test_line, ...) { va_list constraints; RecordedExpectation *expectation; CgreenVector *constraints_vector; if (have_always_expectation_for(function)) { test_reporter->assert_true( test_reporter, test_file, test_line, false, "Mocked function [%s] already has an expectation that it will always be called a certain way; " "any expectations declared after an always expectation are invalid", function); va_start(constraints, test_line); destroy_constraints(constraints); va_end(constraints); return; } if (have_never_call_expectation_for(function)) { remove_never_call_expectation_for(function); test_reporter->assert_true( test_reporter, test_file, test_line, false, "Mocked function [%s] already has an expectation that it will never be called; " "any expectations declared after a never call expectation are invalid", function); va_start(constraints, test_line); destroy_constraints(constraints); va_end(constraints); return; } va_start(constraints, test_line); constraints_vector = constraints_vector_from_va_list(constraints); expectation = create_recorded_expectation(function, test_file, test_line, constraints_vector); va_end(constraints); expectation->time_to_live = 1; for (int i = 0 ; i < cgreen_vector_size(expectation->constraints) ; i++) { Constraint * constraint = cgreen_vector_get(expectation->constraints, i); if (constraint && constraint->type == CGREEN_CALL_COUNTER_CONSTRAINT) { expectation->time_to_live = (int)constraint->expected_value.value.integer_value; break; } } cgreen_vector_add(global_expectation_queue, expectation); } void always_expect_(TestReporter* test_reporter, const char *function, const char *test_file, int test_line, ...) { va_list constraints; RecordedExpectation *expectation; CgreenVector *constraints_vector; if (have_always_expectation_for(function)) { test_reporter->assert_true( test_reporter, test_file, test_line, false, "Mocked function [%s] already has an expectation and will always be called a certain way; " "any expectations declared after an always expectation are discarded", function); va_start(constraints, test_line); destroy_constraints(constraints); va_end(constraints); return; } if (have_never_call_expectation_for(function)) { remove_never_call_expectation_for(function); test_reporter->assert_true( test_reporter, test_file, test_line, false, "Mocked function [%s] already has an expectation that it will never be called; " "any expectations declared after a never call expectation are discarded", function); va_start(constraints, test_line); destroy_constraints(constraints); va_end(constraints); return; } va_start(constraints, test_line); constraints_vector = constraints_vector_from_va_list(constraints); expectation = create_recorded_expectation(function, test_file, test_line, constraints_vector); va_end(constraints); expectation->time_to_live = UNLIMITED_TIME_TO_LIVE; cgreen_vector_add(global_expectation_queue, expectation); } void never_expect_(TestReporter* test_reporter, const char *function, const char *test_file, int test_line, ...) { va_list constraints; RecordedExpectation *expectation; CgreenVector *constraints_vector; if (have_always_expectation_for(function)) { test_reporter->assert_true( test_reporter, test_file, test_line, false, "Mocked function [%s] already has an expectation and will always be called a certain way; " "declaring an expectation after an always expectation is not allowed", function); va_start(constraints, test_line); destroy_constraints(constraints); va_end(constraints); return; } if (have_never_call_expectation_for(function)) { remove_never_call_expectation_for(function); test_reporter->assert_true( test_reporter, test_file, test_line, false, "Mocked function [%s] already has an expectation that it will never be called; " "declaring an expectation for a function after a never call expectation is not allowed", function); va_start(constraints, test_line); destroy_constraints(constraints); va_end(constraints); return; } va_start(constraints, test_line); constraints_vector = constraints_vector_from_va_list(constraints); expectation = create_recorded_expectation(function, test_file, test_line, constraints_vector); expectation->time_to_live = -UNLIMITED_TIME_TO_LIVE; cgreen_vector_add(global_expectation_queue, expectation); } static void report_violated_never_call(TestReporter *test_reporter, RecordedExpectation* expectation) { test_reporter->assert_true( test_reporter, expectation->test_file, expectation->test_line, false, "Mocked function [%s] has an expectation that it will never be called, but it was", expectation->function); } static bool successfully_mocked_call(const char *function_name) { int i; for (i = 0; i < cgreen_vector_size(successfully_mocked_calls); i++) { const char *successfully_mocked_function_name = (const char *)cgreen_vector_get(successfully_mocked_calls, i); if (strcmp(successfully_mocked_function_name, function_name) == 0) { return true; } } return false; } static void report_unexpected_call(TestReporter *test_reporter, RecordedExpectation* expectation) { const char *message; if (successfully_mocked_call(expectation->function)) { message = "Mocked function [%s] was called too many times"; } else { message = "Mocked function [%s] did not have an expectation that it would be called"; } test_reporter->assert_true( test_reporter, current_test->filename, current_test->line, false, message, expectation->function); } void clear_mocks(void) { if (global_expectation_queue != NULL) { destroy_cgreen_vector(global_expectation_queue); global_expectation_queue = NULL; } if (learned_mock_calls != NULL) { int i; for (i = 0; i < cgreen_vector_size(learned_mock_calls); i++) { RecordedExpectation *expectation = (RecordedExpectation*)cgreen_vector_get(learned_mock_calls, i); destroy_expectation(expectation); } destroy_cgreen_vector(learned_mock_calls); learned_mock_calls = NULL; } } static void show_breadcrumb(const char *name, void *memo) { if (*(int *) memo > 1) { fprintf(stderr, "-> "); } if (*(int *) memo > 0) { fprintf(stderr, "%s ", name); } (*(int *) memo)++; } void print_learned_mocks(void) { int e, c, i = 0; CgreenBreadcrumb *breadcrumb = get_test_reporter()->breadcrumb; walk_breadcrumb(breadcrumb, &show_breadcrumb, (void *) &i); fprintf(stderr, ": Learned mocks are\n"); if (cgreen_vector_size(learned_mock_calls) == 0) { fprintf(stderr, "\t\n"); return; } for (e = 0; e < cgreen_vector_size(learned_mock_calls); e++) { RecordedExpectation *expectation = (RecordedExpectation*)cgreen_vector_get(learned_mock_calls, e); const char *function_name = expectation->function; fprintf(stderr, "\texpect(%s", function_name); for (c = 0; c < cgreen_vector_size(expectation->constraints); c++) { Constraint *constraint = (Constraint *)cgreen_vector_get(expectation->constraints, c); if (constraint->expected_value.type == CGREEN_DOUBLE) fprintf(stderr, ", when(%s, is_equal_to_double(%f))", constraint->expected_value_name, constraint->expected_value.value.double_value); else fprintf(stderr, ", when(%s, is_equal_to(%" PRIdPTR "))", constraint->expected_value_name, constraint->expected_value.value.integer_value); } fprintf(stderr, ");\n"); } } void tally_mocks(TestReporter *reporter) { if (cgreen_mocks_are_ == learning_mocks) { print_learned_mocks(); } trigger_unfulfilled_expectations(global_expectation_queue, reporter); clear_mocks(); } static CgreenVector *create_constraints_vector(void) { return create_cgreen_vector((GenericDestructor)&destroy_constraint); } static CgreenVector *constraints_vector_from_va_list(va_list constraints) { CgreenVector *vector = create_constraints_vector(); Constraint *constraint; while ((constraint = va_arg(constraints, Constraint *)) != (Constraint *)0) { cgreen_vector_add(vector, constraint); } return vector; } static RecordedExpectation *create_recorded_expectation(const char *function, const char *test_file, int test_line, CgreenVector *constraints) { RecordedExpectation *expectation; ensure_expectation_queue_exists(); expectation = (RecordedExpectation *)malloc(sizeof(RecordedExpectation)); expectation->function = function; expectation->test_file = test_file; expectation->test_line = test_line; expectation->constraints = constraints; expectation->number_times_called = 0; expectation->times_triggered = 0; return expectation; } static void destroy_expectation(RecordedExpectation *expectation) { destroy_cgreen_vector(expectation->constraints); expectation->constraints = NULL; expectation->function = NULL; expectation->test_file = NULL; expectation->test_line = 0; expectation->time_to_live = 0; expectation->number_times_called = 0; expectation->times_triggered = 0; free(expectation); } static void ensure_successfully_mocked_calls_list_exists(void) { if (successfully_mocked_calls == NULL) { // successfully_mocked_calls are __func__, so there's nothing to destroy successfully_mocked_calls = create_cgreen_vector(NULL); } } static void ensure_learned_mock_calls_list_exists(void) { if (learned_mock_calls == NULL) { // learned_mock_calls are __func__, so there's nothing to destroy learned_mock_calls = create_cgreen_vector(NULL); } } static void ensure_expectation_queue_exists(void) { if (global_expectation_queue == NULL) { global_expectation_queue = create_cgreen_vector((GenericDestructor)&destroy_expectation); } } static void remove_expectation_for(const char *function) { int i; for (i = 0; i < cgreen_vector_size(global_expectation_queue); i++) { RecordedExpectation *expectation = (RecordedExpectation *)cgreen_vector_get(global_expectation_queue, i); if (NULL == expectation) { fprintf(stderr, "*** CGREEN: NULL expectation found -- maybe a previous incorrect removal?"); continue; } if (strcmp(expectation->function, function) == 0) { cgreen_vector_remove(global_expectation_queue, i); return; } } } static bool is_first_call_matching(RecordedExpectation *expectation) { return expectation->times_triggered == 0; } static void trigger_unfulfilled_expectations(CgreenVector *expectation_queue, TestReporter *reporter) { for (int e = 0; e < cgreen_vector_size(expectation_queue); e++) { RecordedExpectation *expectation = (RecordedExpectation *)cgreen_vector_get(expectation_queue, e); if (NULL == expectation) { fprintf(stderr, "*** NULL unfulfilled cgreen expectation found -- maybe a previous incorrect removal?"); continue; } if (is_always_call(expectation)) { continue; } if (is_never_call(expectation)) { if (is_first_call_matching(expectation)) { (*reporter->assert_true)(reporter, expectation->test_file, expectation->test_line, 1, "The mocked function [%s] was never called", expectation->function); } continue; } bool call_counter_present = false; for (int c = 0; c < cgreen_vector_size(expectation->constraints); c++) { Constraint *constraint = (Constraint *) cgreen_vector_get(expectation->constraints, c); if (constraint->type == CGREEN_CALL_COUNTER_CONSTRAINT) { constraint->execute( constraint, expectation->function, make_cgreen_integer_value(expectation->number_times_called), expectation->test_file, expectation->test_line, get_test_reporter()); call_counter_present = true; } } if (!call_counter_present) (*reporter->assert_true)( reporter, expectation->test_file, expectation->test_line, 0, "Expected call was not made to mocked function [%s]", expectation->function); } } static RecordedExpectation *find_expectation(const char *function) { int i; for (i = 0; i < cgreen_vector_size(global_expectation_queue); i++) { RecordedExpectation *expectation = (RecordedExpectation *)cgreen_vector_get(global_expectation_queue, i); if (strcmp(expectation->function, function) == 0) { return expectation; } } return NULL; } static void report_mock_parameter_name_not_found(TestReporter *test_reporter, RecordedExpectation *expectation, const char *constraint_parameter_name) { test_reporter->assert_true( test_reporter, expectation->test_file, expectation->test_line, false, "Mocked function [%s] did not define a parameter named [%s]. Did you misspell it in the expectation or forget it in the mock's argument list?", expectation->function, constraint_parameter_name); } static void apply_any_read_only_parameter_constraints(RecordedExpectation *expectation, const char *parameter, CgreenValue actual, TestReporter* test_reporter) { int i; for (i = 0; i < cgreen_vector_size(expectation->constraints); i++) { Constraint *constraint = (Constraint *)cgreen_vector_get(expectation->constraints, i); if (is_content_setting(constraint) || is_side_effect_constraint(constraint)) { continue; } /* TODO: we need to classify constraints better, now this filters on COMPARING to not execute RETURN constraints here...*/ if (constraint_is_not_for_parameter(constraint, parameter)) { continue; } constraint->execute( constraint, expectation->function, actual, expectation->test_file, expectation->test_line, test_reporter); } } static void apply_any_content_setting_parameter_constraints(RecordedExpectation *expectation, const char *parameter, CgreenValue actual, TestReporter* test_reporter) { for (int i = 0; i < cgreen_vector_size(expectation->constraints); i++) { Constraint *constraint = (Constraint *)cgreen_vector_get(expectation->constraints, i); if (constraint_is_not_for_parameter(constraint, parameter)) { continue; } if (constraint->type != CGREEN_CONTENT_SETTER_CONSTRAINT) { continue; } constraint->execute( constraint, expectation->function, actual, expectation->test_file, expectation->test_line, test_reporter); } } static CgreenValue stored_result_or_default_for(CgreenVector* constraints) { for (int i = 0; i < cgreen_vector_size(constraints); i++) { Constraint *constraint = (Constraint *)cgreen_vector_get(constraints, i); switch (constraint->type) { case CGREEN_RETURN_VALUE_CONSTRAINT: case CGREEN_RETURN_POINTER_CONSTRAINT: return constraint->expected_value; case CGREEN_RETURN_BY_VALUE_CONSTRAINT: { /* When returning a struct by value we need to copy the struct pointed out by the Cgreen pointer value so that it does not get lost when the constraint is destroyed. The user will be responsible for deallocating the copy of the struct. */ CgreenValue returnable = constraint->expected_value; void *the_struct = malloc(returnable.value_size); memcpy(the_struct, returnable.value.pointer_value, returnable.value_size); returnable.value.pointer_value = the_struct; return returnable; } default: break; } } return (CgreenValue){CGREEN_INTEGER, {0}, 0}; } static bool is_always_call(RecordedExpectation* expectation) { return expectation->time_to_live == UNLIMITED_TIME_TO_LIVE; } static bool have_always_expectation_for(const char* function) { for (int i = 0; i < cgreen_vector_size(global_expectation_queue); i++) { RecordedExpectation *expectation = (RecordedExpectation *)cgreen_vector_get(global_expectation_queue, i); if (strcmp(expectation->function, function) == 0) { if (is_always_call(expectation)) { return true; } } } return false; } static bool is_never_call(RecordedExpectation* expectation) { return expectation->time_to_live == -UNLIMITED_TIME_TO_LIVE; } static bool have_never_call_expectation_for(const char* function) { for (int i = 0; i < cgreen_vector_size(global_expectation_queue); i++) { RecordedExpectation *expectation = (RecordedExpectation *)cgreen_vector_get(global_expectation_queue, i); if (strcmp(expectation->function, function) == 0) { if (is_never_call(expectation)) { return true; } } } return false; } static bool remove_never_call_expectation_for(const char* function) { for (int i = 0; i < cgreen_vector_size(global_expectation_queue); i++) { RecordedExpectation *expectation = (RecordedExpectation *)cgreen_vector_get(global_expectation_queue, i); if (strcmp(expectation->function, function) == 0) { if (is_never_call(expectation)) { cgreen_vector_remove(global_expectation_queue, i); destroy_expectation(expectation); } } } return false; } /* vim: set ts=4 sw=4 et cindent: */ cgreen-1.6.3/src/parameters.c000066400000000000000000000103171450461175400160730ustar00rootroot00000000000000#include #include #include #include #include #include "parameters.h" static char *tokenise_by_commas_and_whitespace(char *list); static char *skip_nulls_until(char *pointer, char *pointer_end); static char *end_of_token(char *token); static char *strip_function_from(char *token, const char *function_name); static bool begins_with(char *token, const char *beginning); static char *stringdup(const char *string) { return strcpy((char *)malloc(strlen(string)+1), string); } CgreenVector *create_vector_of_names(const char *parameters) { char *parameters_to_tokenize; char *parameters_end; char *tokens; char *token; CgreenVector *names = create_cgreen_vector(&free); if ((parameters == NULL) || (strlen(parameters) == 0)) { return names; } parameters_to_tokenize = stringdup(parameters); if (parameters_to_tokenize == NULL) { return names; } parameters_end = parameters_to_tokenize + strlen(parameters_to_tokenize); tokens = tokenise_by_commas_and_whitespace(parameters_to_tokenize); token = tokens; while (token < tokens + strlen(parameters)) { token = skip_nulls_until(token, parameters_end); int length_of_token = strlen(token); token = strip_function_from(token, "box_double"); token = strip_function_from(token, "d"); cgreen_vector_add(names, (void*)stringdup(token)); token += length_of_token; } free(tokens); return names; } static bool *pointer_to_bool(bool value) { bool *ptr = (bool *)malloc(sizeof(value)); *ptr = value; return ptr; } /* TODO: Much duplication ahead. This should probably be folded into the 'create_vector_of_names()' above */ CgreenVector *create_vector_of_double_markers_for(const char *parameters) { char *parameters_to_tokenize; char *parameters_end; char *tokens; char *token; CgreenVector *markers = create_cgreen_vector(&free); if ((parameters == NULL) || (strlen(parameters) == 0)) { return markers; } parameters_to_tokenize = stringdup(parameters); if (parameters_to_tokenize == NULL) { return markers; } parameters_end = parameters_to_tokenize + strlen(parameters_to_tokenize); tokens = tokenise_by_commas_and_whitespace(parameters_to_tokenize); token = tokens; while (token < tokens + strlen(parameters)) { token = skip_nulls_until(token, parameters_end); int length_of_token = strlen(token); if (begins_with(token, "box_double")) cgreen_vector_add(markers, pointer_to_bool(true)); else cgreen_vector_add(markers, pointer_to_bool(false)); token = strip_function_from(token, "box_double"); token = strip_function_from(token, "d"); token += length_of_token; } free(tokens); return markers; } static char *tokenise_by_commas_and_whitespace(char *list) { size_t i, length; for (i = 0, length = strlen(list); i < length; i++) { if (isspace((int)list[i]) || list[i] == ',') { list[i] = '\0'; } } return list; } static char *skip_nulls_until(char *pointer, char *pointer_end) { while (*pointer == '\0' && pointer < pointer_end) { pointer++; } return pointer; } static char *end_of_token(char *token) { return token + strlen(token); } static char last_char_of(char *token) { return *(end_of_token(token) - 1); } static bool begins_with(char *token, const char *beginning) { return strncmp(beginning, token, strlen(beginning)) == 0; } static void move_parameter_to_beginning_of(char *token, const char *function_name, int parameter_length) { memmove(token, token + strlen(function_name) + strlen("("), parameter_length+strlen(")")+1); *(end_of_token(token) - 1) = '\0'; } static char *strip_function_from(char *token, const char *function_name) { if (begins_with(token, function_name) && token[strlen(function_name)] == '(' && last_char_of(token) == ')') { int parameter_length = strlen(token) - strlen(function_name) - strlen("()"); move_parameter_to_beginning_of(token, function_name, parameter_length); } return token; } /* vim: set ts=4 sw=4 et cindent: */ cgreen-1.6.3/src/parameters.h000066400000000000000000000006261450461175400161020ustar00rootroot00000000000000#ifndef PARAMETERS_HEADER #define PARAMETERS_HEADER #include /* Parameters are used from some user level tests so must be compilable in C++ */ #ifdef __cplusplus namespace cgreen { extern "C" { #endif CgreenVector *create_vector_of_names(const char *parameters); CgreenVector *create_vector_of_double_markers_for(const char *parameters); #ifdef __cplusplus } } #endif #endif cgreen-1.6.3/src/posix_cgreen_pipe.c000066400000000000000000000034561450461175400174400ustar00rootroot00000000000000#include "cgreen/internal/cgreen_pipe.h" #include "utils.h" #include #include #include #include #include #include #ifdef __ANDROID__ #include "cgreen/internal/android_headers/androidcompat.h" #endif // #ifdef __ANDROID__ #ifndef O_NONBLOCK # error "Your platform does not support POSIX ASYNC pipe reads. Please report a bug to http://github.com/cgreen-devs/cgreen/issues" /* One way to do it the old way is: ioctl(fd, FIOBIO, &flags); */ #endif int cgreen_pipe_open(int pipes[2]) { int pipe_open_result; int pipe_nonblock_result; pipe_open_result = pipe(pipes); if (pipe_open_result != 0) { return pipe_open_result; } pipe_nonblock_result = fcntl(pipes[1], F_SETFL, O_NONBLOCK); if (pipe_nonblock_result != 0) { return pipe_open_result; } return 0; } void cgreen_pipe_close(int p) { close(p); } ssize_t cgreen_pipe_read(int p, void *buf, size_t count) { if (0 != fcntl(p, F_SETFL, O_NONBLOCK)) { fprintf(stderr, "could not set file status flag on read pipe\n"); return -1; } return read(p, buf, count); } ssize_t cgreen_pipe_write(int p, const void *buf, size_t count) { int pipe_write_result = write(p, buf, count); int status; if (pipe_write_result < 0) { if (errno == EWOULDBLOCK) { PANIC("Too many assertions within a single test."); } else if (errno != EPIPE) { PANIC("Error when reporting from test case process to reporter."); } raise(SIGPIPE); wait(&status); /* Safe-guarding against a signalhandler for SIGPIPE, which incidentally the test case for pipe block need to have... */ } return pipe_write_result; } /* vim: set ts=4 sw=4 et cindent: */ cgreen-1.6.3/src/posix_cgreen_time.c000066400000000000000000000023361450461175400174350ustar00rootroot00000000000000#include "cgreen/internal/cgreen_time.h" #include #include #include #ifdef __ANDROID__ #include "cgreen/internal/android_headers/androidcompat.h" #endif // #ifdef __ANDROID__ /* TODO: this should really be handle by CMake config... */ #if defined(__FreeBSD__) || defined(__linux__) || defined(__APPLE__) || defined(__CYGWIN__) || defined(__OpenBSD__) # include # define HAVE_GETTIMEOFDAY 1 #else # error "Your POSIX platform does not support gettimeofday(). Please report a bug to http://github.com/cgreen-devs/cgreen/issues" #endif #if defined(HAVE_GETTIMEOFDAY) uint32_t cgreen_time_get_current_milliseconds(void) { #ifdef __CYGWIN__ /* TODO: This is actually the POSIX recommended way to do this */ struct timespec ts; if (clock_gettime(CLOCK_REALTIME, &ts) != 0) { fprintf(stderr, "cgreen error: could not get time\n"); return 0; } return ts.tv_sec * 1000u + ts.tv_nsec / 1000000u; #else struct timeval tv; if (gettimeofday(&tv, NULL) != 0) { fprintf(stderr, "cgreen error: could not get time of day\n"); return 0; } return tv.tv_sec * 1000u + tv.tv_usec / 1000u; #endif } #endif /* vim: set ts=4 sw=4 et cindent: */ cgreen-1.6.3/src/posix_runner_platform.c000066400000000000000000000062401450461175400203670ustar00rootroot00000000000000#ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifndef __ANDROID__ #include "config.h" #endif // #ifdef __ANDROID__ #include "runner.h" #include "cgreen/internal/runner_platform.h" #include #include #include #include #include #include #include #include #ifdef __ANDROID__ #include "cgreen/internal/android_headers/androidcompat.h" #endif // #ifdef __ANDROID__ typedef void (*sighandler_t)(int); static int in_child_process(void); static int wait_for_child_process(void); static void stop(void); static void ignore_ctrl_c(void); static void allow_ctrl_c(void); void run_test_in_its_own_process(TestSuite *suite, CgreenTest *test, TestReporter *reporter) { uint32_t test_starting_milliseconds = cgreen_time_get_current_milliseconds(); (*reporter->start_test)(reporter, test->name); if (test->skip) { send_reporter_skipped_notification(reporter); (*reporter->finish_test)(reporter, test->filename, test->line, NULL); } else if (in_child_process()) { run_the_test_code(suite, test, reporter); send_reporter_completion_notification(reporter); stop(); } else { const int status = wait_for_child_process(); reporter->duration = cgreen_time_duration_in_milliseconds(test_starting_milliseconds, cgreen_time_get_current_milliseconds()); if (WIFSIGNALED(status)) { /* a C++ exception generates SIGABRT. Only print our special message for other signals. */ const int sig = WTERMSIG(status); if (sig != SIGABRT) { char buf[128]; snprintf(buf, sizeof(buf), "Test terminated with signal: %s", (const char *)strsignal(sig)); (*reporter->finish_test)(reporter, test->filename, test->line, buf); return; } } (*reporter->finish_test)(reporter, test->filename, test->line, NULL); } } static int in_child_process(void) { fflush(NULL); /* Flush all buffers before forking */ pid_t child = fork(); if (child < 0) { die("Could not fork process\n"); } return ! child; } static int wait_for_child_process(void) { int status = 0; ignore_ctrl_c(); wait(&status); allow_ctrl_c(); return status; } void die_in(unsigned int seconds) { sighandler_t signal_result = signal(SIGALRM, (sighandler_t)&stop); if (SIG_ERR == signal_result) { fprintf(stderr, "could not set alarm signal handler\n"); return; } alarm(seconds); } void run_specified_test_if_child(TestSuite *suite, TestReporter *reporter){ //not needed for systems that support fork() (void)suite; (void)reporter; } static void stop(void) { #ifdef CGREEN_INTERNAL_WITH_GCOV if (1) #else if (getenv("CGREEN_CHILD_EXIT_WITH__EXIT") == NULL) #endif exit(EXIT_SUCCESS); else _exit(EXIT_SUCCESS); } static void ignore_ctrl_c(void) { signal(SIGINT, SIG_IGN); } static void allow_ctrl_c(void) { signal(SIGINT, SIG_DFL); } /* vim: set ts=4 sw=4 et cindent: */ cgreen-1.6.3/src/reporter.c000066400000000000000000000155671450461175400156060ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include enum { pass = 1, fail, skipped ,completion, exception }; enum { FINISH_NOTIFICATION_RECEIVED = 0, FINISH_TEST_SKIPPED, FINISH_NOTIFICATION_NOT_RECEIVED }; struct TestContext_ { TestReporter *reporter; }; typedef struct TestContext_ TestContext; static TestContext context; static void show_pass(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments); static void show_skip(TestReporter *reporter, const char *file, int line); static void show_fail(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments); static void show_incomplete(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments); static void assert_true(TestReporter *reporter, const char *file, int line, int result, const char *message, ...); static int read_reporter_results(TestReporter *reporter); TestReporter *get_test_reporter(void) { return context.reporter; } void setup_reporting(TestReporter *reporter) { reporter->ipc = start_cgreen_messaging(45); context.reporter = reporter; } void set_reporter_options(TestReporter *reporter, void *options) { /* We should really copy the options locally to avoid caller to free the area, but we don't know the size of it... */ reporter->options = options; } TestReporter *create_reporter(void) { CgreenBreadcrumb *breadcrumb; TestReporter *reporter = (TestReporter *) malloc(sizeof(TestReporter)); if (reporter == NULL) { return NULL; } breadcrumb = create_breadcrumb(); if (breadcrumb == NULL) { free(reporter); return NULL; } reporter->destroy = &destroy_reporter; reporter->start_suite = &reporter_start_suite; reporter->start_test = &reporter_start_test; reporter->show_pass = &show_pass; reporter->show_skip = &show_skip; reporter->show_fail = &show_fail; reporter->show_incomplete = &show_incomplete; reporter->assert_true = &assert_true; reporter->finish_test = &reporter_finish_test; reporter->finish_suite = &reporter_finish_suite; reporter->passes = 0; reporter->skips = 0; reporter->failures = 0; reporter->exceptions = 0; reporter->duration = 0; reporter->total_passes = 0; reporter->total_skips = 0; reporter->total_failures = 0; reporter->total_exceptions = 0; reporter->total_duration = 0; reporter->breadcrumb = breadcrumb; reporter->memo = NULL; reporter->options = NULL; return reporter; } void destroy_reporter(TestReporter *reporter) { destroy_breadcrumb((CgreenBreadcrumb *)reporter->breadcrumb); destroy_memo((TestReportMemo *)reporter->memo); free(reporter); // hack to allow destroy_reporter to be called in reporter_tests when // tests are running in same process if (context.reporter == reporter) { context.reporter = NULL; } } void destroy_memo(TestReportMemo *memo) { if (NULL != memo) { free(memo); } } void reporter_start_test(TestReporter *reporter, const char *name) { push_breadcrumb((CgreenBreadcrumb *) reporter->breadcrumb, name); } void reporter_start_suite(TestReporter *reporter, const char *name, const int count) { (void) count; push_breadcrumb((CgreenBreadcrumb *) reporter->breadcrumb, name); } void reporter_finish_test(TestReporter *reporter, const char *filename, int line, const char *message) { int status = read_reporter_results(reporter); if (status == FINISH_TEST_SKIPPED) { (*reporter->show_skip)(reporter, filename, line); } else if (status == FINISH_NOTIFICATION_NOT_RECEIVED) { va_list no_arguments; memset(&no_arguments, 0, sizeof(va_list)); reporter->exceptions++; (*reporter->show_incomplete)(reporter, filename, line, message, no_arguments); } pop_breadcrumb((CgreenBreadcrumb *)reporter->breadcrumb); } void reporter_finish_suite(TestReporter *reporter, const char *filename, int line) { (void)filename; (void)line; read_reporter_results(reporter); pop_breadcrumb((CgreenBreadcrumb *)reporter->breadcrumb); } void add_reporter_result(TestReporter *reporter, int result) { send_cgreen_message(reporter->ipc, result ? pass : fail); } void send_reporter_exception_notification(TestReporter *reporter) { send_cgreen_message(reporter->ipc, exception); } void send_reporter_skipped_notification(TestReporter *reporter) { send_cgreen_message(reporter->ipc, skipped); } void send_reporter_completion_notification(TestReporter *reporter) { send_cgreen_message(reporter->ipc, completion); } static void show_pass(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments) { (void)reporter; (void)file; (void)line; (void)message; (void)arguments; } static void show_skip(TestReporter *reporter, const char *file, int line) { (void)reporter; (void)file; (void)line; } static void show_fail(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments) { (void)reporter; (void)file; (void)line; (void)message; (void)arguments; } static void show_incomplete(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments) { (void)reporter; (void)file; (void)line; (void)message; (void)arguments; } static void assert_true(TestReporter *reporter, const char *file, int line, int result, const char *message, ...) { va_list arguments; memset(&arguments, 0, sizeof(va_list)); va_start(arguments, message); if (result) { (*reporter->show_pass)(reporter, file, line, message, arguments); } else { (*reporter->show_fail)(reporter, file, line, message, arguments); } add_reporter_result(reporter, result); va_end(arguments); } static int read_reporter_results(TestReporter *reporter) { int result; while ((result = receive_cgreen_message(reporter->ipc)) > 0) { if (result == pass) { reporter->passes++; } else if (result == skipped) { reporter->skips++; return FINISH_TEST_SKIPPED; } else if (result == fail) { reporter->failures++; } else if (result == exception) { reporter->exceptions++; } else if (result == completion) { /* TODO: this should always be the last message; if it's not, there's a bad race */ return FINISH_NOTIFICATION_RECEIVED; } } return FINISH_NOTIFICATION_NOT_RECEIVED; } /* vim: set ts=4 sw=4 et cindent: */ cgreen-1.6.3/src/runner.c000066400000000000000000000271431450461175400152460ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include "runner.h" #ifdef __ANDROID__ #include "cgreen/internal/android_headers/androidcompat.h" #endif // #ifdef __ANDROID__ // Export the current running test CgreenTest *current_test; static const char *CGREEN_PER_TEST_TIMEOUT_ENVIRONMENT_VARIABLE = "CGREEN_PER_TEST_TIMEOUT"; static void run_every_test(TestSuite *suite, TestReporter *reporter); static void run_named_test(TestSuite *suite, const char *name, TestReporter *reporter); static void run_test_in_the_current_process(TestSuite *suite, CgreenTest *test, TestReporter *reporter); static int per_test_timeout_defined(void); static int per_test_timeout_value(void); static void validate_per_test_timeout_value(void); int run_test_suite(TestSuite *suite, TestReporter *reporter) { int success; if (per_test_timeout_defined()) { validate_per_test_timeout_value(); } setup_reporting(reporter); run_every_test(suite, reporter); success = (reporter->total_failures == 0) && (reporter->total_exceptions == 0); return success ? EXIT_SUCCESS : EXIT_FAILURE; } int run_single_test(TestSuite *suite, const char *name, TestReporter *reporter) { int success; if (per_test_timeout_defined()) { validate_per_test_timeout_value(); } setup_reporting(reporter); run_named_test(suite, name, reporter); success = (reporter->total_failures == 0); return success ? EXIT_SUCCESS : EXIT_FAILURE; } static void run_every_test(TestSuite *suite, TestReporter *reporter) { int i; run_specified_test_if_child(suite, reporter); uint32_t total_test_starting_milliseconds = cgreen_time_get_current_milliseconds(); (*reporter->start_suite)(reporter, suite->name, count_tests(suite)); // Run sub-suites first for (i = 0; i < suite->size; i++) { if (suite->tests[i].type != test_function) { (*suite->setup)(); run_every_test(suite->tests[i].Runnable.suite, reporter); (*suite->teardown)(); } } // Reset counters for top-level tests reporter->passes = 0; reporter->failures = 0; reporter->skips = 0; reporter->exceptions = 0; uint32_t test_starting_milliseconds = cgreen_time_get_current_milliseconds(); // Run top-level tests for (i = 0; i < suite->size; i++) { if (suite->tests[i].type == test_function) { if (getenv("CGREEN_NO_FORK") == NULL) run_test_in_its_own_process(suite, suite->tests[i].Runnable.test, reporter); else run_test_in_the_current_process(suite, suite->tests[i].Runnable.test, reporter); } } reporter->duration = cgreen_time_duration_in_milliseconds(test_starting_milliseconds, cgreen_time_get_current_milliseconds()); reporter->total_duration = cgreen_time_duration_in_milliseconds(total_test_starting_milliseconds, cgreen_time_get_current_milliseconds()); send_reporter_completion_notification(reporter); (*reporter->finish_suite)(reporter, suite->filename, suite->line); } static void run_named_test(TestSuite *suite, const char *name, TestReporter *reporter) { int i; uint32_t total_test_starting_milliseconds = cgreen_time_get_current_milliseconds(); (*reporter->start_suite)(reporter, suite->name, count_tests(suite)); for (i = 0; i < suite->size; i++) { if (suite->tests[i].type != test_function && has_test(suite->tests[i].Runnable.suite, name)) { (*suite->setup)(); run_named_test(suite->tests[i].Runnable.suite, name, reporter); (*suite->teardown)(); } } // Reset counters for top-level tests reporter->passes = 0; reporter->failures = 0; reporter->skips = 0; reporter->exceptions = 0; uint32_t test_starting_milliseconds = cgreen_time_get_current_milliseconds(); for (i = 0; i < suite->size; i++) { if (suite->tests[i].type == test_function) { if (strcmp(suite->tests[i].name, name) == 0) { run_test_in_the_current_process(suite, suite->tests[i].Runnable.test, reporter); } } } reporter->duration = cgreen_time_duration_in_milliseconds(test_starting_milliseconds, cgreen_time_get_current_milliseconds()); reporter->total_duration = cgreen_time_duration_in_milliseconds(total_test_starting_milliseconds, cgreen_time_get_current_milliseconds()); send_reporter_completion_notification(reporter); (*reporter->finish_suite)(reporter, suite->filename, suite->line); } static void run_test_in_the_current_process(TestSuite *suite, CgreenTest *test, TestReporter *reporter) { uint32_t test_starting_milliseconds = cgreen_time_get_current_milliseconds(); (*reporter->start_test)(reporter, test->name); if (test->skip) { send_reporter_skipped_notification(reporter); } else { run_the_test_code(suite, test, reporter); reporter->duration = cgreen_time_duration_in_milliseconds(test_starting_milliseconds, cgreen_time_get_current_milliseconds()); send_reporter_completion_notification(reporter); } (*reporter->finish_test)(reporter, test->filename, test->line, NULL); } static int per_test_timeout_defined(void) { return getenv(CGREEN_PER_TEST_TIMEOUT_ENVIRONMENT_VARIABLE) != NULL; } static int per_test_timeout_value(void) { char *timeout_string; int timeout_value; if (!per_test_timeout_defined()) { die("attempt to fetch undefined value for %s\n", CGREEN_PER_TEST_TIMEOUT_ENVIRONMENT_VARIABLE); } timeout_string = getenv(CGREEN_PER_TEST_TIMEOUT_ENVIRONMENT_VARIABLE); timeout_value = atoi(timeout_string); return timeout_value; } static void validate_per_test_timeout_value(void) { int timeout = per_test_timeout_value(); if (timeout <= 0) { die("invalid value for %s environment variable: %d\n", CGREEN_PER_TEST_TIMEOUT_ENVIRONMENT_VARIABLE, timeout); } } static void run_setup_for(CgreenTest *spec) { #ifdef __cplusplus std::string message = "an exception was thrown during setup: "; try { #endif spec->context->setup(); #ifdef __cplusplus return; } catch (const std::exception &exception) { message += '['; message += exception.what(); message += ']'; } catch (const std::exception *exception) { message += '['; message += exception->what(); message += ']'; } catch (const std::string &exception_message) { message += '['; message += exception_message; message += ']'; } catch (const std::string *exception_message) { message += '['; message += *exception_message; message += ']'; } catch (const char *exception_message) { message += '['; message += exception_message; message += ']'; } catch (...) { message += "unknown exception type"; } va_list no_arguments; memset(&no_arguments, 0, sizeof(va_list)); TestReporter *reporter = get_test_reporter(); reporter->show_incomplete(reporter, spec->filename, spec->line, message.c_str(), no_arguments); send_reporter_exception_notification(reporter); #endif } static void run_teardown_for(CgreenTest *spec) { #ifdef __cplusplus std::string message = "an exception was thrown during teardown: "; try { #endif spec->context->teardown(); #ifdef __cplusplus return; } catch (const std::exception &exception) { message += '['; message += exception.what(); message += ']'; } catch (const std::exception *exception) { message += '['; message += exception->what(); message += ']'; } catch (const std::string &exception_message) { message += '['; message += exception_message; message += ']'; } catch (const std::string *exception_message) { message += '['; message += *exception_message; message += ']'; } catch (const char *exception_message) { message += '['; message += exception_message; message += ']'; } catch (...) { message += "unknown exception type"; } va_list no_arguments; memset(&no_arguments, 0, sizeof(va_list)); TestReporter *reporter = get_test_reporter(); reporter->show_incomplete(reporter, spec->filename, spec->line, message.c_str(), no_arguments); send_reporter_exception_notification(reporter); #endif } /** run() N.B. Although this is neither an API or public function, it is documented as a good place to put a breakpoint. Do not change the name or semantics of this function, it should continue to be very close to the test code. */ static void run(CgreenTest *spec) { #ifdef __cplusplus std::string message = "an exception was thrown during test: "; try { #endif current_test = spec; spec->run(); #ifdef __cplusplus return; } catch (const std::exception &exception) { message += '['; message += exception.what(); message += ']'; } catch (const std::exception *exception) { message += '['; message += exception->what(); message += ']'; } catch (const std::string &exception_message) { message += '['; message += exception_message; message += ']'; } catch (const std::string *exception_message) { message += '['; message += *exception_message; message += ']'; } catch (const char *exception_message) { message += '['; message += exception_message; message += ']'; } catch (...) { message += "unknown exception type"; } va_list no_arguments; memset(&no_arguments, 0, sizeof(va_list)); TestReporter *reporter = get_test_reporter(); reporter->show_incomplete(reporter, spec->filename, spec->line, message.c_str(), no_arguments); send_reporter_exception_notification(reporter); #endif } void run_the_test_code(TestSuite *suite, CgreenTest *spec, TestReporter *reporter) { significant_figures_for_assert_double_are(8); clear_mocks(); if (per_test_timeout_defined()) { validate_per_test_timeout_value(); die_in(per_test_timeout_value()); } // for historical reasons the suite can have a setup if (has_setup(suite)) { (*suite->setup)(); } else { if (spec->context->setup != NULL) { run_setup_for(spec); } } run(spec); // for historical reasons the suite can have a teardown if (has_teardown(suite)) { (*suite->teardown)(); } else { if (spec->context->teardown != NULL) { run_teardown_for(spec); } } tally_mocks(reporter); } void die(const char *message, ...) { va_list arguments; va_start(arguments, message); vprintf(message, arguments); va_end(arguments); exit(EXIT_FAILURE); } /* vim: set ts=4 sw=4 et cindent: */ cgreen-1.6.3/src/runner.h000066400000000000000000000000751450461175400152460ustar00rootroot00000000000000#include extern CgreenTest *current_test; cgreen-1.6.3/src/string_comparison.c000066400000000000000000000013331450461175400174660ustar00rootroot00000000000000#include #ifndef __cplusplus #include #endif #include #include bool strings_are_equal(const char* actual, const char* expected) { /* TODO: if expected is null, warn user to use appropriate non-string assert instead */ if ((actual == NULL) && (expected == NULL)) { return true; } if ((actual == NULL) || (expected == NULL)) { return false; } return (strcmp(actual, expected) == 0); } bool string_contains(const char* actual, const char* expected) { /* TODO: if expected is null, warn user */ if ((actual == NULL) || (expected == NULL)) { return false; } return (strstr(actual, expected) != NULL); } cgreen-1.6.3/src/suite.c000066400000000000000000000064621450461175400150670ustar00rootroot00000000000000#include #include #include #include #ifndef __cplusplus #include #endif #include #include #include #include "parameters.h" CgreenContext defaultContext = { /* name */ "", /* filename */ FILENAME, /* setup */ &do_nothing, /* teardown */ &do_nothing }; bool has_test(TestSuite *suite, const char *name) { int i; for (i = 0; i < suite->size; i++) { if (suite->tests[i].type == test_function) { if (strcmp(suite->tests[i].name, name) == 0) { return true; } } else if (has_test(suite->tests[i].Runnable.suite, name)) { return true; } } return false; } bool has_setup(TestSuite *suite) { return (suite->setup != &do_nothing); } bool has_teardown(TestSuite *suite) { return (suite->teardown != &do_nothing); } void do_nothing(void) { } TestSuite *create_named_test_suite_(const char *name, const char *filename, int line) { TestSuite *suite = (TestSuite *)malloc(sizeof(TestSuite)); suite->name = name; suite->filename = filename; suite->line = line; suite->tests = NULL; suite->setup = &do_nothing; suite->teardown = &do_nothing; suite->size = 0; return suite; } void destroy_test_suite(TestSuite *suiteToDestroy) { int i; for (i = 0; i < suiteToDestroy->size; i++) { UnitTest test = suiteToDestroy->tests[i]; TestSuite* suite = test.Runnable.suite; if (test_suite == test.type && suite != NULL) { suiteToDestroy->tests[i].Runnable.suite = NULL; destroy_test_suite(suite); } } if (suiteToDestroy->tests != NULL) free(suiteToDestroy->tests); free(suiteToDestroy); } void add_test_(TestSuite *suite, const char *name, CgreenTest *test) { suite->size++; suite->tests = (UnitTest *)realloc(suite->tests, sizeof(UnitTest) * suite->size); suite->tests[suite->size - 1].type = test_function; suite->tests[suite->size - 1].name = name; suite->tests[suite->size - 1].Runnable.test = test; } void add_tests_(TestSuite *suite, const char *names, ...) { CgreenVector *test_names = create_vector_of_names(names); int i; va_list tests; va_start(tests, names); for (i = 0; i < cgreen_vector_size(test_names); i++) { add_test_(suite, (char *)(cgreen_vector_get(test_names, i)), va_arg(tests, CgreenTest *)); } va_end(tests); destroy_cgreen_vector(test_names); } void add_suite_(TestSuite *owner, const char *name, TestSuite *suite) { owner->size++; owner->tests = (UnitTest *)realloc(owner->tests, sizeof(UnitTest) * owner->size); owner->tests[owner->size - 1].type = test_suite; owner->tests[owner->size - 1].name = name; owner->tests[owner->size - 1].Runnable.suite = suite; } void set_setup(TestSuite *suite, void (*set_up)(void)) { suite->setup = set_up; } void set_teardown(TestSuite *suite, void (*tear_down)(void)) { suite->teardown = tear_down; } int count_tests(TestSuite *suite) { int count = 0; int i; for (i = 0; i < suite->size; i++) { if (suite->tests[i].type == test_function) { count++; } else { count += count_tests(suite->tests[i].Runnable.suite); } } return count; } cgreen-1.6.3/src/text_reporter.c000066400000000000000000000253041450461175400166400ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "text_reporter_internal.h" #ifdef __ANDROID__ #include "cgreen/internal/android_headers/androidcompat.h" #endif // #ifdef __ANDROID__ #define GREEN "\x1b[32m" #define YELLOW "\x1b[33m" #define RED "\x1b[31m" #define MAGENTA "\x1b[35m" #define RESET "\x1b[0m" static void text_reporter_start_suite(TestReporter *reporter, const char *name, const int number_of_tests); static void text_reporter_start_test(TestReporter *reporter, const char *name); static void text_reporter_finish(TestReporter *reporter, const char *filename, int line, const char *message); static void show_fail(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments); static void show_incomplete(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments); static void show_breadcrumb(const char *name, void *memo); static void text_reporter_finish_suite(TestReporter *reporter, const char *file, int line); /* To be able to run a reporter as CUT for testing with Cgreen itself we need two reporters simultaneously, so the injected printer needs to be local to the reporter which means we must store it in the memo and use that. This requires a single printer function to be used, often printf() or similar, so any other tricks needs to be performed in char buffers so that memo->printer can do the printing. */ typedef struct { TextPrinter *printer; TextVPrinter *vprinter; int depth; } TextMemo; void set_text_reporter_printer(TestReporter *reporter, TextPrinter *new_printer) { TextMemo *memo = (TextMemo *)reporter->memo; memo->printer = new_printer; } void set_text_reporter_vprinter(TestReporter *reporter, TextVPrinter *new_vprinter) { TextMemo *memo = (TextMemo *)reporter->memo; memo->vprinter = new_vprinter; } TestReporter *create_text_reporter(void) { TextMemo *memo; TestReporter *reporter = create_reporter(); if (reporter == NULL) { return NULL; } memo = (TextMemo *)malloc(sizeof(TextMemo)); if (memo == NULL) { destroy_reporter(reporter); return NULL; } reporter->memo = memo; reporter->start_suite = &text_reporter_start_suite; reporter->start_test = &text_reporter_start_test; reporter->show_fail = &show_fail; reporter->show_incomplete = &show_incomplete; reporter->finish_test = &text_reporter_finish; reporter->finish_suite = &text_reporter_finish_suite; set_text_reporter_printer(reporter, printf); set_text_reporter_vprinter(reporter, vprintf); return reporter; } static bool have_quiet_mode(TestReporter *reporter) { return reporter->options&&((TextReporterOptions *)reporter->options)->quiet_mode; } static bool inhibit_start_suite_message(TestReporter *reporter) { return reporter->options&&((TextReporterOptions *)reporter->options)->inhibit_start_suite_message; } static bool inhibit_finish_suite_message(TestReporter *reporter) { return reporter->options&&((TextReporterOptions *)reporter->options)->inhibit_finish_suite_message; } static void text_reporter_start_suite(TestReporter *reporter, const char *name, const int number_of_tests) { TextMemo *memo = (TextMemo *)reporter->memo; reporter->passes = 0; reporter->failures = 0; reporter->skips = 0; reporter->exceptions = 0; reporter_start_test(reporter, name); if (get_breadcrumb_depth((CgreenBreadcrumb *) reporter->breadcrumb) == 1) { if (!have_quiet_mode(reporter) && !inhibit_start_suite_message(reporter)) memo->printer("Running \"%s\" (%d test%s)...\n", get_current_from_breadcrumb((CgreenBreadcrumb *) reporter->breadcrumb), number_of_tests, number_of_tests==1?"":"s"); fflush(stdout); } } static void text_reporter_start_test(TestReporter *reporter, const char *name) { reporter_start_test(reporter, name); } static void text_reporter_finish(TestReporter *reporter, const char *filename, int line, const char *message) { reporter_finish_test(reporter, filename, line, message); } static void format_count(char *buff, int count, const char *name, const char *color, const char *plural, bool use_colors) { const char *color_on = use_colors?color:""; const char *color_off = use_colors?RESET:""; sprintf(buff, "%s%d %s%s%s", count>0?color_on:"", count, name, count==1?"":plural, color_off); } static char *format_passes(int passes, bool use_colors) { static char buff[100]; format_count(buff, passes, "pass", GREEN, "es", use_colors); return buff; } static char *format_skips(int skips, bool use_colors) { static char buff[100]; format_count(buff, skips, "skipped", YELLOW, "", use_colors); return buff; } static char *format_failures(int failures, bool use_colors) { static char buff[100]; format_count(buff, failures, "failure", RED, "s", use_colors); return buff; } static char *format_exceptions(int exceptions, bool use_colors) { static char buff[100]; format_count(buff, exceptions, "exception", MAGENTA, "s", use_colors); return buff; } static char *format_duration(uint32_t duration) { static char buff[100]; snprintf(buff, sizeof(buff), " in %dms", duration); return buff; } static void insert_comma(char buf[]) { if (buf[strlen(buf)-1] != ' ') strcat(buf, ", "); } static void text_reporter_print_results(char *buf, char *prepend, int passes, int failures, int skips, int exceptions, uint32_t duration, bool use_colors) { sprintf(buf, "%s", prepend); if (passes || failures || skips || exceptions) { if (passes) strcat(buf, format_passes(passes, use_colors)); if (skips) { insert_comma(buf); strcat(buf, format_skips(skips, use_colors)); } if (failures) { insert_comma(buf); strcat(buf, format_failures(failures, use_colors)); } if (exceptions) { insert_comma(buf); strcat(buf, format_exceptions(exceptions, use_colors)); } strcat(buf, format_duration(duration)); } else { strcat(buf, "No assertions"); } } static void text_reporter_finish_suite(TestReporter *reporter, const char *file, int line) { const char *name = get_current_from_breadcrumb((CgreenBreadcrumb *) reporter->breadcrumb); bool use_colors = reporter->options && ((TextReporterOptions *)reporter->options)->use_colours; TextMemo *memo = (TextMemo *)reporter->memo; reporter_finish_suite(reporter, file, line); reporter->total_passes += reporter->passes; reporter->total_failures += reporter->failures; reporter->total_skips += reporter->skips; reporter->total_exceptions += reporter->exceptions; if (have_quiet_mode(reporter)) { if (use_colors) { memo->printer(GREEN); if (reporter->failures) memo->printer(RED); if (reporter->exceptions) memo->printer(MAGENTA); } if (reporter->exceptions) memo->printer("X"); else if (reporter->failures) memo->printer("F"); else memo->printer("."); if (use_colors) { memo->printer(RESET); } } else { char buf[1000]; char prepend[100]; sprintf(prepend, " \"%s\": ", name); text_reporter_print_results(buf, prepend, reporter->passes, reporter->failures, reporter->skips, reporter->exceptions, reporter->duration, use_colors); // Don't report top-level (pseudo-suite) if it had no asserts at all if (get_breadcrumb_depth((CgreenBreadcrumb *) reporter->breadcrumb) != 0 || (reporter->passes || reporter->failures || reporter->skips || reporter->exceptions)) { memo->printer("%s.\n", buf); } // Report totals if (get_breadcrumb_depth((CgreenBreadcrumb *) reporter->breadcrumb) == 0) { if (!have_quiet_mode(reporter) && !inhibit_finish_suite_message(reporter)) { sprintf(prepend, "Completed \"%s\": ", name); text_reporter_print_results(buf, prepend, reporter->total_passes, reporter->total_failures, reporter->total_skips, reporter->total_exceptions, reporter->total_duration, use_colors); memo->printer("%s.\n", buf); } } } } static void show_fail(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments) { TextMemo *memo = (TextMemo *)reporter->memo; if (have_quiet_mode(reporter)) memo->printer("\n"); memo->printer("%s:%d: ", file, line); memo->printer("Failure: "); memo->depth = 0; walk_breadcrumb((CgreenBreadcrumb *) reporter->breadcrumb, &show_breadcrumb, memo); memo->printer("\n\t"); // Simplify *printf statements for more robust cross-platform logging if (message == NULL) { memo->printer(""); } else { memo->vprinter(message, arguments); } memo->printer("\n"); memo->printer("\n"); fflush(NULL); } static void show_incomplete(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments) { TextMemo *memo = (TextMemo *)reporter->memo; if (have_quiet_mode(reporter)) memo->printer("\n"); /* To break line of "....." for error message parsing */ memo->printer("%s:%d: ", file, line); memo->printer("Exception: "); memo->depth = 0; walk_breadcrumb((CgreenBreadcrumb *) reporter->breadcrumb, &show_breadcrumb, memo); memo->printer("\n\t"); if (message == NULL) { memo->printer("Test terminated unexpectedly, " "likely from a non-standard exception or Posix signal"); } else { memo->vprinter(message, arguments); } memo->printer("\n"); memo->printer("\n"); fflush(NULL); } static void show_breadcrumb(const char *name, void *memo_ptr) { TextMemo *memo = (TextMemo *)memo_ptr; if (memo->depth > 1) { memo->printer("-> "); } if (memo->depth > 0) { memo->printer("%s ", name); } memo->depth++; } /* vim: set ts=4 sw=4 et cindent: */ /* Local variables: */ /* tab-width: 4 */ /* End: */ cgreen-1.6.3/src/text_reporter_internal.h000066400000000000000000000007061450461175400205400ustar00rootroot00000000000000#ifndef TEXT_REPORTER_INTERNAL_H #define TEXT_REPORTER_INTERNAL_H #include #ifdef __cplusplus extern "C" { #endif typedef int TextPrinter(const char *format, ...); typedef int TextVPrinter(const char *format, va_list arguments); extern void set_text_reporter_printer(TestReporter *reporter, TextPrinter *printer); extern void set_text_reporter_vprinter(TestReporter *reporter, TextVPrinter *vprinter); #ifdef __cplusplus } #endif #endif cgreen-1.6.3/src/utils.c000066400000000000000000000024041450461175400150660ustar00rootroot00000000000000#include "utils.h" #include #include #include #include #include bool panic_use_colours = false; /* TODO these are actually a duplicate of the ones in text_reporter.c */ #define GREEN "\x1b[32m" #define YELLOW "\x1b[33m" #define RED "\x1b[31m" #define MAGENTA "\x1b[35m" #define RESET "\x1b[0m" #include "../gitrevision.h" char *cgreen_library_version = VERSION; char *cgreen_library_revision = GITREVISION; char *string_dup(const char *string) { char *dup = (char *)malloc(strlen(string)+1); if (dup) strcpy(dup, string); return dup; } static char *panic_message_buffer = NULL; /* For unittesting */ void panic_set_output_buffer(const char *buffer) { panic_message_buffer = (char *)buffer; } void panic(const char *filename, int line, const char *fmt, ...) { va_list args; char buffer[1000]; va_start(args, fmt); sprintf(buffer, "%sCGREEN EXCEPTION%s: <%s:%d>", panic_use_colours?MAGENTA:"", panic_use_colours?RESET:"", filename, line); vsprintf(&buffer[strlen(buffer)], fmt, args); va_end(args); if (panic_message_buffer != NULL) strcpy(panic_message_buffer, buffer); else fprintf(stderr, "%s\n", buffer); } cgreen-1.6.3/src/utils.h000066400000000000000000000007631450461175400151010ustar00rootroot00000000000000#ifndef UTILS_HEADER #define UTILS_HEADER #include #include #ifdef __cplusplus namespace cgreen { extern "C" { #endif extern bool panic_use_colours; #define PANIC(...) panic(FILENAME, __LINE__, __VA_ARGS__) extern char *string_dup(const char *original); extern void panic_set_output_buffer(const char *buffer); extern void panic(const char *filename, int line, const char *fmt, ...); #ifdef __cplusplus } } #endif #endif cgreen-1.6.3/src/vector.c000066400000000000000000000043251450461175400152340ustar00rootroot00000000000000#include #include #include #include "utils.h" #ifdef __ANDROID__ #include "cgreen/internal/android_headers/androidcompat.h" #endif // #ifdef __ANDROID__ struct CgreenVector_ { int size; void (*destructor)(void *); int space; void **items; }; static void increase_space(CgreenVector *vector); CgreenVector *create_cgreen_vector(void (*destructor)(void *)) { CgreenVector *vector = (CgreenVector *)malloc(sizeof(CgreenVector)); vector->size = 0; vector->destructor = destructor; vector->space = 0; vector->items = NULL; return vector; } void destroy_cgreen_vector(CgreenVector *vector) { int i; if (vector->destructor != NULL) { for (i = 0; i < vector->size; i++) { (*vector->destructor)(vector->items[i]); } } free(vector->items); vector->items = NULL; vector->destructor = NULL; vector->size = 0; vector->space = 0; free(vector); } void cgreen_vector_add(CgreenVector *vector, void *item) { if (vector->size == vector->space) { increase_space(vector); } vector->items[vector->size] = item; vector->size++; } void *cgreen_vector_remove(CgreenVector *vector, int position) { void *item; int i; if (position < 0 || position > cgreen_vector_size(vector)) { PANIC("illegal position (%d) in vector operation", position); return NULL; } item = vector->items[position]; for (i = position; i < vector->size; i++) { vector->items[i] = vector->items[i + 1]; } vector->items[vector->size] = NULL; vector->size--; return item; } void *cgreen_vector_get(const CgreenVector *vector, int position) { if (position < 0 || position > cgreen_vector_size(vector)) { PANIC("CGREEN INTERNAL ERROR: illegal position (%d) in vector operation", position); return NULL; } return vector->items[position]; } int cgreen_vector_size(const CgreenVector *vector) { return (vector == NULL ? 0 : vector->size); } static void increase_space(CgreenVector *vector) { vector->space += 100; vector->items = (void**)realloc(vector->items, sizeof(void *) * vector->space); } /* vim: set ts=4 sw=4 et cindent: */ cgreen-1.6.3/src/win32_cgreen.h000066400000000000000000000002311450461175400162140ustar00rootroot00000000000000#ifndef WIN32_CGREEN_H #define WIN32_CGREEN_H #define CGREEN_READ_HANDLE "CGREEN_READ_HANDLE" #define CGREEN_WRITE_HANDLE "CGREEN_WRITE_HANDLE" #endif cgreen-1.6.3/src/win32_cgreen_pipe.c000066400000000000000000000044411450461175400172330ustar00rootroot00000000000000#ifdef WIN32 #include #include #include "cgreen/internal/windows_headers/wincompat.h" #include "cgreen/internal/cgreen_pipe.h" #include "win32_cgreen.h" ssize_t cgreen_pipe_read(int p, void *buf, size_t count) { DWORD bytesRead; ReadFile((HANDLE)p, buf, (DWORD)count, &bytesRead, NULL); return bytesRead; } ssize_t cgreen_pipe_write(int p, const void *buf, size_t count) { DWORD bytesWritten; WriteFile((HANDLE)p, buf, (DWORD)count, &bytesWritten, NULL); if (bytesWritten != count) { printf("failed to write %d bytes - error = %d\n",count,GetLastError()); } return bytesWritten; } int cgreen_pipe_open(int pipes[2]) { SECURITY_ATTRIBUTES saAttr = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE}; char handleString[256]; DWORD result; // Figure out if we are a child process, and if so, use the handle provided by our parent result = GetEnvironmentVariableA(CGREEN_READ_HANDLE,handleString,sizeof(handleString)); if (result) //we are a child process { pipes[0] = (int)atoi(handleString); result = GetEnvironmentVariableA(CGREEN_WRITE_HANDLE,handleString,sizeof(handleString)); pipes[1] = (int)atoi(handleString); //now that we have retrieved these handles, clear the environment variables so //that subsequent calls to this function will create new pipes //(This is needed for unit tests "will_report_beginning_and_successful_finishing_of_test" //and "will_report_failing_of_test_only_once") SetEnvironmentVariableA(CGREEN_READ_HANDLE,NULL); SetEnvironmentVariableA(CGREEN_WRITE_HANDLE,NULL); } else { HANDLE readpipe,writepipe; DWORD mode = PIPE_READMODE_BYTE | PIPE_NOWAIT; const DWORD DEFAULT_BUFFER_SIZE = 0; if (!CreatePipe(&readpipe, &writepipe, &saAttr, DEFAULT_BUFFER_SIZE)) return -1; //turn on NOWAIT if (!SetNamedPipeHandleState(readpipe,&mode,NULL,NULL)) { fprintf(stderr, "could not set file status flag on read pipe\n"); return -1; } pipes[0] = (int)readpipe; pipes[1] = (int)writepipe; } return 0; } void cgreen_pipe_close(int p) { CloseHandle((HANDLE)p); } #endif /* vim: set ts=4 sw=4 et cindent: */ cgreen-1.6.3/src/win32_cgreen_time.c000066400000000000000000000012241450461175400172300ustar00rootroot00000000000000#include "cgreen/internal/cgreen_time.h" #include #include #include #include #include #include static LARGE_INTEGER qry_freq; static bool qry_freq_initialized = false; uint32_t cgreen_time_get_current_milliseconds() { if (!qry_freq_initialized) { QueryPerformanceFrequency(&qry_freq); qry_freq_initialized = true; } LARGE_INTEGER current_count; QueryPerformanceCounter(¤t_count); current_count.QuadPart = current_count.QuadPart * 1000000 / qry_freq.QuadPart; return trunc(current_count.QuadPart / 1000); } /* vim: set ts=4 sw=4 et cindent: */ cgreen-1.6.3/src/win32_runner_platform.c000066400000000000000000000153051450461175400201710ustar00rootroot00000000000000#ifdef WIN32 #include "config.h" #include "runner.h" #include "cgreen/internal/runner_platform.h" #include "cgreen/messaging.h" #include "wincompat.h" #include "cgreen/internal/cgreen_time.h" #include "win32_cgreen.h" #include "Strsafe.h" #define SECOND (1000) static void run_named_test_child(TestSuite *suite, const char *name, TestReporter *reporter); static void CALLBACK stop(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) { #ifdef CGREEN_INTERNAL_WITH_GCOV if (1) #else if (NULL != getenv("CGREEN_CHILD_EXIT_WITH_FLUSH")) #endif exit(EXIT_SUCCESS); else _exit(EXIT_SUCCESS); } void die_in(unsigned int seconds) { MMRESULT signal_result = timeSetEvent(seconds*SECOND,SECOND,&stop,0,TIME_ONESHOT); if (0 == signal_result){ fprintf(stderr, "could not set alarm signal handler\n"); return; } } static void run_test_in_the_current_process_child(TestSuite *suite, CgreenTest *test, TestReporter *reporter) { (*reporter->start_test)(reporter, test->name); run_the_test_code(suite, test, reporter); send_reporter_completion_notification(reporter); stop(0, 0, 0, 0, 0); } static void run_named_test_child(TestSuite *suite, const char *name, TestReporter *reporter) { int i; //(*reporter->start_suite)(reporter, suite->name, count_tests(suite)); for (i = 0; i < suite->size; i++) { if (suite->tests[i].type == test_function) { if (strcmp(suite->tests[i].name, name) == 0) { run_test_in_the_current_process_child(suite, suite->tests[i].Runnable.test, reporter); } } else if (has_test(suite->tests[i].Runnable.suite, name)) { TestSuite* newSuite=suite->tests[i].Runnable.suite; (*suite->setup)(); //moved recursive calls to start_suite and finish_suite to the caller, so I //can control the printf that occurs in the first one. //This may have undesireable side effects. Not sure of the best solution (*reporter->start_suite)(reporter, newSuite->name, count_tests(newSuite)); uint32_t test_starting_milliseconds = cgreen_time_get_current_milliseconds(); run_named_test_child(newSuite, name, reporter); reporter->duration = cgreen_time_duration_in_milliseconds(test_starting_milliseconds, cgreen_time_get_current_milliseconds()); (*reporter->finish_suite)(reporter, newSuite->filename, newSuite->line, test_duration); (*suite->teardown)(); } } send_reporter_completion_notification(reporter); } void run_specified_test_if_child(TestSuite *suite, TestReporter *reporter){ //figure out if we are a child process, and if so, use the test name provided by our parent char testName[256]; DWORD result = GetEnvironmentVariableA(CGREEN_TEST_TO_RUN,testName,sizeof(testName)); if (result) //we are a child process, only run the specified test { //May have to deal with some issues here. I don't call the function pointer for //reporter start and finish in order to avoid extraneous prints to the console, //but this may cause problems for other types of reporters. Not sure the //best solution for this. reporter_start_test(reporter, testName); //add breadcrumb without triggering output to console uint32_t test_starting_milliseconds = cgreen_time_get_current_milliseconds(); run_named_test_child(suite, testName, reporter); reporter->duration = cgreen_time_duration_in_milliseconds(test_starting_milliseconds, cgreen_time_get_current_milliseconds()); reporter_finish_test(reporter, suite->filename, suite->line, NULL, test_duration); return; //never happens because we call stop inside run_named_test_child } } struct environment { char env[MAX_PATH]; char *p_head; }; struct environment* create_environment() { struct environment* p = (struct environment*)malloc(sizeof(struct environment)); memset(p->env, 0, sizeof(p->env)); p->p_head = p->env; return p; } static void AddEnvironmentVariable(struct environment* env,const char* varName, const char* valueString) { size_t len; size_t envSize = MAX_PATH - (env->p_head-env->env); StringCbCopyA(env->p_head, envSize, varName); StringCbCatA(env->p_head, envSize, "="); StringCbCatA(env->p_head, envSize, valueString); StringCbCatA(env->p_head, envSize, "\0"); len = strnlen_s(env->p_head, envSize); env->p_head += (len + 1); } static const char* get_environment_block(const struct environment* env) { return env->env; } static void dispose_environment(struct environment* env) { free(env); } void run_test_in_its_own_process(TestSuite *suite, CgreenTest *test, TestReporter *reporter) { #define COMMAND_LINE_LENGTH (2*MAX_PATH) BOOL success; char fname[MAX_PATH+1]; //make enough room for full path plus null terminator struct environment* p_environment = create_environment(); char handleString[256]; STARTUPINFOA siStartupInfo; PROCESS_INFORMATION piProcessInfo; //get executable path GetModuleFileNameA(NULL, fname,MAX_PATH); //launch process memset(&siStartupInfo, 0, sizeof(siStartupInfo)); memset(&piProcessInfo, 0, sizeof(piProcessInfo)); siStartupInfo.cb = sizeof(siStartupInfo); sprintf_s(handleString,sizeof(handleString), "%i", get_pipe_read_handle()); AddEnvironmentVariable(p_environment, CGREEN_READ_HANDLE, handleString); sprintf_s(handleString,sizeof(handleString), "%i", get_pipe_write_handle()); AddEnvironmentVariable(p_environment, CGREEN_WRITE_HANDLE, handleString); //put name of test to run in environment AddEnvironmentVariable(p_environment, CGREEN_TEST_TO_RUN, test->name); (*reporter->start_test)(reporter, test->name); uint32_t test_starting_milliseconds = cgreen_time_get_current_milliseconds(); //success = CreateProcessA(fname, NULL, NULL, NULL, true, NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW , p_environment, NULL, &siStartupInfo, &piProcessInfo); success = CreateProcessA(fname, NULL, NULL, NULL, true, NORMAL_PRIORITY_CLASS , p_environment, NULL, &siStartupInfo, &piProcessInfo); dispose_environment(p_environment); WaitForSingleObject(piProcessInfo.hProcess,INFINITE); reporter->duration = cgreen_time_duration_in_milliseconds(test_starting_milliseconds, cgreen_time_get_current_milliseconds()); (*reporter->finish_test)(reporter, test->filename, test->line, NULL, test_duration); return; } #endif /* vim: set ts=4 sw=4 et cindent: */ cgreen-1.6.3/src/xml_reporter.c000066400000000000000000000244501450461175400164550ustar00rootroot00000000000000#include #include #include #include #include #include #include "utils.h" #include "xml_reporter_internal.h" #ifdef __ANDROID__ #include "cgreen/internal/android_headers/androidcompat.h" #endif // #ifdef __ANDROID__ typedef struct { XmlPrinter *printer; int segment_count; } XmlMemo; static void xml_reporter_start_suite(TestReporter *reporter, const char *name, int count); static void xml_reporter_start_test(TestReporter *reporter, const char *name); static void xml_reporter_finish_test(TestReporter *reporter, const char *filename, int line, const char *message); static void xml_reporter_finish_suite(TestReporter *reporter, const char *filename, int line); static void xml_show_skip(TestReporter *reporter, const char *file, int line); static void xml_show_fail(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments); static void xml_show_incomplete(TestReporter *reporter, const char *filename, int line, const char *message, va_list arguments); void set_xml_reporter_printer(TestReporter *reporter, XmlPrinter *new_printer) { XmlMemo *memo = (XmlMemo *)reporter->memo; memo->printer = new_printer; } static const char *file_prefix; TestReporter *create_xml_reporter(const char *prefix) { TestReporter *reporter; XmlMemo *memo; reporter = create_reporter(); if (reporter == NULL) { return NULL; } memo = (XmlMemo *) malloc(sizeof(XmlMemo)); if (memo == NULL) { destroy_reporter(reporter); return NULL; } memo->printer = fprintf; reporter->memo = memo; file_prefix = prefix; reporter->start_suite = &xml_reporter_start_suite; reporter->start_test = &xml_reporter_start_test; reporter->show_fail = &xml_show_fail; reporter->show_skip = &xml_show_skip; reporter->show_incomplete = &xml_show_incomplete; reporter->finish_test = &xml_reporter_finish_test; reporter->finish_suite = &xml_reporter_finish_suite; return reporter; } static int file_stack_p = 0; static FILE *file_stack[100]; static char *indent(TestReporter *reporter) { static char buffer[1000]; int depth = get_breadcrumb_depth(reporter->breadcrumb); memset(buffer, '\0', depth+1); memset(buffer, '\t', depth); return buffer; } static void print_path_separator_if_needed(XmlMemo *memo, int *more_segments) { if (*more_segments > 0) { memo->printer(file_stack[file_stack_p-1], "/"); (*more_segments)--; } } static void print_path_segment_walker(const char *segment, void *void_memo) { XmlMemo *memo = (XmlMemo *)void_memo; memo->printer(file_stack[file_stack_p-1], "%s", segment); print_path_separator_if_needed(memo, &memo->segment_count); } #ifndef PATH_MAX #define PATH_MAX 4096 #endif static char suite_path[PATH_MAX]; static void strcat_path_segment(const char *segment, void *more_segments) { (void)more_segments; if (suite_path[0] != '\0') strcat(suite_path, "-"); strncat(suite_path, segment, sizeof(suite_path)-strlen(suite_path)-1); } static void add_suite_name(const char *suite_name) { if (suite_path[0] != '\0') strcat(suite_path, "-"); strncat(suite_path, suite_name, sizeof(suite_path)-strlen(suite_path)-1); } static void xml_reporter_start_suite(TestReporter *reporter, const char *suitename, int count) { char filename[PATH_MAX]; int segment_decrementer = reporter->breadcrumb->depth; XmlMemo *memo = (XmlMemo *)reporter->memo; FILE *out; (void)count; /* UNUSED */ reporter->passes = 0; reporter->failures = 0; reporter->skips = 0; reporter->exceptions = 0; suite_path[0] = '\0'; walk_breadcrumb(reporter->breadcrumb, strcat_path_segment, &segment_decrementer); add_suite_name(suitename); if (snprintf(filename, sizeof(filename), "%s-%s.xml", file_prefix, suite_path) < 0) PANIC("Error when creating output filename"); if (memo->printer == fprintf) { // If we're really printing to files, then open one... out = fopen(filename, "w"); if (!out) { memo->printer(stderr, "could not open %s: %s\r\n", filename, strerror(errno)); exit(EXIT_FAILURE); } } else out = stdout; file_stack[file_stack_p++] = out; memo->printer(out, "\n"); memo->printer(out, indent(reporter)); memo->printer(out, "\n", suite_path); reporter_start_suite(reporter, suitename, 0); } /* Accumulate output from the actual test (the "" nodes) in a file since the tests usually are run in a child processes, so there is no simple way to save output from it and then use it in the parent (start_test() and finish_test() are run from parent) */ static char *output = NULL; static FILE *child_output_tmpfile; static void xml_reporter_start_test(TestReporter *reporter, const char *testname) { XmlMemo *memo = (XmlMemo *)reporter->memo; FILE *out = file_stack[file_stack_p-1]; memo->printer(out, indent(reporter)); memo->printer(out, "segment_count = reporter->breadcrumb->depth - 1; walk_breadcrumb(reporter->breadcrumb, print_path_segment_walker, memo); // Don't terminate the XML-node now so that we can add the duration later // But then we need to accumulate subsequent output to report later memo->printer(out, "\" name=\"%s\"", testname); reporter_start_test(reporter, testname); output = strdup(""); child_output_tmpfile = tmpfile(); } static char *concat(char *head, const char *tail) { char *result = realloc(head, strlen(head)+strlen(tail)+1); return strcat(result, tail); } static void xml_show_skip(TestReporter *reporter, const char *file, int line) { (void)file; (void)line; output = concat(output, indent(reporter)); output = concat(output, "\t\n"); fseek(child_output_tmpfile,0,SEEK_SET); fputs(output, child_output_tmpfile); } static void xml_concat_escaped_message(const char *message, va_list arguments) { char buffer[1000]; snprintf(buffer, sizeof(buffer)/sizeof(buffer[0]), message, arguments); size_t current_char_position = 0; for (; current_char_position < strlen(buffer); current_char_position++) { switch (buffer[current_char_position]) { case '"': output = concat(output, """); break; case '&': output = concat(output, "&"); break; case '<': output = concat(output, "<"); break; case '>': output = concat(output, ">"); break; case '\'': output = concat(output, "'"); break; default: { char single_char[2] = {0}; single_char[0] = buffer[current_char_position]; output = concat(output, single_char); } } } } static void xml_show_fail(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments) { char buffer[1000]; output = concat(output, indent(reporter)); output = concat(output, "\n"); output = concat(output, indent(reporter)); snprintf(buffer, sizeof(buffer)/sizeof(buffer[0]), "\t\n", file, line); output = concat(output, buffer); output = concat(output, indent(reporter)); output = concat(output, "\n"); fseek(child_output_tmpfile,0,SEEK_SET); fputs(output, child_output_tmpfile); } static void xml_show_incomplete(TestReporter *reporter, const char *filename, int line, const char *message, va_list arguments) { char buffer[1000]; output = concat(output, indent(reporter)); output = concat(output, "\n"); output = concat(output, indent(reporter)); snprintf(buffer, sizeof(buffer)/sizeof(buffer[0]),"\t\n", filename, line); output = concat(output, buffer); output = concat(output, indent(reporter)); output = concat(output, "\n"); fseek(child_output_tmpfile,0,SEEK_SET); fputs(output, child_output_tmpfile); } static void transfer_output_from(FILE *tmpfile, XmlPrinter printer, FILE *out) { fseek(tmpfile, 0, SEEK_SET); char buffer[1000]; while (fgets(buffer, 1000, tmpfile) != NULL) printer(out, buffer); } static void xml_reporter_finish_test(TestReporter *reporter, const char *filename, int line, const char *message) { XmlMemo *memo = (XmlMemo *)reporter->memo; FILE *out = file_stack[file_stack_p-1]; reporter_finish_test(reporter, filename, line, message); memo->printer(out, " time=\"%.5f\">\n", (double)reporter->duration/(double)1000); if (output && strlen(output) == 0) { free(output); output = NULL; } transfer_output_from(child_output_tmpfile, memo->printer, out); memo->printer(out, indent(reporter)); memo->printer(out, "\n"); fflush(out); } static void xml_reporter_finish_suite(TestReporter *reporter, const char *filename, int line) { XmlMemo *memo = (XmlMemo *)reporter->memo; FILE *out = file_stack[--file_stack_p]; reporter_finish_suite(reporter, filename, line); reporter->total_passes += reporter->passes; reporter->total_failures += reporter->failures; reporter->total_skips += reporter->skips; reporter->total_exceptions += reporter->exceptions; // TODO: Here we should backpatch the time for the suite but that's not // exactly necessary as Jenkins, at least, seems to sum it up automatically memo->printer(out, indent(reporter)); memo->printer(out, "\n"); if (file_stack_p != 0) fclose(out); } cgreen-1.6.3/src/xml_reporter_internal.h000066400000000000000000000005201450461175400203460ustar00rootroot00000000000000#ifndef XML_REPORTER_INTERNAL_H #define XML_REPORTER_INTERNAL_H #include #ifdef __cplusplus extern "C" { #endif #include typedef int XmlPrinter(FILE *, const char *format, ...); extern void set_xml_reporter_printer(TestReporter *reporter, XmlPrinter *printer); #ifdef __cplusplus } #endif #endif cgreen-1.6.3/tests/000077500000000000000000000000001450461175400141355ustar00rootroot00000000000000cgreen-1.6.3/tests/.gitignore000066400000000000000000000007171450461175400161320ustar00rootroot00000000000000libassertion_tests.so libbreadcrumb_tests.so libcdash_reporter_tests.so libcgreen_value_tests.so libconstraint_tests.so libcute_reporter_tests.so libdouble_tests.so libenvironment_variables_tests.so libmessage_formatting_tests.so libmessaging_tests.so libmocks_tests.so libparameters_tests.so libreflective_runner_no_teardown_tests.so libreflective_tests.so libtext_reporter_tests.so libunit_tests.so libutils_tests.so libvector_tests.so libxml_reporter_tests.so cgreen-1.6.3/tests/CMakeLists.txt000066400000000000000000000242561450461175400167060ustar00rootroot00000000000000set(CGREEN_TEST_INCLUDE_DIRS ${CGREEN_PUBLIC_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR} ) check_include_file("sys/resource.h" HAVE_SYS_RESOURCE_H) if (HAVE_SYS_RESOURCE_H) add_definitions(-DHAVE_SYS_RESOURCE_H) endif(HAVE_SYS_RESOURCE_H) if (MSVC) LIST(APPEND CGREEN_TEST_INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/include/cgreen/internal/windows_headers ) endif(MSVC) include_directories(${CGREEN_TEST_INCLUDE_DIRS}) # Dependency on our own library if (CGREEN_WITH_STATIC_LIBRARY) set(CGREEN_LIBRARY ${CGREEN_STATIC_LIBRARY}) else () set(CGREEN_LIBRARY ${CGREEN_SHARED_LIBRARY}) endif() # C tests, library to use with runner, and a main program # NOTE that some of these are "pure" unit tests which only # need to work in C, since Cgreen's internal is C. # Some others are actually testing user level functionality # which must work both for C and C++ compiles. # TODO: separate out those into separate dirs? Or just # two lists of files, one which should go into C++ compilation # too. set(c_tests_library_SRCS assertion_tests.c breadcrumb_tests.c cdash_reporter_tests.c cgreen_value_tests.c constraint_tests.c cute_reporter_tests.c double_tests.c environment_variables_tests.c message_formatting_tests.c messaging_tests.c mocks_tests.c mocks_struct_tests.c parameters_tests.c reflective_runner_no_teardown_tests.c reflective_tests.c text_reporter_tests.c unit_tests.c vector_tests.c ) if (CGREEN_WITH_XML) LIST(APPEND c_tests_library_SRCS xml_reporter_tests.c) endif (CGREEN_WITH_XML) if (CGREEN_WITH_LIBXML2) LIST(APPEND c_tests_library_SRCS libxml_reporter_tests.c) endif (CGREEN_WITH_LIBXML2) SET_SOURCE_FILES_PROPERTIES(${c_tests_library_SRCS} PROPERTIES LANGUAGE C) set(CGREEN_C_TESTS_LIBRARY cgreen_c_tests CACHE INTERNAL "cgreen shared library with tests for C" ) add_library(${CGREEN_C_TESTS_LIBRARY} SHARED ${c_tests_library_SRCS}) target_link_libraries(${CGREEN_C_TESTS_LIBRARY} ${CGREEN_LIBRARY} $<$:${LIBXML2_LIBRARIES}>) include_directories($<$:${LIBXML2_INCLUDE_DIRS}>) macro_add_valgrind_test(${CGREEN_C_TESTS_LIBRARY}) set(c_tests_SRCS all_c_tests.c ${c_tests_library_SRCS} ) SET_SOURCE_FILES_PROPERTIES(${c_tests_SRCS} PROPERTIES LANGUAGE C) set(TEST_TARGET_LIBRARIES ${CGREEN_LIBRARY} $<$:${LIBXML2_LIBRARIES}>) # unit test with main program runner macro_add_unit_test(test_cgreen_c "${c_tests_SRCS}" "${TEST_TARGET_LIBRARIES}") macro_add_test(NAME test_cgreen_c_run_named_test COMMAND test_cgreen_c integer_one_should_assert_true) set(cgreen_runner_args) if (CGREEN_WITH_XML) set(cgreen_runner_args -x TEST) endif (CGREEN_WITH_XML) # run them with cgreen-runner also macro_add_test(NAME runner_test_cgreen_c COMMAND cgreen-runner ${cgreen_runner_args} ./${CMAKE_SHARED_LIBRARY_PREFIX}${CGREEN_C_TESTS_LIBRARY}${CMAKE_SHARED_LIBRARY_SUFFIX}) # C++ tests, library to use with runner, and a main program # NOTE that .cpp-versions should be links to .c-versions so we avoid duplication # so we just use the same list and add the CPP-specific tests here foreach(c_test_file ${c_tests_library_SRCS}) string(REGEX REPLACE "\\.c" ".cpp" cpp_test_file ${c_test_file}) list(APPEND cpp_tests_library_SRCS ${cpp_test_file}) endforeach() set(cpp_tests_library_SRCS ${cpp_tests_library_SRCS} cpp_assertion_tests.cpp ) SET_SOURCE_FILES_PROPERTIES(${cpp_tests_library_SRCS} PROPERTIES LANGUAGE CXX) set(CGREEN_CPP_TESTS_LIBRARY cgreen_cpp_tests CACHE INTERNAL "cgreen shared library with tests for C++" ) add_library(${CGREEN_CPP_TESTS_LIBRARY} SHARED ${cpp_tests_library_SRCS}) target_link_libraries(${CGREEN_CPP_TESTS_LIBRARY} ${CGREEN_LIBRARY} ${CMAKE_CXX_IMPLICIT_LINK_LIBRARIES}) macro_add_valgrind_test(${CGREEN_CPP_TESTS_LIBRARY}) set(cpp_tests_SRCS all_cpp_tests.cpp ${cpp_tests_library_SRCS} ) SET_SOURCE_FILES_PROPERTIES(${cpp_tests_SRCS} PROPERTIES LANGUAGE CXX) macro_add_unit_test(test_cgreen_cpp "${cpp_tests_SRCS}" "${TEST_TARGET_LIBRARIES}" ${CMAKE_CXX_IMPLICIT_LINK_LIBRARIES}) macro_add_test(NAME test_cgreen_cpp_run_named_test COMMAND test_cgreen_cpp different_pointers_with_same_contents_should_assert_equal) macro_add_test(NAME runner_test_cgreen_cpp COMMAND cgreen-runner ${cgreen_runner_args} ./${CMAKE_SHARED_LIBRARY_PREFIX}${CGREEN_CPP_TESTS_LIBRARY}${CMAKE_SHARED_LIBRARY_SUFFIX}) # Temporary single CUT test library # Maybe we should do this for all tests instead # and then aggregate the DLL/so/dylibs instead... # Then this might be possible to turn into a macro # which could allow "add_runner_lib(text_reporter)" foreach(case assertion breadcrumb cdash_reporter cgreen_value constraint cute_reporter double message_formatting messaging mocks mocks_struct parameters reflective reflective_runner_no_teardown text_reporter unit vector ) set(${case}_tests_SRCS ${case}_tests.c ) set(${case}_tests_library ${case}_tests ) add_library(${${case}_tests_library} SHARED ${${case}_tests_SRCS}) target_link_libraries(${${case}_tests_library} ${CGREEN_LIBRARY}) endforeach(case) if (CGREEN_WITH_XML) add_library(xml_reporter_tests SHARED xml_reporter_tests.c) target_link_libraries(xml_reporter_tests ${CGREEN_LIBRARY}) endif (CGREEN_WITH_XML) if (CGREEN_WITH_LIBXML2) add_library(libxml_reporter_tests SHARED libxml_reporter_tests.c) target_link_libraries(libxml_reporter_tests ${CGREEN_LIBRARY}) endif (CGREEN_WITH_LIBXML2) # Libraries for a set of output comparing tests to run with runner set(constraint_messages_library constraint_messages_tests) set(constraint_messages_library_SRCS constraint_messages_tests.c) add_library(${constraint_messages_library} SHARED ${constraint_messages_library_SRCS}) target_link_libraries(${constraint_messages_library} ${CGREEN_LIBRARY}) set(custom_constraint_messages_library custom_constraint_messages_tests) set(custom_constraint_messages_library_SRCS custom_constraint_messages_tests.c) add_library(${custom_constraint_messages_library} SHARED ${custom_constraint_messages_library_SRCS}) target_link_libraries(${custom_constraint_messages_library} ${CGREEN_LIBRARY}) set(mock_messages_library mock_messages_tests) set(mock_messages_library_SRCS mock_messages_tests.c) add_library(${mock_messages_library} SHARED ${mock_messages_library_SRCS}) target_link_libraries(${mock_messages_library} ${CGREEN_LIBRARY}) set(failure_messages_library failure_messages_tests) set(failure_messages_library_SRCS failure_messages_tests.c) add_library(${failure_messages_library} SHARED ${failure_messages_library_SRCS}) target_link_libraries(${failure_messages_library} ${CGREEN_LIBRARY}) set(assertion_messages_library assertion_messages_tests) set(assertion_messages_library_SRCS assertion_messages_tests.c) add_library(${assertion_messages_library} SHARED ${assertion_messages_library_SRCS}) target_link_libraries(${assertion_messages_library} ${CGREEN_LIBRARY}) set(ignore_messages_library ignore_messages_tests) set(ignore_messages_library_SRCS ignore_messages_tests.c) add_library(${ignore_messages_library} SHARED ${ignore_messages_library_SRCS}) target_link_libraries(${ignore_messages_library} ${CGREEN_LIBRARY}) if (CGREEN_WITH_XML) set(xml_output_library xml_output_tests) set(xml_output_library_SRCS xml_output_tests.c) add_library(${xml_output_library} SHARED ${xml_output_library_SRCS}) target_link_libraries(${xml_output_library} ${CGREEN_LIBRARY}) endif (CGREEN_WITH_XML) if (CGREEN_WITH_LIBXML2) set(libxml_output_library libxml_output_tests) set(libxml_output_library_SRCS libxml_output_tests.c) add_library(${libxml_output_library} SHARED ${libxml_output_library_SRCS}) target_link_libraries(${libxml_output_library} ${CGREEN_LIBRARY}) endif (CGREEN_WITH_LIBXML2) # TODO We should not add these if the cgreen-runner was not built e.g. no 'nm' available macro_add_test( NAME constraint_messsages COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/../tools/cgreen_runner_output_diff constraint_messages_tests # Name ${CMAKE_CURRENT_SOURCE_DIR} # Where sources are ${constraint_messages_library}.expected ) macro_add_test( NAME custom_constraint_messsages COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/../tools/cgreen_runner_output_diff custom_constraint_messages_tests # Name ${CMAKE_CURRENT_SOURCE_DIR} # Where sources are ${custom_constraint_messages_library}.expected ) macro_add_test( NAME mock_messsages COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/../tools/cgreen_runner_output_diff mock_messages_tests # Name ${CMAKE_CURRENT_SOURCE_DIR} # Where sources are ${mock_messages_library}.expected ) macro_add_test(NAME failure_messages COMMAND env "CGREEN_PER_TEST_TIMEOUT=2" ${CMAKE_CURRENT_SOURCE_DIR}/../tools/cgreen_runner_output_diff failure_messages_tests # Name ${CMAKE_CURRENT_SOURCE_DIR} # Where sources are ${failure_messages_library}.expected ) macro_add_test(NAME assertion_messages COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/../tools/cgreen_runner_output_diff assertion_messages_tests # Name ${CMAKE_CURRENT_SOURCE_DIR} # Where sources are ${assertion_messages_library}.expected ) macro_add_test(NAME ignore_messages COMMAND env "CGREEN_PER_TEST_TIMEOUT=2" ${CMAKE_CURRENT_SOURCE_DIR}/../tools/cgreen_runner_output_diff ignore_messages_tests # Name ${CMAKE_CURRENT_SOURCE_DIR} # Where sources are ${ignore_messages_library}.expected ) if (CGREEN_WITH_XML) macro_add_test(NAME xml_output COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/../tools/cgreen_xml_output_diff xml_output_tests # Name ${CMAKE_CURRENT_SOURCE_DIR} # Where sources are ${xml_output_library}.expected ) endif (CGREEN_WITH_XML) if (CGREEN_WITH_LIBXML2) macro_add_test(NAME libxml_output COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/../tools/cgreen_libxml_output_diff libxml_output_tests ${CMAKE_CURRENT_SOURCE_DIR} ${libxml_output_library}.expected ) endif (CGREEN_WITH_LIBXML2) # add verification that all public api is available as it should add_subdirectory(api) cgreen-1.6.3/tests/CTestCustom.cmake000066400000000000000000000001621450461175400173530ustar00rootroot00000000000000set(CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE "2048") set(CTEST_CUSTOM_MAXIMUM_FAILED_TEST_OUTPUT_SIZE "2048") cgreen-1.6.3/tests/Makefile000066400000000000000000000024031450461175400155740ustar00rootroot00000000000000# This make file may serve as an example of how to easily build a lot # of Cgreen test libraries and run them through the runner. By # structuring it this way only affected libraries need to be rebuilt. # # Note that this is not official builds or tests for Cgreen. To do # that you should go to root directory and do "make unit" or "make # test" CFLAGS = -Wall -fPIC -std=c99 -I../include -I.. -I../src LIBRARY_PATH = ../build/src ifneq ($(shell uname), Darwin) LOAD_PATH = LD_LIBRARY_PATH=$(LIBRARY_PATH) else LOAD_PATH = DYLD_LIBRARY_PATH=$(LIBRARY_PATH) endif TEST_SOURCES = \ assertion_tests.c \ breadcrumb_tests.c \ cdash_reporter_tests.c \ cgreen_value_tests.c \ constraint_tests.c \ cute_reporter_tests.c \ double_tests.c \ environment_variables_tests.c \ message_formatting_tests.c \ messaging_tests.c \ mocks_tests.c \ parameters_tests.c \ reflective_runner_no_teardown_tests.c \ reflective_tests.c \ text_reporter_tests.c \ unit_tests.c \ utils_tests.c \ vector_tests.c \ xml_reporter_tests.c \ TEST_LIBRARIES = $(patsubst %.c,lib%.so, $(TEST_SOURCES)) all: $(TEST_LIBRARIES) cd ..; make --no-print-directory $(LOAD_PATH) ../build/tools/cgreen-runner -s unittests $? lib%_tests.so : %_tests.o ; $(CC) -shared -o $@ $^ -L$(LIBRARY_PATH) -lcgreen cgreen-1.6.3/tests/accept_output_for000077500000000000000000000012761450461175400176160ustar00rootroot00000000000000#!/bin/bash # # Script to accept the current output for some output comparing test as the golden output # # Usage: accept # # Will copy build/tests/.output to tests/.expected if [ "$#" -ne 1 ] then echo "Usage: accept " exit 1 fi scriptdir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" rootdir=$(dirname $scriptdir) if [[ ! -f $rootdir/build/tests/$1.output ]] then echo "Output file does not exist." exit fi echo "About to 'cp build/tests/$1.output tests/$1.expected'" read -r -p "Are you sure? [y/N] " response if [[ ! $response =~ ^([yY][eE][sS]|[yY])$ ]] then exit fi cp $rootdir/build/tests/$1.output $rootdir/tests/$1.expected echo "Accepted!" cgreen-1.6.3/tests/all_c_tests.c000066400000000000000000000042211450461175400165740ustar00rootroot00000000000000#include /* all_c_tests.c - which also doubles as all_cpp_tests.c using symbolic link and CPP conditionals */ #ifdef __cplusplus using namespace cgreen; #endif TestSuite *assertion_tests(void); TestSuite *breadcrumb_tests(void); TestSuite *cdash_reporter_tests(void); TestSuite *collector_tests(void); TestSuite *constraint_tests(void); #ifdef __cplusplus TestSuite *cpp_assertion_tests(void); #endif TestSuite *cute_reporter_tests(void); TestSuite *cgreen_value_tests(void); TestSuite *message_formatting_tests(void); TestSuite *messaging_tests(void); TestSuite *mock_tests(void); TestSuite *parameter_tests(void); TestSuite *reflective_no_teardown_tests(void); TestSuite *reflective_tests(void); TestSuite *text_reporter_tests(void); TestSuite *unit_tests(void); TestSuite *vector_tests(void); TestSuite *xml_reporter_tests(void); TestSuite *libxml_reporter_tests(void); int main(int argc, char **argv) { int suite_result; TestSuite *suite = create_named_test_suite("all_c_tests"); TestReporter *reporter = create_text_reporter(); add_suite(suite, assertion_tests()); add_suite(suite, breadcrumb_tests()); add_suite(suite, cgreen_value_tests()); add_suite(suite, cdash_reporter_tests()); add_suite(suite, constraint_tests()); #ifdef __cplusplus add_suite(suite, cpp_assertion_tests()); #endif add_suite(suite, cute_reporter_tests()); add_suite(suite, message_formatting_tests()); add_suite(suite, messaging_tests()); add_suite(suite, mock_tests()); add_suite(suite, parameter_tests()); add_suite(suite, reflective_no_teardown_tests()); add_suite(suite, reflective_tests()); add_suite(suite, text_reporter_tests()); add_suite(suite, unit_tests()); add_suite(suite, vector_tests()); #if HAVE_XML_REPORTER add_suite(suite, xml_reporter_tests()); #endif #if HAVE_LIBXML2_REPORTER add_suite(suite, libxml_reporter_tests()); #endif if (argc > 1) { suite_result = run_single_test(suite, argv[1], reporter); } else { suite_result = run_test_suite(suite, reporter); } destroy_test_suite(suite); destroy_reporter(reporter); return suite_result; } cgreen-1.6.3/tests/all_cpp_tests.cpp000066400000000000000000000006371450461175400175030ustar00rootroot00000000000000/* This file used to be a link to the corresponding .c file because we want to compile the same tests for C and C++. But since some systems don't handle symbolic links the same way as *ix systems we get inconsistencies (looking at you Cygwin) or plain out wrong (looking at you MSYS2, copying ?!?!?) behaviour. So we will simply include the complete .c source instead... */ #include "all_c_tests.c" cgreen-1.6.3/tests/api/000077500000000000000000000000001450461175400147065ustar00rootroot00000000000000cgreen-1.6.3/tests/api/CMakeLists.txt000066400000000000000000000024661450461175400174560ustar00rootroot00000000000000# This subdirectory verifies that the user level api compiles using # only the publiced includes by compiling test files refering to that # api. Goal is to reference, and thus verify, the whole api so that # unintended changes to the API gets noticed early. # # There is no need to run the tests... include_directories(${CGREEN_PUBLIC_INCLUDE_DIRS}) set(api_SRCS core_api.c suites_without_context_api.c suites_with_context_api.c ) set(CGREEN_API_TEST_LIBRARY cgreen_api CACHE INTERNAL "cgreen library of user level api verification source" ) add_library(${CGREEN_API_TEST_LIBRARY} SHARED ${api_SRCS}) target_link_libraries(${CGREEN_API_TEST_LIBRARY} ${CGREEN_LIBRARY} ${CMAKE_THREAD_LIBS_INIT}) #macro_add_test(NAME api_compilation_test # COMMAND ${PROJECT_SOURCE_DIR}/tools/compare_test_output_to_expected # ${PROJECT_BINARY_DIR}/tools # Where is cgreen-runner? # $ # Library to run # ${PROJECT_SOURCE_DIR} # Remove lines with these from output # ${CGREEN_API_TEST_LIBRARY} # Normalized library name # ${CMAKE_CURRENT_SOURCE_DIR}) # Where is the expected output? cgreen-1.6.3/tests/api/cgreen_api.expected000066400000000000000000000040651450461175400205320ustar00rootroot00000000000000Running "libcgreen_api" (6 tests)... tests/api/suites_with_context_api.c:12: Exception: context_api -> compiles_suite_api Test terminated with signal: Segmentation fault: 11 Completed "context_api": 0 passes, 0 failures, 1 exception. tests/api/core_api.c:15: Exception: default -> assert_that_compiles Test terminated with signal: Segmentation fault: 11 tests/api/core_api.c:28: Failure: default -> constraints_compiles Expected [1] to [not equal] [1] tests/api/core_api.c:29: Failure: default -> constraints_compiles Expected [1] to [be greater than] [1] tests/api/core_api.c:30: Failure: default -> constraints_compiles Expected [1] to [be less than] [1] tests/api/core_api.c:33: Failure: default -> constraints_compiles Expected [array] to [not equal contents of] [array] at offset: [-1] tests/api/core_api.c:36: Failure: default -> constraints_compiles Expected [string] to [not equal string] [string] actual value: ["some string"] tests/api/core_api.c:38: Failure: default -> constraints_compiles Expected [string] to [not contain string] [string] actual value: ["some string"] expected to not contain: ["some string"] tests/api/core_api.c:49: Failure: default -> mocks_compiles Mocked function [int_stub] already has an expectation and will always be called a certain way; any expectations declared after an always expectation are discarded tests/api/core_api.c:50: Failure: default -> mocks_compiles Mocked function [int_stub] already has an expectation and will always be called a certain way; declaring an expectation after an always expectation is not allowed tests/api/core_api.c:51: Failure: default -> mocks_compiles Mocked function [int_stub] already has an expectation that it will always be called a certain way; any expectations declared after an always expectation are invalid tests/api/suites_without_context_api.c:10: Exception: default -> suites_compiles Test terminated with signal: Segmentation fault: 11 Completed "default": 7 passes, 9 failures, 3 exceptions. Completed "libcgreen_api": 7 passes, 9 failures, 3 exceptions. cgreen-1.6.3/tests/api/core_api.c000066400000000000000000000027701450461175400166410ustar00rootroot00000000000000#include #include /* These tests are only an attempt to exercise the whole public API of Cgreen to ensure that it compiles. Attempting to run them will surely result in crashes, plagues and pestilence. For unit tests see other tests. */ #ifdef __cplusplus using namespace cgreen; #endif // ASSERT Ensure(assert_that_compiles) { assert_that(1 == 1); assert_that(1 == 1, is_true); assert_that_double(1, is_equal_to(1)); significant_figures_for_assert_double_are(3); } // CONSTRAINTS Ensure(constraints_compiles) { char array[5]; char *string = (char *)"some string"; assert_that(1, is_equal_to(1)); assert_that(1, is_not_equal_to(1)); assert_that(1, is_greater_than(1)); assert_that(1, is_less_than(1)); assert_that(array, is_equal_to_contents_of(array, 5)); assert_that(array, is_not_equal_to_contents_of(array, 3)); assert_that(string, is_equal_to_string(string)); assert_that(string, is_not_equal_to_string(string)); assert_that(string, contains_string(string)); assert_that(string, does_not_contain_string(string)); assert_that(string, begins_with_string(string)); } static int int_stub(int parameter) { return mock(parameter); } // Mocks Ensure(mocks_compiles) { always_expect(int_stub, will_return(1)); always_expect(int_stub, will_set_contents_of_parameter(parameter, 1, sizeof(int))); never_expect(int_stub); expect(int_stub, when(parameter, is_equal_to(1))); int_stub(1); } cgreen-1.6.3/tests/api/suites_with_context_api.c000066400000000000000000000006761450461175400220270ustar00rootroot00000000000000#include #ifdef __cplusplus using namespace cgreen; #endif Describe(context_api); BeforeEach(context_api) {} AfterEach(context_api) {} // SUITES Ensure(context_api, compiles_suite_api) { TestSuite *suite = create_test_suite(); add_test_with_context(suite, context_api, compiles_suite_api); run_test_suite(suite, NULL); run_single_test(suite, "name", NULL); die_in(1); destroy_test_suite(suite); } cgreen-1.6.3/tests/api/suites_without_context_api.c000066400000000000000000000005741450461175400225540ustar00rootroot00000000000000#include #ifdef __cplusplus using namespace cgreen; #endif // SUITES Ensure(a_test) {} Ensure(suites_compiles) { TestSuite *suite = create_test_suite(); add_test(suite, a_test); add_tests(suite, a_test, a_test, a_test); run_test_suite(suite, NULL); run_single_test(suite, "name", NULL); die_in(1); destroy_test_suite(suite); } cgreen-1.6.3/tests/assertion_messages_tests.c000066400000000000000000000031141450461175400214200ustar00rootroot00000000000000#include #include #include #include #include #include #ifdef __cplusplus using namespace cgreen; #endif Describe(AssertionMessage); BeforeEach(AssertionMessage) {} AfterEach(AssertionMessage) {} char something[42]; Ensure(AssertionMessage, for_comparing_content_with_negative_length) { assert_that(47, is_equal_to_contents_of(something, -4)); } Ensure(AssertionMessage, return_value_constraints_are_not_allowed) { assert_that(0, will_return(1)); } Ensure(AssertionMessage, for_compare_area_to_null) { char area[100]; void *null_pointer = NULL; assert_that(area, is_equal_to_contents_of(null_pointer, 1)); } Ensure(AssertionMessage, for_compare_null_to_area) { char area[100]; assert_that(NULL, is_equal_to_contents_of(area, 1)); } Ensure(AssertionMessage, for_actual_with_percent) { assert_that(strlen("%d"), is_equal_to(3)); /* Actually, it's not but should preserve '%' */ } /* CAUTION: These two tests outputs the expected warning messages, but also fails the comparisons, obviously, since that is what they try to warn against. So the output of those failed constraints might change unintentionally. */ Ensure(AssertionMessage, for_using_double_constraints_with_assert_that) { assert_that(3, is_equal_to_double(3.1415926)); assert_that(0, is_less_than_double(3.1415926)); assert_that(7, is_greater_than_double(3.1415926)); } Ensure(AssertionMessage, for_using_non_double_constraints_with_assert_that_double) { assert_that_double(3, is_equal_to(3)); } cgreen-1.6.3/tests/assertion_messages_tests.expected000066400000000000000000000054201450461175400230010ustar00rootroot00000000000000Running "assertion_messages_tests" (7 tests)... assertion_messages_tests.c:000: Failure: AssertionMessage -> for_actual_with_percent Expected [strlen("%d")] to [equal] [3] actual value: [2] expected value: [3] assertion_messages_tests.c:000: Failure: AssertionMessage -> for_compare_area_to_null Wanted to compare contents of [null_pointer] but it had a value of NULL. If you want to explicitly check for null, use the is_null constraint instead. assertion_messages_tests.c:000: Failure: AssertionMessage -> for_compare_null_to_area Wanted to compare contents with [area], but NULL was used for the pointer we wanted to compare to. If you want to explicitly check for null, use the is_null constraint instead. assertion_messages_tests.c:000: Failure: AssertionMessage -> for_comparing_content_with_negative_length Wanted to compare contents with [something], but [-4] was given for the comparison size. assertion_messages_tests.c:000: Failure: AssertionMessage -> for_using_double_constraints_with_assert_that Constraints of double type, such as [equal double], should only be used with 'assert_that_double()' to ensure proper comparison. assertion_messages_tests.c:000: Failure: AssertionMessage -> for_using_double_constraints_with_assert_that Expected [3] to [equal double] [3.1415926] assertion_messages_tests.c:000: Failure: AssertionMessage -> for_using_double_constraints_with_assert_that Constraints of double type, such as [be less than double], should only be used with 'assert_that_double()' to ensure proper comparison. assertion_messages_tests.c:000: Failure: AssertionMessage -> for_using_double_constraints_with_assert_that Constraints of double type, such as [be greater than double], should only be used with 'assert_that_double()' to ensure proper comparison. assertion_messages_tests.c:000: Failure: AssertionMessage -> for_using_double_constraints_with_assert_that Expected [7] to [be greater than double] [3.1415926] assertion_messages_tests.c:000: Failure: AssertionMessage -> for_using_non_double_constraints_with_assert_that_double Only constraints of double type should be used with 'assert_that_double()'. Other types of constraints, such as [equal], will probably fail comparison. assertion_messages_tests.c:000: Failure: AssertionMessage -> for_using_non_double_constraints_with_assert_that_double Expected [3] to [equal] [3] within [8] significant figures actual value: [3.000000] expected value: [0.000000] assertion_messages_tests.c:000: Failure: AssertionMessage -> return_value_constraints_are_not_allowed Got constraint of type [return value], but they are not allowed for assertions, only in mock expectations. "AssertionMessage": 1 pass, 12 failures in 0ms. Completed "assertion_messages_tests": 1 pass, 12 failures in 0ms. cgreen-1.6.3/tests/assertion_tests.c000066400000000000000000000265001450461175400175350ustar00rootroot00000000000000#include #include #ifndef __cplusplus #include #endif #include #include #ifdef __cplusplus using namespace cgreen; #endif Ensure(integer_one_should_assert_true) { assert_that(1, is_true); } Ensure(integer_one_should_assert_true_short) { assert_that(1); } Ensure(integer_two_should_assert_true) { assert_that(2, is_true); } Ensure(integer_zero_should_assert_false) { assert_that(0, is_false); } Ensure(one_should_assert_equal_to_one) { assert_that(1, is_equal_to(1)); } Ensure(zero_should_assert_not_equal_to_one) { assert_that(0, is_not_equal_to(1)); } Ensure(one_should_assert_long_equal_to_one) { long x = 1; long y = 1; assert_that(x, is_equal_to(y)); } Ensure(zero_should_assert_long_not_equal_to_one) { long x = 0; long y = 1; assert_that(x, is_not_equal_to(y)); } Ensure(one_should_assert_unsigned_long_equal_to_one) { unsigned long x = 1; unsigned long y = 1; assert_that(x, is_equal_to(y)); } Ensure(zero_should_assert_unsigned_long_not_equal_to_one) { unsigned long x = 0; unsigned long y = 1; assert_that(x, is_not_equal_to(y)); } Ensure(one_should_assert_long_long_equal_to_one) { long long x = 1; long long y = 1; assert_that(x, is_equal_to(y)); } Ensure(zero_should_assert_long_long_not_equal_to_one) { long long x = 0; long long y = 1; assert_that(x, is_not_equal_to(y)); } Ensure(one_should_assert_unsigned_long_long_equal_to_one) { unsigned long long x = 1; unsigned long long y = 1; assert_equal(x, y); } Ensure(zero_should_assert_unsigned_long_long_not_equal_to_one) { unsigned long long x = 0; unsigned long long y = 1; assert_that(x, is_not_equal_to(y)); } Ensure(one_should_assert_short_equal_to_one) { short x = 1; short y = 1; assert_equal(x, y); } Ensure(zero_should_assert_short_not_equal_to_one) { short x = 0; short y = 1; assert_not_equal(x, y); } Ensure(one_should_assert_unsigned_short_equal_to_one) { unsigned short x = 1; unsigned short y = 1; assert_equal(x, y); } Ensure(zero_should_assert_unsigned_short_not_equal_to_one) { unsigned short x = 0; unsigned short y = 1; assert_not_equal(x, y); } Ensure(one_should_assert_char_equal_to_one) { char x = 1; char y = 1; assert_equal(x, y); } Ensure(zero_should_assert_char_not_equal_to_one) { char x = 0; char y = 1; assert_not_equal(x, y); } Ensure(one_should_assert_unsigned_char_equal_to_one) { unsigned char x = 1; unsigned char y = 1; assert_equal(x, y); } Ensure(zero_should_assert_unsigned_char_not_equal_to_one) { unsigned char x = 0; unsigned char y = 1; assert_not_equal(x, y); } Ensure(different_pointers_with_different_contents_should_not_assert_equal) { int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 666 }; int other_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 666 }; assert_that(data, is_equal_to_contents_of(other_data, sizeof(other_data)) ); } Ensure(different_pointers_with_same_contents_should_assert_equal) { int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 }; int same_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 }; assert_that(data, is_equal_to_contents_of(same_data, sizeof(same_data)) ); } Ensure(one_should_assert_float_equal_to_one) { float x = 1; float y = 1; assert_that_double(x, is_equal_to_double(y)); } Ensure(zero_should_assert_float_not_equal_to_one) { float x = 0; float y = 1; assert_that_double(x, is_not_equal_to_double(y)); } Ensure(one_should_assert_double_equal_to_one) { assert_that_double(1, is_equal_to_double(1)); } Ensure(zero_should_assert_double_not_equal_to_one) { assert_double_not_equal(0, 1); } Ensure(zero_should_assert_double_equal_to_zero) { assert_double_equal(0, 0); } Ensure(one_should_assert_long_double_equal_to_one) { long double x = 1; long double y = 1; assert_that_double(x, is_equal_to_double(y)); } Ensure(zero_should_assert_long_double_not_equal_to_one) { long double x = 0; long double y = 1; assert_that_double(x, is_not_equal_to_double(y)); } Ensure(double_differences_do_not_matter_past_significant_figures) { significant_figures_for_assert_double_are(3); assert_that_double(1.113, is_equal_to_double(1.115)); assert_that_double(1113, is_equal_to_double(1115)); assert_that_double(1113000, is_equal_to_double(1115000)); assert_that_double(1.1199999999, is_less_than_double(1.11)); assert_that_double(1.11, is_greater_than_double(1.119999)); } Ensure(can_check_equality_of_negative_floating_point_numbers) { significant_figures_for_assert_double_are(3); assert_that_double(-1.113, is_equal_to_double(-1.115)); assert_that_double(-1.13, is_not_equal_to_double(-1.15)); } Ensure(double_one_is_less_than_two) { assert_that_double(1.0, is_less_than_double(2.0)); } Ensure(double_one_is_greater_than_zero) { assert_that_double(1.0, is_greater_than_double(0.0)); } Ensure(double_can_compare_negative_numbers) { assert_that_double(1.0, is_greater_than_double(-10.0)); assert_that_double(-2.0, is_less_than_double(1.0)); assert_that_double(-21.0, is_less_than_double(-10.0)); assert_that_double(-11.0, is_greater_than_double(-12.0)); } Ensure(double_differences_matter_past_significant_figures) { significant_figures_for_assert_double_are(4); assert_that_double(1.113, is_not_equal_to_double(1.115)); assert_that_double(1.113, is_less_than_double(1.115)); assert_that_double(1.115, is_greater_than_double(1.113)); assert_that_double(1113, is_not_equal_to_double(1115)); assert_that_double(1113000, is_not_equal_to_double(1115000)); } Ensure(double_assertions_can_have_custom_messages) { significant_figures_for_assert_double_are(3); /* this passes because the difference is below the set significant figure */ assert_that_double(1.113, is_equal_to_double(1.115)); } Ensure(identical_string_copies_should_match) { assert_that("Hello", is_equal_to_string("Hello")); } Ensure(case_different_strings_should_not_match) { assert_that("Hello", is_not_equal_to_string("hello")); } Ensure(identical_strings_contain_eachother) { assert_that("Hello", contains_string("Hello")); } Ensure(contains_substring_at_beginning) { assert_that("Hello", contains_string("Hell")); } Ensure(contains_substring_at_end) { assert_that("Hello", contains_string("llo")); } Ensure(contains_substring_after_newline) { assert_that("Hello\nagain", contains_string("gai")); } Ensure(null_string_should_only_match_another_null_string) { assert_string_equal(NULL, NULL); assert_string_not_equal(NULL, ""); assert_string_not_equal("", NULL); // fluent syntax technically doesn't allow NULL on left-hand side // we force the issue to make sure we are testing both syntaxes assert_that((intptr_t)NULL, is_equal_to_string((char *)NULL)); assert_that((intptr_t)NULL, is_not_equal_to_string("")); assert_that("", is_not_equal_to_string((char *)NULL)); } Ensure(null_string_should_only_match_another_null_string_even_with_messages) { assert_string_equal_with_message(NULL, NULL, "Oh dear"); assert_string_equal_with_message("", "", "Oh dear"); assert_string_not_equal_with_message(NULL, "", "Oh dear"); assert_string_not_equal_with_message("", NULL, "Oh dear"); } /* * TODO: make TestContext more easily injectable so we can trap the failure * and compare the message. for now, manually uncomment and verify. */ Ensure(inspecting_contents_of_expected_value_of_null_produces_nice_error_message) { // char buffer[0]; // const int NON_ZERO = !0; // assert_that(buffer, is_equal_to_contents_of(NULL, NON_ZERO)); } Ensure(inspecting_contents_of_actual_value_of_null_produces_nice_error_message) { // char buffer[0]; // const int NON_ZERO = !0; // assert_that(NULL, is_equal_to_contents_of(buffer, NON_ZERO)); } Ensure(inspecting_contents_of_with_zero_size_produces_nice_error_message) { // char buffer[0]; // const int ZERO = 0; // assert_that(buffer, is_equal_to_contents_of(buffer, ZERO)); } Ensure(fail_reports_message) { // fail("\n*** correctly failing ***\n"); } Ensure(return_value_constraints_are_not_allowed) { // assert_that(0, will_return(1)); } TestSuite *assertion_tests(void) { TestSuite *suite = create_test_suite(); add_test(suite, integer_one_should_assert_true); add_test(suite, integer_two_should_assert_true); add_test(suite, integer_zero_should_assert_false); add_test(suite, one_should_assert_equal_to_one); add_test(suite, zero_should_assert_not_equal_to_one); add_test(suite, one_should_assert_long_equal_to_one); add_test(suite, zero_should_assert_long_not_equal_to_one); add_test(suite, one_should_assert_unsigned_long_equal_to_one); add_test(suite, zero_should_assert_unsigned_long_not_equal_to_one); add_test(suite, one_should_assert_long_long_equal_to_one); add_test(suite, zero_should_assert_long_long_not_equal_to_one); add_test(suite, one_should_assert_unsigned_long_long_equal_to_one); add_test(suite, zero_should_assert_unsigned_long_long_not_equal_to_one); add_test(suite, one_should_assert_short_equal_to_one); add_test(suite, zero_should_assert_short_not_equal_to_one); add_test(suite, one_should_assert_unsigned_short_equal_to_one); add_test(suite, zero_should_assert_unsigned_short_not_equal_to_one); add_test(suite, one_should_assert_char_equal_to_one); add_test(suite, zero_should_assert_char_not_equal_to_one); add_test(suite, one_should_assert_unsigned_char_equal_to_one); add_test(suite, zero_should_assert_unsigned_char_not_equal_to_one); add_test(suite, different_pointers_with_different_contents_should_not_assert_equal); add_test(suite, different_pointers_with_same_contents_should_assert_equal); add_test(suite, one_should_assert_float_equal_to_one); add_test(suite, zero_should_assert_float_not_equal_to_one); add_test(suite, one_should_assert_double_equal_to_one); add_test(suite, zero_should_assert_double_not_equal_to_one); add_test(suite, zero_should_assert_double_equal_to_zero); add_test(suite, one_should_assert_long_double_equal_to_one); add_test(suite, zero_should_assert_long_double_not_equal_to_one); add_test(suite, double_differences_do_not_matter_past_significant_figures); add_test(suite, can_check_equality_of_negative_floating_point_numbers); add_test(suite, double_one_is_less_than_two); add_test(suite, double_one_is_greater_than_zero); add_test(suite, double_can_compare_negative_numbers); add_test(suite, double_differences_matter_past_significant_figures); add_test(suite, double_assertions_can_have_custom_messages); add_test(suite, identical_string_copies_should_match); add_test(suite, case_different_strings_should_not_match); add_test(suite, identical_strings_contain_eachother); add_test(suite, null_string_should_only_match_another_null_string); add_test(suite, null_string_should_only_match_another_null_string_even_with_messages); add_test(suite, inspecting_contents_of_expected_value_of_null_produces_nice_error_message); add_test(suite, inspecting_contents_of_actual_value_of_null_produces_nice_error_message); add_test(suite, inspecting_contents_of_with_zero_size_produces_nice_error_message); add_test(suite, fail_reports_message); add_test(suite, return_value_constraints_are_not_allowed); return suite; } cgreen-1.6.3/tests/assertion_tests.cpp000066400000000000000000000006431450461175400200750ustar00rootroot00000000000000/* This file used to be a link to the corresponding .c file because we want to compile the same tests for C and C++. But since some systems don't handle symbolic links the same way as *ix systems we get inconsistencies (looking at you Cygwin) or plain out wrong (looking at you MSYS2, copying ?!?!?) behaviour. So we will simply include the complete .c source instead... */ #include "assertion_tests.c" cgreen-1.6.3/tests/breadcrumb_tests.c000066400000000000000000000065271450461175400176430ustar00rootroot00000000000000#include #include #include #include #ifdef __cplusplus using namespace cgreen; #endif static CgreenBreadcrumb* breadcrumb; static void breadcrumb_tests_setup(void) { breadcrumb = create_breadcrumb(); } static void breadcrumb_tests_teardown(void) { destroy_breadcrumb(breadcrumb); } Describe(Breadcrumb); BeforeEach(Breadcrumb) { breadcrumb_tests_setup(); } AfterEach(Breadcrumb) { breadcrumb_tests_teardown(); } Ensure(Breadcrumb, can_destroy_empty_breadcrumb) { destroy_breadcrumb(create_breadcrumb()); } Ensure(Breadcrumb, last_name_pushed_is_current) { push_breadcrumb(breadcrumb, "Hello"); assert_that(get_current_from_breadcrumb(breadcrumb), is_equal_to_string("Hello")); } Ensure(Breadcrumb, can_push_more_than_one_item) { push_breadcrumb(breadcrumb, "Hello"); push_breadcrumb(breadcrumb, "Goodbye"); assert_that(get_current_from_breadcrumb(breadcrumb), is_equal_to_string("Goodbye")); } Ensure(Breadcrumb, popping_item_takes_us_back_to_the_previous_item) { push_breadcrumb(breadcrumb, "Hello"); push_breadcrumb(breadcrumb, "Goodbye"); pop_breadcrumb(breadcrumb); assert_that(get_current_from_breadcrumb(breadcrumb), is_equal_to_string("Hello")); } Ensure(Breadcrumb, empty_breadcrumb_has_null_as_current) { assert_that(get_current_from_breadcrumb(breadcrumb), is_null); } Ensure(Breadcrumb, popping_last_name_leaves_breadcrumb_empty) { push_breadcrumb(breadcrumb, "Hello"); pop_breadcrumb(breadcrumb); assert_that(get_current_from_breadcrumb(breadcrumb), is_null); } void mock_walker(const char *name, void *memo) { mock(name, memo); } Ensure(Breadcrumb, empty_breadcrumb_does_not_trigger_walker) { never_expect(mock_walker); walk_breadcrumb(breadcrumb, &mock_walker, NULL); } Ensure(Breadcrumb, single_item_breadcrumb_does_calls_walker_only_once) { expect(mock_walker, when(name, is_equal_to_string("Hello"))); push_breadcrumb(breadcrumb, "Hello"); walk_breadcrumb(breadcrumb, &mock_walker, NULL); } Ensure(Breadcrumb, double_item_breadcrumb_does_calls_walker_only_once) { expect(mock_walker, when(name, is_equal_to_string("Hello"))); expect(mock_walker, when(name, is_equal_to_string("Goodbye"))); push_breadcrumb(breadcrumb, "Hello"); push_breadcrumb(breadcrumb, "Goodbye"); walk_breadcrumb(breadcrumb, &mock_walker, NULL); } TestSuite *breadcrumb_tests(void) { TestSuite *suite = create_test_suite(); set_setup(suite, breadcrumb_tests_setup); add_test_with_context(suite, Breadcrumb, can_destroy_empty_breadcrumb); add_test_with_context(suite, Breadcrumb, last_name_pushed_is_current); add_test_with_context(suite, Breadcrumb, can_push_more_than_one_item); add_test_with_context(suite, Breadcrumb, popping_item_takes_us_back_to_the_previous_item); add_test_with_context(suite, Breadcrumb, empty_breadcrumb_has_null_as_current); add_test_with_context(suite, Breadcrumb, popping_last_name_leaves_breadcrumb_empty); add_test_with_context(suite, Breadcrumb, empty_breadcrumb_does_not_trigger_walker); add_test_with_context(suite, Breadcrumb, single_item_breadcrumb_does_calls_walker_only_once); add_test_with_context(suite, Breadcrumb, double_item_breadcrumb_does_calls_walker_only_once); set_teardown(suite, breadcrumb_tests_teardown); return suite; } cgreen-1.6.3/tests/breadcrumb_tests.cpp000066400000000000000000000006441450461175400201750ustar00rootroot00000000000000/* This file used to be a link to the corresponding .c file because we want to compile the same tests for C and C++. But since some systems don't handle symbolic links the same way as *ix systems we get inconsistencies (looking at you Cygwin) or plain out wrong (looking at you MSYS2, copying ?!?!?) behaviour. So we will simply include the complete .c source instead... */ #include "breadcrumb_tests.c" cgreen-1.6.3/tests/cdash_reporter_tests.c000066400000000000000000000134771450461175400205430ustar00rootroot00000000000000#include #include #include #include #include #include #include "src/cdash_reporter_internal.h" #ifdef __cplusplus using namespace cgreen; #endif static const int line=666; static char *output = NULL; static void clear_output(void) { if (NULL != output) { free(output); } output = (char*)malloc(1); *output = '\0'; } static char *concat(char *output, char *buffer) { output = (char *) realloc(output, strlen(output)+strlen(buffer)+1); strcat(output, buffer); return output; } static int mocked_vprinter(FILE *stream, const char *format, va_list ap) { (void)stream; /* Unused */ char buffer[10000]; vsnprintf(buffer, sizeof(buffer), format, ap); output = concat(output, buffer); return strlen(output); } static int mocked_printer(FILE *stream, const char *format, ...) { int result = 0; va_list ap; va_start(ap, format); result = mocked_vprinter(stream, format, ap); va_end(ap); return result; } static TestReporter *reporter; static CDashInfo info; static void setup_cdash_reporter_tests(void) { reporter = create_cdash_reporter(&info); // We can not use setup_reporting() since we are running // inside a test suite which needs the real reporting // So we'll have to set up the messaging explicitly reporter->ipc = start_cgreen_messaging(666); clear_output(); set_cdash_reporter_printer(reporter, mocked_printer); set_cdash_reporter_vprinter(reporter, mocked_vprinter); } static void teardown_cdash_reporter_tests(void) { reporter->destroy(reporter); //bad mojo when running tests in same process, as destroy_reporter also sets //context.reporter = NULL, thus breaking the next test to run if (NULL != output) { free(output); //need to set output to NULL to avoid second free in subsequent call to setup_cdash_reporter_tests->clear_output //when running tests in same process output = NULL; } } Describe(CDashReporter); BeforeEach(CDashReporter) { setup_cdash_reporter_tests(); } AfterEach(CDashReporter) { teardown_cdash_reporter_tests(); } Ensure(CDashReporter, will_report_nothing_for_suites) { reporter->start_suite(reporter, "suite_name", 2); reporter->finish_suite(reporter, "filename", line); } Ensure(CDashReporter, will_report_passed_for_test_with_one_pass) { va_list arguments; reporter->start_test(reporter, "test_name"); memset(&arguments, 0, sizeof(va_list)); reporter->show_pass(reporter, "file", 2, "test_name", arguments); // Must indicate test case completion before calling finish_test() send_reporter_completion_notification(reporter); reporter->finish_test(reporter, "filename", line, NULL); assert_that(output, contains_string("")); } Ensure(CDashReporter, will_report_failed_once_for_each_fail) { va_list arguments; reporter->start_test(reporter, "test_name"); reporter->failures++; // Simulating a failed assert memset(&arguments, 0, sizeof(va_list)); reporter->show_fail(reporter, "file", 2, "test_name", arguments); assert_that(output, contains_string("")); assert_that(output, contains_string("test_name")); assert_that(output, contains_string("file")); assert_that(output, contains_string("at [file] line [2]")); clear_output(); reporter->failures++; // Simulating another failed assert reporter->show_fail(reporter, "file", 3, "test_name", arguments); assert_that(output, contains_string("")); assert_that(output, contains_string("test_name")); assert_that(output, contains_string("at [file] line [3]")); clear_output(); // Must indicate test case completion before calling finish_test() send_reporter_completion_notification(reporter); reporter->finish_test(reporter, "filename", line, NULL); assert_that(output, is_equal_to_string("")); } static void wrapped_show_fail(TestReporter *reporter, const char *file, int line, const char *message, ...) { va_list arguments; va_start(arguments, message); reporter->show_fail(reporter, file, line, message, arguments); va_end(arguments); } Ensure(CDashReporter, will_use_arguments_for_show_fail) { reporter->start_test(reporter, "test_name"); reporter->failures++; // Simulating a failed assert wrapped_show_fail(reporter, "file", 2, "test_case %i is %s", 5, "alive"); assert_that(output, contains_string("test_case 5 is alive")); clear_output(); // Must indicate test case completion before calling finish_test() send_reporter_completion_notification(reporter); reporter->finish_test(reporter, "filename", line, NULL); assert_that(output, is_equal_to_string("")); } Ensure(CDashReporter, will_report_non_finishing_test) { const int line = 666; reporter->start_suite(reporter, "suite_name", 1); send_reporter_exception_notification(reporter); reporter->finish_suite(reporter, "filename", line); assert_that(output, contains_string("")); } TestSuite *cdash_reporter_tests(void) { TestSuite *suite = create_test_suite(); set_setup(suite, setup_cdash_reporter_tests); add_test_with_context(suite, CDashReporter, will_report_nothing_for_suites); add_test_with_context(suite, CDashReporter, will_report_passed_for_test_with_one_pass); add_test_with_context(suite, CDashReporter, will_report_failed_once_for_each_fail); add_test_with_context(suite, CDashReporter, will_report_non_finishing_test); set_teardown(suite, teardown_cdash_reporter_tests); return suite; } cgreen-1.6.3/tests/cdash_reporter_tests.cpp000066400000000000000000000006501450461175400210700ustar00rootroot00000000000000/* This file used to be a link to the corresponding .c file because we want to compile the same tests for C and C++. But since some systems don't handle symbolic links the same way as *ix systems we get inconsistencies (looking at you Cygwin) or plain out wrong (looking at you MSYS2, copying ?!?!?) behaviour. So we will simply include the complete .c source instead... */ #include "cdash_reporter_tests.c" cgreen-1.6.3/tests/cgreen_value_tests.c000066400000000000000000000037441450461175400201720ustar00rootroot00000000000000#include #include #include "cgreen_value_internal.h" #ifdef __cplusplus using namespace cgreen; #endif Describe(CgreenValue); BeforeEach(CgreenValue) {} AfterEach(CgreenValue) {} Ensure(CgreenValue, makes_integer_value) { CgreenValue value = make_cgreen_integer_value(14); assert_that(value.type, is_equal_to(CGREEN_INTEGER)); assert_that(value.value.integer_value, is_equal_to(14)); destroy_cgreen_value(value); } Ensure(CgreenValue, makes_string_value) { CgreenValue value = make_cgreen_string_value("hej hopp"); assert_that(value.type, is_equal_to(CGREEN_STRING)); assert_that(value.value.string_value, is_equal_to_string("hej hopp")); destroy_cgreen_value(value); } Ensure(CgreenValue, makes_pointer_value) { int buffer[20]; CgreenValue value = make_cgreen_pointer_value(buffer); assert_that(value.type, is_equal_to(CGREEN_POINTER)); assert_that(value.value.string_value, is_equal_to(buffer)); destroy_cgreen_value(value); } Ensure(CgreenValue, makes_double_value) { CgreenValue value = make_cgreen_double_value(3.1415926); assert_that(value.type, is_equal_to(CGREEN_DOUBLE)); assert_that_double(value.value.double_value, is_equal_to_double(3.1415926)); destroy_cgreen_value(value); } Ensure(CgreenValue, makes_by_value) { char actualString[] = "1234"; CgreenValue value = make_cgreen_by_value(actualString, 4); assert_that(value.type, is_equal_to(CGREEN_BYVALUE)); assert_that(value.value.pointer_value, is_equal_to_string("1234")); } TestSuite *cgreen_value_tests(void) { TestSuite *suite = create_test_suite(); add_test_with_context(suite, CgreenValue, makes_integer_value); add_test_with_context(suite, CgreenValue, makes_string_value); add_test_with_context(suite, CgreenValue, makes_pointer_value); add_test_with_context(suite, CgreenValue, makes_double_value); add_test_with_context(suite, CgreenValue, makes_by_value); return suite; } cgreen-1.6.3/tests/cgreen_value_tests.cpp000066400000000000000000000006461450461175400205300ustar00rootroot00000000000000/* This file used to be a link to the corresponding .c file because we want to compile the same tests for C and C++. But since some systems don't handle symbolic links the same way as *ix systems we get inconsistencies (looking at you Cygwin) or plain out wrong (looking at you MSYS2, copying ?!?!?) behaviour. So we will simply include the complete .c source instead... */ #include "cgreen_value_tests.c" cgreen-1.6.3/tests/constraint_messages_tests.c000066400000000000000000000167621450461175400216120ustar00rootroot00000000000000/* Note: the whole point of these tests is that they should fail! This makes it hard to think straight and to give the variables good names ;-) */ #include #include #include #include #ifdef HAVE_SYS_RESOURCE_H #include #endif #ifdef __cplusplus using namespace cgreen; #endif Describe(ConstraintMessage); BeforeEach(ConstraintMessage) {} AfterEach(ConstraintMessage) {} Ensure(ConstraintMessage,for_is_null) { int i; int *pointer = &i; assert_that(pointer, is_null); } Ensure(ConstraintMessage,for_is_non_null) { int *pointer = NULL; assert_that(pointer, is_non_null); } Ensure(ConstraintMessage,for_is_equal_to) { int forty_five = 45, thirty_three = 33; assert_that(forty_five, is_equal_to(thirty_three)); } Ensure(ConstraintMessage, for_is_equal_to_hex) { unsigned char bytes[4]; memset(bytes, 0xaa, sizeof(bytes)); assert_that((unsigned char) bytes[0], is_equal_to_hex(0xbb)); } Ensure(ConstraintMessage, for_is_not_equal_to) { int should_not_be_forty_five = 45, forty_five = 45; assert_that(should_not_be_forty_five, is_not_equal_to(forty_five)); } Ensure(ConstraintMessage, for_is_greater_than) { int forty_five = 45, thirty_three = 33; assert_that(thirty_three, is_greater_than(forty_five)); } Ensure(ConstraintMessage, for_is_less_than) { int forty_five = 45, thirty_three = 33; assert_that(forty_five, is_less_than(thirty_three)); } // Contents of struct/memory Ensure(ConstraintMessage, for_is_equal_to_contents_of) { char forty_five[45] = {45, 44, 43}, thirty_three[33] = {45, 44, 33}; assert_that(thirty_three, is_equal_to_contents_of(forty_five, 45)); } Ensure(ConstraintMessage, for_is_not_equal_to_contents_of) { int forty_five_and_up[3] = {45, 46, 47}, another_forty_five_and_up[3] = {45, 46, 47}; assert_that(forty_five_and_up, is_not_equal_to_contents_of(another_forty_five_and_up, 3)); } // Strings Ensure(ConstraintMessage, for_is_equal_to_string) { const char *forty_five = "this string is fortyfive", *thirty_three = "this string is thirtythree"; assert_that(thirty_three, is_equal_to_string(forty_five)); } Ensure(ConstraintMessage, for_is_not_equal_to_string) { const char *forty_five = "this string is fortyfive", *another_forty_five = "this string is fortyfive"; assert_that(another_forty_five, is_not_equal_to_string(forty_five)); } Ensure(ConstraintMessage, for_contains_string) { const char *forty_five = "fortyfive", *not_containing_forty_five = "this text is thirtythree"; assert_that(not_containing_forty_five, contains_string(forty_five)); } Ensure(ConstraintMessage, for_does_not_contain_string) { const char *contains_forty_five = "this string is fortyfive", *forty_five = "fortyfive"; assert_that(contains_forty_five, does_not_contain_string(forty_five)); } Ensure(ConstraintMessage, for_begins_with_string) { const char *does_not_begin_with_forty_five = "this string does not begin with fortyfive", *forty_five = "fortyfive"; assert_that(does_not_begin_with_forty_five, begins_with_string(forty_five)); } Ensure(ConstraintMessage, for_does_not_begin_with_string) { const char *begins_with_forty_five = "fortyfive is the start of this", *forty_five = "fortyfive"; assert_that(begins_with_forty_five, does_not_begin_with_string(forty_five)); } Ensure(ConstraintMessage, for_ends_with_string) { const char *does_not_end_with_forty_five = "fortyfive is not the end of this string", *forty_five = "fortyfive"; assert_that(does_not_end_with_forty_five, ends_with_string(forty_five)); } Ensure(ConstraintMessage, for_does_not_end_with_string) { const char *ends_with_forty_five = "this string ends with fortyfive", *forty_five = "fortyfive"; assert_that(ends_with_forty_five, does_not_end_with_string(forty_five)); } // Double Ensure(ConstraintMessage, for_is_equal_to_double) { double four_point_five = 4.5f, three_point_three = 3.3f; assert_that_double(four_point_five, is_equal_to_double(three_point_three)); } Ensure(ConstraintMessage, for_is_not_equal_to_double) { significant_figures_for_assert_double_are(4); double epsilon = 1.0e-4; double four_point_five = 4.5, almost_four_point_five = 4.5 - epsilon; assert_that_double(four_point_five, is_not_equal_to_double(almost_four_point_five)); } Ensure(ConstraintMessage, for_is_greater_than_double) { double four_point_five = 4.5f, three_point_three = 3.3f; assert_that_double(three_point_three, is_greater_than_double(four_point_five)); } Ensure(ConstraintMessage, for_is_less_than_double) { double four_point_five = 4.5f, three_point_three = 3.3f; assert_that_double(four_point_five, is_less_than_double(three_point_three)); } Ensure(ConstraintMessage, for_equal_to_double) { assert_that_double(0, is_equal_to_double(1)); } Ensure(ConstraintMessage, for_equal_to_double_negative) { assert_that_double(-1, is_equal_to_double(-2)); } Ensure(ConstraintMessage, for_not_equal_to_double) { assert_that_double(0, is_not_equal_to_double(0)); } Ensure(ConstraintMessage, for_not_equal_to_double_negative) { assert_that_double(-1, is_not_equal_to_double(-1)); } Ensure(ConstraintMessage, for_is_less_than_double_with_accuracy) { significant_figures_for_assert_double_are(4); assert_that_double(1.0, is_less_than_double(1.0 - 1.0e-3 - DBL_EPSILON)); } Ensure(ConstraintMessage, for_is_greater_than_double_with_accuracy) { significant_figures_for_assert_double_are(4); assert_that_double(1.0, is_greater_than_double(1.0 + 1.0e-3 + DBL_EPSILON)); } // Basic core assert_that() Ensure(ConstraintMessage, for_assert_that) { assert_that(0 == 1); } // Mocks void some_mock(int parameter) { mock(parameter); } Ensure(ConstraintMessage, for_mock_called_without_expectation) { some_mock(0); } Ensure(ConstraintMessage, for_mock_called_more_times_than_expected) { expect(some_mock); some_mock(0); some_mock(0); } Ensure(ConstraintMessage, for_mock_called_with_unexpected_parameter_value) { expect(some_mock, when(parameter, is_equal_to(1))); some_mock(0); } /* Tests that will fail with "illegal" type of messages */ Ensure(ConstraintMessage, for_always_followed_by_expectation) { always_expect(some_mock, when(parameter, is_equal_to(1))); expect(some_mock, when(parameter, is_equal_to(0))); } Ensure(ConstraintMessage, for_violated_never_expect) { never_expect(some_mock, when(parameter, is_equal_to(1))); some_mock(1); } Ensure(ConstraintMessage, for_mock_parameter_name_not_matching_constraint_parameter_name) { expect(some_mock, when(PARAMETER, is_equal_to(0))); some_mock(0); } void forgot_to_pass_parameters_mock(int x) { (void)x; // to silence compiler warning mock(); } Ensure(ConstraintMessage, for_no_mock_parameters_with_parameter_constraint) { expect(forgot_to_pass_parameters_mock, when(x, is_equal_to(0))); forgot_to_pass_parameters_mock(0); } Ensure(ConstraintMessage, increments_exception_count_when_terminating_via_SIGQUIT) { #ifdef HAVE_SYS_RESOURCE_H struct rlimit core_limit; core_limit.rlim_cur = 1U; core_limit.rlim_max = 1U; setrlimit(RLIMIT_CORE, &core_limit); #endif raise(SIGQUIT); } Ensure(ConstraintMessage, increments_exception_count_when_terminating_via_SIGTERM) { raise(SIGTERM); } #ifdef __cplusplus Ensure(ConstraintMessage, for_incorrect_assert_throws) { assert_throws(std::string, throw "something else"); } Ensure(ConstraintMessage, for_exception_was_expected_but_nothing_thrown) { assert_throws(std::string, (void)5); } #endif cgreen-1.6.3/tests/constraint_messages_tests.expected000066400000000000000000000200241450461175400231530ustar00rootroot00000000000000Running "constraint_messages_tests" (37 tests)... constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_always_followed_by_expectation Mocked function [some_mock] already has an expectation that it will always be called a certain way; any expectations declared after an always expectation are invalid constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_assert_that Expected [0 == 1] to [be true] constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_begins_with_string Expected [does_not_begin_with_forty_five] to [begin with string] [forty_five] actual value: ["this string does not begin with fortyfive"] expected to begin with: ["fortyfive"] constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_contains_string Expected [not_containing_forty_five] to [contain string] [forty_five] actual value: ["this text is thirtythree"] expected to contain: ["fortyfive"] constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_does_not_begin_with_string Expected [begins_with_forty_five] to [not begin with string] [forty_five] actual value: ["fortyfive is the start of this"] expected to not begin with: ["fortyfive"] constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_does_not_contain_string Expected [contains_forty_five] to [not contain string] [forty_five] actual value: ["this string is fortyfive"] expected to not contain: ["fortyfive"] constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_does_not_end_with_string Expected [ends_with_forty_five] to [not end with string] [forty_five] actual value: ["this string ends with fortyfive"] expected to not end with: ["fortyfive"] constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_ends_with_string Expected [does_not_end_with_forty_five] to [end with string] [forty_five] actual value: ["fortyfive is not the end of this string"] expected to end with: ["fortyfive"] constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_equal_to_double Expected [0] to [equal double] [1] within [8] significant figures actual value: [0.000000] expected value: [1.000000] constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_equal_to_double_negative Expected [-1] to [equal double] [-2] within [8] significant figures actual value: [-1.000000] expected value: [-2.000000] constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_is_equal_to Expected [forty_five] to [equal] [thirty_three] actual value: [45] expected value: [33] constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_is_equal_to_contents_of Expected [thirty_three] to [equal contents of] [forty_five] at offset: [2] actual value: [0x21] expected value: [0x2b] constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_is_equal_to_double Expected [four_point_five] to [equal double] [three_point_three] within [8] significant figures actual value: [4.500000] expected value: [3.300000] constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_is_equal_to_hex Expected [(unsigned char) bytes[0]] to [equal] [0xbb] actual value: [0xaa] expected value: [0xbb] constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_is_equal_to_string Expected [thirty_three] to [equal string] [forty_five] actual value: ["this string is thirtythree"] expected to equal: ["this string is fortyfive"] constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_is_greater_than Expected [thirty_three] to [be greater than] [forty_five] actual value: [33] expected to be greater than: [45] constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_is_greater_than_double Expected [three_point_three] to [be greater than double] [four_point_five] within [8] significant figures actual value: [3.300000] expected value: [4.500000] constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_is_greater_than_double_with_accuracy Expected [1.0] to [be greater than double] [1.0 + 1.0e-3 + DBL_EPSILON] within [4] significant figures actual value: [1.000000] expected value: [1.001000] constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_is_less_than Expected [forty_five] to [be less than] [thirty_three] actual value: [45] expected to be less than: [33] constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_is_less_than_double Expected [four_point_five] to [be less than double] [three_point_three] within [8] significant figures actual value: [4.500000] expected value: [3.300000] constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_is_less_than_double_with_accuracy Expected [1.0] to [be less than double] [1.0 - 1.0e-3 - DBL_EPSILON] within [4] significant figures actual value: [1.000000] expected value: [0.999000] constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_is_non_null Expected [pointer] to [be non null] constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_is_not_equal_to Expected [should_not_be_forty_five] to [not equal] [forty_five] actual value: [45] constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_is_not_equal_to_contents_of Expected [forty_five_and_up] to [not equal contents of] [another_forty_five_and_up] constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_is_not_equal_to_double Expected [four_point_five] to [not equal double] [almost_four_point_five] within [4] significant figures actual value: [4.500000] expected value: [4.499900] constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_is_not_equal_to_string Expected [another_forty_five] to [not equal string] [forty_five] actual value: ["this string is fortyfive"] constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_is_null Expected [pointer] to [be null] constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_mock_called_more_times_than_expected Mocked function [some_mock] was called too many times constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_mock_called_with_unexpected_parameter_value Expected [[parameter] parameter in [some_mock]] to [equal] [1] actual value: [0] expected value: [1] constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_mock_called_without_expectation Mocked function [some_mock] did not have an expectation that it would be called constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_mock_parameter_name_not_matching_constraint_parameter_name Mocked function [some_mock] did not define a parameter named [PARAMETER]. Did you misspell it in the expectation or forget it in the mock's argument list? constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_no_mock_parameters_with_parameter_constraint Mocked function [forgot_to_pass_parameters_mock] did not define a parameter named [x]. Did you misspell it in the expectation or forget it in the mock's argument list? constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_not_equal_to_double Expected [0] to [not equal double] [0] within [8] significant figures actual value: [0.000000] expected value: [0.000000] constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_not_equal_to_double_negative Expected [-1] to [not equal double] [-1] within [8] significant figures actual value: [-1.000000] expected value: [-1.000000] constraint_messages_tests.c:000: Failure: ConstraintMessage -> for_violated_never_expect Mocked function [some_mock] has an expectation that it will never be called, but it was constraint_messages_tests.c:000: Exception: ConstraintMessage -> increments_exception_count_when_terminating_via_SIGQUIT Test terminated with signal: Quit constraint_messages_tests.c:000: Exception: ConstraintMessage -> increments_exception_count_when_terminating_via_SIGTERM Test terminated with signal: Terminated "ConstraintMessage": 35 failures, 2 exceptions in 0ms. Completed "constraint_messages_tests": 35 failures, 2 exceptions in 0ms. cgreen-1.6.3/tests/constraint_tests.c000066400000000000000000000273471450461175400177240ustar00rootroot00000000000000#include #include #include #include #ifdef __cplusplus using namespace cgreen; #endif #include "../src/cgreen_value_internal.h" #include "../src/constraint_internal.h" static bool compare_integer_constraint(Constraint *c, int x) { CgreenValue v = make_cgreen_integer_value(x); bool r = (*c->compare)(c, v); destroy_cgreen_value(v); return r; } static bool compare_pointer_constraint(Constraint *c, void *x) { CgreenValue v = make_cgreen_pointer_value(x); bool r = (*c->compare)(c, v); destroy_cgreen_value(v); return r; } static bool compare_string_constraint(Constraint *c, const char *x) { CgreenValue v = make_cgreen_string_value(x); bool r = (*c->compare)(c, v); destroy_cgreen_value(v); return r; } static bool compare_double_constraint(Constraint *c, double x) { CgreenValue v = make_cgreen_double_value(x); bool r = (*c->compare)(c, v); destroy_cgreen_value(v); return r; } Describe(Constraint); BeforeEach(Constraint) {} AfterEach(Constraint) {} Ensure(Constraint, default_destroy_clears_state) { Constraint *constraint = create_constraint(); destroy_constraint(constraint); /* these tests correctly trip valgrind's use-after-free check, so * uncomment and check manually assert_that(constraint->name, NULL); assert_that(constraint->parameter, NULL); assert_that(constraint->storedValue, NULL); assert_that(constraint->test, NULL); assert_that(constraint->compare, NULL); assert_that(constraint->destroy, NULL); */ } Ensure(Constraint, parameter_name_matches_correctly) { Constraint *constraint = create_constraint(); constraint->type = CGREEN_VALUE_COMPARER_CONSTRAINT; constraint->parameter_name = "label"; assert_that(constraint_is_not_for_parameter(constraint, "wrong_label"), is_true); assert_that(constraint_is_not_for_parameter(constraint, "label"), is_false); destroy_constraint(constraint); } Ensure(Constraint, compare_contents_is_correct_on_larger_than_intptr_array) { int content[] = { 0, 1, 2, 3, 4, 5, 6, 7 ,8 ,9, 10, 11, 12, 13, 14, 15 }; int also_content[] = { 0, 1, 2, 3, 4, 5, 6, 7 ,8 ,9, 10, 11, 12, 13, 14, 15 }; Constraint *is_equal_to_contents_constraint = create_equal_to_contents_constraint(content, sizeof(content), "content"); int not_content[] = { 0, 1, 2, 3, 4, 5, 6, 7, 108, 109, 110, 111, 112, 113, 114, 115 }; assert_that(compare_pointer_constraint(is_equal_to_contents_constraint, also_content), is_true); assert_that(compare_pointer_constraint(is_equal_to_contents_constraint, not_content), is_false); destroy_constraint(is_equal_to_contents_constraint); } Ensure(Constraint, compare_is_correct_when_using_integers) { Constraint *is_equal_to_37 = create_equal_to_value_constraint(37, "37"); assert_that(compare_integer_constraint(is_equal_to_37, 37), is_true); assert_that(compare_integer_constraint(is_equal_to_37, 36), is_false); destroy_constraint(is_equal_to_37); } Ensure(Constraint, compare_to_is_null_correctly) { assert_that(0, is_null); assert_that(14, is_not_null); } Ensure(Constraint, string_constraint_destroy_clears_state) { Constraint *string_constraint = create_equal_to_string_constraint("Hello", "user_greeting"); destroy_constraint(string_constraint); /* these checks correctly trip valgrind's use-after-free check, so * uncomment and check manually assert_that(string_constraint->name, is_null); assert_that(string_constraint->parameter, is_null); assert_that(string_constraint->storedValue, is_null); assert_that(string_constraint->test, is_null); assert_that(string_constraint->compare, is_null); assert_that(string_constraint->destroy, is_null); */ } Ensure(Constraint, matching_strings_as_equal) { Constraint *equals_string_hello_constraint = create_equal_to_string_constraint("Hello", "user_greeting"); assert_that(compare_string_constraint(equals_string_hello_constraint, "Hello"), is_true); assert_that(compare_string_constraint(equals_string_hello_constraint, "Goodbye"), is_false); destroy_constraint(equals_string_hello_constraint); } Ensure(Constraint, matching_beginning_of_string) { Constraint *beginning_of_string_hello_constraint = create_begins_with_string_constraint("Hell", "user_greeting"); assert_that(compare_string_constraint(beginning_of_string_hello_constraint, "Hello"), is_true); assert_that(compare_string_constraint(beginning_of_string_hello_constraint, "Goodbye"), is_false); destroy_constraint(beginning_of_string_hello_constraint); } Ensure(Constraint, not_matching_beginning_of_string) { Constraint *beginning_of_string_hello_constraint = create_does_not_begin_with_string_constraint("Goodby", "user_greeting"); assert_that(compare_string_constraint(beginning_of_string_hello_constraint, "Hello"), is_true); assert_that(compare_string_constraint(beginning_of_string_hello_constraint, "Goodbye"), is_false); destroy_constraint(beginning_of_string_hello_constraint); } Ensure(Constraint, matching_end_of_string) { Constraint *end_of_string_hello_constraint = create_ends_with_string_constraint("ello", "user_greeting"); assert_that(compare_string_constraint(end_of_string_hello_constraint, "Hello"), is_true); assert_that(compare_string_constraint(end_of_string_hello_constraint, "Goodbye"), is_false); assert_that(compare_string_constraint(end_of_string_hello_constraint, "Hello ello"), is_true); destroy_constraint(end_of_string_hello_constraint); } Ensure(Constraint, not_matching_end_of_string) { Constraint *end_of_string_hello_constraint = create_does_not_end_with_string_constraint("oodbye", "user_greeting"); assert_that(compare_string_constraint(end_of_string_hello_constraint, "Hello"), is_true); assert_that(compare_string_constraint(end_of_string_hello_constraint, "Goodbye"), is_false); destroy_constraint(end_of_string_hello_constraint); } Ensure(Constraint, matching_null_string_against_non_null_string) { Constraint *equals_string_hello_constraint = create_equal_to_string_constraint("Hello", "user_greeting"); assert_that(compare_string_constraint(equals_string_hello_constraint, NULL), is_false); destroy_constraint(equals_string_hello_constraint); } Ensure(Constraint, matching_against_null_string) { Constraint *equals_null_string_constraint = create_equal_to_string_constraint((const char *)NULL, "user_greeting"); assert_that(compare_string_constraint(equals_null_string_constraint, NULL), is_true); assert_that(compare_string_constraint(equals_null_string_constraint, "Hello"), is_false); destroy_constraint(equals_null_string_constraint); } Ensure(Constraint, matching_doubles_as_equal_with_default_significance) { Constraint *equal_to_double_37 = create_equal_to_double_constraint(37.0, "height"); assert_that(compare_double_constraint(equal_to_double_37, 37.0), is_true); assert_that(compare_double_constraint(equal_to_double_37, 36.0), is_false); destroy_constraint(equal_to_double_37); } Ensure(Constraint, matching_doubles_respects_significant_figure_setting) { Constraint *want_337 = create_equal_to_double_constraint(337.0, "height"); significant_figures_for_assert_double_are(2); assert_that(compare_double_constraint(want_337, 339.0), is_true); significant_figures_for_assert_double_are(3); assert_that(compare_double_constraint(want_337, 339.0), is_false); destroy_constraint(want_337); } // TODO: convert to create_constraint_for_comparator("non-empty string", &is_non_empty_string); //typedef struct { // char* value; // unsigned int length; //} String; // //static int is_non_empty_string(const void* other) { // String* our = (String*)other; // return our->length != 0; //} // //Ensure(Constraint, unequal_structs_with_same_value_for_specific_field_compare_true) { // String name; // name.value = "bob"; // name.length = 3; // // Constraint *string_constraint = with(name, is_non_empty_string); // // assert_that(compare_constraint(string_constraint, is_non_empty_string), is_equal_to(1)); // // destroy_constraint(string_constraint); // // name.value = "tim"; // name.length = 3; // // string_constraint = with(name, is_non_empty_string); // assert_that(compare_constraint(string_constraint, is_non_empty_string), is_equal_to(1)); // // destroy_constraint(string_constraint); //} /* these misuse scenarios should be prevented by checks in higher-level constructs */ #ifdef CANNOT_CREATE_NULL_CONSTRAINTS Ensure(Constraint, cannot_create_contents_constraint_with_null_content) { const size_t NON_ZERO = !0; Constraint *is_equal_to_contents_constraint = create_equal_to_contents_constraint(NULL, NON_ZERO, "NULL"); assert_that(is_equal_to_contents_constraint, is_null); } Ensure(Constraint, cannot_create_contents_constraint_with_zero_size) { int content[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; Constraint *is_equal_to_contents_constraint = create_equal_to_contents_constraint(content, 0, "content"); assert_that(is_equal_to_contents_constraint, is_null); } #endif Ensure(Constraint, compare_equal_to_contents_is_false_on_null) { int content[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; Constraint *is_equal_to_contents_constraint = create_equal_to_contents_constraint(content, sizeof(content), "content"); assert_that(compare_pointer_constraint(is_equal_to_contents_constraint, NULL), is_false); destroy_constraint(is_equal_to_contents_constraint); } Ensure(Constraint, compare_not_equal_to_contents_is_false_on_null) { int content[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; Constraint *is_not_equal_to_contents = create_not_equal_to_contents_constraint(content, sizeof(content), "content"); assert_that(compare_pointer_constraint(is_not_equal_to_contents, NULL), is_false); destroy_constraint(is_not_equal_to_contents); } Ensure(Constraint, can_compare_to_hex) { char chars[3]; memset(chars, 0xaa, sizeof(chars)); assert_that((unsigned char)chars[0], is_equal_to_hex(0xaa)); } TestSuite *constraint_tests(void) { TestSuite *suite = create_test_suite(); add_test_with_context(suite, Constraint, default_destroy_clears_state); add_test_with_context(suite, Constraint, parameter_name_matches_correctly); add_test_with_context(suite, Constraint, compare_contents_is_correct_on_larger_than_intptr_array); add_test_with_context(suite, Constraint, compare_is_correct_when_using_integers); add_test_with_context(suite, Constraint, compare_to_is_null_correctly); add_test_with_context(suite, Constraint, string_constraint_destroy_clears_state); add_test_with_context(suite, Constraint, matching_strings_as_equal); add_test_with_context(suite, Constraint, matching_beginning_of_string); add_test_with_context(suite, Constraint, not_matching_beginning_of_string); add_test_with_context(suite, Constraint, matching_end_of_string); add_test_with_context(suite, Constraint, not_matching_end_of_string); add_test_with_context(suite, Constraint, matching_null_string_against_non_null_string); add_test_with_context(suite, Constraint, matching_against_null_string); add_test_with_context(suite, Constraint, matching_doubles_as_equal_with_default_significance); add_test_with_context(suite, Constraint, matching_doubles_respects_significant_figure_setting); add_test_with_context(suite, Constraint, compare_equal_to_contents_is_false_on_null); add_test_with_context(suite, Constraint, compare_not_equal_to_contents_is_false_on_null); add_test_with_context(suite, Constraint, can_compare_to_hex); // add_test_with_context(suite, Constraint, unequal_structs_with_same_value_for_specific_field_compare_true); return suite; } cgreen-1.6.3/tests/constraint_tests.cpp000066400000000000000000000006441450461175400202530ustar00rootroot00000000000000/* This file used to be a link to the corresponding .c file because we want to compile the same tests for C and C++. But since some systems don't handle symbolic links the same way as *ix systems we get inconsistencies (looking at you Cygwin) or plain out wrong (looking at you MSYS2, copying ?!?!?) behaviour. So we will simply include the complete .c source instead... */ #include "constraint_tests.c" cgreen-1.6.3/tests/cpp_assertion_tests.cpp000066400000000000000000000154371450461175400207460ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include using namespace cgreen; class MyType { public: double x_; double y_; uint64_t z_; MyType(double x, double y, uint64_t z) : x_(x), y_(y), z_(z) {} bool operator==(MyType& other) { return this->z_ == other.z_; } bool operator!=(MyType& other) { return this->z_ != other.z_; } std::ostream& operator<<(std::ostream& stream) { return stream << "x: " << x_ << " " << "y: " << y_ << " " << "z: " << z_ << std::endl; } }; static std::string* bob_pointer = NULL; static std::string* alice_pointer = NULL; static std::string* exception_pointer = NULL; void setup(void) { bob_pointer = alice_pointer = exception_pointer = NULL; // for testing output of exceptions during setup // throw std::logic_error("this is why we fail"); } // TODO: future featre to use stream operators to print expected/actual //Ensure(outputs_expected_value_using_stream_operator) { // MyType first = { 1.1, 2.2, 31337 }; // MyType second = { 1.1, 2.2, 65536 }; // assert_that(first, is_not_equal_to(second)); //} Ensure(custom_large_classes_are_equal) { MyType my_class(3.1337f, 3.14159f, 90210); MyType other(0.0f, 0.0f, 90210); assert_that(my_class == other); } Ensure(custom_large_classes_are_not_equal) { MyType my_class(3.1337f, 3.14159f, 90210); MyType other(3.1337f, 3.14159f, 90211); assert_that(my_class != other); } Ensure(same_stl_string_references_are_equal) { std::string bob("bob"); assert_that(bob, is_equal_to_string(bob)); } Ensure(stl_string_contains_string) { std::string bobbob("bobbob"); assert_that(bobbob, contains_string("obbo")); } Ensure(string_contains_stl_string) { std::string obbo("obbo"); assert_that("bobbob", contains_string(obbo)); } Ensure(string_contains_stl_string_pointer) { bob_pointer = new std::string("obbo"); assert_that("bobbob", contains_string(bob_pointer)); } Ensure(stl_string_does_not_contain_string) { std::string bobbob("bobbob"); assert_that(bobbob, does_not_contain_string("alice")); } Ensure(string_does_not_contain_stl_string) { std::string obbo("obbo"); assert_that("alice", does_not_contain_string(obbo)); } Ensure(string_does_not_contain_stl_string_pointer) { bob_pointer = new std::string("bob"); assert_that("alice", does_not_contain_string(bob_pointer)); } Ensure(stl_string_begins_with_string) { std::string bobbob("bobbob"); assert_that(bobbob, begins_with_string("bob")); } Ensure(string_begins_with_stl_string) { std::string bob("bob"); assert_that("bobbob", begins_with_string(bob)); } Ensure(string_begins_with_stl_string_pointer) { bob_pointer = new std::string("bob"); assert_that("bobbob", begins_with_string(bob_pointer)); } Ensure(different_stl_string_references_are_not_equal) { std::string bob("bob"); std::string alice("alice"); assert_that(bob, is_not_equal_to_string(alice)); } Ensure(different_stl_string_pointers_are_not_equal) { bob_pointer = new std::string("bob"); alice_pointer = new std::string("alice"); assert_that(bob_pointer, is_not_equal_to_string(alice_pointer)); } Ensure(different_stl_string_pointer_and_reference_are_not_equal) { bob_pointer = new std::string("bob"); std::string alice("alice"); assert_that(bob_pointer, is_not_equal_to_string(alice)); } Ensure(different_stl_string_reference_and_pointer_are_not_equal) { bob_pointer = new std::string("bob"); std::string alice("alice"); assert_that(alice, is_not_equal_to_string(bob_pointer)); } Ensure(same_stl_string_pointer_and_reference_are_equal) { alice_pointer = new std::string("alice"); std::string alice_reference("alice"); assert_that(alice_pointer, is_equal_to_string(alice_reference)); } Ensure(same_stl_string_reference_and_pointer_are_equal) { alice_pointer = new std::string("alice"); std::string alice_reference("alice"); assert_that(alice_reference, is_equal_to_string(alice_pointer)); } Ensure(stl_string_pointer_is_not_null) { bob_pointer = new std::string("bob"); assert_that(bob_pointer, is_non_null); } Ensure(stl_string_pointer_is_null) { std::string *null_string = (std::string *)NULL; assert_that(null_string, is_null); } // for quickly iterating on failure message formatting improvements Ensure(stl_string_length_assertion_failure_is_readable) { // auto bob = new std::string("bob"); // assert_that(bob->length(), is_not_equal_to(strlen("bob"))); } Ensure(std_exception_what_is_output) { // throw std::logic_error("this is why we fail"); } static void throwing_function(void) { throw std::string("throwing_function test"); } Ensure(assert_throws_macro_passes_basic_type) { assert_throws(std::string, throwing_function()); } static void pointer_throwing_function(void) { exception_pointer = new std::string("pointer_throwing_function test"); throw exception_pointer; } Ensure(assert_throws_macro_passes_pointer_type) { assert_throws(std::string, pointer_throwing_function()); } void teardown(void) { delete bob_pointer; delete alice_pointer; delete exception_pointer; } TestSuite* cpp_assertion_tests() { TestSuite *suite = create_test_suite(); set_setup(suite, setup); set_teardown(suite, teardown); add_test(suite, custom_large_classes_are_equal); add_test(suite, custom_large_classes_are_not_equal); add_test(suite, same_stl_string_references_are_equal); add_test(suite, stl_string_contains_string); add_test(suite, string_contains_stl_string); add_test(suite, string_contains_stl_string_pointer); add_test(suite, stl_string_does_not_contain_string); add_test(suite, string_does_not_contain_stl_string); add_test(suite, string_does_not_contain_stl_string_pointer); add_test(suite, stl_string_begins_with_string); add_test(suite, string_begins_with_stl_string); add_test(suite, string_begins_with_stl_string_pointer); add_test(suite, different_stl_string_references_are_not_equal); add_test(suite, different_stl_string_pointers_are_not_equal); add_test(suite, different_stl_string_pointer_and_reference_are_not_equal); add_test(suite, different_stl_string_reference_and_pointer_are_not_equal); add_test(suite, same_stl_string_pointer_and_reference_are_equal); add_test(suite, same_stl_string_reference_and_pointer_are_equal); add_test(suite, stl_string_pointer_is_not_null); add_test(suite, stl_string_pointer_is_null); add_test(suite, stl_string_length_assertion_failure_is_readable); add_test(suite, std_exception_what_is_output); add_test(suite, assert_throws_macro_passes_basic_type); add_test(suite, assert_throws_macro_passes_pointer_type); return suite; } cgreen-1.6.3/tests/custom_constraint_messages_tests.c000066400000000000000000000104231450461175400231700ustar00rootroot00000000000000#include #include #include "constraint_internal.h" #include "cgreen_value_internal.h" #include "utils.h" Describe(CustomConstraint); BeforeEach(CustomConstraint) {} AfterEach(CustomConstraint) {} /* Example 1 from documentation : is_bigger_than_5() No argument to the constraint. */ bool compare_want_greater_than_5(Constraint *constraint, CgreenValue actual) { (void)constraint; return actual.value.integer_value > 5; } Constraint static_is_bigger_than_5 = { /* .type */ CGREEN_VALUE_COMPARER_CONSTRAINT, /* .name */ "be bigger than 5", /* .destroy */ destroy_static_constraint, /* .compare */ compare_want_greater_than_5, /* .test */ test_want, /* .format_failure_message_for */ failure_message_for, /* .actual_value_message */ "", /* .expected_value_message */ "", /* .expected_value */ {CGREEN_INTEGER, {5}, 0}, /* .stored_value_name */ "null", /* .parameter_name */ NULL, /* .size_of_stored_value */ 0, /* .side_effect_callback */ NULL, /* .side_effect_data */ NULL }; /* Remember: failing tests to get output */ Ensure(CustomConstraint, custom_constraint_using_static_function) { Constraint * is_bigger_than_5 = &static_is_bigger_than_5; assert_that(1, is_bigger_than_5); } /* Example 2 from documentation : is_smaller_than() Standard data type argument to constraint. */ bool compare_want_smaller_value(Constraint *constraint, CgreenValue actual) { return actual.value.integer_value < constraint->expected_value.value.integer_value ; } Constraint *create_smaller_than_constraint(intptr_t expected_value, const char *expected_value_name) { Constraint *constraint = create_constraint(); constraint->expected_value = make_cgreen_integer_value(expected_value); constraint->expected_value_name = string_dup(expected_value_name); constraint->type = CGREEN_VALUE_COMPARER_CONSTRAINT; constraint->compare = &compare_want_smaller_value; constraint->execute = &test_want; constraint->name = "be smaller than"; constraint->size_of_expected_value = sizeof(intptr_t); return constraint; } #define is_smaller_than(value) create_smaller_than_constraint(value, #value) Ensure(CustomConstraint, custom_constraint_using_a_function_with_arguments_function) { assert_that(19, is_smaller_than(10)); } /* Example 3 from documentation : can_fit_in_box() Using custom data types. */ typedef struct Struct { char id; int size; } Struct; typedef struct Piece { char id; int size; } Piece; bool compare_piece_and_box_size(Constraint *constraint, CgreenValue actual) { return ((Piece *)actual.value.pointer_value)->size < ((Struct*)constraint->expected_value.value.pointer_value)->size ; } static void test_fit_piece(Constraint *constraint, const char *function_name, CgreenValue actual, const char *test_file, int test_line, TestReporter *reporter) { (*reporter->assert_true)( reporter, test_file, test_line, (*constraint->compare)(constraint, actual), "Piece [%f], does not fit in [%f] in function [%s] parameter [%s]", ((Piece *)constraint->expected_value.value.pointer_value)->id, ((Struct *)actual.value.pointer_value)->id, function_name, constraint->parameter_name); } Constraint *create_piece_fit_in_box_constraint(intptr_t expected_value, const char *expected_value_name) { Constraint *constraint = create_constraint(); constraint->expected_value = make_cgreen_pointer_value((void*)expected_value); constraint->expected_value_name = string_dup(expected_value_name); constraint->type = CGREEN_CONTENT_COMPARER_CONSTRAINT; constraint->compare = &compare_piece_and_box_size; constraint->execute = &test_fit_piece; constraint->name = "fit in box"; constraint->size_of_expected_value = sizeof(intptr_t); return constraint; } #define can_fit_in_box(box) create_piece_fit_in_box_constraint((intptr_t)box, #box) Ensure(CustomConstraint, more_complex_custom_constraint_function) { Struct box1 = {.id = (char)1, .size = 5}; Piece piece99 = {.id = (char)99, .size = 6}; assert_that(&piece99, can_fit_in_box(&box1)); } cgreen-1.6.3/tests/custom_constraint_messages_tests.expected000066400000000000000000000013031450461175400245440ustar00rootroot00000000000000Running "custom_constraint_messages_tests" (3 tests)... custom_constraint_messages_tests.c:000: Failure: CustomConstraint -> custom_constraint_using_a_function_with_arguments_function Expected [19] to [be smaller than] [10] custom_constraint_messages_tests.c:000: Failure: CustomConstraint -> custom_constraint_using_static_function Expected [1] to [be bigger than 5] custom_constraint_messages_tests.c:000: Failure: CustomConstraint -> more_complex_custom_constraint_function Expected [&piece99] to [fit in box] [&box1] at offset: [0] actual value: [0x63] expected value: [0x01] "CustomConstraint": 3 failures in 0ms. Completed "custom_constraint_messages_tests": 3 failures in 0ms. cgreen-1.6.3/tests/cute_reporter_tests.c000066400000000000000000000143501450461175400204100ustar00rootroot00000000000000 #include #include #include #include #include #include #include "cute_reporter_internal.h" #ifdef __cplusplus using namespace cgreen; #endif static const int line=666; static char *output = NULL; static void clear_output(void) { if (NULL != output) { free(output); } output = (char*)malloc(1); *output = '\0'; } static char *concat(char *output, char *buffer) { output = (char *) realloc(output, strlen(output)+strlen(buffer)+1); strcat(output, buffer); return output; } static int mocked_vprintf(const char *format, va_list arguments) { char buffer[10000]; vsnprintf(buffer, sizeof(buffer), format, arguments); output = concat(output, buffer); return strlen(output); } static int mocked_printf(const char *format, ...) { int result = 0; va_list ap; va_start(ap, format); result = mocked_vprintf(format, ap); va_end(ap); return result; } static TestReporter *reporter; static void setup_cute_reporter_tests(void) { reporter = create_cute_reporter(); // We can not use setup_reporting() since we are running // inside a test suite which needs the real reporting // So we'll have to set up the messaging explicitly reporter->ipc = start_cgreen_messaging(666); clear_output(); set_cute_reporter_printer(reporter, mocked_printf); set_cute_reporter_vprinter(reporter, mocked_vprintf); } static void teardown_cute_reporter_tests(void) { //bad mojo when running tests in same process, as destroy_reporter also sets //context.reporter = NULL, thus breaking the next test to run destroy_reporter(reporter); if (NULL != output) { free(output); //need to set output to NULL to avoid second free in subsequent call to setup_cute_reporter_tests->clear_output //when running tests in same process output = NULL; } } static void assert_no_output(void) { assert_that(strlen(output), is_equal_to(0)); } Describe(CuteReporter); BeforeEach(CuteReporter) { setup_cute_reporter_tests(); } AfterEach(CuteReporter) { teardown_cute_reporter_tests(); } Ensure(CuteReporter, will_report_beginning_of_suite) { reporter->start_suite(reporter, "suite_name", 2); assert_that(output, begins_with_string("#beginning")); assert_that(output, contains_string("suite_name")); } Ensure(CuteReporter, will_report_beginning_and_successful_finishing_of_test) { va_list arguments; reporter->start_test(reporter, "test_name"); assert_that(output, begins_with_string("#starting")); assert_that(output, contains_string("test_name")); clear_output(); memset(&arguments, 0, sizeof(va_list)); reporter->show_pass(reporter, "file", 2, "test_name", arguments); assert_no_output(); // Must indicate test case completion before calling finish_test() send_reporter_completion_notification(reporter); reporter->finish_test(reporter, "filename", line, NULL); assert_that(output, begins_with_string("#success")); assert_that(output, contains_string("test_name")); } Ensure(CuteReporter, will_report_failing_of_test_only_once) { va_list arguments; reporter->start_test(reporter, "test_name"); clear_output(); reporter->failures++; // Simulating a failed assert memset(&arguments, 0, sizeof(va_list)); reporter->show_fail(reporter, "file", 2, "test_name", arguments); assert_that(output, begins_with_string("#failure")); assert_that(output, contains_string("test_name")); clear_output(); reporter->failures++; // Simulating another failed assert reporter->show_fail(reporter, "file", 2, "test_name", arguments); assert_no_output(); // Must indicate test case completion before calling finish_test() send_reporter_completion_notification(reporter); reporter->finish_test(reporter, "filename", line, NULL); assert_no_output(); } static void wrapped_show_fail(TestReporter *reporter, const char *file, int line, const char *message, ...) { va_list arguments; va_start(arguments, message); reporter->show_fail(reporter, file, line, message, arguments); va_end(arguments); } Ensure(CuteReporter, will_use_arguments_for_show_fail) { reporter->start_test(reporter, "test_name"); clear_output(); reporter->failures++; // Simulating a failed assert wrapped_show_fail(reporter, "file", 2, "test_case %i provides %s", 42, "the answer"); assert_that(output, begins_with_string("#failure")); assert_that(output, contains_string("test_case 42 provides the answer")); clear_output(); // Must indicate test case completion before calling finish_test() send_reporter_completion_notification(reporter); reporter->finish_test(reporter, "filename", line, NULL); assert_no_output(); } Ensure(CuteReporter, will_report_finishing_of_suite) { // Must indicate test suite completion before calling finish_suite() reporter->start_suite(reporter, "suite_name", 1); clear_output(); send_reporter_completion_notification(reporter); reporter->finish_suite(reporter, "filename", line); assert_that(output, begins_with_string("#ending")); assert_that(output, contains_string("suite_name")); } Ensure(CuteReporter, will_report_non_finishing_test) { const int line = 666; reporter->start_suite(reporter, "suite_name", 1); clear_output(); send_reporter_exception_notification(reporter); reporter->finish_suite(reporter, "filename", line); assert_that(output, begins_with_string("#error")); assert_that(output, contains_string("failed to complete")); } TestSuite *cute_reporter_tests(void) { TestSuite *suite = create_test_suite(); set_setup(suite, setup_cute_reporter_tests); add_test_with_context(suite, CuteReporter, will_report_beginning_of_suite); add_test_with_context(suite, CuteReporter, will_report_beginning_and_successful_finishing_of_test); add_test_with_context(suite, CuteReporter, will_report_failing_of_test_only_once); add_test_with_context(suite, CuteReporter, will_report_finishing_of_suite); add_test_with_context(suite, CuteReporter, will_report_non_finishing_test); set_teardown(suite, teardown_cute_reporter_tests); return suite; } cgreen-1.6.3/tests/cute_reporter_tests.cpp000066400000000000000000000006471450461175400207540ustar00rootroot00000000000000/* This file used to be a link to the corresponding .c file because we want to compile the same tests for C and C++. But since some systems don't handle symbolic links the same way as *ix systems we get inconsistencies (looking at you Cygwin) or plain out wrong (looking at you MSYS2, copying ?!?!?) behaviour. So we will simply include the complete .c source instead... */ #include "cute_reporter_tests.c" cgreen-1.6.3/tests/double_tests.c000066400000000000000000000013151450461175400167750ustar00rootroot00000000000000#include #ifdef __cplusplus using namespace cgreen; #endif Describe(Double); BeforeEach(Double) {} AfterEach(Double) {} Ensure(Double, comparison_with_negative_values_should_not_always_succeed) { /* Issue #146 - Fixed */ assert_that_double(-500, is_not_equal_to_double(0)); } Ensure(Double, comparisons_with_extremely_small_numbers_should_not_always_fail) { /* Issue #149 */ assert_that_double(4.9406564584124654E-324, is_equal_to_double(4.9406564584124654E-324)); } Ensure(Double, numbers_within_absolute_tolerance_of_zero_are_considered_equal_to_zero) { double my_dbl_min = 2.2250738585072014e-308; assert_that_double(1.0e4 * my_dbl_min, is_equal_to_double(0.0)); } cgreen-1.6.3/tests/double_tests.cpp000066400000000000000000000006371450461175400173430ustar00rootroot00000000000000/* This file used to be a link to the corresponding .c file because we want to compile the same tests for C and C++. But since some systems don't handle symbolic links the same way as *ix systems we get inconsistencies (looking at you Cygwin) or plain out wrong (looking at you MSYS2, copying ?!?!?) behaviour. So we will simply include the complete .c source instead... */ #include "double_tests.c" cgreen-1.6.3/tests/environment_variables_tests.c000066400000000000000000000007441450461175400221240ustar00rootroot00000000000000#define _POSIX_C_SOURCE 200809L #include /* TODO: are these include necessary? */ #include #include #include #ifdef __cplusplus using namespace cgreen; #endif Describe(EnvironmentVariables); BeforeEach(EnvironmentVariables) { setenv("TEST", "test", true); } AfterEach(EnvironmentVariables) {} Ensure(EnvironmentVariables, set_in_before_each_should_be_set_in_test) { assert_that(getenv("TEST"), is_equal_to_string("test")); } cgreen-1.6.3/tests/environment_variables_tests.cpp000066400000000000000000000006571450461175400224670ustar00rootroot00000000000000/* This file used to be a link to the corresponding .c file because we want to compile the same tests for C and C++. But since some systems don't handle symbolic links the same way as *ix systems we get inconsistencies (looking at you Cygwin) or plain out wrong (looking at you MSYS2, copying ?!?!?) behaviour. So we will simply include the complete .c source instead... */ #include "environment_variables_tests.c" cgreen-1.6.3/tests/failure_messages_tests.c000066400000000000000000000017751450461175400210530ustar00rootroot00000000000000#include #include #include #include #ifdef __cplusplus using namespace cgreen; #endif Describe(FailureMessage); BeforeEach(FailureMessage) {} AfterEach(FailureMessage) {} Ensure(FailureMessage, for_time_out_in_only_one_second) { die_in(1); sleep(10); } Ensure(FailureMessage, for_CGREEN_PER_TEST_TIMEOUT) { // Setting the environment variable here does not work // It needs to be set before the runner forks // setenv("CGREEN_PER_TEST_TIMEOUT", "2", true); // so we leave that to the test environment... // And fail if there is no environment variable set assert_that(getenv("CGREEN_PER_TEST_TIMEOUT"), is_not_equal_to(NULL)); sleep(3); fail_test("This test should have been aborted within CGREEN_PER_TEST_TIMEOUT seconds and not get here. When running this test you need to define CGREEN_PER_TEST_TIMEOUT=2."); } #ifdef __cplusplus Ensure(FailureMessage, increments_exception_count_when_throwing) { throw; } #endif cgreen-1.6.3/tests/failure_messages_tests.expected000066400000000000000000000007761450461175400224320ustar00rootroot00000000000000Running "failure_messages_tests" (2 tests)... failure_messages_tests.c:000: Exception: FailureMessage -> for_CGREEN_PER_TEST_TIMEOUT Test terminated unexpectedly, likely from a non-standard exception or Posix signal failure_messages_tests.c:000: Exception: FailureMessage -> for_time_out_in_only_one_second Test terminated unexpectedly, likely from a non-standard exception or Posix signal "FailureMessage": 1 pass, 2 exceptions in 0ms. Completed "failure_messages_tests": 1 pass, 2 exceptions in 0ms. cgreen-1.6.3/tests/ignore_messages_tests.c000066400000000000000000000016521450461175400207010ustar00rootroot00000000000000#include #include #include #include #include #ifdef HAVE_SYS_RESOURCE_H #include #endif #ifdef __cplusplus using namespace cgreen; #endif Describe(IgnoreMessage); BeforeEach(IgnoreMessage) {} AfterEach(IgnoreMessage) {} Ensure(IgnoreMessage, should_not_count_empty_tests_as_ignored) { } Ensure(IgnoreMessage, should_not_count_passing_tests_as_ignored) { assert_that(true); } Ensure(IgnoreMessage, should_not_count_failing_tests_as_ignored) { assert_that(false); } Ensure(IgnoreMessage, should_not_count_exceptions_as_ignored) { #ifdef HAVE_SYS_RESOURCE_H struct rlimit core_limit; core_limit.rlim_cur = 1U; core_limit.rlim_max = 1U; setrlimit(RLIMIT_CORE, &core_limit); #endif raise(SIGSEGV); } xEnsure(IgnoreMessage, should_present_this_as_ignored) { fail_test("Should not be run since it's inside an ignored test"); } cgreen-1.6.3/tests/ignore_messages_tests.expected000066400000000000000000000007301450461175400222540ustar00rootroot00000000000000Running "ignore_messages_tests" (5 tests)... ignore_messages_tests.c:000: Exception: IgnoreMessage -> should_not_count_exceptions_as_ignored Test terminated with signal: Segmentation fault ignore_messages_tests.c:000: Failure: IgnoreMessage -> should_not_count_failing_tests_as_ignored Expected [0] to [be true] "IgnoreMessage": 1 pass, 1 skipped, 1 failure, 1 exception in 0ms. Completed "ignore_messages_tests": 1 pass, 1 skipped, 1 failure, 1 exception in 0ms. cgreen-1.6.3/tests/libxml_output_tests.c000066400000000000000000000002701450461175400204310ustar00rootroot00000000000000#include Ensure(failing_test_is_listed_by_libxml_reporter) { assert_that(false); } Ensure(passing_test_is_listed_by_libxml_reporter) { assert_that(true); } cgreen-1.6.3/tests/libxml_output_tests.expected000066400000000000000000000012041450461175400220060ustar00rootroot00000000000000 cgreen-1.6.3/tests/libxml_reporter_tests.c000066400000000000000000000340121450461175400207340ustar00rootroot00000000000000#include #include #include #include "cgreen_value_internal.h" #include "constraint_internal.h" #include #include #include #include #include #ifdef __cplusplus using namespace cgreen; #endif #include "libxml_reporter_internal.h" #define XMLSTRING(x) (BAD_CAST x) static const int line=666; static xmlChar *output = NULL; static void clear_output(void) { if (NULL != output) { xmlFree(output); } output = NULL; } static int mocked_xmlout(xmlDocPtr doc) { if (output) { xmlFree(output); } xmlDocDumpMemoryEnc(doc, &output, NULL, "UTF-8"); return 0; } static TestReporter *reporter; static void setup_xml_reporter_tests(void) { reporter = create_libxml_reporter("PREFIX"); // We can not use setup_reporting() since we are running // inside a test suite which needs the real reporting // So we'll have to set up the messaging explicitly reporter->ipc = start_cgreen_messaging(667); clear_output(); set_libxml_reporter_printer(reporter, mocked_xmlout); } static void teardown_xml_reporter_tests(void) { //bad mojo when running tests in same process, as destroy_reporter also sets //context.reporter = NULL, thus breaking the next test to run destroy_reporter(reporter); if (NULL != output) { free(output); //need to set output to NULL to avoid second free in //subsequent call to setup_xml_reporter_tests->clear_output //when running tests in same process output = NULL; } } static xmlChar* getAttribute(xmlNodePtr node, const xmlChar* name) { xmlAttr *attr = node->properties; while (attr) { if (xmlStrEqual(attr->name, name)) { return xmlNodeGetContent((xmlNode*)attr); } attr = attr->next; } return NULL; } static bool hasAttribute(xmlNodePtr node, const xmlChar* name) { xmlAttr *attr = node->properties; while (attr) { if (xmlStrEqual(attr->name, name)) { return true; } attr = attr->next; } return false; } struct xmlNode_has_attribute_equal_to { xmlChar *attr, *value; }; static bool compare_xmlNode_has_attribute_equal_to(Constraint *constraint, CgreenValue actual) { xmlNodePtr actualNode = (xmlNodePtr)actual.value.pointer_value; struct xmlNode_has_attribute_equal_to *expected = (struct xmlNode_has_attribute_equal_to*)constraint->expected_value.value.pointer_value; xmlChar* actualValue = getAttribute(actualNode, expected->attr); bool ret = xmlStrEqual(actualValue, expected->value); xmlFree(actualValue); return ret; } static char *failure_message_xmlNode_has_attribute_equal_to( Constraint *constraint, const char *actual_string, intptr_t actual_value) { struct xmlNode_has_attribute_equal_to *expected = (struct xmlNode_has_attribute_equal_to*)constraint->expected_value.value.pointer_value; xmlChar* actualValue = getAttribute((xmlNodePtr)actual_value, expected->attr); const char *message_template = "Expected attribute [%s] of [%s] to [equal] [%s]\n" "\tactual value:\t\t[%s]\n" "\texpected to equal:\t[%s]\n"; size_t msglen = xmlStrlen(expected->attr) + strlen(actual_string) + strlen(constraint->expected_value_name) + xmlStrlen(actualValue) + xmlStrlen(expected->value) + strlen(message_template); char *message = (char*)malloc(msglen); if (!message) { xmlFree(actualValue); return NULL; } if (snprintf(message, msglen, message_template, expected->attr, actual_string, constraint->expected_value_name, actualValue, expected->value) >= (ssize_t)msglen) { xmlFree(actualValue); free(message); return NULL; } xmlFree(actualValue); return message; } static void destroy_xmlNode_has_attribute_equal_to(Constraint* constraint) { struct xmlNode_has_attribute_equal_to *expected = (struct xmlNode_has_attribute_equal_to*)constraint->expected_value.value.pointer_value; xmlFree(expected->attr); xmlFree(expected->value); free(expected); destroy_empty_constraint(constraint); } static Constraint *create_xmlNode_has_attribute_equal_to(const xmlChar* attr, const xmlChar *value, const char* expected_value_name) { Constraint *constraint = create_constraint(); if (!constraint) return NULL; struct xmlNode_has_attribute_equal_to *expected = (struct xmlNode_has_attribute_equal_to *)malloc(sizeof(struct xmlNode_has_attribute_equal_to)); if (!expected) { constraint->destroy(constraint); return NULL; } expected->attr = xmlStrdup(attr); expected->value = xmlStrdup(value); constraint->expected_value = make_cgreen_pointer_value(expected); constraint->expected_value_name = strdup(expected_value_name); constraint->type = CGREEN_STRING_COMPARER_CONSTRAINT; constraint->compare = &compare_xmlNode_has_attribute_equal_to; constraint->failure_message = &failure_message_xmlNode_has_attribute_equal_to; constraint->name = "have attribute with value"; constraint->size_of_expected_value = sizeof(intptr_t); constraint->destroy = &destroy_xmlNode_has_attribute_equal_to; return constraint; } #define xmlnode_has_attribute_equal_to(attr, value) \ create_xmlNode_has_attribute_equal_to(XMLSTRING(attr), XMLSTRING(value), #value) static xmlNodePtr xmlnode_find_sibling(xmlNodePtr node, const char *name) { while (node) { if (xmlStrEqual(node->name, XMLSTRING(name))) break; node = xmlNextElementSibling(node); } return node; } Describe(LibXmlReporter); BeforeEach(LibXmlReporter) { setup_xml_reporter_tests(); } AfterEach(LibXmlReporter) { teardown_xml_reporter_tests(); } Ensure(LibXmlReporter, will_report_beginning_of_suite) { reporter->start_suite(reporter, "suite_name", 2); reporter->finish_suite(reporter, "filename", line); xmlDocPtr doc = xmlParseDoc(output); assert_that(doc, is_not_null); xmlNodePtr testsuite = xmlDocGetRootElement(doc); assert_that(testsuite->name, is_equal_to_string("testsuite")); assert_that(xmlChildElementCount(testsuite), is_equal_to(0)); assert_that(testsuite, xmlnode_has_attribute_equal_to("name", "suite_name")); xmlFreeDoc(doc); } static void reporter_show_pass_vargs(TestReporter *reporter, const char *name, int line, const char *format, ...) { va_list vargs; va_start(vargs, format); reporter->show_pass(reporter, name, line, format, vargs); va_end(vargs); } Ensure(LibXmlReporter, will_report_beginning_and_successful_finishing_of_passing_test) { reporter->start_suite(reporter, "suite_name", 2); reporter->start_test(reporter, "test_name"); reporter_show_pass_vargs(reporter, "file", 2, "test_name"); send_reporter_completion_notification(reporter); reporter->finish_test(reporter, "filename", line, NULL); reporter->finish_suite(reporter, "filename", line); xmlDocPtr doc = xmlParseDoc(output); assert_that(doc, is_not_null); xmlNodePtr testsuite = xmlDocGetRootElement(doc); assert_that(xmlChildElementCount(testsuite), is_equal_to(1)); xmlNodePtr testcase = xmlFirstElementChild(testsuite); assert_that(testcase->name, is_equal_to_string("testcase")); assert_that(xmlChildElementCount(testcase), is_equal_to(0)); assert_that(testcase, xmlnode_has_attribute_equal_to("name", "test_name")); assert_that(testcase, xmlnode_has_attribute_equal_to("classname", "suite_name")); } static void reporter_show_fail_vargs(TestReporter *reporter, const char *name, int line, const char *format, ...) { va_list vargs; va_start(vargs, format); reporter->show_fail(reporter, name, line, format, vargs); va_end(vargs); } Ensure(LibXmlReporter, will_report_a_failing_test) { reporter->start_suite(reporter, "suite_name", 2); reporter->start_test(reporter, "test_name"); reporter_show_fail_vargs(reporter, "file", 2, "test_name"); send_reporter_completion_notification(reporter); reporter->finish_test(reporter, "filename", line, NULL); reporter->finish_suite(reporter, "filename", line); xmlDocPtr doc = xmlParseDoc(output); assert_that(doc, is_not_null); xmlNodePtr testsuite = xmlDocGetRootElement(doc); assert_that(xmlChildElementCount(testsuite), is_equal_to(1)); xmlNodePtr testcase = xmlFirstElementChild(testsuite); assert_that(testcase->name, is_equal_to_string("testcase")); assert_that(xmlChildElementCount(testcase), is_equal_to(1)); assert_that(hasAttribute(testcase, XMLSTRING("time")), is_true); xmlNodePtr failure = xmlFirstElementChild(testcase); assert_that(failure->name, is_equal_to_string("failure")); assert_that(xmlChildElementCount(failure), is_equal_to(1)); assert_that(failure, xmlnode_has_attribute_equal_to("message", "test_name")); xmlNodePtr location = xmlFirstElementChild(failure); assert_that(location->name, is_equal_to_string("location")); assert_that(xmlChildElementCount(location), is_equal_to(0)); assert_that(location, xmlnode_has_attribute_equal_to("file", "file")); assert_that(location, xmlnode_has_attribute_equal_to("line", "2")); } Ensure(LibXmlReporter, will_report_a_failing_test_only_once) { va_list null_arguments; memset(&null_arguments, 0, sizeof(null_arguments)); reporter->start_suite(reporter, "suite_name", 2); reporter->start_test(reporter, "test_name"); reporter->show_fail(reporter, "file", 2, "test_failure_message", null_arguments); reporter->show_fail(reporter, "file", 2, "other_message", null_arguments); reporter->finish_test(reporter, "filename", line, NULL); reporter->finish_suite(reporter, "filename", line); xmlDocPtr doc = xmlParseDoc(output); xmlNodePtr testsuite = xmlDocGetRootElement(doc); xmlNodePtr testcase = xmlFirstElementChild(testsuite); static const char FAILURE[] = "failure"; xmlNodePtr failure = xmlnode_find_sibling(xmlFirstElementChild(testcase), FAILURE); assert_that(failure->name, is_equal_to_string(FAILURE)); assert_that(failure, xmlnode_has_attribute_equal_to("message", "test_failure_message")); failure = xmlnode_find_sibling(xmlNextElementSibling(failure), FAILURE); assert_that(failure, xmlnode_has_attribute_equal_to("message", "other_message")); failure = xmlnode_find_sibling(xmlNextElementSibling(failure), FAILURE); assert_that(failure, is_null); } Ensure(LibXmlReporter, will_mark_ignored_test_as_skipped) { const int line = 666; reporter->start_suite(reporter, "suite_name", 1); reporter->start_test(reporter, "skipped_test_name"); send_reporter_skipped_notification(reporter); reporter->finish_test(reporter, "filename", line, "message"); reporter->finish_suite(reporter, "filename", line); xmlDocPtr doc = xmlParseDoc(output); assert_that(doc, is_not_null); xmlNodePtr testsuite = xmlDocGetRootElement(doc); assert_that(xmlChildElementCount(testsuite), is_equal_to(1)); xmlNodePtr testcase = xmlFirstElementChild(testsuite); assert_that(testcase->name, is_equal_to_string("testcase")); assert_that(xmlChildElementCount(testcase), is_equal_to(1)); assert_that(hasAttribute(testcase, XMLSTRING("time")), is_true); xmlNodePtr skipped = xmlFirstElementChild(testcase); assert_that(skipped->name, is_equal_to_string("skipped")); assert_that(xmlChildElementCount(skipped), is_equal_to(0)); } Ensure(LibXmlReporter, will_report_non_finishing_test) { const int line = 666; reporter->start_suite(reporter, "suite_name", 1); reporter->start_test(reporter, "test_name"); send_reporter_exception_notification(reporter); reporter->finish_test(reporter, "filename", line, "message"); reporter->finish_suite(reporter, "filename", line); xmlDocPtr doc = xmlParseDoc(output); assert_that(doc, is_not_null); xmlNodePtr testsuite = xmlDocGetRootElement(doc); assert_that(xmlChildElementCount(testsuite), is_equal_to(1)); xmlNodePtr testcase = xmlFirstElementChild(testsuite); assert_that(testcase->name, is_equal_to_string("testcase")); assert_that(xmlChildElementCount(testcase), is_equal_to(1)); assert_that(hasAttribute(testcase, XMLSTRING("time")), is_true); xmlNodePtr error = xmlFirstElementChild(testcase); assert_that(error->name, is_equal_to_string("error")); assert_that(error, xmlnode_has_attribute_equal_to("type", "Fatal")); assert_that(error, xmlnode_has_attribute_equal_to("message", "message")); } Ensure(LibXmlReporter, will_report_time_correctly_for_non_finishing_test) { const int line = 666; reporter->start_suite(reporter, "suite_name", 1); reporter->start_test(reporter, "test_name"); send_reporter_exception_notification(reporter); reporter->finish_test(reporter, "filename", line, "message"); reporter->finish_suite(reporter, "filename", line); assert_that(output, contains_string("name=\"test_name\"")); assert_that(output, contains_string(" time=\"")); } TestSuite *libxml_reporter_tests(void) { TestSuite *suite = create_test_suite(); set_setup(suite, setup_xml_reporter_tests); add_test_with_context(suite, LibXmlReporter, will_report_beginning_of_suite); add_test_with_context(suite, LibXmlReporter, will_report_beginning_and_successful_finishing_of_passing_test); add_test_with_context(suite, LibXmlReporter, will_report_a_failing_test); add_test_with_context(suite, LibXmlReporter, will_report_a_failing_test_only_once); add_test_with_context(suite, LibXmlReporter, will_mark_ignored_test_as_skipped); add_test_with_context(suite, LibXmlReporter, will_report_non_finishing_test); add_test_with_context(suite, LibXmlReporter, will_report_time_correctly_for_non_finishing_test); set_teardown(suite, teardown_xml_reporter_tests); return suite; } cgreen-1.6.3/tests/libxml_reporter_tests.cpp000066400000000000000000000006511450461175400212760ustar00rootroot00000000000000/* This file used to be a link to the corresponding .c file because we want to compile the same tests for C and C++. But since some systems don't handle symbolic links the same way as *ix systems we get inconsistencies (looking at you Cygwin) or plain out wrong (looking at you MSYS2, copying ?!?!?) behaviour. So we will simply include the complete .c source instead... */ #include "libxml_reporter_tests.c" cgreen-1.6.3/tests/message_formatting_tests.c000066400000000000000000000040211450461175400213760ustar00rootroot00000000000000#include #include #include #include "src/constraint_internal.h" #ifdef __cplusplus using namespace cgreen; #endif Describe(MessageFormatting); BeforeEach(MessageFormatting) {} AfterEach(MessageFormatting) {} Ensure(MessageFormatting, can_show_failure_message_containing_percent_sign) { const char *string_with_percent = "This contains %!"; Constraint *constraint = create_equal_to_string_constraint(string_with_percent, "string_with_percent"); char *failure_message = failure_message_for(constraint, "actual_string", (intptr_t)"This contains another %!"); assert_that(failure_message, contains_string("contains %%!")); assert_that(failure_message, contains_string("another %%!")); constraint->destroy(constraint); free(failure_message); } Ensure(MessageFormatting, shows_offset_as_zero_based) { char actual_data[] = {0x0a, 0x0b, 0x0c, 0x0d}; char expected_data[] = {0x0b, 0x0b, 0x0c, 0x0d}; Constraint *constraint = create_equal_to_contents_constraint(expected_data, 4, "expectd_data"); char *failure_message = failure_message_for(constraint, "actual_data", (intptr_t)actual_data); assert_that(failure_message, contains_string("at offset")); assert_that(failure_message, contains_string("[0]")); assert_that(failure_message, contains_string("actual value:")); assert_that(failure_message, contains_string("expected value:")); assert_that(strstr(failure_message, "actual"), is_less_than(strstr(failure_message, "expected"))); assert_that(failure_message, contains_string("0x0a")); assert_that(failure_message, contains_string("0x0b")); assert_that(strstr(failure_message, "0x0a"), is_less_than(strstr(failure_message, "0x0b"))); free(failure_message); destroy_constraint(constraint); } TestSuite *message_formatting_tests(void) { TestSuite *suite = create_test_suite(); add_test_with_context(suite, MessageFormatting, can_show_failure_message_containing_percent_sign); return suite; } cgreen-1.6.3/tests/message_formatting_tests.cpp000066400000000000000000000006541450461175400217460ustar00rootroot00000000000000/* This file used to be a link to the corresponding .c file because we want to compile the same tests for C and C++. But since some systems don't handle symbolic links the same way as *ix systems we get inconsistencies (looking at you Cygwin) or plain out wrong (looking at you MSYS2, copying ?!?!?) behaviour. So we will simply include the complete .c source instead... */ #include "message_formatting_tests.c" cgreen-1.6.3/tests/messaging_tests.c000066400000000000000000000036041450461175400175030ustar00rootroot00000000000000#include #include #include #include #include "../src/utils.h" #include #ifdef __cplusplus using namespace cgreen; #endif Ensure(highly_nested_test_suite_should_still_complete) { assert_that(true); } TestSuite *highly_nested_test_suite(void) { int i; TestSuite *suite = create_test_suite(); add_test(suite, highly_nested_test_suite_should_still_complete); for (i = 0; i < 1000; i++) { TestSuite *nesting = create_test_suite(); add_suite(nesting, suite); suite = nesting; } return suite; } Ensure(can_send_message) { int messaging = start_cgreen_messaging(33); send_cgreen_message(messaging, 99); assert_that(receive_cgreen_message(messaging), is_equal_to(99)); } static int signal_received = 0; static void catch_signal(int s) { (void)s; signal_received = 1; signal(SIGPIPE, SIG_DFL); } Ensure(failure_reported_and_exception_thrown_when_messaging_would_block) { const int LOOPS = 65537; int messaging = start_cgreen_messaging(33); int loop; char panic_message[1000]; signal_received = 0; signal(SIGPIPE, catch_signal); panic_set_output_buffer(panic_message); for (loop = 0; loop < LOOPS; loop++) { send_cgreen_message(messaging, 99); if (signal_received == 1) break; } assert_that(signal_received, is_equal_to(1)); assert_that(loop, is_less_than(LOOPS)); assert_that(panic_message, contains_string("Too many assertions")); } TestSuite *messaging_tests(void) { TestSuite *suite = create_test_suite(); add_suite(suite, highly_nested_test_suite()); add_test(suite, can_send_message); #ifndef WIN32 // TODO: win32 needs non-blocking pipes like posix for this to pass add_test(suite, failure_reported_and_exception_thrown_when_messaging_would_block); #endif return suite; } cgreen-1.6.3/tests/messaging_tests.cpp000066400000000000000000000006431450461175400200430ustar00rootroot00000000000000/* This file used to be a link to the corresponding .c file because we want to compile the same tests for C and C++. But since some systems don't handle symbolic links the same way as *ix systems we get inconsistencies (looking at you Cygwin) or plain out wrong (looking at you MSYS2, copying ?!?!?) behaviour. So we will simply include the complete .c source instead... */ #include "messaging_tests.c" cgreen-1.6.3/tests/mock_messages_tests.c000066400000000000000000000117361450461175400203530ustar00rootroot00000000000000#include #include #include #include #include #ifdef __cplusplus using namespace cgreen; #endif /* NOTE: These tests are not designed to pass, they are run to output messages which need to be compared to some golden output */ Describe(Mocks); BeforeEach(Mocks) {} AfterEach(Mocks) {} static int integer_out(void) { return (int)mock(); } static char *string_out(int p1) { return (char *)mock(p1); } static int sample_mock(int i, const char *s) { return (int)mock(i, s); } Ensure(Mocks, can_declare_function_never_called) { never_expect(sample_mock); sample_mock(0, ""); } Ensure(Mocks, when_never_expected_mock_function_is_not_called_pass_counter_increments_by_one) { never_expect(sample_mock); } Ensure(Mocks, calls_beyond_expected_sequence_fail_when_mocks_are_strict) { expect(integer_out, will_return(1) ); expect(integer_out, will_return(2) ); expect(integer_out, will_return(3) ); assert_that(integer_out(), is_equal_to(1)); assert_that(integer_out(), is_equal_to(2)); assert_that(integer_out(), is_equal_to(3)); // expected fail assert_that(integer_out(), is_equal_to(3)); } static void unexpected_mock(void) { mock(); } Ensure(Mocks, lists_unexpected_mock_calls) { unexpected_mock(); } // These are tentative solutions to mocks returning doubles and // trapping type errors when they do. /* xEnsure(Mocks, traps_double_return_value_for_int_mock) { */ /* expect(integer_out, will_return_double(3.1415926)); */ /* integer_out(); */ /* } */ /* static double double_out() { */ /* return mock_double(); */ /* } */ /* xEnsure(Mocks, traps_int_return_value_for_double_mock) { */ /* expect(double_out, will_return_double(3.1415926)); */ /* assert_that(double_out(), is_equal_to_double(3.1415926)); */ /* } */ Ensure(Mocks, failure_when_no_presets_for_default_strict_mock) { assert_that(integer_out(), is_equal_to(0)); } Ensure(Mocks, failure_reported_when_expect_after_never_expect_for_same_function) { never_expect(integer_out); expect(integer_out); } Ensure(Mocks, failure_reported_when_expect_after_always_expect_for_same_function) { always_expect(integer_out, will_return(666) ); expect(integer_out); } Ensure(Mocks, reports_multiple_always_expect) { always_expect(integer_out); always_expect(integer_out); } Ensure(Mocks, reports_always_expect_after_never_expect_for_same_function) { never_expect(integer_out); always_expect(integer_out); } Ensure(Mocks, reports_never_expect_after_always_expect_for_same_function) { always_expect(integer_out); never_expect(integer_out); } Ensure(Mocks, reports_multiple_never_expect) { never_expect(integer_out); never_expect(integer_out); } Ensure(Mocks, single_uncalled_expectation_fails_tally) { expect(string_out, will_return(5), when(i, is_equal_to(666)), when(s, is_equal_to_string("devil")) ); } Ensure(Mocks, should_detect_two_unfulfilled_expectations_on_unknown_functions) { expect(f1, will_return('a')); expect(f2, will_return('b')); } Ensure(Mocks, should_detect_two_unfulfilled_expectations_without_constraints_on_unknown_functions) { expect(f1); expect(f2); } static double double_out(void) { return (double)mock(); } static void double_in(double in) { mock(box_double(in)); } /* TODO: this will not report anything until v2 */ /* Why? */ xEnsure(Mocks, reports_mock_cannot_return_double) { expect(double_out, will_return_double(4.123)); double_out(); } Ensure(Mocks, learning_mocks_emit_none_when_learning_no_mocks) { cgreen_mocks_are(learning_mocks); } Ensure(Mocks, learning_mocks_emit_pastable_code) { cgreen_mocks_are(learning_mocks); string_out(1); string_out(2); integer_out(); integer_out(); string_out(3); integer_out(); } Ensure(Mocks, can_learn_double_expects) { cgreen_mocks_are(learning_mocks); double_in(3.14); } /* It would be very nice if learning mocks could survive unexpected terminations but since the child process is already gone when the parent process detects this we need to either start catching exceptions in the child or communicate the learned mock calls to the parent some other way. */ xEnsure(Mocks, learning_mocks_survive_termination) { int *ip = 0; cgreen_mocks_are(learning_mocks); string_out(1); *ip = 0; } static void simple_mocked_function(int first, int second) { mock(first, second); } Ensure(Mocks, constraint_number_of_calls_when_not_called_enough_times) { expect(simple_mocked_function, times(2)); simple_mocked_function(1, 2); } Ensure(Mocks, constraint_number_of_calls_out_of_order_expectations_fail) { expect(simple_mocked_function, when(first, is_equal_to(1)), times(1)); expect(simple_mocked_function, when(first, is_equal_to(2)), times(1)); simple_mocked_function(2, 2); simple_mocked_function(1, 2); } cgreen-1.6.3/tests/mock_messages_tests.expected000066400000000000000000000107741450461175400217330ustar00rootroot00000000000000Running "mock_messages_tests" (21 tests)... mock_messages_tests.c:000: Failure: Mocks -> calls_beyond_expected_sequence_fail_when_mocks_are_strict Mocked function [integer_out] was called too many times mock_messages_tests.c:000: Failure: Mocks -> calls_beyond_expected_sequence_fail_when_mocks_are_strict Expected [integer_out()] to [equal] [3] actual value: [0] expected value: [3] mock_messages_tests.c:000: Failure: Mocks -> can_declare_function_never_called Mocked function [sample_mock] has an expectation that it will never be called, but it was mock_messages_tests.c:000: Failure: Mocks -> constraint_number_of_calls_out_of_order_expectations_fail Expected [[first] parameter in [simple_mocked_function]] to [equal] [1] actual value: [2] expected value: [1] mock_messages_tests.c:000: Failure: Mocks -> constraint_number_of_calls_out_of_order_expectations_fail Expected [[first] parameter in [simple_mocked_function]] to [equal] [2] actual value: [1] expected value: [2] mock_messages_tests.c:000: Failure: Mocks -> constraint_number_of_calls_when_not_called_enough_times Expected [simple_mocked_function] to [be called] [times] actual value: [1] expected to have been called: [2] times mock_messages_tests.c:000: Failure: Mocks -> failure_reported_when_expect_after_always_expect_for_same_function Mocked function [integer_out] already has an expectation that it will always be called a certain way; any expectations declared after an always expectation are invalid mock_messages_tests.c:000: Failure: Mocks -> failure_reported_when_expect_after_never_expect_for_same_function Mocked function [integer_out] already has an expectation that it will never be called; any expectations declared after a never call expectation are invalid mock_messages_tests.c:000: Failure: Mocks -> failure_when_no_presets_for_default_strict_mock Mocked function [integer_out] did not have an expectation that it would be called mock_messages_tests.c:000: Failure: Mocks -> lists_unexpected_mock_calls Mocked function [unexpected_mock] did not have an expectation that it would be called mock_messages_tests.c:000: Failure: Mocks -> reports_always_expect_after_never_expect_for_same_function Mocked function [integer_out] already has an expectation that it will never be called; any expectations declared after a never call expectation are discarded mock_messages_tests.c:000: Failure: Mocks -> reports_multiple_always_expect Mocked function [integer_out] already has an expectation and will always be called a certain way; any expectations declared after an always expectation are discarded mock_messages_tests.c:000: Failure: Mocks -> reports_multiple_never_expect Mocked function [integer_out] already has an expectation that it will never be called; declaring an expectation for a function after a never call expectation is not allowed mock_messages_tests.c:000: Failure: Mocks -> reports_never_expect_after_always_expect_for_same_function Mocked function [integer_out] already has an expectation and will always be called a certain way; declaring an expectation after an always expectation is not allowed mock_messages_tests.c:000: Failure: Mocks -> should_detect_two_unfulfilled_expectations_on_unknown_functions Expected call was not made to mocked function [f1] mock_messages_tests.c:000: Failure: Mocks -> should_detect_two_unfulfilled_expectations_on_unknown_functions Expected call was not made to mocked function [f2] mock_messages_tests.c:000: Failure: Mocks -> should_detect_two_unfulfilled_expectations_without_constraints_on_unknown_functions Expected call was not made to mocked function [f1] mock_messages_tests.c:000: Failure: Mocks -> should_detect_two_unfulfilled_expectations_without_constraints_on_unknown_functions Expected call was not made to mocked function [f2] mock_messages_tests.c:000: Failure: Mocks -> single_uncalled_expectation_fails_tally Expected call was not made to mocked function [string_out] "Mocks": 5 passes, 2 skipped, 19 failures in 0ms. Completed "mock_messages_tests": 5 passes, 2 skipped, 19 failures in 0ms. Mocks -> can_learn_double_expects : Learned mocks are expect(double_in, when(in, is_equal_to_double(3.140000))); Mocks -> learning_mocks_emit_none_when_learning_no_mocks : Learned mocks are Mocks -> learning_mocks_emit_pastable_code : Learned mocks are expect(string_out, when(p1, is_equal_to(1))); expect(string_out, when(p1, is_equal_to(2))); expect(integer_out); expect(integer_out); expect(string_out, when(p1, is_equal_to(3))); expect(integer_out); cgreen-1.6.3/tests/mocks_struct_tests.c000066400000000000000000000027461450461175400202540ustar00rootroot00000000000000#include #include #include #include #include #include #ifdef __cplusplus using namespace cgreen; namespace cgreen { extern "C" { extern CgreenValue make_cgreen_pointer_value(void *ptr); } } #else extern CgreenValue make_cgreen_pointer_value(void *ptr); #endif Describe(MockStruct); BeforeEach(MockStruct) {} AfterEach(MockStruct) {} typedef struct { int i; const char *string; } Struct; /* If you are only interested in a single, or few, fields: */ void function_mocking_field(Struct s) { mock(s.i); } Ensure(MockStruct, can_mock_a_struct_parameters_field) { Struct struct_to_send = { .i = 12, .string = "hello" }; expect(function_mocking_field, when(s.i, is_equal_to(12))); function_mocking_field(struct_to_send); } void *cgreen_memdup(void *s, size_t size) { void *p = malloc(size); memcpy(p, s, size); return p; } #define memdup(s) cgreen_memdup(&s, sizeof(s)) /* If you need to get the whole struct: */ void function_mocking_the_whole_struct(Struct s) { Struct *sP = (Struct *)memdup(s); mock(sP); } Ensure(MockStruct, can_mock_a_struct_parameter) { Struct struct_to_send = { .i = 13, .string = "hello" }; Struct *p; expect(function_mocking_the_whole_struct, will_capture_parameter(sP, p)); function_mocking_the_whole_struct(struct_to_send); assert_that(p->i, is_equal_to(13)); } cgreen-1.6.3/tests/mocks_struct_tests.cpp000066400000000000000000000006451450461175400206100ustar00rootroot00000000000000/* This file used to be a link to the corresponding .c file because we want to compile the same tests for C and C++. But since some systems don't handle symbolic links the same way as *ix systems we get inconsistencies (looking at you Cygwin) or plain out wrong (looking at you MSYS2, copying ?!?!?) behaviour. So we will simply include the complete .c source instead... */ #include "mocks_struct_tests.c" cgreen-1.6.3/tests/mocks_tests.c000066400000000000000000000403061450461175400166420ustar00rootroot00000000000000#include #include #include #include #include #ifdef __cplusplus using namespace cgreen; #endif Describe(Mocks); BeforeEach(Mocks) {} AfterEach(Mocks) {} static int integer_out(void) { return (int)mock(); } Ensure(Mocks, default_return_value_when_no_presets_for_loose_mock) { cgreen_mocks_are(loose_mocks); assert_that(integer_out(), is_equal_to(0)); } Ensure(Mocks, can_stub_an_integer_return) { expect(integer_out, will_return(3) ); assert_that(integer_out(), is_equal_to(3)); } Ensure(Mocks, repeats_return_value_when_set_to_always) { always_expect(integer_out, will_return(3) ); assert_that(integer_out(), is_equal_to(3)); assert_that(integer_out(), is_equal_to(3)); } Ensure(Mocks, can_stub_an_integer_return_sequence) { expect(integer_out, will_return(1) ); expect(integer_out, will_return(2) ); expect(integer_out, will_return(3) ); assert_that(integer_out(), is_equal_to(1)); assert_that(integer_out(), is_equal_to(2)); assert_that(integer_out(), is_equal_to(3)); } Ensure(Mocks, expectations_are_reset_between_tests_with_loose_mocks) { cgreen_mocks_are(loose_mocks); assert_that(integer_out(), is_equal_to(0)); } static char *string_out(int p1) { return (char *)mock(p1); } Ensure(Mocks, can_stub_a_string_return) { expect(string_out, will_return("hello")); assert_that(string_out(1), is_equal_to_string("hello")); } Ensure(Mocks, can_stub_a_string_sequence) { expect(string_out, will_return("hello")); expect(string_out, will_return("goodbye")); assert_that(string_out(2), is_equal_to_string("hello")); assert_that(string_out(3), is_equal_to_string("goodbye")); } static void integer_in(int i) { mock(i); } Ensure(Mocks, expecting_once_with_any_parameters) { expect(integer_in); integer_in(3); } Ensure(Mocks, expecting_once_with_parameter_checks_that_parameter) { expect(integer_in, when(i, is_equal_to(3))); integer_in(3); } Ensure(Mocks, always_expect_keeps_affirming_parameter) { always_expect(integer_in, when(i, is_equal_to(3))); integer_in(3); integer_in(3); integer_in(3); } Ensure(Mocks, expect_a_sequence) { expect(integer_in, when(i, is_equal_to(1))); expect(integer_in, when(i, is_equal_to(2))); expect(integer_in, when(i, is_equal_to(3))); integer_in(1); integer_in(2); integer_in(3); } static void string_in(const char *s) { mock(s); } Ensure(Mocks, string_expect_is_confirmed) { expect(string_in, when(s, is_equal_to_string("hello"))); string_in("hello"); } Ensure(Mocks, string_contains_expectation_is_confirmed) { expect(string_in, when(s, contains_string("hello"))); string_in("alice, hello"); } Ensure(Mocks, string_expect_is_confirmed_even_when_null) { expect(string_in, when(s, is_equal_to_string((char *)NULL))); string_in(NULL); } Ensure(Mocks, string_expect_sequence) { expect(string_in, when(s, is_equal_to_string("hello"))); expect(string_in, when(s, is_equal_to_string("goodbye"))); string_in("hello"); string_in("goodbye"); } Ensure(Mocks, expecting_once_with_non_null_parameter_checks_that_parameter) { expect(string_in, when(s, is_non_null)); string_in("anything"); } static void string_in2(const char *s2) { mock(s2); } Ensure(Mocks, expecting_twice_with_non_null_constraint_should_not_mix_them_up) { expect(string_in, when(s, is_not_null)); expect(string_in2, when(s2, is_not_null)); string_in("anything"); string_in2("anything"); } Ensure(Mocks, expecting_twice_with_is_null_constraint_should_not_mix_them_up) { expect(string_in, when(s, is_null)); expect(string_in2, when(s2, is_null)); string_in(NULL); string_in2(NULL); } static void bool_in(bool b) { mock(b); } static void bool_in2(bool b2) { mock(b2); } Ensure(Mocks, expecting_twice_with_is_true_constraint_should_not_mix_them_up) { expect(bool_in, when(b, is_true)); expect(bool_in2, when(b2, is_true)); bool_in(true); bool_in2(true); } Ensure(Mocks, expecting_twice_with_is_false_constraint_should_not_mix_them_up) { expect(bool_in, when(b, is_false)); expect(bool_in2, when(b2, is_false)); bool_in(false); bool_in2(false); } static void double_in(double d) { mock(box_double(d)); } Ensure(Mocks, double_expect_is_confirmed) { expect(double_in, when(d, is_equal_to_double(3.14))); double_in(3.14); } Ensure(Mocks, double_expect_sequence) { expect(double_in, when(d, is_equal_to_double(1.0))); expect(double_in, when(d, is_equal_to_double(2.0))); double_in(1.0); double_in(2.0); } /* non-static to avoid "unused" warning in C++ as long as 'can_always_return_double' does not work in C++ */ double double_out(void) { /* TODO: For v2 this should change to "return mock_double();" */ return unbox_double(mock()); } #ifndef __cplusplus /* TODO: This does not work in C++ because of the overloading of assert_that() which currently has no match for double */ Ensure(Mocks, can_return_double) { expect(double_out, will_return_double(4.23)); assert_that_double(double_out(), is_equal_to_double(4.23)); } Ensure(Mocks, can_always_return_double) { always_expect(double_out, will_return_double(4.23)); assert_that_double(double_out(), is_equal_to_double(4.23)); assert_that_double(double_out(), is_equal_to_double(4.23)); assert_that_double(double_out(), is_equal_to_double(4.23)); } #endif typedef struct { int field; } S; /* The mock function */ S func(void) { S s; S *sp; sp = (S *)mock(); /* Copy content of struct pointed to by returned value */ memcpy(&s, sp, sizeof(S)); /* Return it */ return s; } Ensure(Mocks, can_return_struct) { /* Allocate a struct */ S *sp = (S *)malloc(sizeof(S)); /* Prime one field */ sp->field = 42; /* Expect a call and return a pointer to the struct */ expect(func, will_return(sp)); /* Call our mock function which returns a struct */ S ret = func(); /* And assert that the field in the returned struct is propagated */ assert_that(ret.field, is_equal_to(42)); free(sp); } static void mixed_parameters(int i, const char *s) { mock(i, s); } Ensure(Mocks, confirming_multiple_parameters_multiple_times) { expect(mixed_parameters, when(i, is_equal_to(1)), when(s, is_equal_to_string("Hello")) ); expect(mixed_parameters, when(i, is_equal_to(2)), when(s, is_equal_to_string("Goodbye")) ); mixed_parameters(1, "Hello"); mixed_parameters(2, "Goodbye"); } static int sample_mock(int i, const char *s) { return (int)mock(i, s); } Ensure(Mocks, can_mock_full_function_call) { expect(sample_mock, will_return(5), when(i, is_equal_to(666)), when(s, is_equal_to_string("devil")) ); assert_that(sample_mock(666, "devil"), is_equal_to(5)); } Ensure(Mocks, when_called_with_always_should_not_tally_counts) { always_expect(string_out, will_return(5), when(i, is_equal_to(666)), when(s, is_equal_to_string("devil")) ); } Ensure(Mocks, can_mock_full_sequence) { expect(sample_mock, will_return(5), when(i, is_equal_to(666)), when(s, is_equal_to_string("devil")) ); expect(sample_mock, will_return(6), when(i, is_equal_to(667)), when(s, is_equal_to_string("beastie")) ); assert_that(sample_mock(666, "devil"), is_equal_to(5)); assert_that(sample_mock(667, "beastie"), is_equal_to(6)); } Ensure(Mocks, can_always_mock_full_function_call) { always_expect(sample_mock, will_return(5), when(i, is_equal_to(666)), when(s, is_equal_to_string("devil")) ); assert_that(sample_mock(666, "devil"), is_equal_to(5)); assert_that(sample_mock(666, "devil"), is_equal_to(5)); assert_that(sample_mock(666, "devil"), is_equal_to(5)); } static void sample_mock_with_parameters_without_space_between_them(int i, const char *s) { mock(i,s); } Ensure(Mocks, can_mock_full_function_call_when_there_is_no_space_between_parameters) { expect(sample_mock_with_parameters_without_space_between_them, when(i, is_equal_to(666)), when(s, is_equal_to_string("devil")) ); sample_mock_with_parameters_without_space_between_them(666, "devil"); } typedef struct { double a; double b; const char *name; } LargerThanIntptr; static void out_param_mock(LargerThanIntptr* result) { mock(result); } Ensure(Mocks, can_stub_an_out_parameter) { LargerThanIntptr actual = { 3.14, 6.66, "bob" }; LargerThanIntptr local = { 4.13, 7.89, "alice" }; expect(out_param_mock, will_set_contents_of_parameter(result, &actual, sizeof(LargerThanIntptr)) ); out_param_mock(&local); assert_that_double(actual.a, is_equal_to_double(local.a)); assert_that_double(actual.b, is_equal_to_double(local.b)); assert_that(actual.name, is_equal_to_string(local.name)); assert_that(&local, is_equal_to_contents_of(&actual, sizeof(LargerThanIntptr))); } static void mocked_read(char *ch) { mock(ch); } Ensure(Mocks, can_stub_a_char_out_parameter) { char stubbed_char = 'a'; char returned_char; expect(mocked_read, will_set_contents_of_parameter(ch, &stubbed_char, 1)); mocked_read(&returned_char); assert_that(returned_char, is_equal_to(stubbed_char)); } // function which when mocked will be referred to by preprocessor macro static void function_macro_mock(void) { mock(); } #define FUNCTION_MACRO function_macro_mock Ensure(Mocks, can_mock_a_function_macro) { // expect to mock by real function name expect(function_macro_mock); function_macro_mock(); // expect to mock by macro function name expect(FUNCTION_MACRO); FUNCTION_MACRO(); } #undef FUNCTION_MACRO static void simple_mocked_function(int first, int second) { mock(first, second); } Ensure(Mocks, constraint_number_of_calls_when_no_when_is_present) { expect(simple_mocked_function, times(2)); simple_mocked_function(1, 2); simple_mocked_function(1, 2); } Ensure(Mocks, constraint_number_of_calls_when_is_present) { expect(simple_mocked_function, when(first, is_equal_to(1)), times(2)); simple_mocked_function(1, 2); simple_mocked_function(1, 2); } Ensure(Mocks, constraint_number_of_calls_when_multiple_expectations_are_present) { expect(simple_mocked_function, when(first, is_equal_to(1)), times(2)); expect(simple_mocked_function, when(first, is_equal_to(2)), times(1)); simple_mocked_function(1, 2); simple_mocked_function(1, 2); simple_mocked_function(2, 2); } Ensure(Mocks, constraint_number_of_calls_order_of_expectations_matter) { expect(simple_mocked_function, when(first, is_equal_to(1)), times(1)); expect(simple_mocked_function, when(first, is_equal_to(2)), times(1)); expect(simple_mocked_function, when(first, is_equal_to(1)), times(1)); simple_mocked_function(1, 2); simple_mocked_function(2, 2); simple_mocked_function(1, 2); } Ensure(Mocks, can_capture_parameter) { int captured_first = 0; int captured_second = 0; expect(simple_mocked_function, will_capture_parameter(first, captured_first), will_capture_parameter(second, captured_second)); simple_mocked_function(0x12345678, 0x76543210); assert_that(captured_first, is_equal_to_hex(0x12345678)); assert_that(captured_second, is_equal_to_hex(0x76543210)); } static int changed_by_sideeffect = 1; static int mock_with_side_effect(void) { return (int)mock(); } static void the_sideeffect(void * data) { assert_that(*(int*)data, is_equal_to(99)); changed_by_sideeffect = 2; } Ensure(Mocks, mock_expect_with_side_effect) { int data_passed_to_sideeffect = 99; expect(mock_with_side_effect, with_side_effect(&the_sideeffect, &data_passed_to_sideeffect), will_return(22)); assert_that(mock_with_side_effect(), is_equal_to(22)); assert_that(changed_by_sideeffect, is_equal_to(2)); } typedef struct Struct { int height; int weight; } Struct; Struct retrieveStruct(void) { Struct *struct_p = (Struct *)mock(); Struct the_struct = *struct_p; free(struct_p); return the_struct; } Ensure(Mocks, can_return_by_value) { Struct someStruct = {.height = 10, .weight = 20}; expect(retrieveStruct, will_return_by_value(someStruct, sizeof(Struct))); someStruct.height = 30; Struct actualStruct = retrieveStruct(); assert_that(actualStruct.weight, is_equal_to(20)); assert_that(actualStruct.height, is_equal_to(10)); } Struct retrieveSpecialStruct(int structNumber) { Struct *struct_p = (Struct *)mock(structNumber); Struct the_struct = *struct_p; free(struct_p); return the_struct; } Ensure(Mocks, can_return_by_value_depending_on_input_parameter) { Struct struct1 = {.height = 10, .weight = 20}; Struct struct2 = {.height = 5, .weight = 33}; expect(retrieveSpecialStruct, will_return_by_value(struct1, sizeof(Struct)), when(structNumber, is_equal_to(1))); expect(retrieveSpecialStruct, will_return_by_value(struct2, sizeof(Struct)), when(structNumber, is_equal_to(2))); struct1.height = 30; Struct retrievedStruct1 = retrieveSpecialStruct(1); assert_that(retrievedStruct1.weight, is_equal_to(20)); assert_that(retrievedStruct1.height, is_equal_to(10)); Struct retrievedStruct2 = retrieveSpecialStruct(2); assert_that(retrievedStruct2.weight, is_equal_to(33)); assert_that(retrievedStruct2.height, is_equal_to(5)); } TestSuite *mock_tests(void) { TestSuite *suite = create_test_suite(); add_test_with_context(suite, Mocks, default_return_value_when_no_presets_for_loose_mock); add_test_with_context(suite, Mocks, can_stub_an_integer_return); add_test_with_context(suite, Mocks, repeats_return_value_when_set_to_always); add_test_with_context(suite, Mocks, can_stub_an_integer_return_sequence); add_test_with_context(suite, Mocks, expectations_are_reset_between_tests_with_loose_mocks); add_test_with_context(suite, Mocks, can_stub_a_string_return); add_test_with_context(suite, Mocks, can_stub_a_string_sequence); add_test_with_context(suite, Mocks, expecting_once_with_any_parameters); add_test_with_context(suite, Mocks, expecting_once_with_parameter_checks_that_parameter); add_test_with_context(suite, Mocks, always_expect_keeps_affirming_parameter); add_test_with_context(suite, Mocks, expect_a_sequence); add_test_with_context(suite, Mocks, string_expect_is_confirmed); add_test_with_context(suite, Mocks, string_expect_is_confirmed_even_when_null); add_test_with_context(suite, Mocks, string_expect_sequence); add_test_with_context(suite, Mocks, expecting_once_with_non_null_parameter_checks_that_parameter); add_test_with_context(suite, Mocks, double_expect_is_confirmed); add_test_with_context(suite, Mocks, double_expect_sequence); add_test_with_context(suite, Mocks, confirming_multiple_parameters_multiple_times); add_test_with_context(suite, Mocks, can_mock_full_function_call); add_test_with_context(suite, Mocks, when_called_with_always_should_not_tally_counts); add_test_with_context(suite, Mocks, can_mock_full_sequence); add_test_with_context(suite, Mocks, can_always_mock_full_function_call); add_test_with_context(suite, Mocks, can_mock_full_function_call_when_there_is_no_space_between_parameters); add_test_with_context(suite, Mocks, can_stub_an_out_parameter); add_test_with_context(suite, Mocks, string_contains_expectation_is_confirmed); add_test_with_context(suite, Mocks, can_mock_a_function_macro); add_test_with_context(suite, Mocks, constraint_number_of_calls_when_no_when_is_present); add_test_with_context(suite, Mocks, constraint_number_of_calls_when_is_present); add_test_with_context(suite, Mocks, constraint_number_of_calls_when_multiple_expectations_are_present); add_test_with_context(suite, Mocks, constraint_number_of_calls_order_of_expectations_matter); add_test_with_context(suite, Mocks, mock_expect_with_side_effect); add_test_with_context(suite, Mocks, can_return_by_value); add_test_with_context(suite, Mocks, can_return_by_value_depending_on_input_parameter); return suite; } cgreen-1.6.3/tests/mocks_tests.cpp000066400000000000000000000006371450461175400172050ustar00rootroot00000000000000/* This file used to be a link to the corresponding .c file because we want to compile the same tests for C and C++. But since some systems don't handle symbolic links the same way as *ix systems we get inconsistencies (looking at you Cygwin) or plain out wrong (looking at you MSYS2, copying ?!?!?) behaviour. So we will simply include the complete .c source instead... */ #include "mocks_tests.c" cgreen-1.6.3/tests/normalize_assertion_messages_tests.sed000066400000000000000000000000001450461175400240200ustar00rootroot00000000000000cgreen-1.6.3/tests/normalize_constraint_messages_tests.sed000066400000000000000000000000701450461175400242040ustar00rootroot00000000000000s/Terminated:.+[0-9]+/Terminated/ s/Quit:.+[0-9]+/Quit/ cgreen-1.6.3/tests/normalize_custom_constraint_messages_tests.sed000066400000000000000000000000001450461175400255670ustar00rootroot00000000000000cgreen-1.6.3/tests/normalize_failure_messages_tests.sed000066400000000000000000000001421450461175400234470ustar00rootroot00000000000000# Darwin clang++ : s/libc\+\+abi.dylib: terminating/terminate called without an active exception/ cgreen-1.6.3/tests/normalize_ignore_messages_tests.sed000066400000000000000000000000561450461175400233070ustar00rootroot00000000000000s/Segmentation fault: 11/Segmentation fault/g cgreen-1.6.3/tests/normalize_libxml_output_tests.sed000066400000000000000000000002741450461175400230460ustar00rootroot00000000000000# 'time="?.?????"' => time="0.00000" s/time=".+"/time="0.00000"/g s/line=".+"/line="0"/g # filenames, suites, libraries and "classnames" starting with "lib" or "cyg" s/"lib/"/g s/"cyg/"/g cgreen-1.6.3/tests/normalize_mock_messages_tests.sed000066400000000000000000000000001450461175400227420ustar00rootroot00000000000000cgreen-1.6.3/tests/normalize_xml_output_tests.sed000066400000000000000000000003161450461175400223540ustar00rootroot00000000000000# 'time="?.?????"' => time="0.00000" s/time=".+"/time="0.00000"/g s/line=".+"/line="0"/g # filenames, suites, libraries and "classnames" starting with "lib", "cyg" or ... s/"lib/"/g s/"cyg/"/g s/"msys-/"/g cgreen-1.6.3/tests/parameters_tests.c000066400000000000000000000172231450461175400176730ustar00rootroot00000000000000#include #include #include #include "../src/parameters.h" #ifdef __cplusplus using namespace cgreen; #endif static CgreenVector *names = NULL; void destroy_names(void) { destroy_cgreen_vector(names); names = NULL; } Ensure(can_create_vector_of_no_parameters_and_destroy_it) { names = create_vector_of_names(""); assert_that(cgreen_vector_size(names), is_equal_to(0)); } Ensure(can_read_single_parameter) { names = create_vector_of_names("a"); assert_that(cgreen_vector_size(names), is_equal_to(1)); assert_that((const char *)cgreen_vector_get(names, 0), is_equal_to_string("a")); } Ensure(can_read_two_parameters) { names = create_vector_of_names("a, b"); assert_that(cgreen_vector_size(names), is_equal_to(2)); assert_that((const char *)cgreen_vector_get(names, 0), is_equal_to_string("a")); assert_that((const char *)cgreen_vector_get(names, 1), is_equal_to_string("b")); } Ensure(can_read_three_parameters) { names = create_vector_of_names("a, b, c"); assert_that(cgreen_vector_size(names), is_equal_to(3)); assert_that((const char *)cgreen_vector_get(names, 0), is_equal_to_string("a")); assert_that((const char *)cgreen_vector_get(names, 1), is_equal_to_string("b")); assert_that((const char *)cgreen_vector_get(names, 2), is_equal_to_string("c")); } Ensure(can_read_two_parameters_without_spaces) { names = create_vector_of_names("a,b"); assert_that((const char *)cgreen_vector_get(names, 0), is_equal_to_string("a")); assert_that((const char *)cgreen_vector_get(names, 1), is_equal_to_string("b")); } Ensure(can_read_long_parameters) { names = create_vector_of_names("abacus, banana"); assert_that((const char *)cgreen_vector_get(names, 0), is_equal_to_string("abacus")); assert_that((const char *)cgreen_vector_get(names, 1), is_equal_to_string("banana")); } Ensure(can_read_long_parameters_with_funky_names) { names = create_vector_of_names("a_b-c+d, +a-d_c/d"); assert_that((const char *)cgreen_vector_get(names, 0), is_equal_to_string("a_b-c+d")); assert_that((const char *)cgreen_vector_get(names, 1), is_equal_to_string("+a-d_c/d")); } Ensure(can_read_two_parameters_with_varied_whitespace) { names = create_vector_of_names("\ra\t,\nb\t\t\t"); assert_that((const char *)cgreen_vector_get(names, 0), is_equal_to_string("a")); assert_that((const char *)cgreen_vector_get(names, 1), is_equal_to_string("b")); } Ensure(can_strip_box_double_to_leave_original_name) { names = create_vector_of_names("box_double(a)"); assert_that((const char *)cgreen_vector_get(names, 0), is_equal_to_string("a")); } Ensure(can_strip_two_box_doubles_to_leave_original_names) { names = create_vector_of_names("box_double(a), box_double(b)"); assert_that((const char *)cgreen_vector_get(names, 0), is_equal_to_string("a")); assert_that((const char *)cgreen_vector_get(names, 1), is_equal_to_string("b")); } Ensure(can_strip_argument_and_box_double_to_leave_original_names) { names = create_vector_of_names("a, box_double(b)"); assert_that((const char *)cgreen_vector_get(names, 0), is_equal_to_string("a")); assert_that((const char *)cgreen_vector_get(names, 1), is_equal_to_string("b")); } Ensure(can_strip_box_double_and_argument_to_leave_original_names) { names = create_vector_of_names("box_double(a), b"); assert_that((const char *)cgreen_vector_get(names, 0), is_equal_to_string("a")); assert_that((const char *)cgreen_vector_get(names, 1), is_equal_to_string("b")); } Ensure(can_strip_d_macro_to_leave_original_name) { names = create_vector_of_names("d(a)"); assert_that((const char *)cgreen_vector_get(names, 0), is_equal_to_string("a")); } Ensure(can_strip_two_d_macros_to_leave_original_names) { names = create_vector_of_names("d(a), d(b)"); assert_that((const char *)cgreen_vector_get(names, 0), is_equal_to_string("a")); assert_that((const char *)cgreen_vector_get(names, 1), is_equal_to_string("b")); } Ensure(can_strip_d_macro_and_box_double_to_leave_original_names) { names = create_vector_of_names("d(a), box_double(b)"); assert_that((const char *)cgreen_vector_get(names, 0), is_equal_to_string("a")); assert_that((const char *)cgreen_vector_get(names, 1), is_equal_to_string("b")); } Ensure(can_strip_box_double_and_d_macro_to_leave_original_names) { names = create_vector_of_names("box_double(a), d(b)"); assert_that((const char *)cgreen_vector_get(names, 0), is_equal_to_string("a")); assert_that((const char *)cgreen_vector_get(names, 1), is_equal_to_string("b")); } Ensure(can_strip_multiple_mixed_parameters_to_leave_original_names) { names = create_vector_of_names("box_double(a), d(b), c, d,e,box_double(f),d(g)"); assert_that((const char *)cgreen_vector_get(names, 0), is_equal_to_string("a")); assert_that((const char *)cgreen_vector_get(names, 1), is_equal_to_string("b")); assert_that((const char *)cgreen_vector_get(names, 2), is_equal_to_string("c")); assert_that((const char *)cgreen_vector_get(names, 3), is_equal_to_string("d")); assert_that((const char *)cgreen_vector_get(names, 4), is_equal_to_string("e")); assert_that((const char *)cgreen_vector_get(names, 5), is_equal_to_string("f")); assert_that((const char *)cgreen_vector_get(names, 6), is_equal_to_string("g")); } Ensure(can_create_empty_vector_of_double_markers) { CgreenVector *markers = create_vector_of_double_markers_for(""); assert_that(cgreen_vector_size(markers), is_equal_to(0)); destroy_cgreen_vector(markers); } Ensure(can_create_markers_for_single_non_double) { CgreenVector *markers = create_vector_of_double_markers_for("a"); assert_that(cgreen_vector_size(markers), is_equal_to(1)); assert_that(!*(bool*)cgreen_vector_get(markers, 0)); destroy_cgreen_vector(markers); } Ensure(can_create_markers_for_single_double) { CgreenVector *markers = create_vector_of_double_markers_for("box_double(a)"); assert_that(cgreen_vector_size(markers), is_equal_to(1)); assert_that(*(bool*)cgreen_vector_get(markers, 0)); destroy_cgreen_vector(markers); } Ensure(can_create_markers_for_mixed_parameters) { CgreenVector *markers = create_vector_of_double_markers_for("a, box_double(b), c,d,box_double(e)"); assert_that(cgreen_vector_size(markers), is_equal_to(5)); assert_that(!*(bool*)cgreen_vector_get(markers, 0)); assert_that(*(bool*)cgreen_vector_get(markers, 1)); assert_that(!*(bool*)cgreen_vector_get(markers, 2)); assert_that(!*(bool*)cgreen_vector_get(markers, 3)); assert_that(*(bool*)cgreen_vector_get(markers, 4)); destroy_cgreen_vector(markers); } TestSuite *parameter_tests(void) { TestSuite *suite = create_test_suite(); set_teardown(suite, destroy_names); add_test(suite, can_create_vector_of_no_parameters_and_destroy_it); add_test(suite, can_read_single_parameter); add_test(suite, can_read_two_parameters); add_test(suite, can_read_three_parameters); add_test(suite, can_read_two_parameters_without_spaces); add_test(suite, can_read_long_parameters); add_test(suite, can_read_long_parameters_with_funky_names); add_test(suite, can_read_two_parameters_with_varied_whitespace); add_test(suite, can_strip_box_double_to_leave_original_name); add_test(suite, can_strip_two_box_doubles_to_leave_original_names); add_test(suite, can_strip_d_macro_to_leave_original_name); add_test(suite, can_strip_two_d_macros_to_leave_original_names); add_test(suite, can_strip_d_macro_and_box_double_to_leave_original_names); add_test(suite, can_strip_box_double_and_d_macro_to_leave_original_names); add_test(suite, can_strip_multiple_mixed_parameters_to_leave_original_names); return suite; } cgreen-1.6.3/tests/parameters_tests.cpp000066400000000000000000000006441450461175400202320ustar00rootroot00000000000000/* This file used to be a link to the corresponding .c file because we want to compile the same tests for C and C++. But since some systems don't handle symbolic links the same way as *ix systems we get inconsistencies (looking at you Cygwin) or plain out wrong (looking at you MSYS2, copying ?!?!?) behaviour. So we will simply include the complete .c source instead... */ #include "parameters_tests.c" cgreen-1.6.3/tests/reflective_runner_no_teardown_tests.c000066400000000000000000000015631450461175400236500ustar00rootroot00000000000000#include #ifdef __cplusplus using namespace cgreen; #endif static int counter = 0; /* this suite exercises a former crash bug in the reflective runner by not having a teardown */ Describe(ReflectiveNoTeardownTest); BeforeEach(ReflectiveNoTeardownTest) { counter += 5; } AfterEach(ReflectiveNoTeardownTest) {} Ensure(ReflectiveNoTeardownTest, before_called_implicitly_before_each_test) { assert_that(counter, is_equal_to(5)); } Ensure(ReflectiveNoTeardownTest, second_test_unaffected_by_first) { assert_that(counter, is_equal_to(5)); } TestSuite *reflective_no_teardown_tests(void) { TestSuite *suite = create_test_suite(); add_test_with_context(suite, ReflectiveNoTeardownTest, before_called_implicitly_before_each_test); add_test_with_context(suite, ReflectiveNoTeardownTest, second_test_unaffected_by_first); return suite; } cgreen-1.6.3/tests/reflective_runner_no_teardown_tests.cpp000066400000000000000000000006671450461175400242140ustar00rootroot00000000000000/* This file used to be a link to the corresponding .c file because we want to compile the same tests for C and C++. But since some systems don't handle symbolic links the same way as *ix systems we get inconsistencies (looking at you Cygwin) or plain out wrong (looking at you MSYS2, copying ?!?!?) behaviour. So we will simply include the complete .c source instead... */ #include "reflective_runner_no_teardown_tests.c" cgreen-1.6.3/tests/reflective_tests.c000066400000000000000000000013451450461175400176560ustar00rootroot00000000000000#include #ifdef __cplusplus using namespace cgreen; #endif static int counter = 0; Describe(ReflectiveRunner); BeforeEach(ReflectiveRunner) { counter += 5; } AfterEach(ReflectiveRunner) { counter += 1; } Ensure(ReflectiveRunner, calls_setup_before_each_test) { assert_that(counter, is_equal_to(5)); } Ensure(ReflectiveRunner, running_first_test_does_not_affect_second_test) { assert_that(counter, is_equal_to(5)); } TestSuite *reflective_tests(void) { TestSuite *suite = create_test_suite(); add_test_with_context(suite, ReflectiveRunner, calls_setup_before_each_test); add_test_with_context(suite, ReflectiveRunner, running_first_test_does_not_affect_second_test); return suite; } cgreen-1.6.3/tests/reflective_tests.cpp000066400000000000000000000006441450461175400202170ustar00rootroot00000000000000/* This file used to be a link to the corresponding .c file because we want to compile the same tests for C and C++. But since some systems don't handle symbolic links the same way as *ix systems we get inconsistencies (looking at you Cygwin) or plain out wrong (looking at you MSYS2, copying ?!?!?) behaviour. So we will simply include the complete .c source instead... */ #include "reflective_tests.c" cgreen-1.6.3/tests/text_reporter_tests.c000066400000000000000000000140741450461175400204370ustar00rootroot00000000000000#include #include #include #include #include #ifdef __cplusplus using namespace cgreen; #endif #include #include "src/text_reporter_internal.h" static const int line=666; static char *output = NULL; static void clear_output(void) { if (NULL != output) { free(output); } output = (char*)malloc(1); *output = '\0'; } static char *concat(char *output, char *buffer) { output = (char *) realloc(output, strlen(output)+strlen(buffer)+1); strcat(output, buffer); return output; } static int mocked_vprinter(const char *format, va_list ap) { char buffer[10000]; vsnprintf(buffer, sizeof(buffer), format, ap); output = concat(output, buffer); return strlen(output); } static int mocked_printer(const char *format, ...) { int result = 0; va_list ap; va_start(ap, format); result = mocked_vprinter(format, ap); va_end(ap); return result; } static TestReporter *reporter; static void text_reporter_tests_setup(void) { reporter = create_text_reporter(); // We can not use setup_reporting() since we are running // inside a test suite which needs the real reporting // So we'll have to set up the messaging explicitly reporter->ipc = start_cgreen_messaging(666); clear_output(); set_text_reporter_printer(reporter, mocked_printer); set_text_reporter_vprinter(reporter, mocked_vprinter); } static void text_reporter_tests_teardown(void) { reporter->destroy(reporter); // bad mojo when running tests in same process, as destroy_reporter // also sets context.reporter = NULL, thus breaking the next test // to run if (output != NULL) { free(output); // need to set output to NULL to avoid second free in // subsequent call to setup_*_reporter_tests->clear_output when // running tests in same process output = NULL; } } Describe(TextReporter); BeforeEach(TextReporter) { text_reporter_tests_setup(); } AfterEach(TextReporter) { text_reporter_tests_teardown(); } Ensure(TextReporter, will_report_beginning_and_end_of_suites) { reporter->start_suite(reporter, "suite_name", 2); reporter->finish_suite(reporter, "filename", line); assert_that(output, begins_with_string("Running \"suite_name\" (2 tests)")); assert_that(output, contains_string("Completed \"suite_name\"")); } Ensure(TextReporter, will_report_passed_for_test_with_one_pass_on_completion) { reporter->start_suite(reporter, "suite_name", 15); reporter->start_test(reporter, "test_name"); (*reporter->assert_true)(reporter, "file", 2, true, ""); // Must indicate test case completion before calling finish_test() send_reporter_completion_notification(reporter); reporter->finish_test(reporter, "filename", line, NULL); reporter->finish_suite(reporter, "filename", line); assert_that(output, contains_string("Completed \"suite_name\": 1 pass")); } Ensure(TextReporter, will_report_no_asserts_for_suites_with_no_asserts) { reporter->start_suite(reporter, "suite_name", 15); reporter->start_test(reporter, "test_name"); // Must indicate test case completion before calling finish_test() send_reporter_completion_notification(reporter); reporter->finish_test(reporter, "filename", line, NULL); reporter->finish_suite(reporter, "filename", line); assert_that(output, contains_string("Completed \"suite_name\": No assertions")); } Ensure(TextReporter, will_report_failed_once_for_each_fail) { va_list arguments; reporter->start_test(reporter, "test_name"); reporter->failures++; // Simulating a failed assert memset(&arguments, 0, sizeof(va_list)); reporter->show_fail(reporter, "file", 2, "test_name", arguments); assert_that(output, contains_string("file:2: Failure")); clear_output(); reporter->failures++; // Simulating another failed assert reporter->show_fail(reporter, "file", 3, "test_name", arguments); assert_that(output, contains_string("file:3: Failure:")); clear_output(); // Must indicate test case completion before calling finish_test() send_reporter_completion_notification(reporter); reporter->finish_test(reporter, "filename", line, NULL); assert_that(output, is_equal_to_string("")); } static void wrapped_show_fail(TestReporter *reporter, const char *file, int line, const char *message, ...) { va_list arguments; va_start(arguments, message); reporter->show_fail(reporter, file, line, message, arguments); va_end(arguments); } Ensure(TextReporter, will_use_arguments_for_show_fail) { reporter->start_test(reporter, "test_name"); reporter->failures++; // Simulating a failed assert wrapped_show_fail(reporter, "file", 2, "test_case %s requires %i arguments", "Foo", 2); assert_that(output, contains_string("file:2: Failure")); assert_that(output, contains_string("test_case Foo requires 2 arguments")); clear_output(); // Must indicate test case completion before calling finish_test() send_reporter_completion_notification(reporter); reporter->finish_test(reporter, "filename", line, NULL); assert_that(output, is_equal_to_string("")); } Ensure(TextReporter, will_report_non_finishing_test) { const int line = 666; reporter->start_suite(reporter, "suite_name", 1); send_reporter_exception_notification(reporter); reporter->finish_suite(reporter, "filename", line); assert_that(output, contains_string("1 exception")); } TestSuite *text_reporter_tests(void) { TestSuite *suite = create_test_suite(); set_setup(suite, text_reporter_tests_setup); add_test_with_context(suite, TextReporter, will_report_beginning_and_end_of_suites); add_test_with_context(suite, TextReporter, will_report_passed_for_test_with_one_pass_on_completion); add_test_with_context(suite, TextReporter, will_report_failed_once_for_each_fail); add_test_with_context(suite, TextReporter, will_report_non_finishing_test); set_teardown(suite, text_reporter_tests_teardown); return suite; } cgreen-1.6.3/tests/text_reporter_tests.cpp000066400000000000000000000006471450461175400210000ustar00rootroot00000000000000/* This file used to be a link to the corresponding .c file because we want to compile the same tests for C and C++. But since some systems don't handle symbolic links the same way as *ix systems we get inconsistencies (looking at you Cygwin) or plain out wrong (looking at you MSYS2, copying ?!?!?) behaviour. So we will simply include the complete .c source instead... */ #include "text_reporter_tests.c" cgreen-1.6.3/tests/unit_tests.c000066400000000000000000000045301450461175400165040ustar00rootroot00000000000000#include #include #include #include #ifdef __cplusplus using namespace cgreen; #endif static TestSuite* suite; static void unit_tests_setup(void) { suite = create_test_suite(); } static void unit_tests_teardown(void) { destroy_test_suite(suite); } Describe(Unittests); BeforeEach(Unittests) { unit_tests_setup(); } AfterEach(Unittests) { unit_tests_teardown(); } Ensure(Unittests, can_see_correct_version_marking) { char version_string[20]; snprintf(version_string, sizeof(version_string), "%d.%d.%d", CGREEN_VERSION_MAJOR, CGREEN_VERSION_MINOR, CGREEN_VERSION_PATCH); assert_that(cgreen_library_version, is_equal_to_string(CGREEN_VERSION)); assert_that(CGREEN_VERSION, is_equal_to_string(version_string)); } Ensure(Unittests, count_tests_return_zero_for_empty_suite) { assert_that(count_tests(suite), is_equal_to(0)); } Ensure(Unittests, count_tests_return_one_for_suite_with_one_testcase) { add_test_with_context(suite, Unittests, count_tests_return_one_for_suite_with_one_testcase); assert_that(count_tests(suite), is_equal_to(1)); } Ensure(Unittests, count_tests_return_four_for_four_nested_suite_with_one_testcase_each) { TestSuite *suite2 = create_test_suite(); TestSuite *suite3 = create_test_suite(); TestSuite *suite4 = create_test_suite(); add_test_with_context(suite, Unittests, count_tests_return_one_for_suite_with_one_testcase); add_suite(suite, suite2); add_test_with_context(suite2, Unittests, count_tests_return_one_for_suite_with_one_testcase); add_suite(suite2, suite3); add_test_with_context(suite3, Unittests, count_tests_return_one_for_suite_with_one_testcase); add_suite(suite3, suite4); add_test_with_context(suite4, Unittests, count_tests_return_one_for_suite_with_one_testcase); assert_that(count_tests(suite), is_equal_to(4)); } TestSuite *unit_tests(void) { TestSuite *suite = create_test_suite(); set_setup(suite, unit_tests_setup); add_test_with_context(suite, Unittests, count_tests_return_zero_for_empty_suite); add_test_with_context(suite, Unittests, count_tests_return_one_for_suite_with_one_testcase); add_test_with_context(suite, Unittests, count_tests_return_four_for_four_nested_suite_with_one_testcase_each); set_teardown(suite, unit_tests_teardown); return suite; } cgreen-1.6.3/tests/unit_tests.cpp000066400000000000000000000006361450461175400170470ustar00rootroot00000000000000/* This file used to be a link to the corresponding .c file because we want to compile the same tests for C and C++. But since some systems don't handle symbolic links the same way as *ix systems we get inconsistencies (looking at you Cygwin) or plain out wrong (looking at you MSYS2, copying ?!?!?) behaviour. So we will simply include the complete .c source instead... */ #include "unit_tests.c" cgreen-1.6.3/tests/utils_tests.c000066400000000000000000000010401450461175400166560ustar00rootroot00000000000000#include #include #include "../src/utils.h" Describe(Utils); BeforeEach(Utils) {} AfterEach(Utils) {} Ensure(Utils, panic_output_contains_message) { char message[] = "some error occurred"; char buffer[100]; panic_set_output_buffer(buffer); PANIC(message); assert_that(buffer, contains_string(message)); } Ensure(Utils, panic_output_contains_filename) { char buffer[100]; panic_set_output_buffer(buffer); PANIC(""); assert_that(buffer, contains_string(FILENAME)); } cgreen-1.6.3/tests/vector_tests.c000066400000000000000000000132151450461175400170270ustar00rootroot00000000000000#include #include #include #include "../src/utils.h" #ifdef __cplusplus using namespace cgreen; #endif static CgreenVector *vector; static char a = 'a', b = 'b', c = 'c'; static int times_called = 0; static void set_up_vector(void) { vector = create_cgreen_vector(NULL); times_called = 0; } static void tear_down_vector(void) { destroy_cgreen_vector(vector); } Describe(Vector); BeforeEach(Vector) { set_up_vector(); } AfterEach(Vector) { tear_down_vector(); } Ensure(Vector, new_vector_is_empty) { assert_that(cgreen_vector_size(vector), is_equal_to(0)); } Ensure(Vector, single_item_gives_count_of_one) { cgreen_vector_add(vector, &a); assert_that(cgreen_vector_size(vector), is_equal_to(1)); } Ensure(Vector, single_item_is_readable) { cgreen_vector_add(vector, &a); assert_that(*(char *)cgreen_vector_get(vector, 0), is_equal_to('a')); } Ensure(Vector, double_item_gives_count_of_two) { cgreen_vector_add(vector, &a); cgreen_vector_add(vector, &b); assert_that(cgreen_vector_size(vector), is_equal_to(2)); } Ensure(Vector, two_items_are_readable) { cgreen_vector_add(vector, &a); cgreen_vector_add(vector, &b); assert_that(*(char *)cgreen_vector_get(vector, 0), is_equal_to('a')); assert_that(*(char *)cgreen_vector_get(vector, 1), is_equal_to('b')); } Ensure(Vector, can_extract_only_item) { cgreen_vector_add(vector, &a); assert_that(*(char *)cgreen_vector_remove(vector, 0), is_equal_to('a')); assert_that(cgreen_vector_size(vector), is_equal_to(0)); } Ensure(Vector, can_extract_head_item) { cgreen_vector_add(vector, &a); cgreen_vector_add(vector, &b); cgreen_vector_add(vector, &c); assert_that(*(char *)cgreen_vector_remove(vector, 0), is_equal_to('a')); assert_that(*(char *)cgreen_vector_get(vector, 0), is_equal_to('b')); assert_that(*(char *)cgreen_vector_get(vector, 1), is_equal_to('c')); } Ensure(Vector, can_extract_tail_item) { cgreen_vector_add(vector, &a); cgreen_vector_add(vector, &b); cgreen_vector_add(vector, &c); assert_that(*(char *)cgreen_vector_remove(vector, 2), is_equal_to('c')); assert_that(*(char *)cgreen_vector_get(vector, 0), is_equal_to('a')); assert_that(*(char *)cgreen_vector_get(vector, 1), is_equal_to('b')); } Ensure(Vector, can_extract_middle_item) { cgreen_vector_add(vector, &a); cgreen_vector_add(vector, &b); cgreen_vector_add(vector, &c); assert_that(*(char *)cgreen_vector_remove(vector, 1), is_equal_to('b')); assert_that(*(char *)cgreen_vector_get(vector, 0), is_equal_to('a')); assert_that(*(char *)cgreen_vector_get(vector, 1), is_equal_to('c')); } static void sample_destructor(void *item) { (void)item; times_called++; } Ensure(Vector, destructor_is_called_on_single_item) { CgreenVector *vector = create_cgreen_vector(&sample_destructor); cgreen_vector_add(vector, &a); destroy_cgreen_vector(vector); assert_that(times_called, is_equal_to(1)); } Ensure(Vector, destructor_is_not_called_on_empty_vector) { CgreenVector *vector = create_cgreen_vector(&sample_destructor); destroy_cgreen_vector(vector); assert_that(times_called, is_equal_to(0)); } Ensure(Vector, destructor_is_called_three_times_on_three_item_vector) { CgreenVector *vector = create_cgreen_vector(&sample_destructor); cgreen_vector_add(vector, &a); cgreen_vector_add(vector, &b); cgreen_vector_add(vector, &c); destroy_cgreen_vector(vector); assert_that(times_called, is_equal_to(3)); } Ensure(Vector, vector_size_of_null_pointer_is_zero) { assert_that(cgreen_vector_size(NULL), is_equal_to(0)); } Ensure(Vector, returns_null_for_get_on_illegal_index) { CgreenVector *vector = create_cgreen_vector(NULL); char panic_message[1000]; panic_set_output_buffer(panic_message); assert_that(cgreen_vector_get(vector, -1), is_equal_to(NULL)); assert_that(panic_message, contains_string("illegal position (-1) in vector operation")); destroy_cgreen_vector(vector); } Ensure(Vector, returns_null_for_remove_from_illegal_index) { CgreenVector *vector = create_cgreen_vector(NULL); char panic_message[1000]; panic_set_output_buffer(panic_message); assert_that(cgreen_vector_remove(vector, 1), is_equal_to(NULL)); assert_that(panic_message, contains_string("illegal position (1) in vector operation")); destroy_cgreen_vector(vector); } TestSuite *vector_tests(void) { TestSuite *suite = create_test_suite(); set_setup(suite, set_up_vector); set_teardown(suite, tear_down_vector); add_test_with_context(suite, Vector, new_vector_is_empty); add_test_with_context(suite, Vector, single_item_gives_count_of_one); add_test_with_context(suite, Vector, single_item_is_readable); add_test_with_context(suite, Vector, double_item_gives_count_of_two); add_test_with_context(suite, Vector, two_items_are_readable); add_test_with_context(suite, Vector, can_extract_only_item); add_test_with_context(suite, Vector, can_extract_head_item); add_test_with_context(suite, Vector, can_extract_tail_item); add_test_with_context(suite, Vector, can_extract_middle_item); add_test_with_context(suite, Vector, destructor_is_called_on_single_item); add_test_with_context(suite, Vector, destructor_is_not_called_on_empty_vector); add_test_with_context(suite, Vector, destructor_is_called_three_times_on_three_item_vector); add_test_with_context(suite, Vector, vector_size_of_null_pointer_is_zero); add_test_with_context(suite, Vector, returns_null_for_get_on_illegal_index); add_test_with_context(suite, Vector, returns_null_for_remove_from_illegal_index); return suite; } cgreen-1.6.3/tests/vector_tests.cpp000066400000000000000000000006401450461175400173650ustar00rootroot00000000000000/* This file used to be a link to the corresponding .c file because we want to compile the same tests for C and C++. But since some systems don't handle symbolic links the same way as *ix systems we get inconsistencies (looking at you Cygwin) or plain out wrong (looking at you MSYS2, copying ?!?!?) behaviour. So we will simply include the complete .c source instead... */ #include "vector_tests.c" cgreen-1.6.3/tests/xml_output_tests.c000066400000000000000000000012461450461175400177460ustar00rootroot00000000000000#include #include Ensure(failing_test_is_listed_by_xml_reporter) { assert_that(false); } Ensure(passing_test_is_listed_by_xml_reporter) { assert_that(true); } Ensure(error_message_gets_escaped_by_xml_reporter) { char *test_string = "\n" "\n" " I'm the content & have chars which have to be escaped, " "if put in outer XML.\n" ""; char *expected_string = "I'm not to be found!"; assert_that(test_string, contains_string(expected_string)); } cgreen-1.6.3/tests/xml_output_tests.expected000066400000000000000000000022571450461175400213300ustar00rootroot00000000000000 cgreen-1.6.3/tests/xml_reporter_tests.c000066400000000000000000000154371450461175400202570ustar00rootroot00000000000000#include #include #include #include #include #include #ifdef __cplusplus using namespace cgreen; #endif #include "xml_reporter_internal.h" static const int line=666; static char *output = NULL; static void clear_output(void) { if (NULL != output) { free(output); } output = (char*)malloc(1); *output = '\0'; } static char *concat(char *output, char *buffer) { output = (char *) realloc(output, strlen(output)+strlen(buffer)+1); strcat(output, buffer); return output; } static char* pointer_to_substring(char* haystack, const char* needle) { return strstr(haystack,needle); } static char* pointer_to_second_substring(char* haystack, const char* needle) { return strstr(strstr(haystack,needle)+1,needle); } static int mocked_printf(FILE *file, const char *format, ...) { char buffer[10000]; va_list ap; va_start(ap, format); vsnprintf(buffer, sizeof(buffer), format, ap); va_end(ap); (void)file; output = concat(output, buffer); return strlen(output); } static TestReporter *reporter; static void setup_xml_reporter_tests(void) { reporter = create_xml_reporter("PREFIX"); // We can not use setup_reporting() since we are running // inside a test suite which needs the real reporting // So we'll have to set up the messaging explicitly reporter->ipc = start_cgreen_messaging(667); clear_output(); set_xml_reporter_printer(reporter, mocked_printf); } static void teardown_xml_reporter_tests(void) { //bad mojo when running tests in same process, as destroy_reporter also sets //context.reporter = NULL, thus breaking the next test to run destroy_reporter(reporter); if (NULL != output) { free(output); //need to set output to NULL to avoid second free in //subsequent call to setup_xml_reporter_tests->clear_output //when running tests in same process output = NULL; } } Describe(XmlReporter); BeforeEach(XmlReporter) { setup_xml_reporter_tests(); } AfterEach(XmlReporter) { teardown_xml_reporter_tests(); } Ensure(XmlReporter, will_report_beginning_of_suite) { reporter->start_suite(reporter, "suite_name", 2); assert_that(output, begins_with_string("\nstart_test(reporter, "test_name"); assert_that(output, begins_with_string("show_pass(reporter, "file", 2, "test_name", null_arguments); assert_that(strlen(output), is_equal_to(0)); reporter->finish_test(reporter, "filename", line, NULL); assert_that(output, contains_string("")); } Ensure(XmlReporter, will_report_a_failing_test) { va_list null_arguments; memset(&null_arguments, 0, sizeof(null_arguments)); reporter->start_test(reporter, "test_name"); reporter->show_fail(reporter, "file", 2, "test_name", null_arguments); reporter->finish_test(reporter, "filename", line, NULL); assert_that(output, contains_string("")); assert_that(output, contains_string("")); assert_that(strstr(output, "time="), is_less_than(strstr(output, "start_test(reporter, "test_name"); reporter->show_fail(reporter, "file", 2, "test_failure_message", null_arguments); reporter->show_fail(reporter, "file", 2, "other_message", null_arguments); reporter->finish_test(reporter, "filename", line, NULL); assert_that(pointer_to_substring(output, ""), is_not_null); assert_that(pointer_to_substring(output, ""), is_not_null); assert_that(pointer_to_second_substring(output, ""), is_null); } Ensure(XmlReporter, will_report_finishing_of_suite) { reporter->start_suite(reporter, "suite_name", 1); reporter->finish_suite(reporter, "filename", line); assert_that(output, contains_string("")); } Ensure(XmlReporter, will_mark_ignored_test_as_skipped) { const int line = 666; reporter->start_suite(reporter, "suite_name", 1); reporter->start_test(reporter, "skipped_test_name"); send_reporter_skipped_notification(reporter); reporter->finish_test(reporter, "filename", line, "message"); reporter->finish_suite(reporter, "filename", line); assert_that(output, contains_string("")); assert_that(strstr(output, "time="), is_less_than(strstr(output, "start_suite(reporter, "suite_name", 1); reporter->start_test(reporter, "test_name"); send_reporter_exception_notification(reporter); reporter->finish_test(reporter, "filename", line, "message"); reporter->finish_suite(reporter, "filename", line); assert_that(output, contains_string("error type=\"Fatal\"")); assert_that(output, contains_string("message=\"message\"")); } Ensure(XmlReporter, will_report_time_correctly_for_non_finishing_test) { const int line = 666; reporter->start_suite(reporter, "suite_name", 1); reporter->start_test(reporter, "test_name"); send_reporter_exception_notification(reporter); reporter->finish_test(reporter, "filename", line, "message"); reporter->finish_suite(reporter, "filename", line); assert_that(output, contains_string("name=\"test_name\" time=\"")); } TestSuite *xml_reporter_tests(void) { TestSuite *suite = create_test_suite(); set_setup(suite, setup_xml_reporter_tests); add_test_with_context(suite, XmlReporter, will_report_beginning_of_suite); add_test_with_context(suite, XmlReporter, will_report_beginning_and_successful_finishing_of_passing_test); add_test_with_context(suite, XmlReporter, will_report_a_failing_test); add_test_with_context(suite, XmlReporter, will_report_a_failing_test_only_once); add_test_with_context(suite, XmlReporter, will_mark_ignored_test_as_skipped); add_test_with_context(suite, XmlReporter, will_report_finishing_of_suite); add_test_with_context(suite, XmlReporter, will_report_non_finishing_test); add_test_with_context(suite, XmlReporter, will_report_time_correctly_for_non_finishing_test); set_teardown(suite, teardown_xml_reporter_tests); return suite; } cgreen-1.6.3/tests/xml_reporter_tests.cpp000066400000000000000000000006461450461175400206130ustar00rootroot00000000000000/* This file used to be a link to the corresponding .c file because we want to compile the same tests for C and C++. But since some systems don't handle symbolic links the same way as *ix systems we get inconsistencies (looking at you Cygwin) or plain out wrong (looking at you MSYS2, copying ?!?!?) behaviour. So we will simply include the complete .c source instead... */ #include "xml_reporter_tests.c" cgreen-1.6.3/tools/000077500000000000000000000000001450461175400141335ustar00rootroot00000000000000cgreen-1.6.3/tools/.gitignore000066400000000000000000000001571450461175400161260ustar00rootroot00000000000000*.o *.d lib*.so discoverer_unit_test_runner.c discoverer_unit_tests runner_unit_test_runner.c runner_unit_testscgreen-1.6.3/tools/CMakeLists.txt000066400000000000000000000112621450461175400166750ustar00rootroot00000000000000include_directories(${CGREEN_PUBLIC_INCLUDE_DIRS} ${PROJECT_BINARY_DIR} ${CURRENT_BINARY_DIR}) set(RUNNER_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/cgreen-runner.c ${CMAKE_CURRENT_SOURCE_DIR}/gopt.c ${CMAKE_CURRENT_SOURCE_DIR}/gopt-errors.c ${CMAKE_CURRENT_SOURCE_DIR}/runner.c ${CMAKE_CURRENT_SOURCE_DIR}/discoverer.c ${CMAKE_CURRENT_SOURCE_DIR}/test_item.c ${CMAKE_CURRENT_SOURCE_DIR}/io.c ) set_source_files_properties(${RUNNER_SRCS} PROPERTIES LANGUAGE C) # Do we have an "nm"? include(FindNm) if (NM_FOUND) set_source_files_properties(discoverer.c PROPERTIES COMPILE_FLAGS -DNM_EXECUTABLE='\"${NM_EXECUTABLE}\"') include(DefineRelativeFilePaths) cmake_define_relative_file_paths("${RUNNER_SRCS}") add_executable(cgreen-runner ${RUNNER_SRCS}) target_link_libraries(cgreen-runner ${CGREEN_LIBRARY} $<$:${LIBXML2_LIBRARIES}> ${CMAKE_DL_LIBS}) install(TARGETS cgreen-runner LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} DESTINATION ${CMAKE_INSTALL_BINDIR} ) install(FILES cgreen-debug DESTINATION ${CMAKE_INSTALL_BINDIR}) set(CGREEN_RUNNER_TESTS_LIBRARY cgreen_runner_tests CACHE INTERNAL "cgreen-runner tests shared library" ) set(RUNNER_TESTS_SRCS runner_unit_tests.c test_item.c ) add_library(${CGREEN_RUNNER_TESTS_LIBRARY} SHARED ${RUNNER_TESTS_SRCS}) target_link_libraries(${CGREEN_RUNNER_TESTS_LIBRARY} ${CGREEN_LIBRARY}) # Due to some (of many) CMake irregularities to reference the test libraries # we can't just use its CMake name variable, but have to look it up with # some special attributes of the library: # $/$ # SET(CGREEN_RUNNER_TESTS_LIBRARY "$/$") macro_add_test(NAME cgreen_runner_unit_tests COMMAND cgreen-runner ${CGREEN_RUNNER_TESTS_LIBRARY}) macro_add_test(NAME cgreen_runner_usage COMMAND cgreen-runner --help) macro_add_test(NAME cgreen_runner_quiet COMMAND cgreen-runner -q ${CGREEN_RUNNER_TESTS_LIBRARY}) macro_add_test(NAME cgreen_runner_verbose COMMAND cgreen-runner -v -C ${CGREEN_RUNNER_TESTS_LIBRARY}) macro_add_test(NAME cgreen_runner_version COMMAND cgreen-runner --version) macro_add_test(NAME cgreen_runner_single_explicit_named_test COMMAND cgreen-runner $/$ Runner:can_match_test_name) macro_add_test(NAME cgreen_runner_patternmatched_testnames COMMAND cgreen-runner $/$ Runner:can*) macro_add_test(NAME cgreen_runner_suite_name COMMAND cgreen-runner -s Suite ${CGREEN_RUNNER_TESTS_LIBRARY}) macro_add_test(NAME cgreen_runner_fail_on_non_existing_library COMMAND cgreen-runner Suite non_existent_library) set_tests_properties(cgreen_runner_fail_on_non_existing_library PROPERTIES WILL_FAIL true) macro_add_test(NAME cgreen_runner_fail_on_non_existing_library_with_suite COMMAND cgreen-runner -s Suite non_existent_library WILL_FAIL) set_tests_properties(cgreen_runner_fail_on_non_existing_library_with_suite PROPERTIES WILL_FAIL true) macro_add_test(NAME cgreen_runner_patternmatched_testnames_in_patternmatched_context COMMAND cgreen-runner $/$ Run*:can*) macro_add_test(NAME cgreen_runner_wildcarded_tests_in_named_context COMMAND cgreen-runner $/$ Runner:*) macro_add_test(NAME cgreen_runner_wildcarded_tests_in_wildcarded_context COMMAND cgreen-runner $/$ *:*) if (CGREEN_WITH_XML) macro_add_test(NAME cgreen_runner_with_xml_reporter COMMAND cgreen-runner --xml TEST --suite cgreen_runner_tests $/$) endif (CGREEN_WITH_XML) if (CGREEN_WITH_LIBXML2) macro_add_test(NAME cgreen_runner_with_libxml2_reporter COMMAND cgreen-runner --libxml2 TEST --suite cgreen_runner_tests $/$) endif (CGREEN_WITH_LIBXML2) macro_add_test(NAME cgreen_runner_multiple_libraries COMMAND cgreen-runner ${CGREEN_RUNNER_TESTS_LIBRARY} ${CGREEN_RUNNER_TESTS_LIBRARY} ${CGREEN_RUNNER_TESTS_LIBRARY}) else() message("No 'nm' found on this system. 'cgreen-runner' will not be built.") endif() cgreen-1.6.3/tools/Makefile000066400000000000000000000074501450461175400156010ustar00rootroot00000000000000# Makefile to run unit tests for cgreen-runner units # # We are using cgreen itself to test this but since the modules here # might at some point get into the actual cgreen-runner there will be # a clash when it loads the test library. So we will have to make the # external symbols in the modules have other names when unittesting # them using macro magic. The UNITTESTING preprocessor symbol will # add the suffix '_unittesting' to externally, clashing symbols so # that we can separate the ones in the cgreen-runner that is running # the tests, and the ones in the units being tested. UNAMEOEXISTS=$(shell uname -o 1>&2 2>/dev/null; echo $$?) ifeq ($(UNAMEOEXISTS),0) OS=$(shell uname -o) else OS=$(shell uname -s) endif CFLAGS = -Wall -g -I../include -MMD -DUNITTESTING -I. ifneq ($(OS),Cygwin) CFLAGS+=-fPIC endif LDFLAGS = $(COMMONFLAGS) LIBRARIES = -L../build/src -lcgreen VPATH = ../src ifeq ($(OS),Darwin) LD_PATH_NAME=DYLD_LIBRARY_PATH else LD_PATH_NAME=LD_LIBRARY_PATH endif CGREEN_RUNNER = $(LD_PATH_NAME)=../build/src cgreen-runner # Redirect to CMake build from top level all: make --no-print-directory -C .. # Use this if you want quick feed-back in this directory tests: unit_tests acceptance_tests #---------------------------------------------------------------------- unit unit_tests: discoverer_unit_tests runner_unit_tests LD_LIBRARY_PATH=. ./discoverer_unit_tests LD_LIBRARY_PATH=. ./runner_unit_tests discoverer.o: CFLAGS += -DNM_EXECUTABLE='"nm"' discoverer_unit_tests : discoverer_unit_tests.so $(CC) $(LDFLAGS) -o $@ $^ discoverer_unit_tests.so : discoverer_unit_test_runner.o discoverer.o test_item.o $(CC) $(LDFLAGS) -shared -o $@ $^ $(LIBRARIES) # Auto-generate a runner for discoverer unittests discoverer_unit_test_runner.c : discoverer_unit_tests.c echo "#include \"discoverer_unit_tests.c\"" > discoverer_unit_test_runner.c echo "TestSuite *discoverer_unit_tests() {" >> discoverer_unit_test_runner.c echo " TestSuite *suite = create_test_suite();" >> discoverer_unit_test_runner.c grep Ensure discoverer_unit_tests.c | sed -e 's/Ensure(/ add_test_with_context(suite, /g' -e 's/) {/);/g' >> discoverer_unit_test_runner.c echo " return suite;" >> discoverer_unit_test_runner.c echo "}" >> discoverer_unit_test_runner.c echo "int main(int argc, char **argv) {" >> discoverer_unit_test_runner.c echo " return run_test_suite(discoverer_unit_tests(), create_text_reporter());" >> discoverer_unit_test_runner.c echo "}" >> discoverer_unit_test_runner.c runner_unit_tests: runner_unit_tests.so $(CC) $(LDFLAGS) -o $@ $^ $(LIBRARIES) runner_unit_tests.so: runner_unit_test_runner.o test_item.o $(CC) $(LDFLAGS) -shared -o $@ $^ -ldl $(LIBRARIES) # Auto-generate a runner for runner unittests runner_unit_test_runner.c : runner_unit_tests.c echo "#include \"runner_unit_tests.c\"" > runner_unit_test_runner.c echo "TestSuite *runner_unit_tests() {" >> runner_unit_test_runner.c echo " TestSuite *suite = create_test_suite();" >> runner_unit_test_runner.c grep Ensure runner_unit_tests.c | sed -e 's/Ensure(/ add_test_with_context(suite, /g' -e 's/) {/);/g' >> runner_unit_test_runner.c echo " return suite;" >> runner_unit_test_runner.c echo "}" >> runner_unit_test_runner.c echo "int main(int argc, char **argv) {" >> runner_unit_test_runner.c echo " return run_test_suite(runner_unit_tests(), create_text_reporter());" >> runner_unit_test_runner.c echo "}" >> runner_unit_test_runner.c #---------------------------------------------------------------------- acceptance_tests: libdiscoverer_acceptance_tests.so $(CGREEN_RUNNER) $^ libdiscoverer_acceptance_tests.so: discoverer_acceptance_tests.o discoverer.o test_item.o io.o $(CC) -shared -o $@ $^ $(LIBRARIES) #---------------------------------------------------------------------- clean: -rm *.o *.so *.dll -include *.d cgreen-1.6.3/tools/TODO000066400000000000000000000000001450461175400146110ustar00rootroot00000000000000cgreen-1.6.3/tools/build_mock_table.pl000066400000000000000000000057621450461175400177610ustar00rootroot00000000000000#!perl use strict; use warnings; print <<'EOF'; #ifndef MOCK_TABLE_HEADER #define MOCK_TABLE_HEADER /* DO NOT EDIT THIS FILE */ /* auto-generated by build_mock_table.pl */ #define MOCK_VA_NUM_ARGS(...) MOCK_VA_NUM_ARGS_IMPL_((__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)) #define MOCK_VA_NUM_ARGS_IMPL_(tuple) MOCK_VA_NUM_ARGS_IMPL tuple #define MOCK_VA_NUM_ARGS_IMPL( \ _1, _2, _3, _4, _5, _6, _7, _8, _9,_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,N,...) N #define MOCK_macro_dispatcher(func, ...) MOCK_macro_dispatcher_(func, MOCK_VA_NUM_ARGS(__VA_ARGS__)) // the three levels of indirection are a work-around for broken variadic macro support in Visual C++ #define MOCK_macro_dispatcher_(func, nargs) MOCK_macro_dispatcher__(func, nargs) #define MOCK_macro_dispatcher__(func, nargs) MOCK_macro_dispatcher___(func, nargs) #define MOCK_macro_dispatcher___(func, nargs) func ## nargs #define PP_NARG(...) MOCK_macro_dispatcher(mock, __VA_ARGS__) //mock1 works for 1 or 0 #define mock1(test_reporter, function_name, mock_file, mock_line, arguments_string, ...)\ mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, __VA_ARGS__) EOF my @macros; my @mocks = ("mock_", "mock_"); for my $i (2 .. 63) { push(@mocks, sprintf("mock%d", $i)); push(@macros, define_mock($i)); } my @reverse_mocks = reverse(@mocks); my @chunk; print "#define PP_RSEQ_N() \\\n"; while (@chunk = splice(@reverse_mocks, 0, 10)) { print "\t"; print join(", ", @chunk); if (@reverse_mocks) { print ",\\\n"; } else { print "\n"; } } print "\n"; print join("\n", @macros); print "\n"; print "#endif /* MOCK_TABLE_HEADER */\n"; sub define_mock { my ($num_args) = @_; my @args; my $i; for ($i = 0; $i < $num_args; $i++) { push(@args, sprintf "arg%d", $i); } my $macro = sprintf("#define mock%d", $num_args); $macro .= "(test_reporter, function_name, mock_file, mock_line, arguments_string, "; $macro .= join(", ", @args); $macro .= ")\\\n"; $macro .= " mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, "; $macro .= join(", ", (map "(intptr_t) $_", @args)); $macro .= ")\n"; return $macro; } cgreen-1.6.3/tools/cgreen-debug000077500000000000000000000121671450461175400164170ustar00rootroot00000000000000#!/bin/bash # cgreen-debug # # Script to start cgreen-runner under gdb, load a library and break # on a named test. # # If you are viewing 'cgreen-debug' this *is* that script and you'll # find the logic at the end of this file. To update it, edit # `cgreen-debug.argbash` instead. # But if you are looking at 'cgreen-debug.argbash' then this is # actually a template for argbash (https://argbash.io) which generates # argument parsing capable bash scripts from a template just like # this. # To generate a new 'cgreen-debug' use # # 'argbash cgreen-debug.argbash -o cgreen-debug' # # if you have argbash installed, or go to https://argbash.io and paste # this file into the online version. # ARG_HELP([Start cgreen-runner under GDB (or other debugger) and break at a specific test]) # ARG_OPTIONAL_SINGLE([debugger],[d],[The debugger to use],[cgdb]) # ARG_POSITIONAL_SINGLE([library],[Dynamically loadable library with Cgreen tests],[]) # ARG_POSITIONAL_SINGLE([testname],[The test to debug, in Cgreen notation (':')],[]) # ARGBASH_GO() # needed because of Argbash --> m4_ignore([ ### START OF CODE GENERATED BY Argbash v2.9.0 one line above ### # Argbash is a bash code generator used to get arguments parsing right. # Argbash is FREE SOFTWARE, see https://argbash.io for more info # Generated online by https://argbash.io/generate die() { local _ret="${2:-1}" test "${_PRINT_HELP:-no}" = yes && print_help >&2 echo "$1" >&2 exit "${_ret}" } begins_with_short_option() { local first_option all_short_options='hd' first_option="${1:0:1}" test "$all_short_options" = "${all_short_options/$first_option/}" && return 1 || return 0 } # THE DEFAULTS INITIALIZATION - POSITIONALS _positionals=() # THE DEFAULTS INITIALIZATION - OPTIONALS _arg_debugger="cgdb" print_help() { printf '%s\n' "Start cgreen-runner under GDB (or other debugger) and break at a specific test" printf 'Usage: %s [-h|--help] [-d|--debugger ] \n' "$0" printf '\t%s\n' ": Dynamically loadable library with Cgreen tests" printf '\t%s\n' ": The test to debug, in Cgreen notation (':')" printf '\t%s\n' "-h, --help: Prints help" printf '\t%s\n' "-d, --debugger: The debugger to use (default: 'cgdb')" } parse_commandline() { _positionals_count=0 while test $# -gt 0 do _key="$1" case "$_key" in -h|--help) print_help exit 0 ;; -h*) print_help exit 0 ;; -d|--debugger) test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 _arg_debugger="$2" shift ;; --debugger=*) _arg_debugger="${_key##--debugger=}" ;; -d*) _arg_debugger="${_key##-d}" ;; *) _last_positional="$1" _positionals+=("$_last_positional") _positionals_count=$((_positionals_count + 1)) ;; esac shift done } handle_passed_args_count() { local _required_args_string="'library' and 'testname'" test "${_positionals_count}" -ge 2 || _PRINT_HELP=yes die "FATAL ERROR: Not enough positional arguments - we require exactly 2 (namely: $_required_args_string), but got only ${_positionals_count}." 1 test "${_positionals_count}" -le 2 || _PRINT_HELP=yes die "FATAL ERROR: There were spurious positional arguments --- we expect exactly 2 (namely: $_required_args_string), but got ${_positionals_count} (the last one was: '${_last_positional}')." 1 } assign_positional_args() { local _positional_name _shift_for=$1 _positional_names="_arg_library _arg_testname " shift "$_shift_for" for _positional_name in ${_positional_names} do test $# -gt 0 || break eval "$_positional_name=\${1}" || die "Error during argument parsing, possibly an Argbash bug." 1 shift done } parse_commandline "$@" handle_passed_args_count assign_positional_args 1 "${_positionals[@]}" # OTHER STUFF GENERATED BY Argbash ### END OF CODE GENERATED BY Argbash (sortof) ### ]) # [ <-- needed because of Argbash if [ "$_arg_debugger" == "" ]; then if command -v cgdb > /dev/null 2>&1 ; then debugger=cgdb else debugger=gdb fi else if command -v $_arg_debugger > /dev/null 2>&1 ; then debugger=$_arg_debugger else echo "No such debugger: $_arg_debugger" exit 1 fi fi # Figure out where to place breakpoint by replacing ':' with '__' bp=${_arg_testname//:/__} if [ "$debugger" == "lldb" ] ; then echo break set -n $bp > .cgreen-debug-commands echo run $_arg_library $_arg_testname >> .cgreen-debug-commands $debugger cgreen-runner --source .cgreen-debug-commands else echo break $bp > .cgreen-debug-commands echo run $_arg_library $_arg_testname >> .cgreen-debug-commands $debugger -ex "set breakpoint pending on" cgreen-runner --command=.cgreen-debug-commands fi #rm .cgreen-debug-commands # ] <-- needed because of Argbash cgreen-1.6.3/tools/cgreen-debug.argbash000066400000000000000000000037161450461175400200220ustar00rootroot00000000000000#!/bin/bash # cgreen-debug # # Script to start cgreen-runner under gdb, load a library and break # on a named test. # # If you are viewing 'cgreen-debug' this *is* that script and you'll # find the logic at the end of this file. To update it, edit # `cgreen-debug.argbash` instead. # But if you are looking at 'cgreen-debug.argbash' then this is # actually a template for argbash (https://argbash.io) which generates # argument parsing capable bash scripts from a template just like # this. # To generate a new 'cgreen-debug' use # # 'argbash cgreen-debug.argbash -o cgreen-debug' # # if you have argbash installed, or go to https://argbash.io and paste # this file into the online version. # ARG_HELP([Start cgreen-runner under GDB (or other debugger) and break at a specific test]) # ARG_OPTIONAL_SINGLE([debugger], d, [The debugger to use], [cgdb]) # ARG_POSITIONAL_SINGLE([library], [Dynamically loadable library with Cgreen tests], ) # ARG_POSITIONAL_SINGLE([testname], [The test to debug, in Cgreen notation (':')], ) # ARGBASH_GO # [ <-- needed because of Argbash if [ "$_arg_debugger" == "" ]; then if command -v cgdb > /dev/null 2>&1 ; then debugger=cgdb else debugger=gdb fi else if command -v $_arg_debugger > /dev/null 2>&1 ; then debugger=$_arg_debugger else echo "No such debugger: $_arg_debugger" exit 1 fi fi # Figure out where to place breakpoint by replacing ':' with '__' bp=${_arg_testname//:/__} if [ "$debugger" == "lldb" ] ; then echo break set -n $bp > .cgreen-debug-commands echo run $_arg_library $_arg_testname >> .cgreen-debug-commands $debugger cgreen-runner --source .cgreen-debug-commands else echo break $bp > .cgreen-debug-commands echo run $_arg_library $_arg_testname >> .cgreen-debug-commands $debugger -ex "set breakpoint pending on" cgreen-runner --command=.cgreen-debug-commands fi rm .cgreen-debug-commands # ] <-- needed because of Argbash cgreen-1.6.3/tools/cgreen-runner.c000066400000000000000000000253011450461175400170520ustar00rootroot00000000000000#include #include #include #include "utils.h" #include #include #include "gopt.h" #include "runner.h" #include "discoverer.h" /*----------------------------------------------------------------------*/ static int file_exists(const char *filename) { if (! filename) return 0; return (access(filename, F_OK) == 0); } /*----------------------------------------------------------------------*/ static void version(void) { printf("cgreen-runner for Cgreen unittest and mocking framework v%s\n", VERSION); printf("Cgreen library version %s (%s) loaded\n", cgreen_library_version, cgreen_library_revision); } /*----------------------------------------------------------------------*/ static void usage(const char *program_name) { printf("cgreen-runner for Cgreen unittest and mocking framework v%s\n\n", VERSION); printf("Usage:\n %s [--suite ] [--verbose] [--quiet] [--no-run] " #if HAVE_XML_REPORTER "[--xml ] " #endif #if HAVE_LIBXML2_REPORTER "[--libxml2 ] " #endif "[--help] ( [])+\n\n", program_name); printf("Discover and run all or named cgreen test(s) from one or multiple\n"); printf("dynamically loadable libraries.\n\n"); printf("A single test can be run using the form [:] where can\n"); printf("be omitted if there is no context.\n\n"); printf(" -c --colours/colors\t\tUse colours to emphasis result (requires ANSI-capable terminal)\n"); printf(" -C --no-colours/no-colors\tDon't use colours\n"); #if HAVE_XML_REPORTER printf(" -x --xml \t\tInstead of messages on stdout, write results into one XML-file\n"); printf("\t\t\t\tper suite, compatible with Hudson/Jenkins CI. The filename(s)\n"); printf("\t\t\t\twill be '-.xml'\n"); #endif #if HAVE_LIBXML2_REPORTER printf(" -X --libxml2 \t\tFormat the test results using libxml2\n"); #endif printf(" -s --suite \t\tName the top level suite\n"); printf(" -n --no-run\t\t\tDon't run the tests\n"); printf(" -v --verbose\t\t\tShow progress information\n"); printf(" -q --quiet\t\t\tJust output dots for each test\n"); printf(" --version\t\t\tShow version information\n"); } /*======================================================================*/ enum option_arg { HELP_OPT, XML_OPT, LIBXML2_OPT, SUITE_OPT, VERBOSE_OPT, QUITE_OPT, VERSION_OPT, COLORS_OPT, COLOURS_OPT, NO_COLORS_OPT, NO_COLOURS_OPT, NO_RUN_OPT, LAST_OPT, }; static struct option options[] = { [HELP_OPT] = { .short_name = 'h', .long_name = "help", .flags = GOPT_ARGUMENT_FORBIDDEN, }, [XML_OPT] = { #if HAVE_XML_REPORTER .short_name = 'x', .long_name = "xml", .flags = GOPT_ARGUMENT_REQUIRED, #endif }, [LIBXML2_OPT] = { #if HAVE_LIBXML2_REPORTER .short_name = 'X', .long_name = "libxml2", #endif .flags = GOPT_ARGUMENT_REQUIRED, }, [SUITE_OPT] = { .short_name = 's', .long_name = "suite", .flags = GOPT_ARGUMENT_REQUIRED, }, [VERBOSE_OPT] = { .short_name = 'v', .long_name = "verbose", .flags = GOPT_ARGUMENT_FORBIDDEN, }, [QUITE_OPT] = { .short_name = 'q', .long_name = "quiet", .flags = GOPT_ARGUMENT_FORBIDDEN, }, [VERSION_OPT] = { .short_name = 'V', .long_name = "version", .flags = GOPT_ARGUMENT_FORBIDDEN, }, [COLORS_OPT] = { .short_name = 'c', .long_name = "colors", .flags = GOPT_ARGUMENT_FORBIDDEN, }, [COLOURS_OPT] = { .short_name = 'c', .long_name = "colours", .flags = GOPT_ARGUMENT_FORBIDDEN, }, [NO_COLORS_OPT] = { .short_name = 'C', .long_name = "no-colors", .flags = GOPT_ARGUMENT_FORBIDDEN, }, [NO_COLOURS_OPT] = { .short_name = 'C', .long_name = "no-colours", .flags = GOPT_ARGUMENT_FORBIDDEN, }, [NO_RUN_OPT] = { .short_name = 'n', .long_name = "no-run", .flags = GOPT_ARGUMENT_FORBIDDEN, }, [LAST_OPT] = { .flags = GOPT_LAST, }, }; static TestReporter *reporter = NULL; static TextReporterOptions reporter_options; static void cleanup(void) { if (reporter) reporter->destroy(reporter); } static char* get_a_suite_name(const char *suite_option, const char *test_library_name) { if (suite_option == NULL) { char *suite_name; char *s; /* basename can return the parameter or an internal static string. Work around this. */ s = string_dup(test_library_name); suite_name = string_dup(basename(s)); free(s); if ((s = strchr(suite_name, '.'))) { *s = '\0'; } return suite_name; } else { return string_dup(suite_option); } } /*----------------------------------------------------------------------*/ static bool have_xml_option(void) { return options[XML_OPT].count > 0 || options[LIBXML2_OPT].count > 0; } static bool have_libxml2_option(void) { return options[LIBXML2_OPT].count > 0; } /*----------------------------------------------------------------------*/ static bool run_tests_in_library(const char *suite_name_option, const char *test_name, const char *test_library, bool verbose, bool no_run) { int status; char *suite_name; suite_name = get_a_suite_name(suite_name_option, test_library); status = runner(reporter, test_library, suite_name, test_name, verbose, no_run); free((void*)suite_name); return status != 0; } /*----------------------------------------------------------------------*/ static void print_common_header(const char *suite_name_option, int library_count, int test_count) { char in_libraries_text[100] = ""; sprintf(in_libraries_text, " in %d libraries", library_count); printf("Running \"%s\" (%d test%s%s)...\n", suite_name_option, test_count, test_count>1?"s":"", in_libraries_text); } /*----------------------------------------------------------------------*/ static void inhibit_appropriate_suite_message(int i, int library_count) { /* If we are using the text_reporter && a common suite name then inhibit the start suite message for all libraries and for all except the last library inhibit the finish suite message. NOTE that the last library might be the second to last arg since there might be a testname pattern after it. */ reporter_options.inhibit_start_suite_message = true; if (i < library_count-1 && library_count > 1) { reporter_options.inhibit_finish_suite_message = true; } else reporter_options.inhibit_finish_suite_message = false; } /*======================================================================*/ int main(int argc, char **argv) { int i; bool verbose = false; bool no_run = false; const char *suite_name_option = NULL; bool any_fail = false; atexit(cleanup); argc = gopt(argv, options); gopt_errors(argv[0], options); if (have_libxml2_option()) { #if HAVE_LIBXML2_REPORTER reporter = create_libxml_reporter(options[LIBXML2_OPT].argument); #else printf("libxml2 reporter not available\n"); return EXIT_FAILURE; #endif } else if (have_xml_option()) { #if HAVE_XML_REPORTER reporter = create_xml_reporter(options[XML_OPT].argument); #else printf("XML reporter not available\n"); return EXIT_FAILURE; #endif } else reporter = create_text_reporter(); suite_name_option = options[SUITE_OPT].argument; verbose = options[VERBOSE_OPT].count > 0; no_run = options[NO_RUN_OPT].count > 0; reporter_options.use_colours = true; if (isatty(fileno(stdout))) { if (options[NO_COLORS_OPT].count || options[NO_COLOURS_OPT].count) reporter_options.use_colours = false; } else { if (!options[COLORS_OPT].count && !options[COLOURS_OPT].count) reporter_options.use_colours = false; } panic_use_colours = reporter_options.use_colours; reporter_options.quiet_mode = options[QUITE_OPT].count > 0; if (options[HELP_OPT].count) { usage(argv[0]); return EXIT_SUCCESS; } if (options[VERSION_OPT].count) { version(); return EXIT_SUCCESS; } if (argc < 2) { usage(argv[0]); return EXIT_FAILURE; } set_reporter_options(reporter, &reporter_options); /* Walk through all arguments and set up list of libraries and testnames */ const char **libraries; /* Array of libraries to run tests in */ libraries = malloc(sizeof(char *)*argc); const char **testname; /* Array of test name patterns, maybe NULL */ testname = malloc(sizeof(char *)*argc); int library_count = 0; /* Find libraries */ i = 1; while(i < argc) { libraries[library_count++] = argv[i++]; /* Check if the next argument is not a filename, thus a test name, remember and move past it */ if (!file_exists(argv[i])) { testname[library_count-1] = argv[i++]; } else testname[library_count-1] = NULL; } reporter_options.inhibit_start_suite_message = false; reporter_options.inhibit_finish_suite_message = false; int test_count = 0; if (!have_xml_option() && (suite_name_option != NULL)) { /* Count all tests */ for (i = 0; i__ from the library in $word local SUTs=( $(printf "%s\n" "${specs[@]}" | awk -F '__' '{ print $1 }' | sort | uniq) ) # SUTs should now contain all SUTs present in the library for SUT in "${SUTs[@]}"; do sut_tests=() for spec in "${specs[@]}"; do if [[ $spec == "$SUT"* ]] ; then sut_tests+=( $spec ) fi done if test $SUT = "default" ; then # Tests have no SUT in its name tests+=( ${sut_tests[@]/default__/} ) else tests+=( ${sut_tests[@]/__/:} ) fi done fi } case $OSTYPE in darwin* ) LIBEXT=dylib ;; linux* ) LIBEXT=so ;; cygwin ) LIBEXT=dll ;; esac _cgreen_runner_completion() { local options libraries tests options=("--colours" "--no-colours" "--xml" "--suite" "--verbose" "--no-run" "--help" " --version") libraries=() tests=() # Look for words in the command given so far for word in ${COMP_WORDS[@]:1}; do # Matching loadable libraries? if compgen -G "$word*.$LIBEXT" > /dev/null; then # Add that pattern libraries+=($word*.$LIBEXT) fi # Is it a library? if echo $word | grep -q -E "\b\.$LIBEXT\b"; then _discover_tests fi done # Remove all suggestions already used for word in ${COMP_WORDS[@]:1}; do if [[ "$word" != "${COMP_WORDS[0]}" ]] ; then _removeFromOptions $word _removeFromLibraries $word _removeFromTests $word fi done completion_word=${COMP_WORDS[$COMP_CWORD]} expansions="${options[@]} ${libraries[@]} ${tests[@]}" COMPREPLY=($(compgen -W "$expansions" -- "$completion_word")) } _cgreen_debug_completion() { local options libraries tests options=("--debugger") libraries=() tests=() # Look for words in the command given so far for word in ${COMP_WORDS[@]}; do # Matching loadable libraries? if compgen -G "$word*.$LIBEXT" > /dev/null; then # Add that pattern libraries+=($word*.$LIBEXT) fi if echo $word | grep -q -E "\b\.$LIBEXT\b"; then _discover_tests fi done # Remove libraries and tests if already used (only one library and one test allowed) for word in ${COMP_WORDS[@]}; do if [[ $word == *".$LIBEXT" ]]; then # Only one library allowed libraries=() fi if [[ $word == *"\\:"* ]]; then if [[ "${COMP_WORDS[$COMP_CWORD]}" == "" ]]; then # Only one test allowed tests=() fi fi if [[ "$word" != "${COMP_WORDS[0]}" ]] ; then _removeFromOptions $word fi done completion_word=${COMP_WORDS[$COMP_CWORD]} expansions="${options[@]} ${libraries[@]} ${tests[@]}" COMPREPLY=($(compgen -W "$expansions" -- "$completion_word")) } complete -o nosort -o dirnames -A directory -F _cgreen_runner_completion cgreen-runner complete -o nosort -A directory -F _cgreen_debug_completion cgreen-debug cgreen-1.6.3/tools/cgreen_libxml_output_diff000077500000000000000000000057051450461175400213120ustar00rootroot00000000000000#!/bin/bash # # Will run the cgreen-runner in directory ../tools # on library with name $1 (e.g. 'lib${name}.so') # generating XML output that will be compared to # sources are in $2 for... # ...expected output file name in $3 # ...and commands to normalize output (in the file normalize_{name}.sed) # # Determine OS unameo=`uname -o 1>/dev/null 2>/dev/null; echo $?` if [ $unameo -eq 0 ]; then OS=`uname -o` else OS=`uname -s` fi # Set up library prefix and extension case "$OS" in Darwin) prefix=lib extension=dylib ;; GNU/Linux|FreeBSD) prefix=lib extension=so ;; Cygwin) prefix=cyg extension=dll ;; Msys) prefix=lib extension=dll ;; *) echo "ERROR: $0 can't handle OS=$OS" exit 2 ;; esac # Handle arguments if [ $# -ne 3 ]; then echo "ERROR: $0 requires exactly 3 arguments" exit 2 fi # TODO: don't shift name=$1; shift 1 sourcedir=$1 ; shift 1 sourcedir=$(perl -e 'use Cwd "abs_path"; print abs_path(@ARGV[0])' -- "$sourcedir") if [ $(uname -n) = thoni64 ]; then # On my Cygwin machine I have linked /home to c:/Users so absolute paths don't match # what runner prints, so try to replace that (don't know how to generalize this...) sourcedir=`echo $sourcedir | sed -e s#/cygdrive/c/Users#/home#` fi # TODO: don't shift expected=$1 ; shift 1 commandfile="${sourcedir}/normalize_${name}.sed" # Do it! if [ -z "$CGREEN_PER_TEST_TIMEOUT" ]; then printf "Comparing output of ${name} to expected: " else printf "Comparing output of ${name} to expected with CGREEN_PER_TEST_TIMEOUT=$CGREEN_PER_TEST_TIMEOUT: " fi # Run runner on library store output and error ../tools/cgreen-runner -X L "${prefix}${name}.${extension}" > "${name}.output" 2> "${name}.error" cat "${name}.error" >> "${name}.output" cat L-*${name}.xml L-*${name}-default.xml >> "${name}.output" tempfile=`mktemp` # sed commands to normalize... # - line numbers in error messages echo "s/:[0-9]+:/:/g" > $tempfile # - timing info echo "s/in [0-9]+ms\./in 0ms\./g" >> $tempfile # - library prefix # TODO: should use prefix, shouldn't it? echo s/\".*${name}\"/\"${name}\"/g >> $tempfile # - source path, ensure parenthesis are not interpreted by sed -E # but allow any characters before sourcedir in the string echo s%\".*${sourcedir//[\(\)]/.}/%\"%g >> $tempfile # Do normalization using the commands in the tempfile and the specified commandfile sed -E -f "${tempfile}" -f "${commandfile}" "${name}.output" > "${name}.output.normalized" # Check for color capability if test -t 1; then ncolors=$(tput colors) if test -n "$ncolors" && test $ncolors -ge 8; then green="$(tput setaf 2)" normal="$(tput sgr0)" fi fi # Compare normalized output to expected cmp -s "${name}.output.normalized" "${sourcedir}/${expected}" # If not the same, show diff rc=$? if [ $rc -ne 0 ] then echo diff -c "${name}.output.normalized" "${sourcedir}/${expected}" else echo ${green}Ok${normal} fi exit $rc cgreen-1.6.3/tools/cgreen_runner_output_diff000077500000000000000000000057701450461175400213360ustar00rootroot00000000000000#!/bin/bash # # Will run the cgreen-runner in directory ../tools # on library with name $1 (e.g. 'lib${name}.so') # sources are in $2 for... # ...expected output file name in $3 # ...and commands to normalize output (in the file normalize_{name}.sed) # # TODO: refactor the duplication in this and cgreen_xml_output_diff to something # not having the duplication, common sub-script, maybe? # # TODO: make 'prefix' and 'extension' into arguments instead of evaluating them here # Determine OS unameo=`uname -o 1>/dev/null 2>/dev/null; echo $?` if [ $unameo -eq 0 ]; then OS=`uname -o` else OS=`uname -s` fi # Set up library prefix and extension case "$OS" in Darwin) prefix=lib extension=dylib ;; GNU/Linux|FreeBSD) prefix=lib extension=so ;; Cygwin) prefix=cyg extension=dll ;; Msys) prefix=msys- extension=dll ;; *) echo "ERROR: $0 can't handle OS=$OS" exit 2 ;; esac # Handle arguments if [ $# -ne 3 ]; then echo "ERROR: $0 requires exactly 3 arguments" exit 2 fi # TODO: don't shift name=$1; shift 1 sourcedir=$1 ; shift 1 sourcedir=$(perl -e 'use Cwd "abs_path"; print abs_path(@ARGV[0])' -- "$sourcedir") if [ $(uname -n) = thoni64 ]; then # On my Cygwin machine I have linked /home to c:/Users so absolute paths don't match # what runner prints, so try to replace that # TODO: generalize this... sourcedir=`echo $sourcedir | sed -e s#/cygdrive/c/Users#/home#` fi expected=$1 ; shift 1 # TODO: remove empty normalize-files and don't call them if not necessary commandfile="${sourcedir}/normalize_${name}.sed" # Do it! if [ -z "$CGREEN_PER_TEST_TIMEOUT" ]; then printf "Comparing output of ${name} to expected: " else printf "Comparing output of ${name} to expected with CGREEN_PER_TEST_TIMEOUT=$CGREEN_PER_TEST_TIMEOUT: " fi # Run runner on library store output and error ../tools/cgreen-runner ./${prefix}${name}.${extension} > "${name}.output" 2> "${name}.error" cat "${name}.error" >> "${name}.output" tempfile=`mktemp` # sed commands to normalize... # - line numbers in error messages echo "s/:[0-9]+:/:000:/g" > $tempfile # - timing info echo "s/in [0-9]+ms\./in 0ms\./g" >> $tempfile # - library prefix echo s/\"${prefix}${name}\"/\"${name}\"/g >> $tempfile # - source path, ensure parenthesis are not interpreted by sed -E echo s%.*${sourcedir//[\(\)]/.}/%%g >> $tempfile # Do normalization using the commands in the tempfile and the specified commandfile sed -E -f "${tempfile}" -f "${commandfile}" "${name}.output" > "${name}.output.normalized" # Check for color capability if test -t 1; then ncolors=$(tput colors) if test -n "$ncolors" && test $ncolors -ge 8; then green="$(tput setaf 2)" normal="$(tput sgr0)" fi fi # Compare normalized output to expected cmp -s "${name}.output.normalized" "${sourcedir}/${expected}" # If not the same, show diff rc=$? if [ $rc -ne 0 ] then echo diff -c "${name}.output.normalized" "${sourcedir}/${expected}" else echo ${green}Ok${normal} fi exit $rc cgreen-1.6.3/tools/cgreen_xml_output_diff000077500000000000000000000061761450461175400206260ustar00rootroot00000000000000#!/bin/bash # # Will run the cgreen-runner in directory ../tools # on library with name $1 (e.g. 'lib${name}.so') # generating XML output that will be compared to # sources are in $2 for... # ...expected output file name in $3 # ...and commands to normalize output (in the file normalize_{name}.sed) # # TODO: refactor the duplication in this and cgreen_xml_output_diff to something # not having the duplication, common sub-script, maybe? # # TODO: make 'prefix' and 'extension' into arguments instead of evaluating them here # Determine OS unameo=`uname -o 1>/dev/null 2>/dev/null; echo $?` if [ $unameo -eq 0 ]; then OS=`uname -o` else OS=`uname -s` fi # Set up library prefix and extension case "$OS" in Darwin) prefix=lib extension=dylib ;; GNU/Linux|FreeBSD) prefix=lib extension=so ;; Cygwin) prefix=cyg extension=dll ;; Msys) prefix=msys- extension=dll ;; *) echo "ERROR: $0 can't handle OS=$OS" exit 2 ;; esac # Handle arguments if [ $# -ne 3 ]; then echo "ERROR: $0 requires exactly 3 arguments" exit 2 fi # TODO: don't shift name=$1; shift 1 sourcedir=$1 ; shift 1 sourcedir=$(perl -e 'use Cwd "abs_path"; print abs_path(@ARGV[0])' -- "$sourcedir") if [ $(uname -n) = thoni64 ]; then # On my Cygwin machine I have linked /home to c:/Users so absolute paths don't match # what runner prints, so try to replace that # TODO: generalize this... sourcedir=`echo $sourcedir | sed -e s#/cygdrive/c/Users#/home#` fi # TODO: don't shift expected=$1 ; shift 1 commandfile="${sourcedir}/normalize_${name}.sed" # Do it! if [ -z "$CGREEN_PER_TEST_TIMEOUT" ]; then printf "Comparing output of ${name} to expected: " else printf "Comparing output of ${name} to expected with CGREEN_PER_TEST_TIMEOUT=$CGREEN_PER_TEST_TIMEOUT: " fi # Run runner on library store output and error ../tools/cgreen-runner -x X "${prefix}${name}.${extension}" > "${name}.output" 2> "${name}.error" cat "${name}.error" >> "${name}.output" cat X-*${name}.xml X-*${name}-default.xml >> "${name}.output" tempfile=`mktemp` # sed commands to normalize... # - line numbers in error messages echo "s/:[0-9]+:/:/g" > $tempfile # - timing info echo "s/in [0-9]+ms\./in 0ms\./g" >> $tempfile # - library prefix echo s/\"${prefix}${name}\"/\"${name}\"/g >> $tempfile # - source path, ensure parenthesis are not interpreted by sed -E # but allow any characters before sourcedir in the string echo s%\".*${sourcedir//[\(\)]/.}/%\"%g >> $tempfile # Do normalization using the commands in the tempfile and the specified commandfile sed -E -f "${tempfile}" -f "${commandfile}" "${name}.output" > "${name}.output.normalized" # Check for color capability if test -t 1; then ncolors=$(tput colors) if test -n "$ncolors" && test $ncolors -ge 8; then green="$(tput setaf 2)" normal="$(tput sgr0)" fi fi # Compare normalized output to expected cmp -s "${name}.output.normalized" "${sourcedir}/${expected}" # If not the same, show diff rc=$? if [ $rc -ne 0 ] then echo diff -c "${name}.output.normalized" "${sourcedir}/${expected}" else echo ${green}Ok${normal} fi exit $rc cgreen-1.6.3/tools/discoverer.c000066400000000000000000000041361450461175400164500ustar00rootroot00000000000000#include "discoverer.h" #include "io.h" #include #include #include #include #include "../src/utils.h" #include "test_item.h" static const char *cgreen_spec_start_of(const char *line) { return strstr(line, CGREEN_SPEC_PREFIX CGREEN_SEPARATOR); } static bool contains_cgreen_spec(const char *line) { return cgreen_spec_start_of(line) != NULL; } static bool is_definition(const char *line) { return strstr(line, " D ") != NULL; } static bool complete_line_read(char line[]) { return line[strlen(line)-1] == '\n'; } static void strip_newline_from(char *name) { if (name[strlen(name)-1] == '\n') name[strlen(name)-1] = '\0'; } static void add_all_tests_from(FILE *nm_output_pipe, CgreenVector *tests, bool verbose) { char line[1000]; int length = read_line(nm_output_pipe, line, sizeof(line)-1); while (length > -1) { /* TODO: >0 ? */ if (!complete_line_read(line)) PANIC("Too long line in nm output"); if (contains_cgreen_spec(line) && is_definition(line)) { strip_newline_from(line); TestItem *test_item = create_test_item_from(cgreen_spec_start_of(line)); if (verbose) printf("Discovered %s:%s (%s)\n", test_item->context_name, test_item->test_name, test_item->specification_name); cgreen_vector_add(tests, test_item); } length = read_line(nm_output_pipe, line, sizeof(line)-1); } } CgreenVector *discover_tests_in(const char *filename, bool verbose) { FILE *library = open_file(filename, "r"); if (library == NULL) return NULL; close_file(library); char nm_command[1000]; sprintf(nm_command, "%s '%s' 2>&1", NM_EXECUTABLE, filename); FILE *nm_output_pipe = open_process(nm_command, "r"); if (nm_output_pipe == NULL) return NULL; CgreenVector *tests = create_cgreen_vector((GenericDestructor)&destroy_test_item); add_all_tests_from(nm_output_pipe, tests, verbose); close_process(nm_output_pipe); return tests; } cgreen-1.6.3/tools/discoverer.h000066400000000000000000000007271450461175400164570ustar00rootroot00000000000000#ifndef DISCOVERER_H #define DISCOVERER_H #include #include // We want to run our tests with cgreen, of course, so in order to not // cause conflicts with the function in the library itself we rename // it here when we are running unittests. Also see Makefile. #ifdef UNITTESTING #define discover_tests_in(x,y) unittesting_discover_tests_in(x,y) #endif extern CgreenVector *discover_tests_in(const char *filename, bool verbose); #endif cgreen-1.6.3/tools/discoverer.mock000066400000000000000000000007261450461175400171600ustar00rootroot00000000000000#include "cgreen/mocks.h" #include "discoverer.h" // We want to run our tests with cgreen, of course, so in order to not // cause conflicts with the function in the library itself we rename // it here when we are running unittests. Also see Makefile. #ifdef UNITTESTING #define discover_tests_in(x,y) unittesting_discover_tests_in(x,y) #endif CgreenVector *discover_tests_in(const char *filename, bool verbose) { return (CgreenVector *)mock(filename, verbose); } cgreen-1.6.3/tools/discoverer_acceptance_tests.c000066400000000000000000000017711450461175400220420ustar00rootroot00000000000000#include #include "discoverer.h" #include Describe(Discoverer); BeforeEach(Discoverer) {} AfterEach(Discoverer) {} static bool verbose = false; static int count_tests_in(const char *filename) { char command[1000]; sprintf(command, "/usr/bin/nm '%s'", filename); FILE *nm_output = popen(command, "r"); char line[10000]; int count = 0; while (fgets(line, sizeof(line), nm_output) != 0) { if (strstr(line, CGREEN_SPEC_PREFIX CGREEN_SEPARATOR) != NULL) count++; } return count; } Ensure(Discoverer, reads_a_library_and_finds_the_tests) { char filename[] = "libdiscoverer_unit_tests.so"; CgreenVector *tests = discover_tests_in(filename, verbose); assert_that(cgreen_vector_size(tests), is_equal_to(count_tests_in(filename))); } TestSuite *discoverer_acceptance_tests(void) { TestSuite *suite = create_test_suite(); add_test_with_context(suite, Discoverer, reads_a_library_and_finds_the_tests); return suite; } cgreen-1.6.3/tools/discoverer_unit_tests.c000066400000000000000000000143271450461175400207340ustar00rootroot00000000000000#include #include #include "discoverer.h" #include "test_item.h" #include #include #include #include "io.h" #include "io.mocks" Describe(Discoverer); BeforeEach(Discoverer) {} AfterEach(Discoverer) {} static bool verbose = false; /* Helper functions */ static void expect_open_file(const char *filename, void *result) { expect(open_file, when(filename, is_equal_to_string(filename)), will_return(result)); } static void expect_open_process(const char *partial_command, void *result) { expect(open_process, when(command, contains_string(partial_command)), will_return(result)); } static void given_a_file_with_no_lines(const char *filename) { expect_open_file(filename, (void *)1); expect(close_file, when(file, is_equal_to(1))); expect_open_process("nm ", (void *)2); expect(read_line, when(file, is_equal_to(2)), will_return(EOF)); /* End of input */ expect(close_process, when(file, is_equal_to(2))); } static void expect_read_line_from(int file_id, const char *line) { if (line == NULL) expect(read_line, when(file, is_equal_to(file_id)), will_return(EOF)); else expect(read_line, when(file, is_equal_to(file_id)), will_set_contents_of_parameter(buffer, line, strlen(line)+1), will_return(strlen(line)+1)); } static void given_a_file_with_two_lines(const char *filename, const char *line1, const char *line2) { static char command[100]; expect_open_file(filename, (void *)1); expect(close_file, when(file, is_equal_to(1))); sprintf(command, "nm '%s'", filename); expect_open_process(command, (void *)2); expect_read_line_from(2, line1); expect_read_line_from(2, line2); expect_read_line_from(2, NULL); expect(close_process, when(file, is_equal_to(2))); } static void given_a_file_with_one_line(const char *filename, const char *line) { expect_open_file(filename, (void *)1); expect(close_file, when(file, is_equal_to(1))); expect_open_process("nm ", (void *)2); expect_read_line_from(2, line); expect_read_line_from(2, NULL); expect(close_process, when(file, is_equal_to(2))); } /*======================================================================*/ Ensure(Discoverer, should_find_no_tests_in_non_existing_file) { expect_open_file("non-existing-file", NULL); CgreenVector *tests = discover_tests_in("non-existing-file", verbose); assert_that(tests, is_null); } /*======================================================================*/ Ensure(Discoverer, should_find_no_tests_in_existing_empty_file) { given_a_file_with_no_lines("empty-file"); CgreenVector *tests = discover_tests_in("empty-file", verbose); assert_that(cgreen_vector_size(tests), is_equal_to(0)); } /*======================================================================*/ Ensure(Discoverer, should_find_one_test_in_file_with_one_line_containing_testname_pattern) { given_a_file_with_one_line("some-file", "0000000000202160 D CgreenSpec__A_context__a_test__\n"); CgreenVector *tests = discover_tests_in("some-file", verbose); assert_that(cgreen_vector_size(tests), is_equal_to(1)); } /*======================================================================*/ Ensure(Discoverer, should_find_two_test_in_two_line_file_with_two_lines_containing_testname_pattern) { given_a_file_with_two_lines("some-file", "0000000000202160 D CgreenSpec__Context1__test1__\n", "0000000000202160 D CgreenSpec__Context2__test2__\n"); CgreenVector *tests = discover_tests_in("some-file", verbose); assert_that(cgreen_vector_size(tests), is_equal_to(2)); } /*======================================================================*/ Ensure(Discoverer, should_find_one_test_in_two_line_file_with_one_line_containing_testname_pattern) { given_a_file_with_two_lines("some-file", "0000000000202160 D CgreenSpec__Discoverer__test1__\n", "0000000000202160 D ID\n"); CgreenVector *tests = discover_tests_in("some-file", verbose); assert_that(cgreen_vector_size(tests), is_equal_to(1)); } /*======================================================================*/ Ensure(Discoverer, should_find_no_test_in_file_with_no_definiton) { given_a_file_with_one_line("some-file", "0000000000202160 U CgreenSpec__Discoverer__test1__\n"); CgreenVector *tests = discover_tests_in("some-file", verbose); assert_that(cgreen_vector_size(tests), is_equal_to(0)); } /*======================================================================*/ Ensure(Discoverer, should_strip_newline_at_end_of_specification_name) { given_a_file_with_one_line("some-file", "0000000000202160 U CgreenSpec__Discoverer__test1__\n"); CgreenVector *tests = discover_tests_in("some-file", verbose); assert_that(cgreen_vector_size(tests), is_equal_to(0)); } /*======================================================================*/ Ensure(Discoverer, should_return_valid_test_item_for_a_line_containing_testname_pattern) { given_a_file_with_one_line("some-file", "0000000000202160 D CgreenSpec__Context1__test_1__\n"); CgreenVector *tests = discover_tests_in("some-file", verbose); assert_that(cgreen_vector_size(tests), is_equal_to(1)); TestItem *test_item = (TestItem*)cgreen_vector_get(tests, 0); assert_that(test_item->specification_name, is_equal_to_string("CgreenSpec__Context1__test_1__")); assert_that(test_item->context_name, is_equal_to_string("Context1")); assert_that(test_item->test_name, is_equal_to_string("test_1")); } /*======================================================================*/ Ensure(Discoverer, can_handle_truncated_testnames) { given_a_file_with_one_line("some-file", "0000000000202160 D CgreenSpec__Context1__a\n"); CgreenVector *tests = discover_tests_in("some-file", verbose); TestItem *test_item = (TestItem*)cgreen_vector_get(tests, 0); assert_that(test_item->test_name, is_equal_to_string("a")); } cgreen-1.6.3/tools/gopt-errors.c000066400000000000000000000054051450461175400165660ustar00rootroot00000000000000/* gopt-errors.c PUBILC DOMAIN 2015 t.gopt@purposeful.co.uk */ /* */ /* I, Tom Vajzovic, am the author of this software and its documentation. I permanently abandon all intellectual property rights in them, including copyright, trademarks, design rights, database right, patents, and the right to be identified as the author. I am fairly certain that the software does what the documentation says it does, but I do not guarantee that it does, or that it does what you think it should. I do not guarantee that it will not have undesirable side effects. You are free to use, modify and distribute this software as you please, but you do so at your own risk. If you do not pass on this warning then you may be responsible for any problems encountered by those who obtain the software through you. */ #include #include #ifdef _BSD_SOURCE #include #else #define EX_USAGE EXIT_FAILURE #endif #include "gopt.h" void gopt_errors (const char *argv0, const struct option *options) { unsigned int bad_option_index = 0; unsigned int i; while (!(options[bad_option_index].flags & GOPT_LAST)) { bad_option_index++; } if (options[bad_option_index].short_name) { fprintf (stderr, "%s: unrecognised option -%c\n", argv0, options[bad_option_index].short_name); exit (EX_USAGE); } if (options[bad_option_index].long_name) { fprintf (stderr, "%s: unrecognised option --%s\n", argv0, options[bad_option_index].long_name); exit (EX_USAGE); } for (i = 0; i < bad_option_index; i++) { if ((options[i].flags & GOPT_SEEN_SHORT_WITHOUT) && (options[i].flags & GOPT_ARGUMENT_REQUIRED)) { fprintf (stderr, "%s: option -%c requires an option-argument\n", argv0, options[i].short_name); exit (EX_USAGE); } if ((options[i].flags & GOPT_SEEN_SHORT_WITH) && (options[i].flags & GOPT_ARGUMENT_FORBIDDEN)) { fprintf (stderr, "%s: option -%c must not have an option-argument\n", argv0, options[i].short_name); exit (EX_USAGE); } if ((options[i].flags & GOPT_SEEN_LONG_WITHOUT) && (options[i].flags & GOPT_ARGUMENT_REQUIRED)) { fprintf (stderr, "%s: option --%s requires an option-argument\n", argv0, options[i].long_name); exit (EX_USAGE); } if ((options[i].flags & GOPT_SEEN_LONG_WITH) && (options[i].flags & GOPT_ARGUMENT_FORBIDDEN)) { fprintf (stderr, "%s: option --%s must not have an option-argument\n", argv0, options[i].long_name); exit (EX_USAGE); } if ((options[i].count > 1) && !(options[i].flags & GOPT_REPEATABLE)) { fprintf (stderr, "%s: option -%c/--%s may not be repeated\n", argv0, options[i].short_name, options[i].long_name); exit (EX_USAGE); } } } cgreen-1.6.3/tools/gopt.c000066400000000000000000000131531450461175400152530ustar00rootroot00000000000000/* gopt.c PUBILC DOMAIN 2015 t.gopt@purposeful.co.uk */ /* */ /* I, Tom Vajzovic, am the author of this software and its documentation. I permanently abandon all intellectual property rights in them, including copyright, trademarks, design rights, database right, patents, and the right to be identified as the author. I am fairly certain that the software does what the documentation says it does, but I do not guarantee that it does, or that it does what you think it should. I do not guarantee that it will not have undesirable side effects. You are free to use, modify and distribute this software as you please, but you do so at your own risk. If you do not pass on this warning then you may be responsible for any problems encountered by those who obtain the software through you. */ #include #ifdef _WIN32 #define strncasecmp _strnicmp #else #include #endif #include "gopt.h" /* returns index of first exact match or only prefix match, or last index */ static unsigned int long_option_get_index (const char *arg, const struct option *options) { unsigned int count = 0; unsigned int found; unsigned int i; size_t arg_len = strcspn (arg, "="); for (i = 0; !(options[i].flags & GOPT_LAST); i++) { if (options[i].long_name) { size_t full_len = strlen (options[i].long_name); if ((arg_len <= full_len) && !strncasecmp (options[i].long_name, arg, arg_len)) { if (arg_len == full_len) { return i; } found = i; count++; } } } return ((count == 1) ? found : i); } /* returns index of first match, or last index */ static unsigned int short_option_get_index (char c, const struct option *options) { unsigned int i; for (i = 0; !(options[i].flags & GOPT_LAST); i++) { if (options[i].short_name == c) { return i; } } return i; } int gopt (char **argv, struct option *options) { unsigned int operand_count = 1; unsigned int doubledash = 0; unsigned int expecting = 0; unsigned int option_index = 0; unsigned int i, j; for (i = 0; !(options[i].flags & GOPT_LAST); i++) { options[i].argument = NULL; options[i].count = 0; } options[i].short_name = 0; options[i].long_name = NULL; options[i].argument = NULL; options[i].count = 0; for (i = 1; argv[i]; i++) { if (doubledash) { argv[operand_count] = argv[i]; operand_count++; continue; } if (expecting) { if ((argv[i][0] != '-') || !argv[i][1] || !(options[option_index].flags & GOPT_ARGUMENT_NO_HYPHEN)) { options[option_index].flags |= expecting; options[option_index].argument = argv[i]; expecting = 0; continue; } else { options[option_index].flags |= (expecting >> 1); /* change _WITH to _WITHOUT */ options[option_index].argument = NULL; expecting = 0; } } if ((argv[i][0] == '-') && (argv[i][1] == '-') && (argv[i][2] == 0)) { doubledash = 1; continue; } if ((argv[i][0] == '-') && (argv[i][1] == '-')) { char *eq = strchr (&argv[i][2], '='); option_index = long_option_get_index (&argv[i][2], options); options[option_index].count++; if ((options[option_index].flags & GOPT_LAST) && !options[option_index].long_name) { options[option_index].long_name = &argv[i][2]; } if (eq) { options[option_index].argument = (eq + 1); options[option_index].flags |= GOPT_SEEN_LONG_WITH; } else if (options[option_index].flags & GOPT_ARGUMENT_REQUIRED) { expecting = GOPT_SEEN_LONG_WITH; } else { options[option_index].argument = NULL; options[option_index].flags |= GOPT_SEEN_LONG_WITHOUT; } } else if ((argv[i][0] == '-') && argv[i][1]) { for (j = 1; argv[i][j]; j++) { option_index = short_option_get_index (argv[i][j], options); options[option_index].count++; if (options[option_index].flags & GOPT_LAST) { if (!options[option_index].short_name) { options[option_index].short_name = argv[i][j]; } if (argv[i][j+1]) { options[option_index].argument = &argv[i][j+1]; options[option_index].flags |= GOPT_SEEN_SHORT_WITH; } else { options[option_index].argument = NULL; options[option_index].flags |= GOPT_SEEN_SHORT_WITHOUT; } break; } if (options[option_index].flags & GOPT_ARGUMENT_FORBIDDEN) { options[option_index].argument = NULL; options[option_index].flags |= GOPT_SEEN_SHORT_WITHOUT; } else if (argv[i][j+1]) { options[option_index].argument = &argv[i][j+1]; options[option_index].flags |= GOPT_SEEN_SHORT_WITH; break; } else if (options[option_index].flags & GOPT_ARGUMENT_REQUIRED) { expecting = GOPT_SEEN_SHORT_WITH; } else { options[option_index].argument = NULL; options[option_index].flags |= GOPT_SEEN_SHORT_WITHOUT; } } } else { argv[operand_count] = argv[i]; operand_count++; } } if (expecting) { options[option_index].flags |= (expecting >> 1); /* change _WITH to _WITHOUT */ options[option_index].argument = NULL; } argv[operand_count] = NULL; return operand_count; } cgreen-1.6.3/tools/gopt.h000066400000000000000000000143611450461175400152620ustar00rootroot00000000000000/* gopt.h PUBILC DOMAIN 2015 t.gopt@purposeful.co.uk */ /* */ /* I, Tom Vajzovic, am the author of this software and its documentation. I permanently abandon all intellectual property rights in them, including copyright, trademarks, design rights, database right, patents, and the right to be identified as the author. I am fairly certain that the software does what the documentation says it does, but I do not guarantee that it does, or that it does what you think it should. I do not guarantee that it will not have undesirable side effects. You are free to use, modify and distribute this software as you please, but you do so at your own risk. If you do not pass on this warning then you may be responsible for any problems encountered by those who obtain the software through you. */ #ifndef GOPT_H_INCLUDED #define GOPT_H_INCLUDED #ifdef __cplusplus extern "C" { #endif struct option { /* input: */ char short_name; const char *long_name; /* input/output: */ unsigned int flags; /* output: */ unsigned int count; char *argument; }; /* values for flags: */ #define GOPT_ARGUMENT_OPTIONAL 0x000u /* option may or may not have an option-argument */ #define GOPT_ARGUMENT_FORBIDDEN 0x001u /* option must not have an option-argument */ #define GOPT_ARGUMENT_REQUIRED 0x002u /* option must have an option-argument */ #define GOPT_ARGUMENT_NO_HYPHEN 0x004u /* option-argument may not start with hyphen/minus */ #define GOPT_REPEATABLE 0x008u /* option may be specified more than once */ #define GOPT_SEEN_SHORT_WITHOUT 0x010u /* short form of option was present without an option-argument in argv */ #define GOPT_SEEN_SHORT_WITH 0x020u /* short form of option was present with an option-argument in argv */ #define GOPT_SEEN_LONG_WITHOUT 0x040u /* long form of option was present without an option-argument in argv */ #define GOPT_SEEN_LONG_WITH 0x080u /* long form of option was present with an option-argument in argv */ #define GOPT_LAST 0x100u /* this is the last element of the array */ int gopt (char **argv, struct option *options); /* The function gopt() takes an argument vector argv, which has the same form as the second argument to main(). It removes from the vector all options and option-arguments, leaving only the program name, the operands and a null pointer at the end. It returns the updated argument count argc. It does not need to know the initial value of argc because the input vector must be null-terminated. It also takes an array of struct option, the elements of which are used for specifying the options which are to be recognized and for returning details of which options were present in the argument vector. The members of struct option are used as follows: On input, short_name is the single character that follows "-" to make a short option, or zero if there is no short form of this option. On input, long_name is the name of the long option excluding the "--", or NULL if there is no long form of this option. On return short_name and long_name are unaltered. count may be uninitialized on input. On return it is set to the number of times the option was specified. If the option is not present, this is zero. If an option has both a short and long name, this is the sum of counts for both forms. argument may be uninitialized on input. On return it is set to the last option-argument specified to this option, or NULL if no option-argument was specified with the last occurrence of this option, or the option was never specified. flags is the bitwise-or of certain constants. On input flags must contain exactly one of: GOPT_ARGUMENT_FORBIDDEN if the option does not take an option-argument GOPT_ARGUMENT_REQUIRED if it always requires an option-argument GOPT_ARGUMENT_OPTIONAL if it may or may not take an option-argument If flags contains GOPT_ARGUMENT_REQUIRED, it may also contain GOPT_ARGUMENT_NO_HYPHEN. If the option argument is not allowed to start with a '-', but the next member of the argument vector does start with one where an option argument was expected, then this flag causes it to be interpreted as another option, leaving the argument to the preceding option NULL. The application can then detect the NULL and give an error message like "missing option argument" which may be preferable to treating the next program argument as an option argument and then giving a less helpful message when the option argument is found to be invalid. flags may also optionally contain GOPT_REPEATABLE. This is ignored by the option parsing code, but may be used when checking the value returned in count, where if this flag is specified then the application will presumably report an error if count is greater than one. On return, the initial value of flags is still present, and additionally GOPT_SEEN_SHORT_WITH and/or GOPT_SEEN_SHORT_WITHOUT are set if the short name was used at least once with or without an option-argument, respectively, and GOPT_SEEN_LONG_WITH and/or GOPT_SEEN_LONG_WITHOUT are set if the long name was used. On input there must be zero or more elements in the options array initialized as above. These must be followed by one element where flags is exactly GOPT_LAST. All other members of this element may be uninitialized on input. On return the count member of this element will be set to the total number of unrecognized options present. The short_name member will be set to the first unrecognized short option, or zero if there were none. The long_name will be set to point to the start of the name of the first unrecognized long option, or NULL if there were none. For completeness the argument member will be set to the option argument of the last unrecognized option (the same as with other options) but this is probably useless to the application. */ void gopt_errors (const char *argv0, const struct option *options); /* The function gopt_errors() examines the array of struct option after it has been filled out by gopt(). If the options specified were invalid it prints an error message starting with argv0 and terminates the program. */ #ifdef __cplusplus } #endif #endif /* GOPT_H_INCLUDED */ cgreen-1.6.3/tools/io.c000066400000000000000000000013611450461175400147070ustar00rootroot00000000000000#include "io.h" /* Adapter to C I/O functions */ #include FILE *open_file(const char *filename, const char *mode) { return fopen(filename, mode); } int close_file(FILE *file) { return fclose(file); } FILE *open_process(const char *command, const char *mode) { return popen(command, mode); } int close_process(FILE *process) { return pclose(process); } /* read_line() - read characters from a FILE - behaves like fgets() except will return - number of characters read and - EOF if at end of file */ int read_line(FILE *file, char *buffer, int max_length) { char *result = fgets(buffer, max_length, file); return result==NULL? EOF : (signed)strlen(result); } cgreen-1.6.3/tools/io.h000066400000000000000000000010741450461175400147150ustar00rootroot00000000000000#ifndef IO_H #define IO_H #include #ifdef UNITTESTING #define open_file open_file_unittesting #define close_file close_file_unittesting #define open_process open_process_file_unittesting #define close_process close_process_unittesting #define read_line read_line_unittesting #endif extern FILE *open_file(const char *filename, const char *mode); extern int close_file(FILE *file); extern FILE *open_process(const char *command, const char *mode); extern int close_process(FILE *file); extern int read_line(FILE *file, char *buffer, int max_length); #endif cgreen-1.6.3/tools/io.mock000066400000000000000000000007061450461175400154200ustar00rootroot00000000000000#include "io.h" FILE *open_file(const char *filename, const char *mode) { return (FILE *) mock(filename, mode); } int close_file(FILE *file) { return (int) mock(file); } FILE *open_process(const char *command, const char *mode) { return (FILE *) mock(command, mode); } int close_process(FILE *file) { return (int) mock(file); } int read_line(FILE *file, char *buffer, int max_length) { return (int) mock(file, buffer, max_length); } cgreen-1.6.3/tools/runner.c000066400000000000000000000256741450461175400156260ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include "../src/utils.h" #include "runner.h" #include "test_item.h" #include "discoverer.h" /* The ContextSuite is a datastructure created to partion the tests in suites according to the contexts, one suite per context. It consists of a list of nodes, each mapping a context name to a TestSuite. If there where a public way to navigate the structure of suites, we could name the TestSuites after the context and then find the appropriate suite by navigating in the TestSuite structure, but this seems impossible for now. */ typedef struct ContextSuite { char *context_name; TestSuite *suite; struct ContextSuite *next; } ContextSuite; /*----------------------------------------------------------------------*/ static void destroy_context_suites(ContextSuite *context_suite) { if (context_suite != NULL) { if (context_suite->next != NULL) destroy_context_suites(context_suite->next); free(context_suite->context_name); free(context_suite); } } #define CGREEN_DEFAULT_SUITE "default" /*----------------------------------------------------------------------*/ static char *context_name_of(const char* symbolic_name) { char *context_name; if (strchr(symbolic_name, ':')) { context_name = string_dup(symbolic_name); *strchr(context_name, ':') = '\0'; } else { context_name = string_dup(CGREEN_DEFAULT_SUITE); } return context_name; } /*----------------------------------------------------------------------*/ static char *test_name_of(const char *symbolic_name) { const char *colon = strchr(symbolic_name, ':'); if (colon) { return string_dup(colon+1); } return string_dup(symbolic_name); } /*----------------------------------------------------------------------*/ static bool test_matches_pattern(const char *symbolic_name_pattern, TestItem *test_item) { char* context_name = context_name_of(symbolic_name_pattern); int context_name_matches_test = fnmatch(context_name, test_item->context_name, 0) == 0; char* test_name = test_name_of(symbolic_name_pattern); int test_name_matches_test = fnmatch(test_name, test_item->test_name, 0) == 0; free(context_name); free(test_name); return context_name_matches_test && test_name_matches_test; } /*----------------------------------------------------------------------*/ static TestSuite *find_suite_for_context(ContextSuite *suites, const char *context_name) { ContextSuite *suite; for (suite = suites; suite != NULL; suite = suite->next) { if (strcmp(suite->context_name, context_name) == 0) break; } if (suite != NULL) { return suite->suite; } return NULL; } /*----------------------------------------------------------------------*/ static ContextSuite *add_new_context_suite(TestSuite *parent, const char* context_name, ContextSuite *next) { ContextSuite *new_context_suite = (ContextSuite *)calloc(1, sizeof(ContextSuite)); new_context_suite->context_name = string_dup(context_name); new_context_suite->suite = create_named_test_suite(context_name); new_context_suite->next = next; add_suite_(parent, context_name, new_context_suite->suite); return new_context_suite; } /*----------------------------------------------------------------------*/ static void add_test_to_context(TestSuite *parent, ContextSuite **context_suites, TestItem *test_item, CgreenTest *test) { TestSuite *suite_for_context = find_suite_for_context(*context_suites, test_item->context_name); if (suite_for_context == NULL) { *context_suites = add_new_context_suite(parent, test_item->context_name, *context_suites); suite_for_context = (*context_suites)->suite; } add_test_(suite_for_context, test_item->test_name, test); } /*----------------------------------------------------------------------*/ static TestItem *get_item_from(CgreenVector *tests, int i) { return (TestItem*)cgreen_vector_get(tests, i); } /*----------------------------------------------------------------------*/ static int add_matching_tests_to_suite(void *handle, const char *symbolic_name_pattern, CgreenVector *tests, TestSuite *suite, ContextSuite **context_suites) { int count = 0; for (int i = 0; ispecification_name; CgreenTest *test_function = (CgreenTest *)(dlsym(handle, specification_name)); if ((error = dlerror()) != NULL) { PANIC("Could not find specification_name symbol '%s'", specification_name); return -1; } add_test_to_context(suite, context_suites, get_item_from(tests, i), test_function); count++; } } return count; } /*----------------------------------------------------------------------*/ static bool matching_test_exists(const char *test_name, CgreenVector *tests) { for (int i = 0; i 0) status = run_test_suite(suite, reporter); else { fprintf(stderr, "ERROR: No such test: '%s' in '%s'\n", symbolic_name, suite_name); status = EXIT_FAILURE; } } destroy_test_suite(suite); destroy_context_suites(context_suites); return(status); } /*----------------------------------------------------------------------*/ const char *test_name_of_element(CgreenVector *tests, int index) { return get_item_from(tests, index)->test_name; } /*----------------------------------------------------------------------*/ static CgreenVector *sorted_test_items_from(CgreenVector *test_items) { CgreenVector *sorted = create_cgreen_vector((GenericDestructor)destroy_test_item); while (cgreen_vector_size(test_items) > 1) { int smallest = 0; const char *smallest_test_name = test_name_of_element(test_items, smallest); for (int i=1; i 0) { smallest = i; smallest_test_name = test_name_of_element(test_items, smallest); } } cgreen_vector_add(sorted, cgreen_vector_remove(test_items, smallest)); } if (cgreen_vector_size(test_items) == 1) { cgreen_vector_add(sorted, cgreen_vector_remove(test_items, 0)); destroy_cgreen_vector(test_items); } return sorted; } /*----------------------------------------------------------------------*/ static char *absolute(const char *file_path) { if (strchr("./", file_path[0]) != NULL) return strdup(file_path); else { char *tmp = malloc(strlen(file_path)+3); strcpy(tmp, "./"); strcat(tmp, file_path); return tmp; } } /*======================================================================*/ int runner(TestReporter *reporter, const char *test_library_name, const char *suite_name, const char *test_name, bool verbose, bool dont_run) { int status = 0; void *test_library_handle = NULL; CgreenVector *tests = discover_tests_in(test_library_name, verbose); if (count(tests) == 0) { printf("No tests found in '%s'.\n", test_library_name); return 1; } if (verbose) printf("Discovered %d test(s)\n", count(tests)); char *absolute_library_name = absolute(test_library_name); tests = sorted_test_items_from(tests); if (verbose) printf("Opening [%s]", test_library_name); test_library_handle = dlopen(absolute_library_name, RTLD_NOW); if (test_library_handle == NULL) { PANIC("dlopen failure when trying to run '%s' (error: %s)\n", absolute_library_name, dlerror()); status = 2; } else { if (!dont_run) { status = run_tests(reporter, suite_name, test_name, test_library_handle, tests, verbose); } dlclose(test_library_handle); } free(absolute_library_name); destroy_cgreen_vector(tests); return status; } cgreen-1.6.3/tools/runner.h000066400000000000000000000003441450461175400156160ustar00rootroot00000000000000#ifndef CGREEN_RUNNER_H #define CGREEN_RUNNER_H /* Cgreen runner module */ extern int runner(TestReporter *reporter, const char *test_library, const char *suite_name, const char *test_name, bool verbose, bool no_run); #endif cgreen-1.6.3/tools/runner_unit_test_runner.c000066400000000000000000000017701450461175400213040ustar00rootroot00000000000000#include "runner_unit_tests.c" TestSuite *runner_unit_tests() { TestSuite *suite = create_test_suite(); add_test_with_context(suite, Runner, can_get_context_name_of_name); add_test_with_context(suite, Runner, can_get_test_name_of_symbolic_name); add_test_with_context(suite, Runner, can_ensure_test_exists_from_context_and_name); add_test_with_context(suite, Runner, can_match_test_name); add_test_with_context(suite, Runner, can_add_test_to_the_suite_for_its_context); add_test_with_context(suite, Runner, can_sort_an_empty_list_of_tests); add_test_with_context(suite, Runner, can_sort_a_list_of_a_single_tests); add_test_with_context(suite, Runner, can_sort_a_list_of_two_unordered_tests); add_test_with_context(suite, Runner, can_sort_an_ordered_list_of_two_tests); add_test_with_context(suite, Runner, can_sort_an_unordered_list_of_tests); return suite; } int main(int argc, char **argv) { return run_test_suite(runner_unit_tests(), create_text_reporter()); } cgreen-1.6.3/tools/runner_unit_tests.c000066400000000000000000000152301450461175400200720ustar00rootroot00000000000000#include #include "../src/utils.h" #ifdef __cplusplus using namespace cgreen; #endif #include "runner.c" #include "test_item.h" #include "discoverer.mock" #include "io.mock" Describe(Runner); BeforeEach(Runner){} AfterEach(Runner){} #define CONTEXT_NAME "context" #define TEST_NAME "test" #define STRINGIFY_X(x) #x #define STRINGIFY(x) STRINGIFY_X(x) Ensure(Runner, can_get_context_name_of_name) { char *context_name = context_name_of("Context:Test"); assert_that(context_name, is_equal_to_string("Context")); free(context_name); context_name = context_name_of("Test"); assert_that(context_name, is_equal_to_string(CGREEN_DEFAULT_SUITE)); free(context_name); } Ensure(Runner, can_get_test_name_of_symbolic_name) { char *test_name = test_name_of("Context:Test"); assert_that(test_name, is_equal_to_string("Test")); free(test_name); test_name = test_name_of("Test"); assert_that(test_name, is_equal_to_string("Test")); free(test_name); } static void add_test_items_to_vector(TestItem items[], CgreenVector *test_items, int count) { for (int i=0; i < count; i++) cgreen_vector_add(test_items, &items[i]); } Ensure(Runner, can_ensure_test_exists_from_context_and_name) { TestItem test_items[5] = { {(char *)"", (char *)"Context1", (char *)"Test1"}, {(char *)"", (char *)"Context1", (char *)"Test2"}, {(char *)"", (char *)"Context2", (char *)"Test1"}, {(char *)"", (char *)"Context2", (char *)"Test2"}}; CgreenVector *tests = create_cgreen_vector(NULL); add_test_items_to_vector(test_items, tests, 5); assert_that(matching_test_exists("Context1:Test1", tests)); } Ensure(Runner, can_match_test_name) { TestItem test_item = {(char *)"", (char *)"Context1", (char *)"Test1"}; assert_that(test_matches_pattern("Context1:Test1", &test_item)); assert_that(test_matches_pattern("Context*:Test1", &test_item)); assert_that(test_matches_pattern("*:Test1", &test_item)); assert_that(test_matches_pattern("Context*:Test1", &test_item)); assert_that(test_matches_pattern("*:Test1", &test_item)); assert_that(test_matches_pattern("Context1:Test*", &test_item)); assert_that(test_matches_pattern("Context*:Test*", &test_item)); assert_that(test_matches_pattern("Context*:*", &test_item)); assert_that(test_matches_pattern("*:Test*", &test_item)); assert_that(test_matches_pattern("*:*", &test_item)); } Ensure(Runner, can_add_test_to_the_suite_for_its_context) { ContextSuite *suite_list = NULL; CgreenTest *test = (CgreenTest *)&test; TestSuite *parent_suite = create_test_suite(); TestSuite *first_suite, *second_suite; TestItem test_item1 = {"", "TheFirstContext", "TheName"}; TestItem test_item2 = {"", "TheSecondContext", "TheName"}; assert_that(suite_list, is_null); add_test_to_context(parent_suite, &suite_list, &test_item1, test); first_suite = find_suite_for_context(suite_list, "TheFirstContext"); assert_that(first_suite, is_non_null); assert_that(first_suite->size, is_equal_to(1)); second_suite = find_suite_for_context(suite_list, "TheSecondContext"); assert_that(second_suite, is_null); add_test_to_context(parent_suite, &suite_list, &test_item2, test); assert_that(find_suite_for_context(suite_list, "TheFirstContext")->size, is_equal_to(1)); assert_that(find_suite_for_context(suite_list, "TheSecondContext")->size, is_equal_to(1)); destroy_test_suite(parent_suite); destroy_context_suites(suite_list); } Ensure(Runner, can_sort_an_empty_list_of_tests) { CgreenVector *test_items = create_cgreen_vector(NULL); test_items = sorted_test_items_from(test_items); assert_that(cgreen_vector_size(test_items) == 0); } Ensure(Runner, can_sort_a_list_of_a_single_tests) { TestItem test_item = { (char *)"", (char *)"Context1", (char *)"Test1", }; CgreenVector *test_items = create_cgreen_vector(NULL); cgreen_vector_add(test_items, &test_item); test_items = sorted_test_items_from(test_items); assert_that(((TestItem *)cgreen_vector_get(test_items, 0))->test_name, is_equal_to_string("Test1")); } Ensure(Runner, can_sort_a_list_of_two_unordered_tests) { TestItem test_items[] = { {(char *)"", (char *)"Context1", (char *)"Test2"}, {(char *)"", (char *)"Context1", (char *)"Test1"}, }; CgreenVector *tests = create_cgreen_vector(NULL); add_test_items_to_vector(test_items, tests, 2); tests = sorted_test_items_from(tests); assert_that(((TestItem *)cgreen_vector_get(tests, 0))->test_name, is_equal_to_string("Test1")); assert_that(((TestItem *)cgreen_vector_get(tests, 1))->test_name, is_equal_to_string("Test2")); } Ensure(Runner, can_sort_an_ordered_list_of_two_tests) { TestItem test_item[] = { {(char *)"", (char *)"Context1", (char *)"Test1"}, {(char *)"", (char *)"Context1", (char *)"Test2"} }; CgreenVector *test_items = create_cgreen_vector(NULL); cgreen_vector_add(test_items, &test_item[0]); cgreen_vector_add(test_items, &test_item[1]); test_items = sorted_test_items_from(test_items); assert_that(((TestItem *)cgreen_vector_get(test_items, 0))->test_name, is_equal_to_string("Test1")); assert_that(((TestItem *)cgreen_vector_get(test_items, 1))->test_name, is_equal_to_string("Test2")); } Ensure(Runner, can_sort_an_unordered_list_of_tests) { TestItem unordered_test_items[] = { {(char *)"", (char *)"Context1", (char *)"Test9"}, {(char *)"", (char *)"Context1", (char *)"Test6"}, {(char *)"", (char *)"Context1", (char *)"Test3"}, {(char *)"", (char *)"Context1", (char *)"Test1"}, {(char *)"", (char *)"Context1", (char *)"Test5"}, {(char *)"", (char *)"Context1", (char *)"Test8"}, {(char *)"", (char *)"Context1", (char *)"Test7"}, {(char *)"", (char *)"Context1", (char *)"Test4"}, {(char *)"", (char *)"Context1", (char *)"Test2"}, }; const char *expected_test_name[] = { "Test1", "Test2", "Test3", "Test4", "Test5", "Test6", "Test7", "Test8", "Test9" }; CgreenVector *tests = create_cgreen_vector(NULL); add_test_items_to_vector(unordered_test_items, tests, sizeof(unordered_test_items)/sizeof(unordered_test_items[0])); tests = sorted_test_items_from(tests); for (int i=0; itest_name, is_equal_to_string(expected_test_name[i])); } /* vim: set ts=4 sw=4 et cindent: */ /* Local variables: */ /* tab-width: 4 */ /* End: */ cgreen-1.6.3/tools/test_item.c000066400000000000000000000032771450461175400163050ustar00rootroot00000000000000#include "test_item.h" #include #include #include #include static const char *skip_to_separator(const char *start) { return strstr(start, CGREEN_SEPARATOR); } static const char *skip_over_separator(const char *start) { return strstr(start, CGREEN_SEPARATOR)+strlen(CGREEN_SEPARATOR); } static const char *skip_cgreen_spec_marker(const char *string) { return &string[strlen(CGREEN_SPEC_PREFIX CGREEN_SEPARATOR)]; } static const char *string_copy_of(const char *start, const char *end) { char *string = strdup(start); string[end-start] = '\0'; return string; } static const char *context_name_from(const char *specification_name) { const char *start = skip_cgreen_spec_marker(specification_name); const char *end = skip_to_separator(start); return string_copy_of(start, end); } static const char *test_name_from(const char *specification_name) { const char *start = skip_cgreen_spec_marker(specification_name); start = skip_over_separator(start); const char *end = skip_to_separator(start); return string_copy_of(start, end? end : &start[strlen(start)]); } TestItem *create_test_item_from(const char *specification_name) { TestItem *test_item = (TestItem *)malloc(sizeof(TestItem)); test_item->specification_name = strdup(specification_name); test_item->context_name = context_name_from(specification_name); test_item->test_name = test_name_from(specification_name); return test_item; } void destroy_test_item(TestItem *item) { free((void *)item->specification_name); free((void *)item->context_name); free((void *)item->test_name); free((void *)item); } cgreen-1.6.3/tools/test_item.h000066400000000000000000000011771450461175400163070ustar00rootroot00000000000000#ifndef TEST_ITEM_H #define TEST_ITEM_H /* The name of a test is either a named mangled from the name of the context, if any, and the actual test name. Names (or patterns) on the command line is formatted as a symbolic name composed of the context name, a colon and the test name. The variable naming below is trying to be clear about which type of name it is. */ typedef struct test_item { const char *specification_name; const char *context_name; const char *test_name; } TestItem; extern TestItem *create_test_item_from(const char *specification_name); extern void destroy_test_item(TestItem *item); #endif