[mapbox-variant] 01/03: Imported Upstream version 1.1.0
Sebastiaan Couwenberg
sebastic at moszumanska.debian.org
Fri Feb 26 21:41:24 UTC 2016
This is an automated email from the git hooks/post-receive script.
sebastic pushed a commit to branch master
in repository mapbox-variant.
commit ee6f75b52a9a5542f1d481ad0b2ccee5cad2fe5e
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date: Fri Feb 26 21:51:13 2016 +0100
Imported Upstream version 1.1.0
---
.clang-format | 89 +
.gitignore | 8 +
.travis.yml | 127 +
.ycm_extra_conf.py | 40 +
Jamroot | 73 +
LICENSE | 25 +
LICENSE_1_0.txt | 23 +
Makefile | 110 +
README.md | 111 +
appveyor.yml | 17 +
common.gypi | 143 +
doc/other_implementations.md | 15 +
doc/standards_effort.md | 28 +
optional.hpp | 74 +
recursive_wrapper.hpp | 122 +
scripts/build-appveyor.bat | 32 +
scripts/build-local.bat | 7 +
scripts/run_compilation_failure_tests.sh | 50 +
test/bench_variant.cpp | 185 +
test/binary_visitor_test.cpp | 138 +
test/boost_variant_hello_world.cpp | 20 +
test/compilation_failure/default_constructor.cpp | 22 +
test/compilation_failure/empty_typelist.cpp | 11 +
test/compilation_failure/equality.cpp | 11 +
test/compilation_failure/get_type.cpp | 10 +
test/compilation_failure/is_type.cpp | 10 +
.../mutating_visitor_on_const.cpp | 24 +
test/compilation_failure/no-reference.cpp | 9 +
test/include/catch.hpp | 11613 +++++++++++++++++++
test/our_variant_hello_world.cpp | 20 +
test/recursive_wrapper_test.cpp | 125 +
test/reference_wrapper_test.cpp | 76 +
test/t/binary_visitor_1.cpp | 7 +
test/t/binary_visitor_2.cpp | 7 +
test/t/binary_visitor_3.cpp | 7 +
test/t/binary_visitor_4.cpp | 7 +
test/t/binary_visitor_5.cpp | 7 +
test/t/binary_visitor_6.cpp | 7 +
test/t/binary_visitor_impl.hpp | 204 +
test/t/issue21.cpp | 48 +
test/t/mutating_visitor.cpp | 36 +
test/t/optional.cpp | 102 +
test/t/recursive_wrapper.cpp | 158 +
test/t/sizeof.cpp | 52 +
test/t/unary_visitor.cpp | 127 +
test/t/variant.cpp | 570 +
test/unique_ptr_test.cpp | 126 +
test/unit.cpp | 2 +
variant.gyp | 35 +
variant.hpp | 901 ++
variant_io.hpp | 45 +
51 files changed, 15816 insertions(+)
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..c1aca2a
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,89 @@
+---
+# Mapbox.Variant C/C+ style
+Language: Cpp
+AccessModifierOffset: -2
+AlignAfterOpenBracket: Align
+AlignConsecutiveAssignments: false
+AlignConsecutiveDeclarations: false
+AlignEscapedNewlinesLeft: false
+AlignOperands: true
+AlignTrailingComments: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: All
+AllowShortIfStatementsOnASingleLine: true
+AllowShortLoopsOnASingleLine: true
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: true
+BinPackArguments: true
+BinPackParameters: true
+BraceWrapping:
+ AfterClass: true
+ AfterControlStatement: true
+ AfterEnum: true
+ AfterFunction: true
+ AfterNamespace: false
+ AfterObjCDeclaration: true
+ AfterStruct: true
+ AfterUnion: true
+ BeforeCatch: true
+ BeforeElse: true
+ IndentBraces: false
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: Custom
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializersBeforeComma: false
+ColumnLimit: 0
+CommentPragmas: '^ IWYU pragma:'
+ConstructorInitializerAllOnOneLineOrOnePerLine: true
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+DerivePointerAlignment: false
+DisableFormat: false
+ExperimentalAutoDetectBinPacking: false
+ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
+IncludeCategories:
+ - Regex: '^"(llvm|llvm-c|clang|clang-c)/'
+ Priority: 2
+ - Regex: '^(<|"(gtest|isl|json)/)'
+ Priority: 3
+ - Regex: '.*'
+ Priority: 1
+IndentCaseLabels: false
+IndentWidth: 4
+IndentWrappedFunctionNames: false
+KeepEmptyLinesAtTheStartOfBlocks: true
+MacroBlockBegin: ''
+MacroBlockEnd: ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBlockIndentWidth: 2
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: true
+PenaltyBreakBeforeFirstCallParameter: 19
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakString: 1000
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 60
+PointerAlignment: Left
+ReflowComments: true
+SortIncludes: true
+SpaceAfterCStyleCast: false
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeParens: ControlStatements
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles: false
+SpacesInContainerLiterals: true
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard: Cpp11
+TabWidth: 4
+UseTab: Never
+...
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a9bc860
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+.DS_Store
+out
+profiling
+build
+deps
+*.gcda
+*.gcno
+.ycm_extra_conf.pyc
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..99d0b48
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,127 @@
+language: c
+
+sudo: false
+
+# Save common build configurations as shortcuts, so we can reference them later.
+addons_shortcuts:
+ addons_clang35: &clang35
+ apt:
+ sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.5', 'boost-latest' ]
+ packages: [ 'clang-3.5', 'libboost1.55-all-dev' ]
+ addons_clang36: &clang36
+ apt:
+ sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.6', 'boost-latest' ]
+ packages: [ 'clang-3.6', 'libboost1.55-all-dev' ]
+ addons_clang37: &clang37
+ apt:
+ sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.7', 'boost-latest' ]
+ packages: [ 'clang-3.7', 'libboost1.55-all-dev' ]
+ addons_clang38: &clang38
+ apt:
+ sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise', 'boost-latest' ]
+ packages: [ 'clang-3.8', 'libboost1.55-all-dev']
+ addons_gcc47: &gcc47
+ apt:
+ sources: [ 'ubuntu-toolchain-r-test', 'boost-latest' ]
+ packages: [ 'g++-4.7', 'libboost1.55-all-dev' ]
+ addons_gcc48: &gcc48
+ apt:
+ sources: [ 'ubuntu-toolchain-r-test', 'boost-latest' ]
+ packages: [ 'g++-4.8', 'libboost1.55-all-dev' ]
+ addons_gcc49: &gcc49
+ apt:
+ sources: [ 'ubuntu-toolchain-r-test', 'boost-latest' ]
+ packages: [ 'g++-4.9', 'libboost1.55-all-dev' ]
+ addons_gcc5: &gcc5
+ apt:
+ sources: [ 'ubuntu-toolchain-r-test', 'boost-latest' ]
+ packages: [ 'g++-5', 'libboost1.55-all-dev' ]
+
+matrix:
+ include:
+ - os: osx
+ osx_image: xcode6
+ compiler: clang
+ - os: osx
+ osx_image: xcode7
+ env: TEST_GYP_BUILD=True
+ compiler: clang
+ - os: linux
+ compiler: "clang35"
+ env: CXX=clang++-3.5
+ addons: *clang35
+ - os: linux
+ compiler: "clang36"
+ env: CXX=clang++-3.6
+ addons: *clang36
+ - os: linux
+ compiler: "clang37"
+ env: CXX=clang++-3.7 COVERAGE=True
+ addons: *clang37
+ - os: linux
+ compiler: "clang38"
+ env: CXX=clang++-3.8
+ addons: *clang38
+ - os: linux
+ compiler: "clang38"
+ env: CXX=clang++-3.8 CXX_STD=c++14
+ addons: *clang38
+ - os: linux
+ compiler: "gcc47"
+ env: CXX=g++-4.7
+ addons: *gcc47
+ - os: linux
+ compiler: "gcc48"
+ env: CXX=g++-4.8
+ addons: *gcc48
+ - os: linux
+ compiler: "gcc49"
+ env: CXX=g++-4.9
+ addons: *gcc49
+ - os: linux
+ compiler: "gcc49"
+ env: CXX=g++-4.9 CXX_STD=c++14
+ addons: *gcc49
+ - os: linux
+ compiler: "gcc5"
+ env: CXX=g++-5 CXXFLAGS="-D_GLIBCXX_USE_CXX11_ABI=0"
+ addons: *gcc5
+ - os: linux
+ compiler: "gcc5"
+ env: CXX=g++-5 CXXFLAGS="-D_GLIBCXX_USE_CXX11_ABI=1"
+ addons: *gcc5
+
+before_install:
+ - echo ${CXX}
+ - if [[ $(uname -s) == 'Linux' ]]; then
+ export PYTHONPATH=$(pwd)/.local/lib/python2.7/site-packages;
+ else
+ brew install boost;
+ export PYTHONPATH=$(pwd)/.local/lib/python/site-packages;
+ fi
+ - if [[ ${COVERAGE:-0} == 'True' ]]; then
+ PYTHONUSERBASE=$(pwd)/.local pip install --user cpp-coveralls;
+ fi
+
+install:
+ - make test
+ - make bench
+ - if [[ $(uname -s) == 'Linux' ]]; then
+ make sizes /usr/include/boost/variant.hpp;
+ else
+ make sizes `brew --prefix`/include/boost/variant.hpp;
+ fi
+ - scripts/run_compilation_failure_tests.sh
+ - if [[ ${TEST_GYP_BUILD:-0} == 'True' ]]; then
+ make clean;
+ make gyp;
+ fi
+
+script:
+ - if [[ ${COVERAGE:-0} == 'True' ]]; then
+ make clean;
+ make coverage;
+ ./out/cov-test;
+ cp unit*gc* test/;
+ ./.local/bin/cpp-coveralls -i optional.hpp -i recursive_wrapper.hpp -i variant.hpp -i variant_io.hpp --gcov-options '\-lp';
+ fi
diff --git a/.ycm_extra_conf.py b/.ycm_extra_conf.py
new file mode 100644
index 0000000..ba74668
--- /dev/null
+++ b/.ycm_extra_conf.py
@@ -0,0 +1,40 @@
+#-----------------------------------------------------------------------------
+#
+# Configuration for YouCompleteMe Vim plugin
+#
+# http://valloric.github.io/YouCompleteMe/
+#
+#-----------------------------------------------------------------------------
+
+from os.path import realpath, dirname
+
+basedir = dirname(realpath(__file__))
+
+# some default flags
+# for more information install clang-3.2-doc package and
+# check UsersManual.html
+flags = [
+'-Werror',
+'-Wall',
+'-Wextra',
+'-pedantic',
+
+'-std=c++11',
+
+# '-x' and 'c++' also required
+# use 'c' for C projects
+'-x',
+'c++',
+
+# include third party libraries
+'-I.',
+]
+
+# youcompleteme is calling this function to get flags
+# You can also set database for flags. Check: JSONCompilationDatabase.html in
+# clang-3.2-doc package
+def FlagsForFile( filename ):
+ return {
+ 'flags': flags,
+ 'do_cache': True
+ }
diff --git a/Jamroot b/Jamroot
new file mode 100644
index 0000000..1e98cf5
--- /dev/null
+++ b/Jamroot
@@ -0,0 +1,73 @@
+# Inofficial and incomplete build file using Boost build system.
+# You should use make unless you know what you are doing.
+
+local BOOST_DIR = "/usr/local" ;
+
+#using clang : : ;
+
+lib system : : <name>boost_system <search>$(BOOST_DIR)/lib ;
+lib timer : chrono : <name>boost_timer <search>$(BOOST_DIR)/lib ;
+lib chrono : system : <name>boost_chrono <search>$(BOOST_DIR)/lib ;
+
+exe variant-test
+ :
+ test/bench_variant.cpp
+ .//system
+ .//timer
+ .//chrono
+ :
+ <include>$(BOOST_DIR)/include
+ <include>./
+ #<define>SINGLE_THREADED
+ <variant>release:<cxxflags>-march=native
+ ;
+
+
+exe binary-visitor-test
+ :
+ test/binary_visitor_test.cpp
+ .//system
+ .//timer
+ .//chrono
+ :
+ <include>$(BOOST_DIR)/include
+ <include>./
+ <variant>release:<cxxflags>-march=native
+ ;
+
+exe recursive-wrapper-test
+ :
+ test/recursive_wrapper_test.cpp
+ .//system
+ .//timer
+ .//chrono
+ :
+ <include>$(BOOST_DIR)/include
+ <include>./
+ <variant>release:<cxxflags>-march=native
+ ;
+
+exe unique-ptr-test
+ :
+ test/unique_ptr_test.cpp
+ .//system
+ .//timer
+ .//chrono
+ :
+ <include>$(BOOST_DIR)/include
+ <include>./
+ <variant>release:<cxxflags>-march=native
+ ;
+
+
+exe reference_wrapper_test
+ :
+ test/reference_wrapper_test.cpp
+ .//system
+ .//timer
+ .//chrono
+ :
+ <include>$(BOOST_DIR)/include
+ <include>./
+ <variant>release:<cxxflags>-march=native
+ ;
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..6c4ce40
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,25 @@
+Copyright (c) MapBox
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+- Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+- Neither the name "MapBox" nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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.
\ No newline at end of file
diff --git a/LICENSE_1_0.txt b/LICENSE_1_0.txt
new file mode 100644
index 0000000..36b7cd9
--- /dev/null
+++ b/LICENSE_1_0.txt
@@ -0,0 +1,23 @@
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..3665251
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,110 @@
+
+CXX := $(CXX)
+CXX_STD ?= c++11
+
+BOOST_LIBS = -lboost_timer -lboost_system -lboost_chrono
+RELEASE_FLAGS = -O3 -DNDEBUG -march=native -DSINGLE_THREADED -fvisibility-inlines-hidden
+DEBUG_FLAGS = -O0 -g -DDEBUG -fno-inline-functions
+COMMON_FLAGS = -Wall -pedantic -Wextra -Wsign-compare -Wsign-conversion -Wshadow -Wunused-parameter -std=$(CXX_STD)
+CXXFLAGS := $(CXXFLAGS)
+LDFLAGS := $(LDFLAGS)
+
+OS:=$(shell uname -s)
+ifeq ($(OS),Darwin)
+ CXXFLAGS += -stdlib=libc++
+ LDFLAGS += -stdlib=libc++ -F/ -framework CoreFoundation
+else
+ BOOST_LIBS += -lrt
+endif
+
+ifeq (sizes,$(firstword $(MAKECMDGOALS)))
+ RUN_ARGS := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
+ $(eval $(RUN_ARGS):;@:)
+ ifndef RUN_ARGS
+ $(error sizes target requires you pass full path to boost variant.hpp)
+ endif
+ .PHONY: $(RUN_ARGS)
+endif
+
+all: out/bench-variant out/unique_ptr_test out/unique_ptr_test out/recursive_wrapper_test out/binary_visitor_test
+
+./deps/gyp:
+ git clone --depth 1 https://chromium.googlesource.com/external/gyp.git ./deps/gyp
+
+gyp: ./deps/gyp
+ deps/gyp/gyp --depth=. -Goutput_dir=./ --generator-output=./out -f make
+ make V=1 -C ./out tests
+ ./out/Release/tests
+
+out/bench-variant-debug: Makefile test/bench_variant.cpp variant.hpp recursive_wrapper.hpp
+ mkdir -p ./out
+ $(CXX) -o out/bench-variant-debug test/bench_variant.cpp -I./ -pthreads $(DEBUG_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
+
+out/bench-variant: Makefile test/bench_variant.cpp variant.hpp recursive_wrapper.hpp
+ mkdir -p ./out
+ $(CXX) -o out/bench-variant test/bench_variant.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
+
+out/unique_ptr_test: Makefile test/unique_ptr_test.cpp variant.hpp recursive_wrapper.hpp
+ mkdir -p ./out
+ $(CXX) -o out/unique_ptr_test test/unique_ptr_test.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
+
+out/recursive_wrapper_test: Makefile test/recursive_wrapper_test.cpp variant.hpp recursive_wrapper.hpp
+ mkdir -p ./out
+ $(CXX) -o out/recursive_wrapper_test test/recursive_wrapper_test.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
+
+out/binary_visitor_test: Makefile test/binary_visitor_test.cpp variant.hpp variant_io.hpp recursive_wrapper.hpp
+ mkdir -p ./out
+ $(CXX) -o out/binary_visitor_test test/binary_visitor_test.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
+
+bench: out/bench-variant out/unique_ptr_test out/unique_ptr_test out/recursive_wrapper_test out/binary_visitor_test
+ ./out/bench-variant 100000
+ ./out/unique_ptr_test 100000
+ ./out/recursive_wrapper_test 100000
+ ./out/binary_visitor_test 100000
+
+out/unit.o: Makefile test/unit.cpp
+ mkdir -p ./out
+ $(CXX) -c -o $@ test/unit.cpp -Itest/include $(DEBUG_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS)
+
+out/%.o: test/t/%.cpp Makefile optional.hpp recursive_wrapper.hpp variant.hpp variant_io.hpp
+ mkdir -p ./out
+ $(CXX) -c -o $@ $< -I. -Itest/include $(DEBUG_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS)
+
+out/unit: out/unit.o out/binary_visitor_1.o out/binary_visitor_2.o out/binary_visitor_3.o out/binary_visitor_4.o out/binary_visitor_5.o out/binary_visitor_6.o out/issue21.o out/mutating_visitor.o out/optional.o out/recursive_wrapper.o out/sizeof.o out/unary_visitor.o out/variant.o
+ mkdir -p ./out
+ $(CXX) -o $@ $^ $(LDFLAGS)
+
+test: out/unit
+ ./out/unit
+
+coverage:
+ mkdir -p ./out
+ $(CXX) -o out/cov-test --coverage test/unit.cpp test/t/*.cpp -I./ -Itest/include $(DEBUG_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS)
+
+sizes: Makefile variant.hpp recursive_wrapper.hpp
+ mkdir -p ./out
+ @$(CXX) -o ./out/our_variant_hello_world.out variant.hpp $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) && du -h ./out/our_variant_hello_world.out
+ @$(CXX) -o ./out/boost_variant_hello_world.out $(RUN_ARGS) $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) && du -h ./out/boost_variant_hello_world.out
+ @$(CXX) -o ./out/our_variant_hello_world ./test/our_variant_hello_world.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) && du -h ./out/our_variant_hello_world
+ @$(CXX) -o ./out/boost_variant_hello_world ./test/boost_variant_hello_world.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) && du -h ./out/boost_variant_hello_world
+
+profile: out/bench-variant-debug
+ mkdir -p profiling/
+ rm -rf profiling/*
+ iprofiler -timeprofiler -d profiling/ ./out/bench-variant-debug 500000
+
+clean:
+ rm -rf ./out
+ rm -rf *.dSYM
+ rm -f unit.gc*
+ rm -f *gcov
+ rm -f test/unit.gc*
+ rm -f test/*gcov
+ rm -f *.gcda *.gcno
+
+pgo: out Makefile variant.hpp recursive_wrapper.hpp
+ $(CXX) -o out/bench-variant test/bench_variant.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS) -pg -fprofile-generate
+ ./test-variant 500000 >/dev/null 2>/dev/null
+ $(CXX) -o out/bench-variant test/bench_variant.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS) -fprofile-use
+
+.PHONY: sizes test
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..24cdb57
--- /dev/null
+++ b/README.md
@@ -0,0 +1,111 @@
+# Mapbox Variant
+
+An alternative to `boost::variant` for C++11.
+
+[![Build Status](https://secure.travis-ci.org/mapbox/variant.svg)](https://travis-ci.org/mapbox/variant)
+[![Build status](https://ci.appveyor.com/api/projects/status/v9tatx21j1k0fcgy)](https://ci.appveyor.com/project/Mapbox/variant)
+[![Coverage Status](https://coveralls.io/repos/mapbox/variant/badge.svg?branch=master&service=github)](https://coveralls.io/r/mapbox/variant?branch=master)
+
+
+## Why use Mapbox Variant?
+
+Mapbox variant has the same speedy performance of `boost::variant` but is
+faster to compile, results in smaller binaries, and has no dependencies.
+
+For example on OS X 10.9 with clang++ and libc++:
+
+Test | Mapbox Variant | Boost Variant
+---- | -------------- | -------------
+Size of pre-compiled header (release / debug) | 2.8/2.8 MB | 12/15 MB
+Size of simple program linking variant (release / debug) | 8/24 K | 12/40 K
+Time to compile header | 185 ms | 675 ms
+
+(Numbers from an older version of Mapbox variant.)
+
+
+## Goals
+
+Mapbox `variant` has been a very valuable, lightweight alternative for apps
+that can use c++11 or c++14 but that do not want a boost dependency.
+Mapbox `variant` has also been useful in apps that do depend on boost, like
+mapnik, to help (slightly) with compile times and to majorly lessen dependence
+on boost in core headers. The original goal and near term goal is to maintain
+external API compatibility with `boost::variant` such that Mapbox `variant`
+can be a "drop in". At the same time the goal is to stay minimal: Only
+implement the features that are actually needed in existing software. So being
+an "incomplete" implementation is just fine.
+
+Currently Mapbox variant doesn't try to be API compatible with the upcoming
+variant standard, because the standard is not finished and it would be too much
+work. But we'll revisit this decision in the future if needed.
+
+If Mapbox variant is not for you, have a look at [these other
+implementations](doc/other_implementations.md).
+
+Want to know more about the upcoming standard? Have a look at our
+[overview](doc/standards_effort.md).
+
+
+## Depends
+
+ - Compiler supporting `-std=c++11` or `-std=c++14`
+
+Tested with:
+
+ - g++-4.7
+ - g++-4.8
+ - g++-4.9
+ - g++-5
+ - clang++-3.5
+ - clang++-3.6
+ - clang++-3.7
+ - clang++-3.8
+ - Visual Studio 2015
+
+## Usage
+
+There is nothing to build, just include `variant.hpp` and
+`recursive_wrapper.hpp` in your project. Include `variant_io.hpp` if you need
+the `operator<<` overload for variant.
+
+
+## Unit Tests
+
+On Unix systems compile and run the unit tests with `make test`.
+
+On Windows run `scripts/build-local.bat`.
+
+
+## Limitations
+
+* The `variant` can not hold references (something like `variant<int&>` is
+ not possible). You might want to try `std::reference_wrapper` instead.
+
+
+## Deprecations
+
+* The included implementation of `optional` is deprecated and will be removed
+ in a future version. See https://github.com/mapbox/variant/issues/64.
+* Old versions of the code needed visitors to derive from `static_visitor`.
+ This is not needed any more and marked as deprecated. The `static_visitor`
+ class will be removed in future versions.
+
+
+## Benchmarks
+
+The benchmarks depend on:
+
+ - Boost headers (for benchmarking against `boost::variant`)
+ - Boost built with `--with-timer` (used for benchmark timing)
+
+On Unix systems set your boost includes and libs locations and run `make test`:
+
+ export LDFLAGS='-L/opt/boost/lib'
+ export CXXFLAGS='-I/opt/boost/include'
+ make bench
+
+
+## Check object sizes
+
+ make sizes /path/to/boost/variant.hpp
+
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 0000000..050ad25
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,17 @@
+
+platform:
+ - x64
+ - x86
+
+configuration:
+ - Debug
+ - Release
+
+os: Visual Studio 2015
+
+install:
+ - CALL scripts\build-appveyor.bat
+
+build: off
+test: off
+deploy: off
diff --git a/common.gypi b/common.gypi
new file mode 100644
index 0000000..d4f09f8
--- /dev/null
+++ b/common.gypi
@@ -0,0 +1,143 @@
+{
+ "conditions": [
+ ["OS=='win'", {
+ "target_defaults": {
+ "default_configuration": "Release_x64",
+ "msbuild_toolset":"v140",
+ "msvs_settings": {
+ "VCCLCompilerTool": {
+ "ExceptionHandling": 1, # /EHsc
+ "RuntimeTypeInfo": "true" # /GR
+ }
+ },
+ "configurations": {
+ "Debug_Win32": {
+ "msvs_configuration_platform": "Win32",
+ "defines": [ "DEBUG","_DEBUG"],
+ "msvs_settings": {
+ "VCCLCompilerTool": {
+ "RuntimeLibrary": "1", # static debug /MTd
+ "Optimization": 0, # /Od, no optimization
+ "MinimalRebuild": "false",
+ "OmitFramePointers": "false",
+ "BasicRuntimeChecks": 3 # /RTC1
+ }
+ }
+ },
+ "Debug_x64": {
+ "msvs_configuration_platform": "x64",
+ "defines": [ "DEBUG","_DEBUG"],
+ "msvs_settings": {
+ "VCCLCompilerTool": {
+ "RuntimeLibrary": "1", # static debug /MTd
+ "Optimization": 0, # /Od, no optimization
+ "MinimalRebuild": "false",
+ "OmitFramePointers": "false",
+ "BasicRuntimeChecks": 3 # /RTC1
+ }
+ }
+ },
+ "Release_Win32": {
+ "msvs_configuration_platform": "Win32",
+ "defines": [ "NDEBUG"],
+ "msvs_settings": {
+ "VCCLCompilerTool": {
+ "RuntimeLibrary": 0, # static release
+ "Optimization": 3, # /Ox, full optimization
+ "FavorSizeOrSpeed": 1, # /Ot, favour speed over size
+ "InlineFunctionExpansion": 2, # /Ob2, inline anything eligible
+ "WholeProgramOptimization": "true", # /GL, whole program optimization, needed for LTCG
+ "OmitFramePointers": "true",
+ "EnableFunctionLevelLinking": "true",
+ "EnableIntrinsicFunctions": "true",
+ "AdditionalOptions": [
+ "/MP", # compile across multiple CPUs
+ ],
+ "DebugInformationFormat": "0"
+ },
+ "VCLibrarianTool": {
+ "AdditionalOptions": [
+ "/LTCG" # link time code generation
+ ],
+ },
+ "VCLinkerTool": {
+ "LinkTimeCodeGeneration": 1, # link-time code generation
+ "OptimizeReferences": 2, # /OPT:REF
+ "EnableCOMDATFolding": 2, # /OPT:ICF
+ "LinkIncremental": 1, # disable incremental linking
+ "GenerateDebugInformation": "false"
+ }
+ }
+ },
+ "Release_x64": {
+ "msvs_configuration_platform": "x64",
+ "defines": [ "NDEBUG"],
+ "msvs_settings": {
+ "VCCLCompilerTool": {
+ "RuntimeLibrary": 0, # static release
+ "Optimization": 3, # /Ox, full optimization
+ "FavorSizeOrSpeed": 1, # /Ot, favour speed over size
+ "InlineFunctionExpansion": 2, # /Ob2, inline anything eligible
+ "WholeProgramOptimization": "true", # /GL, whole program optimization, needed for LTCG
+ "OmitFramePointers": "true",
+ "EnableFunctionLevelLinking": "true",
+ "EnableIntrinsicFunctions": "true",
+ "AdditionalOptions": [
+ "/MP", # compile across multiple CPUs
+ ],
+ "DebugInformationFormat": "0"
+ },
+ "VCLibrarianTool": {
+ "AdditionalOptions": [
+ "/LTCG" # link time code generation
+ ],
+ },
+ "VCLinkerTool": {
+ "LinkTimeCodeGeneration": 1, # link-time code generation
+ "OptimizeReferences": 2, # /OPT:REF
+ "EnableCOMDATFolding": 2, # /OPT:ICF
+ "LinkIncremental": 1, # disable incremental linking
+ "GenerateDebugInformation": "false"
+ }
+ }
+ }
+ }
+ }
+ }, {
+ "target_defaults": {
+ "default_configuration": "Release",
+ "xcode_settings": {
+ "CLANG_CXX_LIBRARY": "libc++",
+ "CLANG_CXX_LANGUAGE_STANDARD":"c++11",
+ "GCC_VERSION": "com.apple.compilers.llvm.clang.1_0",
+ },
+ "cflags_cc": ["-std=c++11"],
+ "configurations": {
+ "Debug": {
+ "defines": [
+ "DEBUG"
+ ],
+ "xcode_settings": {
+ "GCC_OPTIMIZATION_LEVEL": "0",
+ "GCC_GENERATE_DEBUGGING_SYMBOLS": "YES",
+ "OTHER_CPLUSPLUSFLAGS": [ "-Wall", "-Wextra", "-pedantic", "-g", "-O0" ]
+ }
+ },
+ "Release": {
+ "defines": [
+ "NDEBUG"
+ ],
+ "xcode_settings": {
+ "GCC_OPTIMIZATION_LEVEL": "3",
+ "GCC_GENERATE_DEBUGGING_SYMBOLS": "NO",
+ "DEAD_CODE_STRIPPING": "YES",
+ "GCC_INLINES_ARE_PRIVATE_EXTERN": "YES",
+ "OTHER_CPLUSPLUSFLAGS": [ "-Wall", "-Wextra", "-pedantic", "-O3" ]
+ }
+ }
+ }
+ }
+ }]
+ ]
+}
+
diff --git a/doc/other_implementations.md b/doc/other_implementations.md
new file mode 100644
index 0000000..a0d8b9b
--- /dev/null
+++ b/doc/other_implementations.md
@@ -0,0 +1,15 @@
+
+# Other implementations of variant and optional
+
+These are some other implementations of `variant` and/or `optional` types.
+They are not necessarily compatible with this implementation. This is an
+incomplete list.
+
+* [Boost Variant](http://www.boost.org/doc/libs/1_59_0/doc/html/variant.html) and [Boost Optional](http://www.boost.org/doc/libs/1_59_0/libs/optional/doc/html/index.html)
+* [Eggs Variant](http://eggs-cpp.github.io/variant/) by [Agustín Bergé](http://talesofcpp.fusionfenix.com/)
+* [anthonyw/variant](https://bitbucket.org/anthonyw/variant) (implementation of P0110R0)
+* [JasonL9000/cppcon14](https://github.com/JasonL9000/cppcon14)
+* [tomilov/variant](https://github.com/tomilov/variant)
+* [akrzemi1/Optional](https://github.com/akrzemi1/Optional)
+* [mpark/variant](https://github.com/mpark/variant)
+
diff --git a/doc/standards_effort.md b/doc/standards_effort.md
new file mode 100644
index 0000000..d2df488
--- /dev/null
+++ b/doc/standards_effort.md
@@ -0,0 +1,28 @@
+
+# Standards efforts
+
+A `variant` type is on planned for inclusion in the C++ Standard, probably in
+C++17. Current working papers are (list extracted from [2015 working group
+papers](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/)):
+
+* 2015-09-28: Variant design review. [P0086R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0086r0.pdf)
+* 2015-09-28: Variant: a type-safe union without undefined behavior (v2) [P0087R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0087r0.pdf)
+* 2015-09-27: Variant: a type-safe union that is rarely invalid (v5) [P0088R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0088r0.pdf)
+* 2015-09-24: Simply a Strong Variant [P0093R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0093r0.html)
+* 2015-09-24: Simply a Basic Variant [P0094R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0094r0.html)
+* 2015-09-24: The Case for a Language Based Variant [P0096R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0095r0.html)
+* 2015-09-25: Implementing the strong guarantee for variant<> assignment [P0110R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0110r0.html)
+* 2015-09-24: Homogeneous interface for variant, any and optional (Revision 1) [P0032R1](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0032r1.pdf)
+
+Last state can be seen from
+[The Variant Saga: A happy ending?](https://isocpp.org/blog/2015/11/the-variant-saga-a-happy-ending).
+
+The `optional` type is also on the way into the standard. The papers are:
+* 2013-10-03: A proposal to add a utility class to represent optional objects (Revision 5) [N3793](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3793.html)
+* 2014-01-18: Working Draft, Technical Specification on C++ Extensions for Library Fundamentals [N3848](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3848.html)
+
+## Older Papers
+
+* Older working drafts are: N4218 (rev 1), N4516 (rev 2), N4450 (rev 3), and [N4542](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4542.pdf) (rev 4). They have been split into P0086 (general design discussions) and P0087 and P0088 (containing two competing? specs).
+* 2015-07-28: Variant: Discriminated Union with Value Semantics [P0080R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0080r0.pdf) An alternative proposal to N4542.
+
diff --git a/optional.hpp b/optional.hpp
new file mode 100644
index 0000000..1185894
--- /dev/null
+++ b/optional.hpp
@@ -0,0 +1,74 @@
+#ifndef MAPBOX_UTIL_OPTIONAL_HPP
+#define MAPBOX_UTIL_OPTIONAL_HPP
+
+#pragma message("This implementation of optional is deprecated. See https://github.com/mapbox/variant/issues/64.")
+
+#include <type_traits>
+#include <utility>
+
+#include "variant.hpp"
+
+namespace mapbox {
+namespace util {
+
+template <typename T>
+class optional
+{
+ static_assert(!std::is_reference<T>::value, "optional doesn't support references");
+
+ struct none_type
+ {
+ };
+
+ variant<none_type, T> variant_;
+
+ public:
+ optional() = default;
+
+ optional(optional const& rhs)
+ {
+ if (this != &rhs)
+ { // protect against invalid self-assignment
+ variant_ = rhs.variant_;
+ }
+ }
+
+ optional(T const& v) { variant_ = v; }
+
+ explicit operator bool() const noexcept { return variant_.template is<T>(); }
+
+ T const& get() const { return variant_.template get<T>(); }
+ T& get() { return variant_.template get<T>(); }
+
+ T const& operator*() const { return this->get(); }
+ T operator*() { return this->get(); }
+
+ optional& operator=(T const& v)
+ {
+ variant_ = v;
+ return *this;
+ }
+
+ optional& operator=(optional const& rhs)
+ {
+ if (this != &rhs)
+ {
+ variant_ = rhs.variant_;
+ }
+ return *this;
+ }
+
+ template <typename... Args>
+ void emplace(Args&&... args)
+ {
+ variant_ = T{std::forward<Args>(args)...};
+ }
+
+ void reset() { variant_ = none_type{}; }
+
+}; // class optional
+
+} // namespace util
+} // namespace mapbox
+
+#endif // MAPBOX_UTIL_OPTIONAL_HPP
diff --git a/recursive_wrapper.hpp b/recursive_wrapper.hpp
new file mode 100644
index 0000000..4becdd6
--- /dev/null
+++ b/recursive_wrapper.hpp
@@ -0,0 +1,122 @@
+#ifndef MAPBOX_UTIL_RECURSIVE_WRAPPER_HPP
+#define MAPBOX_UTIL_RECURSIVE_WRAPPER_HPP
+
+// Based on variant/recursive_wrapper.hpp from boost.
+//
+// Original license:
+//
+// Copyright (c) 2002-2003
+// Eric Friedman, Itay Maman
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <cassert>
+#include <utility>
+
+namespace mapbox {
+namespace util {
+
+template <typename T>
+class recursive_wrapper
+{
+
+ T* p_;
+
+ void assign(T const& rhs)
+ {
+ this->get() = rhs;
+ }
+
+ public:
+ using type = T;
+
+ /**
+ * Default constructor default initializes the internally stored value.
+ * For POD types this means nothing is done and the storage is
+ * uninitialized.
+ *
+ * @throws std::bad_alloc if there is insufficient memory for an object
+ * of type T.
+ * @throws any exception thrown by the default constructur of T.
+ */
+ recursive_wrapper()
+ : p_(new T){};
+
+ ~recursive_wrapper() noexcept { delete p_; };
+
+ recursive_wrapper(recursive_wrapper const& operand)
+ : p_(new T(operand.get())) {}
+
+ recursive_wrapper(T const& operand)
+ : p_(new T(operand)) {}
+
+ recursive_wrapper(recursive_wrapper&& operand)
+ : p_(new T(std::move(operand.get()))) {}
+
+ recursive_wrapper(T&& operand)
+ : p_(new T(std::move(operand))) {}
+
+ inline recursive_wrapper& operator=(recursive_wrapper const& rhs)
+ {
+ assign(rhs.get());
+ return *this;
+ }
+
+ inline recursive_wrapper& operator=(T const& rhs)
+ {
+ assign(rhs);
+ return *this;
+ }
+
+ inline void swap(recursive_wrapper& operand) noexcept
+ {
+ T* temp = operand.p_;
+ operand.p_ = p_;
+ p_ = temp;
+ }
+
+ recursive_wrapper& operator=(recursive_wrapper&& rhs) noexcept
+ {
+ swap(rhs);
+ return *this;
+ }
+
+ recursive_wrapper& operator=(T&& rhs)
+ {
+ get() = std::move(rhs);
+ return *this;
+ }
+
+ T& get()
+ {
+ assert(p_);
+ return *get_pointer();
+ }
+
+ T const& get() const
+ {
+ assert(p_);
+ return *get_pointer();
+ }
+
+ T* get_pointer() { return p_; }
+
+ const T* get_pointer() const { return p_; }
+
+ operator T const&() const { return this->get(); }
+
+ operator T&() { return this->get(); }
+
+}; // class recursive_wrapper
+
+template <typename T>
+inline void swap(recursive_wrapper<T>& lhs, recursive_wrapper<T>& rhs) noexcept
+{
+ lhs.swap(rhs);
+}
+} // namespace util
+} // namespace mapbox
+
+#endif // MAPBOX_UTIL_RECURSIVE_WRAPPER_HPP
diff --git a/scripts/build-appveyor.bat b/scripts/build-appveyor.bat
new file mode 100644
index 0000000..bdee7ea
--- /dev/null
+++ b/scripts/build-appveyor.bat
@@ -0,0 +1,32 @@
+ at ECHO OFF
+SETLOCAL
+
+SET PATH=c:\python27;%PATH%
+
+ECHO activating VS command prompt
+IF /I "%PLATFORM"=="x64" (
+ CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64
+) ELSE (
+ CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86
+)
+
+IF NOT EXIST deps\gyp git clone --quiet --depth 1 https://chromium.googlesource.com/external/gyp.git deps/gyp
+
+CALL deps\gyp\gyp.bat variant.gyp --depth=. ^
+-f msvs ^
+-G msvs_version=2015 ^
+--generator-output=build
+
+SET MSBUILD_PLATFORM=%platform%
+IF /I "%MSBUILD_PLATFORM%" == "x86" SET MSBUILD_PLATFORM=Win32
+
+
+msbuild ^
+build\variant.sln ^
+/nologo ^
+/toolsversion:14.0 ^
+/p:PlatformToolset=v140 ^
+/p:Configuration=%configuration% ^
+/p:Platform=%MSBUILD_PLATFORM%
+
+build\"%configuration%"\tests.exe
diff --git a/scripts/build-local.bat b/scripts/build-local.bat
new file mode 100644
index 0000000..34a2e61
--- /dev/null
+++ b/scripts/build-local.bat
@@ -0,0 +1,7 @@
+ at ECHO OFF
+SETLOCAL
+
+SET platform=x64
+SET configuration=Release
+
+CALL scripts\build-appveyor.bat
\ No newline at end of file
diff --git a/scripts/run_compilation_failure_tests.sh b/scripts/run_compilation_failure_tests.sh
new file mode 100755
index 0000000..c2608fe
--- /dev/null
+++ b/scripts/run_compilation_failure_tests.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+#
+# Try to compile all programs in the test/compilation_failure directory.
+# Compilation must fail and the error message must match the pattern in the
+# corresponding .pattern file.
+#
+
+DIR="test/compilation_failure"
+CXX=${CXX:-clang++}
+
+if [ `uname -s` = "Darwin" ]; then
+ CXXFLAGS="$CXXFLAGS -stdlib=libc++"
+fi
+
+error_msg() {
+ if [ ! -z "$1" ]; then
+ printf 'output was:\n=======\n%s\n=======\n' "$1"
+ fi
+}
+
+exit_code=0
+for test_code in $DIR/*.cpp; do
+ name=`basename $test_code .cpp`
+
+ result=`${CXX} -std=c++11 -c -o /dev/null -I. ${CXXFLAGS} ${test_code} 2>&1`
+ status=$?
+
+ if [ $status = 1 ]; then
+ expected=`sed -n -e '/@EXPECTED/s/.*: \+//p' ${test_code}`
+ if echo $result | grep -q "$expected"; then
+ echo "$name [OK]"
+ else
+ echo "$name [FAILED - wrong error message]"
+ echo "Expected error message: $expected"
+ error_msg "$result"
+ exit_code=1
+ fi
+ elif [ $status = 0 ]; then
+ echo "$name [FAILED - compile was successful]"
+ error_msg "$result"
+ exit_code=1
+ else
+ echo "$name [FAILED - unknown error in compile]"
+ error_msg "$result"
+ exit_code=1
+ fi
+done
+
+exit ${exit_code}
+
diff --git a/test/bench_variant.cpp b/test/bench_variant.cpp
new file mode 100644
index 0000000..700dac7
--- /dev/null
+++ b/test/bench_variant.cpp
@@ -0,0 +1,185 @@
+
+#include <algorithm>
+#include <cstdlib>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <thread>
+#include <utility>
+#include <vector>
+
+#include <boost/timer/timer.hpp>
+#include <boost/variant.hpp>
+
+#include "variant.hpp"
+
+#define TEXT_SHORT "Test"
+#define TEXT_LONG "Testing various variant implementations with a longish string ........................................."
+#define NUM_SAMPLES 3
+//#define BOOST_VARIANT_MINIMIZE_SIZE
+
+using namespace mapbox;
+
+namespace test {
+
+template <typename V>
+struct Holder
+{
+ typedef V value_type;
+ std::vector<value_type> data;
+
+ template <typename T>
+ void append_move(T&& obj)
+ {
+ data.emplace_back(std::forward<T>(obj));
+ }
+
+ template <typename T>
+ void append(T const& obj)
+ {
+ data.push_back(obj);
+ }
+};
+
+} // namespace test
+
+struct print
+{
+ template <typename T>
+ void operator()(T const& val) const
+ {
+ std::cerr << val << ":" << typeid(T).name() << std::endl;
+ }
+};
+
+template <typename V>
+struct dummy : boost::static_visitor<>
+{
+ dummy(V& v)
+ : v_(v) {}
+
+ template <typename T>
+ void operator()(T&& val) const
+ {
+ v_ = std::move(val);
+ }
+ V& v_;
+};
+
+template <typename V>
+struct dummy2
+{
+ dummy2(V& v)
+ : v_(v) {}
+
+ template <typename T>
+ void operator()(T&& val) const
+ {
+ v_ = std::move(val);
+ }
+ V& v_;
+};
+
+void run_boost_test(std::size_t runs)
+{
+ test::Holder<boost::variant<int, double, std::string>> h;
+ h.data.reserve(runs);
+ for (std::size_t i = 0; i < runs; ++i)
+ {
+ h.append_move(std::string(TEXT_SHORT));
+ h.append_move(std::string(TEXT_LONG));
+ h.append_move(123);
+ h.append_move(3.14159);
+ }
+
+ boost::variant<int, double, std::string> v;
+ for (auto const& v2 : h.data)
+ {
+ dummy<boost::variant<int, double, std::string>> d(v);
+ boost::apply_visitor(d, v2);
+ }
+}
+
+void run_variant_test(std::size_t runs)
+{
+ test::Holder<util::variant<int, double, std::string>> h;
+ h.data.reserve(runs);
+ for (std::size_t i = 0; i < runs; ++i)
+ {
+ h.append_move(std::string(TEXT_SHORT));
+ h.append_move(std::string(TEXT_LONG));
+ h.append_move(123);
+ h.append_move(3.14159);
+ }
+
+ util::variant<int, double, std::string> v;
+ for (auto const& v2 : h.data)
+ {
+ dummy2<util::variant<int, double, std::string>> d(v);
+ util::apply_visitor(d, v2);
+ }
+}
+
+int main(int argc, char** argv)
+{
+ if (argc != 2)
+ {
+ std::cerr << "Usage:" << argv[0] << " <num-runs>" << std::endl;
+ return 1;
+ }
+
+#ifndef SINGLE_THREADED
+ const std::size_t THREADS = 4;
+#endif
+ const std::size_t NUM_RUNS = static_cast<std::size_t>(std::stol(argv[1]));
+
+#ifdef SINGLE_THREADED
+
+ for (std::size_t j = 0; j < NUM_SAMPLES; ++j)
+ {
+
+ {
+ std::cerr << "custom variant: ";
+ boost::timer::auto_cpu_timer t;
+ run_variant_test(NUM_RUNS);
+ }
+ {
+ std::cerr << "boost variant: ";
+ boost::timer::auto_cpu_timer t;
+ run_boost_test(NUM_RUNS);
+ }
+ }
+
+#else
+ for (std::size_t j = 0; j < NUM_SAMPLES; ++j)
+ {
+ {
+ typedef std::vector<std::unique_ptr<std::thread>> thread_group;
+ typedef thread_group::value_type value_type;
+ thread_group tg;
+ std::cerr << "custom variant: ";
+ boost::timer::auto_cpu_timer timer;
+ for (std::size_t i = 0; i < THREADS; ++i)
+ {
+ tg.emplace_back(new std::thread(run_variant_test, NUM_RUNS));
+ }
+ std::for_each(tg.begin(), tg.end(), [](value_type& t) {if (t->joinable()) t->join(); });
+ }
+
+ {
+ typedef std::vector<std::unique_ptr<std::thread>> thread_group;
+ typedef thread_group::value_type value_type;
+ thread_group tg;
+ std::cerr << "boost variant: ";
+ boost::timer::auto_cpu_timer timer;
+ for (std::size_t i = 0; i < THREADS; ++i)
+ {
+ tg.emplace_back(new std::thread(run_boost_test, NUM_RUNS));
+ }
+ std::for_each(tg.begin(), tg.end(), [](value_type& t) {if (t->joinable()) t->join(); });
+ }
+ }
+#endif
+
+ return EXIT_SUCCESS;
+}
diff --git a/test/binary_visitor_test.cpp b/test/binary_visitor_test.cpp
new file mode 100644
index 0000000..fa0f2ea
--- /dev/null
+++ b/test/binary_visitor_test.cpp
@@ -0,0 +1,138 @@
+
+#include <algorithm>
+#include <cstdint>
+#include <cstdlib>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "variant.hpp"
+#include "variant_io.hpp"
+
+using namespace mapbox;
+
+namespace test {
+
+template <typename T>
+struct string_to_number
+{
+};
+
+template <>
+struct string_to_number<double>
+{
+ double operator()(std::string const& str) const
+ {
+ return std::stod(str);
+ }
+};
+
+template <>
+struct string_to_number<std::int64_t>
+{
+ std::int64_t operator()(std::string const& str) const
+ {
+ return std::stoll(str);
+ }
+};
+
+template <>
+struct string_to_number<std::uint64_t>
+{
+ std::uint64_t operator()(std::string const& str) const
+ {
+ return std::stoull(str);
+ }
+};
+
+template <>
+struct string_to_number<bool>
+{
+ bool operator()(std::string const& str) const
+ {
+ bool result;
+ std::istringstream(str) >> std::boolalpha >> result;
+ return result;
+ }
+};
+
+struct javascript_equal_visitor
+{
+ template <typename T>
+ bool operator()(T lhs, T rhs) const
+ {
+ return lhs == rhs;
+ }
+
+ template <typename T, class = typename std::enable_if<std::is_arithmetic<T>::value>::type>
+ bool operator()(T lhs, std::string const& rhs) const
+ {
+ return lhs == string_to_number<T>()(rhs);
+ }
+
+ template <typename T, class = typename std::enable_if<std::is_arithmetic<T>::value>::type>
+ bool operator()(std::string const& lhs, T rhs) const
+ {
+ return string_to_number<T>()(lhs) == rhs;
+ }
+
+ template <typename T0, typename T1>
+ bool operator()(T0 lhs, T1 rhs) const
+ {
+ return lhs == static_cast<T0>(rhs);
+ }
+};
+
+template <typename T>
+struct javascript_equal
+{
+ javascript_equal(T const& lhs)
+ : lhs_(lhs) {}
+
+ bool operator()(T const& rhs) const
+ {
+ return util::apply_visitor(test::javascript_equal_visitor(), lhs_, rhs);
+ }
+ T const& lhs_;
+};
+
+} // namespace test
+
+int main()
+{
+ typedef util::variant<bool, std::int64_t, std::uint64_t, double, std::string> variant_type;
+ variant_type v0(3.14159);
+ variant_type v1(std::string("3.14159"));
+ variant_type v2(std::uint64_t(1));
+
+ std::cerr << v0 << " == " << v1 << " -> "
+ << std::boolalpha << util::apply_visitor(test::javascript_equal_visitor(), v0, v1) << std::endl;
+
+ std::vector<variant_type> vec;
+
+ vec.emplace_back(std::string("1"));
+ vec.push_back(variant_type(std::uint64_t(2)));
+ vec.push_back(variant_type(std::uint64_t(3)));
+ vec.push_back(std::string("3.14159"));
+ vec.emplace_back(3.14159);
+
+ //auto itr = std::find_if(vec.begin(), vec.end(), [&v0](variant_type const& val) {
+ // return util::apply_visitor(test::javascript_equal_visitor(), v0, val);
+ // });
+
+ auto itr = std::find_if(vec.begin(), vec.end(), test::javascript_equal<variant_type>(v2));
+
+ if (itr != std::end(vec))
+ {
+ std::cout << "found " << *itr << std::endl;
+ }
+ else
+ {
+ std::cout << "can't find " << v2 << '\n';
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/test/boost_variant_hello_world.cpp b/test/boost_variant_hello_world.cpp
new file mode 100644
index 0000000..fdb200e
--- /dev/null
+++ b/test/boost_variant_hello_world.cpp
@@ -0,0 +1,20 @@
+#include <boost/variant.hpp>
+
+#include <stdexcept>
+
+struct check : boost::static_visitor<>
+{
+ template <typename T>
+ void operator()(T const& val) const
+ {
+ if (val != 0) throw std::runtime_error("invalid");
+ }
+};
+
+int main()
+{
+ typedef boost::variant<bool, int, double> variant_type;
+ variant_type v(0);
+ boost::apply_visitor(check(), v);
+ return 0;
+}
diff --git a/test/compilation_failure/default_constructor.cpp b/test/compilation_failure/default_constructor.cpp
new file mode 100644
index 0000000..c75a8c1
--- /dev/null
+++ b/test/compilation_failure/default_constructor.cpp
@@ -0,0 +1,22 @@
+
+// @EXPECTED: First type in variant must be default constructible to allow default construction of variant
+
+#include <variant.hpp>
+
+// Checks that the first type in a variant must be default constructible to
+// make the variant default constructible.
+
+struct no_def_constructor
+{
+
+ int value;
+
+ no_def_constructor() = delete;
+
+ no_def_constructor(int v) : value(v) {}
+};
+
+int main()
+{
+ mapbox::util::variant<no_def_constructor> x;
+}
diff --git a/test/compilation_failure/empty_typelist.cpp b/test/compilation_failure/empty_typelist.cpp
new file mode 100644
index 0000000..69a631c
--- /dev/null
+++ b/test/compilation_failure/empty_typelist.cpp
@@ -0,0 +1,11 @@
+
+// @EXPECTED: Template parameter type list of variant can not be empty
+
+#include <variant.hpp>
+
+// Empty type list should not work.
+
+int main()
+{
+ mapbox::util::variant<> x;
+}
diff --git a/test/compilation_failure/equality.cpp b/test/compilation_failure/equality.cpp
new file mode 100644
index 0000000..b99a308
--- /dev/null
+++ b/test/compilation_failure/equality.cpp
@@ -0,0 +1,11 @@
+
+// @EXPECTED:
+
+#include <variant.hpp>
+
+int main()
+{
+ mapbox::util::variant<int> x;
+ mapbox::util::variant<double> y;
+ x == y;
+}
diff --git a/test/compilation_failure/get_type.cpp b/test/compilation_failure/get_type.cpp
new file mode 100644
index 0000000..5123eb1
--- /dev/null
+++ b/test/compilation_failure/get_type.cpp
@@ -0,0 +1,10 @@
+
+// @EXPECTED: enable_if
+
+#include <variant.hpp>
+
+int main()
+{
+ mapbox::util::variant<int, double> x;
+ x.get<std::string>();
+}
diff --git a/test/compilation_failure/is_type.cpp b/test/compilation_failure/is_type.cpp
new file mode 100644
index 0000000..a79638e
--- /dev/null
+++ b/test/compilation_failure/is_type.cpp
@@ -0,0 +1,10 @@
+
+// @EXPECTED: invalid type in T in `is<T>()` for this variant
+
+#include <variant.hpp>
+
+int main()
+{
+ mapbox::util::variant<int, double> x;
+ x.is<std::string>();
+}
diff --git a/test/compilation_failure/mutating_visitor_on_const.cpp b/test/compilation_failure/mutating_visitor_on_const.cpp
new file mode 100644
index 0000000..ee77b56
--- /dev/null
+++ b/test/compilation_failure/mutating_visitor_on_const.cpp
@@ -0,0 +1,24 @@
+
+// @EXPECTED: const int
+
+#include <variant.hpp>
+
+struct mutating_visitor
+{
+ mutating_visitor(int val)
+ : val_(val) {}
+
+ void operator()(int& val) const
+ {
+ val = val_;
+ }
+
+ int val_;
+};
+
+int main()
+{
+ const mapbox::util::variant<int> var(123);
+ const mutating_visitor visitor(456);
+ mapbox::util::apply_visitor(visitor, var);
+}
diff --git a/test/compilation_failure/no-reference.cpp b/test/compilation_failure/no-reference.cpp
new file mode 100644
index 0000000..17123ce
--- /dev/null
+++ b/test/compilation_failure/no-reference.cpp
@@ -0,0 +1,9 @@
+
+// @EXPECTED: Variant can not hold reference types
+
+#include <variant.hpp>
+
+int main()
+{
+ mapbox::util::variant<double, int&, long> x{mapbox::util::no_init()};
+}
diff --git a/test/include/catch.hpp b/test/include/catch.hpp
new file mode 100644
index 0000000..dd6e3ed
--- /dev/null
+++ b/test/include/catch.hpp
@@ -0,0 +1,11613 @@
+/*
+ * Catch v1.3.2
+ * Generated: 2015-12-28 15:07:07.166291
+ * ----------------------------------------------------------
+ * This file has been merged from multiple headers. Please don't edit it directly
+ * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved.
+ *
+ * Distributed under the Boost Software License, Version 1.0. (See accompanying
+ * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+ */
+#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
+#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
+
+#define TWOBLUECUBES_CATCH_HPP_INCLUDED
+
+#ifdef __clang__
+#pragma clang system_header
+#elif defined __GNUC__
+#pragma GCC system_header
+#endif
+
+// #included from: internal/catch_suppress_warnings.h
+
+#ifdef __clang__
+#ifdef __ICC // icpc defines the __clang__ macro
+#pragma warning(push)
+#pragma warning(disable : 161 1682)
+#else // __ICC
+#pragma clang diagnostic ignored "-Wglobal-constructors"
+#pragma clang diagnostic ignored "-Wvariadic-macros"
+#pragma clang diagnostic ignored "-Wc99-extensions"
+#pragma clang diagnostic ignored "-Wunused-variable"
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#pragma clang diagnostic ignored "-Wc++98-compat"
+#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
+#pragma clang diagnostic ignored "-Wswitch-enum"
+#pragma clang diagnostic ignored "-Wcovered-switch-default"
+#endif
+#elif defined __GNUC__
+#pragma GCC diagnostic ignored "-Wvariadic-macros"
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpadded"
+#endif
+#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER)
+#define CATCH_IMPL
+#endif
+
+#ifdef CATCH_IMPL
+#ifndef CLARA_CONFIG_MAIN
+#define CLARA_CONFIG_MAIN_NOT_DEFINED
+#define CLARA_CONFIG_MAIN
+#endif
+#endif
+
+// #included from: internal/catch_notimplemented_exception.h
+#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED
+
+// #included from: catch_common.h
+#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED
+
+#define INTERNAL_CATCH_UNIQUE_NAME_LINE2(name, line) name##line
+#define INTERNAL_CATCH_UNIQUE_NAME_LINE(name, line) INTERNAL_CATCH_UNIQUE_NAME_LINE2(name, line)
+#define INTERNAL_CATCH_UNIQUE_NAME(name) INTERNAL_CATCH_UNIQUE_NAME_LINE(name, __LINE__)
+
+#define INTERNAL_CATCH_STRINGIFY2(expr) #expr
+#define INTERNAL_CATCH_STRINGIFY(expr) INTERNAL_CATCH_STRINGIFY2(expr)
+
+#include <algorithm>
+#include <sstream>
+#include <stdexcept>
+
+// #included from: catch_compiler_capabilities.h
+#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
+
+// Detect a number of compiler features - mostly C++11/14 conformance - by compiler
+// The following features are defined:
+//
+// CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported?
+// CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported?
+// CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods
+// CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported?
+// CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported
+// CATCH_CONFIG_CPP11_LONG_LONG : is long long supported?
+// CATCH_CONFIG_CPP11_OVERRIDE : is override supported?
+// CATCH_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr)
+
+// CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported?
+
+// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported?
+
+// ****************
+// Note to maintainers: if new toggles are added please document them
+// in configuration.md, too
+// ****************
+
+// In general each macro has a _NO_<feature name> form
+// (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature.
+// Many features, at point of detection, define an _INTERNAL_ macro, so they
+// can be combined, en-mass, with the _NO_ forms later.
+
+// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11
+
+#ifdef __clang__
+
+#if __has_feature(cxx_nullptr)
+#define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
+#endif
+
+#if __has_feature(cxx_noexcept)
+#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#endif
+
+#endif // __clang__
+
+////////////////////////////////////////////////////////////////////////////////
+// Borland
+#ifdef __BORLANDC__
+
+#endif // __BORLANDC__
+
+////////////////////////////////////////////////////////////////////////////////
+// EDG
+#ifdef __EDG_VERSION__
+
+#endif // __EDG_VERSION__
+
+////////////////////////////////////////////////////////////////////////////////
+// Digital Mars
+#ifdef __DMC__
+
+#endif // __DMC__
+
+////////////////////////////////////////////////////////////////////////////////
+// GCC
+#ifdef __GNUC__
+
+#if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__)
+#define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
+#endif
+
+// - otherwise more recent versions define __cplusplus >= 201103L
+// and will get picked up below
+
+#endif // __GNUC__
+
+////////////////////////////////////////////////////////////////////////////////
+// Visual C++
+#ifdef _MSC_VER
+
+#if (_MSC_VER >= 1600)
+#define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
+#define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
+#endif
+
+#if (_MSC_VER >= 1900) // (VC++ 13 (VS2015))
+#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
+#endif
+
+#endif // _MSC_VER
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Use variadic macros if the compiler supports them
+#if (defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \
+ (defined __WAVE__ && __WAVE_HAS_VARIADICS) || \
+ (defined __GNUC__ && __GNUC__ >= 3) || \
+ (!defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L)
+
+#define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// C++ language feature support
+
+// catch all support for C++11
+#if defined(__cplusplus) && __cplusplus >= 201103L
+
+#define CATCH_CPP11_OR_GREATER
+
+#if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR)
+#define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
+#endif
+
+#ifndef CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#endif
+
+#ifndef CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
+#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
+#endif
+
+#ifndef CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM
+#define CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM
+#endif
+
+#ifndef CATCH_INTERNAL_CONFIG_CPP11_TUPLE
+#define CATCH_INTERNAL_CONFIG_CPP11_TUPLE
+#endif
+
+#ifndef CATCH_INTERNAL_CONFIG_VARIADIC_MACROS
+#define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS
+#endif
+
+#if !defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG)
+#define CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG
+#endif
+
+#if !defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE)
+#define CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE
+#endif
+#if !defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR)
+#define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
+#endif
+
+#endif // __cplusplus >= 201103L
+
+// Now set the actual defines based on the above + anything the user has configured
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NO_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_NO_CPP11)
+#define CATCH_CONFIG_CPP11_NULLPTR
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_NO_CPP11)
+#define CATCH_CONFIG_CPP11_NOEXCEPT
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_NO_CPP11)
+#define CATCH_CONFIG_CPP11_GENERATED_METHODS
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_NO_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_NO_CPP11)
+#define CATCH_CONFIG_CPP11_IS_ENUM
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_CPP11_NO_TUPLE) && !defined(CATCH_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_NO_CPP11)
+#define CATCH_CONFIG_CPP11_TUPLE
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS)
+#define CATCH_CONFIG_VARIADIC_MACROS
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11)
+#define CATCH_CONFIG_CPP11_LONG_LONG
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11)
+#define CATCH_CONFIG_CPP11_OVERRIDE
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11)
+#define CATCH_CONFIG_CPP11_UNIQUE_PTR
+#endif
+
+// noexcept support:
+#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT)
+#define CATCH_NOEXCEPT noexcept
+#define CATCH_NOEXCEPT_IS(x) noexcept(x)
+#else
+#define CATCH_NOEXCEPT throw()
+#define CATCH_NOEXCEPT_IS(x)
+#endif
+
+// nullptr support
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+#define CATCH_NULL nullptr
+#else
+#define CATCH_NULL NULL
+#endif
+
+// override support
+#ifdef CATCH_CONFIG_CPP11_OVERRIDE
+#define CATCH_OVERRIDE override
+#else
+#define CATCH_OVERRIDE
+#endif
+
+// unique_ptr support
+#ifdef CATCH_CONFIG_CPP11_UNIQUE_PTR
+#define CATCH_AUTO_PTR(T) std::unique_ptr<T>
+#else
+#define CATCH_AUTO_PTR(T) std::auto_ptr<T>
+#endif
+
+namespace Catch {
+
+struct IConfig;
+
+struct CaseSensitive
+{
+ enum Choice
+ {
+ Yes,
+ No
+ };
+};
+
+class NonCopyable
+{
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+ NonCopyable(NonCopyable const&) = delete;
+ NonCopyable(NonCopyable&&) = delete;
+ NonCopyable& operator=(NonCopyable const&) = delete;
+ NonCopyable& operator=(NonCopyable&&) = delete;
+#else
+ NonCopyable(NonCopyable const& info);
+ NonCopyable& operator=(NonCopyable const&);
+#endif
+
+ protected:
+ NonCopyable() {}
+ virtual ~NonCopyable();
+};
+
+class SafeBool
+{
+ public:
+ typedef void (SafeBool::*type)() const;
+
+ static type makeSafe(bool value)
+ {
+ return value ? &SafeBool::trueValue : 0;
+ }
+
+ private:
+ void trueValue() const {}
+};
+
+template <typename ContainerT>
+inline void deleteAll(ContainerT& container)
+{
+ typename ContainerT::const_iterator it = container.begin();
+ typename ContainerT::const_iterator itEnd = container.end();
+ for (; it != itEnd; ++it)
+ delete *it;
+}
+template <typename AssociativeContainerT>
+inline void deleteAllValues(AssociativeContainerT& container)
+{
+ typename AssociativeContainerT::const_iterator it = container.begin();
+ typename AssociativeContainerT::const_iterator itEnd = container.end();
+ for (; it != itEnd; ++it)
+ delete it->second;
+}
+
+bool startsWith(std::string const& s, std::string const& prefix);
+bool endsWith(std::string const& s, std::string const& suffix);
+bool contains(std::string const& s, std::string const& infix);
+void toLowerInPlace(std::string& s);
+std::string toLower(std::string const& s);
+std::string trim(std::string const& str);
+bool replaceInPlace(std::string& str, std::string const& replaceThis, std::string const& withThis);
+
+struct pluralise
+{
+ pluralise(std::size_t count, std::string const& label);
+
+ friend std::ostream& operator<<(std::ostream& os, pluralise const& pluraliser);
+
+ std::size_t m_count;
+ std::string m_label;
+};
+
+struct SourceLineInfo
+{
+
+ SourceLineInfo();
+ SourceLineInfo(char const* _file, std::size_t _line);
+ SourceLineInfo(SourceLineInfo const& other);
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+ SourceLineInfo(SourceLineInfo&&) = default;
+ SourceLineInfo& operator=(SourceLineInfo const&) = default;
+ SourceLineInfo& operator=(SourceLineInfo&&) = default;
+#endif
+ bool empty() const;
+ bool operator==(SourceLineInfo const& other) const;
+ bool operator<(SourceLineInfo const& other) const;
+
+ std::string file;
+ std::size_t line;
+};
+
+std::ostream& operator<<(std::ostream& os, SourceLineInfo const& info);
+
+// This is just here to avoid compiler warnings with macro constants and boolean literals
+inline bool isTrue(bool value) { return value; }
+inline bool alwaysTrue() { return true; }
+inline bool alwaysFalse() { return false; }
+
+void throwLogicError(std::string const& message, SourceLineInfo const& locationInfo);
+
+void seedRng(IConfig const& config);
+unsigned int rngSeed();
+
+// Use this in variadic streaming macros to allow
+// >> +StreamEndStop
+// as well as
+// >> stuff +StreamEndStop
+struct StreamEndStop
+{
+ std::string operator+()
+ {
+ return std::string();
+ }
+};
+template <typename T>
+T const& operator+(T const& value, StreamEndStop)
+{
+ return value;
+}
+}
+
+#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo(__FILE__, static_cast<std::size_t>(__LINE__))
+#define CATCH_INTERNAL_ERROR(msg) ::Catch::throwLogicError(msg, CATCH_INTERNAL_LINEINFO);
+
+#include <ostream>
+
+namespace Catch {
+
+class NotImplementedException : public std::exception
+{
+ public:
+ NotImplementedException(SourceLineInfo const& lineInfo);
+ NotImplementedException(NotImplementedException const&) {}
+
+ virtual ~NotImplementedException() CATCH_NOEXCEPT {}
+
+ virtual const char* what() const CATCH_NOEXCEPT;
+
+ private:
+ std::string m_what;
+ SourceLineInfo m_lineInfo;
+};
+
+} // end namespace Catch
+
+///////////////////////////////////////////////////////////////////////////////
+#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException(CATCH_INTERNAL_LINEINFO)
+
+// #included from: internal/catch_context.h
+#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED
+
+// #included from: catch_interfaces_generators.h
+#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+struct IGeneratorInfo
+{
+ virtual ~IGeneratorInfo();
+ virtual bool moveNext() = 0;
+ virtual std::size_t getCurrentIndex() const = 0;
+};
+
+struct IGeneratorsForTest
+{
+ virtual ~IGeneratorsForTest();
+
+ virtual IGeneratorInfo& getGeneratorInfo(std::string const& fileInfo, std::size_t size) = 0;
+ virtual bool moveNext() = 0;
+};
+
+IGeneratorsForTest* createGeneratorsForTest();
+
+} // end namespace Catch
+
+// #included from: catch_ptr.hpp
+#define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+namespace Catch {
+
+// An intrusive reference counting smart pointer.
+// T must implement addRef() and release() methods
+// typically implementing the IShared interface
+template <typename T>
+class Ptr
+{
+ public:
+ Ptr() : m_p(CATCH_NULL) {}
+ Ptr(T* p) : m_p(p)
+ {
+ if (m_p)
+ m_p->addRef();
+ }
+ Ptr(Ptr const& other) : m_p(other.m_p)
+ {
+ if (m_p)
+ m_p->addRef();
+ }
+ ~Ptr()
+ {
+ if (m_p)
+ m_p->release();
+ }
+ void reset()
+ {
+ if (m_p)
+ m_p->release();
+ m_p = CATCH_NULL;
+ }
+ Ptr& operator=(T* p)
+ {
+ Ptr temp(p);
+ swap(temp);
+ return *this;
+ }
+ Ptr& operator=(Ptr const& other)
+ {
+ Ptr temp(other);
+ swap(temp);
+ return *this;
+ }
+ void swap(Ptr& other) { std::swap(m_p, other.m_p); }
+ T* get() const { return m_p; }
+ T& operator*() const { return *m_p; }
+ T* operator->() const { return m_p; }
+ bool operator!() const { return m_p == CATCH_NULL; }
+ operator SafeBool::type() const { return SafeBool::makeSafe(m_p != CATCH_NULL); }
+
+ private:
+ T* m_p;
+};
+
+struct IShared : NonCopyable
+{
+ virtual ~IShared();
+ virtual void addRef() const = 0;
+ virtual void release() const = 0;
+};
+
+template <typename T = IShared>
+struct SharedImpl : T
+{
+
+ SharedImpl() : m_rc(0) {}
+
+ virtual void addRef() const
+ {
+ ++m_rc;
+ }
+ virtual void release() const
+ {
+ if (--m_rc == 0)
+ delete this;
+ }
+
+ mutable unsigned int m_rc;
+};
+
+} // end namespace Catch
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#include <memory>
+#include <stdlib.h>
+#include <vector>
+
+namespace Catch {
+
+class TestCase;
+class Stream;
+struct IResultCapture;
+struct IRunner;
+struct IGeneratorsForTest;
+struct IConfig;
+
+struct IContext
+{
+ virtual ~IContext();
+
+ virtual IResultCapture* getResultCapture() = 0;
+ virtual IRunner* getRunner() = 0;
+ virtual size_t getGeneratorIndex(std::string const& fileInfo, size_t totalSize) = 0;
+ virtual bool advanceGeneratorsForCurrentTest() = 0;
+ virtual Ptr<IConfig const> getConfig() const = 0;
+};
+
+struct IMutableContext : IContext
+{
+ virtual ~IMutableContext();
+ virtual void setResultCapture(IResultCapture* resultCapture) = 0;
+ virtual void setRunner(IRunner* runner) = 0;
+ virtual void setConfig(Ptr<IConfig const> const& config) = 0;
+};
+
+IContext& getCurrentContext();
+IMutableContext& getCurrentMutableContext();
+void cleanUpContext();
+Stream createStream(std::string const& streamName);
+}
+
+// #included from: internal/catch_test_registry.hpp
+#define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED
+
+// #included from: catch_interfaces_testcase.h
+#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED
+
+#include <vector>
+
+namespace Catch {
+
+class TestSpec;
+
+struct ITestCase : IShared
+{
+ virtual void invoke() const = 0;
+
+ protected:
+ virtual ~ITestCase();
+};
+
+class TestCase;
+struct IConfig;
+
+struct ITestCaseRegistry
+{
+ virtual ~ITestCaseRegistry();
+ virtual std::vector<TestCase> const& getAllTests() const = 0;
+ virtual std::vector<TestCase> const& getAllTestsSorted(IConfig const& config) const = 0;
+};
+
+bool matchTest(TestCase const& testCase, TestSpec const& testSpec, IConfig const& config);
+std::vector<TestCase> filterTests(std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config);
+std::vector<TestCase> const& getAllTestCasesSorted(IConfig const& config);
+}
+
+namespace Catch {
+
+template <typename C>
+class MethodTestCase : public SharedImpl<ITestCase>
+{
+
+ public:
+ MethodTestCase(void (C::*method)()) : m_method(method) {}
+
+ virtual void invoke() const
+ {
+ C obj;
+ (obj.*m_method)();
+ }
+
+ private:
+ virtual ~MethodTestCase() {}
+
+ void (C::*m_method)();
+};
+
+typedef void (*TestFunction)();
+
+struct NameAndDesc
+{
+ NameAndDesc(const char* _name = "", const char* _description = "")
+ : name(_name), description(_description)
+ {
+ }
+
+ const char* name;
+ const char* description;
+};
+
+void registerTestCase(ITestCase* testCase,
+ char const* className,
+ NameAndDesc const& nameAndDesc,
+ SourceLineInfo const& lineInfo);
+
+struct AutoReg
+{
+
+ AutoReg(TestFunction function,
+ SourceLineInfo const& lineInfo,
+ NameAndDesc const& nameAndDesc);
+
+ template <typename C>
+ AutoReg(void (C::*method)(),
+ char const* className,
+ NameAndDesc const& nameAndDesc,
+ SourceLineInfo const& lineInfo)
+ {
+
+ registerTestCase(new MethodTestCase<C>(method),
+ className,
+ nameAndDesc,
+ lineInfo);
+ }
+
+ ~AutoReg();
+
+ private:
+ AutoReg(AutoReg const&);
+ void operator=(AutoReg const&);
+};
+
+void registerTestCaseFunction(TestFunction function,
+ SourceLineInfo const& lineInfo,
+ NameAndDesc const& nameAndDesc);
+
+} // end namespace Catch
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TESTCASE(...) \
+ static void INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____)(); \
+ namespace { \
+ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME(autoRegistrar)(&INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc(__VA_ARGS__)); \
+ } \
+ static void INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____)()
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_METHOD_AS_TEST_CASE(QualifiedMethod, ...) \
+ namespace { \
+ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME(autoRegistrar)(&QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc(__VA_ARGS__), CATCH_INTERNAL_LINEINFO); \
+ }
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TEST_CASE_METHOD(ClassName, ...) \
+ namespace { \
+ struct INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____) : ClassName \
+ { \
+ void test(); \
+ }; \
+ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME(autoRegistrar)(&INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____)::test, #ClassName, Catch::NameAndDesc(__VA_ARGS__), CATCH_INTERNAL_LINEINFO); \
+ } \
+ void INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____)::test()
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_REGISTER_TESTCASE(Function, ...) \
+ Catch::AutoReg(Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc(__VA_ARGS__));
+
+#else
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TESTCASE(Name, Desc) \
+ static void INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____)(); \
+ namespace { \
+ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME(autoRegistrar)(&INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc(Name, Desc)); \
+ } \
+ static void INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____)()
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_METHOD_AS_TEST_CASE(QualifiedMethod, Name, Desc) \
+ namespace { \
+ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME(autoRegistrar)(&QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc(Name, Desc), CATCH_INTERNAL_LINEINFO); \
+ }
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TEST_CASE_METHOD(ClassName, TestName, Desc) \
+ namespace { \
+ struct INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____) : ClassName \
+ { \
+ void test(); \
+ }; \
+ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME(autoRegistrar)(&INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____)::test, #ClassName, Catch::NameAndDesc(TestName, Desc), CATCH_INTERNAL_LINEINFO); \
+ } \
+ void INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____)::test()
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_REGISTER_TESTCASE(Function, Name, Desc) \
+ Catch::AutoReg(Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc(Name, Desc));
+#endif
+
+// #included from: internal/catch_capture.hpp
+#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
+
+// #included from: catch_result_builder.h
+#define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED
+
+// #included from: catch_result_type.h
+#define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED
+
+namespace Catch {
+
+// ResultWas::OfType enum
+struct ResultWas
+{
+ enum OfType
+ {
+ Unknown = -1,
+ Ok = 0,
+ Info = 1,
+ Warning = 2,
+
+ FailureBit = 0x10,
+
+ ExpressionFailed = FailureBit | 1,
+ ExplicitFailure = FailureBit | 2,
+
+ Exception = 0x100 | FailureBit,
+
+ ThrewException = Exception | 1,
+ DidntThrowException = Exception | 2,
+
+ FatalErrorCondition = 0x200 | FailureBit
+
+ };
+};
+
+inline bool isOk(ResultWas::OfType resultType)
+{
+ return (resultType & ResultWas::FailureBit) == 0;
+}
+inline bool isJustInfo(int flags)
+{
+ return flags == ResultWas::Info;
+}
+
+// ResultDisposition::Flags enum
+struct ResultDisposition
+{
+ enum Flags
+ {
+ Normal = 0x01,
+
+ ContinueOnFailure = 0x02, // Failures fail test, but execution continues
+ FalseTest = 0x04, // Prefix expression with !
+ SuppressFail = 0x08 // Failures are reported but do not fail the test
+ };
+};
+
+inline ResultDisposition::Flags operator|(ResultDisposition::Flags lhs, ResultDisposition::Flags rhs)
+{
+ return static_cast<ResultDisposition::Flags>(static_cast<int>(lhs) | static_cast<int>(rhs));
+}
+
+inline bool shouldContinueOnFailure(int flags) { return (flags & ResultDisposition::ContinueOnFailure) != 0; }
+inline bool isFalseTest(int flags) { return (flags & ResultDisposition::FalseTest) != 0; }
+inline bool shouldSuppressFailure(int flags) { return (flags & ResultDisposition::SuppressFail) != 0; }
+
+} // end namespace Catch
+
+// #included from: catch_assertionresult.h
+#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+struct AssertionInfo
+{
+ AssertionInfo() {}
+ AssertionInfo(std::string const& _macroName,
+ SourceLineInfo const& _lineInfo,
+ std::string const& _capturedExpression,
+ ResultDisposition::Flags _resultDisposition);
+
+ std::string macroName;
+ SourceLineInfo lineInfo;
+ std::string capturedExpression;
+ ResultDisposition::Flags resultDisposition;
+};
+
+struct AssertionResultData
+{
+ AssertionResultData() : resultType(ResultWas::Unknown) {}
+
+ std::string reconstructedExpression;
+ std::string message;
+ ResultWas::OfType resultType;
+};
+
+class AssertionResult
+{
+ public:
+ AssertionResult();
+ AssertionResult(AssertionInfo const& info, AssertionResultData const& data);
+ ~AssertionResult();
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+ AssertionResult(AssertionResult const&) = default;
+ AssertionResult(AssertionResult&&) = default;
+ AssertionResult& operator=(AssertionResult const&) = default;
+ AssertionResult& operator=(AssertionResult&&) = default;
+#endif
+
+ bool isOk() const;
+ bool succeeded() const;
+ ResultWas::OfType getResultType() const;
+ bool hasExpression() const;
+ bool hasMessage() const;
+ std::string getExpression() const;
+ std::string getExpressionInMacro() const;
+ bool hasExpandedExpression() const;
+ std::string getExpandedExpression() const;
+ std::string getMessage() const;
+ SourceLineInfo getSourceInfo() const;
+ std::string getTestMacroName() const;
+
+ protected:
+ AssertionInfo m_info;
+ AssertionResultData m_resultData;
+};
+
+} // end namespace Catch
+
+// #included from: catch_matchers.hpp
+#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED
+
+namespace Catch {
+namespace Matchers {
+namespace Impl {
+
+namespace Generic {
+template <typename ExpressionT>
+class AllOf;
+template <typename ExpressionT>
+class AnyOf;
+template <typename ExpressionT>
+class Not;
+}
+
+template <typename ExpressionT>
+struct Matcher : SharedImpl<IShared>
+{
+ typedef ExpressionT ExpressionType;
+
+ virtual ~Matcher() {}
+ virtual Ptr<Matcher> clone() const = 0;
+ virtual bool match(ExpressionT const& expr) const = 0;
+ virtual std::string toString() const = 0;
+
+ Generic::AllOf<ExpressionT> operator&&(Matcher<ExpressionT> const& other) const;
+ Generic::AnyOf<ExpressionT> operator||(Matcher<ExpressionT> const& other) const;
+ Generic::Not<ExpressionT> operator!() const;
+};
+
+template <typename DerivedT, typename ExpressionT>
+struct MatcherImpl : Matcher<ExpressionT>
+{
+
+ virtual Ptr<Matcher<ExpressionT>> clone() const
+ {
+ return Ptr<Matcher<ExpressionT>>(new DerivedT(static_cast<DerivedT const&>(*this)));
+ }
+};
+
+namespace Generic {
+template <typename ExpressionT>
+class Not : public MatcherImpl<Not<ExpressionT>, ExpressionT>
+{
+ public:
+ explicit Not(Matcher<ExpressionT> const& matcher) : m_matcher(matcher.clone()) {}
+ Not(Not const& other) : m_matcher(other.m_matcher) {}
+
+ virtual bool match(ExpressionT const& expr) const CATCH_OVERRIDE
+ {
+ return !m_matcher->match(expr);
+ }
+
+ virtual std::string toString() const CATCH_OVERRIDE
+ {
+ return "not " + m_matcher->toString();
+ }
+
+ private:
+ Ptr<Matcher<ExpressionT>> m_matcher;
+};
+
+template <typename ExpressionT>
+class AllOf : public MatcherImpl<AllOf<ExpressionT>, ExpressionT>
+{
+ public:
+ AllOf() {}
+ AllOf(AllOf const& other) : m_matchers(other.m_matchers) {}
+
+ AllOf& add(Matcher<ExpressionT> const& matcher)
+ {
+ m_matchers.push_back(matcher.clone());
+ return *this;
+ }
+ virtual bool match(ExpressionT const& expr) const
+ {
+ for (std::size_t i = 0; i < m_matchers.size(); ++i)
+ if (!m_matchers[i]->match(expr))
+ return false;
+ return true;
+ }
+ virtual std::string toString() const
+ {
+ std::ostringstream oss;
+ oss << "( ";
+ for (std::size_t i = 0; i < m_matchers.size(); ++i)
+ {
+ if (i != 0)
+ oss << " and ";
+ oss << m_matchers[i]->toString();
+ }
+ oss << " )";
+ return oss.str();
+ }
+
+ AllOf operator&&(Matcher<ExpressionT> const& other) const
+ {
+ AllOf allOfExpr(*this);
+ allOfExpr.add(other);
+ return allOfExpr;
+ }
+
+ private:
+ std::vector<Ptr<Matcher<ExpressionT>>> m_matchers;
+};
+
+template <typename ExpressionT>
+class AnyOf : public MatcherImpl<AnyOf<ExpressionT>, ExpressionT>
+{
+ public:
+ AnyOf() {}
+ AnyOf(AnyOf const& other) : m_matchers(other.m_matchers) {}
+
+ AnyOf& add(Matcher<ExpressionT> const& matcher)
+ {
+ m_matchers.push_back(matcher.clone());
+ return *this;
+ }
+ virtual bool match(ExpressionT const& expr) const
+ {
+ for (std::size_t i = 0; i < m_matchers.size(); ++i)
+ if (m_matchers[i]->match(expr))
+ return true;
+ return false;
+ }
+ virtual std::string toString() const
+ {
+ std::ostringstream oss;
+ oss << "( ";
+ for (std::size_t i = 0; i < m_matchers.size(); ++i)
+ {
+ if (i != 0)
+ oss << " or ";
+ oss << m_matchers[i]->toString();
+ }
+ oss << " )";
+ return oss.str();
+ }
+
+ AnyOf operator||(Matcher<ExpressionT> const& other) const
+ {
+ AnyOf anyOfExpr(*this);
+ anyOfExpr.add(other);
+ return anyOfExpr;
+ }
+
+ private:
+ std::vector<Ptr<Matcher<ExpressionT>>> m_matchers;
+};
+
+} // namespace Generic
+
+template <typename ExpressionT>
+Generic::AllOf<ExpressionT> Matcher<ExpressionT>::operator&&(Matcher<ExpressionT> const& other) const
+{
+ Generic::AllOf<ExpressionT> allOfExpr;
+ allOfExpr.add(*this);
+ allOfExpr.add(other);
+ return allOfExpr;
+}
+
+template <typename ExpressionT>
+Generic::AnyOf<ExpressionT> Matcher<ExpressionT>::operator||(Matcher<ExpressionT> const& other) const
+{
+ Generic::AnyOf<ExpressionT> anyOfExpr;
+ anyOfExpr.add(*this);
+ anyOfExpr.add(other);
+ return anyOfExpr;
+}
+
+template <typename ExpressionT>
+Generic::Not<ExpressionT> Matcher<ExpressionT>::operator!() const
+{
+ return Generic::Not<ExpressionT>(*this);
+}
+
+namespace StdString {
+
+inline std::string makeString(std::string const& str) { return str; }
+inline std::string makeString(const char* str) { return str ? std::string(str) : std::string(); }
+
+struct CasedString
+{
+ CasedString(std::string const& str, CaseSensitive::Choice caseSensitivity)
+ : m_caseSensitivity(caseSensitivity),
+ m_str(adjustString(str))
+ {
+ }
+ std::string adjustString(std::string const& str) const
+ {
+ return m_caseSensitivity == CaseSensitive::No
+ ? toLower(str)
+ : str;
+ }
+ std::string toStringSuffix() const
+ {
+ return m_caseSensitivity == CaseSensitive::No
+ ? " (case insensitive)"
+ : "";
+ }
+ CaseSensitive::Choice m_caseSensitivity;
+ std::string m_str;
+};
+
+struct Equals : MatcherImpl<Equals, std::string>
+{
+ Equals(std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
+ : m_data(str, caseSensitivity)
+ {
+ }
+ Equals(Equals const& other) : m_data(other.m_data) {}
+
+ virtual ~Equals();
+
+ virtual bool match(std::string const& expr) const
+ {
+ return m_data.m_str == m_data.adjustString(expr);
+ ;
+ }
+ virtual std::string toString() const
+ {
+ return "equals: \"" + m_data.m_str + "\"" + m_data.toStringSuffix();
+ }
+
+ CasedString m_data;
+};
+
+struct Contains : MatcherImpl<Contains, std::string>
+{
+ Contains(std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
+ : m_data(substr, caseSensitivity) {}
+ Contains(Contains const& other) : m_data(other.m_data) {}
+
+ virtual ~Contains();
+
+ virtual bool match(std::string const& expr) const
+ {
+ return m_data.adjustString(expr).find(m_data.m_str) != std::string::npos;
+ }
+ virtual std::string toString() const
+ {
+ return "contains: \"" + m_data.m_str + "\"" + m_data.toStringSuffix();
+ }
+
+ CasedString m_data;
+};
+
+struct StartsWith : MatcherImpl<StartsWith, std::string>
+{
+ StartsWith(std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
+ : m_data(substr, caseSensitivity) {}
+
+ StartsWith(StartsWith const& other) : m_data(other.m_data) {}
+
+ virtual ~StartsWith();
+
+ virtual bool match(std::string const& expr) const
+ {
+ return m_data.adjustString(expr).find(m_data.m_str) == 0;
+ }
+ virtual std::string toString() const
+ {
+ return "starts with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix();
+ }
+
+ CasedString m_data;
+};
+
+struct EndsWith : MatcherImpl<EndsWith, std::string>
+{
+ EndsWith(std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
+ : m_data(substr, caseSensitivity) {}
+ EndsWith(EndsWith const& other) : m_data(other.m_data) {}
+
+ virtual ~EndsWith();
+
+ virtual bool match(std::string const& expr) const
+ {
+ return m_data.adjustString(expr).find(m_data.m_str) == expr.size() - m_data.m_str.size();
+ }
+ virtual std::string toString() const
+ {
+ return "ends with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix();
+ }
+
+ CasedString m_data;
+};
+} // namespace StdString
+} // namespace Impl
+
+// The following functions create the actual matcher objects.
+// This allows the types to be inferred
+template <typename ExpressionT>
+inline Impl::Generic::Not<ExpressionT> Not(Impl::Matcher<ExpressionT> const& m)
+{
+ return Impl::Generic::Not<ExpressionT>(m);
+}
+
+template <typename ExpressionT>
+inline Impl::Generic::AllOf<ExpressionT> AllOf(Impl::Matcher<ExpressionT> const& m1,
+ Impl::Matcher<ExpressionT> const& m2)
+{
+ return Impl::Generic::AllOf<ExpressionT>().add(m1).add(m2);
+}
+template <typename ExpressionT>
+inline Impl::Generic::AllOf<ExpressionT> AllOf(Impl::Matcher<ExpressionT> const& m1,
+ Impl::Matcher<ExpressionT> const& m2,
+ Impl::Matcher<ExpressionT> const& m3)
+{
+ return Impl::Generic::AllOf<ExpressionT>().add(m1).add(m2).add(m3);
+}
+template <typename ExpressionT>
+inline Impl::Generic::AnyOf<ExpressionT> AnyOf(Impl::Matcher<ExpressionT> const& m1,
+ Impl::Matcher<ExpressionT> const& m2)
+{
+ return Impl::Generic::AnyOf<ExpressionT>().add(m1).add(m2);
+}
+template <typename ExpressionT>
+inline Impl::Generic::AnyOf<ExpressionT> AnyOf(Impl::Matcher<ExpressionT> const& m1,
+ Impl::Matcher<ExpressionT> const& m2,
+ Impl::Matcher<ExpressionT> const& m3)
+{
+ return Impl::Generic::AnyOf<ExpressionT>().add(m1).add(m2).add(m3);
+}
+
+inline Impl::StdString::Equals Equals(std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
+{
+ return Impl::StdString::Equals(str, caseSensitivity);
+}
+inline Impl::StdString::Equals Equals(const char* str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
+{
+ return Impl::StdString::Equals(Impl::StdString::makeString(str), caseSensitivity);
+}
+inline Impl::StdString::Contains Contains(std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
+{
+ return Impl::StdString::Contains(substr, caseSensitivity);
+}
+inline Impl::StdString::Contains Contains(const char* substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
+{
+ return Impl::StdString::Contains(Impl::StdString::makeString(substr), caseSensitivity);
+}
+inline Impl::StdString::StartsWith StartsWith(std::string const& substr)
+{
+ return Impl::StdString::StartsWith(substr);
+}
+inline Impl::StdString::StartsWith StartsWith(const char* substr)
+{
+ return Impl::StdString::StartsWith(Impl::StdString::makeString(substr));
+}
+inline Impl::StdString::EndsWith EndsWith(std::string const& substr)
+{
+ return Impl::StdString::EndsWith(substr);
+}
+inline Impl::StdString::EndsWith EndsWith(const char* substr)
+{
+ return Impl::StdString::EndsWith(Impl::StdString::makeString(substr));
+}
+
+} // namespace Matchers
+
+using namespace Matchers;
+
+} // namespace Catch
+
+namespace Catch {
+
+struct TestFailureException
+{
+};
+
+template <typename T>
+class ExpressionLhs;
+
+struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison;
+
+struct CopyableStream
+{
+ CopyableStream() {}
+ CopyableStream(CopyableStream const& other)
+ {
+ oss << other.oss.str();
+ }
+ CopyableStream& operator=(CopyableStream const& other)
+ {
+ oss.str("");
+ oss << other.oss.str();
+ return *this;
+ }
+ std::ostringstream oss;
+};
+
+class ResultBuilder
+{
+ public:
+ ResultBuilder(char const* macroName,
+ SourceLineInfo const& lineInfo,
+ char const* capturedExpression,
+ ResultDisposition::Flags resultDisposition,
+ char const* secondArg = "");
+
+ template <typename T>
+ ExpressionLhs<T const&> operator<=(T const& operand);
+ ExpressionLhs<bool> operator<=(bool value);
+
+ template <typename T>
+ ResultBuilder& operator<<(T const& value)
+ {
+ m_stream.oss << value;
+ return *this;
+ }
+
+ template <typename RhsT>
+ STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator&&(RhsT const&);
+ template <typename RhsT>
+ STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator||(RhsT const&);
+
+ ResultBuilder& setResultType(ResultWas::OfType result);
+ ResultBuilder& setResultType(bool result);
+ ResultBuilder& setLhs(std::string const& lhs);
+ ResultBuilder& setRhs(std::string const& rhs);
+ ResultBuilder& setOp(std::string const& op);
+
+ void endExpression();
+
+ std::string reconstructExpression() const;
+ AssertionResult build() const;
+
+ void useActiveException(ResultDisposition::Flags resultDisposition = ResultDisposition::Normal);
+ void captureResult(ResultWas::OfType resultType);
+ void captureExpression();
+ void captureExpectedException(std::string const& expectedMessage);
+ void captureExpectedException(Matchers::Impl::Matcher<std::string> const& matcher);
+ void handleResult(AssertionResult const& result);
+ void react();
+ bool shouldDebugBreak() const;
+ bool allowThrows() const;
+
+ private:
+ AssertionInfo m_assertionInfo;
+ AssertionResultData m_data;
+ struct ExprComponents
+ {
+ ExprComponents() : testFalse(false) {}
+ bool testFalse;
+ std::string lhs, rhs, op;
+ } m_exprComponents;
+ CopyableStream m_stream;
+
+ bool m_shouldDebugBreak;
+ bool m_shouldThrow;
+};
+
+} // namespace Catch
+
+// Include after due to circular dependency:
+// #included from: catch_expression_lhs.hpp
+#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED
+
+// #included from: catch_evaluate.hpp
+#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4389) // '==' : signed/unsigned mismatch
+#endif
+
+#include <cstddef>
+
+namespace Catch {
+namespace Internal {
+
+enum Operator
+{
+ IsEqualTo,
+ IsNotEqualTo,
+ IsLessThan,
+ IsGreaterThan,
+ IsLessThanOrEqualTo,
+ IsGreaterThanOrEqualTo
+};
+
+template <Operator Op>
+struct OperatorTraits
+{
+ static const char* getName() { return "*error*"; }
+};
+template <>
+struct OperatorTraits<IsEqualTo>
+{
+ static const char* getName() { return "=="; }
+};
+template <>
+struct OperatorTraits<IsNotEqualTo>
+{
+ static const char* getName() { return "!="; }
+};
+template <>
+struct OperatorTraits<IsLessThan>
+{
+ static const char* getName() { return "<"; }
+};
+template <>
+struct OperatorTraits<IsGreaterThan>
+{
+ static const char* getName() { return ">"; }
+};
+template <>
+struct OperatorTraits<IsLessThanOrEqualTo>
+{
+ static const char* getName() { return "<="; }
+};
+template <>
+struct OperatorTraits<IsGreaterThanOrEqualTo>
+{
+ static const char* getName() { return ">="; }
+};
+
+template <typename T>
+inline T& opCast(T const& t)
+{
+ return const_cast<T&>(t);
+}
+
+// nullptr_t support based on pull request #154 from Konstantin Baumann
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+inline std::nullptr_t opCast(std::nullptr_t)
+{
+ return nullptr;
+}
+#endif // CATCH_CONFIG_CPP11_NULLPTR
+
+// So the compare overloads can be operator agnostic we convey the operator as a template
+// enum, which is used to specialise an Evaluator for doing the comparison.
+template <typename T1, typename T2, Operator Op>
+class Evaluator
+{
+};
+
+template <typename T1, typename T2>
+struct Evaluator<T1, T2, IsEqualTo>
+{
+ static bool evaluate(T1 const& lhs, T2 const& rhs)
+ {
+ return opCast(lhs) == opCast(rhs);
+ }
+};
+template <typename T1, typename T2>
+struct Evaluator<T1, T2, IsNotEqualTo>
+{
+ static bool evaluate(T1 const& lhs, T2 const& rhs)
+ {
+ return opCast(lhs) != opCast(rhs);
+ }
+};
+template <typename T1, typename T2>
+struct Evaluator<T1, T2, IsLessThan>
+{
+ static bool evaluate(T1 const& lhs, T2 const& rhs)
+ {
+ return opCast(lhs) < opCast(rhs);
+ }
+};
+template <typename T1, typename T2>
+struct Evaluator<T1, T2, IsGreaterThan>
+{
+ static bool evaluate(T1 const& lhs, T2 const& rhs)
+ {
+ return opCast(lhs) > opCast(rhs);
+ }
+};
+template <typename T1, typename T2>
+struct Evaluator<T1, T2, IsGreaterThanOrEqualTo>
+{
+ static bool evaluate(T1 const& lhs, T2 const& rhs)
+ {
+ return opCast(lhs) >= opCast(rhs);
+ }
+};
+template <typename T1, typename T2>
+struct Evaluator<T1, T2, IsLessThanOrEqualTo>
+{
+ static bool evaluate(T1 const& lhs, T2 const& rhs)
+ {
+ return opCast(lhs) <= opCast(rhs);
+ }
+};
+
+template <Operator Op, typename T1, typename T2>
+bool applyEvaluator(T1 const& lhs, T2 const& rhs)
+{
+ return Evaluator<T1, T2, Op>::evaluate(lhs, rhs);
+}
+
+// This level of indirection allows us to specialise for integer types
+// to avoid signed/ unsigned warnings
+
+// "base" overload
+template <Operator Op, typename T1, typename T2>
+bool compare(T1 const& lhs, T2 const& rhs)
+{
+ return Evaluator<T1, T2, Op>::evaluate(lhs, rhs);
+}
+
+// unsigned X to int
+template <Operator Op>
+bool compare(unsigned int lhs, int rhs)
+{
+ return applyEvaluator<Op>(lhs, static_cast<unsigned int>(rhs));
+}
+template <Operator Op>
+bool compare(unsigned long lhs, int rhs)
+{
+ return applyEvaluator<Op>(lhs, static_cast<unsigned int>(rhs));
+}
+template <Operator Op>
+bool compare(unsigned char lhs, int rhs)
+{
+ return applyEvaluator<Op>(lhs, static_cast<unsigned int>(rhs));
+}
+
+// unsigned X to long
+template <Operator Op>
+bool compare(unsigned int lhs, long rhs)
+{
+ return applyEvaluator<Op>(lhs, static_cast<unsigned long>(rhs));
+}
+template <Operator Op>
+bool compare(unsigned long lhs, long rhs)
+{
+ return applyEvaluator<Op>(lhs, static_cast<unsigned long>(rhs));
+}
+template <Operator Op>
+bool compare(unsigned char lhs, long rhs)
+{
+ return applyEvaluator<Op>(lhs, static_cast<unsigned long>(rhs));
+}
+
+// int to unsigned X
+template <Operator Op>
+bool compare(int lhs, unsigned int rhs)
+{
+ return applyEvaluator<Op>(static_cast<unsigned int>(lhs), rhs);
+}
+template <Operator Op>
+bool compare(int lhs, unsigned long rhs)
+{
+ return applyEvaluator<Op>(static_cast<unsigned int>(lhs), rhs);
+}
+template <Operator Op>
+bool compare(int lhs, unsigned char rhs)
+{
+ return applyEvaluator<Op>(static_cast<unsigned int>(lhs), rhs);
+}
+
+// long to unsigned X
+template <Operator Op>
+bool compare(long lhs, unsigned int rhs)
+{
+ return applyEvaluator<Op>(static_cast<unsigned long>(lhs), rhs);
+}
+template <Operator Op>
+bool compare(long lhs, unsigned long rhs)
+{
+ return applyEvaluator<Op>(static_cast<unsigned long>(lhs), rhs);
+}
+template <Operator Op>
+bool compare(long lhs, unsigned char rhs)
+{
+ return applyEvaluator<Op>(static_cast<unsigned long>(lhs), rhs);
+}
+
+// pointer to long (when comparing against NULL)
+template <Operator Op, typename T>
+bool compare(long lhs, T* rhs)
+{
+ return Evaluator<T*, T*, Op>::evaluate(reinterpret_cast<T*>(lhs), rhs);
+}
+template <Operator Op, typename T>
+bool compare(T* lhs, long rhs)
+{
+ return Evaluator<T*, T*, Op>::evaluate(lhs, reinterpret_cast<T*>(rhs));
+}
+
+// pointer to int (when comparing against NULL)
+template <Operator Op, typename T>
+bool compare(int lhs, T* rhs)
+{
+ return Evaluator<T*, T*, Op>::evaluate(reinterpret_cast<T*>(lhs), rhs);
+}
+template <Operator Op, typename T>
+bool compare(T* lhs, int rhs)
+{
+ return Evaluator<T*, T*, Op>::evaluate(lhs, reinterpret_cast<T*>(rhs));
+}
+
+#ifdef CATCH_CONFIG_CPP11_LONG_LONG
+// long long to unsigned X
+template <Operator Op>
+bool compare(long long lhs, unsigned int rhs)
+{
+ return applyEvaluator<Op>(static_cast<unsigned long>(lhs), rhs);
+}
+template <Operator Op>
+bool compare(long long lhs, unsigned long rhs)
+{
+ return applyEvaluator<Op>(static_cast<unsigned long>(lhs), rhs);
+}
+template <Operator Op>
+bool compare(long long lhs, unsigned long long rhs)
+{
+ return applyEvaluator<Op>(static_cast<unsigned long>(lhs), rhs);
+}
+template <Operator Op>
+bool compare(long long lhs, unsigned char rhs)
+{
+ return applyEvaluator<Op>(static_cast<unsigned long>(lhs), rhs);
+}
+
+// unsigned long long to X
+template <Operator Op>
+bool compare(unsigned long long lhs, int rhs)
+{
+ return applyEvaluator<Op>(static_cast<long>(lhs), rhs);
+}
+template <Operator Op>
+bool compare(unsigned long long lhs, long rhs)
+{
+ return applyEvaluator<Op>(static_cast<long>(lhs), rhs);
+}
+template <Operator Op>
+bool compare(unsigned long long lhs, long long rhs)
+{
+ return applyEvaluator<Op>(static_cast<long>(lhs), rhs);
+}
+template <Operator Op>
+bool compare(unsigned long long lhs, char rhs)
+{
+ return applyEvaluator<Op>(static_cast<long>(lhs), rhs);
+}
+
+// pointer to long long (when comparing against NULL)
+template <Operator Op, typename T>
+bool compare(long long lhs, T* rhs)
+{
+ return Evaluator<T*, T*, Op>::evaluate(reinterpret_cast<T*>(lhs), rhs);
+}
+template <Operator Op, typename T>
+bool compare(T* lhs, long long rhs)
+{
+ return Evaluator<T*, T*, Op>::evaluate(lhs, reinterpret_cast<T*>(rhs));
+}
+#endif // CATCH_CONFIG_CPP11_LONG_LONG
+
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+// pointer to nullptr_t (when comparing against nullptr)
+template <Operator Op, typename T>
+bool compare(std::nullptr_t, T* rhs)
+{
+ return Evaluator<T*, T*, Op>::evaluate(nullptr, rhs);
+}
+template <Operator Op, typename T>
+bool compare(T* lhs, std::nullptr_t)
+{
+ return Evaluator<T*, T*, Op>::evaluate(lhs, nullptr);
+}
+#endif // CATCH_CONFIG_CPP11_NULLPTR
+
+} // end of namespace Internal
+} // end of namespace Catch
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+// #included from: catch_tostring.h
+#define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED
+
+#include <cstddef>
+#include <iomanip>
+#include <limits>
+#include <sstream>
+#include <vector>
+
+#ifdef __OBJC__
+// #included from: catch_objc_arc.hpp
+#define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED
+
+#import <Foundation/Foundation.h>
+
+#ifdef __has_feature
+#define CATCH_ARC_ENABLED __has_feature(objc_arc)
+#else
+#define CATCH_ARC_ENABLED 0
+#endif
+
+void arcSafeRelease(NSObject* obj);
+id performOptionalSelector(id obj, SEL sel);
+
+#if !CATCH_ARC_ENABLED
+inline void arcSafeRelease(NSObject* obj)
+{
+ [obj release];
+}
+inline id performOptionalSelector(id obj, SEL sel)
+{
+ if ([obj respondsToSelector:sel])
+ return [obj performSelector:sel];
+ return nil;
+}
+#define CATCH_UNSAFE_UNRETAINED
+#define CATCH_ARC_STRONG
+#else
+inline void arcSafeRelease(NSObject*)
+{
+}
+inline id performOptionalSelector(id obj, SEL sel)
+{
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+#endif
+ if ([obj respondsToSelector:sel])
+ return [obj performSelector:sel];
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+ return nil;
+}
+#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained
+#define CATCH_ARC_STRONG __strong
+#endif
+
+#endif
+
+#ifdef CATCH_CONFIG_CPP11_TUPLE
+#include <tuple>
+#endif
+
+#ifdef CATCH_CONFIG_CPP11_IS_ENUM
+#include <type_traits>
+#endif
+
+namespace Catch {
+
+// Why we're here.
+template <typename T>
+std::string toString(T const& value);
+
+// Built in overloads
+
+std::string toString(std::string const& value);
+std::string toString(std::wstring const& value);
+std::string toString(const char* const value);
+std::string toString(char* const value);
+std::string toString(const wchar_t* const value);
+std::string toString(wchar_t* const value);
+std::string toString(int value);
+std::string toString(unsigned long value);
+std::string toString(unsigned int value);
+std::string toString(const double value);
+std::string toString(const float value);
+std::string toString(bool value);
+std::string toString(char value);
+std::string toString(signed char value);
+std::string toString(unsigned char value);
+
+#ifdef CATCH_CONFIG_CPP11_LONG_LONG
+std::string toString(long long value);
+std::string toString(unsigned long long value);
+#endif
+
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+std::string toString(std::nullptr_t);
+#endif
+
+#ifdef __OBJC__
+std::string toString(NSString const* const& nsstring);
+std::string toString(NSString* CATCH_ARC_STRONG const& nsstring);
+std::string toString(NSObject* const& nsObject);
+#endif
+
+namespace Detail {
+
+extern const std::string unprintableString;
+
+struct BorgType
+{
+ template <typename T>
+ BorgType(T const&);
+};
+
+struct TrueType
+{
+ char sizer[1];
+};
+struct FalseType
+{
+ char sizer[2];
+};
+
+TrueType& testStreamable(std::ostream&);
+FalseType testStreamable(FalseType);
+
+FalseType operator<<(std::ostream const&, BorgType const&);
+
+template <typename T>
+struct IsStreamInsertable
+{
+ static std::ostream& s;
+ static T const& t;
+ enum
+ {
+ value = sizeof(testStreamable(s << t)) == sizeof(TrueType)
+ };
+};
+
+#if defined(CATCH_CONFIG_CPP11_IS_ENUM)
+template <typename T,
+ bool IsEnum = std::is_enum<T>::value>
+struct EnumStringMaker
+{
+ static std::string convert(T const&) { return unprintableString; }
+};
+
+template <typename T>
+struct EnumStringMaker<T, true>
+{
+ static std::string convert(T const& v)
+ {
+ return ::Catch::toString(
+ static_cast<typename std::underlying_type<T>::type>(v));
+ }
+};
+#endif
+template <bool C>
+struct StringMakerBase
+{
+#if defined(CATCH_CONFIG_CPP11_IS_ENUM)
+ template <typename T>
+ static std::string convert(T const& v)
+ {
+ return EnumStringMaker<T>::convert(v);
+ }
+#else
+ template <typename T>
+ static std::string convert(T const&)
+ {
+ return unprintableString;
+ }
+#endif
+};
+
+template <>
+struct StringMakerBase<true>
+{
+ template <typename T>
+ static std::string convert(T const& _value)
+ {
+ std::ostringstream oss;
+ oss << _value;
+ return oss.str();
+ }
+};
+
+std::string rawMemoryToString(const void* object, std::size_t size);
+
+template <typename T>
+inline std::string rawMemoryToString(const T& object)
+{
+ return rawMemoryToString(&object, sizeof(object));
+}
+
+} // end namespace Detail
+
+template <typename T>
+struct StringMaker : Detail::StringMakerBase<Detail::IsStreamInsertable<T>::value>
+{
+};
+
+template <typename T>
+struct StringMaker<T*>
+{
+ template <typename U>
+ static std::string convert(U* p)
+ {
+ if (!p)
+ return "NULL";
+ else
+ return Detail::rawMemoryToString(p);
+ }
+};
+
+template <typename R, typename C>
+struct StringMaker<R C::*>
+{
+ static std::string convert(R C::*p)
+ {
+ if (!p)
+ return "NULL";
+ else
+ return Detail::rawMemoryToString(p);
+ }
+};
+
+namespace Detail {
+template <typename InputIterator>
+std::string rangeToString(InputIterator first, InputIterator last);
+}
+
+//template<typename T, typename Allocator>
+//struct StringMaker<std::vector<T, Allocator> > {
+// static std::string convert( std::vector<T,Allocator> const& v ) {
+// return Detail::rangeToString( v.begin(), v.end() );
+// }
+//};
+
+template <typename T, typename Allocator>
+std::string toString(std::vector<T, Allocator> const& v)
+{
+ return Detail::rangeToString(v.begin(), v.end());
+}
+
+#ifdef CATCH_CONFIG_CPP11_TUPLE
+
+// toString for tuples
+namespace TupleDetail {
+template <
+ typename Tuple,
+ std::size_t N = 0,
+ bool = (N < std::tuple_size<Tuple>::value)>
+struct ElementPrinter
+{
+ static void print(const Tuple& tuple, std::ostream& os)
+ {
+ os << (N ? ", " : " ")
+ << Catch::toString(std::get<N>(tuple));
+ ElementPrinter<Tuple, N + 1>::print(tuple, os);
+ }
+};
+
+template <
+ typename Tuple,
+ std::size_t N>
+struct ElementPrinter<Tuple, N, false>
+{
+ static void print(const Tuple&, std::ostream&) {}
+};
+}
+
+template <typename... Types>
+struct StringMaker<std::tuple<Types...>>
+{
+
+ static std::string convert(const std::tuple<Types...>& tuple)
+ {
+ std::ostringstream os;
+ os << '{';
+ TupleDetail::ElementPrinter<std::tuple<Types...>>::print(tuple, os);
+ os << " }";
+ return os.str();
+ }
+};
+#endif // CATCH_CONFIG_CPP11_TUPLE
+
+namespace Detail {
+template <typename T>
+std::string makeString(T const& value)
+{
+ return StringMaker<T>::convert(value);
+}
+} // end namespace Detail
+
+/// \brief converts any type to a string
+///
+/// The default template forwards on to ostringstream - except when an
+/// ostringstream overload does not exist - in which case it attempts to detect
+/// that and writes {?}.
+/// Overload (not specialise) this template for custom typs that you don't want
+/// to provide an ostream overload for.
+template <typename T>
+std::string toString(T const& value)
+{
+ return StringMaker<T>::convert(value);
+}
+
+namespace Detail {
+template <typename InputIterator>
+std::string rangeToString(InputIterator first, InputIterator last)
+{
+ std::ostringstream oss;
+ oss << "{ ";
+ if (first != last)
+ {
+ oss << Catch::toString(*first);
+ for (++first; first != last; ++first)
+ oss << ", " << Catch::toString(*first);
+ }
+ oss << " }";
+ return oss.str();
+}
+}
+
+} // end namespace Catch
+
+namespace Catch {
+
+// Wraps the LHS of an expression and captures the operator and RHS (if any) -
+// wrapping them all in a ResultBuilder object
+template <typename T>
+class ExpressionLhs
+{
+ ExpressionLhs& operator=(ExpressionLhs const&);
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+ ExpressionLhs& operator=(ExpressionLhs&&) = delete;
+#endif
+
+ public:
+ ExpressionLhs(ResultBuilder& rb, T lhs) : m_rb(rb), m_lhs(lhs) {}
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+ ExpressionLhs(ExpressionLhs const&) = default;
+ ExpressionLhs(ExpressionLhs&&) = default;
+#endif
+
+ template <typename RhsT>
+ ResultBuilder& operator==(RhsT const& rhs)
+ {
+ return captureExpression<Internal::IsEqualTo>(rhs);
+ }
+
+ template <typename RhsT>
+ ResultBuilder& operator!=(RhsT const& rhs)
+ {
+ return captureExpression<Internal::IsNotEqualTo>(rhs);
+ }
+
+ template <typename RhsT>
+ ResultBuilder& operator<(RhsT const& rhs)
+ {
+ return captureExpression<Internal::IsLessThan>(rhs);
+ }
+
+ template <typename RhsT>
+ ResultBuilder& operator>(RhsT const& rhs)
+ {
+ return captureExpression<Internal::IsGreaterThan>(rhs);
+ }
+
+ template <typename RhsT>
+ ResultBuilder& operator<=(RhsT const& rhs)
+ {
+ return captureExpression<Internal::IsLessThanOrEqualTo>(rhs);
+ }
+
+ template <typename RhsT>
+ ResultBuilder& operator>=(RhsT const& rhs)
+ {
+ return captureExpression<Internal::IsGreaterThanOrEqualTo>(rhs);
+ }
+
+ ResultBuilder& operator==(bool rhs)
+ {
+ return captureExpression<Internal::IsEqualTo>(rhs);
+ }
+
+ ResultBuilder& operator!=(bool rhs)
+ {
+ return captureExpression<Internal::IsNotEqualTo>(rhs);
+ }
+
+ void endExpression()
+ {
+ bool value = m_lhs ? true : false;
+ m_rb
+ .setLhs(Catch::toString(value))
+ .setResultType(value)
+ .endExpression();
+ }
+
+ // Only simple binary expressions are allowed on the LHS.
+ // If more complex compositions are required then place the sub expression in parentheses
+ template <typename RhsT>
+ STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator+(RhsT const&);
+ template <typename RhsT>
+ STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator-(RhsT const&);
+ template <typename RhsT>
+ STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator/(RhsT const&);
+ template <typename RhsT>
+ STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator*(RhsT const&);
+ template <typename RhsT>
+ STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator&&(RhsT const&);
+ template <typename RhsT>
+ STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator||(RhsT const&);
+
+ private:
+ template <Internal::Operator Op, typename RhsT>
+ ResultBuilder& captureExpression(RhsT const& rhs)
+ {
+ return m_rb
+ .setResultType(Internal::compare<Op>(m_lhs, rhs))
+ .setLhs(Catch::toString(m_lhs))
+ .setRhs(Catch::toString(rhs))
+ .setOp(Internal::OperatorTraits<Op>::getName());
+ }
+
+ private:
+ ResultBuilder& m_rb;
+ T m_lhs;
+};
+
+} // end namespace Catch
+
+namespace Catch {
+
+template <typename T>
+inline ExpressionLhs<T const&> ResultBuilder::operator<=(T const& operand)
+{
+ return ExpressionLhs<T const&>(*this, operand);
+}
+
+inline ExpressionLhs<bool> ResultBuilder::operator<=(bool value)
+{
+ return ExpressionLhs<bool>(*this, value);
+}
+
+} // namespace Catch
+
+// #included from: catch_message.h
+#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+struct MessageInfo
+{
+ MessageInfo(std::string const& _macroName,
+ SourceLineInfo const& _lineInfo,
+ ResultWas::OfType _type);
+
+ std::string macroName;
+ SourceLineInfo lineInfo;
+ ResultWas::OfType type;
+ std::string message;
+ unsigned int sequence;
+
+ bool operator==(MessageInfo const& other) const
+ {
+ return sequence == other.sequence;
+ }
+ bool operator<(MessageInfo const& other) const
+ {
+ return sequence < other.sequence;
+ }
+
+ private:
+ static unsigned int globalCount;
+};
+
+struct MessageBuilder
+{
+ MessageBuilder(std::string const& macroName,
+ SourceLineInfo const& lineInfo,
+ ResultWas::OfType type)
+ : m_info(macroName, lineInfo, type)
+ {
+ }
+
+ template <typename T>
+ MessageBuilder& operator<<(T const& value)
+ {
+ m_stream << value;
+ return *this;
+ }
+
+ MessageInfo m_info;
+ std::ostringstream m_stream;
+};
+
+class ScopedMessage
+{
+ public:
+ ScopedMessage(MessageBuilder const& builder);
+ ScopedMessage(ScopedMessage const& other);
+ ~ScopedMessage();
+
+ MessageInfo m_info;
+};
+
+} // end namespace Catch
+
+// #included from: catch_interfaces_capture.h
+#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+class TestCase;
+class AssertionResult;
+struct AssertionInfo;
+struct SectionInfo;
+struct SectionEndInfo;
+struct MessageInfo;
+class ScopedMessageBuilder;
+struct Counts;
+
+struct IResultCapture
+{
+
+ virtual ~IResultCapture();
+
+ virtual void assertionEnded(AssertionResult const& result) = 0;
+ virtual bool sectionStarted(SectionInfo const& sectionInfo,
+ Counts& assertions) = 0;
+ virtual void sectionEnded(SectionEndInfo const& endInfo) = 0;
+ virtual void sectionEndedEarly(SectionEndInfo const& endInfo) = 0;
+ virtual void pushScopedMessage(MessageInfo const& message) = 0;
+ virtual void popScopedMessage(MessageInfo const& message) = 0;
+
+ virtual std::string getCurrentTestName() const = 0;
+ virtual const AssertionResult* getLastResult() const = 0;
+
+ virtual void handleFatalErrorCondition(std::string const& message) = 0;
+};
+
+IResultCapture& getResultCapture();
+}
+
+// #included from: catch_debugger.h
+#define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED
+
+// #included from: catch_platform.h
+#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED
+
+#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
+#define CATCH_PLATFORM_MAC
+#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
+#define CATCH_PLATFORM_IPHONE
+#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
+#define CATCH_PLATFORM_WINDOWS
+#endif
+
+#include <string>
+
+namespace Catch {
+
+bool isDebuggerActive();
+void writeToDebugConsole(std::string const& text);
+}
+
+#ifdef CATCH_PLATFORM_MAC
+
+// The following code snippet based on:
+// http://cocoawithlove.com/2008/03/break-into-debugger.html
+#ifdef DEBUG
+#if defined(__ppc64__) || defined(__ppc__)
+#define CATCH_BREAK_INTO_DEBUGGER() \
+ if (Catch::isDebuggerActive()) \
+ { \
+ __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
+ : \
+ : \
+ : "memory", "r0", "r3", "r4"); \
+ }
+#else
+#define CATCH_BREAK_INTO_DEBUGGER() \
+ if (Catch::isDebuggerActive()) \
+ { \
+ __asm__("int $3\n" \
+ : \
+ :); \
+ }
+#endif
+#endif
+
+#elif defined(_MSC_VER)
+#define CATCH_BREAK_INTO_DEBUGGER() \
+ if (Catch::isDebuggerActive()) \
+ { \
+ __debugbreak(); \
+ }
+#elif defined(__MINGW32__)
+extern "C" __declspec(dllimport) void __stdcall DebugBreak();
+#define CATCH_BREAK_INTO_DEBUGGER() \
+ if (Catch::isDebuggerActive()) \
+ { \
+ DebugBreak(); \
+ }
+#endif
+
+#ifndef CATCH_BREAK_INTO_DEBUGGER
+#define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue();
+#endif
+
+// #included from: catch_interfaces_runner.h
+#define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED
+
+namespace Catch {
+class TestCase;
+
+struct IRunner
+{
+ virtual ~IRunner();
+ virtual bool aborting() const = 0;
+};
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// In the event of a failure works out if the debugger needs to be invoked
+// and/or an exception thrown and takes appropriate action.
+// This needs to be done as a macro so the debugger will stop in the user
+// source code rather than in Catch library code
+#define INTERNAL_CATCH_REACT(resultBuilder) \
+ if (resultBuilder.shouldDebugBreak()) CATCH_BREAK_INTO_DEBUGGER(); \
+ resultBuilder.react();
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TEST(expr, resultDisposition, macroName) \
+ do \
+ { \
+ Catch::ResultBuilder __catchResult(macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition); \
+ try \
+ { \
+ (__catchResult <= expr).endExpression(); \
+ } \
+ catch (...) \
+ { \
+ __catchResult.useActiveException(Catch::ResultDisposition::Normal); \
+ } \
+ INTERNAL_CATCH_REACT(__catchResult) \
+ } while (Catch::isTrue(false && (expr))) // expr here is never evaluated at runtime but it forces the compiler to give it a look
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_IF(expr, resultDisposition, macroName) \
+ INTERNAL_CATCH_TEST(expr, resultDisposition, macroName); \
+ if (Catch::getResultCapture().getLastResult()->succeeded())
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_ELSE(expr, resultDisposition, macroName) \
+ INTERNAL_CATCH_TEST(expr, resultDisposition, macroName); \
+ if (!Catch::getResultCapture().getLastResult()->succeeded())
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_NO_THROW(expr, resultDisposition, macroName) \
+ do \
+ { \
+ Catch::ResultBuilder __catchResult(macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition); \
+ try \
+ { \
+ expr; \
+ __catchResult.captureResult(Catch::ResultWas::Ok); \
+ } \
+ catch (...) \
+ { \
+ __catchResult.useActiveException(resultDisposition); \
+ } \
+ INTERNAL_CATCH_REACT(__catchResult) \
+ } while (Catch::alwaysFalse())
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_THROWS(expr, resultDisposition, matcher, macroName) \
+ do \
+ { \
+ Catch::ResultBuilder __catchResult(macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher); \
+ if (__catchResult.allowThrows()) \
+ try \
+ { \
+ expr; \
+ __catchResult.captureResult(Catch::ResultWas::DidntThrowException); \
+ } \
+ catch (...) \
+ { \
+ __catchResult.captureExpectedException(matcher); \
+ } \
+ else \
+ __catchResult.captureResult(Catch::ResultWas::Ok); \
+ INTERNAL_CATCH_REACT(__catchResult) \
+ } while (Catch::alwaysFalse())
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_THROWS_AS(expr, exceptionType, resultDisposition, macroName) \
+ do \
+ { \
+ Catch::ResultBuilder __catchResult(macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition); \
+ if (__catchResult.allowThrows()) \
+ try \
+ { \
+ expr; \
+ __catchResult.captureResult(Catch::ResultWas::DidntThrowException); \
+ } \
+ catch (exceptionType) \
+ { \
+ __catchResult.captureResult(Catch::ResultWas::Ok); \
+ } \
+ catch (...) \
+ { \
+ __catchResult.useActiveException(resultDisposition); \
+ } \
+ else \
+ __catchResult.captureResult(Catch::ResultWas::Ok); \
+ INTERNAL_CATCH_REACT(__catchResult) \
+ } while (Catch::alwaysFalse())
+
+///////////////////////////////////////////////////////////////////////////////
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+#define INTERNAL_CATCH_MSG(messageType, resultDisposition, macroName, ...) \
+ do \
+ { \
+ Catch::ResultBuilder __catchResult(macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition); \
+ __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \
+ __catchResult.captureResult(messageType); \
+ INTERNAL_CATCH_REACT(__catchResult) \
+ } while (Catch::alwaysFalse())
+#else
+#define INTERNAL_CATCH_MSG(messageType, resultDisposition, macroName, log) \
+ do \
+ { \
+ Catch::ResultBuilder __catchResult(macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition); \
+ __catchResult << log + ::Catch::StreamEndStop(); \
+ __catchResult.captureResult(messageType); \
+ INTERNAL_CATCH_REACT(__catchResult) \
+ } while (Catch::alwaysFalse())
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_INFO(log, macroName) \
+ Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME(scopedMessage) = Catch::MessageBuilder(macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info) << log;
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CHECK_THAT(arg, matcher, resultDisposition, macroName) \
+ do \
+ { \
+ Catch::ResultBuilder __catchResult(macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition); \
+ try \
+ { \
+ std::string matcherAsString = (matcher).toString(); \
+ __catchResult \
+ .setLhs(Catch::toString(arg)) \
+ .setRhs(matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString) \
+ .setOp("matches") \
+ .setResultType((matcher).match(arg)); \
+ __catchResult.captureExpression(); \
+ } \
+ catch (...) \
+ { \
+ __catchResult.useActiveException(resultDisposition | Catch::ResultDisposition::ContinueOnFailure); \
+ } \
+ INTERNAL_CATCH_REACT(__catchResult) \
+ } while (Catch::alwaysFalse())
+
+// #included from: internal/catch_section.h
+#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED
+
+// #included from: catch_section_info.h
+#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED
+
+// #included from: catch_totals.hpp
+#define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED
+
+#include <cstddef>
+
+namespace Catch {
+
+struct Counts
+{
+ Counts() : passed(0), failed(0), failedButOk(0) {}
+
+ Counts operator-(Counts const& other) const
+ {
+ Counts diff;
+ diff.passed = passed - other.passed;
+ diff.failed = failed - other.failed;
+ diff.failedButOk = failedButOk - other.failedButOk;
+ return diff;
+ }
+ Counts& operator+=(Counts const& other)
+ {
+ passed += other.passed;
+ failed += other.failed;
+ failedButOk += other.failedButOk;
+ return *this;
+ }
+
+ std::size_t total() const
+ {
+ return passed + failed + failedButOk;
+ }
+ bool allPassed() const
+ {
+ return failed == 0 && failedButOk == 0;
+ }
+ bool allOk() const
+ {
+ return failed == 0;
+ }
+
+ std::size_t passed;
+ std::size_t failed;
+ std::size_t failedButOk;
+};
+
+struct Totals
+{
+
+ Totals operator-(Totals const& other) const
+ {
+ Totals diff;
+ diff.assertions = assertions - other.assertions;
+ diff.testCases = testCases - other.testCases;
+ return diff;
+ }
+
+ Totals delta(Totals const& prevTotals) const
+ {
+ Totals diff = *this - prevTotals;
+ if (diff.assertions.failed > 0)
+ ++diff.testCases.failed;
+ else if (diff.assertions.failedButOk > 0)
+ ++diff.testCases.failedButOk;
+ else
+ ++diff.testCases.passed;
+ return diff;
+ }
+
+ Totals& operator+=(Totals const& other)
+ {
+ assertions += other.assertions;
+ testCases += other.testCases;
+ return *this;
+ }
+
+ Counts assertions;
+ Counts testCases;
+};
+}
+
+namespace Catch {
+
+struct SectionInfo
+{
+ SectionInfo(SourceLineInfo const& _lineInfo,
+ std::string const& _name,
+ std::string const& _description = std::string());
+
+ std::string name;
+ std::string description;
+ SourceLineInfo lineInfo;
+};
+
+struct SectionEndInfo
+{
+ SectionEndInfo(SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds)
+ : sectionInfo(_sectionInfo), prevAssertions(_prevAssertions), durationInSeconds(_durationInSeconds)
+ {
+ }
+
+ SectionInfo sectionInfo;
+ Counts prevAssertions;
+ double durationInSeconds;
+};
+
+} // end namespace Catch
+
+// #included from: catch_timer.h
+#define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED
+
+#ifdef CATCH_PLATFORM_WINDOWS
+typedef unsigned long long uint64_t;
+#else
+#include <stdint.h>
+#endif
+
+namespace Catch {
+
+class Timer
+{
+ public:
+ Timer() : m_ticks(0) {}
+ void start();
+ unsigned int getElapsedMicroseconds() const;
+ unsigned int getElapsedMilliseconds() const;
+ double getElapsedSeconds() const;
+
+ private:
+ uint64_t m_ticks;
+};
+
+} // namespace Catch
+
+#include <string>
+
+namespace Catch {
+
+class Section : NonCopyable
+{
+ public:
+ Section(SectionInfo const& info);
+ ~Section();
+
+ // This indicates whether the section should be executed or not
+ operator bool() const;
+
+ private:
+ SectionInfo m_info;
+
+ std::string m_name;
+ Counts m_assertions;
+ bool m_sectionIncluded;
+ Timer m_timer;
+};
+
+} // end namespace Catch
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+#define INTERNAL_CATCH_SECTION(...) \
+ if (Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME(catch_internal_Section) = Catch::SectionInfo(CATCH_INTERNAL_LINEINFO, __VA_ARGS__))
+#else
+#define INTERNAL_CATCH_SECTION(name, desc) \
+ if (Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME(catch_internal_Section) = Catch::SectionInfo(CATCH_INTERNAL_LINEINFO, name, desc))
+#endif
+
+// #included from: internal/catch_generators.hpp
+#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
+
+#include <iterator>
+#include <stdlib.h>
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+template <typename T>
+struct IGenerator
+{
+ virtual ~IGenerator() {}
+ virtual T getValue(std::size_t index) const = 0;
+ virtual std::size_t size() const = 0;
+};
+
+template <typename T>
+class BetweenGenerator : public IGenerator<T>
+{
+ public:
+ BetweenGenerator(T from, T to) : m_from(from), m_to(to) {}
+
+ virtual T getValue(std::size_t index) const
+ {
+ return m_from + static_cast<int>(index);
+ }
+
+ virtual std::size_t size() const
+ {
+ return static_cast<std::size_t>(1 + m_to - m_from);
+ }
+
+ private:
+ T m_from;
+ T m_to;
+};
+
+template <typename T>
+class ValuesGenerator : public IGenerator<T>
+{
+ public:
+ ValuesGenerator() {}
+
+ void add(T value)
+ {
+ m_values.push_back(value);
+ }
+
+ virtual T getValue(std::size_t index) const
+ {
+ return m_values[index];
+ }
+
+ virtual std::size_t size() const
+ {
+ return m_values.size();
+ }
+
+ private:
+ std::vector<T> m_values;
+};
+
+template <typename T>
+class CompositeGenerator
+{
+ public:
+ CompositeGenerator() : m_totalSize(0) {}
+
+ // *** Move semantics, similar to auto_ptr ***
+ CompositeGenerator(CompositeGenerator& other)
+ : m_fileInfo(other.m_fileInfo),
+ m_totalSize(0)
+ {
+ move(other);
+ }
+
+ CompositeGenerator& setFileInfo(const char* fileInfo)
+ {
+ m_fileInfo = fileInfo;
+ return *this;
+ }
+
+ ~CompositeGenerator()
+ {
+ deleteAll(m_composed);
+ }
+
+ operator T() const
+ {
+ size_t overallIndex = getCurrentContext().getGeneratorIndex(m_fileInfo, m_totalSize);
+
+ typename std::vector<const IGenerator<T>*>::const_iterator it = m_composed.begin();
+ typename std::vector<const IGenerator<T>*>::const_iterator itEnd = m_composed.end();
+ for (size_t index = 0; it != itEnd; ++it)
+ {
+ const IGenerator<T>* generator = *it;
+ if (overallIndex >= index && overallIndex < index + generator->size())
+ {
+ return generator->getValue(overallIndex - index);
+ }
+ index += generator->size();
+ }
+ CATCH_INTERNAL_ERROR("Indexed past end of generated range");
+ return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so
+ }
+
+ void add(const IGenerator<T>* generator)
+ {
+ m_totalSize += generator->size();
+ m_composed.push_back(generator);
+ }
+
+ CompositeGenerator& then(CompositeGenerator& other)
+ {
+ move(other);
+ return *this;
+ }
+
+ CompositeGenerator& then(T value)
+ {
+ ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+ valuesGen->add(value);
+ add(valuesGen);
+ return *this;
+ }
+
+ private:
+ void move(CompositeGenerator& other)
+ {
+ std::copy(other.m_composed.begin(), other.m_composed.end(), std::back_inserter(m_composed));
+ m_totalSize += other.m_totalSize;
+ other.m_composed.clear();
+ }
+
+ std::vector<const IGenerator<T>*> m_composed;
+ std::string m_fileInfo;
+ size_t m_totalSize;
+};
+
+namespace Generators {
+template <typename T>
+CompositeGenerator<T> between(T from, T to)
+{
+ CompositeGenerator<T> generators;
+ generators.add(new BetweenGenerator<T>(from, to));
+ return generators;
+}
+
+template <typename T>
+CompositeGenerator<T> values(T val1, T val2)
+{
+ CompositeGenerator<T> generators;
+ ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+ valuesGen->add(val1);
+ valuesGen->add(val2);
+ generators.add(valuesGen);
+ return generators;
+}
+
+template <typename T>
+CompositeGenerator<T> values(T val1, T val2, T val3)
+{
+ CompositeGenerator<T> generators;
+ ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+ valuesGen->add(val1);
+ valuesGen->add(val2);
+ valuesGen->add(val3);
+ generators.add(valuesGen);
+ return generators;
+}
+
+template <typename T>
+CompositeGenerator<T> values(T val1, T val2, T val3, T val4)
+{
+ CompositeGenerator<T> generators;
+ ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+ valuesGen->add(val1);
+ valuesGen->add(val2);
+ valuesGen->add(val3);
+ valuesGen->add(val4);
+ generators.add(valuesGen);
+ return generators;
+}
+
+} // end namespace Generators
+
+using namespace Generators;
+
+} // end namespace Catch
+
+#define INTERNAL_CATCH_LINESTR2(line) #line
+#define INTERNAL_CATCH_LINESTR(line) INTERNAL_CATCH_LINESTR2(line)
+
+#define INTERNAL_CATCH_GENERATE(expr) expr.setFileInfo(__FILE__ "(" INTERNAL_CATCH_LINESTR(__LINE__) ")")
+
+// #included from: internal/catch_interfaces_exception.h
+#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED
+
+#include <string>
+#include <vector>
+
+// #included from: catch_interfaces_registry_hub.h
+#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+class TestCase;
+struct ITestCaseRegistry;
+struct IExceptionTranslatorRegistry;
+struct IExceptionTranslator;
+struct IReporterRegistry;
+struct IReporterFactory;
+
+struct IRegistryHub
+{
+ virtual ~IRegistryHub();
+
+ virtual IReporterRegistry const& getReporterRegistry() const = 0;
+ virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
+ virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0;
+};
+
+struct IMutableRegistryHub
+{
+ virtual ~IMutableRegistryHub();
+ virtual void registerReporter(std::string const& name, Ptr<IReporterFactory> const& factory) = 0;
+ virtual void registerListener(Ptr<IReporterFactory> const& factory) = 0;
+ virtual void registerTest(TestCase const& testInfo) = 0;
+ virtual void registerTranslator(const IExceptionTranslator* translator) = 0;
+};
+
+IRegistryHub& getRegistryHub();
+IMutableRegistryHub& getMutableRegistryHub();
+void cleanUp();
+std::string translateActiveException();
+}
+
+namespace Catch {
+
+typedef std::string (*exceptionTranslateFunction)();
+
+struct IExceptionTranslator;
+typedef std::vector<const IExceptionTranslator*> ExceptionTranslators;
+
+struct IExceptionTranslator
+{
+ virtual ~IExceptionTranslator();
+ virtual std::string translate(ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd) const = 0;
+};
+
+struct IExceptionTranslatorRegistry
+{
+ virtual ~IExceptionTranslatorRegistry();
+
+ virtual std::string translateActiveException() const = 0;
+};
+
+class ExceptionTranslatorRegistrar
+{
+ template <typename T>
+ class ExceptionTranslator : public IExceptionTranslator
+ {
+ public:
+ ExceptionTranslator(std::string (*translateFunction)(T&))
+ : m_translateFunction(translateFunction)
+ {
+ }
+
+ virtual std::string translate(ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd) const CATCH_OVERRIDE
+ {
+ try
+ {
+ if (it == itEnd)
+ throw;
+ else
+ return (*it)->translate(it + 1, itEnd);
+ }
+ catch (T& ex)
+ {
+ return m_translateFunction(ex);
+ }
+ }
+
+ protected:
+ std::string (*m_translateFunction)(T&);
+ };
+
+ public:
+ template <typename T>
+ ExceptionTranslatorRegistrar(std::string (*translateFunction)(T&))
+ {
+ getMutableRegistryHub().registerTranslator(new ExceptionTranslator<T>(translateFunction));
+ }
+};
+}
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TRANSLATE_EXCEPTION(signature) \
+ static std::string INTERNAL_CATCH_UNIQUE_NAME(catch_internal_ExceptionTranslator)(signature); \
+ namespace { \
+ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME(catch_internal_ExceptionRegistrar)(&INTERNAL_CATCH_UNIQUE_NAME(catch_internal_ExceptionTranslator)); \
+ } \
+ static std::string INTERNAL_CATCH_UNIQUE_NAME(catch_internal_ExceptionTranslator)(signature)
+
+// #included from: internal/catch_approx.hpp
+#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED
+
+#include <cmath>
+#include <limits>
+
+namespace Catch {
+namespace Detail {
+
+class Approx
+{
+ public:
+ explicit Approx(double value)
+ : m_epsilon(std::numeric_limits<float>::epsilon() * 100),
+ m_scale(1.0),
+ m_value(value)
+ {
+ }
+
+ Approx(Approx const& other)
+ : m_epsilon(other.m_epsilon),
+ m_scale(other.m_scale),
+ m_value(other.m_value)
+ {
+ }
+
+ static Approx custom()
+ {
+ return Approx(0);
+ }
+
+ Approx operator()(double value)
+ {
+ Approx approx(value);
+ approx.epsilon(m_epsilon);
+ approx.scale(m_scale);
+ return approx;
+ }
+
+ friend bool operator==(double lhs, Approx const& rhs)
+ {
+ // Thanks to Richard Harris for his help refining this formula
+ return fabs(lhs - rhs.m_value) < rhs.m_epsilon * (rhs.m_scale + (std::max)(fabs(lhs), fabs(rhs.m_value)));
+ }
+
+ friend bool operator==(Approx const& lhs, double rhs)
+ {
+ return operator==(rhs, lhs);
+ }
+
+ friend bool operator!=(double lhs, Approx const& rhs)
+ {
+ return !operator==(lhs, rhs);
+ }
+
+ friend bool operator!=(Approx const& lhs, double rhs)
+ {
+ return !operator==(rhs, lhs);
+ }
+
+ Approx& epsilon(double newEpsilon)
+ {
+ m_epsilon = newEpsilon;
+ return *this;
+ }
+
+ Approx& scale(double newScale)
+ {
+ m_scale = newScale;
+ return *this;
+ }
+
+ std::string toString() const
+ {
+ std::ostringstream oss;
+ oss << "Approx( " << Catch::toString(m_value) << " )";
+ return oss.str();
+ }
+
+ private:
+ double m_epsilon;
+ double m_scale;
+ double m_value;
+};
+}
+
+template <>
+inline std::string toString<Detail::Approx>(Detail::Approx const& value)
+{
+ return value.toString();
+}
+
+} // end namespace Catch
+
+// #included from: internal/catch_interfaces_tag_alias_registry.h
+#define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED
+
+// #included from: catch_tag_alias.h
+#define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+struct TagAlias
+{
+ TagAlias(std::string _tag, SourceLineInfo _lineInfo) : tag(_tag), lineInfo(_lineInfo) {}
+
+ std::string tag;
+ SourceLineInfo lineInfo;
+};
+
+struct RegistrarForTagAliases
+{
+ RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo);
+};
+
+} // end namespace Catch
+
+#define CATCH_REGISTER_TAG_ALIAS(alias, spec) \
+ namespace { \
+ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME(AutoRegisterTagAlias)(alias, spec, CATCH_INTERNAL_LINEINFO); \
+ }
+// #included from: catch_option.hpp
+#define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED
+
+namespace Catch {
+
+// An optional type
+template <typename T>
+class Option
+{
+ public:
+ Option() : nullableValue(CATCH_NULL) {}
+ Option(T const& _value)
+ : nullableValue(new (storage) T(_value))
+ {
+ }
+ Option(Option const& _other)
+ : nullableValue(_other ? new (storage) T(*_other) : CATCH_NULL)
+ {
+ }
+
+ ~Option()
+ {
+ reset();
+ }
+
+ Option& operator=(Option const& _other)
+ {
+ if (&_other != this)
+ {
+ reset();
+ if (_other)
+ nullableValue = new (storage) T(*_other);
+ }
+ return *this;
+ }
+ Option& operator=(T const& _value)
+ {
+ reset();
+ nullableValue = new (storage) T(_value);
+ return *this;
+ }
+
+ void reset()
+ {
+ if (nullableValue)
+ nullableValue->~T();
+ nullableValue = CATCH_NULL;
+ }
+
+ T& operator*() { return *nullableValue; }
+ T const& operator*() const { return *nullableValue; }
+ T* operator->() { return nullableValue; }
+ const T* operator->() const { return nullableValue; }
+
+ T valueOr(T const& defaultValue) const
+ {
+ return nullableValue ? *nullableValue : defaultValue;
+ }
+
+ bool some() const { return nullableValue != CATCH_NULL; }
+ bool none() const { return nullableValue == CATCH_NULL; }
+
+ bool operator!() const { return nullableValue == CATCH_NULL; }
+ operator SafeBool::type() const
+ {
+ return SafeBool::makeSafe(some());
+ }
+
+ private:
+ T* nullableValue;
+ char storage[sizeof(T)];
+};
+
+} // end namespace Catch
+
+namespace Catch {
+
+struct ITagAliasRegistry
+{
+ virtual ~ITagAliasRegistry();
+ virtual Option<TagAlias> find(std::string const& alias) const = 0;
+ virtual std::string expandAliases(std::string const& unexpandedTestSpec) const = 0;
+
+ static ITagAliasRegistry const& get();
+};
+
+} // end namespace Catch
+
+// These files are included here so the single_include script doesn't put them
+// in the conditionally compiled sections
+// #included from: internal/catch_test_case_info.h
+#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED
+
+#include <set>
+#include <string>
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+namespace Catch {
+
+struct ITestCase;
+
+struct TestCaseInfo
+{
+ enum SpecialProperties
+ {
+ None = 0,
+ IsHidden = 1 << 1,
+ ShouldFail = 1 << 2,
+ MayFail = 1 << 3,
+ Throws = 1 << 4
+ };
+
+ TestCaseInfo(std::string const& _name,
+ std::string const& _className,
+ std::string const& _description,
+ std::set<std::string> const& _tags,
+ SourceLineInfo const& _lineInfo);
+
+ TestCaseInfo(TestCaseInfo const& other);
+
+ friend void setTags(TestCaseInfo& testCaseInfo, std::set<std::string> const& tags);
+
+ bool isHidden() const;
+ bool throws() const;
+ bool okToFail() const;
+ bool expectedToFail() const;
+
+ std::string name;
+ std::string className;
+ std::string description;
+ std::set<std::string> tags;
+ std::set<std::string> lcaseTags;
+ std::string tagsAsString;
+ SourceLineInfo lineInfo;
+ SpecialProperties properties;
+};
+
+class TestCase : public TestCaseInfo
+{
+ public:
+ TestCase(ITestCase* testCase, TestCaseInfo const& info);
+ TestCase(TestCase const& other);
+
+ TestCase withName(std::string const& _newName) const;
+
+ void invoke() const;
+
+ TestCaseInfo const& getTestCaseInfo() const;
+
+ void swap(TestCase& other);
+ bool operator==(TestCase const& other) const;
+ bool operator<(TestCase const& other) const;
+ TestCase& operator=(TestCase const& other);
+
+ private:
+ Ptr<ITestCase> test;
+};
+
+TestCase makeTestCase(ITestCase* testCase,
+ std::string const& className,
+ std::string const& name,
+ std::string const& description,
+ SourceLineInfo const& lineInfo);
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#ifdef __OBJC__
+// #included from: internal/catch_objc.hpp
+#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED
+
+#import <objc/runtime.h>
+
+#include <string>
+
+// NB. Any general catch headers included here must be included
+// in catch.hpp first to make sure they are included by the single
+// header for non obj-usage
+
+///////////////////////////////////////////////////////////////////////////////
+// This protocol is really only here for (self) documenting purposes, since
+// all its methods are optional.
+ at protocol OcFixture
+
+ at optional
+
+- (void)setUp;
+- (void)tearDown;
+
+ at end
+
+namespace Catch {
+
+class OcMethod : public SharedImpl<ITestCase>
+{
+
+ public:
+ OcMethod(Class cls, SEL sel) : m_cls(cls), m_sel(sel) {}
+
+ virtual void invoke() const
+ {
+ id obj = [[m_cls alloc] init];
+
+ performOptionalSelector(obj, @selector(setUp));
+ performOptionalSelector(obj, m_sel);
+ performOptionalSelector(obj, @selector(tearDown));
+
+ arcSafeRelease(obj);
+ }
+
+ private:
+ virtual ~OcMethod() {}
+
+ Class m_cls;
+ SEL m_sel;
+};
+
+namespace Detail {
+
+inline std::string getAnnotation(Class cls,
+ std::string const& annotationName,
+ std::string const& testCaseName)
+{
+ NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()];
+ SEL sel = NSSelectorFromString(selStr);
+ arcSafeRelease(selStr);
+ id value = performOptionalSelector(cls, sel);
+ if (value)
+ return [(NSString*)value UTF8String];
+ return "";
+}
+}
+
+inline size_t registerTestMethods()
+{
+ size_t noTestMethods = 0;
+ int noClasses = objc_getClassList(CATCH_NULL, 0);
+
+ Class* classes = (CATCH_UNSAFE_UNRETAINED Class*)malloc(sizeof(Class) * noClasses);
+ objc_getClassList(classes, noClasses);
+
+ for (int c = 0; c < noClasses; c++)
+ {
+ Class cls = classes[c];
+ {
+ u_int count;
+ Method* methods = class_copyMethodList(cls, &count);
+ for (u_int m = 0; m < count; m++)
+ {
+ SEL selector = method_getName(methods[m]);
+ std::string methodName = sel_getName(selector);
+ if (startsWith(methodName, "Catch_TestCase_"))
+ {
+ std::string testCaseName = methodName.substr(15);
+ std::string name = Detail::getAnnotation(cls, "Name", testCaseName);
+ std::string desc = Detail::getAnnotation(cls, "Description", testCaseName);
+ const char* className = class_getName(cls);
+
+ getMutableRegistryHub().registerTest(makeTestCase(new OcMethod(cls, selector), className, name.c_str(), desc.c_str(), SourceLineInfo()));
+ noTestMethods++;
+ }
+ }
+ free(methods);
+ }
+ }
+ return noTestMethods;
+}
+
+namespace Matchers {
+namespace Impl {
+namespace NSStringMatchers {
+
+template <typename MatcherT>
+struct StringHolder : MatcherImpl<MatcherT, NSString*>
+{
+ StringHolder(NSString* substr) : m_substr([substr copy]) {}
+ StringHolder(StringHolder const& other) : m_substr([other.m_substr copy]) {}
+ StringHolder()
+ {
+ arcSafeRelease(m_substr);
+ }
+
+ NSString* m_substr;
+};
+
+struct Equals : StringHolder<Equals>
+{
+ Equals(NSString* substr) : StringHolder(substr) {}
+
+ virtual bool match(ExpressionType const& str) const
+ {
+ return (str != nil || m_substr == nil) &&
+ [str isEqualToString:m_substr];
+ }
+
+ virtual std::string toString() const
+ {
+ return "equals string: " + Catch::toString(m_substr);
+ }
+};
+
+struct Contains : StringHolder<Contains>
+{
+ Contains(NSString* substr) : StringHolder(substr) {}
+
+ virtual bool match(ExpressionType const& str) const
+ {
+ return (str != nil || m_substr == nil) &&
+ [str rangeOfString:m_substr].location != NSNotFound;
+ }
+
+ virtual std::string toString() const
+ {
+ return "contains string: " + Catch::toString(m_substr);
+ }
+};
+
+struct StartsWith : StringHolder<StartsWith>
+{
+ StartsWith(NSString* substr) : StringHolder(substr) {}
+
+ virtual bool match(ExpressionType const& str) const
+ {
+ return (str != nil || m_substr == nil) &&
+ [str rangeOfString:m_substr].location == 0;
+ }
+
+ virtual std::string toString() const
+ {
+ return "starts with: " + Catch::toString(m_substr);
+ }
+};
+struct EndsWith : StringHolder<EndsWith>
+{
+ EndsWith(NSString* substr) : StringHolder(substr) {}
+
+ virtual bool match(ExpressionType const& str) const
+ {
+ return (str != nil || m_substr == nil) &&
+ [str rangeOfString:m_substr].location == [str length] - [m_substr length];
+ }
+
+ virtual std::string toString() const
+ {
+ return "ends with: " + Catch::toString(m_substr);
+ }
+};
+
+} // namespace NSStringMatchers
+} // namespace Impl
+
+inline Impl::NSStringMatchers::Equals
+Equals(NSString* substr) { return Impl::NSStringMatchers::Equals(substr); }
+
+inline Impl::NSStringMatchers::Contains
+Contains(NSString* substr) { return Impl::NSStringMatchers::Contains(substr); }
+
+inline Impl::NSStringMatchers::StartsWith
+StartsWith(NSString* substr) { return Impl::NSStringMatchers::StartsWith(substr); }
+
+inline Impl::NSStringMatchers::EndsWith
+EndsWith(NSString* substr) { return Impl::NSStringMatchers::EndsWith(substr); }
+
+} // namespace Matchers
+
+using namespace Matchers;
+
+} // namespace Catch
+
+///////////////////////////////////////////////////////////////////////////////
+#define OC_TEST_CASE(name, desc) \
+ +(NSString*)INTERNAL_CATCH_UNIQUE_NAME(Catch_Name_test) \
+ { \
+ return @name; \
+ } \
+ +(NSString*)INTERNAL_CATCH_UNIQUE_NAME(Catch_Description_test) \
+ { \
+ return @desc; \
+ } \
+ -(void)INTERNAL_CATCH_UNIQUE_NAME(Catch_TestCase_test)
+
+#endif
+
+#ifdef CATCH_IMPL
+// #included from: internal/catch_impl.hpp
+#define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED
+
+// Collect all the implementation files together here
+// These are the equivalent of what would usually be cpp files
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wweak-vtables"
+#endif
+
+// #included from: ../catch_session.hpp
+#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED
+
+// #included from: internal/catch_commandline.hpp
+#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED
+
+// #included from: catch_config.hpp
+#define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED
+
+// #included from: catch_test_spec_parser.hpp
+#define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+// #included from: catch_test_spec.hpp
+#define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+// #included from: catch_wildcard_pattern.hpp
+#define TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED
+
+namespace Catch {
+class WildcardPattern
+{
+ enum WildcardPosition
+ {
+ NoWildcard = 0,
+ WildcardAtStart = 1,
+ WildcardAtEnd = 2,
+ WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd
+ };
+
+ public:
+ WildcardPattern(std::string const& pattern, CaseSensitive::Choice caseSensitivity)
+ : m_caseSensitivity(caseSensitivity),
+ m_wildcard(NoWildcard),
+ m_pattern(adjustCase(pattern))
+ {
+ if (startsWith(m_pattern, "*"))
+ {
+ m_pattern = m_pattern.substr(1);
+ m_wildcard = WildcardAtStart;
+ }
+ if (endsWith(m_pattern, "*"))
+ {
+ m_pattern = m_pattern.substr(0, m_pattern.size() - 1);
+ m_wildcard = static_cast<WildcardPosition>(m_wildcard | WildcardAtEnd);
+ }
+ }
+ virtual ~WildcardPattern();
+ virtual bool matches(std::string const& str) const
+ {
+ switch (m_wildcard)
+ {
+ case NoWildcard:
+ return m_pattern == adjustCase(str);
+ case WildcardAtStart:
+ return endsWith(adjustCase(str), m_pattern);
+ case WildcardAtEnd:
+ return startsWith(adjustCase(str), m_pattern);
+ case WildcardAtBothEnds:
+ return contains(adjustCase(str), m_pattern);
+ }
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunreachable-code"
+#endif
+ throw std::logic_error("Unknown enum");
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+ }
+
+ private:
+ std::string adjustCase(std::string const& str) const
+ {
+ return m_caseSensitivity == CaseSensitive::No ? toLower(str) : str;
+ }
+ CaseSensitive::Choice m_caseSensitivity;
+ WildcardPosition m_wildcard;
+ std::string m_pattern;
+};
+}
+
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+class TestSpec
+{
+ struct Pattern : SharedImpl<>
+ {
+ virtual ~Pattern();
+ virtual bool matches(TestCaseInfo const& testCase) const = 0;
+ };
+ class NamePattern : public Pattern
+ {
+ public:
+ NamePattern(std::string const& name)
+ : m_wildcardPattern(toLower(name), CaseSensitive::No)
+ {
+ }
+ virtual ~NamePattern();
+ virtual bool matches(TestCaseInfo const& testCase) const
+ {
+ return m_wildcardPattern.matches(toLower(testCase.name));
+ }
+
+ private:
+ WildcardPattern m_wildcardPattern;
+ };
+
+ class TagPattern : public Pattern
+ {
+ public:
+ TagPattern(std::string const& tag) : m_tag(toLower(tag)) {}
+ virtual ~TagPattern();
+ virtual bool matches(TestCaseInfo const& testCase) const
+ {
+ return testCase.lcaseTags.find(m_tag) != testCase.lcaseTags.end();
+ }
+
+ private:
+ std::string m_tag;
+ };
+
+ class ExcludedPattern : public Pattern
+ {
+ public:
+ ExcludedPattern(Ptr<Pattern> const& underlyingPattern) : m_underlyingPattern(underlyingPattern) {}
+ virtual ~ExcludedPattern();
+ virtual bool matches(TestCaseInfo const& testCase) const { return !m_underlyingPattern->matches(testCase); }
+ private:
+ Ptr<Pattern> m_underlyingPattern;
+ };
+
+ struct Filter
+ {
+ std::vector<Ptr<Pattern>> m_patterns;
+
+ bool matches(TestCaseInfo const& testCase) const
+ {
+ // All patterns in a filter must match for the filter to be a match
+ for (std::vector<Ptr<Pattern>>::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it)
+ if (!(*it)->matches(testCase))
+ return false;
+ return true;
+ }
+ };
+
+ public:
+ bool hasFilters() const
+ {
+ return !m_filters.empty();
+ }
+ bool matches(TestCaseInfo const& testCase) const
+ {
+ // A TestSpec matches if any filter matches
+ for (std::vector<Filter>::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it)
+ if (it->matches(testCase))
+ return true;
+ return false;
+ }
+
+ private:
+ std::vector<Filter> m_filters;
+
+ friend class TestSpecParser;
+};
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+namespace Catch {
+
+class TestSpecParser
+{
+ enum Mode
+ {
+ None,
+ Name,
+ QuotedName,
+ Tag
+ };
+ Mode m_mode;
+ bool m_exclusion;
+ std::size_t m_start, m_pos;
+ std::string m_arg;
+ TestSpec::Filter m_currentFilter;
+ TestSpec m_testSpec;
+ ITagAliasRegistry const* m_tagAliases;
+
+ public:
+ TestSpecParser(ITagAliasRegistry const& tagAliases) : m_tagAliases(&tagAliases) {}
+
+ TestSpecParser& parse(std::string const& arg)
+ {
+ m_mode = None;
+ m_exclusion = false;
+ m_start = std::string::npos;
+ m_arg = m_tagAliases->expandAliases(arg);
+ for (m_pos = 0; m_pos < m_arg.size(); ++m_pos)
+ visitChar(m_arg[m_pos]);
+ if (m_mode == Name)
+ addPattern<TestSpec::NamePattern>();
+ return *this;
+ }
+ TestSpec testSpec()
+ {
+ addFilter();
+ return m_testSpec;
+ }
+
+ private:
+ void visitChar(char c)
+ {
+ if (m_mode == None)
+ {
+ switch (c)
+ {
+ case ' ':
+ return;
+ case '~':
+ m_exclusion = true;
+ return;
+ case '[':
+ return startNewMode(Tag, ++m_pos);
+ case '"':
+ return startNewMode(QuotedName, ++m_pos);
+ default:
+ startNewMode(Name, m_pos);
+ break;
+ }
+ }
+ if (m_mode == Name)
+ {
+ if (c == ',')
+ {
+ addPattern<TestSpec::NamePattern>();
+ addFilter();
+ }
+ else if (c == '[')
+ {
+ if (subString() == "exclude:")
+ m_exclusion = true;
+ else
+ addPattern<TestSpec::NamePattern>();
+ startNewMode(Tag, ++m_pos);
+ }
+ }
+ else if (m_mode == QuotedName && c == '"')
+ addPattern<TestSpec::NamePattern>();
+ else if (m_mode == Tag && c == ']')
+ addPattern<TestSpec::TagPattern>();
+ }
+ void startNewMode(Mode mode, std::size_t start)
+ {
+ m_mode = mode;
+ m_start = start;
+ }
+ std::string subString() const { return m_arg.substr(m_start, m_pos - m_start); }
+ template <typename T>
+ void addPattern()
+ {
+ std::string token = subString();
+ if (startsWith(token, "exclude:"))
+ {
+ m_exclusion = true;
+ token = token.substr(8);
+ }
+ if (!token.empty())
+ {
+ Ptr<TestSpec::Pattern> pattern = new T(token);
+ if (m_exclusion)
+ pattern = new TestSpec::ExcludedPattern(pattern);
+ m_currentFilter.m_patterns.push_back(pattern);
+ }
+ m_exclusion = false;
+ m_mode = None;
+ }
+ void addFilter()
+ {
+ if (!m_currentFilter.m_patterns.empty())
+ {
+ m_testSpec.m_filters.push_back(m_currentFilter);
+ m_currentFilter = TestSpec::Filter();
+ }
+ }
+};
+inline TestSpec parseTestSpec(std::string const& arg)
+{
+ return TestSpecParser(ITagAliasRegistry::get()).parse(arg).testSpec();
+}
+
+} // namespace Catch
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+// #included from: catch_interfaces_config.h
+#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+struct Verbosity
+{
+ enum Level
+ {
+ NoOutput = 0,
+ Quiet,
+ Normal
+ };
+};
+
+struct WarnAbout
+{
+ enum What
+ {
+ Nothing = 0x00,
+ NoAssertions = 0x01
+ };
+};
+
+struct ShowDurations
+{
+ enum OrNot
+ {
+ DefaultForReporter,
+ Always,
+ Never
+ };
+};
+struct RunTests
+{
+ enum InWhatOrder
+ {
+ InDeclarationOrder,
+ InLexicographicalOrder,
+ InRandomOrder
+ };
+};
+
+class TestSpec;
+
+struct IConfig : IShared
+{
+
+ virtual ~IConfig();
+
+ virtual bool allowThrows() const = 0;
+ virtual std::ostream& stream() const = 0;
+ virtual std::string name() const = 0;
+ virtual bool includeSuccessfulResults() const = 0;
+ virtual bool shouldDebugBreak() const = 0;
+ virtual bool warnAboutMissingAssertions() const = 0;
+ virtual int abortAfter() const = 0;
+ virtual bool showInvisibles() const = 0;
+ virtual ShowDurations::OrNot showDurations() const = 0;
+ virtual TestSpec const& testSpec() const = 0;
+ virtual RunTests::InWhatOrder runOrder() const = 0;
+ virtual unsigned int rngSeed() const = 0;
+ virtual bool forceColour() const = 0;
+};
+}
+
+// #included from: catch_stream.h
+#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
+
+// #included from: catch_streambuf.h
+#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED
+
+#include <streambuf>
+
+namespace Catch {
+
+class StreamBufBase : public std::streambuf
+{
+ public:
+ virtual ~StreamBufBase() CATCH_NOEXCEPT;
+};
+}
+
+#include <fstream>
+#include <ostream>
+#include <streambuf>
+
+namespace Catch {
+
+std::ostream& cout();
+std::ostream& cerr();
+
+struct IStream
+{
+ virtual ~IStream() CATCH_NOEXCEPT;
+ virtual std::ostream& stream() const = 0;
+};
+
+class FileStream : public IStream
+{
+ mutable std::ofstream m_ofs;
+
+ public:
+ FileStream(std::string const& filename);
+ virtual ~FileStream() CATCH_NOEXCEPT;
+
+ public: // IStream
+ virtual std::ostream& stream() const CATCH_OVERRIDE;
+};
+
+class CoutStream : public IStream
+{
+ mutable std::ostream m_os;
+
+ public:
+ CoutStream();
+ virtual ~CoutStream() CATCH_NOEXCEPT;
+
+ public: // IStream
+ virtual std::ostream& stream() const CATCH_OVERRIDE;
+};
+
+class DebugOutStream : public IStream
+{
+ std::auto_ptr<StreamBufBase> m_streamBuf;
+ mutable std::ostream m_os;
+
+ public:
+ DebugOutStream();
+ virtual ~DebugOutStream() CATCH_NOEXCEPT;
+
+ public: // IStream
+ virtual std::ostream& stream() const CATCH_OVERRIDE;
+};
+}
+
+#include <ctime>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <vector>
+
+#ifndef CATCH_CONFIG_CONSOLE_WIDTH
+#define CATCH_CONFIG_CONSOLE_WIDTH 80
+#endif
+
+namespace Catch {
+
+struct ConfigData
+{
+
+ ConfigData()
+ : listTests(false),
+ listTags(false),
+ listReporters(false),
+ listTestNamesOnly(false),
+ showSuccessfulTests(false),
+ shouldDebugBreak(false),
+ noThrow(false),
+ showHelp(false),
+ showInvisibles(false),
+ forceColour(false),
+ filenamesAsTags(false),
+ abortAfter(-1),
+ rngSeed(0),
+ verbosity(Verbosity::Normal),
+ warnings(WarnAbout::Nothing),
+ showDurations(ShowDurations::DefaultForReporter),
+ runOrder(RunTests::InDeclarationOrder)
+ {
+ }
+
+ bool listTests;
+ bool listTags;
+ bool listReporters;
+ bool listTestNamesOnly;
+
+ bool showSuccessfulTests;
+ bool shouldDebugBreak;
+ bool noThrow;
+ bool showHelp;
+ bool showInvisibles;
+ bool forceColour;
+ bool filenamesAsTags;
+
+ int abortAfter;
+ unsigned int rngSeed;
+
+ Verbosity::Level verbosity;
+ WarnAbout::What warnings;
+ ShowDurations::OrNot showDurations;
+ RunTests::InWhatOrder runOrder;
+
+ std::string outputFilename;
+ std::string name;
+ std::string processName;
+
+ std::vector<std::string> reporterNames;
+ std::vector<std::string> testsOrTags;
+};
+
+class Config : public SharedImpl<IConfig>
+{
+ private:
+ Config(Config const& other);
+ Config& operator=(Config const& other);
+ virtual void dummy();
+
+ public:
+ Config()
+ {
+ }
+
+ Config(ConfigData const& data)
+ : m_data(data),
+ m_stream(openStream())
+ {
+ if (!data.testsOrTags.empty())
+ {
+ TestSpecParser parser(ITagAliasRegistry::get());
+ for (std::size_t i = 0; i < data.testsOrTags.size(); ++i)
+ parser.parse(data.testsOrTags[i]);
+ m_testSpec = parser.testSpec();
+ }
+ }
+
+ virtual ~Config()
+ {
+ }
+
+ std::string const& getFilename() const
+ {
+ return m_data.outputFilename;
+ }
+
+ bool listTests() const { return m_data.listTests; }
+ bool listTestNamesOnly() const { return m_data.listTestNamesOnly; }
+ bool listTags() const { return m_data.listTags; }
+ bool listReporters() const { return m_data.listReporters; }
+
+ std::string getProcessName() const { return m_data.processName; }
+
+ bool shouldDebugBreak() const { return m_data.shouldDebugBreak; }
+
+ std::vector<std::string> getReporterNames() const { return m_data.reporterNames; }
+
+ int abortAfter() const { return m_data.abortAfter; }
+
+ TestSpec const& testSpec() const { return m_testSpec; }
+
+ bool showHelp() const { return m_data.showHelp; }
+ bool showInvisibles() const { return m_data.showInvisibles; }
+
+ // IConfig interface
+ virtual bool allowThrows() const { return !m_data.noThrow; }
+ virtual std::ostream& stream() const { return m_stream->stream(); }
+ virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; }
+ virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; }
+ virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; }
+ virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; }
+ virtual RunTests::InWhatOrder runOrder() const { return m_data.runOrder; }
+ virtual unsigned int rngSeed() const { return m_data.rngSeed; }
+ virtual bool forceColour() const { return m_data.forceColour; }
+
+ private:
+ IStream const* openStream()
+ {
+ if (m_data.outputFilename.empty())
+ return new CoutStream();
+ else if (m_data.outputFilename[0] == '%')
+ {
+ if (m_data.outputFilename == "%debug")
+ return new DebugOutStream();
+ else
+ throw std::domain_error("Unrecognised stream: " + m_data.outputFilename);
+ }
+ else
+ return new FileStream(m_data.outputFilename);
+ }
+ ConfigData m_data;
+
+ std::auto_ptr<IStream const> m_stream;
+ TestSpec m_testSpec;
+};
+
+} // end namespace Catch
+
+// #included from: catch_clara.h
+#define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED
+
+// Use Catch's value for console width (store Clara's off to the side, if present)
+#ifdef CLARA_CONFIG_CONSOLE_WIDTH
+#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH
+#undef CLARA_CONFIG_CONSOLE_WIDTH
+#endif
+#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH
+
+// Declare Clara inside the Catch namespace
+#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch {
+// #included from: ../external/clara.h
+
+// Only use header guard if we are not using an outer namespace
+#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE)
+
+#ifndef STITCH_CLARA_OPEN_NAMESPACE
+#define TWOBLUECUBES_CLARA_H_INCLUDED
+#define STITCH_CLARA_OPEN_NAMESPACE
+#define STITCH_CLARA_CLOSE_NAMESPACE
+#else
+#define STITCH_CLARA_CLOSE_NAMESPACE }
+#endif
+
+#define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE
+
+// ----------- #included from tbc_text_format.h -----------
+
+// Only use header guard if we are not using an outer namespace
+#if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE)
+#ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+#define TBC_TEXT_FORMAT_H_INCLUDED
+#endif
+
+#include <sstream>
+#include <string>
+#include <vector>
+
+// Use optional outer namespace
+#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE {
+#endif
+
+namespace Tbc {
+
+#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH
+const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH;
+#else
+const unsigned int consoleWidth = 80;
+#endif
+
+struct TextAttributes
+{
+ TextAttributes()
+ : initialIndent(std::string::npos),
+ indent(0),
+ width(consoleWidth - 1),
+ tabChar('\t')
+ {
+ }
+
+ TextAttributes& setInitialIndent(std::size_t _value)
+ {
+ initialIndent = _value;
+ return *this;
+ }
+ TextAttributes& setIndent(std::size_t _value)
+ {
+ indent = _value;
+ return *this;
+ }
+ TextAttributes& setWidth(std::size_t _value)
+ {
+ width = _value;
+ return *this;
+ }
+ TextAttributes& setTabChar(char _value)
+ {
+ tabChar = _value;
+ return *this;
+ }
+
+ std::size_t initialIndent; // indent of first line, or npos
+ std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos
+ std::size_t width; // maximum width of text, including indent. Longer text will wrap
+ char tabChar; // If this char is seen the indent is changed to current pos
+};
+
+class Text
+{
+ public:
+ Text(std::string const& _str, TextAttributes const& _attr = TextAttributes())
+ : attr(_attr)
+ {
+ std::string wrappableChars = " [({.,/|\\-";
+ std::size_t indent = _attr.initialIndent != std::string::npos
+ ? _attr.initialIndent
+ : _attr.indent;
+ std::string remainder = _str;
+
+ while (!remainder.empty())
+ {
+ if (lines.size() >= 1000)
+ {
+ lines.push_back("... message truncated due to excessive size");
+ return;
+ }
+ std::size_t tabPos = std::string::npos;
+ std::size_t width = (std::min)(remainder.size(), _attr.width - indent);
+ std::size_t pos = remainder.find_first_of('\n');
+ if (pos <= width)
+ {
+ width = pos;
+ }
+ pos = remainder.find_last_of(_attr.tabChar, width);
+ if (pos != std::string::npos)
+ {
+ tabPos = pos;
+ if (remainder[width] == '\n')
+ width--;
+ remainder = remainder.substr(0, tabPos) + remainder.substr(tabPos + 1);
+ }
+
+ if (width == remainder.size())
+ {
+ spliceLine(indent, remainder, width);
+ }
+ else if (remainder[width] == '\n')
+ {
+ spliceLine(indent, remainder, width);
+ if (width <= 1 || remainder.size() != 1)
+ remainder = remainder.substr(1);
+ indent = _attr.indent;
+ }
+ else
+ {
+ pos = remainder.find_last_of(wrappableChars, width);
+ if (pos != std::string::npos && pos > 0)
+ {
+ spliceLine(indent, remainder, pos);
+ if (remainder[0] == ' ')
+ remainder = remainder.substr(1);
+ }
+ else
+ {
+ spliceLine(indent, remainder, width - 1);
+ lines.back() += "-";
+ }
+ if (lines.size() == 1)
+ indent = _attr.indent;
+ if (tabPos != std::string::npos)
+ indent += tabPos;
+ }
+ }
+ }
+
+ void spliceLine(std::size_t _indent, std::string& _remainder, std::size_t _pos)
+ {
+ lines.push_back(std::string(_indent, ' ') + _remainder.substr(0, _pos));
+ _remainder = _remainder.substr(_pos);
+ }
+
+ typedef std::vector<std::string>::const_iterator const_iterator;
+
+ const_iterator begin() const { return lines.begin(); }
+ const_iterator end() const { return lines.end(); }
+ std::string const& last() const { return lines.back(); }
+ std::size_t size() const { return lines.size(); }
+ std::string const& operator[](std::size_t _index) const { return lines[_index]; }
+ std::string toString() const
+ {
+ std::ostringstream oss;
+ oss << *this;
+ return oss.str();
+ }
+
+ inline friend std::ostream& operator<<(std::ostream& _stream, Text const& _text)
+ {
+ for (Text::const_iterator it = _text.begin(), itEnd = _text.end();
+ it != itEnd; ++it)
+ {
+ if (it != _text.begin())
+ _stream << "\n";
+ _stream << *it;
+ }
+ return _stream;
+ }
+
+ private:
+ std::string str;
+ TextAttributes attr;
+ std::vector<std::string> lines;
+};
+
+} // end namespace Tbc
+
+#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+} // end outer namespace
+#endif
+
+#endif // TBC_TEXT_FORMAT_H_INCLUDED
+
+// ----------- end of #include from tbc_text_format.h -----------
+// ........... back in /Users/philnash/Dev/OSS/Clara/srcs/clara.h
+
+#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE
+
+#include <algorithm>
+#include <map>
+#include <memory>
+#include <stdexcept>
+
+// Use optional outer namespace
+#ifdef STITCH_CLARA_OPEN_NAMESPACE
+STITCH_CLARA_OPEN_NAMESPACE
+#endif
+
+namespace Clara {
+
+struct UnpositionalTag
+{
+};
+
+extern UnpositionalTag _;
+
+#ifdef CLARA_CONFIG_MAIN
+UnpositionalTag _;
+#endif
+
+namespace Detail {
+
+#ifdef CLARA_CONSOLE_WIDTH
+const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH;
+#else
+const unsigned int consoleWidth = 80;
+#endif
+
+using namespace Tbc;
+
+inline bool startsWith(std::string const& str, std::string const& prefix)
+{
+ return str.size() >= prefix.size() && str.substr(0, prefix.size()) == prefix;
+}
+
+template <typename T>
+struct RemoveConstRef
+{
+ typedef T type;
+};
+template <typename T>
+struct RemoveConstRef<T&>
+{
+ typedef T type;
+};
+template <typename T>
+struct RemoveConstRef<T const&>
+{
+ typedef T type;
+};
+template <typename T>
+struct RemoveConstRef<T const>
+{
+ typedef T type;
+};
+
+template <typename T>
+struct IsBool
+{
+ static const bool value = false;
+};
+template <>
+struct IsBool<bool>
+{
+ static const bool value = true;
+};
+
+template <typename T>
+void convertInto(std::string const& _source, T& _dest)
+{
+ std::stringstream ss;
+ ss << _source;
+ ss >> _dest;
+ if (ss.fail())
+ throw std::runtime_error("Unable to convert " + _source + " to destination type");
+}
+inline void convertInto(std::string const& _source, std::string& _dest)
+{
+ _dest = _source;
+}
+inline void convertInto(std::string const& _source, bool& _dest)
+{
+ std::string sourceLC = _source;
+ std::transform(sourceLC.begin(), sourceLC.end(), sourceLC.begin(), ::tolower);
+ if (sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on")
+ _dest = true;
+ else if (sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off")
+ _dest = false;
+ else
+ throw std::runtime_error("Expected a boolean value but did not recognise:\n '" + _source + "'");
+}
+inline void convertInto(bool _source, bool& _dest)
+{
+ _dest = _source;
+}
+template <typename T>
+inline void convertInto(bool, T&)
+{
+ throw std::runtime_error("Invalid conversion");
+}
+
+template <typename ConfigT>
+struct IArgFunction
+{
+ virtual ~IArgFunction() {}
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+ IArgFunction() = default;
+ IArgFunction(IArgFunction const&) = default;
+#endif
+ virtual void set(ConfigT& config, std::string const& value) const = 0;
+ virtual void setFlag(ConfigT& config) const = 0;
+ virtual bool takesArg() const = 0;
+ virtual IArgFunction* clone() const = 0;
+};
+
+template <typename ConfigT>
+class BoundArgFunction
+{
+ public:
+ BoundArgFunction() : functionObj(CATCH_NULL) {}
+ BoundArgFunction(IArgFunction<ConfigT>* _functionObj) : functionObj(_functionObj) {}
+ BoundArgFunction(BoundArgFunction const& other) : functionObj(other.functionObj ? other.functionObj->clone() : CATCH_NULL) {}
+ BoundArgFunction& operator=(BoundArgFunction const& other)
+ {
+ IArgFunction<ConfigT>* newFunctionObj = other.functionObj ? other.functionObj->clone() : CATCH_NULL;
+ delete functionObj;
+ functionObj = newFunctionObj;
+ return *this;
+ }
+ ~BoundArgFunction() { delete functionObj; }
+
+ void set(ConfigT& config, std::string const& value) const
+ {
+ functionObj->set(config, value);
+ }
+ void setFlag(ConfigT& config) const
+ {
+ functionObj->setFlag(config);
+ }
+ bool takesArg() const { return functionObj->takesArg(); }
+
+ bool isSet() const
+ {
+ return functionObj != CATCH_NULL;
+ }
+
+ private:
+ IArgFunction<ConfigT>* functionObj;
+};
+
+template <typename C>
+struct NullBinder : IArgFunction<C>
+{
+ virtual void set(C&, std::string const&) const {}
+ virtual void setFlag(C&) const {}
+ virtual bool takesArg() const { return true; }
+ virtual IArgFunction<C>* clone() const { return new NullBinder(*this); }
+};
+
+template <typename C, typename M>
+struct BoundDataMember : IArgFunction<C>
+{
+ BoundDataMember(M C::*_member) : member(_member) {}
+ virtual void set(C& p, std::string const& stringValue) const
+ {
+ convertInto(stringValue, p.*member);
+ }
+ virtual void setFlag(C& p) const
+ {
+ convertInto(true, p.*member);
+ }
+ virtual bool takesArg() const { return !IsBool<M>::value; }
+ virtual IArgFunction<C>* clone() const { return new BoundDataMember(*this); }
+ M C::*member;
+};
+template <typename C, typename M>
+struct BoundUnaryMethod : IArgFunction<C>
+{
+ BoundUnaryMethod(void (C::*_member)(M)) : member(_member) {}
+ virtual void set(C& p, std::string const& stringValue) const
+ {
+ typename RemoveConstRef<M>::type value;
+ convertInto(stringValue, value);
+ (p.*member)(value);
+ }
+ virtual void setFlag(C& p) const
+ {
+ typename RemoveConstRef<M>::type value;
+ convertInto(true, value);
+ (p.*member)(value);
+ }
+ virtual bool takesArg() const { return !IsBool<M>::value; }
+ virtual IArgFunction<C>* clone() const { return new BoundUnaryMethod(*this); }
+ void (C::*member)(M);
+};
+template <typename C>
+struct BoundNullaryMethod : IArgFunction<C>
+{
+ BoundNullaryMethod(void (C::*_member)()) : member(_member) {}
+ virtual void set(C& p, std::string const& stringValue) const
+ {
+ bool value;
+ convertInto(stringValue, value);
+ if (value)
+ (p.*member)();
+ }
+ virtual void setFlag(C& p) const
+ {
+ (p.*member)();
+ }
+ virtual bool takesArg() const { return false; }
+ virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod(*this); }
+ void (C::*member)();
+};
+
+template <typename C>
+struct BoundUnaryFunction : IArgFunction<C>
+{
+ BoundUnaryFunction(void (*_function)(C&)) : function(_function) {}
+ virtual void set(C& obj, std::string const& stringValue) const
+ {
+ bool value;
+ convertInto(stringValue, value);
+ if (value)
+ function(obj);
+ }
+ virtual void setFlag(C& p) const
+ {
+ function(p);
+ }
+ virtual bool takesArg() const { return false; }
+ virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction(*this); }
+ void (*function)(C&);
+};
+
+template <typename C, typename T>
+struct BoundBinaryFunction : IArgFunction<C>
+{
+ BoundBinaryFunction(void (*_function)(C&, T)) : function(_function) {}
+ virtual void set(C& obj, std::string const& stringValue) const
+ {
+ typename RemoveConstRef<T>::type value;
+ convertInto(stringValue, value);
+ function(obj, value);
+ }
+ virtual void setFlag(C& obj) const
+ {
+ typename RemoveConstRef<T>::type value;
+ convertInto(true, value);
+ function(obj, value);
+ }
+ virtual bool takesArg() const { return !IsBool<T>::value; }
+ virtual IArgFunction<C>* clone() const { return new BoundBinaryFunction(*this); }
+ void (*function)(C&, T);
+};
+
+} // namespace Detail
+
+struct Parser
+{
+ Parser() : separators(" \t=:") {}
+
+ struct Token
+ {
+ enum Type
+ {
+ Positional,
+ ShortOpt,
+ LongOpt
+ };
+ Token(Type _type, std::string const& _data) : type(_type), data(_data) {}
+ Type type;
+ std::string data;
+ };
+
+ void parseIntoTokens(int argc, char const* const* argv, std::vector<Parser::Token>& tokens) const
+ {
+ const std::string doubleDash = "--";
+ for (int i = 1; i < argc && argv[i] != doubleDash; ++i)
+ parseIntoTokens(argv[i], tokens);
+ }
+ void parseIntoTokens(std::string arg, std::vector<Parser::Token>& tokens) const
+ {
+ while (!arg.empty())
+ {
+ Parser::Token token(Parser::Token::Positional, arg);
+ arg = "";
+ if (token.data[0] == '-')
+ {
+ if (token.data.size() > 1 && token.data[1] == '-')
+ {
+ token = Parser::Token(Parser::Token::LongOpt, token.data.substr(2));
+ }
+ else
+ {
+ token = Parser::Token(Parser::Token::ShortOpt, token.data.substr(1));
+ if (token.data.size() > 1 && separators.find(token.data[1]) == std::string::npos)
+ {
+ arg = "-" + token.data.substr(1);
+ token.data = token.data.substr(0, 1);
+ }
+ }
+ }
+ if (token.type != Parser::Token::Positional)
+ {
+ std::size_t pos = token.data.find_first_of(separators);
+ if (pos != std::string::npos)
+ {
+ arg = token.data.substr(pos + 1);
+ token.data = token.data.substr(0, pos);
+ }
+ }
+ tokens.push_back(token);
+ }
+ }
+ std::string separators;
+};
+
+template <typename ConfigT>
+struct CommonArgProperties
+{
+ CommonArgProperties() {}
+ CommonArgProperties(Detail::BoundArgFunction<ConfigT> const& _boundField) : boundField(_boundField) {}
+
+ Detail::BoundArgFunction<ConfigT> boundField;
+ std::string description;
+ std::string detail;
+ std::string placeholder; // Only value if boundField takes an arg
+
+ bool takesArg() const
+ {
+ return !placeholder.empty();
+ }
+ void validate() const
+ {
+ if (!boundField.isSet())
+ throw std::logic_error("option not bound");
+ }
+};
+struct OptionArgProperties
+{
+ std::vector<std::string> shortNames;
+ std::string longName;
+
+ bool hasShortName(std::string const& shortName) const
+ {
+ return std::find(shortNames.begin(), shortNames.end(), shortName) != shortNames.end();
+ }
+ bool hasLongName(std::string const& _longName) const
+ {
+ return _longName == longName;
+ }
+};
+struct PositionalArgProperties
+{
+ PositionalArgProperties() : position(-1) {}
+ int position; // -1 means non-positional (floating)
+
+ bool isFixedPositional() const
+ {
+ return position != -1;
+ }
+};
+
+template <typename ConfigT>
+class CommandLine
+{
+
+ struct Arg : CommonArgProperties<ConfigT>, OptionArgProperties, PositionalArgProperties
+ {
+ Arg() {}
+ Arg(Detail::BoundArgFunction<ConfigT> const& _boundField) : CommonArgProperties<ConfigT>(_boundField) {}
+
+ using CommonArgProperties<ConfigT>::placeholder; // !TBD
+
+ std::string dbgName() const
+ {
+ if (!longName.empty())
+ return "--" + longName;
+ if (!shortNames.empty())
+ return "-" + shortNames[0];
+ return "positional args";
+ }
+ std::string commands() const
+ {
+ std::ostringstream oss;
+ bool first = true;
+ std::vector<std::string>::const_iterator it = shortNames.begin(), itEnd = shortNames.end();
+ for (; it != itEnd; ++it)
+ {
+ if (first)
+ first = false;
+ else
+ oss << ", ";
+ oss << "-" << *it;
+ }
+ if (!longName.empty())
+ {
+ if (!first)
+ oss << ", ";
+ oss << "--" << longName;
+ }
+ if (!placeholder.empty())
+ oss << " <" << placeholder << ">";
+ return oss.str();
+ }
+ };
+
+ typedef CATCH_AUTO_PTR(Arg) ArgAutoPtr;
+
+ friend void addOptName(Arg& arg, std::string const& optName)
+ {
+ if (optName.empty())
+ return;
+ if (Detail::startsWith(optName, "--"))
+ {
+ if (!arg.longName.empty())
+ throw std::logic_error("Only one long opt may be specified. '" + arg.longName + "' already specified, now attempting to add '" + optName + "'");
+ arg.longName = optName.substr(2);
+ }
+ else if (Detail::startsWith(optName, "-"))
+ arg.shortNames.push_back(optName.substr(1));
+ else
+ throw std::logic_error("option must begin with - or --. Option was: '" + optName + "'");
+ }
+ friend void setPositionalArg(Arg& arg, int position)
+ {
+ arg.position = position;
+ }
+
+ class ArgBuilder
+ {
+ public:
+ ArgBuilder(Arg* arg) : m_arg(arg) {}
+
+ // Bind a non-boolean data member (requires placeholder string)
+ template <typename C, typename M>
+ void bind(M C::*field, std::string const& placeholder)
+ {
+ m_arg->boundField = new Detail::BoundDataMember<C, M>(field);
+ m_arg->placeholder = placeholder;
+ }
+ // Bind a boolean data member (no placeholder required)
+ template <typename C>
+ void bind(bool C::*field)
+ {
+ m_arg->boundField = new Detail::BoundDataMember<C, bool>(field);
+ }
+
+ // Bind a method taking a single, non-boolean argument (requires a placeholder string)
+ template <typename C, typename M>
+ void bind(void (C::*unaryMethod)(M), std::string const& placeholder)
+ {
+ m_arg->boundField = new Detail::BoundUnaryMethod<C, M>(unaryMethod);
+ m_arg->placeholder = placeholder;
+ }
+
+ // Bind a method taking a single, boolean argument (no placeholder string required)
+ template <typename C>
+ void bind(void (C::*unaryMethod)(bool))
+ {
+ m_arg->boundField = new Detail::BoundUnaryMethod<C, bool>(unaryMethod);
+ }
+
+ // Bind a method that takes no arguments (will be called if opt is present)
+ template <typename C>
+ void bind(void (C::*nullaryMethod)())
+ {
+ m_arg->boundField = new Detail::BoundNullaryMethod<C>(nullaryMethod);
+ }
+
+ // Bind a free function taking a single argument - the object to operate on (no placeholder string required)
+ template <typename C>
+ void bind(void (*unaryFunction)(C&))
+ {
+ m_arg->boundField = new Detail::BoundUnaryFunction<C>(unaryFunction);
+ }
+
+ // Bind a free function taking a single argument - the object to operate on (requires a placeholder string)
+ template <typename C, typename T>
+ void bind(void (*binaryFunction)(C&, T), std::string const& placeholder)
+ {
+ m_arg->boundField = new Detail::BoundBinaryFunction<C, T>(binaryFunction);
+ m_arg->placeholder = placeholder;
+ }
+
+ ArgBuilder& describe(std::string const& description)
+ {
+ m_arg->description = description;
+ return *this;
+ }
+ ArgBuilder& detail(std::string const& _detail)
+ {
+ m_arg->detail = _detail;
+ return *this;
+ }
+
+ protected:
+ Arg* m_arg;
+ };
+
+ class OptBuilder : public ArgBuilder
+ {
+ public:
+ OptBuilder(Arg* arg) : ArgBuilder(arg) {}
+ OptBuilder(OptBuilder& other) : ArgBuilder(other) {}
+
+ OptBuilder& operator[](std::string const& optName)
+ {
+ addOptName(*ArgBuilder::m_arg, optName);
+ return *this;
+ }
+ };
+
+ public:
+ CommandLine()
+ : m_boundProcessName(new Detail::NullBinder<ConfigT>()),
+ m_highestSpecifiedArgPosition(0),
+ m_throwOnUnrecognisedTokens(false)
+ {
+ }
+ CommandLine(CommandLine const& other)
+ : m_boundProcessName(other.m_boundProcessName),
+ m_options(other.m_options),
+ m_positionalArgs(other.m_positionalArgs),
+ m_highestSpecifiedArgPosition(other.m_highestSpecifiedArgPosition),
+ m_throwOnUnrecognisedTokens(other.m_throwOnUnrecognisedTokens)
+ {
+ if (other.m_floatingArg.get())
+ m_floatingArg.reset(new Arg(*other.m_floatingArg));
+ }
+
+ CommandLine& setThrowOnUnrecognisedTokens(bool shouldThrow = true)
+ {
+ m_throwOnUnrecognisedTokens = shouldThrow;
+ return *this;
+ }
+
+ OptBuilder operator[](std::string const& optName)
+ {
+ m_options.push_back(Arg());
+ addOptName(m_options.back(), optName);
+ OptBuilder builder(&m_options.back());
+ return builder;
+ }
+
+ ArgBuilder operator[](int position)
+ {
+ m_positionalArgs.insert(std::make_pair(position, Arg()));
+ if (position > m_highestSpecifiedArgPosition)
+ m_highestSpecifiedArgPosition = position;
+ setPositionalArg(m_positionalArgs[position], position);
+ ArgBuilder builder(&m_positionalArgs[position]);
+ return builder;
+ }
+
+ // Invoke this with the _ instance
+ ArgBuilder operator[](UnpositionalTag)
+ {
+ if (m_floatingArg.get())
+ throw std::logic_error("Only one unpositional argument can be added");
+ m_floatingArg.reset(new Arg());
+ ArgBuilder builder(m_floatingArg.get());
+ return builder;
+ }
+
+ template <typename C, typename M>
+ void bindProcessName(M C::*field)
+ {
+ m_boundProcessName = new Detail::BoundDataMember<C, M>(field);
+ }
+ template <typename C, typename M>
+ void bindProcessName(void (C::*_unaryMethod)(M))
+ {
+ m_boundProcessName = new Detail::BoundUnaryMethod<C, M>(_unaryMethod);
+ }
+
+ void optUsage(std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth) const
+ {
+ typename std::vector<Arg>::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it;
+ std::size_t maxWidth = 0;
+ for (it = itBegin; it != itEnd; ++it)
+ maxWidth = (std::max)(maxWidth, it->commands().size());
+
+ for (it = itBegin; it != itEnd; ++it)
+ {
+ Detail::Text usageText(it->commands(), Detail::TextAttributes()
+ .setWidth(maxWidth + indent)
+ .setIndent(indent));
+ Detail::Text desc(it->description, Detail::TextAttributes()
+ .setWidth(width - maxWidth - 3));
+
+ for (std::size_t i = 0; i < (std::max)(usageText.size(), desc.size()); ++i)
+ {
+ std::string usageCol = i < usageText.size() ? usageText[i] : "";
+ os << usageCol;
+
+ if (i < desc.size() && !desc[i].empty())
+ os << std::string(indent + 2 + maxWidth - usageCol.size(), ' ')
+ << desc[i];
+ os << "\n";
+ }
+ }
+ }
+ std::string optUsage() const
+ {
+ std::ostringstream oss;
+ optUsage(oss);
+ return oss.str();
+ }
+
+ void argSynopsis(std::ostream& os) const
+ {
+ for (int i = 1; i <= m_highestSpecifiedArgPosition; ++i)
+ {
+ if (i > 1)
+ os << " ";
+ typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find(i);
+ if (it != m_positionalArgs.end())
+ os << "<" << it->second.placeholder << ">";
+ else if (m_floatingArg.get())
+ os << "<" << m_floatingArg->placeholder << ">";
+ else
+ throw std::logic_error("non consecutive positional arguments with no floating args");
+ }
+ // !TBD No indication of mandatory args
+ if (m_floatingArg.get())
+ {
+ if (m_highestSpecifiedArgPosition > 1)
+ os << " ";
+ os << "[<" << m_floatingArg->placeholder << "> ...]";
+ }
+ }
+ std::string argSynopsis() const
+ {
+ std::ostringstream oss;
+ argSynopsis(oss);
+ return oss.str();
+ }
+
+ void usage(std::ostream& os, std::string const& procName) const
+ {
+ validate();
+ os << "usage:\n " << procName << " ";
+ argSynopsis(os);
+ if (!m_options.empty())
+ {
+ os << " [options]\n\nwhere options are: \n";
+ optUsage(os, 2);
+ }
+ os << "\n";
+ }
+ std::string usage(std::string const& procName) const
+ {
+ std::ostringstream oss;
+ usage(oss, procName);
+ return oss.str();
+ }
+
+ ConfigT parse(int argc, char const* const* argv) const
+ {
+ ConfigT config;
+ parseInto(argc, argv, config);
+ return config;
+ }
+
+ std::vector<Parser::Token> parseInto(int argc, char const* const* argv, ConfigT& config) const
+ {
+ std::string processName = argv[0];
+ std::size_t lastSlash = processName.find_last_of("/\\");
+ if (lastSlash != std::string::npos)
+ processName = processName.substr(lastSlash + 1);
+ m_boundProcessName.set(config, processName);
+ std::vector<Parser::Token> tokens;
+ Parser parser;
+ parser.parseIntoTokens(argc, argv, tokens);
+ return populate(tokens, config);
+ }
+
+ std::vector<Parser::Token> populate(std::vector<Parser::Token> const& tokens, ConfigT& config) const
+ {
+ validate();
+ std::vector<Parser::Token> unusedTokens = populateOptions(tokens, config);
+ unusedTokens = populateFixedArgs(unusedTokens, config);
+ unusedTokens = populateFloatingArgs(unusedTokens, config);
+ return unusedTokens;
+ }
+
+ std::vector<Parser::Token> populateOptions(std::vector<Parser::Token> const& tokens, ConfigT& config) const
+ {
+ std::vector<Parser::Token> unusedTokens;
+ std::vector<std::string> errors;
+ for (std::size_t i = 0; i < tokens.size(); ++i)
+ {
+ Parser::Token const& token = tokens[i];
+ typename std::vector<Arg>::const_iterator it = m_options.begin(), itEnd = m_options.end();
+ for (; it != itEnd; ++it)
+ {
+ Arg const& arg = *it;
+
+ try
+ {
+ if ((token.type == Parser::Token::ShortOpt && arg.hasShortName(token.data)) ||
+ (token.type == Parser::Token::LongOpt && arg.hasLongName(token.data)))
+ {
+ if (arg.takesArg())
+ {
+ if (i == tokens.size() - 1 || tokens[i + 1].type != Parser::Token::Positional)
+ errors.push_back("Expected argument to option: " + token.data);
+ else
+ arg.boundField.set(config, tokens[++i].data);
+ }
+ else
+ {
+ arg.boundField.setFlag(config);
+ }
+ break;
+ }
+ }
+ catch (std::exception& ex)
+ {
+ errors.push_back(std::string(ex.what()) + "\n- while parsing: (" + arg.commands() + ")");
+ }
+ }
+ if (it == itEnd)
+ {
+ if (token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens)
+ unusedTokens.push_back(token);
+ else if (errors.empty() && m_throwOnUnrecognisedTokens)
+ errors.push_back("unrecognised option: " + token.data);
+ }
+ }
+ if (!errors.empty())
+ {
+ std::ostringstream oss;
+ for (std::vector<std::string>::const_iterator it = errors.begin(), itEnd = errors.end();
+ it != itEnd;
+ ++it)
+ {
+ if (it != errors.begin())
+ oss << "\n";
+ oss << *it;
+ }
+ throw std::runtime_error(oss.str());
+ }
+ return unusedTokens;
+ }
+ std::vector<Parser::Token> populateFixedArgs(std::vector<Parser::Token> const& tokens, ConfigT& config) const
+ {
+ std::vector<Parser::Token> unusedTokens;
+ int position = 1;
+ for (std::size_t i = 0; i < tokens.size(); ++i)
+ {
+ Parser::Token const& token = tokens[i];
+ typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find(position);
+ if (it != m_positionalArgs.end())
+ it->second.boundField.set(config, token.data);
+ else
+ unusedTokens.push_back(token);
+ if (token.type == Parser::Token::Positional)
+ position++;
+ }
+ return unusedTokens;
+ }
+ std::vector<Parser::Token> populateFloatingArgs(std::vector<Parser::Token> const& tokens, ConfigT& config) const
+ {
+ if (!m_floatingArg.get())
+ return tokens;
+ std::vector<Parser::Token> unusedTokens;
+ for (std::size_t i = 0; i < tokens.size(); ++i)
+ {
+ Parser::Token const& token = tokens[i];
+ if (token.type == Parser::Token::Positional)
+ m_floatingArg->boundField.set(config, token.data);
+ else
+ unusedTokens.push_back(token);
+ }
+ return unusedTokens;
+ }
+
+ void validate() const
+ {
+ if (m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get())
+ throw std::logic_error("No options or arguments specified");
+
+ for (typename std::vector<Arg>::const_iterator it = m_options.begin(),
+ itEnd = m_options.end();
+ it != itEnd; ++it)
+ it->validate();
+ }
+
+ private:
+ Detail::BoundArgFunction<ConfigT> m_boundProcessName;
+ std::vector<Arg> m_options;
+ std::map<int, Arg> m_positionalArgs;
+ ArgAutoPtr m_floatingArg;
+ int m_highestSpecifiedArgPosition;
+ bool m_throwOnUnrecognisedTokens;
+};
+
+} // end namespace Clara
+
+STITCH_CLARA_CLOSE_NAMESPACE
+#undef STITCH_CLARA_OPEN_NAMESPACE
+#undef STITCH_CLARA_CLOSE_NAMESPACE
+
+#endif // TWOBLUECUBES_CLARA_H_INCLUDED
+#undef STITCH_CLARA_OPEN_NAMESPACE
+
+// Restore Clara's value for console width, if present
+#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
+#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
+#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
+#endif
+
+#include <fstream>
+
+namespace Catch {
+
+inline void abortAfterFirst(ConfigData& config) { config.abortAfter = 1; }
+inline void abortAfterX(ConfigData& config, int x)
+{
+ if (x < 1)
+ throw std::runtime_error("Value after -x or --abortAfter must be greater than zero");
+ config.abortAfter = x;
+}
+inline void addTestOrTags(ConfigData& config, std::string const& _testSpec) { config.testsOrTags.push_back(_testSpec); }
+inline void addReporterName(ConfigData& config, std::string const& _reporterName) { config.reporterNames.push_back(_reporterName); }
+
+inline void addWarning(ConfigData& config, std::string const& _warning)
+{
+ if (_warning == "NoAssertions")
+ config.warnings = static_cast<WarnAbout::What>(config.warnings | WarnAbout::NoAssertions);
+ else
+ throw std::runtime_error("Unrecognised warning: '" + _warning + "'");
+}
+inline void setOrder(ConfigData& config, std::string const& order)
+{
+ if (startsWith("declared", order))
+ config.runOrder = RunTests::InDeclarationOrder;
+ else if (startsWith("lexical", order))
+ config.runOrder = RunTests::InLexicographicalOrder;
+ else if (startsWith("random", order))
+ config.runOrder = RunTests::InRandomOrder;
+ else
+ throw std::runtime_error("Unrecognised ordering: '" + order + "'");
+}
+inline void setRngSeed(ConfigData& config, std::string const& seed)
+{
+ if (seed == "time")
+ {
+ config.rngSeed = static_cast<unsigned int>(std::time(0));
+ }
+ else
+ {
+ std::stringstream ss;
+ ss << seed;
+ ss >> config.rngSeed;
+ if (ss.fail())
+ throw std::runtime_error("Argment to --rng-seed should be the word 'time' or a number");
+ }
+}
+inline void setVerbosity(ConfigData& config, int level)
+{
+ // !TBD: accept strings?
+ config.verbosity = static_cast<Verbosity::Level>(level);
+}
+inline void setShowDurations(ConfigData& config, bool _showDurations)
+{
+ config.showDurations = _showDurations
+ ? ShowDurations::Always
+ : ShowDurations::Never;
+}
+inline void loadTestNamesFromFile(ConfigData& config, std::string const& _filename)
+{
+ std::ifstream f(_filename.c_str());
+ if (!f.is_open())
+ throw std::domain_error("Unable to load input file: " + _filename);
+
+ std::string line;
+ while (std::getline(f, line))
+ {
+ line = trim(line);
+ if (!line.empty() && !startsWith(line, "#"))
+ addTestOrTags(config, "\"" + line + "\",");
+ }
+}
+
+inline Clara::CommandLine<ConfigData> makeCommandLineParser()
+{
+
+ using namespace Clara;
+ CommandLine<ConfigData> cli;
+
+ cli.bindProcessName(&ConfigData::processName);
+
+ cli["-?"]["-h"]["--help"]
+ .describe("display usage information")
+ .bind(&ConfigData::showHelp);
+
+ cli["-l"]["--list-tests"]
+ .describe("list all/matching test cases")
+ .bind(&ConfigData::listTests);
+
+ cli["-t"]["--list-tags"]
+ .describe("list all/matching tags")
+ .bind(&ConfigData::listTags);
+
+ cli["-s"]["--success"]
+ .describe("include successful tests in output")
+ .bind(&ConfigData::showSuccessfulTests);
+
+ cli["-b"]["--break"]
+ .describe("break into debugger on failure")
+ .bind(&ConfigData::shouldDebugBreak);
+
+ cli["-e"]["--nothrow"]
+ .describe("skip exception tests")
+ .bind(&ConfigData::noThrow);
+
+ cli["-i"]["--invisibles"]
+ .describe("show invisibles (tabs, newlines)")
+ .bind(&ConfigData::showInvisibles);
+
+ cli["-o"]["--out"]
+ .describe("output filename")
+ .bind(&ConfigData::outputFilename, "filename");
+
+ cli["-r"]["--reporter"]
+ // .placeholder( "name[:filename]" )
+ .describe("reporter to use (defaults to console)")
+ .bind(&addReporterName, "name");
+
+ cli["-n"]["--name"]
+ .describe("suite name")
+ .bind(&ConfigData::name, "name");
+
+ cli["-a"]["--abort"]
+ .describe("abort at first failure")
+ .bind(&abortAfterFirst);
+
+ cli["-x"]["--abortx"]
+ .describe("abort after x failures")
+ .bind(&abortAfterX, "no. failures");
+
+ cli["-w"]["--warn"]
+ .describe("enable warnings")
+ .bind(&addWarning, "warning name");
+
+ // - needs updating if reinstated
+ // cli.into( &setVerbosity )
+ // .describe( "level of verbosity (0=no output)" )
+ // .shortOpt( "v")
+ // .longOpt( "verbosity" )
+ // .placeholder( "level" );
+
+ cli[_]
+ .describe("which test or tests to use")
+ .bind(&addTestOrTags, "test name, pattern or tags");
+
+ cli["-d"]["--durations"]
+ .describe("show test durations")
+ .bind(&setShowDurations, "yes/no");
+
+ cli["-f"]["--input-file"]
+ .describe("load test names to run from a file")
+ .bind(&loadTestNamesFromFile, "filename");
+
+ cli["-#"]["--filenames-as-tags"]
+ .describe("adds a tag for the filename")
+ .bind(&ConfigData::filenamesAsTags);
+
+ // Less common commands which don't have a short form
+ cli["--list-test-names-only"]
+ .describe("list all/matching test cases names only")
+ .bind(&ConfigData::listTestNamesOnly);
+
+ cli["--list-reporters"]
+ .describe("list all reporters")
+ .bind(&ConfigData::listReporters);
+
+ cli["--order"]
+ .describe("test case order (defaults to decl)")
+ .bind(&setOrder, "decl|lex|rand");
+
+ cli["--rng-seed"]
+ .describe("set a specific seed for random numbers")
+ .bind(&setRngSeed, "'time'|number");
+
+ cli["--force-colour"]
+ .describe("force colourised output")
+ .bind(&ConfigData::forceColour);
+
+ return cli;
+}
+
+} // end namespace Catch
+
+// #included from: internal/catch_list.hpp
+#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED
+
+// #included from: catch_text.h
+#define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED
+
+#define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH
+
+#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch
+// #included from: ../external/tbc_text_format.h
+// Only use header guard if we are not using an outer namespace
+#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+#ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED
+#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+#define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+#endif
+#else
+#define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED
+#endif
+#endif
+#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+#include <sstream>
+#include <string>
+#include <vector>
+
+// Use optional outer namespace
+#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE {
+#endif
+
+namespace Tbc {
+
+#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH
+const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH;
+#else
+const unsigned int consoleWidth = 80;
+#endif
+
+struct TextAttributes
+{
+ TextAttributes()
+ : initialIndent(std::string::npos),
+ indent(0),
+ width(consoleWidth - 1),
+ tabChar('\t')
+ {
+ }
+
+ TextAttributes& setInitialIndent(std::size_t _value)
+ {
+ initialIndent = _value;
+ return *this;
+ }
+ TextAttributes& setIndent(std::size_t _value)
+ {
+ indent = _value;
+ return *this;
+ }
+ TextAttributes& setWidth(std::size_t _value)
+ {
+ width = _value;
+ return *this;
+ }
+ TextAttributes& setTabChar(char _value)
+ {
+ tabChar = _value;
+ return *this;
+ }
+
+ std::size_t initialIndent; // indent of first line, or npos
+ std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos
+ std::size_t width; // maximum width of text, including indent. Longer text will wrap
+ char tabChar; // If this char is seen the indent is changed to current pos
+};
+
+class Text
+{
+ public:
+ Text(std::string const& _str, TextAttributes const& _attr = TextAttributes())
+ : attr(_attr)
+ {
+ std::string wrappableChars = " [({.,/|\\-";
+ std::size_t indent = _attr.initialIndent != std::string::npos
+ ? _attr.initialIndent
+ : _attr.indent;
+ std::string remainder = _str;
+
+ while (!remainder.empty())
+ {
+ if (lines.size() >= 1000)
+ {
+ lines.push_back("... message truncated due to excessive size");
+ return;
+ }
+ std::size_t tabPos = std::string::npos;
+ std::size_t width = (std::min)(remainder.size(), _attr.width - indent);
+ std::size_t pos = remainder.find_first_of('\n');
+ if (pos <= width)
+ {
+ width = pos;
+ }
+ pos = remainder.find_last_of(_attr.tabChar, width);
+ if (pos != std::string::npos)
+ {
+ tabPos = pos;
+ if (remainder[width] == '\n')
+ width--;
+ remainder = remainder.substr(0, tabPos) + remainder.substr(tabPos + 1);
+ }
+
+ if (width == remainder.size())
+ {
+ spliceLine(indent, remainder, width);
+ }
+ else if (remainder[width] == '\n')
+ {
+ spliceLine(indent, remainder, width);
+ if (width <= 1 || remainder.size() != 1)
+ remainder = remainder.substr(1);
+ indent = _attr.indent;
+ }
+ else
+ {
+ pos = remainder.find_last_of(wrappableChars, width);
+ if (pos != std::string::npos && pos > 0)
+ {
+ spliceLine(indent, remainder, pos);
+ if (remainder[0] == ' ')
+ remainder = remainder.substr(1);
+ }
+ else
+ {
+ spliceLine(indent, remainder, width - 1);
+ lines.back() += "-";
+ }
+ if (lines.size() == 1)
+ indent = _attr.indent;
+ if (tabPos != std::string::npos)
+ indent += tabPos;
+ }
+ }
+ }
+
+ void spliceLine(std::size_t _indent, std::string& _remainder, std::size_t _pos)
+ {
+ lines.push_back(std::string(_indent, ' ') + _remainder.substr(0, _pos));
+ _remainder = _remainder.substr(_pos);
+ }
+
+ typedef std::vector<std::string>::const_iterator const_iterator;
+
+ const_iterator begin() const { return lines.begin(); }
+ const_iterator end() const { return lines.end(); }
+ std::string const& last() const { return lines.back(); }
+ std::size_t size() const { return lines.size(); }
+ std::string const& operator[](std::size_t _index) const { return lines[_index]; }
+ std::string toString() const
+ {
+ std::ostringstream oss;
+ oss << *this;
+ return oss.str();
+ }
+
+ inline friend std::ostream& operator<<(std::ostream& _stream, Text const& _text)
+ {
+ for (Text::const_iterator it = _text.begin(), itEnd = _text.end();
+ it != itEnd; ++it)
+ {
+ if (it != _text.begin())
+ _stream << "\n";
+ _stream << *it;
+ }
+ return _stream;
+ }
+
+ private:
+ std::string str;
+ TextAttributes attr;
+ std::vector<std::string> lines;
+};
+
+} // end namespace Tbc
+
+#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+} // end outer namespace
+#endif
+
+#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+
+namespace Catch {
+using Tbc::Text;
+using Tbc::TextAttributes;
+}
+
+// #included from: catch_console_colour.hpp
+#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED
+
+namespace Catch {
+
+struct Colour
+{
+ enum Code
+ {
+ None = 0,
+
+ White,
+ Red,
+ Green,
+ Blue,
+ Cyan,
+ Yellow,
+ Grey,
+
+ Bright = 0x10,
+
+ BrightRed = Bright | Red,
+ BrightGreen = Bright | Green,
+ LightGrey = Bright | Grey,
+ BrightWhite = Bright | White,
+
+ // By intention
+ FileName = LightGrey,
+ Warning = Yellow,
+ ResultError = BrightRed,
+ ResultSuccess = BrightGreen,
+ ResultExpectedFailure = Warning,
+
+ Error = BrightRed,
+ Success = Green,
+
+ OriginalExpression = Cyan,
+ ReconstructedExpression = Yellow,
+
+ SecondaryText = LightGrey,
+ Headers = White
+ };
+
+ // Use constructed object for RAII guard
+ Colour(Code _colourCode);
+ Colour(Colour const& other);
+ ~Colour();
+
+ // Use static method for one-shot changes
+ static void use(Code _colourCode);
+
+ private:
+ bool m_moved;
+};
+
+inline std::ostream& operator<<(std::ostream& os, Colour const&) { return os; }
+
+} // end namespace Catch
+
+// #included from: catch_interfaces_reporter.h
+#define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED
+
+#include <assert.h>
+#include <map>
+#include <ostream>
+#include <string>
+
+namespace Catch {
+struct ReporterConfig
+{
+ explicit ReporterConfig(Ptr<IConfig const> const& _fullConfig)
+ : m_stream(&_fullConfig->stream()), m_fullConfig(_fullConfig) {}
+
+ ReporterConfig(Ptr<IConfig const> const& _fullConfig, std::ostream& _stream)
+ : m_stream(&_stream), m_fullConfig(_fullConfig) {}
+
+ std::ostream& stream() const { return *m_stream; }
+ Ptr<IConfig const> fullConfig() const { return m_fullConfig; }
+
+ private:
+ std::ostream* m_stream;
+ Ptr<IConfig const> m_fullConfig;
+};
+
+struct ReporterPreferences
+{
+ ReporterPreferences()
+ : shouldRedirectStdOut(false)
+ {
+ }
+
+ bool shouldRedirectStdOut;
+};
+
+template <typename T>
+struct LazyStat : Option<T>
+{
+ LazyStat() : used(false) {}
+ LazyStat& operator=(T const& _value)
+ {
+ Option<T>::operator=(_value);
+ used = false;
+ return *this;
+ }
+ void reset()
+ {
+ Option<T>::reset();
+ used = false;
+ }
+ bool used;
+};
+
+struct TestRunInfo
+{
+ TestRunInfo(std::string const& _name) : name(_name) {}
+ std::string name;
+};
+struct GroupInfo
+{
+ GroupInfo(std::string const& _name,
+ std::size_t _groupIndex,
+ std::size_t _groupsCount)
+ : name(_name),
+ groupIndex(_groupIndex),
+ groupsCounts(_groupsCount)
+ {
+ }
+
+ std::string name;
+ std::size_t groupIndex;
+ std::size_t groupsCounts;
+};
+
+struct AssertionStats
+{
+ AssertionStats(AssertionResult const& _assertionResult,
+ std::vector<MessageInfo> const& _infoMessages,
+ Totals const& _totals)
+ : assertionResult(_assertionResult),
+ infoMessages(_infoMessages),
+ totals(_totals)
+ {
+ if (assertionResult.hasMessage())
+ {
+ // Copy message into messages list.
+ // !TBD This should have been done earlier, somewhere
+ MessageBuilder builder(assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType());
+ builder << assertionResult.getMessage();
+ builder.m_info.message = builder.m_stream.str();
+
+ infoMessages.push_back(builder.m_info);
+ }
+ }
+ virtual ~AssertionStats();
+
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+ AssertionStats(AssertionStats const&) = default;
+ AssertionStats(AssertionStats&&) = default;
+ AssertionStats& operator=(AssertionStats const&) = default;
+ AssertionStats& operator=(AssertionStats&&) = default;
+#endif
+
+ AssertionResult assertionResult;
+ std::vector<MessageInfo> infoMessages;
+ Totals totals;
+};
+
+struct SectionStats
+{
+ SectionStats(SectionInfo const& _sectionInfo,
+ Counts const& _assertions,
+ double _durationInSeconds,
+ bool _missingAssertions)
+ : sectionInfo(_sectionInfo),
+ assertions(_assertions),
+ durationInSeconds(_durationInSeconds),
+ missingAssertions(_missingAssertions)
+ {
+ }
+ virtual ~SectionStats();
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+ SectionStats(SectionStats const&) = default;
+ SectionStats(SectionStats&&) = default;
+ SectionStats& operator=(SectionStats const&) = default;
+ SectionStats& operator=(SectionStats&&) = default;
+#endif
+
+ SectionInfo sectionInfo;
+ Counts assertions;
+ double durationInSeconds;
+ bool missingAssertions;
+};
+
+struct TestCaseStats
+{
+ TestCaseStats(TestCaseInfo const& _testInfo,
+ Totals const& _totals,
+ std::string const& _stdOut,
+ std::string const& _stdErr,
+ bool _aborting)
+ : testInfo(_testInfo),
+ totals(_totals),
+ stdOut(_stdOut),
+ stdErr(_stdErr),
+ aborting(_aborting)
+ {
+ }
+ virtual ~TestCaseStats();
+
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+ TestCaseStats(TestCaseStats const&) = default;
+ TestCaseStats(TestCaseStats&&) = default;
+ TestCaseStats& operator=(TestCaseStats const&) = default;
+ TestCaseStats& operator=(TestCaseStats&&) = default;
+#endif
+
+ TestCaseInfo testInfo;
+ Totals totals;
+ std::string stdOut;
+ std::string stdErr;
+ bool aborting;
+};
+
+struct TestGroupStats
+{
+ TestGroupStats(GroupInfo const& _groupInfo,
+ Totals const& _totals,
+ bool _aborting)
+ : groupInfo(_groupInfo),
+ totals(_totals),
+ aborting(_aborting)
+ {
+ }
+ TestGroupStats(GroupInfo const& _groupInfo)
+ : groupInfo(_groupInfo),
+ aborting(false)
+ {
+ }
+ virtual ~TestGroupStats();
+
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+ TestGroupStats(TestGroupStats const&) = default;
+ TestGroupStats(TestGroupStats&&) = default;
+ TestGroupStats& operator=(TestGroupStats const&) = default;
+ TestGroupStats& operator=(TestGroupStats&&) = default;
+#endif
+
+ GroupInfo groupInfo;
+ Totals totals;
+ bool aborting;
+};
+
+struct TestRunStats
+{
+ TestRunStats(TestRunInfo const& _runInfo,
+ Totals const& _totals,
+ bool _aborting)
+ : runInfo(_runInfo),
+ totals(_totals),
+ aborting(_aborting)
+ {
+ }
+ virtual ~TestRunStats();
+
+#ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS
+ TestRunStats(TestRunStats const& _other)
+ : runInfo(_other.runInfo),
+ totals(_other.totals),
+ aborting(_other.aborting)
+ {
+ }
+#else
+ TestRunStats(TestRunStats const&) = default;
+ TestRunStats(TestRunStats&&) = default;
+ TestRunStats& operator=(TestRunStats const&) = default;
+ TestRunStats& operator=(TestRunStats&&) = default;
+#endif
+
+ TestRunInfo runInfo;
+ Totals totals;
+ bool aborting;
+};
+
+struct IStreamingReporter : IShared
+{
+ virtual ~IStreamingReporter();
+
+ // Implementing class must also provide the following static method:
+ // static std::string getDescription();
+
+ virtual ReporterPreferences getPreferences() const = 0;
+
+ virtual void noMatchingTestCases(std::string const& spec) = 0;
+
+ virtual void testRunStarting(TestRunInfo const& testRunInfo) = 0;
+ virtual void testGroupStarting(GroupInfo const& groupInfo) = 0;
+
+ virtual void testCaseStarting(TestCaseInfo const& testInfo) = 0;
+ virtual void sectionStarting(SectionInfo const& sectionInfo) = 0;
+
+ virtual void assertionStarting(AssertionInfo const& assertionInfo) = 0;
+
+ // The return value indicates if the messages buffer should be cleared:
+ virtual bool assertionEnded(AssertionStats const& assertionStats) = 0;
+
+ virtual void sectionEnded(SectionStats const& sectionStats) = 0;
+ virtual void testCaseEnded(TestCaseStats const& testCaseStats) = 0;
+ virtual void testGroupEnded(TestGroupStats const& testGroupStats) = 0;
+ virtual void testRunEnded(TestRunStats const& testRunStats) = 0;
+
+ virtual void skipTest(TestCaseInfo const& testInfo) = 0;
+};
+
+struct IReporterFactory : IShared
+{
+ virtual ~IReporterFactory();
+ virtual IStreamingReporter* create(ReporterConfig const& config) const = 0;
+ virtual std::string getDescription() const = 0;
+};
+
+struct IReporterRegistry
+{
+ typedef std::map<std::string, Ptr<IReporterFactory>> FactoryMap;
+ typedef std::vector<Ptr<IReporterFactory>> Listeners;
+
+ virtual ~IReporterRegistry();
+ virtual IStreamingReporter* create(std::string const& name, Ptr<IConfig const> const& config) const = 0;
+ virtual FactoryMap const& getFactories() const = 0;
+ virtual Listeners const& getListeners() const = 0;
+};
+
+Ptr<IStreamingReporter> addReporter(Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter);
+}
+
+#include <algorithm>
+#include <limits>
+
+namespace Catch {
+
+inline std::size_t listTests(Config const& config)
+{
+
+ TestSpec testSpec = config.testSpec();
+ if (config.testSpec().hasFilters())
+ Catch::cout() << "Matching test cases:\n";
+ else
+ {
+ Catch::cout() << "All available test cases:\n";
+ testSpec = TestSpecParser(ITagAliasRegistry::get()).parse("*").testSpec();
+ }
+
+ std::size_t matchedTests = 0;
+ TextAttributes nameAttr, tagsAttr;
+ nameAttr.setInitialIndent(2).setIndent(4);
+ tagsAttr.setIndent(6);
+
+ std::vector<TestCase> matchedTestCases = filterTests(getAllTestCasesSorted(config), testSpec, config);
+ for (std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
+ it != itEnd;
+ ++it)
+ {
+ matchedTests++;
+ TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
+ Colour::Code colour = testCaseInfo.isHidden()
+ ? Colour::SecondaryText
+ : Colour::None;
+ Colour colourGuard(colour);
+
+ Catch::cout() << Text(testCaseInfo.name, nameAttr) << std::endl;
+ if (!testCaseInfo.tags.empty())
+ Catch::cout() << Text(testCaseInfo.tagsAsString, tagsAttr) << std::endl;
+ }
+
+ if (!config.testSpec().hasFilters())
+ Catch::cout() << pluralise(matchedTests, "test case") << "\n"
+ << std::endl;
+ else
+ Catch::cout() << pluralise(matchedTests, "matching test case") << "\n"
+ << std::endl;
+ return matchedTests;
+}
+
+inline std::size_t listTestsNamesOnly(Config const& config)
+{
+ TestSpec testSpec = config.testSpec();
+ if (!config.testSpec().hasFilters())
+ testSpec = TestSpecParser(ITagAliasRegistry::get()).parse("*").testSpec();
+ std::size_t matchedTests = 0;
+ std::vector<TestCase> matchedTestCases = filterTests(getAllTestCasesSorted(config), testSpec, config);
+ for (std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
+ it != itEnd;
+ ++it)
+ {
+ matchedTests++;
+ TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
+ Catch::cout() << testCaseInfo.name << std::endl;
+ }
+ return matchedTests;
+}
+
+struct TagInfo
+{
+ TagInfo() : count(0) {}
+ void add(std::string const& spelling)
+ {
+ ++count;
+ spellings.insert(spelling);
+ }
+ std::string all() const
+ {
+ std::string out;
+ for (std::set<std::string>::const_iterator it = spellings.begin(), itEnd = spellings.end();
+ it != itEnd;
+ ++it)
+ out += "[" + *it + "]";
+ return out;
+ }
+ std::set<std::string> spellings;
+ std::size_t count;
+};
+
+inline std::size_t listTags(Config const& config)
+{
+ TestSpec testSpec = config.testSpec();
+ if (config.testSpec().hasFilters())
+ Catch::cout() << "Tags for matching test cases:\n";
+ else
+ {
+ Catch::cout() << "All available tags:\n";
+ testSpec = TestSpecParser(ITagAliasRegistry::get()).parse("*").testSpec();
+ }
+
+ std::map<std::string, TagInfo> tagCounts;
+
+ std::vector<TestCase> matchedTestCases = filterTests(getAllTestCasesSorted(config), testSpec, config);
+ for (std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
+ it != itEnd;
+ ++it)
+ {
+ for (std::set<std::string>::const_iterator tagIt = it->getTestCaseInfo().tags.begin(),
+ tagItEnd = it->getTestCaseInfo().tags.end();
+ tagIt != tagItEnd;
+ ++tagIt)
+ {
+ std::string tagName = *tagIt;
+ std::string lcaseTagName = toLower(tagName);
+ std::map<std::string, TagInfo>::iterator countIt = tagCounts.find(lcaseTagName);
+ if (countIt == tagCounts.end())
+ countIt = tagCounts.insert(std::make_pair(lcaseTagName, TagInfo())).first;
+ countIt->second.add(tagName);
+ }
+ }
+
+ for (std::map<std::string, TagInfo>::const_iterator countIt = tagCounts.begin(),
+ countItEnd = tagCounts.end();
+ countIt != countItEnd;
+ ++countIt)
+ {
+ std::ostringstream oss;
+ oss << " " << std::setw(2) << countIt->second.count << " ";
+ Text wrapper(countIt->second.all(), TextAttributes()
+ .setInitialIndent(0)
+ .setIndent(oss.str().size())
+ .setWidth(CATCH_CONFIG_CONSOLE_WIDTH - 10));
+ Catch::cout() << oss.str() << wrapper << "\n";
+ }
+ Catch::cout() << pluralise(tagCounts.size(), "tag") << "\n"
+ << std::endl;
+ return tagCounts.size();
+}
+
+inline std::size_t listReporters(Config const& /*config*/)
+{
+ Catch::cout() << "Available reporters:\n";
+ IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
+ IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it;
+ std::size_t maxNameLen = 0;
+ for (it = itBegin; it != itEnd; ++it)
+ maxNameLen = (std::max)(maxNameLen, it->first.size());
+
+ for (it = itBegin; it != itEnd; ++it)
+ {
+ Text wrapper(it->second->getDescription(), TextAttributes()
+ .setInitialIndent(0)
+ .setIndent(7 + maxNameLen)
+ .setWidth(CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen - 8));
+ Catch::cout() << " "
+ << it->first
+ << ":"
+ << std::string(maxNameLen - it->first.size() + 2, ' ')
+ << wrapper << "\n";
+ }
+ Catch::cout() << std::endl;
+ return factories.size();
+}
+
+inline Option<std::size_t> list(Config const& config)
+{
+ Option<std::size_t> listedCount;
+ if (config.listTests())
+ listedCount = listedCount.valueOr(0) + listTests(config);
+ if (config.listTestNamesOnly())
+ listedCount = listedCount.valueOr(0) + listTestsNamesOnly(config);
+ if (config.listTags())
+ listedCount = listedCount.valueOr(0) + listTags(config);
+ if (config.listReporters())
+ listedCount = listedCount.valueOr(0) + listReporters(config);
+ return listedCount;
+}
+
+} // end namespace Catch
+
+// #included from: internal/catch_run_context.hpp
+#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED
+
+// #included from: catch_test_case_tracker.hpp
+#define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
+
+#include <assert.h>
+#include <map>
+#include <string>
+#include <vector>
+
+namespace Catch {
+namespace TestCaseTracking {
+
+struct ITracker : SharedImpl<>
+{
+ virtual ~ITracker();
+
+ // static queries
+ virtual std::string name() const = 0;
+
+ // dynamic queries
+ virtual bool isComplete() const = 0; // Successfully completed or failed
+ virtual bool isSuccessfullyCompleted() const = 0;
+ virtual bool isOpen() const = 0; // Started but not complete
+ virtual bool hasChildren() const = 0;
+
+ virtual ITracker& parent() = 0;
+
+ // actions
+ virtual void close() = 0; // Successfully complete
+ virtual void fail() = 0;
+ virtual void markAsNeedingAnotherRun() = 0;
+
+ virtual void addChild(Ptr<ITracker> const& child) = 0;
+ virtual ITracker* findChild(std::string const& name) = 0;
+ virtual void openChild() = 0;
+};
+
+class TrackerContext
+{
+
+ enum RunState
+ {
+ NotStarted,
+ Executing,
+ CompletedCycle
+ };
+
+ Ptr<ITracker> m_rootTracker;
+ ITracker* m_currentTracker;
+ RunState m_runState;
+
+ public:
+ static TrackerContext& instance()
+ {
+ static TrackerContext s_instance;
+ return s_instance;
+ }
+
+ TrackerContext()
+ : m_currentTracker(CATCH_NULL),
+ m_runState(NotStarted)
+ {
+ }
+
+ ITracker& startRun();
+
+ void endRun()
+ {
+ m_rootTracker.reset();
+ m_currentTracker = CATCH_NULL;
+ m_runState = NotStarted;
+ }
+
+ void startCycle()
+ {
+ m_currentTracker = m_rootTracker.get();
+ m_runState = Executing;
+ }
+ void completeCycle()
+ {
+ m_runState = CompletedCycle;
+ }
+
+ bool completedCycle() const
+ {
+ return m_runState == CompletedCycle;
+ }
+ ITracker& currentTracker()
+ {
+ return *m_currentTracker;
+ }
+ void setCurrentTracker(ITracker* tracker)
+ {
+ m_currentTracker = tracker;
+ }
+};
+
+class TrackerBase : public ITracker
+{
+ protected:
+ enum CycleState
+ {
+ NotStarted,
+ Executing,
+ ExecutingChildren,
+ NeedsAnotherRun,
+ CompletedSuccessfully,
+ Failed
+ };
+ class TrackerHasName
+ {
+ std::string m_name;
+
+ public:
+ TrackerHasName(std::string const& name) : m_name(name) {}
+ bool operator()(Ptr<ITracker> const& tracker)
+ {
+ return tracker->name() == m_name;
+ }
+ };
+ typedef std::vector<Ptr<ITracker>> Children;
+ std::string m_name;
+ TrackerContext& m_ctx;
+ ITracker* m_parent;
+ Children m_children;
+ CycleState m_runState;
+
+ public:
+ TrackerBase(std::string const& name, TrackerContext& ctx, ITracker* parent)
+ : m_name(name),
+ m_ctx(ctx),
+ m_parent(parent),
+ m_runState(NotStarted)
+ {
+ }
+ virtual ~TrackerBase();
+
+ virtual std::string name() const CATCH_OVERRIDE
+ {
+ return m_name;
+ }
+ virtual bool isComplete() const CATCH_OVERRIDE
+ {
+ return m_runState == CompletedSuccessfully || m_runState == Failed;
+ }
+ virtual bool isSuccessfullyCompleted() const CATCH_OVERRIDE
+ {
+ return m_runState == CompletedSuccessfully;
+ }
+ virtual bool isOpen() const CATCH_OVERRIDE
+ {
+ return m_runState != NotStarted && !isComplete();
+ }
+ virtual bool hasChildren() const CATCH_OVERRIDE
+ {
+ return !m_children.empty();
+ }
+
+ virtual void addChild(Ptr<ITracker> const& child) CATCH_OVERRIDE
+ {
+ m_children.push_back(child);
+ }
+
+ virtual ITracker* findChild(std::string const& name) CATCH_OVERRIDE
+ {
+ Children::const_iterator it = std::find_if(m_children.begin(), m_children.end(), TrackerHasName(name));
+ return (it != m_children.end())
+ ? it->get()
+ : CATCH_NULL;
+ }
+ virtual ITracker& parent() CATCH_OVERRIDE
+ {
+ assert(m_parent); // Should always be non-null except for root
+ return *m_parent;
+ }
+
+ virtual void openChild() CATCH_OVERRIDE
+ {
+ if (m_runState != ExecutingChildren)
+ {
+ m_runState = ExecutingChildren;
+ if (m_parent)
+ m_parent->openChild();
+ }
+ }
+ void open()
+ {
+ m_runState = Executing;
+ moveToThis();
+ if (m_parent)
+ m_parent->openChild();
+ }
+
+ virtual void close() CATCH_OVERRIDE
+ {
+
+ // Close any still open children (e.g. generators)
+ while (&m_ctx.currentTracker() != this)
+ m_ctx.currentTracker().close();
+
+ switch (m_runState)
+ {
+ case NotStarted:
+ case CompletedSuccessfully:
+ case Failed:
+ throw std::logic_error("Illogical state");
+
+ case NeedsAnotherRun:
+ break;
+ ;
+
+ case Executing:
+ m_runState = CompletedSuccessfully;
+ break;
+ case ExecutingChildren:
+ if (m_children.empty() || m_children.back()->isComplete())
+ m_runState = CompletedSuccessfully;
+ break;
+
+ default:
+ throw std::logic_error("Unexpected state");
+ }
+ moveToParent();
+ m_ctx.completeCycle();
+ }
+ virtual void fail() CATCH_OVERRIDE
+ {
+ m_runState = Failed;
+ if (m_parent)
+ m_parent->markAsNeedingAnotherRun();
+ moveToParent();
+ m_ctx.completeCycle();
+ }
+ virtual void markAsNeedingAnotherRun() CATCH_OVERRIDE
+ {
+ m_runState = NeedsAnotherRun;
+ }
+
+ private:
+ void moveToParent()
+ {
+ assert(m_parent);
+ m_ctx.setCurrentTracker(m_parent);
+ }
+ void moveToThis()
+ {
+ m_ctx.setCurrentTracker(this);
+ }
+};
+
+class SectionTracker : public TrackerBase
+{
+ public:
+ SectionTracker(std::string const& name, TrackerContext& ctx, ITracker* parent)
+ : TrackerBase(name, ctx, parent)
+ {
+ }
+ virtual ~SectionTracker();
+
+ static SectionTracker& acquire(TrackerContext& ctx, std::string const& name)
+ {
+ SectionTracker* section = CATCH_NULL;
+
+ ITracker& currentTracker = ctx.currentTracker();
+ if (ITracker* childTracker = currentTracker.findChild(name))
+ {
+ section = dynamic_cast<SectionTracker*>(childTracker);
+ assert(section);
+ }
+ else
+ {
+ section = new SectionTracker(name, ctx, ¤tTracker);
+ currentTracker.addChild(section);
+ }
+ if (!ctx.completedCycle() && !section->isComplete())
+ {
+
+ section->open();
+ }
+ return *section;
+ }
+};
+
+class IndexTracker : public TrackerBase
+{
+ int m_size;
+ int m_index;
+
+ public:
+ IndexTracker(std::string const& name, TrackerContext& ctx, ITracker* parent, int size)
+ : TrackerBase(name, ctx, parent),
+ m_size(size),
+ m_index(-1)
+ {
+ }
+ virtual ~IndexTracker();
+
+ static IndexTracker& acquire(TrackerContext& ctx, std::string const& name, int size)
+ {
+ IndexTracker* tracker = CATCH_NULL;
+
+ ITracker& currentTracker = ctx.currentTracker();
+ if (ITracker* childTracker = currentTracker.findChild(name))
+ {
+ tracker = dynamic_cast<IndexTracker*>(childTracker);
+ assert(tracker);
+ }
+ else
+ {
+ tracker = new IndexTracker(name, ctx, ¤tTracker, size);
+ currentTracker.addChild(tracker);
+ }
+
+ if (!ctx.completedCycle() && !tracker->isComplete())
+ {
+ if (tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun)
+ tracker->moveNext();
+ tracker->open();
+ }
+
+ return *tracker;
+ }
+
+ int index() const { return m_index; }
+
+ void moveNext()
+ {
+ m_index++;
+ m_children.clear();
+ }
+
+ virtual void close() CATCH_OVERRIDE
+ {
+ TrackerBase::close();
+ if (m_runState == CompletedSuccessfully && m_index < m_size - 1)
+ m_runState = Executing;
+ }
+};
+
+inline ITracker& TrackerContext::startRun()
+{
+ m_rootTracker = new SectionTracker("{root}", *this, CATCH_NULL);
+ m_currentTracker = CATCH_NULL;
+ m_runState = Executing;
+ return *m_rootTracker;
+}
+
+} // namespace TestCaseTracking
+
+using TestCaseTracking::ITracker;
+using TestCaseTracking::TrackerContext;
+using TestCaseTracking::SectionTracker;
+using TestCaseTracking::IndexTracker;
+
+} // namespace Catch
+
+// #included from: catch_fatal_condition.hpp
+#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
+
+namespace Catch {
+
+// Report the error condition then exit the process
+inline void fatal(std::string const& message, int exitCode)
+{
+ IContext& context = Catch::getCurrentContext();
+ IResultCapture* resultCapture = context.getResultCapture();
+ resultCapture->handleFatalErrorCondition(message);
+
+ if (Catch::alwaysTrue()) // avoids "no return" warnings
+ exit(exitCode);
+}
+
+} // namespace Catch
+
+#if defined(CATCH_PLATFORM_WINDOWS) /////////////////////////////////////////
+
+namespace Catch {
+
+struct FatalConditionHandler
+{
+ void reset() {}
+};
+
+} // namespace Catch
+
+#else // Not Windows - assumed to be POSIX compatible //////////////////////////
+
+#include <signal.h>
+
+namespace Catch {
+
+struct SignalDefs
+{
+ int id;
+ const char* name;
+};
+extern SignalDefs signalDefs[];
+SignalDefs signalDefs[] = {
+ {SIGINT, "SIGINT - Terminal interrupt signal"},
+ {SIGILL, "SIGILL - Illegal instruction signal"},
+ {SIGFPE, "SIGFPE - Floating point error signal"},
+ {SIGSEGV, "SIGSEGV - Segmentation violation signal"},
+ {SIGTERM, "SIGTERM - Termination request signal"},
+ {SIGABRT, "SIGABRT - Abort (abnormal termination) signal"}};
+
+struct FatalConditionHandler
+{
+
+ static void handleSignal(int sig)
+ {
+ for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i)
+ if (sig == signalDefs[i].id)
+ fatal(signalDefs[i].name, -sig);
+ fatal("<unknown signal>", -sig);
+ }
+
+ FatalConditionHandler() : m_isSet(true)
+ {
+ for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i)
+ signal(signalDefs[i].id, handleSignal);
+ }
+ ~FatalConditionHandler()
+ {
+ reset();
+ }
+ void reset()
+ {
+ if (m_isSet)
+ {
+ for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i)
+ signal(signalDefs[i].id, SIG_DFL);
+ m_isSet = false;
+ }
+ }
+
+ bool m_isSet;
+};
+
+} // namespace Catch
+
+#endif // not Windows
+
+#include <set>
+#include <string>
+
+namespace Catch {
+
+class StreamRedirect
+{
+
+ public:
+ StreamRedirect(std::ostream& stream, std::string& targetString)
+ : m_stream(stream),
+ m_prevBuf(stream.rdbuf()),
+ m_targetString(targetString)
+ {
+ stream.rdbuf(m_oss.rdbuf());
+ }
+
+ ~StreamRedirect()
+ {
+ m_targetString += m_oss.str();
+ m_stream.rdbuf(m_prevBuf);
+ }
+
+ private:
+ std::ostream& m_stream;
+ std::streambuf* m_prevBuf;
+ std::ostringstream m_oss;
+ std::string& m_targetString;
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+class RunContext : public IResultCapture, public IRunner
+{
+
+ RunContext(RunContext const&);
+ void operator=(RunContext const&);
+
+ public:
+ explicit RunContext(Ptr<IConfig const> const& _config, Ptr<IStreamingReporter> const& reporter)
+ : m_runInfo(_config->name()),
+ m_context(getCurrentMutableContext()),
+ m_activeTestCase(CATCH_NULL),
+ m_config(_config),
+ m_reporter(reporter)
+ {
+ m_context.setRunner(this);
+ m_context.setConfig(m_config);
+ m_context.setResultCapture(this);
+ m_reporter->testRunStarting(m_runInfo);
+ }
+
+ virtual ~RunContext()
+ {
+ m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting()));
+ }
+
+ void testGroupStarting(std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount)
+ {
+ m_reporter->testGroupStarting(GroupInfo(testSpec, groupIndex, groupsCount));
+ }
+ void testGroupEnded(std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount)
+ {
+ m_reporter->testGroupEnded(TestGroupStats(GroupInfo(testSpec, groupIndex, groupsCount), totals, aborting()));
+ }
+
+ Totals runTest(TestCase const& testCase)
+ {
+ Totals prevTotals = m_totals;
+
+ std::string redirectedCout;
+ std::string redirectedCerr;
+
+ TestCaseInfo testInfo = testCase.getTestCaseInfo();
+
+ m_reporter->testCaseStarting(testInfo);
+
+ m_activeTestCase = &testCase;
+
+ do
+ {
+ m_trackerContext.startRun();
+ do
+ {
+ m_trackerContext.startCycle();
+ m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, testInfo.name);
+ runCurrentTest(redirectedCout, redirectedCerr);
+ } while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting());
+ }
+ // !TBD: deprecated - this will be replaced by indexed trackers
+ while (getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting());
+
+ Totals deltaTotals = m_totals.delta(prevTotals);
+ m_totals.testCases += deltaTotals.testCases;
+ m_reporter->testCaseEnded(TestCaseStats(testInfo,
+ deltaTotals,
+ redirectedCout,
+ redirectedCerr,
+ aborting()));
+
+ m_activeTestCase = CATCH_NULL;
+ m_testCaseTracker = CATCH_NULL;
+
+ return deltaTotals;
+ }
+
+ Ptr<IConfig const> config() const
+ {
+ return m_config;
+ }
+
+ private: // IResultCapture
+ virtual void assertionEnded(AssertionResult const& result)
+ {
+ if (result.getResultType() == ResultWas::Ok)
+ {
+ m_totals.assertions.passed++;
+ }
+ else if (!result.isOk())
+ {
+ m_totals.assertions.failed++;
+ }
+
+ if (m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals)))
+ m_messages.clear();
+
+ // Reset working state
+ m_lastAssertionInfo = AssertionInfo("", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}", m_lastAssertionInfo.resultDisposition);
+ m_lastResult = result;
+ }
+
+ virtual bool sectionStarted(
+ SectionInfo const& sectionInfo,
+ Counts& assertions)
+ {
+ std::ostringstream oss;
+ oss << sectionInfo.name << "@" << sectionInfo.lineInfo;
+
+ ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, oss.str());
+ if (!sectionTracker.isOpen())
+ return false;
+ m_activeSections.push_back(§ionTracker);
+
+ m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
+
+ m_reporter->sectionStarting(sectionInfo);
+
+ assertions = m_totals.assertions;
+
+ return true;
+ }
+ bool testForMissingAssertions(Counts& assertions)
+ {
+ if (assertions.total() != 0)
+ return false;
+ if (!m_config->warnAboutMissingAssertions())
+ return false;
+ if (m_trackerContext.currentTracker().hasChildren())
+ return false;
+ m_totals.assertions.failed++;
+ assertions.failed++;
+ return true;
+ }
+
+ virtual void sectionEnded(SectionEndInfo const& endInfo)
+ {
+ Counts assertions = m_totals.assertions - endInfo.prevAssertions;
+ bool missingAssertions = testForMissingAssertions(assertions);
+
+ if (!m_activeSections.empty())
+ {
+ m_activeSections.back()->close();
+ m_activeSections.pop_back();
+ }
+
+ m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions));
+ m_messages.clear();
+ }
+
+ virtual void sectionEndedEarly(SectionEndInfo const& endInfo)
+ {
+ if (m_unfinishedSections.empty())
+ m_activeSections.back()->fail();
+ else
+ m_activeSections.back()->close();
+ m_activeSections.pop_back();
+
+ m_unfinishedSections.push_back(endInfo);
+ }
+
+ virtual void pushScopedMessage(MessageInfo const& message)
+ {
+ m_messages.push_back(message);
+ }
+
+ virtual void popScopedMessage(MessageInfo const& message)
+ {
+ m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end());
+ }
+
+ virtual std::string getCurrentTestName() const
+ {
+ return m_activeTestCase
+ ? m_activeTestCase->getTestCaseInfo().name
+ : "";
+ }
+
+ virtual const AssertionResult* getLastResult() const
+ {
+ return &m_lastResult;
+ }
+
+ virtual void handleFatalErrorCondition(std::string const& message)
+ {
+ ResultBuilder resultBuilder = makeUnexpectedResultBuilder();
+ resultBuilder.setResultType(ResultWas::FatalErrorCondition);
+ resultBuilder << message;
+ resultBuilder.captureExpression();
+
+ handleUnfinishedSections();
+
+ // Recreate section for test case (as we will lose the one that was in scope)
+ TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
+ SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description);
+
+ Counts assertions;
+ assertions.failed = 1;
+ SectionStats testCaseSectionStats(testCaseSection, assertions, 0, false);
+ m_reporter->sectionEnded(testCaseSectionStats);
+
+ TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo();
+
+ Totals deltaTotals;
+ deltaTotals.testCases.failed = 1;
+ m_reporter->testCaseEnded(TestCaseStats(testInfo,
+ deltaTotals,
+ "",
+ "",
+ false));
+ m_totals.testCases.failed++;
+ testGroupEnded("", m_totals, 1, 1);
+ m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false));
+ }
+
+ public:
+ // !TBD We need to do this another way!
+ bool aborting() const
+ {
+ return m_totals.assertions.failed == static_cast<std::size_t>(m_config->abortAfter());
+ }
+
+ private:
+ void runCurrentTest(std::string& redirectedCout, std::string& redirectedCerr)
+ {
+ TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
+ SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description);
+ m_reporter->sectionStarting(testCaseSection);
+ Counts prevAssertions = m_totals.assertions;
+ double duration = 0;
+ try
+ {
+ m_lastAssertionInfo = AssertionInfo("TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal);
+
+ seedRng(*m_config);
+
+ Timer timer;
+ timer.start();
+ if (m_reporter->getPreferences().shouldRedirectStdOut)
+ {
+ StreamRedirect coutRedir(Catch::cout(), redirectedCout);
+ StreamRedirect cerrRedir(Catch::cerr(), redirectedCerr);
+ invokeActiveTestCase();
+ }
+ else
+ {
+ invokeActiveTestCase();
+ }
+ duration = timer.getElapsedSeconds();
+ }
+ catch (TestFailureException&)
+ {
+ // This just means the test was aborted due to failure
+ }
+ catch (...)
+ {
+ makeUnexpectedResultBuilder().useActiveException();
+ }
+ m_testCaseTracker->close();
+ handleUnfinishedSections();
+ m_messages.clear();
+
+ Counts assertions = m_totals.assertions - prevAssertions;
+ bool missingAssertions = testForMissingAssertions(assertions);
+
+ if (testCaseInfo.okToFail())
+ {
+ std::swap(assertions.failedButOk, assertions.failed);
+ m_totals.assertions.failed -= assertions.failedButOk;
+ m_totals.assertions.failedButOk += assertions.failedButOk;
+ }
+
+ SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions);
+ m_reporter->sectionEnded(testCaseSectionStats);
+ }
+
+ void invokeActiveTestCase()
+ {
+ FatalConditionHandler fatalConditionHandler; // Handle signals
+ m_activeTestCase->invoke();
+ fatalConditionHandler.reset();
+ }
+
+ private:
+ ResultBuilder makeUnexpectedResultBuilder() const
+ {
+ return ResultBuilder(m_lastAssertionInfo.macroName.c_str(),
+ m_lastAssertionInfo.lineInfo,
+ m_lastAssertionInfo.capturedExpression.c_str(),
+ m_lastAssertionInfo.resultDisposition);
+ }
+
+ void handleUnfinishedSections()
+ {
+ // If sections ended prematurely due to an exception we stored their
+ // infos here so we can tear them down outside the unwind process.
+ for (std::vector<SectionEndInfo>::const_reverse_iterator it = m_unfinishedSections.rbegin(),
+ itEnd = m_unfinishedSections.rend();
+ it != itEnd;
+ ++it)
+ sectionEnded(*it);
+ m_unfinishedSections.clear();
+ }
+
+ TestRunInfo m_runInfo;
+ IMutableContext& m_context;
+ TestCase const* m_activeTestCase;
+ ITracker* m_testCaseTracker;
+ ITracker* m_currentSectionTracker;
+ AssertionResult m_lastResult;
+
+ Ptr<IConfig const> m_config;
+ Totals m_totals;
+ Ptr<IStreamingReporter> m_reporter;
+ std::vector<MessageInfo> m_messages;
+ AssertionInfo m_lastAssertionInfo;
+ std::vector<SectionEndInfo> m_unfinishedSections;
+ std::vector<ITracker*> m_activeSections;
+ TrackerContext m_trackerContext;
+};
+
+IResultCapture& getResultCapture()
+{
+ if (IResultCapture* capture = getCurrentContext().getResultCapture())
+ return *capture;
+ else
+ throw std::logic_error("No result capture instance");
+}
+
+} // end namespace Catch
+
+// #included from: internal/catch_version.h
+#define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED
+
+namespace Catch {
+
+// Versioning information
+struct Version
+{
+ Version(unsigned int _majorVersion,
+ unsigned int _minorVersion,
+ unsigned int _patchNumber,
+ std::string const& _branchName,
+ unsigned int _buildNumber);
+
+ unsigned int const majorVersion;
+ unsigned int const minorVersion;
+ unsigned int const patchNumber;
+
+ // buildNumber is only used if branchName is not null
+ std::string const branchName;
+ unsigned int const buildNumber;
+
+ friend std::ostream& operator<<(std::ostream& os, Version const& version);
+
+ private:
+ void operator=(Version const&);
+};
+
+extern Version libraryVersion;
+}
+
+#include <fstream>
+#include <limits>
+#include <stdlib.h>
+
+namespace Catch {
+
+Ptr<IStreamingReporter> createReporter(std::string const& reporterName, Ptr<Config> const& config)
+{
+ Ptr<IStreamingReporter> reporter = getRegistryHub().getReporterRegistry().create(reporterName, config.get());
+ if (!reporter)
+ {
+ std::ostringstream oss;
+ oss << "No reporter registered with name: '" << reporterName << "'";
+ throw std::domain_error(oss.str());
+ }
+ return reporter;
+}
+
+Ptr<IStreamingReporter> makeReporter(Ptr<Config> const& config)
+{
+ std::vector<std::string> reporters = config->getReporterNames();
+ if (reporters.empty())
+ reporters.push_back("console");
+
+ Ptr<IStreamingReporter> reporter;
+ for (std::vector<std::string>::const_iterator it = reporters.begin(), itEnd = reporters.end();
+ it != itEnd;
+ ++it)
+ reporter = addReporter(reporter, createReporter(*it, config));
+ return reporter;
+}
+Ptr<IStreamingReporter> addListeners(Ptr<IConfig const> const& config, Ptr<IStreamingReporter> reporters)
+{
+ IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners();
+ for (IReporterRegistry::Listeners::const_iterator it = listeners.begin(), itEnd = listeners.end();
+ it != itEnd;
+ ++it)
+ reporters = addReporter(reporters, (*it)->create(ReporterConfig(config)));
+ return reporters;
+}
+
+Totals runTests(Ptr<Config> const& config)
+{
+
+ Ptr<IConfig const> iconfig = config.get();
+
+ Ptr<IStreamingReporter> reporter = makeReporter(config);
+ reporter = addListeners(iconfig, reporter);
+
+ RunContext context(iconfig, reporter);
+
+ Totals totals;
+
+ context.testGroupStarting(config->name(), 1, 1);
+
+ TestSpec testSpec = config->testSpec();
+ if (!testSpec.hasFilters())
+ testSpec = TestSpecParser(ITagAliasRegistry::get()).parse("~[.]").testSpec(); // All not hidden tests
+
+ std::vector<TestCase> const& allTestCases = getAllTestCasesSorted(*iconfig);
+ for (std::vector<TestCase>::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end();
+ it != itEnd;
+ ++it)
+ {
+ if (!context.aborting() && matchTest(*it, testSpec, *iconfig))
+ totals += context.runTest(*it);
+ else
+ reporter->skipTest(*it);
+ }
+
+ context.testGroupEnded(iconfig->name(), totals, 1, 1);
+ return totals;
+}
+
+void applyFilenamesAsTags(IConfig const& config)
+{
+ std::vector<TestCase> const& tests = getAllTestCasesSorted(config);
+ for (std::size_t i = 0; i < tests.size(); ++i)
+ {
+ TestCase& test = const_cast<TestCase&>(tests[i]);
+ std::set<std::string> tags = test.tags;
+
+ std::string filename = test.lineInfo.file;
+ std::string::size_type lastSlash = filename.find_last_of("\\/");
+ if (lastSlash != std::string::npos)
+ filename = filename.substr(lastSlash + 1);
+
+ std::string::size_type lastDot = filename.find_last_of(".");
+ if (lastDot != std::string::npos)
+ filename = filename.substr(0, lastDot);
+
+ tags.insert("#" + filename);
+ setTags(test, tags);
+ }
+}
+
+class Session : NonCopyable
+{
+ static bool alreadyInstantiated;
+
+ public:
+ struct OnUnusedOptions
+ {
+ enum DoWhat
+ {
+ Ignore,
+ Fail
+ };
+ };
+
+ Session()
+ : m_cli(makeCommandLineParser())
+ {
+ if (alreadyInstantiated)
+ {
+ std::string msg = "Only one instance of Catch::Session can ever be used";
+ Catch::cerr() << msg << std::endl;
+ throw std::logic_error(msg);
+ }
+ alreadyInstantiated = true;
+ }
+ ~Session()
+ {
+ Catch::cleanUp();
+ }
+
+ void showHelp(std::string const& processName)
+ {
+ Catch::cout() << "\nCatch v" << libraryVersion << "\n";
+
+ m_cli.usage(Catch::cout(), processName);
+ Catch::cout() << "For more detail usage please see the project docs\n"
+ << std::endl;
+ }
+
+ int applyCommandLine(int argc, char const* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail)
+ {
+ try
+ {
+ m_cli.setThrowOnUnrecognisedTokens(unusedOptionBehaviour == OnUnusedOptions::Fail);
+ m_unusedTokens = m_cli.parseInto(argc, argv, m_configData);
+ if (m_configData.showHelp)
+ showHelp(m_configData.processName);
+ m_config.reset();
+ }
+ catch (std::exception& ex)
+ {
+ {
+ Colour colourGuard(Colour::Red);
+ Catch::cerr()
+ << "\nError(s) in input:\n"
+ << Text(ex.what(), TextAttributes().setIndent(2))
+ << "\n\n";
+ }
+ m_cli.usage(Catch::cout(), m_configData.processName);
+ return (std::numeric_limits<int>::max)();
+ }
+ return 0;
+ }
+
+ void useConfigData(ConfigData const& _configData)
+ {
+ m_configData = _configData;
+ m_config.reset();
+ }
+
+ int run(int argc, char const* const argv[])
+ {
+
+ int returnCode = applyCommandLine(argc, argv);
+ if (returnCode == 0)
+ returnCode = run();
+ return returnCode;
+ }
+
+ int run()
+ {
+ if (m_configData.showHelp)
+ return 0;
+
+ try
+ {
+ config(); // Force config to be constructed
+
+ seedRng(*m_config);
+
+ if (m_configData.filenamesAsTags)
+ applyFilenamesAsTags(*m_config);
+
+ // Handle list request
+ if (Option<std::size_t> listed = list(config()))
+ return static_cast<int>(*listed);
+
+ return static_cast<int>(runTests(m_config).assertions.failed);
+ }
+ catch (std::exception& ex)
+ {
+ Catch::cerr() << ex.what() << std::endl;
+ return (std::numeric_limits<int>::max)();
+ }
+ }
+
+ Clara::CommandLine<ConfigData> const& cli() const
+ {
+ return m_cli;
+ }
+ std::vector<Clara::Parser::Token> const& unusedTokens() const
+ {
+ return m_unusedTokens;
+ }
+ ConfigData& configData()
+ {
+ return m_configData;
+ }
+ Config& config()
+ {
+ if (!m_config)
+ m_config = new Config(m_configData);
+ return *m_config;
+ }
+
+ private:
+ Clara::CommandLine<ConfigData> m_cli;
+ std::vector<Clara::Parser::Token> m_unusedTokens;
+ ConfigData m_configData;
+ Ptr<Config> m_config;
+};
+
+bool Session::alreadyInstantiated = false;
+
+} // end namespace Catch
+
+// #included from: catch_registry_hub.hpp
+#define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED
+
+// #included from: catch_test_case_registry_impl.hpp
+#define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED
+
+#include <algorithm>
+#include <iostream>
+#include <set>
+#include <sstream>
+#include <vector>
+
+namespace Catch {
+
+struct LexSort
+{
+ bool operator()(TestCase i, TestCase j) const { return (i < j); }
+};
+struct RandomNumberGenerator
+{
+ int operator()(int n) const { return std::rand() % n; }
+};
+
+inline std::vector<TestCase> sortTests(IConfig const& config, std::vector<TestCase> const& unsortedTestCases)
+{
+
+ std::vector<TestCase> sorted = unsortedTestCases;
+
+ switch (config.runOrder())
+ {
+ case RunTests::InLexicographicalOrder:
+ std::sort(sorted.begin(), sorted.end(), LexSort());
+ break;
+ case RunTests::InRandomOrder:
+ {
+ seedRng(config);
+
+ RandomNumberGenerator rng;
+ std::random_shuffle(sorted.begin(), sorted.end(), rng);
+ }
+ break;
+ case RunTests::InDeclarationOrder:
+ // already in declaration order
+ break;
+ }
+ return sorted;
+}
+bool matchTest(TestCase const& testCase, TestSpec const& testSpec, IConfig const& config)
+{
+ return testSpec.matches(testCase) && (config.allowThrows() || !testCase.throws());
+}
+
+void enforceNoDuplicateTestCases(std::vector<TestCase> const& functions)
+{
+ std::set<TestCase> seenFunctions;
+ for (std::vector<TestCase>::const_iterator it = functions.begin(), itEnd = functions.end();
+ it != itEnd;
+ ++it)
+ {
+ std::pair<std::set<TestCase>::const_iterator, bool> prev = seenFunctions.insert(*it);
+ if (!prev.second)
+ {
+ Catch::cerr()
+ << Colour(Colour::Red)
+ << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n"
+ << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n"
+ << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl;
+ exit(1);
+ }
+ }
+}
+
+std::vector<TestCase> filterTests(std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config)
+{
+ std::vector<TestCase> filtered;
+ filtered.reserve(testCases.size());
+ for (std::vector<TestCase>::const_iterator it = testCases.begin(), itEnd = testCases.end();
+ it != itEnd;
+ ++it)
+ if (matchTest(*it, testSpec, config))
+ filtered.push_back(*it);
+ return filtered;
+}
+std::vector<TestCase> const& getAllTestCasesSorted(IConfig const& config)
+{
+ return getRegistryHub().getTestCaseRegistry().getAllTestsSorted(config);
+}
+
+class TestRegistry : public ITestCaseRegistry
+{
+ public:
+ TestRegistry()
+ : m_currentSortOrder(RunTests::InDeclarationOrder),
+ m_unnamedCount(0)
+ {
+ }
+ virtual ~TestRegistry();
+
+ virtual void registerTest(TestCase const& testCase)
+ {
+ std::string name = testCase.getTestCaseInfo().name;
+ if (name == "")
+ {
+ std::ostringstream oss;
+ oss << "Anonymous test case " << ++m_unnamedCount;
+ return registerTest(testCase.withName(oss.str()));
+ }
+ m_functions.push_back(testCase);
+ }
+
+ virtual std::vector<TestCase> const& getAllTests() const
+ {
+ return m_functions;
+ }
+ virtual std::vector<TestCase> const& getAllTestsSorted(IConfig const& config) const
+ {
+ if (m_sortedFunctions.empty())
+ enforceNoDuplicateTestCases(m_functions);
+
+ if (m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty())
+ {
+ m_sortedFunctions = sortTests(config, m_functions);
+ m_currentSortOrder = config.runOrder();
+ }
+ return m_sortedFunctions;
+ }
+
+ private:
+ std::vector<TestCase> m_functions;
+ mutable RunTests::InWhatOrder m_currentSortOrder;
+ mutable std::vector<TestCase> m_sortedFunctions;
+ size_t m_unnamedCount;
+ std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+class FreeFunctionTestCase : public SharedImpl<ITestCase>
+{
+ public:
+ FreeFunctionTestCase(TestFunction fun) : m_fun(fun) {}
+
+ virtual void invoke() const
+ {
+ m_fun();
+ }
+
+ private:
+ virtual ~FreeFunctionTestCase();
+
+ TestFunction m_fun;
+};
+
+inline std::string extractClassName(std::string const& classOrQualifiedMethodName)
+{
+ std::string className = classOrQualifiedMethodName;
+ if (startsWith(className, "&"))
+ {
+ std::size_t lastColons = className.rfind("::");
+ std::size_t penultimateColons = className.rfind("::", lastColons - 1);
+ if (penultimateColons == std::string::npos)
+ penultimateColons = 1;
+ className = className.substr(penultimateColons, lastColons - penultimateColons);
+ }
+ return className;
+}
+
+void registerTestCase(ITestCase* testCase,
+ char const* classOrQualifiedMethodName,
+ NameAndDesc const& nameAndDesc,
+ SourceLineInfo const& lineInfo)
+{
+
+ getMutableRegistryHub().registerTest(makeTestCase(testCase,
+ extractClassName(classOrQualifiedMethodName),
+ nameAndDesc.name,
+ nameAndDesc.description,
+ lineInfo));
+}
+void registerTestCaseFunction(TestFunction function,
+ SourceLineInfo const& lineInfo,
+ NameAndDesc const& nameAndDesc)
+{
+ registerTestCase(new FreeFunctionTestCase(function), "", nameAndDesc, lineInfo);
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+AutoReg::AutoReg(TestFunction function,
+ SourceLineInfo const& lineInfo,
+ NameAndDesc const& nameAndDesc)
+{
+ registerTestCaseFunction(function, lineInfo, nameAndDesc);
+}
+
+AutoReg::~AutoReg() {}
+
+} // end namespace Catch
+
+// #included from: catch_reporter_registry.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED
+
+#include <map>
+
+namespace Catch {
+
+class ReporterRegistry : public IReporterRegistry
+{
+
+ public:
+ virtual ~ReporterRegistry() CATCH_OVERRIDE {}
+
+ virtual IStreamingReporter* create(std::string const& name, Ptr<IConfig const> const& config) const CATCH_OVERRIDE
+ {
+ FactoryMap::const_iterator it = m_factories.find(name);
+ if (it == m_factories.end())
+ return CATCH_NULL;
+ return it->second->create(ReporterConfig(config));
+ }
+
+ void registerReporter(std::string const& name, Ptr<IReporterFactory> const& factory)
+ {
+ m_factories.insert(std::make_pair(name, factory));
+ }
+ void registerListener(Ptr<IReporterFactory> const& factory)
+ {
+ m_listeners.push_back(factory);
+ }
+
+ virtual FactoryMap const& getFactories() const CATCH_OVERRIDE
+ {
+ return m_factories;
+ }
+ virtual Listeners const& getListeners() const CATCH_OVERRIDE
+ {
+ return m_listeners;
+ }
+
+ private:
+ FactoryMap m_factories;
+ Listeners m_listeners;
+};
+}
+
+// #included from: catch_exception_translator_registry.hpp
+#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
+
+#ifdef __OBJC__
+#import "Foundation/Foundation.h"
+#endif
+
+namespace Catch {
+
+class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry
+{
+ public:
+ ~ExceptionTranslatorRegistry()
+ {
+ deleteAll(m_translators);
+ }
+
+ virtual void registerTranslator(const IExceptionTranslator* translator)
+ {
+ m_translators.push_back(translator);
+ }
+
+ virtual std::string translateActiveException() const
+ {
+ try
+ {
+#ifdef __OBJC__
+ // In Objective-C try objective-c exceptions first
+ @try
+ {
+ return tryTranslators();
+ }
+ @catch (NSException* exception)
+ {
+ return Catch::toString([exception description]);
+ }
+#else
+ return tryTranslators();
+#endif
+ }
+ catch (TestFailureException&)
+ {
+ throw;
+ }
+ catch (std::exception& ex)
+ {
+ return ex.what();
+ }
+ catch (std::string& msg)
+ {
+ return msg;
+ }
+ catch (const char* msg)
+ {
+ return msg;
+ }
+ catch (...)
+ {
+ return "Unknown exception";
+ }
+ }
+
+ std::string tryTranslators() const
+ {
+ if (m_translators.empty())
+ throw;
+ else
+ return m_translators[0]->translate(m_translators.begin() + 1, m_translators.end());
+ }
+
+ private:
+ std::vector<const IExceptionTranslator*> m_translators;
+};
+}
+
+namespace Catch {
+
+namespace {
+
+class RegistryHub : public IRegistryHub, public IMutableRegistryHub
+{
+
+ RegistryHub(RegistryHub const&);
+ void operator=(RegistryHub const&);
+
+ public: // IRegistryHub
+ RegistryHub()
+ {
+ }
+ virtual IReporterRegistry const& getReporterRegistry() const CATCH_OVERRIDE
+ {
+ return m_reporterRegistry;
+ }
+ virtual ITestCaseRegistry const& getTestCaseRegistry() const CATCH_OVERRIDE
+ {
+ return m_testCaseRegistry;
+ }
+ virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE
+ {
+ return m_exceptionTranslatorRegistry;
+ }
+
+ public: // IMutableRegistryHub
+ virtual void registerReporter(std::string const& name, Ptr<IReporterFactory> const& factory) CATCH_OVERRIDE
+ {
+ m_reporterRegistry.registerReporter(name, factory);
+ }
+ virtual void registerListener(Ptr<IReporterFactory> const& factory) CATCH_OVERRIDE
+ {
+ m_reporterRegistry.registerListener(factory);
+ }
+ virtual void registerTest(TestCase const& testInfo) CATCH_OVERRIDE
+ {
+ m_testCaseRegistry.registerTest(testInfo);
+ }
+ virtual void registerTranslator(const IExceptionTranslator* translator) CATCH_OVERRIDE
+ {
+ m_exceptionTranslatorRegistry.registerTranslator(translator);
+ }
+
+ private:
+ TestRegistry m_testCaseRegistry;
+ ReporterRegistry m_reporterRegistry;
+ ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
+};
+
+// Single, global, instance
+inline RegistryHub*& getTheRegistryHub()
+{
+ static RegistryHub* theRegistryHub = CATCH_NULL;
+ if (!theRegistryHub)
+ theRegistryHub = new RegistryHub();
+ return theRegistryHub;
+}
+}
+
+IRegistryHub& getRegistryHub()
+{
+ return *getTheRegistryHub();
+}
+IMutableRegistryHub& getMutableRegistryHub()
+{
+ return *getTheRegistryHub();
+}
+void cleanUp()
+{
+ delete getTheRegistryHub();
+ getTheRegistryHub() = CATCH_NULL;
+ cleanUpContext();
+}
+std::string translateActiveException()
+{
+ return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();
+}
+
+} // end namespace Catch
+
+// #included from: catch_notimplemented_exception.hpp
+#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED
+
+#include <ostream>
+
+namespace Catch {
+
+NotImplementedException::NotImplementedException(SourceLineInfo const& lineInfo)
+ : m_lineInfo(lineInfo)
+{
+ std::ostringstream oss;
+ oss << lineInfo << ": function ";
+ oss << "not implemented";
+ m_what = oss.str();
+}
+
+const char* NotImplementedException::what() const CATCH_NOEXCEPT
+{
+ return m_what.c_str();
+}
+
+} // end namespace Catch
+
+// #included from: catch_context_impl.hpp
+#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED
+
+// #included from: catch_stream.hpp
+#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED
+
+#include <cstdio>
+#include <iostream>
+#include <stdexcept>
+
+namespace Catch {
+
+template <typename WriterF, size_t bufferSize = 256>
+class StreamBufImpl : public StreamBufBase
+{
+ char data[bufferSize];
+ WriterF m_writer;
+
+ public:
+ StreamBufImpl()
+ {
+ setp(data, data + sizeof(data));
+ }
+
+ ~StreamBufImpl() CATCH_NOEXCEPT
+ {
+ sync();
+ }
+
+ private:
+ int overflow(int c)
+ {
+ sync();
+
+ if (c != EOF)
+ {
+ if (pbase() == epptr())
+ m_writer(std::string(1, static_cast<char>(c)));
+ else
+ sputc(static_cast<char>(c));
+ }
+ return 0;
+ }
+
+ int sync()
+ {
+ if (pbase() != pptr())
+ {
+ m_writer(std::string(pbase(), static_cast<std::string::size_type>(pptr() - pbase())));
+ setp(pbase(), epptr());
+ }
+ return 0;
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+FileStream::FileStream(std::string const& filename)
+{
+ m_ofs.open(filename.c_str());
+ if (m_ofs.fail())
+ {
+ std::ostringstream oss;
+ oss << "Unable to open file: '" << filename << "'";
+ throw std::domain_error(oss.str());
+ }
+}
+
+std::ostream& FileStream::stream() const
+{
+ return m_ofs;
+}
+
+struct OutputDebugWriter
+{
+
+ void operator()(std::string const& str)
+ {
+ writeToDebugConsole(str);
+ }
+};
+
+DebugOutStream::DebugOutStream()
+ : m_streamBuf(new StreamBufImpl<OutputDebugWriter>()),
+ m_os(m_streamBuf.get())
+{
+}
+
+std::ostream& DebugOutStream::stream() const
+{
+ return m_os;
+}
+
+// Store the streambuf from cout up-front because
+// cout may get redirected when running tests
+CoutStream::CoutStream()
+ : m_os(Catch::cout().rdbuf())
+{
+}
+
+std::ostream& CoutStream::stream() const
+{
+ return m_os;
+}
+
+#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions
+std::ostream& cout()
+{
+ return std::cout;
+}
+std::ostream& cerr()
+{
+ return std::cerr;
+}
+#endif
+}
+
+namespace Catch {
+
+class Context : public IMutableContext
+{
+
+ Context() : m_config(CATCH_NULL), m_runner(CATCH_NULL), m_resultCapture(CATCH_NULL) {}
+ Context(Context const&);
+ void operator=(Context const&);
+
+ public: // IContext
+ virtual IResultCapture* getResultCapture()
+ {
+ return m_resultCapture;
+ }
+ virtual IRunner* getRunner()
+ {
+ return m_runner;
+ }
+ virtual size_t getGeneratorIndex(std::string const& fileInfo, size_t totalSize)
+ {
+ return getGeneratorsForCurrentTest()
+ .getGeneratorInfo(fileInfo, totalSize)
+ .getCurrentIndex();
+ }
+ virtual bool advanceGeneratorsForCurrentTest()
+ {
+ IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
+ return generators && generators->moveNext();
+ }
+
+ virtual Ptr<IConfig const> getConfig() const
+ {
+ return m_config;
+ }
+
+ public: // IMutableContext
+ virtual void setResultCapture(IResultCapture* resultCapture)
+ {
+ m_resultCapture = resultCapture;
+ }
+ virtual void setRunner(IRunner* runner)
+ {
+ m_runner = runner;
+ }
+ virtual void setConfig(Ptr<IConfig const> const& config)
+ {
+ m_config = config;
+ }
+
+ friend IMutableContext& getCurrentMutableContext();
+
+ private:
+ IGeneratorsForTest* findGeneratorsForCurrentTest()
+ {
+ std::string testName = getResultCapture()->getCurrentTestName();
+
+ std::map<std::string, IGeneratorsForTest*>::const_iterator it =
+ m_generatorsByTestName.find(testName);
+ return it != m_generatorsByTestName.end()
+ ? it->second
+ : CATCH_NULL;
+ }
+
+ IGeneratorsForTest& getGeneratorsForCurrentTest()
+ {
+ IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
+ if (!generators)
+ {
+ std::string testName = getResultCapture()->getCurrentTestName();
+ generators = createGeneratorsForTest();
+ m_generatorsByTestName.insert(std::make_pair(testName, generators));
+ }
+ return *generators;
+ }
+
+ private:
+ Ptr<IConfig const> m_config;
+ IRunner* m_runner;
+ IResultCapture* m_resultCapture;
+ std::map<std::string, IGeneratorsForTest*> m_generatorsByTestName;
+};
+
+namespace {
+Context* currentContext = CATCH_NULL;
+}
+IMutableContext& getCurrentMutableContext()
+{
+ if (!currentContext)
+ currentContext = new Context();
+ return *currentContext;
+}
+IContext& getCurrentContext()
+{
+ return getCurrentMutableContext();
+}
+
+void cleanUpContext()
+{
+ delete currentContext;
+ currentContext = CATCH_NULL;
+}
+}
+
+// #included from: catch_console_colour_impl.hpp
+#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED
+
+namespace Catch {
+namespace {
+
+struct IColourImpl
+{
+ virtual ~IColourImpl() {}
+ virtual void use(Colour::Code _colourCode) = 0;
+};
+
+struct NoColourImpl : IColourImpl
+{
+ void use(Colour::Code) {}
+
+ static IColourImpl* instance()
+ {
+ static NoColourImpl s_instance;
+ return &s_instance;
+ }
+};
+
+} // anon namespace
+} // namespace Catch
+
+#if !defined(CATCH_CONFIG_COLOUR_NONE) && !defined(CATCH_CONFIG_COLOUR_WINDOWS) && !defined(CATCH_CONFIG_COLOUR_ANSI)
+#ifdef CATCH_PLATFORM_WINDOWS
+#define CATCH_CONFIG_COLOUR_WINDOWS
+#else
+#define CATCH_CONFIG_COLOUR_ANSI
+#endif
+#endif
+
+#if defined(CATCH_CONFIG_COLOUR_WINDOWS) /////////////////////////////////////////
+
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+
+#ifdef __AFXDLL
+#include <AfxWin.h>
+#else
+#include <windows.h>
+#endif
+
+namespace Catch {
+namespace {
+
+class Win32ColourImpl : public IColourImpl
+{
+ public:
+ Win32ColourImpl() : stdoutHandle(GetStdHandle(STD_OUTPUT_HANDLE))
+ {
+ CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
+ GetConsoleScreenBufferInfo(stdoutHandle, &csbiInfo);
+ originalForegroundAttributes = csbiInfo.wAttributes & ~(BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY);
+ originalBackgroundAttributes = csbiInfo.wAttributes & ~(FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
+ }
+
+ virtual void use(Colour::Code _colourCode)
+ {
+ switch (_colourCode)
+ {
+ case Colour::None:
+ return setTextAttribute(originalForegroundAttributes);
+ case Colour::White:
+ return setTextAttribute(FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE);
+ case Colour::Red:
+ return setTextAttribute(FOREGROUND_RED);
+ case Colour::Green:
+ return setTextAttribute(FOREGROUND_GREEN);
+ case Colour::Blue:
+ return setTextAttribute(FOREGROUND_BLUE);
+ case Colour::Cyan:
+ return setTextAttribute(FOREGROUND_BLUE | FOREGROUND_GREEN);
+ case Colour::Yellow:
+ return setTextAttribute(FOREGROUND_RED | FOREGROUND_GREEN);
+ case Colour::Grey:
+ return setTextAttribute(0);
+
+ case Colour::LightGrey:
+ return setTextAttribute(FOREGROUND_INTENSITY);
+ case Colour::BrightRed:
+ return setTextAttribute(FOREGROUND_INTENSITY | FOREGROUND_RED);
+ case Colour::BrightGreen:
+ return setTextAttribute(FOREGROUND_INTENSITY | FOREGROUND_GREEN);
+ case Colour::BrightWhite:
+ return setTextAttribute(FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE);
+
+ case Colour::Bright:
+ throw std::logic_error("not a colour");
+ }
+ }
+
+ private:
+ void setTextAttribute(WORD _textAttribute)
+ {
+ SetConsoleTextAttribute(stdoutHandle, _textAttribute | originalBackgroundAttributes);
+ }
+ HANDLE stdoutHandle;
+ WORD originalForegroundAttributes;
+ WORD originalBackgroundAttributes;
+};
+
+IColourImpl* platformColourInstance()
+{
+ static Win32ColourImpl s_instance;
+ return &s_instance;
+}
+
+} // end anon namespace
+} // end namespace Catch
+
+#elif defined(CATCH_CONFIG_COLOUR_ANSI) //////////////////////////////////////
+
+#include <unistd.h>
+
+namespace Catch {
+namespace {
+
+// use POSIX/ ANSI console terminal codes
+// Thanks to Adam Strzelecki for original contribution
+// (http://github.com/nanoant)
+// https://github.com/philsquared/Catch/pull/131
+class PosixColourImpl : public IColourImpl
+{
+ public:
+ virtual void use(Colour::Code _colourCode)
+ {
+ switch (_colourCode)
+ {
+ case Colour::None:
+ case Colour::White:
+ return setColour("[0m");
+ case Colour::Red:
+ return setColour("[0;31m");
+ case Colour::Green:
+ return setColour("[0;32m");
+ case Colour::Blue:
+ return setColour("[0:34m");
+ case Colour::Cyan:
+ return setColour("[0;36m");
+ case Colour::Yellow:
+ return setColour("[0;33m");
+ case Colour::Grey:
+ return setColour("[1;30m");
+
+ case Colour::LightGrey:
+ return setColour("[0;37m");
+ case Colour::BrightRed:
+ return setColour("[1;31m");
+ case Colour::BrightGreen:
+ return setColour("[1;32m");
+ case Colour::BrightWhite:
+ return setColour("[1;37m");
+
+ case Colour::Bright:
+ throw std::logic_error("not a colour");
+ }
+ }
+ static IColourImpl* instance()
+ {
+ static PosixColourImpl s_instance;
+ return &s_instance;
+ }
+
+ private:
+ void setColour(const char* _escapeCode)
+ {
+ Catch::cout() << '\033' << _escapeCode;
+ }
+};
+
+IColourImpl* platformColourInstance()
+{
+ Ptr<IConfig const> config = getCurrentContext().getConfig();
+ return (config && config->forceColour()) || isatty(STDOUT_FILENO)
+ ? PosixColourImpl::instance()
+ : NoColourImpl::instance();
+}
+
+} // end anon namespace
+} // end namespace Catch
+
+#else // not Windows or ANSI ///////////////////////////////////////////////
+
+namespace Catch {
+
+static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); }
+
+} // end namespace Catch
+
+#endif // Windows/ ANSI/ None
+
+namespace Catch {
+
+Colour::Colour(Code _colourCode) : m_moved(false) { use(_colourCode); }
+Colour::Colour(Colour const& _other) : m_moved(false) { const_cast<Colour&>(_other).m_moved = true; }
+Colour::~Colour()
+{
+ if (!m_moved) use(None);
+}
+
+void Colour::use(Code _colourCode)
+{
+ static IColourImpl* impl = isDebuggerActive()
+ ? NoColourImpl::instance()
+ : platformColourInstance();
+ impl->use(_colourCode);
+}
+
+} // end namespace Catch
+
+// #included from: catch_generators_impl.hpp
+#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED
+
+#include <map>
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+struct GeneratorInfo : IGeneratorInfo
+{
+
+ GeneratorInfo(std::size_t size)
+ : m_size(size),
+ m_currentIndex(0)
+ {
+ }
+
+ bool moveNext()
+ {
+ if (++m_currentIndex == m_size)
+ {
+ m_currentIndex = 0;
+ return false;
+ }
+ return true;
+ }
+
+ std::size_t getCurrentIndex() const
+ {
+ return m_currentIndex;
+ }
+
+ std::size_t m_size;
+ std::size_t m_currentIndex;
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+class GeneratorsForTest : public IGeneratorsForTest
+{
+
+ public:
+ ~GeneratorsForTest()
+ {
+ deleteAll(m_generatorsInOrder);
+ }
+
+ IGeneratorInfo& getGeneratorInfo(std::string const& fileInfo, std::size_t size)
+ {
+ std::map<std::string, IGeneratorInfo*>::const_iterator it = m_generatorsByName.find(fileInfo);
+ if (it == m_generatorsByName.end())
+ {
+ IGeneratorInfo* info = new GeneratorInfo(size);
+ m_generatorsByName.insert(std::make_pair(fileInfo, info));
+ m_generatorsInOrder.push_back(info);
+ return *info;
+ }
+ return *it->second;
+ }
+
+ bool moveNext()
+ {
+ std::vector<IGeneratorInfo*>::const_iterator it = m_generatorsInOrder.begin();
+ std::vector<IGeneratorInfo*>::const_iterator itEnd = m_generatorsInOrder.end();
+ for (; it != itEnd; ++it)
+ {
+ if ((*it)->moveNext())
+ return true;
+ }
+ return false;
+ }
+
+ private:
+ std::map<std::string, IGeneratorInfo*> m_generatorsByName;
+ std::vector<IGeneratorInfo*> m_generatorsInOrder;
+};
+
+IGeneratorsForTest* createGeneratorsForTest()
+{
+ return new GeneratorsForTest();
+}
+
+} // end namespace Catch
+
+// #included from: catch_assertionresult.hpp
+#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED
+
+namespace Catch {
+
+AssertionInfo::AssertionInfo(std::string const& _macroName,
+ SourceLineInfo const& _lineInfo,
+ std::string const& _capturedExpression,
+ ResultDisposition::Flags _resultDisposition)
+ : macroName(_macroName),
+ lineInfo(_lineInfo),
+ capturedExpression(_capturedExpression),
+ resultDisposition(_resultDisposition)
+{
+}
+
+AssertionResult::AssertionResult() {}
+
+AssertionResult::AssertionResult(AssertionInfo const& info, AssertionResultData const& data)
+ : m_info(info),
+ m_resultData(data)
+{
+}
+
+AssertionResult::~AssertionResult() {}
+
+// Result was a success
+bool AssertionResult::succeeded() const
+{
+ return Catch::isOk(m_resultData.resultType);
+}
+
+// Result was a success, or failure is suppressed
+bool AssertionResult::isOk() const
+{
+ return Catch::isOk(m_resultData.resultType) || shouldSuppressFailure(m_info.resultDisposition);
+}
+
+ResultWas::OfType AssertionResult::getResultType() const
+{
+ return m_resultData.resultType;
+}
+
+bool AssertionResult::hasExpression() const
+{
+ return !m_info.capturedExpression.empty();
+}
+
+bool AssertionResult::hasMessage() const
+{
+ return !m_resultData.message.empty();
+}
+
+std::string AssertionResult::getExpression() const
+{
+ if (isFalseTest(m_info.resultDisposition))
+ return "!" + m_info.capturedExpression;
+ else
+ return m_info.capturedExpression;
+}
+std::string AssertionResult::getExpressionInMacro() const
+{
+ if (m_info.macroName.empty())
+ return m_info.capturedExpression;
+ else
+ return m_info.macroName + "( " + m_info.capturedExpression + " )";
+}
+
+bool AssertionResult::hasExpandedExpression() const
+{
+ return hasExpression() && getExpandedExpression() != getExpression();
+}
+
+std::string AssertionResult::getExpandedExpression() const
+{
+ return m_resultData.reconstructedExpression;
+}
+
+std::string AssertionResult::getMessage() const
+{
+ return m_resultData.message;
+}
+SourceLineInfo AssertionResult::getSourceInfo() const
+{
+ return m_info.lineInfo;
+}
+
+std::string AssertionResult::getTestMacroName() const
+{
+ return m_info.macroName;
+}
+
+} // end namespace Catch
+
+// #included from: catch_test_case_info.hpp
+#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED
+
+namespace Catch {
+
+inline TestCaseInfo::SpecialProperties parseSpecialTag(std::string const& tag)
+{
+ if (startsWith(tag, ".") ||
+ tag == "hide" ||
+ tag == "!hide")
+ return TestCaseInfo::IsHidden;
+ else if (tag == "!throws")
+ return TestCaseInfo::Throws;
+ else if (tag == "!shouldfail")
+ return TestCaseInfo::ShouldFail;
+ else if (tag == "!mayfail")
+ return TestCaseInfo::MayFail;
+ else
+ return TestCaseInfo::None;
+}
+inline bool isReservedTag(std::string const& tag)
+{
+ return parseSpecialTag(tag) == TestCaseInfo::None && tag.size() > 0 && !isalnum(tag[0]);
+}
+inline void enforceNotReservedTag(std::string const& tag, SourceLineInfo const& _lineInfo)
+{
+ if (isReservedTag(tag))
+ {
+ {
+ Colour colourGuard(Colour::Red);
+ Catch::cerr()
+ << "Tag name [" << tag << "] not allowed.\n"
+ << "Tag names starting with non alpha-numeric characters are reserved\n";
+ }
+ {
+ Colour colourGuard(Colour::FileName);
+ Catch::cerr() << _lineInfo << std::endl;
+ }
+ exit(1);
+ }
+}
+
+TestCase makeTestCase(ITestCase* _testCase,
+ std::string const& _className,
+ std::string const& _name,
+ std::string const& _descOrTags,
+ SourceLineInfo const& _lineInfo)
+{
+ bool isHidden(startsWith(_name, "./")); // Legacy support
+
+ // Parse out tags
+ std::set<std::string> tags;
+ std::string desc, tag;
+ bool inTag = false;
+ for (std::size_t i = 0; i < _descOrTags.size(); ++i)
+ {
+ char c = _descOrTags[i];
+ if (!inTag)
+ {
+ if (c == '[')
+ inTag = true;
+ else
+ desc += c;
+ }
+ else
+ {
+ if (c == ']')
+ {
+ TestCaseInfo::SpecialProperties prop = parseSpecialTag(tag);
+ if (prop == TestCaseInfo::IsHidden)
+ isHidden = true;
+ else if (prop == TestCaseInfo::None)
+ enforceNotReservedTag(tag, _lineInfo);
+
+ tags.insert(tag);
+ tag.clear();
+ inTag = false;
+ }
+ else
+ tag += c;
+ }
+ }
+ if (isHidden)
+ {
+ tags.insert("hide");
+ tags.insert(".");
+ }
+
+ TestCaseInfo info(_name, _className, desc, tags, _lineInfo);
+ return TestCase(_testCase, info);
+}
+
+void setTags(TestCaseInfo& testCaseInfo, std::set<std::string> const& tags)
+{
+ testCaseInfo.tags = tags;
+ testCaseInfo.lcaseTags.clear();
+
+ std::ostringstream oss;
+ for (std::set<std::string>::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it)
+ {
+ oss << "[" << *it << "]";
+ std::string lcaseTag = toLower(*it);
+ testCaseInfo.properties = static_cast<TestCaseInfo::SpecialProperties>(testCaseInfo.properties | parseSpecialTag(lcaseTag));
+ testCaseInfo.lcaseTags.insert(lcaseTag);
+ }
+ testCaseInfo.tagsAsString = oss.str();
+}
+
+TestCaseInfo::TestCaseInfo(std::string const& _name,
+ std::string const& _className,
+ std::string const& _description,
+ std::set<std::string> const& _tags,
+ SourceLineInfo const& _lineInfo)
+ : name(_name),
+ className(_className),
+ description(_description),
+ lineInfo(_lineInfo),
+ properties(None)
+{
+ setTags(*this, _tags);
+}
+
+TestCaseInfo::TestCaseInfo(TestCaseInfo const& other)
+ : name(other.name),
+ className(other.className),
+ description(other.description),
+ tags(other.tags),
+ lcaseTags(other.lcaseTags),
+ tagsAsString(other.tagsAsString),
+ lineInfo(other.lineInfo),
+ properties(other.properties)
+{
+}
+
+bool TestCaseInfo::isHidden() const
+{
+ return (properties & IsHidden) != 0;
+}
+bool TestCaseInfo::throws() const
+{
+ return (properties & Throws) != 0;
+}
+bool TestCaseInfo::okToFail() const
+{
+ return (properties & (ShouldFail | MayFail)) != 0;
+}
+bool TestCaseInfo::expectedToFail() const
+{
+ return (properties & (ShouldFail)) != 0;
+}
+
+TestCase::TestCase(ITestCase* testCase, TestCaseInfo const& info) : TestCaseInfo(info), test(testCase) {}
+
+TestCase::TestCase(TestCase const& other)
+ : TestCaseInfo(other),
+ test(other.test)
+{
+}
+
+TestCase TestCase::withName(std::string const& _newName) const
+{
+ TestCase other(*this);
+ other.name = _newName;
+ return other;
+}
+
+void TestCase::swap(TestCase& other)
+{
+ test.swap(other.test);
+ name.swap(other.name);
+ className.swap(other.className);
+ description.swap(other.description);
+ tags.swap(other.tags);
+ lcaseTags.swap(other.lcaseTags);
+ tagsAsString.swap(other.tagsAsString);
+ std::swap(TestCaseInfo::properties, static_cast<TestCaseInfo&>(other).properties);
+ std::swap(lineInfo, other.lineInfo);
+}
+
+void TestCase::invoke() const
+{
+ test->invoke();
+}
+
+bool TestCase::operator==(TestCase const& other) const
+{
+ return test.get() == other.test.get() &&
+ name == other.name &&
+ className == other.className;
+}
+
+bool TestCase::operator<(TestCase const& other) const
+{
+ return name < other.name;
+}
+TestCase& TestCase::operator=(TestCase const& other)
+{
+ TestCase temp(other);
+ swap(temp);
+ return *this;
+}
+
+TestCaseInfo const& TestCase::getTestCaseInfo() const
+{
+ return *this;
+}
+
+} // end namespace Catch
+
+// #included from: catch_version.hpp
+#define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED
+
+namespace Catch {
+
+Version::Version(unsigned int _majorVersion,
+ unsigned int _minorVersion,
+ unsigned int _patchNumber,
+ std::string const& _branchName,
+ unsigned int _buildNumber)
+ : majorVersion(_majorVersion),
+ minorVersion(_minorVersion),
+ patchNumber(_patchNumber),
+ branchName(_branchName),
+ buildNumber(_buildNumber)
+{
+}
+
+std::ostream& operator<<(std::ostream& os, Version const& version)
+{
+ os << version.majorVersion << "."
+ << version.minorVersion << "."
+ << version.patchNumber;
+
+ if (!version.branchName.empty())
+ {
+ os << "-" << version.branchName
+ << "." << version.buildNumber;
+ }
+ return os;
+}
+
+Version libraryVersion(1, 3, 2, "", 0);
+}
+
+// #included from: catch_message.hpp
+#define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED
+
+namespace Catch {
+
+MessageInfo::MessageInfo(std::string const& _macroName,
+ SourceLineInfo const& _lineInfo,
+ ResultWas::OfType _type)
+ : macroName(_macroName),
+ lineInfo(_lineInfo),
+ type(_type),
+ sequence(++globalCount)
+{
+}
+
+// This may need protecting if threading support is added
+unsigned int MessageInfo::globalCount = 0;
+
+////////////////////////////////////////////////////////////////////////////
+
+ScopedMessage::ScopedMessage(MessageBuilder const& builder)
+ : m_info(builder.m_info)
+{
+ m_info.message = builder.m_stream.str();
+ getResultCapture().pushScopedMessage(m_info);
+}
+ScopedMessage::ScopedMessage(ScopedMessage const& other)
+ : m_info(other.m_info)
+{
+}
+
+ScopedMessage::~ScopedMessage()
+{
+ getResultCapture().popScopedMessage(m_info);
+}
+
+} // end namespace Catch
+
+// #included from: catch_legacy_reporter_adapter.hpp
+#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED
+
+// #included from: catch_legacy_reporter_adapter.h
+#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED
+
+namespace Catch {
+// Deprecated
+struct IReporter : IShared
+{
+ virtual ~IReporter();
+
+ virtual bool shouldRedirectStdout() const = 0;
+
+ virtual void StartTesting() = 0;
+ virtual void EndTesting(Totals const& totals) = 0;
+ virtual void StartGroup(std::string const& groupName) = 0;
+ virtual void EndGroup(std::string const& groupName, Totals const& totals) = 0;
+ virtual void StartTestCase(TestCaseInfo const& testInfo) = 0;
+ virtual void EndTestCase(TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr) = 0;
+ virtual void StartSection(std::string const& sectionName, std::string const& description) = 0;
+ virtual void EndSection(std::string const& sectionName, Counts const& assertions) = 0;
+ virtual void NoAssertionsInSection(std::string const& sectionName) = 0;
+ virtual void NoAssertionsInTestCase(std::string const& testName) = 0;
+ virtual void Aborted() = 0;
+ virtual void Result(AssertionResult const& result) = 0;
+};
+
+class LegacyReporterAdapter : public SharedImpl<IStreamingReporter>
+{
+ public:
+ LegacyReporterAdapter(Ptr<IReporter> const& legacyReporter);
+ virtual ~LegacyReporterAdapter();
+
+ virtual ReporterPreferences getPreferences() const;
+ virtual void noMatchingTestCases(std::string const&);
+ virtual void testRunStarting(TestRunInfo const&);
+ virtual void testGroupStarting(GroupInfo const& groupInfo);
+ virtual void testCaseStarting(TestCaseInfo const& testInfo);
+ virtual void sectionStarting(SectionInfo const& sectionInfo);
+ virtual void assertionStarting(AssertionInfo const&);
+ virtual bool assertionEnded(AssertionStats const& assertionStats);
+ virtual void sectionEnded(SectionStats const& sectionStats);
+ virtual void testCaseEnded(TestCaseStats const& testCaseStats);
+ virtual void testGroupEnded(TestGroupStats const& testGroupStats);
+ virtual void testRunEnded(TestRunStats const& testRunStats);
+ virtual void skipTest(TestCaseInfo const&);
+
+ private:
+ Ptr<IReporter> m_legacyReporter;
+};
+}
+
+namespace Catch {
+LegacyReporterAdapter::LegacyReporterAdapter(Ptr<IReporter> const& legacyReporter)
+ : m_legacyReporter(legacyReporter)
+{
+}
+LegacyReporterAdapter::~LegacyReporterAdapter() {}
+
+ReporterPreferences LegacyReporterAdapter::getPreferences() const
+{
+ ReporterPreferences prefs;
+ prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout();
+ return prefs;
+}
+
+void LegacyReporterAdapter::noMatchingTestCases(std::string const&) {}
+void LegacyReporterAdapter::testRunStarting(TestRunInfo const&)
+{
+ m_legacyReporter->StartTesting();
+}
+void LegacyReporterAdapter::testGroupStarting(GroupInfo const& groupInfo)
+{
+ m_legacyReporter->StartGroup(groupInfo.name);
+}
+void LegacyReporterAdapter::testCaseStarting(TestCaseInfo const& testInfo)
+{
+ m_legacyReporter->StartTestCase(testInfo);
+}
+void LegacyReporterAdapter::sectionStarting(SectionInfo const& sectionInfo)
+{
+ m_legacyReporter->StartSection(sectionInfo.name, sectionInfo.description);
+}
+void LegacyReporterAdapter::assertionStarting(AssertionInfo const&)
+{
+ // Not on legacy interface
+}
+
+bool LegacyReporterAdapter::assertionEnded(AssertionStats const& assertionStats)
+{
+ if (assertionStats.assertionResult.getResultType() != ResultWas::Ok)
+ {
+ for (std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end();
+ it != itEnd;
+ ++it)
+ {
+ if (it->type == ResultWas::Info)
+ {
+ ResultBuilder rb(it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal);
+ rb << it->message;
+ rb.setResultType(ResultWas::Info);
+ AssertionResult result = rb.build();
+ m_legacyReporter->Result(result);
+ }
+ }
+ }
+ m_legacyReporter->Result(assertionStats.assertionResult);
+ return true;
+}
+void LegacyReporterAdapter::sectionEnded(SectionStats const& sectionStats)
+{
+ if (sectionStats.missingAssertions)
+ m_legacyReporter->NoAssertionsInSection(sectionStats.sectionInfo.name);
+ m_legacyReporter->EndSection(sectionStats.sectionInfo.name, sectionStats.assertions);
+}
+void LegacyReporterAdapter::testCaseEnded(TestCaseStats const& testCaseStats)
+{
+ m_legacyReporter->EndTestCase(testCaseStats.testInfo,
+ testCaseStats.totals,
+ testCaseStats.stdOut,
+ testCaseStats.stdErr);
+}
+void LegacyReporterAdapter::testGroupEnded(TestGroupStats const& testGroupStats)
+{
+ if (testGroupStats.aborting)
+ m_legacyReporter->Aborted();
+ m_legacyReporter->EndGroup(testGroupStats.groupInfo.name, testGroupStats.totals);
+}
+void LegacyReporterAdapter::testRunEnded(TestRunStats const& testRunStats)
+{
+ m_legacyReporter->EndTesting(testRunStats.totals);
+}
+void LegacyReporterAdapter::skipTest(TestCaseInfo const&)
+{
+}
+}
+
+// #included from: catch_timer.hpp
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wc++11-long-long"
+#endif
+
+#ifdef CATCH_PLATFORM_WINDOWS
+#include <windows.h>
+#else
+#include <sys/time.h>
+#endif
+
+namespace Catch {
+
+namespace {
+#ifdef CATCH_PLATFORM_WINDOWS
+uint64_t getCurrentTicks()
+{
+ static uint64_t hz = 0, hzo = 0;
+ if (!hz)
+ {
+ QueryPerformanceFrequency(reinterpret_cast<LARGE_INTEGER*>(&hz));
+ QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&hzo));
+ }
+ uint64_t t;
+ QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&t));
+ return ((t - hzo) * 1000000) / hz;
+}
+#else
+uint64_t getCurrentTicks()
+{
+ timeval t;
+ gettimeofday(&t, CATCH_NULL);
+ return static_cast<uint64_t>(t.tv_sec) * 1000000ull + static_cast<uint64_t>(t.tv_usec);
+}
+#endif
+}
+
+void Timer::start()
+{
+ m_ticks = getCurrentTicks();
+}
+unsigned int Timer::getElapsedMicroseconds() const
+{
+ return static_cast<unsigned int>(getCurrentTicks() - m_ticks);
+}
+unsigned int Timer::getElapsedMilliseconds() const
+{
+ return static_cast<unsigned int>(getElapsedMicroseconds() / 1000);
+}
+double Timer::getElapsedSeconds() const
+{
+ return getElapsedMicroseconds() / 1000000.0;
+}
+
+} // namespace Catch
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+// #included from: catch_common.hpp
+#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED
+
+namespace Catch {
+
+bool startsWith(std::string const& s, std::string const& prefix)
+{
+ return s.size() >= prefix.size() && s.substr(0, prefix.size()) == prefix;
+}
+bool endsWith(std::string const& s, std::string const& suffix)
+{
+ return s.size() >= suffix.size() && s.substr(s.size() - suffix.size(), suffix.size()) == suffix;
+}
+bool contains(std::string const& s, std::string const& infix)
+{
+ return s.find(infix) != std::string::npos;
+}
+void toLowerInPlace(std::string& s)
+{
+ std::transform(s.begin(), s.end(), s.begin(), ::tolower);
+}
+std::string toLower(std::string const& s)
+{
+ std::string lc = s;
+ toLowerInPlace(lc);
+ return lc;
+}
+std::string trim(std::string const& str)
+{
+ static char const* whitespaceChars = "\n\r\t ";
+ std::string::size_type start = str.find_first_not_of(whitespaceChars);
+ std::string::size_type end = str.find_last_not_of(whitespaceChars);
+
+ return start != std::string::npos ? str.substr(start, 1 + end - start) : "";
+}
+
+bool replaceInPlace(std::string& str, std::string const& replaceThis, std::string const& withThis)
+{
+ bool replaced = false;
+ std::size_t i = str.find(replaceThis);
+ while (i != std::string::npos)
+ {
+ replaced = true;
+ str = str.substr(0, i) + withThis + str.substr(i + replaceThis.size());
+ if (i < str.size() - withThis.size())
+ i = str.find(replaceThis, i + withThis.size());
+ else
+ i = std::string::npos;
+ }
+ return replaced;
+}
+
+pluralise::pluralise(std::size_t count, std::string const& label)
+ : m_count(count),
+ m_label(label)
+{
+}
+
+std::ostream& operator<<(std::ostream& os, pluralise const& pluraliser)
+{
+ os << pluraliser.m_count << " " << pluraliser.m_label;
+ if (pluraliser.m_count != 1)
+ os << "s";
+ return os;
+}
+
+SourceLineInfo::SourceLineInfo() : line(0) {}
+SourceLineInfo::SourceLineInfo(char const* _file, std::size_t _line)
+ : file(_file),
+ line(_line)
+{
+}
+SourceLineInfo::SourceLineInfo(SourceLineInfo const& other)
+ : file(other.file),
+ line(other.line)
+{
+}
+bool SourceLineInfo::empty() const
+{
+ return file.empty();
+}
+bool SourceLineInfo::operator==(SourceLineInfo const& other) const
+{
+ return line == other.line && file == other.file;
+}
+bool SourceLineInfo::operator<(SourceLineInfo const& other) const
+{
+ return line < other.line || (line == other.line && file < other.file);
+}
+
+void seedRng(IConfig const& config)
+{
+ if (config.rngSeed() != 0)
+ std::srand(config.rngSeed());
+}
+unsigned int rngSeed()
+{
+ return getCurrentContext().getConfig()->rngSeed();
+}
+
+std::ostream& operator<<(std::ostream& os, SourceLineInfo const& info)
+{
+#ifndef __GNUG__
+ os << info.file << "(" << info.line << ")";
+#else
+ os << info.file << ":" << info.line;
+#endif
+ return os;
+}
+
+void throwLogicError(std::string const& message, SourceLineInfo const& locationInfo)
+{
+ std::ostringstream oss;
+ oss << locationInfo << ": Internal Catch error: '" << message << "'";
+ if (alwaysTrue())
+ throw std::logic_error(oss.str());
+}
+}
+
+// #included from: catch_section.hpp
+#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED
+
+namespace Catch {
+
+SectionInfo::SectionInfo(SourceLineInfo const& _lineInfo,
+ std::string const& _name,
+ std::string const& _description)
+ : name(_name),
+ description(_description),
+ lineInfo(_lineInfo)
+{
+}
+
+Section::Section(SectionInfo const& info)
+ : m_info(info),
+ m_sectionIncluded(getResultCapture().sectionStarted(m_info, m_assertions))
+{
+ m_timer.start();
+}
+
+Section::~Section()
+{
+ if (m_sectionIncluded)
+ {
+ SectionEndInfo endInfo(m_info, m_assertions, m_timer.getElapsedSeconds());
+ if (std::uncaught_exception())
+ getResultCapture().sectionEndedEarly(endInfo);
+ else
+ getResultCapture().sectionEnded(endInfo);
+ }
+}
+
+// This indicates whether the section should be executed or not
+Section::operator bool() const
+{
+ return m_sectionIncluded;
+}
+
+} // end namespace Catch
+
+// #included from: catch_debugger.hpp
+#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED
+
+#include <iostream>
+
+#ifdef CATCH_PLATFORM_MAC
+
+#include <assert.h>
+#include <stdbool.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace Catch {
+
+// The following function is taken directly from the following technical note:
+// http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html
+
+// Returns true if the current process is being debugged (either
+// running under the debugger or has a debugger attached post facto).
+bool isDebuggerActive()
+{
+
+ int mib[4];
+ struct kinfo_proc info;
+ size_t size;
+
+ // Initialize the flags so that, if sysctl fails for some bizarre
+ // reason, we get a predictable result.
+
+ info.kp_proc.p_flag = 0;
+
+ // Initialize mib, which tells sysctl the info we want, in this case
+ // we're looking for information about a specific process ID.
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PID;
+ mib[3] = getpid();
+
+ // Call sysctl.
+
+ size = sizeof(info);
+ if (sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, CATCH_NULL, 0) != 0)
+ {
+ Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n"
+ << std::endl;
+ return false;
+ }
+
+ // We're being debugged if the P_TRACED flag is set.
+
+ return ((info.kp_proc.p_flag & P_TRACED) != 0);
+}
+} // namespace Catch
+
+#elif defined(_MSC_VER)
+extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
+namespace Catch {
+bool isDebuggerActive()
+{
+ return IsDebuggerPresent() != 0;
+}
+}
+#elif defined(__MINGW32__)
+extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
+namespace Catch {
+bool isDebuggerActive()
+{
+ return IsDebuggerPresent() != 0;
+}
+}
+#else
+namespace Catch {
+inline bool isDebuggerActive() { return false; }
+}
+#endif // Platform
+
+#ifdef CATCH_PLATFORM_WINDOWS
+extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(const char*);
+namespace Catch {
+void writeToDebugConsole(std::string const& text)
+{
+ ::OutputDebugStringA(text.c_str());
+}
+}
+#else
+namespace Catch {
+void writeToDebugConsole(std::string const& text)
+{
+ // !TBD: Need a version for Mac/ XCode and other IDEs
+ Catch::cout() << text;
+}
+}
+#endif // Platform
+
+// #included from: catch_tostring.hpp
+#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED
+
+namespace Catch {
+
+namespace Detail {
+
+const std::string unprintableString = "{?}";
+
+namespace {
+const int hexThreshold = 255;
+
+struct Endianness
+{
+ enum Arch
+ {
+ Big,
+ Little
+ };
+
+ static Arch which()
+ {
+ union _
+ {
+ int asInt;
+ char asChar[sizeof(int)];
+ } u;
+
+ u.asInt = 1;
+ return (u.asChar[sizeof(int) - 1] == 1) ? Big : Little;
+ }
+};
+}
+
+std::string rawMemoryToString(const void* object, std::size_t size)
+{
+ // Reverse order for little endian architectures
+ int i = 0, end = static_cast<int>(size), inc = 1;
+ if (Endianness::which() == Endianness::Little)
+ {
+ i = end - 1;
+ end = inc = -1;
+ }
+
+ unsigned char const* bytes = static_cast<unsigned char const*>(object);
+ std::ostringstream os;
+ os << "0x" << std::setfill('0') << std::hex;
+ for (; i != end; i += inc)
+ os << std::setw(2) << static_cast<unsigned>(bytes[i]);
+ return os.str();
+}
+}
+
+std::string toString(std::string const& value)
+{
+ std::string s = value;
+ if (getCurrentContext().getConfig()->showInvisibles())
+ {
+ for (size_t i = 0; i < s.size(); ++i)
+ {
+ std::string subs;
+ switch (s[i])
+ {
+ case '\n':
+ subs = "\\n";
+ break;
+ case '\t':
+ subs = "\\t";
+ break;
+ default:
+ break;
+ }
+ if (!subs.empty())
+ {
+ s = s.substr(0, i) + subs + s.substr(i + 1);
+ ++i;
+ }
+ }
+ }
+ return "\"" + s + "\"";
+}
+std::string toString(std::wstring const& value)
+{
+
+ std::string s;
+ s.reserve(value.size());
+ for (size_t i = 0; i < value.size(); ++i)
+ s += value[i] <= 0xff ? static_cast<char>(value[i]) : '?';
+ return Catch::toString(s);
+}
+
+std::string toString(const char* const value)
+{
+ return value ? Catch::toString(std::string(value)) : std::string("{null string}");
+}
+
+std::string toString(char* const value)
+{
+ return Catch::toString(static_cast<const char*>(value));
+}
+
+std::string toString(const wchar_t* const value)
+{
+ return value ? Catch::toString(std::wstring(value)) : std::string("{null string}");
+}
+
+std::string toString(wchar_t* const value)
+{
+ return Catch::toString(static_cast<const wchar_t*>(value));
+}
+
+std::string toString(int value)
+{
+ std::ostringstream oss;
+ oss << value;
+ if (value > Detail::hexThreshold)
+ oss << " (0x" << std::hex << value << ")";
+ return oss.str();
+}
+
+std::string toString(unsigned long value)
+{
+ std::ostringstream oss;
+ oss << value;
+ if (value > Detail::hexThreshold)
+ oss << " (0x" << std::hex << value << ")";
+ return oss.str();
+}
+
+std::string toString(unsigned int value)
+{
+ return Catch::toString(static_cast<unsigned long>(value));
+}
+
+template <typename T>
+std::string fpToString(T value, int precision)
+{
+ std::ostringstream oss;
+ oss << std::setprecision(precision)
+ << std::fixed
+ << value;
+ std::string d = oss.str();
+ std::size_t i = d.find_last_not_of('0');
+ if (i != std::string::npos && i != d.size() - 1)
+ {
+ if (d[i] == '.')
+ i++;
+ d = d.substr(0, i + 1);
+ }
+ return d;
+}
+
+std::string toString(const double value)
+{
+ return fpToString(value, 10);
+}
+std::string toString(const float value)
+{
+ return fpToString(value, 5) + "f";
+}
+
+std::string toString(bool value)
+{
+ return value ? "true" : "false";
+}
+
+std::string toString(char value)
+{
+ return value < ' '
+ ? toString(static_cast<unsigned int>(value))
+ : Detail::makeString(value);
+}
+
+std::string toString(signed char value)
+{
+ return toString(static_cast<char>(value));
+}
+
+std::string toString(unsigned char value)
+{
+ return toString(static_cast<char>(value));
+}
+
+#ifdef CATCH_CONFIG_CPP11_LONG_LONG
+std::string toString(long long value)
+{
+ std::ostringstream oss;
+ oss << value;
+ if (value > Detail::hexThreshold)
+ oss << " (0x" << std::hex << value << ")";
+ return oss.str();
+}
+std::string toString(unsigned long long value)
+{
+ std::ostringstream oss;
+ oss << value;
+ if (value > Detail::hexThreshold)
+ oss << " (0x" << std::hex << value << ")";
+ return oss.str();
+}
+#endif
+
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+std::string toString(std::nullptr_t)
+{
+ return "nullptr";
+}
+#endif
+
+#ifdef __OBJC__
+std::string toString(NSString const* const& nsstring)
+{
+ if (!nsstring)
+ return "nil";
+ return "@" + toString([nsstring UTF8String]);
+}
+std::string toString(NSString* CATCH_ARC_STRONG const& nsstring)
+{
+ if (!nsstring)
+ return "nil";
+ return "@" + toString([nsstring UTF8String]);
+}
+std::string toString(NSObject* const& nsObject)
+{
+ return toString([nsObject description]);
+}
+#endif
+
+} // end namespace Catch
+
+// #included from: catch_result_builder.hpp
+#define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED
+
+namespace Catch {
+
+std::string capturedExpressionWithSecondArgument(std::string const& capturedExpression, std::string const& secondArg)
+{
+ return secondArg.empty() || secondArg == "\"\""
+ ? capturedExpression
+ : capturedExpression + ", " + secondArg;
+}
+ResultBuilder::ResultBuilder(char const* macroName,
+ SourceLineInfo const& lineInfo,
+ char const* capturedExpression,
+ ResultDisposition::Flags resultDisposition,
+ char const* secondArg)
+ : m_assertionInfo(macroName, lineInfo, capturedExpressionWithSecondArgument(capturedExpression, secondArg), resultDisposition),
+ m_shouldDebugBreak(false),
+ m_shouldThrow(false)
+{
+}
+
+ResultBuilder& ResultBuilder::setResultType(ResultWas::OfType result)
+{
+ m_data.resultType = result;
+ return *this;
+}
+ResultBuilder& ResultBuilder::setResultType(bool result)
+{
+ m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed;
+ return *this;
+}
+ResultBuilder& ResultBuilder::setLhs(std::string const& lhs)
+{
+ m_exprComponents.lhs = lhs;
+ return *this;
+}
+ResultBuilder& ResultBuilder::setRhs(std::string const& rhs)
+{
+ m_exprComponents.rhs = rhs;
+ return *this;
+}
+ResultBuilder& ResultBuilder::setOp(std::string const& op)
+{
+ m_exprComponents.op = op;
+ return *this;
+}
+
+void ResultBuilder::endExpression()
+{
+ m_exprComponents.testFalse = isFalseTest(m_assertionInfo.resultDisposition);
+ captureExpression();
+}
+
+void ResultBuilder::useActiveException(ResultDisposition::Flags resultDisposition)
+{
+ m_assertionInfo.resultDisposition = resultDisposition;
+ m_stream.oss << Catch::translateActiveException();
+ captureResult(ResultWas::ThrewException);
+}
+
+void ResultBuilder::captureResult(ResultWas::OfType resultType)
+{
+ setResultType(resultType);
+ captureExpression();
+}
+void ResultBuilder::captureExpectedException(std::string const& expectedMessage)
+{
+ if (expectedMessage.empty())
+ captureExpectedException(Matchers::Impl::Generic::AllOf<std::string>());
+ else
+ captureExpectedException(Matchers::Equals(expectedMessage));
+}
+
+void ResultBuilder::captureExpectedException(Matchers::Impl::Matcher<std::string> const& matcher)
+{
+
+ assert(m_exprComponents.testFalse == false);
+ AssertionResultData data = m_data;
+ data.resultType = ResultWas::Ok;
+ data.reconstructedExpression = m_assertionInfo.capturedExpression;
+
+ std::string actualMessage = Catch::translateActiveException();
+ if (!matcher.match(actualMessage))
+ {
+ data.resultType = ResultWas::ExpressionFailed;
+ data.reconstructedExpression = actualMessage;
+ }
+ AssertionResult result(m_assertionInfo, data);
+ handleResult(result);
+}
+
+void ResultBuilder::captureExpression()
+{
+ AssertionResult result = build();
+ handleResult(result);
+}
+void ResultBuilder::handleResult(AssertionResult const& result)
+{
+ getResultCapture().assertionEnded(result);
+
+ if (!result.isOk())
+ {
+ if (getCurrentContext().getConfig()->shouldDebugBreak())
+ m_shouldDebugBreak = true;
+ if (getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal))
+ m_shouldThrow = true;
+ }
+}
+void ResultBuilder::react()
+{
+ if (m_shouldThrow)
+ throw Catch::TestFailureException();
+}
+
+bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; }
+bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); }
+
+AssertionResult ResultBuilder::build() const
+{
+ assert(m_data.resultType != ResultWas::Unknown);
+
+ AssertionResultData data = m_data;
+
+ // Flip bool results if testFalse is set
+ if (m_exprComponents.testFalse)
+ {
+ if (data.resultType == ResultWas::Ok)
+ data.resultType = ResultWas::ExpressionFailed;
+ else if (data.resultType == ResultWas::ExpressionFailed)
+ data.resultType = ResultWas::Ok;
+ }
+
+ data.message = m_stream.oss.str();
+ data.reconstructedExpression = reconstructExpression();
+ if (m_exprComponents.testFalse)
+ {
+ if (m_exprComponents.op == "")
+ data.reconstructedExpression = "!" + data.reconstructedExpression;
+ else
+ data.reconstructedExpression = "!(" + data.reconstructedExpression + ")";
+ }
+ return AssertionResult(m_assertionInfo, data);
+}
+std::string ResultBuilder::reconstructExpression() const
+{
+ if (m_exprComponents.op == "")
+ return m_exprComponents.lhs.empty() ? m_assertionInfo.capturedExpression : m_exprComponents.op + m_exprComponents.lhs;
+ else if (m_exprComponents.op == "matches")
+ return m_exprComponents.lhs + " " + m_exprComponents.rhs;
+ else if (m_exprComponents.op != "!")
+ {
+ if (m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 &&
+ m_exprComponents.lhs.find("\n") == std::string::npos &&
+ m_exprComponents.rhs.find("\n") == std::string::npos)
+ return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs;
+ else
+ return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs;
+ }
+ else
+ return "{can't expand - use " + m_assertionInfo.macroName + "_FALSE( " + m_assertionInfo.capturedExpression.substr(1) + " ) instead of " + m_assertionInfo.macroName + "( " + m_assertionInfo.capturedExpression + " ) for better diagnostics}";
+}
+
+} // end namespace Catch
+
+// #included from: catch_tag_alias_registry.hpp
+#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED
+
+// #included from: catch_tag_alias_registry.h
+#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED
+
+#include <map>
+
+namespace Catch {
+
+class TagAliasRegistry : public ITagAliasRegistry
+{
+ public:
+ virtual ~TagAliasRegistry();
+ virtual Option<TagAlias> find(std::string const& alias) const;
+ virtual std::string expandAliases(std::string const& unexpandedTestSpec) const;
+ void add(char const* alias, char const* tag, SourceLineInfo const& lineInfo);
+ static TagAliasRegistry& get();
+
+ private:
+ std::map<std::string, TagAlias> m_registry;
+};
+
+} // end namespace Catch
+
+#include <iostream>
+#include <map>
+
+namespace Catch {
+
+TagAliasRegistry::~TagAliasRegistry() {}
+
+Option<TagAlias> TagAliasRegistry::find(std::string const& alias) const
+{
+ std::map<std::string, TagAlias>::const_iterator it = m_registry.find(alias);
+ if (it != m_registry.end())
+ return it->second;
+ else
+ return Option<TagAlias>();
+}
+
+std::string TagAliasRegistry::expandAliases(std::string const& unexpandedTestSpec) const
+{
+ std::string expandedTestSpec = unexpandedTestSpec;
+ for (std::map<std::string, TagAlias>::const_iterator it = m_registry.begin(), itEnd = m_registry.end();
+ it != itEnd;
+ ++it)
+ {
+ std::size_t pos = expandedTestSpec.find(it->first);
+ if (pos != std::string::npos)
+ {
+ expandedTestSpec = expandedTestSpec.substr(0, pos) +
+ it->second.tag +
+ expandedTestSpec.substr(pos + it->first.size());
+ }
+ }
+ return expandedTestSpec;
+}
+
+void TagAliasRegistry::add(char const* alias, char const* tag, SourceLineInfo const& lineInfo)
+{
+
+ if (!startsWith(alias, "[@") || !endsWith(alias, "]"))
+ {
+ std::ostringstream oss;
+ oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n"
+ << lineInfo;
+ throw std::domain_error(oss.str().c_str());
+ }
+ if (!m_registry.insert(std::make_pair(alias, TagAlias(tag, lineInfo))).second)
+ {
+ std::ostringstream oss;
+ oss << "error: tag alias, \"" << alias << "\" already registered.\n"
+ << "\tFirst seen at " << find(alias)->lineInfo << "\n"
+ << "\tRedefined at " << lineInfo;
+ throw std::domain_error(oss.str().c_str());
+ }
+}
+
+TagAliasRegistry& TagAliasRegistry::get()
+{
+ static TagAliasRegistry instance;
+ return instance;
+}
+
+ITagAliasRegistry::~ITagAliasRegistry() {}
+ITagAliasRegistry const& ITagAliasRegistry::get() { return TagAliasRegistry::get(); }
+
+RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo)
+{
+ try
+ {
+ TagAliasRegistry::get().add(alias, tag, lineInfo);
+ }
+ catch (std::exception& ex)
+ {
+ Colour colourGuard(Colour::Red);
+ Catch::cerr() << ex.what() << std::endl;
+ exit(1);
+ }
+}
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_multi.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_MULTI_HPP_INCLUDED
+
+namespace Catch {
+
+class MultipleReporters : public SharedImpl<IStreamingReporter>
+{
+ typedef std::vector<Ptr<IStreamingReporter>> Reporters;
+ Reporters m_reporters;
+
+ public:
+ void add(Ptr<IStreamingReporter> const& reporter)
+ {
+ m_reporters.push_back(reporter);
+ }
+
+ public: // IStreamingReporter
+ virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE
+ {
+ return m_reporters[0]->getPreferences();
+ }
+
+ virtual void noMatchingTestCases(std::string const& spec) CATCH_OVERRIDE
+ {
+ for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it)
+ (*it)->noMatchingTestCases(spec);
+ }
+
+ virtual void testRunStarting(TestRunInfo const& testRunInfo) CATCH_OVERRIDE
+ {
+ for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it)
+ (*it)->testRunStarting(testRunInfo);
+ }
+
+ virtual void testGroupStarting(GroupInfo const& groupInfo) CATCH_OVERRIDE
+ {
+ for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it)
+ (*it)->testGroupStarting(groupInfo);
+ }
+
+ virtual void testCaseStarting(TestCaseInfo const& testInfo) CATCH_OVERRIDE
+ {
+ for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it)
+ (*it)->testCaseStarting(testInfo);
+ }
+
+ virtual void sectionStarting(SectionInfo const& sectionInfo) CATCH_OVERRIDE
+ {
+ for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it)
+ (*it)->sectionStarting(sectionInfo);
+ }
+
+ virtual void assertionStarting(AssertionInfo const& assertionInfo) CATCH_OVERRIDE
+ {
+ for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it)
+ (*it)->assertionStarting(assertionInfo);
+ }
+
+ // The return value indicates if the messages buffer should be cleared:
+ virtual bool assertionEnded(AssertionStats const& assertionStats) CATCH_OVERRIDE
+ {
+ bool clearBuffer = false;
+ for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it)
+ clearBuffer |= (*it)->assertionEnded(assertionStats);
+ return clearBuffer;
+ }
+
+ virtual void sectionEnded(SectionStats const& sectionStats) CATCH_OVERRIDE
+ {
+ for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it)
+ (*it)->sectionEnded(sectionStats);
+ }
+
+ virtual void testCaseEnded(TestCaseStats const& testCaseStats) CATCH_OVERRIDE
+ {
+ for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it)
+ (*it)->testCaseEnded(testCaseStats);
+ }
+
+ virtual void testGroupEnded(TestGroupStats const& testGroupStats) CATCH_OVERRIDE
+ {
+ for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it)
+ (*it)->testGroupEnded(testGroupStats);
+ }
+
+ virtual void testRunEnded(TestRunStats const& testRunStats) CATCH_OVERRIDE
+ {
+ for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it)
+ (*it)->testRunEnded(testRunStats);
+ }
+
+ virtual void skipTest(TestCaseInfo const& testInfo) CATCH_OVERRIDE
+ {
+ for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it)
+ (*it)->skipTest(testInfo);
+ }
+};
+
+Ptr<IStreamingReporter> addReporter(Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter)
+{
+ Ptr<IStreamingReporter> resultingReporter;
+
+ if (existingReporter)
+ {
+ MultipleReporters* multi = dynamic_cast<MultipleReporters*>(existingReporter.get());
+ if (!multi)
+ {
+ multi = new MultipleReporters;
+ resultingReporter = Ptr<IStreamingReporter>(multi);
+ if (existingReporter)
+ multi->add(existingReporter);
+ }
+ else
+ resultingReporter = existingReporter;
+ multi->add(additionalReporter);
+ }
+ else
+ resultingReporter = additionalReporter;
+
+ return resultingReporter;
+}
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_xml.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED
+
+// #included from: catch_reporter_bases.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED
+
+#include <cstring>
+
+namespace Catch {
+
+struct StreamingReporterBase : SharedImpl<IStreamingReporter>
+{
+
+ StreamingReporterBase(ReporterConfig const& _config)
+ : m_config(_config.fullConfig()),
+ stream(_config.stream())
+ {
+ m_reporterPrefs.shouldRedirectStdOut = false;
+ }
+
+ virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE
+ {
+ return m_reporterPrefs;
+ }
+
+ virtual ~StreamingReporterBase() CATCH_OVERRIDE;
+
+ virtual void noMatchingTestCases(std::string const&) CATCH_OVERRIDE {}
+
+ virtual void testRunStarting(TestRunInfo const& _testRunInfo) CATCH_OVERRIDE
+ {
+ currentTestRunInfo = _testRunInfo;
+ }
+ virtual void testGroupStarting(GroupInfo const& _groupInfo) CATCH_OVERRIDE
+ {
+ currentGroupInfo = _groupInfo;
+ }
+
+ virtual void testCaseStarting(TestCaseInfo const& _testInfo) CATCH_OVERRIDE
+ {
+ currentTestCaseInfo = _testInfo;
+ }
+ virtual void sectionStarting(SectionInfo const& _sectionInfo) CATCH_OVERRIDE
+ {
+ m_sectionStack.push_back(_sectionInfo);
+ }
+
+ virtual void sectionEnded(SectionStats const& /* _sectionStats */) CATCH_OVERRIDE
+ {
+ m_sectionStack.pop_back();
+ }
+ virtual void testCaseEnded(TestCaseStats const& /* _testCaseStats */) CATCH_OVERRIDE
+ {
+ currentTestCaseInfo.reset();
+ }
+ virtual void testGroupEnded(TestGroupStats const& /* _testGroupStats */) CATCH_OVERRIDE
+ {
+ currentGroupInfo.reset();
+ }
+ virtual void testRunEnded(TestRunStats const& /* _testRunStats */) CATCH_OVERRIDE
+ {
+ currentTestCaseInfo.reset();
+ currentGroupInfo.reset();
+ currentTestRunInfo.reset();
+ }
+
+ virtual void skipTest(TestCaseInfo const&) CATCH_OVERRIDE
+ {
+ // Don't do anything with this by default.
+ // It can optionally be overridden in the derived class.
+ }
+
+ Ptr<IConfig const> m_config;
+ std::ostream& stream;
+
+ LazyStat<TestRunInfo> currentTestRunInfo;
+ LazyStat<GroupInfo> currentGroupInfo;
+ LazyStat<TestCaseInfo> currentTestCaseInfo;
+
+ std::vector<SectionInfo> m_sectionStack;
+ ReporterPreferences m_reporterPrefs;
+};
+
+struct CumulativeReporterBase : SharedImpl<IStreamingReporter>
+{
+ template <typename T, typename ChildNodeT>
+ struct Node : SharedImpl<>
+ {
+ explicit Node(T const& _value) : value(_value) {}
+ virtual ~Node() {}
+
+ typedef std::vector<Ptr<ChildNodeT>> ChildNodes;
+ T value;
+ ChildNodes children;
+ };
+ struct SectionNode : SharedImpl<>
+ {
+ explicit SectionNode(SectionStats const& _stats) : stats(_stats) {}
+ virtual ~SectionNode();
+
+ bool operator==(SectionNode const& other) const
+ {
+ return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo;
+ }
+ bool operator==(Ptr<SectionNode> const& other) const
+ {
+ return operator==(*other);
+ }
+
+ SectionStats stats;
+ typedef std::vector<Ptr<SectionNode>> ChildSections;
+ typedef std::vector<AssertionStats> Assertions;
+ ChildSections childSections;
+ Assertions assertions;
+ std::string stdOut;
+ std::string stdErr;
+ };
+
+ struct BySectionInfo
+ {
+ BySectionInfo(SectionInfo const& other) : m_other(other) {}
+ BySectionInfo(BySectionInfo const& other) : m_other(other.m_other) {}
+ bool operator()(Ptr<SectionNode> const& node) const
+ {
+ return node->stats.sectionInfo.lineInfo == m_other.lineInfo;
+ }
+
+ private:
+ void operator=(BySectionInfo const&);
+ SectionInfo const& m_other;
+ };
+
+ typedef Node<TestCaseStats, SectionNode> TestCaseNode;
+ typedef Node<TestGroupStats, TestCaseNode> TestGroupNode;
+ typedef Node<TestRunStats, TestGroupNode> TestRunNode;
+
+ CumulativeReporterBase(ReporterConfig const& _config)
+ : m_config(_config.fullConfig()),
+ stream(_config.stream())
+ {
+ m_reporterPrefs.shouldRedirectStdOut = false;
+ }
+ ~CumulativeReporterBase();
+
+ virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE
+ {
+ return m_reporterPrefs;
+ }
+
+ virtual void testRunStarting(TestRunInfo const&) CATCH_OVERRIDE {}
+ virtual void testGroupStarting(GroupInfo const&) CATCH_OVERRIDE {}
+
+ virtual void testCaseStarting(TestCaseInfo const&) CATCH_OVERRIDE {}
+
+ virtual void sectionStarting(SectionInfo const& sectionInfo) CATCH_OVERRIDE
+ {
+ SectionStats incompleteStats(sectionInfo, Counts(), 0, false);
+ Ptr<SectionNode> node;
+ if (m_sectionStack.empty())
+ {
+ if (!m_rootSection)
+ m_rootSection = new SectionNode(incompleteStats);
+ node = m_rootSection;
+ }
+ else
+ {
+ SectionNode& parentNode = *m_sectionStack.back();
+ SectionNode::ChildSections::const_iterator it =
+ std::find_if(parentNode.childSections.begin(),
+ parentNode.childSections.end(),
+ BySectionInfo(sectionInfo));
+ if (it == parentNode.childSections.end())
+ {
+ node = new SectionNode(incompleteStats);
+ parentNode.childSections.push_back(node);
+ }
+ else
+ node = *it;
+ }
+ m_sectionStack.push_back(node);
+ m_deepestSection = node;
+ }
+
+ virtual void assertionStarting(AssertionInfo const&) CATCH_OVERRIDE {}
+
+ virtual bool assertionEnded(AssertionStats const& assertionStats)
+ {
+ assert(!m_sectionStack.empty());
+ SectionNode& sectionNode = *m_sectionStack.back();
+ sectionNode.assertions.push_back(assertionStats);
+ return true;
+ }
+ virtual void sectionEnded(SectionStats const& sectionStats) CATCH_OVERRIDE
+ {
+ assert(!m_sectionStack.empty());
+ SectionNode& node = *m_sectionStack.back();
+ node.stats = sectionStats;
+ m_sectionStack.pop_back();
+ }
+ virtual void testCaseEnded(TestCaseStats const& testCaseStats) CATCH_OVERRIDE
+ {
+ Ptr<TestCaseNode> node = new TestCaseNode(testCaseStats);
+ assert(m_sectionStack.size() == 0);
+ node->children.push_back(m_rootSection);
+ m_testCases.push_back(node);
+ m_rootSection.reset();
+
+ assert(m_deepestSection);
+ m_deepestSection->stdOut = testCaseStats.stdOut;
+ m_deepestSection->stdErr = testCaseStats.stdErr;
+ }
+ virtual void testGroupEnded(TestGroupStats const& testGroupStats) CATCH_OVERRIDE
+ {
+ Ptr<TestGroupNode> node = new TestGroupNode(testGroupStats);
+ node->children.swap(m_testCases);
+ m_testGroups.push_back(node);
+ }
+ virtual void testRunEnded(TestRunStats const& testRunStats) CATCH_OVERRIDE
+ {
+ Ptr<TestRunNode> node = new TestRunNode(testRunStats);
+ node->children.swap(m_testGroups);
+ m_testRuns.push_back(node);
+ testRunEndedCumulative();
+ }
+ virtual void testRunEndedCumulative() = 0;
+
+ virtual void skipTest(TestCaseInfo const&) CATCH_OVERRIDE {}
+
+ Ptr<IConfig const> m_config;
+ std::ostream& stream;
+ std::vector<AssertionStats> m_assertions;
+ std::vector<std::vector<Ptr<SectionNode>>> m_sections;
+ std::vector<Ptr<TestCaseNode>> m_testCases;
+ std::vector<Ptr<TestGroupNode>> m_testGroups;
+
+ std::vector<Ptr<TestRunNode>> m_testRuns;
+
+ Ptr<SectionNode> m_rootSection;
+ Ptr<SectionNode> m_deepestSection;
+ std::vector<Ptr<SectionNode>> m_sectionStack;
+ ReporterPreferences m_reporterPrefs;
+};
+
+template <char C>
+char const* getLineOfChars()
+{
+ static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0};
+ if (!*line)
+ {
+ memset(line, C, CATCH_CONFIG_CONSOLE_WIDTH - 1);
+ line[CATCH_CONFIG_CONSOLE_WIDTH - 1] = 0;
+ }
+ return line;
+}
+
+struct TestEventListenerBase : StreamingReporterBase
+{
+ TestEventListenerBase(ReporterConfig const& _config)
+ : StreamingReporterBase(_config)
+ {
+ }
+
+ virtual void assertionStarting(AssertionInfo const&) CATCH_OVERRIDE {}
+ virtual bool assertionEnded(AssertionStats const&) CATCH_OVERRIDE
+ {
+ return false;
+ }
+};
+
+} // end namespace Catch
+
+// #included from: ../internal/catch_reporter_registrars.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED
+
+namespace Catch {
+
+template <typename T>
+class LegacyReporterRegistrar
+{
+
+ class ReporterFactory : public IReporterFactory
+ {
+ virtual IStreamingReporter* create(ReporterConfig const& config) const
+ {
+ return new LegacyReporterAdapter(new T(config));
+ }
+
+ virtual std::string getDescription() const
+ {
+ return T::getDescription();
+ }
+ };
+
+ public:
+ LegacyReporterRegistrar(std::string const& name)
+ {
+ getMutableRegistryHub().registerReporter(name, new ReporterFactory());
+ }
+};
+
+template <typename T>
+class ReporterRegistrar
+{
+
+ class ReporterFactory : public SharedImpl<IReporterFactory>
+ {
+
+ // *** Please Note ***:
+ // - If you end up here looking at a compiler error because it's trying to register
+ // your custom reporter class be aware that the native reporter interface has changed
+ // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via
+ // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter.
+ // However please consider updating to the new interface as the old one is now
+ // deprecated and will probably be removed quite soon!
+ // Please contact me via github if you have any questions at all about this.
+ // In fact, ideally, please contact me anyway to let me know you've hit this - as I have
+ // no idea who is actually using custom reporters at all (possibly no-one!).
+ // The new interface is designed to minimise exposure to interface changes in the future.
+ virtual IStreamingReporter* create(ReporterConfig const& config) const
+ {
+ return new T(config);
+ }
+
+ virtual std::string getDescription() const
+ {
+ return T::getDescription();
+ }
+ };
+
+ public:
+ ReporterRegistrar(std::string const& name)
+ {
+ getMutableRegistryHub().registerReporter(name, new ReporterFactory());
+ }
+};
+
+template <typename T>
+class ListenerRegistrar
+{
+
+ class ListenerFactory : public SharedImpl<IReporterFactory>
+ {
+
+ virtual IStreamingReporter* create(ReporterConfig const& config) const
+ {
+ return new T(config);
+ }
+ virtual std::string getDescription() const
+ {
+ return "";
+ }
+ };
+
+ public:
+ ListenerRegistrar()
+ {
+ getMutableRegistryHub().registerListener(new ListenerFactory());
+ }
+};
+}
+
+#define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER(name, reporterType) \
+ namespace { \
+ Catch::LegacyReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType(name); \
+ }
+
+#define INTERNAL_CATCH_REGISTER_REPORTER(name, reporterType) \
+ namespace { \
+ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType(name); \
+ }
+
+#define INTERNAL_CATCH_REGISTER_LISTENER(listenerType) \
+ namespace { \
+ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; \
+ }
+
+// #included from: ../internal/catch_xmlwriter.hpp
+#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED
+
+#include <iomanip>
+#include <sstream>
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+class XmlEncode
+{
+ public:
+ enum ForWhat
+ {
+ ForTextNodes,
+ ForAttributes
+ };
+
+ XmlEncode(std::string const& str, ForWhat forWhat = ForTextNodes)
+ : m_str(str),
+ m_forWhat(forWhat)
+ {
+ }
+
+ void encodeTo(std::ostream& os) const
+ {
+
+ // Apostrophe escaping not necessary if we always use " to write attributes
+ // (see: http://www.w3.org/TR/xml/#syntax)
+
+ for (std::size_t i = 0; i < m_str.size(); ++i)
+ {
+ char c = m_str[i];
+ switch (c)
+ {
+ case '<':
+ os << "<";
+ break;
+ case '&':
+ os << "&";
+ break;
+
+ case '>':
+ // See: http://www.w3.org/TR/xml/#syntax
+ if (i > 2 && m_str[i - 1] == ']' && m_str[i - 2] == ']')
+ os << ">";
+ else
+ os << c;
+ break;
+
+ case '\"':
+ if (m_forWhat == ForAttributes)
+ os << """;
+ else
+ os << c;
+ break;
+
+ default:
+ // Escape control chars - based on contribution by @espenalb in PR #465
+ if ((c < '\x09') || (c > '\x0D' && c < '\x20') || c == '\x7F')
+ os << "&#x" << std::uppercase << std::hex << static_cast<int>(c);
+ else
+ os << c;
+ }
+ }
+ }
+
+ friend std::ostream& operator<<(std::ostream& os, XmlEncode const& xmlEncode)
+ {
+ xmlEncode.encodeTo(os);
+ return os;
+ }
+
+ private:
+ std::string m_str;
+ ForWhat m_forWhat;
+};
+
+class XmlWriter
+{
+ public:
+ class ScopedElement
+ {
+ public:
+ ScopedElement(XmlWriter* writer)
+ : m_writer(writer)
+ {
+ }
+
+ ScopedElement(ScopedElement const& other)
+ : m_writer(other.m_writer)
+ {
+ other.m_writer = CATCH_NULL;
+ }
+
+ ~ScopedElement()
+ {
+ if (m_writer)
+ m_writer->endElement();
+ }
+
+ ScopedElement& writeText(std::string const& text, bool indent = true)
+ {
+ m_writer->writeText(text, indent);
+ return *this;
+ }
+
+ template <typename T>
+ ScopedElement& writeAttribute(std::string const& name, T const& attribute)
+ {
+ m_writer->writeAttribute(name, attribute);
+ return *this;
+ }
+
+ private:
+ mutable XmlWriter* m_writer;
+ };
+
+ XmlWriter()
+ : m_tagIsOpen(false),
+ m_needsNewline(false),
+ m_os(&Catch::cout())
+ {
+ }
+
+ XmlWriter(std::ostream& os)
+ : m_tagIsOpen(false),
+ m_needsNewline(false),
+ m_os(&os)
+ {
+ }
+
+ ~XmlWriter()
+ {
+ while (!m_tags.empty())
+ endElement();
+ }
+
+ XmlWriter& startElement(std::string const& name)
+ {
+ ensureTagClosed();
+ newlineIfNecessary();
+ stream() << m_indent << "<" << name;
+ m_tags.push_back(name);
+ m_indent += " ";
+ m_tagIsOpen = true;
+ return *this;
+ }
+
+ ScopedElement scopedElement(std::string const& name)
+ {
+ ScopedElement scoped(this);
+ startElement(name);
+ return scoped;
+ }
+
+ XmlWriter& endElement()
+ {
+ newlineIfNecessary();
+ m_indent = m_indent.substr(0, m_indent.size() - 2);
+ if (m_tagIsOpen)
+ {
+ stream() << "/>\n";
+ m_tagIsOpen = false;
+ }
+ else
+ {
+ stream() << m_indent << "</" << m_tags.back() << ">\n";
+ }
+ m_tags.pop_back();
+ return *this;
+ }
+
+ XmlWriter& writeAttribute(std::string const& name, std::string const& attribute)
+ {
+ if (!name.empty() && !attribute.empty())
+ stream() << " " << name << "=\"" << XmlEncode(attribute, XmlEncode::ForAttributes) << "\"";
+ return *this;
+ }
+
+ XmlWriter& writeAttribute(std::string const& name, bool attribute)
+ {
+ stream() << " " << name << "=\"" << (attribute ? "true" : "false") << "\"";
+ return *this;
+ }
+
+ template <typename T>
+ XmlWriter& writeAttribute(std::string const& name, T const& attribute)
+ {
+ std::ostringstream oss;
+ oss << attribute;
+ return writeAttribute(name, oss.str());
+ }
+
+ XmlWriter& writeText(std::string const& text, bool indent = true)
+ {
+ if (!text.empty())
+ {
+ bool tagWasOpen = m_tagIsOpen;
+ ensureTagClosed();
+ if (tagWasOpen && indent)
+ stream() << m_indent;
+ stream() << XmlEncode(text);
+ m_needsNewline = true;
+ }
+ return *this;
+ }
+
+ XmlWriter& writeComment(std::string const& text)
+ {
+ ensureTagClosed();
+ stream() << m_indent << "<!--" << text << "-->";
+ m_needsNewline = true;
+ return *this;
+ }
+
+ XmlWriter& writeBlankLine()
+ {
+ ensureTagClosed();
+ stream() << "\n";
+ return *this;
+ }
+
+ void setStream(std::ostream& os)
+ {
+ m_os = &os;
+ }
+
+ private:
+ XmlWriter(XmlWriter const&);
+ void operator=(XmlWriter const&);
+
+ std::ostream& stream()
+ {
+ return *m_os;
+ }
+
+ void ensureTagClosed()
+ {
+ if (m_tagIsOpen)
+ {
+ stream() << ">\n";
+ m_tagIsOpen = false;
+ }
+ }
+
+ void newlineIfNecessary()
+ {
+ if (m_needsNewline)
+ {
+ stream() << "\n";
+ m_needsNewline = false;
+ }
+ }
+
+ bool m_tagIsOpen;
+ bool m_needsNewline;
+ std::vector<std::string> m_tags;
+ std::string m_indent;
+ std::ostream* m_os;
+};
+}
+// #included from: catch_reenable_warnings.h
+
+#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED
+
+#ifdef __clang__
+#ifdef __ICC // icpc defines the __clang__ macro
+#pragma warning(pop)
+#else
+#pragma clang diagnostic pop
+#endif
+#elif defined __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+namespace Catch {
+class XmlReporter : public StreamingReporterBase
+{
+ public:
+ XmlReporter(ReporterConfig const& _config)
+ : StreamingReporterBase(_config),
+ m_sectionDepth(0)
+ {
+ m_reporterPrefs.shouldRedirectStdOut = true;
+ }
+
+ virtual ~XmlReporter() CATCH_OVERRIDE;
+
+ static std::string getDescription()
+ {
+ return "Reports test results as an XML document";
+ }
+
+ public: // StreamingReporterBase
+ virtual void noMatchingTestCases(std::string const& s) CATCH_OVERRIDE
+ {
+ StreamingReporterBase::noMatchingTestCases(s);
+ }
+
+ virtual void testRunStarting(TestRunInfo const& testInfo) CATCH_OVERRIDE
+ {
+ StreamingReporterBase::testRunStarting(testInfo);
+ m_xml.setStream(stream);
+ m_xml.startElement("Catch");
+ if (!m_config->name().empty())
+ m_xml.writeAttribute("name", m_config->name());
+ }
+
+ virtual void testGroupStarting(GroupInfo const& groupInfo) CATCH_OVERRIDE
+ {
+ StreamingReporterBase::testGroupStarting(groupInfo);
+ m_xml.startElement("Group")
+ .writeAttribute("name", groupInfo.name);
+ }
+
+ virtual void testCaseStarting(TestCaseInfo const& testInfo) CATCH_OVERRIDE
+ {
+ StreamingReporterBase::testCaseStarting(testInfo);
+ m_xml.startElement("TestCase").writeAttribute("name", trim(testInfo.name));
+
+ if (m_config->showDurations() == ShowDurations::Always)
+ m_testCaseTimer.start();
+ }
+
+ virtual void sectionStarting(SectionInfo const& sectionInfo) CATCH_OVERRIDE
+ {
+ StreamingReporterBase::sectionStarting(sectionInfo);
+ if (m_sectionDepth++ > 0)
+ {
+ m_xml.startElement("Section")
+ .writeAttribute("name", trim(sectionInfo.name))
+ .writeAttribute("description", sectionInfo.description);
+ }
+ }
+
+ virtual void assertionStarting(AssertionInfo const&) CATCH_OVERRIDE {}
+
+ virtual bool assertionEnded(AssertionStats const& assertionStats) CATCH_OVERRIDE
+ {
+ const AssertionResult& assertionResult = assertionStats.assertionResult;
+
+ // Print any info messages in <Info> tags.
+ if (assertionStats.assertionResult.getResultType() != ResultWas::Ok)
+ {
+ for (std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end();
+ it != itEnd;
+ ++it)
+ {
+ if (it->type == ResultWas::Info)
+ {
+ m_xml.scopedElement("Info")
+ .writeText(it->message);
+ }
+ else if (it->type == ResultWas::Warning)
+ {
+ m_xml.scopedElement("Warning")
+ .writeText(it->message);
+ }
+ }
+ }
+
+ // Drop out if result was successful but we're not printing them.
+ if (!m_config->includeSuccessfulResults() && isOk(assertionResult.getResultType()))
+ return true;
+
+ // Print the expression if there is one.
+ if (assertionResult.hasExpression())
+ {
+ m_xml.startElement("Expression")
+ .writeAttribute("success", assertionResult.succeeded())
+ .writeAttribute("type", assertionResult.getTestMacroName())
+ .writeAttribute("filename", assertionResult.getSourceInfo().file)
+ .writeAttribute("line", assertionResult.getSourceInfo().line);
+
+ m_xml.scopedElement("Original")
+ .writeText(assertionResult.getExpression());
+ m_xml.scopedElement("Expanded")
+ .writeText(assertionResult.getExpandedExpression());
+ }
+
+ // And... Print a result applicable to each result type.
+ switch (assertionResult.getResultType())
+ {
+ case ResultWas::ThrewException:
+ m_xml.scopedElement("Exception")
+ .writeAttribute("filename", assertionResult.getSourceInfo().file)
+ .writeAttribute("line", assertionResult.getSourceInfo().line)
+ .writeText(assertionResult.getMessage());
+ break;
+ case ResultWas::FatalErrorCondition:
+ m_xml.scopedElement("Fatal Error Condition")
+ .writeAttribute("filename", assertionResult.getSourceInfo().file)
+ .writeAttribute("line", assertionResult.getSourceInfo().line)
+ .writeText(assertionResult.getMessage());
+ break;
+ case ResultWas::Info:
+ m_xml.scopedElement("Info")
+ .writeText(assertionResult.getMessage());
+ break;
+ case ResultWas::Warning:
+ // Warning will already have been written
+ break;
+ case ResultWas::ExplicitFailure:
+ m_xml.scopedElement("Failure")
+ .writeText(assertionResult.getMessage());
+ break;
+ default:
+ break;
+ }
+
+ if (assertionResult.hasExpression())
+ m_xml.endElement();
+
+ return true;
+ }
+
+ virtual void sectionEnded(SectionStats const& sectionStats) CATCH_OVERRIDE
+ {
+ StreamingReporterBase::sectionEnded(sectionStats);
+ if (--m_sectionDepth > 0)
+ {
+ XmlWriter::ScopedElement e = m_xml.scopedElement("OverallResults");
+ e.writeAttribute("successes", sectionStats.assertions.passed);
+ e.writeAttribute("failures", sectionStats.assertions.failed);
+ e.writeAttribute("expectedFailures", sectionStats.assertions.failedButOk);
+
+ if (m_config->showDurations() == ShowDurations::Always)
+ e.writeAttribute("durationInSeconds", sectionStats.durationInSeconds);
+
+ m_xml.endElement();
+ }
+ }
+
+ virtual void testCaseEnded(TestCaseStats const& testCaseStats) CATCH_OVERRIDE
+ {
+ StreamingReporterBase::testCaseEnded(testCaseStats);
+ XmlWriter::ScopedElement e = m_xml.scopedElement("OverallResult");
+ e.writeAttribute("success", testCaseStats.totals.assertions.allOk());
+
+ if (m_config->showDurations() == ShowDurations::Always)
+ e.writeAttribute("durationInSeconds", m_testCaseTimer.getElapsedSeconds());
+
+ m_xml.endElement();
+ }
+
+ virtual void testGroupEnded(TestGroupStats const& testGroupStats) CATCH_OVERRIDE
+ {
+ StreamingReporterBase::testGroupEnded(testGroupStats);
+ // TODO: Check testGroupStats.aborting and act accordingly.
+ m_xml.scopedElement("OverallResults")
+ .writeAttribute("successes", testGroupStats.totals.assertions.passed)
+ .writeAttribute("failures", testGroupStats.totals.assertions.failed)
+ .writeAttribute("expectedFailures", testGroupStats.totals.assertions.failedButOk);
+ m_xml.endElement();
+ }
+
+ virtual void testRunEnded(TestRunStats const& testRunStats) CATCH_OVERRIDE
+ {
+ StreamingReporterBase::testRunEnded(testRunStats);
+ m_xml.scopedElement("OverallResults")
+ .writeAttribute("successes", testRunStats.totals.assertions.passed)
+ .writeAttribute("failures", testRunStats.totals.assertions.failed)
+ .writeAttribute("expectedFailures", testRunStats.totals.assertions.failedButOk);
+ m_xml.endElement();
+ }
+
+ private:
+ Timer m_testCaseTimer;
+ XmlWriter m_xml;
+ int m_sectionDepth;
+};
+
+INTERNAL_CATCH_REGISTER_REPORTER("xml", XmlReporter)
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_junit.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED
+
+#include <assert.h>
+
+namespace Catch {
+
+class JunitReporter : public CumulativeReporterBase
+{
+ public:
+ JunitReporter(ReporterConfig const& _config)
+ : CumulativeReporterBase(_config),
+ xml(_config.stream())
+ {
+ m_reporterPrefs.shouldRedirectStdOut = true;
+ }
+
+ virtual ~JunitReporter() CATCH_OVERRIDE;
+
+ static std::string getDescription()
+ {
+ return "Reports test results in an XML format that looks like Ant's junitreport target";
+ }
+
+ virtual void noMatchingTestCases(std::string const& /*spec*/) CATCH_OVERRIDE {}
+
+ virtual void testRunStarting(TestRunInfo const& runInfo) CATCH_OVERRIDE
+ {
+ CumulativeReporterBase::testRunStarting(runInfo);
+ xml.startElement("testsuites");
+ }
+
+ virtual void testGroupStarting(GroupInfo const& groupInfo) CATCH_OVERRIDE
+ {
+ suiteTimer.start();
+ stdOutForSuite.str("");
+ stdErrForSuite.str("");
+ unexpectedExceptions = 0;
+ CumulativeReporterBase::testGroupStarting(groupInfo);
+ }
+
+ virtual bool assertionEnded(AssertionStats const& assertionStats) CATCH_OVERRIDE
+ {
+ if (assertionStats.assertionResult.getResultType() == ResultWas::ThrewException)
+ unexpectedExceptions++;
+ return CumulativeReporterBase::assertionEnded(assertionStats);
+ }
+
+ virtual void testCaseEnded(TestCaseStats const& testCaseStats) CATCH_OVERRIDE
+ {
+ stdOutForSuite << testCaseStats.stdOut;
+ stdErrForSuite << testCaseStats.stdErr;
+ CumulativeReporterBase::testCaseEnded(testCaseStats);
+ }
+
+ virtual void testGroupEnded(TestGroupStats const& testGroupStats) CATCH_OVERRIDE
+ {
+ double suiteTime = suiteTimer.getElapsedSeconds();
+ CumulativeReporterBase::testGroupEnded(testGroupStats);
+ writeGroup(*m_testGroups.back(), suiteTime);
+ }
+
+ virtual void testRunEndedCumulative() CATCH_OVERRIDE
+ {
+ xml.endElement();
+ }
+
+ void writeGroup(TestGroupNode const& groupNode, double suiteTime)
+ {
+ XmlWriter::ScopedElement e = xml.scopedElement("testsuite");
+ TestGroupStats const& stats = groupNode.value;
+ xml.writeAttribute("name", stats.groupInfo.name);
+ xml.writeAttribute("errors", unexpectedExceptions);
+ xml.writeAttribute("failures", stats.totals.assertions.failed - unexpectedExceptions);
+ xml.writeAttribute("tests", stats.totals.assertions.total());
+ xml.writeAttribute("hostname", "tbd"); // !TBD
+ if (m_config->showDurations() == ShowDurations::Never)
+ xml.writeAttribute("time", "");
+ else
+ xml.writeAttribute("time", suiteTime);
+ xml.writeAttribute("timestamp", "tbd"); // !TBD
+
+ // Write test cases
+ for (TestGroupNode::ChildNodes::const_iterator
+ it = groupNode.children.begin(),
+ itEnd = groupNode.children.end();
+ it != itEnd;
+ ++it)
+ writeTestCase(**it);
+
+ xml.scopedElement("system-out").writeText(trim(stdOutForSuite.str()), false);
+ xml.scopedElement("system-err").writeText(trim(stdErrForSuite.str()), false);
+ }
+
+ void writeTestCase(TestCaseNode const& testCaseNode)
+ {
+ TestCaseStats const& stats = testCaseNode.value;
+
+ // All test cases have exactly one section - which represents the
+ // test case itself. That section may have 0-n nested sections
+ assert(testCaseNode.children.size() == 1);
+ SectionNode const& rootSection = *testCaseNode.children.front();
+
+ std::string className = stats.testInfo.className;
+
+ if (className.empty())
+ {
+ if (rootSection.childSections.empty())
+ className = "global";
+ }
+ writeSection(className, "", rootSection);
+ }
+
+ void writeSection(std::string const& className,
+ std::string const& rootName,
+ SectionNode const& sectionNode)
+ {
+ std::string name = trim(sectionNode.stats.sectionInfo.name);
+ if (!rootName.empty())
+ name = rootName + "/" + name;
+
+ if (!sectionNode.assertions.empty() ||
+ !sectionNode.stdOut.empty() ||
+ !sectionNode.stdErr.empty())
+ {
+ XmlWriter::ScopedElement e = xml.scopedElement("testcase");
+ if (className.empty())
+ {
+ xml.writeAttribute("classname", name);
+ xml.writeAttribute("name", "root");
+ }
+ else
+ {
+ xml.writeAttribute("classname", className);
+ xml.writeAttribute("name", name);
+ }
+ xml.writeAttribute("time", Catch::toString(sectionNode.stats.durationInSeconds));
+
+ writeAssertions(sectionNode);
+
+ if (!sectionNode.stdOut.empty())
+ xml.scopedElement("system-out").writeText(trim(sectionNode.stdOut), false);
+ if (!sectionNode.stdErr.empty())
+ xml.scopedElement("system-err").writeText(trim(sectionNode.stdErr), false);
+ }
+ for (SectionNode::ChildSections::const_iterator
+ it = sectionNode.childSections.begin(),
+ itEnd = sectionNode.childSections.end();
+ it != itEnd;
+ ++it)
+ if (className.empty())
+ writeSection(name, "", **it);
+ else
+ writeSection(className, name, **it);
+ }
+
+ void writeAssertions(SectionNode const& sectionNode)
+ {
+ for (SectionNode::Assertions::const_iterator
+ it = sectionNode.assertions.begin(),
+ itEnd = sectionNode.assertions.end();
+ it != itEnd;
+ ++it)
+ writeAssertion(*it);
+ }
+ void writeAssertion(AssertionStats const& stats)
+ {
+ AssertionResult const& result = stats.assertionResult;
+ if (!result.isOk())
+ {
+ std::string elementName;
+ switch (result.getResultType())
+ {
+ case ResultWas::ThrewException:
+ case ResultWas::FatalErrorCondition:
+ elementName = "error";
+ break;
+ case ResultWas::ExplicitFailure:
+ elementName = "failure";
+ break;
+ case ResultWas::ExpressionFailed:
+ elementName = "failure";
+ break;
+ case ResultWas::DidntThrowException:
+ elementName = "failure";
+ break;
+
+ // We should never see these here:
+ case ResultWas::Info:
+ case ResultWas::Warning:
+ case ResultWas::Ok:
+ case ResultWas::Unknown:
+ case ResultWas::FailureBit:
+ case ResultWas::Exception:
+ elementName = "internalError";
+ break;
+ }
+
+ XmlWriter::ScopedElement e = xml.scopedElement(elementName);
+
+ xml.writeAttribute("message", result.getExpandedExpression());
+ xml.writeAttribute("type", result.getTestMacroName());
+
+ std::ostringstream oss;
+ if (!result.getMessage().empty())
+ oss << result.getMessage() << "\n";
+ for (std::vector<MessageInfo>::const_iterator
+ it = stats.infoMessages.begin(),
+ itEnd = stats.infoMessages.end();
+ it != itEnd;
+ ++it)
+ if (it->type == ResultWas::Info)
+ oss << it->message << "\n";
+
+ oss << "at " << result.getSourceInfo();
+ xml.writeText(oss.str(), false);
+ }
+ }
+
+ XmlWriter xml;
+ Timer suiteTimer;
+ std::ostringstream stdOutForSuite;
+ std::ostringstream stdErrForSuite;
+ unsigned int unexpectedExceptions;
+};
+
+INTERNAL_CATCH_REGISTER_REPORTER("junit", JunitReporter)
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_console.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED
+
+namespace Catch {
+
+struct ConsoleReporter : StreamingReporterBase
+{
+ ConsoleReporter(ReporterConfig const& _config)
+ : StreamingReporterBase(_config),
+ m_headerPrinted(false)
+ {
+ }
+
+ virtual ~ConsoleReporter() CATCH_OVERRIDE;
+ static std::string getDescription()
+ {
+ return "Reports test results as plain lines of text";
+ }
+
+ virtual void noMatchingTestCases(std::string const& spec) CATCH_OVERRIDE
+ {
+ stream << "No test cases matched '" << spec << "'" << std::endl;
+ }
+
+ virtual void assertionStarting(AssertionInfo const&) CATCH_OVERRIDE
+ {
+ }
+
+ virtual bool assertionEnded(AssertionStats const& _assertionStats) CATCH_OVERRIDE
+ {
+ AssertionResult const& result = _assertionStats.assertionResult;
+
+ bool printInfoMessages = true;
+
+ // Drop out if result was successful and we're not printing those
+ if (!m_config->includeSuccessfulResults() && result.isOk())
+ {
+ if (result.getResultType() != ResultWas::Warning)
+ return false;
+ printInfoMessages = false;
+ }
+
+ lazyPrint();
+
+ AssertionPrinter printer(stream, _assertionStats, printInfoMessages);
+ printer.print();
+ stream << std::endl;
+ return true;
+ }
+
+ virtual void sectionStarting(SectionInfo const& _sectionInfo) CATCH_OVERRIDE
+ {
+ m_headerPrinted = false;
+ StreamingReporterBase::sectionStarting(_sectionInfo);
+ }
+ virtual void sectionEnded(SectionStats const& _sectionStats) CATCH_OVERRIDE
+ {
+ if (_sectionStats.missingAssertions)
+ {
+ lazyPrint();
+ Colour colour(Colour::ResultError);
+ if (m_sectionStack.size() > 1)
+ stream << "\nNo assertions in section";
+ else
+ stream << "\nNo assertions in test case";
+ stream << " '" << _sectionStats.sectionInfo.name << "'\n"
+ << std::endl;
+ }
+ if (m_headerPrinted)
+ {
+ if (m_config->showDurations() == ShowDurations::Always)
+ stream << "Completed in " << _sectionStats.durationInSeconds << "s" << std::endl;
+ m_headerPrinted = false;
+ }
+ else
+ {
+ if (m_config->showDurations() == ShowDurations::Always)
+ stream << _sectionStats.sectionInfo.name << " completed in " << _sectionStats.durationInSeconds << "s" << std::endl;
+ }
+ StreamingReporterBase::sectionEnded(_sectionStats);
+ }
+
+ virtual void testCaseEnded(TestCaseStats const& _testCaseStats) CATCH_OVERRIDE
+ {
+ StreamingReporterBase::testCaseEnded(_testCaseStats);
+ m_headerPrinted = false;
+ }
+ virtual void testGroupEnded(TestGroupStats const& _testGroupStats) CATCH_OVERRIDE
+ {
+ if (currentGroupInfo.used)
+ {
+ printSummaryDivider();
+ stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n";
+ printTotals(_testGroupStats.totals);
+ stream << "\n"
+ << std::endl;
+ }
+ StreamingReporterBase::testGroupEnded(_testGroupStats);
+ }
+ virtual void testRunEnded(TestRunStats const& _testRunStats) CATCH_OVERRIDE
+ {
+ printTotalsDivider(_testRunStats.totals);
+ printTotals(_testRunStats.totals);
+ stream << std::endl;
+ StreamingReporterBase::testRunEnded(_testRunStats);
+ }
+
+ private:
+ class AssertionPrinter
+ {
+ void operator=(AssertionPrinter const&);
+
+ public:
+ AssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages)
+ : stream(_stream),
+ stats(_stats),
+ result(_stats.assertionResult),
+ colour(Colour::None),
+ message(result.getMessage()),
+ messages(_stats.infoMessages),
+ printInfoMessages(_printInfoMessages)
+ {
+ switch (result.getResultType())
+ {
+ case ResultWas::Ok:
+ colour = Colour::Success;
+ passOrFail = "PASSED";
+ //if( result.hasMessage() )
+ if (_stats.infoMessages.size() == 1)
+ messageLabel = "with message";
+ if (_stats.infoMessages.size() > 1)
+ messageLabel = "with messages";
+ break;
+ case ResultWas::ExpressionFailed:
+ if (result.isOk())
+ {
+ colour = Colour::Success;
+ passOrFail = "FAILED - but was ok";
+ }
+ else
+ {
+ colour = Colour::Error;
+ passOrFail = "FAILED";
+ }
+ if (_stats.infoMessages.size() == 1)
+ messageLabel = "with message";
+ if (_stats.infoMessages.size() > 1)
+ messageLabel = "with messages";
+ break;
+ case ResultWas::ThrewException:
+ colour = Colour::Error;
+ passOrFail = "FAILED";
+ messageLabel = "due to unexpected exception with message";
+ break;
+ case ResultWas::FatalErrorCondition:
+ colour = Colour::Error;
+ passOrFail = "FAILED";
+ messageLabel = "due to a fatal error condition";
+ break;
+ case ResultWas::DidntThrowException:
+ colour = Colour::Error;
+ passOrFail = "FAILED";
+ messageLabel = "because no exception was thrown where one was expected";
+ break;
+ case ResultWas::Info:
+ messageLabel = "info";
+ break;
+ case ResultWas::Warning:
+ messageLabel = "warning";
+ break;
+ case ResultWas::ExplicitFailure:
+ passOrFail = "FAILED";
+ colour = Colour::Error;
+ if (_stats.infoMessages.size() == 1)
+ messageLabel = "explicitly with message";
+ if (_stats.infoMessages.size() > 1)
+ messageLabel = "explicitly with messages";
+ break;
+ // These cases are here to prevent compiler warnings
+ case ResultWas::Unknown:
+ case ResultWas::FailureBit:
+ case ResultWas::Exception:
+ passOrFail = "** internal error **";
+ colour = Colour::Error;
+ break;
+ }
+ }
+
+ void print() const
+ {
+ printSourceInfo();
+ if (stats.totals.assertions.total() > 0)
+ {
+ if (result.isOk())
+ stream << "\n";
+ printResultType();
+ printOriginalExpression();
+ printReconstructedExpression();
+ }
+ else
+ {
+ stream << "\n";
+ }
+ printMessage();
+ }
+
+ private:
+ void printResultType() const
+ {
+ if (!passOrFail.empty())
+ {
+ Colour colourGuard(colour);
+ stream << passOrFail << ":\n";
+ }
+ }
+ void printOriginalExpression() const
+ {
+ if (result.hasExpression())
+ {
+ Colour colourGuard(Colour::OriginalExpression);
+ stream << " ";
+ stream << result.getExpressionInMacro();
+ stream << "\n";
+ }
+ }
+ void printReconstructedExpression() const
+ {
+ if (result.hasExpandedExpression())
+ {
+ stream << "with expansion:\n";
+ Colour colourGuard(Colour::ReconstructedExpression);
+ stream << Text(result.getExpandedExpression(), TextAttributes().setIndent(2)) << "\n";
+ }
+ }
+ void printMessage() const
+ {
+ if (!messageLabel.empty())
+ stream << messageLabel << ":"
+ << "\n";
+ for (std::vector<MessageInfo>::const_iterator it = messages.begin(), itEnd = messages.end();
+ it != itEnd;
+ ++it)
+ {
+ // If this assertion is a warning ignore any INFO messages
+ if (printInfoMessages || it->type != ResultWas::Info)
+ stream << Text(it->message, TextAttributes().setIndent(2)) << "\n";
+ }
+ }
+ void printSourceInfo() const
+ {
+ Colour colourGuard(Colour::FileName);
+ stream << result.getSourceInfo() << ": ";
+ }
+
+ std::ostream& stream;
+ AssertionStats const& stats;
+ AssertionResult const& result;
+ Colour::Code colour;
+ std::string passOrFail;
+ std::string messageLabel;
+ std::string message;
+ std::vector<MessageInfo> messages;
+ bool printInfoMessages;
+ };
+
+ void lazyPrint()
+ {
+
+ if (!currentTestRunInfo.used)
+ lazyPrintRunInfo();
+ if (!currentGroupInfo.used)
+ lazyPrintGroupInfo();
+
+ if (!m_headerPrinted)
+ {
+ printTestCaseAndSectionHeader();
+ m_headerPrinted = true;
+ }
+ }
+ void lazyPrintRunInfo()
+ {
+ stream << "\n"
+ << getLineOfChars<'~'>() << "\n";
+ Colour colour(Colour::SecondaryText);
+ stream << currentTestRunInfo->name
+ << " is a Catch v" << libraryVersion << " host application.\n"
+ << "Run with -? for options\n\n";
+
+ if (m_config->rngSeed() != 0)
+ stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n";
+
+ currentTestRunInfo.used = true;
+ }
+ void lazyPrintGroupInfo()
+ {
+ if (!currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1)
+ {
+ printClosedHeader("Group: " + currentGroupInfo->name);
+ currentGroupInfo.used = true;
+ }
+ }
+ void printTestCaseAndSectionHeader()
+ {
+ assert(!m_sectionStack.empty());
+ printOpenHeader(currentTestCaseInfo->name);
+
+ if (m_sectionStack.size() > 1)
+ {
+ Colour colourGuard(Colour::Headers);
+
+ std::vector<SectionInfo>::const_iterator
+ it = m_sectionStack.begin() + 1, // Skip first section (test case)
+ itEnd = m_sectionStack.end();
+ for (; it != itEnd; ++it)
+ printHeaderString(it->name, 2);
+ }
+
+ SourceLineInfo lineInfo = m_sectionStack.front().lineInfo;
+
+ if (!lineInfo.empty())
+ {
+ stream << getLineOfChars<'-'>() << "\n";
+ Colour colourGuard(Colour::FileName);
+ stream << lineInfo << "\n";
+ }
+ stream << getLineOfChars<'.'>() << "\n"
+ << std::endl;
+ }
+
+ void printClosedHeader(std::string const& _name)
+ {
+ printOpenHeader(_name);
+ stream << getLineOfChars<'.'>() << "\n";
+ }
+ void printOpenHeader(std::string const& _name)
+ {
+ stream << getLineOfChars<'-'>() << "\n";
+ {
+ Colour colourGuard(Colour::Headers);
+ printHeaderString(_name);
+ }
+ }
+
+ // if string has a : in first line will set indent to follow it on
+ // subsequent lines
+ void printHeaderString(std::string const& _string, std::size_t indent = 0)
+ {
+ std::size_t i = _string.find(": ");
+ if (i != std::string::npos)
+ i += 2;
+ else
+ i = 0;
+ stream << Text(_string, TextAttributes()
+ .setIndent(indent + i)
+ .setInitialIndent(indent))
+ << "\n";
+ }
+
+ struct SummaryColumn
+ {
+
+ SummaryColumn(std::string const& _label, Colour::Code _colour)
+ : label(_label),
+ colour(_colour)
+ {
+ }
+ SummaryColumn addRow(std::size_t count)
+ {
+ std::ostringstream oss;
+ oss << count;
+ std::string row = oss.str();
+ for (std::vector<std::string>::iterator it = rows.begin(); it != rows.end(); ++it)
+ {
+ while (it->size() < row.size())
+ *it = " " + *it;
+ while (it->size() > row.size())
+ row = " " + row;
+ }
+ rows.push_back(row);
+ return *this;
+ }
+
+ std::string label;
+ Colour::Code colour;
+ std::vector<std::string> rows;
+ };
+
+ void printTotals(Totals const& totals)
+ {
+ if (totals.testCases.total() == 0)
+ {
+ stream << Colour(Colour::Warning) << "No tests ran\n";
+ }
+ else if (totals.assertions.total() > 0 && totals.assertions.allPassed())
+ {
+ stream << Colour(Colour::ResultSuccess) << "All tests passed";
+ stream << " ("
+ << pluralise(totals.assertions.passed, "assertion") << " in "
+ << pluralise(totals.testCases.passed, "test case") << ")"
+ << "\n";
+ }
+ else
+ {
+
+ std::vector<SummaryColumn> columns;
+ columns.push_back(SummaryColumn("", Colour::None)
+ .addRow(totals.testCases.total())
+ .addRow(totals.assertions.total()));
+ columns.push_back(SummaryColumn("passed", Colour::Success)
+ .addRow(totals.testCases.passed)
+ .addRow(totals.assertions.passed));
+ columns.push_back(SummaryColumn("failed", Colour::ResultError)
+ .addRow(totals.testCases.failed)
+ .addRow(totals.assertions.failed));
+ columns.push_back(SummaryColumn("failed as expected", Colour::ResultExpectedFailure)
+ .addRow(totals.testCases.failedButOk)
+ .addRow(totals.assertions.failedButOk));
+
+ printSummaryRow("test cases", columns, 0);
+ printSummaryRow("assertions", columns, 1);
+ }
+ }
+ void printSummaryRow(std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row)
+ {
+ for (std::vector<SummaryColumn>::const_iterator it = cols.begin(); it != cols.end(); ++it)
+ {
+ std::string value = it->rows[row];
+ if (it->label.empty())
+ {
+ stream << label << ": ";
+ if (value != "0")
+ stream << value;
+ else
+ stream << Colour(Colour::Warning) << "- none -";
+ }
+ else if (value != "0")
+ {
+ stream << Colour(Colour::LightGrey) << " | ";
+ stream << Colour(it->colour)
+ << value << " " << it->label;
+ }
+ }
+ stream << "\n";
+ }
+
+ static std::size_t makeRatio(std::size_t number, std::size_t total)
+ {
+ std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number / total : 0;
+ return (ratio == 0 && number > 0) ? 1 : ratio;
+ }
+ static std::size_t& findMax(std::size_t& i, std::size_t& j, std::size_t& k)
+ {
+ if (i > j && i > k)
+ return i;
+ else if (j > k)
+ return j;
+ else
+ return k;
+ }
+
+ void printTotalsDivider(Totals const& totals)
+ {
+ if (totals.testCases.total() > 0)
+ {
+ std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total());
+ std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total());
+ std::size_t passedRatio = makeRatio(totals.testCases.passed, totals.testCases.total());
+ while (failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1)
+ findMax(failedRatio, failedButOkRatio, passedRatio)++;
+ while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1)
+ findMax(failedRatio, failedButOkRatio, passedRatio)--;
+
+ stream << Colour(Colour::Error) << std::string(failedRatio, '=');
+ stream << Colour(Colour::ResultExpectedFailure) << std::string(failedButOkRatio, '=');
+ if (totals.testCases.allPassed())
+ stream << Colour(Colour::ResultSuccess) << std::string(passedRatio, '=');
+ else
+ stream << Colour(Colour::Success) << std::string(passedRatio, '=');
+ }
+ else
+ {
+ stream << Colour(Colour::Warning) << std::string(CATCH_CONFIG_CONSOLE_WIDTH - 1, '=');
+ }
+ stream << "\n";
+ }
+ void printSummaryDivider()
+ {
+ stream << getLineOfChars<'-'>() << "\n";
+ }
+
+ private:
+ bool m_headerPrinted;
+};
+
+INTERNAL_CATCH_REGISTER_REPORTER("console", ConsoleReporter)
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_compact.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED
+
+namespace Catch {
+
+struct CompactReporter : StreamingReporterBase
+{
+
+ CompactReporter(ReporterConfig const& _config)
+ : StreamingReporterBase(_config)
+ {
+ }
+
+ virtual ~CompactReporter();
+
+ static std::string getDescription()
+ {
+ return "Reports test results on a single line, suitable for IDEs";
+ }
+
+ virtual ReporterPreferences getPreferences() const
+ {
+ ReporterPreferences prefs;
+ prefs.shouldRedirectStdOut = false;
+ return prefs;
+ }
+
+ virtual void noMatchingTestCases(std::string const& spec)
+ {
+ stream << "No test cases matched '" << spec << "'" << std::endl;
+ }
+
+ virtual void assertionStarting(AssertionInfo const&)
+ {
+ }
+
+ virtual bool assertionEnded(AssertionStats const& _assertionStats)
+ {
+ AssertionResult const& result = _assertionStats.assertionResult;
+
+ bool printInfoMessages = true;
+
+ // Drop out if result was successful and we're not printing those
+ if (!m_config->includeSuccessfulResults() && result.isOk())
+ {
+ if (result.getResultType() != ResultWas::Warning)
+ return false;
+ printInfoMessages = false;
+ }
+
+ AssertionPrinter printer(stream, _assertionStats, printInfoMessages);
+ printer.print();
+
+ stream << std::endl;
+ return true;
+ }
+
+ virtual void testRunEnded(TestRunStats const& _testRunStats)
+ {
+ printTotals(_testRunStats.totals);
+ stream << "\n"
+ << std::endl;
+ StreamingReporterBase::testRunEnded(_testRunStats);
+ }
+
+ private:
+ class AssertionPrinter
+ {
+ void operator=(AssertionPrinter const&);
+
+ public:
+ AssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages)
+ : stream(_stream), stats(_stats), result(_stats.assertionResult), messages(_stats.infoMessages), itMessage(_stats.infoMessages.begin()), printInfoMessages(_printInfoMessages)
+ {
+ }
+
+ void print()
+ {
+ printSourceInfo();
+
+ itMessage = messages.begin();
+
+ switch (result.getResultType())
+ {
+ case ResultWas::Ok:
+ printResultType(Colour::ResultSuccess, passedString());
+ printOriginalExpression();
+ printReconstructedExpression();
+ if (!result.hasExpression())
+ printRemainingMessages(Colour::None);
+ else
+ printRemainingMessages();
+ break;
+ case ResultWas::ExpressionFailed:
+ if (result.isOk())
+ printResultType(Colour::ResultSuccess, failedString() + std::string(" - but was ok"));
+ else
+ printResultType(Colour::Error, failedString());
+ printOriginalExpression();
+ printReconstructedExpression();
+ printRemainingMessages();
+ break;
+ case ResultWas::ThrewException:
+ printResultType(Colour::Error, failedString());
+ printIssue("unexpected exception with message:");
+ printMessage();
+ printExpressionWas();
+ printRemainingMessages();
+ break;
+ case ResultWas::FatalErrorCondition:
+ printResultType(Colour::Error, failedString());
+ printIssue("fatal error condition with message:");
+ printMessage();
+ printExpressionWas();
+ printRemainingMessages();
+ break;
+ case ResultWas::DidntThrowException:
+ printResultType(Colour::Error, failedString());
+ printIssue("expected exception, got none");
+ printExpressionWas();
+ printRemainingMessages();
+ break;
+ case ResultWas::Info:
+ printResultType(Colour::None, "info");
+ printMessage();
+ printRemainingMessages();
+ break;
+ case ResultWas::Warning:
+ printResultType(Colour::None, "warning");
+ printMessage();
+ printRemainingMessages();
+ break;
+ case ResultWas::ExplicitFailure:
+ printResultType(Colour::Error, failedString());
+ printIssue("explicitly");
+ printRemainingMessages(Colour::None);
+ break;
+ // These cases are here to prevent compiler warnings
+ case ResultWas::Unknown:
+ case ResultWas::FailureBit:
+ case ResultWas::Exception:
+ printResultType(Colour::Error, "** internal error **");
+ break;
+ }
+ }
+
+ private:
+ // Colour::LightGrey
+
+ static Colour::Code dimColour() { return Colour::FileName; }
+
+#ifdef CATCH_PLATFORM_MAC
+ static const char* failedString()
+ {
+ return "FAILED";
+ }
+ static const char* passedString() { return "PASSED"; }
+#else
+ static const char* failedString()
+ {
+ return "failed";
+ }
+ static const char* passedString() { return "passed"; }
+#endif
+
+ void printSourceInfo() const
+ {
+ Colour colourGuard(Colour::FileName);
+ stream << result.getSourceInfo() << ":";
+ }
+
+ void printResultType(Colour::Code colour, std::string passOrFail) const
+ {
+ if (!passOrFail.empty())
+ {
+ {
+ Colour colourGuard(colour);
+ stream << " " << passOrFail;
+ }
+ stream << ":";
+ }
+ }
+
+ void printIssue(std::string issue) const
+ {
+ stream << " " << issue;
+ }
+
+ void printExpressionWas()
+ {
+ if (result.hasExpression())
+ {
+ stream << ";";
+ {
+ Colour colour(dimColour());
+ stream << " expression was:";
+ }
+ printOriginalExpression();
+ }
+ }
+
+ void printOriginalExpression() const
+ {
+ if (result.hasExpression())
+ {
+ stream << " " << result.getExpression();
+ }
+ }
+
+ void printReconstructedExpression() const
+ {
+ if (result.hasExpandedExpression())
+ {
+ {
+ Colour colour(dimColour());
+ stream << " for: ";
+ }
+ stream << result.getExpandedExpression();
+ }
+ }
+
+ void printMessage()
+ {
+ if (itMessage != messages.end())
+ {
+ stream << " '" << itMessage->message << "'";
+ ++itMessage;
+ }
+ }
+
+ void printRemainingMessages(Colour::Code colour = dimColour())
+ {
+ if (itMessage == messages.end())
+ return;
+
+ // using messages.end() directly yields compilation error:
+ std::vector<MessageInfo>::const_iterator itEnd = messages.end();
+ const std::size_t N = static_cast<std::size_t>(std::distance(itMessage, itEnd));
+
+ {
+ Colour colourGuard(colour);
+ stream << " with " << pluralise(N, "message") << ":";
+ }
+
+ for (; itMessage != itEnd;)
+ {
+ // If this assertion is a warning ignore any INFO messages
+ if (printInfoMessages || itMessage->type != ResultWas::Info)
+ {
+ stream << " '" << itMessage->message << "'";
+ if (++itMessage != itEnd)
+ {
+ Colour colourGuard(dimColour());
+ stream << " and";
+ }
+ }
+ }
+ }
+
+ private:
+ std::ostream& stream;
+ AssertionStats const& stats;
+ AssertionResult const& result;
+ std::vector<MessageInfo> messages;
+ std::vector<MessageInfo>::const_iterator itMessage;
+ bool printInfoMessages;
+ };
+
+ // Colour, message variants:
+ // - white: No tests ran.
+ // - red: Failed [both/all] N test cases, failed [both/all] M assertions.
+ // - white: Passed [both/all] N test cases (no assertions).
+ // - red: Failed N tests cases, failed M assertions.
+ // - green: Passed [both/all] N tests cases with M assertions.
+
+ std::string bothOrAll(std::size_t count) const
+ {
+ return count == 1 ? "" : count == 2 ? "both " : "all ";
+ }
+
+ void printTotals(const Totals& totals) const
+ {
+ if (totals.testCases.total() == 0)
+ {
+ stream << "No tests ran.";
+ }
+ else if (totals.testCases.failed == totals.testCases.total())
+ {
+ Colour colour(Colour::ResultError);
+ const std::string qualify_assertions_failed =
+ totals.assertions.failed == totals.assertions.total() ? bothOrAll(totals.assertions.failed) : "";
+ stream << "Failed " << bothOrAll(totals.testCases.failed)
+ << pluralise(totals.testCases.failed, "test case") << ", "
+ "failed "
+ << qualify_assertions_failed << pluralise(totals.assertions.failed, "assertion") << ".";
+ }
+ else if (totals.assertions.total() == 0)
+ {
+ stream << "Passed " << bothOrAll(totals.testCases.total())
+ << pluralise(totals.testCases.total(), "test case")
+ << " (no assertions).";
+ }
+ else if (totals.assertions.failed)
+ {
+ Colour colour(Colour::ResultError);
+ stream << "Failed " << pluralise(totals.testCases.failed, "test case") << ", "
+ "failed "
+ << pluralise(totals.assertions.failed, "assertion") << ".";
+ }
+ else
+ {
+ Colour colour(Colour::ResultSuccess);
+ stream << "Passed " << bothOrAll(totals.testCases.passed)
+ << pluralise(totals.testCases.passed, "test case") << " with " << pluralise(totals.assertions.passed, "assertion") << ".";
+ }
+ }
+};
+
+INTERNAL_CATCH_REGISTER_REPORTER("compact", CompactReporter)
+
+} // end namespace Catch
+
+namespace Catch {
+// These are all here to avoid warnings about not having any out of line
+// virtual methods
+NonCopyable::~NonCopyable() {}
+IShared::~IShared() {}
+IStream::~IStream() CATCH_NOEXCEPT {}
+FileStream::~FileStream() CATCH_NOEXCEPT {}
+CoutStream::~CoutStream() CATCH_NOEXCEPT {}
+DebugOutStream::~DebugOutStream() CATCH_NOEXCEPT {}
+StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {}
+IContext::~IContext() {}
+IResultCapture::~IResultCapture() {}
+ITestCase::~ITestCase() {}
+ITestCaseRegistry::~ITestCaseRegistry() {}
+IRegistryHub::~IRegistryHub() {}
+IMutableRegistryHub::~IMutableRegistryHub() {}
+IExceptionTranslator::~IExceptionTranslator() {}
+IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {}
+IReporter::~IReporter() {}
+IReporterFactory::~IReporterFactory() {}
+IReporterRegistry::~IReporterRegistry() {}
+IStreamingReporter::~IStreamingReporter() {}
+AssertionStats::~AssertionStats() {}
+SectionStats::~SectionStats() {}
+TestCaseStats::~TestCaseStats() {}
+TestGroupStats::~TestGroupStats() {}
+TestRunStats::~TestRunStats() {}
+CumulativeReporterBase::SectionNode::~SectionNode() {}
+CumulativeReporterBase::~CumulativeReporterBase() {}
+
+StreamingReporterBase::~StreamingReporterBase() {}
+ConsoleReporter::~ConsoleReporter() {}
+CompactReporter::~CompactReporter() {}
+IRunner::~IRunner() {}
+IMutableContext::~IMutableContext() {}
+IConfig::~IConfig() {}
+XmlReporter::~XmlReporter() {}
+JunitReporter::~JunitReporter() {}
+TestRegistry::~TestRegistry() {}
+FreeFunctionTestCase::~FreeFunctionTestCase() {}
+IGeneratorInfo::~IGeneratorInfo() {}
+IGeneratorsForTest::~IGeneratorsForTest() {}
+WildcardPattern::~WildcardPattern() {}
+TestSpec::Pattern::~Pattern() {}
+TestSpec::NamePattern::~NamePattern() {}
+TestSpec::TagPattern::~TagPattern() {}
+TestSpec::ExcludedPattern::~ExcludedPattern() {}
+
+Matchers::Impl::StdString::Equals::~Equals() {}
+Matchers::Impl::StdString::Contains::~Contains() {}
+Matchers::Impl::StdString::StartsWith::~StartsWith() {}
+Matchers::Impl::StdString::EndsWith::~EndsWith() {}
+
+void Config::dummy() {}
+
+namespace TestCaseTracking {
+ITracker::~ITracker() {}
+TrackerBase::~TrackerBase() {}
+SectionTracker::~SectionTracker() {}
+IndexTracker::~IndexTracker() {}
+}
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#endif
+
+#ifdef CATCH_CONFIG_MAIN
+// #included from: internal/catch_default_main.hpp
+#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED
+
+#ifndef __OBJC__
+
+// Standard C/C++ main entry point
+int main(int argc, char* argv[])
+{
+ return Catch::Session().run(argc, argv);
+}
+
+#else // __OBJC__
+
+// Objective-C entry point
+int main(int argc, char* const argv[])
+{
+#if !CATCH_ARC_ENABLED
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+#endif
+
+ Catch::registerTestMethods();
+ int result = Catch::Session().run(argc, (char* const*)argv);
+
+#if !CATCH_ARC_ENABLED
+ [pool drain];
+#endif
+
+ return result;
+}
+
+#endif // __OBJC__
+
+#endif
+
+#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED
+#undef CLARA_CONFIG_MAIN
+#endif
+
+//////
+
+// If this config identifier is defined then all CATCH macros are prefixed with CATCH_
+#ifdef CATCH_CONFIG_PREFIX_ALL
+
+#define CATCH_REQUIRE(expr) INTERNAL_CATCH_TEST(expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE")
+#define CATCH_REQUIRE_FALSE(expr) INTERNAL_CATCH_TEST(expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE")
+
+#define CATCH_REQUIRE_THROWS(expr) INTERNAL_CATCH_THROWS(expr, Catch::ResultDisposition::Normal, "", "CATCH_REQUIRE_THROWS")
+#define CATCH_REQUIRE_THROWS_AS(expr, exceptionType) INTERNAL_CATCH_THROWS_AS(expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS")
+#define CATCH_REQUIRE_THROWS_WITH(expr, matcher) INTERNAL_CATCH_THROWS(expr, Catch::ResultDisposition::Normal, matcher, "CATCH_REQUIRE_THROWS_WITH")
+#define CATCH_REQUIRE_NOTHROW(expr) INTERNAL_CATCH_NO_THROW(expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW")
+
+#define CATCH_CHECK(expr) INTERNAL_CATCH_TEST(expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK")
+#define CATCH_CHECK_FALSE(expr) INTERNAL_CATCH_TEST(expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CATCH_CHECK_FALSE")
+#define CATCH_CHECKED_IF(expr) INTERNAL_CATCH_IF(expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_IF")
+#define CATCH_CHECKED_ELSE(expr) INTERNAL_CATCH_ELSE(expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE")
+#define CATCH_CHECK_NOFAIL(expr) INTERNAL_CATCH_TEST(expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL")
+
+#define CATCH_CHECK_THROWS(expr) INTERNAL_CATCH_THROWS(expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS")
+#define CATCH_CHECK_THROWS_AS(expr, exceptionType) INTERNAL_CATCH_THROWS_AS(expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS")
+#define CATCH_CHECK_THROWS_WITH(expr, matcher) INTERNAL_CATCH_THROWS(expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CATCH_CHECK_THROWS_WITH")
+#define CATCH_CHECK_NOTHROW(expr) INTERNAL_CATCH_NO_THROW(expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW")
+
+#define CHECK_THAT(arg, matcher) INTERNAL_CHECK_THAT(arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT")
+#define CATCH_REQUIRE_THAT(arg, matcher) INTERNAL_CHECK_THAT(arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT")
+
+#define CATCH_INFO(msg) INTERNAL_CATCH_INFO(msg, "CATCH_INFO")
+#define CATCH_WARN(msg) INTERNAL_CATCH_MSG(Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "CATCH_WARN", msg)
+#define CATCH_SCOPED_INFO(msg) INTERNAL_CATCH_INFO(msg, "CATCH_INFO")
+#define CATCH_CAPTURE(msg) INTERNAL_CATCH_INFO(#msg " := " << msg, "CATCH_CAPTURE")
+#define CATCH_SCOPED_CAPTURE(msg) INTERNAL_CATCH_INFO(#msg " := " << msg, "CATCH_CAPTURE")
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+#define CATCH_TEST_CASE(...) INTERNAL_CATCH_TESTCASE(__VA_ARGS__)
+#define CATCH_TEST_CASE_METHOD(className, ...) INTERNAL_CATCH_TEST_CASE_METHOD(className, __VA_ARGS__)
+#define CATCH_METHOD_AS_TEST_CASE(method, ...) INTERNAL_CATCH_METHOD_AS_TEST_CASE(method, __VA_ARGS__)
+#define CATCH_REGISTER_TEST_CASE(...) INTERNAL_CATCH_REGISTER_TESTCASE(__VA_ARGS__)
+#define CATCH_SECTION(...) INTERNAL_CATCH_SECTION(__VA_ARGS__)
+#define CATCH_FAIL(...) INTERNAL_CATCH_MSG(Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__)
+#define CATCH_SUCCEED(...) INTERNAL_CATCH_MSG(Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__)
+#else
+#define CATCH_TEST_CASE(name, description) INTERNAL_CATCH_TESTCASE(name, description)
+#define CATCH_TEST_CASE_METHOD(className, name, description) INTERNAL_CATCH_TEST_CASE_METHOD(className, name, description)
+#define CATCH_METHOD_AS_TEST_CASE(method, name, description) INTERNAL_CATCH_METHOD_AS_TEST_CASE(method, name, description)
+#define CATCH_REGISTER_TEST_CASE(function, name, description) INTERNAL_CATCH_REGISTER_TESTCASE(function, name, description)
+#define CATCH_SECTION(name, description) INTERNAL_CATCH_SECTION(name, description)
+#define CATCH_FAIL(msg) INTERNAL_CATCH_MSG(Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg)
+#define CATCH_SUCCEED(msg) INTERNAL_CATCH_MSG(Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg)
+#endif
+#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE("", "")
+
+#define CATCH_REGISTER_REPORTER(name, reporterType) INTERNAL_CATCH_REGISTER_REPORTER(name, reporterType)
+#define CATCH_REGISTER_LEGACY_REPORTER(name, reporterType) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER(name, reporterType)
+
+#define CATCH_GENERATE(expr) INTERNAL_CATCH_GENERATE(expr)
+
+// "BDD-style" convenience wrappers
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+#define CATCH_SCENARIO(...) CATCH_TEST_CASE("Scenario: " __VA_ARGS__)
+#define CATCH_SCENARIO_METHOD(className, ...) INTERNAL_CATCH_TEST_CASE_METHOD(className, "Scenario: " __VA_ARGS__)
+#else
+#define CATCH_SCENARIO(name, tags) CATCH_TEST_CASE("Scenario: " name, tags)
+#define CATCH_SCENARIO_METHOD(className, name, tags) INTERNAL_CATCH_TEST_CASE_METHOD(className, "Scenario: " name, tags)
+#endif
+#define CATCH_GIVEN(desc) CATCH_SECTION(std::string("Given: ") + desc, "")
+#define CATCH_WHEN(desc) CATCH_SECTION(std::string(" When: ") + desc, "")
+#define CATCH_AND_WHEN(desc) CATCH_SECTION(std::string(" And: ") + desc, "")
+#define CATCH_THEN(desc) CATCH_SECTION(std::string(" Then: ") + desc, "")
+#define CATCH_AND_THEN(desc) CATCH_SECTION(std::string(" And: ") + desc, "")
+
+// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
+#else
+
+#define REQUIRE(expr) INTERNAL_CATCH_TEST(expr, Catch::ResultDisposition::Normal, "REQUIRE")
+#define REQUIRE_FALSE(expr) INTERNAL_CATCH_TEST(expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE")
+
+#define REQUIRE_THROWS(expr) INTERNAL_CATCH_THROWS(expr, Catch::ResultDisposition::Normal, "", "REQUIRE_THROWS")
+#define REQUIRE_THROWS_AS(expr, exceptionType) INTERNAL_CATCH_THROWS_AS(expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS")
+#define REQUIRE_THROWS_WITH(expr, matcher) INTERNAL_CATCH_THROWS(expr, Catch::ResultDisposition::Normal, matcher, "REQUIRE_THROWS_WITH")
+#define REQUIRE_NOTHROW(expr) INTERNAL_CATCH_NO_THROW(expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW")
+
+#define CHECK(expr) INTERNAL_CATCH_TEST(expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK")
+#define CHECK_FALSE(expr) INTERNAL_CATCH_TEST(expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CHECK_FALSE")
+#define CHECKED_IF(expr) INTERNAL_CATCH_IF(expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_IF")
+#define CHECKED_ELSE(expr) INTERNAL_CATCH_ELSE(expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE")
+#define CHECK_NOFAIL(expr) INTERNAL_CATCH_TEST(expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL")
+
+#define CHECK_THROWS(expr) INTERNAL_CATCH_THROWS(expr, Catch::ResultDisposition::ContinueOnFailure, "", "CHECK_THROWS")
+#define CHECK_THROWS_AS(expr, exceptionType) INTERNAL_CATCH_THROWS_AS(expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS")
+#define CHECK_THROWS_WITH(expr, matcher) INTERNAL_CATCH_THROWS(expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CHECK_THROWS_WITH")
+#define CHECK_NOTHROW(expr) INTERNAL_CATCH_NO_THROW(expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW")
+
+#define CHECK_THAT(arg, matcher) INTERNAL_CHECK_THAT(arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT")
+#define REQUIRE_THAT(arg, matcher) INTERNAL_CHECK_THAT(arg, matcher, Catch::ResultDisposition::Normal, "REQUIRE_THAT")
+
+#define INFO(msg) INTERNAL_CATCH_INFO(msg, "INFO")
+#define WARN(msg) INTERNAL_CATCH_MSG(Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "WARN", msg)
+#define SCOPED_INFO(msg) INTERNAL_CATCH_INFO(msg, "INFO")
+#define CAPTURE(msg) INTERNAL_CATCH_INFO(#msg " := " << msg, "CAPTURE")
+#define SCOPED_CAPTURE(msg) INTERNAL_CATCH_INFO(#msg " := " << msg, "CAPTURE")
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+#define TEST_CASE(...) INTERNAL_CATCH_TESTCASE(__VA_ARGS__)
+#define TEST_CASE_METHOD(className, ...) INTERNAL_CATCH_TEST_CASE_METHOD(className, __VA_ARGS__)
+#define METHOD_AS_TEST_CASE(method, ...) INTERNAL_CATCH_METHOD_AS_TEST_CASE(method, __VA_ARGS__)
+#define REGISTER_TEST_CASE(...) INTERNAL_CATCH_REGISTER_TESTCASE(__VA_ARGS__)
+#define SECTION(...) INTERNAL_CATCH_SECTION(__VA_ARGS__)
+#define FAIL(...) INTERNAL_CATCH_MSG(Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__)
+#define SUCCEED(...) INTERNAL_CATCH_MSG(Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__)
+#else
+#define TEST_CASE(name, description) INTERNAL_CATCH_TESTCASE(name, description)
+#define TEST_CASE_METHOD(className, name, description) INTERNAL_CATCH_TEST_CASE_METHOD(className, name, description)
+#define METHOD_AS_TEST_CASE(method, name, description) INTERNAL_CATCH_METHOD_AS_TEST_CASE(method, name, description)
+#define REGISTER_TEST_CASE(method, name, description) INTERNAL_CATCH_REGISTER_TESTCASE(method, name, description)
+#define SECTION(name, description) INTERNAL_CATCH_SECTION(name, description)
+#define FAIL(msg) INTERNAL_CATCH_MSG(Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg)
+#define SUCCEED(msg) INTERNAL_CATCH_MSG(Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg)
+#endif
+#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE("", "")
+
+#define REGISTER_REPORTER(name, reporterType) INTERNAL_CATCH_REGISTER_REPORTER(name, reporterType)
+#define REGISTER_LEGACY_REPORTER(name, reporterType) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER(name, reporterType)
+
+#define GENERATE(expr) INTERNAL_CATCH_GENERATE(expr)
+
+#endif
+
+#define CATCH_TRANSLATE_EXCEPTION(signature) INTERNAL_CATCH_TRANSLATE_EXCEPTION(signature)
+
+// "BDD-style" convenience wrappers
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+#define SCENARIO(...) TEST_CASE("Scenario: " __VA_ARGS__)
+#define SCENARIO_METHOD(className, ...) INTERNAL_CATCH_TEST_CASE_METHOD(className, "Scenario: " __VA_ARGS__)
+#else
+#define SCENARIO(name, tags) TEST_CASE("Scenario: " name, tags)
+#define SCENARIO_METHOD(className, name, tags) INTERNAL_CATCH_TEST_CASE_METHOD(className, "Scenario: " name, tags)
+#endif
+#define GIVEN(desc) SECTION(std::string(" Given: ") + desc, "")
+#define WHEN(desc) SECTION(std::string(" When: ") + desc, "")
+#define AND_WHEN(desc) SECTION(std::string("And when: ") + desc, "")
+#define THEN(desc) SECTION(std::string(" Then: ") + desc, "")
+#define AND_THEN(desc) SECTION(std::string(" And: ") + desc, "")
+
+using Catch::Detail::Approx;
+
+#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
diff --git a/test/our_variant_hello_world.cpp b/test/our_variant_hello_world.cpp
new file mode 100644
index 0000000..be5996b
--- /dev/null
+++ b/test/our_variant_hello_world.cpp
@@ -0,0 +1,20 @@
+#include "variant.hpp"
+
+#include <stdexcept>
+
+struct check
+{
+ template <typename T>
+ void operator()(T const& val) const
+ {
+ if (val != 0) throw std::runtime_error("invalid");
+ }
+};
+
+int main()
+{
+ typedef mapbox::util::variant<bool, int, double> variant_type;
+ variant_type v(0);
+ mapbox::util::apply_visitor(check(), v);
+ return 0;
+}
diff --git a/test/recursive_wrapper_test.cpp b/test/recursive_wrapper_test.cpp
new file mode 100644
index 0000000..0492af4
--- /dev/null
+++ b/test/recursive_wrapper_test.cpp
@@ -0,0 +1,125 @@
+
+#include <cstdlib>
+#include <iostream>
+#include <string>
+#include <typeinfo>
+#include <utility>
+
+#include <boost/timer/timer.hpp>
+
+#include "variant.hpp"
+
+using namespace mapbox;
+
+namespace test {
+
+struct add;
+struct sub;
+
+template <typename OpTag>
+struct binary_op;
+
+typedef util::variant<int,
+ util::recursive_wrapper<binary_op<add>>,
+ util::recursive_wrapper<binary_op<sub>>>
+ expression;
+
+template <typename Op>
+struct binary_op
+{
+ expression left; // variant instantiated here...
+ expression right;
+
+ binary_op(expression&& lhs, expression&& rhs)
+ : left(std::move(lhs)), right(std::move(rhs))
+ {
+ }
+};
+
+struct print
+{
+ template <typename T>
+ void operator()(T const& val) const
+ {
+ std::cerr << val << ":" << typeid(T).name() << std::endl;
+ }
+};
+
+struct test
+{
+ template <typename T>
+ std::string operator()(T const& obj) const
+ {
+ return std::string("TYPE_ID=") + typeid(obj).name();
+ }
+};
+
+struct calculator
+{
+ public:
+ int operator()(int value) const
+ {
+ return value;
+ }
+
+ int operator()(binary_op<add> const& binary) const
+ {
+ return util::apply_visitor(calculator(), binary.left) + util::apply_visitor(calculator(), binary.right);
+ }
+
+ int operator()(binary_op<sub> const& binary) const
+ {
+ return util::apply_visitor(calculator(), binary.left) - util::apply_visitor(calculator(), binary.right);
+ }
+};
+
+struct to_string
+{
+ public:
+ std::string operator()(int value) const
+ {
+ return std::to_string(value);
+ }
+
+ std::string operator()(binary_op<add> const& binary) const
+ {
+ return util::apply_visitor(to_string(), binary.left) + std::string("+") + util::apply_visitor(to_string(), binary.right);
+ }
+
+ std::string operator()(binary_op<sub> const& binary) const
+ {
+ return util::apply_visitor(to_string(), binary.left) + std::string("-") + util::apply_visitor(to_string(), binary.right);
+ }
+};
+
+} // namespace test
+
+int main(int argc, char** argv)
+{
+ if (argc != 2)
+ {
+ std::cerr << "Usage" << argv[0] << " <num-iter>" << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ const std::size_t NUM_ITER = static_cast<std::size_t>(std::stol(argv[1]));
+
+ test::expression sum(test::binary_op<test::add>(2, 3));
+ test::expression result(test::binary_op<test::sub>(std::move(sum), 4));
+
+ std::cerr << "TYPE OF RESULT-> " << util::apply_visitor(test::test(), result) << std::endl;
+
+ int total = 0;
+ {
+ boost::timer::auto_cpu_timer t;
+ for (std::size_t i = 0; i < NUM_ITER; ++i)
+ {
+ total += util::apply_visitor(test::calculator(), result);
+ }
+ }
+ std::cerr << "total=" << total << std::endl;
+
+ std::cerr << util::apply_visitor(test::to_string(), result) << "=" << util::apply_visitor(test::calculator(), result) << std::endl;
+
+ return EXIT_SUCCESS;
+}
diff --git a/test/reference_wrapper_test.cpp b/test/reference_wrapper_test.cpp
new file mode 100644
index 0000000..dc1209f
--- /dev/null
+++ b/test/reference_wrapper_test.cpp
@@ -0,0 +1,76 @@
+#include <cstdlib>
+#include <functional>
+#include <iostream>
+#include <type_traits>
+#include <typeinfo>
+#include <utility>
+#include <vector>
+
+#include "variant.hpp"
+
+using namespace mapbox;
+
+namespace test {
+
+struct point
+{
+ public:
+ point(double x_, double y_)
+ : x(x_), y(y_) {}
+ double x;
+ double y;
+};
+
+struct line_string : std::vector<point>
+{
+};
+struct polygon : std::vector<line_string>
+{
+};
+using variant = util::variant<std::reference_wrapper<const point>,
+ std::reference_wrapper<const line_string>,
+ std::reference_wrapper<const polygon>>;
+
+struct print
+{
+ using result_type = void;
+ void operator()(point const& pt) const
+ {
+ std::cerr << "Point(" << pt.x << "," << pt.y << ")" << std::endl;
+ }
+ void operator()(line_string const& line) const
+ {
+ std::cerr << "Line(";
+ for (auto const& pt : line)
+ {
+ std::cerr << pt.x << " " << pt.y << ",";
+ }
+ std::cerr << ")" << std::endl;
+ }
+ template <typename T>
+ void operator()(T const& val) const
+ {
+ std::cerr << typeid(T).name() << std::endl;
+ }
+};
+}
+
+int main()
+{
+ std::cerr << sizeof(test::polygon) << std::endl;
+ std::cerr << sizeof(test::variant) << std::endl;
+ test::point pt(123, 456);
+ test::variant var = std::cref(pt);
+ util::apply_visitor(test::print(), var);
+ test::line_string line;
+ line.push_back(pt);
+ line.push_back(pt);
+ line.push_back(test::point(999, 333));
+ var = std::cref(line);
+ util::apply_visitor(test::print(), var);
+ std::cerr << "Is line (cref) ? " << var.is<std::reference_wrapper<test::line_string const>>() << std::endl;
+ auto const& line2 = var.get<test::line_string>(); // accessing underlying type of std::reference_wrapper<T>
+ test::print printer;
+ printer(line2);
+ return EXIT_SUCCESS;
+}
diff --git a/test/t/binary_visitor_1.cpp b/test/t/binary_visitor_1.cpp
new file mode 100644
index 0000000..298a40b
--- /dev/null
+++ b/test/t/binary_visitor_1.cpp
@@ -0,0 +1,7 @@
+
+#include "variant.hpp"
+
+#define NAME_EXT " i-d"
+using variant_type = mapbox::util::variant<int, double>;
+
+#include "binary_visitor_impl.hpp"
diff --git a/test/t/binary_visitor_2.cpp b/test/t/binary_visitor_2.cpp
new file mode 100644
index 0000000..33768b6
--- /dev/null
+++ b/test/t/binary_visitor_2.cpp
@@ -0,0 +1,7 @@
+
+#include "variant.hpp"
+
+#define NAME_EXT " b-i-d"
+using variant_type = mapbox::util::variant<bool, int, double>;
+
+#include "binary_visitor_impl.hpp"
diff --git a/test/t/binary_visitor_3.cpp b/test/t/binary_visitor_3.cpp
new file mode 100644
index 0000000..d35af4e
--- /dev/null
+++ b/test/t/binary_visitor_3.cpp
@@ -0,0 +1,7 @@
+
+#include "variant.hpp"
+
+#define NAME_EXT " i-d-b"
+using variant_type = mapbox::util::variant<int, double, bool>;
+
+#include "binary_visitor_impl.hpp"
diff --git a/test/t/binary_visitor_4.cpp b/test/t/binary_visitor_4.cpp
new file mode 100644
index 0000000..daacc1b
--- /dev/null
+++ b/test/t/binary_visitor_4.cpp
@@ -0,0 +1,7 @@
+
+#include "variant.hpp"
+
+#define NAME_EXT " b-i-d-c"
+using variant_type = mapbox::util::variant<bool, int, double, char>;
+
+#include "binary_visitor_impl.hpp"
diff --git a/test/t/binary_visitor_5.cpp b/test/t/binary_visitor_5.cpp
new file mode 100644
index 0000000..28669be
--- /dev/null
+++ b/test/t/binary_visitor_5.cpp
@@ -0,0 +1,7 @@
+
+#include "variant.hpp"
+
+#define NAME_EXT " b-i-c-d-i"
+using variant_type = mapbox::util::variant<bool, int, char, double, int>;
+
+#include "binary_visitor_impl.hpp"
diff --git a/test/t/binary_visitor_6.cpp b/test/t/binary_visitor_6.cpp
new file mode 100644
index 0000000..c881b0f
--- /dev/null
+++ b/test/t/binary_visitor_6.cpp
@@ -0,0 +1,7 @@
+
+#include "variant.hpp"
+
+#define NAME_EXT " b-i-i-d-c-u"
+using variant_type = mapbox::util::variant<bool, int, int, double, char, short int>;
+
+#include "binary_visitor_impl.hpp"
diff --git a/test/t/binary_visitor_impl.hpp b/test/t/binary_visitor_impl.hpp
new file mode 100644
index 0000000..4d9a43f
--- /dev/null
+++ b/test/t/binary_visitor_impl.hpp
@@ -0,0 +1,204 @@
+
+#include <type_traits>
+
+#include "catch.hpp"
+
+#include "variant_io.hpp"
+
+struct add_visitor
+{
+ add_visitor() {}
+
+ template <typename A, typename B>
+ double operator()(A a, B b) const
+ {
+ return a + b;
+ }
+};
+
+TEST_CASE("const binary visitor works on const variants" NAME_EXT, "[visitor][binary visitor]")
+{
+ const variant_type a{7};
+ const variant_type b = 3;
+ const variant_type c{7.1};
+ const variant_type d = 2.9;
+
+ const add_visitor v;
+
+ REQUIRE(mapbox::util::apply_visitor(v, a, b) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(v, c, d) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(v, a, c) == Approx(14.1));
+ REQUIRE(mapbox::util::apply_visitor(v, a, d) == Approx(9.9));
+
+ REQUIRE(mapbox::util::apply_visitor(v, b, a) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(v, d, c) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(v, c, a) == Approx(14.1));
+ REQUIRE(mapbox::util::apply_visitor(v, d, a) == Approx(9.9));
+}
+
+TEST_CASE("non-const binary visitor works on const variants" NAME_EXT, "[visitor][binary visitor]")
+{
+ const variant_type a = 7;
+ const variant_type b = 3;
+ const variant_type c = 7.1;
+ const variant_type d = 2.9;
+
+ add_visitor v;
+
+ REQUIRE(mapbox::util::apply_visitor(v, a, b) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(v, c, d) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(v, a, c) == Approx(14.1));
+ REQUIRE(mapbox::util::apply_visitor(v, a, d) == Approx(9.9));
+
+ REQUIRE(mapbox::util::apply_visitor(v, b, a) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(v, d, c) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(v, c, a) == Approx(14.1));
+ REQUIRE(mapbox::util::apply_visitor(v, d, a) == Approx(9.9));
+}
+
+TEST_CASE("const binary visitor works on non-const variants" NAME_EXT, "[visitor][binary visitor]")
+{
+ variant_type a = 7;
+ variant_type b = 3;
+ variant_type c = 7.1;
+ variant_type d = 2.9;
+
+ const add_visitor v;
+
+ REQUIRE(mapbox::util::apply_visitor(v, a, b) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(v, c, d) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(v, a, c) == Approx(14.1));
+ REQUIRE(mapbox::util::apply_visitor(v, a, d) == Approx(9.9));
+
+ REQUIRE(mapbox::util::apply_visitor(v, b, a) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(v, d, c) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(v, c, a) == Approx(14.1));
+ REQUIRE(mapbox::util::apply_visitor(v, d, a) == Approx(9.9));
+}
+
+TEST_CASE("non-const binary visitor works on non-const variants" NAME_EXT, "[visitor][binary visitor]")
+{
+ variant_type a = 7;
+ variant_type b = 3;
+ variant_type c = 7.1;
+ variant_type d = 2.9;
+
+ add_visitor v;
+
+ REQUIRE(mapbox::util::apply_visitor(v, a, b) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(v, c, d) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(v, a, c) == Approx(14.1));
+ REQUIRE(mapbox::util::apply_visitor(v, a, d) == Approx(9.9));
+
+ REQUIRE(mapbox::util::apply_visitor(v, b, a) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(v, d, c) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(v, c, a) == Approx(14.1));
+ REQUIRE(mapbox::util::apply_visitor(v, d, a) == Approx(9.9));
+}
+
+TEST_CASE("rvalue binary visitor works on const variants" NAME_EXT, "[visitor][binary visitor]")
+{
+ const variant_type a = 7;
+ const variant_type b = 3;
+ const variant_type c = 7.1;
+ const variant_type d = 2.9;
+
+ REQUIRE(mapbox::util::apply_visitor(add_visitor{}, a, b) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(add_visitor{}, c, d) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(add_visitor{}, a, c) == Approx(14.1));
+ REQUIRE(mapbox::util::apply_visitor(add_visitor{}, a, d) == Approx(9.9));
+
+ REQUIRE(mapbox::util::apply_visitor(add_visitor{}, b, a) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(add_visitor{}, d, c) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(add_visitor{}, c, a) == Approx(14.1));
+ REQUIRE(mapbox::util::apply_visitor(add_visitor{}, d, a) == Approx(9.9));
+}
+
+struct sum_mul_visitor
+{
+ double sum;
+
+ sum_mul_visitor() : sum(0.0) {}
+
+ template <typename A, typename B>
+ double operator()(A a, B b)
+ {
+ double m = a * b;
+ sum += m;
+ return m;
+ }
+};
+
+TEST_CASE("mutable binary visitor works" NAME_EXT, "[visitor][binary visitor]")
+{
+ const variant_type a = 2;
+ const variant_type b = 3;
+ const variant_type c = 0.1;
+ const variant_type d = 0.2;
+
+ sum_mul_visitor v;
+
+ REQUIRE(mapbox::util::apply_visitor(v, a, b) == Approx(6));
+ REQUIRE(mapbox::util::apply_visitor(v, c, d) == Approx(0.02));
+ REQUIRE(mapbox::util::apply_visitor(v, a, c) == Approx(0.2));
+ REQUIRE(mapbox::util::apply_visitor(v, a, d) == Approx(0.4));
+
+ REQUIRE(v.sum == Approx(6.62));
+
+ REQUIRE(mapbox::util::apply_visitor(v, b, a) == Approx(6));
+ REQUIRE(mapbox::util::apply_visitor(v, d, c) == Approx(0.02));
+ REQUIRE(mapbox::util::apply_visitor(v, c, a) == Approx(0.2));
+ REQUIRE(mapbox::util::apply_visitor(v, d, a) == Approx(0.4));
+}
+
+struct swap_visitor
+{
+ swap_visitor(){};
+
+ template <typename A, typename B>
+ void operator()(A& a, B& b) const
+ {
+ using T = typename std::common_type<A, B>::type;
+ T tmp = a;
+ a = b;
+ b = tmp;
+ }
+};
+
+TEST_CASE("static mutating visitor on mutable variants works" NAME_EXT, "[visitor][binary visitor]")
+{
+ variant_type a = 2;
+ variant_type b = 3;
+ variant_type c = 0.1;
+ variant_type d = 0.2;
+
+ const swap_visitor v;
+
+ SECTION("swap a and b")
+ {
+ mapbox::util::apply_visitor(v, a, b);
+ REQUIRE(a.get<int>() == 3);
+ REQUIRE(b.get<int>() == 2);
+ }
+
+ SECTION("swap c and d")
+ {
+ mapbox::util::apply_visitor(v, c, d);
+ REQUIRE(c.get<double>() == Approx(0.2));
+ REQUIRE(d.get<double>() == Approx(0.1));
+ }
+
+ SECTION("swap a and c")
+ {
+ mapbox::util::apply_visitor(v, a, c);
+ REQUIRE(a.get<int>() == 0);
+ REQUIRE(c.get<double>() == Approx(2.0));
+ }
+
+ SECTION("swap c and a")
+ {
+ mapbox::util::apply_visitor(v, c, a);
+ REQUIRE(a.get<int>() == 0);
+ REQUIRE(c.get<double>() == Approx(2.0));
+ }
+}
diff --git a/test/t/issue21.cpp b/test/t/issue21.cpp
new file mode 100644
index 0000000..b952313
--- /dev/null
+++ b/test/t/issue21.cpp
@@ -0,0 +1,48 @@
+
+#include "catch.hpp"
+
+#include "variant.hpp"
+#include "variant_io.hpp"
+
+// https://github.com/mapbox/variant/issues/21
+
+static int count;
+
+struct t1
+{
+ int value;
+ t1(int v) : value(v)
+ {
+ ++count;
+ }
+ ~t1()
+ {
+ --count;
+ }
+};
+
+struct t2
+{
+ int value;
+ t2(int v) : value(v)
+ { // constructor fails
+ throw std::runtime_error("fail");
+ }
+};
+
+TEST_CASE("set() works cleanly even if the constructor throws ", "[variant]")
+{
+
+ using variant_type = mapbox::util::variant<t1, t2>;
+
+ count = 0;
+ {
+ variant_type v{42};
+ REQUIRE(v.is<t1>());
+ REQUIRE(v.get<t1>().value == 42);
+ REQUIRE_THROWS({
+ v.set<t2>(13);
+ });
+ }
+ REQUIRE(count == 0);
+}
diff --git a/test/t/mutating_visitor.cpp b/test/t/mutating_visitor.cpp
new file mode 100644
index 0000000..f07afb8
--- /dev/null
+++ b/test/t/mutating_visitor.cpp
@@ -0,0 +1,36 @@
+
+#include "catch.hpp"
+
+#include "variant.hpp"
+#include "variant_io.hpp"
+
+#include <string>
+
+template <typename T>
+struct mutating_visitor
+{
+ mutating_visitor(T& val)
+ : val_(val) {}
+
+ void operator()(T& val) const
+ {
+ val = val_;
+ }
+
+ template <typename T1>
+ void operator()(T1&) const
+ {
+ } // no-op
+
+ T& val_;
+};
+
+TEST_CASE("variant visitation", "[visitor][unary visitor]")
+{
+ mapbox::util::variant<int, double, std::string> var(123);
+ REQUIRE(var.get<int>() == 123);
+ int val = 456;
+ const mutating_visitor<int> visitor(val);
+ mapbox::util::apply_visitor(visitor, var);
+ REQUIRE(var.get<int>() == 456);
+}
diff --git a/test/t/optional.cpp b/test/t/optional.cpp
new file mode 100644
index 0000000..b77beda
--- /dev/null
+++ b/test/t/optional.cpp
@@ -0,0 +1,102 @@
+
+#include "catch.hpp"
+
+#include "optional.hpp"
+
+struct dummy
+{
+ dummy(int _m_1, int _m_2) : m_1(_m_1), m_2(_m_2) {}
+ int m_1;
+ int m_2;
+};
+
+TEST_CASE("optional can be instantiated with a POD type", "[optional]")
+{
+ mapbox::util::optional<int> dbl_opt;
+
+ REQUIRE(!dbl_opt);
+ dbl_opt = 3;
+ REQUIRE(dbl_opt);
+
+ REQUIRE(dbl_opt.get() == 3);
+ REQUIRE(*dbl_opt == 3);
+}
+
+TEST_CASE("copy c'tor", "[optional]")
+{
+ mapbox::util::optional<int> dbl_opt;
+
+ REQUIRE(!dbl_opt);
+ dbl_opt = 3;
+ REQUIRE(dbl_opt);
+
+ mapbox::util::optional<int> other = dbl_opt;
+
+ REQUIRE(other.get() == 3);
+ REQUIRE(*other == 3);
+}
+
+TEST_CASE("const operator*, const get()", "[optional]")
+{
+ const mapbox::util::optional<int> dbl_opt = 3;
+
+ REQUIRE(dbl_opt);
+
+ auto pi1 = dbl_opt.get();
+ auto pi2 = *dbl_opt;
+
+ REQUIRE(pi1 == 3);
+ REQUIRE(pi2 == 3);
+}
+
+TEST_CASE("non-const operator*, non-const get()", "[optional]")
+{
+ mapbox::util::optional<int> dbl_opt = 3;
+
+ REQUIRE(dbl_opt);
+
+ auto pi1 = dbl_opt.get();
+ auto pi2 = *dbl_opt;
+
+ REQUIRE(pi1 == 3);
+ REQUIRE(pi2 == 3);
+}
+
+TEST_CASE("emplace initialization, reset", "[optional]")
+{
+ mapbox::util::optional<dummy> dummy_opt;
+ REQUIRE(!dummy_opt);
+
+ // rvalues, baby!
+ dummy_opt.emplace(1, 2);
+ REQUIRE(dummy_opt);
+ REQUIRE(dummy_opt.get().m_1 == 1);
+ REQUIRE((*dummy_opt).m_2 == 2);
+
+ dummy_opt.reset();
+ REQUIRE(!dummy_opt);
+}
+
+TEST_CASE("assignment", "[optional]")
+{
+ mapbox::util::optional<int> a;
+ mapbox::util::optional<int> b;
+
+ a = 1;
+ b = 3;
+ REQUIRE(a.get() == 1);
+ REQUIRE(b.get() == 3);
+ b = a;
+ REQUIRE(a.get() == b.get());
+ REQUIRE(b.get() == 1);
+}
+
+TEST_CASE("self assignment", "[optional]")
+{
+ mapbox::util::optional<int> a;
+
+ a = 1;
+ REQUIRE(a.get() == 1);
+ a = a;
+ REQUIRE(a.get() == 1);
+}
diff --git a/test/t/recursive_wrapper.cpp b/test/t/recursive_wrapper.cpp
new file mode 100644
index 0000000..b2dec45
--- /dev/null
+++ b/test/t/recursive_wrapper.cpp
@@ -0,0 +1,158 @@
+
+#include "catch.hpp"
+
+#include "recursive_wrapper.hpp"
+
+#include <type_traits>
+#include <utility>
+
+using rwi = mapbox::util::recursive_wrapper<int>;
+using rwp = mapbox::util::recursive_wrapper<std::pair<int, int>>;
+
+static_assert(std::is_same<rwi::type, int>::value, "type check failed");
+
+TEST_CASE("recursive wrapper of int")
+{
+
+ SECTION("construct with value")
+ {
+ rwi a{7};
+
+ REQUIRE(a.get() == 7);
+ REQUIRE(*a.get_pointer() == 7);
+
+ a = 8;
+ REQUIRE(a.get() == 8);
+
+ rwi b{a};
+ REQUIRE(b.get() == 8);
+
+ rwi c;
+ c = b;
+ REQUIRE(b.get() == 8);
+ REQUIRE(c.get() == 8);
+
+ c = 9;
+ REQUIRE(c.get() == 9);
+
+ int x = 10;
+ c = x;
+ REQUIRE(c.get() == 10);
+
+ b = std::move(c);
+ REQUIRE(b.get() == 10);
+ }
+
+ SECTION("construct with const reference")
+ {
+ int i = 7;
+ rwi a{i};
+
+ REQUIRE(a.get() == 7);
+ }
+
+ SECTION("implicit conversion to reference of underlying type")
+ {
+
+ SECTION("const")
+ {
+ rwi const a{7};
+ REQUIRE(a.get() == 7);
+ REQUIRE(*a.get_pointer() == 7);
+
+ rwi::type const& underlying = a;
+ REQUIRE(underlying == 7);
+ }
+
+ SECTION("non const")
+ {
+ rwi a{7};
+ REQUIRE(a.get() == 7);
+ REQUIRE(*a.get_pointer() == 7);
+
+ rwi::type& underlying = a;
+ REQUIRE(underlying == 7);
+ a = 8;
+ REQUIRE(underlying == 8);
+ }
+ }
+}
+
+TEST_CASE("move of recursive wrapper")
+{
+ rwi a{1};
+
+ SECTION("move constructor")
+ {
+ rwi b{std::move(a)};
+ REQUIRE(b.get() == 1);
+ }
+
+ SECTION("operator= on rvalue")
+ {
+ rwi b{2};
+ b = std::move(a);
+ REQUIRE(b.get() == 1);
+ }
+}
+
+TEST_CASE("swap")
+{
+ rwi a{1};
+ rwi b{2};
+
+ REQUIRE(a.get() == 1);
+ REQUIRE(b.get() == 2);
+
+ using std::swap;
+ swap(a, b);
+
+ REQUIRE(a.get() == 2);
+ REQUIRE(b.get() == 1);
+}
+
+TEST_CASE("recursive wrapper of pair<int, int>")
+{
+
+ SECTION("default constructed")
+ {
+ rwp a;
+ REQUIRE(a.get().first == 0);
+ REQUIRE(a.get().second == 0);
+ }
+
+ SECTION("construct with value")
+ {
+ rwp a{std::make_pair(1, 2)};
+
+ REQUIRE(a.get().first == 1);
+ REQUIRE(a.get().second == 2);
+
+ REQUIRE(a.get_pointer()->first == 1);
+ REQUIRE(a.get_pointer()->second == 2);
+
+ a = {3, 4};
+ REQUIRE(a.get().first == 3);
+ REQUIRE(a.get().second == 4);
+
+ rwp b{a};
+ REQUIRE(b.get().first == 3);
+ REQUIRE(b.get().second == 4);
+
+ rwp c;
+ c = b;
+ REQUIRE(b.get().first == 3);
+ REQUIRE(b.get().second == 4);
+ REQUIRE(c.get().first == 3);
+ REQUIRE(c.get().second == 4);
+
+ c = {5, 6};
+ REQUIRE(c.get().first == 5);
+ REQUIRE(c.get().second == 6);
+
+ b = std::move(c);
+ REQUIRE(b.get().first == 5);
+ REQUIRE(b.get().second == 6);
+ // REQUIRE(c.get_pointer() == nullptr);
+ }
+}
diff --git a/test/t/sizeof.cpp b/test/t/sizeof.cpp
new file mode 100644
index 0000000..0e74ce5
--- /dev/null
+++ b/test/t/sizeof.cpp
@@ -0,0 +1,52 @@
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+
+#include "catch.hpp"
+
+#include "variant.hpp"
+#include "variant_io.hpp"
+
+struct some_struct
+{
+ int a;
+ bool b;
+ std::string c;
+};
+
+using variant_internal_index_type = size_t;
+
+TEST_CASE("size of variants")
+{
+ constexpr const auto min_overhead = sizeof(variant_internal_index_type);
+
+ using namespace std; // workaround for bug in GCC <= 4.8 where max_align_t is not in std
+ constexpr const auto max_overhead = alignof(max_align_t) + min_overhead;
+
+ using v1 = mapbox::util::variant<int>;
+ using v2 = mapbox::util::variant<int, bool, int64_t>;
+ using v3 = mapbox::util::variant<int, std::string>;
+ using v4 = mapbox::util::variant<std::string, std::string>;
+ using v5 = mapbox::util::variant<some_struct>;
+
+ constexpr const auto si = sizeof(int);
+ constexpr const auto sb = sizeof(bool);
+ constexpr const auto si64 = sizeof(int64_t);
+ constexpr const auto sd = sizeof(double);
+ constexpr const auto sstr = sizeof(std::string);
+ constexpr const auto spi = sizeof(std::pair<int, int>);
+ constexpr const auto ss = sizeof(some_struct);
+
+ REQUIRE(sizeof(v1) <= max_overhead + si);
+ REQUIRE(sizeof(v2) <= max_overhead + std::max({si, sb, si64}));
+ REQUIRE(sizeof(v3) <= max_overhead + std::max({si, sstr}));
+ REQUIRE(sizeof(v4) <= max_overhead + sstr);
+ REQUIRE(sizeof(v5) <= max_overhead + ss);
+
+ REQUIRE(sizeof(v1) >= min_overhead + si);
+ REQUIRE(sizeof(v2) >= min_overhead + std::max({si, sb, si64}));
+ REQUIRE(sizeof(v3) >= min_overhead + std::max({si, sstr}));
+ REQUIRE(sizeof(v4) >= min_overhead + sstr);
+ REQUIRE(sizeof(v5) >= min_overhead + ss);
+}
diff --git a/test/t/unary_visitor.cpp b/test/t/unary_visitor.cpp
new file mode 100644
index 0000000..8df6110
--- /dev/null
+++ b/test/t/unary_visitor.cpp
@@ -0,0 +1,127 @@
+
+#include "catch.hpp"
+
+#include "variant.hpp"
+#include "variant_io.hpp"
+
+#include <string>
+
+struct some_visitor
+{
+ int var_;
+
+ some_visitor(int init)
+ : var_(init) {}
+
+ int operator()(int val) const
+ {
+ return var_ + val;
+ }
+
+ int operator()(double val) const
+ {
+ return var_ + int(val);
+ }
+
+ int operator()(const std::string&) const
+ {
+ return 0;
+ }
+};
+
+TEST_CASE("non-const visitor works on const variants", "[visitor][unary visitor]")
+{
+ using variant_type = const mapbox::util::variant<int, double, std::string>;
+ variant_type var1(123);
+ variant_type var2(3.2);
+ variant_type var3("foo");
+ REQUIRE(var1.get<int>() == 123);
+ REQUIRE(var2.get<double>() == Approx(3.2));
+ REQUIRE(var3.get<std::string>() == "foo");
+
+ some_visitor visitor{1};
+
+ REQUIRE(mapbox::util::apply_visitor(visitor, var1) == 124);
+ REQUIRE(mapbox::util::apply_visitor(visitor, var2) == 4);
+ REQUIRE(mapbox::util::apply_visitor(visitor, var3) == 0);
+}
+
+TEST_CASE("const visitor works on const variants", "[visitor][unary visitor]")
+{
+ using variant_type = const mapbox::util::variant<int, double, std::string>;
+ variant_type var1(123);
+ variant_type var2(3.2);
+ variant_type var3("foo");
+ REQUIRE(var1.get<int>() == 123);
+ REQUIRE(var2.get<double>() == Approx(3.2));
+ REQUIRE(var3.get<std::string>() == "foo");
+
+ const some_visitor visitor{1};
+
+ REQUIRE(mapbox::util::apply_visitor(visitor, var1) == 124);
+ REQUIRE(mapbox::util::apply_visitor(visitor, var2) == 4);
+ REQUIRE(mapbox::util::apply_visitor(visitor, var3) == 0);
+}
+
+TEST_CASE("rvalue visitor works on const variants", "[visitor][unary visitor]")
+{
+ using variant_type = const mapbox::util::variant<int, double, std::string>;
+ variant_type var1(123);
+ variant_type var2(3.2);
+ variant_type var3("foo");
+ REQUIRE(var1.get<int>() == 123);
+ REQUIRE(var2.get<double>() == Approx(3.2));
+ REQUIRE(var3.get<std::string>() == "foo");
+
+ REQUIRE(mapbox::util::apply_visitor(some_visitor{1}, var1) == 124);
+ REQUIRE(mapbox::util::apply_visitor(some_visitor{1}, var2) == 4);
+ REQUIRE(mapbox::util::apply_visitor(some_visitor{1}, var3) == 0);
+}
+
+TEST_CASE("visitor works on rvalue variants", "[visitor][unary visitor]")
+{
+ using variant_type = const mapbox::util::variant<int, double, std::string>;
+
+ REQUIRE(mapbox::util::apply_visitor(some_visitor{1}, variant_type{123}) == 124);
+ REQUIRE(mapbox::util::apply_visitor(some_visitor{1}, variant_type{3.2}) == 4);
+ REQUIRE(mapbox::util::apply_visitor(some_visitor{1}, variant_type{"foo"}) == 0);
+}
+
+struct total_sizeof
+{
+ total_sizeof() : total_(0) {}
+
+ template <class Value>
+ int operator()(const Value&) const
+ {
+ total_ += int(sizeof(Value));
+ return total_;
+ }
+
+ int result() const
+ {
+ return total_;
+ }
+
+ mutable int total_;
+
+}; // total_sizeof
+
+TEST_CASE("changes in visitor should be visible", "[visitor][unary visitor]")
+{
+ using variant_type = mapbox::util::variant<int, std::string, double>;
+ variant_type v;
+ total_sizeof ts;
+ v = 5.9;
+ REQUIRE(mapbox::util::apply_visitor(ts, v) == sizeof(double));
+ REQUIRE(ts.result() == sizeof(double));
+}
+
+TEST_CASE("changes in const visitor (with mutable internals) should be visible", "[visitor][unary visitor]")
+{
+ using variant_type = const mapbox::util::variant<int, std::string, double>;
+ variant_type v{"foo"};
+ const total_sizeof ts;
+ REQUIRE(mapbox::util::apply_visitor(ts, v) == sizeof(std::string));
+ REQUIRE(ts.result() == sizeof(std::string));
+}
diff --git a/test/t/variant.cpp b/test/t/variant.cpp
new file mode 100644
index 0000000..36655a5
--- /dev/null
+++ b/test/t/variant.cpp
@@ -0,0 +1,570 @@
+#include "catch.hpp"
+
+#include "variant.hpp"
+#include "variant_io.hpp"
+
+#include <algorithm>
+#include <cstdint>
+#include <functional>
+#include <iterator>
+#include <limits>
+#include <memory>
+#include <ostream>
+#include <sstream>
+#include <string>
+
+// Hack to make nullptr work with Catch
+namespace std {
+
+template <class C, class T>
+std::basic_ostream<C, T>& operator<<(std::basic_ostream<C, T>& os, std::nullptr_t)
+{
+ return os << (void*)nullptr;
+}
+}
+
+TEST_CASE("variant can be moved into vector", "[variant]")
+{
+ using variant_type = mapbox::util::variant<bool, std::string>;
+ variant_type v(std::string("test"));
+ std::vector<variant_type> vec;
+ vec.emplace_back(std::move(v));
+ REQUIRE(v.get<std::string>() != std::string("test"));
+ REQUIRE(vec.at(0).get<std::string>() == std::string("test"));
+}
+
+TEST_CASE("variant should support built-in types", "[variant]")
+{
+ SECTION("bool")
+ {
+ mapbox::util::variant<bool> v(true);
+ REQUIRE(v.valid());
+ REQUIRE(v.is<bool>());
+ REQUIRE(v.which() == 0);
+ REQUIRE(v.get<bool>() == true);
+ v.set<bool>(false);
+ REQUIRE(v.get<bool>() == false);
+ v = true;
+ REQUIRE(v == mapbox::util::variant<bool>(true));
+ }
+ SECTION("nullptr")
+ {
+ using value_type = std::nullptr_t;
+ mapbox::util::variant<value_type> v(nullptr);
+ REQUIRE(v.valid());
+ REQUIRE(v.is<value_type>());
+ REQUIRE(v.which() == 0);
+ REQUIRE(v.get<value_type>() == nullptr);
+ REQUIRE(v == mapbox::util::variant<value_type>(nullptr));
+ }
+ SECTION("unique_ptr")
+ {
+ using value_type = std::unique_ptr<std::string>;
+ mapbox::util::variant<value_type> v(value_type(new std::string("hello")));
+ REQUIRE(v.valid());
+ REQUIRE(v.is<value_type>());
+ REQUIRE(v.which() == 0);
+ REQUIRE(*v.get<value_type>().get() == *value_type(new std::string("hello")).get());
+ REQUIRE(*v.get<value_type>() == "hello");
+ }
+ SECTION("string")
+ {
+ using value_type = std::string;
+ mapbox::util::variant<value_type> v(value_type("hello"));
+ REQUIRE(v.valid());
+ REQUIRE(v.is<value_type>());
+ REQUIRE(v.which() == 0);
+ REQUIRE(v.get<value_type>() == value_type("hello"));
+ v.set<value_type>(value_type("there"));
+ REQUIRE(v.get<value_type>() == value_type("there"));
+ v = value_type("variant");
+ REQUIRE(v == mapbox::util::variant<value_type>(value_type("variant")));
+ }
+ SECTION("size_t")
+ {
+ using value_type = std::size_t;
+ mapbox::util::variant<value_type> v(std::numeric_limits<value_type>::max());
+ REQUIRE(v.valid());
+ REQUIRE(v.is<value_type>());
+ REQUIRE(v.which() == 0);
+ REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
+ v.set<value_type>(value_type(0));
+ REQUIRE(v.get<value_type>() == value_type(0));
+ v = value_type(1);
+ REQUIRE(v == mapbox::util::variant<value_type>(value_type(1)));
+ }
+ SECTION("int8_t")
+ {
+ using value_type = std::int8_t;
+ mapbox::util::variant<value_type> v(std::numeric_limits<value_type>::max());
+ REQUIRE(v.valid());
+ REQUIRE(v.is<value_type>());
+ REQUIRE(v.which() == 0);
+ REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
+ v.set<value_type>(0);
+ REQUIRE(v.get<value_type>() == value_type(0));
+ v = value_type(1);
+ REQUIRE(v == mapbox::util::variant<value_type>(value_type(1)));
+ }
+ SECTION("int16_t")
+ {
+ using value_type = std::int16_t;
+ mapbox::util::variant<value_type> v(std::numeric_limits<value_type>::max());
+ REQUIRE(v.valid());
+ REQUIRE(v.is<value_type>());
+ REQUIRE(v.which() == 0);
+ REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
+ v.set<value_type>(0);
+ REQUIRE(v.get<value_type>() == value_type(0));
+ v = value_type(1);
+ REQUIRE(v == mapbox::util::variant<value_type>(value_type(1)));
+ }
+ SECTION("int32_t")
+ {
+ using value_type = std::int32_t;
+ mapbox::util::variant<value_type> v(std::numeric_limits<value_type>::max());
+ REQUIRE(v.valid());
+ REQUIRE(v.is<value_type>());
+ REQUIRE(v.which() == 0);
+ REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
+ v.set<value_type>(0);
+ REQUIRE(v.get<value_type>() == value_type(0));
+ v = value_type(1);
+ REQUIRE(v == mapbox::util::variant<value_type>(value_type(1)));
+ }
+ SECTION("int64_t")
+ {
+ using value_type = std::int64_t;
+ mapbox::util::variant<value_type> v(std::numeric_limits<value_type>::max());
+ REQUIRE(v.valid());
+ REQUIRE(v.is<value_type>());
+ REQUIRE(v.which() == 0);
+ REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
+ v.set<value_type>(0);
+ REQUIRE(v.get<value_type>() == value_type(0));
+ v = value_type(1);
+ REQUIRE(v == mapbox::util::variant<value_type>(value_type(1)));
+ }
+}
+
+struct MissionInteger
+{
+ using value_type = uint64_t;
+ value_type val_;
+
+ public:
+ MissionInteger(uint64_t val) : val_(val) {}
+
+ bool operator==(MissionInteger const& rhs) const
+ {
+ return (val_ == rhs.get());
+ }
+
+ uint64_t get() const
+ {
+ return val_;
+ }
+};
+
+std::ostream& operator<<(std::ostream& os, MissionInteger const& rhs)
+{
+ os << rhs.get();
+ return os;
+}
+
+TEST_CASE("variant should support custom types", "[variant]")
+{
+ // http://www.missionintegers.com/integer/34838300
+ mapbox::util::variant<MissionInteger> v(MissionInteger(34838300));
+ REQUIRE(v.valid());
+ REQUIRE(v.is<MissionInteger>());
+ REQUIRE(v.which() == 0);
+ REQUIRE(v.get<MissionInteger>() == MissionInteger(34838300));
+ REQUIRE(v.get<MissionInteger>().get() == MissionInteger::value_type(34838300));
+ // TODO: should both of the set usages below compile?
+ v.set<MissionInteger>(MissionInteger::value_type(0));
+ v.set<MissionInteger>(MissionInteger(0));
+ REQUIRE(v.get<MissionInteger>().get() == MissionInteger::value_type(0));
+ v = MissionInteger(1);
+ REQUIRE(v == mapbox::util::variant<MissionInteger>(MissionInteger(1)));
+}
+
+TEST_CASE("variant::which() returns zero based index of stored type", "[variant]")
+{
+ using variant_type = mapbox::util::variant<bool, std::string, std::uint64_t, std::int64_t, double, float>;
+ // which() returns index in forward order
+ REQUIRE(0 == variant_type(true).which());
+ REQUIRE(1 == variant_type(std::string("test")).which());
+ REQUIRE(2 == variant_type(std::uint64_t(0)).which());
+ REQUIRE(3 == variant_type(std::int64_t(0)).which());
+ REQUIRE(4 == variant_type(double(0.0)).which());
+ REQUIRE(5 == variant_type(float(0.0)).which());
+}
+
+TEST_CASE("get with wrong type (here: double) should throw", "[variant]")
+{
+ using variant_type = mapbox::util::variant<int, double>;
+ variant_type var = 5;
+ REQUIRE(var.is<int>());
+ REQUIRE_FALSE(var.is<double>());
+ REQUIRE(var.get<int>() == 5);
+ REQUIRE_THROWS_AS({
+ var.get<double>();
+ },
+ mapbox::util::bad_variant_access&);
+}
+
+TEST_CASE("get with wrong type (here: int) should throw", "[variant]")
+{
+ using variant_type = mapbox::util::variant<int, double>;
+ variant_type var = 5.0;
+ REQUIRE(var.is<double>());
+ REQUIRE_FALSE(var.is<int>());
+ REQUIRE(var.get<double>() == 5.0);
+ REQUIRE(mapbox::util::get<double>(var) == 5.0);
+ REQUIRE_THROWS_AS({
+ var.get<int>();
+ },
+ mapbox::util::bad_variant_access&);
+ REQUIRE_THROWS_AS({
+ mapbox::util::get<int>(var);
+ },
+ mapbox::util::bad_variant_access&);
+}
+
+TEST_CASE("get on const varint with wrong type (here: int) should throw", "[variant]")
+{
+ using variant_type = mapbox::util::variant<int, double>;
+ const variant_type var = 5.0;
+ REQUIRE(var.is<double>());
+ REQUIRE_FALSE(var.is<int>());
+ REQUIRE(var.get<double>() == 5.0);
+ REQUIRE(mapbox::util::get<double>(var) == 5.0);
+ REQUIRE_THROWS_AS({
+ var.get<int>();
+ },
+ mapbox::util::bad_variant_access&);
+ REQUIRE_THROWS_AS({
+ mapbox::util::get<int>(var);
+ },
+ mapbox::util::bad_variant_access&);
+}
+
+TEST_CASE("get with any type should throw if not initialized", "[variant]")
+{
+ mapbox::util::variant<int, double> var{mapbox::util::no_init()};
+ REQUIRE_THROWS_AS({
+ var.get<int>();
+ },
+ mapbox::util::bad_variant_access&);
+ REQUIRE_THROWS_AS({
+ var.get<double>();
+ },
+ mapbox::util::bad_variant_access&);
+}
+
+TEST_CASE("no_init variant can be copied and moved from", "[variant]")
+{
+ using variant_type = mapbox::util::variant<int, double>;
+
+ variant_type v1{mapbox::util::no_init()};
+ variant_type v2{42};
+ variant_type v3{23};
+
+ REQUIRE(v2.get<int>() == 42);
+ v2 = v1;
+ REQUIRE_THROWS_AS({
+ v2.get<int>();
+ },
+ mapbox::util::bad_variant_access&);
+
+ REQUIRE(v3.get<int>() == 23);
+ v3 = std::move(v1);
+ REQUIRE_THROWS_AS({
+ v3.get<int>();
+ },
+ mapbox::util::bad_variant_access&);
+}
+
+TEST_CASE("no_init variant can be copied and moved to", "[variant]")
+{
+ using variant_type = mapbox::util::variant<int, double>;
+
+ variant_type v1{42};
+ variant_type v2{mapbox::util::no_init()};
+ variant_type v3{mapbox::util::no_init()};
+
+ REQUIRE_THROWS_AS({
+ v2.get<int>();
+ },
+ mapbox::util::bad_variant_access&);
+
+ REQUIRE(v1.get<int>() == 42);
+ v2 = v1;
+ REQUIRE(v2.get<int>() == 42);
+ REQUIRE(v1.get<int>() == 42);
+
+ REQUIRE_THROWS_AS({
+ v3.get<int>();
+ },
+ mapbox::util::bad_variant_access&);
+
+ v3 = std::move(v1);
+ REQUIRE(v3.get<int>() == 42);
+}
+
+TEST_CASE("implicit conversion", "[variant][implicit conversion]")
+{
+ using variant_type = mapbox::util::variant<int>;
+ variant_type var(5.0); // converted to int
+ REQUIRE(var.get<int>() == 5);
+ var = 6.0; // works for operator=, too
+ REQUIRE(var.get<int>() == 6);
+}
+
+TEST_CASE("implicit conversion to first type in variant type list", "[variant][implicit conversion]")
+{
+ using variant_type = mapbox::util::variant<long, char>;
+ variant_type var = 5.0; // converted to long
+ REQUIRE(var.get<long>() == 5);
+ REQUIRE_THROWS_AS({
+ var.get<char>();
+ },
+ mapbox::util::bad_variant_access&);
+}
+
+TEST_CASE("implicit conversion to unsigned char", "[variant][implicit conversion]")
+{
+ using variant_type = mapbox::util::variant<unsigned char>;
+ variant_type var = 100.0;
+ CHECK(var.get<unsigned char>() == static_cast<unsigned char>(100.0));
+ CHECK(var.get<unsigned char>() == static_cast<unsigned char>(static_cast<unsigned int>(100.0)));
+}
+
+struct dummy
+{
+};
+
+TEST_CASE("implicit conversion to a suitable type", "[variant][implicit conversion]")
+{
+ using mapbox::util::variant;
+ CHECK_NOTHROW((variant<dummy, float, std::string>(123)).get<float>());
+ CHECK_NOTHROW((variant<dummy, float, std::string>("foo")).get<std::string>());
+}
+
+TEST_CASE("value_traits for non-convertible type", "[variant::detail]")
+{
+ namespace detail = mapbox::util::detail;
+ using target_type = detail::value_traits<dummy, int>::target_type;
+ CHECK((std::is_same<target_type, void>::value) == true);
+}
+
+TEST_CASE("Type indexing should work with variants with duplicated types", "[variant::detail]")
+{
+ // Index is in reverse order
+ REQUIRE((mapbox::util::detail::value_traits<bool, bool, int, double, std::string>::index == 3));
+ REQUIRE((mapbox::util::detail::value_traits<bool, bool, int, double, int>::index == 3));
+ REQUIRE((mapbox::util::detail::value_traits<int, bool, int, double, std::string>::index == 2));
+ REQUIRE((mapbox::util::detail::value_traits<int, bool, int, double, int>::index == 2));
+ REQUIRE((mapbox::util::detail::value_traits<double, bool, int, double, std::string>::index == 1));
+ REQUIRE((mapbox::util::detail::value_traits<bool, bool, int, bool, std::string>::index == 3));
+ REQUIRE((mapbox::util::detail::value_traits<std::string, bool, int, double, std::string>::index == 0));
+ REQUIRE((mapbox::util::detail::value_traits<dummy, bool, int, double, std::string>::index == mapbox::util::detail::invalid_value));
+ REQUIRE((mapbox::util::detail::value_traits<std::vector<int>, bool, int, double, std::string>::index == mapbox::util::detail::invalid_value));
+}
+
+TEST_CASE("variant default constructor", "[variant][default constructor]")
+{
+ // By default variant is initialised with (default constructed) first type in template parameters pack
+ // As a result first type in Types... must be default constructable
+ // NOTE: index in reverse order -> index = N - 1
+ using variant_type = mapbox::util::variant<int, double, std::string>;
+ REQUIRE(variant_type{}.which() == 0);
+ REQUIRE(variant_type{}.valid());
+ REQUIRE_FALSE(variant_type{mapbox::util::no_init()}.valid());
+}
+
+TEST_CASE("variant printer", "[visitor][unary visitor][printer]")
+{
+ using variant_type = mapbox::util::variant<int, double, std::string>;
+ std::vector<variant_type> var = {2.1, 123, "foo", 456};
+ std::stringstream out;
+ std::copy(var.begin(), var.end(), std::ostream_iterator<variant_type>(out, ","));
+ out << var[2];
+ REQUIRE(out.str() == "2.1,123,foo,456,foo");
+}
+
+TEST_CASE("swapping variants should do the right thing", "[variant]")
+{
+ using variant_type = mapbox::util::variant<int, double, std::string>;
+ variant_type a = 7;
+ variant_type b = 3;
+ variant_type c = 3.141;
+ variant_type d = "foo";
+ variant_type e = "a long string that is longer than small string optimization";
+
+ using std::swap;
+ swap(a, b);
+ REQUIRE(a.get<int>() == 3);
+ REQUIRE(a.which() == 0);
+ REQUIRE(b.get<int>() == 7);
+ REQUIRE(b.which() == 0);
+
+ swap(b, c);
+ REQUIRE(b.get<double>() == Approx(3.141));
+ REQUIRE(b.which() == 1);
+ REQUIRE(c.get<int>() == 7);
+ REQUIRE(c.which() == 0);
+
+ swap(b, d);
+ REQUIRE(b.get<std::string>() == "foo");
+ REQUIRE(b.which() == 2);
+ REQUIRE(d.get<double>() == Approx(3.141));
+ REQUIRE(d.which() == 1);
+
+ swap(b, e);
+ REQUIRE(b.get<std::string>() == "a long string that is longer than small string optimization");
+ REQUIRE(b.which() == 2);
+ REQUIRE(e.get<std::string>() == "foo");
+ REQUIRE(e.which() == 2);
+}
+
+TEST_CASE("variant should work with equality operators")
+{
+ using variant_type = mapbox::util::variant<int, std::string>;
+
+ variant_type a{1};
+ variant_type b{1};
+ variant_type c{2};
+ variant_type s{"foo"};
+
+ REQUIRE(a == a);
+ REQUIRE(a == b);
+ REQUIRE_FALSE(a == c);
+ REQUIRE_FALSE(a == s);
+ REQUIRE_FALSE(c == s);
+
+ REQUIRE_FALSE(a != a);
+ REQUIRE_FALSE(a != b);
+ REQUIRE(a != c);
+ REQUIRE(a != s);
+ REQUIRE(c != s);
+}
+
+TEST_CASE("variant should work with comparison operators")
+{
+ using variant_type = mapbox::util::variant<int, std::string>;
+
+ variant_type a{1};
+ variant_type b{1};
+ variant_type c{2};
+ variant_type s{"foo"};
+ variant_type t{"bar"};
+
+ REQUIRE_FALSE(a < a);
+ REQUIRE_FALSE(a < b);
+ REQUIRE(a < c);
+ REQUIRE(a < s);
+ REQUIRE(c < s);
+ REQUIRE(t < s);
+
+ REQUIRE_FALSE(a > a);
+ REQUIRE_FALSE(a > b);
+ REQUIRE_FALSE(a > c);
+ REQUIRE_FALSE(a > s);
+ REQUIRE_FALSE(c > s);
+ REQUIRE_FALSE(t > s);
+
+ REQUIRE(a <= a);
+ REQUIRE(a <= b);
+ REQUIRE(a <= c);
+ REQUIRE(a <= s);
+ REQUIRE(c <= s);
+ REQUIRE(t <= s);
+
+ REQUIRE(a >= a);
+ REQUIRE(a >= b);
+ REQUIRE_FALSE(a >= c);
+ REQUIRE_FALSE(a >= s);
+ REQUIRE_FALSE(c >= s);
+ REQUIRE_FALSE(t >= s);
+}
+
+TEST_CASE("storing reference wrappers works")
+{
+ using variant_type = mapbox::util::variant<std::reference_wrapper<int>, std::reference_wrapper<double>>;
+
+ int a = 1;
+ variant_type v{std::ref(a)};
+ REQUIRE(v.get<int>() == 1);
+ REQUIRE(mapbox::util::get<int>(v) == 1);
+ REQUIRE_THROWS_AS({
+ v.get<double>();
+ },
+ mapbox::util::bad_variant_access&);
+ REQUIRE_THROWS_AS({
+ mapbox::util::get<double>(v);
+ },
+ mapbox::util::bad_variant_access&);
+ a = 2;
+ REQUIRE(v.get<int>() == 2);
+ v.get<int>() = 3;
+ REQUIRE(a == 3);
+
+ double b = 3.141;
+ v = std::ref(b);
+ REQUIRE(v.get<double>() == Approx(3.141));
+ REQUIRE(mapbox::util::get<double>(v) == Approx(3.141));
+ REQUIRE_THROWS_AS({
+ v.get<int>();
+ },
+ mapbox::util::bad_variant_access&);
+ REQUIRE_THROWS_AS({
+ mapbox::util::get<int>(v);
+ },
+ mapbox::util::bad_variant_access&);
+ b = 2.718;
+ REQUIRE(v.get<double>() == Approx(2.718));
+ a = 3;
+ REQUIRE(v.get<double>() == Approx(2.718));
+ v.get<double>() = 4.1;
+ REQUIRE(b == Approx(4.1));
+
+ REQUIRE_THROWS_AS({
+ v.get<int>() = 4;
+ },
+ mapbox::util::bad_variant_access&);
+}
+
+TEST_CASE("storing reference wrappers to consts works")
+{
+ using variant_type = mapbox::util::variant<std::reference_wrapper<int const>, std::reference_wrapper<double const>>;
+
+ int a = 1;
+ variant_type v{std::cref(a)};
+ REQUIRE(v.get<int const>() == 1);
+ REQUIRE(v.get<int>() == 1); // this works (see #82)
+ REQUIRE(mapbox::util::get<int const>(v) == 1);
+ // REQUIRE(mapbox::util::get<int>(v) == 1); // this doesn't work (see #82)
+ REQUIRE_THROWS_AS({
+ v.get<double const>();
+ },
+ mapbox::util::bad_variant_access&);
+ REQUIRE_THROWS_AS({
+ mapbox::util::get<double const>(v);
+ },
+ mapbox::util::bad_variant_access&);
+
+ double b = 3.141;
+ v = std::cref(b);
+ REQUIRE(v.get<double const>() == Approx(3.141));
+ REQUIRE(mapbox::util::get<double const>(v) == Approx(3.141));
+ REQUIRE_THROWS_AS({
+ v.get<int const>();
+ },
+ mapbox::util::bad_variant_access&);
+ REQUIRE_THROWS_AS({
+ mapbox::util::get<int const>(v);
+ },
+ mapbox::util::bad_variant_access&);
+}
diff --git a/test/unique_ptr_test.cpp b/test/unique_ptr_test.cpp
new file mode 100644
index 0000000..6578991
--- /dev/null
+++ b/test/unique_ptr_test.cpp
@@ -0,0 +1,126 @@
+
+#include <cstdlib>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <typeinfo>
+#include <utility>
+
+#include <boost/timer/timer.hpp>
+
+#include "variant.hpp"
+
+using namespace mapbox;
+
+namespace test {
+
+struct add;
+struct sub;
+
+template <typename OpTag>
+struct binary_op;
+
+typedef util::variant<int,
+ std::unique_ptr<binary_op<add>>,
+ std::unique_ptr<binary_op<sub>>>
+ expression;
+
+template <typename Op>
+struct binary_op
+{
+ expression left; // variant instantiated here...
+ expression right;
+
+ binary_op(expression&& lhs, expression&& rhs)
+ : left(std::move(lhs)), right(std::move(rhs))
+ {
+ }
+};
+
+struct print
+{
+ template <typename T>
+ void operator()(T const& val) const
+ {
+ std::cerr << val << ":" << typeid(T).name() << std::endl;
+ }
+};
+
+struct test
+{
+ template <typename T>
+ std::string operator()(T const& obj) const
+ {
+ return std::string("TYPE_ID=") + typeid(obj).name();
+ }
+};
+
+struct calculator
+{
+ public:
+ int operator()(int value) const
+ {
+ return value;
+ }
+
+ int operator()(std::unique_ptr<binary_op<add>> const& binary) const
+ {
+ return util::apply_visitor(calculator(), binary->left) + util::apply_visitor(calculator(), binary->right);
+ }
+
+ int operator()(std::unique_ptr<binary_op<sub>> const& binary) const
+ {
+ return util::apply_visitor(calculator(), binary->left) - util::apply_visitor(calculator(), binary->right);
+ }
+};
+
+struct to_string
+{
+ public:
+ std::string operator()(int value) const
+ {
+ return std::to_string(value);
+ }
+
+ std::string operator()(std::unique_ptr<binary_op<add>> const& binary) const
+ {
+ return util::apply_visitor(to_string(), binary->left) + std::string("+") + util::apply_visitor(to_string(), binary->right);
+ }
+
+ std::string operator()(std::unique_ptr<binary_op<sub>> const& binary) const
+ {
+ return util::apply_visitor(to_string(), binary->left) + std::string("-") + util::apply_visitor(to_string(), binary->right);
+ }
+};
+
+} // namespace test
+
+int main(int argc, char** argv)
+{
+ if (argc != 2)
+ {
+ std::cerr << "Usage" << argv[0] << " <num-iter>" << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ const std::size_t NUM_ITER = static_cast<std::size_t>(std::stol(argv[1]));
+
+ test::expression sum(std::unique_ptr<test::binary_op<test::add>>(new test::binary_op<test::add>(2, 3)));
+ test::expression result(std::unique_ptr<test::binary_op<test::sub>>(new test::binary_op<test::sub>(std::move(sum), 4)));
+
+ std::cerr << "TYPE OF RESULT-> " << util::apply_visitor(test::test(), result) << std::endl;
+
+ int total = 0;
+ {
+ boost::timer::auto_cpu_timer t;
+ for (std::size_t i = 0; i < NUM_ITER; ++i)
+ {
+ total += util::apply_visitor(test::calculator(), result);
+ }
+ }
+ std::cerr << "total=" << total << std::endl;
+
+ std::cerr << util::apply_visitor(test::to_string(), result) << "=" << util::apply_visitor(test::calculator(), result) << std::endl;
+
+ return EXIT_SUCCESS;
+}
diff --git a/test/unit.cpp b/test/unit.cpp
new file mode 100644
index 0000000..0c7c351
--- /dev/null
+++ b/test/unit.cpp
@@ -0,0 +1,2 @@
+#define CATCH_CONFIG_MAIN
+#include "catch.hpp"
diff --git a/variant.gyp b/variant.gyp
new file mode 100644
index 0000000..b1f3801
--- /dev/null
+++ b/variant.gyp
@@ -0,0 +1,35 @@
+{
+ "includes": [
+ "common.gypi"
+ ],
+ "targets": [
+ {
+ "target_name": "tests",
+ "type": "executable",
+ "sources": [
+ "test/unit.cpp",
+ "test/t/binary_visitor_1.cpp",
+ "test/t/binary_visitor_2.cpp",
+ "test/t/binary_visitor_3.cpp",
+ "test/t/binary_visitor_4.cpp",
+ "test/t/binary_visitor_5.cpp",
+ "test/t/binary_visitor_6.cpp",
+ "test/t/issue21.cpp",
+ "test/t/mutating_visitor.cpp",
+ "test/t/optional.cpp",
+ "test/t/recursive_wrapper.cpp",
+ "test/t/sizeof.cpp",
+ "test/t/unary_visitor.cpp",
+ "test/t/variant.cpp"
+ ],
+ "xcode_settings": {
+ "SDKROOT": "macosx",
+ "SUPPORTED_PLATFORMS":["macosx"]
+ },
+ "include_dirs": [
+ "./",
+ "test/include"
+ ]
+ }
+ ]
+}
diff --git a/variant.hpp b/variant.hpp
new file mode 100644
index 0000000..db5d3c8
--- /dev/null
+++ b/variant.hpp
@@ -0,0 +1,901 @@
+#ifndef MAPBOX_UTIL_VARIANT_HPP
+#define MAPBOX_UTIL_VARIANT_HPP
+
+#include <cassert>
+#include <cstddef> // size_t
+#include <new> // operator new
+#include <stdexcept> // runtime_error
+#include <string>
+#include <tuple>
+#include <type_traits>
+#include <typeinfo>
+#include <utility>
+
+#include "recursive_wrapper.hpp"
+
+// clang-format off
+// [[deprecated]] is only available in C++14, use this for the time being
+#if __cplusplus <= 201103L
+# ifdef __GNUC__
+# define MAPBOX_VARIANT_DEPRECATED __attribute__((deprecated))
+# elif defined(_MSC_VER)
+# define MAPBOX_VARIANT_DEPRECATED __declspec(deprecated)
+# else
+# define MAPBOX_VARIANT_DEPRECATED
+# endif
+#else
+# define MAPBOX_VARIANT_DEPRECATED [[deprecated]]
+#endif
+
+
+#ifdef _MSC_VER
+ // https://msdn.microsoft.com/en-us/library/bw1hbe6y.aspx
+ #ifdef NDEBUG
+ #define VARIANT_INLINE __forceinline
+ #else
+ #define VARIANT_INLINE __declspec(noinline)
+ #endif
+#else
+ #ifdef NDEBUG
+ #define VARIANT_INLINE inline __attribute__((always_inline))
+ #else
+ #define VARIANT_INLINE __attribute__((noinline))
+ #endif
+#endif
+// clang-format on
+
+#define VARIANT_MAJOR_VERSION 1
+#define VARIANT_MINOR_VERSION 1
+#define VARIANT_PATCH_VERSION 0
+
+#define VARIANT_VERSION (VARIANT_MAJOR_VERSION * 100000) + (VARIANT_MINOR_VERSION * 100) + (VARIANT_PATCH_VERSION)
+
+namespace mapbox {
+namespace util {
+
+// XXX This should derive from std::logic_error instead of std::runtime_error.
+// See https://github.com/mapbox/variant/issues/48 for details.
+class bad_variant_access : public std::runtime_error
+{
+
+ public:
+ explicit bad_variant_access(const std::string& what_arg)
+ : runtime_error(what_arg) {}
+
+ explicit bad_variant_access(const char* what_arg)
+ : runtime_error(what_arg) {}
+
+}; // class bad_variant_access
+
+template <typename R = void>
+struct MAPBOX_VARIANT_DEPRECATED static_visitor
+{
+ using result_type = R;
+
+ protected:
+ static_visitor() {}
+ ~static_visitor() {}
+};
+
+namespace detail {
+
+static constexpr std::size_t invalid_value = std::size_t(-1);
+
+template <typename T, typename... Types>
+struct direct_type;
+
+template <typename T, typename First, typename... Types>
+struct direct_type<T, First, Types...>
+{
+ static constexpr std::size_t index = std::is_same<T, First>::value
+ ? sizeof...(Types)
+ : direct_type<T, Types...>::index;
+};
+
+template <typename T>
+struct direct_type<T>
+{
+ static constexpr std::size_t index = invalid_value;
+};
+
+template <typename T, typename... Types>
+struct convertible_type;
+
+template <typename T, typename First, typename... Types>
+struct convertible_type<T, First, Types...>
+{
+ static constexpr std::size_t index = std::is_convertible<T, First>::value
+ ? sizeof...(Types)
+ : convertible_type<T, Types...>::index;
+};
+
+template <typename T>
+struct convertible_type<T>
+{
+ static constexpr std::size_t index = invalid_value;
+};
+
+template <typename T, typename... Types>
+struct value_traits
+{
+ using value_type = typename std::remove_reference<T>::type;
+ static constexpr std::size_t direct_index = direct_type<value_type, Types...>::index;
+ static constexpr bool is_direct = direct_index != invalid_value;
+ static constexpr std::size_t index = is_direct ? direct_index : convertible_type<value_type, Types...>::index;
+ static constexpr bool is_valid = index != invalid_value;
+ static constexpr std::size_t tindex = is_valid ? sizeof...(Types)-index : 0;
+ using target_type = typename std::tuple_element<tindex, std::tuple<void, Types...>>::type;
+};
+
+// check if T is in Types...
+template <typename T, typename... Types>
+struct has_type;
+
+template <typename T, typename First, typename... Types>
+struct has_type<T, First, Types...>
+{
+ static constexpr bool value = std::is_same<T, First>::value || has_type<T, Types...>::value;
+};
+
+template <typename T>
+struct has_type<T> : std::false_type
+{
+};
+
+template <typename T, typename... Types>
+struct is_valid_type;
+
+template <typename T, typename First, typename... Types>
+struct is_valid_type<T, First, Types...>
+{
+ static constexpr bool value = std::is_convertible<T, First>::value || is_valid_type<T, Types...>::value;
+};
+
+template <typename T>
+struct is_valid_type<T> : std::false_type
+{
+};
+
+template <typename T, typename R = void>
+struct enable_if_type
+{
+ using type = R;
+};
+
+template <typename F, typename V, typename Enable = void>
+struct result_of_unary_visit
+{
+ using type = typename std::result_of<F(V&)>::type;
+};
+
+template <typename F, typename V>
+struct result_of_unary_visit<F, V, typename enable_if_type<typename F::result_type>::type>
+{
+ using type = typename F::result_type;
+};
+
+template <typename F, typename V, typename Enable = void>
+struct result_of_binary_visit
+{
+ using type = typename std::result_of<F(V&, V&)>::type;
+};
+
+template <typename F, typename V>
+struct result_of_binary_visit<F, V, typename enable_if_type<typename F::result_type>::type>
+{
+ using type = typename F::result_type;
+};
+
+template <std::size_t arg1, std::size_t... others>
+struct static_max;
+
+template <std::size_t arg>
+struct static_max<arg>
+{
+ static const std::size_t value = arg;
+};
+
+template <std::size_t arg1, std::size_t arg2, std::size_t... others>
+struct static_max<arg1, arg2, others...>
+{
+ static const std::size_t value = arg1 >= arg2 ? static_max<arg1, others...>::value : static_max<arg2, others...>::value;
+};
+
+template <typename... Types>
+struct variant_helper;
+
+template <typename T, typename... Types>
+struct variant_helper<T, Types...>
+{
+ VARIANT_INLINE static void destroy(const std::size_t type_index, void* data)
+ {
+ if (type_index == sizeof...(Types))
+ {
+ reinterpret_cast<T*>(data)->~T();
+ }
+ else
+ {
+ variant_helper<Types...>::destroy(type_index, data);
+ }
+ }
+
+ VARIANT_INLINE static void move(const std::size_t old_type_index, void* old_value, void* new_value)
+ {
+ if (old_type_index == sizeof...(Types))
+ {
+ new (new_value) T(std::move(*reinterpret_cast<T*>(old_value)));
+ }
+ else
+ {
+ variant_helper<Types...>::move(old_type_index, old_value, new_value);
+ }
+ }
+
+ VARIANT_INLINE static void copy(const std::size_t old_type_index, const void* old_value, void* new_value)
+ {
+ if (old_type_index == sizeof...(Types))
+ {
+ new (new_value) T(*reinterpret_cast<const T*>(old_value));
+ }
+ else
+ {
+ variant_helper<Types...>::copy(old_type_index, old_value, new_value);
+ }
+ }
+};
+
+template <>
+struct variant_helper<>
+{
+ VARIANT_INLINE static void destroy(const std::size_t, void*) {}
+ VARIANT_INLINE static void move(const std::size_t, void*, void*) {}
+ VARIANT_INLINE static void copy(const std::size_t, const void*, void*) {}
+};
+
+template <typename T>
+struct unwrapper
+{
+ static T const& apply_const(T const& obj) { return obj; }
+ static T& apply(T& obj) { return obj; }
+};
+
+template <typename T>
+struct unwrapper<recursive_wrapper<T>>
+{
+ static auto apply_const(recursive_wrapper<T> const& obj)
+ -> typename recursive_wrapper<T>::type const&
+ {
+ return obj.get();
+ }
+ static auto apply(recursive_wrapper<T>& obj)
+ -> typename recursive_wrapper<T>::type&
+ {
+ return obj.get();
+ }
+};
+
+template <typename T>
+struct unwrapper<std::reference_wrapper<T>>
+{
+ static auto apply_const(std::reference_wrapper<T> const& obj)
+ -> typename std::reference_wrapper<T>::type const&
+ {
+ return obj.get();
+ }
+ static auto apply(std::reference_wrapper<T>& obj)
+ -> typename std::reference_wrapper<T>::type&
+ {
+ return obj.get();
+ }
+};
+
+template <typename F, typename V, typename R, typename... Types>
+struct dispatcher;
+
+template <typename F, typename V, typename R, typename T, typename... Types>
+struct dispatcher<F, V, R, T, Types...>
+{
+ VARIANT_INLINE static R apply_const(V const& v, F&& f)
+ {
+ if (v.template is<T>())
+ {
+ return f(unwrapper<T>::apply_const(v.template get<T>()));
+ }
+ else
+ {
+ return dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f));
+ }
+ }
+
+ VARIANT_INLINE static R apply(V& v, F&& f)
+ {
+ if (v.template is<T>())
+ {
+ return f(unwrapper<T>::apply(v.template get<T>()));
+ }
+ else
+ {
+ return dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f));
+ }
+ }
+};
+
+template <typename F, typename V, typename R, typename T>
+struct dispatcher<F, V, R, T>
+{
+ VARIANT_INLINE static R apply_const(V const& v, F&& f)
+ {
+ return f(unwrapper<T>::apply_const(v.template get<T>()));
+ }
+
+ VARIANT_INLINE static R apply(V& v, F&& f)
+ {
+ return f(unwrapper<T>::apply(v.template get<T>()));
+ }
+};
+
+template <typename F, typename V, typename R, typename T, typename... Types>
+struct binary_dispatcher_rhs;
+
+template <typename F, typename V, typename R, typename T0, typename T1, typename... Types>
+struct binary_dispatcher_rhs<F, V, R, T0, T1, Types...>
+{
+ VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
+ {
+ if (rhs.template is<T1>()) // call binary functor
+ {
+ return f(unwrapper<T0>::apply_const(lhs.template get<T0>()),
+ unwrapper<T1>::apply_const(rhs.template get<T1>()));
+ }
+ else
+ {
+ return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply_const(lhs, rhs, std::forward<F>(f));
+ }
+ }
+
+ VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
+ {
+ if (rhs.template is<T1>()) // call binary functor
+ {
+ return f(unwrapper<T0>::apply(lhs.template get<T0>()),
+ unwrapper<T1>::apply(rhs.template get<T1>()));
+ }
+ else
+ {
+ return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply(lhs, rhs, std::forward<F>(f));
+ }
+ }
+};
+
+template <typename F, typename V, typename R, typename T0, typename T1>
+struct binary_dispatcher_rhs<F, V, R, T0, T1>
+{
+ VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
+ {
+ return f(unwrapper<T0>::apply_const(lhs.template get<T0>()),
+ unwrapper<T1>::apply_const(rhs.template get<T1>()));
+ }
+
+ VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
+ {
+ return f(unwrapper<T0>::apply(lhs.template get<T0>()),
+ unwrapper<T1>::apply(rhs.template get<T1>()));
+ }
+};
+
+template <typename F, typename V, typename R, typename T, typename... Types>
+struct binary_dispatcher_lhs;
+
+template <typename F, typename V, typename R, typename T0, typename T1, typename... Types>
+struct binary_dispatcher_lhs<F, V, R, T0, T1, Types...>
+{
+ VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
+ {
+ if (lhs.template is<T1>()) // call binary functor
+ {
+ return f(unwrapper<T1>::apply_const(lhs.template get<T1>()),
+ unwrapper<T0>::apply_const(rhs.template get<T0>()));
+ }
+ else
+ {
+ return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply_const(lhs, rhs, std::forward<F>(f));
+ }
+ }
+
+ VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
+ {
+ if (lhs.template is<T1>()) // call binary functor
+ {
+ return f(unwrapper<T1>::apply(lhs.template get<T1>()),
+ unwrapper<T0>::apply(rhs.template get<T0>()));
+ }
+ else
+ {
+ return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply(lhs, rhs, std::forward<F>(f));
+ }
+ }
+};
+
+template <typename F, typename V, typename R, typename T0, typename T1>
+struct binary_dispatcher_lhs<F, V, R, T0, T1>
+{
+ VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
+ {
+ return f(unwrapper<T1>::apply_const(lhs.template get<T1>()),
+ unwrapper<T0>::apply_const(rhs.template get<T0>()));
+ }
+
+ VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
+ {
+ return f(unwrapper<T1>::apply(lhs.template get<T1>()),
+ unwrapper<T0>::apply(rhs.template get<T0>()));
+ }
+};
+
+template <typename F, typename V, typename R, typename... Types>
+struct binary_dispatcher;
+
+template <typename F, typename V, typename R, typename T, typename... Types>
+struct binary_dispatcher<F, V, R, T, Types...>
+{
+ VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f)
+ {
+ if (v0.template is<T>())
+ {
+ if (v1.template is<T>())
+ {
+ return f(unwrapper<T>::apply_const(v0.template get<T>()),
+ unwrapper<T>::apply_const(v1.template get<T>())); // call binary functor
+ }
+ else
+ {
+ return binary_dispatcher_rhs<F, V, R, T, Types...>::apply_const(v0, v1, std::forward<F>(f));
+ }
+ }
+ else if (v1.template is<T>())
+ {
+ return binary_dispatcher_lhs<F, V, R, T, Types...>::apply_const(v0, v1, std::forward<F>(f));
+ }
+ return binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f));
+ }
+
+ VARIANT_INLINE static R apply(V& v0, V& v1, F&& f)
+ {
+ if (v0.template is<T>())
+ {
+ if (v1.template is<T>())
+ {
+ return f(unwrapper<T>::apply(v0.template get<T>()),
+ unwrapper<T>::apply(v1.template get<T>())); // call binary functor
+ }
+ else
+ {
+ return binary_dispatcher_rhs<F, V, R, T, Types...>::apply(v0, v1, std::forward<F>(f));
+ }
+ }
+ else if (v1.template is<T>())
+ {
+ return binary_dispatcher_lhs<F, V, R, T, Types...>::apply(v0, v1, std::forward<F>(f));
+ }
+ return binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f));
+ }
+};
+
+template <typename F, typename V, typename R, typename T>
+struct binary_dispatcher<F, V, R, T>
+{
+ VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f)
+ {
+ return f(unwrapper<T>::apply_const(v0.template get<T>()),
+ unwrapper<T>::apply_const(v1.template get<T>())); // call binary functor
+ }
+
+ VARIANT_INLINE static R apply(V& v0, V& v1, F&& f)
+ {
+ return f(unwrapper<T>::apply(v0.template get<T>()),
+ unwrapper<T>::apply(v1.template get<T>())); // call binary functor
+ }
+};
+
+// comparator functors
+struct equal_comp
+{
+ template <typename T>
+ bool operator()(T const& lhs, T const& rhs) const
+ {
+ return lhs == rhs;
+ }
+};
+
+struct less_comp
+{
+ template <typename T>
+ bool operator()(T const& lhs, T const& rhs) const
+ {
+ return lhs < rhs;
+ }
+};
+
+template <typename Variant, typename Comp>
+class comparer
+{
+ public:
+ explicit comparer(Variant const& lhs) noexcept
+ : lhs_(lhs) {}
+ comparer& operator=(comparer const&) = delete;
+ // visitor
+ template <typename T>
+ bool operator()(T const& rhs_content) const
+ {
+ T const& lhs_content = lhs_.template get<T>();
+ return Comp()(lhs_content, rhs_content);
+ }
+
+ private:
+ Variant const& lhs_;
+};
+
+// True if Predicate matches for all of the types Ts
+template <template <typename> class Predicate, typename... Ts>
+struct static_all_of : std::is_same<std::tuple<std::true_type, typename Predicate<Ts>::type...>,
+ std::tuple<typename Predicate<Ts>::type..., std::true_type>>
+{
+};
+
+// True if Predicate matches for none of the types Ts
+template <template <typename> class Predicate, typename... Ts>
+struct static_none_of : std::is_same<std::tuple<std::false_type, typename Predicate<Ts>::type...>,
+ std::tuple<typename Predicate<Ts>::type..., std::false_type>>
+{
+};
+
+} // namespace detail
+
+struct no_init
+{
+};
+
+template <typename... Types>
+class variant
+{
+ static_assert(sizeof...(Types) > 0, "Template parameter type list of variant can not be empty");
+ static_assert(detail::static_none_of<std::is_reference, Types...>::value, "Variant can not hold reference types. Maybe use std::reference?");
+
+ private:
+ static const std::size_t data_size = detail::static_max<sizeof(Types)...>::value;
+ static const std::size_t data_align = detail::static_max<alignof(Types)...>::value;
+
+ using first_type = typename std::tuple_element<0, std::tuple<Types...>>::type;
+ using data_type = typename std::aligned_storage<data_size, data_align>::type;
+ using helper_type = detail::variant_helper<Types...>;
+
+ std::size_t type_index;
+ data_type data;
+
+ public:
+ VARIANT_INLINE variant() noexcept(std::is_nothrow_default_constructible<first_type>::value)
+ : type_index(sizeof...(Types)-1)
+ {
+ static_assert(std::is_default_constructible<first_type>::value, "First type in variant must be default constructible to allow default construction of variant");
+ new (&data) first_type();
+ }
+
+ VARIANT_INLINE variant(no_init) noexcept
+ : type_index(detail::invalid_value) {}
+
+ // http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers
+ template <typename T, typename Traits = detail::value_traits<T, Types...>,
+ typename Enable = typename std::enable_if<Traits::is_valid>::type>
+ VARIANT_INLINE variant(T&& val) noexcept(std::is_nothrow_constructible<typename Traits::target_type, T&&>::value)
+ : type_index(Traits::index)
+ {
+ new (&data) typename Traits::target_type(std::forward<T>(val));
+ }
+
+ VARIANT_INLINE variant(variant<Types...> const& old)
+ : type_index(old.type_index)
+ {
+ helper_type::copy(old.type_index, &old.data, &data);
+ }
+
+ VARIANT_INLINE variant(variant<Types...>&& old) noexcept(std::is_nothrow_move_constructible<std::tuple<Types...>>::value)
+ : type_index(old.type_index)
+ {
+ helper_type::move(old.type_index, &old.data, &data);
+ }
+
+ private:
+ VARIANT_INLINE void copy_assign(variant<Types...> const& rhs)
+ {
+ helper_type::destroy(type_index, &data);
+ type_index = detail::invalid_value;
+ helper_type::copy(rhs.type_index, &rhs.data, &data);
+ type_index = rhs.type_index;
+ }
+
+ VARIANT_INLINE void move_assign(variant<Types...>&& rhs)
+ {
+ helper_type::destroy(type_index, &data);
+ type_index = detail::invalid_value;
+ helper_type::move(rhs.type_index, &rhs.data, &data);
+ type_index = rhs.type_index;
+ }
+
+ public:
+ VARIANT_INLINE variant<Types...>& operator=(variant<Types...>&& other)
+ {
+ move_assign(std::move(other));
+ return *this;
+ }
+
+ VARIANT_INLINE variant<Types...>& operator=(variant<Types...> const& other)
+ {
+ copy_assign(other);
+ return *this;
+ }
+
+ // conversions
+ // move-assign
+ template <typename T>
+ VARIANT_INLINE variant<Types...>& operator=(T&& rhs) noexcept
+ {
+ variant<Types...> temp(std::forward<T>(rhs));
+ move_assign(std::move(temp));
+ return *this;
+ }
+
+ // copy-assign
+ template <typename T>
+ VARIANT_INLINE variant<Types...>& operator=(T const& rhs)
+ {
+ variant<Types...> temp(rhs);
+ copy_assign(temp);
+ return *this;
+ }
+
+ template <typename T>
+ VARIANT_INLINE bool is() const
+ {
+ static_assert(detail::has_type<T, Types...>::value, "invalid type in T in `is<T>()` for this variant");
+ return type_index == detail::direct_type<T, Types...>::index;
+ }
+
+ VARIANT_INLINE bool valid() const
+ {
+ return type_index != detail::invalid_value;
+ }
+
+ template <typename T, typename... Args>
+ VARIANT_INLINE void set(Args&&... args)
+ {
+ helper_type::destroy(type_index, &data);
+ type_index = detail::invalid_value;
+ new (&data) T(std::forward<Args>(args)...);
+ type_index = detail::direct_type<T, Types...>::index;
+ }
+
+ // get<T>()
+ template <typename T, typename std::enable_if<
+ (detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
+ VARIANT_INLINE T& get()
+ {
+ if (type_index == detail::direct_type<T, Types...>::index)
+ {
+ return *reinterpret_cast<T*>(&data);
+ }
+ else
+ {
+ throw bad_variant_access("in get<T>()");
+ }
+ }
+
+ template <typename T, typename std::enable_if<
+ (detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
+ VARIANT_INLINE T const& get() const
+ {
+ if (type_index == detail::direct_type<T, Types...>::index)
+ {
+ return *reinterpret_cast<T const*>(&data);
+ }
+ else
+ {
+ throw bad_variant_access("in get<T>()");
+ }
+ }
+
+ // get<T>() - T stored as recursive_wrapper<T>
+ template <typename T, typename std::enable_if<
+ (detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
+ VARIANT_INLINE T& get()
+ {
+ if (type_index == detail::direct_type<recursive_wrapper<T>, Types...>::index)
+ {
+ return (*reinterpret_cast<recursive_wrapper<T>*>(&data)).get();
+ }
+ else
+ {
+ throw bad_variant_access("in get<T>()");
+ }
+ }
+
+ template <typename T, typename std::enable_if<
+ (detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
+ VARIANT_INLINE T const& get() const
+ {
+ if (type_index == detail::direct_type<recursive_wrapper<T>, Types...>::index)
+ {
+ return (*reinterpret_cast<recursive_wrapper<T> const*>(&data)).get();
+ }
+ else
+ {
+ throw bad_variant_access("in get<T>()");
+ }
+ }
+
+ // get<T>() - T stored as std::reference_wrapper<T>
+ template <typename T, typename std::enable_if<
+ (detail::direct_type<std::reference_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
+ VARIANT_INLINE T& get()
+ {
+ if (type_index == detail::direct_type<std::reference_wrapper<T>, Types...>::index)
+ {
+ return (*reinterpret_cast<std::reference_wrapper<T>*>(&data)).get();
+ }
+ else
+ {
+ throw bad_variant_access("in get<T>()");
+ }
+ }
+
+ template <typename T, typename std::enable_if<
+ (detail::direct_type<std::reference_wrapper<T const>, Types...>::index != detail::invalid_value)>::type* = nullptr>
+ VARIANT_INLINE T const& get() const
+ {
+ if (type_index == detail::direct_type<std::reference_wrapper<T const>, Types...>::index)
+ {
+ return (*reinterpret_cast<std::reference_wrapper<T const> const*>(&data)).get();
+ }
+ else
+ {
+ throw bad_variant_access("in get<T>()");
+ }
+ }
+
+ // This function is deprecated because it returns an internal index field.
+ // Use which() instead.
+ MAPBOX_VARIANT_DEPRECATED VARIANT_INLINE std::size_t get_type_index() const
+ {
+ return type_index;
+ }
+
+ VARIANT_INLINE int which() const noexcept
+ {
+ return static_cast<int>(sizeof...(Types)-type_index - 1);
+ }
+
+ // visitor
+ // unary
+ template <typename F, typename V, typename R = typename detail::result_of_unary_visit<F, first_type>::type>
+ auto VARIANT_INLINE static visit(V const& v, F&& f)
+ -> decltype(detail::dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f)))
+ {
+ return detail::dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f));
+ }
+ // non-const
+ template <typename F, typename V, typename R = typename detail::result_of_unary_visit<F, first_type>::type>
+ auto VARIANT_INLINE static visit(V& v, F&& f)
+ -> decltype(detail::dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f)))
+ {
+ return detail::dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f));
+ }
+
+ // binary
+ // const
+ template <typename F, typename V, typename R = typename detail::result_of_binary_visit<F, first_type>::type>
+ auto VARIANT_INLINE static binary_visit(V const& v0, V const& v1, F&& f)
+ -> decltype(detail::binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f)))
+ {
+ return detail::binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f));
+ }
+ // non-const
+ template <typename F, typename V, typename R = typename detail::result_of_binary_visit<F, first_type>::type>
+ auto VARIANT_INLINE static binary_visit(V& v0, V& v1, F&& f)
+ -> decltype(detail::binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f)))
+ {
+ return detail::binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f));
+ }
+
+ ~variant() noexcept // no-throw destructor
+ {
+ helper_type::destroy(type_index, &data);
+ }
+
+ // comparison operators
+ // equality
+ VARIANT_INLINE bool operator==(variant const& rhs) const
+ {
+ assert(valid() && rhs.valid());
+ if (this->which() != rhs.which())
+ {
+ return false;
+ }
+ detail::comparer<variant, detail::equal_comp> visitor(*this);
+ return visit(rhs, visitor);
+ }
+
+ VARIANT_INLINE bool operator!=(variant const& rhs) const
+ {
+ return !(*this == rhs);
+ }
+
+ // less than
+ VARIANT_INLINE bool operator<(variant const& rhs) const
+ {
+ assert(valid() && rhs.valid());
+ if (this->which() != rhs.which())
+ {
+ return this->which() < rhs.which();
+ }
+ detail::comparer<variant, detail::less_comp> visitor(*this);
+ return visit(rhs, visitor);
+ }
+ VARIANT_INLINE bool operator>(variant const& rhs) const
+ {
+ return rhs < *this;
+ }
+ VARIANT_INLINE bool operator<=(variant const& rhs) const
+ {
+ return !(*this > rhs);
+ }
+ VARIANT_INLINE bool operator>=(variant const& rhs) const
+ {
+ return !(*this < rhs);
+ }
+};
+
+// unary visitor interface
+// const
+template <typename F, typename V>
+auto VARIANT_INLINE apply_visitor(F&& f, V const& v) -> decltype(V::visit(v, std::forward<F>(f)))
+{
+ return V::visit(v, std::forward<F>(f));
+}
+
+// non-const
+template <typename F, typename V>
+auto VARIANT_INLINE apply_visitor(F&& f, V& v) -> decltype(V::visit(v, std::forward<F>(f)))
+{
+ return V::visit(v, std::forward<F>(f));
+}
+
+// binary visitor interface
+// const
+template <typename F, typename V>
+auto VARIANT_INLINE apply_visitor(F&& f, V const& v0, V const& v1) -> decltype(V::binary_visit(v0, v1, std::forward<F>(f)))
+{
+ return V::binary_visit(v0, v1, std::forward<F>(f));
+}
+
+// non-const
+template <typename F, typename V>
+auto VARIANT_INLINE apply_visitor(F&& f, V& v0, V& v1) -> decltype(V::binary_visit(v0, v1, std::forward<F>(f)))
+{
+ return V::binary_visit(v0, v1, std::forward<F>(f));
+}
+
+// getter interface
+template <typename ResultType, typename T>
+ResultType& get(T& var)
+{
+ return var.template get<ResultType>();
+}
+
+template <typename ResultType, typename T>
+ResultType const& get(T const& var)
+{
+ return var.template get<ResultType>();
+}
+} // namespace util
+} // namespace mapbox
+
+#endif // MAPBOX_UTIL_VARIANT_HPP
diff --git a/variant_io.hpp b/variant_io.hpp
new file mode 100644
index 0000000..e64cbad
--- /dev/null
+++ b/variant_io.hpp
@@ -0,0 +1,45 @@
+#ifndef MAPBOX_UTIL_VARIANT_IO_HPP
+#define MAPBOX_UTIL_VARIANT_IO_HPP
+
+#include <iosfwd>
+
+#include "variant.hpp"
+
+namespace mapbox {
+namespace util {
+
+namespace detail {
+// operator<< helper
+template <typename Out>
+class printer
+{
+ public:
+ explicit printer(Out& out)
+ : out_(out) {}
+ printer& operator=(printer const&) = delete;
+
+ // visitor
+ template <typename T>
+ void operator()(T const& operand) const
+ {
+ out_ << operand;
+ }
+
+ private:
+ Out& out_;
+};
+}
+
+// operator<<
+template <typename CharT, typename Traits, typename... Types>
+VARIANT_INLINE std::basic_ostream<CharT, Traits>&
+operator<<(std::basic_ostream<CharT, Traits>& out, variant<Types...> const& rhs)
+{
+ detail::printer<std::basic_ostream<CharT, Traits>> visitor(out);
+ apply_visitor(visitor, rhs);
+ return out;
+}
+} // namespace util
+} // namespace mapbox
+
+#endif // MAPBOX_UTIL_VARIANT_IO_HPP
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/mapbox-variant.git
More information about the Pkg-grass-devel
mailing list